#include #include #include #include #include #define GL_GLEXT_PROTOTYPES #include #include #define BALLS 4 static PFNGLGETOBJECTPARAMETERIVARBPROC eglGetObjectParameterivARB =NULL; static PFNGLGETINFOLOGARBPROC eglGetInfoLogARB =NULL; static PFNGLCREATESHADEROBJECTARBPROC eglCreateShaderObjectARB =NULL; static PFNGLSHADERSOURCEARBPROC eglShaderSourceARB =NULL; static PFNGLCOMPILESHADERARBPROC eglCompileShaderARB =NULL; static PFNGLCREATEPROGRAMOBJECTARBPROC eglCreateProgramObjectARB =NULL; static PFNGLATTACHOBJECTARBPROC eglAttachObjectARB =NULL; static PFNGLLINKPROGRAMARBPROC eglLinkProgramARB =NULL; static PFNGLUNIFORM1IARBPROC eglUniform1iARB =NULL; static PFNGLUNIFORM3FARBPROC eglUniform3fARB =NULL; static PFNGLGETUNIFORMLOCATIONARBPROC eglGetUniformLocationARB =NULL; static PFNGLUSEPROGRAMOBJECTARBPROC eglUseProgramObjectARB =NULL; static void vr_glext_glsl_init_exts() { static bool init=false; if (init) return; eglGetObjectParameterivARB=(PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB"); eglGetInfoLogARB=(PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB"); eglCreateShaderObjectARB=(PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB"); eglShaderSourceARB=(PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB"); eglCompileShaderARB=(PFNGLCOMPILESHADERARBPROC)SDL_GL_GetProcAddress("glCompileShaderARB"); eglCreateProgramObjectARB=(PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB"); eglAttachObjectARB=(PFNGLATTACHOBJECTARBPROC)SDL_GL_GetProcAddress("glAttachObjectARB"); eglLinkProgramARB=(PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB"); eglUniform1iARB=(PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB"); eglUniform3fARB=(PFNGLUNIFORM3FARBPROC)SDL_GL_GetProcAddress("glUniform3fARB"); eglGetUniformLocationARB=(PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB"); eglUseProgramObjectARB=(PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB"); } static void vr_glext_glsl_dump_log(GLhandleARB p,const GLcharARB* shader) { vr_glext_glsl_init_exts(); GLint log_size; eglGetObjectParameterivARB(p, GL_OBJECT_INFO_LOG_LENGTH_ARB, &log_size); if (log_size>1) { GLcharARB* s=(GLcharARB*)malloc((log_size+1)*sizeof(GLcharARB)); eglGetInfoLogARB(p,log_size,NULL,s); printf("============================================================\n"); printf("Faulty ARB program. Log (%d bytes) : \n%s\n",log_size,s); free(s); printf("Faulty ARB program : \n"); int lc=0; printf("\n%4d: ",++lc); for(int i=0;i<(int)strlen(shader);i++) { if (shader[i]=='\n') printf("\n%4d: ",++lc); else printf("%c",shader[i]); } printf("\n"); printf("============================================================\n"); } } bool vr_glext_glsl_create_program(const GLcharARB* vshader,const GLcharARB* fshader,GLhandleARB* res) { vr_glext_glsl_init_exts(); GLint ok; GLhandleARB vs=eglCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); GLhandleARB fs=eglCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); eglShaderSourceARB(vs, 1, &vshader,NULL); eglShaderSourceARB(fs, 1, &fshader,NULL); eglCompileShaderARB(vs); vr_glext_glsl_dump_log(vs,vshader); eglGetObjectParameterivARB(vs,GL_OBJECT_COMPILE_STATUS_ARB,&ok); if (!ok) { printf("compiling vertex shader\n"); return false; } eglCompileShaderARB(fs); vr_glext_glsl_dump_log(fs,fshader); eglGetObjectParameterivARB(fs,GL_OBJECT_COMPILE_STATUS_ARB,&ok); if (!ok) { printf("compiling fragment shader\n"); return false; } GLhandleARB p = eglCreateProgramObjectARB(); eglAttachObjectARB(p,vs); eglAttachObjectARB(p,fs); eglLinkProgramARB(p); vr_glext_glsl_dump_log(p,"(Linking Stage)"); eglGetObjectParameterivARB(p,GL_OBJECT_LINK_STATUS_ARB,&ok); if (!ok) { printf("linking program\n"); return false; } *res=p; return true; } char vshader[] = "void main()" "{" " gl_TexCoord[0] = gl_MultiTexCoord0;" " gl_Position = ftransform();" "}"; char fshader_ray[] = "uniform sampler1D spheres_geom; \n" "uniform sampler2D wall_texture; \n" //"uniform sampler1D spheres_color; \n" "uniform vec3 light_pos; \n" "float intersect(vec3 ray_pos, vec3 ray_vec) \n" "{ \n" " float i = 0.0; \n" " float current = 1.0; \n" " for( i=0.0 ; i<1.0 ; i+= 1.0/%d.0) \n" " { \n" " vec4 sphere_geom = texture1D( spheres_geom, i); \n" " vec3 dst = ray_pos - sphere_geom.xyz; \n" " float a = dot (ray_vec, ray_vec); \n" " float b = 2.0 * dot (dst, ray_vec); \n" " float c = dot (dst, dst) - sphere_geom.a*sphere_geom.a; \n" " float d = b*b - 4.0*a*c; \n" " if ( d > -0.01 ) \n" " { \n" " float dp = d < 0.0 ? 0.0 : d; \n" " if ( (-b - sqrt(dp) ) /(2.0 * a) > 0.0) \n" " { \n" " if (d > 0.0) \n" " current = min(0.2 , current); \n" " else \n" " current = min(0.2 - d * 80.0 , current); \n" " } \n" " } \n" " } \n" " return current; \n" "} \n" "void main () \n" "{ \n" " float i = 0.0; \n" " float j = 0.0; \n" " const vec3 observer = vec3( 0.5, 0.5, -2.0 ); \n" " vec3 reflect; \n" " vec3 ray_pos = observer; \n" " vec3 ray_vec = gl_TexCoord[0].xyz - ray_pos; \n" " ray_vec /= length( ray_vec ); \n" " vec4 out_color = vec4(0.0); \n" " vec3 contact_point = vec3(0.0); \n" " float bestt, besti; \n" " vec3 normal, half_vector; \n" " vec3 object_color; \n" " \n" " for(j = 0.0 ; j < 3.0 ; j += 1.0) \n" " { \n" " bestt = 1000.0; \n" " besti = -1.0; \n" // find out which sphere is our first intersection " for( i=0.0 ; i<1.0 ; i+= 1.0/%d.0) \n" " { \n" " vec4 sphere_geom = texture1D( spheres_geom, i); \n" " vec3 dst = ray_pos - sphere_geom.xyz; \n" " float a = dot (ray_vec, ray_vec); \n" " float b = 2.0 * dot (dst, ray_vec); \n" " float c = dot (dst, dst) - sphere_geom.a*sphere_geom.a; \n" " float d = b*b - 4.0*a*c; \n" " if ( d > 0.0 ) \n" " { \n" " float t1; \n" " t1 = (-b - sqrt(d) ) /(2.0 * a); \n" " if (t1 < bestt) \n" " { \n" " bestt = t1; \n" " besti = i; \n" " contact_point = ray_pos + ray_vec * t1; \n" " } \n" " } \n" " } \n" " \n" // if we had an intersection " if (besti >= 0.0) \n" " { \n" // find the local normal " vec4 sphere_geom = texture1D( spheres_geom, besti); \n" " vec3 light_vec = light_pos - contact_point; \n" " light_vec /= length (light_vec); \n" " normal = contact_point - sphere_geom.xyz; \n" " half_vector = (light_vec - ray_vec)/2.0; \n" " normal /= length(normal); \n" " object_color = vec3(0.2,0.4,0.8); \n" // compute lighting " float diffuse = dot (normal, light_vec) + 2.0 * pow (dot ( normal, half_vector), 32.0); \n" " float ambient = 0.1; \n" " float l = intersect(contact_point, light_vec) * (diffuse > 0.0 ? diffuse + ambient : ambient); \n" " out_color.rgb += 0.6 * (1.0 - out_color.a) * vec3(l) * object_color; \n" " out_color.a += 0.6 * (1.0 - out_color.a); \n" // find the reflecction vector " reflect = ray_vec - vec3(2.0 * dot ( normal, ray_vec)) * normal; \n" " reflect /= length(reflect); \n" // new parameters " ray_pos = contact_point; \n" " ray_vec = reflect; \n" " } \n" " else \n" " { \n" " vec3 steps1 = abs((1.0 - ray_pos)/ray_vec); \n" " vec3 steps2 = abs((ray_pos)/ray_vec); \n" " vec3 steps; \n" " vec2 tex_coords; \n" " if (ray_vec.x>0.0) \n" " steps.x=steps1.x; \n" " else \n" " steps.x=steps2.x; \n" " if (ray_vec.y>0.0) \n" " steps.y=steps1.y; \n" " else \n" " steps.y=steps2.y; \n" " if (ray_vec.z>0.0) \n" " steps.z=steps1.z; \n" " else \n" " steps.z=steps2.z; \n" " \n" " if ( (steps.x <= steps.y) && (steps.x <= steps.z) ) \n" " { \n" " normal = vec3(1.0, 0.0, 0.0); \n" " contact_point = ray_pos + ray_vec * steps.x; \n" " tex_coords.xy = contact_point.zy; \n" " } \n" " else if ( (steps.y <= steps.x) && (steps.y <= steps.z) ) \n" " { \n" " normal = vec3(0.0, 1.0, 0.0); \n" " contact_point = ray_pos + ray_vec * steps.y; \n" " tex_coords.xy = contact_point.xz; \n" " } \n" " else \n" " { \n" " normal = vec3(0.0, 0.0, 1.0); \n" " contact_point = ray_pos + ray_vec * steps.z; \n" " tex_coords.xy = contact_point.xy; \n" " } \n" " vec3 light_vec = light_pos - contact_point; \n" " light_vec /= length (light_vec); \n" //" half_vector = (light_vec - ray_vec)/2.0; \n" " float diffuse = abs(dot (normal, light_vec));"// + 4.0 * pow (dot ( normal, half_vector), 4.0); \n" " float ambient = 0.1; \n" " float l = intersect(contact_point, light_vec) * (diffuse > 0.0 ? diffuse + ambient : ambient); \n" " object_color = texture2D( wall_texture, vec2(tex_coords.xy)).rgb; \n" //" object_color = vec3(0.8,0.5,0.2); \n" " out_color.rgb += (1.0 - out_color.a) * vec3(l) * object_color; \n" " break; \n" " } \n" " } \n" " gl_FragColor.rgb = out_color.rgb; \n" "} \n" ; int main(int argc, char* argv[]) { int i,j; SDL_Init( SDL_INIT_EVERYTHING ); SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 0 ); SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); SDL_SetVideoMode( 1024, 1024, 0, SDL_OPENGL ); GLhandleARB prog; char fshader[8192]; sprintf(fshader, fshader_ray, BALLS, BALLS); if ( !vr_glext_glsl_create_program(vshader,fshader,&prog) ) return 0; // generate sphere geometry/color srand(42); GLuint tex_spheres_geom; GLuint tex_wall; float spheres_pos[4*BALLS]; float spheres_dir[4*BALLS]; for( i=0; i 1.0) && (vx > 0.0) ) vx = -vx; if ( (y - r < 0.0) && (vy < 0.0) ) vy = -vy; if ( (y + r > 1.0) && (vy > 0.0) ) vy = -vy; if ( (z - r < 0.0) && (vz < 0.0) ) vz = -vz; if ( (z + r > 1.0) && (vz > 0.0) ) vz = -vz; spheres_pos [ 4*ii + 0] = x; spheres_pos [ 4*ii + 1] = y; spheres_pos [ 4*ii + 2] = z; spheres_dir[ 4*ii + 0] = vx; spheres_dir[ 4*ii + 1] = vy; spheres_dir[ 4*ii + 2] = vz; } eglUseProgramObjectARB(prog); // upload the sphere geometry texture glActiveTextureARB(GL_TEXTURE0); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_1D, tex_spheres_geom); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F_ARB, BALLS, 0, GL_RGBA, GL_FLOAT, spheres_pos); glActiveTextureARB(GL_TEXTURE0); glDisable (GL_TEXTURE_2D); glEnable (GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_1D, tex_spheres_geom); eglUniform1iARB(eglGetUniformLocationARB(prog, "spheres_geom"),0); glActiveTextureARB(GL_TEXTURE1); glEnable (GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex_wall); eglUniform1iARB(eglGetUniformLocationARB(prog, "wall_texture"),1); glBegin(GL_QUADS); glTexCoord3f( 0.0, 0.0, 0.0); glVertex2f( 0.0, 0.0); glTexCoord3f( 0.0, 1.0, 0.0); glVertex2f( 0.0, 1.0); glTexCoord3f( 1.0, 1.0, 0.0); glVertex2f( 1.0, 1.0); glTexCoord3f( 1.0, 0.0, 0.0 ); glVertex2f( 1.0, 0.0); glEnd(); SDL_GL_SwapBuffers(); i++; while(SDL_PollEvent(&event)>0) { switch(event.type) { case SDL_KEYDOWN: case SDL_QUIT: quit = true; } } } while(!quit); int after = SDL_GetTicks(); float time = (after-before)/1000.0; printf("%.2f seconds total (avg %.2f fps)\n",time,i/time); SDL_Quit(); }