/* newrobot.c + newfile.c -> newrobot version 0.2a (.1 is original bot) By: Andrew Wiles SSN: 215-15-5027 5/11/97 This is a modified version of Assignment 4's robot assignment It retains almost all of the functionality of the original robot, plus adds many more features. The only function lost is moving the camera around the object (it was taken out as it was the least useful function, and the right button was needed to add menus). The first thing noticeable is that it defaults to viewing int red-blue stereo. It also has multiple window support, wireframe and solid support, lighting and various shading models, and other controls. Menus support toggling many features, including cloneing windows, toggling wireframe/solid, and togling stereo. Menus are activated with the right mouse button. The middle and left mouse buttons are left the same. In addition, StControl functions are included, with allow adjustment of stereo parameters. All windows are locked in their stereo parameters, and in rotation. */ #include #include #include #include #include #include #include #include "newrobot.h" #include "glst.h" #include "glstrb.h" #include "stcontrol.h" robotptr obj; windowparam *windows; int numwindows = 0; static int shoulder = 0, elbow = 0, istate, ix, iy; static int camera = 0, ibutton; robotptr selpiece; /* Internal prototypes */ void display(void); void reshape(int, int); void keyboard(unsigned char, int, int); void mouse(int, int, int, int); void mousemove(int, int); void agvMakeAxesList(); void olddisplay(int); void clearlightprops(); void loadlightprops(lightstruct *); void loadmaterialprops(materialparam *); void SetMenu(); void HandleMenu(int); void SetMenu() { /* This function creates the glut menus for each function */ glutCreateMenu(HandleMenu); glutAddMenuEntry("Clone Window", CLONE); glutAddMenuEntry("Toggle Wire Frame / Solid", TOGGLEWS); glutAddMenuEntry("Toggle Stereo", TOGGLEST); glutAttachMenu(GLUT_RIGHT_BUTTON); } void HandleMenu(int sel) { /* This function handles the return from the glut menus for every window */ int win = glutGetWindow(); int i; for(i = 0; windows[i].glutnum != win; i++); switch(sel) { case CLONE: /* Create a clone of the present window */ windows = realloc(windows, sizeof(windowparam) * (numwindows + 1)); memcpy(&windows[numwindows], &windows[i], sizeof(windowparam)); windows[numwindows].glutnum = glutCreateWindow("Clone"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(mousemove); glutIdleFunc(StControlGlutIdleFunc); SetMenu(); numwindows++; glutPostRedisplay(); break; case TOGGLEWS: /* Toggle wireframe / solid mode */ windows[i].wire = !windows[i].wire; glutPostRedisplay(); break; case TOGGLEST: /* Toggle stereo for current window */ windows[i].stereo = !windows[i].stereo; glutPostRedisplay(); break; } return; } void init(void) { /* Initialize function called from main() */ glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); } void olddisplay(int j) { /* Display function */ int i; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* This loop was all that was added to make the stereo conversion */ while(glstLoopRender()) { glPushMatrix(); render(&i, obj); /* This function actually draws the robot */ renderbot(obj, GL_RENDER, j); glPopMatrix(); } glutSwapBuffers(); } void display(void) { /* Display function - redraws every window when redraw event is encountered. The reason for this is that none of the libraries are thread safe, and if one window were to start a redraw cycle while another was already redrawing it would be a huge mess */ int i, j; for(i = 0; i < numwindows; i++) { glutSetWindow(windows[i].glutnum); clearlightprops(); if(!windows[i].wire) { glShadeModel(windows[i].shade); glEnable(GL_DEPTH_TEST); for(j = 0; j < windows[i].lights; j++) { loadlightprops(&windows[i].light[j]); } } else { glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); } if(windows[i].stereo) { glstToggle(True); } else { glstToggle(False); } olddisplay(i); glFlush(); } } void clearlightprops() { /* Clear all lights */ glDisable(GL_LIGHT0); glDisable(GL_LIGHT1); glDisable(GL_LIGHT2); glDisable(GL_LIGHT3); glDisable(GL_LIGHT4); glDisable(GL_LIGHT5); glDisable(GL_LIGHT6); glDisable(GL_LIGHT7); } void loadlightprops(lightstruct *tmp) { /* Load the lighting properties for the given light */ glLightfv(tmp->gltag, GL_AMBIENT, (float *) &tmp->ambient); glLightfv(tmp->gltag, GL_DIFFUSE, (float *) &tmp->diffuse); glLightfv(tmp->gltag, GL_SPECULAR, (float *) &tmp->specular); glLightfv(tmp->gltag, GL_POSITION, (float *) &tmp->position); glLightfv(tmp->gltag, GL_SPOT_DIRECTION, (float *) &tmp->spot_direction); glLightf(tmp->gltag, GL_SPOT_EXPONENT, tmp->spot_exponent); glLightf(tmp->gltag, GL_SPOT_CUTOFF, tmp->spot_cutoff); glLightf(tmp->gltag, GL_CONSTANT_ATTENUATION, tmp->constant_attenuation); glLightf(tmp->gltag, GL_LINEAR_ATTENUATION, tmp->linear_attenuation); glEnable(GL_LIGHTING); glEnable(tmp->gltag); return; } void loadmaterialprops(materialparam *tmp) { /* Load the material properties for the given solid */ glMaterialfv(GL_FRONT, GL_AMBIENT, (float *) &tmp->ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, (float *) &tmp->diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, (float *) &tmp->specular); glMaterialf(GL_FRONT, GL_SHININESS, tmp->shininess); glMaterialfv(GL_FRONT, GL_EMISSION, (float *) &tmp->emission); return; } void renderbot(robotptr pres, GLenum mode, int j) { /* Function which renders the robot */ int i; glPushMatrix(); /* Translate to the attachment position */ glTranslatef(pres->attach.x, pres->attach.y, pres->attach.z); /* Apply any rotations */ glRotatef(pres->rotate.x, 1.0, 0.0, 0.0); glRotatef(pres->rotate.y, 0.0, 1.0, 0.0); glRotatef(pres->rotate.z, 0.0, 0.0, 1.0); /* Translate from the hotspot (the attachment) to the center to create the box */ glTranslatef(-pres->hotspot.x, -pres->hotspot.y, -pres->hotspot.z); glPushMatrix(); glScalef(pres->geom.vert[0].x, pres->geom.vert[0].y, pres->geom.vert[0].z); glColor3f(pres->color.x, pres->color.y, pres->color.z); /* Used for mouse handling */ if(mode == GL_SELECT) { glLoadName((GLint) pres); glutSolidCube(1.0); } else { if(windows[j].wire) { loadmaterialprops(&pres->mat); glutWireCube(1.0); } else if(!windows[j].wire) { glutSolidCube(1.0); } } glPopMatrix(); /* Recurse through all children */ for(i = 0; i < pres->attachm; i++) renderbot(pres->children[i], mode, j); glPopMatrix(); } void reshape(int w, int h) { /* Called if the window is resized - doesn't seem to work though */ /*float m[16]; int i;*/ glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(80.0, (GLfloat) w/ (GLfloat) h, 1.0, 200.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -5.0); glutPostRedisplay(); } void clearrot(robotptr pres) { /* Clear the rotation matricies - used to return to normal */ int i; pres->rotate.x = 0.0; pres->rotate.y = 0.0; pres->rotate.z = 0.0; for(i = 0; i < pres->attachm; i++) clearrot(pres->children[i]); } void keyboard(unsigned char key, int x, int y) { /* Keyboard handler - most functions here are archaic - the only ones that still do anything are t and T */ switch(key) { case 's': shoulder = (shoulder + 5) % 360; glutPostRedisplay(); break; case 'S': shoulder = (shoulder - 5) % 360; glutPostRedisplay(); break; case 'e': elbow = (elbow + 5) % 360; glutPostRedisplay(); break; case 'E': elbow = (elbow - 5) % 360; glutPostRedisplay(); break; case 'c': camera += 2; glutPostRedisplay(); break; case 'C': gluLookAt(0.0, 0.0, (GLfloat) -2, 0.0, 0.0, -100.0, 0.0, 1.0, 0.0); camera -= 2; glutPostRedisplay(); break; case 'T': clearrot(obj); case 't': glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(80.0, 1.0, 1.0, 200.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -5.0); glutPostRedisplay(); break; default: break; } } robotptr processHits(GLint hits, GLuint buffer[]) { /* Processes the mouse stuff - finds the active object using labeling */ unsigned int i, j; GLuint names, *ptr; int lowest = INT_MAX; int lowass = 0; int lowname; /* Process the hits */ if(hits == 0) return 0; ptr = (GLuint *) buffer; for(i = 0; i < hits; i++) { names = *ptr; ptr++; if(*ptr < lowest) { lowest = *ptr; lowass = i; } ptr++; if(*ptr < lowest) { lowest = *ptr; lowass = i; } ptr++; for(j = 0; j < names; j++) { if(i == lowass) lowname = *ptr; ptr++; } } /* The name is actually a pointer to the correct structure for the give piece */ return (robotptr) lowname; } void mouse(int button, int state, int x, int y) { /* The mouse handling function - sets up a labeled set of objects and finds when the mouse is inside a particular object */ GLint viewport[4]; /*GLdouble mvmatrix[16], projmatrix[16]; GLint realy; GLdouble wx, wy, wz; GLdouble nx, ny, nz; robotptr tmp;*/ static GLuint selectBuf[512]; GLint hits; if(state == GLUT_DOWN) { istate = TRUE; ibutton = button; ix = x; iy = y; if(button == GLUT_RIGHT_BUTTON) return; /* Set up the labeling */ glGetIntegerv(GL_VIEWPORT, viewport); glSelectBuffer(512, selectBuf); glRenderMode(GL_SELECT); glInitNames(); glPushName(0); glLoadName(0); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluPickMatrix((GLdouble) x, (GLdouble) (viewport[3] - y), 5.0, 5.0, viewport); gluPerspective(80.0, (GLfloat) viewport[2]/ (GLfloat) viewport[3], 1.0, 200.0); glMatrixMode(GL_MODELVIEW); /* Render the bot in select mode */ renderbot(obj, GL_SELECT, 0); glMatrixMode(GL_PROJECTION); glPopMatrix(); glFlush(); glMatrixMode(GL_MODELVIEW); hits = glRenderMode(GL_RENDER); selpiece = processHits(hits, selectBuf); return; } else if(state == GLUT_UP) { istate = FALSE; } } void mousemove(int x, int y) { /* Handles mouse motion */ if(!istate) return; if(ibutton == GLUT_LEFT_BUTTON) { /* Left button - rotation around the pivot point and the x and y axes */ if(!selpiece) return; glPushMatrix(); glLoadIdentity(); rotaterec((GLfloat) ix - x, 0.0, 1.0, 0.0, selpiece); rotaterec((GLfloat) iy - y, 1.0, 0.0, 0.0, selpiece); glPopMatrix(); ix = x; iy = y; glutPostRedisplay(); } if(ibutton == GLUT_MIDDLE_BUTTON) { /* Middle button - rotatin around the pivot point and the y and z axes */ if(!selpiece) return; glPushMatrix(); glLoadIdentity(); rotaterec((GLfloat) ix - x, 0.0, 1.0, 0.0, selpiece); rotaterec((GLfloat) iy - y, 0.0, 0.0, 1.0, selpiece); glPopMatrix(); ix = x; iy = y; glutPostRedisplay(); } /* if(ibutton == GLUT_RIGHT_BUTTON) { gluLookAt((GLdouble) ix - x, 0.0, (GLdouble) iy - y, (GLdouble) -(ix - x), 0.0, -100.0, 0.0, 1.0, 0.0); iy = y; ix = x; glutPostRedisplay(); } */ return; } void rotaterec(float theta, float x, float y, float z, robotptr pres) { /*GLdouble m[16];*/ static float itheta, ix, iy, iz; /*int i;*/ /* Rotate the object in pres by (theta, x, y, z) */ if(!itheta) { itheta = theta; ix = x; iy = y; iz = z; } /* Store the values for furture reference */ if(x > 0.0) pres->rotate.x = ((float)(((int)(pres->rotate.x + theta)) % 360)); if(y > 0.0) pres->rotate.y = ((float)(((int)(pres->rotate.y + theta)) % 360)); if(z > 0.0) pres->rotate.z = ((float)(((int)(pres->rotate.z + theta)) % 360)); } int main(int argc, char **argv) { /* Main function - sets up and calls appropriate functions */ /*float m[16];*/ int i=0; glstrbAutoRegister(); glstInit(GLSTRB); StControlInit(&argc, argv, STCONTROLGLUT); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_ACCUM); glutInitWindowSize(350, 300); glutInitWindowPosition(100, 100); if(argc <= 1) parse_robot("newrobot.disc"); else parse_robot(argv[1]); for(i = 0; i < numwindows; i++) { windows[i].glutnum = glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(mousemove); glutIdleFunc(StControlGlutIdleFunc); SetMenu(); } init(); glstToggle(True); glMatrixMode(GL_MODELVIEW); /* If there's a command line or not */ render(&i, obj); glutMainLoop(); return 0; }