/******************************Module*Header*******************************\ * Module Name: metasup.c * * OpenGL metafile support * * History: * Thu Feb 23 15:27:47 1995 -by- Drew Bliss [drewb] * Created * * Copyright (c) 1995 Microsoft Corporation \**************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #include "global.h" #include #include "metasup.h" #if defined(GL_METAFILE) #include #include GLCLTPROCTABLE gcptGlsProcTable; GLEXTPROCTABLE geptGlsExtProcTable; // Functions in GL which we will do device coordinate translation for typedef struct _GLDEVICEPROCS { void (APIENTRY *glBitmap)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); void (APIENTRY *glCopyPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); void (APIENTRY *glCopyTexImage1D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); void (APIENTRY *glCopyTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); void (APIENTRY *glCopyTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); void (APIENTRY *glCopyTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); void (APIENTRY *glDrawPixels)(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); void (APIENTRY *glLineWidth)(GLfloat width); void (APIENTRY *glPointSize)(GLfloat size); void (APIENTRY *glScissor)(GLint x, GLint y, GLsizei width, GLsizei height); void (APIENTRY *glViewport)(GLint x, GLint y, GLsizei w, GLsizei h); } GLDEVICEPROCS; #define GL_DEVICE_PROCS (sizeof(GLDEVICEPROCS)/sizeof(PROC)) // Opcode for device procs static GLSopcode glsopDeviceProcs[GL_DEVICE_PROCS] = { GLS_OP_glBitmap, GLS_OP_glCopyPixels, GLS_OP_glCopyTexImage1D, GLS_OP_glCopyTexImage2D, GLS_OP_glCopyTexSubImage1D, GLS_OP_glCopyTexSubImage2D, GLS_OP_glDrawPixels, GLS_OP_glLineWidth, GLS_OP_glPointSize, GLS_OP_glScissor, GLS_OP_glViewport }; static GLDEVICEPROCS gdpGlsActual; /*****************************Private*Routine******************************\ * * GLS recording callbacks * * Perfoms any necessary work when capturing a call * * History: * Mon Mar 27 14:21:09 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlsBitmapIn(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) { PLRC plrc; RECTL rcl; plrc = GLTEB_CLTCURRENTRC(); ASSERTOPENGL(plrc != NULL, "GlsBitmapIn: No current RC!\n"); // Record bounds for the bitmap rcl.left = 0; rcl.top = 0; rcl.right = width; rcl.bottom = height; plrc->prclGlsBounds = &rcl; gdpGlsActual.glBitmap(width, height, xorig, yorig, xmove, ymove, bitmap); plrc->prclGlsBounds = NULL; } void GlsDrawPixelsIn(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) { PLRC plrc; RECTL rcl; plrc = GLTEB_CLTCURRENTRC(); ASSERTOPENGL(plrc != NULL, "GlsBitmapIn: No current RC!\n"); // Record bounds for the bitmap rcl.left = 0; rcl.top = 0; rcl.right = width; rcl.bottom = height; plrc->prclGlsBounds = &rcl; gdpGlsActual.glDrawPixels(width, height, format, type, pixels); plrc->prclGlsBounds = NULL; } void GlsViewportIn(GLint x, GLint y, GLsizei width, GLsizei height) { RECTL rcl; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ASSERTOPENGL(plrc != NULL, "GlsViewportIn: No current RC!\n"); // Send the bounds on // The rect is inclusive-exclusive while the incoming parameters // are inclusive-inclusive rcl.left = x; rcl.right = x+width+1; rcl.top = y; rcl.bottom = y+height+1; if (!GlGdiAddGlsBounds(plrc->gwidCreate.hdc, &rcl)) { ASSERTOPENGL(FALSE, "GdiAddGlsBounds failed"); } gdpGlsActual.glViewport(x, y, width, height); } // glViewport is the only device-dependent function that we need to // do work for on input static GLDEVICEPROCS gdpInput = { GlsBitmapIn, NULL, NULL, NULL, NULL, NULL, GlsDrawPixelsIn, NULL, NULL, NULL, GlsViewportIn }; /*****************************Private*Routine******************************\ * * MetaLoadGls * * Loads glmf32.dll for metafile use * * History: * Thu Feb 23 17:40:59 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ static char *pszGlsEntryPoints[] = { "glsBeginCapture", "glsBinary", "glsCallArrayInContext", "glsCaptureFlags", "glsCaptureFunc", "glsCommandFunc", "glsContext", "glsDeleteContext", "glsEndCapture", "glsFlush", "glsGenContext", "glsGetCaptureDispatchTable", "glsGetCaptureExecTable", "glsGetCommandAlignment", "glsGetCurrentContext", "glsUpdateCaptureExecTable", "glsWriteFunc", "glsBeginGLS", "glsBlock", "glsCallStream", "glsEndGLS", "glsError", "glsGLRC", "glsGLRCLayer", "glsHeaderGLRCi", "glsHeaderLayerf", "glsHeaderLayeri", "glsHeaderf", "glsHeaderfv", "glsHeaderi", "glsHeaderiv", "glsHeaderubz", "glsRequireExtension", "glsUnsupportedCommand", "glsAppRef", "glsBeginObj", "glsCharubz", "glsComment", "glsDisplayMapfv", "glsEndObj", "glsNumb", "glsNumbv", "glsNumd", "glsNumdv", "glsNumf", "glsNumfv", "glsNumi", "glsNumiv", "glsNuml", "glsNumlv", "glsNums", "glsNumsv", "glsNumub", "glsNumubv", "glsNumui", "glsNumuiv", "glsNumul", "glsNumulv", "glsNumus", "glsNumusv", "glsPad", "glsSwapBuffers" }; #define GLS_ENTRY_POINT_STRINGS (sizeof(pszGlsEntryPoints)/sizeof(char *)) typedef struct _GLSENTRYPOINTS { GLboolean (APIENTRY *glsBeginCapture)(const GLubyte *, GLSenum, GLbitfield); GLSenum (APIENTRY *glsBinary)(GLboolean); void (APIENTRY *glsCallArrayInContext)(GLuint, GLSenum, size_t, const GLubyte *); void (APIENTRY *glsCaptureFlags)(GLSopcode, GLbitfield); void (APIENTRY *glsCaptureFunc)(GLSenum, GLScaptureFunc); void (APIENTRY *glsCommandFunc)(GLSopcode, GLSfunc); void (APIENTRY *glsContext)(GLuint); void (APIENTRY *glsDeleteContext)(GLuint); void (APIENTRY *glsEndCapture)(void); void (APIENTRY *glsFlush)(GLSenum); GLuint (APIENTRY *glsGenContext)(void); void (APIENTRY *glsGetCaptureDispatchTable)(GLCLTPROCTABLE *, GLEXTPROCTABLE *); void (APIENTRY *glsGetCaptureExecTable)(GLCLTPROCTABLE *, GLEXTPROCTABLE *); GLScommandAlignment * (APIENTRY *glsGetCommandAlignment)(GLSopcode, GLSenum, GLScommandAlignment *); GLuint (APIENTRY *glsGetCurrentContext)(void); void (APIENTRY *glsUpdateCaptureExecTable)(GLCLTPROCTABLE *, GLEXTPROCTABLE *); void (APIENTRY *glsWriteFunc)(GLSwriteFunc); // The following are only used in glsCommandFunc and so don't // require real prototypes GLSfunc glsBeginGLS; GLSfunc glsBlock; GLSfunc glsCallStream; GLSfunc glsEndGLS; GLSfunc glsError; GLSfunc glsGLRC; GLSfunc glsGLRCLayer; GLSfunc glsHeaderGLRCi; GLSfunc glsHeaderLayerf; GLSfunc glsHeaderLayeri; GLSfunc glsHeaderf; GLSfunc glsHeaderfv; GLSfunc glsHeaderi; GLSfunc glsHeaderiv; GLSfunc glsHeaderubz; GLSfunc glsRequireExtension; GLSfunc glsUnsupportedCommand; GLSfunc glsAppRef; GLSfunc glsBeginObj; GLSfunc glsCharubz; GLSfunc glsComment; GLSfunc glsDisplayMapfv; GLSfunc glsEndObj; GLSfunc glsNumb; GLSfunc glsNumbv; GLSfunc glsNumd; GLSfunc glsNumdv; GLSfunc glsNumf; GLSfunc glsNumfv; GLSfunc glsNumi; GLSfunc glsNumiv; GLSfunc glsNuml; GLSfunc glsNumlv; GLSfunc glsNums; GLSfunc glsNumsv; GLSfunc glsNumub; GLSfunc glsNumubv; GLSfunc glsNumui; GLSfunc glsNumuiv; GLSfunc glsNumul; GLSfunc glsNumulv; GLSfunc glsNumus; GLSfunc glsNumusv; GLSfunc glsPad; GLSfunc glsSwapBuffers; } GLSENTRYPOINTS; #define GLS_ENTRY_POINTS (sizeof(GLSENTRYPOINTS)/sizeof(void *)) static GLSENTRYPOINTS gepGlsFuncs = {NULL}; static HMODULE hGlsDll = NULL; BOOL MetaLoadGls(void) { HMODULE hdll; BOOL bRet = FALSE; GLSENTRYPOINTS gep; PROC *ppfn, *ppfnActual, *ppfnInput; GLSfunc *pgfnNormal, *pgfnExt; int i; ASSERTOPENGL(GLS_ENTRY_POINT_STRINGS == GLS_ENTRY_POINTS, "GLS entry point strings/pointers mismatch\n"); ENTERCRITICALSECTION(&semLocal); if (hGlsDll != NULL) { bRet = TRUE; goto Exit; } hdll = LoadLibrary(__TEXT("glmf32.dll")); if (hdll == NULL) { WARNING1("Unable to load glmf32.dll, %d\n", GetLastError()); goto Exit; } ppfn = (PROC *)&gep; for (i = 0; i < GLS_ENTRY_POINTS; i++) { if (!(*ppfn = GetProcAddress(hdll, pszGlsEntryPoints[i]))) { WARNING1("glmf32.dll is missing '%s'\n", pszGlsEntryPoints[i]); FreeLibrary(hdll); goto Exit; } ppfn++; } // The table copied out is constant as long as the DLL is loaded gep.glsGetCaptureDispatchTable(&gcptGlsProcTable, &geptGlsExtProcTable); // Patch the table for certain functions to allow us to // do some coordinate conversion and bounds accumlation ppfnActual = (PROC *)&gdpGlsActual; ppfnInput = (PROC *)&gdpInput; for (i = 0; i < GL_DEVICE_PROCS; i++) { if (*ppfnInput != NULL) { ppfn = ((PROC *)&gcptGlsProcTable.glDispatchTable)+ glsopDeviceProcs[i]-GLS_OP_glNewList; *ppfnActual = *ppfn; *ppfn = *ppfnInput; } ppfnActual++; ppfnInput++; } gepGlsFuncs = gep; hGlsDll = hdll; bRet = TRUE; Exit: LEAVECRITICALSECTION(&semLocal); return bRet; } /*****************************Private*Routine******************************\ * * MetaGlProcTables * * Returns the GL dispatch tables to use for metafile RC's * * History: * Thu Feb 23 17:40:25 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void MetaGlProcTables(PGLCLTPROCTABLE *ppgcpt, PGLEXTPROCTABLE *ppgept) { ASSERTOPENGL(hGlsDll != NULL, "MetaGlProcTables: GLS not loaded\n"); *ppgcpt = &gcptGlsProcTable; *ppgept = &geptGlsExtProcTable; } /******************************Public*Routine******************************\ * * MetaSetCltProcTable * * Update GLS's generic dispatch tables * * History: * Fri Jan 05 16:40:31 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void MetaSetCltProcTable(GLCLTPROCTABLE *pgcpt, GLEXTPROCTABLE *pgept) { gepGlsFuncs.glsUpdateCaptureExecTable(pgcpt, pgept); } /******************************Public*Routine******************************\ * * MetaGetCltProcTable * * Retrieves GLS's generic dispatch tables * * History: * Fri Jan 05 19:14:18 1996 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void MetaGetCltProcTable(GLCLTPROCTABLE *pgcpt, GLEXTPROCTABLE *pgept) { gepGlsFuncs.glsGetCaptureExecTable(pgcpt, pgept); } /*****************************Private*Routine******************************\ * * GlsWriter * * GLS write function for metafile support * * History: * Thu Feb 23 15:49:03 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ size_t GlsWriter(size_t cb, CONST BYTE *pb) { PLRC plrc; #if 0 DbgPrint("GlsWriter(%d)\n", cb); #endif plrc = GLTEB_CLTCURRENTRC(); if( plrc == NULL ) { DBGERROR( "GlsWriter: No current RC!\n"); return 0; } ASSERTOPENGL(plrc->gwidCreate.hdc != NULL, "GlsWriter: hdcCreate is NULL\n"); ASSERTOPENGL(gepGlsFuncs.glsGetCurrentContext() == plrc->uiGlsCaptureContext, "GlsWriter: Wrong GLS context\n"); ASSERTOPENGL(plrc->fCapturing == TRUE, "GlsWriter: Not capturing\n"); if (GlGdiAddGlsRecord(plrc->gwidCreate.hdc, cb, (BYTE *)pb, plrc->prclGlsBounds)) { return cb; } else { return 0; } } /*****************************Private*Routine******************************\ * * GlsFlush * * Post-command GLS callback to flush the GLS stream * * History: * Fri Feb 24 10:12:49 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlsFlush(GLSopcode op) { gepGlsFuncs.glsFlush(GLS_LAST); } /*****************************Private*Routine******************************\ * * MetaRcBegin * * Start capturing on a metafile * * History: * Thu Feb 23 18:35:32 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL MetaRcBegin(PLRC plrc, HDC hdc) { PLRC plrcOld; // The GLS commands here will cause data to be written, which // requires a current RC. The RC is only used for data storage // so we don't need to set the proc table plrcOld = GLTEB_CLTCURRENTRC(); GLTEB_SET_CLTCURRENTRC(plrc); // Set capturing first because the block commands will cause // GlsWriter calls plrc->fCapturing = TRUE; // Start recording if (!gepGlsFuncs.glsBeginCapture("", gepGlsFuncs.glsBinary(GL_FALSE), GLS_NONE)) { plrc->fCapturing = FALSE; SetLastError(ERROR_NOT_ENOUGH_MEMORY); GLTEB_SET_CLTCURRENTRC(plrcOld); return FALSE; } GLTEB_SET_CLTCURRENTRC(plrcOld); return TRUE; } /*****************************Private*Routine******************************\ * * MetaRcEnd * * Stop capturing on a metafile RC * * History: * Thu Feb 23 17:13:48 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void MetaRcEnd(PLRC plrc) { PLRC plrcOld; // The GLS commands here will cause data to be written, which // requires a current RC. The RC is only used for data storage // so we don't need to set the proc table plrcOld = GLTEB_CLTCURRENTRC(); GLTEB_SET_CLTCURRENTRC(plrc); gepGlsFuncs.glsEndCapture(); plrc->fCapturing = FALSE; GLTEB_SET_CLTCURRENTRC(plrcOld); } // Table of operations which GLS should execute when capturing // in order to return information // Currently all of them are in the list // Should we attempt to do only the critical calls? static GLSopcode opExecuteBits[] = { GLS_OP_glAccum, GLS_OP_glAlphaFunc, GLS_OP_glAreTexturesResidentEXT, GLS_OP_glArrayElementEXT, GLS_OP_glBegin, GLS_OP_glBindTextureEXT, GLS_OP_glBitmap, GLS_OP_glBlendColorEXT, GLS_OP_glBlendEquationEXT, GLS_OP_glBlendFunc, GLS_OP_glCallList, GLS_OP_glCallLists, GLS_OP_glClear, GLS_OP_glClearAccum, GLS_OP_glClearColor, GLS_OP_glClearDepth, GLS_OP_glClearIndex, GLS_OP_glClearStencil, GLS_OP_glClipPlane, GLS_OP_glColor3b, GLS_OP_glColor3bv, GLS_OP_glColor3d, GLS_OP_glColor3dv, GLS_OP_glColor3f, GLS_OP_glColor3fv, GLS_OP_glColor3i, GLS_OP_glColor3iv, GLS_OP_glColor3s, GLS_OP_glColor3sv, GLS_OP_glColor3ub, GLS_OP_glColor3ubv, GLS_OP_glColor3ui, GLS_OP_glColor3uiv, GLS_OP_glColor3us, GLS_OP_glColor3usv, GLS_OP_glColor4b, GLS_OP_glColor4bv, GLS_OP_glColor4d, GLS_OP_glColor4dv, GLS_OP_glColor4f, GLS_OP_glColor4fv, GLS_OP_glColor4i, GLS_OP_glColor4iv, GLS_OP_glColor4s, GLS_OP_glColor4sv, GLS_OP_glColor4ub, GLS_OP_glColor4ubv, GLS_OP_glColor4ui, GLS_OP_glColor4uiv, GLS_OP_glColor4us, GLS_OP_glColor4usv, GLS_OP_glColorMask, GLS_OP_glColorMaterial, GLS_OP_glColorPointerEXT, GLS_OP_glColorSubTableEXT, GLS_OP_glDrawRangeElementsWIN, GLS_OP_glColorTableParameterfvSGI, GLS_OP_glColorTableParameterivSGI, GLS_OP_glColorTableEXT, GLS_OP_glConvolutionFilter1DEXT, GLS_OP_glConvolutionFilter2DEXT, GLS_OP_glConvolutionParameterfEXT, GLS_OP_glConvolutionParameterfvEXT, GLS_OP_glConvolutionParameteriEXT, GLS_OP_glConvolutionParameterivEXT, GLS_OP_glCopyColorTableSGI, GLS_OP_glCopyConvolutionFilter1DEXT, GLS_OP_glCopyConvolutionFilter2DEXT, GLS_OP_glCopyPixels, GLS_OP_glCopyTexImage1DEXT, GLS_OP_glCopyTexImage2DEXT, GLS_OP_glCopyTexSubImage1DEXT, GLS_OP_glCopyTexSubImage2DEXT, GLS_OP_glCopyTexSubImage3DEXT, GLS_OP_glCullFace, GLS_OP_glDeleteLists, GLS_OP_glDeleteTexturesEXT, GLS_OP_glDepthFunc, GLS_OP_glDepthMask, GLS_OP_glDepthRange, GLS_OP_glDetailTexFuncSGIS, GLS_OP_glDisable, GLS_OP_glDrawArraysEXT, GLS_OP_glDrawBuffer, GLS_OP_glDrawPixels, GLS_OP_glEdgeFlag, GLS_OP_glEdgeFlagPointerEXT, GLS_OP_glEdgeFlagv, GLS_OP_glEnable, GLS_OP_glEnd, GLS_OP_glEndList, GLS_OP_glEvalCoord1d, GLS_OP_glEvalCoord1dv, GLS_OP_glEvalCoord1f, GLS_OP_glEvalCoord1fv, GLS_OP_glEvalCoord2d, GLS_OP_glEvalCoord2dv, GLS_OP_glEvalCoord2f, GLS_OP_glEvalCoord2fv, GLS_OP_glEvalMesh1, GLS_OP_glEvalMesh2, GLS_OP_glEvalPoint1, GLS_OP_glEvalPoint2, GLS_OP_glFeedbackBuffer, GLS_OP_glFinish, GLS_OP_glFlush, GLS_OP_glFogf, GLS_OP_glFogfv, GLS_OP_glFogi, GLS_OP_glFogiv, GLS_OP_glFrontFace, GLS_OP_glFrustum, GLS_OP_glGenLists, GLS_OP_glGenTexturesEXT, GLS_OP_glGetBooleanv, GLS_OP_glGetClipPlane, GLS_OP_glGetColorTableParameterfvEXT, GLS_OP_glGetColorTableParameterivEXT, GLS_OP_glGetColorTableEXT, GLS_OP_glGetConvolutionFilterEXT, GLS_OP_glGetConvolutionParameterfvEXT, GLS_OP_glGetConvolutionParameterivEXT, GLS_OP_glGetDetailTexFuncSGIS, GLS_OP_glGetDoublev, GLS_OP_glGetError, GLS_OP_glGetFloatv, GLS_OP_glGetHistogramEXT, GLS_OP_glGetHistogramParameterfvEXT, GLS_OP_glGetHistogramParameterivEXT, GLS_OP_glGetIntegerv, GLS_OP_glGetLightfv, GLS_OP_glGetLightiv, GLS_OP_glGetMapdv, GLS_OP_glGetMapfv, GLS_OP_glGetMapiv, GLS_OP_glGetMaterialfv, GLS_OP_glGetMaterialiv, GLS_OP_glGetMinmaxEXT, GLS_OP_glGetMinmaxParameterfvEXT, GLS_OP_glGetMinmaxParameterivEXT, GLS_OP_glGetPixelMapfv, GLS_OP_glGetPixelMapuiv, GLS_OP_glGetPixelMapusv, GLS_OP_glGetPointervEXT, GLS_OP_glGetPolygonStipple, GLS_OP_glGetSeparableFilterEXT, GLS_OP_glGetSharpenTexFuncSGIS, GLS_OP_glGetString, GLS_OP_glGetTexColorTableParameterfvSGI, GLS_OP_glGetTexColorTableParameterivSGI, GLS_OP_glGetTexEnvfv, GLS_OP_glGetTexEnviv, GLS_OP_glGetTexGendv, GLS_OP_glGetTexGenfv, GLS_OP_glGetTexGeniv, GLS_OP_glGetTexImage, GLS_OP_glGetTexLevelParameterfv, GLS_OP_glGetTexLevelParameteriv, GLS_OP_glGetTexParameterfv, GLS_OP_glGetTexParameteriv, GLS_OP_glHint, GLS_OP_glHistogramEXT, GLS_OP_glIndexMask, GLS_OP_glIndexPointerEXT, GLS_OP_glIndexd, GLS_OP_glIndexdv, GLS_OP_glIndexf, GLS_OP_glIndexfv, GLS_OP_glIndexi, GLS_OP_glIndexiv, GLS_OP_glIndexs, GLS_OP_glIndexsv, GLS_OP_glInitNames, GLS_OP_glIsEnabled, GLS_OP_glIsList, GLS_OP_glIsTextureEXT, GLS_OP_glLightModelf, GLS_OP_glLightModelfv, GLS_OP_glLightModeli, GLS_OP_glLightModeliv, GLS_OP_glLightf, GLS_OP_glLightfv, GLS_OP_glLighti, GLS_OP_glLightiv, GLS_OP_glLineStipple, GLS_OP_glLineWidth, GLS_OP_glListBase, GLS_OP_glLoadIdentity, GLS_OP_glLoadMatrixd, GLS_OP_glLoadMatrixf, GLS_OP_glLoadName, GLS_OP_glLogicOp, GLS_OP_glMap1d, GLS_OP_glMap1f, GLS_OP_glMap2d, GLS_OP_glMap2f, GLS_OP_glMapGrid1d, GLS_OP_glMapGrid1f, GLS_OP_glMapGrid2d, GLS_OP_glMapGrid2f, GLS_OP_glMaterialf, GLS_OP_glMaterialfv, GLS_OP_glMateriali, GLS_OP_glMaterialiv, GLS_OP_glMatrixMode, GLS_OP_glMinmaxEXT, GLS_OP_glMultMatrixd, GLS_OP_glMultMatrixf, GLS_OP_glNewList, GLS_OP_glNormal3b, GLS_OP_glNormal3bv, GLS_OP_glNormal3d, GLS_OP_glNormal3dv, GLS_OP_glNormal3f, GLS_OP_glNormal3fv, GLS_OP_glNormal3i, GLS_OP_glNormal3iv, GLS_OP_glNormal3s, GLS_OP_glNormal3sv, GLS_OP_glNormalPointerEXT, GLS_OP_glOrtho, GLS_OP_glPassThrough, GLS_OP_glPixelMapfv, GLS_OP_glPixelMapuiv, GLS_OP_glPixelMapusv, GLS_OP_glPixelStoref, GLS_OP_glPixelStorei, GLS_OP_glPixelTexGenSGIX, GLS_OP_glPixelTransferf, GLS_OP_glPixelTransferi, GLS_OP_glPixelZoom, GLS_OP_glPointSize, GLS_OP_glPolygonMode, GLS_OP_glPolygonOffsetEXT, GLS_OP_glPolygonStipple, GLS_OP_glPopAttrib, GLS_OP_glPopMatrix, GLS_OP_glPopName, GLS_OP_glPrioritizeTexturesEXT, GLS_OP_glPushAttrib, GLS_OP_glPushMatrix, GLS_OP_glPushName, GLS_OP_glRasterPos2d, GLS_OP_glRasterPos2dv, GLS_OP_glRasterPos2f, GLS_OP_glRasterPos2fv, GLS_OP_glRasterPos2i, GLS_OP_glRasterPos2iv, GLS_OP_glRasterPos2s, GLS_OP_glRasterPos2sv, GLS_OP_glRasterPos3d, GLS_OP_glRasterPos3dv, GLS_OP_glRasterPos3f, GLS_OP_glRasterPos3fv, GLS_OP_glRasterPos3i, GLS_OP_glRasterPos3iv, GLS_OP_glRasterPos3s, GLS_OP_glRasterPos3sv, GLS_OP_glRasterPos4d, GLS_OP_glRasterPos4dv, GLS_OP_glRasterPos4f, GLS_OP_glRasterPos4fv, GLS_OP_glRasterPos4i, GLS_OP_glRasterPos4iv, GLS_OP_glRasterPos4s, GLS_OP_glRasterPos4sv, GLS_OP_glReadBuffer, GLS_OP_glReadPixels, GLS_OP_glRectd, GLS_OP_glRectdv, GLS_OP_glRectf, GLS_OP_glRectfv, GLS_OP_glRecti, GLS_OP_glRectiv, GLS_OP_glRects, GLS_OP_glRectsv, GLS_OP_glRenderMode, GLS_OP_glResetHistogramEXT, GLS_OP_glResetMinmaxEXT, GLS_OP_glRotated, GLS_OP_glRotatef, GLS_OP_glSampleMaskSGIS, GLS_OP_glSamplePatternSGIS, GLS_OP_glScaled, GLS_OP_glScalef, GLS_OP_glScissor, GLS_OP_glSelectBuffer, GLS_OP_glSeparableFilter2DEXT, GLS_OP_glShadeModel, GLS_OP_glSharpenTexFuncSGIS, GLS_OP_glStencilFunc, GLS_OP_glStencilMask, GLS_OP_glStencilOp, GLS_OP_glTagSampleBufferSGIX, GLS_OP_glTexColorTableParameterfvSGI, GLS_OP_glTexColorTableParameterivSGI, GLS_OP_glTexCoord1d, GLS_OP_glTexCoord1dv, GLS_OP_glTexCoord1f, GLS_OP_glTexCoord1fv, GLS_OP_glTexCoord1i, GLS_OP_glTexCoord1iv, GLS_OP_glTexCoord1s, GLS_OP_glTexCoord1sv, GLS_OP_glTexCoord2d, GLS_OP_glTexCoord2dv, GLS_OP_glTexCoord2f, GLS_OP_glTexCoord2fv, GLS_OP_glTexCoord2i, GLS_OP_glTexCoord2iv, GLS_OP_glTexCoord2s, GLS_OP_glTexCoord2sv, GLS_OP_glTexCoord3d, GLS_OP_glTexCoord3dv, GLS_OP_glTexCoord3f, GLS_OP_glTexCoord3fv, GLS_OP_glTexCoord3i, GLS_OP_glTexCoord3iv, GLS_OP_glTexCoord3s, GLS_OP_glTexCoord3sv, GLS_OP_glTexCoord4d, GLS_OP_glTexCoord4dv, GLS_OP_glTexCoord4f, GLS_OP_glTexCoord4fv, GLS_OP_glTexCoord4i, GLS_OP_glTexCoord4iv, GLS_OP_glTexCoord4s, GLS_OP_glTexCoord4sv, GLS_OP_glTexCoordPointerEXT, GLS_OP_glTexEnvf, GLS_OP_glTexEnvfv, GLS_OP_glTexEnvi, GLS_OP_glTexEnviv, GLS_OP_glTexGend, GLS_OP_glTexGendv, GLS_OP_glTexGenf, GLS_OP_glTexGenfv, GLS_OP_glTexGeni, GLS_OP_glTexGeniv, GLS_OP_glTexImage1D, GLS_OP_glTexImage2D, GLS_OP_glTexImage3DEXT, GLS_OP_glTexImage4DSGIS, GLS_OP_glTexParameterf, GLS_OP_glTexParameterfv, GLS_OP_glTexParameteri, GLS_OP_glTexParameteriv, GLS_OP_glTexSubImage1DEXT, GLS_OP_glTexSubImage2DEXT, GLS_OP_glTexSubImage3DEXT, GLS_OP_glTexSubImage4DSGIS, GLS_OP_glTranslated, GLS_OP_glTranslatef, GLS_OP_glVertex2d, GLS_OP_glVertex2dv, GLS_OP_glVertex2f, GLS_OP_glVertex2fv, GLS_OP_glVertex2i, GLS_OP_glVertex2iv, GLS_OP_glVertex2s, GLS_OP_glVertex2sv, GLS_OP_glVertex3d, GLS_OP_glVertex3dv, GLS_OP_glVertex3f, GLS_OP_glVertex3fv, GLS_OP_glVertex3i, GLS_OP_glVertex3iv, GLS_OP_glVertex3s, GLS_OP_glVertex3sv, GLS_OP_glVertex4d, GLS_OP_glVertex4dv, GLS_OP_glVertex4f, GLS_OP_glVertex4fv, GLS_OP_glVertex4i, GLS_OP_glVertex4iv, GLS_OP_glVertex4s, GLS_OP_glVertex4sv, GLS_OP_glVertexPointerEXT, GLS_OP_glViewport, GLS_OP_glArrayElement, GLS_OP_glBindTexture, GLS_OP_glColorPointer, GLS_OP_glDisableClientState, GLS_OP_glDrawArrays, GLS_OP_glDrawElements, GLS_OP_glEdgeFlagPointer, GLS_OP_glEnableClientState, GLS_OP_glIndexPointer, GLS_OP_glIndexub, GLS_OP_glIndexubv, GLS_OP_glInterleavedArrays, GLS_OP_glNormalPointer, GLS_OP_glPolygonOffset, GLS_OP_glTexCoordPointer, GLS_OP_glVertexPointer, GLS_OP_glAreTexturesResident, GLS_OP_glCopyTexImage1D, GLS_OP_glCopyTexImage2D, GLS_OP_glCopyTexSubImage1D, GLS_OP_glCopyTexSubImage2D, GLS_OP_glDeleteTextures, GLS_OP_glGenTextures, GLS_OP_glGetPointerv, GLS_OP_glIsTexture, GLS_OP_glPrioritizeTextures, GLS_OP_glTexSubImage1D, GLS_OP_glTexSubImage2D, GLS_OP_glPushClientAttrib, GLS_OP_glPopClientAttrib, }; #define EXECUTE_BITS (sizeof(opExecuteBits)/sizeof(opExecuteBits[0])) /*****************************Private*Routine******************************\ * * CreateMetaRc * * Creates a rendering context for a metafile DC * * History: * Thu Feb 23 15:27:47 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL CreateMetaRc(HDC hdc, PLRC plrc) { int i; BOOL fSuccess; if (!MetaLoadGls()) { return FALSE; } // If there's currently a GLS context active we can't record // because we require our own context to be current for recording if (gepGlsFuncs.glsGetCurrentContext() != 0) { SetLastError(ERROR_BUSY); return FALSE; } // Create a GLS context to record into plrc->uiGlsCaptureContext = gepGlsFuncs.glsGenContext(); if (plrc->uiGlsCaptureContext == 0) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); goto EH_NoContext; } // No bounds by default plrc->prclGlsBounds = NULL; // Set current GLS context gepGlsFuncs.glsContext(plrc->uiGlsCaptureContext); // Point to our writer function gepGlsFuncs.glsWriteFunc(GlsWriter); // Set up a callback to flush after every command // This lets every GL command form its own separate record in the // metafile gepGlsFuncs.glsCaptureFunc(GLS_CAPTURE_EXIT_FUNC, GlsFlush); // Set execute bits on commands which retrieve state // This allows accurate results to come back for retrieval functions for (i = 0; i < EXECUTE_BITS; i++) { gepGlsFuncs.glsCaptureFlags(opExecuteBits[i], GLS_CAPTURE_EXECUTE_BIT | GLS_CAPTURE_WRITE_BIT); } fSuccess = MetaRcBegin(plrc, hdc); // Remove context to avoid inadvertent GLS calls // Also needed in failure case gepGlsFuncs.glsContext(0); if (fSuccess) { return TRUE; } gepGlsFuncs.glsDeleteContext(plrc->uiGlsCaptureContext); plrc->uiGlsCaptureContext = 0; EH_NoContext: DBGERROR("CreateMetaRc failed\n"); return FALSE; } /*****************************Private*Routine******************************\ * * DeleteMetaRc * * Cleans up a metafile RC * * History: * Thu Feb 23 16:35:19 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void DeleteMetaRc(PLRC plrc) { GLuint uiGlsCurrent; if (plrc->uiGlsCaptureContext != 0) { // Make the GLS context current just in case // A different GLS context can be active at this time, though, // because a different metafile RC could be current to this // thread at the time of the delete, so we have to preserve // any current context uiGlsCurrent = gepGlsFuncs.glsGetCurrentContext(); gepGlsFuncs.glsContext(plrc->uiGlsCaptureContext); // If we're still capturing, stop if (plrc->fCapturing) { MetaRcEnd(plrc); } // Restore old context gepGlsFuncs.glsContext(uiGlsCurrent); // Clean up dying context gepGlsFuncs.glsDeleteContext(plrc->uiGlsCaptureContext); plrc->uiGlsCaptureContext = 0; } // Clean up playback context if necessary // This can happen when metafile playback crashes or an // application crashes while enumerating if (plrc->uiGlsPlaybackContext != 0) { gepGlsFuncs.glsDeleteContext(plrc->uiGlsPlaybackContext); plrc->uiGlsPlaybackContext = 0; } // LRC and handle will be cleaned up elsewhere } /*****************************Private*Routine******************************\ * * ActivateMetaRc * * Make a metafile RC current * * History: * Thu Feb 23 16:50:31 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void ActivateMetaRc(PLRC plrc, HDC hdc) { ASSERTOPENGL(plrc->uiGlsCaptureContext != 0, "ActivateMetaRc: No GLS context\n"); ASSERTOPENGL(gepGlsFuncs.glsGetCurrentContext() == 0, "ActivateMetaRc: Already a current GLS context\n"); gepGlsFuncs.glsContext(plrc->uiGlsCaptureContext); } /*****************************Private*Routine******************************\ * * DeactivateMetaRc * * Make a metafile RC non-current * * History: * Thu Feb 23 16:49:51 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void DeactivateMetaRc(PLRC plrc) { // The current GLS context may not be this RC's capturing context // in the case where the RC has been made current after a // CloseEnhMetaFile has stopped capturing if (gepGlsFuncs.glsGetCurrentContext() == plrc->uiGlsCaptureContext) { gepGlsFuncs.glsContext(0); } } /*****************************Private*Routine******************************\ * * GlmfSave * * Save all current GL state * * History: * Fri Feb 24 15:15:50 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlmfSave(void) { // What is the exact list of state to be saved? // What about overflowing the projection and textures stacks? // They're small glPushAttrib(GL_ALL_ATTRIB_BITS); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_TEXTURE); glPushMatrix(); } /*****************************Private*Routine******************************\ * * GlmfRestore * * Restores saved state * * History: * Fri Feb 24 15:16:14 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlmfRestore(void) { glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glPopAttrib(); } #define ScaleLongX(plrc, l) \ MulDiv(l, plrc->iGlsNumeratorX, plrc->iGlsDenominatorX) #define ScaleLongY(plrc, l) \ MulDiv(l, plrc->iGlsNumeratorY, plrc->iGlsDenominatorY) #define ScaleFloatX(plrc, f) ((f)*(plrc)->fGlsScaleX) #define ScaleFloatY(plrc, f) ((f)*(plrc)->fGlsScaleY) /*****************************Private*Routine******************************\ * * TransformLongPt * * Transform an integer point * * History: * Fri Feb 24 15:27:37 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void TransformLongPt(PLRC plrc, POINT *ppt) { ppt->x = MulDiv(ppt->x-plrc->iGlsSubtractX, plrc->iGlsNumeratorX, plrc->iGlsDenominatorX)+plrc->iGlsAddX; ppt->y = MulDiv(ppt->y-plrc->iGlsSubtractY, plrc->iGlsNumeratorY, plrc->iGlsDenominatorY)+plrc->iGlsAddY; } /*****************************Private*Routine******************************\ * * ScaleLongPt * * Scale an integer point, no translation, for values rather than coordinates * * History: * Fri Feb 24 15:27:52 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void ScaleLongPt(PLRC plrc, POINT *ppt) { ppt->x = MulDiv(ppt->x, plrc->iGlsNumeratorX, plrc->iGlsDenominatorX); ppt->y = MulDiv(ppt->y, plrc->iGlsNumeratorY, plrc->iGlsDenominatorY); } /*****************************Private*Routine******************************\ * * TransformFloatPt * * Transform a float point * * History: * Fri Feb 24 15:27:37 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void TransformFloatPt(PLRC plrc, POINTFLOAT *pptf) { pptf->x = (pptf->x-plrc->iGlsSubtractX)*plrc->iGlsNumeratorX/ plrc->iGlsDenominatorX+plrc->iGlsAddX; pptf->y = (pptf->y-plrc->iGlsSubtractY)*plrc->iGlsNumeratorY/ plrc->iGlsDenominatorY+plrc->iGlsAddY; } /*****************************Private*Routine******************************\ * * ScaleFloatPt * * Scale a float point * * History: * Fri Feb 24 15:27:37 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void ScaleFloatPt(PLRC plrc, POINTFLOAT *pptf) { pptf->x = pptf->x*plrc->iGlsNumeratorX/plrc->iGlsDenominatorX; pptf->y = pptf->y*plrc->iGlsNumeratorY/plrc->iGlsDenominatorY; } /*****************************Private*Routine******************************\ * * GLS output scaling callbacks * * The following functions are used as GLS command functions for * intercepting device coordinates and scaling them appropriately * * Bitmap contents are not scaled, but the current raster position is * correctly maintained so that they are positioned appropriately * * Stipples are not scaled * * History: * Fri Feb 24 15:28:23 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlsBitmapOut(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap) { PLRC plrc; POINTFLOAT ptf; plrc = GLTEB_CLTCURRENTRC(); ptf.x = xmove; ptf.y = ymove; ScaleFloatPt(plrc, &ptf); glBitmap(width, height, xorig, yorig, ptf.x, ptf.y, bitmap); } void GlsCopyPixelsOut(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) { POINT ptXY, ptWH; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); ptWH.x = (LONG)width; ptWH.y = (LONG)height; ScaleLongPt(plrc, &ptWH); glCopyPixels(ptXY.x, ptXY.y, ptWH.x, ptWH.y, type); } void GlsCopyTexImage1DOut(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border) { POINT ptXY; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); glCopyTexImage1D(target, level, internalformat, ptXY.x, ptXY.y, ScaleLongX(plrc, width), border); } void GlsCopyTexImage2DOut(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { POINT ptXY, ptWH; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); ptWH.x = (LONG)width; ptWH.y = (LONG)height; ScaleLongPt(plrc, &ptWH); glCopyTexImage2D(target, level, internalformat, ptXY.x, ptXY.y, ptWH.x, ptWH.y, border); } void GlsCopyTexSubImage1DOut(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width) { POINT ptXY; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); glCopyTexSubImage1D(target, level, xoffset, ptXY.x, ptXY.y, ScaleLongX(plrc, width)); } void GlsCopyTexSubImage2DOut(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { POINT ptXY, ptWH; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); ptWH.x = (LONG)width; ptWH.y = (LONG)height; ScaleLongPt(plrc, &ptWH); glCopyTexSubImage2D(target, level, xoffset, yoffset, ptXY.x, ptXY.y, ptWH.x, ptWH.y); } void GlsLineWidthOut(GLfloat width) { PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); // Use X scaling here glLineWidth(ScaleFloatX(plrc, width)); } void GlsPointSizeOut(GLfloat size) { PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); // Use X scaling here glPointSize(ScaleFloatX(plrc, size)); } void GlsScissorOut(GLint x, GLint y, GLsizei width, GLsizei height) { POINT ptXY, ptWH; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); ptWH.x = (LONG)width; ptWH.y = (LONG)height; ScaleLongPt(plrc, &ptWH); glScissor(ptXY.x, ptXY.y, ptWH.x, ptWH.y); } void GlsViewportOut(GLint x, GLint y, GLsizei width, GLsizei height) { POINT ptXY, ptWH; PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); ptXY.x = x; ptXY.y = y; TransformLongPt(plrc, &ptXY); ptWH.x = (LONG)width; ptWH.y = (LONG)height; ScaleLongPt(plrc, &ptWH); #if 0 DbgPrint("glViewport(%d, %d, %d, %d)\n", ptXY.x, ptXY.y, ptWH.x, ptWH.y); #endif glViewport(ptXY.x, ptXY.y, ptWH.x, ptWH.y); } static GLDEVICEPROCS gdpOutput = { GlsBitmapOut, GlsCopyPixelsOut, GlsCopyTexImage1DOut, GlsCopyTexImage2DOut, GlsCopyTexSubImage1DOut, GlsCopyTexSubImage2DOut, NULL, // glDrawPixels GlsLineWidthOut, GlsPointSizeOut, GlsScissorOut, GlsViewportOut }; /*****************************Private*Routine******************************\ * * GlmfHookDeviceFns * * Hook all functions that deal with device units * * History: * Fri Feb 24 15:30:45 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlmfHookDeviceFns(void) { int i; PROC *ppfn; ppfn = (PROC *)&gdpOutput; for (i = 0; i < GL_DEVICE_PROCS; i++) { if (*ppfn != NULL) { gepGlsFuncs.glsCommandFunc(glsopDeviceProcs[i], *ppfn); } ppfn++; } } /*****************************Private*Routine******************************\ * * GlmfInitTransform * * Compute 2D playback transform from source and destination rectangles * Hook GLS with scaling functions * * History: * Fri Feb 24 15:31:24 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ void GlmfInitTransform(LPRECTL prclFrom, LPRECTL prclTo) { PLRC plrc; plrc = GLTEB_CLTCURRENTRC(); // Rectangles are inclusive-inclusive plrc->iGlsSubtractX = prclFrom->left; plrc->iGlsSubtractY = prclFrom->top; plrc->iGlsNumeratorX = prclTo->right-prclTo->left+1; plrc->iGlsNumeratorY = prclTo->bottom-prclTo->top+1; plrc->iGlsDenominatorX = prclFrom->right-prclFrom->left+1; plrc->iGlsDenominatorY = prclFrom->bottom-prclFrom->top+1; plrc->iGlsAddX = prclTo->left; plrc->iGlsAddY = prclTo->top; #if 0 DbgPrint("- %d,%d * %d,%d / %d,%d + %d,%d\n", plrc->iGlsSubtractX, plrc->iGlsSubtractY, plrc->iGlsNumeratorX, plrc->iGlsNumeratorY, plrc->iGlsDenominatorX, plrc->iGlsDenominatorY, plrc->iGlsAddX, plrc->iGlsAddY); #endif // Only install hooks if the transform is not identity if (plrc->iGlsSubtractX != plrc->iGlsAddX || plrc->iGlsSubtractY != plrc->iGlsAddY || plrc->iGlsNumeratorX != plrc->iGlsDenominatorX || plrc->iGlsNumeratorY != plrc->iGlsDenominatorY) { plrc->fGlsScaleX = (GLfloat)plrc->iGlsNumeratorX/ plrc->iGlsDenominatorX; plrc->fGlsScaleY = (GLfloat)plrc->iGlsNumeratorY/ plrc->iGlsDenominatorY; GlmfHookDeviceFns(); } } // Table of functions which need to have their command funcs // reset for playback virtualization static GLSopcode opRecirculate[] = { GLS_OP_glsBeginGLS, GLS_OP_glsBlock, GLS_OP_glsCallStream, GLS_OP_glsEndGLS, GLS_OP_glsError, GLS_OP_glsGLRC, GLS_OP_glsGLRCLayer, GLS_OP_glsHeaderGLRCi, GLS_OP_glsHeaderLayerf, GLS_OP_glsHeaderLayeri, GLS_OP_glsHeaderf, GLS_OP_glsHeaderfv, GLS_OP_glsHeaderi, GLS_OP_glsHeaderiv, GLS_OP_glsHeaderubz, GLS_OP_glsRequireExtension, GLS_OP_glsUnsupportedCommand, GLS_OP_glsAppRef, GLS_OP_glsBeginObj, GLS_OP_glsCharubz, GLS_OP_glsComment, GLS_OP_glsDisplayMapfv, GLS_OP_glsEndObj, GLS_OP_glsNumb, GLS_OP_glsNumbv, GLS_OP_glsNumd, GLS_OP_glsNumdv, GLS_OP_glsNumf, GLS_OP_glsNumfv, GLS_OP_glsNumi, GLS_OP_glsNumiv, GLS_OP_glsNuml, GLS_OP_glsNumlv, GLS_OP_glsNums, GLS_OP_glsNumsv, GLS_OP_glsNumub, GLS_OP_glsNumubv, GLS_OP_glsNumui, GLS_OP_glsNumuiv, GLS_OP_glsNumul, GLS_OP_glsNumulv, GLS_OP_glsNumus, GLS_OP_glsNumusv, GLS_OP_glsPad, GLS_OP_glsSwapBuffers }; #define RECIRCULATE_OPS (sizeof(opRecirculate)/sizeof(opRecirculate[0])) /******************************Public*Routine******************************\ * * GlmfInitPlayback * * Initialize GL metafile playback, called from PlayEnhMetaFile for * metafiles with GL information in them * * History: * Fri Feb 24 10:32:29 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GlmfInitPlayback(HDC hdc, ENHMETAHEADER *pemh, LPRECTL prclDest) { GLuint uiCurrentCtx; PLRC plrc; RECTL rclSourceDevice; int i; // If we don't have the appropriate GL context set up, // do nothing. This allows applications to play metafiles containing // GL information even if they don't know anything about GL plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL) { return TRUE; } if (!MetaLoadGls()) { return FALSE; } plrc->uiGlsPlaybackContext = gepGlsFuncs.glsGenContext(); if (plrc->uiGlsPlaybackContext == 0) { return FALSE; } GlmfSave(); // Set an initial viewport just as a default glViewport(prclDest->left, prclDest->top, prclDest->right-prclDest->left, prclDest->bottom-prclDest->top); // The frame is in .01mm units. Convert it to reference // device units using the information in the metafile header rclSourceDevice.left = MulDiv(pemh->rclFrame.left, pemh->szlDevice.cx, pemh->szlMillimeters.cx*100); rclSourceDevice.right = MulDiv(pemh->rclFrame.right, pemh->szlDevice.cx, pemh->szlMillimeters.cx*100); rclSourceDevice.top = MulDiv(pemh->rclFrame.top, pemh->szlDevice.cy, pemh->szlMillimeters.cy*100); rclSourceDevice.bottom = MulDiv(pemh->rclFrame.bottom, pemh->szlDevice.cy, pemh->szlMillimeters.cy*100); // We are resetting command funcs so we need our playback context // to be current. Another context could be current now, though, // so preserve it uiCurrentCtx = gepGlsFuncs.glsGetCurrentContext(); gepGlsFuncs.glsContext(plrc->uiGlsPlaybackContext); GlmfInitTransform(&rclSourceDevice, prclDest); // Reset all GLS command funcs to point to the actual exported // routines. This means that playback on this context will // be exactly the same as if all the routines were being called // directly, so embedding a metafile into another one works // as expected // // NOTE: This context should not be made current because any // GLS commands executed on it when it is current will now // cause infinite loops for (i = 0; i < RECIRCULATE_OPS; i++) { gepGlsFuncs.glsCommandFunc(opRecirculate[i], (&gepGlsFuncs.glsBeginGLS)[i]); } // Restore preserved context gepGlsFuncs.glsContext(uiCurrentCtx); return TRUE; } /******************************Public*Routine******************************\ * * GlmfBeginGlsBlock * * Sets up things for GLS record playback which can only be active during * GLS records * Currently this only sets the world transform to identity to avoid * it interacting with GL drawing * * History: * Mon Apr 10 11:20:19 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GlmfBeginGlsBlock(HDC hdc) { PLRC plrc; BOOL bRet; // If we don't have the appropriate GL context set up, // do nothing. This allows applications to play metafiles containing // GL information even if they don't know anything about GL plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL) { return TRUE; } bRet = GetWorldTransform(hdc, &plrc->xformMeta); if (bRet) { bRet = ModifyWorldTransform(hdc, NULL, MWT_IDENTITY); } return bRet; } /******************************Public*Routine******************************\ * * GlmfPlayGlsRecord * * Play a GL metafile record * * History: * Fri Feb 24 10:33:38 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ #define PLAY_STACK_BUFFER 256 BOOL APIENTRY GlmfPlayGlsRecord(HDC hdc, DWORD cb, BYTE *pb, LPRECTL prclBounds) { PLRC plrc; LARGE_INTEGER liBuffer[(PLAY_STACK_BUFFER+sizeof(LARGE_INTEGER)-1)/ sizeof(LARGE_INTEGER)+1]; BYTE *pbPlay, *pbAlloc = NULL; __GLSbinCommandHead_large *gbch; GLSopcode op; GLScommandAlignment gca; #if 0 DbgPrint("GlmfPlayGlsRecord(%d)\n", cb); #endif // If we don't have the appropriate GL and GLS contexts set up, // do nothing. This allows applications to play metafiles containing // GL information even if they don't know anything about GL plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL || plrc->uiGlsPlaybackContext == 0) { return TRUE; } ASSERTOPENGL(hGlsDll != NULL, "GlmfPlayGlsRecord: GLS not loaded\n"); ASSERTOPENGL(plrc->tidCurrent == GetCurrentThreadId(), "GlmfPlayGlsRecord: " "Current RC does not belong to this thread!\n"); ASSERTOPENGL(plrc->gwidCurrent.hdc != 0, "GlmfPlayGlsRecord: Current HDC is NULL!\n"); // pb points to some arbitrary block of memory // GLS requires that this block be appropriately aligned for // any commands that are executed out of it, so we need to // determine which command is in the buffer and then query // GLS for its alignment. // This is trickier than you would think since GLS doesn't // always add padding to commands relative to their beginning; it // sometimes adds padding to the end of the previous command. // We need to detect the case where padding is added. // // NOTE: This definitely works when there is only one command // in the buffer. It should work when there are multiple commands // because the following commands are padded according to the // alignment of the initial command. However, this assumption // should probably be validated if blocks start containing // multiple commands. // Check for an initial pad and skip it if necessary gbch = (__GLSbinCommandHead_large *)pb; if (gbch->opSmall == GLS_OP_glsPad && gbch->countSmall == 1) { pb += sizeof(__GLSbinCommandHead_small); cb -= sizeof(__GLSbinCommandHead_small); gbch = (__GLSbinCommandHead_large *)pb; } ASSERTOPENGL(gbch->countSmall == 0 || gbch->opSmall != GLS_OP_glsPad, "Unexpected glsPad in command buffer\n"); op = gbch->countSmall == 0 ? gbch->opLarge : gbch->opSmall; gepGlsFuncs.glsGetCommandAlignment(op, gepGlsFuncs.glsBinary(GL_FALSE), &gca); ASSERTOPENGL(gca.mask <= 7, "Unhandled GLS playback alignment\n"); if (((ULONG_PTR)pb & gca.mask) != gca.value) { if (cb <= PLAY_STACK_BUFFER) { pbPlay = (BYTE *)liBuffer+gca.value; } else { pbAlloc = (BYTE *)ALLOC(cb+gca.value); if (pbAlloc == NULL) { return FALSE; } pbPlay = pbAlloc+gca.value; } RtlCopyMemory(pbPlay, pb, cb); } else { pbPlay = pb; } gepGlsFuncs.glsCallArrayInContext(plrc->uiGlsPlaybackContext, gepGlsFuncs.glsBinary(GL_FALSE), cb, pbPlay); if (pbAlloc != NULL) { FREE(pbAlloc); } return TRUE; } /******************************Public*Routine******************************\ * * GlmfEndGlsBlock * * Resets state changed for GLS record playback * Currently restores the world transform * * History: * Mon Apr 10 11:23:06 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GlmfEndGlsBlock(HDC hdc) { PLRC plrc; // If we don't have the appropriate GL context set up, // do nothing. This allows applications to play metafiles containing // GL information even if they don't know anything about GL plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL) { return TRUE; } // Doesn't matter which side we multiply by since the transform // should be identity return ModifyWorldTransform(hdc, &plrc->xformMeta, MWT_LEFTMULTIPLY); } /******************************Public*Routine******************************\ * * GlmfEndPlayback * * End GL metafile playback, called at the end of metafile playback * Only called if GlmfInitPlayback was successful * * History: * Fri Feb 24 10:36:36 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GlmfEndPlayback(HDC hdc) { PLRC plrc; // If we don't have the appropriate GL and GLS contexts set up, // do nothing. This allows applications to play metafiles containing // GL information even if they don't know anything about GL plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL || plrc->uiGlsPlaybackContext == 0) { return TRUE; } ASSERTOPENGL(hGlsDll != NULL, "GlmfEndPlayback: GLS not loaded\n"); // Since GlmfInitPlayback completed, we must have saved state GlmfRestore(); ASSERTOPENGL(plrc->uiGlsPlaybackContext != 0, "GlmfEndPlayback: No playback context\n"); gepGlsFuncs.glsDeleteContext(plrc->uiGlsPlaybackContext); plrc->uiGlsPlaybackContext = 0; // Request cleanup of windows on the theory that most orphaned // windows are produced by DCs created for metafiles and memory // DCs used by printing. Cleaning up during playback will mean // that orphaned windows are only around for one extra playback wglValidateWindows(); return TRUE; } /******************************Public*Routine******************************\ * * GlmfCloseMetaFile * * Called in CloseEnhMetaFile if GL records are present in the metafile * * History: * Fri Mar 03 18:05:50 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ BOOL APIENTRY GlmfCloseMetaFile(HDC hdc) { PLRC plrc; GLGENwindow *pwnd; GLWINDOWID gwid; // This DC has just gone away so clean up its WNDOBJ if necessary WindowIdFromHdc(hdc, &gwid); pwnd = pwndGetFromID(&gwid); if (pwnd != NULL) { pwndCleanup(pwnd); } // The app could have called wglDeleteContext before CloseEnhMetaFile, // so we're not guaranteed to have a context plrc = GLTEB_CLTCURRENTRC(); if (plrc == NULL || !plrc->fCapturing) { return TRUE; } ASSERTOPENGL(hGlsDll != NULL, "GlmfCloseMetaFile: GLS not loaded\n"); ASSERTOPENGL(plrc->uiGlsCaptureContext != 0, "GlmfCloseMetaFile: GLS context is invalid"); MetaRcEnd(plrc); // Set the proc table to the generic routines because capturing // is over. Metafiling always uses the generic routines because // the underlying surface is always faked on top of an info DC. { // Use RGBA or CI proc table depending on the color mode. GLCLTPROCTABLE *pglProcTable; __GL_SETUP(); if (gc->modes.colorIndexMode) pglProcTable = &glCltCIProcTable; else pglProcTable = &glCltRGBAProcTable; SetCltProcTable(pglProcTable, &glExtProcTable, TRUE); } return TRUE; } /******************************Public*Routine******************************\ * * GlGdi routines * * Thunks to allow the same binary to run on both NT with metafile support * and Win95 without it * * History: * Thu Aug 31 15:46:37 1995 -by- Drew Bliss [drewb] * Created * \**************************************************************************/ #if DBG BOOL APIENTRY GlGdiAddGlsRecord(HDC hdc, DWORD cb, BYTE *pb, LPRECTL prclBounds) { ASSERTOPENGL(pfnGdiAddGlsRecord != NULL, "GdiAddGlsRecord called without support\n"); return pfnGdiAddGlsRecord(hdc, cb, pb, prclBounds); } BOOL APIENTRY GlGdiAddGlsBounds(HDC hdc, LPRECTL prclBounds) { ASSERTOPENGL(pfnGdiAddGlsBounds != NULL, "GdiAddGlsBounds called without support\n"); return pfnGdiAddGlsBounds(hdc, prclBounds); } BOOL APIENTRY GlGdiIsMetaPrintDC(HDC hdc) { ASSERTOPENGL(pfnGdiIsMetaPrintDC != NULL, "GdiIsMetaPrintDC called without support\n"); return pfnGdiIsMetaPrintDC(hdc); } #endif #else PROC * APIENTRY wglGetDefaultDispatchTable(void) { return NULL; } BOOL APIENTRY GlmfInitPlayback(HDC hdc, ENHMETAHEADER *pemh, LPRECTL prclDest) { return FALSE; } BOOL APIENTRY GlmfBeginGlsBlock(HDC hdc) { return FALSE; } BOOL APIENTRY GlmfPlayGlsRecord(HDC hdc, DWORD cb, BYTE *pb, LPRECTL prclBounds) { return FALSE; } BOOL APIENTRY GlmfEndGlsBlock(HDC hdc) { return FALSE; } BOOL APIENTRY GlmfEndPlayback(HDC hdc) { return FALSE; } BOOL APIENTRY GlmfCloseMetaFile(HDC hdc) { return FALSE; } #endif