/* mushroom1.c - Don Yang (uguu.org) lclint 2.5m: 61 errors -boolops -fixedformalarray -paramuse -predboolint -realcompare -retvalint -type -usedef I am convinced that this code is self documenting... 02/26/01 */ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #define PI 3.14159265358979323846264338327950288419716939937510 #define WINDOW_WIDTH 640 #define WINDOW_HEIGHT 480 #define WINDOW_POS_X 100 #define WINDOW_POS_Y 100 #define WINDOW_SCALE 40 #define ORTHO_NEAR -1000.0 #define ORTHO_FAR 1000.0 #define DELTA_ROTATE 0.05 #define DELTA_SCALE 0.01 #define MIN_SCALE 0.1f #define MAX_SCALE 20.0f #define INIT_SCALE 3.0f #define CURVE_RESOLUTION 32 #define REVOLVE_RESOLUTION 64 #define SPOT_COUNT 5 #define SPOT_LIMIT 1 static int MouseX, MouseY, MouseB; static int Window; static float Rotate[16], Scale; static GLuint MushroomObjR, MushroomObjW; static int ShowObjR, ShowObjW; static float SpotX[SPOT_COUNT]; static float SpotY[SPOT_COUNT]; static float SpotZ[SPOT_COUNT]; static float SpotR[SPOT_COUNT]; static void Curve(float *cx, float *cy, float *ox, float *oy); static void Display(void); static void IdentityMatrix(float *m); static void Init(void); static void Keyboard(unsigned char c, int u, int v); static void Menu(int action); static void MouseButton(int button, int state, int x, int y); static void MouseMotion(int x, int y); static void MultMatrix(float *m0, float *m1); static void Mushroom(void); static void MushroomQuad(float v[4][3], float *n, int inside); static void Reshape(int w, int h); static void RotateView(int dx, int dy); static float SpotDistance(float *v); /******************************************************************** main */ int main(int argc, char **argv) { glutInit(&argc, argv); Init(); glutMainLoop(); return 0; } /* main() */ /******************************************************************* Curve */ static void Curve(float *cx, float *cy, float *ox, float *oy) { float p1, p2, p3, p4, q1, q2, q3, q4; float c1, c2, c3; int i; /* 4th degree polynomial curve */ for(i = 0; i < CURVE_RESOLUTION; i++) { p1 = 1 - (q1 = ((float)i) / (CURVE_RESOLUTION - 1)); p4 = p1 * (p3 = p1 * (p2 = p1 * p1)); q4 = q1 * (q3 = q1 * (q2 = q1 * q1)); ox[i] = cx[0] * p4 + cx[1] * (c1 = p3 * q1 * 4) + cx[2] * (c2 = p2 * q2 * 6) + cx[3] * (c3 = p1 * q3 * 4) + cx[4] * q4; oy[i] = cy[0] * p4 + cy[1] * c1 + cy[2] * c2 + cy[3] * c3 + cy[4] * q4; } } /* Curve() */ /***************************************************************** Display */ static void Display(void) { static GLfloat position[4] = {50.0f, 50.0f, 100.0f, 0.0f}; static GLfloat direction[4] = {-1.0f, -1.0f, -1.0f, 0.0f}; GLfloat dw, dh; int width, height; glutSetWindow(Window); glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glViewport(0, 0, width = glutGet(GLUT_WINDOW_WIDTH), height = glutGet(GLUT_WINDOW_HEIGHT)); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if( width > height ) { dw = ((GLfloat)(WINDOW_SCALE * width)) / (2 * height); dh = ((GLfloat)(WINDOW_SCALE)) / 2; } else { dw = ((GLfloat)(WINDOW_SCALE)) / 2; dh = ((GLfloat)(WINDOW_SCALE * height)) / (2 * width); } glOrtho(-dw, dw, -dh, dh, ORTHO_NEAR, ORTHO_FAR); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glShadeModel(GL_FLAT); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction); gluLookAt(0.0, 0.0, -100.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); glMultMatrixf(Rotate); glScalef(Scale, Scale, Scale); if( ShowObjR ) glCallList(MushroomObjR); if( ShowObjW ) glCallList(MushroomObjW); glutSwapBuffers(); glFlush(); } /* Display() */ /********************************************************** IdentityMatrix */ static void IdentityMatrix(float *m) { m[ 0] = m[ 5] = m[10] = m[15] = 1.0f; m[ 1] = m[ 2] = m[ 3] = m[ 4] = m[ 6] = m[ 7] = m[ 8] = m[ 9] = m[11] = m[12] = m[13] = m[14] = 0.0f; } /* IdentityMatrix() */ /******************************************************************** Init */ static void Init(void) { srand((unsigned)time(NULL)); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(WINDOW_POS_X, WINDOW_POS_Y); glutSetWindow(Window = glutCreateWindow("Mushroom")); glutDisplayFunc(Display); glutKeyboardFunc(Keyboard); glutMouseFunc(MouseButton); glutMotionFunc(MouseMotion); glutReshapeFunc(Reshape); glutCreateMenu(Menu); glutAddMenuEntry("[r] Regenerate", 'r'); glutAddMenuEntry("[1] Toggle object 1", '1'); glutAddMenuEntry("[2] Toggle object 2", '2'); glutAddMenuEntry("[q] Quit", 'q'); glutAttachMenu(GLUT_MIDDLE_BUTTON); IdentityMatrix(Rotate); Scale = INIT_SCALE; MouseX = MouseY = MouseB = 0; ShowObjR = ShowObjW = 1; MushroomObjR = glGenLists(1); MushroomObjW = glGenLists(1); Mushroom(); } /* Init() */ /**************************************************************** Keyboard */ static void Keyboard(unsigned char c, int u, int v) { switch( c ) { case 'q': glDeleteLists(MushroomObjR, 1); glDeleteLists(MushroomObjW, 1); exit(EXIT_SUCCESS); case '1': ShowObjR = !ShowObjR; break; case '2': ShowObjW = !ShowObjW; break; case 'r': Mushroom(); break; default: break; } glutSetWindow(Window); glutPostRedisplay(); } /* Keyboard() */ /******************************************************************** Menu */ static void Menu(int action) { Keyboard((unsigned char)action, 0, 0); } /* Menu() */ /************************************************************* MouseButton */ static void MouseButton(int button, int state, int x, int y) { MouseX = x; MouseY = y; MouseB = (state == GLUT_DOWN) ? button : -1; } /* MouseButton() */ /************************************************************* MouseMotion */ static void MouseMotion(int x, int y) { int dx, dy; dx = x - MouseX; dy = MouseY - y; MouseX = x; MouseY = y; if( MouseB == GLUT_LEFT_BUTTON ) { RotateView(dx, dy); } else if( MouseB == GLUT_RIGHT_BUTTON ) { Scale += (dx + dy) * DELTA_SCALE; if( Scale < MIN_SCALE ) Scale = MIN_SCALE; if( Scale > MAX_SCALE ) Scale = MAX_SCALE; } glutSetWindow(Window); glutPostRedisplay(); } /* MouseMotion() */ /************************************************************** MultMatrix */ static void MultMatrix(float *m0, float *m1) { float r[16], cell; int i, j, k; for(i = 0; i < 16; i += 4) { for(j = 0; j < 4; j++) { cell = 0; for(k = 0; k < 4; k++) cell += m0[i + k] * m1[k * 4 + j]; r[i + j] = cell; } } for(i = 0; i < 16; i++) m0[i] = r[i]; } /* MultMatrix() */ /**************************************************************** Mushroom */ static void Mushroom(void) { static GLfloat ambient[4] = {0.5f, 0.5f, 0.5f, 1.0f}; static GLfloat diffuse[4] = {0.5f, 0.5f, 0.5f, 1.0f}; static GLfloat ambientw[4] = {0.5f, 0.5f, 0.5f, 1.0f}; static GLfloat diffusew[4] = {1.0f, 1.0f, 1.0f, 1.0f}; static GLfloat specular[4] = {1.0f, 1.0f, 1.0f, 1.0f}; float pr[2][CURVE_RESOLUTION], py[2][CURVE_RESOLUTION]; float nr[2][CURVE_RESOLUTION - 1], ny[2][CURVE_RESOLUTION - 1]; float cr1[5], cy1[5], cr2[5], cy2[5]; float v[4][3], n[3]; float a, na, b, h, s, l; int i, j; #define Rand() (((float)(rand() & 1023)) / 1023.0) /* Randomize curve control points */ cr1[0] = cr2[4] = 0; cr1[4] = cr2[0] = 1; cy1[0] = 5; cy1[4] = cy2[0] = -0.7; cy2[4] = -5; cr1[1] = 2.5 * Rand() + 1; cy1[1] = 5; cr1[2] = 3.5 * Rand() + 7; cy1[2] = 2.3 * Rand() + 0.7; cr1[3] = 4.5 * Rand() + 2.5; cy1[3] = -2.6 * Rand() - 0.7; cr2[1] = 1.3 * Rand(); cy2[1] = -1.2 * Rand() - 0.7; cr2[2] = cr2[1] * Rand() + 2; cy2[2] = 1.2 * Rand() - 5; cr2[3] = 0.5 * Rand() + 1.2; cy2[3] = -5; cr2[1] += 2; /* Create profile curve points for surface of revolution */ Curve(cr1, cy1, pr[0], py[0]); Curve(cr2, cy2, pr[1], py[1]); /* Compute normals */ for(i = 0; i < 2; i++) { for(j = 0; j < CURVE_RESOLUTION - 1; j++) { nr[i][j] = py[i][j] - py[i][j + 1]; ny[i][j] = pr[i][j + 1] - pr[i][j]; } } /* Set color (HSV) */ h = 6 * Rand(); s = 0.4 * Rand() + 0.2; l = 0.6 * Rand() + 0.4; i = (int)floor(h); h -= i; a = l * (1 - s); b = l * (1 - s * h); h = l * (1 - s * (1 - h)); switch( i ) { case 0: diffuse[0] = l; diffuse[1] = h; diffuse[2] = a; break; case 1: diffuse[1] = b; diffuse[2] = l; diffuse[0] = a; break; case 2: diffuse[2] = a; diffuse[0] = l; diffuse[1] = h; break; case 3: diffuse[0] = a; diffuse[1] = b; diffuse[2] = l; break; case 4: diffuse[1] = h; diffuse[2] = a; diffuse[0] = l; break; default: diffuse[2] = l; diffuse[0] = a; diffuse[1] = b; break; } /* Select spot location from vertices with upward normals */ for(i = 0; i < SPOT_COUNT; i++) { do { j = rand() % (CURVE_RESOLUTION - 1); } while( ny[0][j] < 0 ); a = (2 * i * PI) / SPOT_COUNT; SpotR[i] = 2.5 * Rand() + 0.5; SpotX[i] = pr[0][j] * cos(a); SpotY[i] = py[0][j]; SpotZ[i] = pr[0][j] * sin(a); } /* Colored polys */ glNewList(MushroomObjR, GL_COMPILE); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); for(i = 0; i < REVOLVE_RESOLUTION; i++) { a = (PI * (2 * i)) / REVOLVE_RESOLUTION; b = (PI * (2 * (i + 1))) / REVOLVE_RESOLUTION; na = a + PI / REVOLVE_RESOLUTION; for(j = 0; j < CURVE_RESOLUTION - 1; j++) { v[0][0] = pr[0][j] * cos(a); v[0][1] = py[0][j]; v[0][2] = pr[0][j] * sin(a); v[1][0] = pr[0][j] * cos(b); v[1][1] = py[0][j]; v[1][2] = pr[0][j] * sin(b); v[2][0] = pr[0][j + 1] * cos(b); v[2][1] = py[0][j + 1]; v[2][2] = pr[0][j + 1] * sin(b); v[3][0] = pr[0][j + 1] * cos(a); v[3][1] = py[0][j + 1]; v[3][2] = pr[0][j + 1] * sin(a); n[0] = nr[0][j] * cos(na); n[1] = ny[0][j]; n[2] = nr[0][j] * sin(na); MushroomQuad(v, n, 0); } } glEndList(); /* White polys */ glNewList(MushroomObjW, GL_COMPILE); glLightfv(GL_LIGHT0, GL_AMBIENT, ambientw); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffusew); glLightfv(GL_LIGHT0, GL_SPECULAR, specular); /* Spots */ for(i = 0; i < REVOLVE_RESOLUTION; i++) { a = (PI * (2 * i)) / REVOLVE_RESOLUTION; b = (PI * (2 * (i + 1))) / REVOLVE_RESOLUTION; na = a + PI / REVOLVE_RESOLUTION; for(j = 0; j < CURVE_RESOLUTION - 1; j++) { v[0][0] = pr[0][j] * cos(a); v[0][1] = py[0][j]; v[0][2] = pr[0][j] * sin(a); v[1][0] = pr[0][j] * cos(b); v[1][1] = py[0][j]; v[1][2] = pr[0][j] * sin(b); v[2][0] = pr[0][j + 1] * cos(b); v[2][1] = py[0][j + 1]; v[2][2] = pr[0][j + 1] * sin(b); v[3][0] = pr[0][j + 1] * cos(a); v[3][1] = py[0][j + 1]; v[3][2] = pr[0][j + 1] * sin(a); n[0] = nr[0][j] * cos(na); n[1] = ny[0][j]; n[2] = nr[0][j] * sin(na); MushroomQuad(v, n, 1); } } /* Stem */ for(i = 0; i < REVOLVE_RESOLUTION; i++) { a = (PI * (2 * i)) / REVOLVE_RESOLUTION; b = (PI * (2 * (i + 1))) / REVOLVE_RESOLUTION; na = a + PI / REVOLVE_RESOLUTION; glBegin(GL_QUADS); for(j = 0; j < CURVE_RESOLUTION - 1; j++) { glNormal3d(nr[1][j] * cos(na), ny[1][j], nr[1][j] * sin(na)); glVertex3d(pr[1][j] * cos(a), py[1][j], pr[1][j] * sin(a)); glVertex3d(pr[1][j] * cos(b), py[1][j], pr[1][j] * sin(b)); glVertex3d(pr[1][j + 1] * cos(b), py[1][j + 1], pr[1][j + 1] * sin(b)); glVertex3d(pr[1][j + 1] * cos(a), py[1][j + 1], pr[1][j + 1] * sin(a)); } glEnd(); } glEndList(); } /* Mushroom() */ /************************************************************ MushroomQuad */ static void MushroomQuad(float v[4][3], float *n, int inside) { static int vtranslate[5] = {0, 1, 2, 0, 3}; float s[4], iv[4][3], t; int i, a, b; /* Marching squares */ for(i = 0; i < 4; i++) s[i] = SpotDistance(v[i]); for(i = a = b = 0; i < 4; i++) { if( s[(i + 1) % 4] != s[i] ) { t = (SPOT_LIMIT - s[i]) / (s[(i + 1) % 4] - s[i]); if( t >= 0 && t <= 1 ) { iv[a][0] = v[i][0] + t * (v[(i + 1) % 4][0] - v[i][0]); iv[a][1] = v[i][1] + t * (v[(i + 1) % 4][1] - v[i][1]); iv[a][2] = v[i][2] + t * (v[(i + 1) % 4][2] - v[i][2]); a++; b |= 1 << i; } } } switch( b ) { case 5: case 10: /* 2 intersections (opposite edge) */ if( s[0] > SPOT_LIMIT ) inside = !inside; i = ~b & 1; glBegin(GL_QUADS); glNormal3fv(n); if( inside ) { glVertex3fv(v[(i + 3) % 4]); glVertex3fv(v[i]); glVertex3fv(iv[0]); glVertex3fv(iv[1]); } else { glVertex3fv(v[i + 1]); glVertex3fv(v[i + 2]); glVertex3fv(iv[1]); glVertex3fv(iv[0]); } glEnd(); break; case 3: case 6: case 9: case 12: /* 2 intersections (adjacent edge) */ if( s[i = vtranslate[b / 3]] > SPOT_LIMIT ) inside = !inside; if( i == 0 ) { a = 0; b = 1; } else { a = 1; b = 0; } glBegin(GL_TRIANGLE_FAN); glNormal3fv(n); if( inside ) { glVertex3fv(v[i]); glVertex3fv(iv[a]); glVertex3fv(iv[b]); } else { glVertex3fv(v[(i + 1) % 4]); glVertex3fv(v[(i + 2) % 4]); glVertex3fv(v[(i + 3) % 4]); glVertex3fv(iv[b]); glVertex3fv(iv[a]); } glEnd(); break; case 15: /* 4 intersections */ t = (s[0] + s[1] + s[2] + s[3]) / 4; if( s[0] > SPOT_LIMIT ) inside = !inside; if( inside ) { if( s[0] < t && s[3] < t ) { glBegin(GL_TRIANGLES); glNormal3fv(n); glVertex3fv(v[0]); glVertex3fv(iv[0]); glVertex3fv(iv[3]); glVertex3fv(v[2]); glVertex3fv(iv[2]); glVertex3fv(iv[1]); glEnd(); } else { glBegin(GL_QUAD_STRIP); glNormal3fv(n); glVertex3fv(iv[0]); glVertex3fv(iv[1]); glVertex3fv(v[0]); glVertex3fv(v[2]); glVertex3fv(iv[3]); glVertex3fv(iv[2]); glEnd(); } } else { if( s[0] < t && s[3] < t ) { glBegin(GL_QUAD_STRIP); glNormal3fv(n); glVertex3fv(iv[1]); glVertex3fv(iv[2]); glVertex3fv(v[1]); glVertex3fv(v[3]); glVertex3fv(iv[0]); glVertex3fv(iv[3]); glEnd(); } else { glBegin(GL_TRIANGLES); glNormal3fv(n); glVertex3fv(v[1]); glVertex3fv(iv[1]); glVertex3fv(iv[0]); glVertex3fv(v[3]); glVertex3fv(iv[3]); glVertex3fv(iv[2]); glEnd(); } } break; default: /* Completely filled square */ if( s[0] > SPOT_LIMIT ) inside = !inside; if( inside ) { glBegin(GL_QUADS); glNormal3fv(n); for(i = 0; i < 4; glVertex3fv(v[i++])); glEnd(); } break; } } /* MushroomQuad() */ /***************************************************************** Reshape */ static void Reshape(int w, int h) { glutSetWindow(Window); glutPostRedisplay(); } /* Reshape() */ /************************************************************** RotateView */ static void RotateView(int dx, int dy) { float r[16]; IdentityMatrix(r); r[0] = r[10] = (float)cos(dx * DELTA_ROTATE); r[2] = -(r[8] = (float)sin(dx * DELTA_ROTATE)); MultMatrix(Rotate, r); IdentityMatrix(r); r[5] = r[10] = (float)cos(dy * DELTA_ROTATE); r[9] = -(r[6] = (float)sin(dy * DELTA_ROTATE)); MultMatrix(Rotate, r); } /* RotateView() */ /************************************************************ SpotDistance */ static float SpotDistance(float *v) { float dx, dy, dz, s, r; int i; r = 9999.0f; for(i = 0; i < SPOT_COUNT; i++) { dx = SpotX[i] - v[0]; dy = SpotY[i] - v[1]; dz = SpotZ[i] - v[2]; s = (dx * dx + dy * dy + dz * dz) / SpotR[i]; if( s < r ) r = s; } return r; } /* SpotDistance() */