1/* -*- mode: c; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3; coding: utf-8-unix -*- */
2/*
3  Copyright (c) 2013 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// Simplified version of the algorithm described in
25// K. Ralovich, M. Magdics: Recursive Ray Tracing in Geometry Shader,
26// Proceedings of the Fifth Hungarian Conference on Computer Graphics and
27// Geometry, Budapest, Hungary, 26 Jan 2010.
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <GL/glew.h>
32#include "glut_wrap.h"
33#include "shaderutil.h"
34#include <math.h>
35#include <stddef.h> // offsetof
36
37// TODO: port to piglit too
38
39#define STRINGIFY_(x) #x
40#define STRINGIFY(x) STRINGIFY_(x)
41#define S__LINE__ STRINGIFY(__LINE__)
42
43static const float INF=9999.9F;
44
45static int Win;
46static int WinWidth = 256, WinHeight = 256;
47static GLboolean mouseGrabbed = GL_FALSE;
48
49static GLuint vertShader;
50static GLuint geomShader;
51static GLuint fragShader;
52static GLuint program;
53
54static GLuint pgQuery;
55
56static GLuint dst;
57static GLuint eyeRaysAsPoints;
58
59int posAttribLoc;
60int orig_tAttribLoc;
61int dir_idxAttribLoc;
62int uv_stateAttribLoc;
63int posVaryingLoc;
64int orig_tVaryingLoc;
65int dir_idxVaryingLoc;
66int uv_stateVaryingLoc;
67size_t nRayGens=3;
68
69float rot[9] = {1,0,0,  0,1,0,   0,0,1};
70
71static const char* vsSource =
72"                                                                  \n"
73"#version 150 core                                                 \n"
74"#line " S__LINE__ "\n"
75"#define SHADOWS                                                   \n"
76"#define RECURSION                                                 \n"
77"                                                                  \n"
78"const float INF=9999.9;                                           \n"
79"const float EPSILON = 0.00001;                                    \n"
80"                                                                  \n"
81"uniform vec3 cameraPos;                                           \n"
82"uniform mat3 rot3;                                                \n"
83"uniform vec3 lightPos;                                            \n"
84"uniform vec4 backgroundColor;                                     \n"
85"uniform int emitNoMore;                                           \n"
86"                                                                  \n"
87"in vec4 pos;                                                      \n"
88"in vec4 orig_t;                                                   \n"
89"in vec4 dir_idx;                                                  \n"
90"in vec4 uv_state;                                                 \n"
91"// uv_state.z = state                                             \n"
92"// uv_state.w = type (ray generation)                             \n"
93"                                                                  \n"
94"//int state // inFB                                               \n"
95"//    0: generation of ray dirs needed                            \n"
96"//    1: do not generate ray dirs, keep in GS, intersect, not in FB\n"
97"//    3: cull in next GS, already in FB                           \n"
98"//int type  // isShadow                                           \n"
99"//   -1: not shadow ray, reflected                                \n"
100"//    0: not shadow ray, eye ray                                  \n"
101"//    1: shadow ray                                               \n"
102"                                                                  \n"
103"out vec4 orig_t1;                                                 \n"
104"out vec4 dir_idx1;                                                \n"
105"out vec4 uv_state1;                                               \n"
106"                                                                  \n"
107"                                                                  \n"
108"//----------------------------------------------------------------\n"
109"                                                                  \n"
110"struct Ray                                                        \n"
111"{                                                                 \n"
112"  vec3 orig;                                                      \n"
113"  vec3 dir;                                                       \n"
114"};                                                                \n"
115"                                                                  \n"
116"struct Sphere                                                     \n"
117"{                                                                 \n"
118"  vec3 c;                                                         \n"
119"  float r;                                                        \n"
120"};                                                                \n"
121"                                                                  \n"
122"struct Isec                                                       \n"
123"{                                                                 \n"
124"  float t;                                                        \n"
125"  int idx;                                                        \n"
126"                                                                  \n"
127"  vec3 hit;                                                       \n"
128"  vec3 n;                                                         \n"
129"};                                                                \n"
130"                                                                  \n"
131"const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 );        \n"
132"const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 );       \n"
133"const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 );        \n"
134"const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 );        \n"
135"const Sphere spheres4 = Sphere( vec3(0.0,-11.0,-1.0), 10.0 );     \n"
136"const int nSpheres = 5;                                           \n"
137"const Sphere spheres[5]=Sphere[5](spheres0, spheres1, spheres2, spheres3, spheres4);\n"
138"                                                                  \n"
139"Isec                                                              \n"
140"lookupNormal(const in Ray ray, in Isec isec)                      \n"
141"{                                                                 \n"
142"  Sphere sph=spheres[isec.idx];                                   \n"
143"  vec3 c = sph.c;                                                 \n"
144"  float r = sph.r;                                                \n"
145"  isec.hit  = ray.orig + ray.dir * isec.t;                        \n"
146"  isec.n = (isec.hit - c) / r;                                    \n"
147"  return isec;                                                    \n"
148"}                                                                 \n"
149"                                                                  \n"
150"void                                                              \n"
151"intersect(const in Ray ray,                                       \n"
152"          const in Sphere sph,                                    \n"
153"          const in int idx,                                       \n"
154"          inout Isec isec)                                        \n"
155"{                                                                 \n"
156"  // Project both o and the sphere to the plane perpendicular to d\n"
157"  // and containing c. Let x be the point where the ray intersects\n"
158"  // the plane. If |x-c| < r, the ray intersects the sphere.      \n"
159"  vec3 o = ray.orig;                                              \n"
160"  vec3 d = ray.dir;                                               \n"
161"  vec3 n = -d;                                                    \n"
162"  vec3 c = sph.c;                                                 \n"
163"  float r = sph.r;                                                \n"
164"  float t = dot(c-o,n)/dot(n,d);//ray parameter for point x       \n"
165"  vec3 x = o+d*t;                                                 \n"
166"  float e = length(x-c);                                          \n"
167"  if (e > r)                                                      \n"
168"  {                                                               \n"
169"    // no intersection                                            \n"
170"    return;                                                       \n"
171"  }                                                               \n"
172"                                                                  \n"
173"  // Apply Pythagorean theorem on the (intersection,x,c) triangle \n"
174"  // to get the distance between c and the intersection.          \n"
175"  float f = sqrt(r*r - e*e);                                      \n"
176"  float dist = t - f;                                             \n"
177"  if (dist < 0.0)                                                 \n"
178"  {                                                               \n"
179"    // inside the sphere                                          \n"
180"    return;                                                       \n"
181"  }                                                               \n"
182"                                                                  \n"
183"  if (dist < EPSILON)                                             \n"
184"    return;                                                       \n"
185"                                                                  \n"
186"  if (dist > isec.t)                                              \n"
187"    return;                                                       \n"
188"                                                                  \n"
189"  isec.t = dist;                                                  \n"
190" isec.idx = idx;                                                  \n"
191"}                                                                 \n"
192"                                                                  \n"
193"Isec\n"
194"intersect_spheres(const in Ray ray,\n"
195"                  const in float max_t /*= INF*/)\n"
196"{\n"
197"  Isec nearest;\n"
198"  nearest.t = max_t;\n"
199"  nearest.idx = -1;\n"
200"\n"
201"  intersect(ray, spheres0, 0, nearest);\n"
202"  intersect(ray, spheres1, 1, nearest);\n"
203"  intersect(ray, spheres2, 2, nearest);\n"
204"  intersect(ray, spheres3, 3, nearest);\n"
205"  intersect(ray, spheres4, 4, nearest);                                \n"
206"                                                                       \n"
207"  return nearest;                                                      \n"
208"}                                                                      \n"
209"                                                                       \n"
210"                                                                       \n"
211"                                                                       \n"
212"//---------------------------------------------------------------------\n"
213"                                                                       \n"
214"                                                                       \n"
215"                                                                       \n"
216"                                                                       \n"
217"void                                                                   \n"
218"main()                                                                 \n"
219"{                                                                      \n"
220"  //inVS();                                                            \n"
221"  Ray  ray   = Ray(orig_t.xyz, dir_idx.xyz);                                \n"
222"  Isec isec  = Isec(orig_t.w, int(dir_idx.w), vec3(0,0,0), vec3(0,0,0));    \n"
223"  int  state = int(uv_state.z);                                             \n"
224"  int  type  = int(uv_state.w);                                             \n"
225"                                                                            \n"
226"  if (state == 0)                                                            \n"
227"  {                                                                         \n"
228"    // generate eye rays\n"
229"    ray = Ray(cameraPos, normalize(vec3(pos.x, pos.y, -1.0) * rot3));   \n"
230"    isec.t = INF;\n"
231"    isec.idx = -1;\n"
232"    state = 1;\n"
233"    type = 0;                                                           \n"
234"    isec = intersect_spheres(ray, isec.t);                              \n"
235"  }                                                                     \n"
236"#if defined(SHADOWS) || defined(RECURSION)                              \n"
237"  else if (state == 1)                                                  \n"
238"  {                                                                     \n"
239"    isec = intersect_spheres(ray, isec.t);                              \n"
240"  }                                                                     \n"
241"#endif                                                                  \n"
242"  //else state == 3                                                     \n"
243"                                                                        \n"
244"  //outVS();                                                            \n"
245"  gl_Position  = pos;                                                   \n"
246"  orig_t1.xyz  = ray.orig;                                              \n"
247"  orig_t1.w    = isec.t;                                                \n"
248"  dir_idx1.xyz = ray.dir;                                               \n"
249"  dir_idx1.w   = float(isec.idx);                                       \n"
250"  uv_state1.z  = float(state);                                          \n"
251"  uv_state1.w  = float(type);                                           \n"
252"}\n";
253
254
255static const char* gsSource =
256"#version 150 core                                                        \n"
257"#line " S__LINE__ "\n"
258"layout(points) in;                                                       \n"
259"layout(points, max_vertices = 3) out;                                    \n"
260"                                                                         \n"
261"#define SHADOWS                                                          \n"
262"#define RECURSION                                                        \n"
263"                                                                         \n"
264"const float INF=9999.9;                                                  \n"
265"const float EPSILON = 0.00001;                                           \n"
266"                                                                         \n"
267"uniform vec3 cameraPos;                                                  \n"
268"uniform mat3 rot3;                                                       \n"
269"uniform vec3 lightPos;                                                   \n"
270"uniform vec4 backgroundColor;                                            \n"
271"uniform int emitNoMore;                                                  \n"
272"                                                                         \n"
273"                                                                         \n"
274"//-----------------------------------------------------------------------\n"
275"                                                                         \n"
276"struct Ray                                                               \n"
277"{                                                                        \n"
278"  vec3 orig;                                                             \n"
279"  vec3 dir;                                                              \n"
280"};                                                                       \n"
281"                                                                         \n"
282"struct Sphere                                                            \n"
283"{                                                                        \n"
284"  vec3 c;                                                                \n"
285"  float r;                                                               \n"
286"};                                                                       \n"
287"                                                                         \n"
288"struct Isec                                                              \n"
289"{                                                                        \n"
290"  float t;                                                               \n"
291"  int idx;                                                               \n"
292"                                                                         \n"
293"  vec3 hit;                                                              \n"
294"  vec3 n;                                                                \n"
295"};                                                                       \n"
296"                                                                         \n"
297"const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 );\n"
298"const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 );\n"
299"const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 );\n"
300"const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 );\n"
301"const Sphere spheres4 = Sphere( vec3(0.0,-11.0,-1.0), 10.0 );\n"
302"const int nSpheres = 5;\n"
303"const Sphere spheres[5]=Sphere[5](spheres0, spheres1, spheres2, spheres3, spheres4);\n"
304"                                                                         \n"
305"Isec                                                                     \n"
306"lookupNormal(const in Ray ray, in Isec isec)                             \n"
307"{                                                                        \n"
308"  Sphere sph=spheres[isec.idx];                                          \n"
309"  vec3 c = sph.c;                                                        \n"
310"  float r = sph.r;                                                       \n"
311"  isec.hit  = ray.orig + ray.dir * isec.t;                               \n"
312"  isec.n = (isec.hit - c) / r;                                           \n"
313"  return isec;                                                           \n"
314"}                                                                        \n"
315"                                                                         \n"
316"in vec4 orig_t1[1];                                                      \n"
317"in vec4 dir_idx1[1];                                                     \n"
318"in vec4 uv_state1[1];                                                    \n"
319"                                                                         \n"
320"out vec4 orig_t2;                                                        \n"
321"out vec4 dir_idx2;                                                       \n"
322"out vec4 uv_state2;                                                      \n"
323"                                                                         \n"
324"                                                                         \n"
325"void                                                                     \n"
326"main()                                                                   \n"
327"{                                                                        \n"
328"  //inGS();                                                              \n"
329"  Ray  ray   = Ray(orig_t1[0].xyz, dir_idx1[0].xyz);                     \n"
330"  Isec isec  = Isec(orig_t1[0].w, int(dir_idx1[0].w), vec3(0,0,0), vec3(0,0,0));  \n"
331"  int  state = int(uv_state1[0].z);                                      \n"
332"  int  type  = int(uv_state1[0].w);                                      \n"
333"                                                                         \n"
334"  if (state > 1)                                                         \n"
335"    return;                                                              \n"
336"                                                                         \n"
337"  if (isec.idx == -1)                                                    \n"
338"    return;                                                              \n"
339"                                                                         \n"
340"  // emitPassThrough();                          \n"
341"  gl_Position  = gl_in[0].gl_Position;           \n"
342"  orig_t2      = orig_t1[0];                     \n"
343"  dir_idx2     = dir_idx1[0];                    \n"
344"  uv_state2.xyw= uv_state1[0].xyw;               \n"
345"  uv_state2.z = 3.0; /*state*/                   \n"
346"  EmitVertex();                                  \n"
347"  EndPrimitive();                                                        \n"
348"                                                                         \n"
349"  if (type != 0 || emitNoMore>0)                                         \n"
350"    return;                                                              \n"
351"                                                                         \n"
352"#if defined(SHADOWS) || defined(RECURSION)\n"
353"  isec = lookupNormal(ray, isec);\n"
354"  vec3 hitN = isec.n;\n"
355"  vec3 hitP = ray.orig + ray.dir*isec.t + hitN*EPSILON;\n"
356"#endif                                                                \n"
357"#ifdef SHADOWS                                                          \n"
358"  vec3 toLight = lightPos - hitP;\n"
359"  float lightDist = length(toLight);\n"
360"  Ray shadowRay = Ray(hitP, toLight/lightDist);\n"
361"  Isec shadowHit = Isec(lightDist, -1, vec3(0,0,0), vec3(0,0,0));\n"
362"  state = 1;                                       \n"
363"  type = 1;                                        \n"
364"                                                   \n"
365"  //emitShadowRay();                               \n"
366"  gl_Position  = gl_in[0].gl_Position;             \n"
367"  orig_t2.xyz  = shadowRay.orig;                   \n"
368"  orig_t2.w    = shadowHit.t;                      \n"
369"  dir_idx2.xyz = shadowRay.dir;                    \n"
370"  dir_idx2.w   = float(shadowHit.idx);             \n"
371"  uv_state2.z  = float(state);                     \n"
372"  uv_state2.w  = float(type);                      \n"
373"  EmitVertex();                                    \n"
374"  EndPrimitive();                                  \n"
375"#endif                                             \n"
376"#ifdef RECURSION                                   \n"
377"  Ray  reflRay = Ray(hitP, reflect(ray.dir, hitN));\n"
378"  Isec reflHit = Isec(INF, -1, vec3(0,0,0), vec3(0,0,0));\n"
379"  state = 1;          // intersect in next pass, FS discard in this pass\n"
380"  type  = -1;                                   \n"
381"                                                \n"
382"  //emitReflRay();                              \n"
383"  gl_Position  = gl_in[0].gl_Position;          \n"
384"  orig_t2.xyz  = reflRay.orig;                  \n"
385"  orig_t2.w    = reflHit.t;                     \n"
386"  dir_idx2.xyz = reflRay.dir;                   \n"
387"  dir_idx2.w   = float(reflHit.idx);            \n"
388"  uv_state2.z  = float(state);                  \n"
389"  uv_state2.w  = float(type);                   \n"
390"  EmitVertex();                                 \n"
391"  EndPrimitive();                               \n"
392"#endif\n"
393"}\n";
394
395static const char* fsSource =
396"#version 150 core                                                        \n"
397"#line " S__LINE__ "\n"
398"                                                                         \n"
399"#define SHADOWS                                                          \n"
400"#define RECURSION                                                        \n"
401"                                                                         \n"
402"const float INF=9999.9;                                                  \n"
403"const float EPSILON = 0.00001;                                           \n"
404"                                                                         \n"
405"uniform vec3 cameraPos;                                                  \n"
406"uniform mat3 rot3;                                                       \n"
407"uniform vec3 lightPos;                                                   \n"
408"uniform vec4 backgroundColor;                                            \n"
409"uniform int emitNoMore;                                                  \n"
410"                                                                         \n"
411"out vec4 frag_color;                                                     \n"
412"                                                                         \n"
413"//-----------------------------------------------------------------------\n"
414"                                                                         \n"
415"struct Ray\n"
416"{\n"
417"  vec3 orig;\n"
418"  vec3 dir;\n"
419"};\n"
420"\n"
421"struct Sphere\n"
422"{\n"
423"  vec3 c;\n"
424"  float r;\n"
425"};\n"
426"\n"
427"struct Isec\n"
428"{\n"
429"  float t;\n"
430"  int idx;\n"
431"\n"
432"  vec3 hit;\n"
433"  vec3 n;\n"
434"};\n"
435"\n"
436"const Sphere spheres0 = Sphere( vec3(0.0,0.0,-1.0), 0.5 );\n"
437"const Sphere spheres1 = Sphere( vec3(-3.0,0.0,-1.0), 1.5 );\n"
438"const Sphere spheres2 = Sphere( vec3(0.0,3.0,-1.0), 0.5 );\n"
439"const Sphere spheres3 = Sphere( vec3(2.0,0.0,-1.0), 1.0 );\n"
440"const Sphere spheres4 = Sphere( vec3(0.0,-11.0,-1.0), 10.0 );\n"
441"const int nSpheres = 5;\n"
442"const Sphere spheres[5]=Sphere[5](spheres0, spheres1, spheres2, spheres3, spheres4);\n"
443"\n"
444"Isec\n"
445"lookupNormal(const in Ray ray, in Isec isec)\n"
446"{\n"
447"  Sphere sph=spheres[isec.idx];\n"
448"  vec3 c = sph.c;\n"
449"  float r = sph.r;\n"
450"  isec.hit  = ray.orig + ray.dir * isec.t;\n"
451"  isec.n = (isec.hit - c) / r;\n"
452"  return isec;\n"
453"}\n"
454"\n"
455"in vec4 orig_t2;\n"
456"in vec4 dir_idx2;\n"
457"in vec4 uv_state2;\n"
458"\n"
459"vec3\n"
460"idx2color(const in int idx)\n"
461"{\n"
462"  vec3 diff;\n"
463"  if (idx == 0)\n"
464"    diff = vec3(1.0, 0.0, 0.0);\n"
465"  else if (idx == 1)\n"
466"    diff = vec3(0.0, 1.0, 0.0);\n"
467"  else if (idx == 2)\n"
468"    diff = vec3(0.0, 0.0, 1.0);\n"
469"  else if (idx == 3)\n"
470"    diff = vec3(1.0, 1.0, 0.0);\n"
471"  else if (idx == 4)\n"
472"    diff = vec3(0.7, 0.7, 0.7);\n"
473"  return diff;\n"
474"}\n"
475"\n"
476"\n"
477"void\n"
478"main()\n"
479"{\n"
480"  Ray  ray   = Ray(orig_t2.xyz, dir_idx2.xyz);\n"
481"  Isec isec  = Isec(orig_t2.w, int(dir_idx2.w), vec3(0,0,0), vec3(0,0,0));\n"
482"  int  state = int(uv_state2.z);\n"
483"  int  type  = int(uv_state2.w);\n"
484"\n"
485"  if (state < 3)\n"
486"  {\n"
487"    discard;\n"
488"  }\n"
489"\n"
490"\n"
491"  if (type == 0)\n"
492"  {\n"
493"    Ray eyeRay = ray;\n"
494"    Isec eyeHit = isec;\n"
495"    if (eyeHit.idx == -1)\n"
496"    {\n"
497"      frag_color = vec4(backgroundColor.rgb, 0.0);\n"
498"      return;\n"
499"    }\n"
500"    vec3 eyeHitPosition = eyeRay.orig + eyeRay.dir * eyeHit.t;\n"
501"    vec3 lightVec = lightPos - eyeHitPosition;\n"
502"    eyeHit = lookupNormal(eyeRay, eyeHit);\n"
503"    vec3  N      = eyeHit.n;\n"
504"    vec3  L      = normalize(lightVec);                                         \n"
505"    float NdotL  = max(dot(N, L), 0.0);                                         \n"
506"    vec3 diffuse = idx2color(eyeHit.idx); // material color of the visible point\n"
507"    frag_color = vec4(diffuse * NdotL, 1.0);                                  \n"
508"    return;                                                                \n"
509"  }                                                                        \n"
510"#ifdef SHADOWS                                                             \n"
511"  if (type > 0)                                                            \n"
512"  {                                                               \n"
513"    Isec shadowHit = isec;                                        \n"
514"    if (shadowHit.idx == -1)                                      \n"
515"    {                                                             \n"
516"      discard;                                                    \n"
517"    }                                                             \n"
518"    frag_color = vec4(-1,-1,-1, 0.0);                           \n"
519"    return;                                                       \n"
520"  }                                                               \n"
521"#endif                                                            \n"
522"#ifdef RECURSION                                                  \n"
523"  // else type < 0                                                \n"
524"  {                                                               \n"
525"    Ray reflRay = ray;                                            \n"
526"    Isec reflHit = isec;                                          \n"
527"    if (reflHit.idx == -1)                                        \n"
528"    {                                                             \n"
529"      discard;                                                    \n"
530"    }                                                             \n"
531"    vec3 reflHitPosition = reflRay.orig + reflRay.dir * reflHit.t;\n"
532"    vec3 lightVec = lightPos - reflHitPosition;                   \n"
533"    reflHit = lookupNormal(reflRay, reflHit);                     \n"
534"    vec3  N      = reflHit.n;                                     \n"
535"    vec3  L      = normalize(lightVec);                           \n"
536"    float NdotL  = max(dot(N, L), 0.0);                           \n"
537"    vec3 diffuse = idx2color(reflHit.idx);                        \n"
538"    frag_color = vec4(diffuse * NdotL * 0.25, 1.0); // material color of the visible point\n"
539"    return;                                                       \n"
540"  }                                                               \n"
541"#endif                                                            \n"
542"}                                                                 \n";
543
544struct vec4
545{
546   union {
547      float _[4];
548      struct { float x,y,z,w; };
549   };
550   vec4(float a, float b, float c, float d) : x(a), y(b), z(c), w(d) {}
551};
552
553struct GSRay
554{
555   vec4 pos;
556   vec4 orig_t;
557   vec4 dir_idx;
558   vec4 uv_state;
559};
560
561static float
562deg2rad(const float degree)
563{
564   return( degree * 0.017453292519943295769236907684886F);
565}
566
567static void
568rotate_xy(float* mat3, const float degreesAroundX, const float degreesAroundY)
569{
570   const float radX = deg2rad(degreesAroundX);
571   const float c1 = cosf(radX);
572   const float s1 = sinf(radX);
573   const float radY = deg2rad(degreesAroundY);
574   const float c2 = cosf(radY);
575   const float s2 = sinf(radY);
576   mat3[0] = c2;    mat3[3] = 0.0F; mat3[6] = s2;
577   mat3[1] = s1*s2; mat3[4] = c1;   mat3[7] = -s1*c2;
578   mat3[2] = -c1*s2;mat3[5] = s1;   mat3[8] = c1*c2;
579}
580
581static void
582identity(float* mat3)
583{
584   mat3[0] = 1.0F; mat3[3] = 0.0F; mat3[6] = 0.0F;
585   mat3[1] = 0.0F; mat3[4] = 1.0F; mat3[7] = 0.0F;
586   mat3[2] = 0.0F; mat3[5] = 0.0F; mat3[8] = 1.0F;
587}
588
589static void
590Draw(void)
591{
592   glClearColor( 0.2, 0.5, 0.3, 0.0 );
593   glClearDepth(0.11F);
594   glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
595
596   glDisable(GL_DEPTH_TEST);
597   glEnable(GL_CULL_FACE);
598
599   glUseProgram(program);
600
601   glUniformMatrix3fv(glGetUniformLocation(program, "rot3"), 1, 0, rot);
602
603   //gs.gs->getVertexAttribLocation("pos", gs.posAttribLoc);
604   //gs.gs->getVertexAttribLocation("orig_t", gs.orig_tAttribLoc);
605   //gs.gs->getVertexAttribLocation("dir_idx", gs.dir_idxAttribLoc);
606   //gs.gs->getVertexAttribLocation("uv_state", gs.uv_stateAttribLoc);
607   posAttribLoc = glGetAttribLocation(program, "pos");
608   orig_tAttribLoc = glGetAttribLocation(program, "orig_t");
609   dir_idxAttribLoc = glGetAttribLocation(program, "dir_idx");
610   uv_stateAttribLoc = glGetAttribLocation(program, "uv_state");
611
612   glBindFragDataLocation(program, 0, "frag_color");
613
614   ////printf("%d\n", i);
615   //gs.fpwQuery->beginQuery();
616   //gs.pgQuery->beginQuery();
617   glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, dst);
618   glBeginQuery(GL_PRIMITIVES_GENERATED, pgQuery);
619   glBeginTransformFeedback(GL_POINTS);
620   //gs.eyeRaysAsPoints->bindAs(ARRAY);
621   glBindBuffer(GL_ARRAY_BUFFER, eyeRaysAsPoints);
622   {
623      glEnableVertexAttribArray(posAttribLoc);
624      glVertexAttribPointer(posAttribLoc, 4, GL_FLOAT, GL_FALSE,
625                            sizeof(GSRay), (void*)offsetof(GSRay, pos));
626
627      glEnableVertexAttribArray(orig_tAttribLoc);
628      glVertexAttribPointer(orig_tAttribLoc, 4, GL_FLOAT, GL_FALSE,
629                            sizeof(GSRay), (void*)offsetof(GSRay, orig_t));
630
631      glEnableVertexAttribArray(dir_idxAttribLoc);
632      glVertexAttribPointer(dir_idxAttribLoc, 4, GL_FLOAT, GL_FALSE,
633                            sizeof(GSRay), (void*)offsetof(GSRay, dir_idx));
634
635      glEnableVertexAttribArray(uv_stateAttribLoc);
636      glVertexAttribPointer(uv_stateAttribLoc, 4, GL_FLOAT, GL_FALSE,
637                            sizeof(GSRay), (void*)offsetof(GSRay, uv_state));
638
639      //if (getShadows() || getMaxRecursion() > 0)
640      //gs.gs->set_uniform("emitNoMore", 1, 0);
641      glUniform1i(glGetUniformLocation(program, "emitNoMore"), 0);
642
643      //glEnable(GL_RASTERIZER_DISCARD);
644      glDrawArrays(GL_POINTS, 0, WinWidth*WinHeight);
645      //glDisable(GL_RASTERIZER_DISCARD);
646
647      glDisableVertexAttribArray(uv_stateAttribLoc);
648
649      glDisableVertexAttribArray(dir_idxAttribLoc);
650
651      glDisableVertexAttribArray(orig_tAttribLoc);
652
653      glDisableVertexAttribArray(posAttribLoc);
654   }
655   //gs.eyeRaysAsPoints->unbindAs(ARRAY);
656   glBindBuffer(GL_ARRAY_BUFFER, 0);
657   glEndTransformFeedback();
658   //gs.pgQuery->endQuery();
659   glEndQuery(GL_PRIMITIVES_GENERATED);
660   //gs.fpwQuery->endQuery();
661
662   ////psoLog(LOG_RAW) << "1st: " << gs.fpwQuery->getQueryResult() << ", " << gs.pgQuery->getQueryResult() << "\n";
663
664
665   ////swap(src, dst);
666   glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
667
668   ////clear();
669
670   ////fpwQuery->beginQuery();
671   ////pgQuery->beginQuery();
672   //// With GL_ARB_color_buffer_float we can use negative color values
673   //// and disable clamping with ClampColorARB. This might be better for
674   //// compositing the pixels in shadow.
675   glEnable(GL_BLEND);
676   glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); // modeRGB, modeA
677   glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA,     // srcRGB, dstRGB
678                       GL_ONE, GL_ONE);          // arcA,   dstA
679   //gs.dst->bindAs(ARRAY);
680   glBindBuffer(GL_ARRAY_BUFFER, dst);
681   {
682      glEnableVertexAttribArray(posAttribLoc);
683      glVertexAttribPointer(posAttribLoc, 4, GL_FLOAT, GL_FALSE,
684                            sizeof(GSRay), (void*)offsetof(GSRay, pos));
685
686      glEnableVertexAttribArray(orig_tAttribLoc);
687      glVertexAttribPointer(orig_tAttribLoc, 4, GL_FLOAT, GL_FALSE,
688                            sizeof(GSRay), (void*)offsetof(GSRay, orig_t));
689
690      glEnableVertexAttribArray(dir_idxAttribLoc);
691      glVertexAttribPointer(dir_idxAttribLoc, 4, GL_FLOAT, GL_FALSE,
692                            sizeof(GSRay), (void*)offsetof(GSRay, dir_idx));
693
694      glEnableVertexAttribArray(uv_stateAttribLoc);
695      glVertexAttribPointer(uv_stateAttribLoc, 4, GL_FLOAT, GL_FALSE,
696                            sizeof(GSRay), (void*)offsetof(GSRay, uv_state));
697
698      //if (getShadows() || getMaxRecursion() > 0)
699      //gs.gs->set_uniform("emitNoMore", 1, 1);
700      glUniform1i(glGetUniformLocation(program, "emitNoMore"), 1);
701      //GLint fpw = gs.fpwQuery->getQueryResult();
702      //GLint pg = gs.pgQuery->getQueryResult();
703      GLint pg;
704      glGetQueryObjectiv(pgQuery, GL_QUERY_RESULT, &pg);
705      //pso_runtime_check(fpw == pg);
706      glDrawArrays(GL_POINTS, 0, pg);
707
708      glDisableVertexAttribArray(uv_stateAttribLoc);
709
710      glDisableVertexAttribArray(dir_idxAttribLoc);
711
712      glDisableVertexAttribArray(orig_tAttribLoc);
713
714      glDisableVertexAttribArray(posAttribLoc);
715   }
716   //gs.dst->unbindAs(ARRAY);
717   glBindBuffer(GL_ARRAY_BUFFER, 0);
718   glDisable(GL_BLEND);
719   ////pgQuery->endQuery();
720   ////fpwQuery->endQuery();
721
722   ////psoLog(LOG_RAW) << "2nd: " << fpwQuery->getQueryResult() << ", " << pgQuery->getQueryResult() << "\n\n";
723   ////pso_runtime_check(fpwQuery->getQueryResult() == pgQuery->getQueryResult());
724
725   ////swap(src, dst);
726   ////for(;;);
727
728   glUseProgram(0);
729
730   glDisable(GL_CULL_FACE);
731
732//////////////////////////////////////////////////////////////////////
733
734   glutSwapBuffers();
735
736   {
737      static int frames = 0;
738      static int t0 = 0;
739      static int t1 = 0;
740      float dt;
741      frames++;
742      t1 = glutGet(GLUT_ELAPSED_TIME);
743      dt = (float)(t1-t0)/1000.0F;
744      if (dt >= 5.0F)
745      {
746         float fps = (float)frames / dt;
747         printf("%f FPS (%d frames in %f seconds)\n", fps, frames, dt);
748         frames = 0;
749         t0 = t1;
750      }
751   }
752}
753
754
755static void
756Reshape(int width, int height)
757{
758   WinWidth = width;
759   WinHeight = height;
760   glViewport(0, 0, width, height);
761
762   {
763      size_t nElem = WinWidth*WinHeight*nRayGens;
764      glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, dst);
765      glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, nElem*sizeof(GSRay), 0, GL_STREAM_DRAW);
766      GSRay* d = (GSRay*)glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_WRITE);
767      for (size_t i = 0; i < nElem; i++)
768      {
769         d[i].dir_idx = vec4(0.0F, 0.0F, 0.0F, -1.0F);
770      }
771      glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
772      glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);
773      //printf("Ping-pong VBO size 2x%d Kbytes.\n", (int)nElem*sizeof(GSRay)/1024);
774   }
775
776   {
777      glBindBuffer(GL_ARRAY_BUFFER, eyeRaysAsPoints);
778      glBufferData(GL_ARRAY_BUFFER, WinWidth*WinHeight*sizeof(GSRay), 0, GL_STATIC_DRAW);
779      GSRay* d = (GSRay*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
780      const float w = 0.5F * WinWidth;
781      const float h = 0.5F * WinHeight;
782      for (int y = 0; y < WinHeight; y++)
783      {
784         for (int x = 0; x < WinWidth; x++)
785         {
786            unsigned int i = y*WinWidth+x;
787            const float posx = x / w - 1.0F;
788            const float posy = y / h - 1.0F;
789            d[i].pos     = vec4(posx, posy, 0.5F, 1.0F);
790            d[i].orig_t  = vec4(0.0F, 0.0F, 0.0F, INF);
791            d[i].dir_idx = vec4(0.0F, 0.0F, 0.0F, -0.0F);
792            d[i].uv_state = vec4(0, 0, 0, 0);
793         }
794      }
795      glUnmapBuffer(GL_ARRAY_BUFFER);
796      glBindBuffer(GL_ARRAY_BUFFER, 0);
797   }
798}
799
800
801static void
802Key(unsigned char key, int x, int y)
803{
804   if (key == 27)
805   {
806      glutDestroyWindow(Win);
807      exit(0);
808   }
809   glutPostRedisplay();
810}
811
812
813static void
814drag(int x, int y)
815{
816   float scale = 1.5F;
817   if (mouseGrabbed)
818   {
819      static GLfloat xRot = 0, yRot = 0;
820      xRot = (float)(x - WinWidth/2) / scale;
821      yRot = (float)(y - WinHeight/2) / scale;
822      identity(rot);
823      rotate_xy(rot, yRot, xRot);
824      glutPostRedisplay();
825   }
826}
827
828
829static void
830mouse(int button, int state, int x, int y)
831{
832   mouseGrabbed = (state == GLUT_DOWN);
833}
834
835
836static void
837Init(void)
838{
839   glDisable(GL_DEPTH_TEST);
840
841   if (!ShadersSupported())
842   {
843      fprintf(stderr, "Shaders are not supported!\n");
844      exit(-1);
845   }
846
847   if (!GLEW_VERSION_3_2)
848   {
849      fprintf(stderr, "OpenGL 3.2 (needed for transform feedback and "
850              "geometry shaders) not supported!\n");
851      exit(-1);
852   }
853
854   vertShader = CompileShaderText(GL_VERTEX_SHADER, vsSource);
855   geomShader = CompileShaderText(GL_GEOMETRY_SHADER_ARB, gsSource);
856   fragShader = CompileShaderText(GL_FRAGMENT_SHADER, fsSource);
857   program = LinkShaders3(vertShader, geomShader, fragShader);
858
859   const char *varyings[] = {
860      "gl_Position",
861      "orig_t2",
862      "dir_idx2",
863      "uv_state2"
864   };
865   // I think it will be a performance win to use multiple buffer objects to write to
866   // instead of using the interleaved mode.
867   glTransformFeedbackVaryings(program, 4, varyings, GL_INTERLEAVED_ATTRIBS);
868   glLinkProgram(program);
869
870   if (glGetError() != 0)
871   {
872      fprintf(stderr, "Shaders were not loaded!\n");
873      exit(-1);
874   }
875
876   if (!glIsShader(vertShader))
877   {
878      fprintf(stderr, "Vertex shader failed!\n");
879      exit(-1);
880   }
881
882   if (!glIsShader(geomShader))
883   {
884      fprintf(stderr, "Geometry shader failed!\n");
885      exit(-1);
886   }
887
888   if (!glIsShader(fragShader))
889   {
890      fprintf(stderr, "Fragment shader failed!\n");
891      exit(-1);
892   }
893
894   if (!glIsProgram(program))
895   {
896      fprintf(stderr, "Shader program failed!\n");
897      exit(-1);
898   }
899
900   glUseProgram(program);
901   glUniform3f(glGetUniformLocation(program, "cameraPos"), 0,3,5);
902   glUniform4f(glGetUniformLocation(program, "backgroundColor"), 0,0,0,1);
903   glUniform1i(glGetUniformLocation(program, "emitNoMore"), 1);
904   glUniform3f(glGetUniformLocation(program, "lightPos"), 0,8,1);
905   glUseProgram(0);
906
907   printf("GL_RENDERER = %s\n",(const char *) glGetString(GL_RENDERER));
908
909   glGenQueries(1, &pgQuery);
910   glGenBuffers(1, &dst);
911   glGenBuffers(1, &eyeRaysAsPoints);
912
913   GLuint vao;
914   glGenVertexArrays(1, &vao);
915   glBindVertexArray(vao);
916
917   printf("\nESC                 = exit demo\nleft mouse + drag   = rotate camera\n\n");
918}
919
920
921int
922main(int argc, char *argv[])
923{
924   glutInitWindowSize(WinWidth, WinHeight);
925   glutInit(&argc, argv);
926
927#ifdef HAVE_FREEGLUT
928   glutInitContextVersion(3, 2);
929   glutInitContextProfile(GLUT_CORE_PROFILE);
930   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
931#elif defined __APPLE__
932   glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
933#else
934   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
935#endif
936   Win = glutCreateWindow(argv[0]);
937
938   // glewInit requires glewExperimentel set to true for core profiles.
939   // Depending on the glew version it also generates GL_INVALID_ENUM.
940   glewExperimental = GL_TRUE;
941   glewInit();
942   glGetError();
943
944   glutReshapeFunc(Reshape);
945   glutKeyboardFunc(Key);
946   glutDisplayFunc(Draw);
947   glutIdleFunc(Draw);
948   glutMouseFunc(mouse);
949   glutMotionFunc(drag);
950   Init();
951   Reshape(WinWidth, WinHeight ); // fix crash under nvidia driver, as Reshape() not being called before rendering, and thus the BO-s were not created
952   glutMainLoop();
953   glutDestroyWindow(Win);
954   return 0;
955}
956
957