1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
|
/*
* Polygon Reduction Demo by Stan Melax (c) 1998
* Permission to use any of this code wherever you want is granted..
* Although, please do acknowledge authorship if appropriate.
*
* This module contains the window setup code, mouse input, timing
* routines, and that sort of stuff. The interesting modules
* to see are bunnygut.cpp and progmesh.cpp.
*
* The windows 95 specific code for this application was taken from
* an example of processing mouse events in an OpenGL program using
* the Win32 API from the www.opengl.org web site.
*
* Under Project->Settings, Link Options, General Category
* Add:
* Opengl32.lib glu32.lib winmm.lib
* to the Object/Library Modules
*
* You will need have OpenGL libs and include files to compile this
* Go to the www.opengl.org web site if you need help with this.
*/
#include <windows.h> /* must include this before GL/gl.h */
#include <GL/gl.h> /* OpenGL header file */
#include <GL/glu.h> /* OpenGL utilities header file */
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <time.h>
#include "vector.h"
#include "font.h"
// Functions and Variables from bunny module
extern void InitModel();
extern void RenderModel();
extern Vector model_position; // position of bunny
extern Quaternion model_orientation; // orientation of bunny
// Global Variables
float DeltaT = 0.1f;
float FPS;
int Width = 512;
int Height = 512;
int MouseX = 0;
int MouseY = 0;
Vector MouseVector; // 3D direction mouse points
Vector OldMouseVector;
int MouseState=0; // true iff left button down
float ViewAngle=45.0f;
HDC hDC; /* device context */
HPALETTE hPalette = 0; /* custom palette (if needed) */
void CalcFPSDeltaT(){
static int timeinit=0;
static int start,start2,current,last;
static int frame=0, frame2=0;
if(!timeinit){
frame=0;
start=timeGetTime();
timeinit=1;
}
frame++;
frame2++;
current=timeGetTime(); // found in winmm.lib
double dif=(double)(current-start)/CLOCKS_PER_SEC;
double rv = (dif)? (double)frame/(double)dif:-1.0;
if(dif>2.0 && frame >10) {
start = start2;
frame = frame2;
start2 = timeGetTime();
frame2 = 0;
}
DeltaT = (float)(current-last)/CLOCKS_PER_SEC;
if(current==last) {
DeltaT = 0.1f/CLOCKS_PER_SEC; // it just cant be 0
}
// if(DeltaT>1.0) DeltaT=1.0;
FPS = (float)rv;
last = current;
}
void ComputeMouseVector(){
OldMouseVector=MouseVector;
float spread = (float)tan(ViewAngle/2*3.14/180);
float y = spread * ((Height-MouseY)-Height/2.0f) /(Height/2.0f);
float x = spread * (MouseX-Width/2.0f) /(Height/2.0f);
Vector v(x ,y,-1);
// v=UserOrientation *v;
v=normalize(v);
MouseVector = v;
}
Quaternion VirtualTrackBall(Vector cop,Vector cor,Vector dir1,Vector dir2) {
// Implement track ball functionality to spin stuf on the screen
// cop center of projection
// cor center of rotation
// dir1 old mouse direction
// dir2 new mouse direction
// pretend there is a sphere around cor. Then find the points
// where dir1 and dir2 intersect that sphere. Find the
// rotation that takes the first point to the second.
float m;
// compute plane
Vector nrml = cor - cop;
// since trackball proportional to distance from cop
float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f);
nrml = normalize(nrml);
float dist = -(nrml^cor);
Vector u= planelineintersection(nrml,dist,cop,cop+dir1);
u=u-cor;
u=u*fudgefactor;
m= magnitude(u);
if(m>1) {u=u*1.0f/m;}
else {
u=u - (nrml * (float)sqrt(1-m*m));
}
Vector v= planelineintersection(nrml,dist,cop,cop+dir2);
v=v-cor;
v=v*fudgefactor;
m= magnitude(v);
if(m>1) {v=v*1.0f/m;}
else {
v=v - (nrml * (float)sqrt(1-m*m));
}
Vector axis = u*v;
float angle;
m=magnitude(axis);
if(m>1)m=1; // avoid potential floating point error
Quaternion q(Vector(1.0f,0.0f,0.0f),0.0f);
if(m>0 && (angle=(float)asin(m))>3.14/180) {
axis = normalize(axis);
q=Quaternion(axis,angle);
}
return q;
}
void SpinIt(){
// Change the orientation of the bunny according to mouse drag
Quaternion q=VirtualTrackBall(Vector(0,0,0),model_position,
OldMouseVector,MouseVector);
model_orientation=q*model_orientation;
}
void Reshape(int width, int height){
// called initially and when the window changes size
Width=width;
Height=height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(ViewAngle, (float)width/height, 0.1, 50.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void PrintStats(){
char buf[1024];buf[0]='\0';
sprintf(buf,"FPS: %5.2f ",FPS);
PostString(buf,0,-1,0);
}
void Display(){
// main drawing routine - called every frame
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
// camera at default (zero) position and orientation
RenderModel();
PrintStats();
glLoadIdentity();
RenderStrings();
glPopMatrix();
glFlush();
SwapBuffers(hDC); /* nop if singlebuffered */
}
LONG WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static PAINTSTRUCT ps;
static GLboolean left = GL_FALSE; /* left button currently down? */
static GLboolean right = GL_FALSE; /* right button currently down? */
static int omx, omy, mx, my;
switch(uMsg) {
case WM_PAINT:
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SIZE:
Reshape(LOWORD(lParam), HIWORD(lParam));
PostMessage(hWnd, WM_PAINT, 0, 0);
return 0;
case WM_CHAR:
switch (wParam) {
case 27: /* ESC key */
PostQuitMessage(0);
break;
}
return 0;
case WM_LBUTTONDOWN:
/* if we don't set the capture we won't get mouse move
messages when the mouse moves outside the window. */
SetCapture(hWnd);
MouseX = LOWORD(lParam);
MouseY = HIWORD(lParam);
ComputeMouseVector();
MouseState = 1;
return 0;
case WM_LBUTTONUP:
MouseX = LOWORD(lParam);
MouseY = HIWORD(lParam);
if(MouseX & 1 << 15) MouseX -= (1 << 16);
if(MouseY & 1 << 15) MouseY -= (1 << 16);
ComputeMouseVector();
if(MouseState) SpinIt();
MouseState=0;
/* remember to release the capture when we are finished. */
ReleaseCapture();
return 0;
case WM_MOUSEMOVE:
MouseX = LOWORD(lParam);
MouseY = HIWORD(lParam);
/* Win32 is pretty braindead about the x, y position that
it returns when the mouse is off the left or top edge
of the window (due to them being unsigned). therefore,
roll the Win32's 0..2^16 pointer co-ord range to the
more amenable (and useful) 0..+/-2^15. */
if(MouseX & 1 << 15) MouseX -= (1 << 16);
if(MouseY & 1 << 15) MouseY -= (1 << 16);
ComputeMouseVector();
if(MouseState) SpinIt();
return 0;
case WM_PALETTECHANGED:
if (hWnd == (HWND)wParam) break;
/* fall through to WM_QUERYNEWPALETTE */
case WM_QUERYNEWPALETTE:
if (hPalette) {
UnrealizeObject(hPalette);
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
return TRUE;
}
return FALSE;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
HWND CreateOpenGLWindow(char* title)
{
// make a double-buffered, rgba, opengl window
int n, pf;
HWND hWnd;
WNDCLASS wc;
LOGPALETTE* lpPal;
PIXELFORMATDESCRIPTOR pfd;
static HINSTANCE hInstance = 0;
/* only register the window class once - use hInstance as a flag. */
if (!hInstance) {
hInstance = GetModuleHandle(NULL);
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC)WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc)) {
MessageBox(NULL, "RegisterClass() failed: "
"Cannot register window class.",
"Error", MB_OK);
return NULL;
}
}
hWnd = CreateWindow("OpenGL", title, WS_OVERLAPPEDWINDOW |
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0,0,Width,Height, NULL, NULL, hInstance, NULL);
if (hWnd == NULL) {
MessageBox(NULL,
"CreateWindow() failed: Cannot create a window.",
"Error", MB_OK);
return NULL;
}
hDC = GetDC(hWnd);
/* there is no guarantee that the contents of the stack that become
the pfd are zeroed, therefore _make sure_ to clear these bits. */
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW
| PFD_SUPPORT_OPENGL
| PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cDepthBits = 32;
pfd.cColorBits = 32;
pf = ChoosePixelFormat(hDC, &pfd);
if (pf == 0) {
MessageBox(NULL, "ChoosePixelFormat() failed: "
"Cannot find a suitable pixel format.",
"Error", MB_OK);
return 0;
}
if (SetPixelFormat(hDC, pf, &pfd) == FALSE) {
MessageBox(NULL, "SetPixelFormat() failed: "
"Cannot set format specified.", "Error", MB_OK);
return 0;
}
DescribePixelFormat(hDC, pf, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
if (pfd.dwFlags & PFD_NEED_PALETTE ||
pfd.iPixelType == PFD_TYPE_COLORINDEX) {
n = 1 << pfd.cColorBits;
if (n > 256) n = 256;
lpPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +
sizeof(PALETTEENTRY) * n);
memset(lpPal, 0, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * n);
lpPal->palVersion = 0x300;
lpPal->palNumEntries = n;
GetSystemPaletteEntries(hDC, 0, n, &lpPal->palPalEntry[0]);
/* if the pixel type is RGBA, then we want to make an RGB ramp,
otherwise (color index) set individual colors. */
if (pfd.iPixelType == PFD_TYPE_RGBA) {
int redMask = (1 << pfd.cRedBits) - 1;
int greenMask = (1 << pfd.cGreenBits) - 1;
int blueMask = (1 << pfd.cBlueBits) - 1;
int i;
/* fill in the entries with an RGB color ramp. */
for (i = 0; i < n; ++i) {
lpPal->palPalEntry[i].peRed =
(((i >> pfd.cRedShift) & redMask) * 255)
/redMask;
lpPal->palPalEntry[i].peGreen =
(((i >> pfd.cGreenShift) & greenMask) * 255)
/greenMask;
lpPal->palPalEntry[i].peBlue =
(((i >> pfd.cBlueShift) & blueMask) * 255)
/blueMask;
lpPal->palPalEntry[i].peFlags = 0;
}
} else {
lpPal->palPalEntry[0].peRed = 0;
lpPal->palPalEntry[0].peGreen = 0;
lpPal->palPalEntry[0].peBlue = 0;
lpPal->palPalEntry[0].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[1].peRed = 255;
lpPal->palPalEntry[1].peGreen = 0;
lpPal->palPalEntry[1].peBlue = 0;
lpPal->palPalEntry[1].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[2].peRed = 0;
lpPal->palPalEntry[2].peGreen = 255;
lpPal->palPalEntry[2].peBlue = 0;
lpPal->palPalEntry[2].peFlags = PC_NOCOLLAPSE;
lpPal->palPalEntry[3].peRed = 0;
lpPal->palPalEntry[3].peGreen = 0;
lpPal->palPalEntry[3].peBlue = 255;
lpPal->palPalEntry[3].peFlags = PC_NOCOLLAPSE;
}
hPalette = CreatePalette(lpPal);
if (hPalette) {
SelectPalette(hDC, hPalette, FALSE);
RealizePalette(hDC);
}
free(lpPal);
}
ReleaseDC(hDC, hWnd);
return hWnd;
}
int APIENTRY WinMain(HINSTANCE hCurrentInst, HINSTANCE hPreviousInst,
LPSTR lpszCmdLine, int nCmdShow)
{
HGLRC hRC; /* opengl context */
HWND hWnd; /* window */
MSG msg; /* message */
// InitModel() initializes some data structures and
// does the progressive mesh polygon reduction algorithm
// on the model.
CalcFPSDeltaT(); // to time the algorithm
InitModel();
CalcFPSDeltaT();
hWnd = CreateOpenGLWindow("bunnylod by Stan Melax");
if (hWnd == NULL) exit(1);
hDC = GetDC(hWnd);
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
ShowWindow(hWnd, nCmdShow);
glEnable(GL_DEPTH_TEST);
PostString("Demo by Stan Melax (c)1998",5,-5,20);
PostString("Model by Viewpoint Datalabs (c)1996",5,-4,20);
char buf[128];
PostString("Mesh Reduction Algorithm (non-optimized)",1,0,5);
sprintf(buf,"was executed in %5.3f seconds",DeltaT);
PostString(buf,2,1,6);
while (1) {
while(PeekMessage(&msg, hWnd, 0, 0, PM_NOREMOVE)) {
if(GetMessage(&msg, hWnd, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
// This 'goto' was in the sample code
goto quit;
}
}
CalcFPSDeltaT();
Display();
}
quit:
wglMakeCurrent(NULL, NULL);
ReleaseDC(hDC, hWnd);
wglDeleteContext(hRC);
DestroyWindow(hWnd);
if (hPalette) DeleteObject(hPalette);
return msg.wParam;
}
|