windows-nt/Source/XPSP1/NT/multimedia/opengl/client/metasup.c
2020-09-26 16:20:57 +08:00

2134 lines
56 KiB
C

/******************************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 <ntpsapi.h>
#include <wingdip.h>
#include "global.h"
#include <glgenwin.h>
#include "metasup.h"
#if defined(GL_METAFILE)
#include <glmf.h>
#include <encoding.h>
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