2025-04-27 07:49:33 -04:00

762 lines
20 KiB
C

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <GL\gl.h>
#include <GL\glu.h>
#include "mesh.h"
#include "trackbal.h"
#include "globals.h"
static const RGBA lightAmbient = {0.21f, 0.21f, 0.21f, 1.0f};
static const RGBA light0Ambient = {0.0f, 0.0f, 0.0f, 1.0f};
static const RGBA light0Diffuse = {0.7f, 0.7f, 0.7f, 1.0f};
static const RGBA light0Specular = {1.0f, 1.0f, 1.0f, 1.0f};
static const GLfloat light0Pos[] = {100.0f, 100.0f, 100.0f, 0.0f};
#define PALETTE_PER_MATL 32
#define PALETTE_PER_DIFF 26
#define PALETTE_PER_SPEC 6
#define MATL_MAX 7
MATERIAL Material[16];
static RGBA matlColors[MATL_MAX] = {{1.0f, 0.0f, 0.0f, 1.0f},
{0.0f, 1.0f, 0.0f, 1.0f},
{0.0f, 0.0f, 1.0f, 1.0f},
{1.0f, 1.0f, 0.0f, 1.0f},
{0.0f, 1.0f, 1.0f, 1.0f},
{1.0f, 0.0f, 1.0f, 1.0f},
{0.235f, 0.0f, 0.78f, 1.0f},
};
// Global variables defining current position and orientation.
GLuint DListCube;
UINT guiTimerTick = 1;
POINT gptWindow;
SIZE gszWindow;
RECT grcCurWindow;
float curquat[4], lastquat[4];
LONG glMouseDownX, glMouseDownY;
BOOL gbLeftMouse = FALSE;
BOOL gbSpinning = FALSE;
SHADE gShadeMode = SHADE_FLAT;
POLYDRAW gPolyDrawMode = POLYDRAW_FILLED;
GLfloat gfCurEyeZ = 5.0f, gfGoToEyeZ = 5.0f;
MESH mesh;
CURVE curve;
POINT3D apt[] = {
// {0.0f, 1.0f, 0.0f},
// {1.0f, 0.8f, 0.0f},
// {0.5f, -0.8f, 0.0f},
// {0.0f, -1.0f, 0.0f}
{0.3f, 0.5f, 0.0f},
{1.0f, 0.4f, 0.0f},
{0.5f, -0.4f, 0.0f},
{0.3f, -0.5f, 0.0f},
{0.3f, 0.5f, 0.0f}
};
int steps = 12;
HGLRC ghrc = (HGLRC) 0;
HPALETTE ghpalOld, ghPalette = (HPALETTE) 0;
HWND ghwndObject;
void CreateObjectWindow( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
static char szAppName[] = "Lathe";
static char szIniFile[] = "lathe.ini";
RECT Rect;
WNDCLASS wndclass;
if ( !hPrevInstance )
{
wndclass.style = CS_OWNDC;
wndclass.lpfnWndProc = (WNDPROC)WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
//wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hCursor = NULL;
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
// With a NULL icon handle, app will paint into the icon window.
wndclass.hIcon = NULL;
//wndclass.hIcon = LoadIcon(hInstance, "CubeIcon");
RegisterClass(&wndclass);
}
/*
* Make the windows a reasonable size and pick a
* position for it.
*/
Rect.left = GetPrivateProfileInt("ObjectWindow", "left", 500, szIniFile);
Rect.top = GetPrivateProfileInt("ObjectWindow", "top", 50, szIniFile);
Rect.right = GetPrivateProfileInt("ObjectWindow", "right", 900, szIniFile);
Rect.bottom = GetPrivateProfileInt("ObjectWindow", "bottom", 450, szIniFile);
guiTimerTick= GetPrivateProfileInt("Animate", "Timer", 1, szIniFile);
gptWindow.x = Rect.left;
gptWindow.y = Rect.top;
gszWindow.cx = WINDSIZEX(Rect);
gszWindow.cy = WINDSIZEY(Rect);
AdjustWindowRect( &Rect, WS_OVERLAPPEDWINDOW, FALSE );
ghwndObject = CreateWindow(szAppName, // window class name
"Lathe", // window caption
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
Rect.left, // initial x position
Rect.top, // initial y position
WINDSIZEX(Rect), // initial x size
WINDSIZEY(Rect), // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL // creation parameter
);
ShowWindow( ghwndObject, nCmdShow );
UpdateWindow( ghwndObject );
SetTimer(ghwndObject, 1, guiTimerTick, NULL);
}
long
WndProc ( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
HDC hdc;
PAINTSTRUCT ps;
switch ( message )
{
case WM_CREATE:
if(hdc = GetDC(hwnd))
{
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
ReleaseDC(hwnd,hdc);
}
break;
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
DoGlStuff( hwnd, hdc );
EndPaint( hwnd, &ps );
return 0;
case WM_MOVE:
gptWindow.x = (int) LOWORD(lParam);
gptWindow.y = (int) HIWORD(lParam);
return 0;
case WM_SIZE:
gszWindow.cx = LOWORD(lParam);
gszWindow.cy = HIWORD(lParam);
vSetSize(hwnd);
ForceRedraw(hwnd);
return 0;
case WM_PALETTECHANGED:
if (hwnd != (HWND) wParam)
{
if (hdc = GetDC(hwnd))
{
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, TRUE);
if (RealizePalette(hdc) != GDI_ERROR)
return 1;
}
}
return 0;
case WM_QUERYNEWPALETTE:
if (hdc = GetDC(hwnd))
{
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, FALSE);
if (RealizePalette(hdc) != GDI_ERROR)
return 1;
}
return 0;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostMessage(hwnd, WM_DESTROY, 0, 0);
break;
case VK_UP:
gfGoToEyeZ -= 1.0f;
break;
case VK_DOWN:
gfGoToEyeZ += 1.0f;
break;
default:
break;
}
return 0;
case WM_LBUTTONDOWN:
SetCapture(hwnd);
glMouseDownX = LOWORD(lParam);
glMouseDownY = HIWORD(lParam);
gbLeftMouse = TRUE;
ForceRedraw(hwnd);
return 0;
case WM_LBUTTONUP:
ReleaseCapture();
gbLeftMouse = FALSE;
ForceRedraw(hwnd);
return 0;
case WM_CHAR:
switch(wParam)
{
case '[':
case '{':
guiTimerTick = guiTimerTick << 1;
guiTimerTick = min(0x40000000, guiTimerTick);
KillTimer(hwnd, 1);
SetTimer(hwnd, 1, guiTimerTick, NULL);
break;
case ']':
case '}':
guiTimerTick = guiTimerTick >> 1;
guiTimerTick = max(1, guiTimerTick);
KillTimer(hwnd, 1);
SetTimer(hwnd, 1, guiTimerTick, NULL);
break;
case ',':
case '<':
if (steps > 4) // also have at least 3 sides -- its 3D!
{
steps--;
vMakeObject();
}
break;
case '.':
case '>':
steps++;
vMakeObject();
break;
case 's':
case 'S':
gShadeMode = (gShadeMode + 1) % 3;
switch (gShadeMode)
{
case SHADE_SMOOTH_AROUND:
case SHADE_SMOOTH_BOTH:
glShadeModel(GL_SMOOTH);
break;
case SHADE_FLAT:
default:
glShadeModel(GL_FLAT);
break;
}
vMakeObject();
break;
case 'w':
case 'W':
gPolyDrawMode = (gPolyDrawMode + 1) % 3;
switch (gPolyDrawMode)
{
case POLYDRAW_POINTS:
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glEnable(GL_FOG);
//glDisable(GL_STENCIL_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
break;
case POLYDRAW_LINES:
glDisable(GL_LIGHTING);
glDisable(GL_CULL_FACE);
glEnable(GL_FOG);
//glEnable(GL_STENCIL_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
break;
case POLYDRAW_FILLED:
default:
glEnable(GL_LIGHTING);
glEnable(GL_CULL_FACE);
glDisable(GL_FOG);
//glDisable(GL_STENCIL_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
break;
}
break;
default:
break;
}
return 0;
case WM_TIMER:
hdc = GetDC(hwnd);
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
if ( fabs(gfCurEyeZ - gfGoToEyeZ) > 0.1f )
{
gfCurEyeZ += (gfCurEyeZ < gfGoToEyeZ) ? 0.2f : -0.2f;
vSetSize(hwnd);
}
DoGlStuff( hwnd, hdc );
ReleaseDC(hwnd, hdc);
return 0;
#if 1
case WM_DESTROY:
vCleanupGL(ghrc);
KillTimer(hwnd, 1);
PostQuitMessage( 0 );
PostMessage(ghwndInput, WM_QUIT, 0, 0); // quit input thread too
return 0;
#endif
case WM_USER_INPUTMESH:
vMeshToList();
return 0;
default:
break;
}
return( DefWindowProc( hwnd, message, wParam, lParam ) );
}
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);
//SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
ghpalOld = SelectPalette(hdc, ghPalette, FALSE);
n = RealizePalette(hdc);
UnrealizeObject(ghPalette);
n = RealizePalette(hdc);
}
}
BOOL bSetupPixelFormat(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
int pixelformat;
ppfd = &pfd;
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;
}
void initMaterial(int id, float r, float g, float b, float a)
{
Material[id].ka.r = r;
Material[id].ka.g = g;
Material[id].ka.b = b;
Material[id].ka.a = a;
Material[id].kd.r = r;
Material[id].kd.g = g;
Material[id].kd.b = b;
Material[id].kd.a = a;
Material[id].ks.r = 1.0f;
Material[id].ks.g = 1.0f;
Material[id].ks.b = 1.0f;
Material[id].ks.a = 1.0f;
Material[id].specExp = 128.0f;
Material[id].indexStart = (float) (id * PALETTE_PER_MATL);
}
HGLRC hrcInitGL(HWND hwnd, HDC hdc)
{
HGLRC hrc;
int i;
GLfloat fDens = 0.25;
/* Create a Rendering Context */
bSetupPixelFormat( hdc );
hrc = wglCreateContext( hdc );
/* Make it Current */
wglMakeCurrent( hdc, hrc );
glDrawBuffer(GL_BACK);
/* Set the clear color */
glClearColor( ZERO, ZERO, ZERO, ONE );
/* Turn on z-buffer */
glEnable(GL_DEPTH_TEST);
/* Turn on backface culling */
glEnable(GL_CULL_FACE);
/* Shading */
//glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);
/* Initialize materials */
for (i = 0; i < 7; i++)
initMaterial(i, matlColors[i].r, matlColors[i].g,
matlColors[i].b, matlColors[i].a);
/* Turn on the lights */
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat *) &lightAmbient);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
glLightfv(GL_LIGHT0, GL_AMBIENT, (GLfloat *) &light0Ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, (GLfloat *) &light0Diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, (GLfloat *) &light0Specular);
glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (GLfloat *) &Material[0].ks);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, (GLfloat *) &Material[0].specExp);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &Material[0].kd);
glColor4f( ONE, ONE, ONE, ONE );
glFogi(GL_FOG_MODE, GL_EXP);
glFogfv(GL_FOG_DENSITY, &fDens);
//glFogi(GL_FOG_MODE, GL_LINEAR);
//glFogi(GL_FOG_END, 10);
/* Generate a display list for a cube */
DListCube = glGenLists(1);
curve.numPoints = sizeof(apt) / sizeof(POINT3D);
curve.pts = apt;
vMakeObject();
vSetSize(hwnd);
trackball(curquat, 0.0, 0.0, 0.0, 0.0);
return hrc;
}
VOID vMakeObject()
{
if (glIsList(DListCube))
{
glDeleteLists(DListCube, 1);
delMesh(&mesh);
}
revolveSurface(&mesh, &curve, steps);
MakeList(DListCube, &mesh);
}
VOID vInputThreadMakeObject()
{
delMesh(&mesh);
revolveSurface(&mesh, &curve, steps);
SendMessage(ghwndObject, WM_USER_INPUTMESH, 0, 0);
}
VOID vMeshToList()
{
if (glIsList(DListCube))
{
glDeleteLists(DListCube, 1);
}
MakeList(DListCube, &mesh);
}
VOID vSetSize(HWND hwnd)
{
/* Set up viewport extents */
glViewport(0, 0, gszWindow.cx, gszWindow.cy);
/* Set up the projection matrix */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 1.0, 0.1, 100.0);
/* Set up the model matrix */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,gfCurEyeZ, 0,0,0, 0,-1,0);
}
void
vCleanupGL(HGLRC hrc)
{
glDeleteLists(DListCube, 1);
delMesh(&mesh);
//if (ghPalette)
// DeleteObject(SelectObject(ghdcMem, ghpalOld));
/* Destroy our context */
wglDeleteContext( hrc );
}
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 )
{
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);
gbSpinning = TRUE;
}
else
gbSpinning = FALSE;
glMouseDownX = pt.x;
glMouseDownY = pt.y;
}
}
glPushMatrix();
if (gbSpinning)
add_quats(lastquat, curquat, curquat);
build_rotmatrix(matRot, curquat);
glMultMatrixf(&(matRot[0][0]));
#if 0
if (gPolyDrawMode == POLYDRAW_LINES)
{
// Use stencil buffer technique to do hidden line removal.
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
#if 1
// Create a stencil mask using the lines.
glStencilFunc( GL_ALWAYS, 0, 1 );
glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT );
glColor4f( ONE, ONE, ONE, ONE );
glCallList(DListCube);
// Fill in the faces where there aren't already lines.
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glStencilFunc( GL_EQUAL, 0, 1 );
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
glColor4f( ZERO, ZERO, ZERO, ONE );
glCallList(DListCube);
// ????
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glStencilFunc( GL_ALWAYS, 0, 1 );
glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT );
glColor4f( ONE, ONE, ONE, ONE );
glCallList(DListCube);
#else
glDisable(GL_STENCIL_TEST);
glDepthFunc(GL_LEQUAL);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glColor4f( ZERO, ZERO, ZERO, ONE );
glCallList(DListCube);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor4f( ONE, ONE, ONE, ONE );
glCallList(DListCube);
glDepthFunc(GL_LESS);
#endif
}
else
#endif
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glCallList(DListCube);
}
glPopMatrix();
SwapBuffers(hdc);
}