/* Example 4.3.translight.c: transparent cones to simulate moving spot-lights */ // by Jim X. Chen; May, 2001 #include #include #include #include #include #define ESC 27 #define SPACE 32 int Height=600, Width=600; int cnt=1, moonView=0; float O, A, B, C; float alpha=-30, beta=-30, gama=60, aalpha=1, abeta=1, agama=-2; int depth=2; static float vdata[6][3] = { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {-1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0} }; float white[] = { 1., 1., 1., 1.}; float whitish[] = { .6, .6, .6, 1.}; float black[] = { 0., 0., 0., 1.}; float blackish[] = { .2, .2, .2, 1.}; float red[] = { 1., 0., 0., 1.}; float redish[] = { .3, .0, .0, 1.}; float green[] = { 0., 1., 0., 1.}; float greenish[] = { .0, .3, .0, 1.}; float blue[] = { 0., 0., 1., 1.}; float blueish[] = { 0., 0., .3, 1.}; float cyan[] = { 0.0, 1.0, 1.0, 1.}; float magenta[] = { 1.0, 0.0, 1.0, 1.}; float yellow[] = { 1.0, 1.0, 0.0, 1.}; void normalize(float v[3]) { float d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); if (d == 0) { printf("zero length vector"); return; } v[0] /= d; v[1] /= d; v[2] /= d; } void drawSphereTriangle(float *v1, float *v2, float *v3) { glBegin(GL_TRIANGLES); glNormal3fv(v1); glVertex3fv(v1); glNormal3fv(v2); glVertex3fv(v2); glNormal3fv(v3); glVertex3fv(v3); glEnd(); } void drawConeSide(float *v1, float *v2, float *v3) { float v11[3], v22[3], v33[3]; int i; for (i=0; i<3; i++) { v11[i] = v1[i] + v3[i]; // normal for cone vertex 1 v22[i] = v2[i] + v3[i]; // normal for cone vertex 2 v33[i] = v11[i] + v22[i]; // normal for cone vertex 3 } glBegin(GL_TRIANGLES); glNormal3fv(v11); glVertex3fv(v1); glNormal3fv(v22); glVertex3fv(v2); glNormal3fv(v33); glVertex3fv(v3); glEnd(); } void ncrossprod(float v1[3], float v2[3], float v3[3]) { v3[0] = v1[1]*v2[2] - v1[2]*v2[1]; v3[1] = v1[2]*v2[0] - v1[0]*v2[2]; v3[2] = v1[0]*v2[1] - v1[1]*v2[0]; normalize(v3); } void drawBottom(float *v1, float *v2, float *v3) { float v12[3], v23[3], vb[3];// normal to the cone or cylinder bottom int i; for (i=0; i<3; i++) { // two edge vectors v12[i] = v2[i] - v1[i]; v23[i] = v3[i] - v2[i]; } ncrossprod(v12, v23, vb); // vb = normalized cross prod. of v12 X v23 glBegin(GL_TRIANGLES); glNormal3fv(vb); glVertex3fv(v1); glVertex3fv(v2); glVertex3fv(v3); glEnd(); } void subdivideSphere(float *v1, float *v2, float *v3, long depth) { float v12[3], v23[3], v31[3]; int i; if (depth == 0) { glColor3f(v1[0]*v1[0], v2[1]*v2[1], v3[2]*v3[2]); drawSphereTriangle(v1, v2, v3); return; } for (i = 0; i < 3; i++) { v12[i] = v1[i]+v2[i]; v23[i] = v2[i]+v3[i]; v31[i] = v3[i]+v1[i]; } normalize(v12); normalize(v23); normalize(v31); subdivideSphere(v1, v12, v31, depth - 1); subdivideSphere(v2, v23, v12, depth - 1); subdivideSphere(v3, v31, v23, depth - 1); subdivideSphere(v12, v23, v31, depth - 1); } void drawSphere(void) // draw a cone with z=height and bottom in xy plane { subdivideSphere(vdata[0], vdata[1], vdata[4], depth); subdivideSphere(vdata[0], vdata[4], vdata[3], depth); subdivideSphere(vdata[0], vdata[3], vdata[5], depth); subdivideSphere(vdata[0], vdata[5], vdata[1], depth); subdivideSphere(vdata[2], vdata[1], vdata[5], depth); subdivideSphere(vdata[2], vdata[5], vdata[3], depth); subdivideSphere(vdata[2], vdata[3], vdata[4], depth); subdivideSphere(vdata[2], vdata[4], vdata[1], depth); } void subdivideCone(float *v1, float *v2, int depth) { float v11[3], v22[3], v00[3] = {0, 0, 0}, v12[3]; int i; if (depth == 0) { glColor3f(v1[0]*v1[0], v1[1]*v1[1], v1[2]*v1[2]); for (i=0; i<3; i++) { v11[i] = v1[i]; v22[i] = v2[i]; } drawBottom(v22, v11, v00); // bottom cover of the cone v00[2] = 1; // height of the cone, the tip on z axis drawConeSide(v11, v22, v00); // side cover of the cone return; } for (i=0; i<3; i++) v12[i] = v1[i]+v2[i]; normalize(v12); subdivideCone(v1, v12, depth - 1); subdivideCone(v12, v2, depth - 1); } void drawCone(void) // draw a unit cone with center at the origin and bottom in xy plane { subdivideCone(vdata[0], vdata[1], depth); subdivideCone(vdata[1], vdata[2], depth); subdivideCone(vdata[2], vdata[3], depth); subdivideCone(vdata[3], vdata[0], depth); } void subdivideCylinder(float *v1, float *v2, int depth) { float v11[3], v22[3], v00[3] = {0, 0, 0}, v12[3]; int i; if (depth == 0) { glColor3f(v1[0]*v1[0], v1[1]*v1[1], v1[2]*v1[2]); for (i=0; i<3; i++) { v11[i] = v1[i]; v22[i] = v2[i]; } // the height of the cone along z axis v11[2] = v22[2] = 1; drawBottom(v2, v1, v00); // draw the cylinder bottom glBegin(GL_POLYGON); // draw the side rectangles of the cylinder glNormal3fv(v2); glVertex3fv(v2); glVertex3fv(v22); glNormal3fv(v1); glVertex3fv(v11); glVertex3fv(v1); glEnd(); v00[2] = 1; drawBottom(v11, v22, v00); // draw the other bottom return; } v12[0] = v1[0]+v2[0]; v12[1] = v1[1]+v2[1]; v12[2] = v1[2]+v2[2]; normalize(v12); subdivideCylinder(v1, v12, depth - 1); subdivideCylinder(v12, v2, depth - 1); } void drawCylinder(void) // draw a unit cylinder with bottom in xy plane { subdivideCylinder(vdata[0], vdata[1], depth); subdivideCylinder(vdata[1], vdata[2], depth); subdivideCylinder(vdata[2], vdata[3], depth); subdivideCylinder(vdata[3], vdata[0], depth); } drawColorCoord(float xlen, float ylen, float zlen) { // coordinate lines glBegin(GL_LINES); glMaterialfv(GL_FRONT, GL_EMISSION, red); glColor3f(1,0,0); glVertex3f(0,0,0); glVertex3f(0,0,zlen); glMaterialfv(GL_FRONT, GL_EMISSION, green); glColor3f(0,1,0); glVertex3f(0,0,0); glVertex3f(0,ylen, 0); glMaterialfv(GL_FRONT, GL_EMISSION, blue); glColor3f(0,0,1); glVertex3f(0,0,0); glVertex3f(xlen,0,0); glEnd(); // coordinate labels: X, Y, Z glPushMatrix(); glTranslatef(xlen,0.,0.); glScalef(xlen/Width,xlen/Width,1); glutStrokeCharacter(GLUT_STROKE_ROMAN, 'X'); glPopMatrix(); glPushMatrix(); glMaterialfv(GL_FRONT, GL_EMISSION, green); glColor3f(0,1,0); glTranslatef(0., ylen,0.); glScalef(ylen/Width,ylen/Width,1); glutStrokeCharacter(GLUT_STROKE_ROMAN, 'Y'); glPopMatrix(); glPushMatrix(); glMaterialfv(GL_FRONT, GL_EMISSION, red); glColor3f(1,0,0); glTranslatef(0., 0.,zlen); glScalef(zlen/Width,zlen/Width,1); glutStrokeCharacter(GLUT_STROKE_ROMAN, 'Z'); glPopMatrix(); glMaterialfv(GL_FRONT, GL_EMISSION, black); // turn emission off } myMaterialColor(float *myAmbient, float *myDiffuse, float *mySpecular, float *myEmission) { glMaterialfv(GL_FRONT, GL_AMBIENT, myAmbient); glMaterialfv(GL_FRONT, GL_DIFFUSE, myDiffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mySpecular); glMaterialfv(GL_FRONT, GL_EMISSION, myEmission); } void drawSolar(float E, float e, float M, float m) { float position[] = { 0., 0., 0., 1.}; float spot_direction[] = { -1., 0., 0., 1.}; float tred[] = { 1., 0., 0., .2}; float tgreen[] = { 0., 1., 0., .3}; float tblue[] = { 0., 0., 1., .2}; float tilt=30; float PI = 3.1415926; static float lightAngle, lightInc=1.0; // Global coordinates glLineWidth(2); drawColorCoord(Width/6, Width/6, Width/6); glPushMatrix(); glRotatef(e, 0.0, 1.0, 0.0); // rotating around the "sun"; proceed angle glRotatef(tilt, 0.0, 0.0, 1.0); // tilt angle glTranslatef(0., 1.5*E, .0); glPushMatrix(); glTranslatef(0., E, .0); glScalef(E,E,E); drawSphere(); glPopMatrix(); glPushMatrix(); glScalef(E/2,1.5*E,E/2); glRotatef(90, 1.0, 0.0, 0.0); // orient the cone drawCone(); glPopMatrix(); glTranslatef(0., E/2, .0); glRotatef(m, 0.0, 1.0, 0.); // 1st moon rotating around the "earth" glPushMatrix(); glTranslatef(1.5*M, 0., 0.); glLineWidth(1); drawColorCoord(Width/4, Width/4, Width/4); if (lightAngle > 60.0) lightInc = -1.0; else if (lightAngle < -60.0) lightInc = 1.0; lightAngle = lightAngle + lightInc; glRotatef(lightAngle, 0, 1, 0); glLightfv(GL_LIGHT1, GL_POSITION, position); glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,spot_direction); glLightf(GL_LIGHT1,GL_SPOT_CUTOFF,5.0); glEnable (GL_BLEND); glDepthMask (GL_FALSE); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPushMatrix(); myMaterialColor(red, red, red, red); glScalef(E/8,E/8,E/8); drawSphere(); glPopMatrix(); glScalef(1.5*M,1.5*M*tan(PI*5/180),1.5*M*tan(PI*5/180)); glTranslatef(-1.0, 0.0, 0.0); glRotatef(90, 0.0, 1.0, 0.0); // orient the cone myMaterialColor(tred, tred, tred, tred); drawCone(); glPopMatrix(); glRotatef(120, 0.0, 1.0, 0.); // 2nd moon rotating around the "earth" glPushMatrix(); glTranslatef(1.5*M, 0., 0.); drawColorCoord(Width/4, Width/4, Width/4); glRotatef(lightAngle, 0, 0, 1); glLightfv(GL_LIGHT2, GL_POSITION, position); glLightfv(GL_LIGHT2,GL_SPOT_DIRECTION,spot_direction); glLightf(GL_LIGHT2,GL_SPOT_CUTOFF,10.0); myMaterialColor(green, green, green, green); glPushMatrix(); glScalef(E/8,E/8,E/8); drawSphere(); glPopMatrix(); glScalef(1.5*M,1.5*M*tan(PI*10/180),1.5*M*tan(PI*10/180)); glTranslatef(-1.0, 0.0, 0.0); glRotatef(90, 0.0, 1.0, 0.0); // orient the cone myMaterialColor(tgreen, tgreen, tgreen, tgreen); drawCone(); glPopMatrix(); glRotatef(120, 0.0, 1.0, 0.); // 3rd moon rotating around the "earth" glTranslatef(1.5*M, 0., 0.); glRotatef(lightAngle, 0, 0, 1); glLightfv(GL_LIGHT3, GL_POSITION, position); glLightfv(GL_LIGHT3,GL_SPOT_DIRECTION,spot_direction); glLightf(GL_LIGHT3,GL_SPOT_CUTOFF,15.0); drawColorCoord(Width/4, Width/4, Width/4); myMaterialColor(blue, blue, blue, blue); glPushMatrix(); glScalef(E/8,E/8,E/8); drawSphere(); glPopMatrix(); glScalef(1.5*M,1.5*M*tan(PI*15/180),1.5*M*tan(PI*15/180)); glTranslatef(-1.0, 0.0, 0.0); glRotatef(90, 0.0, 1.0, 0.0); // orient the cone myMaterialColor(tblue, tblue, tblue, tblue); drawCone(); glMaterialfv(GL_FRONT, GL_EMISSION, black); // turn off emission glDepthMask (GL_TRUE); glDisable (GL_BLEND); glPopMatrix(); } drawArm(float End1, float End2) { float scale; scale = End2-End1; glPushMatrix(); glRotatef(90.0, 0.0, 1.0, 0.0); glScalef(scale/10.0, scale/10.0, scale); if (moonView) drawCylinder(); else { glTranslatef(0.0, 0.0, 0.5); drawSphere(); } glPopMatrix(); } static void drawRobot(float A, float B, float C, float alpha, float beta, float gama) { // Global coordinates glLineWidth(3); drawColorCoord(Width/4, Width/4, Width/4); myMaterialColor(blackish, whitish, white, black); glPushMatrix(); glRotatef (cnt, 0.0, 1.0, 0.0); glRotatef (alpha, 0.0, 0.0, 1.0); // R_z(alpha) is on top of the matrix stack drawArm (O, A); glTranslatef (A, 0.0, 0.0); glRotatef (beta, 0.0, 0.0, 1.0); // R_z(alpha)T_x(A)R_z(beta) is on top of the matrix stack drawArm (A, B); glTranslatef (B-A, 0.0, 0.0); glRotatef (gama, 0.0, 0.0, 1.0); // R_z(alpha)T_x(A)R_z(beta)T_x(B)R_z(gama) is on top of the matrix stack drawArm (B, C); // put the solar system at the end of the robot arm glTranslatef (C-B, 0.0, 0.0); drawSolar(Width/4, 2.5*cnt, Width/3, 1.5*cnt); glPopMatrix(); } void myLookat(float A, float B, float C, float alpha, float beta, float gama) { float alpha1=30; float E = Width/4, e = 2.5*cnt, M = Width/6, m = 1.5*cnt; glRotatef (-90., 0., 1., 0.); // camera facing the negative x axis glTranslatef(-M, 0., 0.); glRotatef(-m, 0.0, 1.0, 0.); // rotating around the "earth" glTranslatef(0., -E, 0.0); glRotatef(-alpha1, 0.0, 0.0, 1.0); // tilt angle glRotatef(-e, 0.0, 1.0, 0.0); // rotating around the "sun"; proceed angle glTranslatef (-C+B, 0.0, 0.0); glRotatef (-gama, 0.0, 0.0, 1.0); glTranslatef (-B+A, 0.0, 0.0); glRotatef (-beta, 0.0, 0.0, 1.0); glTranslatef (-A, 0., 0.); // at the end of A glRotatef (-alpha, 0.0, 0.0, 1.0); glRotatef (-cnt, 0.0, 1.0, 0.0); } void display(void) { cnt++; depth = (cnt/100) % 6; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (cnt % 60 == 0) aalpha = -aalpha; if (cnt % 60 == 0) abeta = -abeta; if (cnt % 60 == 0) agama = -agama; alpha+= aalpha; beta+= abeta; gama+= agama; if (cnt % 1000 < 500) moonView = 0; else moonView = 1; glPushMatrix(); if (moonView==1) myLookat(A, B, C, alpha, beta, gama); // look at the solar system from the moon point of view drawRobot(A, B, C, alpha, beta, gama); glPopMatrix(); glutSwapBuffers(); } init() { float position[] = { 0., 0., 1., 0.}; glEnable(GL_LIGHTING); glEnable(GL_NORMALIZE); glEnable(GL_CULL_FACE); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glEnable(GL_LIGHT2); glEnable(GL_LIGHT3); glLightfv(GL_LIGHT0, GL_POSITION, position); glLightfv(GL_LIGHT0, GL_AMBIENT, blackish); glLightfv(GL_LIGHT0, GL_DIFFUSE, blackish); glLightfv(GL_LIGHT0, GL_SPECULAR, black); glLightfv(GL_LIGHT1, GL_AMBIENT, redish); glLightfv(GL_LIGHT1, GL_DIFFUSE, red); glLightfv(GL_LIGHT1, GL_SPECULAR, red); glLightfv(GL_LIGHT2, GL_AMBIENT, greenish); glLightfv(GL_LIGHT2, GL_DIFFUSE, green); glLightfv(GL_LIGHT2, GL_SPECULAR, green); glLightfv(GL_LIGHT3, GL_AMBIENT, blueish); glLightfv(GL_LIGHT3, GL_DIFFUSE, blue); glLightfv(GL_LIGHT3, GL_SPECULAR, blue); glMaterialfv(GL_FRONT, GL_AMBIENT, blackish); glMaterialfv(GL_FRONT, GL_DIFFUSE, whitish); glMaterialfv(GL_FRONT, GL_SPECULAR, white); glMaterialf(GL_FRONT, GL_SHININESS, 100.0); } static void Reshape(int w, int h) { float zNear=w, zFar=4*w; glClearColor (0.0, 0.0, 0.0, 1.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); //initialize robot arm end pointions O = 0.0; A = (float) 4*w/8; B = (float) 7*w/8; C = (float) 9*w/8; glViewport (0, 0, w, h); // hardware set to use projection transformation matrix stack glMatrixMode (GL_PROJECTION); glLoadIdentity (); // glOrtho(-w, w, -h, h, -zNear, zFar); glFrustum(-w/2, w/2, -h/2, h/2, zNear, zFar); // hardware set to use model transformation matrix stack glMatrixMode (GL_MODELVIEW); glLoadIdentity (); glTranslatef (0., 0., -2.5*w); // the origin is at the center between znear and zfar } static void Key(unsigned char key, int x, int y) { switch (key) { case ESC: exit(0); case SPACE: glRotatef(1., 1., 1., 1.); glutIdleFunc(display); break; default: glutIdleFunc(NULL); } } int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(Width, Height); glutCreateWindow("Example: press SPACE & another key"); init(); glutKeyboardFunc(Key); glutReshapeFunc(Reshape); glutDisplayFunc(display); glutIdleFunc(display); glutMainLoop(); }