diff options
author | Brian Paul <brianp@vmware.com> | 2011-05-26 07:15:59 -0600 |
---|---|---|
committer | Brian Paul <brianp@vmware.com> | 2011-05-26 07:15:59 -0600 |
commit | 9319956bedd6b0fe4502b09a45be31f73532cf90 (patch) | |
tree | 8e1741c58925cd6752c2d917611231b2e6333fb5 | |
parent | 086183cea2b7c8e226062b328de3228e568fbf90 (diff) |
cuberender: demo rendering to cube map faces for environment mapping
-rw-r--r-- | src/demos/Makefile.am | 2 | ||||
-rw-r--r-- | src/demos/cuberender.c | 582 |
2 files changed, 584 insertions, 0 deletions
diff --git a/src/demos/Makefile.am b/src/demos/Makefile.am index 87517866..41603fa8 100644 --- a/src/demos/Makefile.am +++ b/src/demos/Makefile.am @@ -40,6 +40,7 @@ bin_PROGRAMS = \ clearspd \ copypix \ cubemap \ + cuberender \ dinoshade \ dissolve \ drawpix \ @@ -94,6 +95,7 @@ tunnel_SOURCES = \ copypix_LDADD = ../util/libutil.la cubemap_LDADD = ../util/libutil.la +cuberender_LDADD = ../util/libutil.la drawpix_LDADD = ../util/libutil.la dissolve_LDADD = ../util/libutil.la engine_LDADD = ../util/libutil.la diff --git a/src/demos/cuberender.c b/src/demos/cuberender.c new file mode 100644 index 00000000..17f9d47a --- /dev/null +++ b/src/demos/cuberender.c @@ -0,0 +1,582 @@ +/* + * Test rendering into a cube map texture with FBOs. + * + * Brian Paul + * May 2011 + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <GL/glew.h> +#include <GL/glut.h> +#include "shaderutil.h" + + +#define DEG_TO_RAD (3.14159 / 180.0) + +#define ELEMENTS(array) (sizeof(array) / sizeof(array[0])) + +static GLint WindowWidth = 750, WindowHeight = 450; +static GLint Win; + +static GLfloat Xrot = 10, Yrot = 0, Zrot = 0; + +static GLfloat GroundColor[4] = {0.5, 0.5, 0.75, 1}; +static GLfloat GroundY = -1.0f; + +static GLfloat ViewDist = 30.0; + +static GLfloat SpherePos[4] = { 0, 2.5, 0, 1 }; +static GLfloat LightDist = 15; +static GLfloat LightLatitude = 30.0; +static GLfloat LightLongitude = 45.0; +static GLfloat LightPos[4]; + +static GLboolean Anim = GL_TRUE; + +static GLboolean NeedNewCubeMap = GL_FALSE; +static GLuint CubeTexture; + + +struct cylinder +{ + float PosX, PosY; + float Radius, Height; + float Color[4]; +}; + +#define NUM_CYLINDERS 30 + +static struct cylinder Cylinders[NUM_CYLINDERS]; + + +static float +RandomFloat(float min, float max) +{ + const int k = 10000; + float t = (rand() % k) / (float) (k - 1); /* t in [0,1] */ + float r = min + t * (max - min); + return r; +} + + +static void +CheckError(int line) +{ + GLenum err = glGetError(); + if (err) { + printf("GL Error 0x%x at line %d\n", (int) err, line); + } +} + + +static void +GenerateCylinders(void) +{ + int i; + for (i = 0; i < NUM_CYLINDERS; i++) { + float r = RandomFloat(5.0, 9.0); + float a = RandomFloat(0, 2 * M_PI); + + Cylinders[i].PosX = r * cos(a); + Cylinders[i].PosY = r * sin(a); + Cylinders[i].Radius = RandomFloat(0.25, 1.0); + Cylinders[i].Height = RandomFloat(1.0, 7.0); + Cylinders[i].Color[0] = RandomFloat(0.25, 1.0); + Cylinders[i].Color[1] = RandomFloat(0.25, 1.0); + Cylinders[i].Color[2] = RandomFloat(0.25, 1.0); + Cylinders[i].Color[3] = RandomFloat(0.25, 1.0); + } +} + +static void +DrawCylinder(const struct cylinder *cyl) +{ + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, cyl->Color); + glPushMatrix(); + glTranslatef(cyl->PosX, GroundY, cyl->PosY); + glRotatef(-90, 1, 0, 0); + glutSolidCone(cyl->Radius, cyl->Height, 12, 2); + glPopMatrix(); +} + + +static void +DrawLightSource(void) +{ + glPushMatrix(); + glTranslatef(LightPos[0], LightPos[1], LightPos[2]); + glColor3f(1, 1, 1); + glutSolidSphere(0.25, 8, 8); + glPopMatrix(); +} + + +static void +DrawScene(void) +{ + int i; + + glEnable(GL_LIGHTING); + + for (i = 0; i < NUM_CYLINDERS; i++) { + DrawCylinder(&Cylinders[i]); + } + + glDisable(GL_LIGHTING); + + if (1) + DrawLightSource(); + + /* ground plane */ + if (1) { + GLfloat k = 10.0, g = GroundY; + CheckError(__LINE__); + glPushMatrix(); + glColor3fv(GroundColor); + glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, GroundColor); + glNormal3f(0, 1, 0); + glBegin(GL_POLYGON); + glVertex3f(-k, g, -k); + glVertex3f( k, g, -k); + glVertex3f( k, g, k); + glVertex3f(-k, g, k); + glEnd(); + glPopMatrix(); + } + + CheckError(__LINE__); +} + + +/* + * Draw sphere with cube map texture that reflects rest of the scene. + */ +static void +DrawShinySphere(void) +{ + glEnable(GL_TEXTURE_CUBE_MAP); + +#if 0 + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB); +#else + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB); + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP_ARB); +#endif + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + glEnable(GL_TEXTURE_GEN_R); + + glPushMatrix(); + glTranslatef(SpherePos[0], SpherePos[1], SpherePos[2]); + glColor3f(0.75, 0.75, 0.75); + + if (1) { + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glRotatef(-Yrot, 0, 1, 0); + glRotatef(-Xrot, 1, 0, 0); + } + + glutSolidSphere(2.5, 16, 16); + + glMatrixMode(GL_MODELVIEW); + + glPopMatrix(); + + glDisable(GL_TEXTURE_CUBE_MAP); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); +} + + +/** + * Setup modelview and projection for drawing a cube face. + */ +static void +SetupCubeFaceView(GLenum face, const GLfloat centerPos[4]) +{ + GLfloat near = 0.5, far = 20.0; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-near, near, -near, near, near, far); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + switch (face) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + glRotatef(180, 1, 0, 0); + glRotatef(-90, 0, 1, 0); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + glRotatef(180, 1, 0, 0); + glRotatef(90, 0, 1, 0); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + glRotatef(-90, 1, 0, 0); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + glRotatef(90, 1, 0, 0); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + glRotatef(180, 1, 0, 0); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + glRotatef(0, 1, 0, 0); + glRotatef(180, 0, 0, 1); + break; + } + + glTranslatef(-centerPos[0], -centerPos[1], -centerPos[2]); + + glLightfv(GL_LIGHT0, GL_POSITION, LightPos); +} + + + +static void +ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude, + GLfloat pos[4]) +{ + pos[0] = dist * sin(longitude * DEG_TO_RAD); + pos[1] = dist * sin(latitude * DEG_TO_RAD); + pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD); + pos[3] = 1; +} + + +static GLint +ChooseCubeSize(void) +{ + if (WindowWidth >= 1024 && WindowHeight >= 1024) { + return 1024; + } + else if (WindowWidth >= 512 && WindowHeight >= 512) { + return 512; + } + else if (WindowWidth >= 256 && WindowHeight >= 256) { + return 256; + } + else { + return 128; + } +} + + +static GLuint +CreateCubeTexture(GLint size) +{ + GLboolean linearFilter = GL_TRUE; + GLuint cube, face; + + glGenTextures(1, &cube); + glBindTexture(GL_TEXTURE_CUBE_MAP, cube); + + /* Set the filter mode so that the texture is texture-complete. + * Otherwise it will cause the framebuffer to fail the framebuffer + * completeness test. + */ + if (linearFilter) { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + + for (face = 0; face < 6; face++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, GL_RGBA, + size, size, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + CheckError(__LINE__); + + return cube; +} + + +/** + * Render the six faces of a cube map. + */ +static void +RenderCubeMap(void) +{ + GLuint fbo, face, depthStencilRb; + GLint cubeSize; + + CheckError(__LINE__); + + cubeSize = ChooseCubeSize(); + printf("Rendering %d x %d cube texture\n", cubeSize, cubeSize); + + CubeTexture = CreateCubeTexture(cubeSize); + + /* + * Make FBO. + */ + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + + /* + * Make depth/stencil renderbuffer. + */ + glGenRenderbuffersEXT(1, &depthStencilRb); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthStencilRb); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_STENCIL, + cubeSize, cubeSize); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, depthStencilRb); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, + GL_STENCIL_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, depthStencilRb); + + glClearColor(0.25, 0.25, 0.25, 1.0); + glViewport(0, 0, cubeSize, cubeSize); + + /* + * Render into cube faces. + */ + for (face = 0; face < 6; face++) { + GLenum status; + + /* Render color into face of cubemap */ + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, + CubeTexture, 0); + + status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + CheckError(__LINE__); + if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { + fprintf(stderr, "FBO not complete! status = 0x%04x\n", status); + assert(status == GL_FRAMEBUFFER_COMPLETE_EXT); + } + + CheckError(__LINE__); + + /* Render the depth image into cube face */ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + SetupCubeFaceView(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, SpherePos); + + DrawScene(); + } + + glDeleteRenderbuffersEXT(1, &depthStencilRb); + glDeleteFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + CheckError(__LINE__); +} + + +/** + * Redraw window image + */ +static void +Display(void) +{ + const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight; + + ComputeLightPos(LightDist, LightLatitude, LightLongitude, LightPos); + + if (NeedNewCubeMap) { + /* regenerate cube map faces */ + RenderCubeMap(); + NeedNewCubeMap = GL_FALSE; + } + + glViewport(0, 0, WindowWidth, WindowHeight); + + /* draw scene from camera's view */ + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -ViewDist); + glRotatef(Xrot, 1, 0, 0); + glRotatef(Yrot, 0, 1, 0); + glRotatef(Zrot, 0, 0, 1); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glLightfv(GL_LIGHT0, GL_POSITION, LightPos); + + DrawScene(); + DrawShinySphere(); + + glutSwapBuffers(); +} + + +static void +Reshape(int width, int height) +{ + WindowWidth = width; + WindowHeight = height; + NeedNewCubeMap = GL_TRUE; +} + + +static void +Idle(void) +{ + static double t0 = -1.; + double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; + if (t0 < 0.0) + t0 = t; + dt = t - t0; + t0 = t; + Yrot += 40.0 * dt; + glutPostRedisplay(); +} + + +static void +Key(unsigned char key, int x, int y) +{ + const GLfloat step = 3.0; + (void) x; + (void) y; + switch (key) { + case 'a': + Anim = !Anim; + if (Anim) + glutIdleFunc(Idle); + else + glutIdleFunc(NULL); + break; + case 'r': + GenerateCylinders(); + NeedNewCubeMap = GL_TRUE; + break; + case 'z': + Zrot -= step; + break; + case 'Z': + Zrot += step; + break; + case 27: + glutDestroyWindow(Win); + exit(0); + break; + } + fflush(stdout); + glutPostRedisplay(); +} + + +static void +SpecialKey(int key, int x, int y) +{ + const GLfloat step = 3.0; + const int mod = glutGetModifiers(); + (void) x; + (void) y; + switch (key) { + case GLUT_KEY_UP: + if (mod) + //LightLatitude += step; + SpherePos[1] += .1*step; + else + Xrot += step; + break; + case GLUT_KEY_DOWN: + if (mod) + //LightLatitude -= step; + SpherePos[1] -= .1*step; + else + Xrot -= step; + break; + case GLUT_KEY_LEFT: + if (mod) + LightLongitude += step; + else + Yrot += step; + break; + case GLUT_KEY_RIGHT: + if (mod) + LightLongitude -= step; + else + Yrot -= step; + break; + } + if (mod) + NeedNewCubeMap = GL_TRUE; + + glutPostRedisplay(); +} + + +static void +Init(void) +{ + const char *extensions[3] = { + "GL_ARB_depth_texture", + "GL_ARB_texture_cube_map", + "GL_EXT_framebuffer_object" + }; + int i; + + for (i = 0; i < ELEMENTS(extensions); i++) { + if (!glutExtensionSupported(extensions[i])) { + printf("Sorry, this demo requires %s\n", extensions[i]); + exit(1); + } + } + + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + + GenerateCylinders(); + + printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); +} + + +static void +PrintHelp(void) +{ + printf("Keys:\n"); + printf(" a = toggle animation\n"); + printf(" cursor keys = rotate scene\n"); + printf(" <shift> + up/down = move sphere\n"); + printf(" <shift> + left/right = move light\n"); + fflush(stdout); +} + + +int +main(int argc, char *argv[]) +{ + glutInitWindowSize(WindowWidth, WindowHeight); + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL); + Win = glutCreateWindow(argv[0]); + glewInit(); + glutReshapeFunc(Reshape); + glutKeyboardFunc(Key); + glutSpecialFunc(SpecialKey); + glutDisplayFunc(Display); + if (Anim) + glutIdleFunc(Idle); + Init(); + PrintHelp(); + glutMainLoop(); + return 0; +} |