/* * (c) Copyright 1993, Silicon Graphics, Inc. * ALL RIGHTS RESERVED * Permission to use, copy, modify, and distribute this software for * any purpose and without fee is hereby granted, provided that the above * copyright notice appear in all copies and that both the copyright notice * and this permission notice appear in supporting documentation, and that * the name of Silicon Graphics, Inc. not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. * * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. * * US Government Users Restricted Rights * Use, duplication, or disclosure by the Government is subject to * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph * (c)(1)(ii) of the Rights in Technical Data and Computer Software * clause at DFARS 252.227-7013 and/or in similar or successor * clauses in the FAR or the DOD or NASA FAR Supplement. * Unpublished-- rights reserved under the copyright laws of the * United States. Contractor/manufacturer is Silicon Graphics, * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. * * OpenGL(TM) is a trademark of Silicon Graphics, Inc. */ #include #include #include #include #include #include "ctk.h" //#define static #if defined(__cplusplus) || defined(c_plusplus) #define class c_class #endif #if DBG #define TKASSERT(x) \ if ( !(x) ) { \ PrintMessage("%s(%d) Assertion failed %s\n", \ __FILE__, __LINE__, #x); \ } #else #define TKASSERT(x) #endif /* DBG */ /********************************************************************/ static long NoOpExecFunc( TK_EventRec *pEvent ); static long (*ExecFunc)(TK_EventRec *pEvent ) = NoOpExecFunc; static TK_EventRec tkEvent = { TK_EVENT_EXPOSE, { 0, 0, 0, 0 } }; static HWND tkhwnd = NULL; static HDC tkhdc = NULL; static HDC tkhmemdc = NULL; static HGLRC tkhrc = NULL; static HPALETTE tkhPalette = NULL; static char *lpszClassName = "ctkLibWClass"; static long tkWndProc(HWND hWnd, UINT message, DWORD wParam, LONG lParam); static VOID StorePixelFormatsIDs( TK_VisualIDsRec *VisualID ); static void PrintMessage( const char *Format, ... ); static HGLRC CreateAndMakeContextCurrent( HDC Dc ); static void CleanUp( void ); static void DestroyThisWindow( HWND Window ); static short FindPixelFormat( HDC Dc, long FormatType ); static short GetPixelFormatInformation( HDC Dc, TK_WindowRec *tkWr, PIXELFORMATDESCRIPTOR *Pfd ); static TK_WindowRec *PIXELFORMATDESCRIPTOR_To_TK_WindowRec ( TK_WindowRec *WindowRec, PIXELFORMATDESCRIPTOR *Pfd ); HDC CreatePixelMapDC(HDC,TK_WindowRec *,UINT, int, LPPIXELFORMATDESCRIPTOR); BOOL DeletePixelMapDC(HDC); // Fixed palette support. #define BLACK PALETTERGB(0,0,0) #define WHITE PALETTERGB(255,255,255) #define NUM_STATIC_COLORS (COLOR_BTNHIGHLIGHT - COLOR_SCROLLBAR + 1) // TRUE if app wants to take over palette static BOOL tkUseStaticColors = FALSE; // TRUE if static system color settings have been replaced with B&W settings. static BOOL tkSystemColorsInUse = FALSE; // TRUE if static colors have been saved static BOOL tkStaticSaved = FALSE; // saved system static colors static COLORREF gacrSave[NUM_STATIC_COLORS]; // new B&W system static colors static COLORREF gacrBlackAndWhite[NUM_STATIC_COLORS] = { WHITE, // COLOR_SCROLLBAR BLACK, // COLOR_BACKGROUND BLACK, // COLOR_ACTIVECAPTION WHITE, // COLOR_INACTIVECAPTION WHITE, // COLOR_MENU WHITE, // COLOR_WINDOW BLACK, // COLOR_WINDOWFRAME BLACK, // COLOR_MENUTEXT BLACK, // COLOR_WINDOWTEXT WHITE, // COLOR_CAPTIONTEXT WHITE, // COLOR_ACTIVEBORDER WHITE, // COLOR_INACTIVEBORDER WHITE, // COLOR_APPWORKSPACE BLACK, // COLOR_HIGHLIGHT WHITE, // COLOR_HIGHLIGHTTEXT WHITE, // COLOR_BTNFACE BLACK, // COLOR_BTNSHADOW BLACK, // COLOR_GRAYTEXT BLACK, // COLOR_BTNTEXT BLACK, // COLOR_INACTIVECAPTIONTEXT BLACK // COLOR_BTNHIGHLIGHT }; static INT gaiStaticIndex[NUM_STATIC_COLORS] = { COLOR_SCROLLBAR , COLOR_BACKGROUND , COLOR_ACTIVECAPTION , COLOR_INACTIVECAPTION , COLOR_MENU , COLOR_WINDOW , COLOR_WINDOWFRAME , COLOR_MENUTEXT , COLOR_WINDOWTEXT , COLOR_CAPTIONTEXT , COLOR_ACTIVEBORDER , COLOR_INACTIVEBORDER , COLOR_APPWORKSPACE , COLOR_HIGHLIGHT , COLOR_HIGHLIGHTTEXT , COLOR_BTNFACE , COLOR_BTNSHADOW , COLOR_GRAYTEXT , COLOR_BTNTEXT , COLOR_INACTIVECAPTIONTEXT, COLOR_BTNHIGHLIGHT }; static VOID SaveStaticEntries(HDC); static VOID UseStaticEntries(HDC); static VOID RestoreStaticEntries(HDC); /********************************************************************/ void tkCloseWindow(void) { DestroyThisWindow(tkhwnd); } /********************************************************************/ long tkWndProc(HWND hWnd, UINT message, DWORD wParam, LONG lParam) { PAINTSTRUCT Paint; switch (message) { case WM_PAINT: BeginPaint( hWnd, &Paint ); if (!(*ExecFunc)(&tkEvent)) { tkCloseWindow(); } EndPaint( hWnd, &Paint ); break; case WM_GETMINMAXINFO: { LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam; lpmmi->ptMinTrackSize.x = 1; lpmmi->ptMinTrackSize.y = 1; } return 0; case WM_DESTROY: CleanUp(); PostQuitMessage(TRUE); return(DefWindowProc( hWnd, message, wParam, lParam)); } return(DefWindowProc( hWnd, message, wParam, lParam)); } void tkExec( long (*Func)(TK_EventRec *pEvent) ) { MSG Message; // WM_SIZE gets delivered before we get here! if ( NULL != Func ) { ExecFunc = Func; /* save a pointer to the drawing function */ } else { ExecFunc = NoOpExecFunc; } while (GL_TRUE) { if (GetMessage(&Message, NULL, 0, 0) ) { TranslateMessage(&Message); DispatchMessage(&Message); } else { break; } } } static long NoOpExecFunc( TK_EventRec *pEvent ) { return(1); } /********************************************************************/ // Default palette entry flags #define PALETTE_FLAGS PC_NOCOLLAPSE // Gamma correction factor * 10 #define GAMMA_CORRECTION 10 // Maximum color distance with 8-bit components #define MAX_COL_DIST (3*256*256L) // Number of static colors #define STATIC_COLORS 20 // Flags used when matching colors #define EXACT_MATCH 1 #define COLOR_USED 1 // Conversion tables for n bits to eight bits #if GAMMA_CORRECTION == 10 // These tables are corrected for a gamma of 1.0 static unsigned char abThreeToEight[8] = { 0, 0111 >> 1, 0222 >> 1, 0333 >> 1, 0444 >> 1, 0555 >> 1, 0666 >> 1, 0377 }; static unsigned char abTwoToEight[4] = { 0, 0x55, 0xaa, 0xff }; static unsigned char abOneToEight[2] = { 0, 255 }; #else // These tables are corrected for a gamma of 1.4 static unsigned char abThreeToEight[8] = { 0, 63, 104, 139, 171, 200, 229, 255 }; static unsigned char abTwoToEight[4] = { 0, 116, 191, 255 }; static unsigned char abOneToEight[2] = { 0, 255 }; #endif // Table which indicates which colors in a 3-3-2 palette should be // replaced with the system default colors #if GAMMA_CORRECTION == 10 static int aiDefaultOverride[STATIC_COLORS] = { 0, 4, 32, 36, 128, 132, 160, 173, 181, 245, 247, 164, 156, 7, 56, 63, 192, 199, 248, 255 }; #else static int aiDefaultOverride[STATIC_COLORS] = { 0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91, 7, 56, 63, 192, 199, 248, 255 }; #endif static unsigned char ComponentFromIndex(int i, int nbits, int shift) { unsigned char val; TKASSERT(nbits >= 1 && nbits <= 3); val = i >> shift; switch (nbits) { case 1: return abOneToEight[val & 1]; case 2: return abTwoToEight[val & 3]; case 3: return abThreeToEight[val & 7]; } } // System default colors static PALETTEENTRY apeDefaultPalEntry[STATIC_COLORS] = { { 0, 0, 0, 0 }, { 0x80,0, 0, 0 }, { 0, 0x80,0, 0 }, { 0x80,0x80,0, 0 }, { 0, 0, 0x80, 0 }, { 0x80,0, 0x80, 0 }, { 0, 0x80,0x80, 0 }, { 0xC0,0xC0,0xC0, 0 }, { 192, 220, 192, 0 }, { 166, 202, 240, 0 }, { 255, 251, 240, 0 }, { 160, 160, 164, 0 }, { 0x80,0x80,0x80, 0 }, { 0xFF,0, 0, 0 }, { 0, 0xFF,0, 0 }, { 0xFF,0xFF,0, 0 }, { 0, 0, 0xFF, 0 }, { 0xFF,0, 0xFF, 0 }, { 0, 0xFF,0xFF, 0 }, { 0xFF,0xFF,0xFF, 0 } }; /******************************Public*Routine******************************\ * * UpdateStaticMapping * * Computes the best match between the current system static colors * and a 3-3-2 palette * * History: * Tue Aug 01 18:18:12 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ static void UpdateStaticMapping(PALETTEENTRY *pe332Palette) { HPALETTE hpalStock; int iStatic, i332; int iMinDist, iDist; int iDelta; int iMinEntry; PALETTEENTRY *peStatic, *pe332; hpalStock = GetStockObject(DEFAULT_PALETTE); // The system should always have one of these TKASSERT(hpalStock != NULL); // Make sure there's the correct number of entries TKASSERT(GetPaletteEntries(hpalStock, 0, 0, NULL) == STATIC_COLORS); // Get the current static colors GetPaletteEntries(hpalStock, 0, STATIC_COLORS, apeDefaultPalEntry); // Zero the flags in the static colors because they are used later peStatic = apeDefaultPalEntry; for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++) { peStatic->peFlags = 0; peStatic++; } // Zero the flags in the incoming palette because they are used later pe332 = pe332Palette; for (i332 = 0; i332 < 256; i332++) { pe332->peFlags = 0; pe332++; } // Try to match each static color exactly // This saves time by avoiding the least-squares match for each // exact match peStatic = apeDefaultPalEntry; for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++) { pe332 = pe332Palette; for (i332 = 0; i332 < 256; i332++) { if (peStatic->peRed == pe332->peRed && peStatic->peGreen == pe332->peGreen && peStatic->peBlue == pe332->peBlue) { TKASSERT(pe332->peFlags != COLOR_USED); peStatic->peFlags = EXACT_MATCH; pe332->peFlags = COLOR_USED; aiDefaultOverride[iStatic] = i332; break; } pe332++; } peStatic++; } // Match each static color as closely as possible to an entry // in the 332 palette by minimized the square of the distance peStatic = apeDefaultPalEntry; for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++) { // Skip colors already matched exactly if (peStatic->peFlags == EXACT_MATCH) { peStatic++; continue; } iMinDist = MAX_COL_DIST+1; #if DBG iMinEntry = -1; #endif pe332 = pe332Palette; for (i332 = 0; i332 < 256; i332++) { // Skip colors already used if (pe332->peFlags == COLOR_USED) { pe332++; continue; } // Compute Euclidean distance squared iDelta = pe332->peRed-peStatic->peRed; iDist = iDelta*iDelta; iDelta = pe332->peGreen-peStatic->peGreen; iDist += iDelta*iDelta; iDelta = pe332->peBlue-peStatic->peBlue; iDist += iDelta*iDelta; if (iDist < iMinDist) { iMinDist = iDist; iMinEntry = i332; } pe332++; } TKASSERT(iMinEntry != -1); // Remember the best match aiDefaultOverride[iStatic] = iMinEntry; pe332Palette[iMinEntry].peFlags = COLOR_USED; peStatic++; } // Zero the flags in the static colors because they may have been // set. We want them to be zero so the colors can be remapped peStatic = apeDefaultPalEntry; for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++) { peStatic->peFlags = 0; peStatic++; } // Reset the 332 flags because we may have set them pe332 = pe332Palette; for (i332 = 0; i332 < 256; i332++) { pe332->peFlags = PALETTE_FLAGS; pe332++; } #if 0 for (iStatic = 0; iStatic < STATIC_COLORS; iStatic++) { PrintMessage("Static color %2d maps to %d\n", iStatic, aiDefaultOverride[iStatic]); } #endif } #define SwapPalE(i,j) { \ PALETTEENTRY palE; \ palE = pPal->palPalEntry[i]; \ pPal->palPalEntry[i] = pPal->palPalEntry[j]; \ pPal->palPalEntry[j] = palE; } /******************************Public*Routine******************************\ * SaveStaticEntries * * Save the current static system color settings. This should be called * prior to UseStaticEntries() to initialize gacrSave. Once gacrSave is * called, RestoreStaticEntries() can be called to restore the static system * color settings. * * The colors can be saved only if the tk palette is the background palette. * This check is done so that we do not accidentally replace the saved * settings with the B&W settings used when static system color usage is set * and the fixed 332 rgb palette is realized in the foreground. * * History: * 26-Apr-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ static VOID SaveStaticEntries(HDC hdc) { int i; if ( !tkSystemColorsInUse ) { for (i = COLOR_SCROLLBAR; i <= COLOR_BTNHIGHLIGHT; i++) gacrSave[i - COLOR_SCROLLBAR] = GetSysColor(i); tkStaticSaved = TRUE; } } /******************************Public*Routine******************************\ * UseStaticEntries * * Replace the static system color settings with black and white color * settings. This is used when taking over the system static colors to * realize a 332 rgb fixed palette. Realizing such a palette in the * foreground screws up the system colors (menus, titles, scrollbars, etc.). * Setting the system colors to B&W, while not perfect (some elements of * the UI are DIBs and will not be effected by this--for example, the * system menu (or "coin slot") button), is somewhat better. * * Side effect: * WM_SYSCOLORCHANGE message is broadcast to all top-level windows to * inform them of the system palette change. * * History: * 26-Apr-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ static VOID UseStaticEntries(HDC hdc) { SetSysColors(NUM_STATIC_COLORS, gaiStaticIndex, gacrBlackAndWhite); tkSystemColorsInUse = TRUE; PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0); } /******************************Public*Routine******************************\ * RestoreStaticEntries * * Restores the static system colors to the settings that existed at the * time SaveStaticEntries was called. * * Side effect: * WM_SYSCOLORCHANGE message is broadcast to all top-level windows to * inform them of the system palette change. * * History: * 26-Apr-1994 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/ static VOID RestoreStaticEntries(HDC hdc) { // Must check to see that SaveStaticEntries was called at least once. // Otherwise, a bad tk app might mess up the system colors. if ( tkStaticSaved ) { SetSysColors(NUM_STATIC_COLORS, gaiStaticIndex, gacrSave); tkSystemColorsInUse = FALSE; PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0); } } /******************************Public*Routine******************************\ * FlushPalette * * Because of Win 3.1 compatibility, GDI palette mapping always starts * at zero and stops at the first exact match. So if there are duplicates, * the higher colors aren't mapped to--which is often a problem if we * are trying to make to any of the upper 10 static colors. To work around * this, we flush the palette to all black. * * This only needs to be done for the 8BPP (256 color) case. * \**************************************************************************/ static void FlushPalette(HDC hdc, int nColors) { LOGPALETTE *pPal; HPALETTE hpal, hpalOld; int i; if (nColors == 256) { pPal = (LOGPALETTE *) LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(LOGPALETTE) + nColors * sizeof(PALETTEENTRY)); if (pPal) { pPal->palVersion = 0x300; pPal->palNumEntries = nColors; // Mark everything PC_NOCOLLAPSE and PC_RESERVED to force every thing // into the palette. Colors are already black because we zero initialized // during memory allocation. for (i = 0; i < nColors; i++) { pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE | PC_RESERVED; } hpal = CreatePalette(pPal); LocalFree(pPal); hpalOld = SelectPalette(hdc, hpal, FALSE); RealizePalette(hdc); SelectPalette(hdc, hpalOld, FALSE); DeleteObject(hpal); } } } static void CreateRGBPalette(HDC hdc, PIXELFORMATDESCRIPTOR *ppfd ) { LOGPALETTE *pPal; int n, i; tkUseStaticColors = ppfd->dwFlags & PFD_NEED_SYSTEM_PALETTE; // PFD_NEED_PALETTE should not be set if PFD_TYPE_COLORINDEX mode. TKASSERT( (ppfd->iPixelType == PFD_TYPE_COLORINDEX) ? ((ppfd->dwFlags & PFD_NEED_PALETTE) == 0) : TRUE ); if (ppfd->dwFlags & PFD_NEED_PALETTE) { if (!tkhPalette) { n = 1 << ppfd->cColorBits; pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)); pPal->palVersion = 0x300; pPal->palNumEntries = n; for (i=0; ipalPalEntry[i].peRed = ComponentFromIndex(i, ppfd->cRedBits, ppfd->cRedShift); pPal->palPalEntry[i].peGreen = ComponentFromIndex(i, ppfd->cGreenBits, ppfd->cGreenShift); pPal->palPalEntry[i].peBlue = ComponentFromIndex(i, ppfd->cBlueBits, ppfd->cBlueShift); pPal->palPalEntry[i].peFlags = PALETTE_FLAGS; } if ( 256 == n ) { if ( tkUseStaticColors ) { // Black and white already exist as the only remaining static // colors. Let those remap. All others should be put into // the palette (i.e., peFlags == PC_NOCOLLAPSE). pPal->palPalEntry[0].peFlags = 0; pPal->palPalEntry[255].peFlags = 0; SaveStaticEntries(hdc); SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); } else { if ( (3 == ppfd->cRedBits) && (0 == ppfd->cRedShift) && (3 == ppfd->cGreenBits) && (3 == ppfd->cGreenShift) && (2 == ppfd->cBlueBits) && (6 == ppfd->cBlueShift) ) { UpdateStaticMapping(pPal->palPalEntry); for (i = 0; i < STATIC_COLORS; i++) { pPal->palPalEntry[aiDefaultOverride[i]] = apeDefaultPalEntry[i]; } } } } tkhPalette = CreatePalette(pPal); LocalFree(pPal); } FlushPalette(hdc, n); SelectPalette(hdc, tkhPalette, FALSE); n = RealizePalette(hdc); if ( tkUseStaticColors ) UseStaticEntries(hdc); } // set up logical indices for CI mode else if( ppfd->iPixelType == PFD_TYPE_COLORINDEX ) { if (!tkhPalette) { if (ppfd->cColorBits == 4) { // for 4-bit, create a logical palette with 16 entries n = 16; pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)); pPal->palVersion = 0x300; pPal->palNumEntries = n; for( i = 0; i < 8; i ++) { pPal->palPalEntry[i] = apeDefaultPalEntry[i]; } for (i = 8; i < 16; i++) { pPal->palPalEntry[i] = apeDefaultPalEntry[i+4]; } // conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so // we rearrange the table for now. SwapPalE(1,9) SwapPalE(2,10) SwapPalE(3,12) } else if (ppfd->cColorBits == 8) { // for 8-bit, create a logical palette with 256 entries, making // sure that the 20 system colors exist in the palette n = 256; pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)); pPal->palVersion = 0x300; pPal->palNumEntries = n; tkhPalette = GetStockObject (DEFAULT_PALETTE); // start by copying default palette into new one GetPaletteEntries( tkhPalette, 0, 20, pPal->palPalEntry); // conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so // we rearrange the table for now. SwapPalE(1,13) SwapPalE(2,14) SwapPalE(3,16) for( i = 20; i < n; i ++) { pPal->palPalEntry[i].peRed = (BYTE) (i - 1); pPal->palPalEntry[i].peGreen = (BYTE) (i - 2); pPal->palPalEntry[i].peBlue = (BYTE) (i - 3); pPal->palPalEntry[i].peFlags = (BYTE) 0; } // If we are taking possession of the system colors, // must guarantee that 0 and 255 are black and white // (respectively), so that they can remap to the // remaining two static colors. All other entries must // be marked as PC_NOCOLLAPSE. if ( tkUseStaticColors ) { pPal->palPalEntry[0].peRed = pPal->palPalEntry[0].peGreen = pPal->palPalEntry[0].peBlue = 0x00; pPal->palPalEntry[255].peRed = pPal->palPalEntry[255].peGreen = pPal->palPalEntry[255].peBlue = 0xFF; pPal->palPalEntry[0].peFlags = pPal->palPalEntry[255].peFlags = 0; for ( i = 1 ; i < 255 ; i++ ) { pPal->palPalEntry[i].peFlags = PC_NOCOLLAPSE; // This is a workaround for a GDI palette "feature". If // any of the static colors are repeated in the palette, // those colors will map to the first occurance. So, for // our case where there are only two static colors (black // and white), if a white color appears anywhere in the // palette other than in the last entry, the static white // will remap to the first white. This destroys the nice // one-to-one mapping we are trying to achieve. // // There are two ways to workaround this. The first is to // simply not allow a pure white anywhere but in the last // entry. Such requests are replaced with an attenuated // white of (0xFE, 0xFE, 0xFE). // // The other way is to mark these extra whites with // PC_RESERVED which will cause GDI to skip these entries // when mapping colors. This way the app gets the actual // colors requested, but can have side effects on other // apps. if ( pPal->palPalEntry[i].peRed == 0xFF && pPal->palPalEntry[i].peGreen == 0xFF && pPal->palPalEntry[i].peBlue == 0xFF ) { pPal->palPalEntry[i].peFlags |= PC_RESERVED; } } SaveStaticEntries(hdc); SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); } } else { // for pixel formats > 8 bits deep, create a logical palette with // 4096 entries n = 4096; pPal = (PLOGPALETTE)LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) + n * sizeof(PALETTEENTRY)); pPal->palVersion = 0x300; pPal->palNumEntries = n; for( i = 0; i < n; i ++) { pPal->palPalEntry[i].peRed = (BYTE) ((i & 0x000f) << 4); pPal->palPalEntry[i].peGreen = (BYTE) (i & 0x00f0); pPal->palPalEntry[i].peBlue = (BYTE) ((i & 0x0f00) >> 4); pPal->palPalEntry[i].peFlags = (BYTE) 0; } // conform expects indices 0..3 to be BLACK,RED,GREEN,BLUE, so // we rearrange the table for now. SwapPalE(1,0xf) SwapPalE(2,0xf0) SwapPalE(3,0xf00) } tkhPalette = CreatePalette(pPal); LocalFree(pPal); } FlushPalette(hdc, n); TKASSERT(tkhPalette != NULL); SelectPalette(hdc, tkhPalette, FALSE); n = RealizePalette(hdc); if ( tkUseStaticColors ) UseStaticEntries(hdc); } } void ShowPixelFormat(HDC hdc) { PIXELFORMATDESCRIPTOR pfd, *ppfd; int format; ppfd = &pfd; format = GetPixelFormat(hdc); DescribePixelFormat(hdc, format, sizeof(PIXELFORMATDESCRIPTOR), ppfd); printf("Pixel format %d\n", format); printf(" dwFlags - 0x%x", ppfd->dwFlags); if (ppfd->dwFlags & PFD_DOUBLEBUFFER) printf("PFD_DOUBLEBUFFER "); if (ppfd->dwFlags & PFD_STEREO) printf("PFD_STEREO "); if (ppfd->dwFlags & PFD_DRAW_TO_WINDOW) printf("PFD_DRAW_TO_WINDOW "); if (ppfd->dwFlags & PFD_DRAW_TO_BITMAP) printf("PFD_DRAW_TO_BITMAP "); if (ppfd->dwFlags & PFD_SUPPORT_GDI) printf("PFD_SUPPORT_GDI "); if (ppfd->dwFlags & PFD_SUPPORT_OPENGL) printf("PFD_SUPPORT_OPENGL "); if (ppfd->dwFlags & PFD_GENERIC_FORMAT) printf("PFD_GENERIC_FORMAT "); if (ppfd->dwFlags & PFD_NEED_PALETTE) printf("PFD_NEED_PALETTE "); if (ppfd->dwFlags & PFD_NEED_SYSTEM_PALETTE) printf("PFD_NEED_SYSTEM_PALETTE "); printf("\n"); printf(" iPixelType - %d", ppfd->iPixelType); if (ppfd->iPixelType == PFD_TYPE_RGBA) printf("PGD_TYPE_RGBA\n"); if (ppfd->iPixelType == PFD_TYPE_COLORINDEX) printf("PGD_TYPE_COLORINDEX\n"); printf(" cColorBits - %d\n", ppfd->cColorBits); printf(" cRedBits - %d\n", ppfd->cRedBits); printf(" cRedShift - %d\n", ppfd->cRedShift); printf(" cGreenBits - %d\n", ppfd->cGreenBits); printf(" cGreenShift - %d\n", ppfd->cGreenShift); printf(" cBlueBits - %d\n", ppfd->cBlueBits); printf(" cBlueShift - %d\n", ppfd->cBlueShift); printf(" cAlphaBits - %d\n", ppfd->cAlphaBits); printf(" cAlphaShift - 0x%x\n", ppfd->cAlphaShift); printf(" cAccumBits - %d\n", ppfd->cAccumBits); printf(" cAccumRedBits - %d\n", ppfd->cAccumRedBits); printf(" cAccumGreenBits - %d\n", ppfd->cAccumGreenBits); printf(" cAccumBlueBits - %d\n", ppfd->cAccumBlueBits); printf(" cAccumAlphaBits - %d\n", ppfd->cAccumAlphaBits); printf(" cDepthBits - %d\n", ppfd->cDepthBits); printf(" cStencilBits - %d\n", ppfd->cStencilBits); printf(" cAuxBuffers - %d\n", ppfd->cAuxBuffers); printf(" iLayerType - %d\n", ppfd->iLayerType); printf(" bReserved - %d\n", ppfd->bReserved); printf(" dwLayerMask - 0x%x\n", ppfd->dwLayerMask); printf(" dwVisibleMask - 0x%x\n", ppfd->dwVisibleMask); printf(" dwDamageMask - 0x%x\n", ppfd->dwDamageMask); } /* * This function returns the pixel format index chosen * by choose pixel format. */ static short FindPixelFormat( HDC Dc, long FormatType ) { PIXELFORMATDESCRIPTOR Pfd; short PfdIndex; Pfd.nSize = sizeof(Pfd); Pfd.nVersion = 1; Pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; Pfd.dwLayerMask = PFD_MAIN_PLANE; if (TK_WIND_IS_DB(FormatType)) { Pfd.dwFlags |= PFD_DOUBLEBUFFER; } if (TK_WIND_IS_CI(FormatType)) { Pfd.iPixelType = PFD_TYPE_COLORINDEX; Pfd.cColorBits = 8; } if (TK_WIND_IS_RGB(FormatType)) { Pfd.iPixelType = PFD_TYPE_RGBA; Pfd.cColorBits = 24; } if (TK_WIND_ACCUM & FormatType) { Pfd.cAccumBits = Pfd.cColorBits; } else { Pfd.cAccumBits = 0; } if (TK_WIND_Z & FormatType) { Pfd.cDepthBits = 32; } else if (TK_WIND_Z16 & FormatType) { Pfd.cDepthBits = 16; } else { Pfd.cDepthBits = 0; } if (TK_WIND_STENCIL & FormatType) { Pfd.cStencilBits = 8; } else { Pfd.cStencilBits = 0; } PfdIndex = ChoosePixelFormat( Dc, &Pfd ); return( PfdIndex ); } // Initialize a window, create a rendering context for that window // only allow CI on palette devices, RGB on true color devices // current server turns on Z, but no accum or stencil // When SetPixelFormat is implemented, remove all of these restrictions long tkNewWindow(TK_WindowRec *tkWr) { WNDCLASS wndclass; RECT WinRect; HANDLE hInstance; PIXELFORMATDESCRIPTOR Pfd; short PfdIndex; int nPixelFormats; BOOL Result = FALSE; HDC tmphdc = NULL; TKASSERT(NULL==tkhwnd ); TKASSERT(NULL==tkhdc ); TKASSERT(NULL==tkhrc ); TKASSERT(NULL==tkhPalette ); TKASSERT(ExecFunc==NoOpExecFunc ); hInstance = GetModuleHandle(NULL); wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wndclass.lpfnWndProc = (WNDPROC)tkWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = lpszClassName; RegisterClass(&wndclass); // Make window large enough to hold a client area as large as tkWr WinRect.left = (tkWr->x == CW_USEDEFAULT) ? 0 : tkWr->x; WinRect.top = (tkWr->y == CW_USEDEFAULT) ? 0 : tkWr->y; WinRect.right = WinRect.left + tkWr->width; WinRect.bottom = WinRect.top + tkWr->height; AdjustWindowRect(&WinRect, WS_OVERLAPPEDWINDOW, FALSE); tkhwnd = CreateWindowEx( WS_EX_TOPMOST, lpszClassName, tkWr->name, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, (tkWr->x == CW_USEDEFAULT ? CW_USEDEFAULT : WinRect.left), (tkWr->y == CW_USEDEFAULT ? CW_USEDEFAULT : WinRect.top), WinRect.right - WinRect.left, WinRect.bottom - WinRect.top, NULL, NULL, hInstance, NULL); /* * Fixup window size in case minimum tracking size did something. */ GetClientRect(tkhwnd, &WinRect); tkWr->width = WinRect.right; tkWr->height = WinRect.bottom; if ( NULL != tkhwnd ) { tkhdc = GetDC(tkhwnd); if (tkWr->type == TK_WIND_VISUAL) { nPixelFormats = DescribePixelFormat(tkhdc,abs(tkWr->info),sizeof(PIXELFORMATDESCRIPTOR),&Pfd); // If tkWr->info is negative, this is a bitmap request // Otherwise, it is a display request if (tkWr->info < 0) { tkWr->info = -(tkWr->info); if (!(Pfd.dwFlags & PFD_DRAW_TO_BITMAP)) goto tkNewWindow_exit; tkhmemdc = CreatePixelMapDC(tkhdc, tkWr, DIB_RGB_COLORS, Pfd.cColorBits, &Pfd); tmphdc = tkhmemdc; } else { if (!(Pfd.dwFlags & PFD_DRAW_TO_WINDOW)) goto tkNewWindow_exit; tmphdc = tkhdc; } } else tmphdc = tkhdc; /* * XXXX * I would like to delay the show window a little longer * but this causes an exception, during clears. New code * will fix this. */ ShowWindow(tkhwnd, SW_SHOWDEFAULT); PfdIndex = GetPixelFormatInformation( tmphdc, tkWr, &Pfd ); if ( PfdIndex ) { if ( SetPixelFormat( tmphdc, PfdIndex, &Pfd ) ) { /* * Would be nice to delay until then, alas, we have a bug */ ShowPixelFormat(tmphdc); /* * If the tmp DC is a memory DC, create and * realize the palette for the screen DC first. * Memory DC palettes are realized as background * palettes, so we must put the palette in the * foreground via the screen DC before we muck * around with the memory DC. */ if (tmphdc != tkhdc) CreateRGBPalette( tkhdc, &Pfd ); CreateRGBPalette( tmphdc, &Pfd ); tkhrc = CreateAndMakeContextCurrent( tmphdc ); if ( NULL != tkhrc ) { ShowWindow(tkhwnd, SW_SHOWDEFAULT); /* * Convert information in the pixel format descriptor * to the TK_WindowRec format */ PIXELFORMATDESCRIPTOR_To_TK_WindowRec ( tkWr, &Pfd ); Result = TRUE; } } } } tkNewWindow_exit: if ( FALSE == Result ) { /* * Something Failed, Destroy this window */ DestroyThisWindow(tkhwnd); /* * Process all the messages */ tkExec( (long (*)(TK_EventRec *pEvent))NULL ); } return( Result ); } /* * If a function fails, this function will clean itself up */ static HGLRC CreateAndMakeContextCurrent( HDC Dc ) { HGLRC Rc = NULL; /* Create a Rendering Context */ Rc = wglCreateContext( Dc ); if ( NULL != Rc ) { /* Make it Current */ if ( FALSE == wglMakeCurrent( Dc, Rc ) ) { wglDeleteContext( Rc ); Rc = NULL; } } return( Rc ); } static void DestroyThisWindow( HWND Window ) { if ( NULL != Window ) { DestroyWindow( Window ); } } /* * This Should be called in response to a WM_DESTROY message */ static void CleanUp( void ) { if ( NULL != tkhwnd ) { if ( NULL != tkhdc ) { if ( NULL != tkhPalette ) { DeleteObject( SelectObject( tkhdc, GetStockObject(DEFAULT_PALETTE) )); if ( tkUseStaticColors ) { SetSystemPaletteUse( tkhdc, SYSPAL_STATIC ); RealizePalette( tkhdc ); RestoreStaticEntries( tkhdc ); } tkhPalette = NULL; } if ( NULL != tkhrc ) { wglMakeCurrent( tkhdc, NULL ); // No current context wglDeleteContext(tkhrc); // Delete this context tkhrc = NULL; } ReleaseDC( tkhwnd, tkhdc ); tkhdc = NULL; } tkhwnd = NULL; } ExecFunc = NoOpExecFunc; } /*******************************************************************/ void tkQuit(void) { TKASSERT(NULL==tkhwnd ); TKASSERT(NULL==tkhdc ); TKASSERT(NULL==tkhrc ); TKASSERT(NULL==tkhPalette ); ExitProcess(0); } /*******************************************************************/ void tkSwapBuffers(void) { SwapBuffers(tkhdc); } /*******************************************************************/ void tkGet(long item, void *data) { if (item == TK_SCREENIMAGE) { // XXXX We will need this the covglx and conformw OutputDebugString("tkGet(TK_SCREENIMAGE) is not implemented\n"); } else if (item == TK_VISUALIDS) { StorePixelFormatsIDs( data ); } } static VOID StorePixelFormatsIDs( TK_VisualIDsRec *VisualID ) { HDC hDc; int AvailableIds; int Id; PIXELFORMATDESCRIPTOR Pfd; /* * Get a DC for the display */ hDc = GetDC(NULL); /* * Get the total number of pixel formats */ AvailableIds = DescribePixelFormat( hDc, 0, 0, NULL ); /* * Store the IDs in the structure. * The first Id starts at one. */ VisualID->count = 0; for ( Id = 1 ; Id <= AvailableIds ; Id++ ) { /* * Make sure you don't overrun the structure's buffer */ if ( Id <= ((sizeof(((TK_VisualIDsRec *)NULL)->IDs) / sizeof(((TK_VisualIDsRec *)NULL)->IDs[0]))) ) { if ( DescribePixelFormat( hDc, Id, sizeof(Pfd), &Pfd ) ) { /* * Make sure the pixel format index supports OpenGL */ if ( PFD_SUPPORT_OPENGL & Pfd.dwFlags ) { VisualID->IDs[VisualID->count++] = Id; } } } else break; } /* * Don't need the DC anymore */ ReleaseDC( NULL, hDc ); } static void PrintMessage( const char *Format, ... ) { va_list ArgList; char Buffer[256]; va_start(ArgList, Format); vsprintf(Buffer, Format, ArgList); va_end(ArgList); fprintf( stderr, "libctk: %s", Buffer ); fflush(stdout); } /********************************************************************/ /* * This function returns the selected pixel format index and * the pixel format descriptor. */ static short GetPixelFormatInformation( HDC Dc, TK_WindowRec *tkWr, PIXELFORMATDESCRIPTOR *Pfd ) { short PfdIndex = 0; // Assume no pixel format matches /* * TK_WIND_REQUEST indicates that tkWr->info is a mask * describing the type of pixel format requested. */ if ( TK_WIND_REQUEST == tkWr->type ) { PfdIndex = FindPixelFormat( Dc, tkWr->info ); } else { /* * Otherwise, tkWr->info contains the pixel format Id. */ PfdIndex = (short)tkWr->info; } if ( DescribePixelFormat( Dc, PfdIndex, sizeof(*Pfd), Pfd) ) { if ( !(PFD_SUPPORT_OPENGL & Pfd->dwFlags) ) { PfdIndex = 0; // Does not support OpenGL, make it fail } } return( PfdIndex ); } /********************************************************************\ | CREATE PIXEL-MAP DC | | hWnd : WindowDC created via GetDC() | nFormat: must be in the range 21 - 40 | uUsage : DIB_RGB_COLORS (do this one) | DIB_PAL_COLORS | \********************************************************************/ HDC CreatePixelMapDC(HDC hDC, TK_WindowRec *tkWr, UINT uUsage, int nBpp, LPPIXELFORMATDESCRIPTOR lpPfd) { HDC hMemDC; HBITMAP hBitmap,hSave; int nWidth,nHeight,nColorTable,idx,nEntries; DWORD dwSize,dwBits,dwCompression; HANDLE hDib; PVOID pvBits; LPSTR lpDib,lpCT; DWORD dwRMask,dwBMask,dwGMask; static COLORREF cr16Color[] = {0x00000000, 0x00000080, 0x00008000, 0x00008080, 0x00800000, 0x00800080, 0x00808000, 0x00808080, 0x00C0C0C0, 0x000000FF, 0x0000FF00, 0x0000FFFF, 0x00FF0000, 0x00FF00FF, 0x00FFFF00, 0x00FFFFFF}; if(hMemDC = CreateCompatibleDC(hDC)) { // Get device information for the surface // nWidth = tkWr->width; nHeight = tkWr->height; #define USE_DFB 1 #if USE_DFB // Use compatible bitmap (DFB if supported) if DC color // depth matches requested color depth. Otherwise, use DIB. if ( nBpp == (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES)) ) { if(hBitmap = CreateCompatibleBitmap(hDC,nWidth,nHeight)) { if(hSave = SelectObject(hMemDC,hBitmap)) { return(hMemDC); } DeleteObject(hBitmap); } } else { #endif if(nBpp) { // Get the colortable size. // switch(nBpp) { case 32: case 16: nColorTable = 3 * sizeof(DWORD); dwCompression = BI_BITFIELDS; break; case 24: nColorTable = 0; dwCompression = BI_RGB; break; default: nColorTable = ((UINT)1 << nBpp) * sizeof(RGBQUAD); dwCompression = BI_RGB; if(uUsage == DIB_PAL_COLORS) nColorTable >>= 1; break; } // Calculate necessary size for dib. // dwBits = (DWORD)(((nWidth * nBpp) + 31) / 32) * nHeight * sizeof(DWORD); dwSize = (DWORD)dwBits + sizeof(BITMAPINFOHEADER) + nColorTable; // Create the bitmap based upon the DIB specification. // if(hDib = GlobalAlloc(GHND,dwSize)) { if(lpDib = GlobalLock(hDib)) { // Initialize DIB specification. // ((LPBITMAPINFOHEADER)lpDib)->biSize = sizeof(BITMAPINFOHEADER); ((LPBITMAPINFOHEADER)lpDib)->biWidth = nWidth; ((LPBITMAPINFOHEADER)lpDib)->biHeight = nHeight; ((LPBITMAPINFOHEADER)lpDib)->biPlanes = 1; ((LPBITMAPINFOHEADER)lpDib)->biBitCount = (UINT)nBpp; ((LPBITMAPINFOHEADER)lpDib)->biCompression = dwCompression; ((LPBITMAPINFOHEADER)lpDib)->biSizeImage = 0; ((LPBITMAPINFOHEADER)lpDib)->biXPelsPerMeter = 0; ((LPBITMAPINFOHEADER)lpDib)->biYPelsPerMeter = 0; ((LPBITMAPINFOHEADER)lpDib)->biClrUsed = 0; ((LPBITMAPINFOHEADER)lpDib)->biClrImportant = 0; // Fill in colortable for appropriate bitmap-format. // lpCT = (LPSTR)((LPBITMAPINFO)lpDib)->bmiColors; switch(nBpp) { case 32: case 16: // This creates the rough mask of bits for the // number of color-bits. // dwRMask = (((DWORD)1 << lpPfd->cRedBits ) - 1); dwGMask = (((DWORD)1 << lpPfd->cGreenBits ) - 1); dwBMask = (((DWORD)1 << lpPfd->cBlueBits ) - 1); // Shift the masks for the color-table. // *((LPDWORD)lpCT) = dwRMask << lpPfd->cRedShift; *(((LPDWORD)lpCT)+1) = dwGMask << lpPfd->cGreenShift; *(((LPDWORD)lpCT)+2) = dwBMask << lpPfd->cBlueShift; break; case 24: break; case 8: nEntries = ((UINT)1 << nBpp); if(uUsage == DIB_PAL_COLORS) { for(idx=0; idx < nEntries; idx++) *(((LPWORD)lpCT)+idx) = idx; } else { for(idx=0; idx < nEntries; idx++) { ((LPBITMAPINFO)lpDib)->bmiColors[idx].rgbRed = ComponentFromIndex(idx,lpPfd->cRedBits ,lpPfd->cRedShift ); ((LPBITMAPINFO)lpDib)->bmiColors[idx].rgbGreen = ComponentFromIndex(idx,lpPfd->cGreenBits,lpPfd->cGreenShift); ((LPBITMAPINFO)lpDib)->bmiColors[idx].rgbBlue = ComponentFromIndex(idx,lpPfd->cBlueBits ,lpPfd->cBlueShift ); ((LPBITMAPINFO)lpDib)->bmiColors[idx].rgbReserved = 0; } } break; case 4: nEntries = sizeof(cr16Color) / sizeof(cr16Color[0]); if(uUsage == DIB_PAL_COLORS) { for(idx=0; idx < nEntries; idx++) *(((LPWORD)lpCT)+idx) = idx; } else { for(idx=0; idx < nEntries; idx++) *(((LPDWORD)lpCT)+idx) = cr16Color[idx]; } break; case 1: if(uUsage == DIB_PAL_COLORS) { *((LPWORD)lpCT)++ = 0; *((LPWORD)lpCT) = 255; } else { ((LPBITMAPINFO)lpDib)->bmiColors[0].rgbBlue = 0; ((LPBITMAPINFO)lpDib)->bmiColors[0].rgbGreen = 0; ((LPBITMAPINFO)lpDib)->bmiColors[0].rgbRed = 0; ((LPBITMAPINFO)lpDib)->bmiColors[0].rgbReserved = 0; ((LPBITMAPINFO)lpDib)->bmiColors[1].rgbBlue = 255; ((LPBITMAPINFO)lpDib)->bmiColors[1].rgbGreen = 255; ((LPBITMAPINFO)lpDib)->bmiColors[1].rgbRed = 255; ((LPBITMAPINFO)lpDib)->bmiColors[1].rgbReserved = 0; } break; } if (hBitmap = CreateDIBSection(hMemDC, (LPBITMAPINFO)lpDib, uUsage, &pvBits, NULL, 0)) { if(hSave = SelectObject(hMemDC,hBitmap)) { GlobalUnlock(hDib); GlobalFree(hDib); return(hMemDC); } DeleteObject(hBitmap); } GlobalUnlock(hDib); } GlobalFree(hDib); } } #if USE_DFB } #endif } return(NULL); } BOOL DeletePixelMapDC(HDC hDC) { HBITMAP hFormat,hBitmap; BOOL bFree; bFree = FALSE; if(hFormat = CreateCompatibleBitmap(hDC,1,1)) { if(hBitmap = SelectObject(hDC,hFormat)) { DeleteObject(hBitmap); bFree = DeleteDC(hDC); } DeleteObject(hFormat); } return(bFree); } /* * This function updates a TK_WindowRec given a PIXELFORMATDESCRIPTOR */ static TK_WindowRec * PIXELFORMATDESCRIPTOR_To_TK_WindowRec ( TK_WindowRec *WindowRec, PIXELFORMATDESCRIPTOR *Pfd ) { WindowRec->type = TK_WIND_REQUEST; WindowRec->info = 0; if ( PFD_DOUBLEBUFFER & Pfd->dwFlags ) { WindowRec->info |= TK_WIND_DB; } else { WindowRec->info |= TK_WIND_SB; } if ( PFD_TYPE_COLORINDEX == Pfd->iPixelType ) { WindowRec->info |= TK_WIND_CI; } else { WindowRec->info |= TK_WIND_RGB; } if ( Pfd->cAccumBits ) { WindowRec->info |= TK_WIND_ACCUM; } if ( Pfd->cDepthBits > 16 ) { WindowRec->info |= TK_WIND_Z; } else if ( Pfd->cDepthBits > 0 ) { WindowRec->info |= TK_WIND_Z16; } if ( Pfd->cStencilBits ) { WindowRec->info |= TK_WIND_STENCIL; } if ( Pfd->cAuxBuffers ) { WindowRec->info |= TK_WIND_AUX; } return( WindowRec ); }