mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2532 lines
78 KiB
2532 lines
78 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: wglsup.c *
|
|
* *
|
|
* WGL support routines. *
|
|
* *
|
|
* Created: 15-Dec-1994 *
|
|
* Author: Gilman Wong [gilmanw] *
|
|
* *
|
|
* Copyright (c) 1994 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#include "devlock.h"
|
|
|
|
#define DONTUSE(x) ( (x) = (x) )
|
|
|
|
//!!!XXX -- Patrick says is necessary, but so far we seem OK. I think
|
|
// it is really the apps responsibility.
|
|
//!!!dbug
|
|
#if 1
|
|
#define REALIZEPALETTE(hdc) RealizePalette((hdc))
|
|
#else
|
|
#define REALIZEPALETTE(hdc)
|
|
#endif
|
|
|
|
//!!!XXX -- BitBlt's involving DIB sections are batched.
|
|
// A GdiFlush is required, but perhaps can be taken out when
|
|
// GDI goes to kernel-mode. Can probably take out for Win95.
|
|
//#ifdef _OPENGL_NT_
|
|
#if 1
|
|
#define GDIFLUSH GdiFlush()
|
|
#else
|
|
#define GDIFLUSH
|
|
#endif
|
|
|
|
// BUGBUG - Remove this dead code
|
|
// #define FASTDIB 1
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetDIBInfo
|
|
*
|
|
* Returns front buffer base pointer and stride. For client-side, this
|
|
* means that DCI must be used.
|
|
*
|
|
* WARNING: While the base and stride of the DCI primary surface normally
|
|
* should not change, the DCI 1.0 spec specifically states that any value
|
|
* in the DCISURFACEINFO can change outside of the BeginAccess/EndAccess
|
|
* locale.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglGetDIBInfo(HDC hdc, PVOID *base, ULONG *pcwidth)
|
|
{
|
|
if ( GLDCIENABLED )
|
|
{
|
|
// Note: for DCI front buffer access, these values are set for each
|
|
// DCIBeginAccess as they can change at any time.
|
|
|
|
*base = (PVOID) GLDCIINFO->pDCISurfInfo->dwOffSurface;
|
|
*pcwidth = (ULONG) GLDCIINFO->pDCISurfInfo->lStride;
|
|
}
|
|
else
|
|
{
|
|
DIBSECTION ds;
|
|
|
|
// If the bitmap selected into the memdc is a DIBSECTION, we can
|
|
// directly access the bitmap memory.
|
|
//
|
|
// Otherwise we should treat the bitmap as a device surface and
|
|
// access the bitmap indirectly via a scanline DIBsection buffer.
|
|
|
|
if ( GetObject(GetCurrentObject(hdc, OBJ_BITMAP), sizeof(ds), &ds) ==
|
|
sizeof(ds) && ds.dsBm.bmBits )
|
|
{
|
|
// For backwards compatibility with Get/SetBitmapBits, GDI does
|
|
// not accurately report the bitmap pitch in bmWidthBytes. It
|
|
// always computes bmWidthBytes assuming WORD-aligned scanlines
|
|
// regardless of the platform.
|
|
//
|
|
// Therefore, if the platform is WinNT, which uses DWORD-aligned
|
|
// scanlines, adjust the bmWidthBytes value.
|
|
|
|
if ( dwPlatformId == VER_PLATFORM_WIN32_NT )
|
|
{
|
|
ds.dsBm.bmWidthBytes = (ds.dsBm.bmWidthBytes + 3) & ~3;
|
|
}
|
|
|
|
// If biHeight is positive, then the bitmap is a bottom-up DIB.
|
|
// If biHeight is negative, then the bitmap is a top-down DIB.
|
|
|
|
ASSERTOPENGL(ds.dsBmih.biHeight != 0,
|
|
"wglGetDIBInfo: zero-height DIB\n");
|
|
|
|
if ( ds.dsBmih.biHeight > 0 )
|
|
{
|
|
*base = (PVOID) (((int) ds.dsBm.bmBits) + (ds.dsBm.bmWidthBytes * (ds.dsBm.bmHeight - 1)));
|
|
*pcwidth = (ULONG) (-ds.dsBm.bmWidthBytes);
|
|
}
|
|
else
|
|
{
|
|
*base = ds.dsBm.bmBits;
|
|
*pcwidth = ds.dsBm.bmWidthBytes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RIP("wglGetDIBInfo: cannot get pointer to DIBSECTION bmBits\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglFillPixelFormat
|
|
*
|
|
* wglDescribePixelFormat doesn't describe the format of the surface we want
|
|
* to render into. Some fields need to be fixed up if the surface is RGB,
|
|
* BGR, or BITFIELDS.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglFillPixelFormat(HDC hdc, PIXELFORMATDESCRIPTOR *ppfd, int ipfd)
|
|
{
|
|
DWORD dwObjectType;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
wglDescribePixelFormat(hdc, ipfd, sizeof(PIXELFORMATDESCRIPTOR),ppfd);
|
|
|
|
dwObjectType = wglObjectType(hdc);
|
|
if ( dwObjectType != OBJ_DC && dwObjectType != OBJ_ENHMETADC )
|
|
{
|
|
HBITMAP hbm;
|
|
BITMAP bm;
|
|
ULONG cBitmapColorBits;
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, 1, 1);
|
|
if ( hbm )
|
|
{
|
|
if ( GetObject(hbm, sizeof(bm), &bm) )
|
|
{
|
|
cBitmapColorBits = bm.bmPlanes * bm.bmBitsPixel;
|
|
|
|
#if DBG
|
|
// If dynamic color depth caused depth mismatch one of two
|
|
// things will happen: 1) bitmap creation will fail because
|
|
// we failed to fill in color format, or 2) drawing will
|
|
// be incorrect. We will not crash.
|
|
|
|
if (cBitmapColorBits != ppfd->cColorBits)
|
|
WARNING("pixel format/surface color depth mismatch\n");
|
|
#endif
|
|
|
|
if ( cBitmapColorBits >= 16 )
|
|
__wglGetBitfieldColorFormat(hdc, cBitmapColorBits, ppfd, TRUE);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglFillPixelFormat: GetObject failed\n");
|
|
}
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglFillPixelFormat: Unable to create cbm\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglPixelVisible
|
|
*
|
|
* Determines if the pixel (x, y) is visible in the window associated with
|
|
* the given DC. The determination is made by checking the coordinate
|
|
* against the visible region data cached in the GLGENwindow structure for
|
|
* this winodw.
|
|
*
|
|
* Returns:
|
|
* TRUE if pixel (x, y) is visible, FALSE if clipped out.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY wglPixelVisible(HDC hdc, LONG x, LONG y)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
GLGENwindow *pwnd = (GLGENwindow *) gengc->pwo;
|
|
|
|
#ifdef _NT_DEADCODE_BOGUS_ASSERT_
|
|
ASSERTOPENGL(
|
|
hdc == gengc->CurrentDC,
|
|
"wglPixelVisible(): hdc is not the current hdc\n"
|
|
);
|
|
#endif
|
|
|
|
DONTUSE(hdc); // silence warning in free builds
|
|
|
|
// If DCI is not active we shouldn't call this function since
|
|
// there's no need to do any visibility clipping ourselves
|
|
ASSERTOPENGL(GLDCIENABLED, "wglPixelVisible called without DCI\n");
|
|
|
|
// Quick test against bounds.
|
|
|
|
if (
|
|
pwnd->prgndat && pwnd->pscandat &&
|
|
x >= pwnd->prgndat->rdh.rcBound.left &&
|
|
x < pwnd->prgndat->rdh.rcBound.right &&
|
|
y >= pwnd->prgndat->rdh.rcBound.top &&
|
|
y < pwnd->prgndat->rdh.rcBound.bottom
|
|
)
|
|
{
|
|
ULONG cScans = pwnd->pscandat->cScans;
|
|
GLGENscan *pscan = pwnd->pscandat->aScans;
|
|
|
|
// Find right scan.
|
|
|
|
for ( ; cScans; cScans--, pscan = pscan->pNext )
|
|
{
|
|
// Check if point is above scan.
|
|
|
|
if ( pscan->top > y )
|
|
{
|
|
// Since scans are ordered top-down, we can conclude that
|
|
// point is also above subsequent scans. Therefore intersection
|
|
// must be NULL and we can terminate search.
|
|
|
|
break;
|
|
}
|
|
|
|
// Check if point is within scan.
|
|
|
|
else if ( pscan->bottom > y )
|
|
{
|
|
LONG *plWalls = pscan->alWalls;
|
|
LONG *plWallsEnd = plWalls + pscan->cWalls;
|
|
|
|
// Check x against each pair of walls.
|
|
|
|
for ( ; plWalls < plWallsEnd; plWalls+=2 )
|
|
{
|
|
// Each pair of walls (inclusive-exclusive) defines
|
|
// a non-NULL interval in the span that is visible.
|
|
|
|
ASSERTOPENGL(
|
|
plWalls[0] < plWalls[1],
|
|
"wglPixelVisible(): bad walls in span\n"
|
|
);
|
|
|
|
// Check if x is within current interval.
|
|
|
|
if ( x >= plWalls[0] && x < plWalls[1] )
|
|
{
|
|
bRet = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Point is below current scan. Try next scan.
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglSpanVisible
|
|
*
|
|
* Determines the visibility of the span [(x, y), (x+w, y)) (test is
|
|
* inclusive-exclusive) in the current window. The span is either
|
|
* completely visible, partially visible (clipped), or completely
|
|
* clipped out (WGL_SPAN_ALL, WGL_SPAN_PARTIAL, and WGL_SPAN_NONE,
|
|
* respectively).
|
|
*
|
|
* WGL_SPAN_ALL
|
|
* ------------
|
|
* The entire span is visible. *pcWalls and *ppWalls are not set.
|
|
*
|
|
* WGL_SPAN_NONE
|
|
* -------------
|
|
* The span is completely obscured (clipped out). *pcWalls and *ppWalls
|
|
* are not set.
|
|
*
|
|
* WGL_SPAN_PARTIAL
|
|
* ----------------
|
|
* If the span is WGL_SPAN_PARTIAL, the function also returns a pointer
|
|
* to the wall array (starting with the first wall actually intersected
|
|
* by the span) and a count of the walls at this pointer.
|
|
*
|
|
* If the wall count is even, then the span starts outside the visible
|
|
* region and the first wall is where the span enters a visible portion.
|
|
*
|
|
* If the wall count is odd, then the span starts inside the visible
|
|
* region and the first wall is where the span exits a visible portion.
|
|
*
|
|
* The span may or may not cross all the walls in the array, but definitely
|
|
* does cross the first wall.
|
|
*
|
|
* Return:
|
|
* Returns WGL_SPAN_ALL, WGL_SPAN_NONE, or WGL_SPAN_PARTIAL. In
|
|
* addition, if return is WGL_SPAN_PARTIAL, pcWalls and ppWalls will
|
|
* be set (see above).
|
|
*
|
|
* History:
|
|
* 06-Dec-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG APIENTRY
|
|
wglSpanVisible(LONG x, LONG y, ULONG w, LONG *pcWalls, LONG **ppWalls)
|
|
{
|
|
ULONG ulRet = WGL_SPAN_NONE;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
GLGENwindow *pwnd = (GLGENwindow *) gengc->pwo;
|
|
LONG xRight = x + w; // Right edge of span (exclusive)
|
|
|
|
// If DCI is not active we shouldn't call this function since
|
|
// there's no need to do any visibility clipping ourselves
|
|
ASSERTOPENGL(GLDCIENABLED, "wglSpanVisible called without DCI\n");
|
|
|
|
// Quick test against bounds.
|
|
|
|
if (
|
|
pwnd->prgndat && pwnd->pscandat &&
|
|
(x < pwnd->prgndat->rdh.rcBound.right ) &&
|
|
(xRight > pwnd->prgndat->rdh.rcBound.left ) &&
|
|
(y >= pwnd->prgndat->rdh.rcBound.top ) &&
|
|
(y < pwnd->prgndat->rdh.rcBound.bottom)
|
|
)
|
|
{
|
|
ULONG cScans = pwnd->pscandat->cScans;
|
|
GLGENscan *pscan = pwnd->pscandat->aScans;
|
|
|
|
// Find right scan.
|
|
|
|
for ( ; cScans; cScans--, pscan = pscan->pNext )
|
|
{
|
|
// Check if span is above scan.
|
|
|
|
if ( pscan->top > y ) // Scans have gone past span
|
|
{
|
|
// Since scans are ordered top-down, we can conclude that
|
|
// span will aslo be above subsequent scans. Therefore
|
|
// intersection must be NULL and we can terminate search.
|
|
|
|
goto wglSpanVisible_exit;
|
|
}
|
|
|
|
// Span is below top of scan. If span is also above bottom,
|
|
// span vertically intersects this scan and only this scan.
|
|
|
|
else if ( pscan->bottom > y )
|
|
{
|
|
LONG *plWalls = pscan->alWalls;
|
|
ULONG cWalls = pscan->cWalls;
|
|
|
|
ASSERTOPENGL(
|
|
(cWalls & 0x1) == 0,
|
|
"wglSpanVisible(): wall count must be even!\n"
|
|
);
|
|
|
|
// Check span against each pair of walls. Walls are walked
|
|
// from left to right.
|
|
//
|
|
// Possible intersections where "[" is inclusive
|
|
// and ")" is exclusive:
|
|
// left wall right wall
|
|
// [ )
|
|
// case 1a [-----) [ )
|
|
// 1b [-----) )
|
|
// [ )
|
|
// case 2a [-----) ) return
|
|
// 2b [-------------------) left wall
|
|
// [ )
|
|
// case 3a [-----) )
|
|
// 3b [ [-----) )
|
|
// 3c [ [-----)
|
|
// 3d [----------------)
|
|
// [ )
|
|
// case 4a [ [-----) return
|
|
// 4b [-------------------) right wall
|
|
// [ )
|
|
// case 5a [ [-----)
|
|
// 5b [ ) [-----)
|
|
// [ )
|
|
// case 6 [----------------------) return
|
|
// [ ) left wall
|
|
|
|
for ( ; cWalls; cWalls-=2, plWalls+=2 )
|
|
{
|
|
// Each pair of walls (inclusive-exclusive) defines
|
|
// a non-NULL interval in the span that is visible.
|
|
|
|
ASSERTOPENGL(
|
|
plWalls[0] < plWalls[1],
|
|
"wglSpanVisible(): bad walls in span\n"
|
|
);
|
|
|
|
// Checking right end against left wall will partition the
|
|
// set into case 1 vs. case 2 thru 6.
|
|
|
|
if ( plWalls[0] >= xRight )
|
|
{
|
|
// Case 1 -- span outside interval on the left.
|
|
//
|
|
// The walls are ordered from left to right (i.e., low
|
|
// to high). So if span is left of this interval, it
|
|
// must also be left of all subsequent intervals and
|
|
// we can terminate the search.
|
|
|
|
goto wglSpanVisible_exit;
|
|
}
|
|
|
|
// Cases 2 thru 6.
|
|
//
|
|
// Checking left end against right wall will partition subset
|
|
// into case 5 vs. cases 2, 3, 4, 6.
|
|
|
|
else if ( plWalls[1] > x )
|
|
{
|
|
// Cases 2, 3, 4, and 6.
|
|
//
|
|
// Checking left end against left wall will partition
|
|
// subset into cases 2, 6 vs. cases 3, 4.
|
|
|
|
if ( plWalls[0] <= x )
|
|
{
|
|
// Cases 3 and 4.
|
|
//
|
|
// Checking right end against right wall will
|
|
// distinguish between the two cases.
|
|
|
|
if ( plWalls[1] >= xRight )
|
|
{
|
|
// Case 3 -- completely visible.
|
|
|
|
ulRet = WGL_SPAN_ALL;
|
|
}
|
|
else
|
|
{
|
|
// Case 4 -- partially visible, straddling the
|
|
// right wall.
|
|
|
|
ulRet = WGL_SPAN_PARTIAL;
|
|
|
|
*ppWalls = &plWalls[1];
|
|
*pcWalls = cWalls - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Cases 2 and 6 -- in either case its a partial
|
|
// intersection where the first intersection is with
|
|
// the left wall.
|
|
|
|
ulRet = WGL_SPAN_PARTIAL;
|
|
|
|
*ppWalls = &plWalls[0];
|
|
*pcWalls = cWalls;
|
|
}
|
|
|
|
goto wglSpanVisible_exit;
|
|
}
|
|
|
|
// Case 5 -- span outside interval to the right. Try
|
|
// next pair of walls.
|
|
}
|
|
|
|
// A span can intersect only one scan. We don't need to check
|
|
// any other scans.
|
|
|
|
goto wglSpanVisible_exit;
|
|
}
|
|
|
|
// Span is below current scan. Try next scan.
|
|
}
|
|
}
|
|
|
|
wglSpanVisible_exit:
|
|
|
|
return ulRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetGdiInfo
|
|
*
|
|
* Return information on the surface associated with the given DC.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY
|
|
wglGetGdiInfo(HDC hdc, PIXELFORMATDESCRIPTOR *ppfd, ULONG *piDCType,
|
|
ULONG *piSurfType, ULONG *piDitherFormat)
|
|
{
|
|
DWORD dwObjectType;
|
|
int cSurfBits = 0;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
dwObjectType = wglObjectType(hdc);
|
|
|
|
// What is the color depth of the DC surface? For a direct DC, query the
|
|
// device caps. For a memory DC, grab it from the bitmap info.
|
|
// For the direct DC case, surface may be either a device dependent
|
|
// surface (which we will access indirectly via a DIB section) or
|
|
// it uses a DIB format (which we will access via DCI).
|
|
|
|
if ( dwObjectType == OBJ_DC )
|
|
{
|
|
cSurfBits = GetDeviceCaps(hdc, BITSPIXEL) *
|
|
GetDeviceCaps(hdc, PLANES);
|
|
|
|
#if DBG
|
|
if (cSurfBits != ppfd->cColorBits)
|
|
{
|
|
WARNING("wglGetGdiInfo: pixelformat does not match display depth\n");
|
|
}
|
|
#endif
|
|
|
|
*piDCType = DCTYPE_DIRECT;
|
|
|
|
if ( GLDCIENABLED )
|
|
*piSurfType = STYPE_BITMAP;
|
|
else
|
|
*piSurfType = STYPE_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
HBITMAP hbm;
|
|
BITMAP bm;
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, 1, 1);
|
|
if ( hbm )
|
|
{
|
|
if ( GetObject(hbm, sizeof(bm), &bm) )
|
|
{
|
|
cSurfBits = bm.bmPlanes * bm.bmBitsPixel;
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglGetGdiInfo: GetObject failed\n");
|
|
}
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglGetGdiInfo: Unable to create cbm\n");
|
|
}
|
|
|
|
if (dwObjectType == OBJ_ENHMETADC)
|
|
{
|
|
*piDCType = DCTYPE_INFO;
|
|
*piSurfType = STYPE_DEVICE;
|
|
|
|
// If we're printing to a monochrome printer it will return
|
|
// 1bpp which will break things later. Since we're going
|
|
// to be doing halftoning and such to fake color, just say
|
|
// that this is a true color device to get things rolling
|
|
#ifdef GL_METAFILE
|
|
if (cSurfBits == 1 && GlGdiIsMetaPrintDC(hdc))
|
|
{
|
|
cSurfBits = 24;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
DIBSECTION ds;
|
|
|
|
ASSERTOPENGL(dwObjectType == OBJ_MEMDC,
|
|
"wglGetGdiInfo: Unknown object type\n");
|
|
|
|
*piDCType = DCTYPE_MEMORY;
|
|
|
|
#if DBG
|
|
if (cSurfBits != ppfd->cColorBits)
|
|
{
|
|
WARNING("wglGetGdiInfo: pixelformat does not match memdc depth\n");
|
|
}
|
|
#endif
|
|
|
|
// If the bitmap selected into the memdc is a DIBSECTION, we can
|
|
// directly access the bitmap memory.
|
|
//
|
|
// Otherwise we should treat the bitmap as a device surface and
|
|
// access the bitmap indirectly via a scanline DIBsection buffer.
|
|
|
|
if (GetObject(GetCurrentObject(hdc, OBJ_BITMAP), sizeof(ds), &ds) ==
|
|
sizeof(ds) && ds.dsBm.bmBits)
|
|
{
|
|
*piSurfType = STYPE_BITMAP;
|
|
}
|
|
else
|
|
{
|
|
*piSurfType = STYPE_DEVICE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Convert color depth to WinNT DDI bitmap format.
|
|
|
|
if (ppfd->cColorBits <= 1)
|
|
*piDitherFormat = BMF_1BPP;
|
|
else if (ppfd->cColorBits <= 4)
|
|
*piDitherFormat = BMF_4BPP;
|
|
else if (ppfd->cColorBits <= 8)
|
|
*piDitherFormat = BMF_8BPP;
|
|
else if (ppfd->cColorBits <= 16)
|
|
*piDitherFormat = BMF_16BPP;
|
|
else if (ppfd->cColorBits <= 24)
|
|
*piDitherFormat = BMF_24BPP;
|
|
else
|
|
*piDitherFormat = BMF_32BPP;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bComputeLogicalToSurfaceMap
|
|
*
|
|
* Copy logical palette to surface palette translation vector to the buffer
|
|
* pointed to by pajVector. The logical palette is specified by hpal. The
|
|
* surface is specified by hdc.
|
|
*
|
|
* Note: The hdc may identify either a direct (display) dc or a DIB memory dc.
|
|
* If hdc is a display dc, then the surface palette is the system palette.
|
|
* If hdc is a memory dc, then the surface palette is the DIB color table.
|
|
*
|
|
* History:
|
|
* 27-Jan-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL bComputeLogicalToSurfaceMap(HPALETTE hpal, HDC hdc, BYTE *pajVector)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
HPALETTE hpalSurf;
|
|
ULONG cEntries, cSysEntries;
|
|
DWORD dwDcType = wglObjectType(hdc);
|
|
LPPALETTEENTRY lppeTmp, lppeEnd;
|
|
|
|
BYTE aj[sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 512) + (sizeof(RGBQUAD) * 256)];
|
|
LOGPALETTE *ppal = (LOGPALETTE *) aj;
|
|
LPPALETTEENTRY lppeSurf = &ppal->palPalEntry[0];
|
|
LPPALETTEENTRY lppe = lppeSurf + 256;
|
|
RGBQUAD *prgb = (RGBQUAD *) (lppe + 256);
|
|
|
|
// Determine number of colors in each palette.
|
|
|
|
cEntries = GetPaletteEntries(hpal, 0, 1, NULL);
|
|
if (dwDcType == OBJ_DC)
|
|
cSysEntries = wglGetSystemPaletteEntries(hdc, 0, 1, NULL);
|
|
else
|
|
cSysEntries = 256;
|
|
|
|
// Dynamic color depth changing can cause this.
|
|
|
|
if ((cSysEntries > 256) || (cEntries > 256))
|
|
{
|
|
WARNING("wglCopyTranslationVector(): palette on > 8BPP device\n");
|
|
|
|
// Drawing will have corrupted colors, but at least we should not crash.
|
|
|
|
cSysEntries = min(cSysEntries, 256);
|
|
cEntries = min(cEntries, 256);
|
|
}
|
|
|
|
// Get the logical palette entries.
|
|
|
|
cEntries = GetPaletteEntries(hpal, 0, cEntries, lppe);
|
|
|
|
// Get the surface palette entries.
|
|
|
|
if (dwDcType == OBJ_DC)
|
|
{
|
|
cSysEntries = wglGetSystemPaletteEntries(hdc, 0, cSysEntries, lppeSurf);
|
|
|
|
lppeTmp = lppeSurf;
|
|
lppeEnd = lppeSurf + cSysEntries;
|
|
|
|
for (; lppeTmp < lppeEnd; lppeTmp++)
|
|
lppeTmp->peFlags = 0;
|
|
}
|
|
else
|
|
{
|
|
RGBQUAD *prgbTmp;
|
|
|
|
// First get RGBQUADs from DIB color table...
|
|
|
|
cSysEntries = GetDIBColorTable(hdc, 0, cSysEntries, prgb);
|
|
|
|
// ...then convert RGBQUADs into PALETTEENTRIES.
|
|
|
|
prgbTmp = prgb;
|
|
lppeTmp = lppeSurf;
|
|
lppeEnd = lppeSurf + cSysEntries;
|
|
|
|
while (lppeTmp < lppeEnd)
|
|
{
|
|
lppeTmp->peRed = prgbTmp->rgbRed;
|
|
lppeTmp->peGreen = prgbTmp->rgbGreen;
|
|
lppeTmp->peBlue = prgbTmp->rgbBlue;
|
|
lppeTmp->peFlags = 0;
|
|
|
|
lppeTmp++;
|
|
prgbTmp++;
|
|
|
|
}
|
|
}
|
|
|
|
// Construct a translation vector by using GetNearestPaletteIndex to
|
|
// map each entry in the logical palette to the surface palette.
|
|
|
|
if (cEntries && cSysEntries)
|
|
{
|
|
// Create a temporary logical palette that matches the surface
|
|
// palette retrieved above.
|
|
|
|
ppal->palVersion = 0x300;
|
|
ppal->palNumEntries = (USHORT) cSysEntries;
|
|
|
|
if ( hpalSurf = CreatePalette(ppal) )
|
|
{
|
|
// Translate each logical palette entry into a surface palette index.
|
|
|
|
lppeTmp = lppe;
|
|
lppeEnd = lppe + cEntries;
|
|
|
|
for ( ; lppeTmp < lppeEnd; lppeTmp++, pajVector++)
|
|
{
|
|
*pajVector = (BYTE) GetNearestPaletteIndex(
|
|
hpalSurf,
|
|
RGB(lppeTmp->peRed,
|
|
lppeTmp->peGreen,
|
|
lppeTmp->peBlue)
|
|
);
|
|
|
|
ASSERTOPENGL(
|
|
*pajVector != CLR_INVALID,
|
|
"bComputeLogicalToSurfaceMap: GetNearestPaletteIndex failed\n"
|
|
);
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
DeleteObject(hpalSurf);
|
|
}
|
|
else
|
|
{
|
|
WARNING("bComputeLogicalToSurfaceMap: CreatePalette failed\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("bComputeLogicalToSurfaceMap: failed to get pal info\n");
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCopyTranslateVector
|
|
*
|
|
* Create a logical palette index to system palette index translation
|
|
* vector.
|
|
*
|
|
* This is done by first reading both the logical palette and system palette
|
|
* entries. A temporary palette is created from the read system palette
|
|
* entries. This will be passed to GetNearestPaletteIndex to translate
|
|
* each logical palette entry into the desired system palette entry.
|
|
*
|
|
* Note: when GetNearestColor was called instead, very unstable results
|
|
* were obtained. GetNearestPaletteIndex is definitely the right way to go.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 25-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Ported from gdi\gre\wglsup.cxx.
|
|
\**************************************************************************/
|
|
|
|
static GLubyte vubRGBtoVGA[8] = {
|
|
0x0,
|
|
0x9,
|
|
0xa,
|
|
0xb,
|
|
0xc,
|
|
0xd,
|
|
0xe,
|
|
0xf
|
|
};
|
|
|
|
BOOL APIENTRY wglCopyTranslateVector(HDC hdc, BYTE *pajVector, ULONG cEntries)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
ULONG i;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
if ( GetObjectType(hdc) == OBJ_MEMDC )
|
|
{
|
|
HBITMAP hbm, hbmSave;
|
|
DIBSECTION ds;
|
|
|
|
// !!!XXXBUGBUG - Technically this assert is invalid
|
|
// because we can't be sure that cEntries will be one
|
|
// of these two cases. To fix this we'd have to add
|
|
// another parameter to this function indicating the
|
|
// bit depth desired and go by that.
|
|
ASSERTOPENGL(cEntries == 16 || cEntries == 256,
|
|
"wglCopyTranslateVector: Unknown cEntries\n");
|
|
|
|
if (GetObject(GetCurrentObject(hdc, OBJ_BITMAP), sizeof(ds), &ds) ==
|
|
sizeof(ds) && ds.dsBm.bmBits)
|
|
{
|
|
// For compatibility, do not do this if the stock palette is
|
|
// selected. The old behavior assumed that the logical palette
|
|
// can be ignored because the bitmap will have a color table
|
|
// that exactly corresponds to the format specified by the
|
|
// pixelformat. Thus, if no palette is selected into the memdc,
|
|
// OpenGL would still render properly since it assumed 1-to-1.
|
|
//
|
|
// However, to enable using optimized DIB sections (i.e., DIBs
|
|
// whose color tables match the system palette exactly), we need
|
|
// to be able to specify the logical palette in the memdc.
|
|
//
|
|
// Therefore the hack is to assume 1-to-1 iff the stock
|
|
// palette is selected into the memdc. Otherwise, we will
|
|
// compute the logical to surface mapping.
|
|
|
|
if ( gengc->gc.modes.rgbMode &&
|
|
(GetCurrentObject(hdc, OBJ_PAL) != GetStockObject(DEFAULT_PALETTE)) )
|
|
{
|
|
// If an RGB DIB section, compute a mapping from logical
|
|
// palette to surface (DIB color table).
|
|
|
|
bRet = bComputeLogicalToSurfaceMap(
|
|
GetCurrentObject(hdc, OBJ_PAL),
|
|
hdc,
|
|
pajVector
|
|
);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// 4bpp has a fixed color table so we can just copy the standard
|
|
// translation into the output vector.
|
|
|
|
if (cEntries == 16)
|
|
{
|
|
// For RGB mode, 4bpp uses a 1-1-1 format. We want to utilize
|
|
// bright versions which exist in the upper 8 entries.
|
|
|
|
if ( gengc->gc.modes.rgbMode )
|
|
{
|
|
memcpy(pajVector, vubRGBtoVGA, 8);
|
|
|
|
// Set the other mappings to white to make problems show up
|
|
memset(pajVector+8, 15, 8);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
// For CI mode, just return FALSE and use the trivial vector.
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// For bitmaps, we can determine the forward translation vector by
|
|
// filling a compatible bitmap with palette index specifiers from
|
|
// 1 to 255 and reading the bits back with GetBitmapBits.
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, cEntries, 1);
|
|
if (hbm)
|
|
{
|
|
LONG cBytes;
|
|
|
|
hbmSave = SelectObject(hdc, hbm);
|
|
RealizePalette(hdc);
|
|
|
|
for (i = 0; i < cEntries; i++)
|
|
SetPixel(hdc, i, 0, PALETTEINDEX(i));
|
|
|
|
cBytes = 256;
|
|
|
|
if ( GetBitmapBits(hbm, cBytes, (LPVOID) pajVector) >= cBytes )
|
|
bRet = TRUE;
|
|
#if DBG
|
|
else
|
|
WARNING("wglCopyTranslateVector: GetBitmapBits failed\n");
|
|
#endif
|
|
|
|
SelectObject(hdc, hbmSave);
|
|
DeleteObject(hbm);
|
|
RealizePalette(hdc);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// Determine number of colors in logical and system palettes, respectively.
|
|
|
|
cEntries = min(GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL),
|
|
0, cEntries, NULL),
|
|
cEntries);
|
|
|
|
if (cEntries == 16)
|
|
{
|
|
// For 16-color displays we are using RGB 1-1-1 since the
|
|
// full 16-color palette doesn't make for very good mappings
|
|
// Since we're only using the first eight of the colors we
|
|
// want to map them to the bright colors in the VGA palette
|
|
// rather than having them map to the dark colors as they would
|
|
// if we ran the loop below
|
|
|
|
if ( gengc->gc.modes.rgbMode )
|
|
{
|
|
memcpy(pajVector, vubRGBtoVGA, 8);
|
|
|
|
// Set the other mappings to white to make problems show up
|
|
memset(pajVector+8, 15, 8);
|
|
|
|
bRet = TRUE;
|
|
}
|
|
|
|
// For CI mode, return FALSE and use the trivial translation vector.
|
|
|
|
return bRet;
|
|
}
|
|
|
|
// Compute logical to surface palette mapping.
|
|
|
|
bRet = bComputeLogicalToSurfaceMap(GetCurrentObject(hdc, OBJ_PAL), hdc,
|
|
pajVector);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCopyBits
|
|
*
|
|
* Calls DrvCopyBits to copy scanline bits into or out of the driver surface.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglCopyBits(
|
|
PVOID _gengc,
|
|
WNDOBJ *_pwo, // ignore
|
|
HBITMAP hbm, // ignore
|
|
LONG x, // screen coordinate of scan
|
|
LONG y,
|
|
ULONG cx, // width of scan
|
|
BOOL bIn) // if TRUE, copy from bm to dev; otherwise, dev to bm
|
|
{
|
|
__GLGENcontext *gengc = (__GLGENcontext *) _gengc;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
// Convert screen coordinates to window coordinates.
|
|
|
|
x -= _pwo->rclClient.left;
|
|
y -= _pwo->rclClient.top;
|
|
|
|
// this shouldn't happen, but better safe than sorry
|
|
|
|
if (y < 0)
|
|
return;
|
|
|
|
//!!!XXX
|
|
REALIZEPALETTE(gengc->CurrentDC);
|
|
|
|
// Copy from bitmap to device.
|
|
|
|
if (bIn)
|
|
{
|
|
LONG xSrc, x0Dst, x1Dst;
|
|
if (x < 0)
|
|
{
|
|
xSrc = -x;
|
|
x0Dst = 0;
|
|
x1Dst = x + (LONG)cx;
|
|
}
|
|
else
|
|
{
|
|
xSrc = 0;
|
|
x0Dst = x;
|
|
x1Dst = x + (LONG)cx;
|
|
}
|
|
if (x1Dst <= x0Dst)
|
|
return;
|
|
|
|
BitBlt(gengc->CurrentDC, x0Dst, y, cx, 1,
|
|
gengc->ColorsMemDC, xSrc, 0, SRCCOPY);
|
|
}
|
|
|
|
// Copy from device to bitmap.
|
|
|
|
else
|
|
{
|
|
LONG xSrc, x0Dst, x1Dst;
|
|
|
|
if (x < 0)
|
|
{
|
|
xSrc = 0;
|
|
x0Dst = -x;
|
|
x1Dst = (LONG)cx;
|
|
}
|
|
else
|
|
{
|
|
xSrc = x;
|
|
x0Dst = 0;
|
|
x1Dst = (LONG)cx;
|
|
}
|
|
if (x1Dst <= x0Dst)
|
|
return;
|
|
|
|
if (dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
|
gengc->iDCType != DCTYPE_DIRECT)
|
|
{
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
gengc->CurrentDC, xSrc, y, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
/* If we're copying from the screen,
|
|
copy through a DDB to avoid some layers of unnecessary
|
|
code in Win95 that deals with translating between
|
|
different bitmap layouts */
|
|
if (gengc->ColorsDdbDc)
|
|
{
|
|
BitBlt(gengc->ColorsDdbDc, 0, 0, cx, 1,
|
|
gengc->CurrentDC, xSrc, y, SRCCOPY);
|
|
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
gengc->ColorsDdbDc, 0, 0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
//!!!Viper fix -- Diamond Viper (Weitek 9000) fails
|
|
//!!! CreateCompatibleBitmap for some
|
|
//!!! (currently unknown) reason. Thus,
|
|
//!!! the DDB does not exist and we will
|
|
//!!! have to incur the perf. hit.
|
|
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
gengc->CurrentDC, xSrc, y, SRCCOPY);
|
|
}
|
|
}
|
|
}
|
|
|
|
GDIFLUSH;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCopyBits2
|
|
*
|
|
* Calls DrvCopyBits to copy scanline bits into or out of the driver surface.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglCopyBits2(
|
|
HDC hdc, // dst/src device
|
|
WNDOBJ *_pwo, // clipping
|
|
PVOID _gengc,
|
|
LONG x, // screen coordinate of scan
|
|
LONG y,
|
|
ULONG cx, // width of scan
|
|
BOOL bIn) // if TRUE, copy from bm to dev; otherwise, dev to bm
|
|
{
|
|
__GLGENcontext *gengc = (__GLGENcontext *) _gengc;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
// Convert screen coordinates to window coordinates.
|
|
|
|
x -= _pwo->rclClient.left;
|
|
y -= _pwo->rclClient.top;
|
|
|
|
// this shouldn't happen, but better safe than sorry
|
|
|
|
if (y < 0)
|
|
return;
|
|
|
|
//!!!XXX
|
|
REALIZEPALETTE(hdc);
|
|
|
|
// Copy from bitmap to device.
|
|
|
|
if (bIn)
|
|
{
|
|
LONG xSrc, x0Dst, x1Dst;
|
|
if (x < 0)
|
|
{
|
|
xSrc = -x;
|
|
x0Dst = 0;
|
|
x1Dst = x + (LONG)cx;
|
|
}
|
|
else
|
|
{
|
|
xSrc = 0;
|
|
x0Dst = x;
|
|
x1Dst = x + (LONG)cx;
|
|
}
|
|
if (x1Dst <= x0Dst)
|
|
return;
|
|
|
|
BitBlt(hdc, x0Dst, y, cx, 1,
|
|
gengc->ColorsMemDC, xSrc, 0, SRCCOPY);
|
|
}
|
|
|
|
// Copy from device to bitmap.
|
|
|
|
else
|
|
{
|
|
LONG xSrc, x0Dst, x1Dst;
|
|
|
|
if (x < 0)
|
|
{
|
|
xSrc = 0;
|
|
x0Dst = -x;
|
|
x1Dst = (LONG)cx;
|
|
}
|
|
else
|
|
{
|
|
xSrc = x;
|
|
x0Dst = 0;
|
|
x1Dst = (LONG)cx;
|
|
}
|
|
if (x1Dst <= x0Dst)
|
|
return;
|
|
|
|
if (dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
|
gengc->iDCType != DCTYPE_DIRECT)
|
|
{
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
hdc, xSrc, y, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
/* If we're copying from the screen,
|
|
copy through a DDB to avoid some layers of unnecessary
|
|
code in Win95 that deals with translating between
|
|
different bitmap layouts */
|
|
if (gengc->ColorsDdbDc)
|
|
{
|
|
BitBlt(gengc->ColorsDdbDc, 0, 0, cx, 1,
|
|
hdc, xSrc, y, SRCCOPY);
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
gengc->ColorsDdbDc, 0, 0, SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
//!!!Viper fix -- Diamond Viper (Weitek 9000) fails
|
|
//!!! CreateCompatibleBitmap for some
|
|
//!!! (currently unknown) reason. Thus,
|
|
//!!! the DDB does not exist and we will
|
|
//!!! have to incur the perf. hit.
|
|
|
|
BitBlt(gengc->ColorsMemDC, x0Dst, 0, cx, 1,
|
|
hdc, xSrc, y, SRCCOPY);
|
|
}
|
|
}
|
|
}
|
|
|
|
GDIFLUSH;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* wglTranslateColor
|
|
*
|
|
* Transforms a GL logical color into a Windows COLORREF
|
|
*
|
|
* Note: This is relatively expensive so it should be avoided if possible
|
|
*
|
|
* History:
|
|
* Tue Aug 15 15:23:29 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
COLORREF wglTranslateColor(COLORREF crColor,
|
|
HDC hdc,
|
|
__GLGENcontext *gengc,
|
|
PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
//!!!XXX
|
|
REALIZEPALETTE(hdc);
|
|
|
|
// If palette managed, then crColor is actually a palette index.
|
|
|
|
if ( ppfd->cColorBits <= 8 )
|
|
{
|
|
PALETTEENTRY peTmp;
|
|
|
|
ASSERTOPENGL(
|
|
crColor < (COLORREF) (1 << ppfd->cColorBits),
|
|
"TranslateColor(): bad color\n"
|
|
);
|
|
|
|
// If rendering to a bitmap, we need to do different things depending
|
|
// on whether it's a DIB or DDB
|
|
|
|
if ( (GLuint) gengc->gc.drawBuffer->buf.other & MEMORY_DC )
|
|
{
|
|
DIBSECTION ds;
|
|
|
|
// Check whether we're drawing to a DIB or a DDB
|
|
if (GetObject(GetCurrentObject(hdc, OBJ_BITMAP),
|
|
sizeof(ds), &ds) == sizeof(ds) && ds.dsBm.bmBits)
|
|
{
|
|
RGBQUAD rgbq;
|
|
|
|
// Drawing to a DIB so retrieve the color from the
|
|
// DIB color table
|
|
if (GetDIBColorTable(hdc, crColor, 1, &rgbq))
|
|
{
|
|
crColor = RGB(rgbq.rgbRed, rgbq.rgbGreen,
|
|
rgbq.rgbBlue);
|
|
}
|
|
else
|
|
{
|
|
WARNING("TranslateColor(): GetDIBColorTable failed\n");
|
|
crColor = RGB(0, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reverse the forward translation so that we get back
|
|
// to a normal palette index
|
|
crColor = gengc->pajInvTranslateVector[crColor];
|
|
|
|
// Drawing to a DDB so we can just use the palette
|
|
// index directly since going through the inverse
|
|
// translation table has given us an index into
|
|
// the logical palette
|
|
crColor = PALETTEINDEX((WORD) crColor);
|
|
}
|
|
}
|
|
|
|
// Otherwise...
|
|
|
|
else
|
|
{
|
|
// I hate to have to confess this, but I don't really understand
|
|
// why this needs to be this way. Either way should work regardless
|
|
// of the bit depth.
|
|
//
|
|
// The reality is that 4bpp we *have* to go into the system palette
|
|
// and fetch an RGB value. At 8bpp on the MGA driver (and possibly
|
|
// others), we *have* to specify PALETTEINDEX.
|
|
|
|
if ( ppfd->cColorBits == 4 )
|
|
{
|
|
if ( wglGetSystemPaletteEntries(hdc, crColor, 1, &peTmp) )
|
|
{
|
|
crColor = RGB(peTmp.peRed, peTmp.peGreen, peTmp.peBlue);
|
|
}
|
|
else
|
|
{
|
|
WARNING("TranslateColor(): wglGetSystemPaletteEntries failed\n");
|
|
crColor = RGB(0, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(gengc->flags & GENGC_MCD_BGR_INTO_RGB))
|
|
crColor = gengc->pajInvTranslateVector[crColor];
|
|
crColor = PALETTEINDEX((WORD) crColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If 24BPP DIB section, BGR ordering is implied.
|
|
|
|
else if ( ppfd->cColorBits == 24 )
|
|
{
|
|
crColor = RGB((crColor & 0xff0000) >> 16,
|
|
(crColor & 0x00ff00) >> 8,
|
|
(crColor & 0x0000ff));
|
|
}
|
|
|
|
// Win95 and 16 BPP case.
|
|
//
|
|
// On Win95, additional munging is necessary to get a COLORREF value
|
|
// that will result in a non-dithered brush.
|
|
|
|
else if ( (dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
|
|
(ppfd->cColorBits == 16) )
|
|
{
|
|
HBITMAP hbmTmp;
|
|
HDC hdcTmp;
|
|
|
|
if (hdcTmp = CreateCompatibleDC(hdc))
|
|
{
|
|
if (hbmTmp = CreateCompatibleBitmap(hdc, 1, 1))
|
|
{
|
|
HBITMAP hbmOld;
|
|
|
|
hbmOld = SelectObject(hdcTmp, hbmTmp);
|
|
|
|
if (SetBitmapBits(hbmTmp, 2, (VOID *) &crColor))
|
|
{
|
|
crColor = GetPixel(hdcTmp, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
WARNING("TranslateColor(): SetBitmapBits failed\n");
|
|
}
|
|
|
|
SelectObject(hdcTmp, hbmOld);
|
|
DeleteObject(hbmTmp);
|
|
}
|
|
else
|
|
{
|
|
WARNING("TranslateColor(): CreateCompatibleBitmap failed\n");
|
|
}
|
|
|
|
DeleteDC(hdcTmp);
|
|
}
|
|
else
|
|
{
|
|
WARNING("TranslateColor(): CreateCompatibleDC failed\n");
|
|
}
|
|
}
|
|
|
|
// Bitfield format (16BPP or 32BPP).
|
|
|
|
else
|
|
{
|
|
// Shift right to position bits at zero and then scale into
|
|
// an 8-bit quantity
|
|
|
|
//!!!XXX -- use rounding?!?
|
|
crColor =
|
|
RGB(((crColor & gengc->gc.modes.redMask) >> ppfd->cRedShift) *
|
|
255 / ((1 << ppfd->cRedBits) - 1),
|
|
((crColor & gengc->gc.modes.greenMask) >> ppfd->cGreenShift) *
|
|
255 / ((1 << ppfd->cGreenBits) - 1),
|
|
((crColor & gengc->gc.modes.blueMask) >> ppfd->cBlueShift) *
|
|
255 / ((1 << ppfd->cBlueBits) - 1));
|
|
|
|
}
|
|
|
|
return crColor;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglFillRect
|
|
*
|
|
* Calls DrvBitBlt to fill a rectangle area of a driver surface with a
|
|
* given color.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglFillRect(
|
|
PVOID _gengc,
|
|
WNDOBJ *_pwo,
|
|
PRECTL prcl, // screen coordinate of the rectangle area
|
|
COLORREF crColor) // color to set
|
|
{
|
|
HBRUSH hbr;
|
|
__GLGENcontext *gengc = (__GLGENcontext *) _gengc;
|
|
PIXELFORMATDESCRIPTOR *ppfd = &gengc->CurrentFormat;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
// If the rectangle is empty, return.
|
|
|
|
if ( (prcl->left >= prcl->right) || (prcl->top >= prcl->bottom) )
|
|
{
|
|
WARNING("wglFillRect(): bad or empty rectangle\n");
|
|
return;
|
|
}
|
|
|
|
// Convert from screen to window coordinates.
|
|
|
|
prcl->left -= _pwo->rclClient.left;
|
|
prcl->right -= _pwo->rclClient.left;
|
|
prcl->top -= _pwo->rclClient.top;
|
|
prcl->bottom -= _pwo->rclClient.top;
|
|
|
|
// Make a solid color brush and fill the rectangle.
|
|
|
|
// If the fill color is the same as the last one, we can reuse
|
|
// the cached brush rather than creating a new one
|
|
if (crColor == gengc->crFill &&
|
|
gengc->CurrentDC == gengc->hdcFill)
|
|
{
|
|
hbr = gengc->hbrFill;
|
|
ASSERTOPENGL(hbr != NULL, "Cached fill brush is null\n");
|
|
}
|
|
else
|
|
{
|
|
if (gengc->hbrFill != NULL)
|
|
{
|
|
DeleteObject(gengc->hbrFill);
|
|
}
|
|
|
|
gengc->crFill = crColor;
|
|
|
|
crColor = wglTranslateColor(crColor, gengc->CurrentDC, gengc, ppfd);
|
|
hbr = CreateSolidBrush(crColor);
|
|
gengc->hbrFill = hbr;
|
|
|
|
if (hbr == NULL)
|
|
{
|
|
gengc->crFill = COLORREF_UNUSED;
|
|
return;
|
|
}
|
|
|
|
gengc->hdcFill = gengc->CurrentDC;
|
|
}
|
|
|
|
FillRect(gengc->CurrentDC, (RECT *) prcl, hbr);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCopyBuf
|
|
*
|
|
* Calls DrvCopyBits to copy a bitmap into the driver surface.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
//!!!XXX -- change to a macro
|
|
|
|
VOID APIENTRY wglCopyBuf(
|
|
HDC hdc, // dst/src DCOBJ
|
|
HDC hdcBmp, // scr/dst bitmap
|
|
LONG x, // dst rect (UL corner) in window coord.
|
|
LONG y,
|
|
ULONG cx, // width of dest rect
|
|
ULONG cy // height of dest rect
|
|
)
|
|
{
|
|
CHECKDCILOCKOUT();
|
|
|
|
//!!!XXX
|
|
REALIZEPALETTE(hdc);
|
|
|
|
BitBlt(hdc, x, y, cx, cy, hdcBmp, 0, 0, SRCCOPY);
|
|
|
|
GDIFLUSH;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCopyBufRECTLIST
|
|
*
|
|
* Calls DrvCopyBits to copy a bitmap into the driver surface.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglCopyBufRECTLIST(
|
|
HDC hdc, // dst/src DCOBJ
|
|
HDC hdcBmp, // scr/dst bitmap
|
|
LONG x, // dst rect (UL corner) in window coord.
|
|
LONG y,
|
|
ULONG cx, // width of dest rect
|
|
ULONG cy, // height of dest rect
|
|
PRECTLIST prl
|
|
)
|
|
{
|
|
PYLIST pylist;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
//!!!XXX
|
|
REALIZEPALETTE(hdc);
|
|
|
|
for (pylist = prl->pylist; pylist != NULL; pylist = pylist->pnext) {
|
|
PXLIST pxlist;
|
|
for (pxlist = pylist->pxlist; pxlist != NULL; pxlist = pxlist->pnext) {
|
|
int xx = pxlist->s;
|
|
int cxx = pxlist->e - pxlist->s;
|
|
int yy = pylist->s;
|
|
int cyy = pylist->e - pylist->s;
|
|
|
|
BitBlt(hdc, xx, yy, cxx, cyy, hdcBmp, xx, yy, SRCCOPY);
|
|
}
|
|
}
|
|
|
|
GDIFLUSH;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglPaletteChanged
|
|
*
|
|
* Check if the palette changed.
|
|
*
|
|
* If the surface for the DC is palette managed we care about the
|
|
* foreground realization, so, return iUniq
|
|
*
|
|
* If the surface is not palette managed, return ulTime
|
|
*
|
|
\**************************************************************************/
|
|
|
|
ULONG APIENTRY wglPaletteChanged(HDC hdc, __GLGENcontext *gengc,
|
|
GLGENwindow *pwnd)
|
|
{
|
|
ULONG ulRet = 0;
|
|
|
|
// Technically we shouldn't be making these GDI calls while we
|
|
// have the DCI lock but currently it would be very difficult
|
|
// to fix because we're actually invoking this routine in
|
|
// glsrvGrabLock in order to ensure that we have stable information
|
|
// while we have the lock
|
|
// We don't seem to be having too many problems so for the moment
|
|
// this will be commented out
|
|
// CHECKDCILOCKOUT();
|
|
|
|
if (pwnd)
|
|
{
|
|
if ( gengc )
|
|
{
|
|
PIXELFORMATDESCRIPTOR *ppfd = &gengc->CurrentFormat;
|
|
BYTE cBitsThreshold;
|
|
BOOL bDibColorTable;
|
|
|
|
// WM_PALETTECHANGED messages are sent for 8bpp on Win95 when the
|
|
// palette is realized. This allows us to update the palette time.
|
|
//
|
|
// When running WinNT on >= 8bpp or running Win95 on >= 16bpp,
|
|
// WM_PALETTECHANGED is not sent so we need to manually examine
|
|
// the contents of the logical palette and compare it with a previously
|
|
// cached copy to look for a palette change.
|
|
|
|
cBitsThreshold = ( dwPlatformId == VER_PLATFORM_WIN32_NT ) ? 8
|
|
: 16;
|
|
|
|
// In addition, if rendering to a 4bpp or 8bpp DIB, we need to check
|
|
// the DIB color table since the foreground translation vector is
|
|
// really determined by both the logical and surface palettes.
|
|
|
|
#ifdef FASTDIB
|
|
bDibColorTable = (!pwnd->hwnd && (ppfd->cColorBits <= 8));
|
|
#else
|
|
bDibColorTable = FALSE;
|
|
#endif
|
|
|
|
if ( bDibColorTable ||
|
|
((ppfd->cColorBits >= cBitsThreshold) &&
|
|
(ppfd->iPixelType == PFD_TYPE_COLORINDEX)) )
|
|
{
|
|
if ( !gengc->ppalBuf )
|
|
{
|
|
UINT cjPal, cjRgb;
|
|
|
|
// Allocate buffer space for *two* copies of the palette.
|
|
// That way we don't need to dynamically allocate space
|
|
// for temp storage of the palette. Also,we don't need
|
|
// to copy the current palette to the save buffer if we
|
|
// keep two pointers (one for the temp storage and one for
|
|
// the saved copy) and swap them.
|
|
|
|
cjRgb = bDibColorTable ? (256 * sizeof(RGBQUAD)) : 0;
|
|
cjPal = sizeof(LOGPALETTE) +
|
|
(MAXPALENTRIES * sizeof(PALETTEENTRY));
|
|
|
|
gengc->ppalBuf = (LOGPALETTE *)
|
|
GenMalloc((cjPal + cjRgb) * 2);
|
|
|
|
if ( gengc->ppalBuf )
|
|
{
|
|
// Setup the logical palette buffers.
|
|
|
|
gengc->ppalSave = gengc->ppalBuf;
|
|
gengc->ppalTemp = (LOGPALETTE *)
|
|
(((BYTE *) gengc->ppalBuf) + cjPal);
|
|
gengc->ppalSave->palVersion = 0x300;
|
|
gengc->ppalTemp->palVersion = 0x300;
|
|
|
|
// If 4/8bpp DIB, setup the color table buffers.
|
|
|
|
if (bDibColorTable)
|
|
{
|
|
gengc->prgbSave = (RGBQUAD *)
|
|
(((BYTE *) gengc->ppalTemp) + cjPal);
|
|
gengc->prgbTemp = gengc->prgbSave + 256;
|
|
|
|
// Copy current color table.
|
|
|
|
gengc->crgbSave = GetDIBColorTable(hdc, 0, 256,
|
|
gengc->prgbSave);
|
|
}
|
|
|
|
// How many palette entries? Note that only the first
|
|
// MAXPALENTRIES are significant to generic OpenGL. The
|
|
// rest are ignored.
|
|
|
|
gengc->ppalSave->palNumEntries =
|
|
(WORD) GetPaletteEntries(
|
|
GetCurrentObject(hdc, OBJ_PAL),
|
|
0, 0, (LPPALETTEENTRY) NULL
|
|
);
|
|
gengc->ppalSave->palNumEntries =
|
|
min(gengc->ppalSave->palNumEntries, MAXPALENTRIES);
|
|
|
|
gengc->ppalSave->palNumEntries =
|
|
(WORD) GetPaletteEntries(
|
|
GetCurrentObject(hdc, OBJ_PAL),
|
|
0, gengc->ppalSave->palNumEntries,
|
|
gengc->ppalSave->palPalEntry
|
|
);
|
|
|
|
// Since we had to allocate buffer, this must be the
|
|
// first time wglPaletteChanged was called for this
|
|
// context.
|
|
|
|
pwnd->ulPaletteUniq++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BOOL bNewPal = FALSE; // TRUE if log palette is different
|
|
|
|
// If 4/8bpp DIB, need to compare current color table to
|
|
// previous saved version.
|
|
|
|
if ( bDibColorTable )
|
|
{
|
|
// Copy current color table into temp buffer.
|
|
|
|
gengc->crgbTemp = GetDIBColorTable(hdc, 0, 256,
|
|
gengc->prgbTemp);
|
|
|
|
// If color table size differs, know table has changed.
|
|
// Otherwise, do a memory compare.
|
|
|
|
bNewPal = (gengc->crgbSave != gengc->crgbTemp);
|
|
if ( !bNewPal )
|
|
{
|
|
bNewPal = !LocalCompareUlongMemory(
|
|
gengc->prgbSave,
|
|
gengc->prgbTemp,
|
|
gengc->crgbSave * sizeof(RGBQUAD)
|
|
);
|
|
}
|
|
|
|
// If color table changed, increment uniqueness and
|
|
// update saved copy.
|
|
|
|
if ( bNewPal )
|
|
{
|
|
RGBQUAD *prgb;
|
|
|
|
pwnd->ulPaletteUniq++;
|
|
|
|
// Update saved palette by swapping pointers.
|
|
|
|
prgb = gengc->prgbSave;
|
|
gengc->prgbSave = gengc->prgbTemp;
|
|
gengc->prgbTemp = prgb;
|
|
|
|
gengc->crgbSave = gengc->crgbTemp;
|
|
}
|
|
}
|
|
|
|
// How many palette entries? Note that only the first
|
|
// MAXPALENTRIES are significant to generic OpenGL. The
|
|
// rest are ignored.
|
|
|
|
gengc->ppalTemp->palNumEntries =
|
|
(WORD) GetPaletteEntries(
|
|
GetCurrentObject(hdc, OBJ_PAL),
|
|
0, 0, (LPPALETTEENTRY) NULL
|
|
);
|
|
gengc->ppalTemp->palNumEntries =
|
|
min(gengc->ppalTemp->palNumEntries, MAXPALENTRIES);
|
|
|
|
gengc->ppalTemp->palNumEntries =
|
|
(WORD) GetPaletteEntries(
|
|
GetCurrentObject(hdc, OBJ_PAL),
|
|
0, gengc->ppalTemp->palNumEntries,
|
|
gengc->ppalTemp->palPalEntry
|
|
);
|
|
|
|
// If number of entries differ, know the palette has changed.
|
|
// Otherwise, need to do the hard word of comparing each entry.
|
|
|
|
ASSERTOPENGL(
|
|
sizeof(PALETTEENTRY) == sizeof(ULONG),
|
|
"wglPaletteChanged(): PALETTEENTRY should be 4 bytes\n"
|
|
);
|
|
|
|
// If color table comparison already detected a change, no
|
|
// need to do logpal comparison.
|
|
//
|
|
// However, we will still go ahead and swap logpal pointers
|
|
// below because we want the palette cache to stay current.
|
|
|
|
if ( !bNewPal )
|
|
{
|
|
bNewPal = (gengc->ppalSave->palNumEntries != gengc->ppalTemp->palNumEntries);
|
|
if ( !bNewPal )
|
|
{
|
|
bNewPal = !LocalCompareUlongMemory(
|
|
gengc->ppalSave->palPalEntry,
|
|
gengc->ppalTemp->palPalEntry,
|
|
gengc->ppalSave->palNumEntries * sizeof(PALETTEENTRY)
|
|
);
|
|
}
|
|
}
|
|
|
|
// So, if palette is different, increment uniqueness and
|
|
// update the saved copy.
|
|
|
|
if ( bNewPal )
|
|
{
|
|
LOGPALETTE *ppal;
|
|
|
|
pwnd->ulPaletteUniq++;
|
|
|
|
// Update saved palette by swapping pointers.
|
|
|
|
ppal = gengc->ppalSave;
|
|
gengc->ppalSave = gengc->ppalTemp;
|
|
gengc->ppalTemp = ppal;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ulRet = pwnd->ulPaletteUniq;
|
|
}
|
|
|
|
return ulRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglPaletteSize
|
|
*
|
|
* Return the size of the current palette
|
|
*
|
|
\**************************************************************************/
|
|
|
|
//!!!XXX -- make into a macro?
|
|
ULONG APIENTRY wglPaletteSize(HDC hdc)
|
|
{
|
|
CHECKDCILOCKOUT();
|
|
|
|
return GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL), 0, 0, (LPPALETTEENTRY) NULL);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetPalette
|
|
*
|
|
* Copy current index-to-color table to the supplied array. Colors are
|
|
* formatted as specified in the current pixelformat and are put into the
|
|
* table as DWORDs (i.e., DWORD alignment) starting at the second DWORD.
|
|
* The first DWORD in the table is the number of colors in the table.
|
|
*
|
|
* History:
|
|
* 15-Dec-1994 -by- Gilman Wong [gilmanw]
|
|
* Ported from gdi\gre\wglsup.cxx.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY wglGetPalette(HDC hdc, ULONG *rgbTable, ULONG cEntries)
|
|
{
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
UINT cColors = 0;
|
|
LPPALETTEENTRY lppe, lppeTable;
|
|
UINT i;
|
|
|
|
CHECKDCILOCKOUT();
|
|
|
|
// first element in table is number of entries
|
|
rgbTable[0] = min(wglPaletteSize(hdc),cEntries);
|
|
|
|
lppeTable = (LPPALETTEENTRY)
|
|
LocalAlloc(LMEM_FIXED, sizeof(PALETTEENTRY) * rgbTable[0]);
|
|
|
|
if (lppeTable)
|
|
{
|
|
int rScale, gScale, bScale;
|
|
int rShift, gShift, bShift;
|
|
|
|
rScale = (1 << gengc->CurrentFormat.cRedBits ) - 1;
|
|
gScale = (1 << gengc->CurrentFormat.cGreenBits) - 1;
|
|
bScale = (1 << gengc->CurrentFormat.cBlueBits ) - 1;
|
|
rShift = gengc->CurrentFormat.cRedShift ;
|
|
gShift = gengc->CurrentFormat.cGreenShift;
|
|
bShift = gengc->CurrentFormat.cBlueShift ;
|
|
|
|
cColors = GetPaletteEntries(GetCurrentObject(hdc, OBJ_PAL),
|
|
0, rgbTable[0], lppeTable);
|
|
|
|
for (i = 1, lppe = lppeTable; i <= cColors; i++, lppe++)
|
|
{
|
|
// Whack the PALETTEENTRY color into proper color format. Store as
|
|
// ULONG.
|
|
|
|
//!!!XXX -- use rounding?!?
|
|
rgbTable[i] = (((ULONG)lppe->peRed * rScale / 255) << rShift) |
|
|
(((ULONG)lppe->peGreen * gScale / 255) << gShift) |
|
|
(((ULONG)lppe->peBlue * bScale / 255) << bShift);
|
|
}
|
|
|
|
LocalFree(lppeTable);
|
|
}
|
|
|
|
return(cColors != 0);
|
|
}
|
|
|
|
//!!!dbug
|
|
//!!!3DDDI
|
|
/******************************Public*Routine******************************\
|
|
* wglGetDevCaps
|
|
*
|
|
* Gets device capabilities
|
|
*
|
|
* Fills in RXCAPS structure if extended DDI is supported (not implemented yet)
|
|
*
|
|
* Returns a flag specifying which standard DDI routines are hooked by the driver
|
|
*
|
|
* History:
|
|
* 17-Mar-1994 -by- Eddie Robinson [v-eddier]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
ULONG APIENTRY wglGetDevCaps(
|
|
HDC hdc,
|
|
//XXX change to RXCAPS * when it is defined
|
|
PVOID prxcaps
|
|
)
|
|
{
|
|
ULONG fl = 0;
|
|
|
|
//XXX add this when RXCAPS is added
|
|
#if 0
|
|
ULONG nDDIEscape;
|
|
|
|
// Query the driver to see if any of the extended DDI is supported
|
|
|
|
nDDIEscape = DDIRXFUNCS;
|
|
if (GreExtEscape(hdc, QUERYESCSUPPORT, 4, &nDDIEscape, 0, NULL)) {
|
|
struct __ddirxcapsbuf {
|
|
DDIRXHDR ddiHdr;
|
|
DDIRXCMD ddiCmd;
|
|
} in;
|
|
|
|
in.ddiHdr.flags = 0;
|
|
in.ddiHdr.cCmd = 1;
|
|
in.ddiHdr.hDDIrc = NULL;
|
|
in.ddiHdr.hMem = NULL;
|
|
in.ddiHdr.memOffset = NULL;
|
|
in.ddiCmd.idFunc = GETINFO;
|
|
in.ddiCmd.flags = NULL;
|
|
in.ddiCmd.cData = RX_INFO_CAPS;
|
|
GreExtEscape(hdc, n, sizeof(struct __ddirxcapsrec), &in, sizeof(RXCAPS), prxcaps);
|
|
}
|
|
#endif
|
|
|
|
return fl;
|
|
}
|
|
|
|
//!!!dbug
|
|
/******************************Public*Routine******************************\
|
|
* wgl3dDDIEscape
|
|
*
|
|
* Calls the extended DDI escape with the supplied input buffer and output
|
|
* buffers.
|
|
*
|
|
* History:
|
|
* Jul-1-1994 -by- Otto Berkes [ottob]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LONG APIENTRY wgl3dDDIEscape(
|
|
HDC hdc,
|
|
WNDOBJ *_pwo,
|
|
ULONG cjIn,
|
|
PVOID pvIn,
|
|
ULONG cjOut,
|
|
PVOID pvOut
|
|
)
|
|
{
|
|
#ifndef _CLIENTSIDE_
|
|
BYTE hdrBuffer[sizeof(RXHDR) + sizeof(RXHDR_NTPRIVATE)];
|
|
RXHDR *pRxHdr = (RXHDR *)hdrBuffer;
|
|
RXHDR_NTPRIVATE *pRxHdrPriv = (RXHDR_NTPRIVATE *)(pRxHdr + 1);
|
|
|
|
*pRxHdr = *((RXHDR *)pvIn);
|
|
|
|
pRxHdrPriv->bufferSize = cjIn - sizeof(RXHDR);
|
|
pRxHdrPriv->pBuffer = (PVOID)((PBYTE)pvIn + sizeof(RXHDR));
|
|
|
|
if (hdc == NULL) {
|
|
|
|
SURFOBJ *pso = (SURFOBJ *)NULL;
|
|
PFN_DrvEscape pfnDrvEscape = (PFN_DrvEscape)NULL;
|
|
|
|
glsrvCopyDriverInfo(_pwo, (PVOID *) &pso,
|
|
(PVOID *) &pfnDrvEscape, FALSE);
|
|
|
|
if (!pso || !pfnDrvEscape)
|
|
return 0;
|
|
|
|
EWNDOBJ *pwo = (EWNDOBJ *)_pwo;
|
|
|
|
if (pwo->pwoSiblingNext)
|
|
pwo = pwo->pwoSiblingNext;
|
|
|
|
if (pwo->fl & WO_GENERIC_WNDOBJ)
|
|
pwo = NULL;
|
|
else if (pwo->pto->pso != pso)
|
|
{
|
|
WARNING("wgl3dDDIEscape(): no WNDOBJ\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
pRxHdrPriv->pwo = (WNDOBJ *)pwo;
|
|
|
|
return((int)(*pfnDrvEscape)(pso,
|
|
(ULONG)RXFUNCS,
|
|
(ULONG)sizeof(hdrBuffer),
|
|
hdrBuffer,
|
|
(ULONG)cjOut,
|
|
pvOut));
|
|
}
|
|
|
|
// Validate the destination DC
|
|
|
|
DCOBJ dco(hdc);
|
|
ASSERTGDI(dco.bValid(), "wgl3dDDIEscape(): invalid hdc\n");
|
|
|
|
if (!pRxHdr->hrxSharedMem) {
|
|
pRxHdrPriv->pBuffer = (VOID *)((PBYTE)pvIn + sizeof(RXHDR));
|
|
pRxHdrPriv->bufferSize = cjIn - sizeof(RXHDR);
|
|
} else {
|
|
pRxHdrPriv->pBuffer = (VOID *)NULL;
|
|
pRxHdrPriv->bufferSize = 0;
|
|
}
|
|
|
|
// Handle context creation
|
|
|
|
if (pRxHdr->flags & RX_FL_CREATE_CONTEXT) {
|
|
|
|
// Dispatch the call.
|
|
|
|
XLDEVOBJ lo(dco.pldev());
|
|
PFN_DrvEscape pfnDrvEscape = PFNDRV(lo,Escape);
|
|
if (pfnDrvEscape == (PFN_DrvEscape) NULL)
|
|
return(0);
|
|
|
|
SURFOBJ *pso = (SURFOBJ *) dco.pso();
|
|
|
|
glsrvCopyDriverInfo(_pwo, (PVOID *) &pso,
|
|
(PVOID *) &pfnDrvEscape, TRUE);
|
|
|
|
// Provide current WNDOBJ if one has already been created by the driver
|
|
|
|
EWNDOBJ *pwo = (EWNDOBJ *)_pwo;
|
|
|
|
if (pwo->pwoSiblingNext)
|
|
pwo = pwo->pwoSiblingNext;
|
|
|
|
if (!(pwo->fl & WO_GENERIC_WNDOBJ || pwo->pto->pso != dco.pso()))
|
|
pRxHdrPriv->pwo = (WNDOBJ *)pwo;
|
|
else
|
|
pRxHdrPriv->pwo = (WNDOBJ *)NULL;
|
|
|
|
int iRet = (int)(*pfnDrvEscape)((SURFOBJ *) dco.pso(),
|
|
(ULONG)RXFUNCS,
|
|
(ULONG)sizeof(hdrBuffer),
|
|
hdrBuffer,
|
|
(ULONG)cjOut,
|
|
pvOut);
|
|
|
|
// If a new WNDOBJ is created, we need to update the window client regions
|
|
// in the driver.
|
|
|
|
if (gbWndobjUpdate)
|
|
{
|
|
gbWndobjUpdate = FALSE;
|
|
vForceClientRgnUpdate();
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
|
|
// No output if full screen mode.
|
|
|
|
if (dco.bFullScreen())
|
|
return 0;
|
|
|
|
// Process 3d DDI request
|
|
|
|
if (dco.bSynchronizeAccess())
|
|
CHECKDEVLOCKIN(dco);
|
|
|
|
ASSERTGDI(dco.bValidSurf(), "wgl3dDDIEscape(): invalid dest surface\n");
|
|
|
|
// Locate the driver entry point.
|
|
|
|
XLDEVOBJ lo(dco.pldev());
|
|
PFN_DrvEscape pfnDrvEscape = PFNDRV(lo,Escape);
|
|
if (pfnDrvEscape == (PFN_DrvEscape) NULL)
|
|
return(0);
|
|
|
|
EWNDOBJ *pwo = (EWNDOBJ *)_pwo;
|
|
|
|
if (pwo->pwoSiblingNext)
|
|
pwo = pwo->pwoSiblingNext;
|
|
|
|
if (pwo->fl & WO_GENERIC_WNDOBJ)
|
|
pwo = NULL;
|
|
else if (pwo->pto->pso != dco.pso())
|
|
{
|
|
WARNING("wgl3dDDIEscape(): no WNDOBJ\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
|
|
pRxHdrPriv->pwo = (WNDOBJ *)pwo;
|
|
|
|
return((int)(*pfnDrvEscape)((SURFOBJ *) dco.pso(),
|
|
(ULONG)RXFUNCS,
|
|
(ULONG)sizeof(hdrBuffer),
|
|
hdrBuffer,
|
|
(ULONG)cjOut,
|
|
pvOut));
|
|
#else
|
|
return ExtEscape(hdc, RXFUNCS, cjIn, pvIn, cjOut, pvOut);
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglValidPixelFormat
|
|
*
|
|
* Determines if a pixelformat is usable with the DC specified.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY wglValidPixelFormat(HDC hdc, int ipfd)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PIXELFORMATDESCRIPTOR pfd, pfdDC;
|
|
|
|
if ( wglDescribePixelFormat(hdc, ipfd, sizeof(pfd), &pfd) )
|
|
{
|
|
DWORD dwDcType = wglObjectType(hdc);
|
|
|
|
if ( dwDcType == OBJ_DC )
|
|
{
|
|
// We have a display DC; make sure the pixelformat allows drawing
|
|
// to the window.
|
|
|
|
bRet = ( (pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0 );
|
|
if (!bRet)
|
|
{
|
|
SetLastError(ERROR_INVALID_FLAGS);
|
|
}
|
|
}
|
|
else if ( dwDcType == OBJ_MEMDC )
|
|
{
|
|
// We have a memory DC. Make sure pixelformat allows drawing
|
|
// to a bitmap.
|
|
|
|
if ( pfd.dwFlags & PFD_DRAW_TO_BITMAP )
|
|
{
|
|
// Make sure that the bitmap and pixelformat have the same
|
|
// color depth.
|
|
|
|
HBITMAP hbm;
|
|
BITMAP bm;
|
|
ULONG cBitmapColorBits;
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, 1, 1);
|
|
if ( hbm )
|
|
{
|
|
if ( GetObject(hbm, sizeof(bm), &bm) )
|
|
{
|
|
cBitmapColorBits = bm.bmPlanes * bm.bmBitsPixel;
|
|
|
|
bRet = ( cBitmapColorBits == pfd.cColorBits );
|
|
if (!bRet)
|
|
{
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglValidPixelFormat: GetObject failed\n");
|
|
}
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglValidPixelFormat: Unable to create cbm\n");
|
|
}
|
|
}
|
|
}
|
|
else if (dwDcType == OBJ_ENHMETADC)
|
|
{
|
|
// We don't know anything about what surfaces this
|
|
// metafile will be played back on so allow any kind
|
|
// of pixel format
|
|
bRet = TRUE;
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglValidPixelFormat: not a valid DC!\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglValidPixelFormat: wglDescribePixelFormat failed\n");
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglMakeScans
|
|
*
|
|
* Converts the visible rectangle list in the provided GLGENwindow to a
|
|
* scan-based data structure. The scan-data is put into the GLGENwindow
|
|
* structure.
|
|
*
|
|
* Note: this function assumes that the rectangles are already organized
|
|
* top-down, left-right in scans. This is true for Windows NT 3.5 and
|
|
* Windows 95. This is because the internal representation of regions
|
|
* in both systems is already a scan-based structure. When the APIs
|
|
* (such as GetRegionData) convert the scans to rectangles, the rectangles
|
|
* automatically have this property.
|
|
*
|
|
* Returns:
|
|
* No function return value.
|
|
*
|
|
* History:
|
|
* 05-Dec-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglMakeScans(GLGENwindow *pwnd)
|
|
{
|
|
RECT *prc, *prcEnd;
|
|
LONG lPrevScanTop;
|
|
ULONG cScans = 0;
|
|
UINT cjNeed;
|
|
GLGENscan *pscan;
|
|
LONG *plWalls;
|
|
|
|
ASSERTOPENGL(
|
|
pwnd->prgndat,
|
|
"wglMakeScans(): NULL region data\n"
|
|
);
|
|
|
|
ASSERTOPENGL(
|
|
pwnd->prgndat->rdh.iType == RDH_RECTANGLES,
|
|
"wglMakeScans(): not RDH_RECTANGLES!\n"
|
|
);
|
|
|
|
// Bail out if no rectangles.
|
|
|
|
if (pwnd->prgndat->rdh.nCount == 0)
|
|
return;
|
|
|
|
// First pass: determine the number of scans.
|
|
|
|
lPrevScanTop = -(LONG) 0x7FFFFFFF;
|
|
prc = (RECT *) pwnd->prgndat->Buffer;
|
|
prcEnd = prc + pwnd->prgndat->rdh.nCount;
|
|
|
|
for ( ; prc < prcEnd; prc++)
|
|
{
|
|
if (prc->top != lPrevScanTop)
|
|
{
|
|
lPrevScanTop = prc->top;
|
|
cScans++;
|
|
}
|
|
}
|
|
|
|
// Determine the size needed: 1 GLGENscanData PLUS a GLGENscan per scan PLUS
|
|
// two walls per rectangle.
|
|
|
|
cjNeed = offsetof(GLGENscanData, aScans) +
|
|
cScans * offsetof(GLGENscan, alWalls) +
|
|
pwnd->prgndat->rdh.nCount * sizeof(LONG) * 2;
|
|
|
|
// Allocate the scan structure.
|
|
|
|
if ( cjNeed > pwnd->cjscandat || !pwnd->pscandat )
|
|
{
|
|
if ( pwnd->pscandat )
|
|
LocalFree(pwnd->pscandat);
|
|
|
|
pwnd->pscandat = LocalAlloc(LMEM_FIXED, pwnd->cjscandat = cjNeed);
|
|
if ( !pwnd->pscandat )
|
|
{
|
|
WARNING("wglMakeScans(): memory failure\n");
|
|
pwnd->cjscandat = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Second pass: fill the scan structure.
|
|
|
|
pwnd->pscandat->cScans = cScans;
|
|
|
|
lPrevScanTop = -(LONG) 0x7FFFFFFF;
|
|
prc = (RECT *) pwnd->prgndat->Buffer; // need to reset prc but prcEnd OK
|
|
plWalls = (LONG *) pwnd->pscandat->aScans;
|
|
pscan = (GLGENscan *) NULL;
|
|
|
|
for ( ; prc < prcEnd; prc++ )
|
|
{
|
|
// Do we need to start a new scan?
|
|
|
|
if ( prc->top != lPrevScanTop )
|
|
{
|
|
// Scan we just finished needs pointer to the next scan. Next
|
|
// will start just after this scan (which, conveniently enough,
|
|
// plWalls is pointing at).
|
|
|
|
if ( pscan )
|
|
pscan->pNext = (GLGENscan *) plWalls;
|
|
|
|
lPrevScanTop = prc->top;
|
|
|
|
// Start the new span.
|
|
|
|
pscan = (GLGENscan *) plWalls;
|
|
pscan->cWalls = 0;
|
|
pscan->top = prc->top;
|
|
pscan->bottom = prc->bottom;
|
|
plWalls = pscan->alWalls;
|
|
}
|
|
|
|
pscan->cWalls+=2;
|
|
*plWalls++ = prc->left;
|
|
*plWalls++ = prc->right;
|
|
}
|
|
|
|
if ( pscan )
|
|
pscan->pNext = (GLGENscan *) NULL; // don't leave ptr unitialized in
|
|
// the last scan
|
|
|
|
#if DBG
|
|
DBGLEVEL1(LEVEL_INFO, "\n-----\nwglMakeScans(): cScans = %ld\n", pwnd->pscandat->cScans);
|
|
|
|
cScans = pwnd->pscandat->cScans;
|
|
pscan = pwnd->pscandat->aScans;
|
|
|
|
for ( ; cScans; cScans--, pscan = pscan->pNext )
|
|
{
|
|
LONG *plWalls = pscan->alWalls;
|
|
LONG *plWallsEnd = plWalls + pscan->cWalls;
|
|
|
|
DBGLEVEL3(LEVEL_INFO, "Scan: top = %ld, bottom = %ld, walls = %ld\n", pscan->top, pscan->bottom, pscan->cWalls);
|
|
|
|
for ( ; plWalls < plWallsEnd; plWalls+=2 )
|
|
{
|
|
DBGLEVEL2(LEVEL_INFO, "\t%ld, %ld\n", plWalls[0], plWalls[1]);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetClipList
|
|
*
|
|
* Gets the visible region, via DCI in the form of a list of rectangles,
|
|
* for the window associated with the given WNDOBJ. The data is placed
|
|
* in the GLGENwindow structure.
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 01-Dec-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY wglGetClipList(WNDOBJ *pwo)
|
|
{
|
|
GLGENwindow *pwnd = (GLGENwindow *) pwo;
|
|
UINT cj;
|
|
RECT rc;
|
|
|
|
// Make sure we have enough memory to cache the clip list.
|
|
|
|
cj = WinWatchGetClipList(pwnd->hww, NULL, 0, (LPRGNDATA) NULL);
|
|
|
|
if ( cj )
|
|
{
|
|
if ( cj > pwnd->cjrgndat || !pwnd->prgndat )
|
|
{
|
|
if ( pwnd->prgndat )
|
|
LocalFree(pwnd->prgndat);
|
|
|
|
pwnd->prgndat = LocalAlloc(LMEM_FIXED, pwnd->cjrgndat = cj);
|
|
if ( !pwnd->prgndat )
|
|
{
|
|
WARNING("wglGetClipList(): memory failure\n");
|
|
pwnd->cjrgndat = 0;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglGetClipList(): WinWatchGetClipList failed to return size\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the clip list (RGNDATA format).
|
|
|
|
if ( WinWatchGetClipList(pwnd->hww, NULL, cj, pwnd->prgndat) != 0 )
|
|
{
|
|
// Compose the scan version of the clip list.
|
|
|
|
wglMakeScans(pwnd);
|
|
}
|
|
else
|
|
{
|
|
WARNING("wglGetClipList(): WinWatchGetClipList failed\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Fixup the protected portions of the WNDOBJ.
|
|
|
|
//!!!XXX
|
|
//!!!dbug -- do we actually need sem? Since this is DCI-only, should
|
|
// DCIBeginAccess protect us?
|
|
//EnterCriticalSection(&pwnd->sem);
|
|
{
|
|
__GLdrawablePrivate *dp;
|
|
__GLGENbuffers *buffers;
|
|
|
|
// Update coClient.rclBounds to match RGNDATA bounds.
|
|
|
|
pwo->coClient.rclBounds = *(RECTL *) &pwnd->prgndat->rdh.rcBound;
|
|
|
|
// Update rclClient to match client area. We cannot do this from the
|
|
// information in RGNDATA as the bounds may be smaller than the window
|
|
// client area. We will have to call GetClientRect().
|
|
|
|
GetClientRect(pwnd->hwnd, (LPRECT) &pwo->rclClient);
|
|
ClientToScreen(pwnd->hwnd, (LPPOINT) &pwo->rclClient);
|
|
pwo->rclClient.right += pwo->rclClient.left;
|
|
pwo->rclClient.bottom += pwo->rclClient.top;
|
|
|
|
// Setup WNDOBJ vis rgn types iDComplexity and iFComplexity.
|
|
//
|
|
// Note: iFComplexity is not currently used by OpenGL. However,
|
|
// iDComplexity is used by the clear code to determine if
|
|
// rectangles need to be enumerated for the clear.
|
|
|
|
if ( pwnd->prgndat->rdh.nCount > 1 )
|
|
{
|
|
pwo->coClient.iFComplexity =
|
|
(pwnd->prgndat->rdh.nCount <= 4) ? FC_RECT4
|
|
: FC_COMPLEX;
|
|
|
|
pwo->coClient.iDComplexity = DC_COMPLEX;
|
|
}
|
|
else if ( pwnd->prgndat->rdh.nCount == 1 )
|
|
{
|
|
RECT *prc = (RECT *) pwnd->prgndat->Buffer;
|
|
|
|
pwo->coClient.iFComplexity = FC_RECT;
|
|
|
|
if (
|
|
prc->left <= pwo->rclClient.left &&
|
|
prc->right >= pwo->rclClient.right &&
|
|
prc->top <= pwo->rclClient.top &&
|
|
prc->bottom >= pwo->rclClient.bottom
|
|
)
|
|
pwo->coClient.iDComplexity = DC_TRIVIAL;
|
|
else
|
|
pwo->coClient.iDComplexity = DC_RECT;
|
|
}
|
|
else
|
|
{
|
|
// Clip count is zero. Bounds should be an empty rectangle.
|
|
|
|
pwo->coClient.iFComplexity = FC_RECT;
|
|
pwo->coClient.iDComplexity = DC_RECT;
|
|
|
|
ASSERTOPENGL(
|
|
pwo->coClient.rclBounds.left == pwo->coClient.rclBounds.right ||
|
|
pwo->coClient.rclBounds.top == pwo->coClient.rclBounds.bottom,
|
|
"wglGetClipList(): non-NULL bounds for zero clip count\n");
|
|
}
|
|
|
|
// Finally, the wndobj has changed, so change the uniqueness number.
|
|
|
|
if ( (dp = (__GLdrawablePrivate *)pwnd->wo.pvConsumer) &&
|
|
(buffers = (__GLGENbuffers *)dp->data) )
|
|
{
|
|
buffers->WndUniq++;
|
|
|
|
// Don't let it hit -1. -1 is special and is used by
|
|
// MakeCurrent to signal that an update is required
|
|
|
|
if (buffers->WndUniq == -1)
|
|
buffers->WndUniq = 0;
|
|
}
|
|
}
|
|
//LeaveCriticalSection(&pwnd->sem);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//!!!dbug
|
|
/******************************Public*Routine******************************\
|
|
* wglReleaseWndobjLock
|
|
*
|
|
* If this thread holds the per-WNDOBJ semaphore, release it.
|
|
*
|
|
* History:
|
|
* 24-Jun-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglReleaseWndobjLock(PVOID _pwo)
|
|
{
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglCleanupWndobj
|
|
*
|
|
* Removes references to the specified WNDOBJ (pointed at by pwo) from
|
|
* all contexts by running through the list of RCs in the handle manager
|
|
* table.
|
|
*
|
|
* History:
|
|
* 05-Jul-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglCleanupWndobj(PVOID _pwo)
|
|
{
|
|
if (_pwo)
|
|
{
|
|
WNDOBJ *pwo = (WNDOBJ *) _pwo;
|
|
|
|
//!!!XXX -- For now remove reference from current context. Need to
|
|
//!!!XXX scrub all contexts for multi-threaded cleanup to work.
|
|
//!!!XXX We need to implement a gengc tracking mechanism.
|
|
|
|
__GLGENcontext *gengc = (__GLGENcontext *) GLTEB_SRVCONTEXT();
|
|
|
|
if ( gengc && (gengc->pwo == pwo) )
|
|
{
|
|
// Found a victim. Must NULL out the pointer both in the RC
|
|
// and in the generic context.
|
|
|
|
//prc->pwo = (WNDOBJ *) NULL;
|
|
glsrvCleanupWndobj(gengc, pwo);
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetSystemPaletteEntries
|
|
*
|
|
* Internal version of GetSystemPaletteEntries.
|
|
*
|
|
* GetSystemPaletteEntries fails on some 4bpp devices. This wgl version
|
|
* will detect the 4bpp case and supply the hardcoded 16-color VGA palette.
|
|
* Otherwise, it will pass the call on to GDI's GetSystemPaletteEntries.
|
|
*
|
|
* It is expected that this call will only be called in the 4bpp and 8bpp
|
|
* cases as it is not necessary for OpenGL to query the system palette
|
|
* for > 8bpp devices.
|
|
*
|
|
* History:
|
|
* 17-Aug-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
static PALETTEENTRY gapeVgaPalette[16] =
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0x80,0, 0, 0 },
|
|
{ 0, 0x80,0, 0 },
|
|
{ 0x80,0x80,0, 0 },
|
|
{ 0, 0, 0x80, 0 },
|
|
{ 0x80,0, 0x80, 0 },
|
|
{ 0, 0x80,0x80, 0 },
|
|
{ 0x80,0x80,0x80, 0 },
|
|
{ 0xC0,0xC0,0xC0, 0 },
|
|
{ 0xFF,0, 0, 0 },
|
|
{ 0, 0xFF,0, 0 },
|
|
{ 0xFF,0xFF,0, 0 },
|
|
{ 0, 0, 0xFF, 0 },
|
|
{ 0xFF,0, 0xFF, 0 },
|
|
{ 0, 0xFF,0xFF, 0 },
|
|
{ 0xFF,0xFF,0xFF, 0 }
|
|
};
|
|
|
|
UINT APIENTRY wglGetSystemPaletteEntries(
|
|
HDC hdc,
|
|
UINT iStartIndex,
|
|
UINT nEntries,
|
|
LPPALETTEENTRY lppe)
|
|
{
|
|
int nDeviceBits;
|
|
|
|
nDeviceBits = GetDeviceCaps(hdc, BITSPIXEL) * GetDeviceCaps(hdc, PLANES);
|
|
|
|
if ( nDeviceBits == 4 )
|
|
{
|
|
if ( lppe )
|
|
{
|
|
nEntries = min(nEntries, (16 - iStartIndex));
|
|
|
|
memcpy(lppe, &gapeVgaPalette[iStartIndex],
|
|
nEntries * sizeof(PALETTEENTRY));
|
|
}
|
|
else
|
|
nEntries = 16;
|
|
|
|
return nEntries;
|
|
}
|
|
else
|
|
{
|
|
return GetSystemPaletteEntries(hdc, iStartIndex, nEntries, lppe);
|
|
}
|
|
}
|