windows-nt/Source/XPSP1/NT/multimedia/opengl/test/demos/viewer/glwindow.c
2020-09-26 16:20:57 +08:00

779 lines
19 KiB
C

/******************************Module*Header*******************************\
* Module Name: glwindow.c
*
* OpenGL window maintenance.
*
* Created: 09-Mar-1995 15:10:10
* Author: Gilman Wong [gilmanw]
*
* Copyright (c) 1995 Microsoft Corporation
*
\**************************************************************************/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "global.h"
#include "glwindow.h"
#include "nff.h"
#include "trackbal.h"
// Move global stuff into SCENE struct.
HGLRC ghrc = (HGLRC) 0;
HPALETTE ghpalOld, ghPalette = (HPALETTE) 0;
BOOL bUseStatic = FALSE;
UINT uiSysPalUse = SYSPAL_STATIC;
extern void DoGlStuff(HWND, HDC);
extern HGLRC hrcInitGL(HWND, HDC);
extern void stateInit(HWND, HDC);
extern void vCleanupGL(HGLRC, HDC);
extern BOOL bSetupPixelFormat(HDC);
extern void CreateRGBPalette(HDC);
extern VOID vSetSize(HWND);
extern void ForceRedraw(HWND);
extern SCENE *OpenScene(LPSTR lpstrFile);
CHAR lpstrFile[256];
// Global ambient lights.
static GLfloat lightAmbient[4] = {0.4f, 0.4f, 0.4f, 1.0f};
static GLfloat lightAmbientLow[4] = {0.2f, 0.2f, 0.2f, 1.0f};
//!!!move to SCENE structure
// Trackball stuff
POINT gptWindow;
SIZE gszWindow; // already in SCENE
float curquat[4], lastquat[4];
LONG glMouseDownX, glMouseDownY;
BOOL gbLeftMouse = FALSE;
BOOL gbSpinning = FALSE;
float zoom = 1.0f;
//!!!move to SCENE structure
typedef enum enumPOLYDRAW {
POLYDRAW_FILLED = 0,
POLYDRAW_LINES = 1,
POLYDRAW_POINTS = 2
} POLYDRAW;
typedef enum enumSHADE {
SHADE_SMOOTH = 0,
SHADE_FLAT = 1
} SHADE;
typedef enum enumLIGHT {
LIGHT_OFF = 0,
LIGHT_INFINITE = 1,
LIGHT_LOCAL = 2
} LIGHT;
SHADE gShadeMode = SHADE_SMOOTH;
POLYDRAW gPolyDrawMode = POLYDRAW_FILLED;
LIGHT gLightMode = LIGHT_INFINITE;
/******************************Public*Routine******************************\
* MyCreateGLWindow
*
* Setup the windows.
*
* History:
* 15-Dec-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HWND MyCreateGLWindow(HINSTANCE hInstance, LPTSTR lpstr)
{
WNDCLASS wc;
RECT rcl;
HWND hwnd;
lstrcpy(lpstrFile, lpstr);
// Create the OpenGL window.
wc.style = CS_OWNDC;
wc.lpfnWndProc = GLWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = "GLWClass";
RegisterClass(&wc);
hwnd = CreateWindow(
"GLWClass",
"OpenGL stuff",
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
//CW_USEDEFAULT,
//CW_USEDEFAULT,
300,
0,
100,
100,
NULL,
NULL,
hInstance,
NULL
);
//!!!hack -- not really the right coordinates
gptWindow.x = 0;
gptWindow.y = 300;
gszWindow.cx = 100;
gszWindow.cy = 100;
if (hwnd)
{
ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);
}
SetTimer(hwnd, 1, 1, NULL);
return hwnd;
}
/******************************Public*Routine******************************\
* GLWndProc
*
* WndProc for the OpenGL window.
*
* History:
* 15-Dec-1994 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
long FAR PASCAL GLWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
long lRet = 0;
RECT rcl;
HDC hdc;
PAINTSTRUCT ps;
SCENE *scene;
if (message != WM_CREATE)
scene = (SCENE *) GetWindowLong(hwnd, GWL_USERDATA);
// Process window message.
switch (message)
{
case WM_CREATE:
//LBprintf("WM_CREATE");
if(hdc = GetDC(hwnd))
{
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
scene = OpenScene(lpstrFile);
if (scene)
{
SetWindowLong(hwnd, GWL_USERDATA, (LONG) scene);
rcl.left = 0;
rcl.top = 0;
rcl.right = scene->szWindow.cx;
rcl.bottom = scene->szWindow.cy;
AdjustWindowRect(&rcl, WS_OVERLAPPEDWINDOW, 0);
SetWindowPos(hwnd, NULL, 0, 0,
rcl.right, rcl.bottom,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS);
stateInit(hwnd, hdc);
}
else
lRet = -1;
ReleaseDC(hwnd,hdc);
}
break;
case WM_MOVE:
gptWindow.x = (int) LOWORD(lParam);
gptWindow.y = (int) HIWORD(lParam);
break;
case WM_SIZE:
gszWindow.cx = LOWORD(lParam);
gszWindow.cy = HIWORD(lParam);
scene->szWindow.cx = LOWORD(lParam);
scene->szWindow.cy = HIWORD(lParam);
vSetSize(hwnd);
ForceRedraw(hwnd);
break;
case WM_PAINT:
//LBprintf("WM_PAINT");
hdc = BeginPaint( hwnd, &ps );
DoGlStuff( hwnd, hdc );
EndPaint( hwnd, &ps );
break;
case WM_PALETTECHANGED:
//LBprintf("WM_PALETTECHANGED");
if (hwnd != (HWND) wParam)
{
if (hdc = GetDC(hwnd))
{
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, TRUE);
if (RealizePalette(hdc) != GDI_ERROR)
lRet = 1;
}
}
break;
case WM_QUERYNEWPALETTE:
//LBprintf("WM_QUERYNEWPALETTE");
if (hdc = GetDC(hwnd))
{
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, FALSE);
if (RealizePalette(hdc) != GDI_ERROR)
lRet = 1;
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE: // <ESC> is quick exit
PostMessage(hwnd, WM_DESTROY, 0, 0);
break;
case VK_UP:
zoom *= .8f;
if (zoom < 1.0f && zoom > .8f)
zoom = 1.0f;
LBprintf("Zoom = %f", zoom);
vSetSize(hwnd);
break;
case VK_DOWN:
zoom *= 1.25f;
if (zoom > 1.0f && zoom < 1.25f)
zoom = 1.0f;
LBprintf("Zoom = %f", zoom);
vSetSize(hwnd);
break;
default:
break;
}
break;
case WM_CHAR:
switch(wParam)
{
case 's':
case 'S':
gShadeMode = (gShadeMode + 1) % 2;
glShadeModel( gShadeMode == SHADE_FLAT ? GL_FLAT : GL_SMOOTH );
LBprintf("glShadeModel(%s)", gShadeMode == SHADE_FLAT ? "GL_FLAT" :
"GL_SMOOTH");
break;
case 'p':
case 'P':
gPolyDrawMode = (gPolyDrawMode + 1) % 3;
switch (gPolyDrawMode)
{
case POLYDRAW_POINTS:
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
break;
case POLYDRAW_LINES:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case POLYDRAW_FILLED:
default:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
}
LBprintf("glPolygonMode(%s)", gPolyDrawMode == POLYDRAW_POINTS ? "GL_POINT" :
gPolyDrawMode == POLYDRAW_LINES ? "GL_LINE" :
"GL_FILL");
break;
case 'l':
case 'L':
gLightMode = (gLightMode + 1) % 3;
if ( gLightMode != LIGHT_OFF )
{
int i;
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,
gLightMode == LIGHT_LOCAL ? GL_TRUE : GL_FALSE);
for (i = 0; i < scene->Lights.count; i++)
{
glCallList(scene->Lights.listBase + i);
glEnable(GL_LIGHT0 + i);
}
/* If no other lights, turn on ambient on higher */
if (!scene->Lights.count)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &lightAmbient);
else
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &lightAmbientLow);
}
else
{
glDisable(GL_NORMALIZE);
glDisable(GL_LIGHTING);
}
LBprintf("Light = %s", gLightMode == LIGHT_OFF ? "disabled" :
gLightMode == LIGHT_INFINITE ? "infinite" :
"local");
break;
default:
break;
}
ForceRedraw(hwnd);
break;
case WM_LBUTTONDOWN:
SetCapture(hwnd);
glMouseDownX = LOWORD(lParam);
glMouseDownY = HIWORD(lParam);
gbLeftMouse = TRUE;
ForceRedraw(hwnd);
break;
case WM_LBUTTONUP:
ReleaseCapture();
gbLeftMouse = FALSE;
ForceRedraw(hwnd);
break;
case WM_TIMER:
hdc = GetDC(hwnd);
DoGlStuff( hwnd, hdc );
ReleaseDC(hwnd, hdc);
break;
case WM_DESTROY:
KillTimer(hwnd, 1);
hdc = GetDC(hwnd);
vCleanupGL(ghrc, hdc);
ReleaseDC(hwnd, hdc);
PostQuitMessage( 0 );
break;
default:
lRet = DefWindowProc(hwnd, message, wParam, lParam);
break;
}
return lRet;
}
unsigned char threeto8[8] = {
0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
};
unsigned char twoto8[4] = {
0, 0x55, 0xaa, 0xff
};
unsigned char oneto8[2] = {
0, 255
};
unsigned char
ComponentFromIndex(i, nbits, shift)
{
unsigned char val;
val = i >> shift;
switch (nbits) {
case 1:
val &= 0x1;
return oneto8[val];
case 2:
val &= 0x3;
return twoto8[val];
case 3:
val &= 0x7;
return threeto8[val];
default:
return 0;
}
}
void
CreateRGBPalette(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
LOGPALETTE *pPal;
int n, i;
ppfd = &pfd;
n = GetPixelFormat(hdc);
DescribePixelFormat(hdc, n, sizeof(PIXELFORMATDESCRIPTOR), ppfd);
if (ppfd->dwFlags & PFD_NEED_PALETTE) {
n = 1 << ppfd->cColorBits;
pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
n * sizeof(PALETTEENTRY));
pPal->palVersion = 0x300;
pPal->palNumEntries = n;
for (i=0; i<n; i++) {
pPal->palPalEntry[i].peRed =
ComponentFromIndex(i, ppfd->cRedBits, ppfd->cRedShift);
pPal->palPalEntry[i].peGreen =
ComponentFromIndex(i, ppfd->cGreenBits, ppfd->cGreenShift);
pPal->palPalEntry[i].peBlue =
ComponentFromIndex(i, ppfd->cBlueBits, ppfd->cBlueShift);
pPal->palPalEntry[i].peFlags = (i == 0 || i == 255) ? 0 : PC_NOCOLLAPSE;
}
ghPalette = CreatePalette(pPal);
LocalFree(pPal);
if (ppfd->dwFlags & PFD_NEED_SYSTEM_PALETTE)
{
uiSysPalUse = SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
bUseStatic = TRUE;
}
ghpalOld = SelectPalette(hdc, ghPalette, FALSE);
n = RealizePalette(hdc);
UnrealizeObject(ghPalette);
n = RealizePalette(hdc);
}
}
BOOL bSetupPixelFormat(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
int pixelformat;
ppfd = &pfd;
memset(ppfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
ppfd->dwLayerMask = PFD_MAIN_PLANE;
ppfd->iPixelType = PFD_TYPE_RGBA;
ppfd->cColorBits = 24;
ppfd->cDepthBits = 16;
ppfd->cAccumBits = 0;
ppfd->cStencilBits = 0;
pixelformat = ChoosePixelFormat(hdc, ppfd);
if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
{
MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
return FALSE;
}
if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
{
MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
return FALSE;
}
CreateRGBPalette(hdc);
return TRUE;
}
HGLRC hrcInitGL(HWND hwnd, HDC hdc)
{
HGLRC hrc;
/* Create a Rendering Context */
bSetupPixelFormat( hdc );
hrc = wglCreateContext( hdc );
/* Make it Current */
wglMakeCurrent( hdc, hrc );
return hrc;
}
void stateInit(HWND hwnd, HDC hdc)
{
GLint i;
SCENE *scene = (SCENE *) GetWindowLong(hwnd, GWL_USERDATA); //!!! pass instead
glDrawBuffer(GL_BACK);
/* Set the clear color */
glClearColor( scene->rgbaClear.r, scene->rgbaClear.g,
scene->rgbaClear.b, scene->rgbaClear.a );
/* Turn on z-buffer */
glEnable(GL_DEPTH_TEST);
/* Turn on backface culling */
glFrontFace(GL_CCW);
//glEnable(GL_CULL_FACE);
/* Shading */
glShadeModel( gShadeMode == SHADE_FLAT ? GL_FLAT : GL_SMOOTH );
/* Polygon draw mode */
switch (gPolyDrawMode)
{
case POLYDRAW_POINTS:
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
break;
case POLYDRAW_LINES:
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case POLYDRAW_FILLED:
default:
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
}
/* Turn on the lights */
if ( gLightMode != LIGHT_OFF )
{
glEnable(GL_NORMALIZE);
glEnable(GL_LIGHTING);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,
gLightMode == LIGHT_LOCAL ? GL_TRUE : GL_FALSE);
for (i = 0; i < scene->Lights.count; i++)
{
glCallList(scene->Lights.listBase + i);
glEnable(GL_LIGHT0 + i);
}
/* If no other lights, turn on ambient on higher */
if (!scene->Lights.count)
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &lightAmbient);
else
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, &lightAmbientLow);
}
else
{
glDisable(GL_NORMALIZE);
glDisable(GL_LIGHTING);
}
/* Setup viewport */
vSetSize(hwnd);
/* Initialize trackball */
trackball(curquat, 0.0, 0.0, 0.0, 0.0);
}
VOID vSetSize(HWND hwnd)
{
SCENE *scene = (SCENE *) GetWindowLong(hwnd, GWL_USERDATA); //!!! pass instead
MyXYZ xyzZoomFrom;
GLfloat localPerspective = scene->AspectRatio;
/* Adjust aspect ratio to window size */
localPerspective *= ((GLfloat) scene->szWindow.cx / (GLfloat) scene->szWindow.cy);
/* Compute the vector from xyzAt to xyzFrom */
xyzZoomFrom.x = scene->xyzFrom.x - scene->xyzAt.x;
xyzZoomFrom.y = scene->xyzFrom.y - scene->xyzAt.y;
xyzZoomFrom.z = scene->xyzFrom.z - scene->xyzAt.z;
/* Scale by the zoom factor */
xyzZoomFrom.x *= zoom;
xyzZoomFrom.y *= zoom;
xyzZoomFrom.z *= zoom;
/* Compute new xyzFrom */
xyzZoomFrom.x += scene->xyzAt.x;
xyzZoomFrom.y += scene->xyzAt.y;
xyzZoomFrom.z += scene->xyzAt.x;
/* Set up viewport extents */
glViewport(0, 0, scene->szWindow.cx, scene->szWindow.cy);
/* Set up the projection matrix */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(scene->ViewAngle, scene->AspectRatio,
// scene->Hither, scene->Yon);
gluPerspective(scene->ViewAngle, localPerspective,
scene->Hither, scene->Yon * zoom);
/* Set up the model matrix */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//gluLookAt(scene->xyzFrom.x,scene->xyzFrom.y,scene->xyzFrom.z,
// scene->xyzAt.x,scene->xyzAt.y,scene->xyzAt.z,
// scene->xyzUp.x,scene->xyzUp.y,scene->xyzUp.z);
gluLookAt(xyzZoomFrom.x,xyzZoomFrom.y,xyzZoomFrom.z,
scene->xyzAt.x,scene->xyzAt.y,scene->xyzAt.z,
scene->xyzUp.x,scene->xyzUp.y,scene->xyzUp.z);
}
void
vCleanupGL(HGLRC hrc, HDC hdc)
{
//if (ghPalette)
// DeleteObject(SelectObject(ghdcMem, ghpalOld));
/* Destroy our context */
wglDeleteContext( hrc );
if (bUseStatic)
SetSystemPaletteUse(hdc, uiSysPalUse);
}
void
ForceRedraw(HWND hwnd)
{
MSG msg;
if (!PeekMessage(&msg, hwnd, WM_PAINT, WM_PAINT, PM_NOREMOVE) )
{
InvalidateRect(hwnd, NULL, FALSE);
}
}
void
DoGlStuff( HWND hwnd, HDC hdc )
{
SCENE *scene = (SCENE *) GetWindowLong(hwnd, GWL_USERDATA); //!!! pass instead
USHORT usMouseCurX, usMouseCurY;
POINT pt;
float matRot[4][4];
if (gbLeftMouse)
{
if (GetCursorPos(&pt))
{
// Subtract current window origin to convert to window coordinates.
pt.x -= gptWindow.x;
pt.y -= gptWindow.y;
// If mouse has moved since button was pressed, change quaternion.
if (pt.x != glMouseDownX || pt.y != glMouseDownY)
{
//trackball(lastquat,
// 2.0*(gszWindow.cx-glMouseDownX)/gszWindow.cx-1.0,
// 2.0*glMouseDownY/gszWindow.cy-1.0,
// 2.0*(gszWindow.cx-pt.x)/gszWindow.cx-1.0,
// 2.0*pt.y/gszWindow.cy-1.0);
trackball(lastquat,
2.0*(glMouseDownX)/gszWindow.cx-1.0,
2.0*(gszWindow.cy-glMouseDownY)/gszWindow.cy-1.0,
2.0*(pt.x)/gszWindow.cx-1.0,
2.0*(gszWindow.cy-pt.y)/gszWindow.cy-1.0);
gbSpinning = TRUE;
}
else
gbSpinning = FALSE;
glMouseDownX = pt.x;
glMouseDownY = pt.y;
}
}
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
if (gbSpinning)
add_quats(lastquat, curquat, curquat);
build_rotmatrix(matRot, curquat);
glMultMatrixf(&(matRot[0][0]));
if (scene->Objects.count)
{
//LBprintf("call display list");
glCallList(scene->Objects.listBase);
}
glPopMatrix();
SwapBuffers(hdc);
}
SCENE *OpenScene(LPSTR lpstrFile)
{
SCENE *scene = (SCENE *) NULL;
CHAR *pchExt;
// Find the extension.
pchExt = lpstrFile;
while ((*pchExt != '.') && (*pchExt != '\0'))
pchExt++;
if (*pchExt == '.')
{
// Use extension as the key to call appropriate parser.
if (!lstrcmpi(pchExt, ".nff"))
scene = NffOpenScene(lpstrFile);
else if (!lstrcmpi(pchExt, ".obj"))
scene = ObjOpenScene(lpstrFile);
else
LBprintf("Unknown extension: %s", pchExt);
}
return scene;
}