| /**************************************************************************** |
| * |
| * Mesa 3-D graphics library |
| * Direct3D Driver Interface |
| * |
| * ======================================================================== |
| * |
| * Copyright (C) 1991-2004 SciTech Software, Inc. All rights reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * SCITECH SOFTWARE INC BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * ====================================================================== |
| * |
| * Language: ANSI C |
| * Environment: Windows 9x (Win32) |
| * |
| * Description: OpenGL window functions (wgl*). |
| * |
| ****************************************************************************/ |
| |
| #include "dglwgl.h" |
| #ifdef _USE_GLD3_WGL |
| #include "gld_driver.h" |
| #endif |
| |
| #include "gl/glu.h" // MUST USE MICROSOFT'S GLU32! |
| |
| #ifndef _USE_GLD3_WGL |
| extern DGL_mesaFuncs mesaFuncs; |
| #endif |
| |
| // Need to export wgl* functions if using GLD3, |
| // otherwise export GLD2 DGL_* functions. |
| #ifdef _USE_GLD3_WGL |
| #define _GLD_WGL_EXPORT(a) wgl##a |
| #else |
| #define _GLD_WGL_EXPORT(a) DGL_##a |
| #endif |
| |
| // Calls into Mesa 4.x are different |
| #ifdef _USE_GLD3_WGL |
| #include "dlist.h" |
| #include "drawpix.h" |
| #include "get.h" |
| #include "matrix.h" |
| // NOTE: All the _GLD* macros now call the gl* functions direct. |
| // This ensures that the correct internal pathway is taken. KeithH |
| #define _GLD_glNewList glNewList |
| #define _GLD_glBitmap glBitmap |
| #define _GLD_glEndList glEndList |
| #define _GLD_glDeleteLists glDeleteLists |
| #define _GLD_glGetError glGetError |
| #define _GLD_glTranslatef glTranslatef |
| #define _GLD_glBegin glBegin |
| #define _GLD_glVertex2fv glVertex2fv |
| #define _GLD_glEnd glEnd |
| #define _GLD_glNormal3f glNormal3f |
| #define _GLD_glVertex3f glVertex3f |
| #define _GLD_glVertex3fv glVertex3fv |
| #else // _USE_GLD3_WGL |
| #define _GLD_glNewList (*mesaFuncs.glNewList) |
| #define _GLD_glBitmap (*mesaFuncs.glBitmap) |
| #define _GLD_glEndList (*mesaFuncs.glEndList) |
| #define _GLD_glDeleteLists (*mesaFuncs.glDeleteLists) |
| #define _GLD_glGetError (*mesaFuncs.glGetError) |
| #define _GLD_glTranslatef (*mesaFuncs.glTranslatef) |
| #define _GLD_glBegin (*mesaFuncs.glBegin) |
| #define _GLD_glVertex2fv (*mesaFuncs.glVertex2fv) |
| #define _GLD_glEnd (*mesaFuncs.glEnd) |
| #define _GLD_glNormal3f (*mesaFuncs.glNormal3f) |
| #define _GLD_glVertex3f (*mesaFuncs.glVertex3f) |
| #define _GLD_glVertex3fv (*mesaFuncs.glVertex3fv) |
| #endif // _USE_GLD3_WGL |
| |
| // *********************************************************************** |
| |
| // Emulate SGI DDK calls. |
| #define __wglMalloc(a) GlobalAlloc(GPTR, (a)) |
| #define __wglFree(a) GlobalFree((a)) |
| |
| // *********************************************************************** |
| |
| // Mesa glu.h and MS glu.h call these different things... |
| //#define GLUtesselator GLUtriangulatorObj |
| //#define GLU_TESS_VERTEX_DATA GLU_VERTEX_DATA |
| |
| // For wglFontOutlines |
| |
| typedef GLUtesselator *(APIENTRY *gluNewTessProto)(void); |
| typedef void (APIENTRY *gluDeleteTessProto)(GLUtesselator *tess); |
| typedef void (APIENTRY *gluTessBeginPolygonProto)(GLUtesselator *tess, void *polygon_data); |
| typedef void (APIENTRY *gluTessBeginContourProto)(GLUtesselator *tess); |
| typedef void (APIENTRY *gluTessVertexProto)(GLUtesselator *tess, GLdouble coords[3], void *data); |
| typedef void (APIENTRY *gluTessEndContourProto)(GLUtesselator *tess); |
| typedef void (APIENTRY *gluTessEndPolygonProto)(GLUtesselator *tess); |
| typedef void (APIENTRY *gluTessPropertyProto)(GLUtesselator *tess, GLenum which, GLdouble value); |
| typedef void (APIENTRY *gluTessNormalProto)(GLUtesselator *tess, GLdouble x, GLdouble y, GLdouble z); |
| typedef void (APIENTRY *gluTessCallbackProto)(GLUtesselator *tess, GLenum which, void (CALLBACK *)()); |
| |
| static HINSTANCE gluModuleHandle; |
| static gluNewTessProto gluNewTessProc; |
| static gluDeleteTessProto gluDeleteTessProc; |
| static gluTessBeginPolygonProto gluTessBeginPolygonProc; |
| static gluTessBeginContourProto gluTessBeginContourProc; |
| static gluTessVertexProto gluTessVertexProc; |
| static gluTessEndContourProto gluTessEndContourProc; |
| static gluTessEndPolygonProto gluTessEndPolygonProc; |
| static gluTessPropertyProto gluTessPropertyProc; |
| static gluTessNormalProto gluTessNormalProc; |
| static gluTessCallbackProto gluTessCallbackProc; |
| |
| static HFONT hNewFont, hOldFont; |
| static FLOAT ScaleFactor; |
| |
| #define LINE_BUF_QUANT 4000 |
| #define VERT_BUF_QUANT 4000 |
| |
| static FLOAT* LineBuf; |
| static DWORD LineBufSize; |
| static DWORD LineBufIndex; |
| static FLOAT* VertBuf; |
| static DWORD VertBufSize; |
| static DWORD VertBufIndex; |
| static GLenum TessErrorOccurred; |
| |
| static int AppendToLineBuf( |
| FLOAT value); |
| |
| static int AppendToVertBuf( |
| FLOAT value); |
| |
| static int DrawGlyph( |
| UCHAR* glyphBuf, |
| DWORD glyphSize, |
| FLOAT chordalDeviation, |
| FLOAT extrusion, |
| INT format); |
| |
| static void FreeLineBuf(void); |
| |
| static void FreeVertBuf(void); |
| |
| static long GetWord( |
| UCHAR** p); |
| |
| static long GetDWord( |
| UCHAR** p); |
| |
| static double GetFixed( |
| UCHAR** p); |
| |
| static int InitLineBuf(void); |
| |
| static int InitVertBuf(void); |
| |
| static HFONT CreateHighResolutionFont( |
| HDC hDC); |
| |
| static int MakeDisplayListFromGlyph( |
| DWORD listName, |
| UCHAR* glyphBuf, |
| DWORD glyphSize, |
| LPGLYPHMETRICSFLOAT glyphMetricsFloat, |
| FLOAT chordalDeviation, |
| FLOAT extrusion, |
| INT format); |
| |
| static BOOL LoadGLUTesselator(void); |
| static BOOL UnloadGLUTesselator(void); |
| |
| static int MakeLinesFromArc( |
| FLOAT x0, |
| FLOAT y0, |
| FLOAT x1, |
| FLOAT y1, |
| FLOAT x2, |
| FLOAT y2, |
| DWORD vertexCountIndex, |
| FLOAT chordalDeviationSquared); |
| |
| static int MakeLinesFromGlyph( UCHAR* glyphBuf, |
| DWORD glyphSize, |
| FLOAT chordalDeviation); |
| |
| static int MakeLinesFromTTLine( UCHAR** pp, |
| DWORD vertexCountIndex, |
| WORD pointCount); |
| |
| static int MakeLinesFromTTPolycurve( UCHAR** pp, |
| DWORD vertexCountIndex, |
| FLOAT chordalDeviation); |
| |
| static int MakeLinesFromTTPolygon( UCHAR** pp, |
| FLOAT chordalDeviation); |
| |
| static int MakeLinesFromTTQSpline( UCHAR** pp, |
| DWORD vertexCountIndex, |
| WORD pointCount, |
| FLOAT chordalDeviation); |
| |
| static void CALLBACK TessCombine( double coords[3], |
| void* vertex_data[4], |
| FLOAT weight[4], |
| void** outData); |
| |
| static void CALLBACK TessError( GLenum error); |
| |
| static void CALLBACK TessVertexOutData( FLOAT p[3], |
| GLfloat z); |
| |
| // *********************************************************************** |
| |
| #ifdef GLD_THREADS |
| #pragma message("compiling DGLWGL.C vars for multi-threaded support") |
| extern CRITICAL_SECTION CriticalSection; |
| extern DWORD dwTLSPixelFormat; // TLS index for current pixel format |
| #endif |
| int curPFD = 0; // Current PFD (static) |
| |
| // *********************************************************************** |
| |
| int dglGetPixelFormat(void) |
| { |
| #ifdef GLD_THREADS |
| int iPixelFormat; |
| // get thread-specific instance |
| if (glb.bMultiThreaded) { |
| __try { |
| iPixelFormat = (int)TlsGetValue(dwTLSPixelFormat); |
| } |
| __except(EXCEPTION_EXECUTE_HANDLER) { |
| iPixelFormat = curPFD; |
| } |
| } |
| // get global static var |
| else { |
| iPixelFormat = curPFD; |
| } |
| return iPixelFormat; |
| #else |
| return curPFD; |
| #endif |
| } |
| |
| // *********************************************************************** |
| |
| void dglSetPixelFormat(int iPixelFormat) |
| { |
| #ifdef GLD_THREADS |
| // set thread-specific instance |
| if (glb.bMultiThreaded) { |
| __try { |
| TlsSetValue(dwTLSPixelFormat, (LPVOID)iPixelFormat); |
| } |
| __except(EXCEPTION_EXECUTE_HANDLER) { |
| curPFD = iPixelFormat; |
| } |
| } |
| // set global static var |
| else { |
| curPFD = iPixelFormat; |
| } |
| #else |
| curPFD = iPixelFormat; |
| #endif |
| } |
| |
| // *********************************************************************** |
| |
| int APIENTRY _GLD_WGL_EXPORT(ChoosePixelFormat)( |
| HDC a, |
| CONST PIXELFORMATDESCRIPTOR *ppfd) |
| { |
| DGL_pixelFormat *lpPF = glb.lpPF; |
| |
| PIXELFORMATDESCRIPTOR ppfdBest; |
| int i; |
| int bestIndex = -1; |
| int numPixelFormats; |
| DWORD dwFlags; |
| |
| char buf[128]; |
| char cat[8]; |
| |
| DWORD dwAllFlags = |
| PFD_DRAW_TO_WINDOW | |
| PFD_DRAW_TO_BITMAP | |
| PFD_SUPPORT_GDI | |
| PFD_SUPPORT_OPENGL | |
| PFD_GENERIC_FORMAT | |
| PFD_NEED_PALETTE | |
| PFD_NEED_SYSTEM_PALETTE | |
| PFD_DOUBLEBUFFER | |
| PFD_STEREO | |
| /*PFD_SWAP_LAYER_BUFFERS |*/ |
| PFD_DOUBLEBUFFER_DONTCARE | |
| PFD_STEREO_DONTCARE | |
| PFD_SWAP_COPY | |
| PFD_SWAP_EXCHANGE | |
| PFD_GENERIC_ACCELERATED | |
| 0; |
| |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| // List may not be built until dglValidate() is called! KeithH |
| lpPF = glb.lpPF; |
| |
| // |
| // Lets print the input pixel format to the log |
| // ** Based on "wglinfo" by Nate Robins ** |
| // |
| ddlogMessage(DDLOG_SYSTEM, "ChoosePixelFormat:\n"); |
| ddlogMessage(DDLOG_INFO, "Input pixel format for ChoosePixelFormat:\n"); |
| ddlogMessage(DDLOG_INFO, |
| " visual x bf lv rg d st r g b a ax dp st accum buffs ms\n"); |
| ddlogMessage(DDLOG_INFO, |
| " id dep cl sp sz l ci b ro sz sz sz sz bf th cl r g b a ns b\n"); |
| ddlogMessage(DDLOG_INFO, |
| "-----------------------------------------------------------------\n"); |
| sprintf(buf, " . "); |
| |
| sprintf(cat, "%2d ", ppfd->cColorBits); |
| strcat(buf, cat); |
| if(ppfd->dwFlags & PFD_DRAW_TO_WINDOW) sprintf(cat, "wn "); |
| else if(ppfd->dwFlags & PFD_DRAW_TO_BITMAP) sprintf(cat, "bm "); |
| else sprintf(cat, ". "); |
| strcat(buf, cat); |
| |
| /* should find transparent pixel from LAYERPLANEDESCRIPTOR */ |
| sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| sprintf(cat, "%2d ", ppfd->cColorBits); |
| strcat(buf, cat); |
| |
| /* bReserved field indicates number of over/underlays */ |
| if(ppfd->bReserved) sprintf(cat, " %d ", ppfd->bReserved); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| sprintf(cat, " %c ", ppfd->iPixelType == PFD_TYPE_RGBA ? 'r' : 'c'); |
| strcat(buf, cat); |
| |
| sprintf(cat, "%c ", ppfd->dwFlags & PFD_DOUBLEBUFFER ? 'y' : '.'); |
| strcat(buf, cat); |
| |
| sprintf(cat, " %c ", ppfd->dwFlags & PFD_STEREO ? 'y' : '.'); |
| strcat(buf, cat); |
| |
| if(ppfd->cRedBits && ppfd->iPixelType == PFD_TYPE_RGBA) |
| sprintf(cat, "%2d ", ppfd->cRedBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cGreenBits && ppfd->iPixelType == PFD_TYPE_RGBA) |
| sprintf(cat, "%2d ", ppfd->cGreenBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cBlueBits && ppfd->iPixelType == PFD_TYPE_RGBA) |
| sprintf(cat, "%2d ", ppfd->cBlueBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAlphaBits && ppfd->iPixelType == PFD_TYPE_RGBA) |
| sprintf(cat, "%2d ", ppfd->cAlphaBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAuxBuffers) sprintf(cat, "%2d ", ppfd->cAuxBuffers); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cDepthBits) sprintf(cat, "%2d ", ppfd->cDepthBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cStencilBits) sprintf(cat, "%2d ", ppfd->cStencilBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAccumRedBits) sprintf(cat, "%2d ", ppfd->cAccumRedBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAccumGreenBits) sprintf(cat, "%2d ", ppfd->cAccumGreenBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAccumBlueBits) sprintf(cat, "%2d ", ppfd->cAccumBlueBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| if(ppfd->cAccumAlphaBits) sprintf(cat, "%2d ", ppfd->cAccumAlphaBits); |
| else sprintf(cat, " . "); |
| strcat(buf, cat); |
| |
| /* no multisample in Win32 */ |
| sprintf(cat, " . .\n"); |
| strcat(buf, cat); |
| |
| ddlogMessage(DDLOG_INFO, buf); |
| ddlogMessage(DDLOG_INFO, |
| "-----------------------------------------------------------------\n"); |
| ddlogMessage(DDLOG_INFO, "\n"); |
| |
| // |
| // Examine the flags for correctness |
| // |
| dwFlags = ppfd->dwFlags; |
| if (dwFlags != (dwFlags & dwAllFlags)) |
| { |
| /* error: bad dwFlags */ |
| ddlogPrintf(DDLOG_WARN, |
| "ChoosePixelFormat: bad flags (0x%x)", |
| dwFlags & (~dwAllFlags)); |
| // Mask illegal flags and continue |
| dwFlags = dwFlags & dwAllFlags; |
| } |
| |
| switch (ppfd->iPixelType) { |
| case PFD_TYPE_RGBA: |
| case PFD_TYPE_COLORINDEX: |
| break; |
| default: |
| /* error: bad iPixelType */ |
| ddlogMessage(DDLOG_WARN, "ChoosePixelFormat: bad pixel type\n"); |
| return 0; |
| } |
| |
| switch (ppfd->iLayerType) { |
| case PFD_MAIN_PLANE: |
| case PFD_OVERLAY_PLANE: |
| case PFD_UNDERLAY_PLANE: |
| break; |
| default: |
| /* error: bad iLayerType */ |
| ddlogMessage(DDLOG_WARN, "ChoosePixelFormat: bad layer type\n"); |
| return 0; |
| } |
| |
| numPixelFormats = glb.nPixelFormatCount; |
| |
| /* loop through candidate pixel format descriptors */ |
| for (i=0; i<numPixelFormats; ++i) { |
| PIXELFORMATDESCRIPTOR ppfdCandidate; |
| |
| memcpy(&ppfdCandidate, &lpPF[i].pfd, sizeof(PIXELFORMATDESCRIPTOR)); |
| |
| /* |
| ** Check attributes which must match |
| */ |
| if (ppfd->iPixelType != ppfdCandidate.iPixelType) { |
| continue; |
| } |
| |
| if (ppfd->iLayerType != ppfdCandidate.iLayerType) { |
| continue; |
| } |
| |
| if (((dwFlags ^ ppfdCandidate.dwFlags) & dwFlags) & |
| (PFD_DRAW_TO_WINDOW | PFD_DRAW_TO_BITMAP | |
| PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL)) |
| { |
| continue; |
| } |
| |
| if (!(dwFlags & PFD_DOUBLEBUFFER_DONTCARE)) { |
| if ((dwFlags & PFD_DOUBLEBUFFER) != |
| (ppfdCandidate.dwFlags & PFD_DOUBLEBUFFER)) |
| { |
| continue; |
| } |
| } |
| |
| // if (!(dwFlags & PFD_STEREO_DONTCARE)) { |
| if ((dwFlags & PFD_STEREO) != |
| (ppfdCandidate.dwFlags & PFD_STEREO)) |
| { |
| continue; |
| } |
| // } |
| |
| if (ppfd->iPixelType==PFD_TYPE_RGBA |
| && ppfd->cAlphaBits && !ppfdCandidate.cAlphaBits) { |
| continue; |
| } |
| |
| if (ppfd->iPixelType==PFD_TYPE_RGBA |
| && ppfd->cAccumBits && !ppfdCandidate.cAccumBits) { |
| continue; |
| } |
| |
| if (ppfd->cDepthBits && !ppfdCandidate.cDepthBits) { |
| continue; |
| } |
| |
| if (ppfd->cStencilBits && !ppfdCandidate.cStencilBits) { |
| continue; |
| } |
| |
| if (ppfd->cAuxBuffers && !ppfdCandidate.cAuxBuffers) { |
| continue; |
| } |
| |
| /* |
| ** See if candidate is better than the previous best choice |
| */ |
| if (bestIndex == -1) { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if ((ppfd->cColorBits > ppfdBest.cColorBits && |
| ppfdCandidate.cColorBits > ppfdBest.cColorBits) || |
| (ppfd->cColorBits <= ppfdCandidate.cColorBits && |
| ppfdCandidate.cColorBits < ppfdBest.cColorBits)) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if (ppfd->iPixelType==PFD_TYPE_RGBA |
| && ppfd->cAlphaBits |
| && ppfdCandidate.cAlphaBits > ppfdBest.cAlphaBits) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if (ppfd->iPixelType==PFD_TYPE_RGBA |
| && ppfd->cAccumBits |
| && ppfdCandidate.cAccumBits > ppfdBest.cAccumBits) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if ((ppfd->cDepthBits > ppfdBest.cDepthBits && |
| ppfdCandidate.cDepthBits > ppfdBest.cDepthBits) || |
| (ppfd->cDepthBits <= ppfdCandidate.cDepthBits && |
| ppfdCandidate.cDepthBits < ppfdBest.cDepthBits)) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if (ppfd->cStencilBits && |
| ppfdCandidate.cStencilBits > ppfdBest.cStencilBits) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| |
| if (ppfd->cAuxBuffers && |
| ppfdCandidate.cAuxBuffers > ppfdBest.cAuxBuffers) |
| { |
| ppfdBest = ppfdCandidate; |
| bestIndex = i; |
| continue; |
| } |
| } |
| |
| if (bestIndex != -1) { |
| ddlogPrintf(DDLOG_SYSTEM, "Pixel Format %d chosen as best match", bestIndex+1); |
| return bestIndex + 1; |
| } |
| |
| // Return the pixelformat that has the most capabilities. |
| // ** NOTE: This is only possible due to the way the list |
| // of pixelformats is built. ** |
| // Now picks best pixelformat. KeithH |
| bestIndex = numPixelFormats; // most capable double buffer format |
| ddlogPrintf(DDLOG_SYSTEM, "Pixel Format %d chosen by default", bestIndex); |
| return (bestIndex); |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(CopyContext)( |
| HGLRC a, |
| HGLRC b, |
| UINT c) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| UNSUPPORTED("wglCopyContext") |
| return FALSE; // Failed |
| } |
| |
| // *********************************************************************** |
| |
| HGLRC APIENTRY _GLD_WGL_EXPORT(CreateContext)( |
| HDC a) |
| { |
| int ipf; |
| |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| // Check that the current PFD is valid |
| ipf = dglGetPixelFormat(); |
| if (!IsValidPFD(ipf)) |
| return (HGLRC)0; |
| |
| return dglCreateContext(a, &glb.lpPF[ipf-1]); |
| } |
| |
| // *********************************************************************** |
| |
| HGLRC APIENTRY _GLD_WGL_EXPORT(CreateLayerContext)( |
| HDC a, |
| int b) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| UNSUPPORTED("wglCreateLayerContext") |
| return NULL; // Failed |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(DeleteContext)( |
| HGLRC a) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| return dglDeleteContext(a); |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(DescribeLayerPlane)( |
| HDC hDC, |
| int iPixelFormat, |
| int iLayerPlane, |
| UINT nBytes, |
| LPLAYERPLANEDESCRIPTOR plpd) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| UNSUPPORTED("DGL_DescribeLayerPlane") |
| |
| // gldLogPrintf(GLDLOG_INFO, "DescribeLayerPlane: %d, %d", iPixelFormat, iLayerPlane); |
| |
| return FALSE; |
| } |
| |
| // *********************************************************************** |
| |
| int APIENTRY _GLD_WGL_EXPORT(DescribePixelFormat)( |
| HDC a, |
| int b, |
| UINT c, |
| LPPIXELFORMATDESCRIPTOR d) |
| { |
| UINT nSize; |
| |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| if (d == NULL) // Calling app requires max number of PF's |
| return glb.nPixelFormatCount; |
| |
| // The supplied buffer may be larger than the info that we |
| // will be copying. |
| if (c > sizeof(PIXELFORMATDESCRIPTOR)) |
| nSize = sizeof(PIXELFORMATDESCRIPTOR); |
| else |
| nSize = c; |
| |
| // Setup an empty PFD before doing validation check |
| memset(d, 0, nSize); |
| d->nSize = nSize; |
| d->nVersion = 1; |
| |
| if (!IsValidPFD(b)) |
| return 0; // Bail if PFD index is invalid |
| |
| memcpy(d, &glb.lpPF[b-1].pfd, nSize); |
| |
| return glb.nPixelFormatCount; |
| } |
| |
| // *********************************************************************** |
| |
| HGLRC APIENTRY _GLD_WGL_EXPORT(GetCurrentContext)(void) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| return dglGetCurrentContext(); |
| } |
| |
| // *********************************************************************** |
| |
| HDC APIENTRY _GLD_WGL_EXPORT(GetCurrentDC)(void) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| return dglGetCurrentDC(); |
| } |
| |
| // *********************************************************************** |
| |
| PROC APIENTRY _GLD_WGL_EXPORT(GetDefaultProcAddress)( |
| LPCSTR a) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return NULL; |
| |
| UNSUPPORTED("DGL_GetDefaultProcAddress") |
| return NULL; |
| } |
| |
| // *********************************************************************** |
| |
| int APIENTRY _GLD_WGL_EXPORT(GetLayerPaletteEntries)( |
| HDC a, |
| int b, |
| int c, |
| int d, |
| COLORREF *e) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| UNSUPPORTED("DGL_GetLayerPaletteEntries") |
| return 0; |
| } |
| |
| // *********************************************************************** |
| |
| int APIENTRY _GLD_WGL_EXPORT(GetPixelFormat)( |
| HDC a) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| return dglGetPixelFormat(); |
| } |
| |
| // *********************************************************************** |
| |
| PROC APIENTRY _GLD_WGL_EXPORT(GetProcAddress)( |
| LPCSTR a) |
| { |
| PROC dglGetProcAddressD3D(LPCSTR a); |
| |
| // Validate license |
| if (!dglValidate()) |
| return NULL; |
| |
| #ifdef _USE_GLD3_WGL |
| return _gldDriver.wglGetProcAddress(a); |
| #else |
| return dglGetProcAddressD3D(a); |
| #endif |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(MakeCurrent)( |
| HDC a, |
| HGLRC b) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| return dglMakeCurrent(a, b); |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(RealizeLayerPalette)( |
| HDC a, |
| int b, |
| BOOL c) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| UNSUPPORTED("DGL_RealizeLayerPalette") |
| return FALSE; |
| } |
| |
| // *********************************************************************** |
| |
| int APIENTRY _GLD_WGL_EXPORT(SetLayerPaletteEntries)( |
| HDC a, |
| int b, |
| int c, |
| int d, |
| CONST COLORREF *e) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return 0; |
| |
| UNSUPPORTED("DGL_SetLayerPaletteEntries") |
| return 0; |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(SetPixelFormat)( |
| HDC a, |
| int b, |
| CONST PIXELFORMATDESCRIPTOR *c) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| if (IsValidPFD(b)) { |
| ddlogPrintf(DDLOG_SYSTEM, "SetPixelFormat: PixelFormat %d has been set", b); |
| dglSetPixelFormat(b); |
| return TRUE; |
| } else { |
| ddlogPrintf(DDLOG_ERROR, |
| "SetPixelFormat: PixelFormat %d is invalid and cannot be set", b); |
| return FALSE; |
| } |
| } |
| |
| // *********************************************************************** |
| /* |
| * Share lists between two gl_context structures. |
| * This was added for WIN32 WGL function support, since wglShareLists() |
| * must be called *after* wglCreateContext() with valid GLRCs. (DaveM) |
| */ |
| // |
| // Copied from GLD2.x. KeithH |
| // |
| static GLboolean _gldShareLists( |
| GLcontext *ctx1, |
| GLcontext *ctx2) |
| { |
| /* Sanity check context pointers */ |
| if (ctx1 == NULL || ctx2 == NULL) |
| return GL_FALSE; |
| /* Sanity check shared list pointers */ |
| if (ctx1->Shared == NULL || ctx2->Shared == NULL) |
| return GL_FALSE; |
| /* Decrement reference count on sharee to release previous list */ |
| ctx2->Shared->RefCount--; |
| #if 0 /* 3DStudio exits on this memory release */ |
| if (ctx2->Shared->RefCount == 0) |
| free_shared_state(ctx2, ctx2->Shared); |
| #endif |
| /* Re-assign list from sharer to sharee and increment reference count */ |
| ctx2->Shared = ctx1->Shared; |
| ctx1->Shared->RefCount++; |
| return GL_TRUE; |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(ShareLists)( |
| HGLRC a, |
| HGLRC b) |
| { |
| DGL_ctx *dgl1, *dgl2; |
| |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| // Mesa supports shared lists, but you need to supply the shared |
| // GL context info when calling gl_create_context(). An auxiliary |
| // function gl_share_lists() has been added to update the shared |
| // list info after the GL contexts have been created. (DaveM) |
| dgl1 = dglGetContextAddress(a); |
| dgl2 = dglGetContextAddress(b); |
| if (dgl1->bAllocated && dgl2->bAllocated) { |
| #ifdef _USE_GLD3_WGL |
| return _gldShareLists(dgl1->glCtx, dgl2->glCtx); |
| #else |
| return (*mesaFuncs.gl_share_lists)(dgl1->glCtx, dgl2->glCtx); |
| #endif |
| } |
| return FALSE; |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(SwapBuffers)( |
| HDC a) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| return dglSwapBuffers(a); |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(SwapLayerBuffers)( |
| HDC a, |
| UINT b) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| return dglSwapBuffers(a); |
| } |
| |
| // *********************************************************************** |
| |
| // *********************************************************************** |
| // Note: This ResizeBuffers() function may be called from |
| // either MESA glViewport() or GLD wglMakeCurrent(). |
| |
| BOOL dglWglResizeBuffers( |
| GLcontext *ctx, |
| BOOL bDefaultDriver) |
| { |
| DGL_ctx *dgl = NULL; |
| RECT rcScreenRect; |
| DWORD dwWidth; |
| DWORD dwHeight; |
| DDSURFACEDESC2 ddsd2; |
| DDSCAPS2 ddscaps2; |
| IDirectDrawClipper *lpddClipper = NULL; |
| DWORD dwFlags; |
| HRESULT hResult; |
| |
| DWORD dwMemoryType; |
| |
| int i; |
| struct gl_texture_object *tObj; |
| struct gl_texture_image *image; |
| |
| BOOL bWasFullscreen; |
| BOOL bSaveDesktop; |
| BOOL bFullScrnWin = FALSE; |
| DDSURFACEDESC2 ddsd2DisplayMode; |
| |
| DDBLTFX ddbltfx; |
| POINT pt; |
| RECT rcDst; |
| #ifdef _USE_GLD3_WGL |
| GLD_displayMode glddm; |
| #endif |
| |
| #define DDLOG_CRITICAL_OR_WARN (bDefaultDriver ? DDLOG_WARN : DDLOG_CRITICAL) |
| |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| // Sanity checks |
| if (ctx == NULL) |
| return FALSE; |
| dgl = ctx->DriverCtx; |
| if (dgl == NULL) |
| return FALSE; |
| |
| // Get the window size and calculate its dimensions |
| if (dgl->hWnd == NULL) { |
| // Check for non-window DC = memory DC ? |
| if (GetClipBox(dgl->hDC, &rcScreenRect) == ERROR) |
| SetRect(&rcScreenRect, 0, 0, 0, 0); |
| } |
| else if (!GetClientRect(dgl->hWnd, &rcScreenRect)) |
| SetRect(&rcScreenRect, 0, 0, 0, 0); |
| dwWidth = rcScreenRect.right - rcScreenRect.left; |
| dwHeight = rcScreenRect.bottom - rcScreenRect.top; |
| CopyRect(&dgl->rcScreenRect, &rcScreenRect); |
| |
| // This will occur on Alt-Tab |
| if ((dwWidth == 0) && (dwHeight == 0)) { |
| //dgl->bCanRender = FALSE; |
| return TRUE; // No resize possible! |
| } |
| |
| // Some apps zero only 1 dimension for non-visible window... (DaveM) |
| if ((dwWidth == 0) || (dwHeight == 0)) { |
| dwWidth = 8; |
| dwHeight = 8; |
| } |
| |
| // Test to see if a resize is required. |
| // Note that the dimensions will be the same if a prior resize attempt failed. |
| if ((dwWidth == dgl->dwWidth) && (dwHeight == dgl->dwHeight) && bDefaultDriver) { |
| return TRUE; // No resize required |
| } |
| |
| ddlogPrintf(DDLOG_SYSTEM, "dglResize: %dx%d", dwWidth, dwHeight); |
| #ifndef _USE_GLD3_WGL |
| // Work out where we want our surfaces created |
| dwMemoryType = (bDefaultDriver) ? glb.dwMemoryType : DDSCAPS_SYSTEMMEMORY; |
| #endif // _USE_GLD3_WGL |
| |
| // Note previous fullscreen vs window display status |
| bWasFullscreen = dgl->bFullscreen; |
| |
| #ifdef _USE_GLD3_WGL |
| if (_gldDriver.GetDisplayMode(dgl, &glddm)) { |
| if ( (dwWidth == glddm.Width) && |
| (dwHeight == glddm.Height) ) { |
| bFullScrnWin = TRUE; |
| } |
| if (bFullScrnWin && glb.bPrimary && !glb.bFullscreenBlit && !glb.bDirectDrawPersistant) { |
| dgl->bFullscreen = TRUE; |
| ddlogMessage(DDLOG_INFO, "Fullscreen window after resize.\n"); |
| } |
| else { |
| dgl->bFullscreen = FALSE; |
| ddlogMessage(DDLOG_INFO, "Non-Fullscreen window after resize.\n"); |
| } |
| // Cache the display mode dimensions |
| dgl->dwModeWidth = glddm.Width; |
| dgl->dwModeHeight = glddm.Height; |
| } |
| |
| // Clamp the effective window dimensions to primary surface. |
| // We need to do this for D3D viewport dimensions even if wide |
| // surfaces are supported. This also is a good idea for handling |
| // whacked-out window dimensions passed for non-drawable windows |
| // like Solid Edge. (DaveM) |
| if (dgl->dwWidth > glddm.Width) |
| dgl->dwWidth = glddm.Width; |
| if (dgl->dwHeight > glddm.Height) |
| dgl->dwHeight = glddm.Height; |
| #else // _USE_GLD3_WGL |
| // Window resize may have changed to fullscreen |
| ZeroMemory(&ddsd2DisplayMode, sizeof(ddsd2DisplayMode)); |
| ddsd2DisplayMode.dwSize = sizeof(ddsd2DisplayMode); |
| hResult = IDirectDraw4_GetDisplayMode( |
| dgl->lpDD4, |
| &ddsd2DisplayMode); |
| if (SUCCEEDED(hResult)) { |
| if ( (dwWidth == ddsd2DisplayMode.dwWidth) && |
| (dwHeight == ddsd2DisplayMode.dwHeight) ) { |
| bFullScrnWin = TRUE; |
| } |
| if (bFullScrnWin && glb.bPrimary && !glb.bFullscreenBlit && !glb.bDirectDrawPersistant) { |
| dgl->bFullscreen = TRUE; |
| ddlogMessage(DDLOG_INFO, "Fullscreen window after resize.\n"); |
| } |
| else { |
| dgl->bFullscreen = FALSE; |
| ddlogMessage(DDLOG_INFO, "Non-Fullscreen window after resize.\n"); |
| } |
| // Cache the display mode dimensions |
| dgl->dwModeWidth = ddsd2DisplayMode.dwWidth; |
| dgl->dwModeHeight = ddsd2DisplayMode.dwHeight; |
| } |
| |
| // Clamp the effective window dimensions to primary surface. |
| // We need to do this for D3D viewport dimensions even if wide |
| // surfaces are supported. This also is a good idea for handling |
| // whacked-out window dimensions passed for non-drawable windows |
| // like Solid Edge. (DaveM) |
| if (dgl->dwWidth > ddsd2DisplayMode.dwWidth) |
| dgl->dwWidth = ddsd2DisplayMode.dwWidth; |
| if (dgl->dwHeight > ddsd2DisplayMode.dwHeight) |
| dgl->dwHeight = ddsd2DisplayMode.dwHeight; |
| #endif // _USE_GLD3_WGL |
| |
| // Note if fullscreen vs window display has changed? |
| bSaveDesktop = (!bWasFullscreen && !dgl->bFullscreen) ? TRUE : FALSE; |
| // Save the desktop primary surface from being destroyed |
| // whenever remaining in windowed mode, since the stereo mode |
| // switches are expensive... |
| |
| #ifndef _USE_GLD3_WGL |
| // Don't need to re-allocate persistant buffers. (DaveM) |
| // Though we should clear the back buffers to hide artifacts. |
| if (glb.bDirectDrawPersistant && glb.bPersistantBuffers) { |
| dgl->dwWidth = dwWidth; |
| dgl->dwHeight = dwHeight; |
| ZeroMemory(&ddbltfx, sizeof(ddbltfx)); |
| ddbltfx.dwSize = sizeof(ddbltfx); |
| ddbltfx.dwFillColor = dgl->dwClearColorPF; |
| IDirectDrawSurface4_Blt(dgl->lpBack4, &rcScreenRect, NULL, NULL, |
| DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); |
| return TRUE; |
| } |
| |
| // Ensure all rendering is complete |
| if (ctx->Driver.Finish) |
| (*ctx->Driver.Finish)(ctx); |
| if (dgl->bSceneStarted == TRUE) { |
| IDirect3DDevice3_EndScene(dgl->lpDev3); |
| dgl->bSceneStarted = FALSE; |
| } |
| #endif // _USE_GLD3_WGL |
| dgl->bCanRender = FALSE; |
| |
| #ifdef GLD_THREADS |
| // Serialize access to DirectDraw and DDS operations |
| if (glb.bMultiThreaded) |
| EnterCriticalSection(&CriticalSection); |
| #endif |
| |
| #ifndef _USE_GLD3_WGL |
| // Release existing surfaces |
| RELEASE(dgl->lpDev3); |
| RELEASE(dgl->lpDepth4); |
| RELEASE(dgl->lpBack4); |
| if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) |
| ; |
| else |
| RELEASE(dgl->lpFront4); |
| #endif // _USE_GLD3_WGL |
| dgl->dwWidth = dwWidth; |
| dgl->dwHeight = dwHeight; |
| |
| // Set defaults |
| dgl->dwModeWidth = dgl->dwWidth; |
| dgl->dwModeHeight = dgl->dwHeight; |
| |
| #ifdef _USE_GLD3_WGL |
| if (!_gldDriver.ResizeDrawable(dgl, bDefaultDriver, glb.bDirectDrawPersistant, glb.bPersistantBuffers)) |
| goto cleanup_and_return_with_error; |
| #else // _USE_GLD3_WGL |
| |
| if (dgl->bFullscreen) { |
| // |
| // FULLSCREEN |
| // |
| |
| // Disable warning popups when in fullscreen mode |
| ddlogWarnOption(FALSE); |
| |
| // Have to release the persistant DirectDraw primary surface |
| // if switching to fullscreen mode. So if application wants |
| // persistant display in fullscreen mode, a fullscreen-size |
| // window should be used instead via fullscreen-blit option. |
| if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) { |
| RELEASE(glb.lpPrimary4); |
| glb.bDirectDrawPrimary = FALSE; |
| } |
| |
| dwFlags = DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT; |
| if (glb.bFastFPU) |
| dwFlags |= DDSCL_FPUSETUP; // optional |
| hResult = IDirectDraw4_SetCooperativeLevel(dgl->lpDD4, dgl->hWnd, dwFlags); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: Unable to set Exclusive Fullscreen mode", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| hResult = IDirectDraw4_SetDisplayMode(dgl->lpDD4, |
| dgl->dwModeWidth, |
| dgl->dwModeHeight, |
| dgl->dwBPP, |
| 0, |
| 0); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: SetDisplayMode failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // ** The display mode has changed, so dont use MessageBox! ** |
| |
| ZeroMemory(&ddsd2, sizeof(ddsd2)); |
| ddsd2.dwSize = sizeof(ddsd2); |
| |
| if (dgl->bDoubleBuffer) { |
| // Double buffered |
| // Primary surface |
| ddsd2.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; |
| ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | |
| DDSCAPS_FLIP | |
| DDSCAPS_COMPLEX | |
| DDSCAPS_3DDEVICE | |
| dwMemoryType; |
| ddsd2.dwBackBufferCount = 1; |
| hResult = IDirectDraw4_CreateSurface(dgl->lpDD4, &ddsd2, &dgl->lpFront4, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: CreateSurface (primary) failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| // Render target surface |
| ZeroMemory(&ddscaps2, sizeof(ddscaps2)); // Clear the entire struct. |
| ddscaps2.dwCaps = DDSCAPS_BACKBUFFER; |
| hResult = IDirectDrawSurface4_GetAttachedSurface(dgl->lpFront4, &ddscaps2, &dgl->lpBack4); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: GetAttachedSurface failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| } else { |
| // Single buffered |
| // Primary surface |
| ddsd2.dwFlags = DDSD_CAPS; |
| ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | |
| //DDSCAPS_3DDEVICE | |
| dwMemoryType; |
| |
| hResult = IDirectDraw4_CreateSurface(dgl->lpDD4, &ddsd2, &dgl->lpFront4, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: CreateSurface (primary) failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| dgl->lpBack4 = NULL; |
| } |
| } else { |
| // WINDOWED |
| |
| // OK to enable warning popups in windowed mode |
| ddlogWarnOption(glb.bMessageBoxWarnings); |
| |
| // Ditto if persistant DirectDraw primary |
| if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) |
| goto DoClipperOnly; |
| |
| // WINDOWED |
| dwFlags = DDSCL_NORMAL; |
| if (glb.bMultiThreaded) |
| dwFlags |= DDSCL_MULTITHREADED; |
| if (glb.bFastFPU) |
| dwFlags |= DDSCL_FPUSETUP; // optional |
| hResult = IDirectDraw4_SetCooperativeLevel(dgl->lpDD4, |
| dgl->hWnd, |
| dwFlags); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: Unable to set Normal coop level", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| // Primary surface |
| ZeroMemory(&ddsd2, sizeof(ddsd2)); |
| ddsd2.dwSize = sizeof(ddsd2); |
| ddsd2.dwFlags = DDSD_CAPS; |
| ddsd2.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; |
| hResult = IDirectDraw4_CreateSurface(dgl->lpDD4, &ddsd2, &dgl->lpFront4, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: CreateSurface (primary) failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // Cache the primary surface for persistant DirectDraw state |
| if (glb.bDirectDrawPersistant && !glb.bDirectDrawPrimary) { |
| glb.lpPrimary4 = dgl->lpFront4; |
| IDirectDrawSurface4_AddRef(glb.lpPrimary4); |
| glb.bDirectDrawPrimary = TRUE; |
| } |
| |
| // Clipper object |
| hResult = DirectDrawCreateClipper(0, &lpddClipper, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: CreateClipper failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| hResult = IDirectDrawClipper_SetHWnd(lpddClipper, 0, dgl->hWnd); |
| if (FAILED(hResult)) { |
| RELEASE(lpddClipper); |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: SetHWnd failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| hResult = IDirectDrawSurface4_SetClipper(dgl->lpFront4, lpddClipper); |
| RELEASE(lpddClipper); // We have finished with it. |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: SetClipper failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| DoClipperOnly: |
| // Update the window for the original clipper |
| if ((glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) || bSaveDesktop) { |
| IDirectDrawSurface4_GetClipper(dgl->lpFront4, &lpddClipper); |
| IDirectDrawClipper_SetHWnd(lpddClipper, 0, dgl->hWnd); |
| RELEASE(lpddClipper); |
| } |
| |
| if (dgl->bDoubleBuffer) { |
| // Render target surface |
| ZeroMemory(&ddsd2, sizeof(ddsd2)); |
| ddsd2.dwSize = sizeof(ddsd2); |
| ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; |
| ddsd2.dwWidth = dgl->dwWidth; |
| ddsd2.dwHeight = dgl->dwHeight; |
| ddsd2.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | |
| DDSCAPS_OFFSCREENPLAIN | |
| dwMemoryType; |
| hResult = IDirectDraw4_CreateSurface(dgl->lpDD4, &ddsd2, &dgl->lpBack4, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: Create Backbuffer failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| } else { |
| dgl->lpBack4 = NULL; |
| } |
| } |
| |
| // |
| // Now create the Zbuffer |
| // |
| if (dgl->bDepthBuffer) { |
| // Get z-buffer dimensions from the render target |
| // Setup the surface desc for the z-buffer. |
| ZeroMemory(&ddsd2, sizeof(ddsd2)); |
| ddsd2.dwSize = sizeof(ddsd2); |
| ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; |
| ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | dwMemoryType; |
| ddsd2.dwWidth = dgl->dwWidth; |
| ddsd2.dwHeight = dgl->dwHeight; |
| memcpy(&ddsd2.ddpfPixelFormat, |
| &glb.lpZBufferPF[dgl->iZBufferPF], |
| sizeof(DDPIXELFORMAT) ); |
| |
| // Create a z-buffer |
| hResult = IDirectDraw4_CreateSurface(dgl->lpDD4, &ddsd2, &dgl->lpDepth4, NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: CreateSurface (ZBuffer) failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // Attach Zbuffer to render target |
| TRY(IDirectDrawSurface4_AddAttachedSurface( |
| dgl->bDoubleBuffer ? dgl->lpBack4 : dgl->lpFront4, |
| dgl->lpDepth4), |
| "dglResize: Attach Zbuffer"); |
| |
| } |
| |
| // Clear the newly resized back buffers for the window client area. |
| ZeroMemory(&ddbltfx, sizeof(ddbltfx)); |
| ddbltfx.dwSize = sizeof(ddbltfx); |
| ddbltfx.dwFillColor = dgl->dwClearColorPF; |
| IDirectDrawSurface4_Blt(dgl->lpBack4, &rcScreenRect, NULL, NULL, |
| DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); |
| |
| // |
| // Now that we have a zbuffer we can create the 3D device |
| // |
| hResult = IDirect3D3_CreateDevice(dgl->lpD3D3, |
| bDefaultDriver ? &glb.d3dGuid : &IID_IDirect3DRGBDevice, |
| dgl->bDoubleBuffer ? dgl->lpBack4 : dgl->lpFront4, |
| &dgl->lpDev3, |
| NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: Could not create Direct3D device", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // We must do this as soon as the device is created |
| dglInitStateCaches(dgl); |
| |
| // |
| // Viewport |
| // |
| hResult = IDirect3DDevice3_AddViewport(dgl->lpDev3, dgl->lpViewport3); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: AddViewport failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // Initialise the viewport |
| dgl->d3dViewport.dwSize = sizeof(dgl->d3dViewport); |
| dgl->d3dViewport.dwX = 0; |
| dgl->d3dViewport.dwY = 0; |
| dgl->d3dViewport.dwWidth = dgl->dwWidth; |
| dgl->d3dViewport.dwHeight = dgl->dwHeight; |
| dgl->d3dViewport.dvClipX = 0; |
| dgl->d3dViewport.dvClipY = 0; |
| dgl->d3dViewport.dvClipWidth = dgl->dwWidth; |
| dgl->d3dViewport.dvClipHeight = dgl->dwHeight; |
| // dgl->d3dViewport.dvMinZ = 0.0f; |
| // dgl->d3dViewport.dvMaxZ = 1.0f; |
| TRY(IDirect3DViewport3_SetViewport2(dgl->lpViewport3, &dgl->d3dViewport), |
| "dglResize: SetViewport2"); |
| |
| hResult = IDirect3DDevice3_SetCurrentViewport(dgl->lpDev3, dgl->lpViewport3); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_CRITICAL_OR_WARN, "dglResize: SetCurrentViewport failed", hResult); |
| goto cleanup_and_return_with_error; |
| } |
| |
| // (Re)Initialise all the Direct3D renderstates |
| dglInitStateD3D(ctx); |
| |
| // Now we have to recreate all of our textures (+ mipmaps). |
| // Walk over all textures in hash table |
| // XXX what about the default texture objects (id=0)? |
| { |
| struct _mesa_HashTable *textures = ctx->Shared->TexObjects; |
| GLuint id; |
| for (id = _mesa_HashFirstEntry(textures); |
| id; |
| id = _mesa_HashNextEntry(textures, id)) { |
| tObj = (struct gl_texture_object *) _mesa_HashLookup(textures, id); |
| if (tObj->DriverData) { |
| // We could call our TexImage function directly, but it's |
| // safer to use the driver pointer. |
| for (i=0; i<MAX_TEXTURE_LEVELS; i++) { |
| image = tObj->Image[i]; |
| if (image) { |
| switch (tObj->Dimensions){ |
| case 1: |
| if (ctx->Driver.TexImage) |
| (*ctx->Driver.TexImage)(ctx, GL_TEXTURE_1D, tObj, i, image->Format, image); |
| break; |
| case 2: |
| if (ctx->Driver.TexImage) |
| (*ctx->Driver.TexImage)(ctx, GL_TEXTURE_2D, tObj, i, image->Format, image); |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // Re-Bind each texture Unit |
| for (i=0; i<glb.wMaxSimultaneousTextures; i++) { |
| tObj = ctx->Texture.Unit[i].Current; |
| if (tObj) { |
| DGL_texture *lpTex = (DGL_texture *)tObj->DriverData; |
| hResult = dglSetTexture(dgl, i, lpTex ? lpTex->lpTexture : NULL); |
| if (FAILED(hResult)) { |
| ddlogError(DDLOG_ERROR, "dglResize: SetTexture failed", hResult); |
| } |
| } |
| } |
| #endif // _USE_GLD3_WGL |
| |
| dgl->bCanRender = TRUE; |
| |
| #ifdef GLD_THREADS |
| // Release serialized access |
| if (glb.bMultiThreaded) |
| LeaveCriticalSection(&CriticalSection); |
| #endif |
| |
| // SUCCESS. |
| return TRUE; |
| |
| cleanup_and_return_with_error: |
| // Relase all interfaces before returning. |
| #ifdef _USE_GLD3_WGL |
| _gldDriver.DestroyDrawable(dgl); |
| #else // _USE_GLD3_WGL |
| RELEASE(dgl->lpDev3); |
| RELEASE(dgl->lpDepth4); |
| RELEASE(dgl->lpBack4); |
| if (glb.bDirectDrawPersistant && glb.bDirectDrawPrimary) |
| ; |
| else |
| RELEASE(dgl->lpFront4); |
| |
| #undef DDLOG_CRITICAL_OR_WARN |
| #endif // _USE_GLD3_WGL |
| |
| // Mark context as not being able to render |
| dgl->bCanRender = FALSE; |
| |
| #ifdef GLD_THREADS |
| // Release serialized access |
| if (glb.bMultiThreaded) |
| LeaveCriticalSection(&CriticalSection); |
| #endif |
| |
| return FALSE; |
| } |
| |
| // *********************************************************************** |
| // *********************************************************************** |
| // Support for bitmap fonts. |
| // *********************************************************************** |
| // *********************************************************************** |
| |
| /***************************************************************************** |
| ** |
| ** InvertGlyphBitmap. |
| ** |
| ** Invert the bitmap so that it suits OpenGL's representation. |
| ** Each row starts on a double word boundary. |
| ** |
| *****************************************************************************/ |
| |
| static void InvertGlyphBitmap( |
| int w, |
| int h, |
| DWORD *fptr, |
| DWORD *tptr) |
| { |
| int dWordsInRow = (w+31)/32; |
| int i, j; |
| DWORD *tmp = tptr; |
| |
| if (w <= 0 || h <= 0) { |
| return; |
| } |
| |
| tptr += ((h-1)*dWordsInRow); |
| for (i = 0; i < h; i++) { |
| for (j = 0; j < dWordsInRow; j++) { |
| *(tptr + j) = *(fptr + j); |
| } |
| tptr -= dWordsInRow; |
| fptr += dWordsInRow; |
| } |
| } |
| |
| // *********************************************************************** |
| |
| /***************************************************************************** |
| * wglUseFontBitmaps |
| * |
| * Converts a subrange of the glyphs in a GDI font to OpenGL display |
| * lists. |
| * |
| * Extended to support any GDI font, not just TrueType fonts. (DaveM) |
| * |
| *****************************************************************************/ |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(UseFontBitmapsA)( |
| HDC hDC, |
| DWORD first, |
| DWORD count, |
| DWORD listBase) |
| { |
| int i, ox, oy, ix, iy; |
| int w, h; |
| int iBufSize, iCurBufSize = 0; |
| DWORD *bitmapBuffer = NULL; |
| DWORD *invertedBitmapBuffer = NULL; |
| BOOL bSuccessOrFail = TRUE; |
| BOOL bTrueType = FALSE; |
| TEXTMETRIC tm; |
| GLYPHMETRICS gm; |
| RASTERIZER_STATUS rs; |
| MAT2 mat; |
| SIZE size; |
| RECT rect; |
| HDC hDCMem; |
| HBITMAP hBitmap; |
| BITMAPINFO bmi; |
| HFONT hFont; |
| |
| // Validate SciTech DirectGL license |
| if (!dglValidate()) |
| return FALSE; |
| |
| // Set up a unity matrix. |
| ZeroMemory(&mat, sizeof(mat)); |
| mat.eM11.value = 1; |
| mat.eM22.value = 1; |
| |
| // Test to see if selected font is TrueType or not |
| ZeroMemory(&tm, sizeof(tm)); |
| if (!GetTextMetrics(hDC, &tm)) { |
| ddlogMessage(DDLOG_ERROR, "DGL_UseFontBitmaps: Font metrics error\n"); |
| return (FALSE); |
| } |
| bTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) ? TRUE : FALSE; |
| |
| // Test to see if TRUE-TYPE capabilities are installed |
| // (only necessary if TrueType font selected) |
| ZeroMemory(&rs, sizeof(rs)); |
| if (bTrueType) { |
| if (!GetRasterizerCaps (&rs, sizeof (RASTERIZER_STATUS))) { |
| ddlogMessage(DDLOG_ERROR, "DGL_UseFontBitmaps: Raster caps error\n"); |
| return (FALSE); |
| } |
| if (!(rs.wFlags & TT_ENABLED)) { |
| ddlogMessage(DDLOG_ERROR, "DGL_UseFontBitmaps: No TrueType caps\n"); |
| return (FALSE); |
| } |
| } |
| |
| // Trick to get the current font handle |
| hFont = SelectObject(hDC, GetStockObject(SYSTEM_FONT)); |
| SelectObject(hDC, hFont); |
| |
| // Have memory device context available for holding bitmaps of font glyphs |
| hDCMem = CreateCompatibleDC(hDC); |
| SelectObject(hDCMem, hFont); |
| SetTextColor(hDCMem, RGB(0xFF, 0xFF, 0xFF)); |
| SetBkColor(hDCMem, 0); |
| |
| for (i = first; (DWORD) i < (first + count); i++) { |
| // Find out how much space is needed for the bitmap so we can |
| // Set the buffer size correctly. |
| if (bTrueType) { |
| // Use TrueType support to get bitmap size of glyph |
| iBufSize = GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, |
| 0, NULL, &mat); |
| if (iBufSize == GDI_ERROR) { |
| bSuccessOrFail = FALSE; |
| break; |
| } |
| } |
| else { |
| // Use generic GDI support to compute bitmap size of glyph |
| w = tm.tmMaxCharWidth; |
| h = tm.tmHeight; |
| if (GetTextExtentPoint32(hDC, (LPCTSTR)&i, 1, &size)) { |
| w = size.cx; |
| h = size.cy; |
| } |
| iBufSize = w * h; |
| // Use DWORD multiple for compatibility |
| iBufSize += 3; |
| iBufSize /= 4; |
| iBufSize *= 4; |
| } |
| |
| // If we need to allocate Larger Buffers, then do so - but allocate |
| // An extra 50 % so that we don't do too many mallocs ! |
| if (iBufSize > iCurBufSize) { |
| if (bitmapBuffer) { |
| __wglFree(bitmapBuffer); |
| } |
| if (invertedBitmapBuffer) { |
| __wglFree(invertedBitmapBuffer); |
| } |
| |
| iCurBufSize = iBufSize * 2; |
| bitmapBuffer = (DWORD *) __wglMalloc(iCurBufSize); |
| invertedBitmapBuffer = (DWORD *) __wglMalloc(iCurBufSize); |
| |
| if (bitmapBuffer == NULL || invertedBitmapBuffer == NULL) { |
| bSuccessOrFail = FALSE; |
| break; |
| } |
| } |
| |
| // If we fail to get the Glyph data, delete the display lists |
| // Created so far and return FALSE. |
| if (bTrueType) { |
| // Use TrueType support to get bitmap of glyph |
| if (GetGlyphOutline(hDC, i, GGO_BITMAP, &gm, |
| iBufSize, bitmapBuffer, &mat) == GDI_ERROR) { |
| bSuccessOrFail = FALSE; |
| break; |
| } |
| |
| // Setup glBitmap parameters for current font glyph |
| w = gm.gmBlackBoxX; |
| h = gm.gmBlackBoxY; |
| ox = gm.gmptGlyphOrigin.x; |
| oy = gm.gmptGlyphOrigin.y; |
| ix = gm.gmCellIncX; |
| iy = gm.gmCellIncY; |
| } |
| else { |
| // Use generic GDI support to create bitmap of glyph |
| ZeroMemory(bitmapBuffer, iBufSize); |
| |
| if (i >= tm.tmFirstChar && i <= tm.tmLastChar) { |
| // Only create bitmaps for actual font glyphs |
| hBitmap = CreateBitmap(w, h, 1, 1, NULL); |
| SelectObject(hDCMem, hBitmap); |
| // Make bitmap of current font glyph |
| SetRect(&rect, 0, 0, w, h); |
| DrawText(hDCMem, (LPCTSTR)&i, 1, &rect, |
| DT_LEFT | DT_BOTTOM | DT_SINGLELINE | DT_NOCLIP); |
| // Make copy of bitmap in our local buffer |
| ZeroMemory(&bmi, sizeof(bmi)); |
| bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); |
| bmi.bmiHeader.biWidth = w; |
| bmi.bmiHeader.biHeight = -h; |
| bmi.bmiHeader.biPlanes = 1; |
| bmi.bmiHeader.biBitCount = 1; |
| bmi.bmiHeader.biCompression = BI_RGB; |
| GetDIBits(hDCMem, hBitmap, 0, h, bitmapBuffer, &bmi, 0); |
| DeleteObject(hBitmap); |
| } |
| else { |
| // Otherwise use empty display list for non-existing glyph |
| iBufSize = 0; |
| } |
| |
| // Setup glBitmap parameters for current font glyph |
| ox = 0; |
| oy = tm.tmDescent; |
| ix = w; |
| iy = 0; |
| } |
| |
| // Create an OpenGL display list. |
| _GLD_glNewList((listBase + i), GL_COMPILE); |
| |
| // Some fonts have no data for the space character, yet advertise |
| // a non-zero size. |
| if (0 == iBufSize) { |
| _GLD_glBitmap(0, 0, 0.0f, 0.0f, (GLfloat) ix, (GLfloat) iy, NULL); |
| } else { |
| // Invert the Glyph data. |
| InvertGlyphBitmap(w, h, bitmapBuffer, invertedBitmapBuffer); |
| |
| // Render an OpenGL bitmap and invert the origin. |
| _GLD_glBitmap(w, h, |
| (GLfloat) ox, (GLfloat) (h-oy), |
| (GLfloat) ix, (GLfloat) iy, |
| (GLubyte *) invertedBitmapBuffer); |
| } |
| |
| // Close this display list. |
| _GLD_glEndList(); |
| } |
| |
| if (bSuccessOrFail == FALSE) { |
| ddlogMessage(DDLOG_ERROR, "DGL_UseFontBitmaps: Get glyph failed\n"); |
| _GLD_glDeleteLists((i+listBase), (i-first)); |
| } |
| |
| // Release resources used |
| DeleteObject(hFont); |
| DeleteDC(hDCMem); |
| |
| if (bitmapBuffer) |
| __wglFree(bitmapBuffer); |
| if (invertedBitmapBuffer) |
| __wglFree(invertedBitmapBuffer); |
| |
| return(bSuccessOrFail); |
| } |
| |
| // *********************************************************************** |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(UseFontBitmapsW)( |
| HDC a, |
| DWORD b, |
| DWORD c, |
| DWORD d) |
| { |
| // Validate license |
| if (!dglValidate()) |
| return FALSE; |
| |
| return _GLD_WGL_EXPORT(UseFontBitmapsA)(a, b, c, d); |
| } |
| |
| // *********************************************************************** |
| // *********************************************************************** |
| // Support for outline TrueType fonts. |
| // *********************************************************************** |
| // *********************************************************************** |
| |
| void * __wglRealloc( |
| void *oldPtr, |
| size_t newSize) |
| { |
| void *newPtr = NULL; |
| |
| if (newSize != 0) { |
| newPtr = (void *) GlobalAlloc(GPTR, newSize); |
| if (oldPtr && newPtr) { |
| DWORD oldSize = GlobalSize(oldPtr); |
| |
| memcpy(newPtr, oldPtr, (oldSize <= newSize ? oldSize : newSize)); |
| GlobalFree(oldPtr); |
| } |
| } else if (oldPtr) { |
| GlobalFree(oldPtr); |
| } |
| if (newPtr == NULL) { |
| return NULL; /* XXX out of memory error */ |
| } |
| return newPtr; |
| } |
| |
| // *********************************************************************** |
| |
| |
| /***************************************************************************** |
| * wglUseFontOutlinesW |
| * |
| * Converts a subrange of the glyphs in a TrueType font to OpenGL display |
| * lists. |
| *****************************************************************************/ |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(UseFontOutlinesW)( |
| IN HDC hDC, |
| IN DWORD first, |
| IN DWORD count, |
| IN DWORD listBase, |
| IN FLOAT chordalDeviation, |
| IN FLOAT extrusion, |
| IN INT format, |
| OUT LPGLYPHMETRICSFLOAT lpgmf) |
| { |
| return _GLD_WGL_EXPORT(UseFontOutlinesA)(hDC, first, count, listBase, |
| chordalDeviation, extrusion, format, lpgmf); |
| } |
| |
| /***************************************************************************** |
| * wglUseFontOutlinesA |
| * |
| * Converts a subrange of the glyphs in a TrueType font to OpenGL display |
| * lists. |
| *****************************************************************************/ |
| |
| BOOL APIENTRY _GLD_WGL_EXPORT(UseFontOutlinesA)( |
| IN HDC hDC, |
| IN DWORD first, |
| IN DWORD count, |
| IN DWORD listBase, |
| IN FLOAT chordalDeviation, |
| IN FLOAT extrusion, |
| IN INT format, |
| OUT LPGLYPHMETRICSFLOAT glyphMetricsFloatArray) |
| { |
| DWORD glyphIndex; |
| UCHAR* glyphBuf; |
| DWORD glyphBufSize; |
| |
| |
| /* |
| * Flush any previous OpenGL errors. This allows us to check for |
| * new errors so they can be reported via the function return value. |
| */ |
| while (_GLD_glGetError() != GL_NO_ERROR) |
| ; |
| |
| /* |
| * Make sure that the current font can be sampled accurately. |
| */ |
| hNewFont = CreateHighResolutionFont(hDC); |
| if (!hNewFont) |
| return FALSE; |
| |
| hOldFont = SelectObject(hDC, hNewFont); |
| if (!hOldFont) |
| return FALSE; |
| |
| /* |
| * Preallocate a buffer for the outline data, and track its size: |
| */ |
| glyphBuf = (UCHAR*) __wglMalloc(glyphBufSize = 10240); |
| if (!glyphBuf) |
| return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/ |
| |
| /* |
| * Process each glyph in the given range: |
| */ |
| for (glyphIndex = first; glyphIndex - first < count; ++glyphIndex) |
| { |
| GLYPHMETRICS glyphMetrics; |
| DWORD glyphSize; |
| static MAT2 matrix = |
| { |
| {0, 1}, {0, 0}, |
| {0, 0}, {0, 1} |
| }; |
| LPGLYPHMETRICSFLOAT glyphMetricsFloat = |
| &glyphMetricsFloatArray[glyphIndex - first]; |
| |
| |
| /* |
| * Determine how much space is needed to store the glyph's |
| * outlines. If our glyph buffer isn't large enough, |
| * resize it. |
| */ |
| glyphSize = GetGlyphOutline( hDC, |
| glyphIndex, |
| GGO_NATIVE, |
| &glyphMetrics, |
| 0, |
| NULL, |
| &matrix |
| ); |
| if (glyphSize < 0) |
| return FALSE; /*WGL_STATUS_FAILURE*/ |
| if (glyphSize > glyphBufSize) |
| { |
| __wglFree(glyphBuf); |
| glyphBuf = (UCHAR*) __wglMalloc(glyphBufSize = glyphSize); |
| if (!glyphBuf) |
| return FALSE; /*WGL_STATUS_NOT_ENOUGH_MEMORY*/ |
| } |
| |
| |
| /* |
| * Get the glyph's outlines. |
| */ |
| if (GetGlyphOutline( hDC, |
| glyphIndex, |
| GGO_NATIVE, |
| &glyphMetrics, |
| glyphBufSize, |
| glyphBuf, |
| &matrix |
| ) < 0) |
| { |
| __wglFree(glyphBuf); |
| return FALSE; /*WGL_STATUS_FAILURE*/ |
| } |
| |
| glyphMetricsFloat->gmfBlackBoxX = |
| (FLOAT) glyphMetrics.gmBlackBoxX * ScaleFactor; |
| glyphMetricsFloat->gmfBlackBoxY = |
| (FLOAT) glyphMetrics.gmBlackBoxY * ScaleFactor; |
| glyphMetricsFloat->gmfptGlyphOrigin.x = |
| (FLOAT) glyphMetrics.gmptGlyphOrigin.x * ScaleFactor; |
| glyphMetricsFloat->gmfptGlyphOrigin.y = |
| (FLOAT) glyphMetrics.gmptGlyphOrigin.y * ScaleFactor; |
| glyphMetricsFloat->gmfCellIncX = |
| (FLOAT) glyphMetrics.gmCellIncX * ScaleFactor; |
| glyphMetricsFloat->gmfCellIncY = |
| (FLOAT) glyphMetrics.gmCellIncY * ScaleFactor; |
| |
| /* |
| * Turn the glyph into a display list: |
| */ |
| if (!MakeDisplayListFromGlyph( (glyphIndex - first) + listBase, |
| glyphBuf, |
| glyphSize, |
| glyphMetricsFloat, |
| chordalDeviation + ScaleFactor, |
| extrusion, |
| format)) |
| { |
| __wglFree(glyphBuf); |
| return FALSE; /*WGL_STATUS_FAILURE*/ |
| } |
| } |
| |
| |
| /* |
| * Clean up temporary storage and return. If an error occurred, |
| * clear all OpenGL error flags and return FAILURE status; |
| * otherwise just return SUCCESS. |
| */ |
| __wglFree(glyphBuf); |
| |
| SelectObject(hDC, hOldFont); |
| |
| if (_GLD_glGetError() == GL_NO_ERROR) |
| return TRUE; /*WGL_STATUS_SUCCESS*/ |
| else |
| { |
| while (_GLD_glGetError() != GL_NO_ERROR) |
| ; |
| return FALSE; /*WGL_STATUS_FAILURE*/ |
| } |
| } |
| |
| |
| |
| /***************************************************************************** |
| * CreateHighResolutionFont |
| * |
| * Gets metrics for the current font and creates an equivalent font |
| * scaled to the design units of the font. |
| * |
| *****************************************************************************/ |
| |
| static HFONT |
| CreateHighResolutionFont(HDC hDC) |
| { |
| UINT otmSize; |
| OUTLINETEXTMETRIC *otm; |
| LONG fontHeight, fontWidth, fontUnits; |
| LOGFONT logFont; |
| |
| otmSize = GetOutlineTextMetrics(hDC, 0, NULL); |
| if (otmSize == 0) |
| return NULL; |
| |
| otm = (OUTLINETEXTMETRIC *) __wglMalloc(otmSize); |
| if (otm == NULL) |
| return NULL; |
| |
| otm->otmSize = otmSize; |
| if (GetOutlineTextMetrics(hDC, otmSize, otm) == 0) |
| return NULL; |
| |
| fontHeight = otm->otmTextMetrics.tmHeight - |
| otm->otmTextMetrics.tmInternalLeading; |
| fontWidth = otm->otmTextMetrics.tmAveCharWidth; |
| fontUnits = (LONG) otm->otmEMSquare; |
| |
| ScaleFactor = 1.0F / (FLOAT) fontUnits; |
| |
| logFont.lfHeight = - ((LONG) fontUnits); |
| logFont.lfWidth = (LONG) |
| ((FLOAT) (fontWidth * fontUnits) / (FLOAT) fontHeight); |
| logFont.lfEscapement = 0; |
| logFont.lfOrientation = 0; |
| logFont.lfWeight = otm->otmTextMetrics.tmWeight; |
| logFont.lfItalic = otm->otmTextMetrics.tmItalic; |
| logFont.lfUnderline = otm->otmTextMetrics.tmUnderlined; |
| logFont.lfStrikeOut = otm->otmTextMetrics.tmStruckOut; |
| logFont.lfCharSet = otm->otmTextMetrics.tmCharSet; |
| logFont.lfOutPrecision = OUT_OUTLINE_PRECIS; |
| logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; |
| logFont.lfQuality = DEFAULT_QUALITY; |
| logFont.lfPitchAndFamily = |
| otm->otmTextMetrics.tmPitchAndFamily & 0xf0; |
| strcpy(logFont.lfFaceName, |
| (char *)otm + (int)otm->otmpFaceName); |
| |
| hNewFont = CreateFontIndirect(&logFont); |
| if (hNewFont == NULL) |
| return NULL; |
| |
| __wglFree(otm); |
| |
| return hNewFont; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeDisplayListFromGlyph |
| * |
| * Converts the outline of a glyph to an OpenGL display list. |
| * |
| * Return value is nonzero for success, zero for failure. |
| * |
| * Does not check for OpenGL errors, so if the caller needs to know about them, |
| * it should call glGetError(). |
| *****************************************************************************/ |
| |
| static int |
| MakeDisplayListFromGlyph( IN DWORD listName, |
| IN UCHAR* glyphBuf, |
| IN DWORD glyphSize, |
| IN LPGLYPHMETRICSFLOAT glyphMetricsFloat, |
| IN FLOAT chordalDeviation, |
| IN FLOAT extrusion, |
| IN INT format) |
| { |
| int status; |
| |
| _GLD_glNewList(listName, GL_COMPILE); |
| status = DrawGlyph( glyphBuf, |
| glyphSize, |
| chordalDeviation, |
| extrusion, |
| format); |
| |
| _GLD_glTranslatef(glyphMetricsFloat->gmfCellIncX, |
| glyphMetricsFloat->gmfCellIncY, |
| 0.0F); |
| _GLD_glEndList(); |
| |
| return status; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * DrawGlyph |
| * |
| * Converts the outline of a glyph to OpenGL drawing primitives, tessellating |
| * as needed, and then draws the glyph. Tessellation of the quadratic splines |
| * in the outline is controlled by "chordalDeviation", and the drawing |
| * primitives (lines or polygons) are selected by "format". |
| * |
| * Return value is nonzero for success, zero for failure. |
| * |
| * Does not check for OpenGL errors, so if the caller needs to know about them, |
| * it should call glGetError(). |
| *****************************************************************************/ |
| |
| static int |
| DrawGlyph( IN UCHAR* glyphBuf, |
| IN DWORD glyphSize, |
| IN FLOAT chordalDeviation, |
| IN FLOAT extrusion, |
| IN INT format) |
| { |
| INT status = 0; |
| FLOAT* p; |
| DWORD loop; |
| DWORD point; |
| GLUtesselator* tess = NULL; |
| |
| |
| /* |
| * Initialize the global buffer into which we place the outlines: |
| */ |
| if (!InitLineBuf()) |
| goto exit; |
| |
| |
| /* |
| * Convert the glyph outlines to a set of polyline loops. |
| * (See MakeLinesFromGlyph() for the format of the loop data |
| * structure.) |
| */ |
| if (!MakeLinesFromGlyph(glyphBuf, glyphSize, chordalDeviation)) |
| goto exit; |
| p = LineBuf; |
| |
| |
| /* |
| * Now draw the loops in the appropriate format: |
| */ |
| if (format == WGL_FONT_LINES) |
| { |
| /* |
| * This is the easy case. Just draw the outlines. |
| */ |
| for (loop = (DWORD) *p++; loop; --loop) |
| { |
| _GLD_glBegin(GL_LINE_LOOP); |
| for (point = (DWORD) *p++; point; --point) |
| { |
| _GLD_glVertex2fv(p); |
| p += 2; |
| } |
| _GLD_glEnd(); |
| } |
| status = 1; |
| } |
| |
| else if (format == WGL_FONT_POLYGONS) |
| { |
| double v[3]; |
| FLOAT *save_p = p; |
| GLfloat z_value; |
| |
| /* |
| * This is the hard case. We have to set up a tessellator |
| * to convert the outlines into a set of polygonal |
| * primitives, which the tessellator passes to some |
| * auxiliary routines for drawing. |
| */ |
| if (!LoadGLUTesselator()) |
| goto exit; |
| if (!InitVertBuf()) |
| goto exit; |
| if (!(tess = gluNewTessProc())) |
| goto exit; |
| gluTessCallbackProc(tess, GLU_BEGIN, (void(CALLBACK *)()) _GLD_glBegin); |
| gluTessCallbackProc(tess, GLU_TESS_VERTEX_DATA, |
| (void(CALLBACK *)()) TessVertexOutData); |
| gluTessCallbackProc(tess, GLU_END, (void(CALLBACK *)()) _GLD_glEnd); |
| gluTessCallbackProc(tess, GLU_ERROR, (void(CALLBACK *)()) TessError); |
| gluTessCallbackProc(tess, GLU_TESS_COMBINE, (void(CALLBACK *)()) TessCombine); |
| gluTessNormalProc(tess, 0.0F, 0.0F, 1.0F); |
| |
| TessErrorOccurred = 0; |
| _GLD_glNormal3f(0.0f, 0.0f, 1.0f); |
| v[2] = 0.0; |
| z_value = 0.0f; |
| |
| gluTessBeginPolygonProc(tess, (void *)*(int *)&z_value); |
| for (loop = (DWORD) *p++; loop; --loop) |
| { |
| gluTessBeginContourProc(tess); |
| |
| for (point = (DWORD) *p++; point; --point) |
| { |
| v[0] = p[0]; |
| v[1] = p[1]; |
| gluTessVertexProc(tess, v, p); |
| p += 2; |
| } |
| |
| gluTessEndContourProc(tess); |
| } |
| gluTessEndPolygonProc(tess); |
| |
| status = !TessErrorOccurred; |
| |
| /* Extrusion code */ |
| if (extrusion) { |
| DWORD loops; |
| GLfloat thickness = (GLfloat) -extrusion; |
| FLOAT *vert, *vert2; |
| DWORD count; |
| |
| p = save_p; |
| loops = (DWORD) *p++; |
| |
| for (loop = 0; loop < loops; loop++) { |
| GLfloat dx, dy, len; |
| DWORD last; |
| |
| count = (DWORD) *p++; |
| _GLD_glBegin(GL_QUAD_STRIP); |
| |
| /* Check if the first and last vertex are identical |
| * so we don't draw the same quad twice. |
| */ |
| vert = p + (count-1)*2; |
| last = (p[0] == vert[0] && p[1] == vert[1]) ? count-1 : count; |
| |
| for (point = 0; point <= last; point++) { |
| vert = p + 2 * (point % last); |
| vert2 = p + 2 * ((point+1) % last); |
| |
| dx = vert[0] - vert2[0]; |
| dy = vert[1] - vert2[1]; |
| len = (GLfloat)sqrt(dx * dx + dy * dy); |
| |
| _GLD_glNormal3f(dy / len, -dx / len, 0.0f); |
| _GLD_glVertex3f((GLfloat) vert[0], |
| (GLfloat) vert[1], thickness); |
| _GLD_glVertex3f((GLfloat) vert[0], |
| (GLfloat) vert[1], 0.0f); |
| } |
| |
| _GLD_glEnd(); |
| p += count*2; |
| } |
| |
| /* Draw the back face */ |
| p = save_p; |
| v[2] = thickness; |
| _GLD_glNormal3f(0.0f, 0.0f, -1.0f); |
| gluTessNormalProc(tess, 0.0F, 0.0F, -1.0F); |
| |
| gluTessBeginPolygonProc(tess, (void *)*(int *)&thickness); |
| |
| for (loop = (DWORD) *p++; loop; --loop) |
| { |
| count = (DWORD) *p++; |
| |
| gluTessBeginContourProc(tess); |
| |
| for (point = 0; point < count; point++) |
| { |
| vert = p + ((count-point-1)<<1); |
| v[0] = vert[0]; |
| v[1] = vert[1]; |
| gluTessVertexProc(tess, v, vert); |
| } |
| p += count*2; |
| |
| gluTessEndContourProc(tess); |
| } |
| gluTessEndPolygonProc(tess); |
| } |
| |
| #if DEBUG |
| if (TessErrorOccurred) |
| printf("Tessellation error %s\n", |
| gluErrorString(TessErrorOccurred)); |
| #endif |
| } |
| |
| |
| exit: |
| FreeLineBuf(); |
| if (tess) |
| gluDeleteTessProc(tess); |
| // UnloadGLUTesselator(); |
| FreeVertBuf(); |
| return status; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * LoadGLUTesselator |
| * |
| * Maps the glu32.dll module and gets function pointers for the |
| * tesselator functions. |
| *****************************************************************************/ |
| |
| static BOOL |
| LoadGLUTesselator(void) |
| { |
| if (gluModuleHandle != NULL) |
| return TRUE; |
| |
| { |
| extern HINSTANCE hInstanceOpenGL; |
| char *gluName = "GLU32.DLL"; |
| // char name[256]; |
| // char *ptr; |
| // int len; |
| |
| /* |
| len = GetModuleFileName(hInstanceOpenGL, name, 255); |
| if (len != 0) |
| { |
| ptr = name+len-1; |
| while (ptr > name && *ptr != '\\') |
| ptr--; |
| if (*ptr == '\\') |
| ptr++; |
| if (!stricmp(ptr, "cosmogl.dll")) |
| { |
| gluName = "COSMOGLU.DLL"; |
| } |
| else if (!stricmp(ptr, "opengl32.dll")) |
| { |
| gluName = "GLU32.DLL"; |
| } |
| } |
| */ |
| if ((gluModuleHandle = LoadLibrary(gluName)) == NULL) |
| return FALSE; |
| } |
| |
| if ((gluNewTessProc = (gluNewTessProto) |
| GetProcAddress(gluModuleHandle, "gluNewTess")) == NULL) |
| return FALSE; |
| |
| if ((gluDeleteTessProc = (gluDeleteTessProto) |
| GetProcAddress(gluModuleHandle, "gluDeleteTess")) == NULL) |
| return FALSE; |
| |
| if ((gluTessBeginPolygonProc = (gluTessBeginPolygonProto) |
| GetProcAddress(gluModuleHandle, "gluTessBeginPolygon")) == NULL) |
| return FALSE; |
| |
| if ((gluTessBeginContourProc = (gluTessBeginContourProto) |
| GetProcAddress(gluModuleHandle, "gluTessBeginContour")) == NULL) |
| return FALSE; |
| |
| if ((gluTessVertexProc = (gluTessVertexProto) |
| GetProcAddress(gluModuleHandle, "gluTessVertex")) == NULL) |
| return FALSE; |
| |
| if ((gluTessEndContourProc = (gluTessEndContourProto) |
| GetProcAddress(gluModuleHandle, "gluTessEndContour")) == NULL) |
| return FALSE; |
| |
| if ((gluTessEndPolygonProc = (gluTessEndPolygonProto) |
| GetProcAddress(gluModuleHandle, "gluTessEndPolygon")) == NULL) |
| return FALSE; |
| |
| if ((gluTessPropertyProc = (gluTessPropertyProto) |
| GetProcAddress(gluModuleHandle, "gluTessProperty")) == NULL) |
| return FALSE; |
| |
| if ((gluTessNormalProc = (gluTessNormalProto) |
| GetProcAddress(gluModuleHandle, "gluTessNormal")) == NULL) |
| return FALSE; |
| |
| if ((gluTessCallbackProc = (gluTessCallbackProto) |
| GetProcAddress(gluModuleHandle, "gluTessCallback")) == NULL) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * UnloadGLUTesselator |
| * |
| * Unmaps the glu32.dll module. |
| *****************************************************************************/ |
| |
| static BOOL |
| UnloadGLUTesselator(void) |
| { |
| if (gluModuleHandle != NULL) |
| if (FreeLibrary(gluModuleHandle) == FALSE) |
| return FALSE; |
| gluModuleHandle = NULL; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * TessVertexOut |
| * |
| * Used by tessellator to handle output vertexes. |
| *****************************************************************************/ |
| |
| static void CALLBACK |
| TessVertexOut(FLOAT p[3]) |
| { |
| GLfloat v[2]; |
| |
| v[0] = p[0] * ScaleFactor; |
| v[1] = p[1] * ScaleFactor; |
| _GLD_glVertex2fv(v); |
| } |
| |
| static void CALLBACK |
| TessVertexOutData(FLOAT p[3], GLfloat z) |
| { |
| GLfloat v[3]; |
| |
| v[0] = (GLfloat) p[0]; |
| v[1] = (GLfloat) p[1]; |
| v[2] = z; |
| _GLD_glVertex3fv(v); |
| } |
| |
| |
| /***************************************************************************** |
| * TessCombine |
| * |
| * Used by tessellator to handle self-intersecting contours and degenerate |
| * geometry. |
| *****************************************************************************/ |
| |
| static void CALLBACK |
| TessCombine(double coords[3], |
| void* vertex_data[4], |
| FLOAT weight[4], |
| void** outData) |
| { |
| if (!AppendToVertBuf((FLOAT) coords[0]) |
| || !AppendToVertBuf((FLOAT) coords[1]) |
| || !AppendToVertBuf((FLOAT) coords[2])) |
| TessErrorOccurred = GL_OUT_OF_MEMORY; |
| *outData = VertBuf + (VertBufIndex - 3); |
| } |
| |
| |
| |
| /***************************************************************************** |
| * TessError |
| * |
| * Saves the last tessellator error code in the global TessErrorOccurred. |
| *****************************************************************************/ |
| |
| static void CALLBACK |
| TessError(GLenum error) |
| { |
| TessErrorOccurred = error; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromGlyph |
| * |
| * Converts the outline of a glyph from the TTPOLYGON format to a simple |
| * array of floating-point values containing one or more loops. |
| * |
| * The first element of the output array is a count of the number of loops. |
| * The loop data follows this count. Each loop consists of a count of the |
| * number of vertices it contains, followed by the vertices. Each vertex |
| * is an X and Y coordinate. For example, a single triangle might be |
| * described by this array: |
| * |
| * 1., 3., 0., 0., 1., 0., 0., 1. |
| * ^ ^ ^ ^ ^ ^ ^ ^ |
| * #loops #verts x1 y1 x2 y2 x3 y3 |
| * |
| * A two-loop glyph would look like this: |
| * |
| * 2., 3., 0.,0., 1.,0., 0.,1., 3., .2,.2, .4,.2, .2,.4 |
| * |
| * Line segments from the TTPOLYGON are transferred to the output array in |
| * the obvious way. Quadratic splines in the TTPOLYGON are converted to |
| * collections of line segments |
| *****************************************************************************/ |
| |
| static int |
| MakeLinesFromGlyph(IN UCHAR* glyphBuf, |
| IN DWORD glyphSize, |
| IN FLOAT chordalDeviation) |
| { |
| UCHAR* p; |
| int status = 0; |
| |
| |
| /* |
| * Pick up all the polygons (aka loops) that make up the glyph: |
| */ |
| if (!AppendToLineBuf(0.0F)) /* loop count at LineBuf[0] */ |
| goto exit; |
| |
| p = glyphBuf; |
| while (p < glyphBuf + glyphSize) |
| { |
| if (!MakeLinesFromTTPolygon(&p, chordalDeviation)) |
| goto exit; |
| LineBuf[0] += 1.0F; /* increment loop count */ |
| } |
| |
| status = 1; |
| |
| exit: |
| return status; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromTTPolygon |
| * |
| * Converts a TTPOLYGONHEADER and its associated curve structures into a |
| * single polyline loop in the global LineBuf. |
| *****************************************************************************/ |
| |
| static int |
| MakeLinesFromTTPolygon( IN OUT UCHAR** pp, |
| IN FLOAT chordalDeviation) |
| { |
| DWORD polySize; |
| UCHAR* polyStart; |
| DWORD vertexCountIndex; |
| |
| /* |
| * Record where the polygon data begins, and where the loop's |
| * vertex count resides: |
| */ |
| polyStart = *pp; |
| vertexCountIndex = LineBufIndex; |
| if (!AppendToLineBuf(0.0F)) |
| return 0; |
| |
| /* |
| * Extract relevant data from the TTPOLYGONHEADER: |
| */ |
| polySize = GetDWord(pp); |
| if (GetDWord(pp) != TT_POLYGON_TYPE) /* polygon type */ |
| return 0; |
| if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first X coord */ |
| return 0; |
| if (!AppendToLineBuf((FLOAT) GetFixed(pp))) /* first Y coord */ |
| return 0; |
| LineBuf[vertexCountIndex] += 1.0F; |
| |
| /* |
| * Process each of the TTPOLYCURVE structures in the polygon: |
| */ |
| while (*pp < polyStart + polySize) |
| if (!MakeLinesFromTTPolycurve( pp, |
| vertexCountIndex, |
| chordalDeviation)) |
| return 0; |
| |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromTTPolyCurve |
| * |
| * Converts the lines and splines in a single TTPOLYCURVE structure to points |
| * in the global LineBuf. |
| *****************************************************************************/ |
| |
| static int |
| MakeLinesFromTTPolycurve( IN OUT UCHAR** pp, |
| IN DWORD vertexCountIndex, |
| IN FLOAT chordalDeviation) |
| { |
| WORD type; |
| WORD pointCount; |
| |
| |
| /* |
| * Pick up the relevant fields of the TTPOLYCURVE structure: |
| */ |
| type = (WORD) GetWord(pp); |
| pointCount = (WORD) GetWord(pp); |
| |
| /* |
| * Convert the "curve" to line segments: |
| */ |
| if (type == TT_PRIM_LINE) |
| return MakeLinesFromTTLine( pp, |
| vertexCountIndex, |
| pointCount); |
| else if (type == TT_PRIM_QSPLINE) |
| return MakeLinesFromTTQSpline( pp, |
| vertexCountIndex, |
| pointCount, |
| chordalDeviation); |
| else |
| return 0; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromTTLine |
| * |
| * Converts points from the polyline in a TT_PRIM_LINE structure to |
| * equivalent points in the global LineBuf. |
| *****************************************************************************/ |
| static int |
| MakeLinesFromTTLine( IN OUT UCHAR** pp, |
| IN DWORD vertexCountIndex, |
| IN WORD pointCount) |
| { |
| /* |
| * Just copy the line segments into the line buffer (converting |
| * type as we go): |
| */ |
| LineBuf[vertexCountIndex] += pointCount; |
| while (pointCount--) |
| { |
| if (!AppendToLineBuf((FLOAT) GetFixed(pp)) /* X coord */ |
| || !AppendToLineBuf((FLOAT) GetFixed(pp))) /* Y coord */ |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromTTQSpline |
| * |
| * Converts points from the poly quadratic spline in a TT_PRIM_QSPLINE |
| * structure to polyline points in the global LineBuf. |
| *****************************************************************************/ |
| |
| static int |
| MakeLinesFromTTQSpline( IN OUT UCHAR** pp, |
| IN DWORD vertexCountIndex, |
| IN WORD pointCount, |
| IN FLOAT chordalDeviation) |
| { |
| FLOAT x0, y0, x1, y1, x2, y2; |
| WORD point; |
| |
| /* |
| * Process each of the non-interpolated points in the outline. |
| * To do this, we need to generate two interpolated points (the |
| * start and end of the arc) for each non-interpolated point. |
| * The first interpolated point is always the one most recently |
| * stored in LineBuf, so we just extract it from there. The |
| * second interpolated point is either the average of the next |
| * two points in the QSpline, or the last point in the QSpline |
| * if only one remains. |
| */ |
| for (point = 0; point < pointCount - 1; ++point) |
| { |
| x0 = LineBuf[LineBufIndex - 2]; |
| y0 = LineBuf[LineBufIndex - 1]; |
| |
| x1 = (FLOAT) GetFixed(pp); |
| y1 = (FLOAT) GetFixed(pp); |
| |
| if (point == pointCount - 2) |
| { |
| /* |
| * This is the last arc in the QSpline. The final |
| * point is the end of the arc. |
| */ |
| x2 = (FLOAT) GetFixed(pp); |
| y2 = (FLOAT) GetFixed(pp); |
| } |
| else |
| { |
| /* |
| * Peek at the next point in the input to compute |
| * the end of the arc: |
| */ |
| x2 = 0.5F * (x1 + (FLOAT) GetFixed(pp)); |
| y2 = 0.5F * (y1 + (FLOAT) GetFixed(pp)); |
| /* |
| * Push the point back onto the input so it will |
| * be reused as the next off-curve point: |
| */ |
| *pp -= 8; |
| } |
| |
| if (!MakeLinesFromArc( x0, y0, |
| x1, y1, |
| x2, y2, |
| vertexCountIndex, |
| chordalDeviation * chordalDeviation)) |
| return 0; |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * MakeLinesFromArc |
| * |
| * Subdivides one arc of a quadratic spline until the chordal deviation |
| * tolerance requirement is met, then places the resulting set of line |
| * segments in the global LineBuf. |
| *****************************************************************************/ |
| |
| static int |
| MakeLinesFromArc( IN FLOAT x0, |
| IN FLOAT y0, |
| IN FLOAT x1, |
| IN FLOAT y1, |
| IN FLOAT x2, |
| IN FLOAT y2, |
| IN DWORD vertexCountIndex, |
| IN FLOAT chordalDeviationSquared) |
| { |
| FLOAT x01; |
| FLOAT y01; |
| FLOAT x12; |
| FLOAT y12; |
| FLOAT midPointX; |
| FLOAT midPointY; |
| FLOAT deltaX; |
| FLOAT deltaY; |
| |
| /* |
| * Calculate midpoint of the curve by de Casteljau: |
| */ |
| x01 = 0.5F * (x0 + x1); |
| y01 = 0.5F * (y0 + y1); |
| x12 = 0.5F * (x1 + x2); |
| y12 = 0.5F * (y1 + y2); |
| midPointX = 0.5F * (x01 + x12); |
| midPointY = 0.5F * (y01 + y12); |
| |
| |
| /* |
| * Estimate chordal deviation by the distance from the midpoint |
| * of the curve to its non-interpolated control point. If this |
| * distance is greater than the specified chordal deviation |
| * constraint, then subdivide. Otherwise, generate polylines |
| * from the three control points. |
| */ |
| deltaX = midPointX - x1; |
| deltaY = midPointY - y1; |
| if (deltaX * deltaX + deltaY * deltaY > chordalDeviationSquared) |
| { |
| MakeLinesFromArc( x0, y0, |
| x01, y01, |
| midPointX, midPointY, |
| vertexCountIndex, |
| chordalDeviationSquared); |
| |
| MakeLinesFromArc( midPointX, midPointY, |
| x12, y12, |
| x2, y2, |
| vertexCountIndex, |
| chordalDeviationSquared); |
| } |
| else |
| { |
| /* |
| * The "pen" is already at (x0, y0), so we don't need to |
| * add that point to the LineBuf. |
| */ |
| if (!AppendToLineBuf(x1) |
| || !AppendToLineBuf(y1) |
| || !AppendToLineBuf(x2) |
| || !AppendToLineBuf(y2)) |
| return 0; |
| LineBuf[vertexCountIndex] += 2.0F; |
| } |
| |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * InitLineBuf |
| * |
| * Initializes the global LineBuf and its associated size and current-element |
| * counters. |
| *****************************************************************************/ |
| |
| static int |
| InitLineBuf(void) |
| { |
| if (!(LineBuf = (FLOAT*) |
| __wglMalloc((LineBufSize = LINE_BUF_QUANT) * sizeof(FLOAT)))) |
| return 0; |
| LineBufIndex = 0; |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * InitVertBuf |
| * |
| * Initializes the global VertBuf and its associated size and current-element |
| * counters. |
| *****************************************************************************/ |
| |
| static int |
| InitVertBuf(void) |
| { |
| if (!(VertBuf = (FLOAT*) |
| __wglMalloc((VertBufSize = VERT_BUF_QUANT) * sizeof(FLOAT)))) |
| return 0; |
| VertBufIndex = 0; |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * AppendToLineBuf |
| * |
| * Appends one floating-point value to the global LineBuf array. Return value |
| * is non-zero for success, zero for failure. |
| *****************************************************************************/ |
| |
| static int |
| AppendToLineBuf(FLOAT value) |
| { |
| if (LineBufIndex >= LineBufSize) |
| { |
| FLOAT* f; |
| |
| f = (FLOAT*) __wglRealloc(LineBuf, |
| (LineBufSize += LINE_BUF_QUANT) * sizeof(FLOAT)); |
| if (!f) |
| return 0; |
| LineBuf = f; |
| } |
| LineBuf[LineBufIndex++] = value; |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * AppendToVertBuf |
| * |
| * Appends one floating-point value to the global VertBuf array. Return value |
| * is non-zero for success, zero for failure. |
| * |
| * Note that we can't realloc this one, because the tessellator is using |
| * pointers into it. |
| *****************************************************************************/ |
| |
| static int |
| AppendToVertBuf(FLOAT value) |
| { |
| if (VertBufIndex >= VertBufSize) |
| return 0; |
| VertBuf[VertBufIndex++] = value; |
| return 1; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * FreeLineBuf |
| * |
| * Cleans up vertex buffer structure. |
| *****************************************************************************/ |
| |
| static void |
| FreeLineBuf(void) |
| { |
| if (LineBuf) |
| { |
| __wglFree(LineBuf); |
| LineBuf = NULL; |
| } |
| } |
| |
| |
| |
| /***************************************************************************** |
| * FreeVertBuf |
| * |
| * Cleans up vertex buffer structure. |
| *****************************************************************************/ |
| |
| static void |
| FreeVertBuf(void) |
| { |
| if (VertBuf) |
| { |
| __wglFree(VertBuf); |
| VertBuf = NULL; |
| } |
| } |
| |
| |
| |
| /***************************************************************************** |
| * GetWord |
| * |
| * Fetch the next 16-bit word from a little-endian byte stream, and increment |
| * the stream pointer to the next unscanned byte. |
| *****************************************************************************/ |
| |
| static long GetWord(UCHAR** p) |
| { |
| long value; |
| |
| value = ((*p)[1] << 8) + (*p)[0]; |
| *p += 2; |
| return value; |
| } |
| |
| |
| |
| /***************************************************************************** |
| * GetDWord |
| * |
| * Fetch the next 32-bit word from a little-endian byte stream, and increment |
| * the stream pointer to the next unscanned byte. |
| *****************************************************************************/ |
| |
| static long GetDWord(UCHAR** p) |
| { |
| long value; |
| |
| value = ((*p)[3] << 24) + ((*p)[2] << 16) + ((*p)[1] << 8) + (*p)[0]; |
| *p += 4; |
| return value; |
| } |
| |
| |
| |
| |
| /***************************************************************************** |
| * GetFixed |
| * |
| * Fetch the next 32-bit fixed-point value from a little-endian byte stream, |
| * convert it to floating-point, and increment the stream pointer to the next |
| * unscanned byte. |
| *****************************************************************************/ |
| |
| static double GetFixed( |
| UCHAR** p) |
| { |
| long hiBits, loBits; |
| double value; |
| |
| loBits = GetWord(p); |
| hiBits = GetWord(p); |
| value = (double) ((hiBits << 16) | loBits) / 65536.0; |
| |
| return value * ScaleFactor; |
| } |
| |
| // *********************************************************************** |
| |