winmain.C
Go to the documentation of this file.
1 /*
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.
5  *
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.
9  *
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.
13  *
14  * Under Project->Settings, Link Options, General Category
15  * Add:
16  * Opengl32.lib glu32.lib winmm.lib
17  * to the Object/Library Modules
18  *
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.
21  */
22 
23 
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 */
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <sys/timeb.h>
30 #include <time.h>
31 
32 #include "vector.h"
33 #include "font.h"
34 
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
40 
41 // Global Variables
42 float DeltaT = 0.1f;
43 float FPS;
44 int Width = 512;
45 int Height = 512;
46 int MouseX = 0;
47 int MouseY = 0;
48 Vector MouseVector; // 3D direction mouse points
49 Vector OldMouseVector;
50 int MouseState=0; // true iff left button down
51 float ViewAngle=45.0f;
52 
53 HDC hDC; /* device context */
54 HPALETTE hPalette = 0; /* custom palette (if needed) */
55 
56 
57 void CalcFPSDeltaT(){
58  static int timeinit=0;
59  static int start,start2,current,last;
60  static int frame=0, frame2=0;
61  if(!timeinit){
62  frame=0;
63  start=timeGetTime();
64  timeinit=1;
65  }
66  frame++;
67  frame2++;
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) {
72  start = start2;
73  frame = frame2;
74  start2 = timeGetTime();
75  frame2 = 0;
76  }
77  DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
78  if(current==last) {
79  DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
80  }
81  // if(DeltaT>1.0) DeltaT=1.0;
82  FPS = (float)rv;
83  last = current;
84 }
85 
86 
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);
92  Vector v(x ,y,-1);
93  // v=UserOrientation *v;
94  v=normalize(v);
95  MouseVector = v;
96 }
97 
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.
107  float m;
108  // compute plane
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);
115  u=u-cor;
116  u=u*fudgefactor;
117  m= magnitude(u);
118  if(m>1) {u=u*1.0f/m;}
119  else {
120  u=u - (nrml * (float)sqrt(1-m*m));
121  }
122  Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
123  v=v-cor;
124  v=v*fudgefactor;
125  m= magnitude(v);
126  if(m>1) {v=v*1.0f/m;}
127  else {
128  v=v - (nrml * (float)sqrt(1-m*m));
129  }
130  Vector axis = u*v;
131  float angle;
132  m=magnitude(axis);
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);
138  }
139  return q;
140 }
141 
142 void SpinIt(){
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;
147 }
148 
149 void Reshape(int width, int height){
150  // called initially and when the window changes size
151  Width=width;
152  Height=height;
153  glViewport(0, 0, width, height);
154  glMatrixMode(GL_PROJECTION);
155  glLoadIdentity();
156  gluPerspective(ViewAngle, (float)width/height, 0.1, 50.0);
157  glMatrixMode(GL_MODELVIEW);
158  glLoadIdentity();
159 }
160 
161 void PrintStats(){
162  char buf[1024];buf[0]='\0';
163  sprintf(buf,"FPS: %5.2f ",FPS);
164  PostString(buf,0,-1,0);
165 }
166 
167 void Display(){
168  // main drawing routine - called every frame
169  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
170  glPushMatrix();
171  glLoadIdentity();
172  // camera at default (zero) position and orientation
173  RenderModel();
174  PrintStats();
175  glLoadIdentity();
176  RenderStrings();
177  glPopMatrix();
178  glFlush();
179  SwapBuffers(hDC); /* nop if singlebuffered */
180 }
181 
182 
183 LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
184 {
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;
189 
190  switch(uMsg) {
191  case WM_PAINT:
192  BeginPaint(hWnd, &ps);
193  EndPaint(hWnd, &ps);
194  return 0;
195  case WM_SIZE:
196  Reshape(LOWORD(lParam), HIWORD(lParam));
197  PostMessage(hWnd, WM_PAINT, 0, 0);
198  return 0;
199  case WM_CHAR:
200  switch (wParam) {
201  case 27: /* ESC key */
202  PostQuitMessage(0);
203  break;
204  }
205  return 0;
206 
207  case WM_LBUTTONDOWN:
208  /* if we don't set the capture we won't get mouse move
209  messages when the mouse moves outside the window. */
210  SetCapture(hWnd);
211  MouseX = LOWORD(lParam);
212  MouseY = HIWORD(lParam);
213  ComputeMouseVector();
214  MouseState = 1;
215  return 0;
216 
217  case WM_LBUTTONUP:
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();
224  MouseState=0;
225  /* remember to release the capture when we are finished. */
226  ReleaseCapture();
227  return 0;
228 
229  case WM_MOUSEMOVE:
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();
241  return 0;
242 
243  case WM_PALETTECHANGED:
244  if (hWnd == (HWND)wParam) break;
245  /* fall through to WM_QUERYNEWPALETTE */
246  case WM_QUERYNEWPALETTE:
247  if (hPalette) {
248  UnrealizeObject(hPalette);
249  SelectPalette(hDC, hPalette, FALSE);
250  RealizePalette(hDC);
251  return TRUE;
252  }
253  return FALSE;
254 
255  case WM_CLOSE:
256  PostQuitMessage(0);
257  return 0;
258  }
259  return DefWindowProc(hWnd, uMsg, wParam, lParam);
260 }
261 
262 HWND CreateOpenGLWindow(char* title)
263 {
264  // make a double-buffered, rgba, opengl window
265  int n, pf;
266  HWND hWnd;
267  WNDCLASS wc;
268  LOGPALETTE* lpPal;
269  PIXELFORMATDESCRIPTOR pfd;
270  static HINSTANCE hInstance = 0;
271 
272  /* only register the window class once - use hInstance as a flag. */
273  if (!hInstance) {
274  hInstance = GetModuleHandle(NULL);
275  wc.style = CS_OWNDC;
276  wc.lpfnWndProc = (WNDPROC)WindowProc;
277  wc.cbClsExtra = 0;
278  wc.cbWndExtra = 0;
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";
285 
286  if (!RegisterClass(&wc)) {
287  MessageBox(NULL, "RegisterClass() failed: "
288  "Cannot register window class.",
289  "Error", MB_OK);
290  return NULL;
291  }
292  }
293 
294  hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
295  WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
296  0,0,Width,Height, NULL, NULL, hInstance, NULL);
297 
298  if (hWnd == NULL) {
299  MessageBox(NULL,
300  "CreateWindow() failed: Cannot create a window.",
301  "Error", MB_OK);
302  return NULL;
303  }
304 
305  hDC = GetDC(hWnd);
306 
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);
311  pfd.nVersion = 1;
312  pfd.dwFlags = PFD_DRAW_TO_WINDOW
313  | PFD_SUPPORT_OPENGL
314  | PFD_DOUBLEBUFFER;
315  pfd.iPixelType = PFD_TYPE_RGBA;
316  pfd.cDepthBits = 32;
317  pfd.cColorBits = 32;
318 
319  pf = ChoosePixelFormat(hDC, &pfd);
320  if (pf == 0) {
321  MessageBox(NULL, "ChoosePixelFormat() failed: "
322  "Cannot find a suitable pixel format.",
323  "Error", MB_OK);
324  return 0;
325  }
326 
327  if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
328  MessageBox(NULL, "SetPixelFormat() failed: "
329  "Cannot set format specified.", "Error", MB_OK);
330  return 0;
331  }
332 
333  DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
334 
335  if (pfd.dwFlags & PFD_NEED_PALETTE ||
336  pfd.iPixelType == PFD_TYPE_COLORINDEX) {
337 
338  n = 1 << pfd.cColorBits;
339  if (n > 256) n = 256;
340 
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;
346 
347  GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
348 
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;
355  int i;
356 
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)
361  /redMask;
362  lpPal->palPalEntry[i].peGreen =
363  (((i >> pfd.cGreenShift) & greenMask) * 255)
364  /greenMask;
365  lpPal->palPalEntry[i].peBlue =
366  (((i >> pfd.cBlueShift) & blueMask) * 255)
367  /blueMask;
368  lpPal->palPalEntry[i].peFlags = 0;
369  }
370  } else {
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;
387  }
388 
389  hPalette = CreatePalette(lpPal);
390  if (hPalette) {
391  SelectPalette(hDC, hPalette, FALSE);
392  RealizePalette(hDC);
393  }
394 
395  free(lpPal);
396  }
397 
398  ReleaseDC(hDC, hWnd);
399  return hWnd;
400 }
401 
402 int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
403  LPSTR lpszCmdLine, int nCmdShow)
404 {
405  HGLRC hRC; /* opengl context */
406  HWND hWnd; /* window */
407  MSG msg; /* message */
408 
409  // InitModel() initializes some data structures and
410  // does the progressive mesh polygon reduction algorithm
411  // on the model.
412  CalcFPSDeltaT(); // to time the algorithm
413  InitModel();
414  CalcFPSDeltaT();
415 
416  hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
417  if (hWnd == NULL) exit(1);
418 
419  hDC = GetDC(hWnd);
420  hRC = wglCreateContext(hDC);
421  wglMakeCurrent(hDC, hRC);
422  ShowWindow(hWnd, nCmdShow);
423  glEnable(GL_DEPTH_TEST);
424 
425  PostString("Demo by Stan Melax (c)1998",5,-5,20);
426  PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
427  char buf[128];
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);
431 
432  while (1) {
433  while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
434  if(GetMessage(&msg, hWnd, 0, 0)) {
435  TranslateMessage(&msg);
436  DispatchMessage(&msg);
437  } else {
438  // This 'goto' was in the sample code
439  goto quit;
440  }
441  }
442  CalcFPSDeltaT();
443  Display();
444  }
445 
446  quit:
447  wglMakeCurrent(NULL, NULL);
448  ReleaseDC(hDC, hWnd);
449  wglDeleteContext(hRC);
450  DestroyWindow(hWnd);
451  if (hPalette) DeleteObject(hPalette);
452  return msg.wParam;
453 }
void spread(volScalarField &field, const volScalarField &alpha, const label nLayers, const scalar alphaDiff=0.2, const scalar alphaMax=0.99, const scalar alphaMin=0.01)
Definition: fvcSmooth.C:124
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
dimensionedScalar sqrt(const dimensionedScalar &ds)
quaternion normalize(const quaternion &q)
Return the normalized (unit) quaternion of the given quaternion.
Definition: quaternionI.H:609
dimensionedScalar asin(const dimensionedScalar &ds)
scalar y
labelList f(nPoints)
label n
dimensionedScalar tan(const dimensionedScalar &ds)