4067 lines
123 KiB
C
4067 lines
123 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include <imfuncs.h>
|
|
#include "genci.h"
|
|
#include "genrgb.h"
|
|
#include "devlock.h"
|
|
#include "imports.h"
|
|
|
|
//
|
|
// CJ_ALIGNDWORD computes the minimum size (in bytes) of a DWORD array that
|
|
// contains at least cj bytes.
|
|
//
|
|
#define CJ_ALIGNDWORD(cj) ( ((cj) + (sizeof(DWORD)-1)) & (-((signed)sizeof(DWORD))) )
|
|
|
|
//
|
|
// BITS_ALIGNDWORD computes the minimum size (in bits) of a DWORD array that
|
|
// contains at least c bits.
|
|
//
|
|
// We assume that there will always be 8 bits in a byte and that sizeof()
|
|
// always returns size in bytes. The rest is independent of the definition
|
|
// of DWORD.
|
|
//
|
|
#define BITS_ALIGNDWORD(c) ( ((c) + ((sizeof(DWORD)*8)-1)) & (-((signed)(sizeof(DWORD)*8))) )
|
|
|
|
// change to "static" after debugging
|
|
#define STATIC
|
|
|
|
#if DBG
|
|
// not multithreaded safe, but only for testing
|
|
#define RANDOMDISABLE \
|
|
{ \
|
|
long saveRandom = glRandomMallocFail; \
|
|
glRandomMallocFail = 0;
|
|
|
|
#define RANDOMREENABLE \
|
|
if (saveRandom) \
|
|
glRandomMallocFail = saveRandom; \
|
|
}
|
|
#else
|
|
#define RANDOMDISABLE
|
|
#define RANDOMREENABLE
|
|
#endif /* DBG */
|
|
|
|
#define INITIAL_TIMESTAMP ((ULONG)-1)
|
|
|
|
/*
|
|
* Function Prototypes
|
|
*/
|
|
|
|
BOOL APIENTRY ValidateLayerIndex(int iLayer, PIXELFORMATDESCRIPTOR *ppfd);
|
|
|
|
|
|
/*
|
|
* Private functions
|
|
*/
|
|
|
|
void FASTCALL GetContextModes(__GLGENcontext *gengc);
|
|
STATIC void FASTCALL ApplyViewport(__GLcontext *gc);
|
|
GLboolean ResizeAncillaryBuffer(__GLGENbuffers *, __GLbuffer *, GLint, GLint);
|
|
GLboolean ResizeHardwareBackBuffer(__GLGENbuffers *, __GLcolorBuffer *, GLint, GLint);
|
|
GLboolean ResizeUnownedDepthBuffer(__GLGENbuffers *, __GLbuffer *, GLint, GLint);
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* EmptyFillStrokeCache
|
|
*
|
|
* Cleans up any objects in the fill and stroke cache
|
|
*
|
|
* History:
|
|
* Tue Aug 15 15:37:30 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL EmptyFillStrokeCache(__GLGENcontext *gengc)
|
|
{
|
|
if (gengc->hbrFill != NULL)
|
|
{
|
|
DeleteObject(gengc->hbrFill);
|
|
gengc->hbrFill = NULL;
|
|
gengc->crFill = COLORREF_UNUSED;
|
|
gengc->hdcFill = NULL;
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
ASSERTOPENGL(gengc->crFill == COLORREF_UNUSED,
|
|
"crFill inconsistent\n");
|
|
}
|
|
#endif
|
|
if (gengc->hpenStroke != NULL)
|
|
{
|
|
// Deselect the pen before deletion if necessary
|
|
if (gengc->hdcStroke != NULL)
|
|
{
|
|
SelectObject(gengc->hdcStroke, GetStockObject(BLACK_PEN));
|
|
gengc->hdcStroke = NULL;
|
|
}
|
|
|
|
DeleteObject(gengc->hpenStroke);
|
|
gengc->hpenStroke = NULL;
|
|
gengc->cStroke.r = -1.0f;
|
|
gengc->fStrokeInvalid = TRUE;
|
|
}
|
|
#if DBG
|
|
else
|
|
{
|
|
ASSERTOPENGL(gengc->cStroke.r < 0.0f &&
|
|
gengc->fStrokeInvalid,
|
|
"rStroke inconsistent\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvDeleteContext
|
|
*
|
|
* Deletes the generic context.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvDeleteContext(__GLcontext *gc)
|
|
{
|
|
__GLGENcontext *gengc;
|
|
|
|
gengc = (__GLGENcontext *)gc;
|
|
|
|
/* Free ancillary buffer related data. Note that these calls do
|
|
** *not* free software ancillary buffers, just any related data
|
|
** stored in them. The ancillary buffers are freed on window destruction
|
|
*/
|
|
if (gc->modes.accumBits) {
|
|
DBGLEVEL(LEVEL_ALLOC,
|
|
"DestroyContext: Freeing accumulation buffer related data\n");
|
|
__glFreeAccum64(gc, &gc->accumBuffer);
|
|
}
|
|
|
|
if (gc->modes.depthBits) {
|
|
DBGLEVEL(LEVEL_ALLOC,
|
|
"DestroyContext: Freeing depth buffer related data\n");
|
|
__glFreeDepth32(gc, &gc->depthBuffer);
|
|
}
|
|
if (gc->modes.stencilBits) {
|
|
DBGLEVEL(LEVEL_ALLOC,
|
|
"DestroyContext: Freeing stencil buffer related data\n");
|
|
__glFreeStencil8(gc, &gc->stencilBuffer);
|
|
}
|
|
|
|
/* Free Translate & Inverse Translate vectors */
|
|
if ((gengc->pajTranslateVector != NULL) &&
|
|
(gengc->pajTranslateVector != gengc->xlatPalette))
|
|
GCFREE(gc, gengc->pajTranslateVector);
|
|
|
|
if (gengc->pajInvTranslateVector != NULL)
|
|
GCFREE(gc, gengc->pajInvTranslateVector);
|
|
|
|
// Make sure that any cached GDI objects are freed
|
|
// This is normally done in LoseCurrent but a context may be
|
|
// left current and then cleaned up
|
|
EmptyFillStrokeCache(gengc);
|
|
|
|
/*
|
|
/* Free the span dibs and storage.
|
|
*/
|
|
|
|
#ifndef _CLIENTSIDE_
|
|
if (gengc->StippleBitmap)
|
|
EngDeleteSurface((HSURF)gengc->StippleBitmap);
|
|
#endif
|
|
|
|
wglDeleteScanlineBuffers(gengc);
|
|
|
|
if (gengc->StippleBits)
|
|
GCFREE(gc, gengc->StippleBits);
|
|
|
|
// Free __GLGENbitmap front-buffer structure
|
|
|
|
if (gc->frontBuffer.bitmap)
|
|
GCFREE(gc, gc->frontBuffer.bitmap);
|
|
|
|
#ifndef _CLIENTSIDE_
|
|
/*
|
|
* Free the buffers that may have been allocated by feedback
|
|
* or selection
|
|
*/
|
|
|
|
if ( NULL != gengc->RenderState.SrvSelectBuffer )
|
|
{
|
|
#ifdef NT
|
|
// match the allocation function
|
|
FREE(gengc->RenderState.SrvSelectBuffer);
|
|
#else
|
|
GCFREE(gc, gengc->RenderState.SrvSelectBuffer);
|
|
#endif
|
|
}
|
|
|
|
if ( NULL != gengc->RenderState.SrvFeedbackBuffer)
|
|
{
|
|
#ifdef NT
|
|
// match the allocation function
|
|
FREE(gengc->RenderState.SrvFeedbackBuffer);
|
|
#else
|
|
GCFREE(gc, gengc->RenderState.SrvFeedbackBuffer);
|
|
#endif
|
|
}
|
|
#endif //_CLIENTSIDE_
|
|
|
|
#ifdef _CLIENTSIDE_
|
|
/*
|
|
* Cleanup logical palette copy if it exists.
|
|
*/
|
|
if ( gengc->ppalBuf )
|
|
FREE(gengc->ppalBuf);
|
|
#endif
|
|
|
|
/* Destroy acceleration-specific context information */
|
|
|
|
__glGenDestroyAccelContext(gc);
|
|
|
|
#ifdef _MCD_
|
|
/* Free the MCD state structure and associated resources. */
|
|
|
|
if (gengc->_pMcdState) {
|
|
GenMcdDeleteContext(gengc->_pMcdState);
|
|
}
|
|
#endif
|
|
|
|
/* Free any temporay buffers in abnormal process exit */
|
|
GC_TEMP_BUFFER_EXIT_CLEANUP(gc);
|
|
|
|
// Release references to DirectDraw surfaces
|
|
if (gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW)
|
|
{
|
|
GLWINDOWID gwid;
|
|
GLGENwindow *pwnd;
|
|
|
|
// Destroy window created for this context
|
|
gwid.iType = GLWID_DDRAW;
|
|
gwid.pdds = gengc->gsurf.dd.gddsFront.pdds;
|
|
gwid.hdc = gengc->gsurf.hdc;
|
|
gwid.hwnd = NULL;
|
|
pwnd = pwndGetFromID(&gwid);
|
|
ASSERTOPENGL(pwnd != NULL,
|
|
"Destroying DDraw context without window\n");
|
|
pwndCleanup(pwnd);
|
|
|
|
gengc->gsurf.dd.gddsFront.pdds->lpVtbl->
|
|
Release(gengc->gsurf.dd.gddsFront.pdds);
|
|
if (gengc->gsurf.dd.gddsZ.pdds != NULL)
|
|
{
|
|
gengc->gsurf.dd.gddsZ.pdds->lpVtbl->
|
|
Release(gengc->gsurf.dd.gddsZ.pdds);
|
|
}
|
|
|
|
}
|
|
|
|
/* Destroy rest of software context (in soft code) */
|
|
__glDestroyContext(gc);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvLoseCurrent
|
|
*
|
|
* Releases the current context (makes it not current).
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY glsrvLoseCurrent(__GLcontext *gc)
|
|
{
|
|
__GLGENcontext *gengc;
|
|
|
|
gengc = (__GLGENcontext *)gc;
|
|
|
|
DBGENTRY("LoseCurrent\n");
|
|
ASSERTOPENGL(gc == GLTEB_SRVCONTEXT(), "LoseCurrent not current!");
|
|
|
|
/*
|
|
** Release lock if still held.
|
|
*/
|
|
if (gengc->fsLocks != 0)
|
|
{
|
|
glsrvReleaseLock(gengc);
|
|
}
|
|
|
|
/*
|
|
** Unscale derived state that depends upon the color scales. This
|
|
** is needed so that if this context is rebound to a memdc, it can
|
|
** then rescale all of those colors using the memdc color scales.
|
|
*/
|
|
__glContextUnsetColorScales(gc);
|
|
memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent));
|
|
|
|
/*
|
|
** Clean up HDC-specific GDI objects
|
|
*/
|
|
EmptyFillStrokeCache(gengc);
|
|
|
|
/*
|
|
** Free up fake window for IC's
|
|
*/
|
|
if ((gengc->dwCurrentFlags & GLSURF_METAFILE) && gengc->ipfdCurrent == 0)
|
|
{
|
|
GLGENwindow *pwnd;
|
|
|
|
pwnd = gengc->pwndMakeCur;
|
|
ASSERTOPENGL(pwnd != NULL,
|
|
"IC with no pixel format but no fake window\n");
|
|
|
|
if (pwnd->buffers != NULL)
|
|
{
|
|
__glGenFreeBuffers(pwnd->buffers);
|
|
}
|
|
|
|
DeleteCriticalSection(&pwnd->sem);
|
|
FREE(pwnd);
|
|
}
|
|
|
|
gengc->pwndMakeCur = NULL;
|
|
|
|
#ifdef _MCD_
|
|
/*
|
|
** Disconnect MCD state.
|
|
*/
|
|
gengc->pMcdState = (GENMCDSTATE *) NULL;
|
|
#endif
|
|
|
|
gc->constants.width = 0;
|
|
gc->constants.height = 0;
|
|
|
|
// Set paTeb to NULL for debugging.
|
|
gc->paTeb = NULL;
|
|
GLTEB_SET_SRVCONTEXT(0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvSwapBuffers
|
|
*
|
|
* This uses the software implementation of double buffering. An engine
|
|
* allocated bitmap is allocated for use as the back buffer. The SwapBuffer
|
|
* routine copies the back buffer to the front buffer surface (which may
|
|
* be another DIB, a device surface in DIB format, or a device managed
|
|
* surface (with a device specific format).
|
|
*
|
|
* The SwapBuffer routine does not disturb the contents of the back buffer,
|
|
* though the defined behavior for now is undefined.
|
|
*
|
|
* Note: the caller should be holding the per-window semaphore.
|
|
*
|
|
* History:
|
|
* 19-Nov-1993 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvSwapBuffers(HDC hdc, GLGENwindow *pwnd)
|
|
{
|
|
DBGENTRY("glsrvSwapBuffers\n");
|
|
|
|
if ( pwnd->buffers ) {
|
|
__GLGENbuffers *buffers;
|
|
__GLGENbitmap *genBm;
|
|
|
|
buffers = pwnd->buffers;
|
|
|
|
if (buffers->pMcdSurf) {
|
|
return GenMcdSwapBuffers(hdc, pwnd);
|
|
}
|
|
|
|
genBm = &buffers->backBitmap;
|
|
|
|
// Make sure the backbuffer exists
|
|
|
|
if (genBm->hbm) {
|
|
if (!RECTLISTIsEmpty(&buffers->rl) && !buffers->fMax) {
|
|
wglCopyBufRECTLIST(
|
|
hdc,
|
|
genBm->hdc,
|
|
0,
|
|
0,
|
|
buffers->backBuffer.width,
|
|
buffers->backBuffer.height,
|
|
&buffers->rl
|
|
);
|
|
} else {
|
|
buffers->fMax = FALSE;
|
|
wglCopyBuf(
|
|
hdc,
|
|
genBm->hdc,
|
|
0,
|
|
0,
|
|
buffers->backBuffer.width,
|
|
buffers->backBuffer.height
|
|
);
|
|
}
|
|
RECTLISTSetEmpty(&buffers->rl);
|
|
}
|
|
if( buffers->alphaBits
|
|
&& buffers->alphaBackBuffer
|
|
&& buffers->alphaFrontBuffer) {
|
|
|
|
ASSERTOPENGL(buffers->alphaFrontBuffer->size ==
|
|
buffers->alphaBackBuffer->size,
|
|
"Destination alpha buffer size mismatch\n");
|
|
|
|
// Destination alpha values are kept in separate buffers.
|
|
// If this buffer set has destination alpha buffers,
|
|
// copy the back alpha values into the front alpha buffer.
|
|
RtlCopyMemory(buffers->alphaFrontBuffer->base,
|
|
buffers->alphaBackBuffer->base,
|
|
buffers->alphaBackBuffer->size);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* gdiCopyPixels
|
|
*
|
|
* Copy span [(x, y), (x + cx, y)) (inclusive-exclusive) to/from specified
|
|
* color buffer cfb from/to the scanline buffer.
|
|
*
|
|
* If bIn is TRUE, the copy is from the scanline buffer to the buffer.
|
|
* If bIn is FALSE, the copy is from the buffer to the scanline buffer.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void gdiCopyPixels(__GLGENcontext *gengc, __GLcolorBuffer *cfb,
|
|
GLint x, GLint y, GLint cx, BOOL bIn)
|
|
{
|
|
wglCopyBits(gengc, gengc->pwndLocked, gengc->ColorsBitmap, x, y, cx, bIn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* dibCopyPixels
|
|
*
|
|
* Special case version of gdiCopyPixels that is used when cfb is a DIB,
|
|
* either a real DIB or a device surface which has a DIB format.
|
|
*
|
|
* This function *must* be used in lieu of gdiCopyPixels if we are
|
|
* directly accessing the screen as it is not safe to call GDI entry
|
|
* points with the screen locked
|
|
*
|
|
* History:
|
|
* 24-May-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void dibCopyPixels(__GLGENcontext *gengc, __GLcolorBuffer *cfb,
|
|
GLint x, GLint y, GLint cx, BOOL bIn)
|
|
{
|
|
VOID *pvDib;
|
|
UINT cjPixel = gengc->gsurf.pfd.cColorBits >> 3;
|
|
ULONG ulSpanVisibility;
|
|
GLint cWalls;
|
|
GLint *pWalls;
|
|
|
|
// Don't handle VGA DIBs.
|
|
//
|
|
// We are not supposed to call GDI if directly accessing the screen. However,
|
|
// we should be able to assume that 4bpp devices do not support
|
|
// direct access making it OK for us to punt this call to the GDI version.
|
|
// This is true for Win95 and, according to AndrewGo, will be
|
|
// true for WinNT SUR.
|
|
|
|
if (gengc->gsurf.pfd.cColorBits <= 4)
|
|
{
|
|
ASSERTOPENGL(
|
|
!((cfb->buf.flags & DIB_FORMAT) &&
|
|
!(cfb->buf.flags & MEMORY_DC)),
|
|
"dibCopyPixels: unexpected 4bpp direct surface\n"
|
|
);
|
|
|
|
gdiCopyPixels(gengc, cfb, x, y, cx, bIn);
|
|
return;
|
|
}
|
|
|
|
// Find out clipping info.
|
|
|
|
if ((cfb->buf.flags & (NO_CLIP | DIB_FORMAT)) ==
|
|
(NO_CLIP | DIB_FORMAT))
|
|
{
|
|
ulSpanVisibility = WGL_SPAN_ALL;
|
|
}
|
|
else
|
|
{
|
|
ulSpanVisibility = wglSpanVisible(x, y, cx, &cWalls, &pWalls);
|
|
}
|
|
|
|
// Completely clipped, nothing to do.
|
|
|
|
if (ulSpanVisibility == WGL_SPAN_NONE)
|
|
return;
|
|
|
|
// Completely visible.
|
|
//
|
|
// Actually, if bIn == FALSE (i.e., copy from screen to scanline buffer)
|
|
// we can cheat a little and ignore the clipping.
|
|
|
|
else if ( (ulSpanVisibility == WGL_SPAN_ALL) || !bIn )
|
|
{
|
|
// Get pointer into DIB at position (x, y).
|
|
|
|
pvDib = (VOID *) (((BYTE *) gengc->gc.front->buf.base) +
|
|
gengc->gc.front->buf.outerWidth * y +
|
|
cjPixel * x);
|
|
|
|
// If bIn == TRUE, copy from scanline buffer to DIB.
|
|
// Otherwise, copy from DIB to scanline buffer.
|
|
|
|
if (bIn)
|
|
RtlCopyMemory_UnalignedDst(pvDib, gengc->ColorsBits, cjPixel * cx);
|
|
else
|
|
RtlCopyMemory_UnalignedSrc(gengc->ColorsBits, pvDib, cjPixel * cx);
|
|
}
|
|
|
|
// Partially visible.
|
|
|
|
else
|
|
{
|
|
GLint xEnd = x + cx; // end of the span
|
|
UINT cjSpan; // size of the current portion of span to copy
|
|
VOID *pvBits; // current copy position in the scanline buf
|
|
BYTE *pjScan; // address of scan line in DIB
|
|
|
|
ASSERTOPENGL( cWalls && pWalls, "dibCopyPixels(): bad wall array\n");
|
|
|
|
// The walls are walked until either the end of the array is reached
|
|
// or the walls exceed the end of the span. The do..while loop
|
|
// construct was choosen because the first iteration will always
|
|
// copy something and after the first iteration we are guaranteed
|
|
// to be in the "cWalls is even" case. This makes the testing the
|
|
// walls against the span end easier.
|
|
//
|
|
// If cWalls is even, clip the span to each pair of walls in pWalls.
|
|
// If cWalls is odd, form the first pair with (x, pWalls[0]) and then
|
|
// pair the remaining walls starting with pWalls[1].
|
|
|
|
pjScan = (VOID *) (((BYTE *) gengc->gc.front->buf.base) +
|
|
gengc->gc.front->buf.outerWidth * y);
|
|
|
|
do
|
|
{
|
|
//!!!XXX -- Make faster by pulling the odd case out of the loop
|
|
|
|
if (cWalls & 0x1)
|
|
{
|
|
pvDib = (VOID *) (pjScan + (cjPixel * x));
|
|
|
|
pvBits = gengc->ColorsBits;
|
|
|
|
if ( pWalls[0] <= xEnd )
|
|
cjSpan = cjPixel * (pWalls[0] - x);
|
|
else
|
|
cjSpan = cjPixel * cx;
|
|
|
|
pWalls++;
|
|
cWalls--; // Now cWalls is even!
|
|
}
|
|
else
|
|
{
|
|
pvDib = (VOID *) (pjScan + (cjPixel * pWalls[0]));
|
|
|
|
pvBits = (VOID *) (((BYTE *) gengc->ColorsBits) +
|
|
cjPixel * (pWalls[0] - x));
|
|
|
|
if ( pWalls[1] <= xEnd )
|
|
cjSpan = cjPixel * (pWalls[1] - pWalls[0]);
|
|
else
|
|
cjSpan = cjPixel * (xEnd - pWalls[0]);
|
|
|
|
pWalls += 2;
|
|
cWalls -= 2;
|
|
}
|
|
|
|
// We are going to cheat and ignore clipping when copying from
|
|
// the dib to the scanline buffer (i.e., we are going to handle
|
|
// the !bIn case as if it were WGL_SPAN_ALL). Thus, we can assume
|
|
// that bIn == TRUE if we get to here.
|
|
//
|
|
// If clipping is needed to read the DIB, its trivial to turn it
|
|
// back on.
|
|
//
|
|
// RtlCopyMemory(bIn ? pvDib : pvBits,
|
|
// bIn ? pvBits : pvDib,
|
|
// cjSpan);
|
|
|
|
//!!!dbug -- Possible COMPILER BUG (compiler should check for
|
|
//!!!dbug alignment before doing the "rep movsd"). Keep around
|
|
//!!!dbug as a test case.
|
|
#if 1
|
|
RtlCopyMemory_UnalignedDst(pvDib, pvBits, cjSpan);
|
|
#else
|
|
RtlCopyMemory(pvDib, pvBits, cjSpan);
|
|
#endif
|
|
|
|
} while ( cWalls && (pWalls[0] < xEnd) );
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* MaskFromBits
|
|
*
|
|
* Support routine for GetContextModes. Computes a color mask given that
|
|
* colors bit count and shift position.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#define MaskFromBits(shift, count) \
|
|
((0xffffffff >> (32-(count))) << (shift))
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetContextModes
|
|
*
|
|
* Convert the information from Gdi into OpenGL format after checking that
|
|
* the formats are compatible and that the surface is compatible with the
|
|
* format.
|
|
*
|
|
* Called during a glsrvMakeCurrent().
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL GetContextModes(__GLGENcontext *gengc)
|
|
{
|
|
PIXELFORMATDESCRIPTOR *pfmt;
|
|
__GLcontextModes *Modes;
|
|
|
|
DBGENTRY("GetContextModes\n");
|
|
|
|
Modes = &((__GLcontext *)gengc)->modes;
|
|
|
|
pfmt = &gengc->gsurf.pfd;
|
|
|
|
if (pfmt->iPixelType == PFD_TYPE_RGBA)
|
|
Modes->rgbMode = GL_TRUE;
|
|
else
|
|
Modes->rgbMode = GL_FALSE;
|
|
|
|
Modes->colorIndexMode = !Modes->rgbMode;
|
|
|
|
if (pfmt->dwFlags & PFD_DOUBLEBUFFER)
|
|
Modes->doubleBufferMode = GL_TRUE;
|
|
else
|
|
Modes->doubleBufferMode = GL_FALSE;
|
|
|
|
if (pfmt->dwFlags & PFD_STEREO)
|
|
Modes->stereoMode = GL_TRUE;
|
|
else
|
|
Modes->stereoMode = GL_FALSE;
|
|
|
|
Modes->accumBits = pfmt->cAccumBits;
|
|
Modes->haveAccumBuffer = GL_FALSE;
|
|
|
|
Modes->auxBits = NULL; // This is a pointer
|
|
|
|
Modes->depthBits = pfmt->cDepthBits;
|
|
Modes->haveDepthBuffer = GL_FALSE;
|
|
|
|
Modes->stencilBits = pfmt->cStencilBits;
|
|
Modes->haveStencilBuffer= GL_FALSE;
|
|
|
|
if (pfmt->cColorBits > 8)
|
|
Modes->indexBits = 8;
|
|
else
|
|
Modes->indexBits = pfmt->cColorBits;
|
|
|
|
Modes->indexFractionBits= 0;
|
|
|
|
// The Modes->{Red,Green,Blue}Bits are used in soft
|
|
Modes->redBits = pfmt->cRedBits;
|
|
Modes->greenBits = pfmt->cGreenBits;
|
|
Modes->blueBits = pfmt->cBlueBits;
|
|
Modes->alphaBits = pfmt->cAlphaBits;
|
|
Modes->redMask = MaskFromBits(pfmt->cRedShift, pfmt->cRedBits);
|
|
Modes->greenMask = MaskFromBits(pfmt->cGreenShift, pfmt->cGreenBits);
|
|
Modes->blueMask = MaskFromBits(pfmt->cBlueShift, pfmt->cBlueBits);
|
|
Modes->alphaMask = MaskFromBits(pfmt->cAlphaShift, pfmt->cAlphaBits);
|
|
Modes->rgbMask = Modes->redMask | Modes->greenMask |
|
|
Modes->blueMask;
|
|
Modes->allMask = Modes->redMask | Modes->greenMask |
|
|
Modes->blueMask | Modes->alphaMask;
|
|
Modes->maxAuxBuffers = 0;
|
|
|
|
Modes->isDirect = GL_FALSE;
|
|
Modes->level = 0;
|
|
|
|
#if DBG
|
|
DBGBEGIN(LEVEL_INFO)
|
|
DbgPrint("GL generic server get modes: rgbmode %d, cimode %d, index bits %d\n", Modes->rgbMode, Modes->colorIndexMode);
|
|
DbgPrint(" redmask 0x%x, greenmask 0x%x, bluemask 0x%x\n", Modes->redMask, Modes->greenMask, Modes->blueMask);
|
|
DbgPrint(" redbits %d, greenbits %d, bluebits %d\n", Modes->redBits, Modes->greenBits, Modes->blueBits);
|
|
DbgPrint("GetContext Modes flags %X\n", gengc->gsurf.dwFlags);
|
|
DBGEND
|
|
#endif /* DBG */
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetSurfacePalette
|
|
*
|
|
* Initialize the array of RGBQUADs to match the color table or palette
|
|
* of the DC's surface.
|
|
*
|
|
* Note:
|
|
* Should be called only for 8bpp or lesser surfaces.
|
|
*
|
|
* History:
|
|
* 12-Jun-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
wglGetSurfacePalette( __GLGENcontext *gengc, RGBQUAD *prgbq,
|
|
BOOL bTranslateDdb )
|
|
{
|
|
int nColors;
|
|
BOOL bRet;
|
|
BOOL bConvert;
|
|
PALETTEENTRY ppe[256];
|
|
int i;
|
|
|
|
ASSERTOPENGL(gengc->gsurf.pfd.cColorBits <= 8,
|
|
"wglGetSurfacePalette called for deep surface\n");
|
|
ASSERTOPENGL((gengc->dwCurrentFlags & GLSURF_METAFILE) == 0,
|
|
"wglGetSurfacePalette called for metafile\n");
|
|
|
|
nColors = 1 << gengc->gsurf.pfd.cColorBits;
|
|
|
|
if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
|
|
{
|
|
LPDIRECTDRAWPALETTE pddp;
|
|
HRESULT hr;
|
|
|
|
// Retrieve DirectDraw palette from surface
|
|
if (gengc->gsurf.dd.gddsFront.pdds->lpVtbl->
|
|
GetPalette(gengc->gsurf.dd.gddsFront.pdds, &pddp) != DD_OK ||
|
|
pddp == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hr = pddp->lpVtbl->GetEntries(pddp, 0, 0, nColors, ppe);
|
|
|
|
pddp->lpVtbl->Release(pddp);
|
|
|
|
bRet = hr == DD_OK;
|
|
bConvert = TRUE;
|
|
}
|
|
else if (GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags))
|
|
{
|
|
// Direct DC, so get the RGB values from the system palette.
|
|
bRet = wglGetSystemPaletteEntries(gengc->gwidCurrent.hdc,
|
|
0, nColors, ppe);
|
|
bConvert = TRUE;
|
|
}
|
|
else if (gengc->dwCurrentFlags & GLSURF_DIRECT_ACCESS)
|
|
{
|
|
// DIB section, so copy the color table.
|
|
bRet = GetDIBColorTable(gengc->gwidCurrent.hdc, 0, nColors, prgbq);
|
|
bConvert = FALSE;
|
|
}
|
|
else
|
|
{
|
|
// DDB surface, so use the logical palette.
|
|
bRet = GetPaletteEntries(GetCurrentObject(gengc->gwidCurrent.hdc,
|
|
OBJ_PAL),
|
|
0, nColors, ppe);
|
|
|
|
// For certain DDB surfaces we need the palette to be permuted
|
|
// by the forward translation vector before use.
|
|
if (bRet && bTranslateDdb)
|
|
{
|
|
BYTE *pjTrans;
|
|
|
|
bConvert = FALSE;
|
|
|
|
// Convert to RGBQUAD with forward translation permutation.
|
|
pjTrans = gengc->pajTranslateVector;
|
|
for (i = 0; i < nColors; i++)
|
|
{
|
|
prgbq[pjTrans[i]].rgbRed = ppe[i].peRed;
|
|
prgbq[pjTrans[i]].rgbGreen = ppe[i].peGreen;
|
|
prgbq[pjTrans[i]].rgbBlue = ppe[i].peBlue;
|
|
prgbq[pjTrans[i]].rgbReserved = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bConvert = TRUE;
|
|
}
|
|
}
|
|
|
|
if (bRet && bConvert)
|
|
{
|
|
// Convert to RGBQUAD.
|
|
for (i = 0; i < nColors; i++)
|
|
{
|
|
prgbq[i].rgbRed = ppe[i].peRed;
|
|
prgbq[i].rgbGreen = ppe[i].peGreen;
|
|
prgbq[i].rgbBlue = ppe[i].peBlue;
|
|
prgbq[i].rgbReserved = 0;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* SyncDibColorTables
|
|
*
|
|
* Setup the color table in each DIB associated with the specified
|
|
* GLGENcontext to match the system palette.
|
|
*
|
|
* Called only for <= 8bpp surfaces.
|
|
*
|
|
* History:
|
|
* 24-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void
|
|
SyncDibColorTables(__GLGENcontext *gengc)
|
|
{
|
|
__GLGENbuffers *buffers = gengc->pwndLocked->buffers;
|
|
|
|
ASSERTOPENGL(gengc->gsurf.pfd.cColorBits <= 8,
|
|
"SyncDibColorTables(): bad surface type");
|
|
|
|
if (gengc->ColorsBitmap || buffers->backBitmap.hbm)
|
|
{
|
|
RGBQUAD rgbq[256];
|
|
|
|
if (wglGetSurfacePalette(gengc, rgbq, TRUE))
|
|
{
|
|
int nColors;
|
|
|
|
// If color table was obtained, setup the DIBs.
|
|
|
|
nColors = 1 << gengc->gsurf.pfd.cColorBits;
|
|
|
|
// Scan-line DIB.
|
|
if (gengc->ColorsBitmap)
|
|
SetDIBColorTable(gengc->ColorsMemDC, 0, nColors, rgbq);
|
|
|
|
// Back buffer
|
|
if (buffers->backBitmap.hbm)
|
|
SetDIBColorTable(buffers->backBitmap.hdc, 0, nColors, rgbq);
|
|
}
|
|
else
|
|
{
|
|
WARNING("SyncDibColorTables: Unable to get surface palette\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
static BYTE vubSystemToRGB8[20] = {
|
|
0x00,
|
|
0x04,
|
|
0x20,
|
|
0x24,
|
|
0x80,
|
|
0x84,
|
|
0xa0,
|
|
0xf6,
|
|
0xf6,
|
|
0xf5,
|
|
0xff,
|
|
0xad,
|
|
0xa4,
|
|
0x07,
|
|
0x38,
|
|
0x3f,
|
|
0xc0,
|
|
0xc7,
|
|
0xf8,
|
|
0xff
|
|
};
|
|
|
|
// ComputeInverseTranslationVector
|
|
// Computes the inverse translation vector for 4-bit and 8-bit.
|
|
//
|
|
// Synopsis:
|
|
// void ComputeInverseTranslation(
|
|
// __GLGENcontext *gengc specifies the generic RC
|
|
// int cColorEntries specifies the number of color entries
|
|
// BYTE iPixeltype specifies the pixel format type
|
|
//
|
|
// Assumtions:
|
|
// The inverse translation vector has been allocated and initialized with
|
|
// zeros.
|
|
//
|
|
// History:
|
|
// 23-NOV-93 Eddie Robinson [v-eddier] Wrote it.
|
|
//
|
|
void FASTCALL ComputeInverseTranslationVector(__GLGENcontext *gengc,
|
|
int cColorEntries,
|
|
int iPixelType)
|
|
{
|
|
BYTE *pXlate, *pInvXlate;
|
|
int i, j;
|
|
|
|
pInvXlate = gengc->pajInvTranslateVector;
|
|
pXlate = gengc->pajTranslateVector;
|
|
for (i = 0; i < cColorEntries; i++)
|
|
{
|
|
if (pXlate[i] == i) { // Look for trivial mapping first
|
|
pInvXlate[i] = (BYTE)i;
|
|
}
|
|
else
|
|
{
|
|
for (j = 0; j < cColorEntries; j++)
|
|
{
|
|
if (pXlate[j] == i) // Look for exact match
|
|
{
|
|
pInvXlate[i] = (BYTE)j;
|
|
goto match_found;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we reach here, there is no exact match, so we should find the
|
|
// closest fit. These indices should match the system colors
|
|
// for 8-bit devices.
|
|
//
|
|
// Note that these pixel values cannot be generated by OpenGL
|
|
// drawing with the current foreground translation vector.
|
|
//
|
|
|
|
if (cColorEntries == 256)
|
|
{
|
|
if (i <= 9)
|
|
{
|
|
if (iPixelType == PFD_TYPE_RGBA)
|
|
pInvXlate[i] = vubSystemToRGB8[i];
|
|
else
|
|
pInvXlate[i] = (BYTE)i;
|
|
}
|
|
else if (i >= 246)
|
|
{
|
|
if (iPixelType == PFD_TYPE_RGBA)
|
|
pInvXlate[i] = vubSystemToRGB8[i-236];
|
|
else
|
|
pInvXlate[i] = i-236;
|
|
}
|
|
}
|
|
}
|
|
match_found:;
|
|
}
|
|
}
|
|
|
|
// er: similar to function in so_textu.c, but rounds up the result
|
|
|
|
/*
|
|
** Return the log based 2 of a number
|
|
**
|
|
** logTab1 returns (int)ceil(log2(index))
|
|
** logTab2 returns (int)log2(index)+1
|
|
*/
|
|
|
|
|
|
static GLubyte logTab1[256] = { 0, 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
|
|
4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
|
|
};
|
|
|
|
static GLubyte logTab2[256] = { 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
|
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
|
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8
|
|
};
|
|
|
|
static GLint FASTCALL Log2RoundUp(GLint i)
|
|
{
|
|
if (i & 0xffff0000) {
|
|
if (i & 0xff000000) {
|
|
if (i & 0x00ffffff)
|
|
return(logTab2[i >> 24] + 24);
|
|
else
|
|
return(logTab1[i >> 24] + 24);
|
|
} else {
|
|
if (i & 0x0000ffff)
|
|
return(logTab2[i >> 16] + 16);
|
|
else
|
|
return(logTab1[i >> 16] + 16);
|
|
}
|
|
} else {
|
|
if (i & 0xff00) {
|
|
if (i & 0x00ff)
|
|
return (logTab2[i >> 8] + 8);
|
|
else
|
|
return (logTab1[i >> 8] + 8);
|
|
} else {
|
|
return (logTab1[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// default translation vector for 4-bit RGB
|
|
|
|
static GLubyte vujRGBtoVGA[16] = {
|
|
0x0, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
|
0x0, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf
|
|
};
|
|
|
|
// SetColorTranslationVector
|
|
// Sets up the translation vector, which may take 2 forms:
|
|
// - In all 8,4-bit surfaces, get the translation vector with
|
|
// wglCopyTranslateVector(), with 2**numBits byte entries.
|
|
// - For 16,24,32 ColorIndex, get the mapping from index to RGB
|
|
// value with wglGetPalette(). All entries in the table are unsigned
|
|
// longs, with the first entry being the number of entries. This table
|
|
// always has (2**n) <= 4096 entries, because gl assumes n bits are
|
|
// used for color index.
|
|
//
|
|
// Synopsis:
|
|
// void SetColorTranslationVector
|
|
// __GLGENcontext *gengc generic RC
|
|
// int cColorEntries number of color entries
|
|
// int cColorBits number of color bits
|
|
// int iPixelType specifies RGB or ColorIndex
|
|
//
|
|
// History:
|
|
// Feb. 02 Eddie Robinson [v-eddier] Added support for 4-bit and 8-bit
|
|
// Jan. 29 Marc Fortier [v-marcf] Wrote it.
|
|
void
|
|
SetColorTranslationVector(__GLGENcontext *gengc, int cColorEntries,
|
|
int cColorBits, int iPixelType)
|
|
{
|
|
int numEntries, numBits;
|
|
__GLcontextModes *Modes;
|
|
BYTE ajBGRtoRGB[256];
|
|
BYTE ajTmp[256];
|
|
|
|
Modes = &((__GLcontext *)gengc)->modes;
|
|
|
|
// Handle formats with a hardware palette (i.e., 4bpp and 8bpp).
|
|
|
|
if ( cColorBits <= 8 )
|
|
{
|
|
int i;
|
|
BYTE *pXlate;
|
|
|
|
// Compute logical to system palette forward translation vector.
|
|
|
|
if (!wglCopyTranslateVector(gengc, gengc->pajTranslateVector,
|
|
cColorEntries))
|
|
{
|
|
// if foreground translation vector doesn't exist, build one
|
|
|
|
pXlate = gengc->pajTranslateVector;
|
|
|
|
if (cColorBits == 4)
|
|
{
|
|
// for RGB, map 1-1-1 to VGA colors. For CI, just map 1 to 1
|
|
if (iPixelType == PFD_TYPE_COLORINDEX)
|
|
{
|
|
for (i = 0; i < 16; i++)
|
|
pXlate[i] = (BYTE)i;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < 16; i++)
|
|
pXlate[i] = vujRGBtoVGA[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for RGB, map 1 to 1. For CI display, 1 - 20 to system colors
|
|
// for CI DIB, just map 1 to 1
|
|
if ((iPixelType == PFD_TYPE_COLORINDEX) &&
|
|
GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags))
|
|
{
|
|
for (i = 0; i < 10; i++)
|
|
pXlate[i] = (BYTE)i;
|
|
|
|
for (i = 10; i < 20; i++)
|
|
pXlate[i] = i + 236;
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < cColorEntries; i++)
|
|
pXlate[i] = (BYTE)i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Some MCD pixelformats specify a 233BGR (i.e., 2-bits blue in least
|
|
// significant bits, etc.) bit ordering. Unfortunately, this is the
|
|
// slow path for simulations. For those formats, we force the ordering
|
|
// to RGB internally and reorder the pajTranslateVector to convert it
|
|
// back to BGR before writing to the surface.
|
|
|
|
if (gengc->flags & GENGC_MCD_BGR_INTO_RGB)
|
|
{
|
|
pXlate = gengc->pajTranslateVector;
|
|
|
|
// Compute a 233BGR to 332RGB translation vector.
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
ajBGRtoRGB[i] = (((i & 0x03) << 6) | // blue
|
|
((i & 0x1c) << 1) | // green
|
|
((i & 0xe0) >> 5)) // red
|
|
& 0xff;
|
|
}
|
|
|
|
// Remap the tranlation vector to 332RGB.
|
|
|
|
RtlCopyMemory(ajTmp, pXlate, 256);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
pXlate[ajBGRtoRGB[i]] = ajTmp[i];
|
|
}
|
|
}
|
|
|
|
//!!!XXX -- I think the code below to fixup 4bpp is no longer needed.
|
|
//!!!XXX There is now special case code in wglCopyTranslateVector
|
|
#if 0
|
|
// wglCopyTranslateVector = TRUE, and 4-bit: need some fixing up
|
|
// For now, zero out upper nibble of returned xlate vector
|
|
else if( cColorBits == 4 ) {
|
|
pXlate = gengc->pajTranslateVector;
|
|
for( i = 0; i < 16; i ++ )
|
|
pXlate[i] &= 0xf;
|
|
}
|
|
#endif
|
|
ComputeInverseTranslationVector( gengc, cColorEntries, iPixelType );
|
|
|
|
#ifdef _CLIENTSIDE_
|
|
SyncDibColorTables( gengc );
|
|
#endif
|
|
}
|
|
|
|
// Handle formats w/o a hardware format (i.e., 16bpp, 24bpp, 32bpp).
|
|
|
|
else
|
|
{
|
|
if( cColorEntries <= 256 ) {
|
|
numEntries = 256;
|
|
numBits = 8;
|
|
}
|
|
else
|
|
{
|
|
numBits = Log2RoundUp( cColorEntries );
|
|
numEntries = 1 << numBits;
|
|
}
|
|
|
|
// We will always allocate 4096 entries for CI mode with > 8 bits
|
|
// of color. This enables us to use a constant (0xfff) mask for
|
|
// color-index clamping.
|
|
|
|
ASSERTOPENGL(numEntries <= MAXPALENTRIES,
|
|
"Maximum color-index size exceeded");
|
|
|
|
if( (numBits == Modes->indexBits) &&
|
|
(gengc->pajTranslateVector != NULL) )
|
|
{
|
|
// New palette same size as previous
|
|
ULONG *pTrans;
|
|
int i;
|
|
|
|
// zero out some entries
|
|
pTrans = (ULONG *)gengc->pajTranslateVector + cColorEntries + 1;
|
|
for( i = cColorEntries + 1; i < MAXPALENTRIES; i ++ )
|
|
*pTrans++ = 0;
|
|
}
|
|
else
|
|
{
|
|
__GLcontext *gc = (__GLcontext *) gengc;
|
|
__GLcolorBuffer *cfb;
|
|
|
|
// New palette has different size
|
|
if( gengc->pajTranslateVector != NULL &&
|
|
(gengc->pajTranslateVector != gengc->xlatPalette) )
|
|
GCFREE(gc, gengc->pajTranslateVector );
|
|
|
|
gengc->pajTranslateVector =
|
|
GCALLOCZ(gc, (MAXPALENTRIES+1)*sizeof(ULONG));
|
|
|
|
// Change indexBits
|
|
Modes->indexBits = numBits;
|
|
|
|
// For depths greater than 8 bits, cfb->redMax must change if the
|
|
// number of entries in the palette changes.
|
|
// Also, change the writemask so that if the palette grows, the
|
|
// new planes will be enabled by default.
|
|
|
|
if (cfb = gc->front)
|
|
{
|
|
GLint oldRedMax;
|
|
|
|
oldRedMax = cfb->redMax;
|
|
cfb->redMax = (1 << gc->modes.indexBits) - 1;
|
|
gc->state.raster.writeMask |= ~oldRedMax;
|
|
gc->state.raster.writeMask &= cfb->redMax;
|
|
}
|
|
if (cfb = gc->back)
|
|
{
|
|
GLint oldRedMax;
|
|
|
|
oldRedMax = cfb->redMax;
|
|
cfb->redMax = (1 << gc->modes.indexBits) - 1;
|
|
gc->state.raster.writeMask |= ~oldRedMax;
|
|
gc->state.raster.writeMask &= cfb->redMax;
|
|
}
|
|
|
|
// store procs may need to be picked based on the change in
|
|
// palette size
|
|
|
|
__GL_DELAY_VALIDATE(gc);
|
|
#ifdef _MCD_
|
|
MCD_STATE_DIRTY(gc, FBUFCTRL);
|
|
#endif
|
|
}
|
|
|
|
// Compute index-to-color table from current palette information
|
|
|
|
wglComputeIndexedColors( gengc,
|
|
(unsigned long *) gengc->pajTranslateVector,
|
|
MAXPALENTRIES );
|
|
}
|
|
}
|
|
|
|
// HandlePaletteChanges
|
|
// Check if palette has changed, update translation vectors
|
|
// XXX add support for malloc failures at attention time
|
|
// Synopsis:
|
|
// void HandlePaletteChanges(
|
|
// __GLGENcontext *gengc specifies the generic RC
|
|
//
|
|
// Assumtions:
|
|
// x wglPaletteChanged() will always return 0 when no palette is set
|
|
// by the client. This has proved to be not always true.
|
|
//
|
|
// History:
|
|
// Feb. 25 Fixed by rightful owner
|
|
// Feb. ?? Mutilated by others
|
|
// Jan. 29 Marc Fortier [v-marcf] Wrote it.
|
|
void HandlePaletteChanges( __GLGENcontext *gengc, GLGENwindow *pwnd )
|
|
{
|
|
ULONG Timestamp;
|
|
GLuint paletteSize;
|
|
PIXELFORMATDESCRIPTOR *pfmt;
|
|
|
|
// No palettes for IC's
|
|
if (gengc->dwCurrentFlags & GLSURF_METAFILE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Timestamp = wglPaletteChanged(gengc, pwnd);
|
|
if (Timestamp != gengc->PaletteTimestamp)
|
|
{
|
|
pfmt = &gengc->gsurf.pfd;
|
|
|
|
if (pfmt->iPixelType == PFD_TYPE_COLORINDEX)
|
|
{
|
|
if (pfmt->cColorBits <= 8)
|
|
{
|
|
paletteSize = 1 << pfmt->cColorBits;
|
|
}
|
|
else
|
|
{
|
|
paletteSize = min(wglPaletteSize(gengc), MAXPALENTRIES);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifndef _CLIENTSIDE_
|
|
/* Only update RGB at makecurrent time */
|
|
if( (gengc->PaletteTimestamp == INITIAL_TIMESTAMP) &&
|
|
(pfmt->cColorBits <= 8) )
|
|
#else
|
|
if (pfmt->cColorBits <= 8)
|
|
#endif
|
|
{
|
|
paletteSize = 1 << pfmt->cColorBits;
|
|
}
|
|
else
|
|
{
|
|
paletteSize = 0;
|
|
}
|
|
}
|
|
|
|
if (paletteSize)
|
|
{
|
|
SetColorTranslationVector( gengc, paletteSize,
|
|
pfmt->cColorBits, pfmt->iPixelType );
|
|
}
|
|
|
|
EmptyFillStrokeCache(gengc);
|
|
|
|
gengc->PaletteTimestamp = Timestamp;
|
|
}
|
|
}
|
|
|
|
#ifdef _CLIENTSIDE_
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglFillBitfields
|
|
*
|
|
* Return the Red, Green, and Blue color masks based on the DC surface
|
|
* format. The masks are returned in the pdwColorFields array in the
|
|
* order: red mask, green mask, blue mask.
|
|
*
|
|
* Note:
|
|
* Should be called only for 16bpp or greater surfaces.
|
|
*
|
|
* History:
|
|
* 12-Jun-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void
|
|
wglFillBitfields(PIXELFORMATDESCRIPTOR *ppfd, DWORD *pdwColorFields)
|
|
{
|
|
*pdwColorFields++ = MaskFromBits(ppfd->cRedShift, ppfd->cRedBits );
|
|
*pdwColorFields++ = MaskFromBits(ppfd->cGreenShift, ppfd->cGreenBits);
|
|
*pdwColorFields++ = MaskFromBits(ppfd->cBlueShift, ppfd->cBlueBits );
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCreateBitmap
|
|
*
|
|
* Create a DIB section and color table that matches the specified format.
|
|
*
|
|
* Returns:
|
|
* A valid bitmap handle if sucessful, NULL otherwise.
|
|
*
|
|
* History:
|
|
* 20-Sep-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP
|
|
wglCreateBitmap( __GLGENcontext *gengc, SIZEL sizl, PVOID *ppvBits )
|
|
{
|
|
BITMAPINFO *pbmi;
|
|
HBITMAP hbmRet = (HBITMAP) NULL;
|
|
size_t cjbmi;
|
|
DWORD dwCompression;
|
|
DWORD cjImage = 0;
|
|
WORD wBitCount;
|
|
int cColors = 0;
|
|
|
|
*ppvBits = (PVOID) NULL;
|
|
|
|
// Figure out what kind of DIB needs to be created based on the
|
|
// DC format.
|
|
|
|
switch ( gengc->gsurf.pfd.cColorBits )
|
|
{
|
|
case 4:
|
|
cjbmi = sizeof(BITMAPINFO) + 16*sizeof(RGBQUAD);
|
|
dwCompression = BI_RGB;
|
|
wBitCount = 4;
|
|
cColors = 16;
|
|
break;
|
|
case 8:
|
|
cjbmi = sizeof(BITMAPINFO) + 256*sizeof(RGBQUAD);
|
|
dwCompression = BI_RGB;
|
|
wBitCount = 8;
|
|
cColors = 256;
|
|
break;
|
|
case 16:
|
|
cjbmi = sizeof(BITMAPINFO) + 3*sizeof(RGBQUAD);
|
|
dwCompression = BI_BITFIELDS;
|
|
cjImage = sizl.cx * sizl.cy * 2;
|
|
wBitCount = 16;
|
|
break;
|
|
case 24:
|
|
cjbmi = sizeof(BITMAPINFO);
|
|
dwCompression = BI_RGB;
|
|
wBitCount = 24;
|
|
break;
|
|
case 32:
|
|
cjbmi = sizeof(BITMAPINFO) + 3*sizeof(RGBQUAD);
|
|
dwCompression = BI_BITFIELDS;
|
|
cjImage = sizl.cx * sizl.cy * 4;
|
|
wBitCount = 32;
|
|
break;
|
|
default:
|
|
WARNING1("wglCreateBitmap: unknown format 0x%lx\n",
|
|
gengc->gsurf.pfd.cColorBits);
|
|
return (HBITMAP) NULL;
|
|
}
|
|
|
|
// Allocate the BITMAPINFO structure and color table.
|
|
|
|
pbmi = ALLOC(cjbmi);
|
|
if (pbmi)
|
|
{
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmi->bmiHeader.biWidth = sizl.cx;
|
|
pbmi->bmiHeader.biHeight = sizl.cy;
|
|
pbmi->bmiHeader.biPlanes = 1;
|
|
pbmi->bmiHeader.biBitCount = wBitCount;
|
|
pbmi->bmiHeader.biCompression = dwCompression;
|
|
pbmi->bmiHeader.biSizeImage = cjImage;
|
|
pbmi->bmiHeader.biXPelsPerMeter = 0;
|
|
pbmi->bmiHeader.biYPelsPerMeter = 0;
|
|
pbmi->bmiHeader.biClrUsed = 0;
|
|
pbmi->bmiHeader.biClrImportant = 0;
|
|
|
|
// Initialize DIB color table.
|
|
|
|
switch (gengc->gsurf.pfd.cColorBits)
|
|
{
|
|
case 4:
|
|
case 8:
|
|
if (!wglGetSurfacePalette(gengc, &pbmi->bmiColors[0], FALSE))
|
|
{
|
|
return NULL;
|
|
}
|
|
break;
|
|
|
|
case 16:
|
|
case 32:
|
|
wglFillBitfields(&gengc->gsurf.pfd, (DWORD *) &pbmi->bmiColors[0]);
|
|
break;
|
|
|
|
case 24:
|
|
// Color table is assumed to be BGR for 24BPP DIBs. Nothing to do.
|
|
break;
|
|
}
|
|
|
|
// Create DIB section.
|
|
|
|
hbmRet = CreateDIBSection(gengc->gwidCurrent.hdc, pbmi, DIB_RGB_COLORS,
|
|
ppvBits, NULL, 0);
|
|
|
|
#if DBG
|
|
if ( hbmRet == (HBITMAP) NULL )
|
|
WARNING("wglCreateBitmap(): DIB section creation failed\n");
|
|
#endif
|
|
|
|
FREE(pbmi);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglCreateBitmap(): memory allocation error\n");
|
|
}
|
|
|
|
return hbmRet;
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCreateScanlineBuffers
|
|
*
|
|
* Allocate the scanline buffers. The scanline buffers are used by the
|
|
* generic implementation to write data to the target (display or bitmap)
|
|
* a span at a time when the target surface is not directly accessible.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Taken from CreateGDIObjects and made into function.
|
|
\**************************************************************************/
|
|
|
|
BOOL FASTCALL wglCreateScanlineBuffers(__GLGENcontext *gengc)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PIXELFORMATDESCRIPTOR *pfmt;
|
|
UINT cBits;
|
|
UINT cBytes;
|
|
SIZEL size;
|
|
int cColorEntries;
|
|
__GLcontext *gc;
|
|
|
|
gc = (__GLcontext *)gengc;
|
|
pfmt = &gengc->gsurf.pfd;
|
|
|
|
//
|
|
// Bitmap must have DWORD sized scanlines.
|
|
//
|
|
|
|
cBits = BITS_ALIGNDWORD(__GL_MAX_WINDOW_WIDTH * pfmt->cColorBits);
|
|
cBytes = cBits / 8;
|
|
|
|
//
|
|
// Create color scanline DIB buffer.
|
|
//
|
|
|
|
size.cx = cBits / pfmt->cColorBits;
|
|
size.cy = 1;
|
|
gengc->ColorsMemDC = CreateCompatibleDC(gengc->gwidCurrent.hdc);
|
|
gengc->ColorsBitmap = wglCreateBitmap(gengc, size,
|
|
&gengc->ColorsBits);
|
|
|
|
if ( (NULL == gengc->ColorsMemDC) ||
|
|
(NULL == gengc->ColorsBitmap) ||
|
|
(NULL == gengc->ColorsBits) ||
|
|
!SelectObject(gengc->ColorsMemDC, gengc->ColorsBitmap) )
|
|
{
|
|
#if DBG
|
|
if (!gengc->ColorsMemDC)
|
|
WARNING("wglCreateScanlineBuffers: dc creation failed, ColorsMemDC\n");
|
|
if (!gengc->ColorsBitmap)
|
|
WARNING("wglCreateScanlineBuffers: bitmap creation failed, ColorsBitmap\n");
|
|
if (!gengc->ColorsBits)
|
|
WARNING("wglCreateScanlineBuffers: bitmap creation failed, ColorsBits\n");
|
|
#endif
|
|
|
|
goto wglCreateScanlineBuffers_exit;
|
|
}
|
|
|
|
//
|
|
// Screen to DIB BitBlt performance on Win95 is very poor.
|
|
// By doing the BitBlt via an intermediate DDB, we can avoid
|
|
// a lot of unnecessary overhead. So create an intermediate
|
|
// scanline DDB to match ColorsBitmap.
|
|
//
|
|
|
|
if ((gengc->dwCurrentFlags & GLSURF_DIRECTDRAW) == 0)
|
|
{
|
|
gengc->ColorsDdbDc = CreateCompatibleDC(gengc->gwidCurrent.hdc);
|
|
gengc->ColorsDdb = CreateCompatibleBitmap(gengc->gwidCurrent.hdc,
|
|
size.cx, size.cy);
|
|
|
|
//!!!Viper fix -- Diamond Viper (Weitek 9000) fails
|
|
//!!! CreateCompatibleBitmap for some (currently unknown)
|
|
//!!! reason
|
|
|
|
if ( !gengc->ColorsDdb )
|
|
{
|
|
WARNING("wglCreateScanlineBuffers: "
|
|
"CreateCompatibleBitmap failed\n");
|
|
if (gengc->ColorsDdbDc)
|
|
DeleteDC(gengc->ColorsDdbDc);
|
|
gengc->ColorsDdbDc = (HDC) NULL;
|
|
}
|
|
else
|
|
{
|
|
if ( (NULL == gengc->ColorsDdbDc) ||
|
|
!SelectObject(gengc->ColorsDdbDc, gengc->ColorsDdb) )
|
|
{
|
|
#if DBG
|
|
if (!gengc->ColorsDdbDc)
|
|
WARNING("wglCreateScanlineBuffers: "
|
|
"dc creation failed, ColorsDdbDc\n");
|
|
if (!gengc->ColorsDdb)
|
|
WARNING("wglCreateScanlineBuffers: "
|
|
"bitmap creation failed, ColorsDdb\n");
|
|
#endif
|
|
|
|
goto wglCreateScanlineBuffers_exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Success.
|
|
//
|
|
|
|
bRet = TRUE;
|
|
|
|
wglCreateScanlineBuffers_exit:
|
|
|
|
if (!bRet)
|
|
{
|
|
//
|
|
// Error case. Delete whatever may have been allocated.
|
|
//
|
|
|
|
wglDeleteScanlineBuffers(gengc);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglDeleteScanlineBuffers
|
|
*
|
|
* Delete the scanline buffers. The scanline buffers are used by the
|
|
* generic implementation to write data to the target (display or bitmap)
|
|
* a span at a time when the target surface is not directly accessible.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Taken from CreateGDIObjects and made into function.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL wglDeleteScanlineBuffers(__GLGENcontext *gengc)
|
|
{
|
|
__GLcontext *gc = (__GLcontext *)gengc;
|
|
|
|
//
|
|
// Delete color scanline DIB buffer.
|
|
//
|
|
|
|
if (gengc->ColorsMemDC)
|
|
{
|
|
DeleteDC(gengc->ColorsMemDC);
|
|
gengc->ColorsMemDC = NULL;
|
|
}
|
|
|
|
if (gengc->ColorsBitmap)
|
|
{
|
|
if (!DeleteObject(gengc->ColorsBitmap))
|
|
ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DeleteObject failed");
|
|
gengc->ColorsBitmap = NULL;
|
|
gengc->ColorsBits = NULL; // deleted for us when DIB section dies
|
|
}
|
|
|
|
//
|
|
// Delete intermediate color scanline DDB buffer.
|
|
//
|
|
|
|
if (gengc->ColorsDdbDc)
|
|
{
|
|
if (!DeleteDC(gengc->ColorsDdbDc))
|
|
{
|
|
ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DDB DeleteDC failed");
|
|
}
|
|
gengc->ColorsDdbDc = NULL;
|
|
}
|
|
|
|
if (gengc->ColorsDdb)
|
|
{
|
|
if (!DeleteObject(gengc->ColorsDdb))
|
|
{
|
|
ASSERTOPENGL(FALSE, "wglDeleteScanlineBuffers: DDB DeleteObject failed");
|
|
}
|
|
gengc->ColorsDdb = NULL;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglInitializeColorBuffers
|
|
*
|
|
* Initialize the color buffer (front and/or back) information.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Taken out of glsrvCreateContext and made into function.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL wglInitializeColorBuffers(__GLGENcontext *gengc)
|
|
{
|
|
__GLcontext *gc = &gengc->gc;
|
|
|
|
gc->front = &gc->frontBuffer;
|
|
|
|
if ( gc->modes.doubleBufferMode)
|
|
{
|
|
gc->back = &gc->backBuffer;
|
|
|
|
if (gc->modes.colorIndexMode)
|
|
{
|
|
__glGenInitCI(gc, gc->front, GL_FRONT);
|
|
__glGenInitCI(gc, gc->back, GL_BACK);
|
|
}
|
|
else
|
|
{
|
|
__glGenInitRGB(gc, gc->front, GL_FRONT);
|
|
__glGenInitRGB(gc, gc->back, GL_BACK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (gc->modes.colorIndexMode)
|
|
{
|
|
__glGenInitCI(gc, gc->front, GL_FRONT);
|
|
}
|
|
else
|
|
{
|
|
__glGenInitRGB(gc, gc->front, GL_FRONT);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglInitializeDepthBuffer
|
|
*
|
|
* Initialize the depth buffer information.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Taken out of glsrvCreateContext and made into function.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL wglInitializeDepthBuffer(__GLGENcontext *gengc)
|
|
{
|
|
__GLcontext *gc = &gengc->gc;
|
|
|
|
if (gc->modes.depthBits)
|
|
{
|
|
if (gengc->_pMcdState) {
|
|
// This is not the final initialization of the MCD depth buffer.
|
|
// This is being done now so that the validate proc can be done
|
|
// in glsrvCreateContext. The real initialization will occur
|
|
// during glsrvMakeCurrent.
|
|
|
|
GenMcdInitDepth(gc, &gc->depthBuffer);
|
|
gc->depthBuffer.scale = gengc->_pMcdState->McdRcInfo.depthBufferMax;
|
|
} else if (gc->modes.depthBits == 16) {
|
|
DBGINFO("CALLING: __glInitDepth16\n");
|
|
__glInitDepth16(gc, &gc->depthBuffer);
|
|
gc->depthBuffer.scale = 0x7fff;
|
|
} else {
|
|
DBGINFO("CALLING: __glInitDepth32\n");
|
|
__glInitDepth32(gc, &gc->depthBuffer);
|
|
gc->depthBuffer.scale = 0x7fffffff;
|
|
}
|
|
/*
|
|
* Note: scale factor does not use the high bit (this avoids
|
|
* floating point exceptions).
|
|
*/
|
|
// XXX (mf) I changed 16 bit depth buffer to use high bit, since
|
|
// there is no possibility of overflow on conversion to float. For
|
|
// 32-bit, (float) 0xffffffff overflows to 0. I was able to avoid
|
|
// overflow in this case by using a scale factor of 0xffffff7f, but
|
|
// this is a weird number, and 31 bits is enough resolution anyways.
|
|
// !! Note asserts in px_fast.c that have hardcoded depth scales.
|
|
}
|
|
#ifdef _MCD_
|
|
else
|
|
{
|
|
// This is not the final initialization of the MCD depth buffer.
|
|
// This is being done now so that the validate proc can be done
|
|
// in glsrvCreateContext. The real initialization will occur
|
|
// during glsrvMakeCurrent.
|
|
|
|
GenMcdInitDepth(gc, &gc->depthBuffer);
|
|
gc->depthBuffer.scale = 0x7fffffff;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglInitializePixelCopyFuncs
|
|
*
|
|
* Set the appropriate CopyPixels and PixelVisible functions in the context.
|
|
*
|
|
* History:
|
|
* 18-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Taken out of glsrvCreateContext and made into function.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL wglInitializePixelCopyFuncs(__GLGENcontext *gengc)
|
|
{
|
|
__GLcontext *gc = &gengc->gc;
|
|
|
|
if ( gc->front->buf.flags & DIB_FORMAT )
|
|
gengc->pfnCopyPixels = dibCopyPixels;
|
|
else {
|
|
if (gengc->pMcdState) {
|
|
gengc->ColorsBits = gengc->pMcdState->pMcdSurf->McdColorBuf.pv;
|
|
gengc->pfnCopyPixels = GenMcdCopyPixels;
|
|
}
|
|
else
|
|
gengc->pfnCopyPixels = gdiCopyPixels;
|
|
}
|
|
gengc->pfnPixelVisible = wglPixelVisible;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateGDIObjects
|
|
*
|
|
* Create various buffers, and GDI objects that we will always need.
|
|
*
|
|
* Called from glsrvCreateContext().
|
|
*
|
|
* Returns:
|
|
* TRUE if sucessful, FALSE if error.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL FASTCALL CreateGDIObjects(__GLGENcontext *gengc)
|
|
{
|
|
PIXELFORMATDESCRIPTOR *pfmt;
|
|
UINT cBytes;
|
|
SIZEL size;
|
|
int cColorEntries;
|
|
__GLcontext *gc;
|
|
|
|
gc = (__GLcontext *)gengc;
|
|
pfmt = &gengc->gsurf.pfd;
|
|
|
|
//
|
|
// Palette translation vectors.
|
|
//
|
|
// If not a true color surface, need space for the foreground xlation
|
|
//
|
|
|
|
if (pfmt->cColorBits <= 8)
|
|
{
|
|
cColorEntries = 1 << pfmt->cColorBits;
|
|
|
|
ASSERTOPENGL(NULL == gengc->pajTranslateVector, "have a xlate vector");
|
|
|
|
//
|
|
// Just set the translation vector to the cache space in the gc:
|
|
//
|
|
|
|
gengc->pajTranslateVector = gengc->xlatPalette;
|
|
|
|
//
|
|
// Allocate the inverse translation vector.
|
|
//
|
|
|
|
ASSERTOPENGL(NULL == gengc->pajInvTranslateVector, "have an inv xlate vector");
|
|
gengc->pajInvTranslateVector = GCALLOCZ(gc, cColorEntries);
|
|
if (NULL == gengc->pajInvTranslateVector)
|
|
{
|
|
WARNING("CreateGDIObjects: memory allocation failed, pajInvTrans\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Scanline buffers.
|
|
//
|
|
// Always create engine bitmaps to provide a generic means of performing
|
|
// pixel transfers using the ColorsBits and StippleBits buffers.
|
|
//
|
|
|
|
if (NULL == gengc->ColorsBits)
|
|
{
|
|
//
|
|
// Color scanline buffer
|
|
//
|
|
|
|
#ifdef _MCD_
|
|
//
|
|
// If MCD the ColorBits will be set when the MCD surface is
|
|
// created, so nothing to do.
|
|
//
|
|
// Otherwise, create the generic scanline buffer.
|
|
//
|
|
//
|
|
|
|
if (!gengc->_pMcdState)
|
|
#endif
|
|
{
|
|
//
|
|
// Generic case.
|
|
//
|
|
|
|
if (!wglCreateScanlineBuffers(gengc))
|
|
{
|
|
WARNING("CreateGDIObjects: wglCreateScanlineBuffers failed\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stipple scanline buffer.
|
|
//
|
|
|
|
// Bitmap must have DWORD sized scanlines. Note that stipple only
|
|
// requires a 1 bit per pel bitmap.
|
|
|
|
ASSERTOPENGL(NULL == gengc->StippleBits, "StippleBits not null");
|
|
size.cx = BITS_ALIGNDWORD(__GL_MAX_WINDOW_WIDTH);
|
|
cBytes = size.cx / 8;
|
|
gengc->StippleBits = GCALLOCZ(gc, cBytes);
|
|
if (NULL == gengc->StippleBits)
|
|
{
|
|
WARNING("CreateGDIObjects: memory allocation failed, StippleBits\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
ASSERTOPENGL(NULL == gengc->StippleBitmap, "StippleBitmap not null");
|
|
#ifndef _CLIENTSIDE_
|
|
//!!!XXX -- why are we even bothering to make the stipple an engine bitmap?
|
|
//!!!XXX It is never used as such (at least not yet).
|
|
gengc->StippleBitmap = EngCreateBitmap(
|
|
size,
|
|
cBytes,
|
|
BMF_1BPP,
|
|
0,
|
|
gengc->StippleBits);
|
|
if (NULL == gengc->StippleBitmap)
|
|
{
|
|
WARNING("CreateGDIObjects: memory allocation failed, StippleBitmap\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
#else
|
|
gengc->StippleBitmap = (HBITMAP) NULL;
|
|
#endif
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
ERROR_EXIT:
|
|
|
|
//
|
|
// Error cleanup --
|
|
// Destroy everything we might have created, return false so makecurrent fails.
|
|
//
|
|
|
|
if (gengc->pajTranslateVector &&
|
|
(gengc->pajTranslateVector != gengc->xlatPalette))
|
|
{
|
|
GCFREE(gc,gengc->pajTranslateVector);
|
|
gengc->pajTranslateVector = NULL;
|
|
}
|
|
|
|
if (gengc->pajInvTranslateVector)
|
|
{
|
|
GCFREE(gc,gengc->pajInvTranslateVector);
|
|
gengc->pajInvTranslateVector = NULL;
|
|
}
|
|
|
|
wglDeleteScanlineBuffers(gengc);
|
|
|
|
if (gengc->StippleBits)
|
|
{
|
|
GCFREE(gc,gengc->StippleBits);
|
|
gengc->StippleBits = NULL;
|
|
}
|
|
|
|
#ifndef _CLIENTSIDE_
|
|
if (gengc->StippleBitmap)
|
|
{
|
|
if (!EngDeleteSurface((HSURF)gengc->StippleBitmap))
|
|
ASSERTOPENGL(FALSE, "EngDeleteSurface failed");
|
|
gengc->StippleBitmap = NULL;
|
|
}
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ApplyViewport
|
|
*
|
|
* Recompute viewport state and clipbox. May also be called via the
|
|
* applyViewport function pointer in the gc's proc table.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// This routine can be called because of a user vieport command, or because
|
|
// of a change in the size of the window
|
|
|
|
static void FASTCALL ApplyViewport(__GLcontext *gc)
|
|
{
|
|
GLint xlow, ylow, xhigh, yhigh;
|
|
GLint llx, lly, urx, ury;
|
|
GLboolean lastReasonable;
|
|
GLGENwindow *pwnd;
|
|
GLint clipLeft, clipRight, clipTop, clipBottom;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) gc;
|
|
|
|
DBGENTRY("ApplyViewport\n");
|
|
|
|
ASSERTOPENGL(gengc->pwndLocked != NULL,
|
|
"ApplyViewport called without lock\n");
|
|
|
|
pwnd = gengc->pwndLocked;
|
|
if (pwnd)
|
|
{
|
|
gengc->visibleWidth = pwnd->rclBounds.right - pwnd->rclBounds.left;
|
|
gengc->visibleHeight = pwnd->rclBounds.bottom - pwnd->rclBounds.top;
|
|
}
|
|
else
|
|
{
|
|
gengc->visibleWidth = 0;
|
|
gengc->visibleHeight = 0;
|
|
}
|
|
|
|
// Sanity check the info from window.
|
|
ASSERTOPENGL(
|
|
gengc->visibleWidth <= __GL_MAX_WINDOW_WIDTH && gengc->visibleHeight <= __GL_MAX_WINDOW_HEIGHT,
|
|
"ApplyViewport(): bad visible rect size\n"
|
|
);
|
|
|
|
/* If this viewport is fully contained in the window, we note this fact,
|
|
** and this can save us on scissoring tests.
|
|
*/
|
|
if (gc->state.enables.general & __GL_SCISSOR_TEST_ENABLE)
|
|
{
|
|
xlow = gc->state.scissor.scissorX;
|
|
xhigh = xlow + gc->state.scissor.scissorWidth;
|
|
ylow = gc->state.scissor.scissorY;
|
|
yhigh = ylow + gc->state.scissor.scissorHeight;
|
|
}
|
|
else
|
|
{
|
|
xlow = 0;
|
|
ylow = 0;
|
|
xhigh = gc->constants.width;
|
|
yhigh = gc->constants.height;
|
|
}
|
|
|
|
/*
|
|
** convert visible region to GL coords and intersect with scissor
|
|
*/
|
|
if (pwnd)
|
|
{
|
|
clipLeft = pwnd->rclBounds.left - pwnd->rclClient.left;
|
|
clipRight = pwnd->rclBounds.right - pwnd->rclClient.left;
|
|
clipTop = gc->constants.height -
|
|
(pwnd->rclBounds.top - pwnd->rclClient.top);
|
|
clipBottom = gc->constants.height -
|
|
(pwnd->rclBounds.bottom - pwnd->rclClient.top);
|
|
}
|
|
else
|
|
{
|
|
clipLeft = 0;
|
|
clipRight = 0;
|
|
clipTop = 0;
|
|
clipBottom = 0;
|
|
}
|
|
|
|
if (xlow < clipLeft) xlow = clipLeft;
|
|
if (xhigh > clipRight) xhigh = clipRight;
|
|
if (ylow < clipBottom) ylow = clipBottom;
|
|
if (yhigh > clipTop) yhigh = clipTop;
|
|
|
|
// ComputeClipBox
|
|
|
|
{
|
|
if (xlow >= xhigh || ylow >= yhigh)
|
|
{
|
|
gc->transform.clipX0 = gc->constants.viewportXAdjust;
|
|
gc->transform.clipX1 = gc->constants.viewportXAdjust;
|
|
gc->transform.clipY0 = gc->constants.viewportYAdjust;
|
|
gc->transform.clipY1 = gc->constants.viewportYAdjust;
|
|
}
|
|
else
|
|
{
|
|
gc->transform.clipX0 = xlow + gc->constants.viewportXAdjust;
|
|
gc->transform.clipX1 = xhigh + gc->constants.viewportXAdjust;
|
|
|
|
if (gc->constants.yInverted) {
|
|
gc->transform.clipY0 = (gc->constants.height - yhigh) +
|
|
gc->constants.viewportYAdjust;
|
|
gc->transform.clipY1 = (gc->constants.height - ylow) +
|
|
gc->constants.viewportYAdjust;
|
|
} else {
|
|
gc->transform.clipY0 = ylow + gc->constants.viewportYAdjust;
|
|
gc->transform.clipY1 = yhigh + gc->constants.viewportYAdjust;
|
|
}
|
|
}
|
|
}
|
|
|
|
llx = (GLint)gc->state.viewport.x;
|
|
lly = (GLint)gc->state.viewport.y;
|
|
|
|
urx = llx + (GLint)gc->state.viewport.width;
|
|
ury = lly + (GLint)gc->state.viewport.height;
|
|
|
|
#ifdef NT
|
|
gc->transform.miny = (gc->constants.height - ury) +
|
|
gc->constants.viewportYAdjust;
|
|
gc->transform.maxy = gc->transform.miny + (GLint)gc->state.viewport.height;
|
|
gc->transform.fminy = (__GLfloat)gc->transform.miny;
|
|
gc->transform.fmaxy = (__GLfloat)gc->transform.maxy;
|
|
|
|
// The viewport xScale, xCenter, yScale and yCenter values are computed in
|
|
// first MakeCurrent and subsequent glViewport calls. When the window is
|
|
// resized (i.e. gc->constatns.height changes), however, we need to recompute
|
|
// yCenter if yInverted is TRUE.
|
|
|
|
if (gc->constants.yInverted)
|
|
{
|
|
__GLfloat hh, h2;
|
|
|
|
h2 = gc->state.viewport.height * __glHalf;
|
|
hh = h2 - gc->constants.viewportEpsilon;
|
|
gc->state.viewport.yCenter =
|
|
gc->constants.height - (gc->state.viewport.y + h2) +
|
|
gc->constants.fviewportYAdjust;
|
|
|
|
#if 0
|
|
DbgPrint("AV ys %.3lf, yc %.3lf (%.3lf)\n",
|
|
-hh, gc->state.viewport.yCenter,
|
|
gc->constants.height - (gc->state.viewport.y + h2));
|
|
#endif
|
|
}
|
|
#else
|
|
ww = gc->state.viewport.width * __glHalf;
|
|
hh = gc->state.viewport.height * __glHalf;
|
|
|
|
gc->state.viewport.xScale = ww;
|
|
gc->state.viewport.xCenter = gc->state.viewport.x + ww +
|
|
gc->constants.fviewportXAdjust;
|
|
|
|
if (gc->constants.yInverted) {
|
|
gc->state.viewport.yScale = -hh;
|
|
gc->state.viewport.yCenter =
|
|
(gc->constants.height - gc->constants.viewportEpsilon) -
|
|
(gc->state.viewport.y + hh) +
|
|
gc->constants.fviewportYAdjust;
|
|
} else {
|
|
gc->state.viewport.yScale = hh;
|
|
gc->state.viewport.yCenter = gc->state.viewport.y + hh +
|
|
gc->constants.fviewportYAdjust;
|
|
}
|
|
#endif
|
|
|
|
// Remember the current reasonableViewport. If it changes, we may
|
|
// need to change the pick procs.
|
|
|
|
lastReasonable = gc->transform.reasonableViewport;
|
|
|
|
// Is viewport entirely within the visible bounding rectangle (which
|
|
// includes scissoring if it is turned on)? reasonableViewport is
|
|
// TRUE if so, FALSE otherwise.
|
|
// The viewport must also have a non-zero size to be reasonable
|
|
|
|
if (llx >= xlow && lly >= ylow && urx <= xhigh && ury <= yhigh &&
|
|
urx-llx >= 1 && ury-lly >= 1)
|
|
{
|
|
gc->transform.reasonableViewport = GL_TRUE;
|
|
} else {
|
|
gc->transform.reasonableViewport = GL_FALSE;
|
|
}
|
|
|
|
#if 0
|
|
DbgPrint("%3X:Clipbox %4d,%4d - %4d,%4d, reasonable %d, g %p, w %p\n",
|
|
GetCurrentThreadId(),
|
|
gc->transform.clipX0, gc->transform.clipY0,
|
|
gc->transform.clipX1, gc->transform.clipY1,
|
|
gc->transform.reasonableViewport,
|
|
gc, ((__GLGENcontext *)gc)->pwndLocked);
|
|
#endif
|
|
|
|
#ifdef NT
|
|
// To be safe than sorry. The new poly array does not break up Begin/End pair.
|
|
|
|
if (lastReasonable != gc->transform.reasonableViewport)
|
|
__GL_DELAY_VALIDATE(gc);
|
|
|
|
#ifdef _MCD_
|
|
MCD_STATE_DIRTY(gc, VIEWPORT);
|
|
#endif
|
|
|
|
#else
|
|
// Old code use to use __GL_DELAY_VALIDATE() macro, this would
|
|
// blow up if resize/position changed and a flush occured between
|
|
// a glBegin/End pair. Only need to pick span, line, & triangle procs
|
|
// since that is safe
|
|
|
|
if (lastReasonable != gc->transform.reasonableViewport) {
|
|
(*gc->procs.pickSpanProcs)(gc);
|
|
(*gc->procs.pickTriangleProcs)(gc);
|
|
(*gc->procs.pickLineProcs)(gc);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* __glGenFreeBuffers
|
|
*
|
|
* Free the __GLGENbuffers structure and its associated ancillary and
|
|
* back buffers.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL __glGenFreeBuffers(__GLGENbuffers *buffers)
|
|
{
|
|
if (buffers == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
DBGBEGIN(LEVEL_INFO)
|
|
DbgPrint("glGenFreeBuffers 0x%x, 0x%x, 0x%x, 0x%x\n",
|
|
buffers->accumBuffer.base,
|
|
buffers->stencilBuffer.base,
|
|
buffers->depthBuffer.base,
|
|
buffers);
|
|
DBGEND;
|
|
#endif
|
|
|
|
//
|
|
// Free ancillary buffers
|
|
//
|
|
|
|
if (buffers->accumBuffer.base) {
|
|
DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing accumulation buffer\n");
|
|
FREE(buffers->accumBuffer.base);
|
|
}
|
|
if (buffers->stencilBuffer.base) {
|
|
DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing stencil buffer\n");
|
|
FREE(buffers->stencilBuffer.base);
|
|
}
|
|
|
|
//
|
|
// Free alpha buffers
|
|
//
|
|
if (buffers->alphaBuffer0.base) {
|
|
DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing alpha buffer 0\n");
|
|
FREE(buffers->alphaBuffer0.base);
|
|
}
|
|
if (buffers->alphaBuffer1.base) {
|
|
DBGLEVEL(LEVEL_ALLOC, "__glGenFreeBuffers: Freeing alpha buffer 1\n");
|
|
FREE(buffers->alphaBuffer1.base);
|
|
}
|
|
|
|
//
|
|
// If its not an MCD managed depth buffer, free the depth
|
|
// buffer.
|
|
//
|
|
|
|
if (buffers->resizeDepth != ResizeUnownedDepthBuffer)
|
|
{
|
|
if (buffers->depthBuffer.base)
|
|
{
|
|
DBGLEVEL(LEVEL_ALLOC,
|
|
"__glGenFreeBuffers: Freeing depth buffer\n");
|
|
FREE(buffers->depthBuffer.base);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free back buffer if we allocated one
|
|
//
|
|
|
|
if (buffers->backBitmap.pvBits) {
|
|
// Note: the DIB section deletion will delete
|
|
// buffers->backBitmap.pvBits for us
|
|
|
|
if (!DeleteDC(buffers->backBitmap.hdc))
|
|
WARNING("__glGenFreeBuffers: DeleteDC failed\n");
|
|
DeleteObject(buffers->backBitmap.hbm);
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
//
|
|
// Free MCD surface.
|
|
//
|
|
|
|
if (buffers->pMcdSurf) {
|
|
GenMcdDeleteSurface(buffers->pMcdSurf);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// free up swap hint region
|
|
//
|
|
|
|
{
|
|
PYLIST pylist;
|
|
PXLIST pxlist;
|
|
|
|
RECTLISTSetEmpty(&buffers->rl);
|
|
|
|
//
|
|
// Free up the free lists
|
|
//
|
|
|
|
pylist = buffers->pylist;
|
|
while (pylist) {
|
|
PYLIST pylistKill = pylist;
|
|
pylist = pylist->pnext;
|
|
FREE(pylistKill);
|
|
}
|
|
buffers->pylist = NULL;
|
|
|
|
pxlist = buffers->pxlist;
|
|
while (pxlist) {
|
|
PXLIST pxlistKill = pxlist;
|
|
pxlist = pxlist->pnext;
|
|
FREE(pxlistKill);
|
|
}
|
|
buffers->pxlist = NULL;
|
|
}
|
|
|
|
//
|
|
// Free the private structure
|
|
//
|
|
|
|
FREE(buffers);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* __glGenAllocAndInitPrivateBufferStruct
|
|
*
|
|
* Allocates and initializes a __GLGENbuffers structure and saves it as
|
|
* the drawable private data.
|
|
*
|
|
* The __GLGENbuffers structure contains the shared ancillary and back
|
|
* buffers, as well as the cache of clip rectangles enumerated from the
|
|
* CLIPOBJ.
|
|
*
|
|
* The __GLGENbuffers structure and its data is freed by calling
|
|
* __glGenFreeBuffers.
|
|
*
|
|
* Returns:
|
|
* NULL if error.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static __GLGENbuffers *
|
|
__glGenAllocAndInitPrivateBufferStruct(__GLcontext *gc)
|
|
{
|
|
__GLGENbuffers *buffers;
|
|
__GLGENcontext *gengc = (__GLGENcontext *)gc;
|
|
PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd;
|
|
|
|
/* No private structure, no ancillary buffers */
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: No private struct existed\n");
|
|
|
|
buffers = (__GLGENbuffers *)ALLOCZ(sizeof(__GLGENbuffers));
|
|
if (NULL == buffers)
|
|
return(NULL);
|
|
|
|
buffers->resize = ResizeAncillaryBuffer;
|
|
buffers->resizeDepth = ResizeAncillaryBuffer;
|
|
|
|
buffers->accumBuffer.elementSize = gc->accumBuffer.buf.elementSize;
|
|
buffers->depthBuffer.elementSize = gc->depthBuffer.buf.elementSize;
|
|
buffers->stencilBuffer.elementSize = gc->stencilBuffer.buf.elementSize;
|
|
|
|
buffers->stencilBits = ppfd->cStencilBits;
|
|
buffers->depthBits = ppfd->cDepthBits;
|
|
buffers->accumBits = ppfd->cAccumBits;
|
|
buffers->colorBits = ppfd->cColorBits;
|
|
buffers->alphaBits = ppfd->cAlphaBits;
|
|
|
|
if (gc->modes.accumBits) {
|
|
gc->accumBuffer.buf.base = 0;
|
|
gc->accumBuffer.buf.size = 0;
|
|
gc->accumBuffer.buf.outerWidth = 0;
|
|
}
|
|
buffers->alphaFrontBuffer = buffers->alphaBackBuffer = NULL;
|
|
// These base values must *always* be set to 0, regardless of alphaBits,
|
|
// since base will be free'd if non-zero on buffer deletion
|
|
buffers->alphaBuffer0.base = 0;
|
|
buffers->alphaBuffer1.base = 0;
|
|
if (gc->modes.alphaBits) {
|
|
buffers->alphaBuffer0.size = 0;
|
|
buffers->alphaBuffer0.outerWidth = 0;
|
|
buffers->alphaFrontBuffer = &buffers->alphaBuffer0;
|
|
if (gc->modes.doubleBufferMode) {
|
|
buffers->alphaBuffer1.size = 0;
|
|
buffers->alphaBuffer1.outerWidth = 0;
|
|
buffers->alphaBackBuffer = &buffers->alphaBuffer1;
|
|
}
|
|
}
|
|
if (gc->modes.depthBits) {
|
|
gc->depthBuffer.buf.base = 0;
|
|
gc->depthBuffer.buf.size = 0;
|
|
gc->depthBuffer.buf.outerWidth = 0;
|
|
}
|
|
if (gc->modes.stencilBits) {
|
|
gc->stencilBuffer.buf.base = 0;
|
|
gc->stencilBuffer.buf.size = 0;
|
|
gc->stencilBuffer.buf.outerWidth = 0;
|
|
}
|
|
|
|
// If double-buffered, initialize the fake window for the back buffer
|
|
if (gc->modes.doubleBufferMode)
|
|
{
|
|
buffers->backBitmap.pwnd = &buffers->backBitmap.wnd;
|
|
buffers->backBitmap.wnd.clipComplexity = DC_TRIVIAL;
|
|
buffers->backBitmap.wnd.rclBounds.left = 0;
|
|
buffers->backBitmap.wnd.rclBounds.top = 0;
|
|
buffers->backBitmap.wnd.rclBounds.right = 0;
|
|
buffers->backBitmap.wnd.rclBounds.bottom = 0;
|
|
buffers->backBitmap.wnd.rclClient =
|
|
buffers->backBitmap.wnd.rclBounds;
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
if (gengc->_pMcdState &&
|
|
!(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC)) {
|
|
if (bInitMcdSurface(gengc, gengc->pwndLocked, buffers)) {
|
|
if (gengc->pMcdState->pDepthSpan) {
|
|
gc->depthBuffer.buf.base = gengc->pMcdState->pDepthSpan;
|
|
buffers->depthBuffer.base = gengc->pMcdState->pDepthSpan;
|
|
buffers->resizeDepth = ResizeUnownedDepthBuffer;
|
|
}
|
|
} else {
|
|
WARNING("__glGenAllocAndInitPrivateBufferStruct: bInitMcdSurface failed\n");
|
|
FREE(buffers);
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
|
|
if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
|
|
{
|
|
// DDraw surfaces provide their own depth buffers
|
|
buffers->resizeDepth = ResizeUnownedDepthBuffer;
|
|
}
|
|
|
|
buffers->clip.WndUniq = -1;
|
|
|
|
//
|
|
// init swap hint region
|
|
//
|
|
|
|
buffers->pxlist = NULL;
|
|
buffers->pylist = NULL;
|
|
|
|
buffers->rl.buffers = buffers;
|
|
buffers->rl.pylist = NULL;
|
|
|
|
buffers->fMax = FALSE;
|
|
|
|
return buffers;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* __glGenCheckBufferStruct
|
|
*
|
|
* Check if context and buffer struct are compatible.
|
|
*
|
|
* To satisfy this requirement, the attributes of the shared buffers
|
|
* (back, depth, stencil, and accum) must match. Otherwise, the context
|
|
* cannot be used with the given set of buffers.
|
|
*
|
|
* Returns:
|
|
* TRUE if compatible, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 17-Jul-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLboolean __glGenCheckBufferStruct(__GLcontext *gc, __GLGENbuffers *buffers)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
__GLGENcontext *gengc = (__GLGENcontext *)gc;
|
|
PIXELFORMATDESCRIPTOR *ppfd = &gengc->gsurf.pfd;
|
|
|
|
if ((buffers->stencilBits == ppfd->cStencilBits) &&
|
|
(buffers->depthBits == ppfd->cDepthBits ) &&
|
|
(buffers->accumBits == ppfd->cAccumBits ) &&
|
|
(buffers->colorBits == ppfd->cColorBits ) &&
|
|
(buffers->alphaBits == ppfd->cAlphaBits ))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
|
|
return (GLboolean)bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvMakeCurrent
|
|
*
|
|
* Make generic context current to this thread with specified DC.
|
|
*
|
|
* Returns:
|
|
* TRUE if sucessful.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// Upper level code should make sure that this context is not current to
|
|
// any other thread, that we "lose" the old context first
|
|
// Called with DEVLOCK held, free to modify window
|
|
//
|
|
// FALSE will be returned if we cannot create the objects we need
|
|
// rcobj.cxx will set the error code to show we are out of memory
|
|
|
|
BOOL APIENTRY glsrvMakeCurrent(GLWINDOWID *pgwid, __GLcontext *gc,
|
|
GLGENwindow *pwnd)
|
|
{
|
|
__GLGENcontext *gengc;
|
|
__GLGENbuffers *buffers;
|
|
GLint width, height;
|
|
BOOL bFreePwnd = FALSE;
|
|
BOOL bUninitSem = FALSE;
|
|
|
|
DBGENTRY("Generic MakeCurrent\n");
|
|
|
|
// Common initialization
|
|
gengc = (__GLGENcontext *)gc;
|
|
|
|
ASSERTOPENGL(GLTEB_SRVCONTEXT() == 0, "current context in makecurrent!");
|
|
ASSERTOPENGL(gengc->pwndMakeCur == NULL &&
|
|
gengc->pwndLocked == NULL,
|
|
"Non-current context has window pointers\n");
|
|
|
|
gengc->gwidCurrent = *pgwid;
|
|
if (pwnd == NULL)
|
|
{
|
|
ASSERTOPENGL((gengc->gsurf.dwFlags & GLSURF_METAFILE),
|
|
"Non-metafile surface without a window\n");
|
|
|
|
// Drawing on an IC, create a fake window with no visible area
|
|
pwnd = (GLGENwindow *)ALLOC(sizeof(GLGENwindow));
|
|
if (pwnd == NULL)
|
|
{
|
|
WARNING("glsrvMakeCurrent: memory allocation failure "
|
|
"(IC, window)\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
bFreePwnd = TRUE;
|
|
|
|
RtlZeroMemory(pwnd, sizeof(GLGENwindow));
|
|
pwnd->clipComplexity = DC_TRIVIAL;
|
|
|
|
// This window data is private so technically there'll never
|
|
// be another thread accessing it so this critsec is unnecessary.
|
|
// However, having it eliminates special cases where
|
|
// window locks are taken or checked for ownership.
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&pwnd->sem);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
bUninitSem = TRUE;
|
|
|
|
// Set this so CreateGDIObjects doesn't attempt to create
|
|
// zero-size objects
|
|
gengc->ColorsBits = (void *)1;
|
|
|
|
gengc->dwCurrentFlags = gengc->gsurf.dwFlags;
|
|
}
|
|
else if (pgwid->iType == GLWID_DDRAW)
|
|
{
|
|
gengc->dwCurrentFlags = gengc->gsurf.dwFlags;
|
|
}
|
|
else
|
|
{
|
|
GLSURF gsurf;
|
|
|
|
if (!InitDeviceSurface(pgwid->hdc, pwnd->ipfd, gengc->gsurf.iLayer,
|
|
wglObjectType(pgwid->hdc), FALSE, &gsurf))
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
gengc->dwCurrentFlags = gsurf.dwFlags;
|
|
}
|
|
|
|
if (gengc->dwCurrentFlags & GLSURF_DIRECTDRAW)
|
|
{
|
|
gengc->pgddsFront = &gengc->gsurf.dd.gddsFront;
|
|
}
|
|
else if (GLDIRECTSCREEN && GLSURF_IS_SCREENDC(gengc->dwCurrentFlags))
|
|
{
|
|
gengc->pgddsFront = &GLSCREENINFO->gdds;
|
|
}
|
|
else
|
|
{
|
|
gengc->pgddsFront = NULL;
|
|
}
|
|
|
|
// We need this field to tell whether we're using a fake window
|
|
// or a real one.
|
|
gengc->ipfdCurrent = pwnd->ipfd;
|
|
|
|
gengc->pwndMakeCur = pwnd;
|
|
ENTER_WINCRIT_GC(pwnd, gengc);
|
|
|
|
width = pwnd->rclClient.right - pwnd->rclClient.left;
|
|
height = pwnd->rclClient.bottom - pwnd->rclClient.top;
|
|
gengc->errorcode = 0;
|
|
|
|
// Sanity check the info from window.
|
|
ASSERTOPENGL(
|
|
width <= __GL_MAX_WINDOW_WIDTH && height <= __GL_MAX_WINDOW_HEIGHT,
|
|
"glsrvMakeCurrrent(): bad window client size\n"
|
|
);
|
|
|
|
// Make our context current in the TEB.
|
|
// If failures after this point, make sure to reset TEB entry
|
|
// Set up this thread's paTeb pointer.
|
|
gc->paTeb = GLTEB_CLTPOLYARRAY();
|
|
GLTEB_SET_SRVCONTEXT(gc);
|
|
|
|
buffers = pwnd->buffers;
|
|
|
|
/* We inherit any drawable state */
|
|
if (buffers)
|
|
{
|
|
gc->constants.width = buffers->width;
|
|
gc->constants.height = buffers->height;
|
|
|
|
if (!__glGenCheckBufferStruct(gc, buffers))
|
|
{
|
|
WARNING("glsrvMakeCurrent: __glGenCheckBufferStruct failed\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
if (GLSURF_IS_DIRECTDC(gengc->dwCurrentFlags))
|
|
{
|
|
if (!(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC) &&
|
|
!(buffers->flags & GLGENBUF_MCD_LOST))
|
|
{
|
|
gengc->pMcdState = gengc->_pMcdState;
|
|
|
|
// Reset MCD scaling values since we're now using
|
|
// MCD hardware acceleration:
|
|
|
|
GenMcdSetScaling(gengc);
|
|
|
|
if (gengc->pMcdState)
|
|
{
|
|
gengc->pMcdState->pMcdSurf = buffers->pMcdSurf;
|
|
if (buffers->pMcdSurf)
|
|
{
|
|
gengc->pMcdState->pDepthSpan = buffers->pMcdSurf->pDepthSpan;
|
|
}
|
|
else
|
|
{
|
|
WARNING("glsrvMakeCurrent: MCD context, generic surface\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Generic context. If the surface is an MCD surface, we
|
|
// cannot continue. The context is generic but the pixelfmt
|
|
// is MCD, so what must have happened is that we attempted
|
|
// to create an MCD context, but failed, so we reverted
|
|
// to generic.
|
|
|
|
if (buffers->pMcdSurf)
|
|
{
|
|
WARNING("glsrvMakeCurrent: generic context, MCD surface\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gengc->pMcdState = (GENMCDSTATE *)NULL;
|
|
|
|
// Reset MCD scaling values since we've fallen back to
|
|
// software:
|
|
|
|
GenMcdSetScaling(gengc);
|
|
|
|
// If MCD context (or former context), either surface or context
|
|
// needs conversion.
|
|
//
|
|
// The only other way to get here is if this is a generic context
|
|
// an a converted surface, which is perfectly OK and requires no
|
|
// further conversion.
|
|
|
|
//!!!SP1 -- should be able to skip this section if no conversion
|
|
//!!!SP1 needed, but we miss out on the forced repick, which
|
|
//!!!SP! could be risky for NT4.0
|
|
//if (gengc->_pMcdState &&
|
|
// (!(gengc->flags & GLGEN_MCD_CONVERTED_TO_GENERIC) ||
|
|
// !(buffers->flags & GLGENBUF_MCD_LOST)))
|
|
if (gengc->_pMcdState)
|
|
{
|
|
BOOL bConverted;
|
|
|
|
// Do conversion. We must have color scales set to do the
|
|
// conversion, but we must restore color scales afterwards.
|
|
|
|
__glContextSetColorScales(gc);
|
|
bConverted = GenMcdConvertContext(gengc, buffers);
|
|
__glContextUnsetColorScales(gc);
|
|
|
|
// Fail makecurrent if conversion failed.
|
|
|
|
if (!bConverted)
|
|
{
|
|
WARNING("glsrvMakeCurrent: GenMcdConvertContext failed\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
gengc->pMcdState = (GENMCDSTATE *)NULL;
|
|
|
|
#endif
|
|
|
|
if (buffers->accumBuffer.base && gc->modes.accumBits)
|
|
{
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Accumulation buffer existed\n");
|
|
gc->accumBuffer.buf.base = buffers->accumBuffer.base;
|
|
gc->accumBuffer.buf.size = buffers->accumBuffer.size;
|
|
gc->accumBuffer.buf.outerWidth = buffers->width;
|
|
gc->modes.haveAccumBuffer = GL_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* No Accum buffer at this point in time */
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Accum buffer doesn't exist\n");
|
|
gc->accumBuffer.buf.base = 0;
|
|
gc->accumBuffer.buf.size = 0;
|
|
gc->accumBuffer.buf.outerWidth = 0;
|
|
}
|
|
if (buffers->depthBuffer.base && gc->modes.depthBits)
|
|
{
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Depth buffer existed\n");
|
|
gc->depthBuffer.buf.base = buffers->depthBuffer.base;
|
|
gc->depthBuffer.buf.size = buffers->depthBuffer.size;
|
|
gc->depthBuffer.buf.outerWidth = buffers->width;
|
|
gc->modes.haveDepthBuffer = GL_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* No Depth buffer at this point in time */
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Depth buffer doesn't exist\n");
|
|
gc->depthBuffer.buf.base = 0;
|
|
gc->depthBuffer.buf.size = 0;
|
|
gc->depthBuffer.buf.outerWidth = 0;
|
|
}
|
|
if (buffers->stencilBuffer.base && gc->modes.stencilBits)
|
|
{
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent: Stencil buffer existed\n");
|
|
gc->stencilBuffer.buf.base = buffers->stencilBuffer.base;
|
|
gc->stencilBuffer.buf.size = buffers->stencilBuffer.size;
|
|
gc->stencilBuffer.buf.outerWidth = buffers->width;
|
|
gc->modes.haveStencilBuffer = GL_TRUE;
|
|
}
|
|
else
|
|
{
|
|
/* No Stencil buffer at this point in time */
|
|
DBGLEVEL(LEVEL_ALLOC, "glsrvMakeCurrent:Stencil buffer doesn't exist\n");
|
|
gc->stencilBuffer.buf.base = 0;
|
|
gc->stencilBuffer.buf.size = 0;
|
|
gc->stencilBuffer.buf.outerWidth = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gc->modes.haveStencilBuffer = GL_FALSE;
|
|
gc->modes.haveDepthBuffer = GL_FALSE;
|
|
gc->modes.haveAccumBuffer = GL_FALSE;
|
|
}
|
|
|
|
/*
|
|
** Allocate and initialize ancillary buffers structures if none were
|
|
** inherited. This will happen if an RC has previously been current
|
|
** and is made current to a new window.
|
|
*/
|
|
if (!buffers)
|
|
{
|
|
buffers = __glGenAllocAndInitPrivateBufferStruct(gc);
|
|
if (NULL == buffers)
|
|
{
|
|
WARNING("glsrvMakeCurrent: __glGenAllocAndInitPrivateBufferStruct failed\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
pwnd->buffers = buffers;
|
|
}
|
|
|
|
// Setup pointer to generic back buffer
|
|
if ( gc->modes.doubleBufferMode)
|
|
{
|
|
gc->backBuffer.bitmap = &buffers->backBitmap;
|
|
UpdateSharedBuffer(&gc->backBuffer.buf, &buffers->backBuffer);
|
|
}
|
|
|
|
// Setup alpha buffer pointers
|
|
|
|
if ( buffers->alphaBits )
|
|
{
|
|
UpdateSharedBuffer( &gc->frontBuffer.alphaBuf.buf,
|
|
buffers->alphaFrontBuffer );
|
|
buffers->alphaFrontBuffer->elementSize =
|
|
gc->frontBuffer.alphaBuf.buf.elementSize;
|
|
if ( gc->modes.doubleBufferMode)
|
|
{
|
|
UpdateSharedBuffer( &gc->backBuffer.alphaBuf.buf,
|
|
buffers->alphaBackBuffer );
|
|
buffers->alphaBackBuffer->elementSize =
|
|
gc->backBuffer.alphaBuf.buf.elementSize;
|
|
}
|
|
}
|
|
|
|
if (gc->gcSig != GC_SIGNATURE)
|
|
{
|
|
__GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL);
|
|
#ifdef _MCD_
|
|
MCD_STATE_DIRTY(gc, ALL);
|
|
#endif
|
|
|
|
// After initializing all of the individual buffer structures, make
|
|
// sure we copy the element size back into the shared buffer.
|
|
// This is a little clumsy,
|
|
|
|
buffers->accumBuffer.elementSize = gc->accumBuffer.buf.elementSize;
|
|
buffers->depthBuffer.elementSize = gc->depthBuffer.buf.elementSize;
|
|
buffers->stencilBuffer.elementSize = gc->stencilBuffer.buf.elementSize;
|
|
|
|
// We always need to initialize the MCD-related scaling values:
|
|
|
|
GenMcdSetScaling(gengc);
|
|
|
|
/*
|
|
** Need some stuff to exist before doing viewport stuff.
|
|
*/
|
|
(*gc->procs.validate)(gc);
|
|
|
|
/*
|
|
** The first time a context is made current the spec requires that
|
|
** the viewport be initialized. The code below does it.
|
|
** The ApplyViewport() routine will be called inside Viewport()
|
|
*/
|
|
|
|
__glim_Viewport(0, 0, width, height);
|
|
__glim_Scissor(0, 0, width, height);
|
|
|
|
/*
|
|
** Now that viewport is set, need to revalidate (initializes all
|
|
** the proc pointers).
|
|
*/
|
|
(*gc->procs.validate)(gc);
|
|
|
|
gc->gcSig = GC_SIGNATURE;
|
|
}
|
|
else /* Not the first makecurrent for this RC */
|
|
{
|
|
/* This will check the window size, and recompute relevant state */
|
|
ApplyViewport(gc);
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
|
|
if (gengc->pMcdState)
|
|
{
|
|
// Now that we are assured that the mcd state is fully initialized,
|
|
// configure the depth buffer.
|
|
|
|
GenMcdInitDepth(gc, &gc->depthBuffer);
|
|
if (gc->modes.depthBits)
|
|
{
|
|
gc->depthBuffer.scale =
|
|
gengc->pMcdState->McdRcInfo.depthBufferMax;
|
|
}
|
|
else
|
|
{
|
|
gc->depthBuffer.scale = 0x7fffffff;
|
|
}
|
|
|
|
// Bind MCD context to window.
|
|
|
|
if (!GenMcdMakeCurrent(gengc, pwnd))
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
gengc->pMcdState->mcdFlags |=
|
|
(MCD_STATE_FORCEPICK | MCD_STATE_FORCERESIZE);
|
|
|
|
__GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL);
|
|
MCD_STATE_DIRTY(gc, ALL);
|
|
}
|
|
|
|
#endif
|
|
|
|
// Common initialization
|
|
|
|
// Select correct pixel-copy function
|
|
|
|
wglInitializePixelCopyFuncs(gengc);
|
|
|
|
// Set front-buffer HDC, window to current HDC, window
|
|
gc->front->bitmap->hdc = pgwid->hdc;
|
|
ASSERT_WINCRIT(pwnd);
|
|
gc->front->bitmap->pwnd = pwnd;
|
|
|
|
// Make sure our GDI object cache is empty
|
|
// It should always be empty at MakeCurrent time since
|
|
// the objects in the cache are HDC-specific and so
|
|
// they cannot be cached between MakeCurrents since the
|
|
// HDC could change
|
|
//
|
|
// This should be done before HandlePaletteChanges since the
|
|
// cache is used there
|
|
ASSERTOPENGL(gengc->crFill == COLORREF_UNUSED &&
|
|
gengc->hbrFill == NULL &&
|
|
gengc->hdcFill == NULL,
|
|
"Fill cache inconsistent at MakeCurrent\n");
|
|
ASSERTOPENGL(gengc->cStroke.r < 0.0f &&
|
|
gengc->hpenStroke == NULL &&
|
|
gengc->hdcStroke == NULL &&
|
|
gengc->fStrokeInvalid,
|
|
"Stroke cache inconsistent at MakeCurrent\n");
|
|
|
|
// Get current xlation
|
|
gengc->PaletteTimestamp = INITIAL_TIMESTAMP;
|
|
HandlePaletteChanges(gengc, pwnd);
|
|
|
|
// Force attention code to check if resize is needed
|
|
gengc->WndUniq = -1;
|
|
gengc->WndSizeUniq = -1;
|
|
|
|
// Check for allocation failures during MakeCurrent
|
|
if (gengc->errorcode)
|
|
{
|
|
WARNING1("glsrvMakeCurrent: errorcode 0x%lx\n", gengc->errorcode);
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
/*
|
|
** Default value for rasterPos needs to be yInverted. The
|
|
** defaults are filled in during SoftResetContext
|
|
** we do the adjusting here.
|
|
*/
|
|
|
|
if (gc->constants.yInverted) {
|
|
gc->state.current.rasterPos.window.y = height +
|
|
gc->constants.fviewportYAdjust - gc->constants.viewportEpsilon;
|
|
}
|
|
|
|
/*
|
|
** Scale all state that depends upon the color scales.
|
|
*/
|
|
__glContextSetColorScales(gc);
|
|
|
|
LEAVE_WINCRIT_GC(pwnd, gengc);
|
|
|
|
return TRUE;
|
|
|
|
ERROR_EXIT:
|
|
memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent));
|
|
|
|
// Set paTeb to NULL for debugging.
|
|
gc->paTeb = NULL;
|
|
|
|
GLTEB_SET_SRVCONTEXT(0);
|
|
|
|
// Remove window pointers.
|
|
if (gengc->pwndLocked != NULL)
|
|
{
|
|
LEAVE_WINCRIT_GC(pwnd, gengc);
|
|
}
|
|
|
|
if (bFreePwnd)
|
|
{
|
|
if (bUninitSem)
|
|
{
|
|
DeleteCriticalSection(&pwnd->sem);
|
|
}
|
|
FREE(pwnd);
|
|
}
|
|
|
|
gengc->pwndMakeCur = NULL;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* AddSwapHintRectWIN()
|
|
*
|
|
* 17-Feb-1995 mikeke Created
|
|
\**************************************************************************/
|
|
|
|
void APIPRIVATE __glim_AddSwapHintRectWIN(
|
|
GLint xs,
|
|
GLint ys,
|
|
GLint xe,
|
|
GLint ye)
|
|
{
|
|
__GLGENbuffers *buffers;
|
|
|
|
__GL_SETUP();
|
|
|
|
buffers = ((__GLGENcontext *)gc)->pwndLocked->buffers;
|
|
|
|
if (xs < 0) xs = 0;
|
|
if (xe > buffers->backBuffer.width) xe = buffers->backBuffer.width;
|
|
if (ys < 0) ys = 0;
|
|
if (ye > buffers->backBuffer.height) ye = buffers->backBuffer.height;
|
|
|
|
if (xs < xe && ys < ye) {
|
|
if (gc->constants.yInverted) {
|
|
RECTLISTAddRect(&buffers->rl,
|
|
xs, buffers->backBuffer.height - ye,
|
|
xe, buffers->backBuffer.height - ys);
|
|
} else {
|
|
RECTLISTAddRect(&buffers->rl, xs, ys, xe, ye);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglFixupPixelFormat
|
|
*
|
|
* Fixes up certain MCD pixel format cases
|
|
*
|
|
* History:
|
|
* 21-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID FASTCALL wglFixupPixelFormat(__GLGENcontext *gengc,
|
|
PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
// Some MCD pixelformats specify a 233BGR (i.e., 2-bits blue in least
|
|
// significant bits, etc.) bit ordering. Unfortunately, this is the
|
|
// slow path for simulations. For those formats, we force the ordering
|
|
// to RGB internally and reorder the pajTranslateVector to convert it
|
|
// back to BGR before writing to the surface.
|
|
|
|
if (((ppfd->dwFlags & (PFD_NEED_SYSTEM_PALETTE | PFD_GENERIC_ACCELERATED))
|
|
== (PFD_NEED_SYSTEM_PALETTE | PFD_GENERIC_ACCELERATED)) &&
|
|
(ppfd->cRedBits == 3) && (ppfd->cRedShift == 5) &&
|
|
(ppfd->cGreenBits == 3) && (ppfd->cGreenShift == 2) &&
|
|
(ppfd->cBlueBits == 2) && (ppfd->cBlueShift == 0))
|
|
{
|
|
ppfd->cRedShift = 0;
|
|
ppfd->cGreenShift = 3;
|
|
ppfd->cBlueShift = 6;
|
|
|
|
gengc->flags |= GENGC_MCD_BGR_INTO_RGB;
|
|
}
|
|
else
|
|
{
|
|
gengc->flags &= ~GENGC_MCD_BGR_INTO_RGB;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvCreateContext
|
|
*
|
|
* Create a generic context.
|
|
*
|
|
* Returns:
|
|
* NULL for failure.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
// hdc is the dc used to create the context, hrc is how the server
|
|
// identifies the GL context, the GLcontext pointer that is return is how
|
|
// the generic code identifies the context. The server will pass that pointer
|
|
// in all calls.
|
|
|
|
PVOID APIENTRY glsrvCreateContext(GLWINDOWID *pgwid, GLSURF *pgsurf)
|
|
{
|
|
__GLGENcontext *gengc;
|
|
__GLcontext *gc;
|
|
|
|
RANDOMDISABLE;
|
|
|
|
DBGENTRY("__glsrvCreateContext\n");
|
|
|
|
// Initialize the temporary memory allocation table
|
|
if (!InitTempAlloc())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
gengc = ALLOCZ(sizeof(*gengc));
|
|
if (gengc == NULL)
|
|
{
|
|
WARNING("bad alloc\n");
|
|
return NULL;
|
|
}
|
|
|
|
gengc->hrc = NULL;
|
|
gc = (__GLcontext *)gengc;
|
|
|
|
// Initialize cached objects to nothing
|
|
gengc->crFill = COLORREF_UNUSED;
|
|
gengc->hbrFill = NULL;
|
|
gengc->hdcFill = NULL;
|
|
gengc->cStroke.r = -1.0f;
|
|
gengc->fStrokeInvalid = TRUE;
|
|
gengc->hpenStroke = NULL;
|
|
gengc->hdcStroke = NULL;
|
|
|
|
gc->gcSig = 0;
|
|
|
|
/*
|
|
* Add a bunch of constants to the context
|
|
*/
|
|
|
|
gc->constants.maxViewportWidth = __GL_MAX_WINDOW_WIDTH;
|
|
gc->constants.maxViewportHeight = __GL_MAX_WINDOW_HEIGHT;
|
|
|
|
gc->constants.viewportXAdjust = __GL_VERTEX_X_BIAS+
|
|
__GL_VERTEX_X_FIX;
|
|
gc->constants.viewportYAdjust = __GL_VERTEX_Y_BIAS+
|
|
__GL_VERTEX_Y_FIX;
|
|
|
|
gc->constants.subpixelBits = __GL_WGL_SUBPIXEL_BITS;
|
|
|
|
gc->constants.numberOfLights = __GL_WGL_NUMBER_OF_LIGHTS;
|
|
gc->constants.numberOfClipPlanes = __GL_WGL_NUMBER_OF_CLIP_PLANES;
|
|
gc->constants.numberOfTextures = __GL_WGL_NUMBER_OF_TEXTURES;
|
|
gc->constants.numberOfTextureEnvs = __GL_WGL_NUMBER_OF_TEXTURE_ENVS;
|
|
gc->constants.maxTextureSize = __GL_WGL_MAX_MIPMAP_LEVEL;/*XXX*/
|
|
gc->constants.maxMipMapLevel = __GL_WGL_MAX_MIPMAP_LEVEL;
|
|
gc->constants.maxListNesting = __GL_WGL_MAX_LIST_NESTING;
|
|
gc->constants.maxEvalOrder = __GL_WGL_MAX_EVAL_ORDER;
|
|
gc->constants.maxPixelMapTable = __GL_WGL_MAX_PIXEL_MAP_TABLE;
|
|
gc->constants.maxAttribStackDepth = __GL_WGL_MAX_ATTRIB_STACK_DEPTH;
|
|
gc->constants.maxClientAttribStackDepth = __GL_WGL_MAX_CLIENT_ATTRIB_STACK_DEPTH;
|
|
gc->constants.maxNameStackDepth = __GL_WGL_MAX_NAME_STACK_DEPTH;
|
|
|
|
gc->constants.pointSizeMinimum =
|
|
(__GLfloat)__GL_WGL_POINT_SIZE_MINIMUM;
|
|
gc->constants.pointSizeMaximum =
|
|
(__GLfloat)__GL_WGL_POINT_SIZE_MAXIMUM;
|
|
gc->constants.pointSizeGranularity =
|
|
(__GLfloat)__GL_WGL_POINT_SIZE_GRANULARITY;
|
|
gc->constants.lineWidthMinimum =
|
|
(__GLfloat)__GL_WGL_LINE_WIDTH_MINIMUM;
|
|
gc->constants.lineWidthMaximum =
|
|
(__GLfloat)__GL_WGL_LINE_WIDTH_MAXIMUM;
|
|
gc->constants.lineWidthGranularity =
|
|
(__GLfloat)__GL_WGL_LINE_WIDTH_GRANULARITY;
|
|
|
|
#ifndef NT
|
|
gc->dlist.optimizer = __glDlistOptimizer;
|
|
gc->dlist.checkOp = __glNopGCListOp;
|
|
gc->dlist.listExec = __gl_GenericDlOps;
|
|
gc->dlist.baseListExec = __glListExecTable;
|
|
#endif
|
|
gc->dlist.initState = __glNopGC;
|
|
|
|
__glEarlyInitContext( gc );
|
|
|
|
if (gengc->errorcode)
|
|
{
|
|
WARNING1("Context error is %d\n", gengc->errorcode);
|
|
glsrvDeleteContext(gc);
|
|
return NULL;
|
|
}
|
|
|
|
RANDOMREENABLE;
|
|
|
|
// Many routines depend on a current surface so set it temporarily
|
|
gengc->gwidCurrent = *pgwid;
|
|
gengc->dwCurrentFlags = pgsurf->dwFlags;
|
|
|
|
// Get copy of current pixelformat
|
|
if (pgsurf->iLayer == 0 &&
|
|
(pgsurf->pfd.dwFlags &
|
|
(PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED)) ==
|
|
(PFD_GENERIC_FORMAT | PFD_GENERIC_ACCELERATED))
|
|
{
|
|
wglFixupPixelFormat(gengc, &pgsurf->pfd);
|
|
}
|
|
gengc->gsurf = *pgsurf;
|
|
|
|
#ifdef _MCD_
|
|
// Is the pixelformat compatible with the generic code, or is it some
|
|
// weird h/w (MCD) format generic cannot handle?
|
|
if (GenMcdGenericCompatibleFormat(gengc))
|
|
gengc->flags |= GENGC_GENERIC_COMPATIBLE_FORMAT;
|
|
#endif
|
|
|
|
// Extract information from pixel format to set up modes
|
|
GetContextModes(gengc);
|
|
|
|
ASSERTOPENGL(GLSURF_IS_MEMDC(gengc->dwCurrentFlags) ?
|
|
!gc->modes.doubleBufferMode : 1, "Double buffered memdc!");
|
|
|
|
// XXX! Reset buffer dimensions to force Bitmap resize call
|
|
// We should eventually handle the Bitmap as we do ancilliary buffers
|
|
gc->constants.width = 0;
|
|
gc->constants.height = 0;
|
|
|
|
__GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_ALL);
|
|
#ifdef _MCD_
|
|
MCD_STATE_DIRTY(gc, ALL);
|
|
#endif
|
|
|
|
gc->constants.yInverted = GL_TRUE;
|
|
gc->constants.ySign = -1;
|
|
|
|
// Allocate GDI objects that we will need
|
|
if (!CreateGDIObjects(gengc))
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
// Allocate __GLGENbitmap front-buffer structure
|
|
|
|
if (!(gc->frontBuffer.bitmap = GCALLOCZ(gc, sizeof(__GLGENbitmap))))
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
// Create MCD rendering context, if MCD is available.
|
|
|
|
if (gengc->gsurf.dwFlags & GLSURF_VIDEO_MEMORY)
|
|
{
|
|
GLGENwindow *pwnd;
|
|
BOOL bMcdContext;
|
|
|
|
// Validate layer index
|
|
if (pgsurf->iLayer &&
|
|
!ValidateLayerIndex(pgsurf->iLayer, &pgsurf->pfd))
|
|
{
|
|
WARNING("glsrvCreateContext: bad iLayer\n");
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
pwnd = pwndGetFromID(pgwid);
|
|
if (pwnd == NULL)
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
// If this fails, _pMcdState is NULL and we fall back on
|
|
// the software-only implementation.
|
|
//
|
|
// Unless we were trying to create a layer context. Generic
|
|
// does not support layers, so fail if we cannot create an
|
|
// MCD context.
|
|
|
|
bMcdContext = bInitMcdContext(gengc, pwnd);
|
|
|
|
if (!(gengc->flags & GENGC_GENERIC_COMPATIBLE_FORMAT) && !bMcdContext)
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
pwndRelease(pwnd);
|
|
}
|
|
|
|
/*
|
|
* Initialize front/back color buffer(s)
|
|
*/
|
|
|
|
wglInitializeColorBuffers(gengc);
|
|
|
|
/*
|
|
* Initialize any other ancillary buffers
|
|
*/
|
|
|
|
// Init accum buffer.
|
|
if (gc->modes.accumBits)
|
|
{
|
|
switch (gc->modes.accumBits)
|
|
{
|
|
case 16:
|
|
// We will now internally use a 32-bit accum for accumBits=16
|
|
case 32:
|
|
__glInitAccum32(gc, &gc->accumBuffer);
|
|
break;
|
|
case 64:
|
|
default:
|
|
__glInitAccum64(gc, &gc->accumBuffer);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Initialize depth buffer.
|
|
wglInitializeDepthBuffer(gengc);
|
|
|
|
// Init stencil buffer.
|
|
if (gc->modes.stencilBits)
|
|
{
|
|
__glInitStencil8( gc, &gc->stencilBuffer);
|
|
}
|
|
|
|
// Look at REX code for procs to make CPU specific
|
|
gc->procs.bitmap = __glDrawBitmap;
|
|
gc->procs.clipPolygon = __glClipPolygon;
|
|
gc->procs.validate = __glGenericValidate;
|
|
|
|
gc->procs.pickAllProcs = __glGenericPickAllProcs;
|
|
gc->procs.pickBlendProcs = __glGenericPickBlendProcs;
|
|
gc->procs.pickFogProcs = __glGenericPickFogProcs;
|
|
gc->procs.pickParameterClipProcs = __glGenericPickParameterClipProcs;
|
|
gc->procs.pickStoreProcs = __glGenPickStoreProcs;
|
|
gc->procs.pickTextureProcs = __glGenericPickTextureProcs;
|
|
|
|
gc->procs.copyImage = __glGenericPickCopyImage;
|
|
|
|
gc->procs.pixel.spanReadCI = __glSpanReadCI;
|
|
gc->procs.pixel.spanReadCI2 = __glSpanReadCI2;
|
|
gc->procs.pixel.spanReadRGBA = __glSpanReadRGBA;
|
|
gc->procs.pixel.spanReadRGBA2 = __glSpanReadRGBA2;
|
|
gc->procs.pixel.spanReadDepth = __glSpanReadDepth;
|
|
gc->procs.pixel.spanReadDepth2 = __glSpanReadDepth2;
|
|
gc->procs.pixel.spanReadStencil = __glSpanReadStencil;
|
|
gc->procs.pixel.spanReadStencil2 = __glSpanReadStencil2;
|
|
gc->procs.pixel.spanRenderCI = __glSpanRenderCI;
|
|
gc->procs.pixel.spanRenderCI2 = __glSpanRenderCI2;
|
|
gc->procs.pixel.spanRenderRGBA = __glSpanRenderRGBA;
|
|
gc->procs.pixel.spanRenderRGBA2 = __glSpanRenderRGBA2;
|
|
gc->procs.pixel.spanRenderDepth = __glSpanRenderDepth;
|
|
gc->procs.pixel.spanRenderDepth2 = __glSpanRenderDepth2;
|
|
gc->procs.pixel.spanRenderStencil = __glSpanRenderStencil;
|
|
gc->procs.pixel.spanRenderStencil2 = __glSpanRenderStencil2;
|
|
|
|
gc->procs.applyViewport = ApplyViewport;
|
|
|
|
gc->procs.pickBufferProcs = __glGenericPickBufferProcs;
|
|
gc->procs.pickColorMaterialProcs = __glGenericPickColorMaterialProcs;
|
|
gc->procs.pickPixelProcs = __glGenericPickPixelProcs;
|
|
|
|
gc->procs.pickClipProcs = __glGenericPickClipProcs;
|
|
gc->procs.pickLineProcs = __fastGenPickLineProcs;
|
|
gc->procs.pickSpanProcs = __fastGenPickSpanProcs;
|
|
gc->procs.pickTriangleProcs = __fastGenPickTriangleProcs;
|
|
gc->procs.pickRenderBitmapProcs = __glGenericPickRenderBitmapProcs;
|
|
gc->procs.pickPointProcs = __glGenericPickPointProcs;
|
|
gc->procs.pickVertexProcs = __glGenericPickVertexProcs;
|
|
gc->procs.pickDepthProcs = __glGenericPickDepthProcs;
|
|
gc->procs.convertPolygonStipple = __glConvertStipple;
|
|
|
|
/* Now reset the context to its default state */
|
|
|
|
RANDOMDISABLE;
|
|
|
|
__glSoftResetContext(gc);
|
|
// Check for allocation failures during SoftResetContext
|
|
if (gengc->errorcode)
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
/* Create acceleration-specific context information */
|
|
|
|
if (!__glGenCreateAccelContext(gc))
|
|
{
|
|
goto ERROR_EXIT;
|
|
}
|
|
|
|
/*
|
|
** Now that we have a context, we can initialize
|
|
** all the proc pointers.
|
|
*/
|
|
(*gc->procs.validate)(gc);
|
|
|
|
/*
|
|
** NOTE: now that context is initialized reset to use the global
|
|
** table.
|
|
*/
|
|
|
|
RANDOMREENABLE;
|
|
|
|
// We won't be fully initialized until the first MakeCurrent
|
|
// so set the signature to uninitialized
|
|
gc->gcSig = 0;
|
|
|
|
memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent));
|
|
gengc->dwCurrentFlags = 0;
|
|
|
|
/*
|
|
* End stuff that may belong in the hardware context
|
|
*/
|
|
|
|
return (PVOID)gc;
|
|
|
|
ERROR_EXIT:
|
|
memset(&gengc->gwidCurrent, 0, sizeof(gengc->gwidCurrent));
|
|
gengc->dwCurrentFlags = 0;
|
|
glsrvDeleteContext(gc);
|
|
return NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UpdateSharedBuffer
|
|
*
|
|
* Make the context buffer state consistent with the shared buffer state.
|
|
* This is called separately for each of the shared buffers.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void UpdateSharedBuffer(__GLbuffer *to, __GLbuffer *from)
|
|
{
|
|
to->width = from->width;
|
|
to->height = from->height;
|
|
to->base = from->base;
|
|
to->outerWidth = from->outerWidth;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ResizeUnownedDepthBuffer
|
|
*
|
|
* Resizes a general-purpose hardware depth buffer. Just updates structure.
|
|
*
|
|
* Returns:
|
|
* TRUE always.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLboolean ResizeUnownedDepthBuffer(__GLGENbuffers *buffers,
|
|
__GLbuffer *fb, GLint w, GLint h)
|
|
{
|
|
fb->width = w;
|
|
fb->height = h;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ResizeHardwareBackBuffer
|
|
*
|
|
* Resizes a general-purpose hardware color buffer. Just updates structure.
|
|
*
|
|
* Returns:
|
|
* TRUE always.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLboolean ResizeHardwareBackBuffer(__GLGENbuffers *buffers,
|
|
__GLcolorBuffer *cfb, GLint w, GLint h)
|
|
{
|
|
__GLGENbitmap *genBm = cfb->bitmap;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) cfb->buf.gc;
|
|
|
|
// Fake up some of the __GLGENbitmap information. The window is required
|
|
// for clipping of the hardware back buffer. The hdc is required to
|
|
// retrieve drawing data from GDI.
|
|
|
|
ASSERT_WINCRIT(gengc->pwndLocked);
|
|
genBm->pwnd = gengc->pwndLocked;
|
|
genBm->hdc = gengc->gwidCurrent.hdc;
|
|
|
|
buffers->backBuffer.width = w;
|
|
buffers->backBuffer.height = h;
|
|
UpdateSharedBuffer(&cfb->buf, &buffers->backBuffer);
|
|
return TRUE;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* ResizeAncillaryBuffer
|
|
*
|
|
* Resizes the indicated shared buffer via a realloc (to preserve as much of
|
|
* the existing data as possible).
|
|
*
|
|
* This is currently used for each of ancillary shared buffers except for
|
|
* the back buffer.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE if error.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLboolean ResizeAncillaryBuffer(__GLGENbuffers *buffers, __GLbuffer *fb,
|
|
GLint w, GLint h)
|
|
{
|
|
size_t newSize = (size_t) (w * h * fb->elementSize);
|
|
__GLbuffer oldbuf, *ofb;
|
|
GLboolean result;
|
|
GLint i, imax, rowsize;
|
|
void *to, *from;
|
|
|
|
ofb = &oldbuf;
|
|
oldbuf = *fb;
|
|
|
|
if (newSize > 0)
|
|
{
|
|
fb->base = ALLOC(newSize);
|
|
}
|
|
else
|
|
{
|
|
// Buffer has no size. If we tried to allocate zero the debug alloc
|
|
// would complain, so skip directly to the underlying allocator
|
|
fb->base = HeapAlloc(GetProcessHeap(), 0, 0);
|
|
}
|
|
ASSERTOPENGL((ULONG_PTR)fb->base % 4 == 0, "base not aligned");
|
|
fb->size = newSize;
|
|
fb->width = w;
|
|
fb->height = h;
|
|
fb->outerWidth = w; // element size
|
|
if (fb->base) {
|
|
result = GL_TRUE;
|
|
if (ofb->base) {
|
|
if (ofb->width > fb->width)
|
|
rowsize = fb->width * fb->elementSize;
|
|
else
|
|
rowsize = ofb->width * fb->elementSize;
|
|
|
|
if (ofb->height > fb->height)
|
|
imax = fb->height;
|
|
else
|
|
imax = ofb->height;
|
|
|
|
from = ofb->base;
|
|
to = fb->base;
|
|
for (i = 0; i < imax; i++) {
|
|
__GL_MEMCOPY(to, from, rowsize);
|
|
(ULONG_PTR)from += (ofb->width * ofb->elementSize);
|
|
(ULONG_PTR)to += (fb->width * fb->elementSize);
|
|
}
|
|
}
|
|
} else {
|
|
result = GL_FALSE;
|
|
}
|
|
if (ofb->base)
|
|
{
|
|
FREE(ofb->base);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/******************************Private*Routine******************************\
|
|
* ResizeBitmapBuffer
|
|
*
|
|
* Used to resize the backbuffer that is implemented as a bitmap. Cannot
|
|
* use same code as ResizeAncillaryBuffer() because each scanline must be
|
|
* dword aligned. We also have to create engine objects for the bitmap.
|
|
*
|
|
* This code handles the case of a bitmap that has never been initialized.
|
|
*
|
|
* History:
|
|
* 18-Nov-1993 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void
|
|
ResizeBitmapBuffer(__GLGENbuffers *buffers, __GLcolorBuffer *cfb,
|
|
GLint w, GLint h)
|
|
{
|
|
__GLGENcontext *gengc = (__GLGENcontext *) cfb->buf.gc;
|
|
__GLcontext *gc = cfb->buf.gc;
|
|
__GLGENbitmap *genBm;
|
|
UINT cBytes; // size of the bitmap in bytes
|
|
LONG cBytesPerScan; // size of a scanline (DWORD aligned)
|
|
SIZEL size; // dimensions of the bitmap
|
|
PIXELFORMATDESCRIPTOR *pfmt = &gengc->gsurf.pfd;
|
|
GLint cBitsPerScan;
|
|
#ifndef _CLIENTSIDE_
|
|
void *newbits;
|
|
#endif
|
|
|
|
DBGENTRY("Entering ResizeBitmapBuffer\n");
|
|
|
|
genBm = cfb->bitmap;
|
|
|
|
ASSERTOPENGL(
|
|
&gc->backBuffer == cfb,
|
|
"ResizeBitmapBuffer(): not back buffer!\n"
|
|
);
|
|
|
|
ASSERTOPENGL(
|
|
genBm == &buffers->backBitmap,
|
|
"ResizeBitmapBuffer(): bad __GLGENbitmap * in cfb\n"
|
|
);
|
|
|
|
// Compute the size of the bitmap.
|
|
// The engine bitmap must have scanlines that are DWORD aligned.
|
|
|
|
cBitsPerScan = BITS_ALIGNDWORD(w * pfmt->cColorBits);
|
|
cBytesPerScan = cBitsPerScan / 8;
|
|
cBytes = h * cBytesPerScan;
|
|
|
|
// Setup size structure with dimensions of the bitmap.
|
|
|
|
size.cx = cBitsPerScan / pfmt->cColorBits;
|
|
size.cy = h;
|
|
|
|
#ifndef _CLIENTSIDE_
|
|
// Malloc new buffer
|
|
if ( (!cBytes) ||
|
|
(NULL == (newbits = GCALLOC(gc, cBytes))) )
|
|
{
|
|
gengc->errorcode = GLGEN_OUT_OF_MEMORY;
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
}
|
|
|
|
// If old buffer existed:
|
|
if ( genBm->pvBits )
|
|
{
|
|
GLint i, imax, rowsize;
|
|
void *to, *from;
|
|
|
|
// Transfer old contents to new buffer
|
|
rowsize = min(-cfb->buf.outerWidth, cBytesPerScan);
|
|
imax = min(cfb->buf.height, h);
|
|
|
|
from = genBm->pvBits;
|
|
to = newbits;
|
|
|
|
for (i = 0; i < imax; i++)
|
|
{
|
|
__GL_MEMCOPY(to, from, rowsize);
|
|
(GLint) from -= cfb->buf.outerWidth;
|
|
(GLint) to += cBytesPerScan;
|
|
}
|
|
|
|
// Free old bitmap and delete old surface
|
|
EngDeleteSurface((HSURF) genBm->hbm);
|
|
GCFREE(gc, genBm->pvBits);
|
|
}
|
|
genBm->pvBits = newbits;
|
|
|
|
// Create new surface
|
|
if ( (genBm->hbm = EngCreateBitmap(size,
|
|
cBytesPerScan,
|
|
gengc->iFormatDC,
|
|
0,
|
|
genBm->pvBits))
|
|
== (HBITMAP) 0 )
|
|
{
|
|
gengc->errorcode = GLGEN_GRE_FAILURE;
|
|
GCFREE(gc, genBm->pvBits);
|
|
genBm->pvBits = (PVOID) NULL;
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
}
|
|
|
|
#else
|
|
// Zero sized bitmap. The error case will set the dimensions to
|
|
// zero, thereby preventing drawing operations.
|
|
|
|
if ( !cBytes )
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
|
|
// Delete old back buffer.
|
|
|
|
if ( genBm->hbm )
|
|
{
|
|
if (!DeleteDC(genBm->hdc))
|
|
WARNING("ResizeBitmapBuffer: DeleteDC failed\n");
|
|
genBm->hdc = (HDC) NULL;
|
|
if (!DeleteObject(genBm->hbm))
|
|
WARNING("ResizeBitmapBuffer: DeleteBitmap failed");
|
|
genBm->hbm = (HBITMAP) NULL;
|
|
genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits
|
|
}
|
|
|
|
if ( (genBm->hdc = CreateCompatibleDC(gengc->gwidCurrent.hdc)) == (HDC) 0 )
|
|
{
|
|
gengc->errorcode = GLGEN_GRE_FAILURE;
|
|
genBm->pvBits = (PVOID) NULL;
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
}
|
|
|
|
// Create new surface
|
|
if ( (genBm->hbm = wglCreateBitmap(gengc, size, &genBm->pvBits))
|
|
== (HBITMAP) 0 )
|
|
{
|
|
gengc->errorcode = GLGEN_GRE_FAILURE;
|
|
genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits
|
|
DeleteDC(genBm->hdc);
|
|
genBm->hdc = (HDC) NULL;
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
}
|
|
|
|
if ( !SelectObject(genBm->hdc, genBm->hbm) )
|
|
{
|
|
gengc->errorcode = GLGEN_GRE_FAILURE;
|
|
DeleteDC(genBm->hdc);
|
|
genBm->hdc = (HDC) NULL;
|
|
DeleteObject(genBm->hbm);
|
|
genBm->hbm = (HBITMAP) NULL;
|
|
genBm->pvBits = (PVOID) NULL; // DIBsect deletion freed pvBits
|
|
goto ERROR_EXIT_ResizeBitmapBuffer;
|
|
}
|
|
#endif
|
|
|
|
// Update buffer data structure
|
|
// Setup the buffer to point to the DIB. A DIB is "upside down"
|
|
// from our perspective, so we will set buf.base to point to the
|
|
// last scan of the buffer and set buf.outerWidth to be negative
|
|
// (causing us to move "up" through the DIB with increasing y).
|
|
|
|
buffers->backBuffer.outerWidth = -(cBytesPerScan);
|
|
buffers->backBuffer.base =
|
|
(PVOID) (((BYTE *)genBm->pvBits) + (cBytesPerScan * (h - 1)));
|
|
|
|
|
|
buffers->backBuffer.xOrigin = 0;
|
|
buffers->backBuffer.yOrigin = 0;
|
|
buffers->backBuffer.width = w;
|
|
buffers->backBuffer.height = h;
|
|
buffers->backBuffer.size = cBytes;
|
|
|
|
UpdateSharedBuffer(&cfb->buf, &buffers->backBuffer);
|
|
|
|
// Update the dummy window for the back buffer
|
|
ASSERTOPENGL(genBm->wnd.clipComplexity == DC_TRIVIAL,
|
|
"Back buffer complexity non-trivial\n");
|
|
genBm->wnd.rclBounds.right = w;
|
|
genBm->wnd.rclBounds.bottom = h;
|
|
genBm->wnd.rclClient = genBm->wnd.rclBounds;
|
|
|
|
return;
|
|
|
|
ERROR_EXIT_ResizeBitmapBuffer:
|
|
|
|
// If we get to here, memory allocation or bitmap creation failed.
|
|
|
|
#if DBG
|
|
switch (gengc->errorcode)
|
|
{
|
|
case 0:
|
|
break;
|
|
|
|
case GLGEN_GRE_FAILURE:
|
|
WARNING("ResizeBitmapBuffer(): object creation failed\n");
|
|
break;
|
|
|
|
case GLGEN_OUT_OF_MEMORY:
|
|
if ( w && h )
|
|
WARNING("ResizeBitmapBuffer(): mem alloc failed\n");
|
|
break;
|
|
|
|
default:
|
|
WARNING1("ResizeBitmapBuffer(): errorcode = 0x%lx\n", gengc->errorcode);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
// If we've blown away the bitmap, we need to set the back buffer info
|
|
// to a consistent state.
|
|
|
|
if (!genBm->pvBits)
|
|
{
|
|
buffers->backBuffer.width = 0;
|
|
buffers->backBuffer.height = 0;
|
|
buffers->backBuffer.base = (PVOID) NULL;
|
|
}
|
|
|
|
cfb->buf.width = 0; // error state: empty buffer
|
|
cfb->buf.height = 0;
|
|
cfb->buf.outerWidth = 0;
|
|
|
|
}
|
|
|
|
/* Lazy allocation of ancillary buffers */
|
|
void FASTCALL LazyAllocateDepth(__GLcontext *gc)
|
|
{
|
|
GLint w = gc->constants.width;
|
|
GLint h = gc->constants.height;
|
|
__GLGENcontext *gengc = (__GLGENcontext *)gc;
|
|
__GLGENbuffers *buffers;
|
|
GLint depthIndex = gc->state.depth.testFunc;
|
|
|
|
ASSERTOPENGL(gc->modes.depthBits, "LazyAllocateDepth: zero depthBits\n");
|
|
|
|
buffers = gengc->pwndLocked->buffers;
|
|
buffers->createdDepthBuffer = GL_TRUE;
|
|
|
|
// If we're using the DDI, we've already allocated depth buffers
|
|
// on the device, so at this point we may simply assume that
|
|
// our depth buffer is available.
|
|
|
|
#ifdef _MCD_
|
|
// If we're using MCD, we allocated the depth buffer when we created
|
|
// the MCD context.
|
|
|
|
if ((gengc->pMcdState) && (gengc->pMcdState->pDepthSpan))
|
|
{
|
|
gc->modes.haveDepthBuffer = GL_TRUE;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
// Depth buffer should never be touched because
|
|
// no output should be generated
|
|
if (gengc->dwCurrentFlags & GLSURF_METAFILE)
|
|
{
|
|
gc->modes.haveDepthBuffer = GL_TRUE;
|
|
return;
|
|
}
|
|
|
|
if (buffers->depthBuffer.base) {
|
|
/* buffer already allocated by another RC */
|
|
UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer);
|
|
} else {
|
|
|
|
DBGLEVEL(LEVEL_ALLOC, "Depth buffer must be allocated\n");
|
|
(*buffers->resize)(buffers, &buffers->depthBuffer, w, h);
|
|
UpdateSharedBuffer(&gc->depthBuffer.buf, &buffers->depthBuffer);
|
|
}
|
|
|
|
if (gc->depthBuffer.buf.base) {
|
|
gc->modes.haveDepthBuffer = GL_TRUE;
|
|
} else {
|
|
gc->modes.haveDepthBuffer = GL_FALSE;
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
__GL_DELAY_VALIDATE_MASK(gc, __GL_DIRTY_DEPTH);
|
|
|
|
// Note similar code in so_pick.c
|
|
// Don't need to handle (depthBits == 0) case because LazyAllocateDepth
|
|
// is not called unless depthBits is non-zero.
|
|
depthIndex -= GL_NEVER;
|
|
if( gc->state.depth.writeEnable == GL_FALSE ) {
|
|
depthIndex += 8;
|
|
}
|
|
if( gc->depthBuffer.buf.elementSize == 2 )
|
|
depthIndex += 16;
|
|
(*gc->depthBuffer.pick)(gc, &gc->depthBuffer, depthIndex);
|
|
}
|
|
|
|
void FASTCALL LazyAllocateStencil(__GLcontext *gc)
|
|
{
|
|
GLint w = gc->constants.width;
|
|
GLint h = gc->constants.height;
|
|
__GLGENbuffers *buffers;
|
|
__GLGENcontext *gengc = (__GLGENcontext *)gc;
|
|
|
|
ASSERTOPENGL(gc->modes.stencilBits, "LazyAllocateStencil: zero stencilBits\n");
|
|
|
|
buffers = gengc->pwndLocked->buffers;
|
|
buffers->createdStencilBuffer = GL_TRUE;
|
|
|
|
// Depth buffer should never be touched because
|
|
// no output should be generated
|
|
if (gengc->dwCurrentFlags & GLSURF_METAFILE)
|
|
{
|
|
gc->modes.haveStencilBuffer = GL_TRUE;
|
|
return;
|
|
}
|
|
|
|
if (buffers->stencilBuffer.base) {
|
|
/* buffer already allocated by another RC */
|
|
UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer);
|
|
} else {
|
|
|
|
DBGLEVEL(LEVEL_ALLOC, "stencil buffer must be allocated\n");
|
|
(*buffers->resize)(buffers, &buffers->stencilBuffer, w, h);
|
|
UpdateSharedBuffer(&gc->stencilBuffer.buf, &buffers->stencilBuffer);
|
|
}
|
|
|
|
if (gc->stencilBuffer.buf.base) {
|
|
gc->modes.haveStencilBuffer = GL_TRUE;
|
|
} else {
|
|
gc->modes.haveStencilBuffer = GL_FALSE;
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
__GL_DELAY_VALIDATE(gc);
|
|
gc->validateMask |= (__GL_VALIDATE_STENCIL_FUNC | __GL_VALIDATE_STENCIL_OP);
|
|
(*gc->stencilBuffer.pick)(gc, &gc->stencilBuffer);
|
|
}
|
|
|
|
|
|
void FASTCALL LazyAllocateAccum(__GLcontext *gc)
|
|
{
|
|
GLint w = gc->constants.width;
|
|
GLint h = gc->constants.height;
|
|
__GLGENbuffers *buffers;
|
|
__GLGENcontext *gengc = (__GLGENcontext *)gc;
|
|
|
|
ASSERTOPENGL(gc->modes.accumBits, "LazyAllocateAccum: zero accumBits\n");
|
|
|
|
buffers = gengc->pwndLocked->buffers;
|
|
buffers->createdAccumBuffer = GL_TRUE;
|
|
|
|
// Depth buffer should never be touched because
|
|
// no output should be generated
|
|
if (gengc->dwCurrentFlags & GLSURF_METAFILE)
|
|
{
|
|
gc->modes.haveAccumBuffer = GL_TRUE;
|
|
return;
|
|
}
|
|
|
|
if (buffers->accumBuffer.base) {
|
|
/* buffer already allocated by another RC */
|
|
UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer);
|
|
} else {
|
|
|
|
DBGLEVEL(LEVEL_ALLOC, "Accum buffer must be allocated\n");
|
|
(*buffers->resize)(buffers, &buffers->accumBuffer, w, h);
|
|
UpdateSharedBuffer(&gc->accumBuffer.buf, &buffers->accumBuffer);
|
|
}
|
|
|
|
if (gc->accumBuffer.buf.base) {
|
|
gc->modes.haveAccumBuffer = GL_TRUE;
|
|
} else {
|
|
gc->modes.haveAccumBuffer = GL_FALSE;
|
|
__glSetError(GL_OUT_OF_MEMORY);
|
|
}
|
|
__GL_DELAY_VALIDATE(gc);
|
|
(*gc->accumBuffer.pick)(gc, &gc->accumBuffer);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glGenInitCommon
|
|
*
|
|
* Called from __glGenInitRGB and __glGenInitCI to handle the shared
|
|
* initialization chores.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void FASTCALL glGenInitCommon(__GLGENcontext *gengc, __GLcolorBuffer *cfb, GLenum type)
|
|
{
|
|
__GLbuffer *bp;
|
|
|
|
bp = &cfb->buf;
|
|
|
|
// If front buffer, we need to setup the buffer if we think its DIB format.
|
|
|
|
if (type == GL_FRONT)
|
|
{
|
|
#ifdef _MCD_
|
|
if (gengc->_pMcdState)
|
|
{
|
|
// Assume that MCD surface is not accessible. Accessibility
|
|
// must be determined on a per-batch basis by calling
|
|
// GenMcdUpdateBufferInfo.
|
|
|
|
bp->flags &= ~(DIB_FORMAT | MEMORY_DC | NO_CLIP);
|
|
}
|
|
#endif
|
|
{
|
|
if (gengc->dwCurrentFlags & GLSURF_DIRECT_ACCESS)
|
|
{
|
|
// These fields will be updated at attention time
|
|
bp->base = NULL;
|
|
bp->outerWidth = 0;
|
|
cfb->buf.flags = DIB_FORMAT;
|
|
}
|
|
|
|
if (GLSURF_IS_MEMDC(gengc->dwCurrentFlags))
|
|
{
|
|
bp->flags = bp->flags | (MEMORY_DC | NO_CLIP);
|
|
}
|
|
else if (gengc->gsurf.dwFlags & GLSURF_DIRECTDRAW)
|
|
{
|
|
LPDIRECTDRAWCLIPPER pddc;
|
|
HRESULT hr;
|
|
|
|
hr = gengc->gsurf.dd.gddsFront.pdds->lpVtbl->
|
|
GetClipper(gengc->gsurf.dd.gddsFront.pdds, &pddc);
|
|
if (hr == DDERR_NOCLIPPERATTACHED)
|
|
{
|
|
bp->flags = bp->flags | NO_CLIP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If back buffer, we assume its a DIB, or a hardware backbuffer.
|
|
// In the case of a DIB, the bitmap memory will be allocated via
|
|
// ResizeBitmapBuffer().
|
|
|
|
else
|
|
{
|
|
#ifdef _MCD_
|
|
if (gengc->_pMcdState)
|
|
{
|
|
// Assume that MCD surface is not accessible. Accessibility
|
|
// must be determined on a per-batch basis by calling
|
|
// GenMcdUpdateBufferInfo.
|
|
|
|
cfb->resize = ResizeHardwareBackBuffer;
|
|
bp->flags &= ~(DIB_FORMAT | MEMORY_DC | NO_CLIP);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
cfb->resize = ResizeBitmapBuffer;
|
|
bp->flags = DIB_FORMAT | MEMORY_DC | NO_CLIP;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* glsrvCleanupWindow
|
|
*
|
|
* Called from wglCleanupWindow to remove the pwnd reference from the
|
|
* context.
|
|
*
|
|
* History:
|
|
* 05-Jul-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY glsrvCleanupWindow(__GLcontext *gc, GLGENwindow *pwnd)
|
|
{
|
|
__GLGENcontext *gengc = (__GLGENcontext *) gc;
|
|
|
|
// The window in gengc should be consistent with the one in the rc object.
|
|
// wglCleanupWindow should have already checked to see if the pwnd in the
|
|
// rc is one we need to remove, so we can just assert here.
|
|
|
|
ASSERTOPENGL(gengc->pwndMakeCur == pwnd,
|
|
"glsrvCleanupWindow(): bad pwnd\n");
|
|
|
|
gengc->pwndLocked = NULL;
|
|
gengc->pwndMakeCur = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
** Fetch the data for a query in its internal type, then convert it to the
|
|
** type that the user asked for.
|
|
**
|
|
** This only handles the NT generic driver specific values (so far just the
|
|
** GL_ACCUM_*_BITS values). All others fall back to the soft code function,
|
|
** __glDoGet().
|
|
*/
|
|
|
|
// These types are stolen from ..\soft\so_get.c. To minimize changes to
|
|
// the soft code, we will pull them into here rather than moving them to
|
|
// a header file and changing so_get.c to use the header file.
|
|
|
|
#define __GL_FLOAT 0 /* __GLfloat */
|
|
#define __GL_FLOAT32 1 /* api 32 bit float */
|
|
#define __GL_FLOAT64 2 /* api 64 bit float */
|
|
#define __GL_INT32 3 /* api 32 bit int */
|
|
#define __GL_BOOLEAN 4 /* api 8 bit boolean */
|
|
#define __GL_COLOR 5 /* unscaled color in __GLfloat */
|
|
#define __GL_SCOLOR 6 /* scaled color in __GLfloat */
|
|
|
|
extern void __glDoGet(GLenum, void *, GLint, const char *);
|
|
extern void __glConvertResult(__GLcontext *, GLint, const void *, GLint,
|
|
void *, GLint);
|
|
|
|
void FASTCALL __glGenDoGet(GLenum sq, void *result, GLint type, const char *procName)
|
|
{
|
|
GLint iVal;
|
|
__GLGENcontext *gengc;
|
|
__GL_SETUP_NOT_IN_BEGIN();
|
|
|
|
gengc = (__GLGENcontext *) gc;
|
|
|
|
switch (sq) {
|
|
case GL_ACCUM_RED_BITS:
|
|
iVal = gengc->gsurf.pfd.cAccumRedBits;
|
|
break;
|
|
case GL_ACCUM_GREEN_BITS:
|
|
iVal = gengc->gsurf.pfd.cAccumGreenBits;
|
|
break;
|
|
case GL_ACCUM_BLUE_BITS:
|
|
iVal = gengc->gsurf.pfd.cAccumBlueBits;
|
|
break;
|
|
case GL_ACCUM_ALPHA_BITS:
|
|
iVal = gengc->gsurf.pfd.cAccumAlphaBits;
|
|
break;
|
|
default:
|
|
__glDoGet(sq, result, type, procName);
|
|
return;
|
|
}
|
|
|
|
__glConvertResult(gc, __GL_INT32, &iVal, type, result, 1);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* glsrvCopyContext
|
|
*
|
|
* Copies state from one context to another
|
|
*
|
|
* History:
|
|
* Mon Jun 05 16:53:42 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY glsrvCopyContext(__GLcontext *gcSource, __GLcontext *gcDest,
|
|
GLuint mask)
|
|
{
|
|
return (BOOL)__glCopyContext(gcDest, gcSource, mask);
|
|
}
|