Merge branch '7.8'
[mesa.git] / progs / glsl / vsraytrace.c
1 /* -*- mode: c; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; coding: utf-8-unix -*- */
2 /*
3 Copyright (c) 2010 Kristóf Ralovich
4
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:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
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
21 THE SOFTWARE.
22 */
23
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <GL/glew.h>
28 #include <GL/glut.h>
29 #include "shaderutil.h"
30 #include <math.h>
31
32 static int Win;
33 static int WinWidth = 256, WinHeight = 256;
34 static GLboolean mouseGrabbed = GL_FALSE;
35 static GLuint vertShader;
36 static GLuint program;
37 float rot[9] = {1,0,0, 0,1,0, 0,0,1};
38
39 static const char* vsSource =
40 "const float INF = 9999.9; \n"
41 "const float EPSILON = 0.00001; \n"
42 "const vec3 lightPos = vec3(0.0, 8.0, 1.0); \n"
43 "const vec4 backgroundColor = vec4(0.2,0.3,0.4,1); \n"
44 " \n"
45 "uniform mat3 rot; \n"
46 " \n"
47 "struct Ray \n"
48 "{ \n"
49 "vec3 orig; \n"
50 "vec3 dir; \n"
51 "}; \n"
52 " \n"
53 "struct Sphere \n"
54 "{ \n"
55 " vec3 c; \n"
56 " float r; \n"
57 "}; \n"
58 " \n"
59 "struct Isec \n"
60 "{ \n"
61 " float t; \n"
62 " int idx; \n"
63 " vec3 hit; \n"
64 " vec3 n; \n"
65 "}; \n"
66 " \n"
67 #ifdef __APPLE__
68 "Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n"
69 "Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n"
70 "Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n"
71 "Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n"
72 #else
73 "const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 ); \n"
74 "const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 ); \n"
75 "const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 ); \n"
76 "const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 ); \n"
77 #endif
78 " \n"
79 "// Mesa intel gen4 generates \"unsupported IR in fragment shader 13\" for\n"
80 "// sqrt, let's work around. \n"
81 "float \n"
82 "sqrt_hack(float f2) \n"
83 "{ \n"
84 " vec3 v = vec3(f2,0.0,0.0); \n"
85 " return length(v); \n"
86 "} \n"
87 " \n"
88 "void \n"
89 "intersect(const in Ray ray, \n"
90 " const in Sphere sph, \n"
91 " const in int idx, \n"
92 " inout Isec isec) \n"
93 "{ \n"
94 " // Project both o and the sphere to the plane perpendicular to d \n"
95 " // and containing c. Let x be the point where the ray intersects \n"
96 " // the plane. If |x-c| < r, the ray intersects the sphere. \n"
97 " vec3 o = ray.orig; \n"
98 " vec3 d = ray.dir; \n"
99 " vec3 n = -d; \n"
100 " vec3 c = sph.c; \n"
101 " float r = sph.r; \n"
102 " float t = dot(c-o,n)/dot(n,d); \n"
103 " vec3 x = o+d*t; \n"
104 " float e = length(x-c); \n"
105 " if(e > r) \n"
106 " { \n"
107 " // no intersection \n"
108 " return; \n"
109 " } \n"
110 " \n"
111 " // Apply Pythagorean theorem on the (intersection,x,c) triangle \n"
112 " // to get the distance between c and the intersection. \n"
113 "#define BUGGY_INTEL_GEN4_GLSL 1 \n"
114 "#ifndef BUGGY_INTEL_GEN4_GLSL \n"
115 " float f = sqrt(r*r - e*e); \n"
116 "#else \n"
117 " float f = sqrt_hack(r*r - e*e); \n"
118 "#endif \n"
119 " float dist = t - f; \n"
120 " if(dist < 0.0) \n"
121 " { \n"
122 " // inside the sphere \n"
123 " return; \n"
124 " } \n"
125 " \n"
126 " if(dist < EPSILON) \n"
127 " return; \n"
128 " \n"
129 " if(dist > isec.t) \n"
130 " return; \n"
131 " \n"
132 " isec.t = dist; \n"
133 " isec.idx = idx; \n"
134 " \n"
135 " isec.hit = ray.orig + ray.dir * isec.t; \n"
136 " isec.n = (isec.hit - c) / r; \n"
137 "} \n"
138 " \n"
139 "Isec \n"
140 "intersect(const in Ray ray, \n"
141 " const in float max_t /*= INF*/) \n"
142 "{ \n"
143 " Isec nearest; \n"
144 " nearest.t = max_t; \n"
145 " nearest.idx = -1; \n"
146 " \n"
147 " intersect(ray, spheres0, 0, nearest); \n"
148 " intersect(ray, spheres1, 1, nearest); \n"
149 " intersect(ray, spheres2, 2, nearest); \n"
150 " intersect(ray, spheres3, 3, nearest); \n"
151 " \n"
152 " return nearest; \n"
153 "} \n"
154 " \n"
155 "vec4 \n"
156 "idx2color(const in int idx) \n"
157 "{ \n"
158 " vec4 diff; \n"
159 " if(idx == 0) \n"
160 " diff = vec4(1.0, 0.0, 0.0, 0.0); \n"
161 " else if(idx == 1) \n"
162 " diff = vec4(0.0, 1.0, 0.0, 0.0); \n"
163 " else if(idx == 2) \n"
164 " diff = vec4(0.0, 0.0, 1.0, 0.0); \n"
165 " else if(idx == 3) \n"
166 " diff = vec4(1.0, 1.0, 0.0, 0.0); \n"
167 " return diff; \n"
168 "} \n"
169 " \n"
170 "vec4 \n"
171 "trace0(const in Ray ray) \n"
172 "{ \n"
173 " Isec isec = intersect(ray, INF); \n"
174 " \n"
175 " if(isec.idx == -1) \n"
176 " { \n"
177 " return backgroundColor; \n"
178 " } \n"
179 " \n"
180 " vec4 diff = idx2color(isec.idx); \n"
181 " \n"
182 " vec3 N = isec.n; \n"
183 " vec3 L = normalize(lightPos-isec.hit); \n"
184 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
185 " return dot(N,L)*diff + pow( \n"
186 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
187 "} \n"
188 " \n"
189 "vec4 \n"
190 "trace1(const in Ray ray) \n"
191 "{ \n"
192 " Isec isec = intersect(ray, INF); \n"
193 " \n"
194 " if(isec.idx == -1) \n"
195 " { \n"
196 " return backgroundColor; \n"
197 " } \n"
198 " \n"
199 " Ray reflRay = Ray(isec.hit, reflect(ray.dir, isec.n)); \n"
200 " \n"
201 " vec4 reflCol = trace0(reflRay); \n"
202 " \n"
203 " vec4 diff = idx2color(isec.idx) + reflCol; \n"
204 " \n"
205 " vec3 N = isec.n; \n"
206 " vec3 L = normalize(lightPos-isec.hit); \n"
207 " vec3 camera_dir = normalize(ray.orig - isec.hit); \n"
208 " return dot(N,L)*diff + pow( \n"
209 " clamp(dot(reflect(-L,N),camera_dir),0.0,1.0),16.0); \n"
210 "} \n"
211 " \n"
212 "void main() \n"
213 "{ \n"
214 " const vec3 cameraPos = vec3(0,0,3); \n"
215 " vec3 rayDir = normalize(vec3(gl_Vertex.x, gl_Vertex.y, -1.0) * rot);\n"
216 " Ray ray = Ray(cameraPos, rayDir); \n"
217 " gl_Position = gl_Vertex; \n"
218 " gl_FrontColor = trace1(ray); \n"
219 "}\n";
220
221
222 static
223 float
224 deg2rad(const float degree)
225 {
226 return( degree * 0.017453292519943295769236907684886F);
227 }
228
229 static void
230 rotate_xy(float* mat3, const float degreesAroundX, const float degreesAroundY)
231 {
232 const float rad1 = deg2rad(degreesAroundX);
233 const float c1 = cosf(rad1);
234 const float s1 = sinf(rad1);
235 const float rad2 = deg2rad(degreesAroundY);
236 const float c2 = cosf(rad2);
237 const float s2 = sinf(rad2);
238 mat3[0] = c2; mat3[3] = 0.0F; mat3[6] = s2;
239 mat3[1] = s1*s2; mat3[4] = c1; mat3[7] = -s1*c2;
240 mat3[2] = -c1*s2;mat3[5] = s1; mat3[8] = c1*c2;
241 }
242
243 static void
244 identity(float* mat3)
245 {
246 mat3[0] = 1.0F; mat3[3] = 0.0F; mat3[6] = 0.0F;
247 mat3[1] = 0.0F; mat3[4] = 1.0F; mat3[7] = 0.0F;
248 mat3[2] = 0.0F; mat3[5] = 0.0F; mat3[8] = 1.0F;
249 }
250
251 static void
252 Draw(void)
253 {
254 const float w = 0.5F * WinWidth;
255 const float h = 0.5F * WinHeight;
256 int x,y;
257
258 GLint location = glGetUniformLocation(program, "rot");
259
260 glUseProgram(program);
261 glUniformMatrix3fv(location, 1, 0, rot);
262 glBegin(GL_POINTS);
263 for(y = 0; y < WinHeight; y++)
264 {
265 for(x = 0; x < WinWidth; x++)
266 {
267 const float posx = x / w - 1.0F;
268 const float posy = y / h - 1.0F;
269 glVertex2f(posx, posy);
270 }
271 }
272 glEnd();
273 glUseProgram(0);
274
275 glutSwapBuffers();
276
277 {
278 static int frames = 0;
279 static int t0 = 0;
280 static int t1 = 0;
281 float dt;
282 frames++;
283 t1 = glutGet(GLUT_ELAPSED_TIME);
284 dt = (float)(t1-t0)/1000.0F;
285 if (dt >= 5.0F)
286 {
287 float fps = (float)frames / dt;
288 printf("%f FPS (%d frames in %f seconds)\n", fps, frames, dt);
289 frames = 0;
290 t0 = t1;
291 }
292 }
293 }
294
295
296 static void
297 Reshape(int width, int height)
298 {
299 WinWidth = width;
300 WinHeight = height;
301 glViewport(0, 0, width, height);
302 glMatrixMode(GL_PROJECTION);
303 glLoadIdentity();
304 glMatrixMode(GL_MODELVIEW);
305 glLoadIdentity();
306 }
307
308
309 static void
310 Key(unsigned char key, int x, int y)
311 {
312 if(key == 27)
313 {
314 glutDestroyWindow(Win);
315 exit(0);
316 }
317 glutPostRedisplay();
318 }
319
320
321 static
322 void
323 drag(int x, int y)
324 {
325 float scale = 1.5F;
326 if(mouseGrabbed)
327 {
328 static GLfloat xRot = 0, yRot = 0;
329 xRot = (float)(x - WinWidth/2) / scale;
330 yRot = (float)(y - WinHeight/2) / scale;
331 identity(rot);
332 rotate_xy(rot, yRot, xRot);
333 glutPostRedisplay();
334 }
335 }
336
337
338 static
339 void
340 mouse(int button, int state, int x, int y)
341 {
342 mouseGrabbed = (state == GLUT_DOWN);
343 }
344
345
346 static void
347 Init(void)
348 {
349 glDisable(GL_DEPTH_TEST);
350
351 if(!ShadersSupported())
352 {
353 fprintf(stderr, "Shaders are not supported!\n");
354 exit(-1);
355 }
356
357 vertShader = CompileShaderText(GL_VERTEX_SHADER, vsSource);
358 program = LinkShaders(vertShader, 0);
359 glUseProgram(0);
360
361 if(glGetError() != 0)
362 {
363 fprintf(stderr, "Shaders were not loaded!\n");
364 exit(-1);
365 }
366
367 if(!glIsShader(vertShader))
368 {
369 fprintf(stderr, "Vertex shader failed!\n");
370 exit(-1);
371 }
372
373 if(!glIsProgram(program))
374 {
375 fprintf(stderr, "Shader program failed!\n");
376 exit(-1);
377 }
378
379 printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
380 }
381
382
383 int
384 main(int argc, char *argv[])
385 {
386 glutInitWindowSize(WinWidth, WinHeight);
387 glutInit(&argc, argv);
388 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
389 Win = glutCreateWindow(argv[0]);
390 glewInit();
391 glutReshapeFunc(Reshape);
392 glutKeyboardFunc(Key);
393 glutDisplayFunc(Draw);
394 glutIdleFunc(Draw);
395 glutMouseFunc(mouse);
396 glutMotionFunc(drag);
397 Init();
398 glutMainLoop();
399 return 0;
400 }
401