1160 lines
28 KiB
C++
1160 lines
28 KiB
C++
#include "precomp.hxx"
|
|
#pragma hdrstop
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "glddint.hxx"
|
|
|
|
// Track the last error returned from a call made by this library
|
|
HRESULT hrGlddLast = DD_OK;
|
|
|
|
// Get the last Win32 error and turn it into an HRESULT
|
|
#define WIN32_HR() ((HRESULT)GetLastError())
|
|
|
|
// Window class
|
|
static char *pszClass = "glddWindow";
|
|
|
|
// Global IDirectDraw
|
|
static LPDIRECTDRAW pdd = NULL;
|
|
|
|
// Structure to pass window creation data
|
|
#pragma pack(1)
|
|
struct GLDDCREATESTRUCT
|
|
{
|
|
WORD wSize;
|
|
GLDDWINDOW gw;
|
|
};
|
|
#pragma pack()
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddWndProc
|
|
*
|
|
* Window procedure for gldd windows
|
|
*
|
|
* History:
|
|
* Fri Aug 30 13:00:23 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LRESULT glddWndProc(HWND hwnd, UINT uiMsg, WPARAM wpm, LPARAM lpm)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
LRESULT lr;
|
|
GLDDWINDOW gw;
|
|
GLDDCREATESTRUCT *pgcs;
|
|
|
|
// Set up the window-related data immediately on WM_CREATE so that
|
|
// a callback can be made for it as well as after it
|
|
if (uiMsg == WM_CREATE)
|
|
{
|
|
pgcs = (GLDDCREATESTRUCT *)((CREATESTRUCT *)lpm)->lpCreateParams;
|
|
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pgcs->gw);
|
|
}
|
|
|
|
gw = (GLDDWINDOW)GetWindowLong(hwnd, GWL_USERDATA);
|
|
|
|
// Pass off window messages if requested
|
|
if (gw != NULL && gw->_cbMessage != NULL)
|
|
{
|
|
if (gw->_cbMessage(gw, hwnd, uiMsg, wpm, lpm, &lr))
|
|
{
|
|
return lr;
|
|
}
|
|
}
|
|
|
|
switch(uiMsg)
|
|
{
|
|
case WM_PAINT:
|
|
// Validate paint region. The assumption is that the app will either
|
|
// interpose and catch the WM_PAINT itself or it's dynamic so
|
|
// the screen will be repainted shortly anyway. Either way,
|
|
// there's nothing for the library to do.
|
|
BeginPaint(hwnd, &ps);
|
|
EndPaint(hwnd, &ps);
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(hwnd);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// Doesn't work with multiple windows
|
|
PostQuitMessage(1);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uiMsg, wpm, lpm);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Default palette entry flags
|
|
#define PALETTE_FLAGS PC_NOCOLLAPSE
|
|
|
|
// Maximum color distance with 8-bit components
|
|
#define MAX_COL_DIST (3*256*256L)
|
|
|
|
// Number of static colors
|
|
#define STATIC_COLORS 20
|
|
|
|
// Flags used when matching colors
|
|
#define EXACT_MATCH 1
|
|
#define COLOR_USED 1
|
|
|
|
// Tables to convert color components between bit sizes
|
|
// 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
|
|
};
|
|
|
|
// Table which indicates which colors in a 3-3-2 palette should be
|
|
// replaced with the system default colors
|
|
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
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddComponentFromIndex
|
|
*
|
|
* Converts a color index to a color component
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:04:45 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
unsigned char glddComponentFromIndex(int i, int nbits, int shift)
|
|
{
|
|
unsigned char val;
|
|
|
|
val = i >> shift;
|
|
switch (nbits)
|
|
{
|
|
case 1:
|
|
return abOneToEight[val & 1];
|
|
|
|
case 2:
|
|
return abTwoToEight[val & 3];
|
|
|
|
case 3:
|
|
return abThreeToEight[val & 7];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// System default colors
|
|
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 }
|
|
};
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddUpdateStaticMapping
|
|
*
|
|
* 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
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddUpdateStaticMapping(PALETTEENTRY *pe332Palette)
|
|
{
|
|
HPALETTE hpalStock;
|
|
int iStatic, i332;
|
|
int iMinDist, iDist;
|
|
int iDelta;
|
|
int iMinEntry;
|
|
PALETTEENTRY *peStatic, *pe332;
|
|
|
|
hpalStock = (HPALETTE)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;
|
|
#if DBG
|
|
iMinEntry = -1;
|
|
#endif
|
|
|
|
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 set them
|
|
pe332 = pe332Palette;
|
|
for (i332 = 0; i332 < 256; i332++)
|
|
{
|
|
pe332->peFlags = PALETTE_FLAGS;
|
|
pe332++;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddMapInSystemColors
|
|
*
|
|
* Reorganizes the given palette to include the system colors in
|
|
* the lower and upper ten slots
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:07:32 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddMapInSystemColors(PALETTEENTRY *ppe)
|
|
{
|
|
int iOld, iNew, iDef;
|
|
PALETTEENTRY peTmp[256-STATIC_COLORS];
|
|
|
|
// Find matches between the given palette and the current system colors.
|
|
glddUpdateStaticMapping(ppe);
|
|
|
|
// Place the first half of the system colors at the beginning of
|
|
// the palette and the second half at the end of the palette.
|
|
// The colors in the given palette which match the system colors most
|
|
// closely are deleted and the remainder are packed into the middle
|
|
// entries.
|
|
iNew = 0;
|
|
for (iOld = 0; iOld < 256; iOld++)
|
|
{
|
|
for (iDef = 0; iDef < STATIC_COLORS; iDef++)
|
|
{
|
|
if (iOld == aiDefaultOverride[iDef])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iDef == STATIC_COLORS)
|
|
{
|
|
peTmp[iNew++] = ppe[iOld];
|
|
}
|
|
}
|
|
|
|
memcpy(ppe, apeDefaultPalEntry,
|
|
sizeof(PALETTEENTRY)*(STATIC_COLORS/2));
|
|
memcpy(ppe+STATIC_COLORS/2, peTmp,
|
|
sizeof(PALETTEENTRY)*(256-STATIC_COLORS));
|
|
memcpy(ppe+256-STATIC_COLORS/2, apeDefaultPalEntry+STATIC_COLORS/2,
|
|
sizeof(PALETTEENTRY)*(STATIC_COLORS/2));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* _GLDDWINDOW::_GLDDWINDOW
|
|
*
|
|
* Initialize fresh window to NULL
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:08:11 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
_GLDDWINDOW::_GLDDWINDOW(void)
|
|
{
|
|
_hwnd = NULL;
|
|
_hrc = NULL;
|
|
_pddc = NULL;
|
|
_pddsFront = NULL;
|
|
_pddsBack = NULL;
|
|
_pddsZ = NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* _GLDDWINDOW::Create
|
|
*
|
|
* Creates a new rendering window
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:34:15 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL _GLDDWINDOW::Create(char *pszTitle, int x, int y,
|
|
int iWidth, int iHeight, int iDepth,
|
|
DWORD dwFlags)
|
|
{
|
|
RECT rct;
|
|
DDSURFACEDESC ddsd, ddsdFront;
|
|
PIXELFORMATDESCRIPTOR pfd;
|
|
GLDDCREATESTRUCT gcs;
|
|
DDSCAPS ddscaps;
|
|
LPDIRECTDRAWSURFACE pddsRender;
|
|
int ipfd;
|
|
HDC hdc;
|
|
BOOL bRet;
|
|
DWORD dwZDepth;
|
|
|
|
// Create base window
|
|
if (dwFlags & GLDD_FULL_SCREEN)
|
|
{
|
|
rct.left = 0;
|
|
rct.top = 0;
|
|
rct.right = iWidth;
|
|
rct.bottom = iHeight;
|
|
}
|
|
else
|
|
{
|
|
rct.left = x;
|
|
rct.top = y;
|
|
rct.right = x+iWidth;
|
|
rct.bottom = y+iHeight;
|
|
AdjustWindowRect(&rct, WS_OVERLAPPEDWINDOW, FALSE);
|
|
}
|
|
|
|
gcs.wSize = sizeof(gcs);
|
|
gcs.gw = this;
|
|
_hwnd = CreateWindow(pszClass, pszTitle,
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
|
|
WS_CLIPSIBLINGS,
|
|
rct.left, rct.top,
|
|
rct.right-rct.left, rct.bottom-rct.top,
|
|
NULL, NULL, GetModuleHandle(NULL), &gcs);
|
|
if (_hwnd == NULL)
|
|
{
|
|
hrGlddLast = WIN32_HR();
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwFlags & GLDD_FULL_SCREEN)
|
|
{
|
|
DWORD dwDdFlags;
|
|
|
|
// If fullscreen, take over the screen, switch the video mode and
|
|
// create a complex flipping surface
|
|
|
|
dwDdFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;
|
|
if (dwFlags & GLDD_USE_MODE_X)
|
|
{
|
|
dwDdFlags |= DDSCL_ALLOWMODEX;
|
|
}
|
|
hrGlddLast = pdd->SetCooperativeLevel(_hwnd, dwDdFlags);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hrGlddLast = pdd->SetDisplayMode(iWidth, iHeight, iDepth);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memset(&ddsdFront, 0, sizeof(DDSURFACEDESC));
|
|
ddsdFront.dwSize = sizeof(ddsdFront);
|
|
ddsdFront.dwFlags = DDSD_CAPS;
|
|
ddsdFront.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
if (dwFlags & GLDD_BACK_BUFFER)
|
|
{
|
|
ddsdFront.dwFlags |= DDSD_BACKBUFFERCOUNT;
|
|
ddsdFront.dwBackBufferCount = 1;
|
|
ddsdFront.ddsCaps.dwCaps |= DDSCAPS_FLIP | DDSCAPS_COMPLEX;
|
|
}
|
|
hrGlddLast = pdd->CreateSurface(&ddsdFront, &_pddsFront, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
hrGlddLast = _pddsFront->GetSurfaceDesc(&ddsdFront);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwFlags & GLDD_BACK_BUFFER)
|
|
{
|
|
ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
|
|
hrGlddLast = _pddsFront->GetAttachedSurface(&ddscaps, &_pddsBack);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Ensure that the back buffer went into video memory so
|
|
// that flipping isn't emulated
|
|
if ((dwFlags & GLDD_STRICT_MEMORY) &&
|
|
(_pddsBack->GetSurfaceDesc(&ddsd) != DD_OK ||
|
|
(ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0))
|
|
{
|
|
hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If windowed, get access to the screen and attach a clipper
|
|
// for visrgn management.
|
|
|
|
hrGlddLast = pdd->SetCooperativeLevel(NULL, DDSCL_NORMAL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
memset(&ddsdFront, 0, sizeof(ddsdFront));
|
|
ddsdFront.dwSize = sizeof(DDSURFACEDESC);
|
|
ddsdFront.dwFlags = DDSD_CAPS;
|
|
ddsdFront.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
|
|
hrGlddLast = pdd->CreateSurface(&ddsdFront, &_pddsFront, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hrGlddLast = _pddsFront->GetSurfaceDesc(&ddsdFront);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hrGlddLast = pdd->CreateClipper(0, &_pddc, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
hrGlddLast = _pddc->SetHWnd(0, _hwnd);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
// Works with multiple windows? Depends on whether
|
|
// multiple primary creates have individual state
|
|
hrGlddLast = _pddsFront->SetClipper(_pddc);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwFlags & GLDD_BACK_BUFFER)
|
|
{
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
|
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
|
ddsd.dwWidth = iWidth;
|
|
ddsd.dwHeight = iHeight;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
|
|
if (dwFlags & GLDD_VIDEO_MEMORY)
|
|
{
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
}
|
|
else
|
|
{
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
|
}
|
|
hrGlddLast = pdd->CreateSurface(&ddsd, &_pddsBack, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Ensure that the back buffer went where we wanted it
|
|
if ((dwFlags & GLDD_STRICT_MEMORY) &&
|
|
(_pddsBack->GetSurfaceDesc(&ddsd) != DD_OK ||
|
|
((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) !=
|
|
((dwFlags & GLDD_VIDEO_MEMORY) == 0)))
|
|
{
|
|
if (dwFlags & GLDD_VIDEO_MEMORY)
|
|
{
|
|
hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hrGlddLast = DDERR_OUTOFMEMORY;
|
|
}
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we're double-buffered, use the back buffer as the rendering target.
|
|
// Otherwise use the front buffer.
|
|
if (dwFlags & GLDD_BACK_BUFFER)
|
|
{
|
|
pddsRender = _pddsBack;
|
|
}
|
|
else
|
|
{
|
|
pddsRender = _pddsFront;
|
|
}
|
|
|
|
// Create a palette for paletted surfaces
|
|
if (ddsdFront.ddpfPixelFormat.dwRGBBitCount < 16)
|
|
{
|
|
int i;
|
|
PALETTEENTRY ppe[256];
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
ppe[i].peRed = glddComponentFromIndex(i, 3, 0);
|
|
ppe[i].peGreen = glddComponentFromIndex(i, 3, 3);
|
|
ppe[i].peBlue = glddComponentFromIndex(i, 2, 6);
|
|
ppe[i].peFlags = 0;
|
|
}
|
|
if ((dwFlags & GLDD_FULL_SCREEN) == 0)
|
|
{
|
|
glddMapInSystemColors(ppe);
|
|
}
|
|
|
|
hrGlddLast = pdd->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE,
|
|
ppe, &_pddp, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (_pddsBack != NULL)
|
|
{
|
|
hrGlddLast = _pddsBack->SetPalette(_pddp);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
// Works with multiple windows?
|
|
hrGlddLast = _pddsFront->SetPalette(_pddp);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
// Create a Z buffer if requested
|
|
if (dwFlags & (GLDD_Z_BUFFER_16 | GLDD_Z_BUFFER_32))
|
|
{
|
|
memset(&ddsd, 0, sizeof(DDSURFACEDESC));
|
|
ddsd.dwSize = sizeof(DDSURFACEDESC);
|
|
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS |
|
|
DDSD_ZBUFFERBITDEPTH;
|
|
ddsd.dwWidth = iWidth;
|
|
ddsd.dwHeight = iHeight;
|
|
dwZDepth = (dwFlags & GLDD_Z_BUFFER_16) ? 16 : 32;
|
|
ddsd.dwZBufferBitDepth = dwZDepth;
|
|
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
|
|
if (dwFlags & GLDD_VIDEO_MEMORY)
|
|
{
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
|
|
}
|
|
else
|
|
{
|
|
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
|
|
}
|
|
hrGlddLast = pdd->CreateSurface(&ddsd, &_pddsZ, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Ensure that the Z buffer went where we wanted it
|
|
if ((dwFlags & GLDD_STRICT_MEMORY) &&
|
|
(_pddsZ->GetSurfaceDesc(&ddsd) != DD_OK ||
|
|
((ddsd.ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY) == 0) !=
|
|
((dwFlags & GLDD_VIDEO_MEMORY) == 0)))
|
|
{
|
|
if (dwFlags & GLDD_VIDEO_MEMORY)
|
|
{
|
|
hrGlddLast = DDERR_OUTOFVIDEOMEMORY;
|
|
}
|
|
else
|
|
{
|
|
hrGlddLast = DDERR_OUTOFMEMORY;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
hrGlddLast = pddsRender->AddAttachedSurface(_pddsZ);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwZDepth = 0;
|
|
}
|
|
|
|
// Create an OpenGL rendering context
|
|
memset(&pfd, 0, sizeof(pfd));
|
|
pfd.nSize = sizeof(pfd);
|
|
pfd.nVersion = 1;
|
|
pfd.dwFlags = PFD_GENERIC_FORMAT | PFD_SUPPORT_DIRECTDRAW;
|
|
if (dwFlags & GLDD_GENERIC_ACCELERATED)
|
|
{
|
|
pfd.dwFlags |= PFD_GENERIC_ACCELERATED;
|
|
}
|
|
pfd.iPixelType = PFD_TYPE_RGBA;
|
|
if (dwFlags & GLDD_ACCUM_BUFFER)
|
|
{
|
|
pfd.cAccumBits = 64;
|
|
}
|
|
if (dwFlags & GLDD_STENCIL_BUFFER)
|
|
{
|
|
pfd.cStencilBits = 8;
|
|
}
|
|
pfd.cDepthBits = (BYTE)dwZDepth;
|
|
|
|
hrGlddLast = pddsRender->GetDC(&hdc);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
ipfd = ChoosePixelFormat(hdc, &pfd);
|
|
|
|
if (ipfd <= 0 ||
|
|
DescribePixelFormat(hdc, ipfd, sizeof(pfd), &pfd) <= 0 ||
|
|
!SetPixelFormat(hdc, ipfd, &pfd) ||
|
|
(_hrc = wglCreateContext(hdc)) == NULL)
|
|
{
|
|
hrGlddLast = WIN32_HR();
|
|
bRet = FALSE;
|
|
}
|
|
|
|
pddsRender->ReleaseDC(hdc);
|
|
|
|
if (!bRet)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
_iWidth = iWidth;
|
|
_iHeight = iHeight;
|
|
_dwFlags = dwFlags;
|
|
|
|
ShowWindow(_hwnd, SW_SHOWDEFAULT);
|
|
UpdateWindow(_hwnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* _GLDDWINDOW::~_GLDDWINDOW
|
|
*
|
|
* Clean up
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:37:12 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
_GLDDWINDOW::~_GLDDWINDOW(void)
|
|
{
|
|
if (_hrc != NULL)
|
|
{
|
|
if (wglGetCurrentContext() == _hrc)
|
|
{
|
|
wglMakeCurrent(NULL, NULL);
|
|
}
|
|
wglDeleteContext(_hrc);
|
|
}
|
|
if (_pddsBack != NULL)
|
|
{
|
|
_pddsBack->Release();
|
|
}
|
|
if (_pddsZ != NULL)
|
|
{
|
|
_pddsZ->Release();
|
|
}
|
|
if (_pddp != NULL)
|
|
{
|
|
_pddp->Release();
|
|
}
|
|
if (_pddc != NULL)
|
|
{
|
|
if (_pddsFront != NULL)
|
|
{
|
|
LPDIRECTDRAWCLIPPER pddc;
|
|
|
|
// Only detach our clipper if it's still the current clipper
|
|
if (_pddsFront->GetClipper(&pddc) == DD_OK &&
|
|
pddc == _pddc)
|
|
{
|
|
_pddsFront->SetClipper(NULL);
|
|
}
|
|
}
|
|
|
|
_pddc->Release();
|
|
}
|
|
if (_pddsFront != NULL)
|
|
{
|
|
_pddsFront->Release();
|
|
}
|
|
|
|
if (_dwFlags & GLDD_FULL_SCREEN)
|
|
{
|
|
// Recover from mode changes
|
|
pdd->SetCooperativeLevel(_hwnd, DDSCL_NORMAL);
|
|
pdd->RestoreDisplayMode();
|
|
}
|
|
|
|
if (_hwnd != NULL)
|
|
{
|
|
DestroyWindow(_hwnd);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddRegisterClass
|
|
*
|
|
* Register a window class if necessary
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:37:49 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL glddRegisterClass(void)
|
|
{
|
|
static ATOM aClass = 0;
|
|
WNDCLASS wc;
|
|
|
|
if (aClass == 0)
|
|
{
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = glddWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = pszClass;
|
|
aClass = RegisterClass(&wc);
|
|
if (aClass == 0)
|
|
{
|
|
hrGlddLast = WIN32_HR();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddCreateWindow
|
|
*
|
|
* Create a new rendering window
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:38:49 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLDDWINDOW glddCreateWindow(char *pszTitle, int x, int y,
|
|
int iWidth, int iHeight, int iDepth,
|
|
DWORD dwFlags)
|
|
{
|
|
GLDDWINDOW gw;
|
|
|
|
if (!glddRegisterClass())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// If we haven't initialized the global IDirectDraw, do so
|
|
if (pdd == NULL)
|
|
{
|
|
hrGlddLast = DirectDrawCreate(NULL, &pdd, NULL);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
gw = new _GLDDWINDOW;
|
|
if (gw == NULL)
|
|
{
|
|
hrGlddLast = E_OUTOFMEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
if (gw->Create(pszTitle, x, y, iWidth, iHeight, iDepth, dwFlags))
|
|
{
|
|
return gw;
|
|
}
|
|
else
|
|
{
|
|
delete gw;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddDestroyWindow
|
|
*
|
|
* Clean up a rendering window
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:39:20 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddDestroyWindow(GLDDWINDOW gw)
|
|
{
|
|
delete gw;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddGetGlrc
|
|
*
|
|
* Return a rendering window's OpenGL rendering context
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:39:29 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HGLRC glddGetGlrc(GLDDWINDOW gw)
|
|
{
|
|
return gw->_hrc;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddGetLastError
|
|
*
|
|
* Returns the last error recorded by the library
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:39:39 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HRESULT glddGetLastError(void)
|
|
{
|
|
#if DBG
|
|
char pszMsg[80];
|
|
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
sprintf(pszMsg, "glddGetLastError returning 0x%08lX\n", hrGlddLast);
|
|
OutputDebugString(pszMsg);
|
|
}
|
|
#endif
|
|
return hrGlddLast;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddMakeCurrent
|
|
*
|
|
* Makes the given rendering window's OpenGL rendering context current
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:39:47 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL glddMakeCurrent(GLDDWINDOW gw)
|
|
{
|
|
BOOL b;
|
|
HDC hdc;
|
|
LPDIRECTDRAWSURFACE pddsRender;
|
|
|
|
if (gw->_dwFlags & GLDD_BACK_BUFFER)
|
|
{
|
|
pddsRender = gw->_pddsBack;
|
|
}
|
|
else
|
|
{
|
|
pddsRender = gw->_pddsFront;
|
|
}
|
|
|
|
hrGlddLast = pddsRender->GetDC(&hdc);
|
|
if (hrGlddLast != DD_OK)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
b = wglMakeCurrent(hdc, gw->_hrc);
|
|
|
|
pddsRender->ReleaseDC(hdc);
|
|
|
|
if (!b)
|
|
{
|
|
hrGlddLast = WIN32_HR();
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddSwapBuffers
|
|
*
|
|
* Performs double-buffer swapping through blt or flip
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:40:49 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL glddSwapBuffers(GLDDWINDOW gw)
|
|
{
|
|
// Check for a back buffer
|
|
if ((gw->_dwFlags & GLDD_BACK_BUFFER) == 0)
|
|
{
|
|
hrGlddLast = E_INVALIDARG;
|
|
return FALSE;
|
|
}
|
|
|
|
if (gw->_dwFlags & GLDD_FULL_SCREEN)
|
|
{
|
|
hrGlddLast = gw->_pddsFront->Flip(NULL, DDFLIP_WAIT);
|
|
return hrGlddLast == DD_OK;
|
|
}
|
|
else
|
|
{
|
|
RECT rctSrc, rctDst;
|
|
POINT pt;
|
|
|
|
GetClientRect(gw->_hwnd, &rctDst);
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
ClientToScreen(gw->_hwnd, &pt);
|
|
rctDst.left = pt.x;
|
|
rctDst.top = pt.y;
|
|
rctDst.right += pt.x;
|
|
rctDst.bottom += pt.y;
|
|
rctSrc.left = 0;
|
|
rctSrc.top = 0;
|
|
rctSrc.right = gw->_iWidth;
|
|
rctSrc.bottom = gw->_iHeight;
|
|
hrGlddLast = gw->_pddsFront->Blt(&rctDst, gw->_pddsBack,
|
|
&rctSrc, DDBLT_WAIT,
|
|
NULL);
|
|
return hrGlddLast == DD_OK;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddIdleCallback
|
|
*
|
|
* Set the idle-time callback
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:41:28 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddIdleCallback(GLDDWINDOW gw, GLDDIDLECALLBACK cb)
|
|
{
|
|
gw->_cbIdle = cb;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddMessageCallback
|
|
*
|
|
* Set the message interposition callback
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:41:40 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddMessageCallback(GLDDWINDOW gw, GLDDMESSAGECALLBACK cb)
|
|
{
|
|
gw->_cbMessage = cb;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glddRun
|
|
*
|
|
* Run the message loop
|
|
*
|
|
* History:
|
|
* Fri Aug 30 14:41:58 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void glddRun(GLDDWINDOW gw)
|
|
{
|
|
MSG msg;
|
|
BOOL bQuit;
|
|
|
|
bQuit = FALSE;
|
|
while (!bQuit)
|
|
{
|
|
// NULL hwnd doesn't work with multiple windows but
|
|
// is necessary to get quit message
|
|
while (!bQuit && PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
|
|
{
|
|
if (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
else
|
|
{
|
|
bQuit = TRUE;
|
|
}
|
|
}
|
|
|
|
// Call the idle callback if one exists
|
|
if (gw->_cbIdle)
|
|
{
|
|
gw->_cbIdle(gw);
|
|
}
|
|
}
|
|
}
|