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.
3303 lines
98 KiB
3303 lines
98 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: pixelfmt.c
|
|
*
|
|
* This contains the pixel format functions.
|
|
*
|
|
* Created: 15-Dec-1994 00:28:39
|
|
* Author: Gilman Wong [gilmanw] -- ported from gdi\gre\pixelfmt.cxx
|
|
*
|
|
* Copyright (c) 1994 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//#define DBG_WINDOW
|
|
//#define DBG_REFCOUNTS
|
|
|
|
#ifdef _CLIENTSIDE_
|
|
// Need for glsbAttention declaration
|
|
#include "glsbcltu.h"
|
|
#include "glscreen.h"
|
|
#endif
|
|
|
|
#ifdef _MCD_
|
|
#include "mcd.h"
|
|
#endif
|
|
|
|
#define SAVE_ERROR_CODE(x) SetLastError((x))
|
|
|
|
// Number of generic pixel formats. There are 5 pixel depths (4,8,16,24,32).
|
|
// This is to convert BMF constants into # bits per pel
|
|
|
|
#define BMF_COUNT (BMF_32BPP+1)
|
|
|
|
ULONG gaulConvert[BMF_COUNT] =
|
|
{
|
|
0,
|
|
1,
|
|
4,
|
|
8,
|
|
16,
|
|
24,
|
|
32
|
|
};
|
|
|
|
#define MIN_GENERIC_PFD 1
|
|
#define MAX_GENERIC_PFD 36
|
|
|
|
LRESULT CALLBACK
|
|
wglWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
|
|
|
|
#define PALETTE_WATCHER_CLASS __TEXT("Palette Watcher")
|
|
static ATOM aPaletteWatcherClass = 0;
|
|
|
|
DWORD tidPaletteWatcherThread = 0;
|
|
ULONG ulPaletteWatcherCount = 0;
|
|
HANDLE hPaletteWatcherThread = 0;
|
|
HWND hwndPaletteWatcher = 0;
|
|
LONG lPaletteWatcherUsers = 0;
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwndNew
|
|
*
|
|
* Allocate a new GLGENwindow, initialize it (from input structure), and
|
|
* insert it into the global linked list.
|
|
*
|
|
* Returns:
|
|
* Pointer to structure if successful, NULL otherwise.
|
|
*
|
|
* History:
|
|
* 01-Nov-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY pwndNew(GLGENwindow *pwndInit)
|
|
{
|
|
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
|
|
BOOL bDirectScreen = GLDIRECTSCREEN && pwndInit->gwid.hwnd;
|
|
LPDIRECTDRAWCLIPPER pddClip = (LPDIRECTDRAWCLIPPER) NULL;
|
|
|
|
// If using direct access, retrieve or create a clipper object to track
|
|
// vis rgn changes.
|
|
|
|
if (pwndInit->gwid.iType == GLWID_DDRAW)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = pwndInit->gwid.pdds->lpVtbl->
|
|
GetClipper(pwndInit->gwid.pdds, &pddClip);
|
|
if (hr != DD_OK && hr != DDERR_NOCLIPPERATTACHED)
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if ( !bDirectScreen ||
|
|
pwndInit->gwid.iType == GLWID_DDRAW ||
|
|
(GLSCREENINFO->pdd->lpVtbl->
|
|
CreateClipper(GLSCREENINFO->pdd, 0, &pddClip, NULL) == DD_OK &&
|
|
pddClip->lpVtbl->SetHWnd(pddClip, 0, pwndInit->gwid.hwnd) == DD_OK) )
|
|
{
|
|
pwndInit->pddClip = pddClip;
|
|
|
|
// Allocate a new GLGENwindow.
|
|
|
|
pwndRet = (GLGENwindow *)ALLOC(sizeof(GLGENwindow));
|
|
if (pwndRet)
|
|
{
|
|
// Initialize from input structure.
|
|
*pwndRet = *pwndInit;
|
|
|
|
// Initialize per-window semaphore.
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&pwndRet->sem);
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
FREE(pwndRet);
|
|
pwndRet = NULL;
|
|
}
|
|
|
|
if (pwndRet)
|
|
{
|
|
// Set initial usage count to one
|
|
pwndRet->lUsers = 1;
|
|
|
|
// Insert into linked list.
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
{
|
|
pwndRet->pNext = gwndHeader.pNext;
|
|
gwndHeader.pNext = pwndRet;
|
|
}
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("pwndNew: Clipper setup failed\n");
|
|
|
|
if (pddClip != NULL)
|
|
{
|
|
pddClip->lpVtbl->Release(pddClip);
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_WINDOW
|
|
if (pwndRet != NULL)
|
|
{
|
|
DbgPrint("Alloc window %p, type %d, hdc %p, hwnd %p, pdds %p\n",
|
|
pwndRet, pwndRet->gwid.iType, pwndRet->gwid.hdc,
|
|
pwndRet->gwid.hwnd, pwndRet->gwid.pdds);
|
|
}
|
|
#endif
|
|
|
|
return pwndRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pwndUnsubclass
|
|
*
|
|
* Removes OpenGL's subclassing set when windows are created
|
|
*
|
|
* History:
|
|
* Mon May 20 14:05:23 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void pwndUnsubclass(GLGENwindow *pwnd, BOOL bProcessExit)
|
|
{
|
|
WNDPROC wpCur;
|
|
|
|
// We only restore the original WNDPROC if the current WNDPROC
|
|
// is one of ours. This prevents us from stomping on the WNDPROC
|
|
// pointer if somebody else has changed it.
|
|
|
|
if ((pwnd->ulFlags & GLGENWIN_OTHERPROCESS) == 0)
|
|
{
|
|
wpCur = (WNDPROC)GetWindowLongPtr(pwnd->gwid.hwnd, GWLP_WNDPROC);
|
|
if (wpCur == wglWndProc)
|
|
{
|
|
SetWindowLongPtr(pwnd->gwid.hwnd, GWLP_WNDPROC,
|
|
(LONG_PTR) pwnd->pfnOldWndProc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Clean up the palette watcher window if this is the last user.
|
|
EnterCriticalSection(&gcsPaletteWatcher);
|
|
|
|
ASSERTOPENGL(lPaletteWatcherUsers > 0,
|
|
"lPaletteWatcherUsers too low\n");
|
|
|
|
if (--lPaletteWatcherUsers == 0)
|
|
{
|
|
if( PostMessage(hwndPaletteWatcher, WM_CLOSE, 0, 0) == FALSE)
|
|
{
|
|
DbgPrint( "PostMessage to hwnd: %08x failed with error: %08x\n",
|
|
hwndPaletteWatcher, GetLastError() );
|
|
|
|
// Check if the thread is still alive
|
|
|
|
if( WaitForSingleObject( hPaletteWatcherThread, 100 ) !=
|
|
WAIT_OBJECT_0 )
|
|
{
|
|
// This means that the thread is still alive and
|
|
// somehow the window is invalid.
|
|
// Kill this thread or else GL will keep waiting.
|
|
TerminateThread( hPaletteWatcherThread, 0 );
|
|
}
|
|
|
|
// Should be safe to do. If the thread is alive, it
|
|
// was killed above else, someone else killed it
|
|
tidPaletteWatcherThread = 0;
|
|
}
|
|
CloseHandle( hPaletteWatcherThread );
|
|
|
|
// We don't want to zero the palette watcher's thread ID
|
|
// at process exit because we use it to wait for the
|
|
// thread to die.
|
|
if (!bProcessExit)
|
|
{
|
|
tidPaletteWatcherThread = 0;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsPaletteWatcher);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwndFree
|
|
*
|
|
* Frees the specified GLGENwindow.
|
|
*
|
|
* Returns:
|
|
* NULL if successful, pointer to structure otherwise
|
|
*
|
|
* History:
|
|
* 07-Nov-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY pwndFree(GLGENwindow *pwndVictim, BOOL bProcessExit)
|
|
{
|
|
BOOL bDirectScreen = GLDIRECTSCREEN && pwndVictim->gwid.hwnd;
|
|
|
|
#ifdef DBG_WINDOW
|
|
DbgPrint("Free window %p\n", pwndVictim);
|
|
#endif
|
|
|
|
// Check for a stray screen lock and release if necessary.
|
|
|
|
if (pwndVictim->ulFlags & GLGENWIN_DIRECTSCREEN)
|
|
EndDirectScreenAccess(pwndVictim);
|
|
|
|
// Free clipper object.
|
|
|
|
if (bDirectScreen)
|
|
{
|
|
pwndVictim->pddClip->lpVtbl->Release(pwndVictim->pddClip);
|
|
}
|
|
|
|
// Cleanup visible region caches if they exist.
|
|
|
|
if ( pwndVictim->prgndat )
|
|
FREE(pwndVictim->prgndat);
|
|
|
|
if ( pwndVictim->pscandat )
|
|
FREE(pwndVictim->pscandat);
|
|
|
|
// Restore original WNDPROC in window.
|
|
if (pwndVictim->gwid.hwnd != NULL)
|
|
pwndUnsubclass(pwndVictim, bProcessExit);
|
|
|
|
// Cleanup GLGENlayers.
|
|
|
|
if (pwndVictim->plyr)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 15; i++)
|
|
{
|
|
if (pwndVictim->plyr->overlayInfo[i])
|
|
FREE(pwndVictim->plyr->overlayInfo[i]);
|
|
|
|
if (pwndVictim->plyr->underlayInfo[i])
|
|
FREE(pwndVictim->plyr->underlayInfo[i]);
|
|
}
|
|
|
|
FREE(pwndVictim->plyr);
|
|
}
|
|
|
|
// Notify MCD that this window has gone away
|
|
if (pwndVictim->dwMcdWindow != 0)
|
|
{
|
|
GenMcdDestroyWindow(pwndVictim);
|
|
}
|
|
|
|
// Delete victim.
|
|
|
|
DeleteCriticalSection(&pwndVictim->sem);
|
|
FREE(pwndVictim);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pwndCleanup
|
|
*
|
|
* Does all cleanup necessary for window destruction
|
|
*
|
|
* History:
|
|
* Mon Mar 18 17:30:49 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void APIENTRY pwndCleanup(GLGENwindow *pwndVictim)
|
|
{
|
|
GLGENwindow *pwnd, *pwndPrev;
|
|
#if DBG
|
|
ULONG ulLoops;
|
|
#endif
|
|
|
|
#ifdef DBG_WINDOW
|
|
DbgPrint("Clean window %p\n", pwndVictim);
|
|
#endif
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
|
|
// Search for victim. Maintain a prev pointer so we can do
|
|
// removal from linked list.
|
|
|
|
for (
|
|
pwndPrev = &gwndHeader, pwnd = pwndPrev->pNext;
|
|
pwnd != &gwndHeader;
|
|
pwndPrev = pwnd, pwnd = pwndPrev->pNext
|
|
)
|
|
{
|
|
if (pwnd == pwndVictim)
|
|
break;
|
|
}
|
|
|
|
// If victim was found, take it out.
|
|
|
|
if (pwnd == pwndVictim)
|
|
{
|
|
// Excise victim from linked list.
|
|
|
|
pwndPrev->pNext = pwnd->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
|
|
if (pwnd == NULL)
|
|
{
|
|
WARNING("pwndFree: pwndVictim not found in list\n");
|
|
return;
|
|
}
|
|
|
|
// If victim was found, it's out of the list so nobody
|
|
// new can get access to it.
|
|
|
|
// Wait for all current accessors to go away before cleaning up
|
|
// the window
|
|
|
|
#if DBG
|
|
ulLoops = 0;
|
|
#endif
|
|
|
|
for (;;)
|
|
{
|
|
if (pwndVictim->lUsers == 1)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#if DBG
|
|
if (++ulLoops == 1000)
|
|
{
|
|
DbgPrint("Spinning on window %p\n", pwndVictim);
|
|
#ifdef DBG_WINDOW
|
|
DebugBreak();
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// Wait on the critical section as a delay
|
|
// Acquiring it doesn't guarantee that we're the last
|
|
// accessor, but it does kill time in the case where
|
|
// another accessor is already holding it
|
|
EnterCriticalSection(&pwndVictim->sem);
|
|
LeaveCriticalSection(&pwndVictim->sem);
|
|
|
|
// Allow other threads time to run so we don't starve
|
|
// anybody while we're waiting
|
|
Sleep(0);
|
|
}
|
|
|
|
if (pwndVictim->buffers != NULL)
|
|
{
|
|
__glGenFreeBuffers(pwndVictim->buffers);
|
|
wglCleanupWindow(pwndVictim);
|
|
}
|
|
|
|
if (pwndFree(pwndVictim, FALSE))
|
|
WARNING("window deletion failed\n");
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* vCleanupWnd
|
|
*
|
|
* Removes and deletes all GLGENwindow structures from the linked list.
|
|
* Must *ONLY* be called from process detach (GLUnInitializeProcess).
|
|
*
|
|
* History:
|
|
* 25-Jul-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY vCleanupWnd()
|
|
{
|
|
GLGENwindow *pwndNext;
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
|
|
while ( gwndHeader.pNext != &gwndHeader )
|
|
{
|
|
pwndNext = gwndHeader.pNext->pNext;
|
|
pwndFree(gwndHeader.pNext, TRUE);
|
|
gwndHeader.pNext = pwndNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
|
|
// Wait for the palette watcher thread to die. This ensures
|
|
// that the palette watcher critical section can be deleted
|
|
// safely in process detach.
|
|
// We don't use a critical section at this point because of
|
|
// the special critsec rules during DLL detach processing.
|
|
while (tidPaletteWatcherThread != 0)
|
|
{
|
|
Sleep(50);
|
|
}
|
|
// Give the palette watcher thread some time to exit after
|
|
// clearing the thread ID.
|
|
Sleep(50);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwndGetFromHWND
|
|
*
|
|
* Finds the corresponding GLGENwindow for the given window handle.
|
|
*
|
|
* Returns:
|
|
* Pointer to GLGENwindow if sucessful; NULL otherwise.
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY pwndGetFromHWND(HWND hwnd)
|
|
{
|
|
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
|
|
GLGENwindow *pwnd = (GLGENwindow *) NULL;
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
{
|
|
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwnd->pNext)
|
|
if (pwnd->gwid.hwnd == hwnd)
|
|
{
|
|
pwndRet = pwnd;
|
|
InterlockedIncrement(&pwnd->lUsers);
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
|
|
#ifdef DBG_REFCOUNTS
|
|
if (pwndRet != 0)
|
|
{
|
|
DbgPrint("GetHWND %p to %d\n", pwndRet, pwndRet->lUsers);
|
|
}
|
|
#endif
|
|
|
|
return pwndRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwndGetFromMemDC
|
|
*
|
|
* Finds the corresponding GLGENwindow for the given mem DC handle.
|
|
*
|
|
* Returns:
|
|
* Pointer to GLGENwindow if sucessful; NULL otherwise.
|
|
*
|
|
* History:
|
|
* 21-Jan-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY pwndGetFromMemDC(HDC hdcMem)
|
|
{
|
|
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
|
|
GLGENwindow *pwnd = (GLGENwindow *) NULL;
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
{
|
|
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwnd->pNext)
|
|
{
|
|
// If the pwnd has an HWND then the DC used at its
|
|
// creation was associated with a window. If we're
|
|
// in this routine, though, that means hdcMem is
|
|
// not associated with a window, so there's been
|
|
// a reuse of the HDC handle and even though
|
|
// we match DCs we can't return the pwnd.
|
|
|
|
if (pwnd->gwid.hdc == hdcMem && pwnd->gwid.hwnd == NULL)
|
|
{
|
|
pwndRet = pwnd;
|
|
InterlockedIncrement(&pwndRet->lUsers);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
|
|
#ifdef DBG_REFCOUNTS
|
|
if (pwndRet != 0)
|
|
{
|
|
DbgPrint("GetDC %p to %d\n", pwndRet, pwndRet->lUsers);
|
|
}
|
|
#endif
|
|
|
|
return pwndRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pwndGetFromDdraw
|
|
*
|
|
* Looks up a window by its DirectDraw surface
|
|
*
|
|
* History:
|
|
* Wed Aug 28 18:15:40 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow *pwndGetFromDdraw(LPDIRECTDRAWSURFACE pdds)
|
|
{
|
|
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
|
|
GLGENwindow *pwnd = (GLGENwindow *) NULL;
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
{
|
|
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwnd->pNext)
|
|
if (pwnd->gwid.pdds == pdds)
|
|
{
|
|
pwndRet = pwnd;
|
|
InterlockedIncrement(&pwndRet->lUsers);
|
|
break;
|
|
}
|
|
}
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
|
|
#ifdef DBG_REFCOUNTS
|
|
if (pwndRet != 0)
|
|
{
|
|
DbgPrint("GetDD %p to %d\n", pwndRet, pwndRet->lUsers);
|
|
}
|
|
#endif
|
|
|
|
return pwndRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* pwndGetFromID
|
|
*
|
|
* Finds the corresponding GLGENwindow for the given window ID.
|
|
*
|
|
* Returns:
|
|
* Pointer to GLGENwindow if sucessful; NULL otherwise.
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY pwndGetFromID(GLWINDOWID *pgwid)
|
|
{
|
|
GLGENwindow *pwndRet = (GLGENwindow *) NULL;
|
|
|
|
switch (pgwid->iType)
|
|
{
|
|
case GLWID_HWND:
|
|
pwndRet = pwndGetFromHWND(pgwid->hwnd);
|
|
break;
|
|
case GLWID_HDC:
|
|
pwndRet = pwndGetFromMemDC(pgwid->hdc);
|
|
break;
|
|
case GLWID_DDRAW:
|
|
pwndRet = pwndGetFromDdraw(pgwid->pdds);
|
|
break;
|
|
}
|
|
|
|
return pwndRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pwndRelease
|
|
*
|
|
* Decrements the user count of a window
|
|
*
|
|
* History:
|
|
* Mon Mar 18 19:35:28 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#if DBG
|
|
void APIENTRY pwndRelease(GLGENwindow *pwnd)
|
|
{
|
|
ASSERTOPENGL(pwnd->lUsers > 0, "Decrement lUsers below zero\n");
|
|
|
|
InterlockedDecrement(&pwnd->lUsers);
|
|
|
|
#ifdef DBG_REFCOUNTS
|
|
DbgPrint("Release %p to %d\n", pwnd, pwnd->lUsers);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* pwndUnlock
|
|
*
|
|
* Releases an owner of a window
|
|
*
|
|
* History:
|
|
* Mon Mar 18 17:25:56 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void APIENTRY pwndUnlock(GLGENwindow *pwnd, __GLGENcontext *gengc)
|
|
{
|
|
ASSERTOPENGL(pwnd != NULL, "Unlocking NULL window\n");
|
|
|
|
LEAVE_WINCRIT_GC(pwnd, gengc);
|
|
pwndRelease(pwnd);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* ENTER_WINCRIT_GC
|
|
* LEAVE_WINCRIT_GC
|
|
*
|
|
* Window lock tracking routines. The pwnd and gengc are validated
|
|
* and updated to reflect current locks.
|
|
*
|
|
* If the gengc is non-NULL then recursion is not allowed. This is
|
|
* to prevent difficulties with maintaining gengc->pwndLocked correctly
|
|
* during recursion. Recursing with gengc == NULL is not a problem.
|
|
*
|
|
* No ASSERTOPENGL usage so these can be enabled on free builds.
|
|
*
|
|
* History:
|
|
* Wed Jul 02 12:57:26 1997 -by- Drew Bliss [drewb]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void ENTER_WINCRIT_GC(GLGENwindow *pwnd, __GLGENcontext *gengc)
|
|
{
|
|
EnterCriticalSection(&pwnd->sem);
|
|
|
|
if (pwnd->owningThread == 0)
|
|
{
|
|
#if DBG || defined(TRACK_WINCRIT)
|
|
if (pwnd->lockRecursion != 0)
|
|
{
|
|
DbgPrint("Unowned window 0x%08lX has recursion count %d\n",
|
|
pwnd, pwnd->lockRecursion);
|
|
DebugBreak();
|
|
}
|
|
if (pwnd->gengc != NULL)
|
|
{
|
|
DbgPrint("Unowned window 0x%08lX has gengc 0x%08lX\n",
|
|
pwnd, pwnd->gengc);
|
|
DebugBreak();
|
|
}
|
|
if (gengc != NULL && gengc->pwndLocked != NULL)
|
|
{
|
|
DbgPrint("gengc 0x%08lX has pwnd 0x%08lX while locking 0x%08lX\n",
|
|
gengc, gengc->pwndLocked, pwnd);
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
|
|
pwnd->owningThread = GetCurrentThreadId();
|
|
if (gengc != NULL)
|
|
{
|
|
gengc->pwndLocked = pwnd;
|
|
pwnd->gengc = gengc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Make sure this thread is really the one holding the lock.
|
|
ASSERT_WINCRIT(pwnd);
|
|
|
|
#if DBG || defined(TRACK_WINCRIT)
|
|
// Recursion is only allowed with gengc == NULL.
|
|
if (gengc != NULL)
|
|
{
|
|
DbgPrint("Window 0x%08lX recursing with gengc 0x%08lX\n",
|
|
pwnd, gengc);
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
pwnd->lockRecursion++;
|
|
}
|
|
|
|
void LEAVE_WINCRIT_GC(GLGENwindow *pwnd, __GLGENcontext *gengc)
|
|
{
|
|
ASSERT_WINCRIT(pwnd);
|
|
|
|
#if 0
|
|
// Currently turned off because of difference in RTL_CRITICAL_SECTION
|
|
// RecursionCount between x86 and Alpha
|
|
#if !defined(_WIN95_) && (DBG || defined(TRACK_WINCRIT))
|
|
// Check and make sure that our tracking information is following
|
|
// what the system thinks.
|
|
if (pwnd->sem.OwningThread != (HANDLE)pwnd->owningThread ||
|
|
(DWORD)pwnd->sem.RecursionCount != pwnd->lockRecursion)
|
|
{
|
|
DbgPrint("pwnd 0x%08lX critsec information mismatch\n", pwnd);
|
|
DebugBreak();
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if DBG || defined(TRACK_WINCRIT)
|
|
if (gengc != NULL)
|
|
{
|
|
if (pwnd->gengc != gengc || gengc->pwndLocked != pwnd)
|
|
{
|
|
DbgPrint("pwnd 0x%08lX:%08lX mismatch with gengc 0x%08lX:%08lX\n",
|
|
pwnd, pwnd->gengc, gengc, gengc->pwndLocked);
|
|
DebugBreak();
|
|
}
|
|
if (pwnd->lockRecursion != 1)
|
|
{
|
|
DbgPrint("gengc 0x%08lX leaving window 0x%08lX with "
|
|
"recursion count of %d\n",
|
|
gengc, pwnd, pwnd->lockRecursion);
|
|
DebugBreak();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (--pwnd->lockRecursion == 0)
|
|
{
|
|
if (gengc != NULL)
|
|
{
|
|
gengc->pwndLocked = NULL;
|
|
}
|
|
|
|
pwnd->gengc = NULL;
|
|
pwnd->owningThread = 0;
|
|
}
|
|
|
|
LeaveCriticalSection(&pwnd->sem);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* wglValidateWindows
|
|
*
|
|
* Walks the window list and prunes away any DC-based windows with
|
|
* invalid DCs. This is necessary because, unlike window-based
|
|
* windows, we usually aren't notified when a memory DC goes away
|
|
* so if it has a window it just hangs around
|
|
*
|
|
* History:
|
|
* Thu May 02 17:44:23 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void APIENTRY wglValidateWindows(void)
|
|
{
|
|
GLGENwindow *pwnd, *pwndNext;
|
|
BOOL bValid;
|
|
|
|
EnterCriticalSection(&gwndHeader.sem);
|
|
for (pwnd = gwndHeader.pNext; pwnd != &gwndHeader; pwnd = pwndNext)
|
|
{
|
|
pwndNext = pwnd->pNext;
|
|
|
|
switch(pwnd->gwid.iType)
|
|
{
|
|
case GLWID_HDC:
|
|
bValid = GetObjectType(pwnd->gwid.hdc) != 0;
|
|
break;
|
|
|
|
case GLWID_DDRAW:
|
|
// Better validation? Not really necessary since properly
|
|
// behaved apps will have the genwin cleaned up on
|
|
// context destruction.
|
|
bValid = !IsBadReadPtr(pwnd->gwid.pdds, sizeof(void *)) &&
|
|
*(void **)pwnd->gwid.pdds == pwnd->pvSurfaceVtbl;
|
|
break;
|
|
|
|
default:
|
|
// No validation for HWNDs necessary
|
|
bValid = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (!bValid)
|
|
{
|
|
// Increment so users count is one
|
|
InterlockedIncrement(&pwnd->lUsers);
|
|
pwndCleanup(pwnd);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&gwndHeader.sem);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* plyriGet
|
|
*
|
|
* Returns the GLGENlayerInfo for the specified layer plane from the pwnd.
|
|
* If it doesn't yet exist, the GLGENlayer and/or GLGENlayerInfo structure(s)
|
|
* are allocated.
|
|
*
|
|
* Returns:
|
|
* A non-NULL pointer if successful; NULL otherwise.
|
|
*
|
|
* History:
|
|
* 16-May-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
GLGENlayerInfo * APIENTRY plyriGet(GLGENwindow *pwnd, HDC hdc, int iLayer)
|
|
{
|
|
GLGENlayerInfo *plyriRet = (GLGENlayerInfo * ) NULL;
|
|
GLGENlayerInfo **pplyri;
|
|
|
|
ASSERTOPENGL(pwnd, "plyriGet: bad pwnd\n");
|
|
|
|
// Allocate plyr if needed.
|
|
|
|
if (!pwnd->plyr)
|
|
{
|
|
pwnd->plyr = (GLGENlayers *) ALLOCZ(sizeof(GLGENlayers));
|
|
|
|
if (!pwnd->plyr)
|
|
{
|
|
WARNING("plyriGet: alloc failed (GLGENlayers)\n");
|
|
goto plyriGet_exit;
|
|
}
|
|
}
|
|
|
|
// Get info for the specified layer (positive values are overlay planes,
|
|
// negative values are underlay planes).
|
|
|
|
if (iLayer > 0)
|
|
pplyri = &pwnd->plyr->overlayInfo[iLayer - 1];
|
|
else if (iLayer < 1)
|
|
pplyri = &pwnd->plyr->underlayInfo[(-iLayer) - 1];
|
|
else
|
|
{
|
|
WARNING("plyriGet: no layer plane info for main plane!\n");
|
|
goto plyriGet_exit;
|
|
}
|
|
|
|
// Allocate plyri if needed.
|
|
|
|
if (!(*pplyri))
|
|
{
|
|
LAYERPLANEDESCRIPTOR lpd;
|
|
|
|
if (!wglDescribeLayerPlane(hdc, pwnd->ipfd, iLayer, sizeof(lpd), &lpd))
|
|
{
|
|
WARNING("plyriGet: wglDescribeLayerPlane failed\n");
|
|
goto plyriGet_exit;
|
|
}
|
|
|
|
*pplyri = (GLGENlayerInfo *)
|
|
ALLOC((sizeof(COLORREF) * (1 << lpd.cColorBits))
|
|
+ sizeof(GLGENlayerInfo));
|
|
|
|
|
|
if (*pplyri)
|
|
{
|
|
int i;
|
|
|
|
// Initialize the new GLGENlayerInfo.
|
|
// Note that the palette is initialized with all white colors.
|
|
|
|
(*pplyri)->cPalEntries = 1 << lpd.cColorBits;
|
|
for (i = 0; i < (*pplyri)->cPalEntries; i++)
|
|
(*pplyri)->pPalEntries[i] = RGB(255, 255, 255);
|
|
}
|
|
else
|
|
{
|
|
WARNING("plyriGet: alloc failed (GLGENlayerInfo)\n");
|
|
goto plyriGet_exit;
|
|
}
|
|
}
|
|
|
|
// Success.
|
|
|
|
plyriRet = *pplyri;
|
|
|
|
plyriGet_exit:
|
|
|
|
return plyriRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetScreenRect
|
|
*
|
|
* Get the screen rectangle by accessing the virtual screen metrics.
|
|
*
|
|
* If the system does not understand multimon, such as old Win95 or NT,
|
|
* just use the device caps. This code technically isn't necessary but
|
|
* it's useful.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static void GetScreenRect( HDC hdc, LPRECTL pRect )
|
|
{
|
|
// If SM_CMONITORS is not understood the system returns zero,
|
|
// so this if test works for both old and new systems.
|
|
if (GetSystemMetrics(SM_CMONITORS) > 1)
|
|
{
|
|
pRect->left = GetSystemMetrics( SM_XVIRTUALSCREEN );
|
|
pRect->top = GetSystemMetrics( SM_YVIRTUALSCREEN );
|
|
pRect->right = pRect->left + GetSystemMetrics( SM_CXVIRTUALSCREEN );
|
|
pRect->bottom = pRect->top + GetSystemMetrics( SM_CYVIRTUALSCREEN );
|
|
}
|
|
else
|
|
{
|
|
pRect->left = 0;
|
|
pRect->top = 0;
|
|
pRect->right = GetDeviceCaps(hdc, HORZRES);
|
|
pRect->bottom = GetDeviceCaps(hdc, VERTRES);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* bClipToScreen(prclDst, prclSrc)
|
|
*
|
|
* Clip source rectangle to screen bounds and store in destination rectangle.
|
|
*
|
|
* Returns:
|
|
* TRUE if resultant prclDst == prclSrc; FALSE otherwise.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bClipToScreen(RECTL *prclDst, RECTL *prclSrc)
|
|
{
|
|
BOOL bRet;
|
|
HDC hdc;
|
|
|
|
if (hdc = GetDC(NULL))
|
|
{
|
|
RECTL rclScreen;
|
|
|
|
GetScreenRect( hdc, &rclScreen );
|
|
|
|
prclDst->left = max(prclSrc->left , rclScreen.left );
|
|
prclDst->top = max(prclSrc->top , rclScreen.top );
|
|
prclDst->right = min(prclSrc->right , rclScreen.right );
|
|
prclDst->bottom = min(prclSrc->bottom, rclScreen.bottom);
|
|
|
|
if ((prclDst->left >= prclDst->right) ||
|
|
(prclDst->top >= prclDst->bottom))
|
|
{
|
|
prclDst->left = 0;
|
|
prclDst->top = 0;
|
|
prclDst->right = 0;
|
|
prclDst->bottom = 0;
|
|
}
|
|
|
|
ReleaseDC(NULL, hdc);
|
|
}
|
|
else
|
|
{
|
|
prclDst->left = 0;
|
|
prclDst->top = 0;
|
|
prclDst->right = 0;
|
|
prclDst->bottom = 0;
|
|
}
|
|
|
|
if ((prclDst->left == prclSrc->left ) &&
|
|
(prclDst->top == prclSrc->top ) &&
|
|
(prclDst->right == prclSrc->right ) &&
|
|
(prclDst->bottom == prclSrc->bottom))
|
|
bRet = TRUE;
|
|
else
|
|
bRet = FALSE;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* PaletteWatcherProc
|
|
*
|
|
* Window proc for the palette watcher
|
|
*
|
|
* History:
|
|
* Mon Oct 14 15:29:10 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
LRESULT WINAPI PaletteWatcherProc(HWND hwnd, UINT uiMsg,
|
|
WPARAM wpm, LPARAM lpm)
|
|
{
|
|
switch(uiMsg)
|
|
{
|
|
case WM_PALETTECHANGED:
|
|
InterlockedIncrement((LONG *)&ulPaletteWatcherCount);
|
|
return 0;
|
|
|
|
default:
|
|
return DefWindowProc(hwnd, uiMsg, wpm, lpm);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* PaletteWatcher
|
|
*
|
|
* Thread routine for the palette change monitor. Creates a hidden
|
|
* top level window and looks for WM_PALETTECHANGED.
|
|
*
|
|
* History:
|
|
* Mon Oct 14 15:16:02 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DWORD WINAPI PaletteWatcher(LPVOID pvArg)
|
|
{
|
|
HWND hwnd;
|
|
|
|
hwnd = CreateWindow(PALETTE_WATCHER_CLASS,
|
|
PALETTE_WATCHER_CLASS,
|
|
WS_OVERLAPPED,
|
|
0, 0, 1, 1,
|
|
NULL,
|
|
NULL,
|
|
(HINSTANCE)GetModuleHandle(NULL),
|
|
NULL);
|
|
if (hwnd != NULL)
|
|
{
|
|
HDC hdc;
|
|
HPALETTE hpal;
|
|
|
|
// Select a palette into the window DC. This is necessary
|
|
// to get around an optimization introduced into NT5 where
|
|
// WM_PALETTECHANGED is only sent to windows that have selected
|
|
// a palette.
|
|
|
|
hpal = NULL;
|
|
|
|
hdc = GetDC(hwnd);
|
|
if (hdc != NULL)
|
|
{
|
|
hpal = SelectPalette(hdc, GetStockObject(DEFAULT_PALETTE), FALSE);
|
|
ReleaseDC(hwnd, hdc);
|
|
}
|
|
|
|
if (hpal == NULL)
|
|
{
|
|
goto EH_Exit;
|
|
}
|
|
|
|
hwndPaletteWatcher = hwnd;
|
|
|
|
for (;;)
|
|
{
|
|
MSG msg;
|
|
|
|
if (GetMessage(&msg, hwnd, 0, 0) > 0)
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
EH_Exit:
|
|
DestroyWindow(hwnd);
|
|
hwndPaletteWatcher = 0;
|
|
}
|
|
|
|
EnterCriticalSection(&gcsPaletteWatcher);
|
|
|
|
// Some kind of problem occurred or this thread is dying.
|
|
// Indicate that this thread is going away and that a
|
|
// new watcher needs to be created.
|
|
if (tidPaletteWatcherThread == GetCurrentThreadId())
|
|
{
|
|
tidPaletteWatcherThread = 0;
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsPaletteWatcher);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* StartPaletteWatcher
|
|
*
|
|
* Spins up a thread to watch for palette change events
|
|
*
|
|
* History:
|
|
* Mon Oct 14 15:11:35 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL StartPaletteWatcher(void)
|
|
{
|
|
BOOL bRet;
|
|
|
|
EnterCriticalSection(&gcsPaletteWatcher);
|
|
|
|
bRet = FALSE;
|
|
if (tidPaletteWatcherThread == 0)
|
|
{
|
|
HANDLE h;
|
|
|
|
if (aPaletteWatcherClass == 0)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.style = 0;
|
|
wc.lpfnWndProc = PaletteWatcherProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = NULL;
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = PALETTE_WATCHER_CLASS;
|
|
|
|
aPaletteWatcherClass = RegisterClass(&wc);
|
|
}
|
|
|
|
if (aPaletteWatcherClass != 0)
|
|
{
|
|
h = CreateThread(NULL, 4096, PaletteWatcher,
|
|
NULL, 0, &tidPaletteWatcherThread);
|
|
if (h != NULL)
|
|
{
|
|
hPaletteWatcherThread = h;
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
|
|
if (bRet)
|
|
{
|
|
lPaletteWatcherUsers++;
|
|
}
|
|
|
|
LeaveCriticalSection(&gcsPaletteWatcher);
|
|
|
|
// Make sure that the Palette watcher window is created.
|
|
// Dont need to be in the CritSec for this.
|
|
while( (hwndPaletteWatcher == 0) &&
|
|
(tidPaletteWatcherThread != 0) ) Sleep( 100 );
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglWndProc
|
|
*
|
|
* Handle window events for keeping GLGENwindows current
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
LRESULT CALLBACK
|
|
wglWndProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
GLGENwindow *pwnd;
|
|
LRESULT lRet = 0;
|
|
WORD width, height;
|
|
__GLGENcontext *gengc;
|
|
|
|
pwnd = pwndGetFromHWND(hwnd);
|
|
|
|
if (pwnd)
|
|
{
|
|
__GLGENbuffers *buffers = (__GLGENbuffers *) NULL;
|
|
// Cache old WNDPROC because we may delete pwnd
|
|
WNDPROC pfnWndProc = pwnd->pfnOldWndProc;
|
|
|
|
// If WM_NCDESTROY, do OpenGL housekeeping after
|
|
// calling original WndProc.
|
|
// NOTE - We shouldn't really need this special case.
|
|
// It's present in order to allow apps to do things like
|
|
// wglDeleteContext in NCDESTROY which wouldn't work if
|
|
// we cleaned up the window before we passed on the message
|
|
// This used to be done in WM_DESTROY where apps do work,
|
|
// but now that it's on NCDESTROY it's much less likely that
|
|
// an app is doing anything. We preserved the old behavior
|
|
// for safety, though.
|
|
|
|
if (uiMsg == WM_NCDESTROY)
|
|
{
|
|
// Subclassing is supposed to be removed during NCDESTROY
|
|
// processing and order is important. Remove our
|
|
// subclassing before passing on the message.
|
|
pwndUnsubclass(pwnd, FALSE);
|
|
|
|
if (pfnWndProc)
|
|
{
|
|
lRet = CallWindowProc(pfnWndProc, hwnd,
|
|
uiMsg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
// OpenGL housekeeping in response to windowing system messages.
|
|
|
|
switch (uiMsg)
|
|
{
|
|
case WM_SIZE:
|
|
width = LOWORD(lParam);
|
|
height = HIWORD(lParam);
|
|
gengc = (__GLGENcontext *)GLTEB_SRVCONTEXT();
|
|
|
|
// Use the non-gc enter to allow recursion.
|
|
ENTER_WINCRIT(pwnd);
|
|
{
|
|
POINT pt;
|
|
|
|
// Convert client coordinates to screen coordinates
|
|
// as genwin information is always in screen coordinates.
|
|
// The given lParam information may be parent-relative
|
|
// for child windows so it can't be used directly.
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
ClientToScreen(hwnd, &pt);
|
|
|
|
pwnd->rclClient.left = pt.x;
|
|
pwnd->rclClient.right = pt.x + width;
|
|
pwnd->rclClient.top = pt.y;
|
|
pwnd->rclClient.bottom = pt.y + height;
|
|
|
|
#if 0
|
|
DbgPrint("size %d,%d - %d,%d\n",
|
|
pwnd->rclClient.left,
|
|
pwnd->rclClient.top,
|
|
pwnd->rclClient.right,
|
|
pwnd->rclClient.bottom);
|
|
#endif
|
|
|
|
// At least clip to screen.
|
|
|
|
if (bClipToScreen(&pwnd->rclBounds,
|
|
&pwnd->rclClient))
|
|
pwnd->clipComplexity = CLC_TRIVIAL;
|
|
else
|
|
pwnd->clipComplexity = CLC_RECT;
|
|
|
|
buffers = pwnd->buffers;
|
|
if (buffers)
|
|
{
|
|
buffers->WndUniq++;
|
|
|
|
buffers->WndSizeUniq++;
|
|
|
|
// 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;
|
|
|
|
if (buffers->WndSizeUniq == -1)
|
|
buffers->WndSizeUniq = 0;
|
|
|
|
if ((gengc != NULL) && (pwnd == gengc->pwndLocked))
|
|
UpdateWindowInfo(gengc);
|
|
}
|
|
}
|
|
LEAVE_WINCRIT(pwnd);
|
|
|
|
break;
|
|
|
|
case WM_MOVE:
|
|
gengc = (__GLGENcontext *)GLTEB_SRVCONTEXT();
|
|
|
|
// Use the non-gc enter to allow recursion.
|
|
ENTER_WINCRIT(pwnd);
|
|
{
|
|
POINT pt;
|
|
|
|
// Convert client coordinates to screen coordinates
|
|
// as genwin information is always in screen coordinates.
|
|
// The given lParam information may be parent-relative
|
|
// for child windows so it can't be used directly.
|
|
pt.x = 0;
|
|
pt.y = 0;
|
|
ClientToScreen(hwnd, &pt);
|
|
|
|
width = (WORD) (pwnd->rclClient.right -
|
|
pwnd->rclClient.left);
|
|
height = (WORD) (pwnd->rclClient.bottom -
|
|
pwnd->rclClient.top);
|
|
|
|
ASSERTOPENGL(
|
|
(pwnd->rclClient.right -
|
|
pwnd->rclClient.left) <= 0x0FFFF &&
|
|
(pwnd->rclClient.bottom -
|
|
pwnd->rclClient.top) <= 0x0FFFF,
|
|
"wglWndProc(): WM_MOVE - width/height overflow\n"
|
|
);
|
|
|
|
pwnd->rclClient.left = pt.x;
|
|
pwnd->rclClient.right = pt.x + width;
|
|
pwnd->rclClient.top = pt.y;
|
|
pwnd->rclClient.bottom = pt.y + height;
|
|
|
|
#if 0
|
|
DbgPrint("move %d,%d - %d,%d\n",
|
|
pwnd->rclClient.left,
|
|
pwnd->rclClient.top,
|
|
pwnd->rclClient.right,
|
|
pwnd->rclClient.bottom);
|
|
#endif
|
|
|
|
// At least clip to screen.
|
|
|
|
if (bClipToScreen(&pwnd->rclBounds,
|
|
&pwnd->rclClient))
|
|
pwnd->clipComplexity = CLC_TRIVIAL;
|
|
else
|
|
pwnd->clipComplexity = CLC_RECT;
|
|
|
|
buffers = pwnd->buffers;
|
|
if (buffers)
|
|
{
|
|
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;
|
|
|
|
if ((gengc != NULL) && (pwnd == gengc->pwndLocked))
|
|
UpdateWindowInfo(gengc);
|
|
}
|
|
}
|
|
LEAVE_WINCRIT(pwnd);
|
|
|
|
break;
|
|
|
|
case WM_PALETTECHANGED:
|
|
gengc = (__GLGENcontext *)GLTEB_SRVCONTEXT();
|
|
|
|
// Use the non-gc enter to allow recursion.
|
|
ENTER_WINCRIT(pwnd);
|
|
{
|
|
pwnd->ulPaletteUniq++;
|
|
if ((gengc != NULL) && (pwnd == gengc->pwndLocked))
|
|
HandlePaletteChanges(gengc, pwnd);
|
|
}
|
|
LEAVE_WINCRIT(pwnd);
|
|
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
pwndCleanup(pwnd);
|
|
|
|
// WM_NCDESTROY (and WM_DESTROY) are sent after the window has
|
|
// been removed from the screen. The window area is invalid
|
|
// but there is no API that allows us to dertermine that. This
|
|
// allows multithreaded drawing to draw on the screen area
|
|
// formerly occupied by the window. On Win95, DirectDraw does
|
|
// not force a repaint of the system when a window is destroyed.
|
|
// Therefore, if we are running multiple threads on Win95,
|
|
// we force a repaint of the desktop. Note that multithreaded
|
|
// does not mean that we are doing multithreaded drawing, but
|
|
// its a reasonable approximation.
|
|
|
|
if (WIN95_PLATFORM && (lThreadsAttached > 1))
|
|
{
|
|
InvalidateRect(NULL, NULL, FALSE);
|
|
}
|
|
|
|
return lRet;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// If !WM_NCDESTROY, do OpenGL housekeeping before calling original
|
|
// WndProc.
|
|
|
|
ASSERTOPENGL(uiMsg != WM_NCDESTROY,
|
|
"WM_NCDESTROY processing didn't terminate\n");
|
|
|
|
pwndRelease(pwnd);
|
|
|
|
if (pfnWndProc)
|
|
lRet = CallWindowProc(pfnWndProc, hwnd,
|
|
uiMsg, wParam, lParam);
|
|
}
|
|
|
|
return lRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* CreatePwnd
|
|
*
|
|
* Creates a window for the given surface
|
|
*
|
|
* History:
|
|
* Thu Aug 29 10:33:59 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GLGENwindow * APIENTRY CreatePwnd(GLWINDOWID *pgwid, int ipfd, int ipfdDevMax,
|
|
DWORD dwObjectType, RECTL *prcl, BOOL *pbNew)
|
|
{
|
|
GLGENwindow *pwnd;
|
|
GLGENwindow wndInit;
|
|
|
|
pwnd = pwndGetFromID(pgwid);
|
|
|
|
if ( !pwnd )
|
|
{
|
|
memset(&wndInit, 0, sizeof(wndInit));
|
|
|
|
wndInit.gwid = *pgwid;
|
|
wndInit.ipfd = ipfd;
|
|
wndInit.ipfdDevMax = ipfdDevMax;
|
|
|
|
//!!!client driver
|
|
//!!!dbug -- Move SetWindowLong call to pwndNew?!? Maybe move
|
|
//!!!dbug everything from this if.. clause to pwndNew?!?
|
|
if ( wndInit.gwid.hwnd )
|
|
{
|
|
DWORD dwPid;
|
|
|
|
if (GetWindowThreadProcessId(wndInit.gwid.hwnd,
|
|
&dwPid) == 0xffffffff)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (dwPid == GetCurrentProcessId())
|
|
{
|
|
wndInit.pfnOldWndProc =
|
|
(WNDPROC) SetWindowLongPtr(wndInit.gwid.hwnd,
|
|
GWLP_WNDPROC, (LONG_PTR) wglWndProc);
|
|
}
|
|
else
|
|
{
|
|
wndInit.ulFlags |= GLGENWIN_OTHERPROCESS;
|
|
|
|
// Start a thread to watch for palette changes
|
|
if (!StartPaletteWatcher())
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
// Get *SCREEN* coordinates of client rectangle.
|
|
|
|
GetClientRect(wndInit.gwid.hwnd, (LPRECT) &wndInit.rclClient);
|
|
ClientToScreen(wndInit.gwid.hwnd, (LPPOINT) &wndInit.rclClient);
|
|
wndInit.rclClient.right += wndInit.rclClient.left;
|
|
wndInit.rclClient.bottom += wndInit.rclClient.top;
|
|
}
|
|
else if (dwObjectType == OBJ_DC)
|
|
{
|
|
// A direct DC without a window is treated like a DFB
|
|
GetScreenRect( pgwid->hdc, &wndInit.rclClient );
|
|
}
|
|
else if (dwObjectType == OBJ_MEMDC)
|
|
{
|
|
DIBSECTION bmi;
|
|
|
|
// Get bitmap dimensions.
|
|
|
|
if ( !GetObject(GetCurrentObject(pgwid->hdc, OBJ_BITMAP),
|
|
sizeof(DIBSECTION), (LPVOID) &bmi) )
|
|
{
|
|
WARNING("wglSetPixelFormat(): GetObject failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
wndInit.rclClient.left = 0;
|
|
wndInit.rclClient.top = 0;
|
|
wndInit.rclClient.right = bmi.dsBm.bmWidth;
|
|
wndInit.rclClient.bottom = abs(bmi.dsBm.bmHeight);
|
|
}
|
|
else if (dwObjectType == OBJ_DDRAW)
|
|
{
|
|
// DirectDraw surface, use passed in rectangle
|
|
ASSERTOPENGL(prcl != NULL, "NULL rect for DDraw surface\n");
|
|
wndInit.rclClient = *prcl;
|
|
|
|
// Record the surface vtbl pointer for later validation
|
|
wndInit.pvSurfaceVtbl = *(void **)pgwid->pdds;
|
|
}
|
|
else
|
|
{
|
|
ASSERTOPENGL(dwObjectType == OBJ_ENHMETADC,
|
|
"Bad dwType in SetPixelFormat\n");
|
|
|
|
// Initialize metafile DC's to have no size so all output
|
|
// is clipped. This is good because there's no surface
|
|
// to draw on
|
|
wndInit.rclClient.left = 0;
|
|
wndInit.rclClient.top = 0;
|
|
wndInit.rclClient.right = 0;
|
|
wndInit.rclClient.bottom = 0;
|
|
}
|
|
|
|
if (wndInit.gwid.hwnd)
|
|
{
|
|
// To be safe, at least clip bounds to screen.
|
|
|
|
if (bClipToScreen(&wndInit.rclBounds,
|
|
&wndInit.rclClient))
|
|
wndInit.clipComplexity = CLC_TRIVIAL;
|
|
else
|
|
wndInit.clipComplexity = CLC_RECT;
|
|
}
|
|
else
|
|
{
|
|
// Make bounds the same as client.
|
|
wndInit.rclBounds = wndInit.rclClient;
|
|
wndInit.clipComplexity = CLC_TRIVIAL;
|
|
}
|
|
|
|
pwnd = pwndNew(&wndInit);
|
|
if (pwnd == NULL)
|
|
{
|
|
WARNING("wglSetPixelFormat: Unable to allocate new window\n");
|
|
|
|
if ( wndInit.gwid.hwnd )
|
|
{
|
|
pwndUnsubclass(&wndInit, FALSE);
|
|
}
|
|
}
|
|
|
|
*pbNew = TRUE;
|
|
}
|
|
else
|
|
{
|
|
// If the given pixel format is the same as the previous one, return
|
|
// success. Otherwise, as the pixel format can be set only once,
|
|
// return error.
|
|
|
|
if ( pwnd->ipfd != ipfd )
|
|
{
|
|
WARNING("wglSetPixelFormat: Attempt to set pixel format twice\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PIXEL_FORMAT);
|
|
pwndRelease(pwnd);
|
|
pwnd = NULL;
|
|
}
|
|
|
|
*pbNew = FALSE;
|
|
}
|
|
|
|
return pwnd;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglGetPixelFormat
|
|
*
|
|
* Get the pixel format for the window or surface associated with the given
|
|
* DC.
|
|
*
|
|
* Returns:
|
|
* 0 if error or no pixel format was previously set in the window or
|
|
* surface; current pixel format index otherwise
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI wglGetPixelFormat(HDC hdc)
|
|
{
|
|
GLGENwindow *pwnd;
|
|
int iRet = 0;
|
|
GLWINDOWID gwid;
|
|
|
|
WindowIdFromHdc(hdc, &gwid);
|
|
pwnd = pwndGetFromID(&gwid);
|
|
|
|
if (pwnd)
|
|
{
|
|
iRet = pwnd->ipfd;
|
|
pwndRelease(pwnd);
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
// Too noisy for normal operation
|
|
WARNING("wglGetPixelFormat: No window for DC\n");
|
|
#endif
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PIXEL_FORMAT);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
*
|
|
* EnterPixelFormatSection
|
|
*
|
|
* Enters pixel format exclusive code
|
|
*
|
|
* NOTE - Pixel format information is maintained in the client process
|
|
* so it is not synchronized between processes. This means that two
|
|
* processes could successfully set the pixel format for a window.
|
|
* If the list becomes global, this synchronization code should also become
|
|
* cross-process aware.
|
|
*
|
|
* History:
|
|
* Mon Jun 26 17:49:04 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#define EnterPixelFormatSection() \
|
|
(EnterCriticalSection(&gcsPixelFormat), TRUE)
|
|
|
|
/*****************************Private*Routine******************************\
|
|
*
|
|
* LeavePixelFormatSection
|
|
*
|
|
* Leaves pixel format exclusive code
|
|
*
|
|
* History:
|
|
* Mon Jun 26 17:55:20 1995 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#define LeavePixelFormatSection() \
|
|
LeaveCriticalSection(&gcsPixelFormat)
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglNumHardwareFormats
|
|
*
|
|
* Returns the number of hardware formats (ICD and MCD), supported on the
|
|
* specified hdc.
|
|
*
|
|
* History:
|
|
* 17-Apr-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
VOID APIENTRY wglNumHardwareFormats(HDC hdc, DWORD dwType,
|
|
int *piMcd, int *piIcd)
|
|
{
|
|
// It is assumed that the caller has already validated the DC.
|
|
|
|
ASSERTOPENGL((dwType == OBJ_DC) ||
|
|
(dwType == OBJ_MEMDC) ||
|
|
(dwType == OBJ_ENHMETADC) ||
|
|
(dwType == OBJ_DDRAW),
|
|
"wglNumHardwareFormats: bad hdc\n");
|
|
|
|
// Do not call MCD or ICD for enhanced metafile DCs. In such a
|
|
// case, the code in ntgdi\client\output.c will return a non-zero value
|
|
// even if there are no ICD or MCD pixelformats.
|
|
#if _WIN32_WINNT >= 0x0501
|
|
{
|
|
BOOL wow64Process;
|
|
|
|
if (IsWow64Process(GetCurrentProcess(), &wow64Process) && wow64Process)
|
|
dwType = OBJ_ENHMETADC;
|
|
}
|
|
#endif
|
|
|
|
if ( dwType == OBJ_ENHMETADC )
|
|
{
|
|
// It's a metafile DC. Therefore it cannot support MCD or ICD
|
|
// (current OpenGL metafiling support would have to be modified
|
|
// to allow this).
|
|
|
|
*piIcd = 0;
|
|
*piMcd = 0;
|
|
}
|
|
else
|
|
{
|
|
// Get ICD pixelformat count.
|
|
|
|
*piIcd = __DrvDescribePixelFormat(hdc, 1, 0, NULL);
|
|
|
|
// Get MCD pixelformat count.
|
|
|
|
#ifdef _MCD_
|
|
if ( gpMcdTable || bInitMcd(hdc) )
|
|
*piMcd = (gpMcdTable->pMCDDescribePixelFormat)(hdc, 1, NULL);
|
|
else
|
|
*piMcd = 0;
|
|
#else
|
|
*piMcd = 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* GetCompatibleDevice
|
|
*
|
|
* Returns an HDC appropriate for making escape calls on.
|
|
* In the memdc case it returns a DC for the screen.
|
|
*
|
|
* History:
|
|
* Wed Nov 20 17:48:57 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
HDC GetCompatibleDevice(HDC hdc, DWORD dwObjectType)
|
|
{
|
|
HDC hdcDriver;
|
|
int iTech;
|
|
|
|
hdcDriver = hdc;
|
|
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
|
|
if ((dwObjectType == OBJ_MEMDC) && (iTech != DT_PLOTTER) &&
|
|
(iTech != DT_RASPRINTER))
|
|
{
|
|
hdcDriver = GetDC(NULL);
|
|
}
|
|
|
|
return hdcDriver;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglSetPixelFormat
|
|
*
|
|
* Set the pixel format for the window or surface associated with the given
|
|
* DC.
|
|
*
|
|
* Note:
|
|
* Since the pixel format is per-window data (per-DC for non-display DCs), a
|
|
* side effect of this call is to create a GLGENwindow structure.
|
|
*
|
|
* Note:
|
|
* For an installable client driver, a GLGENwindow structure is still created
|
|
* to track the pixel format and the driver structure (GLDRIVER).
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL WINAPI wglSetPixelFormat(HDC hdc, int ipfd,
|
|
CONST PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
GLGENwindow *pwnd = NULL;
|
|
int ipfdDevMax, ipfdMcdMax;
|
|
DWORD dwObjectType;
|
|
BOOL bRet = FALSE;
|
|
GLWINDOWID gwid;
|
|
BOOL bNew;
|
|
HDC hdcDriver;
|
|
LPDIRECTDRAWSURFACE pdds;
|
|
RECTL rcl, *prcl;
|
|
DDSURFACEDESC ddsd;
|
|
|
|
//DBGPRINT1("wglSetPixelFormat: ipfd = %ld\n", ipfd);
|
|
|
|
// Validate DC.
|
|
|
|
switch (dwObjectType = wglObjectType(hdc))
|
|
{
|
|
case OBJ_DC:
|
|
case OBJ_MEMDC:
|
|
case OBJ_ENHMETADC:
|
|
break;
|
|
default:
|
|
WARNING1("wglSetPixelFormat: Attempt to set format of %d type DC\n",
|
|
dwObjectType);
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Take the pixel format mutex
|
|
|
|
if (!EnterPixelFormatSection())
|
|
{
|
|
WARNING("wglSetPixelFormat: Unable to take pixel format mutex\n");
|
|
return FALSE;
|
|
}
|
|
|
|
// Get the number of hardware supported formats.
|
|
|
|
if (pfnGetSurfaceFromDC != NULL &&
|
|
pfnGetSurfaceFromDC(hdc, &pdds, &hdcDriver) == DD_OK)
|
|
{
|
|
// Get the surface dimensions
|
|
memset(&ddsd, 0, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
if (pdds->lpVtbl->GetSurfaceDesc(pdds, &ddsd) != DD_OK)
|
|
{
|
|
goto LeaveSection;
|
|
}
|
|
|
|
rcl.left = 0;
|
|
rcl.top = 0;
|
|
rcl.right = ddsd.dwWidth;
|
|
rcl.bottom = ddsd.dwHeight;
|
|
prcl = &rcl;
|
|
|
|
// Switch object type to identify this as a DirectDraw surface
|
|
dwObjectType = OBJ_DDRAW;
|
|
}
|
|
else
|
|
{
|
|
pdds = NULL;
|
|
prcl = NULL;
|
|
|
|
hdcDriver = GetCompatibleDevice(hdc, dwObjectType);
|
|
if (hdcDriver == NULL)
|
|
{
|
|
goto LeaveSection;
|
|
}
|
|
}
|
|
|
|
wglNumHardwareFormats(hdcDriver, dwObjectType,
|
|
&ipfdMcdMax, &ipfdDevMax);
|
|
|
|
// Filter out invalid (out of range) pixel format indices.
|
|
|
|
if ( (ipfd < 1) || (ipfd > (ipfdDevMax + ipfdMcdMax + MAX_GENERIC_PFD)) )
|
|
{
|
|
WARNING1("wglSetPixelFormat: ipfd %d out of range\n", ipfd);
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
goto LeaveSection;
|
|
}
|
|
|
|
// If it exists, grab pwnd. Otherwise, create one.
|
|
|
|
WindowIdFromHdc(hdc, &gwid);
|
|
pwnd = CreatePwnd(&gwid, ipfd, ipfdDevMax, dwObjectType, prcl, &bNew);
|
|
if (pwnd == NULL)
|
|
{
|
|
goto LeaveSection;
|
|
}
|
|
|
|
if (bNew)
|
|
{
|
|
// Dispatch driver formats.
|
|
// Driver is responsible for doing its own validation of the pixelformat.
|
|
// For generic formats, we call wglValidPixelFormat to validate.
|
|
// We do not send DirectDraw pixel format calls to the driver
|
|
// so that we avoid having new pixel format calls.
|
|
|
|
if (dwObjectType != OBJ_DDRAW && ipfd <= ipfdDevMax)
|
|
{
|
|
bRet = __DrvSetPixelFormat(hdc, ipfd, (PVOID) pwnd);
|
|
#if DBG
|
|
if (!bRet)
|
|
{
|
|
WARNING("__DrvSetPixelFormat failed\n");
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
bRet = wglValidPixelFormat(hdc, ipfd, dwObjectType,
|
|
pdds, &ddsd);
|
|
#if DBG
|
|
if (!bRet)
|
|
{
|
|
WARNING("wglValidPixelFormat failed\n");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// If the pixel format is not valid or could not be set in the driver,
|
|
// cleanup and return error.
|
|
|
|
if (!bRet)
|
|
{
|
|
goto FreeWnd;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
|
|
pwndRelease(pwnd);
|
|
|
|
LeaveSection:
|
|
LeavePixelFormatSection();
|
|
|
|
if (pdds != NULL)
|
|
{
|
|
pdds->lpVtbl->Release(pdds);
|
|
}
|
|
else if (hdcDriver != hdc)
|
|
{
|
|
ReleaseDC((HWND) NULL, hdcDriver);
|
|
}
|
|
|
|
return bRet;
|
|
|
|
FreeWnd:
|
|
pwndCleanup(pwnd);
|
|
goto LeaveSection;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglChoosePixelFormat
|
|
*
|
|
* Choose the pixel format.
|
|
*
|
|
* Returns: 0 if error; best matching pixel format index otherwise
|
|
*
|
|
* History:
|
|
*
|
|
* Sat Feb 10 11:55:22 1996 -by- Hock San Lee [hockl]
|
|
* Chose generic 16-bit depth buffer over 32-bit depth buffer.
|
|
* Added PFD_DEPTH_DONTCARE flag.
|
|
*
|
|
* 19-Oct-1994 Gilman Wong [gilmanw]
|
|
* Taken from GreChoosePixelFormat (gdi\gre\pixelfmt.cxx).
|
|
*
|
|
* History for gdi\gre\pixelfmt.cxx:
|
|
* Tue Sep 21 14:25:04 1993 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// Reserve some PFD_SUPPORT flags for other potential graphics systems
|
|
// such as PEX, HOOPS, Renderman etc.
|
|
|
|
#define PFD_SUPPORT_OTHER1 0x01000000
|
|
#define PFD_SUPPORT_OTHER2 0x02000000
|
|
#define PFD_SUPPORT_OTHER3 0x04000000
|
|
#define PFD_SUPPORT_OTHER4 0x08000000
|
|
|
|
// Scores for matching pixel formats
|
|
|
|
#define PFD_DRAW_TO_WINDOW_SCORE 0x10000 /* must match */
|
|
#define PFD_DRAW_TO_BITMAP_SCORE 0x01000
|
|
#define PFD_PIXEL_TYPE_SCORE 0x01000
|
|
#define PFD_SUPPORT_SCORE 0x01000
|
|
#define PFD_DOUBLEBUFFER_SCORE1 0x01000
|
|
#define PFD_DOUBLEBUFFER_SCORE2 0x00001
|
|
#define PFD_STEREO_SCORE1 0x01000
|
|
#define PFD_STEREO_SCORE2 0x00001
|
|
#define PFD_BUFFER_SCORE1 0x01010
|
|
#define PFD_BUFFER_SCORE2 0x01001
|
|
#define PFD_BUFFER_SCORE3 0x01000
|
|
// #define PFD_LAYER_TYPE_SCORE 0x01000
|
|
#define PFD_DEVICE_FORMAT_SCORE 0x00100
|
|
#define PFD_ACCEL_FORMAT_SCORE 0x00010
|
|
#define PFD_SUPPORT_DDRAW_SCORE 0x10000 /* must match */
|
|
|
|
//!!! Add code to choose overlays?
|
|
|
|
int WINAPI wglChoosePixelFormat(HDC hdc, CONST PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
PIXELFORMATDESCRIPTOR pfdIn = *ppfd;
|
|
PIXELFORMATDESCRIPTOR pfdCurrent;
|
|
|
|
// Enumerate and find the best match.
|
|
|
|
int ipfdBest = 1; // assume the default is the best
|
|
int iScoreBest = -1;
|
|
int ipfdMax;
|
|
int ipfd = 1;
|
|
|
|
do
|
|
{
|
|
int iScore = 0;
|
|
|
|
ipfdMax = wglDescribePixelFormat(hdc,ipfd,sizeof(PIXELFORMATDESCRIPTOR),&pfdCurrent);
|
|
|
|
if (ipfdMax == 0)
|
|
return(0); // something went wrong
|
|
|
|
if (pfdIn.iPixelType == pfdCurrent.iPixelType)
|
|
iScore += PFD_PIXEL_TYPE_SCORE;
|
|
|
|
if ((pfdIn.cColorBits == 0)
|
|
|| (pfdIn.cColorBits == pfdCurrent.cColorBits))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cColorBits < pfdCurrent.cColorBits)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cColorBits != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_DRAW_TO_WINDOW)
|
|
|| (pfdCurrent.dwFlags & PFD_DRAW_TO_WINDOW))
|
|
iScore += PFD_DRAW_TO_WINDOW_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_DRAW_TO_BITMAP)
|
|
|| (pfdCurrent.dwFlags & PFD_DRAW_TO_BITMAP))
|
|
iScore += PFD_DRAW_TO_BITMAP_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_GDI)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_GDI))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_OPENGL)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OPENGL))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if ((pfdIn.dwFlags & PFD_SUPPORT_DIRECTDRAW) == 0 ||
|
|
(pfdCurrent.dwFlags & PFD_SUPPORT_DIRECTDRAW))
|
|
{
|
|
iScore += PFD_SUPPORT_DDRAW_SCORE;
|
|
}
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER1)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER1))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER2)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER2))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER3)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER3))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if (!(pfdIn.dwFlags & PFD_SUPPORT_OTHER4)
|
|
|| (pfdCurrent.dwFlags & PFD_SUPPORT_OTHER4))
|
|
iScore += PFD_SUPPORT_SCORE;
|
|
|
|
if (pfdCurrent.dwFlags & PFD_GENERIC_ACCELERATED)
|
|
iScore += PFD_ACCEL_FORMAT_SCORE;
|
|
else if (!(pfdCurrent.dwFlags & PFD_GENERIC_FORMAT))
|
|
iScore += PFD_DEVICE_FORMAT_SCORE;
|
|
|
|
if ((pfdIn.dwFlags & PFD_DOUBLEBUFFER_DONTCARE)
|
|
|| ((pfdIn.dwFlags & PFD_DOUBLEBUFFER)
|
|
== (pfdCurrent.dwFlags & PFD_DOUBLEBUFFER)))
|
|
iScore += PFD_DOUBLEBUFFER_SCORE1;
|
|
else if (pfdCurrent.dwFlags & PFD_DOUBLEBUFFER)
|
|
iScore += PFD_DOUBLEBUFFER_SCORE2;
|
|
|
|
if ((pfdIn.dwFlags & PFD_STEREO_DONTCARE)
|
|
|| ((pfdIn.dwFlags & PFD_STEREO)
|
|
== (pfdCurrent.dwFlags & PFD_STEREO)))
|
|
iScore += PFD_STEREO_SCORE1;
|
|
else if (pfdCurrent.dwFlags & PFD_STEREO)
|
|
iScore += PFD_STEREO_SCORE2;
|
|
|
|
if ((pfdIn.cAlphaBits == 0)
|
|
|| (pfdIn.cAlphaBits == pfdCurrent.cAlphaBits))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cAlphaBits < pfdCurrent.cAlphaBits)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cAlphaBits != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
|
|
if ((pfdIn.cAccumBits == 0)
|
|
|| (pfdIn.cAccumBits == pfdCurrent.cAccumBits))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cAccumBits < pfdCurrent.cAccumBits)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cAccumBits != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
|
|
// Some applications (e.g. GLview browser) specifies a 0-bit depth buffer
|
|
// but expect this function to return a pixel format with a depth buffer.
|
|
// This works in NT 3.51 since all pixel formats have a depth buffer.
|
|
// When pixel formats with no depth buffer were added in NT 4.0, these
|
|
// applications stopped working. The flag PFD_DEPTH_DONTCARE is added to
|
|
// indicate that no depth buffer is required. If this flags is not given,
|
|
// this function will attempt to select a pixel format with a depth buffer.
|
|
|
|
if (pfdIn.dwFlags & PFD_DEPTH_DONTCARE)
|
|
{
|
|
if (pfdCurrent.cDepthBits == 0)
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
}
|
|
else if (pfdCurrent.cDepthBits != 0)
|
|
{
|
|
if ((pfdIn.cDepthBits == 0)
|
|
|| (pfdIn.cDepthBits == pfdCurrent.cDepthBits))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cDepthBits < pfdCurrent.cDepthBits)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cDepthBits != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
}
|
|
|
|
if ((pfdIn.cStencilBits == 0)
|
|
|| (pfdIn.cStencilBits == pfdCurrent.cStencilBits))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cStencilBits < pfdCurrent.cStencilBits)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cStencilBits != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
|
|
if ((pfdIn.cAuxBuffers == 0)
|
|
|| (pfdIn.cAuxBuffers == pfdCurrent.cAuxBuffers))
|
|
iScore += PFD_BUFFER_SCORE1;
|
|
else if (pfdIn.cAuxBuffers < pfdCurrent.cAuxBuffers)
|
|
iScore += PFD_BUFFER_SCORE2;
|
|
else if (pfdCurrent.cAuxBuffers != 0)
|
|
iScore += PFD_BUFFER_SCORE3;
|
|
|
|
#if 0
|
|
DbgPrint("%2d: score is %8X, best %8X (%2d)\n",
|
|
ipfd, iScore, iScoreBest, ipfdBest);
|
|
#endif
|
|
|
|
if (iScore > iScoreBest)
|
|
{
|
|
iScoreBest = iScore;
|
|
ipfdBest = ipfd;
|
|
}
|
|
else if (iScore == iScoreBest)
|
|
{
|
|
// When everything is equal, we should choose the pixel format with a
|
|
// smaller depth size for better performance, provided that the smaller
|
|
// depth buffer satisfies the request. The best way to do this is to
|
|
// order pixel formats such that one with smaller depth buffer comes
|
|
// first. In NT 3.51, however, the generic pixel format was not ordered
|
|
// this way. As a result, pixel formats with 32-bit depth buffer are
|
|
// choosen by default. To maintain compatibility, we modify the selection
|
|
// here without reordering generic pixel formats.
|
|
|
|
if ((pfdCurrent.dwFlags & PFD_GENERIC_FORMAT) &&
|
|
#ifdef _MCD_
|
|
!(pfdCurrent.dwFlags & PFD_GENERIC_ACCELERATED) &&
|
|
#endif
|
|
(pfdIn.cDepthBits < 16 || pfdIn.dwFlags & PFD_DEPTH_DONTCARE) &&
|
|
(pfdCurrent.cDepthBits == 16) &&
|
|
(ipfd == ipfdBest + 1))
|
|
{
|
|
ipfdBest = ipfd;
|
|
}
|
|
}
|
|
|
|
ipfd++;
|
|
} while (ipfd <= ipfdMax);
|
|
|
|
return(ipfdBest);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* MaskToBitsAndShift
|
|
*
|
|
* Counts bits in a mask and determines shift
|
|
* Set bits must be contiguous
|
|
*
|
|
* History:
|
|
* Mon Aug 26 14:16:28 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void APIENTRY MaskToBitsAndShift(DWORD dwMask, BYTE *pbBits, BYTE *pbShift)
|
|
{
|
|
DWORD dwBit;
|
|
|
|
*pbBits = 0;
|
|
*pbShift = 0;
|
|
|
|
/* Determine first set bit and accumulate shift count */
|
|
dwBit = 0x1;
|
|
while ((dwMask & dwBit) == 0)
|
|
{
|
|
dwBit <<= 1;
|
|
(*pbShift)++;
|
|
}
|
|
|
|
/* Count set bits */
|
|
while ((dwMask & dwBit) != 0)
|
|
{
|
|
dwBit <<= 1;
|
|
(*pbBits)++;
|
|
}
|
|
|
|
/* No other bits in the mask can be set */
|
|
ASSERTOPENGL(((*pbBits+*pbShift) == (sizeof(dwMask)*8)) ||
|
|
((dwMask >> (*pbBits+*pbShift)) == 0),
|
|
"Invalid mask\n");
|
|
}
|
|
|
|
/*****************************Private*Routine******************************\
|
|
*
|
|
* ComputeBitsFromMasks
|
|
*
|
|
* Determines the values for c*Bits and c*Shift from BI_BITFIELD
|
|
* channel masks
|
|
*
|
|
* History:
|
|
* Tue Feb 14 10:50:10 1995 -by- Drew Bliss [drewb]
|
|
* Created by pulling out duplicated code
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static void ComputeBitsFromMasks(PIXELFORMATDESCRIPTOR *ppfd,
|
|
DWORD dwRedMask, DWORD dwGreenMask,
|
|
DWORD dwBlueMask)
|
|
{
|
|
/* Masks can't be zero and they can't overlap */
|
|
ASSERTOPENGL(dwRedMask != 0 &&
|
|
dwGreenMask != 0 &&
|
|
dwBlueMask != 0,
|
|
"Bitfield mask is zero");
|
|
ASSERTOPENGL((dwRedMask & dwGreenMask) == 0 &&
|
|
(dwRedMask & dwBlueMask) == 0 &&
|
|
(dwGreenMask & dwBlueMask) == 0,
|
|
"Bitfield masks overlap");
|
|
|
|
MaskToBitsAndShift(dwRedMask, &ppfd->cRedBits, &ppfd->cRedShift);
|
|
MaskToBitsAndShift(dwGreenMask, &ppfd->cGreenBits, &ppfd->cGreenShift);
|
|
MaskToBitsAndShift(dwBlueMask, &ppfd->cBlueBits, &ppfd->cBlueShift);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* __wglGetDdFormat
|
|
*
|
|
* Special case of __wglGetBitfieldColorFormat to support DirectDraw
|
|
* surfaces. Fills in the cRedBits, cRedShift, cGreenBits, etc. fields
|
|
* of the PIXELFORMATDESCRIPTOR for 16, 24, and 32bpp direct surfaces.
|
|
*
|
|
* This is done by interpreting the given surface information
|
|
*
|
|
* History:
|
|
* 07-Jun-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
void __wglGetDdFormat(DDSURFACEDESC *pddsd,
|
|
PIXELFORMATDESCRIPTOR *ppfd)
|
|
{
|
|
// This routine should only be called for bitfield formats, but
|
|
// random mode changes in the middle of certain calls could cause
|
|
// it to be called with non-bitfield formats.
|
|
//
|
|
// When such a mode change occurs OpenGL should not crash but
|
|
// does not necessarily have to produce correct output
|
|
|
|
if ((pddsd->ddpfPixelFormat.dwFlags & DDPF_RGB) == 0 ||
|
|
(pddsd->ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 |
|
|
DDPF_PALETTEINDEXED2 |
|
|
DDPF_PALETTEINDEXED4 |
|
|
DDPF_PALETTEINDEXED8)))
|
|
{
|
|
WARNING1("__wglGetDdFormat called with 0x%08lX ddpf flags\n",
|
|
pddsd->ddpfPixelFormat.dwFlags);
|
|
|
|
ppfd->cRedBits = 8;
|
|
ppfd->cRedShift = 0;
|
|
ppfd->cGreenBits = 8;
|
|
ppfd->cGreenShift = 0;
|
|
ppfd->cBlueBits = 8;
|
|
ppfd->cBlueShift = 0;
|
|
}
|
|
else
|
|
{
|
|
ComputeBitsFromMasks(ppfd,
|
|
pddsd->ddpfPixelFormat.dwRBitMask,
|
|
pddsd->ddpfPixelFormat.dwGBitMask,
|
|
pddsd->ddpfPixelFormat.dwBBitMask);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* __wglGetBitfieldColorFormat
|
|
*
|
|
* Fills in the cRedBits, cRedShift, cGreenBits, etc. fields of the
|
|
* PIXELFORMATDESCRIPTOR for 16, 24, and 32bpp surfaces (either device
|
|
* or bitmap surfaces).
|
|
*
|
|
* This is done by creating a compatible bitmap and calling GetDIBits
|
|
* to return the color masks. This is done with two calls. The first
|
|
* call passes in biBitCount = 0 to GetDIBits which will fill in the
|
|
* base BITMAPINFOHEADER data. The second call to GetDIBits (passing
|
|
* in the BITMAPINFO filled in by the first call) will return the color
|
|
* table or bitmasks, as appropriate.
|
|
*
|
|
* This function is used to describe the color format for both the underlying
|
|
* surface and for the device. This is the same thing if the DC is a
|
|
* display DC. However, for a memory DC, the surface and the device may have
|
|
* different formats. The bDescribeSurf flag indicates whether the caller
|
|
* wants the decription of the device (FALSE) or the surface (TRUE).
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 07-Jun-1995 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL APIENTRY
|
|
__wglGetBitfieldColorFormat(HDC hdc, UINT cColorBits, PIXELFORMATDESCRIPTOR *ppfd,
|
|
BOOL bDescribeSurf)
|
|
{
|
|
HBITMAP hbm = (HBITMAP) NULL;
|
|
BOOL bRet = FALSE;
|
|
HDC hdcDriver;
|
|
|
|
#if DBG
|
|
// Dynamic color depth changes can cause this. It will not cause us to crash,
|
|
// but drawing (color) may be incorrect.
|
|
|
|
if ((GetObjectType(hdc) == OBJ_DC) &&
|
|
(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
|
|
{
|
|
WARNING("Palette managed device that is greater than 8 bits\n");
|
|
}
|
|
|
|
if (cColorBits < 16)
|
|
{
|
|
WARNING("__wglGetBitfieldColorFormat with cColorBits < 16\n");
|
|
}
|
|
#endif
|
|
|
|
// Handle direct case.
|
|
|
|
if ( GLDIRECTSCREEN && wglIsDirectDevice(hdc) )
|
|
{
|
|
__wglGetDdFormat(&GLSCREENINFO->gdds.ddsd, ppfd);
|
|
return TRUE;
|
|
}
|
|
|
|
// Create a dummy bitmap from which we can query color format info.
|
|
//
|
|
// If we want a device format AND its a MEM_DC AND NOT a printer or plotter,
|
|
// then we need to create a compatible bitmap from a display DC (not the mem
|
|
// DC passed into this function).
|
|
//
|
|
// Otherwise, the format of the surface (whether bitmap or device) associated
|
|
// with the DC passed in will suffice.
|
|
//
|
|
// WinNT does not care, but the Win95 GetDIBits call might
|
|
// fail if we use a memory DC. Specifically, if the memory
|
|
// DC contains a surface that does not match the display
|
|
// (remember, the new bitmap is compatible with the display)
|
|
// the Win95 GetDIBits call will fail.
|
|
//
|
|
// So use the display DC. It works on both platforms.
|
|
|
|
if (!bDescribeSurf)
|
|
{
|
|
hdcDriver = GetCompatibleDevice(hdc, GetObjectType(hdc));
|
|
if (hdcDriver == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hdcDriver = hdc;
|
|
}
|
|
|
|
hbm = CreateCompatibleBitmap(hdcDriver, 1, 1);
|
|
if ( !hbm )
|
|
{
|
|
WARNING("__wglGetBitfieldColorFormat: "
|
|
"CreateCompatibleBitmap failed\n");
|
|
}
|
|
|
|
// Get the color format by calling GetDIBits.
|
|
|
|
else
|
|
{
|
|
BYTE ajBitmapInfo[sizeof(BITMAPINFO) + 3*sizeof(DWORD)];
|
|
BITMAPINFO *pbmi = (BITMAPINFO *) ajBitmapInfo;
|
|
int iRet;
|
|
|
|
//!!!dbug -- Init masks to zero so we can
|
|
// tell if they are set by GetDIBits.
|
|
memset(pbmi, 0, sizeof(ajBitmapInfo));
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
// Call first time to fill in BITMAPINFO header.
|
|
iRet = GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
|
|
|
|
#if DBG
|
|
if (pbmi->bmiHeader.biBitCount != cColorBits)
|
|
WARNING2("__wglGetBitfieldColorFormat: bit count != BITSPIXEL "
|
|
" (%ld, %ld)\n", pbmi->bmiHeader.biBitCount, cColorBits);
|
|
#endif
|
|
|
|
switch ( pbmi->bmiHeader.biCompression )
|
|
{
|
|
case BI_RGB:
|
|
|
|
#if DBG
|
|
// Dynamic color depth changes can cause this. It will not cause
|
|
// us to crash, but drawing (color) may be incorrect.
|
|
|
|
if (pbmi->bmiHeader.biBitCount != cColorBits)
|
|
{
|
|
WARNING("__wglGetBitfieldColorFormat(): bit count mismatch\n");
|
|
}
|
|
#endif
|
|
|
|
// Default DIB format. Color masks are implicit for each bit depth.
|
|
|
|
switch ( pbmi->bmiHeader.biBitCount )
|
|
{
|
|
case 16:
|
|
// 16bpp default is 555 BGR-ordering
|
|
ppfd->cRedBits = 5; ppfd->cRedShift = 10;
|
|
ppfd->cGreenBits = 5; ppfd->cGreenShift = 5;
|
|
ppfd->cBlueBits = 5; ppfd->cBlueShift = 0;
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
case 24:
|
|
case 32:
|
|
// 24 and 32bpp default is 888 BGR-ordering
|
|
ppfd->cRedBits = 8; ppfd->cRedShift = 16;
|
|
ppfd->cGreenBits = 8; ppfd->cGreenShift = 8;
|
|
ppfd->cBlueBits = 8; ppfd->cBlueShift = 0;
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case BI_BITFIELDS:
|
|
|
|
// Some drivers seem to return bitfields for everything that's
|
|
// not paletted. They return correct BGR bitfields so we
|
|
// operate correctly, so remove this assert
|
|
#ifdef STRICT_BITFIELD_CHECK
|
|
ASSERTOPENGL(
|
|
cColorBits == 16 || cColorBits == 32,
|
|
"__wglGetBitfieldColorFormat(): "
|
|
"BI_BITFIELDS surface not 16 or 32bpp\n"
|
|
);
|
|
#endif
|
|
|
|
// Call a second time to get the color masks.
|
|
// It's a GetDIBits Win32 "feature".
|
|
iRet = GetDIBits(hdc, hbm, 0, pbmi->bmiHeader.biHeight, NULL,
|
|
pbmi, DIB_RGB_COLORS);
|
|
|
|
ComputeBitsFromMasks(ppfd,
|
|
*(DWORD *)&pbmi->bmiColors[0],
|
|
*(DWORD *)&pbmi->bmiColors[1],
|
|
*(DWORD *)&pbmi->bmiColors[2]);
|
|
|
|
bRet = TRUE;
|
|
break;
|
|
|
|
default:
|
|
RIP("__wglGetBitfieldColorFormat(): bad biCompression\n");
|
|
break;
|
|
}
|
|
|
|
DeleteObject(hbm);
|
|
}
|
|
|
|
if ( hdcDriver != hdc )
|
|
{
|
|
ReleaseDC((HWND) NULL, hdcDriver);
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* wglGetDeviceDepth
|
|
*
|
|
* Returns the depth of the given HDC
|
|
* Primarily used to workaround potential problems with printers
|
|
* that lie about their depth in GetDeviceCaps
|
|
*
|
|
* History:
|
|
* Tue Apr 09 16:52:47 1996 -by- Drew Bliss [drewb]
|
|
* Created
|
|
*
|
|
\**************************************************************************/
|
|
|
|
int wglGetDeviceDepth(HDC hdc)
|
|
{
|
|
int iTech;
|
|
|
|
// If this is an enhanced metafile it should return the technology
|
|
// of the reference device
|
|
iTech = GetDeviceCaps(hdc, TECHNOLOGY);
|
|
if (iTech == DT_PLOTTER || iTech == DT_RASPRINTER)
|
|
{
|
|
HBITMAP hbm;
|
|
BYTE ajBitmapInfo[sizeof(BITMAPINFO) + 3*sizeof(DWORD)];
|
|
BITMAPINFO *pbmi = (BITMAPINFO *) ajBitmapInfo;
|
|
int iRet;
|
|
|
|
// We're dealing with a printer or a metafile that has a printer
|
|
// as a reference device
|
|
// Find out the true depth by creating a compatible
|
|
// bitmap and querying its format
|
|
if ( (hbm = CreateCompatibleBitmap(hdc, 1, 1)) != NULL )
|
|
{
|
|
memset(pbmi, 0, sizeof(ajBitmapInfo));
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
iRet = GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
|
|
|
|
DeleteObject(hbm);
|
|
|
|
return iRet != 0 ? pbmi->bmiHeader.biBitCount : -1;
|
|
}
|
|
|
|
// Failure
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
// We're dealing with a well-behaved DC so just return
|
|
// the normal depth
|
|
return GetDeviceCaps(hdc, BITSPIXEL)*GetDeviceCaps(hdc, PLANES);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglDescribePixelFormat
|
|
*
|
|
* Describe the pixel format.
|
|
* If cjpfd is 0, just return the maximum pixel format index.
|
|
*
|
|
* Returns: 0 if error; maximum pixel format index otherwise
|
|
*
|
|
* History:
|
|
* 19-Oct-1994 Gilman Wong [gilmanw]
|
|
* Adapted from GreDescribePixelFormat (gdi\gre\pixelfmt.cxx).
|
|
*
|
|
* History for gdi\gre\pixelfmt.cxx:
|
|
* Mon Apr 25 15:34:32 1994 -by- Hock San Lee [hockl]
|
|
* Added 16-bit Z buffer formats and removed double buffered formats for bitmaps.
|
|
* Tue Sep 21 14:25:04 1993 -by- Hock San Lee [hockl]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
// Here are the generic formats that we enumerate. ChoosePixelFormat code
|
|
// assumes that generic pixel formats with z32 comes before z16 as given below:
|
|
//
|
|
// I. Native formats:
|
|
//
|
|
// 1. rgb.sb.z32.a0
|
|
// 2. rgb.sb.z16.a0
|
|
// 3. rgb.db.z32.a0
|
|
// 4. rgb.db.z16.a0
|
|
// 5. rgb.sb.z32.a8
|
|
// 6. rgb.sb.z16.a8
|
|
// 7. rgb.db.z32.a8
|
|
// 8. rgb.db.z16.a8
|
|
// 9. ci.sb.z32
|
|
// 10. ci.sb.z16
|
|
// 11. ci.db.z32
|
|
// 12. ci.db.z16
|
|
//
|
|
// II. Other formats:
|
|
//
|
|
// 1. rgb.sb.z32.a0
|
|
// 2. rgb.sb.z16.a0
|
|
// 3. rgb.sb.z32.a8
|
|
// 4. rgb.sb.z16.a8
|
|
// 5. ci.sb.z32
|
|
// 6. ci.sb.z16
|
|
//
|
|
// We always enumerate the native formats first followed by other formats
|
|
// in the BPP order {24, 32, 16, 8, 4} for a total of 1 * 12 + 4 * 6 = 36
|
|
// pixel formats.
|
|
|
|
// Highest native format generic pixel format index.
|
|
#define MAX_NATIVE_GENERIC_PFD 12
|
|
// Number of non-native formats in a non-native group.
|
|
#define NON_NATIVE_PFD_GROUP 6
|
|
|
|
static BYTE aabPixelBits[BMF_COUNT][4] =
|
|
{
|
|
{24, 32, 16, 8}, // error
|
|
{24, 32, 16, 8}, // 1 bpp
|
|
{24, 32, 16, 8}, // 4 bpp
|
|
{24, 32, 16, 4}, // 8 bpp
|
|
{24, 32, 8, 4}, // 16 bpp
|
|
{32, 16, 8, 4}, // 24 bpp
|
|
{24, 16, 8, 4} // 32 bpp
|
|
};
|
|
|
|
static BYTE abPixelType[MAX_GENERIC_PFD] =
|
|
{
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX,PFD_TYPE_COLORINDEX,
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX,
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX,
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX,
|
|
PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA, PFD_TYPE_RGBA,
|
|
PFD_TYPE_COLORINDEX, PFD_TYPE_COLORINDEX
|
|
};
|
|
|
|
int WINAPI InternalDescribePixelFormat(HDC hdc, HDC hdcDriver,
|
|
int ipfd, UINT cjpfd,
|
|
LPPIXELFORMATDESCRIPTOR ppfd,
|
|
int ipfdDevMax, int ipfdMcdMax,
|
|
LPDIRECTDRAWSURFACE pdds,
|
|
DDSURFACEDESC *pddsd)
|
|
{
|
|
int iRet = 0;
|
|
int ipfdGen;
|
|
UINT iDitherFormat;
|
|
BYTE cColorBitsNative;
|
|
|
|
// If cjpfd is 0, just return the maximum pixel format index.
|
|
|
|
if (cjpfd == 0 || ppfd == NULL)
|
|
{
|
|
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
// Validate the size of the pixel format descriptor.
|
|
|
|
if (cjpfd < sizeof(PIXELFORMATDESCRIPTOR))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
// Validate pixel format index.
|
|
// If a driver support device pixel formats 1..ipfdDevMax, the generic
|
|
// pixel formats will be (ipfdDevMax+1)..(ipfdDevMax+MAX_GENERIC_PFD).
|
|
// Otherwise, ipfdDevMax is 0 and the generic pixel formats are
|
|
// 1..MAX_GENERIC_PFD.
|
|
|
|
if ((ipfd < 1) || (ipfd > ipfdDevMax + ipfdMcdMax + MAX_GENERIC_PFD))
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
// Dispatch ICD driver formats.
|
|
|
|
if (ipfd <= ipfdDevMax)
|
|
{
|
|
int iDrvRet = __DrvDescribePixelFormat(hdcDriver,ipfd,cjpfd,ppfd);
|
|
if (iDrvRet)
|
|
{
|
|
ASSERTOPENGL(iDrvRet == ipfdDevMax,
|
|
"wglDescribePixelFornat: Bad ipfdDevMax");
|
|
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
|
|
}
|
|
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
// Dispatch MCD driver formats.
|
|
|
|
ipfdGen = ipfd - ipfdDevMax;
|
|
if (ipfdGen <= ipfdMcdMax)
|
|
{
|
|
int iMcdRet;
|
|
|
|
// Note: don't need to check if gpMcdTable is valid because we can't get
|
|
// here unless ipfdDevMax is non-zero and that can't happen unless the
|
|
// the table is valid.
|
|
|
|
ASSERTOPENGL(gpMcdTable, "wglDescribePixelFormat: bad MCD table\n");
|
|
|
|
iMcdRet = (gpMcdTable->pMCDDescribePixelFormat)(hdcDriver, ipfdGen,
|
|
ppfd);
|
|
if (iMcdRet)
|
|
{
|
|
ASSERTOPENGL(iMcdRet == ipfdMcdMax,
|
|
"wglDescribePixelFornat: Bad ipfdMcdMax");
|
|
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
|
|
}
|
|
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
// Generic implementation.
|
|
// Normalize the generic pixel format index to 0..(MAX_GENERIC_PFD-1).
|
|
|
|
ipfdGen = ipfdGen - ipfdMcdMax - 1;
|
|
#else
|
|
// Generic implementation.
|
|
// Normalize the generic pixel format index to 0..(MAX_GENERIC_PFD-1).
|
|
|
|
ipfdGen = ipfd - ipfdDevMax - 1;
|
|
#endif
|
|
|
|
// Get the native BPP format.
|
|
|
|
if (pdds != NULL)
|
|
{
|
|
cColorBitsNative = DdPixelDepth(pddsd);
|
|
}
|
|
else
|
|
{
|
|
cColorBitsNative = (BYTE)wglGetDeviceDepth(hdc);
|
|
}
|
|
|
|
if (cColorBitsNative < 1)
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
if (cColorBitsNative <= 1)
|
|
{
|
|
cColorBitsNative = 1;
|
|
iDitherFormat = BMF_1BPP;
|
|
}
|
|
else if (cColorBitsNative <= 4)
|
|
{
|
|
cColorBitsNative = 4;
|
|
iDitherFormat = BMF_4BPP;
|
|
}
|
|
else if (cColorBitsNative <= 8)
|
|
{
|
|
cColorBitsNative = 8;
|
|
iDitherFormat = BMF_8BPP;
|
|
}
|
|
else if (cColorBitsNative <= 16)
|
|
{
|
|
cColorBitsNative = 16;
|
|
iDitherFormat = BMF_16BPP;
|
|
}
|
|
else if (cColorBitsNative <= 24)
|
|
{
|
|
cColorBitsNative = 24;
|
|
iDitherFormat = BMF_24BPP;
|
|
}
|
|
else
|
|
{
|
|
cColorBitsNative = 32;
|
|
iDitherFormat = BMF_32BPP;
|
|
}
|
|
|
|
// Fill in the pixel format descriptor.
|
|
|
|
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
|
ppfd->nVersion = 1;
|
|
ppfd->iPixelType = abPixelType[ipfdGen];
|
|
|
|
if (ipfdGen < MAX_NATIVE_GENERIC_PFD)
|
|
{
|
|
ppfd->cColorBits = max(cColorBitsNative, 4); // 1 bpp not supported
|
|
}
|
|
else
|
|
{
|
|
ppfd->cColorBits = aabPixelBits[iDitherFormat]
|
|
[(ipfdGen - MAX_NATIVE_GENERIC_PFD) / NON_NATIVE_PFD_GROUP];
|
|
}
|
|
|
|
// If the color format is compatible to that of the device and the
|
|
// color bits is 16 or greater, use the device description.
|
|
// Otherwise, use the generic format.
|
|
|
|
if (ipfdGen < MAX_NATIVE_GENERIC_PFD && cColorBitsNative >= 16)
|
|
{
|
|
// Handle compatible formats that are greater than 16-bits.
|
|
|
|
if (pdds != NULL)
|
|
{
|
|
__wglGetDdFormat(pddsd, ppfd);
|
|
}
|
|
else if ( !__wglGetBitfieldColorFormat(hdc, cColorBitsNative,
|
|
ppfd, FALSE) )
|
|
{
|
|
// Don't know how to deal with this device!
|
|
|
|
WARNING("Unknown device format");
|
|
SAVE_ERROR_CODE(ERROR_NOT_SUPPORTED);
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Handle generic formats.
|
|
|
|
switch (ppfd->cColorBits)
|
|
{
|
|
case 4:
|
|
ppfd->cRedBits = 1; ppfd->cRedShift = 0;
|
|
ppfd->cGreenBits = 1; ppfd->cGreenShift = 1;
|
|
ppfd->cBlueBits = 1; ppfd->cBlueShift = 2;
|
|
break;
|
|
case 8:
|
|
ppfd->cRedBits = 3; ppfd->cRedShift = 0;
|
|
ppfd->cGreenBits = 3; ppfd->cGreenShift = 3;
|
|
ppfd->cBlueBits = 2; ppfd->cBlueShift = 6;
|
|
break;
|
|
case 16:
|
|
/*
|
|
** Even though Win95 allows arbitrary bitfield definitions
|
|
** for 16bpp DIBs, only 555BGR is usable by Win95's GDI.
|
|
*/
|
|
ppfd->cRedBits = 5; ppfd->cRedShift = 10; // 555BGR
|
|
ppfd->cGreenBits = 5; ppfd->cGreenShift = 5;
|
|
ppfd->cBlueBits = 5; ppfd->cBlueShift = 0;
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
/*
|
|
** Even though Win95 allows arbitrary bitfield definitions
|
|
** for 32bpp, only 888BGR is usable by Win95's GDI. Similarly,
|
|
** NT has the concept of a RGB 24bpp DIB, but Win95 does not.
|
|
*/
|
|
ppfd->cRedBits = 8; ppfd->cRedShift = 16; // 888BGR
|
|
ppfd->cGreenBits = 8; ppfd->cGreenShift = 8;
|
|
ppfd->cBlueBits = 8; ppfd->cBlueShift = 0;
|
|
break;
|
|
default:
|
|
ASSERTOPENGL(FALSE, "wglDescribePixelFornat: Unknown format");
|
|
break;
|
|
}
|
|
}
|
|
|
|
ppfd->cAlphaBits = 0;
|
|
ppfd->cAlphaShift = 0;
|
|
if ( ipfdGen < MAX_NATIVE_GENERIC_PFD)
|
|
{
|
|
// Only report alpha bits if the DirectDraw surface has them.
|
|
if (pdds != NULL)
|
|
{
|
|
if (pddsd->ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS)
|
|
{
|
|
ASSERTOPENGL(pddsd->dwFlags & DDSD_ALPHABITDEPTH,
|
|
"Surface with alpha but no bit depth set\n");
|
|
|
|
ppfd->cAlphaBits = (BYTE)pddsd->dwAlphaBitDepth;
|
|
}
|
|
}
|
|
else if ( (ipfdGen > 3) && (ipfdGen < 8) )
|
|
{
|
|
ppfd->cAlphaBits = 8;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int ipfd = (ipfdGen - MAX_NATIVE_GENERIC_PFD) % NON_NATIVE_PFD_GROUP;
|
|
if ( (ipfd == 2) || (ipfd == 3) )
|
|
{
|
|
ppfd->cAlphaBits = 8;
|
|
}
|
|
}
|
|
|
|
if (ppfd->iPixelType == PFD_TYPE_RGBA)
|
|
{
|
|
if (ppfd->cColorBits <= 16)
|
|
{
|
|
if (ppfd->cColorBits < 8)
|
|
{
|
|
// !!! Internally now, we will actually be using a 32-bit accum
|
|
// buffer, but the user will think it's 16 (This is for
|
|
// backwards compatibility).
|
|
ppfd->cAccumBits = 16;
|
|
if( ppfd->cAlphaBits )
|
|
{
|
|
ppfd->cAccumRedBits = 4;
|
|
ppfd->cAccumGreenBits = 4;
|
|
ppfd->cAccumBlueBits = 4;
|
|
ppfd->cAccumAlphaBits = 4;
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumRedBits = 5;
|
|
ppfd->cAccumGreenBits = 6;
|
|
ppfd->cAccumBlueBits = 5;
|
|
ppfd->cAccumAlphaBits = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumBits = 32;
|
|
if( ppfd->cAlphaBits )
|
|
{
|
|
ppfd->cAccumRedBits = 8;
|
|
ppfd->cAccumGreenBits = 8;
|
|
ppfd->cAccumBlueBits = 8;
|
|
ppfd->cAccumAlphaBits = 8;
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumRedBits = 11;
|
|
ppfd->cAccumGreenBits = 11;
|
|
ppfd->cAccumBlueBits = 10;
|
|
ppfd->cAccumAlphaBits = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumBits = 64;
|
|
|
|
if( ppfd->cAlphaBits )
|
|
{
|
|
ppfd->cAccumRedBits = 16;
|
|
ppfd->cAccumGreenBits = 16;
|
|
ppfd->cAccumBlueBits = 16;
|
|
ppfd->cAccumAlphaBits = 16;
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumRedBits = 16;
|
|
ppfd->cAccumGreenBits = 16;
|
|
ppfd->cAccumBlueBits = 16;
|
|
ppfd->cAccumAlphaBits = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppfd->cAccumBits = 0;
|
|
ppfd->cAccumRedBits = 0;
|
|
ppfd->cAccumGreenBits = 0;
|
|
ppfd->cAccumBlueBits = 0;
|
|
ppfd->cAccumAlphaBits = 0;
|
|
}
|
|
|
|
// Generic formats alternate between 16- and 32-bit depth buffer. Evens
|
|
// are 32-bit, odds are 16-bit.
|
|
// DirectDraw surfaces always report the depth of the attached Z buffer
|
|
// for the native format indices.
|
|
|
|
if (pdds != NULL && ipfdGen < MAX_NATIVE_GENERIC_PFD)
|
|
{
|
|
DDSCAPS ddscaps;
|
|
LPDIRECTDRAWSURFACE pddsZ;
|
|
|
|
// DDraw surfaces may not have attached Z buffers, in which case
|
|
// we should not report depth bits. If one is attached, its
|
|
// depth should be reported.
|
|
// We only do this processing for native pixel formats.
|
|
|
|
memset(&ddscaps, 0, sizeof(ddscaps));
|
|
ddscaps.dwCaps = DDSCAPS_ZBUFFER;
|
|
if (pdds->lpVtbl->
|
|
GetAttachedSurface(pdds, &ddscaps, &pddsZ) == DD_OK)
|
|
{
|
|
HRESULT hr;
|
|
DDSURFACEDESC ddsdZ;
|
|
|
|
memset(&ddsdZ, 0, sizeof(ddsdZ));
|
|
ddsdZ.dwSize = sizeof(ddsdZ);
|
|
|
|
hr = pddsZ->lpVtbl->GetSurfaceDesc(pddsZ, &ddsdZ);
|
|
|
|
pddsZ->lpVtbl->Release(pddsZ);
|
|
|
|
if (hr != DD_OK)
|
|
{
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
ppfd->cDepthBits =
|
|
(BYTE)DdPixDepthToCount(ddsdZ.ddpfPixelFormat.
|
|
dwZBufferBitDepth);
|
|
}
|
|
else
|
|
{
|
|
ppfd->cDepthBits = 0;
|
|
}
|
|
}
|
|
else if (ipfdGen & 0x1)
|
|
{
|
|
ppfd->cDepthBits = 16;
|
|
}
|
|
else
|
|
{
|
|
ppfd->cDepthBits = 32;
|
|
}
|
|
|
|
ppfd->cStencilBits = 8;
|
|
ppfd->cAuxBuffers = 0;
|
|
ppfd->iLayerType = PFD_MAIN_PLANE;
|
|
ppfd->bReserved = 0;
|
|
ppfd->dwLayerMask = 0;
|
|
ppfd->dwVisibleMask = 0;
|
|
ppfd->dwDamageMask = 0;
|
|
|
|
// Compute the buffer flags.
|
|
// Support OpenGL in all generic formats.
|
|
|
|
ppfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT;
|
|
|
|
// Indicate DirectDraw support on native pixel formats for DD surfaces.
|
|
if (pdds != NULL && ipfdGen < MAX_NATIVE_GENERIC_PFD)
|
|
{
|
|
ppfd->dwFlags |= PFD_SUPPORT_DIRECTDRAW;
|
|
}
|
|
|
|
// Bitmaps and GDI drawing are available in single buffered mode only.
|
|
|
|
if (pdds == NULL &&
|
|
(ipfdGen == 2 || ipfdGen == 3 || ipfdGen == 6 || ipfdGen == 7 ||
|
|
ipfdGen == 10 || ipfdGen == 11))
|
|
{
|
|
ppfd->dwFlags |= PFD_DOUBLEBUFFER | PFD_SWAP_COPY;
|
|
}
|
|
else
|
|
{
|
|
ppfd->dwFlags |= PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI;
|
|
}
|
|
|
|
// Draw to window or device surface only if the format is compatible.
|
|
|
|
if (ipfdGen < MAX_NATIVE_GENERIC_PFD)
|
|
{
|
|
ppfd->dwFlags |= PFD_DRAW_TO_WINDOW;
|
|
|
|
// Need a palette if it is a RGBA pixel type on a palette managed device.
|
|
|
|
if (ppfd->cColorBits == 8 && ppfd->iPixelType == PFD_TYPE_RGBA)
|
|
{
|
|
ppfd->dwFlags |= PFD_NEED_PALETTE;
|
|
}
|
|
}
|
|
|
|
// If this is a 1 bpp surface, we don't support drawing to window and
|
|
// double buffered mode. Re-set the buffer flags.
|
|
|
|
if (cColorBitsNative < 4)
|
|
{
|
|
#ifndef GL_METAFILE
|
|
ASSERTOPENGL(ppfd->cColorBits == 4,
|
|
"wglDescribePixelFormat: bad cColorBits for 1 bpp surface\n");
|
|
#endif
|
|
|
|
ppfd->dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_GDI |
|
|
PFD_SUPPORT_OPENGL | PFD_GENERIC_FORMAT;
|
|
}
|
|
|
|
// To support other potential graphics systems, we reserve the following
|
|
// flags in the pixel format descriptor. For example, PEX may use
|
|
// PFD_SUPPORT_OTHER1 on the system that supports PEX. Since we don't
|
|
// support these other systems in the generic implementation, they belong
|
|
// to the device pixel format descriptor.
|
|
|
|
ASSERTOPENGL(!(ppfd->dwFlags & (PFD_SUPPORT_OTHER1 | PFD_SUPPORT_OTHER2 |
|
|
PFD_SUPPORT_OTHER3 | PFD_SUPPORT_OTHER4)),
|
|
"dwFlags reserved for device formats\n");
|
|
|
|
iRet = MAX_GENERIC_PFD + ipfdDevMax + ipfdMcdMax;
|
|
|
|
wglDescribePixelFormat_cleanup:
|
|
|
|
return iRet;
|
|
}
|
|
|
|
int WINAPI wglDescribePixelFormat(HDC hdc, int ipfd, UINT cjpfd,
|
|
LPPIXELFORMATDESCRIPTOR ppfd)
|
|
{
|
|
int iRet = 0;
|
|
int ipfdDevMax, ipfdMcdMax;
|
|
DWORD dwObjectType;
|
|
HDC hdcDriver = NULL;
|
|
LPDIRECTDRAWSURFACE pdds;
|
|
DDSURFACEDESC ddsd;
|
|
|
|
// Validate DC.
|
|
|
|
switch (dwObjectType = wglObjectType(hdc))
|
|
{
|
|
case OBJ_DC:
|
|
case OBJ_MEMDC:
|
|
case OBJ_ENHMETADC:
|
|
break;
|
|
default:
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(0);
|
|
}
|
|
|
|
// Check to see if this is a DirectDraw DC. If it is, use the
|
|
// device DC returned from DirectDraw.
|
|
if (pfnGetSurfaceFromDC != NULL &&
|
|
pfnGetSurfaceFromDC(hdc, &pdds, &hdcDriver) == DD_OK)
|
|
{
|
|
// pdds reference must be released before exiting this function.
|
|
|
|
// Retrieve surface description for later use.
|
|
memset(&ddsd, 0, sizeof(ddsd));
|
|
ddsd.dwSize = sizeof(ddsd);
|
|
if (pdds->lpVtbl->GetSurfaceDesc(pdds, &ddsd) != DD_OK)
|
|
{
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pdds = NULL;
|
|
|
|
hdcDriver = GetCompatibleDevice(hdc, dwObjectType);
|
|
if (hdcDriver == NULL)
|
|
{
|
|
goto wglDescribePixelFormat_cleanup;
|
|
}
|
|
|
|
// NOTE: From this point on, all exit cases must cleanup hdcDriver
|
|
}
|
|
|
|
// Get the number of hardware supported formats.
|
|
|
|
wglNumHardwareFormats(hdcDriver, dwObjectType, &ipfdMcdMax, &ipfdDevMax);
|
|
|
|
iRet = InternalDescribePixelFormat(hdc, hdcDriver, ipfd, cjpfd, ppfd,
|
|
ipfdDevMax, ipfdMcdMax,
|
|
pdds, &ddsd);
|
|
|
|
wglDescribePixelFormat_cleanup:
|
|
|
|
if (pdds != NULL)
|
|
{
|
|
pdds->lpVtbl->Release(pdds);
|
|
}
|
|
else if (hdcDriver != hdc)
|
|
{
|
|
ReleaseDC((HWND) NULL, hdcDriver);
|
|
}
|
|
|
|
return iRet;
|
|
}
|
|
|
|
#ifdef _MCD_
|
|
/******************************Public*Routine******************************\
|
|
* GenMcdGenericCompatibleFormat
|
|
*
|
|
* Determines if pixelformat in gengc can be supported by generic code.
|
|
*
|
|
* Note:
|
|
* The implication of not being compatible is that generic cannot be
|
|
* used for driver kickbacks and MCD contexts cannot be converted.
|
|
*
|
|
* Returns:
|
|
* TRUE if compatible, FALSE otherwise.
|
|
*
|
|
* History:
|
|
* 04-Jun-1996 -by- Gilman Wong [gilmanw]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
BOOL FASTCALL GenMcdGenericCompatibleFormat(__GLGENcontext *gengc)
|
|
{
|
|
PIXELFORMATDESCRIPTOR *ppfd;
|
|
|
|
// Software-only formats are definitely supported.
|
|
|
|
ppfd = &gengc->gsurf.pfd;
|
|
if ((ppfd->dwFlags & (PFD_GENERIC_FORMAT|PFD_GENERIC_ACCELERATED))
|
|
== PFD_GENERIC_FORMAT)
|
|
return TRUE;
|
|
|
|
// Layer planes are not supported.
|
|
|
|
if (gengc->iLayerPlane)
|
|
return FALSE;
|
|
|
|
// Generic is PFD_SWAP_COPY only. There can't be many apps that rely
|
|
// on PFD_SWAP_EXCHANGE behavior (usually they look for PFD_SWAP_COPY
|
|
// so the back buffer can be used as backing store), but for now I think
|
|
// we should be conservative.
|
|
//
|
|
// Note: most MGA cards will set PFD_SWAP_COPY or neither (i.e., either
|
|
// style might be used depending on window size).
|
|
|
|
if (ppfd->dwFlags & PFD_SWAP_EXCHANGE)
|
|
return FALSE;
|
|
|
|
// Can only support 8bpp stencils.
|
|
|
|
if ((ppfd->cStencilBits != 0) && (ppfd->cStencilBits != 8))
|
|
return FALSE;
|
|
|
|
// Passed all the checks, we're compatible.
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
/******************************Public*Routine******************************\
|
|
* wglSwapBuffers
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL WINAPI wglSwapBuffers(HDC hdc)
|
|
{
|
|
int ipfd;
|
|
BOOL bRet = FALSE;
|
|
GLGENwindow *pwnd;
|
|
GLWINDOWID gwid;
|
|
|
|
// Validate the DC.
|
|
|
|
if (IsDirectDrawDevice(hdc))
|
|
{
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return FALSE;
|
|
}
|
|
|
|
switch ( wglObjectType(hdc) )
|
|
{
|
|
case OBJ_DC:
|
|
break;
|
|
case OBJ_MEMDC:
|
|
return(TRUE); // early out -- nothing to do if memory DC
|
|
default:
|
|
WARNING("wglSwapBuffers(): invalid hdc\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Validate pixel format.
|
|
|
|
WindowIdFromHdc(hdc, &gwid);
|
|
pwnd = pwndGetFromID(&gwid);
|
|
if ( pwnd )
|
|
{
|
|
if (pwnd->ipfd > 0)
|
|
{
|
|
// Dispatch to driver or generic. Which one can be determined by
|
|
// the pixel format.
|
|
|
|
if ( pwnd->ipfd <= pwnd->ipfdDevMax )
|
|
{
|
|
// Some ICDs do not need glFinish synchronization so
|
|
// we don't do it here. __DrvSwapBuffers will call
|
|
// it if necessary.
|
|
bRet = __DrvSwapBuffers(hdc, TRUE);
|
|
}
|
|
else
|
|
{
|
|
// Finish OpenGL calls in this thread before doing the swap.
|
|
// We use glFinish instead of glFlush to ensure that all
|
|
// OpenGL operations are completed.
|
|
glFinish();
|
|
|
|
ENTER_WINCRIT(pwnd);
|
|
|
|
// Can't rely on the pwnd's HDC because it may have
|
|
// been released since SetPixelFormat. Always use
|
|
// the DC passed in as the target.
|
|
bRet = glsrvSwapBuffers(hdc, pwnd);
|
|
|
|
LEAVE_WINCRIT(pwnd);
|
|
}
|
|
}
|
|
|
|
pwndRelease(pwnd);
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
|
}
|
|
|
|
return bRet;
|
|
}
|