1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8-unix -*- */
3 Copyright (c) 2010 Kristóf Ralovich
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 #include "shaderutil.h"
33 static int WinWidth
= 512, WinHeight
= 512;
34 static int mouseGrabbed
= 0;
35 static GLuint vertShader
;
36 static GLuint fragShader
;
37 static GLuint program
;
38 static float rot
[9] = {1,0,0, 0,1,0, 0,0,1};
40 static const char* vsSource
=
41 "varying vec2 rayDir; \n"
45 " rayDir = gl_MultiTexCoord0.xy - vec2(0.5,0.5); \n"
46 " gl_Position = gl_ProjectionMatrix * gl_Vertex; \n"
49 static const char* fsSource
=
50 "const float INF = 9999.9; \n"
51 "const float EPSILON = 0.00001; \n"
52 "const vec3 lightPos = vec3(0.0, 8.0, 1.0); \n"
53 "const vec4 backgroundColor = vec4(0.2,0.3,0.4,1); \n"
55 "varying vec2 rayDir; \n"
57 "uniform mat3 rot; \n"
79 "const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n"
80 "const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n"
81 "const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n"
82 "const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n"
84 "// Mesa intel gen4 generates \"unsupported IR in fragment shader 13\" for\n"
85 "// sqrt, let's work around. \n"
87 "sqrt_hack(float f2) \n"
89 " vec3 v = vec3(f2,0.0,0.0); \n"
90 " return length(v); \n"
94 "intersect(const in Ray ray, \n"
95 " const in Sphere sph, \n"
96 " const in int idx, \n"
97 " inout Isec isec) \n"
99 " // Project both o and the sphere to the plane perpendicular to d \n"
100 " // and containing c. Let x be the point where the ray intersects \n"
101 " // the plane. If |x-c| < r, the ray intersects the sphere. \n"
102 " vec3 o = ray.orig; \n"
103 " vec3 d = ray.dir; \n"
105 " vec3 c = sph.c; \n"
106 " float r = sph.r; \n"
107 " float t = dot(c-o,n)/dot(n,d); \n"
108 " vec3 x = o+d*t; \n"
109 " float e = length(x-c); \n"
112 " // no intersection \n"
116 " // Apply Pythagorean theorem on the (intersection,x,c) triangle \n"
117 " // to get the distance between c and the intersection. \n"
118 "#ifndef BUGGY_INTEL_GEN4_GLSL \n"
119 " float f = sqrt(r*r - e*e); \n"
121 " float f = sqrt_hack(r*r - e*e); \n"
123 " float dist = t - f; \n"
126 " // inside the sphere \n"
130 " if(dist < EPSILON) \n"
133 " if(dist > isec.t) \n"
137 " isec.idx = idx; \n"
139 " isec.hit = ray.orig + ray.dir * isec.t; \n"
140 " isec.n = (isec.hit - c) / r; \n"
144 "intersect(const in Ray ray, \n"
145 " const in float max_t /*= INF*/) \n"
148 " nearest.t = max_t; \n"
149 " nearest.idx = -1; \n"
151 " intersect(ray, spheres0, 0, nearest); \n"
152 " intersect(ray, spheres1, 1, nearest); \n"
153 " intersect(ray, spheres2, 2, nearest); \n"
154 " intersect(ray, spheres3, 3, nearest); \n"
156 " return nearest; \n"
160 "idx2color(const in int idx) \n"
164 " diff = vec4(1.0, 0.0, 0.0, 0.0); \n"
165 " else if(idx == 1) \n"
166 " diff = vec4(0.0, 1.0, 0.0, 0.0); \n"
167 " else if(idx == 2) \n"
168 " diff = vec4(0.0, 0.0, 1.0, 0.0); \n"
169 " else if(idx == 3) \n"
170 " diff = vec4(1.0, 1.0, 0.0, 0.0); \n"
175 "trace0(const in Ray ray) \n"
177 " Isec isec = intersect(ray, INF); \n"
179 " if(isec.idx == -1) \n"
181 " return backgroundColor; \n"
184 " vec4 diff = idx2color(isec.idx); \n"
186 " vec3 N = isec.n; \n"
187 " vec3 L = normalize(lightPos-isec.hit); \n"
188 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
189 " return dot(N,L)*diff + pow( \n"
190 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
194 "trace1(const in Ray ray) \n"
196 " Isec isec = intersect(ray, INF); \n"
198 " if(isec.idx == -1) \n"
200 " return backgroundColor; \n"
203 " Ray reflRay = Ray(isec.hit, reflect(ray.dir, isec.n)); \n"
205 " vec4 reflCol = trace0(reflRay); \n"
207 " vec4 diff = idx2color(isec.idx) + reflCol; \n"
209 " vec3 N = isec.n; \n"
210 " vec3 L = normalize(lightPos-isec.hit); \n"
211 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
212 " return dot(N,L)*diff + pow( \n"
213 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
218 " const float z = -0.5; \n"
219 " const vec3 cameraPos = vec3(0,0,3); \n"
220 " Ray r = Ray(cameraPos, normalize(vec3(rayDir, z) * rot)); \n"
221 " gl_FragColor = trace1(r); \n"
226 deg2rad(const float degree
)
228 return( degree
* 0.017453292519943295769236907684886F
);
232 rotate_xy(float* mat3
, const float degreesAroundX
, const float degreesAroundY
)
234 const float rad1
= deg2rad(degreesAroundX
);
235 const float c1
= cosf(rad1
);
236 const float s1
= sinf(rad1
);
237 const float rad2
= deg2rad(degreesAroundY
);
238 const float c2
= cosf(rad2
);
239 const float s2
= sinf(rad2
);
240 mat3
[0] = c2
; mat3
[3] = 0.0F
; mat3
[6] = s2
;
241 mat3
[1] = s1
*s2
; mat3
[4] = c1
; mat3
[7] = -s1
*c2
;
242 mat3
[2] = -c1
*s2
;mat3
[5] = s1
; mat3
[8] = c1
*c2
;
246 identity(float* mat3
)
248 mat3
[0] = 1.0F
; mat3
[3] = 0.0F
; mat3
[6] = 0.0F
;
249 mat3
[1] = 0.0F
; mat3
[4] = 1.0F
; mat3
[7] = 0.0F
;
250 mat3
[2] = 0.0F
; mat3
[5] = 0.0F
; mat3
[8] = 1.0F
;
256 GLint location
= glGetUniformLocation(program
, "rot");
257 static const float m
= -10.F
;
258 static const float p
= 10.F
;
259 static const float d
= -0.5F
;
261 glUseProgram(program
);
262 glUniformMatrix3fv(location
, 1, 0, rot
);
266 glTexCoord2f(0.0F
, 0.0F
); glVertex3f(m
, m
, d
);
267 glTexCoord2f(1.0F
, 0.0F
); glVertex3f(p
, m
, d
);
268 glTexCoord2f(1.0F
, 1.0F
); glVertex3f(p
, p
, d
);
269 glTexCoord2f(0.0F
, 1.0F
); glVertex3f(m
, p
, d
);
277 static int frames
= 0;
282 t1
= glutGet(GLUT_ELAPSED_TIME
);
283 dt
= (float)(t1
-t0
)/1000.0F
;
286 float fps
= (float)frames
/ dt
;
287 printf("%f FPS (%d frames in %f seconds)\n", fps
, frames
, dt
);
296 Reshape(int width
, int height
)
300 glViewport(0, 0, width
, height
);
301 glMatrixMode(GL_PROJECTION
);
303 glOrtho(-10, 10, -10, 10, -1, 1);
304 glMatrixMode(GL_MODELVIEW
);
310 Key(unsigned char key
, int x
, int y
)
316 glutDestroyWindow(Win
);
331 static GLfloat xRot
= 0, yRot
= 0;
332 xRot
= (float)(x
- WinWidth
/2) / scale
;
333 yRot
= (float)(y
- WinHeight
/2) / scale
;
335 rotate_xy(rot
, yRot
, xRot
);
343 mouse(int button
, int state
, int x
, int y
)
345 mouseGrabbed
= (state
== GLUT_DOWN
);
352 glDisable(GL_DEPTH_TEST
);
354 if(!ShadersSupported())
356 fprintf(stderr
, "Shaders are not supported!\n");
360 vertShader
= CompileShaderText(GL_VERTEX_SHADER
, vsSource
);
361 fragShader
= CompileShaderText(GL_FRAGMENT_SHADER
, fsSource
);
362 program
= LinkShaders(vertShader
, fragShader
);
365 if(glGetError() != 0)
367 fprintf(stderr
, "Shaders were not loaded!\n");
371 if(!glIsShader(vertShader
))
373 fprintf(stderr
, "Vertex shader failed!\n");
377 if(!glIsProgram(program
))
379 fprintf(stderr
, "Shader program failed!\n");
383 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER
));
388 main(int argc
, char *argv
[])
390 glutInitWindowSize(WinWidth
, WinHeight
);
391 glutInit(&argc
, argv
);
392 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
393 Win
= glutCreateWindow(argv
[0]);
395 glutReshapeFunc(Reshape
);
396 glutKeyboardFunc(Key
);
397 glutDisplayFunc(Draw
);
398 glutMouseFunc(mouse
);
399 glutMotionFunc(drag
);