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

1206 lines
32 KiB
C

/******************************Module*Header*******************************\
* Module Name: timecube.c
*
* Simple app to render a rotating color cube.
*
* Copyright (c) 1995 Microsoft Corporation
*
\**************************************************************************/
#include <windows.h>
#include <time.h>
#include <sys\types.h>
#include <sys\timeb.h>
#include <gl\gl.h>
#include "fastdib.h"
#define GAMMA_CORRECTION 10
LONG WndProc(HWND, UINT, WPARAM, LPARAM);
VOID vDraw(HWND, HDC);
HGLRC hrcInitGL(HWND, HDC);
VOID vResizeDoubleBuffer(HWND, HDC);
VOID vCleanupGL(HDC, HGLRC);
BOOL bSetupPixelFormat(HDC);
HPALETTE CreateRGBPalette(HDC);
HDC MyCreateCompatibleDC(HDC);
VOID vSetSize(HWND);
ULONG DbgPrint(PCH DebugMessage, ... );
#define WINDSIZEX(Rect) (Rect.right - Rect.left)
#define WINDSIZEY(Rect) (Rect.bottom - Rect.top)
#define ZERO ((GLfloat)0.0)
#define ONE ((GLfloat)1.0)
#define POINT_TWO ((GLfloat)0.2)
#define POINT_SEVEN ((GLfloat)0.7)
#define THREE ((GLfloat)3.0)
#define FIVE ((GLfloat)5.0)
#define TEN ((GLfloat)10.0)
#define FORTY_FIVE ((GLfloat)45.0)
#define FIFTY ((GLfloat)50.0)
//
// Default Logical Palette indexes
//
#define BLACK_INDEX 0
#define WHITE_INDEX 19
#define RED_INDEX 13
#define GREEN_INDEX 14
#define BLUE_INDEX 16
#define YELLOW_INDEX 15
#define MAGENTA_INDEX 17
#define CYAN_INDEX 18
#define ClearColor ZERO, ZERO, ZERO, ONE
#define Cyan ZERO, ONE, ONE, ONE
#define Yellow ONE, ONE, ZERO, ONE
#define Magenta ONE, ZERO, ONE, ONE
#define Red ONE, ZERO, ZERO, ONE
#define Green ZERO, ONE, ZERO, ONE
#define Blue ZERO, ZERO, ONE, ONE
#define White ONE, ONE, ONE, ONE
#define Black ZERO, ZERO, ZERO, ONE
//
// Global variables defining current position and orientation.
//
GLfloat AngleX = (GLfloat)145.0;
GLfloat AngleY = FIFTY;
GLfloat AngleZ = ZERO;
GLfloat DeltaAngle[3] = { TEN, FIVE, -FIVE };
GLfloat OffsetX = ZERO;
GLfloat OffsetY = ZERO;
GLfloat OffsetZ = -THREE;
GLuint DListCube;
UINT guiTimerTick = 1;
ULONG gulZoom = 1;
HDC ghdcMem;
HBITMAP ghbmBackBuffer = (HBITMAP) 0, ghbmOld;
HGLRC ghrc = (HGLRC) 0;
HPALETTE ghpalOld, ghPalette = (HPALETTE) 0;
BOOL bResetStats = TRUE;
struct _timeb thisTime, baseTime;
int frameCount;
void printmemdc(HDC hdc)
{
HBITMAP hbm;
HPALETTE hpal;
int i, iMax;
BYTE aj[(sizeof(PALETTEENTRY) + sizeof(RGBQUAD)) * 256];
LPPALETTEENTRY lppe = (LPPALETTEENTRY) aj;
RGBQUAD *prgb = (RGBQUAD *) (lppe + 256);
hbm = GetCurrentObject(hdc, OBJ_BITMAP);
hpal = GetCurrentObject(hdc, OBJ_PAL);
DbgPrint("Palette\n");
iMax = GetPaletteEntries(hpal, 0, 256, lppe);
for (i = 0; i < iMax; i++)
DbgPrint("%ld\t(0x%02x, 0x%02x, 0x%02x)\n",
i, lppe[i].peRed, lppe[i].peGreen, lppe[i].peBlue);
DbgPrint("Color table\n");
iMax = GetDIBColorTable(hdc, 0, 256, prgb);
for (i = 0; i < iMax; i++)
DbgPrint("%ld\t(0x%02x, 0x%02x, 0x%02x)\n",
i, prgb[i].rgbRed, prgb[i].rgbGreen, prgb[i].rgbBlue);
}
/******************************Public*Routine******************************\
* WinMain
*
* Program entry point.
*
\**************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
static char szAppName[] = "TimeCube";
HWND hwnd;
MSG msg;
RECT rc;
WNDCLASS wndclass;
char title[32];
//
// Create window class.
//
if (!hPrevInstance)
{
wndclass.style = CS_OWNDC;
wndclass.lpfnWndProc = (WNDPROC)WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hCursor = NULL;
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
wndclass.hIcon = LoadIcon(hInstance, "CubeIcon");
RegisterClass(&wndclass);
}
//
// Make the windows a reasonable size and pick a position for it.
//
rc.left = 100;
rc.top = 100;
rc.right = 300;
rc.bottom = 300;
guiTimerTick = 1;
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
hwnd = CreateWindow(szAppName, // window class name
szAppName, // window caption
WS_OVERLAPPEDWINDOW
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
CW_USEDEFAULT, // initial x position
rc.top, // initial y position
WINDSIZEX(rc), // initial x size
WINDSIZEY(rc), // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL // creation parameter
);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
//
// Setup timer. We will draw cube every timer tick.
//
SetTimer(hwnd, 1, guiTimerTick, NULL);
//
// Message loop.
//
while ( GetMessage(&msg, NULL, 0, 0) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return( msg.wParam );
}
/******************************Public*Routine******************************\
* WndProc
*
* Window procedure. Process window messages.
*
\**************************************************************************/
LONG WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HDC hdc = (HDC) NULL;
PAINTSTRUCT ps;
switch (message)
{
case WM_CREATE:
//
// Our app is going to hold the DC for the duration of the
// window to avoid having to call wglMakeCurrent each time.
//
// An alternative would be to create window as CS_OWNDC.
//
hdc = GetDC(hwnd);
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
return(0);
case WM_PAINT:
BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
if (ghrc == (HGLRC) 0)
ghrc = hrcInitGL(hwnd, hdc);
vDraw(hwnd, hdc);
return(0);
case WM_SIZE:
vResizeDoubleBuffer(hwnd, hdc);
vSetSize(hwnd);
return(0);
case WM_PALETTECHANGED:
if (hwnd != (HWND) wParam)
{
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, TRUE);
if (RealizePalette(hdc) != GDI_ERROR)
return 1;
}
return 0;
case WM_QUERYNEWPALETTE:
UnrealizeObject(ghPalette);
SelectPalette(hdc, ghPalette, FALSE);
if (RealizePalette(hdc) != GDI_ERROR)
return 1;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
PostMessage(hwnd, WM_DESTROY, 0, 0);
break;
default:
break;
}
return 0;
case WM_CHAR:
switch(wParam)
{
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
gulZoom = wParam - '0';
vResizeDoubleBuffer(hwnd, hdc);
vSetSize(hwnd);
break;
case 'd':
case 'D':
OffsetX += POINT_TWO;
break;
case 'a':
case 'A':
OffsetX -= POINT_TWO;
break;
case 's':
case 'S':
OffsetY += POINT_TWO;
break;
case 'w':
case 'W':
OffsetY -= POINT_TWO;
break;
case 'q':
case 'Q':
OffsetZ += POINT_TWO;
break;
case 'e':
case 'E':
OffsetZ -= POINT_TWO;
break;
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;
default:
break;
}
return 0;
case WM_TIMER:
//
// Each timer tick, we change the angle and draw a new frame.
//
AngleX += DeltaAngle[0];
if (AngleX > 360.0f)
AngleX -= 360.0f;
AngleY += DeltaAngle[1];
if (AngleY > 360.0f)
AngleY -= 360.0f;
AngleZ += DeltaAngle[2];
if (AngleZ > 360.0f)
AngleZ -= 360.0f;
vDraw(hwnd, hdc);
return 0;
case WM_DESTROY:
vCleanupGL(hdc, ghrc);
ReleaseDC(hwnd, hdc);
KillTimer(hwnd, 1);
PostQuitMessage( 0 );
return( 0 );
}
return( DefWindowProc( hwnd, message, wParam, lParam ) );
}
/******************************Public*Routine******************************\
* vResizeDoubleBuffer
*
\**************************************************************************/
void vResizeDoubleBuffer(HWND hwnd, HDC hdc)
{
RECT rc;
HBITMAP hbmNew;
PVOID pvBits;
if (ghdcMem)
{
GetClientRect(hwnd, &rc);
hbmNew = CreateCompatibleDIB(hdc, NULL, WINDSIZEX(rc)/gulZoom, WINDSIZEY(rc)/gulZoom, &pvBits);
if (hbmNew)
{
if (ghbmBackBuffer != (HBITMAP) 0)
{
SelectObject(ghdcMem, ghbmOld);
DeleteObject(ghbmBackBuffer);
}
ghbmBackBuffer = hbmNew;
ghbmOld = SelectObject(ghdcMem, ghbmBackBuffer);
}
else
DbgPrint("vResizeDoubleBuffer: CreateCompatibleBitmap failed\n");
}
else
DbgPrint("vResizeDoubleBuffer: no memdc\n");
bResetStats = TRUE;
}
/******************************Public*Routine******************************\
* ComponentFromIndex
*
* Translates an 8-bit index into the corresponding 332 RGB value.
* Used only on 8bpp displays.
*
\**************************************************************************/
// Conversion tables for n bits to eight bits
#if GAMMA_CORRECTION == 10
// These tables are corrected for a gamma of 1.0
static unsigned char abThreeToEight[8] =
{
0, 0111 >> 1, 0222 >> 1, 0333 >> 1, 0444 >> 1, 0555 >> 1, 0666 >> 1, 0377
};
static unsigned char abTwoToEight[4] =
{
0, 0x55, 0xaa, 0xff
};
static unsigned char abOneToEight[2] =
{
0, 255
};
#else
// These tables are corrected for a gamma of 1.4
static unsigned char abThreeToEight[8] =
{
0, 63, 104, 139, 171, 200, 229, 255
};
static unsigned char abTwoToEight[4] =
{
0, 116, 191, 255
};
static unsigned char abOneToEight[2] =
{
0, 255
};
#endif
unsigned char
ComponentFromIndex(i, nbits, shift)
{
unsigned char val;
val = i >> shift;
switch (nbits) {
case 1:
val &= 0x1;
return abOneToEight[val];
case 2:
val &= 0x3;
return abTwoToEight[val];
case 3:
val &= 0x7;
return abThreeToEight[val];
default:
return 0;
}
}
/******************************Public*Routine******************************\
*
* UpdateStaticMapping
*
* Computes the best match between the current system static colors
* and a 3-3-2 palette
*
* History:
* Tue Aug 01 18:18:12 1995 -by- Drew Bliss [drewb]
* Created
*
\**************************************************************************/
#define STATIC_COLORS 20
#define EXACT_MATCH 1
#define COLOR_USED 1
#define MAX_COL_DIST (3*256*256L)
// Table which indicates which colors in a 3-3-2 palette should be
// replaced with the system default colors
#if GAMMA_CORRECTION == 10
static int aiDefaultOverride[STATIC_COLORS] =
{
0, 4, 32, 36, 128, 132, 160, 173, 181, 245,
247, 164, 156, 7, 56, 63, 192, 199, 248, 255
};
#else
static int aiDefaultOverride[STATIC_COLORS] =
{
0, 3, 24, 27, 64, 67, 88, 173, 181, 236,
247, 164, 91, 7, 56, 63, 192, 199, 248, 255
};
#endif
static PALETTEENTRY apeDefaultPalEntry[STATIC_COLORS] =
{
{ 0, 0, 0, 0 },
{ 0x80,0, 0, 0 },
{ 0, 0x80,0, 0 },
{ 0x80,0x80,0, 0 },
{ 0, 0, 0x80, 0 },
{ 0x80,0, 0x80, 0 },
{ 0, 0x80,0x80, 0 },
{ 0xC0,0xC0,0xC0, 0 },
{ 192, 220, 192, 0 },
{ 166, 202, 240, 0 },
{ 255, 251, 240, 0 },
{ 160, 160, 164, 0 },
{ 0x80,0x80,0x80, 0 },
{ 0xFF,0, 0, 0 },
{ 0, 0xFF,0, 0 },
{ 0xFF,0xFF,0, 0 },
{ 0, 0, 0xFF, 0 },
{ 0xFF,0, 0xFF, 0 },
{ 0, 0xFF,0xFF, 0 },
{ 0xFF,0xFF,0xFF, 0 }
};
static void
UpdateStaticMapping(PALETTEENTRY *pe332Palette)
{
HPALETTE hpalStock;
int iStatic, i332;
int iMinDist, iDist;
int iDelta;
int iMinEntry;
PALETTEENTRY *peStatic, *pe332;
hpalStock = GetStockObject(DEFAULT_PALETTE);
// Get the current static colors
GetPaletteEntries(hpalStock, 0, STATIC_COLORS, apeDefaultPalEntry);
// Zero the flags in the static colors because they are used later
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
peStatic->peFlags = 0;
peStatic++;
}
// Zero the flags in the incoming palette because they are used later
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
pe332->peFlags = 0;
pe332++;
}
// Try to match each static color exactly
// This saves time by avoiding the least-squares match for each
// exact match
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
if (peStatic->peRed == pe332->peRed &&
peStatic->peGreen == pe332->peGreen &&
peStatic->peBlue == pe332->peBlue)
{
peStatic->peFlags = EXACT_MATCH;
pe332->peFlags = COLOR_USED;
aiDefaultOverride[iStatic] = i332;
break;
}
pe332++;
}
peStatic++;
}
// Match each static color as closely as possible to an entry
// in the 332 palette by minimized the square of the distance
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
// Skip colors already matched exactly
if (peStatic->peFlags == EXACT_MATCH)
{
peStatic++;
continue;
}
iMinDist = MAX_COL_DIST+1;
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
// Skip colors already used
if (pe332->peFlags == COLOR_USED)
{
pe332++;
continue;
}
// Compute Euclidean distance squared
iDelta = pe332->peRed-peStatic->peRed;
iDist = iDelta*iDelta;
iDelta = pe332->peGreen-peStatic->peGreen;
iDist += iDelta*iDelta;
iDelta = pe332->peBlue-peStatic->peBlue;
iDist += iDelta*iDelta;
if (iDist < iMinDist)
{
iMinDist = iDist;
iMinEntry = i332;
}
pe332++;
}
// Remember the best match
aiDefaultOverride[iStatic] = iMinEntry;
pe332Palette[iMinEntry].peFlags = COLOR_USED;
peStatic++;
}
// Zero the flags in the static colors because they may have been
// set. We want them to be zero so the colors can be remapped
peStatic = apeDefaultPalEntry;
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
peStatic->peFlags = 0;
peStatic++;
}
// Reset the 332 flags because we may have modified them
pe332 = pe332Palette;
for (i332 = 0; i332 < 256; i332++)
{
pe332->peFlags = PC_NOCOLLAPSE;
pe332++;
}
#if 0
for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++)
{
DbgPrint("Static color %2d maps to %d\n",
iStatic, aiDefaultOverride[iStatic]);
}
#endif
}
/******************************Public*Routine******************************\
* FlushPalette
*
* Because of Win 3.1 compatibility, GDI palette mapping always starts
* at zero and stops at the first exact match. So if there are duplicates,
* the higher colors aren't mapped to--which is often a problem if we
* are trying to make to any of the upper 10 static colors. To work around
* this, we flush the palette to all black.
*
* This only needs to be done for the 8BPP (256 color) case.
*
\**************************************************************************/
static void
FlushPalette(HDC hdc, int nColors)
{
LOGPALETTE *pPal;
HPALETTE hpal, hpalOld;
int i;
if (nColors == 256)
{
pPal = (LOGPALETTE *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT,
sizeof(LOGPALETTE) + nColors * sizeof(PALETTEENTRY));
if (pPal)
{
pPal->palVersion = 0x300;
pPal->palNumEntries = nColors;
// Mark everything PC_NOCOLLAPSE and PC_RESERVED to force every thing
// into the palette. Colors are already black because we zero initialized
// during memory allocation.
for (i = 0; i < nColors; i++)
{
pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE | PC_RESERVED;
}
hpal = CreatePalette(pPal);
LocalFree(pPal);
hpalOld = SelectPalette(hdc, hpal, FALSE);
RealizePalette(hdc);
SelectPalette(hdc, hpalOld, FALSE);
DeleteObject(hpal);
}
}
}
/******************************Public*Routine******************************\
* CreateRGBPalette
*
* If required by the pixelformat, create the logical palette and select
* into DC.
*
\**************************************************************************/
HPALETTE CreateRGBPalette(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
LOGPALETTE *pPal;
int n, i;
HPALETTE hpalRet = ghPalette;
if (!hpalRet)
{
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 = PC_NOCOLLAPSE;
}
if (n == 256)
{
pPal->palPalEntry[0].peFlags = 0;
pPal->palPalEntry[255].peFlags = 0;
// The defaultOverride array is computed assuming a 332
// palette where red has zero shift, etc.
if ( (3 == ppfd->cRedBits) && (0 == ppfd->cRedShift) &&
(3 == ppfd->cGreenBits) && (3 == ppfd->cGreenShift) &&
(2 == ppfd->cBlueBits) && (6 == ppfd->cBlueShift) )
{
UpdateStaticMapping(pPal->palPalEntry);
for ( i = 0 ; i < STATIC_COLORS ; i++)
{
pPal->palPalEntry[aiDefaultOverride[i]] = apeDefaultPalEntry[i];
}
}
}
hpalRet = CreatePalette(pPal);
LocalFree(pPal);
}
}
return hpalRet;
}
/******************************Public*Routine******************************\
* bSetupPixelFormat
*
* Choose and set pixelformat.
\**************************************************************************/
BOOL bSetupPixelFormat(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
PIXELFORMATDESCRIPTOR pfdGot, *ppfdGot;
int pixelformat;
ppfd = &pfd;
ppfdGot = &pfdGot;
memset(ppfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
if (GetObjectType(hdc) == OBJ_MEMDC)
{
ppfd->dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL;
}
else
{
ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
}
ppfd->iPixelType = PFD_TYPE_RGBA;
ppfd->cColorBits = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);;
ppfd->cDepthBits = 0;
ppfd->cAccumBits = 0;
ppfd->cStencilBits = 0;
ppfd->iLayerType = PFD_MAIN_PLANE;
ppfd->dwLayerMask = PFD_MAIN_PLANE;
if ( (pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0 )
{
MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
return FALSE;
}
DescribePixelFormat(hdc, pixelformat, sizeof(*ppfdGot), ppfdGot);
if ( ((ppfd->dwFlags & PFD_DRAW_TO_BITMAP) && !(ppfdGot->dwFlags & PFD_DRAW_TO_BITMAP)) ||
((ppfd->dwFlags & PFD_DRAW_TO_WINDOW) && !(ppfdGot->dwFlags & PFD_DRAW_TO_WINDOW)) )
MessageBoxA(NULL, "bad flag", "warning",MB_OK);
if (ppfdGot->cColorBits != ppfd->cColorBits)
MessageBoxA(NULL, "bad color depth", "warning", MB_OK);
if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE)
{
MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
return FALSE;
}
if (ppfdGot->dwFlags & PFD_NEED_PALETTE)
{
ghPalette = CreateRGBPalette(hdc);
//!!!dbug
//SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC);
//UnrealizeObject(ghPalette);
FlushPalette(hdc, 1 << ppfdGot->cColorBits);
ghpalOld = SelectPalette(hdc, ghPalette, FALSE);
RealizePalette(hdc);
}
return TRUE;
}
/******************************Public*Routine******************************\
* hrcInitGL
*
* Initialize OpenGL.
*
\**************************************************************************/
HGLRC hrcInitGL(HWND hwnd, HDC hdc)
{
HGLRC hrc;
//
// Create a Rendering Context and make it current.
// If rendering to a bitmap, create the memdc and bitmap.
//
bSetupPixelFormat(hdc);
ghdcMem = CreateCompatibleDC(hdc);
//ghdcMem = MyCreateCompatibleDC(hdc);
if (!ghdcMem)
DbgPrint("CreateCompatibleDC failed\n");
vResizeDoubleBuffer(hwnd, hdc);
//UpdateDIBColorTable(ghdcMem, hdc, NULL);
bSetupPixelFormat(ghdcMem);
hrc = wglCreateContext(ghdcMem);
wglMakeCurrent(ghdcMem, hrc);
//
// Setup OpenGL state.
//
glPushAttrib(GL_TEXTURE_BIT | GL_LIGHTING_BIT | GL_TRANSFORM_BIT);
glClearColor( ClearColor );
glEnable(GL_CULL_FACE);
glDrawBuffer(GL_FRONT);
glDisable(GL_DEPTH_TEST);
//
// Generate color cube as a display list.
//
DListCube = glGenLists(1);
glNewList(DListCube, GL_COMPILE);
glBegin(GL_QUADS);
glColor4f( White );
glVertex3f( POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( Magenta );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( Red );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glColor4f( Yellow );
glVertex3f( POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Yellow );
glVertex3f( POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Red );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glColor4f( Black );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glColor4f( Green );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Green );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Black );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glColor4f( Blue );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( Cyan );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( Cyan );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( Blue );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( Magenta );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( White );
glVertex3f( POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( White );
glVertex3f( POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( Yellow );
glVertex3f( POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Green );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, -POINT_SEVEN);
glColor4f( Cyan );
glVertex3f( -POINT_SEVEN, POINT_SEVEN, POINT_SEVEN);
glColor4f( Magenta );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( Blue );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, POINT_SEVEN);
glColor4f( Black );
glVertex3f( -POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glColor4f( Red );
glVertex3f( POINT_SEVEN, -POINT_SEVEN, -POINT_SEVEN);
glEnd();
glEndList();
//
// Setup transforms.
//
vSetSize(hwnd);
return hrc;
}
/******************************Public*Routine******************************\
* vSetSize
*
* Setup the OpenGL transforms.
*
\**************************************************************************/
VOID vSetSize(HWND hwnd)
{
RECT rc;
GetClientRect(hwnd, &rc);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(OffsetX, OffsetY, OffsetZ);
glViewport(0, 0, WINDSIZEX(rc)/gulZoom, WINDSIZEY(rc)/gulZoom);
}
/******************************Public*Routine******************************\
* vCleanupGL
*
* Release all the various OpenGL resources.
*
\**************************************************************************/
void vCleanupGL(HDC hdc, HGLRC hrc)
{
if (ghPalette)
DeleteObject(SelectObject(ghdcMem, ghpalOld));
wglDeleteContext( hrc );
DeleteObject(SelectObject(ghdcMem, ghbmOld));
DeleteDC(ghdcMem);
//!!!dbug
//SetSystemPaletteUse(hdc, SYSPAL_STATIC);
}
/******************************Public*Routine******************************\
* vDraw
*
* Draw the current frame.
*
\**************************************************************************/
void vDraw(HWND hwnd, HDC hdc)
{
RECT rc;
//
// Clear the buffer.
//
glClear(GL_COLOR_BUFFER_BIT);
//
// Save current transform.
//
glPushMatrix();
//
// Rotate transform to current orientation.
//
glRotatef(AngleX, ONE, ZERO, ZERO);
glRotatef(AngleY, ZERO, ONE, ZERO);
glRotatef(AngleZ, ZERO, ZERO, ONE);
//
// Draw the cube display list.
//
glCallList(DListCube);
//
// Restore the transform.
//
glPopMatrix();
//
// Flush OpenGL queque.
//
glFlush();
//
// Update the window from our bitmap.
//
GetClientRect(hwnd, &rc);
if (gulZoom == 1)
{
BitBlt(hdc, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
ghdcMem, 0, 0, SRCCOPY);
}
else
{
StretchBlt(hdc, 0, 0, rc.right, rc.bottom,
ghdcMem, 0, 0, rc.right/gulZoom, rc.bottom/gulZoom,
SRCCOPY);
}
//
// Flush GDI queque.
//
GdiFlush();
//!!!dbug
if (FALSE)
{
static BOOL bOnce = TRUE;
if (bOnce)
{
printmemdc(ghdcMem);
bOnce = FALSE;
}
}
//
// Accumulate statistics. Every 16 frames, print out the frames/sec.
// Statistics can be reset by forcing bResetStats TRUE.
//
if (bResetStats)
{
_ftime( &baseTime );
frameCount = 0;
bResetStats = FALSE;
}
else
{
frameCount++;
}
if ( !(frameCount & 0x0000000f) )
{
TCHAR ach[256];
double elapsed;
_ftime( &thisTime );
elapsed = thisTime.time + thisTime.millitm/1000.0 -
(baseTime.time + baseTime.millitm/1000.0);
if( elapsed != 0.0 )
{
int frameRate;
frameRate = (int) (100.0 * (frameCount / elapsed));
wsprintf(ach, TEXT("%ld.%02ld fps"), frameRate/100, frameRate%100 );
SetWindowText(hwnd, ach);
}
}
}
/******************************Public*Routine******************************\
* MyCreateCompatibleDC
*
*
* Effects:
*
* Warnings:
*
* History:
* 25-Jan-1996 -by- Gilman Wong [gilmanw]
* Wrote it.
\**************************************************************************/
HDC MyCreateCompatibleDC(HDC hdc)
{
HDC hdcRet;
HPALETTE hpal, hpalMem;
int nEntries;
hdcRet = CreateCompatibleDC(hdc);
if (!hdcRet)
{
DbgPrint("MyCreateCompatibleDC: CreateCompatibleDC failed\n");
}
//hpal = GetCurrentObject(hdc, OBJ_PAL);
//nEntries = GetPaletteEntries(hpal, 0, 0, NULL);
nEntries = GetSystemPaletteEntries(hdc, 0, 0, NULL);
if (nEntries)
{
LOGPALETTE *ppal;
ppal = LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) + (nEntries * sizeof(PALETTEENTRY)));
if (ppal)
{
ppal->palVersion = 0x300;
ppal->palNumEntries = nEntries;
//GetPaletteEntries(hpal, 0, nEntries, ppal->palPalEntry);
GetSystemPaletteEntries(hdc, 0, nEntries, ppal->palPalEntry);
hpalMem = CreatePalette(ppal);
if (!SelectPalette(hdcRet, hpalMem, FALSE) ||
!RealizePalette(hdcRet))
{
DbgPrint("MyCreateCompatibleDC: palette error\n");
}
}
else
{
DbgPrint("MyCreateCompatibleDC: memalloc error\n");
}
}
else
{
DbgPrint("MyCreateCompatibleDC: bad pal size\n");
}
return hdcRet;
}