decal.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:13k
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <GL/glut.h>
- /* Some <math.h> files do not define M_PI... */
- #ifndef M_PI
- #define M_PI 3.14159265358979323846
- #endif
- GLUquadricObj *quadric;
- GLfloat black[] = {0, 0, 0, 1};
- GLfloat white[] = {1, 1, 1, 1};
- int winWidth, winHeight;
- GLfloat *depthSave = NULL;
- GLubyte *stencilSave = NULL;
- GLubyte *colorSave = NULL;
- void resizeBuffers(void)
- {
- colorSave = realloc(colorSave, winWidth * winHeight * 4 * sizeof(GLubyte));
- depthSave = realloc(depthSave, winWidth * winHeight * 4 * sizeof(GLfloat));
- stencilSave = (GLubyte *)depthSave;
- }
- void pushOrthoView(float left, float right, float bottom, float top,
- float znear, float zfar)
- {
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrtho(left, right, bottom, top, znear, zfar);
- }
- void popView(void)
- {
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- void copyDepthToColor(GLenum whichColorBuffer)
- {
- int x, y;
- GLfloat max, min;
- GLint previousColorBuffer;
- glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT, GL_FLOAT,
- depthSave);
- /* I'm sure this could be done much better with OpenGL */
- max = 0;
- min = 1;
- for(y = 0; y < winHeight; y++)
- for(x = 0; x < winWidth; x++) {
- if(depthSave[winWidth * y + x] < min)
- min = depthSave[winWidth * y + x];
- if(depthSave[winWidth * y + x] > max && depthSave[winWidth * y + x] < .999)
- max = depthSave[winWidth * y + x];
- }
- for(y = 0; y < winHeight; y++)
- for(x = 0; x < winWidth; x++) {
- if(depthSave[winWidth * y + x] <= max)
- depthSave[winWidth * y + x] = 1 - (depthSave[winWidth * y + x] - min) / (max - min);
- else
- depthSave[winWidth * y + x] = 0;
- }
- pushOrthoView(0, 1, 0, 1, 0, 1);
- glRasterPos3f(0, 0, -.5);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_STENCIL_TEST);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
- glDrawBuffer(whichColorBuffer);
- glDrawPixels(winWidth, winHeight, GL_LUMINANCE , GL_FLOAT, depthSave);
- glDrawBuffer(previousColorBuffer);
- glEnable(GL_DEPTH_TEST);
- popView();
- }
- unsigned char colors[][3] =
- {
- {255, 0, 0}, /* red */
- {255, 218, 0}, /* yellow */
- {72, 255, 0}, /* yellowish green */
- {0, 255, 145}, /* bluish cyan */
- {0, 145, 255}, /* cyanish blue */
- {72, 0, 255}, /* purplish blue */
- {255, 0, 218}, /* reddish purple */
- };
- void copyStencilToColor(GLenum whichColorBuffer)
- {
- int x, y;
- GLint previousColorBuffer;
- glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE,
- stencilSave);
- /* I'm sure this could be done much better with OpenGL */
- for(y = 0; y < winHeight; y++)
- for(x = 0; x < winWidth; x++) {
- int stencilValue;
-
- stencilValue = stencilSave[winWidth * y + x];
- colorSave[(winWidth * y + x) * 3 + 0] = colors[stencilValue % 7][0];
- colorSave[(winWidth * y + x) * 3 + 1] = colors[stencilValue % 7][1];
- colorSave[(winWidth * y + x) * 3 + 2] = colors[stencilValue % 7][2];
- }
- pushOrthoView(0, 1, 0, 1, 0, 1);
- glRasterPos3f(0, 0, -.5);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_STENCIL_TEST);
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
- glGetIntegerv(GL_DRAW_BUFFER, &previousColorBuffer);
- glDrawBuffer(whichColorBuffer);
- glDrawPixels(winWidth, winHeight, GL_RGB, GL_UNSIGNED_BYTE, colorSave);
- glDrawBuffer(previousColorBuffer);
- glEnable(GL_DEPTH_TEST);
- popView();
- }
- int useStencil = 0;
- int stage = 6;
- typedef enum {COLOR, DEPTH, STENCIL} DataChoice;
- DataChoice dataChoice = COLOR;
- void init(void)
- {
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- quadric = gluNewQuadric();
- glMatrixMode(GL_PROJECTION);
- glFrustum(-.33, .33, -.33, .33, .5, 40);
- glMatrixMode(GL_MODELVIEW);
- gluLookAt(-4, 10, 6, 0, 0, 0, 0, 1, 0);
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_NORMALIZE);
- /*
- * only need this to clear stencil and only need to clear stencil
- * when you're looking at it; the algorithm works without it.
- */
- glClearStencil(5);
- }
- void setupLight(void)
- {
- static GLfloat lightpos[] = {0, 1, 0, 0};
- glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
- }
- void setupNormalDrawingState(void)
- {
- glDisable(GL_STENCIL_TEST);
- glEnable(GL_DEPTH_TEST);
- glDepthMask(1);
- }
- void setupBasePolygonState(int maxDecal)
- {
- glEnable(GL_DEPTH_TEST);
- if(useStencil) {
- glEnable(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, maxDecal + 1, 0xff);
- glStencilOp(GL_KEEP, GL_REPLACE, GL_ZERO);
- }
- }
- void setupDecalState(int decalNum)
- {
- if(useStencil) {
- glDisable(GL_DEPTH_TEST);
- glDepthMask(0);
- glEnable(GL_STENCIL_TEST);
- glStencilFunc(GL_GREATER, decalNum, 0xff);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- }
- }
- void drawAirplane(void)
- {
- GLfloat airplaneColor[4] = {.75, .75, .75, 1};
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, airplaneColor);
- glDisable(GL_CULL_FACE);
- glPushMatrix();
- glTranslatef(0, 0, -2.5);
- gluCylinder(quadric, .5, .5, 5, 10, 10);
- glPushMatrix();
- glTranslatef(0, 0, 5);
- gluCylinder(quadric, .5, 0, 1, 10, 10);
- glPopMatrix();
- glPushMatrix();
- glTranslatef(0, 0, 3);
- glScalef(3, .1, 1);
- gluSphere(quadric, 1, 10, 10);
- glPopMatrix();
- glPushMatrix();
- glTranslatef(0, 0, .5);
- glScalef(2, .1, .5);
- gluSphere(quadric, 1, 10, 10);
- glPopMatrix();
- glEnable(GL_CULL_FACE);
- glBegin(GL_TRIANGLES);
- glNormal3f(1, 0, 0);
- glVertex3f(0, 1.5, 0);
- glVertex3f(0, .5, 1);
- glVertex3f(0, .5, 0);
- glNormal3f(-1, 0, 0);
- glVertex3f(0, 1.5, 0);
- glVertex3f(0, .5, 0);
- glVertex3f(0, .5, 1);
- glEnd();
- glDisable(GL_CULL_FACE);
- glRotatef(180, 0, 1, 0);
- gluDisk(quadric, 0, .5, 10, 10);
- glPopMatrix();
- glEnable(GL_CULL_FACE);
- }
- void drawGround(void)
- {
- GLfloat groundColor[4] = {.647, .165, .165, 1};
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, groundColor);
- glBegin(GL_QUADS);
- glNormal3i(0, 1, 0);
- glVertex3f(10, 0, 10);
- glVertex3f(10, 0, -10);
- glVertex3f(-10, 0, -10);
- glVertex3f(-10, 0, 10);
- glEnd();
- }
- void drawAsphalt(void)
- {
- GLfloat asphaltColor[4] = {.25, .25, .25, 1};
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, asphaltColor);
- glBegin(GL_QUADS);
- glNormal3i(0, 1, 0);
- glVertex3f(5, 0, 9.5);
- glVertex3f(5, 0, -9.5);
- glVertex3f(-5, 0, -9.5);
- glVertex3f(-5, 0, 9.5);
- glEnd();
- }
- int numStripes = 5;
- float stripeGap = .66;
- void drawStripes(void)
- {
- GLfloat stripeColor[4] = {1, 1, 0, 1};
- int i;
- float stripeLength;
- stripeLength = (16 - stripeGap * (numStripes - 1)) / numStripes;
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, stripeColor);
- glBegin(GL_QUADS);
- glNormal3i(0, 1, 0);
- glVertex3f(4.5, 0, 8.5);
- glVertex3f(4.5, 0, -8.5);
- glVertex3f(3.5, 0, -8.5);
- glVertex3f(3.5, 0, 8.5);
- glVertex3f(-3.5, 0, 8.5);
- glVertex3f(-3.5, 0, -8.5);
- glVertex3f(-4.5, 0, -8.5);
- glVertex3f(-4.5, 0, 8.5);
- for(i = 0; i < numStripes; i++) {
- glVertex3f(.5, 0, 8 - i * (stripeLength + stripeGap));
- glVertex3f(.5, 0, 8 - i * (stripeLength + stripeGap) - stripeLength);
- glVertex3f(-.5, 0, 8 - i * (stripeLength + stripeGap) - stripeLength);
- glVertex3f(-.5, 0, 8 - i * (stripeLength + stripeGap));
- }
- glEnd();
- }
- void redraw(void)
- {
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- /* Only need this if you care to look at the stencil buffer */
- if(dataChoice == STENCIL)
- glClear(GL_STENCIL_BUFFER_BIT);
- glPushMatrix();
- glScalef(.5, .5, .5);
- if(stage == 1)
- goto doneWithFrame;
- setupLight();
- setupNormalDrawingState();
- glPushMatrix();
- glTranslatef(0, 1, 4);
- glRotatef(135, 0, 1, 0);
- drawAirplane();
- glPopMatrix();
- if(stage == 2)
- goto doneWithFrame;
- setupBasePolygonState(3); /* 2 decals */
- drawGround();
- if(stage == 3)
- goto doneWithFrame;
- setupDecalState(1); /* decal # 1 = the runway asphalt */
- drawAsphalt();
- if(stage == 4)
- goto doneWithFrame;
- setupDecalState(2); /* decal # 2 = yellow paint on the runway */
- drawStripes();
- if(stage == 5)
- goto doneWithFrame;
- setupDecalState(3); /* decal # 3 = the plane's shadow */
- glDisable(GL_LIGHTING);
- glEnable(GL_BLEND);
- glPushMatrix();
- glColor4f(0, 0, 0, .5);
- glTranslatef(0, 0, 4);
- glRotatef(135, 0, 1, 0);
- glScalef(1, 0, 1);
- drawAirplane();
- glPopMatrix();
- glDisable(GL_BLEND);
- glEnable(GL_LIGHTING);
- doneWithFrame:
- setupNormalDrawingState();
- glPopMatrix();
- switch(dataChoice) {
- case COLOR:
- break; /* color already in back buffer */
- case STENCIL:
- copyStencilToColor(GL_BACK);
- break;
- case DEPTH:
- copyDepthToColor(GL_BACK);
- break;
- }
- glutSwapBuffers();
- }
- void reshape(int width, int height)
- {
- glViewport(0, 0, width, height);
- winWidth = width;
- winHeight = height;
- resizeBuffers();
- glutPostRedisplay();
- }
- static int ox, oy;
- static int mode;
- /* ARGSUSED */
- void button(int b, int state, int x, int y)
- {
- ox = x;
- oy = y;
- mode = b;
- }
- void motion(int x, int y)
- {
- static float ang = 0;
- static float height = 10;
- float eyex, eyez;
- if(mode == GLUT_LEFT_BUTTON)
- {
- ang += (x - ox) / 512.0 * M_PI;
- height += (y - oy) / 512.0 * 10;
- eyex = cos(ang) * 7;
- eyez = sin(ang) * 7;
- glLoadIdentity();
- gluLookAt(eyex, height, eyez, 0, 0, 0, 0, 1, 0);
- glutPostRedisplay();
- ox = x;
- oy = y;
- }
- }
- void changeData(int data)
- {
- char *s;
- dataChoice = data;
- glutPostRedisplay();
- switch(data) {
- case COLOR:
- s = "color";
- break;
- case STENCIL:
- s = "stencil";
- break;
- case DEPTH:
- s = "depth";
- break;
- }
- printf("Now displaying %s datan", s);
- }
- void changeStage(int data)
- {
- char *s;
- stage = data;
- glutPostRedisplay();
- switch(data) {
- case 1:
- s = "clearing";
- break;
- case 2:
- s = "drawing airplane";
- break;
- case 3:
- s = "drawing ground";
- break;
- case 4:
- s = "drawing asphalt";
- break;
- case 5:
- s = "drawing paint";
- break;
- case 6:
- s = "drawing shadow";
- break;
- }
- printf("Now displaying frame after %sn", s);
- }
- int mainMenu;
- void stencilDecalEnable(int enabled)
- {
- glutSetMenu(mainMenu);
- if(enabled){
- glutChangeToMenuEntry(1, "Turn off stencil decal", 0);
- printf("Stencil decaling turned onn");
- glutPostRedisplay();
- } else {
- glutChangeToMenuEntry(1, "Turn on stencil decal", 1);
- printf("Stencil decaling turned offn");
- glutPostRedisplay();
- }
- useStencil = enabled;
- }
- /*
- * Basically shortcuts for menu items
- */
- /* ARGSUSED1 */
- void keyboard(unsigned char key, int x, int y)
- {
- switch(key) {
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- changeStage(key - '0');
- break;
- case 's': case 'S':
- stencilDecalEnable(! useStencil);
- break;
- case 'q': case 'Q': case ' 33':
- exit(0);
- break;
- default:
- fprintf(stderr, "Push right mouse button for menun");
- break;
- }
- }
- int main(int argc, char **argv)
- {
- int bufferMenu;
- int finishMenu;
- int stenSize;
- glutInitWindowSize(winWidth = 512, winHeight = 512);
- glutInit(&argc, argv);
- glutInitDisplayString("samples stencil>=3 rgb double depth");
- /* glutInitDisplayMode(GLUT_DOUBLE|GLUT_STENCIL|GLUT_DEPTH|GLUT_ALPHA); */
- (void)glutCreateWindow("decaling using stencil");
- glutDisplayFunc(redraw);
- glutKeyboardFunc(keyboard);
- glutMotionFunc(motion);
- glutMouseFunc(button);
- glutReshapeFunc(reshape);
- resizeBuffers();
- glGetIntegerv(GL_STENCIL_BITS, &stenSize);
- fprintf(stderr, "(%d bits of stencil available in this visual)n", stenSize);
- fprintf(stderr, "Hit 'h' for help messagen");
- finishMenu = glutCreateMenu(changeStage);
- glutAddMenuEntry("Clearing screen", 1);
- glutAddMenuEntry("Drawing airplane", 2);
- glutAddMenuEntry("Drawing ground ", 3);
- glutAddMenuEntry("Drawing asphalt", 4);
- glutAddMenuEntry("Drawing paint", 5);
- glutAddMenuEntry("Drawing shadow", 6);
- bufferMenu = glutCreateMenu(changeData);
- glutAddMenuEntry("Color data", COLOR);
- glutAddMenuEntry("Stencil data", STENCIL);
- glutAddMenuEntry("Depth data", DEPTH);
- mainMenu = glutCreateMenu(stencilDecalEnable);
- glutAddMenuEntry("Turn on stencil decal", 1);
- glutAddSubMenu("Visible buffer", bufferMenu);
- glutAddSubMenu("Finish frame after...", finishMenu);
- glutAttachMenu(GLUT_RIGHT_BUTTON);
- init();
- glutMainLoop();
- return 0;
- }