FreeFOAM The Cross-Platform CFD Toolkit
winmain.C
Go to the documentation of this file.
1 
2 /*
3  * Polygon Reduction Demo by Stan Melax (c) 1998
4  * Permission to use any of this code wherever you want is granted..
5  * Although, please do acknowledge authorship if appropriate.
6  *
7  * This module contains the window setup code, mouse input, timing
8  * routines, and that sort of stuff. The interesting modules
9  * to see are bunnygut.cpp and progmesh.cpp.
10  *
11  * The windows 95 specific code for this application was taken from
12  * an example of processing mouse events in an OpenGL program using
13  * the Win32 API from the www.opengl.org web site.
14  *
15  * Under Project->Settings, Link Options, General Category
16  * Add:
17  * Opengl32.lib glu32.lib winmm.lib
18  * to the Object/Library Modules
19  *
20  * You will need have OpenGL libs and include files to compile this
21  * Go to the www.opengl.org web site if you need help with this.
22  */
23 
24 
25 #include <windows.h> /* must include this before GL/gl.h */
26 #include <GL/gl.h> /* OpenGL header file */
27 #include <GL/glu.h> /* OpenGL utilities header file */
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/timeb.h>
31 #include <time.h>
32 
33 #include "vector.h"
34 #include "font.h"
35 
36 // Functions and Variables from bunny module
37 extern void InitModel();
38 extern void RenderModel();
39 extern Vector model_position; // position of bunny
40 extern Quaternion model_orientation; // orientation of bunny
41 
42 // Global Variables
43 float DeltaT = 0.1f;
44 float FPS;
45 int Width = 512;
46 int Height = 512;
47 int MouseX = 0;
48 int MouseY = 0;
49 Vector MouseVector; // 3D direction mouse points
50 Vector OldMouseVector;
51 int MouseState=0; // true iff left button down
52 float ViewAngle=45.0f;
53 
54 HDC hDC; /* device context */
55 HPALETTE hPalette = 0; /* custom palette (if needed) */
56 
57 
58 void CalcFPSDeltaT(){
59  static int timeinit=0;
60  static int start,start2,current,last;
61  static int frame=0, frame2=0;
62  if(!timeinit){
63  frame=0;
64  start=timeGetTime();
65  timeinit=1;
66  }
67  frame++;
68  frame2++;
69  current=timeGetTime(); // found in winmm.lib
70  double dif=(double)(current-start)/CLOCKS_PER_SEC;
71  double rv = (dif)? (double)frame/(double)dif:-1.0;
72  if(dif>2.0 && frame >10) {
73  start = start2;
74  frame = frame2;
75  start2 = timeGetTime();
76  frame2 = 0;
77  }
78  DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
79  if(current==last) {
80  DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
81  }
82  // if(DeltaT>1.0) DeltaT=1.0;
83  FPS = (float)rv;
84  last = current;
85 }
86 
87 
88 void ComputeMouseVector(){
89  OldMouseVector=MouseVector;
90  float spread = (float)tan(ViewAngle/2*3.14/180);
91  float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
92  float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
93  Vector v(x ,y,-1);
94  // v=UserOrientation *v;
95  v=normalize(v);
96  MouseVector = v;
97 }
98 
99 Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
100  // Implement track ball functionality to spin stuf on the screen
101  // cop center of projection
102  // cor center of rotation
103  // dir1 old mouse direction
104  // dir2 new mouse direction
105  // pretend there is a sphere around cor. Then find the points
106  // where dir1 and dir2 intersect that sphere. Find the
107  // rotation that takes the first point to the second.
108  float m;
109  // compute plane
110  Vector nrml = cor - cop;
111  float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop
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.", "Error", MB_OK);
289  return NULL;
290  }
291  }
292 
293  hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
294  WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
295  0,0,Width,Height, NULL, NULL, hInstance, NULL);
296 
297  if (hWnd == NULL) {
298  MessageBox(NULL, "CreateWindow() failed: Cannot create a window.",
299  "Error", MB_OK);
300  return NULL;
301  }
302 
303  hDC = GetDC(hWnd);
304 
305  /* there is no guarantee that the contents of the stack that become
306  the pfd are zeroed, therefore _make sure_ to clear these bits. */
307  memset(&pfd, 0, sizeof(pfd));
308  pfd.nSize = sizeof(pfd);
309  pfd.nVersion = 1;
310  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
311  pfd.iPixelType = PFD_TYPE_RGBA;
312  pfd.cDepthBits = 32;
313  pfd.cColorBits = 32;
314 
315  pf = ChoosePixelFormat(hDC, &pfd);
316  if (pf == 0) {
317  MessageBox(NULL, "ChoosePixelFormat() failed: "
318  "Cannot find a suitable pixel format.", "Error", MB_OK);
319  return 0;
320  }
321 
322  if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
323  MessageBox(NULL, "SetPixelFormat() failed: "
324  "Cannot set format specified.", "Error", MB_OK);
325  return 0;
326  }
327 
328  DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
329 
330  if (pfd.dwFlags & PFD_NEED_PALETTE ||
331  pfd.iPixelType == PFD_TYPE_COLORINDEX) {
332 
333  n = 1 << pfd.cColorBits;
334  if (n > 256) n = 256;
335 
336  lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
337  sizeof(PALETTEENTRY) * n);
338  memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
339  lpPal->palVersion = 0x300;
340  lpPal->palNumEntries = n;
341 
342  GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
343 
344  /* if the pixel type is RGBA, then we want to make an RGB ramp,
345  otherwise (color index) set individual colors. */
346  if (pfd.iPixelType == PFD_TYPE_RGBA) {
347  int redMask = (1 << pfd.cRedBits) - 1;
348  int greenMask = (1 << pfd.cGreenBits) - 1;
349  int blueMask = (1 << pfd.cBlueBits) - 1;
350  int i;
351 
352  /* fill in the entries with an RGB color ramp. */
353  for (i = 0; i < n; ++i) {
354  lpPal->palPalEntry[i].peRed =
355  (((i >> pfd.cRedShift) & redMask) * 255)/redMask;
356  lpPal->palPalEntry[i].peGreen =
357  (((i >> pfd.cGreenShift) & greenMask) * 255)/greenMask;
358  lpPal->palPalEntry[i].peBlue =
359  (((i >> pfd.cBlueShift) & blueMask) * 255)/blueMask;
360  lpPal->palPalEntry[i].peFlags = 0;
361  }
362  } else {
363  lpPal->palPalEntry[0].peRed = 0;
364  lpPal->palPalEntry[0].peGreen = 0;
365  lpPal->palPalEntry[0].peBlue = 0;
366  lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
367  lpPal->palPalEntry[1].peRed = 255;
368  lpPal->palPalEntry[1].peGreen = 0;
369  lpPal->palPalEntry[1].peBlue = 0;
370  lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
371  lpPal->palPalEntry[2].peRed = 0;
372  lpPal->palPalEntry[2].peGreen = 255;
373  lpPal->palPalEntry[2].peBlue = 0;
374  lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
375  lpPal->palPalEntry[3].peRed = 0;
376  lpPal->palPalEntry[3].peGreen = 0;
377  lpPal->palPalEntry[3].peBlue = 255;
378  lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
379  }
380 
381  hPalette = CreatePalette(lpPal);
382  if (hPalette) {
383  SelectPalette(hDC, hPalette, FALSE);
384  RealizePalette(hDC);
385  }
386 
387  free(lpPal);
388  }
389 
390  ReleaseDC(hDC, hWnd);
391  return hWnd;
392 }
393 
394 int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
395  LPSTR lpszCmdLine, int nCmdShow)
396 {
397  HGLRC hRC; /* opengl context */
398  HWND hWnd; /* window */
399  MSG msg; /* message */
400 
401  // InitModel() initializes some data structures and
402  // does the progressive mesh polygon reduction algorithm
403  // on the model.
404  CalcFPSDeltaT(); // to time the algorithm
405  InitModel();
406  CalcFPSDeltaT();
407 
408  hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
409  if (hWnd == NULL) exit(1);
410 
411  hDC = GetDC(hWnd);
412  hRC = wglCreateContext(hDC);
413  wglMakeCurrent(hDC, hRC);
414  ShowWindow(hWnd, nCmdShow);
415  glEnable(GL_DEPTH_TEST);
416 
417  PostString("Demo by Stan Melax (c)1998",5,-5,20);
418  PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
419  char buf[128];
420  PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
421  sprintf(buf,"was executed in %5.3f seconds",DeltaT);
422  PostString(buf,2,1,6);
423 
424  while (1) {
425  while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
426  if(GetMessage(&msg, hWnd, 0, 0)) {
427  TranslateMessage(&msg);
428  DispatchMessage(&msg);
429  } else {
430  goto quit; // This 'goto' was in the sample code
431  }
432  }
433  CalcFPSDeltaT();
434  Display();
435  }
436 
437  quit:
438  wglMakeCurrent(NULL, NULL);
439  ReleaseDC(hDC, hWnd);
440  wglDeleteContext(hRC);
441  DestroyWindow(hWnd);
442  if (hPalette) DeleteObject(hPalette);
443  return msg.wParam;
444 }
445 
446 // ************************ vim: set sw=4 sts=4 et: ************************ //