/* Tutor intended to teach the fundamentals of materials and lighting. Based on lightmaterial tutorial by Nate Robins. Written by Caroline Geiersbach and Scott D. Anderson scott.anderson@acm.org Summer 2003 */ #include #include #include #include #include #include #define GAP 25 //gap between subwindows int cWinWidth = 537; //command window width int cWinHeight = 537; //command window height int mWinWidth = GAP*4+256*3; //main window width int mWinHeight = GAP*3+256*2; //main window height //colors used in program twTriple white = {1,1,1}; twTriple cyan = {0,1,1}; twTriple gray = {0.8,0.8,0.8}; twTriple green = {0.8,1,0.6}; //cells are used in the command window; each cell has an id; a //raster location at x,y; min and max values; a current value; the //step for adjusting values; info on what the cell specifies; and //finally the format of the printed values. typedef struct _cell { int id; int x, y; GLfloat min, max; GLfloat value; GLfloat step; char* info; char* format; } cell; cell lightPosition[4] = { { 1, 225, 100, -5.0, 5.0, 3.0, 0.05, "Specifies X coordinate of light vector.", "%.2f" }, { 2, 285, 100, -5.0, 5.0, 0.0, 0.05, "Specifies Y coordinate of light vector.", "%.2f" }, { 3, 345, 100, -5.0, 5.0, 2.0, 0.05, "Specifies Z coordinate of light vector.", "%.2f" }, { 4, 405, 100, 0.0, 1.0, 1.0, 1.0, "Specifies directional (0) or positional (1) light.", "%.2f" }, }; cell lightAmbient[4] = { { 5, 225, 140, 0.0, 1.0, 0.5, 0.01, "Specifies red ambient component of the light.", "%.2f" }, { 6, 285, 140, 0.0, 1.0, 0.5, 0.01, "Specifies green ambient component of the light.", "%.2f" }, { 7, 345, 140, 0.0, 1.0, 0.5, 0.01, "Specifies blue ambient component of the light.", "%.2f" }, { 8, 405, 140, 0.0, 1.0, 1.0, 0.01, "Specifies ambient alpha intensity of the light.", "%.2f" }, }; cell lightDiffuse[4] = { { 9, 220, 180, 0.0, 1.0, 0.5, 0.01, "Specifies red diffuse component of the light.", "%.2f" }, { 10, 280, 180, 0.0, 1.0, 0.5, 0.01, "Specifies green diffuse component of the light.", "%.2f" }, { 11, 340, 180, 0.0, 1.0, 0.5, 0.01, "Specifies blue diffuse component of the light.", "%.2f" }, { 12, 400, 180, 0.0, 1.0, 1.0, 0.01, "Specifies diffuse alpha intensity of the light.", "%.2f" }, }; cell lightSpecular[4] = { { 13, 230, 220, 0.0, 1.0, 1.0, 0.01, "Specifies red specular component of the light.", "%.2f" }, { 14, 290, 220, 0.0, 1.0, 1.0, 0.01, "Specifies green specular component of the light.", "%.2f" }, { 15, 350, 220, 0.0, 1.0, 1.0, 0.01, "Specifies blue specular component of the light.", "%.2f" }, { 16, 410, 220, 0.0, 1.0, 1.0, 0.01, "Specifies specular alpha intensity of the light.", "%.2f" }, }; cell gAmbient[1] = { { 17, 115, 260, 0.0, 1.0, 0.3, 0.01, "Specifies global ambient light value.", "%.2f" }, }; cell material[5] = { { 21, 200, 300, 0.0, 1.0, 0.5, 0.01, "Specifies red component of the material.", "%.2f" }, { 22, 280, 300, 0.0, 1.0, 0.7, 0.01, "Specifies green component of the material.", "%.2f" }, { 23, 360, 300, 0.0, 1.0, 0.5, 0.01, "Specifies blue component of the material.", "%.2f" }, { 24, 180, 340, 0.0, 1.0, 0.7, 0.01, "Specifies specularity of the material.", "%.2f" }, { 25, 260, 340, 0.0, 128, 30.0, 1.0, "Specifies shininess of the material.", "%.2f" }, }; GLboolean savedDraw = GL_TRUE; GLint selection = 0; int old_y; //for command mouse //temp values for lighting and material GLfloat posTemp[4], lATemp[4], lDTemp[4], lSTemp[4], twCTemp[5]; GLfloat lGATemp = gAmbient[0].value; void redisplayAll(void); GLdouble projection[16], modelview[16], inverse[16]; GLuint window, adjustable, saved, command; void cellDraw(cell* cell) { twColor(white,0,0); //color of unselected numbers if (selection == cell->id) { twColor(cyan,0,0); //color of info text twDrawString(10, 20, cell->info); } twDrawString(cell->x, cell->y, cell->format, cell->value); } //returns cell id if cell has been clicked on; 0 otherwise int cellHit(cell* cell, int x, int y) { if (x > cell->x && x < cell->x+55 && y > cell->y-15 && y < cell->y+15){ return cell->id; } return 0; } //updates the cell's value void cellUpdate(cell* cell, int update) { if (selection != cell->id) return; cell->value += update * cell->step; //tests for min and max values of the points if (cell->value < cell->min) cell->value = cell->min; else if (cell->value > cell->max) cell->value = cell->max; } //converts values from cell to a destination vector void cellVector(GLfloat* dst, cell* cell, int num) { while (--num >= 0) dst[num] = cell[num].value; } void mainDisplay() { //set up camera to allow for window labeling glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0,mWinWidth,mWinHeight,0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(0.7, 0.7, 1.0, 0.0); //light blue background glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); twColorName(TW_BLACK); twSetFont("helvetica", 12); twDrawString(GAP,20, "Saved"); twDrawString(GAP,GAP+256+20, "Adjustable"); glutSwapBuffers(); } void adjustableLighting() { GLfloat pos[4], lA[4], lD[4], lS[4]; GLfloat twC[3], lGA[4]; //convert vals from cells to vectors cellVector(pos, lightPosition, 4); cellVector(lA, lightAmbient, 4); cellVector(lD, lightDiffuse, 4); cellVector(lS, lightSpecular, 4); //lighting glShadeModel(GL_SMOOTH); twAmbient(gAmbient[0].value); glLightfv(GL_LIGHT0, GL_POSITION, pos); glLightfv(GL_LIGHT0, GL_AMBIENT, lA); glLightfv(GL_LIGHT0, GL_DIFFUSE, lD); glLightfv(GL_LIGHT0, GL_SPECULAR, lS); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); } //display in the lower left (adjustable-space view) void adjustableDisplay() { twCamera(); glClearColor(0,0,0,1); //clear sub-window to black glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); adjustableLighting(); twTriple colorVal = {material[0].value, material[1].value, material[2].value}; twColor(colorVal, material[3].value,material[4].value); glutSolidTorus(0.25, 0.75, 28, 28); glDisable(GL_LIGHTING); glDisable(GL_LIGHT0); //draw line from light source to center of object glPushMatrix(); twColor(gray,0,0); glBegin(GL_LINE_STRIP); glVertex3f(0, 0, 0); glVertex3f(lightPosition[0].value, lightPosition[1].value, lightPosition[2].value); glEnd(); glPopMatrix(); glFlush(); glutSwapBuffers(); } void savedLighting() { //convert vals from cells to vectors if(savedDraw) { //get new values cellVector(posTemp, lightPosition, 4); cellVector(lATemp, lightAmbient, 4); cellVector(lDTemp, lightDiffuse, 4); cellVector(lSTemp, lightSpecular, 4); cellVector(twCTemp, material,5); lGATemp = gAmbient[0].value; } savedDraw = GL_FALSE; //lighting glShadeModel(GL_SMOOTH); twAmbient(lGATemp); glLightfv(GL_LIGHT1, GL_POSITION, posTemp); glLightfv(GL_LIGHT1, GL_AMBIENT, lATemp); glLightfv(GL_LIGHT1, GL_DIFFUSE, lDTemp); glLightfv(GL_LIGHT1, GL_SPECULAR, lSTemp); glEnable(GL_LIGHT1); glEnable(GL_LIGHTING); } //display in the upper left (saved-space view) void savedDisplay() { twCamera(); glClearColor(0,0,0,1); //clear sub-window to black glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); savedLighting(); twTriple colorVal2 = {twCTemp[0],twCTemp[1],twCTemp[2]}; twColor(colorVal2, twCTemp[3],twCTemp[4]); glutSolidTorus(0.25, 0.75, 28, 28); glDisable(GL_LIGHT0); glDisable(GL_LIGHTING); //draw line from light source to center of object glPushMatrix(); twColor(gray,0,0); glBegin(GL_LINE_STRIP); glVertex3f(0, 0, 0); glVertex3f(posTemp[0],posTemp[1],posTemp[2]); glEnd(); glPopMatrix(); glFlush(); glutSwapBuffers(); } //display on right side; where user can adjust values void commandDisplay() { //set up camera glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, cWinWidth, cWinHeight, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(0.0, 0.0, 0.0, 1.0); //clear to black glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); twSetFont("helvetica", 18); twDrawString(10, lightPosition[0].y, "GLfloat lightPosition[ ] = {"); twDrawString(10, lightAmbient[0].y, "GLfloat lightAmbient[ ] = {"); twDrawString(10, lightDiffuse[0].y, "GLfloat lightDiffuse[ ] = {"); twDrawString(10, lightSpecular[0].y, "GLfloat lightSpecular[ ] = {"); twDrawString(10, gAmbient[0].y, "twAmbient ("); twDrawString(10, material[0].y, "twTriple colorVals = ("); twDrawString(10, material[3].y, "twColor(colorVals,"); twDrawString(lightPosition[0].x+50, lightPosition[0].y, ","); twDrawString(lightPosition[1].x+50, lightPosition[1].y, ","); twDrawString(lightPosition[2].x+50, lightPosition[2].y, ","); twDrawString(lightPosition[3].x+50, lightPosition[3].y, "};"); twDrawString(lightAmbient[0].x+50, lightAmbient[0].y, ","); twDrawString(lightAmbient[1].x+50, lightAmbient[1].y, ","); twDrawString(lightAmbient[2].x+50, lightAmbient[2].y, ","); twDrawString(lightAmbient[3].x+50, lightAmbient[3].y, "};"); twDrawString(lightDiffuse[0].x+50, lightDiffuse[0].y, ","); twDrawString(lightDiffuse[1].x+50, lightDiffuse[1].y, ","); twDrawString(lightDiffuse[2].x+50, lightDiffuse[2].y, ","); twDrawString(lightDiffuse[3].x+50, lightDiffuse[3].y, "};"); twDrawString(lightSpecular[0].x+50, lightSpecular[0].y, ","); twDrawString(lightSpecular[1].x+50, lightSpecular[1].y, ","); twDrawString(lightSpecular[2].x+50, lightSpecular[2].y, ","); twDrawString(lightSpecular[3].x+50, lightSpecular[3].y, "};"); twDrawString(gAmbient[0].x+50, gAmbient[0].y, ");"); twDrawString(material[0].x+50, material[0].y, ","); twDrawString(material[1].x+50, material[1].y, ","); twDrawString(material[2].x+50, material[2].y, ");"); twDrawString(material[3].x+50, material[3].y, ","); twDrawString(material[4].x+60, material[4].y, ");"); //draw values of each cell cellDraw(&lightPosition[0]); cellDraw(&lightPosition[1]); cellDraw(&lightPosition[2]); cellDraw(&lightPosition[3]); cellDraw(&lightAmbient[0]); cellDraw(&lightAmbient[1]); cellDraw(&lightAmbient[2]); cellDraw(&lightAmbient[3]); cellDraw(&lightDiffuse[0]); cellDraw(&lightDiffuse[1]); cellDraw(&lightDiffuse[2]); cellDraw(&lightDiffuse[3]); cellDraw(&lightSpecular[0]); cellDraw(&lightSpecular[1]); cellDraw(&lightSpecular[2]); cellDraw(&lightSpecular[3]); cellDraw(&gAmbient[0]); cellDraw(&material[0]); cellDraw(&material[1]); cellDraw(&material[2]); cellDraw(&material[3]); cellDraw(&material[4]); if (!selection) { twColor(cyan,0,0); twDrawString(10, 20, "Click on the arguments and move the mouse to modify values."); } //directions at bottom of command window twDrawString(10,420, "Hit to save values,

