/* We define this as a global so that we can initialize it in twMainInit. Furthermore, making it global also allows other TW functions to reference it, if desired. */ GLfloat GlobalAmbient = 0.3; // OpenGL default value is 0.2 void twAmbient(GLfloat value) { GlobalAmbient = value; GLfloat matGlobalAmbient [] = {GlobalAmbient,GlobalAmbient,GlobalAmbient}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT,matGlobalAmbient); } void twGrayLight(GLint lightId, GLfloat* pos, GLfloat a, GLfloat d, GLfloat s) { GLfloat lightColor[4] = {0, 0, 0, 1}; // the default if(lightId < GL_LIGHT0 || lightId >= GL_LIGHT0+GL_MAX_LIGHTS ) { printf("invalid light ID: %d\n",lightId); return; } if( pos[3] != 0.0 && pos[3] != 1.0 ) { fprintf(stderr,"w component of light position should be 0 or 1: %f\n", pos[3]); return; } if( !((0 <= a && a <= 1.0) && (0 <= d && d <= 1.0) && (0 <= s && s <= 1.0) ) ) { if( a < 0.0 ) fprintf(stderr,"ambient should be at least 0.0: %f\n", a); if( a > 1.0 ) fprintf(stderr,"ambient should be at most 1.0: %f\n", a); if( d < 0.0 ) fprintf(stderr,"diffuse should be at least 0.0: %f\n", d); if( d > 1.0 ) fprintf(stderr,"diffuse should be at most 1.0: %f\n", d); if( s < 0.0 ) fprintf(stderr,"specular should be at least 0.0: %f\n", s); if( s > 1.0 ) fprintf(stderr,"specular should be at most 1.0: %f\n", s); return; } twError(); // printf("%f %f %f %f\n",pos[0],pos[1],pos[2],pos[3]); glLightfv(lightId, GL_POSITION, pos); twError(); lightColor[0] = lightColor[1] = lightColor[2] = a; glLightfv(lightId, GL_AMBIENT, lightColor); twError(); lightColor[0] = lightColor[1] = lightColor[2] = d; glLightfv(lightId, GL_DIFFUSE, lightColor); twError(); lightColor[0] = lightColor[1] = lightColor[2] = s; glLightfv(lightId, GL_SPECULAR, lightColor); twError(); glEnable(lightId); if( Toggles[ LIGHTS ] ) { glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); if( pos[3] == 1.0 ) { // positional light glColor3f(a,d,s); // for lack of a better idea. glPointSize(5); glBegin(GL_POINTS); glVertex3fv(pos); glEnd(); } else if( pos[3] == 0.0 ) { // directional light glLineWidth(1); twTriple start, end, dir; twTripleCopy(dir,pos); // the light direction twVectorNormalize(dir); // unit length twVectorScale(dir,dir,OuterRadius); // long enough to leave the BB twPoint(end,BBCenter,dir); // compute end point twVectorScale(dir,dir,-1); // reverse it twPoint(start,BBCenter,dir); // compute starting point glBegin(GL_LINES); glColor3f(1,1,1); glVertex3fv(start); glColor3f(0,0,0); glVertex3fv(end); glEnd(); } else { printf("This light seems to be neither positional nor directional"); } glPopAttrib(); } } static bool lightCutoffOkay( GLfloat cutoff ) { return (0.0 <= cutoff && cutoff <= 90.0 ) || cutoff == 180.0; } static bool lightExponentOkay( GLfloat exponent ) { return (0.0 <= exponent && exponent <= 128 ); } void twGraySpotlight(GLint lightId, GLfloat* pos, GLfloat a, GLfloat d, GLfloat s, GLfloat* direction, GLfloat cutoff, GLfloat spot_exponent) { if( pos[3] == 0.0 ) { fprintf(stderr,"Spotlights shouldn't be directional: %f %f %f %f\n", pos[0], pos[1], pos[2], pos[3] ); return; } twGrayLight(lightId, pos, a, d, s); twError(); glLightfv(lightId, GL_SPOT_DIRECTION, direction); if( ! lightCutoffOkay(cutoff) ) { fprintf(stderr,"Spotlight cutoffs must be in [0,90] or equal to 180: %f\n", cutoff); return; } glLightf(lightId, GL_SPOT_CUTOFF, cutoff); if( ! lightExponentOkay(spot_exponent) ) { fprintf(stderr,"Spotlight exponents must be in [0,128]: %f\n", spot_exponent); return; } glLightf(lightId, GL_SPOT_EXPONENT, spot_exponent); twError(); GLfloat lightColor[4] = {0, 0, 0, 1}; // the default glEnable(lightId); if( Toggles[ LIGHTS ] ) { glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); // ideally, draw a cone at the light source, facing the correct // way. The technique should be to compute the cross product and // dot product between the vector of a conventional cone // (e.g. twCylinder) and the direction of the light, and then // rotate the coordinate system around that axis and at that // angle, then draw a cone. Let's see if it works. We'll use a // unit-high cone; scale the world if you want it bigger. twTriple before = { 0, 0, 1 }; twTriple axis; twCrossProduct(axis,before,direction); GLfloat angle = acos(twDot(before,direction))*(180/M_PI); const GLfloat coneHeight = 1; GLfloat coneTop = coneHeight*tan(cutoff*M_PI/180); #ifdef TW_DEBUG printf("angle is %f\n",angle); printf("axis is %f %f %f\n",axis[0],axis[1],axis[2]); #endif glPushMatrix(); glTranslatef(pos[0],pos[1],pos[2]); // move origin to light position glRotatef(angle,axis[0],axis[1],axis[2]); glColor3f(a,d,s); twCylinder(0,coneTop,coneHeight,8,1); glPopMatrix(); glPopAttrib(); } }