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