Windows2003-3790/multimedia/opengl/dlist/dl_opt.c
2020-09-30 16:53:55 +02:00

1387 lines
40 KiB
C

/******************************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;
}