#include "os.h" #include "ph.h" #include "sphere.c" #define BUFFER_WIDTH 128 #define BUFFER_HEIGHT 128 #define VIEW_WIDTH (1 + BUFFER_WIDTH + 1 + BUFFER_WIDTH + 1 + BUFFER_WIDTH + 1 + BUFFER_WIDTH + 1 + BUFFER_WIDTH + 1) #define VIEW_HEIGHT (1 + BUFFER_HEIGHT + 1 + (BUFFER_HEIGHT / 2) + 1 + (BUFFER_HEIGHT / 4) + 1 + (BUFFER_HEIGHT / 8) + 1) #define FILTER_COUNT 4 #define KERNEL_SIZE 3 #define STRINGIFY(A) #A #include "shaders/passv.glsl" #include "shaders/blitf.glsl" #include "shaders/combine5f.glsl" #include "shaders/row3f.glsl" #include "shaders/lightv.glsl" #include "shaders/lightf.glsl" #include "shaders/hipassf.glsl" PHsurface window; PHsurface scene; PHsurface pass0[FILTER_COUNT]; PHsurface pass1[FILTER_COUNT]; GLuint sphereVerts; GLuint sphereFaces; GLuint blitProg; GLuint combineProg; GLuint filterProg; GLuint lightProg; GLuint hiPassProg; GLfloat darkblue[4] = {7, 16, 141, 0}; GLfloat lightblue[4] = {122, 143, 248, 0}; GLfloat brightgold[4] = {5*0.8f, 5*0.498039f, 5*0.196078f, 1.0f}; GLfloat black[4] = {0, 0, 0, 1}; GLfloat white[4] = {1, 1, 1, 1}; GLfloat gray[4] = {0.5f, 0.5f, 0.5f, 1}; float kernel[KERNEL_SIZE] = { 5, 6, 5 }; typedef enum {HORIZONTAL, VERTICAL} Direction; static void blur(PHsurface *sources, PHsurface *dests, int count, Direction dir) { GLint loc; int p; // Set up the filter. glUseProgram(filterProg); loc = glGetUniformLocation(filterProg, "source"); glUniform1i(loc, 0); loc = glGetUniformLocation(filterProg, "coefficients"); glUniform1fv(loc, KERNEL_SIZE, kernel); loc = glGetUniformLocation(filterProg, "offsetx"); glUniform1f(loc, 0); loc = glGetUniformLocation(filterProg, "offsety"); glUniform1f(loc, 0); if (dir == HORIZONTAL) loc = glGetUniformLocation(filterProg, "offsetx"); // Perform the blurring. for (p = 0; p < count; p++) { float offset = 1.2f / sources[p].width; glUniform1f(loc, offset); phBindSurface(dests + p); glBindTexture(GL_TEXTURE_2D, sources[p].texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(1, 0); glVertex2i(1, -1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glEnd(); } } static void init() { int p, c; float sum; GLsizei width; GLsizei height; if (!GLEW_VERSION_2_0) fatalf("OpenGL 2.0 is required"); if (!glewIsSupported("GL_ARB_half_float_pixel")) fatalf("GL_ARB_half_float_pixel is required"); if (!glewIsSupported("GL_EXT_framebuffer_object")) fatalf("GL_EXT_framebuffer_object is required"); glGenBuffers(1, &sphereVerts); glBindBuffer(GL_ARRAY_BUFFER, sphereVerts); glBufferData(GL_ARRAY_BUFFER, sizeof(vertData), (void *) vertData, GL_STATIC_DRAW); glGenBuffers(1, &sphereFaces); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereFaces); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(faceData), (void *) faceData, GL_STATIC_DRAW); glMatrixMode(GL_MODELVIEW); // Compile shaders blitProg = phCompile(passv, blitf); combineProg = phCompile(passv, combine5f); filterProg = phCompile(passv, row3f); lightProg = phCompile(lightv, lightf); hiPassProg = phCompile(passv, hipassf); // Normalize kernel coefficients sum = 0; for (c = 0; c < KERNEL_SIZE; c++) sum += kernel[c]; for (c = 0; c < KERNEL_SIZE; c++) kernel[c] /= sum; // Normalize colors for (c = 0; c < 4; c++) { darkblue[c] /= 255.0f; lightblue[c] /= 255.0f; } // Create Window Surface window.fbo = 0; window.depth = 0; window.width = VIEW_WIDTH; window.height = VIEW_HEIGHT; window.clearColor[0] = lightblue[0]; window.clearColor[1] = lightblue[1]; window.clearColor[2] = lightblue[2]; window.clearColor[3] = lightblue[3]; window.viewport.x = 0; window.viewport.y = 0; window.viewport.width = window.width; window.viewport.height = window.height; glLoadIdentity(); glGetFloatv(GL_MODELVIEW_MATRIX, window.modelview); glOrtho(0, window.width, window.height, 0, 0, 10); glGetFloatv(GL_MODELVIEW_MATRIX, window.projection); glLoadIdentity(); // Create 3D Scene Surface width = BUFFER_WIDTH; height = BUFFER_HEIGHT; scene.width = width; scene.height = height; scene.clearColor[0] = 0; scene.clearColor[1] = 0; scene.clearColor[2] = 0; scene.clearColor[3] = 0; scene.viewport.x = 0; scene.viewport.y = 0; scene.viewport.width = width; scene.viewport.height = height; glGetFloatv(GL_MODELVIEW_MATRIX, scene.modelview); glGetFloatv(GL_MODELVIEW_MATRIX, scene.projection); phCreateSurface(&scene, GL_TRUE, GL_TRUE, GL_FALSE); // Create Pass Surfaces for (p = 0; p < FILTER_COUNT; p++) { pass0[p].width = width; pass0[p].height = height; pass0[p].viewport.x = 0; pass0[p].viewport.y = 0; pass0[p].viewport.width = width; pass0[p].viewport.height = height; glGetFloatv(GL_MODELVIEW_MATRIX, pass0[p].modelview); glGetFloatv(GL_MODELVIEW_MATRIX, pass0[p].projection); phCreateSurface(pass0 + p, GL_FALSE, GL_FALSE, GL_TRUE); width = width >> 1; height = height >> 1; } width = BUFFER_WIDTH; height = BUFFER_HEIGHT; for (p = 0; p < FILTER_COUNT; p++) { pass1[p].width = width; pass1[p].height = height; pass1[p].viewport.x = 0; pass1[p].viewport.y = 0; pass1[p].viewport.width = width; pass1[p].viewport.height = height; glGetFloatv(GL_MODELVIEW_MATRIX, pass1[p].modelview); glGetFloatv(GL_MODELVIEW_MATRIX, pass1[p].projection); phCreateSurface(pass1 + p, GL_FALSE, GL_FALSE, GL_FALSE); width = width >> 1; height = height >> 1; } } static void computeLightingParams(float theta, PHvec3 *vp, PHvec3 *hhat) { PHvec3 position; PHvec3 look = {0, 0, 0}; PHvec3 eye = {0, 0, 1}; position.x = 0; position.y = sinf(theta * PH_PI / 180.0f); position.z = cosf(theta * PH_PI / 180.0f); *vp = phSub(&look, &position); *hhat = phAdd(vp, &eye); phNormalize(hhat); } static void draw() { int p; static float theta = 50; GLint loc; PHvec3 vp; PHvec3 hhat; // Draw 3D scene. srand(0); phBindSurface(&scene); phClearSurface(); glTranslatef(0, 0, -1); glUseProgram(lightProg); computeLightingParams(theta, &vp, &hhat); glEnable(GL_DEPTH_TEST); loc = glGetUniformLocation(lightProg, "shininess"); glUniform1f(loc, 64); loc = glGetUniformLocation(lightProg, "diffuse"); glUniform3fv(loc, 1, gray); loc = glGetUniformLocation(lightProg, "specular"); glUniform3fv(loc, 1, brightgold); loc = glGetUniformLocation(lightProg, "ambient"); glUniform3fv(loc, 1, darkblue); loc = glGetUniformLocation(lightProg, "vp"); glUniform3fv(loc, 1, &vp.x); loc = glGetUniformLocation(lightProg, "hhat"); glUniform3fv(loc, 1, &hhat.x); glScalef(0.5f, 0.5f, 0.5f); glBindBuffer(GL_ARRAY_BUFFER, sphereVerts); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereFaces); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 0, 0); glNormalPointer(GL_FLOAT, 0, 0); glPushMatrix(); glDrawElements(GL_TRIANGLES, FACE_COUNT * 3, GL_UNSIGNED_INT, 0); glPopMatrix(); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisable(GL_DEPTH_TEST); // Hi-pass filter into pass0[0] glUseProgram(hiPassProg); loc = glGetUniformLocation(hiPassProg, "source"); glUniform1i(loc, 0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, scene.texture); phBindSurface(pass0); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(1, 0); glVertex2i(1, -1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glEnd(); glUseProgram(0); // Downsample the scene into the source surfaces. glBindTexture(GL_TEXTURE_2D, pass0[0].texture); for (p = 1; p < FILTER_COUNT; p++) { phBindSurface(pass0 + p); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(-1, -1); glTexCoord2i(1, 0); glVertex2i(1, -1); glTexCoord2i(1, 1); glVertex2i(1, 1); glTexCoord2i(0, 1); glVertex2i(-1, 1); glEnd(); } // Perform the horizontal blurring pass. blur(pass0, pass1, FILTER_COUNT, HORIZONTAL); // Draw left portion of window. glUseProgram(blitProg); loc = glGetUniformLocation(blitProg, "bkgd"); glUniform4fv(loc, 1, black); loc = glGetUniformLocation(blitProg, "source"); glUniform1i(loc, 0); phBindSurface(&window); phClearSurface(); glTranslatef(1, 1, 0); glBindTexture(GL_TEXTURE_2D, scene.texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(scene.width, 0); glTexCoord2i(1, 1); glVertex2i(scene.width, scene.height); glTexCoord2i(0, 1); glVertex2i(0, scene.height); glEnd(); glTranslatef((GLfloat) scene.width + 1, 0, 0); glPushMatrix(); for (p = 0; p < FILTER_COUNT; p++) { glBindTexture(GL_TEXTURE_2D, pass0[p].texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(pass0[p].width, 0); glTexCoord2i(1, 1); glVertex2i(pass0[p].width, pass0[p].height); glTexCoord2i(0, 1); glVertex2i(0, pass0[p].height); glEnd(); glTranslatef(0, (GLfloat) pass0[p].height + 1, 0); } glPopMatrix(); glTranslatef((GLfloat) pass0[0].width + 1, 0, 0); for (p = 0; p < FILTER_COUNT; p++) { glBindTexture(GL_TEXTURE_2D, pass1[p].texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(pass1[p].width, 0); glTexCoord2i(1, 1); glVertex2i(pass1[p].width, pass1[p].height); glTexCoord2i(0, 1); glVertex2i(0, pass1[p].height); glEnd(); glTranslatef(0, (GLfloat) pass1[p].height + 1, 0); } // Perform the vertical blurring pass. blur(pass1, pass0, FILTER_COUNT, VERTICAL); // Draw right portion of window. phBindSurface(&window); glTranslatef((GLfloat) 3 * pass1[0].width + 4, 1, 0); glUseProgram(blitProg); glPushMatrix(); for (p = 0; p < FILTER_COUNT; p++) { glBindTexture(GL_TEXTURE_2D, pass0[p].texture); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(pass0[p].width, 0); glTexCoord2i(1, 1); glVertex2i(pass0[p].width, pass0[p].height); glTexCoord2i(0, 1); glVertex2i(0, pass0[p].height); glEnd(); glTranslatef(0, (GLfloat) pass0[p].height + 1, 0); } glPopMatrix(); glTranslatef((GLfloat) pass0[0].width + 1, 0, 0); glUseProgram(combineProg); for (p = 0; p < FILTER_COUNT; p++) { char name[] = "Pass#"; glActiveTexture(GL_TEXTURE0 + p); glBindTexture(GL_TEXTURE_2D, pass0[p].texture); glEnable(GL_TEXTURE_2D); sprintf(name, "Pass%d", p); loc = glGetUniformLocation(combineProg, name); glUniform1i(loc, p); } glActiveTexture(GL_TEXTURE0 + FILTER_COUNT); glBindTexture(GL_TEXTURE_2D, scene.texture); glEnable(GL_TEXTURE_2D); loc = glGetUniformLocation(combineProg, "Scene"); glUniform1i(loc, FILTER_COUNT); glBegin(GL_QUADS); glTexCoord2i(0, 0); glVertex2i(0, 0); glTexCoord2i(1, 0); glVertex2i(pass0[0].width, 0); glTexCoord2i(1, 1); glVertex2i(pass0[0].width, pass0[0].height); glTexCoord2i(0, 1); glVertex2i(0, pass0[0].height); glEnd(); glUseProgram(0); for (p = 0; p < FILTER_COUNT; p++) { glActiveTexture(GL_TEXTURE0 + p); glDisable(GL_TEXTURE_2D); } glActiveTexture(GL_TEXTURE0 + FILTER_COUNT); glDisable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0); } int main(int argc, char** argv) { int done = 0; OS_Event event; osInit("HDR Bloom" , VIEW_WIDTH, VIEW_HEIGHT, OS_OVERLAY, 0); osWaitVsync(0); init(); while (!done) { while (osPollEvent(&event)) { switch(event.type) { case OS_PAINT: draw(); osSwapBuffers(); break; case OS_KEYUP: switch (event.key.key) { case OSK_ESCAPE: case 'X': case 'x': case 'Q': case 'q': done = 1; break; } break; case OS_QUIT: done = 1; break; } } draw(); osSwapBuffers(); } osQuit(); return 0; }