to print saved values."); twDrawString(10,460, "Hit to reset adjustable to original values."); twDrawString(10,500, "Hit to reset adjustable to original view."); twColor(white,0,0); glutSwapBuffers(); } void commandMouse(int button, int state, int x, int y) { selection = 0; if(state == GLUT_DOWN) { /* mouse should only hit _one_ of the cells, so adding up all the hits just propagates a single hit. */ //lighting selection += cellHit(&lightPosition[0], x, y); selection += cellHit(&lightPosition[1], x, y); selection += cellHit(&lightPosition[2], x, y); selection += cellHit(&lightPosition[3], x, y); selection += cellHit(&lightAmbient[0], x, y); selection += cellHit(&lightAmbient[1], x, y); selection += cellHit(&lightAmbient[2], x, y); selection += cellHit(&lightAmbient[3], x, y); selection += cellHit(&lightDiffuse[0], x, y); selection += cellHit(&lightDiffuse[1], x, y); selection += cellHit(&lightDiffuse[2], x, y); selection += cellHit(&lightDiffuse[3], x, y); selection += cellHit(&lightSpecular[0], x, y); selection += cellHit(&lightSpecular[1], x, y); selection += cellHit(&lightSpecular[2], x, y); selection += cellHit(&lightSpecular[3], x, y); selection += cellHit(&gAmbient[0], x, y); selection += cellHit(&material[0], x, y); selection += cellHit(&material[1], x, y); selection += cellHit(&material[2], x, y); selection += cellHit(&material[3], x, y); selection += cellHit(&material[4], x, y); } old_y = y; redisplayAll(); } //allows for click and drag void commandMotion(int x, int y) { cellUpdate(&lightPosition[0], old_y-y); cellUpdate(&lightPosition[1], old_y-y); cellUpdate(&lightPosition[2], old_y-y); cellUpdate(&lightPosition[3], old_y-y); cellUpdate(&lightAmbient[0], old_y-y); cellUpdate(&lightAmbient[1], old_y-y); cellUpdate(&lightAmbient[2], old_y-y); cellUpdate(&lightAmbient[3], old_y-y); cellUpdate(&lightDiffuse[0], old_y-y); cellUpdate(&lightDiffuse[1], old_y-y); cellUpdate(&lightDiffuse[2], old_y-y); cellUpdate(&lightDiffuse[3], old_y-y); cellUpdate(&lightSpecular[0], old_y-y); cellUpdate(&lightSpecular[1], old_y-y); cellUpdate(&lightSpecular[2], old_y-y); cellUpdate(&lightSpecular[3], old_y-y); cellUpdate(&gAmbient[0], old_y-y); cellUpdate(&material[0], old_y-y); cellUpdate(&material[1], old_y-y); cellUpdate(&material[2], old_y-y); cellUpdate(&material[3], old_y-y); cellUpdate(&material[4], old_y-y); old_y = y; redisplayAll(); } void reset(unsigned char key, int x, int y) { switch(key) { case'R': lightPosition[0].value = 3; lightPosition[1].value = 0; lightPosition[2].value = 2; lightPosition[3].value = 1; lightAmbient[0].value = 0.5; lightAmbient[1].value = 0.5; lightAmbient[2].value = 0.5; lightAmbient[3].value = 1; lightDiffuse[0].value = 0.5; lightDiffuse[1].value = 0.5; lightDiffuse[2].value = 0.5; lightDiffuse[3].value = 1; lightSpecular[0].value = 1; lightSpecular[1].value = 1; lightSpecular[2].value = 1; lightSpecular[3].value = 1; gAmbient[0].value = 0.3; material[0].value = 0.5; material[1].value = 0.7; material[2].value = 0.5; material[3].value = 0.7; material[4].value = 30.0; break; case'r': glutSetWindow(adjustable); twZview(); glutSetWindow(saved); twZview(); break; } redisplayAll(); } void myKeyboard(unsigned char key, int x, int y) { switch(key) { case 'P': printf("your saved light and material values: \n"); printf("lightPosition[] = {%.2f,%.2f,%.2f,%.2f}\n", posTemp[0],posTemp[1],posTemp[2],posTemp[3]); printf("lightAmbient[] = {%.2f,%.2f,%.2f,%.2f}\n", lATemp[0],lATemp[1],lATemp[2],lATemp[3]); printf("lightDiffuse[] = {%.2f,%.2f,%.2f,%.2f}\n", lDTemp[0],lDTemp[1],lDTemp[2],lDTemp[3]); printf("lightSpecular[] = {%.2f,%.2f,%.2f,%.2f}\n", lSTemp[0],lSTemp[1],lSTemp[2],lSTemp[3]); printf("twAmbient(%.2f)\n",lGATemp); printf("colorVals = {%.2f,%.2f,%.2f}\n",twCTemp[0], twCTemp[1],twCTemp[2]); printf("twColor=(colorVals,%.2f,%.2f)\n", twCTemp[3],twCTemp[4]); break; case 'S': savedDraw = GL_TRUE; break; } redisplayAll(); } void keyInit() { twKeyCallback('R',reset,"resets back to original settings"); twKeyCallback('r',reset,"resets back to original view"); twKeyCallback('P',myKeyboard,"prints saved values"); twKeyCallback('S',myKeyboard,"saves current values"); } void redisplayAll(void) { glutSetWindow(saved); glutPostRedisplay(); glutSetWindow(command); glutPostRedisplay(); glutSetWindow(adjustable); glutPostRedisplay(); } void myInit() { twMainInit(); keyInit(); } int main(int argc, char** argv) { glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); glutInitWindowSize(mWinWidth, mWinHeight); glutInitWindowPosition(0, 0); glutInit(&argc, argv); //parent window window = glutCreateWindow("Light & Material Tutor"); glutDisplayFunc(mainDisplay); myInit(); //upper left sub-window saved = glutCreateSubWindow(window, GAP, GAP, 256, 256); twBoundingBox(-1,1,-1,1,-1,1); glutDisplayFunc(savedDisplay); myInit(); //right sub-window command = glutCreateSubWindow(window, GAP*2+256, GAP, cWinWidth,cWinHeight); glutDisplayFunc(commandDisplay); myInit(); glutMotionFunc(commandMotion); glutMouseFunc(commandMouse); //lower left sub-window adjustable = glutCreateSubWindow(window, GAP, GAP*2+256, 256, 256); twBoundingBox(-1,1,-1,1,-1,1); glutDisplayFunc(adjustableDisplay); myInit(); redisplayAll(); glutMainLoop(); return 0; }