|
|
/******************************Module*Header*******************************\
* Module Name: dl_opt.c * * Display list compilation error routines. * * Created: 12-24-1995 * Author: Hock San Lee [hockl] * * Copyright (c) 1995-96 Microsoft Corporation \**************************************************************************/ /*
** Copyright 1991, 1922, Silicon Graphics, Inc. ** All Rights Reserved. ** ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; ** the contents of this file may not be disclosed to third parties, copied or ** duplicated in any form, in whole or in part, without the prior written ** permission of Silicon Graphics, Inc. ** ** RESTRICTED RIGHTS LEGEND: ** Use, duplication or disclosure by the Government is subject to restrictions ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - ** rights reserved under the Copyright Laws of the United States. ** */ #include "precomp.h"
#pragma hdrstop
#include "glclt.h"
void FASTCALL VA_ArrayElementCompile(__GLcontext *gc, GLint i);
/************************************************************************/
/*
** Optimized errors. Strange but true. These are called to save an error ** in the display list. */ void __gllc_InvalidValue() { void *data; __GL_SETUP();
data = __glDlistAddOpUnaligned(gc, DLIST_SIZE(0), DLIST_GENERIC_OP(InvalidValue)); if (data == NULL) return; __glDlistAppendOp(gc, data, __glle_InvalidValue); }
void __gllc_InvalidEnum() { void *data; __GL_SETUP();
data = __glDlistAddOpUnaligned(gc, DLIST_SIZE(0), DLIST_GENERIC_OP(InvalidEnum)); if (data == NULL) return; __glDlistAppendOp(gc, data, __glle_InvalidEnum); }
void __gllc_InvalidOperation() { void *data; __GL_SETUP();
data = __glDlistAddOpUnaligned(gc, DLIST_SIZE(0), DLIST_GENERIC_OP(InvalidOperation)); if (data == NULL) return; __glDlistAppendOp(gc, data, __glle_InvalidOperation); }
/*
** These routines execute an error stored in a display list. */ const GLubyte * FASTCALL __glle_InvalidValue(__GLcontext *gc, const GLubyte *PC) { GLSETERROR(GL_INVALID_VALUE); return PC; }
const GLubyte * FASTCALL __glle_InvalidEnum(__GLcontext *gc, const GLubyte *PC) { GLSETERROR(GL_INVALID_ENUM); return PC; }
const GLubyte * FASTCALL __glle_InvalidOperation(__GLcontext *gc, const GLubyte *PC) { GLSETERROR(GL_INVALID_OPERATION); return PC; }
/***************************************************************************/ // This function compiles a poly material structure. It does not
// execute the record in COMPILE_AND_EXECUTE mode. The execution is done
// when the poly array buffer is flushed.
void APIENTRY __gllc_PolyMaterial(GLuint faceName, __GLmatChange *pdMat) { GLubyte *data, *data0; GLuint dirtyBits; GLuint size, newSize; __GL_SETUP();
ASSERTOPENGL(faceName == POLYDATA_MATERIAL_FRONT || faceName == POLYDATA_MATERIAL_BACK, "bad faceName\n");
// Allocate big enough record and resize it later
size = sizeof(__GLmatChange) + sizeof(GLuint) + sizeof(GLuint); data = (GLubyte *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(size), DLIST_GENERIC_OP(PolyMaterial)); if (data == NULL) return; data0 = data; dirtyBits = pdMat->dirtyBits;
// Skip size field to be filled in last
((GLuint *)data)++;
// Record face name
*((GLuint *) data)++ = faceName;
*((GLuint *) data)++ = dirtyBits;
if (dirtyBits & __GL_MATERIAL_AMBIENT) *((__GLcolor *) data)++ = pdMat->ambient;
if (dirtyBits & __GL_MATERIAL_DIFFUSE) *((__GLcolor *) data)++ = pdMat->diffuse;
if (dirtyBits & __GL_MATERIAL_SPECULAR) *((__GLcolor *) data)++ = pdMat->specular;
if (dirtyBits & __GL_MATERIAL_EMISSIVE) *((__GLcolor *) data)++ = pdMat->emissive;
if (dirtyBits & __GL_MATERIAL_SHININESS) *((__GLfloat *) data)++ = pdMat->shininess;
if (dirtyBits & __GL_MATERIAL_COLORINDEXES) { *((__GLfloat *) data)++ = pdMat->cmapa; *((__GLfloat *) data)++ = pdMat->cmapd; *((__GLfloat *) data)++ = pdMat->cmaps; }
// Now fill in the size field
newSize = (GLuint) (data - data0); *((GLuint *) data0) = newSize;
// Resize the record
__glDlistResizeCurrentOp(gc, DLIST_SIZE(size), DLIST_SIZE(newSize)); }
// Playback a PolyMaterial record in Begin.
const GLubyte * FASTCALL __glle_PolyMaterial(__GLcontext *gc, const GLubyte *PC) { GLubyte *data; POLYARRAY *pa; POLYDATA *pd; GLuint size, faceName, dirtyBits; __GLmatChange *pdMat; POLYMATERIAL *pm;
data = (GLubyte *) PC;
size = *((GLuint *) data)++; faceName = *((GLuint *) data)++; dirtyBits = *((GLuint *) data)++;
ASSERTOPENGL(faceName == POLYDATA_MATERIAL_FRONT || faceName == POLYDATA_MATERIAL_BACK, "bad faceName\n");
pa = gc->paTeb; if (pa->flags & POLYARRAY_IN_BEGIN) { // Update pa flags POLYARRAY_MATERIAL_FRONT and POLYARRAY_MATERIAL_BACK.
pa->flags |= faceName;
// Do front or back material for this vertex.
// Overwrite the previous material changes for this vertex if they exist since
// only the last material changes matter.
pd = pa->pdNextVertex;
// allocate __GLmatChange structure if this vertex hasn't got one
if (!(pd->flags & faceName)) { if (!(pdMat = PAMatAlloc())) return PC + size;
// Get POLYMATERIAL pointer after PAMatAlloc!
pm = GLTEB_CLTPOLYMATERIAL(); if (faceName == POLYDATA_MATERIAL_FRONT) pm->pdMaterial0[pd - pa->pdBuffer0].front = pdMat; else pm->pdMaterial0[pd - pa->pdBuffer0].back = pdMat;
pdMat->dirtyBits = dirtyBits; } else { pm = GLTEB_CLTPOLYMATERIAL(); if (faceName == POLYDATA_MATERIAL_FRONT) pdMat = pm->pdMaterial0[pd - pa->pdBuffer0].front; else pdMat = pm->pdMaterial0[pd - pa->pdBuffer0].back;
pdMat->dirtyBits |= dirtyBits; }
if (dirtyBits & __GL_MATERIAL_AMBIENT) pdMat->ambient = *((__GLcolor *) data)++;
if (dirtyBits & __GL_MATERIAL_DIFFUSE) pdMat->diffuse = *((__GLcolor *) data)++;
if (dirtyBits & __GL_MATERIAL_SPECULAR) pdMat->specular = *((__GLcolor *) data)++;
if (dirtyBits & __GL_MATERIAL_EMISSIVE) pdMat->emissive = *((__GLcolor *) data)++;
if (dirtyBits & __GL_MATERIAL_SHININESS) pdMat->shininess = *((__GLfloat *) data)++;
if (dirtyBits & __GL_MATERIAL_COLORINDEXES) { pdMat->cmapa = *((__GLfloat *) data)++; pdMat->cmapd = *((__GLfloat *) data)++; pdMat->cmaps = *((__GLfloat *) data)++; }
// Finally, update pd flags
pd->flags |= faceName; } else { // Something went wrong at playback time! We can either try to playback
// this record using the regular API or punt it altogether. I cannot think
// of a situation when this can happen, so we will punt it for now.
WARNING("Display list: playing back POLYMATERIAL outside BEGIN!\n"); }
return PC + size; }
// Compile a PolyData structure in Begin. If the poly data contains
// material changes, it will call __gllc_PolyMaterial to compile the material
// changes. This function does not execute the record in COMPILE_AND_EXECUTE
// mode. The execution is done when the poly array buffer is flushed.
void APIENTRY __glDlistCompilePolyData(__GLcontext *gc, GLboolean bPartial) { POLYARRAY *pa; POLYDATA *pd; GLubyte *data, *data0; GLuint pdflags; GLuint size, newSize; __GLlistExecFunc *fp;
ASSERTOPENGL(gc->dlist.beginRec, "not in being!\n");
// If we have already recorded it in PolyArrayFlushPartialPrimitive, skip it.
if (gc->dlist.skipPolyData) { gc->dlist.skipPolyData = GL_FALSE; return; }
pa = gc->paTeb; if (bPartial) { // Record only current attribute changes
pd = pa->pdNextVertex; if (!pd->flags) return; } else { pd = pa->pdNextVertex - 1; }
// Record material changes first.
if (pd->flags & (POLYDATA_MATERIAL_FRONT | POLYDATA_MATERIAL_BACK)) { POLYMATERIAL *pm;
pm = GLTEB_CLTPOLYMATERIAL();
if (pd->flags & POLYDATA_MATERIAL_FRONT) __gllc_PolyMaterial(POLYDATA_MATERIAL_FRONT, pm->pdMaterial0[pd - pa->pdBuffer0].front);
if (pd->flags & POLYDATA_MATERIAL_BACK) __gllc_PolyMaterial(POLYDATA_MATERIAL_BACK, pm->pdMaterial0[pd - pa->pdBuffer0].back);
if (bPartial) { if (!(pd->flags & ~(POLYDATA_MATERIAL_FRONT | POLYDATA_MATERIAL_BACK))) return; } }
// Record POLYARRAY_CLAMP_COLOR flag in the begin record.
if (pa->flags & POLYARRAY_CLAMP_COLOR) gc->dlist.beginRec->flags |= DLIST_BEGIN_HAS_CLAMP_COLOR;
// Make sure that we handle all the flags!
ASSERTOPENGL( !(pd->flags & ~(POLYDATA_EDGEFLAG_BOUNDARY | POLYDATA_EDGEFLAG_VALID | POLYDATA_COLOR_VALID | POLYDATA_NORMAL_VALID | POLYDATA_TEXTURE_VALID | POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4 | POLYDATA_DLIST_COLOR_4 | POLYDATA_FOG_VALID | POLYDATA_DLIST_TEXTURE1 | POLYDATA_DLIST_TEXTURE2 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE4 | POLYDATA_MATERIAL_FRONT | POLYDATA_MATERIAL_BACK)), "Unknown POLYDATA flags!\n");
// Get the flags that we are interested.
pdflags = pd->flags & (POLYDATA_EDGEFLAG_BOUNDARY | POLYDATA_EDGEFLAG_VALID | POLYDATA_COLOR_VALID | POLYDATA_NORMAL_VALID | POLYDATA_TEXTURE_VALID | POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4 | POLYDATA_DLIST_COLOR_4 | POLYDATA_DLIST_TEXTURE1 | POLYDATA_DLIST_TEXTURE2 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE4);
// Find out if it matches one of the following packed data structure for
// fast playback.
// C3F_V3F
// N3F_V3F
// C3F_N3F_V3F (non 1.1 format)
// C4F_N3F_V3F
// T2F_V3F
// T2F_C3F_V3F
// T2F_N3F_V3F
// T2F_C3F_N3F_V3F (non 1.1 format)
// T2F_C4F_N3F_V3F
#define VTYPE_V2F (POLYDATA_VERTEX2)
#define VTYPE_V3F (POLYDATA_VERTEX3)
#define VTYPE_V4F (POLYDATA_VERTEX4)
#define VTYPE_C3F (POLYDATA_COLOR_VALID)
#define VTYPE_C4F (POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4)
#define VTYPE_N3F (POLYDATA_NORMAL_VALID)
#define VTYPE_T2F (POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE2)
#define VTYPE_C3F_V3F (VTYPE_C3F | VTYPE_V3F)
#define VTYPE_N3F_V3F (VTYPE_N3F | VTYPE_V3F)
#define VTYPE_C3F_N3F_V3F (VTYPE_C3F | VTYPE_N3F | VTYPE_V3F)
#define VTYPE_C4F_N3F_V3F (VTYPE_C4F | VTYPE_N3F | VTYPE_V3F)
#define VTYPE_T2F_V3F (VTYPE_T2F | VTYPE_V3F)
#define VTYPE_T2F_C3F_V3F (VTYPE_T2F | VTYPE_C3F | VTYPE_V3F)
#define VTYPE_T2F_N3F_V3F (VTYPE_T2F | VTYPE_N3F | VTYPE_V3F)
#define VTYPE_T2F_C3F_N3F_V3F (VTYPE_T2F | VTYPE_C3F | VTYPE_N3F | VTYPE_V3F)
#define VTYPE_T2F_C4F_N3F_V3F (VTYPE_T2F | VTYPE_C4F | VTYPE_N3F | VTYPE_V3F)
// Default playback routine
fp = __glle_PolyData;
if (!gc->modes.colorIndexMode && !(pdflags & (POLYDATA_EDGEFLAG_BOUNDARY | POLYDATA_EDGEFLAG_VALID))) { switch (pdflags) { case VTYPE_V2F: case VTYPE_V3F: case VTYPE_V4F: ASSERTOPENGL(gc->dlist.mode != GL_COMPILE, "should have been recorded as a Vertex call\n"); break; case VTYPE_C3F_V3F: fp = __glle_PolyData_C3F_V3F; break; case VTYPE_N3F_V3F: fp = __glle_PolyData_N3F_V3F; break; case VTYPE_C3F_N3F_V3F: fp = __glle_PolyData_C3F_N3F_V3F; break; case VTYPE_C4F_N3F_V3F: fp = __glle_PolyData_C4F_N3F_V3F; break; case VTYPE_T2F_V3F: fp = __glle_PolyData_T2F_V3F; break; case VTYPE_T2F_C3F_V3F: fp = __glle_PolyData_T2F_C3F_V3F; break; case VTYPE_T2F_N3F_V3F: fp = __glle_PolyData_T2F_N3F_V3F; break; case VTYPE_T2F_C3F_N3F_V3F: fp = __glle_PolyData_T2F_C3F_N3F_V3F; break; case VTYPE_T2F_C4F_N3F_V3F: fp = __glle_PolyData_T2F_C4F_N3F_V3F; break; } }
// Allocate the dlist record. Allocate big enough record and resize it later.
size = sizeof(POLYDATA) + sizeof(GLuint); data = (GLubyte *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(size), fp); if (data == NULL) return; data0 = data; // Increment vertex count.
if (!bPartial) gc->dlist.beginRec->nVertices++;
// Compile the poly data record.
// The fast poly data records do not include size and flags fields.
if (fp == __glle_PolyData) { // Skip size field to be filled in last
((GLuint *) data)++;
// flags and edge flag
*((GLuint *) data)++ = pdflags; }
// Texture coord
if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE2 | POLYDATA_DLIST_TEXTURE1)) { *((__GLfloat *) data)++ = pd->texture.x; if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE2)) { *((__GLfloat *) data)++ = pd->texture.y; if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3)) { *((__GLfloat *) data)++ = pd->texture.z; if (pdflags & (POLYDATA_DLIST_TEXTURE4)) *((__GLfloat *) data)++ = pd->texture.w; } } }
// Color
if (pdflags & POLYDATA_COLOR_VALID) { *((__GLfloat *) data)++ = pd->colors[0].r; if (!gc->modes.colorIndexMode) { *((__GLfloat *) data)++ = pd->colors[0].g; *((__GLfloat *) data)++ = pd->colors[0].b; if (pdflags & POLYDATA_DLIST_COLOR_4) *((__GLfloat *) data)++ = pd->colors[0].a; } }
// Normal
if (pdflags & POLYDATA_NORMAL_VALID) { *((__GLfloat *) data)++ = pd->normal.x; *((__GLfloat *) data)++ = pd->normal.y; *((__GLfloat *) data)++ = pd->normal.z; }
// Vertex, evalcoord1, evalcoord2, evapoint1, or evalpoint2
if (pdflags & (POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4)) { ASSERTOPENGL(!bPartial, "vertex unexpected\n"); *((__GLfloat *) data)++ = pd->obj.x; if (pdflags & (POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4)) { *((__GLfloat *) data)++ = pd->obj.y; if (pdflags & (POLYDATA_VERTEX3 | POLYDATA_VERTEX4)) { *((__GLfloat *) data)++ = pd->obj.z; if (pdflags & (POLYDATA_VERTEX4)) *((__GLfloat *) data)++ = pd->obj.w; } } } else { ASSERTOPENGL(bPartial, "vertex expected\n"); }
// Now fill in the size field
newSize = (GLuint) (data - data0); if (fp == __glle_PolyData) *((GLuint *) data0) = newSize;
// Resize the record
__glDlistResizeCurrentOp(gc, DLIST_SIZE(size), DLIST_SIZE(newSize)); }
#ifndef __GL_ASM_FAST_DLIST_PLAYBACK
// Define fast playback routines for PolyData records.
#define __GLLE_POLYDATA_C3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_C3F_V3F
#define __GLLE_POLYDATA_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_N3F_V3F
#define __GLLE_POLYDATA_C3F_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_C3F_N3F_V3F
#define __GLLE_POLYDATA_C4F_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_C4F_N3F_V3F
#define __GLLE_POLYDATA_T2F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_T2F_V3F
#define __GLLE_POLYDATA_T2F_C3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_T2F_C3F_V3F
#define __GLLE_POLYDATA_T2F_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_T2F_N3F_V3F
#define __GLLE_POLYDATA_T2F_C3F_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_T2F_C3F_N3F_V3F
#define __GLLE_POLYDATA_T2F_C4F_N3F_V3F 1
#include "dl_pdata.h"
#undef __GLLE_POLYDATA_T2F_C4F_N3F_V3F
#endif // __GL_ASM_FAST_DLIST_PLAYBACK
// Playback a PolyData record in Begin.
const GLubyte * FASTCALL __glle_PolyData(__GLcontext *gc, const GLubyte *PC) { GLubyte *data; POLYARRAY *pa; POLYDATA *pd; GLuint size, pdflags;
data = (GLubyte *) PC;
size = *((GLuint *) data)++;
pa = gc->paTeb; if (pa->flags & POLYARRAY_IN_BEGIN) { pdflags = *((GLuint *) data)++;
// Make sure that we handle all the flags!
ASSERTOPENGL( !(pdflags & ~(POLYDATA_EDGEFLAG_BOUNDARY | POLYDATA_EDGEFLAG_VALID | POLYDATA_COLOR_VALID | POLYDATA_NORMAL_VALID | POLYDATA_TEXTURE_VALID | POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4 | POLYDATA_DLIST_COLOR_4 | POLYDATA_DLIST_TEXTURE1 | POLYDATA_DLIST_TEXTURE2 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE4)), "Unknown POLYDATA flags!\n");
// Update pa flags.
pa->flags |= pdflags & (POLYARRAY_VERTEX2 | POLYARRAY_VERTEX3 | POLYARRAY_VERTEX4 | POLYARRAY_TEXTURE1 | POLYARRAY_TEXTURE2 | POLYARRAY_TEXTURE3 | POLYARRAY_TEXTURE4);
// Update pd attributes.
pd = pa->pdNextVertex; pd->flags |= (pdflags & ~POLYDATA_EDGEFLAG_BOUNDARY);
// Edge flag
if (pdflags & POLYDATA_EDGEFLAG_VALID) { // Clear the edge flag here since they may be a previous edge flag
pd->flags &= ~POLYDATA_EDGEFLAG_BOUNDARY; pd->flags |= pdflags; pa->pdCurEdgeFlag = pd; }
// Texture coord
// We need to be careful here if it has 2 TexCoord calls with
// different sizes.
if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE2 | POLYDATA_DLIST_TEXTURE1)) { pd->texture.x = *((__GLfloat *) data)++; pa->pdCurTexture = pd;
if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3 | POLYDATA_DLIST_TEXTURE2)) pd->texture.y = *((__GLfloat *) data)++; else pd->texture.y = __glZero; if (pdflags & (POLYDATA_DLIST_TEXTURE4 | POLYDATA_DLIST_TEXTURE3)) pd->texture.z = *((__GLfloat *) data)++; else pd->texture.z = __glZero; if (pdflags & (POLYDATA_DLIST_TEXTURE4)) pd->texture.w = *((__GLfloat *) data)++; else pd->texture.w = __glOne; }
// Color
if (pdflags & POLYDATA_COLOR_VALID) { pd->color[0].r = *((__GLfloat *) data)++; if (!gc->modes.colorIndexMode) { pd->color[0].g = *((__GLfloat *) data)++; pd->color[0].b = *((__GLfloat *) data)++; if (pdflags & POLYDATA_DLIST_COLOR_4) pd->color[0].a = *((__GLfloat *) data)++; else pd->color[0].a = gc->alphaVertexScale; } pa->pdCurColor = pd; }
// Normal
if (pdflags & POLYDATA_NORMAL_VALID) { pd->normal.x = *((__GLfloat *) data)++; pd->normal.y = *((__GLfloat *) data)++; pd->normal.z = *((__GLfloat *) data)++; pa->pdCurNormal = pd; }
// Vertex, evalcoord1, evalcoord2, evapoint1, or evalpoint2
if (pdflags & (POLYARRAY_VERTEX2 | POLYARRAY_VERTEX3 | POLYARRAY_VERTEX4)) { pd->obj.x = *((__GLfloat *) data)++;
if (pdflags & (POLYDATA_VERTEX2 | POLYDATA_VERTEX3 | POLYDATA_VERTEX4)) pd->obj.y = *((__GLfloat *) data)++; if (pdflags & (POLYDATA_VERTEX3 | POLYDATA_VERTEX4)) pd->obj.z = *((__GLfloat *) data)++; else pd->obj.z = __glZero; if (pdflags & (POLYDATA_VERTEX4)) pd->obj.w = *((__GLfloat *) data)++; else pd->obj.w = __glOne;
// Advance vertex pointer
pa->pdNextVertex++; pd[1].flags = 0;
if (pd >= pa->pdFlush) PolyArrayFlushPartialPrimitive(); } } else { // Something went wrong at playback time! We can either try to playback
// this record using the regular API or punt it altogether. I cannot think
// of a situation when this can happen, so we will punt it for now.
WARNING("Display list: playing back POLYDATA outside BEGIN!\n"); }
return PC + size; }
void APIENTRY __gllc_ArrayElement(GLint i) { __GL_SETUP();
if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc);
VA_ArrayElementCompile(gc, i); }
#define COMPILEARRAYPOINTER(ap, i) \
((*(ap).pfnCompile)((ap).pointer + (i) * (ap).ibytes))
void FASTCALL VA_ArrayElementCompile(__GLcontext *gc, GLint i) { GLuint vaMask = gc->vertexArray.mask;
// Call the individual compilation routines. They handle Begin mode,
// color mode, and COMPILE_AND_EXECUTE mode correctly.
if (vaMask & VAMASK_EDGEFLAG_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.edgeFlag, i); if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.texCoord, i); if (vaMask & VAMASK_COLOR_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.color, i); if (vaMask & VAMASK_INDEX_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.index, i); if (vaMask & VAMASK_NORMAL_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.normal, i); if (vaMask & VAMASK_VERTEX_ENABLE_MASK) COMPILEARRAYPOINTER(gc->vertexArray.vertex, i); }
// Compile DrawArrays into Begin/End records. Since Begin/End records
// contain optimized POLYDATA records, execution speed of these records
// is optimal. However, it takes longer to compile this function using
// this approach. But with this method, we don't have to deal with color
// mode and COMPILE_AND_EXECUTE mode here.
void APIENTRY __gllc_DrawArrays(GLenum mode, GLint first, GLsizei count) { int i; POLYARRAY *pa; __GL_SETUP();
pa = gc->paTeb;
// Not allowed in begin/end.
if (pa->flags & POLYARRAY_IN_BEGIN) { __gllc_InvalidOperation(); return; }
if ((GLuint) mode > GL_POLYGON) { __gllc_InvalidEnum(); return; }
if (count < 0) { __gllc_InvalidValue(); return; } else if (!count) return;
// Find array element function to use.
if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc);
// Draw the array elements.
__gllc_Begin(mode); gc->dlist.beginRec->flags |= DLIST_BEGIN_DRAWARRAYS;
for (i = 0; i < count; i++) VA_ArrayElementCompile(gc, first + i);
__gllc_End(); }
#define __GL_PAD8(x) (((x) + 7) & ~7)
GLuint FASTCALL __glDrawElements_size(__GLcontext *gc, GLsizei nVertices, GLsizei nElements, struct __gllc_DrawElements_Rec *rec) { GLuint size; GLuint vaMask;
// Compute the size of each of the six arrays. Always keep size and address
// QWORD aligned since some arrays may use GLdouble.
size = __GL_PAD8(sizeof(struct __gllc_DrawElements_Rec)); vaMask = gc->vertexArray.mask;
if (vaMask & VAMASK_EDGEFLAG_ENABLE_MASK) { rec->edgeFlagOff = size; size += __GL_PAD8(nVertices * sizeof(GLboolean)); } else rec->edgeFlagOff = 0;
if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) { rec->texCoordOff = size; size += __GL_PAD8(nVertices * gc->vertexArray.texCoord.size * __GLTYPESIZE(gc->vertexArray.texCoord.type)); } else rec->texCoordOff = 0;
if (vaMask & VAMASK_COLOR_ENABLE_MASK) { rec->colorOff = size; size += __GL_PAD8(nVertices * gc->vertexArray.color.size * __GLTYPESIZE(gc->vertexArray.color.type)); } else rec->colorOff = 0;
if (vaMask & VAMASK_INDEX_ENABLE_MASK) { rec->indexOff = size; size += __GL_PAD8(nVertices * __GLTYPESIZE(gc->vertexArray.index.type)); } else rec->indexOff = 0;
if (vaMask & VAMASK_NORMAL_ENABLE_MASK) { rec->normalOff = size; size += __GL_PAD8(nVertices * 3 * __GLTYPESIZE(gc->vertexArray.normal.type)); } else rec->normalOff = 0;
if (vaMask & VAMASK_VERTEX_ENABLE_MASK) { rec->vertexOff = size; size += __GL_PAD8(nVertices * gc->vertexArray.vertex.size * __GLTYPESIZE(gc->vertexArray.vertex.type)); } else rec->vertexOff = 0;
rec->mapOff = size; size += __GL_PAD8(nElements * sizeof(GLubyte));
return(size); }
void FASTCALL __gllc_ReducedElementsHandler(__GLcontext *gc, GLenum mode, GLsizei iVertexCount, GLsizei iVertexBase, VAMAP *pvmVertices, GLsizei iElementCount, GLubyte *pbElements, GLboolean fPartial) { GLuint vaMask; GLuint size; GLubyte *pv1, *pv2; GLsizei stride; GLsizei i; struct __gllc_DrawElements_Rec *data, drawElementsRec;
ASSERTOPENGL(pvmVertices != NULL, "__gllc_ReducedElementsHandler requires mapped vertices\n"); // Allocate the record.
size = __glDrawElements_size(gc, iVertexCount, iElementCount, &drawElementsRec); data = (struct __gllc_DrawElements_Rec *) __glDlistAddOpAligned(gc, DLIST_SIZE(size), DLIST_GENERIC_OP(DrawElements)); if (data == NULL) { return; }
#ifndef _IA64_
ASSERTOPENGL((UINT_PTR) data == __GL_PAD8((UINT_PTR) data), "data not qword aligned\n"); #endif
vaMask = gc->vertexArray.mask; data->mode = mode; data->iElementCount = iElementCount; data->iVertexCount = iVertexCount; data->vaMask = vaMask; data->partial = fPartial; data->recSize = size; data->edgeFlagOff = drawElementsRec.edgeFlagOff; data->texCoordOff = drawElementsRec.texCoordOff; data->indexOff = drawElementsRec.indexOff; data->colorOff = drawElementsRec.colorOff; data->normalOff = drawElementsRec.normalOff; data->vertexOff = drawElementsRec.vertexOff; data->mapOff = drawElementsRec.mapOff;
// Record the vertex arrays.
// Note that iVertexBase parameter is not used, since all accesses here are
// 0-based. It is there for function ptr compatibility with glcltReducedElementHandler
if (vaMask & VAMASK_EDGEFLAG_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->edgeFlagOff]; pv1 = (GLubyte *) gc->vertexArray.edgeFlag.pointer; stride = gc->vertexArray.edgeFlag.ibytes;
for (i = 0; i < iVertexCount; i++) { *((GLboolean *) pv2) = *((GLboolean *) (pv1 + pvmVertices[i].iIn * stride)); pv2 += sizeof(GLboolean); } }
if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->texCoordOff]; size = gc->vertexArray.texCoord.size * __GLTYPESIZE(gc->vertexArray.texCoord.type); pv1 = (GLubyte *) gc->vertexArray.texCoord.pointer; stride = gc->vertexArray.texCoord.ibytes; data->texCoordSize = gc->vertexArray.texCoord.size; data->texCoordType = gc->vertexArray.texCoord.type;
for (i = 0; i < iVertexCount; i++) { memcpy(pv2, pv1 + pvmVertices[i].iIn * stride, size); pv2 += size; } }
if (vaMask & VAMASK_COLOR_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->colorOff]; size = gc->vertexArray.color.size * __GLTYPESIZE(gc->vertexArray.color.type); pv1 = (GLubyte *) gc->vertexArray.color.pointer; stride = gc->vertexArray.color.ibytes; data->colorSize = gc->vertexArray.color.size; data->colorType = gc->vertexArray.color.type;
for (i = 0; i < iVertexCount; i++) { memcpy(pv2, pv1 + pvmVertices[i].iIn * stride, size); pv2 += size; } }
if (vaMask & VAMASK_INDEX_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->indexOff]; size = __GLTYPESIZE(gc->vertexArray.index.type); pv1 = (GLubyte *) gc->vertexArray.index.pointer; stride = gc->vertexArray.index.ibytes; data->indexType = gc->vertexArray.index.type;
for (i = 0; i < iVertexCount; i++) { memcpy(pv2, pv1 + pvmVertices[i].iIn * stride, size); pv2 += size; } }
if (vaMask & VAMASK_NORMAL_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->normalOff]; size = 3 * __GLTYPESIZE(gc->vertexArray.normal.type); pv1 = (GLubyte *) gc->vertexArray.normal.pointer; stride = gc->vertexArray.normal.ibytes; data->normalType = gc->vertexArray.normal.type;
for (i = 0; i < iVertexCount; i++) { memcpy(pv2, pv1 + pvmVertices[i].iIn * stride, size); pv2 += size; } }
if (vaMask & VAMASK_VERTEX_ENABLE_MASK) { pv2 = &((GLubyte *) data)[data->vertexOff]; size = gc->vertexArray.vertex.size * __GLTYPESIZE(gc->vertexArray.vertex.type); pv1 = (GLubyte *) gc->vertexArray.vertex.pointer; stride = gc->vertexArray.vertex.ibytes; data->vertexSize = gc->vertexArray.vertex.size; data->vertexType = gc->vertexArray.vertex.type;
for (i = 0; i < iVertexCount; i++) { memcpy(pv2, pv1 + pvmVertices[i].iIn * stride, size); pv2 += size; } }
// Record new index mapping array.
pv2 = &((GLubyte *) data)[data->mapOff]; memcpy(pv2, pbElements, iElementCount*sizeof(GLubyte));
__glDlistAppendOp(gc, data, __glle_DrawElements); }
void APIENTRY __gllc_DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *pIn) { POLYARRAY *pa; GLuint iIn; GLsizei iCount; struct __gllc_DrawElementsBegin_Rec *dataBegin;
__GL_SETUP();
// Flush the cached memory pointers if we are in COMPILE_AND_EXECUTE mode.
// See __glShrinkDlist for details.
if (gc->dlist.mode == GL_COMPILE_AND_EXECUTE) glsbAttention();
pa = gc->paTeb;
// If we are already in the begin/end bracket, return an error.
if (pa->flags & POLYARRAY_IN_BEGIN) { __gllc_InvalidOperation(); return; }
if ((GLuint) mode > GL_POLYGON) { __gllc_InvalidEnum(); return; }
if (count < 0) { __gllc_InvalidValue(); return; } else if (!count) return;
switch (type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_SHORT: case GL_UNSIGNED_INT: break; default: __gllc_InvalidEnum(); return; }
// Find array element function to use.
if (gc->vertexArray.flags & __GL_VERTEX_ARRAY_DIRTY) VA_ValidateArrayPointers(gc);
// Convert Points, Line Loop and Polygon to DrawArrays call. Points and Polygon
// don't benefit from optimization in this function. Further, Polygon and
// Line Loop are too tricky to deal with in this function.
if (mode == GL_POINTS || mode == GL_LINE_LOOP || mode == GL_POLYGON) { __gllc_Begin(mode); gc->dlist.beginRec->flags |= DLIST_BEGIN_DRAWARRAYS;
for (iCount = 0; iCount < count; iCount++) { // Get next input index.
if (type == GL_UNSIGNED_BYTE) iIn = (GLuint) ((GLubyte *) pIn)[iCount]; else if (type == GL_UNSIGNED_SHORT) iIn = (GLuint) ((GLushort *) pIn)[iCount]; else iIn = (GLuint) ((GLuint *) pIn)[iCount];
VA_ArrayElementCompile(gc, iIn); }
__gllc_End(); return; }
// Allocate begin record
dataBegin = (struct __gllc_DrawElementsBegin_Rec *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(sizeof(struct __gllc_DrawElementsBegin_Rec)), DLIST_GENERIC_OP(DrawElementsBegin)); if (dataBegin == NULL) { return; }
dataBegin->mode = mode; dataBegin->count = min(count, VA_DRAWELEM_MAP_SIZE); dataBegin->vaMask = gc->vertexArray.mask; __glDlistAppendOp(gc, dataBegin, __glle_DrawElementsBegin);
// Reduce input data into easily processed chunks
ReduceDrawElements(gc, mode, count, type, pIn, __gllc_ReducedElementsHandler); }
const GLubyte * FASTCALL __glle_DrawElementsBegin(__GLcontext *gc, const GLubyte *PC) { struct __gllc_DrawElementsBegin_Rec *data;
// Not allowed in begin/end.
// Must use the client side begin state
if (gc->paTeb->flags & POLYARRAY_IN_BEGIN) { GLSETERROR(GL_INVALID_OPERATION); // Mark saved state as invalid
gc->savedVertexArray.flags = 0xffffffff; goto __glle_DrawElementsBegin_exit; }
data = (struct __gllc_DrawElementsBegin_Rec *) PC;
// Save vertex array states.
gc->savedVertexArray = gc->vertexArray;
// Set up temporary vertex arrays.
// By setting up the mask value in gc, we don't need to call EnableClientState
// and DisableClientState. We still need to set up pointers for the enabled
// arrays.
gc->vertexArray.mask = data->vaMask; // Force validation since we just completely changed the vertex array
// enable state
VA_ValidateArrayPointers(gc);
// Begin primitive
VA_DrawElementsBegin(gc->paTeb, data->mode, data->count); __glle_DrawElementsBegin_exit: return PC + sizeof(struct __gllc_DrawElementsBegin_Rec); }
void APIENTRY __gllc_DrawRangeElementsWIN(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *pIn) { // !!! Currently we call the DrawElements function here when in lc mode.
// If compile time performance for DrawRangeElements becomes an issue, then
// we can flesh out this function.
__gllc_DrawElements( mode, count, type, pIn ); }
const GLubyte * FASTCALL __glle_DrawElements(__GLcontext *gc, const GLubyte *PC) { GLuint vaMask; POLYARRAY *pa; struct __gllc_DrawElements_Rec *data;
data = (struct __gllc_DrawElements_Rec *) PC; pa = gc->paTeb; // Must be in begin since DrawElementsBegin has started the primitive
// Must use the client side begin state
if ((pa->flags & POLYARRAY_IN_BEGIN) == 0 || gc->savedVertexArray.flags == 0xffffffff) { GLSETERROR(GL_INVALID_OPERATION); goto __glle_DrawElements_exit; }
vaMask = data->vaMask;
// Set up temporary vertex arrays.
// We need to temporarily mask off the begin flag so that these
// calls can succeed. We probably want to do something smarter
// that avoids parameter validation but this is good enough for now
// Note that in immediate mode, the array function pointers are set up
// once in __glle_DrawElementsBegin and remain unchanged until all
// sub-batches are processed. In COMPILE_AND_EXECUTE mode, the array
// function pointers are also set up once in __glle_DrawElementsBegin.
// Since these function pointers are the same for compilation and
// execution, we don't need to re-validate them for each sub-batch here.
pa->flags ^= POLYARRAY_IN_BEGIN; if (vaMask & VAMASK_EDGEFLAG_ENABLE_MASK) glcltEdgeFlagPointer(0, &((GLubyte *) data)[data->edgeFlagOff]);
if (vaMask & VAMASK_TEXCOORD_ENABLE_MASK) glcltTexCoordPointer(data->texCoordSize, data->texCoordType, 0, &((GLubyte *) data)[data->texCoordOff]);
if (vaMask & VAMASK_COLOR_ENABLE_MASK) glcltColorPointer(data->colorSize, data->colorType, 0, &((GLubyte *) data)[data->colorOff]);
if (vaMask & VAMASK_INDEX_ENABLE_MASK) glcltIndexPointer(data->indexType, 0, &((GLubyte *) data)[data->indexOff]);
if (vaMask & VAMASK_NORMAL_ENABLE_MASK) glcltNormalPointer(data->normalType, 0, &((GLubyte *) data)[data->normalOff]);
if (vaMask & VAMASK_VERTEX_ENABLE_MASK) glcltVertexPointer(data->vertexSize, data->vertexType, 0, &((GLubyte *) data)[data->vertexOff]);
pa->flags ^= POLYARRAY_IN_BEGIN; // Call immediate mode chunk handler
glcltReducedElementsHandler(gc, data->mode, data->iVertexCount, 0, NULL, data->iElementCount, (GLubyte *)data+data->mapOff, data->partial);
// Restore vertex array states in the following conditions:
// 1. The DrawElements record is completed
// 2. It is in COMPILE_AND_EXECUTE mode and it is not called as a result
// of executing a CallList record. That is, the record is being
// compile *and* executed at the same time.
if ((!data->partial) || ((gc->dlist.mode == GL_COMPILE_AND_EXECUTE) && !gc->dlist.nesting)) { gc->vertexArray = gc->savedVertexArray; }
__glle_DrawElements_exit: return PC + data->recSize; }
void APIENTRY __gllc_Begin ( IN GLenum mode ) { POLYARRAY *pa; struct __gllc_Begin_Rec *data; __GL_SETUP();
// Flush the cached memory pointers if we are in COMPILE_AND_EXECUTE mode.
// See __glShrinkDlist for details.
if (gc->dlist.mode == GL_COMPILE_AND_EXECUTE) glsbAttention();
// If we are already in the begin/end bracket, return an error.
pa = gc->paTeb; if (pa->flags & POLYARRAY_IN_BEGIN) { __gllc_InvalidOperation(); return; }
if ((GLuint) mode > GL_POLYGON) { __gllc_InvalidEnum(); return; }
// Add the Begin record.
data = (struct __gllc_Begin_Rec *) __glDlistAddOpUnaligned(gc, DLIST_SIZE(sizeof(struct __gllc_Begin_Rec)), DLIST_GENERIC_OP(Begin)); if (data == NULL) return; data->mode = mode; data->flags = 0; data->nVertices = 0;
gc->dlist.skipPolyData = GL_FALSE;
// Use poly array code to compile the data structure for this primitive.
(*gc->savedCltProcTable.glDispatchTable.glBegin)(mode);
// Save the Begin record pointer. We are now compiling the poly array
// primitive. It is set to NULL in End.
gc->dlist.beginRec = data; }
const GLubyte * FASTCALL __glle_Begin(__GLcontext *gc, const GLubyte *PC) { POLYARRAY *pa; struct __gllc_Begin_Rec *data;
data = (struct __gllc_Begin_Rec *) PC;
pa = gc->paTeb;
// try not to break the poly data records into batches! The number 8
// is loosely chosen to allow for the poly array entry, the reserved
// polygon entries, and the flush limit. At worst, it causes an
// unnecessary attention!
if (data->nVertices <= (GLint) gc->vertex.pdBufSize - 8 && data->nVertices >= (GLint) (pa->pdBufferMax - pa->pdBufferNext + 1 - 8)) glsbAttention();
// call glcltBegin first
(*gc->savedCltProcTable.glDispatchTable.glBegin)(data->mode); if (data->flags & DLIST_BEGIN_DRAWARRAYS) pa->flags |= POLYARRAY_SAME_POLYDATA_TYPE;
// Set POLYARRAY_CLAMP_COLOR flag.
if (data->flags & DLIST_BEGIN_HAS_CLAMP_COLOR) pa->flags |= POLYARRAY_CLAMP_COLOR;
// handle "otherColor"
if (data->flags & DLIST_BEGIN_HAS_OTHER_COLOR) { if (gc->modes.colorIndexMode) (*gc->savedCltProcTable.glDispatchTable.glColor4fv)((GLfloat *) &data->otherColor); else (*gc->savedCltProcTable.glDispatchTable.glIndexf)(data->otherColor.r); }
return PC + sizeof(struct __gllc_Begin_Rec); }
void APIENTRY __gllc_End ( void ) { GLuint size; POLYARRAY *pa; void *data; __GL_SETUP();
pa = gc->paTeb;
// If we are compiling poly array, finish the poly array processing.
// Note that we may have aborted poly array compilation in CallList(s).
// In that case, we need to compile an End record.
if (gc->dlist.beginRec) { ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin!\n");
// Record the last POLYDATA since it may contain attribute changes.
__glDlistCompilePolyData(gc, GL_TRUE);
// Call glcltEnd to finish the primitive.
(*gc->savedCltProcTable.glDispatchTable.glEnd)();
// Record the End call.
__glDlistAddOpUnaligned(gc, DLIST_SIZE(0), DLIST_GENERIC_OP(End));
// If we are in COMPILE mode, we need to reset the command buffer,
// the poly array buffer, and the poly material buffer.
if (gc->dlist.mode == GL_COMPILE) { glsbResetBuffers(TRUE);
// Clear begin flag too
pa->flags &= ~POLYARRAY_IN_BEGIN; }
// Terminate poly array compilation
gc->dlist.beginRec = NULL; } else { // Record the call.
data = __glDlistAddOpUnaligned(gc, DLIST_SIZE(0), DLIST_GENERIC_OP(End)); if (data == NULL) return; __glDlistAppendOp(gc, data, __glle_End); } }
const GLubyte * FASTCALL __glle_End(__GLcontext *gc, const GLubyte *PC) {
(*gc->savedCltProcTable.glDispatchTable.glEnd)(); return PC; }
|