2 * Polygon Reduction Demo by Stan Melax (c) 1998
3 * Permission to use any of this code wherever you want is granted..
4 * Although, please do acknowledge authorship if appropriate.
6 * This module contains the window setup code, mouse input, timing
7 * routines, and that sort of stuff. The interesting modules
8 * to see are bunnygut.cpp and progmesh.cpp.
10 * The windows 95 specific code for this application was taken from
11 * an example of processing mouse events in an OpenGL program using
12 * the Win32 API from the www.opengl.org web site.
14 * Under Project->Settings, Link Options, General Category
16 * Opengl32.lib glu32.lib winmm.lib
17 * to the Object/Library Modules
19 * You will need have OpenGL libs and include files to compile this
20 * Go to the www.opengl.org web site if you need help with this.
24 #include <windows.h> /* must include this before GL/gl.h */
25 #include <GL/gl.h> /* OpenGL header file */
26 #include <GL/glu.h> /* OpenGL utilities header file */
28 #include <sys/types.h>
29 #include <sys/timeb.h>
35 // Functions and Variables from bunny module
36 extern void InitModel();
37 extern void RenderModel();
38 extern Vector model_position; // position of bunny
39 extern Quaternion model_orientation; // orientation of bunny
48 Vector MouseVector; // 3D direction mouse points
49 Vector OldMouseVector;
50 int MouseState=0; // true iff left button down
51 float ViewAngle=45.0f;
53 HDC hDC; /* device context */
54 HPALETTE hPalette = 0; /* custom palette (if needed) */
58 static int timeinit=0;
59 static int start,start2,current,last;
60 static int frame=0, frame2=0;
68 current=timeGetTime(); // found in winmm.lib
69 double dif=(double)(current-start)/CLOCKS_PER_SEC;
70 double rv = (dif)? (double)frame/(double)dif:-1.0;
71 if(dif>2.0 && frame >10) {
74 start2 = timeGetTime();
77 DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
79 DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
81 // if(DeltaT>1.0) DeltaT=1.0;
87 void ComputeMouseVector(){
88 OldMouseVector=MouseVector;
89 float spread = (float)tan(ViewAngle/2*3.14/180);
90 float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
91 float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
93 // v=UserOrientation *v;
98 Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
99 // Implement track ball functionality to spin stuf on the screen
100 // cop center of projection
101 // cor center of rotation
102 // dir1 old mouse direction
103 // dir2 new mouse direction
104 // pretend there is a sphere around cor. Then find the points
105 // where dir1 and dir2 intersect that sphere. Find the
106 // rotation that takes the first point to the second.
109 Vector nrml = cor - cop;
110 // since trackball proportional to distance from cop
111 float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f);
112 nrml = normalize(nrml);
113 float dist = -(nrml^cor);
114 Vector u= planelineintersection(nrml,dist,cop,cop+dir1);
118 if(m>1) {u=u*1.0f/m;}
120 u=u - (nrml * (float)sqrt(1-m*m));
122 Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
126 if(m>1) {v=v*1.0f/m;}
128 v=v - (nrml * (float)sqrt(1-m*m));
133 if(m>1)m=1; // avoid potential floating point error
134 Quaternion q(Vector(1.0f,0.0f,0.0f),0.0f);
135 if(m>0 && (angle=(float)asin(m))>3.14/180) {
136 axis = normalize(axis);
137 q=Quaternion(axis,angle);
143 // Change the orientation of the bunny according to mouse drag
144 Quaternion q=VirtualTrackBall(Vector(0,0,0),model_position,
145 OldMouseVector,MouseVector);
146 model_orientation=q*model_orientation;
149 void Reshape(int width, int height){
150 // called initially and when the window changes size
153 glViewport(0, 0, width, height);
154 glMatrixMode(GL_PROJECTION);
156 gluPerspective(ViewAngle, (float)width/height, 0.1, 50.0);
157 glMatrixMode(GL_MODELVIEW);
162 char buf[1024];buf[0]='\0';
163 sprintf(buf,"FPS: %5.2f ",FPS);
164 PostString(buf,0,-1,0);
168 // main drawing routine - called every frame
169 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
172 // camera at default (zero) position and orientation
179 SwapBuffers(hDC); /* nop if singlebuffered */
183 LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
185 static PAINTSTRUCT ps;
186 static GLboolean left = GL_FALSE; /* left button currently down? */
187 static GLboolean right = GL_FALSE; /* right button currently down? */
188 static int omx, omy, mx, my;
192 BeginPaint(hWnd, &ps);
196 Reshape(LOWORD(lParam), HIWORD(lParam));
197 PostMessage(hWnd, WM_PAINT, 0, 0);
201 case 27: /* ESC key */
208 /* if we don't set the capture we won't get mouse move
209 messages when the mouse moves outside the window. */
211 MouseX = LOWORD(lParam);
212 MouseY = HIWORD(lParam);
213 ComputeMouseVector();
218 MouseX = LOWORD(lParam);
219 MouseY = HIWORD(lParam);
220 if(MouseX & 1 << 15) MouseX -= (1 << 16);
221 if(MouseY & 1 << 15) MouseY -= (1 << 16);
222 ComputeMouseVector();
223 if(MouseState) SpinIt();
225 /* remember to release the capture when we are finished. */
230 MouseX = LOWORD(lParam);
231 MouseY = HIWORD(lParam);
232 /* Win32 is pretty braindead about the x, y position that
233 it returns when the mouse is off the left or top edge
234 of the window (due to them being unsigned). therefore,
235 roll the Win32's 0..2^16 pointer co-ord range to the
236 more amenable (and useful) 0..+/-2^15. */
237 if(MouseX & 1 << 15) MouseX -= (1 << 16);
238 if(MouseY & 1 << 15) MouseY -= (1 << 16);
239 ComputeMouseVector();
240 if(MouseState) SpinIt();
243 case WM_PALETTECHANGED:
244 if (hWnd == (HWND)wParam) break;
245 /* fall through to WM_QUERYNEWPALETTE */
246 case WM_QUERYNEWPALETTE:
248 UnrealizeObject(hPalette);
249 SelectPalette(hDC, hPalette, FALSE);
259 return DefWindowProc(hWnd, uMsg, wParam, lParam);
262 HWND CreateOpenGLWindow(char* title)
264 // make a double-buffered, rgba, opengl window
269 PIXELFORMATDESCRIPTOR pfd;
270 static HINSTANCE hInstance = 0;
272 /* only register the window class once - use hInstance as a flag. */
274 hInstance = GetModuleHandle(NULL);
276 wc.lpfnWndProc = (WNDPROC)WindowProc;
279 wc.hInstance = hInstance;
280 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
281 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
282 wc.hbrBackground = NULL;
283 wc.lpszMenuName = NULL;
284 wc.lpszClassName = "OpenGL";
286 if (!RegisterClass(&wc)) {
287 MessageBox(NULL, "RegisterClass() failed: "
288 "Cannot register window class.",
294 hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
295 WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
296 0,0,Width,Height, NULL, NULL, hInstance, NULL);
300 "CreateWindow() failed: Cannot create a window.",
307 /* there is no guarantee that the contents of the stack that become
308 the pfd are zeroed, therefore _make sure_ to clear these bits. */
309 memset(&pfd, 0, sizeof(pfd));
310 pfd.nSize = sizeof(pfd);
312 pfd.dwFlags = PFD_DRAW_TO_WINDOW
315 pfd.iPixelType = PFD_TYPE_RGBA;
319 pf = ChoosePixelFormat(hDC, &pfd);
321 MessageBox(NULL, "ChoosePixelFormat() failed: "
322 "Cannot find a suitable pixel format.",
327 if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
328 MessageBox(NULL, "SetPixelFormat() failed: "
329 "Cannot set format specified.", "Error", MB_OK);
333 DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
335 if (pfd.dwFlags & PFD_NEED_PALETTE ||
336 pfd.iPixelType == PFD_TYPE_COLORINDEX) {
338 n = 1 << pfd.cColorBits;
339 if (n > 256) n = 256;
341 lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
342 sizeof(PALETTEENTRY) * n);
343 memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
344 lpPal->palVersion = 0x300;
345 lpPal->palNumEntries = n;
347 GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
349 /* if the pixel type is RGBA, then we want to make an RGB ramp,
350 otherwise (color index) set individual colors. */
351 if (pfd.iPixelType == PFD_TYPE_RGBA) {
352 int redMask = (1 << pfd.cRedBits) - 1;
353 int greenMask = (1 << pfd.cGreenBits) - 1;
354 int blueMask = (1 << pfd.cBlueBits) - 1;
357 /* fill in the entries with an RGB color ramp. */
358 for (i = 0; i < n; ++i) {
359 lpPal->palPalEntry[i].peRed =
360 (((i >> pfd.cRedShift) & redMask) * 255)
362 lpPal->palPalEntry[i].peGreen =
363 (((i >> pfd.cGreenShift) & greenMask) * 255)
365 lpPal->palPalEntry[i].peBlue =
366 (((i >> pfd.cBlueShift) & blueMask) * 255)
368 lpPal->palPalEntry[i].peFlags = 0;
371 lpPal->palPalEntry[0].peRed = 0;
372 lpPal->palPalEntry[0].peGreen = 0;
373 lpPal->palPalEntry[0].peBlue = 0;
374 lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
375 lpPal->palPalEntry[1].peRed = 255;
376 lpPal->palPalEntry[1].peGreen = 0;
377 lpPal->palPalEntry[1].peBlue = 0;
378 lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
379 lpPal->palPalEntry[2].peRed = 0;
380 lpPal->palPalEntry[2].peGreen = 255;
381 lpPal->palPalEntry[2].peBlue = 0;
382 lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
383 lpPal->palPalEntry[3].peRed = 0;
384 lpPal->palPalEntry[3].peGreen = 0;
385 lpPal->palPalEntry[3].peBlue = 255;
386 lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
389 hPalette = CreatePalette(lpPal);
391 SelectPalette(hDC, hPalette, FALSE);
398 ReleaseDC(hDC, hWnd);
402 int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
403 LPSTR lpszCmdLine, int nCmdShow)
405 HGLRC hRC; /* opengl context */
406 HWND hWnd; /* window */
407 MSG msg; /* message */
409 // InitModel() initializes some data structures and
410 // does the progressive mesh polygon reduction algorithm
412 CalcFPSDeltaT(); // to time the algorithm
416 hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
417 if (hWnd == NULL) exit(1);
420 hRC = wglCreateContext(hDC);
421 wglMakeCurrent(hDC, hRC);
422 ShowWindow(hWnd, nCmdShow);
423 glEnable(GL_DEPTH_TEST);
425 PostString("Demo by Stan Melax (c)1998",5,-5,20);
426 PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
428 PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
429 sprintf(buf,"was executed in %5.3f seconds",DeltaT);
430 PostString(buf,2,1,6);
433 while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
434 if(GetMessage(&msg, hWnd, 0, 0)) {
435 TranslateMessage(&msg);
436 DispatchMessage(&msg);
438 // This 'goto' was in the sample code
447 wglMakeCurrent(NULL, NULL);
448 ReleaseDC(hDC, hWnd);
449 wglDeleteContext(hRC);
451 if (hPalette) DeleteObject(hPalette);