|
|
@@ -1,4 +1,4 @@ |
|
|
|
/* $Id: t_imm_dlist.c,v 1.19 2001/05/14 09:00:51 keithw Exp $ */ |
|
|
|
/* $Id: t_imm_dlist.c,v 1.20 2001/06/04 16:09:28 keithw Exp $ */ |
|
|
|
|
|
|
|
/* |
|
|
|
* Mesa 3-D graphics library |
|
|
@@ -63,6 +63,7 @@ typedef struct { |
|
|
|
} TNLvertexcassette; |
|
|
|
|
|
|
|
static void execute_compiled_cassette( GLcontext *ctx, void *data ); |
|
|
|
static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM ); |
|
|
|
|
|
|
|
|
|
|
|
/* Insert the active immediate struct onto the display list currently |
|
|
@@ -143,6 +144,93 @@ _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM ) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void fixup_compiled_primitives( GLcontext *ctx, struct immediate *IM ) |
|
|
|
{ |
|
|
|
TNLcontext *tnl = TNL_CONTEXT(ctx); |
|
|
|
|
|
|
|
/* Can potentially overwrite primitive details - need to save the |
|
|
|
* first slot: |
|
|
|
*/ |
|
|
|
tnl->DlistPrimitive = IM->Primitive[IM->Start]; |
|
|
|
tnl->DlistPrimitiveLength = IM->PrimitiveLength[IM->Start]; |
|
|
|
tnl->DlistLastPrimitive = IM->LastPrimitive; |
|
|
|
|
|
|
|
/* The first primitive may be different from what was recorded in |
|
|
|
* the immediate struct. Consider an immediate that starts with a |
|
|
|
* glBegin, compiled in a display list, which is called from within |
|
|
|
* an existing Begin/End object. |
|
|
|
*/ |
|
|
|
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { |
|
|
|
GLuint i; |
|
|
|
|
|
|
|
if (IM->BeginState & VERT_ERROR_1) |
|
|
|
_mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd"); |
|
|
|
|
|
|
|
for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i]) |
|
|
|
if (IM->Flag[i] & (VERT_BEGIN|VERT_END_VB)) |
|
|
|
break; |
|
|
|
|
|
|
|
/* Would like to just ignore vertices upto this point. Can't |
|
|
|
* set copystart because it might skip materials? |
|
|
|
*/ |
|
|
|
ASSERT(IM->Start == IM->CopyStart); |
|
|
|
if (i > IM->CopyStart) { |
|
|
|
IM->Primitive[IM->CopyStart] = GL_POLYGON+1; |
|
|
|
IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart; |
|
|
|
if (IM->Flag[i] & VERT_END_VB) { |
|
|
|
IM->Primitive[IM->CopyStart] |= PRIM_LAST; |
|
|
|
IM->LastPrimitive = IM->CopyStart; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
GLuint i; |
|
|
|
|
|
|
|
if (IM->BeginState & VERT_ERROR_0) |
|
|
|
_mesa_error( ctx, GL_INVALID_OPERATION, "glBegin/glEnd"); |
|
|
|
|
|
|
|
if (IM->CopyStart == IM->Start && |
|
|
|
IM->Flag[IM->Start] & (VERT_END|VERT_END_VB)) |
|
|
|
{ |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
IM->Primitive[IM->CopyStart] = ctx->Driver.CurrentExecPrimitive; |
|
|
|
if (tnl->ExecParity) |
|
|
|
IM->Primitive[IM->CopyStart] |= PRIM_PARITY; |
|
|
|
|
|
|
|
/* one of these should be true, else we'll be in an infinite loop |
|
|
|
*/ |
|
|
|
ASSERT(IM->PrimitiveLength[IM->Start] > 0 || |
|
|
|
IM->Flag[IM->Start] & (VERT_END|VERT_END_VB)); |
|
|
|
|
|
|
|
for (i = IM->Start ; i <= IM->Count ; i += IM->PrimitiveLength[i]) |
|
|
|
if (IM->Flag[i] & (VERT_END|VERT_END_VB)) { |
|
|
|
IM->PrimitiveLength[IM->CopyStart] = i - IM->CopyStart; |
|
|
|
if (IM->Flag[i] & VERT_END_VB) { |
|
|
|
IM->Primitive[IM->CopyStart] |= PRIM_LAST; |
|
|
|
IM->LastPrimitive = IM->CopyStart; |
|
|
|
} |
|
|
|
if (IM->Flag[i] & VERT_END) { |
|
|
|
IM->Primitive[IM->CopyStart] |= PRIM_END; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Undo any changes potentially made to the immediate in the range |
|
|
|
* IM->Start..IM->Count above. |
|
|
|
*/ |
|
|
|
static void restore_compiled_primitives( GLcontext *ctx, struct immediate *IM ) |
|
|
|
{ |
|
|
|
TNLcontext *tnl = TNL_CONTEXT(ctx); |
|
|
|
IM->Primitive[IM->Start] = tnl->DlistPrimitive; |
|
|
|
IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
execute_compiled_cassette( GLcontext *ctx, void *data ) |
|
|
|
{ |
|
|
@@ -152,12 +240,6 @@ execute_compiled_cassette( GLcontext *ctx, void *data ) |
|
|
|
|
|
|
|
/* fprintf(stderr, "%s\n", __FUNCTION__); */ |
|
|
|
|
|
|
|
if (ctx->NewState) |
|
|
|
_mesa_update_state(ctx); |
|
|
|
|
|
|
|
if (tnl->pipeline.build_state_changes) |
|
|
|
_tnl_validate_pipeline( ctx ); |
|
|
|
|
|
|
|
IM->Start = node->Start; |
|
|
|
IM->CopyStart = node->Start; |
|
|
|
IM->Count = node->Count; |
|
|
@@ -183,11 +265,10 @@ execute_compiled_cassette( GLcontext *ctx, void *data ) |
|
|
|
_tnl_print_vert_flags("orflag", IM->OrFlag); |
|
|
|
} |
|
|
|
|
|
|
|
if (IM->Count == IM->Start) { |
|
|
|
_tnl_copy_to_current( ctx, IM, IM->OrFlag ); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
/* Need to respect 'HardBeginEnd' even if the commands are looped |
|
|
|
* back to a driver tnl module. |
|
|
|
*/ |
|
|
|
if (IM->SavedBeginState) { |
|
|
|
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) |
|
|
|
tnl->ReplayHardBeginEnd = 1; |
|
|
@@ -202,10 +283,35 @@ execute_compiled_cassette( GLcontext *ctx, void *data ) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
_tnl_fixup_compiled_cassette( ctx, IM ); |
|
|
|
_tnl_get_exec_copy_verts( ctx, IM ); |
|
|
|
_tnl_run_cassette( ctx, IM ); |
|
|
|
_tnl_restore_compiled_cassette( ctx, IM ); |
|
|
|
if (tnl->LoopbackDListCassettes) { |
|
|
|
fixup_compiled_primitives( ctx, IM ); |
|
|
|
loopback_compiled_cassette( ctx, IM ); |
|
|
|
restore_compiled_primitives( ctx, IM ); |
|
|
|
} |
|
|
|
else if (IM->Count == IM->Start) { |
|
|
|
_tnl_copy_to_current( ctx, IM, IM->OrFlag ); |
|
|
|
} |
|
|
|
else { |
|
|
|
if (ctx->NewState) |
|
|
|
_mesa_update_state(ctx); |
|
|
|
|
|
|
|
if (tnl->pipeline.build_state_changes) |
|
|
|
_tnl_validate_pipeline( ctx ); |
|
|
|
|
|
|
|
_tnl_fixup_compiled_cassette( ctx, IM ); |
|
|
|
fixup_compiled_primitives( ctx, IM ); |
|
|
|
|
|
|
|
if (IM->Primitive[IM->LastPrimitive] & PRIM_END) |
|
|
|
ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; |
|
|
|
else |
|
|
|
ctx->Driver.CurrentExecPrimitive = |
|
|
|
IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK; |
|
|
|
|
|
|
|
_tnl_get_exec_copy_verts( ctx, IM ); |
|
|
|
_tnl_run_cassette( ctx, IM ); |
|
|
|
|
|
|
|
restore_compiled_primitives( ctx, IM ); |
|
|
|
} |
|
|
|
|
|
|
|
if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) |
|
|
|
tnl->ReplayHardBeginEnd = 0; |
|
|
@@ -322,3 +428,162 @@ _tnl_dlist_init( GLcontext *ctx ) |
|
|
|
destroy_compiled_cassette, |
|
|
|
print_compiled_cassette ); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void emit_material( struct gl_material *src, GLuint bitmask ) |
|
|
|
{ |
|
|
|
if (bitmask & FRONT_EMISSION_BIT) |
|
|
|
glMaterialfv( GL_FRONT, GL_EMISSION, src[0].Emission ); |
|
|
|
|
|
|
|
if (bitmask & BACK_EMISSION_BIT) |
|
|
|
glMaterialfv( GL_BACK, GL_EMISSION, src[1].Emission ); |
|
|
|
|
|
|
|
if (bitmask & FRONT_AMBIENT_BIT) |
|
|
|
glMaterialfv( GL_FRONT, GL_AMBIENT, src[0].Ambient ); |
|
|
|
|
|
|
|
if (bitmask & BACK_AMBIENT_BIT) |
|
|
|
glMaterialfv( GL_BACK, GL_AMBIENT, src[1].Ambient ); |
|
|
|
|
|
|
|
if (bitmask & FRONT_DIFFUSE_BIT) |
|
|
|
glMaterialfv( GL_FRONT, GL_DIFFUSE, src[0].Diffuse ); |
|
|
|
|
|
|
|
if (bitmask & BACK_DIFFUSE_BIT) |
|
|
|
glMaterialfv( GL_BACK, GL_DIFFUSE, src[1].Diffuse ); |
|
|
|
|
|
|
|
if (bitmask & FRONT_SPECULAR_BIT) |
|
|
|
glMaterialfv( GL_FRONT, GL_SPECULAR, src[0].Specular ); |
|
|
|
|
|
|
|
if (bitmask & BACK_SPECULAR_BIT) |
|
|
|
glMaterialfv( GL_BACK, GL_SPECULAR, src[1].Specular ); |
|
|
|
|
|
|
|
if (bitmask & FRONT_SHININESS_BIT) |
|
|
|
glMaterialfv( GL_FRONT, GL_SHININESS, &src[0].Shininess ); |
|
|
|
|
|
|
|
if (bitmask & BACK_SHININESS_BIT) |
|
|
|
glMaterialfv( GL_BACK, GL_SHININESS, &src[1].Shininess ); |
|
|
|
|
|
|
|
if (bitmask & FRONT_INDEXES_BIT) { |
|
|
|
GLfloat ind[3]; |
|
|
|
ind[0] = src[0].AmbientIndex; |
|
|
|
ind[1] = src[0].DiffuseIndex; |
|
|
|
ind[2] = src[0].SpecularIndex; |
|
|
|
glMaterialfv( GL_FRONT, GL_COLOR_INDEXES, ind ); |
|
|
|
} |
|
|
|
|
|
|
|
if (bitmask & BACK_INDEXES_BIT) { |
|
|
|
GLfloat ind[3]; |
|
|
|
ind[0] = src[1].AmbientIndex; |
|
|
|
ind[1] = src[1].DiffuseIndex; |
|
|
|
ind[2] = src[1].SpecularIndex; |
|
|
|
glMaterialfv( GL_BACK, GL_COLOR_INDEXES, ind ); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Low-performance helper function to allow driver-supplied tnl |
|
|
|
* modules to process tnl display lists. This is primarily supplied |
|
|
|
* to avoid fallbacks if CallList is invoked inside a Begin/End pair. |
|
|
|
* For higher performance, drivers should fallback to tnl (if outside |
|
|
|
* begin/end), or (for tnl hardware) implement their own display list |
|
|
|
* mechanism. |
|
|
|
*/ |
|
|
|
static void loopback_compiled_cassette( GLcontext *ctx, struct immediate *IM ) |
|
|
|
{ |
|
|
|
GLuint i; |
|
|
|
GLuint *flags = IM->Flag; |
|
|
|
GLuint orflag = IM->OrFlag; |
|
|
|
GLuint j; |
|
|
|
void (*vertex)( const GLfloat * ); |
|
|
|
void (*texcoordfv[MAX_TEXTURE_UNITS])( GLuint, const GLfloat * ); |
|
|
|
GLuint maxtex = 0; |
|
|
|
GLuint p, length, prim = 0; |
|
|
|
|
|
|
|
if (orflag & VERT_OBJ_234) |
|
|
|
vertex = glVertex4fv; |
|
|
|
else |
|
|
|
vertex = glVertex3fv; |
|
|
|
|
|
|
|
if (orflag & VERT_TEX_ANY) { |
|
|
|
for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) { |
|
|
|
if (orflag & VERT_TEX(j)) { |
|
|
|
maxtex = j+1; |
|
|
|
if ((IM->TexSize & TEX_SIZE_4(j)) == TEX_SIZE_4(j)) |
|
|
|
texcoordfv[j] = glMultiTexCoord4fvARB; |
|
|
|
else if (IM->TexSize & TEX_SIZE_3(j)) |
|
|
|
texcoordfv[j] = glMultiTexCoord3fvARB; |
|
|
|
else |
|
|
|
texcoordfv[j] = glMultiTexCoord2fvARB; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for (p = IM->Start ; !(prim & PRIM_LAST) ; p += length) |
|
|
|
{ |
|
|
|
prim = IM->Primitive[p]; |
|
|
|
length= IM->PrimitiveLength[p]; |
|
|
|
ASSERT(length || (prim & PRIM_LAST)); |
|
|
|
ASSERT((prim & PRIM_MODE_MASK) <= GL_POLYGON+1); |
|
|
|
|
|
|
|
if (prim & PRIM_BEGIN) { |
|
|
|
/* fprintf(stderr, "begin %s\n", _mesa_prim_name[prim&PRIM_MODE_MASK]); */ |
|
|
|
glBegin(prim & PRIM_MODE_MASK); |
|
|
|
} |
|
|
|
|
|
|
|
for ( i = p ; i <= p+length ; i++) { |
|
|
|
if (flags[i] & VERT_TEX_ANY) { |
|
|
|
GLuint k; |
|
|
|
for (k = 0 ; k < maxtex ; k++) { |
|
|
|
if (flags[i] & VERT_TEX(k)) { |
|
|
|
texcoordfv[k]( GL_TEXTURE0_ARB + k, IM->TexCoord[k][i] ); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (flags[i] & VERT_NORM) { |
|
|
|
/* fprintf(stderr, "normal %d: %f %f %f\n", i, */ |
|
|
|
/* IM->Normal[i][0], IM->Normal[i][1], IM->Normal[i][2]); */ |
|
|
|
glNormal3fv(IM->Normal[i]); |
|
|
|
} |
|
|
|
|
|
|
|
if (flags[i] & VERT_RGBA) { |
|
|
|
/* fprintf(stderr, "color %d: %f %f %f\n", i, */ |
|
|
|
/* IM->Color[i][0], IM->Color[i][1], IM->Color[i][2]); */ |
|
|
|
glColor4fv( IM->Color[i] ); |
|
|
|
} |
|
|
|
|
|
|
|
if (flags[i] & VERT_SPEC_RGB) |
|
|
|
glSecondaryColor3fvEXT( IM->SecondaryColor[i] ); |
|
|
|
|
|
|
|
if (flags[i] & VERT_FOG_COORD) |
|
|
|
glFogCoordfEXT( IM->FogCoord[i] ); |
|
|
|
|
|
|
|
if (flags[i] & VERT_INDEX) |
|
|
|
glIndexi( IM->Index[i] ); |
|
|
|
|
|
|
|
if (flags[i] & VERT_EDGE) |
|
|
|
glEdgeFlag( IM->EdgeFlag[i] ); |
|
|
|
|
|
|
|
if (flags[i] & VERT_MATERIAL) |
|
|
|
emit_material( IM->Material[i], IM->MaterialMask[i] ); |
|
|
|
|
|
|
|
if (flags[i]&VERT_OBJ_234) { |
|
|
|
/* fprintf(stderr, "vertex %d: %f %f %f\n", i, */ |
|
|
|
/* IM->Obj[i][0], IM->Obj[i][1], IM->Obj[i][2]); */ |
|
|
|
vertex( IM->Obj[i] ); |
|
|
|
} |
|
|
|
else if (flags[i] & VERT_EVAL_C1) |
|
|
|
glEvalCoord1f(IM->Obj[i][0]); |
|
|
|
else if (flags[i] & VERT_EVAL_P1) |
|
|
|
glEvalPoint1(IM->Obj[i][0]); |
|
|
|
else if (flags[i] & VERT_EVAL_C2) |
|
|
|
glEvalCoord2f( IM->Obj[i][0], IM->Obj[i][1]); |
|
|
|
else if (flags[i] & VERT_EVAL_P2) |
|
|
|
glEvalPoint2( IM->Obj[i][0], IM->Obj[i][1]); |
|
|
|
} |
|
|
|
|
|
|
|
if (prim & PRIM_END) { |
|
|
|
/* fprintf(stderr, "end\n"); */ |
|
|
|
glEnd(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |