/* g.c - Don Yang (uguu.org) OpenGL / Glut renderer. memusage/memprof reports that some memory allocated are not freed. Notably, I didn't do any calloc, so it's all done by glut. My program doesn't leak memory (you can see that by not defining USE_OPENGL), credit for all leaks goes to OpenGL/MesaGL/glut/whatever else. 07/15/01 */ #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include"g.h" #include"grid.h" #include"maze.h" #include"triangle.h" /* Maze states */ static Triangle **Triangles, *StartNode, *EndNode, *CurrentNode; static Vertex **Points; static Grid *Boundary; /* Render states */ static int Window, MazeObj, PathObj, PickObj; static int AntiAlias, RebuildPath; /* Local prototypes */ static void Display(void); static void GL_Edge(Triangle *triangle); static void GL_Goal(Triangle *triangle); static void GL_Path(Triangle *triangle); static void GL_Pick(Triangle *triangle); static void GL_ResetPath(Triangle *triangle); static void InitGraphics(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 int Pick(int x, int y); static void Quit(void); static void Reshape(int w, int h); /**************************************************************** RenderGL */ void RenderGL(Triangle **triangles, Vertex **points, Grid *grid) { Triangles = triangles; Points = points; Boundary = grid; InitGraphics(); glutMainLoop(); } /* RenderGL() */ /***************************************************************** Display */ static void Display(void) { glutSetWindow(Window); glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT); /* Set transformations */ glViewport(0, 0, glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(Boundary->minx, Boundary->maxx, Boundary->miny, Boundary->maxy); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Set quality */ if( AntiAlias ) { glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE); } else { glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); glBlendFunc(GL_ONE, GL_ZERO); } /* Static maze */ if( MazeObj ) { /* Draw path */ if( RebuildPath ) { if( PathObj == 0 ) PathObj = glGenLists(1); glNewList(PathObj, GL_COMPILE_AND_EXECUTE); Apply(*Triangles, GL_ResetPath); /* (triangle.c) */ if( CurrentNode != NULL ) { Solve(StartNode, CurrentNode); glColor3f(0.0f, 0.1f, 0.5f); glBegin(GL_TRIANGLES); Apply(*Triangles, GL_Path); glEnd(); } glEndList(); RebuildPath = 0; } else { glCallList(PathObj); } /* Draw maze over path */ glCallList(MazeObj); } else { glNewList(MazeObj = glGenLists(1), GL_COMPILE_AND_EXECUTE); /* Draw goal, also mark start and end nodes */ glBegin(GL_TRIANGLES); Apply(*Triangles, GL_Goal); glEnd(); /* Draw walls */ glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_LINES); Apply(*Triangles, GL_Edge); glEnd(); glEndList(); } glutSwapBuffers(); glFlush(); } /* Display() */ /***************************************************************** GL_Edge */ static void GL_Edge(Triangle *triangle) { if( triangle->flags & TRIANGLE_WALL1 ) { glVertex3d(triangle->v[Edge1[0]]->x, triangle->v[Edge1[0]]->y, 0.0f); glVertex3d(triangle->v[Edge2[0]]->x, triangle->v[Edge2[0]]->y, 0.0f); } if( triangle->flags & TRIANGLE_WALL2 ) { glVertex3d(triangle->v[Edge1[1]]->x, triangle->v[Edge1[1]]->y, 0.0f); glVertex3d(triangle->v[Edge2[1]]->x, triangle->v[Edge2[1]]->y, 0.0f); } if( triangle->flags & TRIANGLE_WALL3 ) { glVertex3d(triangle->v[Edge1[2]]->x, triangle->v[Edge1[2]]->y, 0.0f); glVertex3d(triangle->v[Edge2[2]]->x, triangle->v[Edge2[2]]->y, 0.0f); } } /* GL_Edge() */ /***************************************************************** GL_Goal */ static void GL_Goal(Triangle *triangle) { if( triangle->flags & TRIANGLE_GOAL ) { if( StartNode == NULL ) { StartNode = triangle; glColor3f(1.0f, 0.0f, 0.0f); } else { EndNode = triangle; glColor3f(0.0f, 1.0f, 0.0f); } glVertex3d(triangle->v[0]->x, triangle->v[0]->y, 0.0f); glVertex3d(triangle->v[1]->x, triangle->v[1]->y, 0.0f); glVertex3d(triangle->v[2]->x, triangle->v[2]->y, 0.0f); } } /* GL_Goal() */ /***************************************************************** GL_Path */ static void GL_Path(Triangle *triangle) { if( triangle->flags & TRIANGLE_PATH ) { glVertex3d(triangle->v[0]->x, triangle->v[0]->y, 0.0f); glVertex3d(triangle->v[1]->x, triangle->v[1]->y, 0.0f); glVertex3d(triangle->v[2]->x, triangle->v[2]->y, 0.0f); } } /* GL_Path() */ /***************************************************************** GL_Pick */ static void GL_Pick(Triangle *triangle) { glLoadName((GLuint)triangle); glBegin(GL_POLYGON); glVertex3d(triangle->v[0]->x, triangle->v[0]->y, 0.0f); glVertex3d(triangle->v[1]->x, triangle->v[1]->y, 0.0f); glVertex3d(triangle->v[2]->x, triangle->v[2]->y, 0.0f); glEnd(); } /* GL_Pick() */ /************************************************************ GL_ResetPath */ static void GL_ResetPath(Triangle *triangle) { triangle->flags &= ~TRIANGLE_PATH; } /* GL_ResetPath() */ /************************************************************ InitGraphics */ static void InitGraphics(void) { int m, width, height; StartNode = EndNode = CurrentNode = NULL; MazeObj = PickObj = PathObj = 0; /* Initialize window */ width = (int)(Boundary->maxx - Boundary->minx); height = (int)(Boundary->maxy - Boundary->miny); glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); glutInitWindowSize(width, height); glutInitWindowPosition(SCREEN_POS_X, SCREEN_POS_Y); Window = glutCreateWindow("maze"); glutSetWindowTitle("maze"); glutSetWindow(Window); /* Set callbacks */ glutDisplayFunc(Display); glutKeyboardFunc(Keyboard); glutMouseFunc(MouseButton); glutReshapeFunc(Reshape); /* Create menu */ m = glutCreateMenu(Menu); glutAddMenuEntry("[A] Toggle antialiasing", (int)'a'); glutAddMenuEntry("[Q] Quit", (int)'q'); glutAttachMenu(GLUT_RIGHT_BUTTON); glutAttachMenu(GLUT_MIDDLE_BUTTON); /* Set states */ glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glDisable(GL_ALPHA_TEST); glDisable(GL_DEPTH_TEST); glDisable(GL_NORMALIZE); glLineWidth(1.0f); AntiAlias = 0; } /* InitGraphics() */ /**************************************************************** Keyboard */ static void Keyboard(unsigned char c, int u, int v) { switch( tolower(c) ) { case 'a': AntiAlias = !AntiAlias; break; case 'q': Quit(); 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) { static GLuint pickbuffer[PICK_BUFFER_SIZE]; Triangle *node; glSelectBuffer(PICK_BUFFER_SIZE, pickbuffer); if( !Pick(x, y) ) { if( !Pick(x, y) ) { CurrentNode = NULL; return; } } node = (Triangle*)pickbuffer[3]; if( node != CurrentNode ) { CurrentNode = node; RebuildPath = 1; } glutSetWindow(Window); glutPostRedisplay(); } /* MouseButton() */ /******************************************************************** Pick */ static int Pick(int x, int y) { int width, height, viewport[4]; /* Initialize pick mode */ glRenderMode(GL_SELECT); glInitNames(); glPushName(0xffffffff); /* Set viewport */ glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); viewport[0] = viewport[1] = 0; viewport[2] = width = glutGet(GLUT_WINDOW_WIDTH); viewport[3] = height = glutGet(GLUT_WINDOW_HEIGHT); glViewport(0, 0, width, height); /* Set transformations */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPickMatrix((GLdouble)x, (GLdouble)(height - y), PICK_TOLERANCE, PICK_TOLERANCE, viewport); gluOrtho2D(Boundary->minx, Boundary->maxx, Boundary->miny, Boundary->maxy); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* Draw grid */ if( PickObj ) { glCallList(PickObj); } else { glNewList(PickObj = glGenLists(1), GL_COMPILE_AND_EXECUTE); Apply(*Triangles, GL_Pick); /* (triangle.c) */ glEndList(); } glFlush(); return glRenderMode(GL_RENDER); } /* Pick() */ /******************************************************************** Quit */ static void Quit(void) { if( PathObj ) glDeleteLists(PathObj, 1); if( MazeObj ) glDeleteLists(MazeObj, 1); if( PickObj ) glDeleteLists(PickObj, 1); DeleteTriangleList(Triangles); /* (triangle.c) */ DeleteVertexList(Points); /* (triangle.c) */ exit(EXIT_SUCCESS); } /* Quit() */ /***************************************************************** Reshape */ static void Reshape(int w, int h) { glutSetWindow(Window); glutPostRedisplay(); } /* Reshape() */