www.pudn.com > 20050921094855818.zip > winmain.cpp



/* 
 *        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 	/* must include this before GL/gl.h */
#include 		/* OpenGL header file */
#include 		/* OpenGL utilities header file */
#include 
#include  
#include  
#include  
 
#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; 
	float fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop 
	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 { 
				goto quit; // This 'goto' was in the sample code 
		    } 
		} 
		CalcFPSDeltaT(); 
		Display(); 
    } 
 
  quit: 
    wglMakeCurrent(NULL, NULL);
    ReleaseDC(hDC, hWnd);
    wglDeleteContext(hRC);
    DestroyWindow(hWnd);
    if (hPalette) DeleteObject(hPalette);
    return msg.wParam;
}