/* * OpenGL Maze Example * * by Stan Melax melax@bioware.com * (Nov 2003 adapted by Theo Verelst, theover@tiscali.nl) * * In this little demo the player navigates through a simple maze * using the arrow keys. The maze is defined by a 2D array where * each element in the array indicates solid or empty space. This * program wraps polygon (quad) walls around the solid space and * disallows the player to navigate into solid space during the demo. * Note that all the walls are limited to being 90 degrees to each * other - there are no "angled" features. The purpose of this * sample program is to show a beginning 3D game programmer some * things they can do. * * One other cool thing that this program does is that it constucts * a single quad strip to draw all the walls by doing a recursive * depth first search on the maze array data. * * Permission to execute this program, or look at the code is only * granted to those who do not like to sue other people :-) * Some of the window setup code was stolen from a simple Cosmo example. * OpenGL is a trademark of SGI. */ #include #include #include #include #include #include #include #include #define IDM_APPLICATION_EXIT (101) #define IDM_APPLICATION_TEXTURE (102) #define IDM_APPLICATION_BANK (103) HMENU hMENU; HWND hWND; HDC hDC; HGLRC hGLRC; int enablebank=0; int enabletexture =0; extern char inlin[]; extern int do_read(); extern int serv_main(); #define MAZE_HEIGHT (16) #define MAZE_WIDTH (16) // unfortunately due to the way the polygon walls are generated there // are restrictions on what the wall/maze data can look like. See below. char mazedata[MAZE_HEIGHT*16] = { "***************** * ** * *** * * ** ** * ** * * ** * * *********** *** ** * ** ***** *** ***** * * * ** ******* ** * * * * ** ***** **** * ** * * *** ** **** *** ** * * * ************** **" }; int wall(int x,int y) { // true if the region at x,y is solid space that // should be surrounded by other solid space or polygon walls return (x>=0 && y>=0 && x=1.0f) { p=0.0f; idlefunc = navmaze; } } int forward(float px,float py,float bf) { // this routine does wall collision detection // the inputs to this routine are: // - the desired location // - the minimum distance to wall allowed // changes: // - the player's x and y coordinates // returns: // - whether a wall caused change in target position // This is really easy with these walls that lie only on axes. // If the player collides into a wall at an angle he/she will // still slide along the wall - I hate programs where you stick // to the polygon and cant move until you back away from it. // This collision detection isn't perfect - if you're precise you // can jump through at a corner - but its tough. int x = ((int)player_x); int y = ((int)player_y); int h=0; // number of walls hit if((px> x+1.0f - bf) && wall(x+1,y)) { px = (float)(x)+1.0f-bf; h++; } if(py> y+1.0f-bf && wall(x,y+1)) { py = (float)(y)+1.0f-bf; h++; } if(px< x+bf && wall(x-1,y)) { px = (float)(x)+bf; h++; } if(py< y+bf && wall(x,y-1)) { py = (float)(y)+bf; h++; } player_x=px; player_y=py; return h; } void navmaze(HDC hDC) { // navigate through the maze and render it from the // players point of view. // Ideally updates to heading and position should be time dependant forward(player_x+player_m*player_s*(float)sin(player_h*3.14/180), player_y+player_m*player_s*(float)cos(player_h*3.14/180), 0.2f); player_h+=player_t; player_b = 3*player_b/4 + player_t/4; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glPushMatrix(); glRotatef(-90.0f,1.0f,0.0f,0.0f); if(enablebank) glRotatef(-player_b,0.0f,1.0f,0.0f); // add roll to viewpoint glRotatef(player_h,0.0f,0.0f,1.0f); glTranslatef(-player_x,-player_y,-0.5f); glCallList(walllist); // no need to draw the top since we're in the maze now glPopMatrix(); SwapBuffers(hDC); if(player_x>MAZE_WIDTH || player_y>MAZE_HEIGHT) { // start over idlefunc = spinmaze; } } void readtexture(){ unsigned char *image, ti; int rc, i, w,h; // the bitmap must be a 24 bit bmp file thats 128x128 // I think i mixed up red and blue componants - oh well :-) FILE *fp; w = 256; h = 256; fp = fopen("maze256.bmp","rb"); if(!fp) return; fseek(fp,54,SEEK_SET); image = (unsigned char *)malloc(w*h*3); assert(image); rc=fread(image,sizeof(unsigned char),w*h*3,fp); for (i=0; i0.0f) player_t = 0.0f; break; case VK_UP: player_s = 0.0f; break; case VK_DOWN: player_s = 0.0f; break; case VK_SHIFT: player_m = 1.0f; break; } break; default: break; } return DefWindowProc(hWND, message, wParam, lParam); } int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst, LPSTR lpszCmdLine, int nCmdShow) { char *className = "OpenGL"; char *winName = "Maze Example"; WNDCLASS winClass; MSG msg; int r; /* Define and register the window class */ winClass.style = CS_HREDRAW | CS_VREDRAW; winClass.lpfnWndProc = WinProc; winClass.cbClsExtra = 0; winClass.cbWndExtra = 0; winClass.hInstance = hCurrentInst; winClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = GetStockObject(WHITE_BRUSH); winClass.lpszMenuName = NULL; winClass.lpszClassName = className; RegisterClass(&winClass); /* create window */ hWND = CreateWindow(className, winName, WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, 0, 0, 600, 600, NULL, /* Parent window's handle */ NULL, /* Menu handle */ hCurrentInst, /* Instance handle */ NULL); /* No additional data */ /* add quit menu item */ hMENU = CreatePopupMenu(); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_EXIT, "Exit"); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_TEXTURE, "Add/Remove Texture"); AppendMenu(hMENU, MF_STRING, IDM_APPLICATION_BANK, "Add/Remove Banking"); ShowWindow(hWND, nCmdShow); UpdateWindow(hWND); serv_main(); /* process events */ while (1) { // oops, busy wait when no messages or idlefunc - ohwell if ( (r = do_read()) > 0) { /* printf("%s\n",&inlin[0]); */ sscanf(&inlin[0],"%f %f",&player_t, &player_s); } if(idlefunc)idlefunc(hDC); if(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE)){ if (GetMessage(&msg, NULL, 0, 0) != TRUE) { return msg.wParam; } TranslateMessage(&msg); DispatchMessage(&msg); } } }