summaryrefslogtreecommitdiff
path: root/src/mesa/tnl
diff options
context:
space:
mode:
authorKeith Whitwell <keith@tungstengraphics.com>2000-12-26 05:09:27 +0000
committerKeith Whitwell <keith@tungstengraphics.com>2000-12-26 05:09:27 +0000
commitcab974cf6c2dbfbf5dd5d291e1aae0f8eeb34290 (patch)
tree45385bd755d8e3876c54b2b0113636f5ceb7976a /src/mesa/tnl
parentd1ff1f6798b003a820f5de9fad835ff352f31afe (diff)
Major rework of tnl module
New array_cache module Support 8 texture units in core mesa (now support 8 everywhere) Rework core mesa statechange operations to avoid flushing on many noop statechanges.
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/t_array_api.c355
-rw-r--r--src/mesa/tnl/t_array_api.h47
-rw-r--r--src/mesa/tnl/t_array_import.c521
-rw-r--r--src/mesa/tnl/t_array_import.h42
-rw-r--r--src/mesa/tnl/t_context.c233
-rw-r--r--src/mesa/tnl/t_context.h729
-rw-r--r--src/mesa/tnl/t_eval_api.c209
-rw-r--r--src/mesa/tnl/t_eval_api.h44
-rw-r--r--src/mesa/tnl/t_imm_alloc.c104
-rw-r--r--src/mesa/tnl/t_imm_alloc.h40
-rw-r--r--src/mesa/tnl/t_imm_api.c1398
-rw-r--r--src/mesa/tnl/t_imm_api.h50
-rw-r--r--src/mesa/tnl/t_imm_debug.c169
-rw-r--r--src/mesa/tnl/t_imm_debug.h11
-rw-r--r--src/mesa/tnl/t_imm_dlist.c415
-rw-r--r--src/mesa/tnl/t_imm_dlist.h46
-rw-r--r--src/mesa/tnl/t_imm_elt.c759
-rw-r--r--src/mesa/tnl/t_imm_elt.h46
-rw-r--r--src/mesa/tnl/t_imm_eval.c623
-rw-r--r--src/mesa/tnl/t_imm_eval.h40
-rw-r--r--src/mesa/tnl/t_imm_exec.c507
-rw-r--r--src/mesa/tnl/t_imm_exec.h62
-rw-r--r--src/mesa/tnl/t_imm_fixup.c811
-rw-r--r--src/mesa/tnl/t_imm_fixup.h52
-rw-r--r--src/mesa/tnl/t_pipeline.c501
-rw-r--r--src/mesa/tnl/t_pipeline.h35
-rw-r--r--src/mesa/tnl/t_vb_cliptmp.h477
-rw-r--r--src/mesa/tnl/t_vb_fog.c201
-rw-r--r--src/mesa/tnl/t_vb_light.c280
-rw-r--r--src/mesa/tnl/t_vb_lighttmp.h965
-rw-r--r--src/mesa/tnl/t_vb_normals.c193
-rw-r--r--src/mesa/tnl/t_vb_points.c124
-rw-r--r--src/mesa/tnl/t_vb_render.c698
-rw-r--r--src/mesa/tnl/t_vb_rendertmp.h452
-rw-r--r--src/mesa/tnl/t_vb_texgen.c685
-rw-r--r--src/mesa/tnl/t_vb_texmat.c148
-rw-r--r--src/mesa/tnl/t_vb_vertex.c311
-rw-r--r--src/mesa/tnl/tnl.h17
38 files changed, 11388 insertions, 1012 deletions
diff --git a/src/mesa/tnl/t_array_api.c b/src/mesa/tnl/t_array_api.c
new file mode 100644
index 0000000000..83d10337be
--- /dev/null
+++ b/src/mesa/tnl/t_array_api.c
@@ -0,0 +1,355 @@
+/* $Id: t_array_api.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+#include "glheader.h"
+#include "api_validate.h"
+#include "context.h"
+#include "macros.h"
+#include "mmath.h"
+#include "mem.h"
+#include "state.h"
+#include "mtypes.h"
+
+#include "array_cache/acache.h"
+
+#include "t_array_api.h"
+#include "t_array_import.h"
+#include "t_imm_api.h"
+#include "t_imm_exec.h"
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+
+
+
+void
+_tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+
+ /* Check arguments, etc.
+ */
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ if (!ctx->CompileFlag && count - start < ctx->Const.MaxArrayLockSize) {
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (ctx->Array.LockCount)
+ {
+ if (start < ctx->Array.LockFirst) start = ctx->Array.LockFirst;
+ if (count > ctx->Array.LockCount) count = ctx->Array.LockCount;
+ if (start >= count) return;
+
+ /* Locked drawarrays. Reuse any previously transformed data.
+ */
+ _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
+ VB->FirstPrimitive = start;
+ VB->Primitive[start] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
+ VB->PrimitiveLength[start] = count - start;
+ _tnl_run_pipeline( ctx );
+ } else {
+ /* The arrays are small enough to fit in a single VB; just bind
+ * them and go. Any untransformed data will be copied on
+ * clipping.
+ *
+ * Invalidate any locked data dependent on these arrays.
+ */
+ _tnl_vb_bind_arrays( ctx, start, count );
+ VB->FirstPrimitive = 0;
+ VB->Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
+ VB->PrimitiveLength[0] = count - start;
+ tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
+ _tnl_run_pipeline( ctx );
+ tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
+ }
+ }
+ else {
+ /* Need to produce immediate structs, either for compiling or
+ * because the array range is too large to process in a single
+ * VB. In GL_EXECUTE mode, this introduces two redundant
+ * operations: producing the flag array and computing the orflag
+ * of the flag array.
+ */
+#if 0
+ if (_tnl_hard_begin( ctx, mode )) {
+ GLuint j;
+ for (j = 0 ; j < count ; ) {
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint nr = MIN2( IMM_MAXDATA - IM->Start, count - j );
+ GLuint sf = IM->Flag[IM->Start];
+
+ _tnl_fill_immediate_drawarrays( ctx, IM, j, j+nr );
+
+ if (j == 0) IM->Flag[IM->Start] |= sf;
+
+ IM->Count = IM->Start + nr;
+ j += nr;
+
+ if (j == count)
+ _tnl_end( ctx );
+
+ _tnl_flush_immediate( IM );
+ }
+ }
+#else
+ /* Simple alternative to above code.
+ */
+/* if (_tnl_hard_begin( ctx, mode )) */
+ _tnl_begin(ctx,mode);
+ {
+ GLuint i;
+ for (i=start;i<count;i++) {
+ _tnl_array_element( ctx, i );
+ }
+ _tnl_end( ctx );
+ }
+#endif
+ }
+}
+
+
+
+static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, const GLuint *indices )
+
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ FLUSH_CURRENT( ctx, 0 );
+
+ _tnl_vb_bind_arrays( ctx, start, end );
+
+ tnl->vb.FirstPrimitive = 0;
+ tnl->vb.Primitive[0] = mode | PRIM_BEGIN | PRIM_END | PRIM_LAST;
+ tnl->vb.PrimitiveLength[0] = count;
+ tnl->vb.Elts = (GLuint *)indices;
+
+ if (ctx->Array.LockCount)
+ _tnl_run_pipeline( ctx );
+ else {
+ /* Note that arrays may have changed before/after execution.
+ */
+ tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
+ _tnl_run_pipeline( ctx );
+ tnl->pipeline.run_input_changes |= ctx->Array._Enabled;
+ }
+}
+
+
+
+
+static void _tnl_draw_elements( GLcontext *ctx, GLenum mode, GLsizei count,
+ const GLuint *indices)
+{
+#if 1
+ /* Optimized code that fakes the effect of calling
+ * _tnl_array_element for each index in the list.
+ */
+ if (_tnl_hard_begin( ctx, mode )) {
+ GLuint i,j;
+ for (j = 0 ; j < count ; ) {
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint start = IM->Start;
+ GLuint nr = MIN2( IMM_MAXDATA - start, count - j ) + start;
+ GLuint sf = IM->Flag[start];
+ IM->FlushElt |= 1;
+
+ for (i = start ; i < nr ; i++) {
+ IM->Elt[i] = (GLuint) *indices++;
+ IM->Flag[i] = VERT_ELT;
+ }
+
+ if (j == 0) IM->Flag[start] |= sf;
+
+ IM->Count = nr;
+ j += nr - start;
+
+ if (j == count)
+ _tnl_end( ctx );
+
+ _tnl_flush_immediate( IM );
+ }
+ }
+#else
+ /* Simple version of the above code.
+ */
+ if (_tnl_hard_begin(ctx, mode)) {
+ GLuint i;
+ for (i = 0 ; i < count ; i++)
+ _tnl_array_element( ctx, indices[i] );
+ _tnl_end( ctx );
+ }
+#endif
+}
+
+
+void
+_tnl_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type, const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint *ui_indices;
+
+ /* Check arguments, etc.
+ */
+ if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
+ type, indices ))
+ return;
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
+ count, type, indices );
+
+
+ if (ctx->Array.LockCount) {
+ /* Are the arrays already locked? If so we currently have to look
+ * at the whole locked range.
+ */
+ if (start >= ctx->Array.LockFirst && end <= ctx->Array.LockCount)
+ _tnl_draw_range_elements( ctx, mode,
+ ctx->Array.LockFirst,
+ ctx->Array.LockCount,
+ count, ui_indices );
+ else {
+ /* The spec says referencing elements outside the locked
+ * range is undefined. I'm going to make it a noop this time
+ * round, maybe come up with something beter before 3.6.
+ *
+ * May be able to get away with just setting LockCount==0,
+ * though this raises the problems of dependent state. May
+ * have to call glUnlockArrays() directly?
+ */
+ gl_problem( ctx,
+ "DrawRangeElements references "
+ "elements outside locked range.");
+ }
+ }
+ else if (end - start < ctx->Const.MaxArrayLockSize) {
+ /* The arrays aren't locked but we can still fit them inside a single
+ * vertexbuffer.
+ */
+ _tnl_draw_range_elements( ctx, mode, start, end, count, ui_indices );
+ } else {
+ /* Range is too big to optimize:
+ */
+ _tnl_draw_elements( ctx, mode, count, ui_indices );
+ }
+}
+
+
+
+void
+_tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint *ui_indices;
+
+ /* Check arguments, etc.
+ */
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+ return;
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
+ count, type, indices );
+
+ if (ctx->Array.LockCount) {
+ _tnl_draw_range_elements( ctx, mode,
+ ctx->Array.LockFirst,
+ ctx->Array.LockCount,
+ count, ui_indices );
+ }
+ else {
+ /* Scan the index list and see if we can use the locked path anyway.
+ */
+ GLuint max_elt = 0;
+ GLuint i;
+
+ for (i = 0 ; i < count ; i++)
+ if (ui_indices[i] > max_elt) max_elt = ui_indices[i];
+
+ if (max_elt < ctx->Const.MaxArrayLockSize && /* can we use it? */
+ max_elt < count) /* do we want to use it? */
+ _tnl_draw_range_elements( ctx, mode, 0, max_elt, count, ui_indices );
+ else
+ _tnl_draw_elements( ctx, mode, count, ui_indices );
+ }
+}
+
+
+void _tnl_array_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_arrays *tmp = &tnl->array_inputs;
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
+ GLuint i;
+
+ vfmt->DrawArrays = _tnl_DrawArrays;
+ vfmt->DrawElements = _tnl_DrawElements;
+ vfmt->DrawRangeElements = _tnl_DrawRangeElements;
+
+ /* Setup vector pointers that will be used to bind arrays to VB's.
+ */
+ gl_vector4f_init( &tmp->Obj, 0, 0 );
+ gl_vector3f_init( &tmp->Normal, 0, 0 );
+ gl_vector4ub_init( &tmp->Color, 0, 0 );
+ gl_vector4ub_init( &tmp->SecondaryColor, 0, 0 );
+ gl_vector1f_init( &tmp->FogCoord, 0, 0 );
+ gl_vector1ui_init( &tmp->Index, 0, 0 );
+ gl_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
+
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
+ gl_vector4f_init( &tmp->TexCoord[i], 0, 0);
+
+ tnl->tmp_primitive = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
+ tnl->tmp_primitive_length = (GLuint *)MALLOC(sizeof(GLuint)*tnl->vb.Size);
+}
+
+
+void _tnl_array_destroy( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ if (tnl->tmp_primitive_length) FREE(tnl->tmp_primitive_length);
+ if (tnl->tmp_primitive) FREE(tnl->tmp_primitive);
+}
diff --git a/src/mesa/tnl/t_array_api.h b/src/mesa/tnl/t_array_api.h
new file mode 100644
index 0000000000..ebb99e78d6
--- /dev/null
+++ b/src/mesa/tnl/t_array_api.h
@@ -0,0 +1,47 @@
+/* $Id: t_array_api.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _T_VARRAY_H
+#define _T_VARRAY_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+extern void _tnl_DrawArrays(GLenum mode, GLint first, GLsizei count);
+
+extern void _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices);
+
+extern void _tnl_DrawRangeElements(GLenum mode, GLuint start,
+ GLuint end, GLsizei count, GLenum type,
+ const GLvoid *indices);
+
+
+extern void _tnl_array_init( GLcontext *ctx );
+extern void _tnl_array_destroy( GLcontext *ctx );
+
+#endif
diff --git a/src/mesa/tnl/t_array_import.c b/src/mesa/tnl/t_array_import.c
new file mode 100644
index 0000000000..16a669dc28
--- /dev/null
+++ b/src/mesa/tnl/t_array_import.c
@@ -0,0 +1,521 @@
+/* $Id: t_array_import.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "state.h"
+#include "mtypes.h"
+
+#include "array_cache/acache.h"
+#include "math/m_translate.h"
+
+#include "t_array_import.h"
+#include "t_context.h"
+
+
+static void _tnl_import_vertex( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+
+ tmp = _ac_import_vertex(ctx,
+ GL_FLOAT,
+ stride ? 4*sizeof(GLfloat) : 0,
+ 0,
+ writeable,
+ &is_writeable);
+
+ inputs->Obj.data = tmp->Ptr;
+ inputs->Obj.start = (GLfloat *)tmp->Ptr;
+ inputs->Obj.stride = tmp->StrideB;
+ inputs->Obj.size = tmp->Size;
+ inputs->Obj.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != 4*sizeof(GLfloat))
+ inputs->Obj.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->Obj.flags |= VEC_NOT_WRITEABLE;
+}
+
+static void _tnl_import_normal( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+
+ tmp = _ac_import_normal(ctx, GL_FLOAT,
+ stride ? 3*sizeof(GLfloat) : 0, writeable,
+ &is_writeable);
+
+ inputs->Normal.data = tmp->Ptr;
+ inputs->Normal.start = (GLfloat *)tmp->Ptr;
+ inputs->Normal.stride = tmp->StrideB;
+ inputs->Normal.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != 3*sizeof(GLfloat))
+ inputs->Normal.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->Normal.flags |= VEC_NOT_WRITEABLE;
+}
+
+
+static void _tnl_import_color( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+
+ tmp = _ac_import_color(ctx,
+ GL_UNSIGNED_BYTE,
+ stride ? 4*sizeof(GLubyte) : 0,
+ 4,
+ writeable,
+ &is_writeable);
+
+ inputs->Color.data = tmp->Ptr;
+ inputs->Color.start = (GLubyte *)tmp->Ptr;
+ inputs->Color.stride = tmp->StrideB;
+ inputs->Color.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != 4*sizeof(GLubyte))
+ inputs->Color.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->Color.flags |= VEC_NOT_WRITEABLE;
+}
+
+
+static void _tnl_import_secondarycolor( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+
+ tmp = _ac_import_secondarycolor(ctx, GL_UNSIGNED_BYTE,
+ stride ? 4*sizeof(GLubyte) : 0,
+ 4,
+ writeable,
+ &is_writeable);
+
+ inputs->SecondaryColor.data = tmp->Ptr;
+ inputs->SecondaryColor.start = (GLubyte *)tmp->Ptr;
+ inputs->SecondaryColor.stride = tmp->StrideB;
+ inputs->SecondaryColor.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != 4*sizeof(GLubyte))
+ inputs->SecondaryColor.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->SecondaryColor.flags |= VEC_NOT_WRITEABLE;
+}
+
+static void _tnl_import_fogcoord( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+
+ tmp = _ac_import_fogcoord(ctx, GL_FLOAT,
+ stride ? sizeof(GLfloat) : 0, writeable,
+ &is_writeable);
+
+ inputs->FogCoord.data = tmp->Ptr;
+ inputs->FogCoord.start = (GLfloat *)tmp->Ptr;
+ inputs->FogCoord.stride = tmp->StrideB;
+ inputs->FogCoord.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != sizeof(GLfloat))
+ inputs->FogCoord.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->FogCoord.flags |= VEC_NOT_WRITEABLE;
+}
+
+static void _tnl_import_index( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+
+ tmp = _ac_import_index(ctx, GL_UNSIGNED_INT,
+ stride ? sizeof(GLuint) : 0, writeable,
+ &is_writeable);
+
+ inputs->Index.data = tmp->Ptr;
+ inputs->Index.start = (GLuint *)tmp->Ptr;
+ inputs->Index.stride = tmp->StrideB;
+ inputs->Index.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != sizeof(GLuint))
+ inputs->Index.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->Index.flags |= VEC_NOT_WRITEABLE;
+}
+
+
+static void _tnl_import_texcoord( GLcontext *ctx,
+ GLuint i,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+
+ tmp = _ac_import_texcoord(ctx, i, GL_FLOAT,
+ stride ? 4*sizeof(GLfloat) : 0,
+ 0,
+ writeable,
+ &is_writeable);
+
+ inputs->TexCoord[i].data = tmp->Ptr;
+ inputs->TexCoord[i].start = (GLfloat *)tmp->Ptr;
+ inputs->TexCoord[i].stride = tmp->StrideB;
+ inputs->TexCoord[i].size = tmp->Size;
+ inputs->TexCoord[i].flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != 4*sizeof(GLfloat))
+ inputs->TexCoord[i].flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->TexCoord[i].flags |= VEC_NOT_WRITEABLE;
+}
+
+
+static void _tnl_import_edgeflag( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+
+ tmp = _ac_import_edgeflag(ctx, GL_UNSIGNED_BYTE,
+ stride ? sizeof(GLubyte) : 0,
+ 0,
+ &is_writeable);
+
+ inputs->EdgeFlag.data = tmp->Ptr;
+ inputs->EdgeFlag.start = (GLubyte *)tmp->Ptr;
+ inputs->EdgeFlag.stride = tmp->StrideB;
+ inputs->EdgeFlag.flags &= ~(VEC_BAD_STRIDE|VEC_NOT_WRITEABLE);
+ if (stride != sizeof(GLubyte))
+ inputs->EdgeFlag.flags |= VEC_BAD_STRIDE;
+ if (!is_writeable)
+ inputs->EdgeFlag.flags |= VEC_NOT_WRITEABLE;
+}
+
+
+
+/* Callback for VB stages that need to improve the quality of arrays
+ * bound to the VB. This is only necessary for client arrays which
+ * have not been transformed at any point in the pipeline.
+ */
+static void _tnl_upgrade_client_data( GLcontext *ctx,
+ GLuint required,
+ GLuint flags )
+{
+ GLuint i;
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ GLboolean writeable = (flags & VEC_NOT_WRITEABLE) != 0;
+ GLboolean stride = (flags & VEC_BAD_STRIDE) != 0;
+
+ if ((required & VERT_CLIP) && VB->ClipPtr == VB->ObjPtr)
+ required |= VERT_OBJ;
+
+ if ((required & VERT_OBJ) && (VB->ObjPtr->flags & flags)) {
+ ASSERT(VB->ObjPtr == &inputs->Obj);
+ _tnl_import_vertex( ctx, writeable, stride );
+ }
+
+ if ((required & VERT_NORM) && (VB->NormalPtr->flags & flags)) {
+ ASSERT(VB->NormalPtr == &inputs->Normal);
+ _tnl_import_normal( ctx, writeable, stride );
+ }
+
+ if ((required & VERT_RGBA) && (VB->ColorPtr[0]->flags & flags)) {
+ ASSERT(VB->ColorPtr[0] == &inputs->Color);
+ _tnl_import_color( ctx, writeable, stride );
+ }
+
+ if ((required & VERT_SPEC_RGB) && (VB->SecondaryColorPtr[0]->flags&flags)) {
+ ASSERT(VB->SecondaryColorPtr[0] == &inputs->SecondaryColor);
+ _tnl_import_secondarycolor( ctx, writeable, stride );
+ }
+
+ if ((required & VERT_FOG_COORD) && (VB->FogCoordPtr->flags & flags)) {
+ ASSERT(VB->FogCoordPtr == &inputs->FogCoord);
+ _tnl_import_fogcoord( ctx, writeable, stride );
+ }
+
+ if ((required & VERT_INDEX) && (VB->IndexPtr[0]->flags & flags)) {
+ ASSERT(VB->IndexPtr[0] == &inputs->Index);
+ _tnl_import_index( ctx, writeable, stride );
+ }
+
+ if (required & VERT_TEX_ANY)
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if ((required & VERT_TEX(i)) && (VB->TexCoordPtr[i]->flags & flags)) {
+ ASSERT(VB->TexCoordPtr[i] == &inputs->TexCoord[i]);
+ _tnl_import_texcoord( ctx, i, writeable, stride );
+ }
+
+ if ((required & VERT_EDGE) && (VB->EdgeFlagPtr->flags & flags)) {
+ ASSERT(VB->EdgeFlagPtr == &inputs->EdgeFlag);
+ _tnl_import_edgeflag( ctx, writeable, stride );
+ }
+
+ VB->importable_data &= ~required;
+}
+
+
+
+
+
+void _tnl_vb_bind_arrays( GLcontext *ctx, GLint start, GLsizei count )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint inputs = tnl->pipeline.inputs;
+ GLuint imports;
+ struct vertex_arrays *tmp = &tnl->array_inputs;
+
+ if (ctx->Array.LockCount) {
+ ASSERT(start == ctx->Array.LockFirst);
+ ASSERT(count == ctx->Array.LockCount);
+ }
+
+ imports = tnl->pipeline.inputs;
+
+ _ac_import_range( ctx, start, count );
+
+ VB->Count = count - start;
+ VB->FirstClipped = VB->Count;
+
+ VB->Elts = 0;
+ VB->MaterialMask = 0;
+ VB->Material = 0;
+ VB->Flag = 0;
+
+/* _tnl_print_vert_flags("_tnl_print_vert_flags: inputs", inputs); */
+/* _tnl_print_vert_flags("_tnl_print_vert_flags: imports", imports); */
+/* _tnl_print_vert_flags("_tnl_print_vert_flags: _Enabled", ctx->Array._Enabled); */
+
+ if (inputs & VERT_OBJ) {
+ if (imports & VERT_OBJ) {
+ _tnl_import_vertex( ctx, 0, 0 );
+ tmp->Obj.count = VB->Count;
+ }
+ VB->ObjPtr = &tmp->Obj;
+ }
+
+ if (inputs & VERT_NORM) {
+ if (imports & VERT_NORM) {
+ _tnl_import_normal( ctx, 0, 0 );
+ tmp->Normal.count = VB->Count;
+ }
+ VB->NormalPtr = &tmp->Normal;
+ }
+
+ if (inputs & VERT_RGBA) {
+ if (imports & VERT_RGBA) {
+ _tnl_import_color( ctx, 0, 0 );
+ tmp->Color.count = VB->Count;
+ }
+ VB->ColorPtr[0] = &tmp->Color;
+ VB->ColorPtr[1] = 0;
+ }
+
+ if (inputs & VERT_INDEX) {
+ if (imports & VERT_INDEX) {
+ _tnl_import_index( ctx, 0, 0 );
+ tmp->Index.count = VB->Count;
+ }
+ VB->IndexPtr[0] = &tmp->Index;
+ VB->IndexPtr[1] = 0;
+ }
+
+
+ if (inputs & VERT_FOG_COORD) {
+ if (imports & VERT_FOG_COORD) {
+ _tnl_import_fogcoord( ctx, 0, 0 );
+ tmp->FogCoord.count = VB->Count;
+ }
+ VB->FogCoordPtr = &tmp->FogCoord;
+ }
+
+ if (inputs & VERT_EDGE) {
+ if (imports & VERT_EDGE) {
+ _tnl_import_edgeflag( ctx, 0, 0 );
+ tmp->EdgeFlag.count = VB->Count;
+ }
+ VB->EdgeFlagPtr = &tmp->EdgeFlag;
+ }
+
+ if (inputs & VERT_SPEC_RGB) {
+ if (imports & VERT_SPEC_RGB) {
+ _tnl_import_secondarycolor( ctx, 0, 0 );
+ tmp->SecondaryColor.count = VB->Count;
+ }
+ VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
+ VB->SecondaryColorPtr[1] = 0;
+ }
+
+ if (inputs & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0; i < ctx->Const.MaxTextureUnits ; i++)
+ if (inputs & VERT_TEX(i)) {
+ if (imports & VERT_TEX(i)) {
+ _tnl_import_texcoord( ctx, i, 0, 0 );
+ tmp->TexCoord[i].count = VB->Count;
+ }
+ VB->TexCoordPtr[i] = &tmp->TexCoord[i];
+ }
+ }
+
+ VB->Primitive = tnl->tmp_primitive;
+ VB->PrimitiveLength = tnl->tmp_primitive_length;
+ VB->import_data = _tnl_upgrade_client_data;
+ VB->importable_data = imports;
+}
+
+
+
+
+/* Function to fill an immediate struct with the effects of
+ * consecutive calls to ArrayElement with consecutive indices.
+ */
+void _tnl_fill_immediate_drawarrays( GLcontext *ctx, struct immediate *IM,
+ GLuint start, GLuint count )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint required = ctx->Array._Enabled;
+ GLuint n = count - start;
+ GLuint i;
+
+ if (!ctx->CompileFlag)
+ required &= tnl->pipeline.inputs;
+
+ if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
+ fprintf(stderr, "exec_full_array_elements %d .. %d\n", start, count);
+
+ _math_trans_4f( IM->Obj + IM->Start,
+ ctx->Array.Vertex.Ptr,
+ ctx->Array.Vertex.StrideB,
+ ctx->Array.Vertex.Type,
+ ctx->Array.Vertex.Size,
+ start, n );
+
+ if (ctx->Array.Vertex.Size == 4)
+ required |= VERT_OBJ_234;
+ else if (ctx->Array.Vertex.Size == 3)
+ required |= VERT_OBJ_23;
+
+
+ if (required & VERT_NORM) {
+ _math_trans_3f( IM->Normal + IM->Start,
+ ctx->Array.Normal.Ptr,
+ ctx->Array.Normal.StrideB,
+ ctx->Array.Normal.Type,
+ start, n );
+ }
+
+ if (required & VERT_EDGE) {
+ _math_trans_1ub( IM->EdgeFlag + IM->Start,
+ ctx->Array.EdgeFlag.Ptr,
+ ctx->Array.EdgeFlag.StrideB,
+ ctx->Array.EdgeFlag.Type,
+ start, n );
+ }
+
+ if (required & VERT_RGBA) {
+ _math_trans_4ub( IM->Color + IM->Start,
+ ctx->Array.Color.Ptr,
+ ctx->Array.Color.StrideB,
+ ctx->Array.Color.Type,
+ ctx->Array.Color.Size,
+ start, n );
+ }
+
+ if (required & VERT_SPEC_RGB) {
+ _math_trans_4ub( IM->SecondaryColor + IM->Start,
+ ctx->Array.SecondaryColor.Ptr,
+ ctx->Array.SecondaryColor.StrideB,
+ ctx->Array.SecondaryColor.Type,
+ ctx->Array.SecondaryColor.Size,
+ start, n );
+ }
+
+ if (required & VERT_FOG_COORD) {
+ _math_trans_1f( IM->FogCoord + IM->Start,
+ ctx->Array.FogCoord.Ptr,
+ ctx->Array.FogCoord.StrideB,
+ ctx->Array.FogCoord.Type,
+ start, n );
+ }
+
+ if (required & VERT_INDEX) {
+ _math_trans_1ui( IM->Index + IM->Start,
+ ctx->Array.Index.Ptr,
+ ctx->Array.Index.StrideB,
+ ctx->Array.Index.Type,
+ start, n );
+ }
+
+ if (required & VERT_TEX_ANY) {
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (required & VERT_TEX(i)) {
+ _math_trans_4f( IM->TexCoord[i] + IM->Start,
+ ctx->Array.TexCoord[i].Ptr,
+ ctx->Array.TexCoord[i].StrideB,
+ ctx->Array.TexCoord[i].Size,
+ ctx->Array.TexCoord[i].Type,
+ start, n );
+
+ if (ctx->Array.TexCoord[i].Size == 4)
+ IM->TexSize |= TEX_SIZE_4(i);
+ else if (ctx->Array.TexCoord[i].Size == 3)
+ IM->TexSize |= TEX_SIZE_3(i);
+ }
+ }
+ }
+
+ IM->Count = IM->Start + n;
+ IM->Flag[IM->Start] |= required;
+ for (i = IM->Start+1 ; i < IM->Count ; i++)
+ IM->Flag[i] = required;
+}
+
+
diff --git a/src/mesa/tnl/t_array_import.h b/src/mesa/tnl/t_array_import.h
new file mode 100644
index 0000000000..c1b903e24a
--- /dev/null
+++ b/src/mesa/tnl/t_array_import.h
@@ -0,0 +1,42 @@
+/* $Id: t_array_import.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _T_ARRAY_IMPORT_H
+#define _T_ARRAY_IMPORT_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+extern void _tnl_vb_bind_arrays( GLcontext *ctx, GLint start, GLsizei count );
+
+extern void _tnl_fill_immediate_drawarrays( GLcontext *ctx,
+ struct immediate *IM,
+ GLuint start, GLuint count ) ;
+
+extern void _tnl_array_import_init( GLcontext *ctx );
+
+
+#endif
diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c
index d27a48b296..5b879d8a83 100644
--- a/src/mesa/tnl/t_context.c
+++ b/src/mesa/tnl/t_context.c
@@ -1,101 +1,74 @@
+/* $Id: t_context.c,v 1.7 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "macros.h"
#include "mtypes.h"
#include "mem.h"
#include "dlist.h"
#include "vtxfmt.h"
#include "t_context.h"
-#include "t_clip.h"
-#include "t_cva.h"
-#include "t_dlist.h"
-#include "t_eval.h"
+#include "t_array_api.h"
+#include "t_eval_api.h"
+#include "t_imm_alloc.h"
+#include "t_imm_exec.h"
+#include "t_imm_dlist.h"
#include "t_pipeline.h"
-#include "t_shade.h"
-#include "t_light.h"
-#include "t_texture.h"
-#include "t_stages.h"
-#include "t_varray.h"
-#include "t_vb.h"
-#include "t_vbrender.h"
-#include "t_vbxform.h"
-#include "t_vtxfmt.h"
#include "tnl.h"
-#if !defined(THREADS)
+#ifndef THREADS
struct immediate *_tnl_CurrentInput = NULL;
#endif
-GLboolean
-_tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct immediate *IM = TNL_CURRENT_IM(ctx);
-
- if ((IM->Flag[IM->Count] & (VERT_BEGIN|VERT_END)) != VERT_END ||
- (flush_flags & (FLUSH_STORED_VERTICES|FLUSH_UPDATE_CURRENT)))
- {
- if (IM->Flag[IM->Start])
- _tnl_maybe_transform_vb( IM );
-
- /* Although this code updates the ctx->Current values, that bit
- * is left set as there is no easy mechanism to set it
- * elsewhere. This means that each time core wants to examine
- * ctx->Current, this function will be called. After the first
- * time, however, it will be a no-op.
- */
- ctx->Driver.NeedFlush &= ~(FLUSH_STORED_VERTICES |
- FLUSH_INSIDE_BEGIN_END);
-
- return (tnl->_CurrentPrimitive == GL_POLYGON+1);
- }
- else
- return GL_TRUE;
-}
-
-
-
- void
+void
_tnl_MakeCurrent( GLcontext *ctx,
GLframebuffer *drawBuffer,
GLframebuffer *readBuffer )
{
#ifndef THREADS
- SET_IMMEDIATE( ctx, TNL_VB(ctx)->IM );
+ SET_IMMEDIATE( ctx, TNL_CURRENT_IM(ctx) );
#endif
}
-/* Update all state that references _NeedEyeCoords
- */
- void
-_tnl_LightingSpaceChange( GLcontext *ctx )
-{
- _tnl_update_normal_transform( ctx );
-}
-
-
static void
install_driver_callbacks( GLcontext *ctx )
{
- ctx->Driver.RenderVBCulledTab = _tnl_render_tab_cull;
- ctx->Driver.RenderVBClippedTab = _tnl_render_tab_clipped;
- ctx->Driver.RenderVBRawTab = _tnl_render_tab_raw;
ctx->Driver.NewList = _tnl_NewList;
ctx->Driver.EndList = _tnl_EndList;
ctx->Driver.FlushVertices = _tnl_flush_vertices;
- ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT;
- ctx->Driver.LightingSpaceChange = _tnl_LightingSpaceChange;
ctx->Driver.MakeCurrent = _tnl_MakeCurrent;
- ctx->Driver.VertexPointer = _tnl_VertexPointer;
- ctx->Driver.NormalPointer = _tnl_NormalPointer;
- ctx->Driver.ColorPointer = _tnl_ColorPointer;
- ctx->Driver.FogCoordPointer = _tnl_FogCoordPointer;
- ctx->Driver.IndexPointer = _tnl_IndexPointer;
- ctx->Driver.SecondaryColorPointer = _tnl_SecondaryColorPointer;
- ctx->Driver.TexCoordPointer = _tnl_TexCoordPointer;
- ctx->Driver.EdgeFlagPointer = _tnl_EdgeFlagPointer;
- ctx->Driver.LockArraysEXT = _tnl_LockArraysEXT;
- ctx->Driver.UnlockArraysEXT = _tnl_UnlockArraysEXT;
+ ctx->Driver.BeginCallList = _tnl_BeginCallList;
+ ctx->Driver.EndCallList = _tnl_EndCallList;
}
@@ -104,21 +77,6 @@ GLboolean
_tnl_CreateContext( GLcontext *ctx )
{
TNLcontext *tnl;
- static int firsttime = 1;
-
- /* Onetime initializations. Doesn't really matter if this gets
- * done twice: no need for mutexes.
- */
- if (firsttime) {
- firsttime = 0;
- _tnl_clip_init();
- _tnl_eval_init();
- _tnl_shade_init();
- _tnl_texture_init();
- _tnl_trans_elt_init();
- _tnl_vbrender_init();
- _tnl_stages_init();
- }
/* Create the TNLcontext structure
*/
@@ -127,43 +85,35 @@ _tnl_CreateContext( GLcontext *ctx )
return GL_FALSE;
}
- /* Create and hook in the data structures available from ctx.
+ /* Initialize the VB.
*/
- ctx->swtnl_vb = (void *)_tnl_vb_create_for_immediate( ctx );
- if (!ctx->swtnl_vb) {
- FREE(tnl);
- ctx->swtnl_context = 0;
- return GL_FALSE;
- }
+ tnl->vb.Size = MAX2( IMM_SIZE,
+ ctx->Const.MaxArrayLockSize + MAX_CLIPPED_VERTICES);
- ctx->swtnl_im = (void *)TNL_VB(ctx)->IM;
-
- /* Initialize tnl state.
+ /* Initialize tnl state and tnl->vtxfmt.
*/
_tnl_dlist_init( ctx );
- _tnl_pipeline_init( ctx );
- _tnl_vtxfmt_init( ctx );
- _tnl_cva_init( ctx );
-
- _tnl_reset_vb( TNL_VB(ctx) );
- _tnl_reset_input( ctx, 0, 0 ); /* initially outside begin/end */
-
-
- tnl->_CurrentTex3Flag = 0;
- tnl->_CurrentTex4Flag = 0;
- tnl->_CurrentPrimitive = GL_POLYGON+1;
+ _tnl_array_init( ctx );
+ _tnl_imm_init( ctx );
+ _tnl_eval_init( ctx );
+ _tnl_install_pipeline( ctx, _tnl_default_pipeline );
+
/* Hook our functions into exec and compile dispatch tables.
*/
_mesa_install_exec_vtxfmt( ctx, &tnl->vtxfmt );
_mesa_install_save_vtxfmt( ctx, &tnl->vtxfmt );
ctx->Save->EvalMesh1 = _mesa_save_EvalMesh1; /* fixme */
ctx->Save->EvalMesh2 = _mesa_save_EvalMesh2;
+ ctx->Save->Begin = _tnl_save_Begin;
/* Set a few default values in the driver struct.
*/
install_driver_callbacks(ctx);
+ ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT|FLUSH_STORED_VERTICES;
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
return GL_TRUE;
}
@@ -174,56 +124,45 @@ _tnl_DestroyContext( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- if (TNL_CURRENT_IM(ctx) != TNL_VB(ctx)->IM)
- _tnl_immediate_free( TNL_CURRENT_IM(ctx) );
-
- _tnl_vb_free( TNL_VB(ctx) );
+/* _tnl_dlist_destroy( ctx ); */
+ _tnl_array_destroy( ctx );
+ _tnl_imm_destroy( ctx );
+/* _tnl_eval_destroy( ctx ); */
+ _tnl_destroy_pipeline( ctx );
- /* Free cache of immediate buffers. */
- while (tnl->nr_im_queued-- > 0) {
- struct immediate * next = tnl->freed_im_queue->next;
- ALIGN_FREE( tnl->freed_im_queue );
- tnl->freed_im_queue = next;
- }
+ FREE(tnl);
+ ctx->swtnl_context = 0;
}
-
void
_tnl_InvalidateState( GLcontext *ctx, GLuint new_state )
{
- if (new_state & _NEW_LIGHT)
- _tnl_update_lighting_function(ctx);
-
- if (new_state & _NEW_ARRAY)
- _tnl_update_client_state( ctx );
-
- if (new_state & _NEW_TEXTURE)
- if (ctx->_Enabled & ENABLE_TEXGEN_ANY)
- _tnl_update_texgen( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
- if (new_state & (_NEW_LIGHT|_NEW_TEXTURE|_NEW_FOG|
- _DD_NEW_TRI_LIGHT_TWOSIDE |
- _DD_NEW_SEPERATE_SPECULAR |
- _DD_NEW_TRI_UNFILLED ))
- _tnl_update_clipmask(ctx);
+ if (new_state & _NEW_ARRAY) {
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ IM->ArrayEltFlags = ~ctx->Array._Enabled;
+ IM->ArrayEltFlush = !ctx->Array.LockCount;
+ IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
+ tnl->pipeline.run_input_changes |= ctx->Array.NewState; /* overkill */
+ }
- if (new_state & _TNL_NEW_NORMAL_TRANSFORM)
- _tnl_update_normal_transform( ctx );
+ tnl->pipeline.run_state_changes |= new_state;
+ tnl->pipeline.build_state_changes |= (new_state &
+ tnl->pipeline.build_state_trigger);
- _tnl_update_pipelines(ctx);
+ tnl->eval.EvalNewState |= new_state;
}
+
void
_tnl_wakeup_exec( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
-#ifndef VMS
- fprintf(stderr, "%s\n", __FUNCTION__);
-#endif
-
install_driver_callbacks(ctx);
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
/* Hook our functions into exec and compile dispatch tables.
*/
@@ -232,35 +171,23 @@ _tnl_wakeup_exec( GLcontext *ctx )
/* Call all appropriate driver callbacks to revive state.
*/
_tnl_MakeCurrent( ctx, ctx->DrawBuffer, ctx->ReadBuffer );
- _tnl_UnlockArraysEXT( ctx );
- _tnl_LockArraysEXT( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
-
- /* Equivalent to calling all _tnl_*Pointer functions:
- */
- tnl->_ArrayNewState = ~0;
/* Assume we haven't been getting state updates either:
*/
- _tnl_InvalidateState( ctx, ~0 );
-
- /* Special state not restored by other methods:
- */
- _tnl_validate_current_tex_flags( ctx, ~0 );
-
+ _tnl_InvalidateState( ctx, ~0 );
+ tnl->pipeline.run_input_changes = ~0;
}
+
void
_tnl_wakeup_save_exec( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
-#ifndef VMS
- fprintf(stderr, "%s\n", __FUNCTION__);
-#endif
-
_tnl_wakeup_exec( ctx );
_mesa_install_save_vtxfmt( ctx, &tnl->vtxfmt );
ctx->Save->EvalMesh1 = _mesa_save_EvalMesh1; /* fixme */
ctx->Save->EvalMesh2 = _mesa_save_EvalMesh2;
+ ctx->Save->Begin = _tnl_save_Begin;
}
diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h
index fb036b9f3d..1a4ebb2170 100644
--- a/src/mesa/tnl/t_context.h
+++ b/src/mesa/tnl/t_context.h
@@ -1,5 +1,4 @@
-
-/* $Id: t_context.h,v 1.6 2000/12/08 00:18:39 brianp Exp $ */
+/* $Id: t_context.h,v 1.7 2000/12/26 05:09:32 keithw Exp $ */
/*
* Mesa 3-D graphics library
@@ -23,6 +22,9 @@
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
*/
#ifndef _T_CONTEXT_H
@@ -35,99 +37,91 @@
#include "math/m_vector.h"
#include "math/m_xform.h"
-#include "t_trans_elt.h"
+#define MAX_PIPELINE_STAGES 30
-/*
- * Bits to indicate which faces a vertex participates in,
- * what facing the primitive provoked by that vertex has,
- * and some misc. flags.
+/* Numbers for sizing immediate structs.
*/
-#define VERT_FACE_FRONT 0x1 /* is in a front-color primitive */
-#define VERT_FACE_REAR 0x2 /* is in a rear-color primitive */
-#define PRIM_FACE_FRONT 0x4 /* use front color */
-#define PRIM_FACE_REAR 0x8 /* use rear color */
-#define PRIM_CLIPPED 0x10 /* needs clipping */
-#define PRIM_USER_CLIPPED CLIP_USER_BIT /* 0x40 */
+#define IMM_MAX_COPIED_VERTS 3
+#define IMM_MAXDATA (216 + IMM_MAX_COPIED_VERTS)
+#define IMM_SIZE (IMM_MAXDATA + MAX_CLIPPED_VERTICES)
-#define PRIM_FLAG_SHIFT 2
-#define PRIM_FACE_FLAGS (PRIM_FACE_FRONT|PRIM_FACE_REAR)
-#define VERT_FACE_FLAGS (VERT_FACE_FRONT|VERT_FACE_REAR)
-
-#define PRIM_ANY_CLIP (PRIM_CLIPPED|PRIM_USER_CLIPPED)
-#define PRIM_NOT_CULLED (PRIM_ANY_CLIP|PRIM_FACE_FLAGS)
-
-/* Flags for VB->CullMode.
+/* Values for IM->BeginState
*/
-#define CULL_MASK_ACTIVE 0x1
-#define COMPACTED_NORMALS 0x2
-#define CLIP_MASK_ACTIVE 0x4
+#define VERT_BEGIN_0 0x1 /* glBegin (if initially inside beg/end) */
+#define VERT_BEGIN_1 0x2 /* glBegin (if initially outside beg/end) */
+#define VERT_ERROR_0 0x4 /* invalid_operation in initial state 0 */
+#define VERT_ERROR_1 0x8 /* invalid_operation in initial state 1 */
-/* Flags for selecting a shading function. The first two bits are
- * shared with the cull mode (ie. cull_mask_active and
- * compacted_normals.)
+
+/* Flags to be added to the primitive enum in VB->Primitive.
*/
-#define SHADE_TWOSIDE 0x4
+#define PRIM_MODE_MASK 0xff /* Extract the actual primitive */
+#define PRIM_BEGIN 0x100 /* The prim starts here (not wrapped) */
+#define PRIM_END 0x200 /* The prim ends in this VB (does not wrap) */
+#define PRIM_PARITY 0x400 /* The prim wrapped on an odd number of verts */
+#define PRIM_LAST 0x800 /* No more prims in the VB */
-/* KW: Flags that describe the current vertex state, and the contents
- * of a vertex in a vertex-cassette.
+/* Flags that describe the inputs and outputs of pipeline stages, and
+ * the contents of a vertex-cassette.
*
- * For really major expansion, consider a 'VERT_ADDITIONAL_FLAGS' flag,
- * which means there is data in another flags array (eg, extra_flags[]).
+ * 5 spare flags, rearrangement of eval flags can secure at least 3
+ * more.
+ */
+#define VERT_OBJ _NEW_ARRAY_VERTEX
+#define VERT_RGBA _NEW_ARRAY_COLOR
+#define VERT_NORM _NEW_ARRAY_NORMAL
+#define VERT_INDEX _NEW_ARRAY_INDEX
+#define VERT_EDGE _NEW_ARRAY_EDGEFLAG
+#define VERT_SPEC_RGB _NEW_ARRAY_SECONDARYCOLOR
+#define VERT_FOG_COORD _NEW_ARRAY_FOGCOORD
+#define VERT_TEX0 _NEW_ARRAY_TEXCOORD_0
+#define VERT_TEX1 _NEW_ARRAY_TEXCOORD_1
+#define VERT_TEX2 _NEW_ARRAY_TEXCOORD_2
+#define VERT_TEX3 _NEW_ARRAY_TEXCOORD_3
+#define VERT_TEX4 _NEW_ARRAY_TEXCOORD_4
+#define VERT_TEX5 _NEW_ARRAY_TEXCOORD_5
+#define VERT_TEX6 _NEW_ARRAY_TEXCOORD_6
+#define VERT_TEX7 _NEW_ARRAY_TEXCOORD_7
+#define VERT_EVAL_C1 0x8000 /* imm only */
+#define VERT_EVAL_C2 0x10000 /* imm only */
+#define VERT_EVAL_P1 0x20000 /* imm only */
+#define VERT_EVAL_P2 0x40000 /* imm only */
+#define VERT_OBJ_3 0x80000 /* imm only */
+#define VERT_OBJ_4 0x100000 /* imm only */
+#define VERT_MATERIAL 0x200000 /* imm only, but tested in vb code */
+#define VERT_ELT 0x400000 /* imm only */
+#define VERT_BEGIN 0x800000 /* imm only, but tested in vb code */
+#define VERT_END 0x1000000 /* imm only, but tested in vb code */
+#define VERT_END_VB 0x2000000 /* imm only, but tested in vb code */
+#define VERT_POINT_SIZE 0x4000000 /* vb only, could reuse a bit */
+#define VERT_EYE VERT_BEGIN /* vb only, reuse imm bit */
+#define VERT_CLIP VERT_END /* vb only, reuse imm bit*/
+
+
+/* Flags for IM->TexCoordSize. Enough flags for 16 units.
*/
+#define TEX_0_SIZE_3 0x1
+#define TEX_0_SIZE_4 0x1000
+#define TEX_SIZE_3(unit) (TEX_0_SIZE_3<<unit)
+#define TEX_SIZE_4(unit) (TEX_0_SIZE_4<<unit)
-#define VERT_OBJ_2 0x1 /* glVertex2 */
-#define VERT_OBJ_3 0x2 /* glVertex3 */
-#define VERT_OBJ_4 0x4 /* glVertex4 */
-#define VERT_BEGIN 0x8 /* glBegin */
-#define VERT_END 0x10 /* glEnd */
-#define VERT_ELT 0x20 /* glArrayElement */
-#define VERT_RGBA 0x40 /* glColor */
-#define VERT_NORM 0x80 /* glNormal */
-#define VERT_INDEX 0x100 /* glIndex */
-#define VERT_EDGE 0x200 /* glEdgeFlag */
-#define VERT_MATERIAL 0x400 /* glMaterial */
-#define VERT_END_VB 0x800 /* end vb marker */
-#define VERT_TEX0 0x1000
-#define VERT_TEX1 0x2000
-#define VERT_TEX2 0x3000
-#define VERT_TEX3 0x4000
-#define VERT_TEX4 0x10000
-#define VERT_TEX5 0x20000
-#define VERT_TEX6 0x30000
-#define VERT_TEX7 0x40000
-#define VERT_TEX8 0x100000
-#define VERT_TEX9 0x200000
-#define VERT_TEX10 0x300000
-#define VERT_TEX11 0x400000
-#define VERT_EVAL_C1 0x1000000 /* could reuse OBJ bits for this? */
-#define VERT_EVAL_C2 0x2000000 /* - or just use 3 bits */
-#define VERT_EVAL_P1 0x4000000 /* */
-#define VERT_EVAL_P2 0x8000000 /* */
-#define VERT_SPEC_RGB 0x10000000
-#define VERT_FOG_COORD 0x20000000
-#define VERT_POINT_SIZE 0x40000000
-
-#define VERT_EYE VERT_BEGIN /* reuse */
-#define VERT_WIN VERT_END /* reuse */
-#define VERT_SETUP_FULL VERT_EVAL_P1 /* Rastersetup has been done */
-#define VERT_PRECALC_DATA VERT_END_VB /* reuse */
/* Shorthands.
*/
-
#define VERT_EVAL_ANY (VERT_EVAL_C1|VERT_EVAL_P1| \
VERT_EVAL_C2|VERT_EVAL_P2)
-#define VERT_OBJ_23 (VERT_OBJ_3|VERT_OBJ_2)
+#define VERT_OBJ_23 (VERT_OBJ_3|VERT_OBJ)
#define VERT_OBJ_234 (VERT_OBJ_4|VERT_OBJ_23)
-#define VERT_OBJ_ANY VERT_OBJ_2
#define VERT_TEX0_SHIFT 11
+
#define VERT_TEX(i) (VERT_TEX0 << i)
+
#define VERT_TEX_ANY (VERT_TEX0 | \
VERT_TEX1 | \
VERT_TEX2 | \
@@ -135,461 +129,287 @@
VERT_TEX4 | \
VERT_TEX5 | \
VERT_TEX6 | \
- VERT_TEX7 | \
- VERT_TEX8 | \
- VERT_TEX9 | \
- VERT_TEX10 | \
- VERT_TEX11)
+ VERT_TEX7)
+
+#define VERT_FIXUP (VERT_TEX_ANY | \
+ VERT_RGBA | \
+ VERT_SPEC_RGB | \
+ VERT_FOG_COORD | \
+ VERT_INDEX | \
+ VERT_EDGE | \
+ VERT_NORM)
-#define VERT_FIXUP (VERT_TEX_ANY | \
+#define VERT_CURRENT_DATA (VERT_FIXUP | \
+ VERT_MATERIAL)
+
+#define VERT_DATA (VERT_TEX_ANY | \
VERT_RGBA | \
VERT_SPEC_RGB | \
VERT_FOG_COORD | \
VERT_INDEX | \
VERT_EDGE | \
- VERT_NORM)
-
-#define VERT_DATA (VERT_TEX_ANY | \
- VERT_RGBA | \
- VERT_SPEC_RGB | \
- VERT_FOG_COORD | \
- VERT_INDEX | \
- VERT_EDGE | \
- VERT_NORM | \
- VERT_OBJ_ANY | \
- VERT_MATERIAL | \
- VERT_ELT | \
- VERT_EVAL_ANY | \
- VERT_FOG_COORD)
-
-
-
-
-struct gl_pipeline;
-struct tnl_context;
-
-/**
- ** Vertex buffer/array structures
- **/
-
-struct vertex_data
-{
- GLfloat (*Obj)[4];
- GLfloat (*Normal)[3];
- GLchan (*Color)[4];
- GLuint *Index;
- GLubyte *EdgeFlag;
- GLfloat (*TexCoord[MAX_TEXTURE_UNITS])[4];
- GLuint *Elt;
- GLfloat *FogCoord;
- GLubyte (*SecondaryColor)[4];
-};
-
-struct vertex_arrays
-{
- GLvector4f Obj;
- GLvector3f Normal;
- GLvector4ub Color;
- GLvector1ui Index;
- GLvector1ub EdgeFlag;
- GLvector4f TexCoord[MAX_TEXTURE_UNITS];
- GLvector1ui Elt;
- GLvector4ub SecondaryColor;
- GLvector1f FogCoord;
-};
+ VERT_NORM | \
+ VERT_OBJ | \
+ VERT_MATERIAL | \
+ VERT_ELT | \
+ VERT_EVAL_ANY)
-struct vertex_array_pointers
-{
- GLvector4f *Obj;
- GLvector3f *Normal;
- GLvector4ub *Color;
- GLvector1ui *Index;
- GLvector1ub *EdgeFlag;
- GLvector4f *TexCoord[MAX_TEXTURE_UNITS];
- GLvector1ui *Elt;
- GLvector4ub *SecondaryColor;
- GLvector1f *FogCoord;
-};
-
-/* Values for VB->Type */
-enum {
- VB_IMMEDIATE,
- VB_CVA_PRECALC
-};
-
-
-/* Values for immediate->BeginState */
-#define VERT_BEGIN_0 0x1 /* glBegin (if initially inside beg/end) */
-#define VERT_BEGIN_1 0x2 /* glBegin (if initially outside beg/end) */
-#define VERT_ERROR_0 0x4 /* invalid_operation in initial state 0 */
-#define VERT_ERROR_1 0x8 /* invalid_operation in initial state 1 */
/* KW: Represents everything that can take place between a begin and
- * end, and can represent multiple begin/end pairs. This plus *any*
- * state variable (GLcontext) should be all you need to replay the
- * represented begin/end pairs as if they took place in that state.
- *
- * Thus this is sufficient for both immediate and compiled modes, but
- * we could/should throw some elements away for compiled mode if we
- * know they were empty.
+ * end, and can represent multiple begin/end pairs. Can be used to
+ * losslessly encode this information in display lists.
*/
struct immediate
{
- struct immediate *next; /* for cache of free IM's */
+ struct __GLcontextRec *backref;
GLuint id, ref_count;
/* This must be saved when immediates are shared in display lists.
*/
- GLuint Start, Count;
+ GLuint CopyStart, Start, Count;
GLuint LastData; /* count or count+1 */
GLuint AndFlag, OrFlag;
- GLuint Tex3Flag, Tex4Flag; /* keep track of texcoord sizes */
+ GLuint TexSize; /* keep track of texcoord sizes */
GLuint BeginState, SavedBeginState;
GLuint LastPrimitive;
- GLuint ArrayAndFlags; /* precalc'ed for glArrayElt */
- GLuint ArrayIncr;
+ GLuint ArrayEltFlags; /* precalc'ed for glArrayElt */
+ GLuint ArrayEltIncr;
GLuint ArrayEltFlush;
GLuint FlushElt;
- GLuint Primitive[VB_SIZE]; /* GLubyte would do... */
- GLuint NextPrimitive[VB_SIZE];
+ GLuint MaxTextureUnits; /* precalc'ed for glMultiTexCoordARB */
- /* allocate storage for these on demand:
+ /* Temporary values created when vertices are copied into the
+ * first 3 slots of the struct:
*/
- struct gl_material (*Material)[2];
- GLuint *MaterialMask;
+ GLuint CopyOrFlag;
+ GLuint CopyAndFlag;
+ GLuint CopyTexSize;
+
- GLfloat (*TexCoordPtr[MAX_TEXTURE_UNITS])[4];
+ /* allocate storage for these on demand:
+ */
+ struct gl_material (*Material)[2];
+ GLuint *MaterialMask;
+ GLfloat *NormalLengths;
+ GLfloat (*TexCoord[MAX_TEXTURE_UNITS])[4];
- struct vertex_arrays v;
+ GLuint Primitive[IMM_SIZE]; /* BEGIN/END */
+ GLuint PrimitiveLength[IMM_SIZE]; /* BEGIN/END */
+ GLuint Flag[IMM_SIZE]; /* VERT_* flags */
+ GLchan Color[IMM_SIZE][4];
+ GLfloat Obj[IMM_SIZE][4];
+ GLfloat Normal[IMM_SIZE][3];
+ GLfloat TexCoord0[IMM_SIZE][4]; /* just VERT_TEX0 */
+ GLuint Elt[IMM_SIZE];
+ GLubyte EdgeFlag[IMM_SIZE];
+ GLuint Index[IMM_SIZE];
+ GLubyte SecondaryColor[IMM_SIZE][4];
+ GLfloat FogCoord[IMM_SIZE];
+};
- struct __GLcontextRec *backref;
- /* Normal lengths, zero if not available.
- */
- GLfloat *NormalLengths;
- GLuint LastCalcedLength;
-
- GLuint Flag[VB_SIZE]; /* bitwise-OR of VERT_ flags */
- GLchan Color[VB_SIZE][4];
- GLfloat Obj[VB_SIZE][4];
- GLfloat Normal[VB_SIZE][3];
- GLfloat TexCoord[MAX_TEXTURE_UNITS][VB_SIZE][4];
- GLuint Elt[VB_SIZE];
- GLubyte EdgeFlag[VB_SIZE];
- GLuint Index[VB_SIZE];
- GLubyte SecondaryColor[VB_SIZE][4];
- GLfloat FogCoord[VB_SIZE];
+struct vertex_arrays
+{
+ GLvector4f Obj;
+ GLvector3f Normal;
+ GLvector4ub Color;
+ GLvector1ui Index;
+ GLvector1ub EdgeFlag;
+ GLvector4f TexCoord[MAX_TEXTURE_UNITS];
+ GLvector1ui Elt;
+ GLvector4ub SecondaryColor;
+ GLvector1f FogCoord;
};
-/* Not so big on storage these days, although still has pointers to
- * arrays used for temporary results.
+typedef struct gl_material GLmaterial;
+
+/* Contains the current state of a running pipeline.
*/
typedef struct vertex_buffer
{
- /* Backpointers.
+ /* Constant over life of the vertex_buffer.
*/
- struct __GLcontextRec *ctx;
- struct tnl_context *tnlctx;
+ GLuint Size;
- /* Driver_data is allocated in Driver.RegisterVB(), if required.
+ /* Constant over the pipeline.
*/
- void *driver_data;
+ GLuint Count; /* for everything except Elts */
+ GLuint FirstClipped; /* temp verts for clipping */
+ GLuint FirstPrimitive; /* usually zero */
- /* List of operations to process vertices in current state.
+ /* Pointers to current data.
*/
- struct gl_pipeline *pipeline;
-
- /* Temporary storage used by immediate mode functions and various
- * operations in the pipeline.
+ GLuint *Elts; /* VERT_ELT */
+ GLvector4f *ObjPtr; /* VERT_OBJ */
+ GLvector4f *EyePtr; /* VERT_EYE */
+ GLvector4f *ClipPtr; /* VERT_CLIP */
+ GLvector4f *ProjectedClipPtr; /* VERT_CLIP (2) */
+ GLubyte ClipOrMask; /* VERT_CLIP (3) */
+ GLubyte *ClipMask; /* VERT_CLIP (4) */
+ GLvector3f *NormalPtr; /* VERT_NORM */
+ GLfloat *NormalLengthPtr; /* VERT_NORM (optional) */
+ GLvector1ub *EdgeFlagPtr; /* VERT_EDGE */
+ GLvector4f *TexCoordPtr[MAX_TEXTURE_UNITS]; /* VERT_TEX_0..n */
+ GLvector1ui *IndexPtr[2]; /* VERT_INDEX */
+ GLvector4ub *ColorPtr[2]; /* VERT_RGBA */
+ GLvector4ub *SecondaryColorPtr[2]; /* VERT_SPEC_RGB */
+ GLvector1f *FogCoordPtr; /* VERT_FOG_COORD */
+ GLvector1f *PointSizePtr; /* VERT_POINT_SIZE */
+ GLmaterial (*Material)[2]; /* VERT_MATERIAL, optional */
+ GLuint *MaterialMask; /* VERT_MATERIAL, optional */
+ GLuint *Flag; /* VERT_* flags, optional */
+ GLuint *Primitive; /* GL_(mode)|PRIM_* flags */
+ GLuint *PrimitiveLength; /* integers */
+
+
+ GLuint importable_data;
+ void (*import_data)( GLcontext *ctx, GLuint flags, GLuint vecflags );
+ /* Callback to the provider of the untransformed input for the
+ * render stage (or other stages) to call if they need to write into
+ * write-protected arrays, or fixup the stride on input arrays.
+ *
+ * This is currently only necessary for client arrays that make it
+ * as far down the pipeline as the render stage.
*/
- struct immediate *IM;
- struct vertex_array_pointers store;
- /* Where to find outstanding untransformed vertices.
- */
- struct immediate *prev_buffer;
-
- GLuint Type; /* Either VB_IMMEDIATE or VB_CVA_PRECALC */
-
- GLuint Size, Start, Count;
- GLuint Free, FirstFree;
- GLuint CopyStart;
- GLuint Parity, Ovf;
- GLuint PurgeFlags;
- GLuint IndirectCount; /* defaults to count */
- GLuint OrFlag, SavedOrFlag;
- GLuint Tex3Flag, Tex4Flag;
- GLuint SavedTex3Flag, SavedTex4Flag;
- GLuint EarlyCull;
- GLuint Culled, CullDone;
-
- /* Pointers to input data - default to buffers in 'im' above.
- */
- GLvector4f *ObjPtr;
- GLvector3f *NormalPtr;
- GLvector4ub *ColorPtr;
- GLvector1ui *IndexPtr;
- GLvector1ub *EdgeFlagPtr;
- GLvector4f *TexCoordPtr[MAX_TEXTURE_UNITS];
- GLvector1ui *EltPtr;
- GLvector4ub *SecondaryColorPtr;
- GLvector1f *FogCoordPtr;
- GLuint *Flag, FlagMax;
- struct gl_material (*Material)[2];
- GLuint *MaterialMask;
-
- GLuint *NextPrimitive;
- GLuint *Primitive;
- GLuint LastPrimitive;
-
- GLfloat (*BoundsPtr)[3]; /* Bounds for cull check */
- GLfloat *NormalLengthPtr; /* Array of precomputed inv. normal lengths */
-
- /* Holds malloced storage for pipeline data not supplied by
- * the immediate struct.
- */
- GLvector4f Eye;
- GLvector4f Clip;
- GLvector4f Win;
- GLvector1f PointSize;
- GLvector4ub BColor; /* not used in cva vb's */
- GLvector1ui BIndex; /* not used in cva vb's */
- GLvector4ub BSecondary; /* not used in cva vb's */
-
- /* Temporary storage - may point into IM, or be dynamically
- * allocated (for cva).
+ GLuint LastClipped;
+ void *interpfunc;
+ /* Two pieces of private data from _tnl_render_stage that have no
+ * business being in this struct.
*/
- GLubyte *ClipMask;
- GLubyte *UserClipMask;
- /* Internal values. Where these point depends on whether
- * there were any identity matrices defined as transformations
- * in the pipeline.
- */
- GLvector4f *EyePtr;
- GLvector4f *ClipPtr;
- GLvector4f *Unprojected;
- GLvector4f *Projected;
- GLvector4f *CurrentTexCoord;
- GLuint *Indirect; /* For eval rescue and cva render */
-
- /* Currently active colors
- */
- GLvector4ub *Color[2];
- GLvector1ui *Index[2];
- GLvector4ub *SecondaryColor[2];
+} TNLvertexbuffer;
- /* Storage for colors which have been lit but not yet fogged.
- * Required for CVA, just point into store for normal VB's.
- */
- GLvector4ub *LitColor[2];
- GLvector1ui *LitIndex[2];
- GLvector4ub *LitSecondary[2];
- /* Temporary values used in texgen.
- */
- GLfloat (*tmp_f)[3];
- GLfloat *tmp_m;
- /* Temporary values used in eval.
- */
- GLuint *EvaluatedFlags;
+/* Describes an individual operation on the pipeline.
+ */
+struct gl_pipeline_stage {
+ const char *name;
+ GLuint check_state; /* All state referenced in check() --
+ * When is the pipeline_stage struct
+ * itself invalidated? Must be
+ * constant.
+ */
- /* Not used for cva:
+ /* Usually constant or set by the 'check' callback:
*/
- GLubyte *NormCullStart;
- GLubyte *CullMask; /* Results of vertex culling */
- GLubyte *NormCullMask; /* Compressed onto shared normals */
-
- GLubyte ClipOrMask; /* bitwise-OR of all ClipMask[] values */
- GLubyte ClipAndMask; /* bitwise-AND of all ClipMask[] values */
- GLubyte CullFlag[2];
- GLubyte CullMode; /* see flags below */
-
- GLuint CopyCount; /* max 3 vertices to copy after transform */
- GLuint Copy[3];
- GLfloat CopyProj[3][4]; /* temporary store for projected clip coords */
-
- /* Hooks for module private data
+ GLuint run_state; /* All state referenced in run() --
+ * When is the cached output of the
+ * stage invalidated?
+ */
+
+ GLboolean active; /* True if runnable in current state */
+ GLuint inputs; /* VERT_* inputs to the stage */
+ GLuint outputs; /* VERT_* outputs of the stage */
+
+ /* Set in _tnl_run_pipeline():
*/
- void *swsetup_vb;
-
-} TNLvertexbuffer;
-
-
-typedef void (*shade_func)( struct vertex_buffer *VB );
-
-typedef void (*clip_interp_func)( struct vertex_buffer *VB, GLuint dst,
- GLfloat t, GLuint in, GLuint out );
-
-typedef GLuint (*clip_line_func)( struct vertex_buffer *VB,
- GLuint *i, GLuint *j,
- GLubyte mask);
-
-typedef GLuint (*clip_poly_func)( struct vertex_buffer *VB,
- GLuint n, GLuint vlist[],
- GLubyte mask );
-
+ GLuint changed_inputs; /* Generated value -- inputs to the
+ * stage that have changed since last
+ * call to 'run'.
+ */
-#define MAX_PIPELINE_STAGES 30
-
-#define PIPE_IMMEDIATE 0x1
-#define PIPE_PRECALC 0x2
-
-#define PIPE_OP_VERT_XFORM 0x1
-#define PIPE_OP_NORM_XFORM 0x2
-#define PIPE_OP_LIGHT 0x4
-#define PIPE_OP_FOG 0x8
-#define PIPE_OP_TEX 0x10
-#define PIPE_OP_RAST_SETUP_0 0x100
-#define PIPE_OP_RAST_SETUP_1 0x200
-#define PIPE_OP_RENDER 0x400
-#define PIPE_OP_CVA_PREPARE 0x800
-#define PIPE_OP_POINT_SIZE 0x1000
+ /* Private data for the pipeline stage:
+ */
+ void *private;
+ /* Free private data. May not be null.
+ */
+ void (*destroy)( struct gl_pipeline_stage * );
-struct gl_pipeline_stage {
- const char *name;
- GLuint ops; /* PIPE_OP flags */
- GLuint type; /* VERT flags */
- GLuint special; /* VERT flags - force update_inputs() */
- GLuint state_change; /* state flags - trigger update_inputs() */
- GLuint cva_state_change; /* state flags - recalc cva buffer */
- GLuint elt_forbidden_inputs; /* VERT flags - force a pipeline recalc */
- GLuint pre_forbidden_inputs; /* VERT flags - force a pipeline recalc */
- GLuint active; /* VERT flags */
- GLuint inputs; /* VERT flags */
- GLuint outputs; /* VERT flags */
+ /* Called from _tnl_validate_pipeline(). Must update all fields in
+ * the pipeline_stage struct for the current state.
+ */
void (*check)( GLcontext *ctx, struct gl_pipeline_stage * );
- void (*run)( struct vertex_buffer *VB );
+
+ /* Called from _tnl_run_pipeline(). The stage.changed_inputs value
+ * encodes all inputs to thee struct which have changed. If
+ * non-zero, recompute all affected outputs of the stage, otherwise
+ * execute any 'sideeffects' of the stage.
+ *
+ * Return value: GL_TRUE - keep going
+ * GL_FALSE - finished pipeline
+ */
+ GLboolean (*run)( GLcontext *ctx, struct gl_pipeline_stage * );
};
struct gl_pipeline {
- GLuint state_change; /* state changes which require recalc */
- GLuint cva_state_change; /* ... which require re-run */
- GLuint forbidden_inputs; /* inputs which require recalc */
- GLuint ops; /* what gets done in this pipe */
- GLuint changed_ops;
- GLuint inputs;
- GLuint outputs;
- GLuint new_inputs;
- GLuint new_outputs;
- GLuint fallback;
- GLuint type;
- GLuint pipeline_valid:1;
- GLuint data_valid:1;
- GLuint copy_transformed_data:1;
- GLuint replay_copied_vertices:1;
- GLuint new_state; /* state changes since last recalc */
- struct gl_pipeline_stage *stages[MAX_PIPELINE_STAGES];
+ GLuint build_state_trigger; /* state changes which require build */
+ GLuint build_state_changes; /* state changes since last build */
+ GLuint run_state_changes; /* state changes since last run */
+ GLuint run_input_changes; /* VERT_* changes since last run */
+ GLuint inputs; /* VERT_* inputs to pipeline */
+ struct gl_pipeline_stage stages[MAX_PIPELINE_STAGES];
+ GLuint nr_stages;
};
+struct tnl_eval_store {
+ GLuint EvalMap1Flags;
+ GLuint EvalMap2Flags;
+ GLuint EvalNewState;
-/* All fields are derived.
- */
-struct gl_cva {
- struct gl_pipeline pre;
- struct gl_pipeline elt;
-
- struct gl_client_array Elt;
- trans_1ui_func EltFunc;
-
- struct vertex_buffer *VB;
- struct vertex_arrays v;
- struct vertex_data store;
-
- GLuint elt_count;
- GLenum elt_mode;
- GLuint elt_size;
-
- GLuint forbidden_inputs;
- GLuint orflag;
- GLuint merge;
-
- GLuint locked;
- GLuint lock_changed;
- GLuint last_orflag;
- GLuint last_array_flags;
- GLuint last_array_new_state;
-};
-
-/* These are used to make the ctx->Current values look like
- * arrays (with zero StrideB).
- */
-struct gl_fallback_arrays {
- struct gl_client_array Normal;
- struct gl_client_array Color;
- struct gl_client_array SecondaryColor;
- struct gl_client_array FogCoord;
- struct gl_client_array Index;
- struct gl_client_array TexCoord[MAX_TEXTURE_UNITS];
- struct gl_client_array EdgeFlag;
+ GLfloat Obj[IMM_SIZE][4];
+ GLfloat TexCoord[IMM_SIZE][4];
+ GLfloat Normal[IMM_SIZE][3];
+ GLchan Color[IMM_SIZE][4];
+ GLuint Index[IMM_SIZE];
+ GLuint Flag[IMM_SIZE];
+ GLuint Elts[IMM_SIZE];
};
+typedef struct {
-
-typedef void (*texgen_func)( struct vertex_buffer *VB,
- GLuint textureSet);
-
-
-
-typedef struct tnl_context {
-
- GLuint _ArrayFlag[VB_SIZE]; /* crock */
- GLuint _ArrayFlags;
- GLuint _ArraySummary; /* Like flags, but no size information */
- GLuint _ArrayNewState; /* Tracks which arrays have been changed. */
- GLuint _ArrayTex3Flag;
- GLuint _ArrayTex4Flag;
-
-
- /* Pipeline stages - shared between the two pipelines,
- * which live in CVA.
- */
- struct gl_pipeline_stage PipelineStage[MAX_PIPELINE_STAGES];
- GLuint NrPipelineStages;
-
- /* Per-texunit derived state.
+ /* Track whether the module is active.
*/
- GLuint _TexgenSize[MAX_TEXTURE_UNITS];
- GLuint _TexgenHoles[MAX_TEXTURE_UNITS];
- texgen_func *_TexgenFunc[MAX_TEXTURE_UNITS];
-
+ GLboolean bound_exec;
/* Display list extensions
*/
GLuint opcode_vertex_cassette;
- /* Cva
+ /* Pipeline
*/
- struct gl_cva CVA;
- GLboolean CompileCVAFlag;
+ struct gl_pipeline pipeline;
+ struct vertex_buffer vb;
- clip_poly_func *_poly_clip_tab;
- clip_line_func *_line_clip_tab;
- clip_interp_func _ClipInterpFunc; /* Clip interpolation function */
- normal_func *_NormalTransform;
- shade_func *_shade_func_tab; /* Current shading function table */
-
- GLenum _CurrentPrimitive; /* Prim or GL_POLYGON+1 */
- GLuint _CurrentTex3Flag;
- GLuint _CurrentTex4Flag;
+ /* GLvectors for binding to vb:
+ */
+ struct vertex_arrays imm_inputs;
+ struct vertex_arrays array_inputs;
+ GLuint *tmp_primitive;
+ GLuint *tmp_primitive_length;
- GLboolean _ReplayHardBeginEnd; /* Display list execution of rect, etc */
+ /* Set when executing an internally generated immediate.
+ */
+ GLboolean ReplayHardBeginEnd;
+ GLenum CurrentPrimitive;
- GLuint _RenderFlags; /* Active inputs to render stage */
+ /* Note which vertices need copying over succesive immediates.
+ * Will add save versions to precompute vertex copying where
+ * possible.
+ */
+ struct immediate *ExecCopySource;
+ GLuint ExecCopyCount;
+ GLuint ExecCopyElts[IMM_MAX_COPIED_VERTS];
+ GLuint ExecCopyTexSize;
+ GLuint ExecParity;
- /* Cache of unused immediate structs */
- struct immediate *freed_im_queue;
- GLuint nr_im_queued;
+ GLuint DlistPrimitive;
+ GLuint DlistPrimitiveLength;
+ GLuint DlistLastPrimitive;
- struct gl_fallback_arrays Fallback;
+ /* Derived state and storage for _tnl_eval_vb:
+ */
+ struct tnl_eval_store eval;
+ /* Functions to be plugged into dispatch when tnl is active.
+ */
GLvertexformat vtxfmt;
} TNLcontext;
@@ -598,20 +418,16 @@ typedef struct tnl_context {
#define TNL_CONTEXT(ctx) ((TNLcontext *)(ctx->swtnl_context))
#define TNL_CURRENT_IM(ctx) ((struct immediate *)(ctx->swtnl_im))
-#define TNL_VB(ctx) ((struct vertex_buffer *)(ctx->swtnl_vb))
-extern GLboolean _tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags );
+#define TYPE_IDX(t) ((t) & 0xf)
+#define MAX_TYPES TYPE_IDX(GL_DOUBLE)+1 /* 0xa + 1 */
-extern void
-_tnl_MakeCurrent( GLcontext *ctx,
- GLframebuffer *drawBuffer,
- GLframebuffer *readBuffer );
+extern void _tnl_MakeCurrent( GLcontext *ctx,
+ GLframebuffer *drawBuffer,
+ GLframebuffer *readBuffer );
-extern void
-_tnl_LightingSpaceChange( GLcontext *ctx );
-
/*
* Macros for fetching current input buffer.
*/
@@ -628,4 +444,5 @@ do { \
} while (0)
#endif
+
#endif
diff --git a/src/mesa/tnl/t_eval_api.c b/src/mesa/tnl/t_eval_api.c
new file mode 100644
index 0000000000..efe7876333
--- /dev/null
+++ b/src/mesa/tnl/t_eval_api.c
@@ -0,0 +1,209 @@
+/* $Id: t_eval_api.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+#include "math/m_eval.h"
+
+#include "t_eval_api.h"
+#include "t_imm_api.h"
+#include "t_imm_alloc.h"
+#include "t_imm_exec.h"
+
+
+
+
+
+/* KW: If are compiling, we don't know whether eval will produce a
+ * vertex when it is run in the future. If this is pure immediate
+ * mode, eval is a noop if neither vertex map is enabled.
+ *
+ * Thus we need to have a check in the display list code or
+ * elsewhere for eval(1,2) vertices in the case where
+ * map(1,2)_vertex is disabled, and to purge those vertices from
+ * the vb.
+ */
+void
+_tnl_exec_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+ GLfloat u, du;
+ GLenum prim;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ switch (mode) {
+ case GL_POINT:
+ prim = GL_POINTS;
+ break;
+ case GL_LINE:
+ prim = GL_LINE_STRIP;
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
+ return;
+ }
+
+ /* No effect if vertex maps disabled.
+ */
+ if (!ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
+ return;
+
+ du = ctx->Eval.MapGrid1du;
+ u = ctx->Eval.MapGrid1u1 + i1 * du;
+
+ /* Need to turn off compilation -- this is already saved, and the
+ * coordinates generated and the test above depend on state that
+ * may change before the list is executed.
+ *
+ * TODO: Anaylse display lists to determine if this state is
+ * constant.
+ */
+ {
+ GLboolean compiling = ctx->CompileFlag;
+ struct immediate *im = TNL_CURRENT_IM(ctx);
+
+ if (compiling) {
+ FLUSH_VERTICES( ctx, 0 );
+ SET_IMMEDIATE( ctx, _tnl_alloc_immediate( ctx ) );
+ ctx->CompileFlag = GL_FALSE;
+ }
+
+ _tnl_begin( ctx, prim );
+ for (i=i1;i<=i2;i++,u+=du) {
+ _tnl_eval_coord1f( ctx, u );
+ }
+ _tnl_end(ctx);
+
+ if (compiling) {
+ FLUSH_VERTICES( ctx, 0 );
+ ASSERT( TNL_CURRENT_IM(ctx)->ref_count == 0 );
+ _tnl_free_immediate( TNL_CURRENT_IM(ctx) );
+ SET_IMMEDIATE( ctx, im );
+ ctx->CompileFlag = GL_TRUE;
+ }
+ }
+}
+
+
+
+void
+_tnl_exec_EvalMesh2( GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i, j;
+ GLfloat u, du, v, dv, v1, u1;
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* No effect if vertex maps disabled.
+ */
+ if (!ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
+ return;
+
+
+ du = ctx->Eval.MapGrid2du;
+ dv = ctx->Eval.MapGrid2dv;
+ v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
+ u1 = ctx->Eval.MapGrid2u1 + i1 * du;
+
+ /* Need to turn off compilation -- this is already saved, and the
+ * coordinates generated and the test above depend on state that
+ * may change before the list is executed.
+ */
+ {
+ GLboolean compiling = ctx->CompileFlag;
+ struct immediate *im = TNL_CURRENT_IM(ctx);
+
+ if (compiling) {
+ FLUSH_VERTICES( ctx, 0 );
+ SET_IMMEDIATE( ctx, _tnl_alloc_immediate( ctx ) );
+ ctx->CompileFlag = GL_FALSE;
+ }
+
+ switch (mode) {
+ case GL_POINT:
+ _tnl_begin( ctx, GL_POINTS );
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ _tnl_eval_coord2f( ctx, u, v );
+ }
+ }
+ _tnl_end(ctx);
+ break;
+ case GL_LINE:
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ _tnl_begin( ctx, GL_LINE_STRIP );
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ _tnl_eval_coord2f( ctx, u, v );
+ }
+ _tnl_end(ctx);
+ }
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ _tnl_begin( ctx, GL_LINE_STRIP );
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ _tnl_eval_coord2f( ctx, u, v );
+ }
+ _tnl_end(ctx);
+ }
+ break;
+ case GL_FILL:
+ for (v=v1,j=j1;j<j2;j++,v+=dv) {
+ _tnl_begin( ctx, GL_TRIANGLE_STRIP );
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ _tnl_eval_coord2f( ctx, u, v );
+ _tnl_eval_coord2f( ctx, u, v+dv );
+ }
+ _tnl_end(ctx);
+ }
+ break;
+ default:
+ gl_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
+ return;
+ }
+
+ if (compiling) {
+ FLUSH_VERTICES( ctx, 0 );
+ _tnl_free_immediate( TNL_CURRENT_IM( ctx ) );
+ SET_IMMEDIATE( ctx, im );
+ ctx->CompileFlag = GL_TRUE;
+ }
+ }
+}
+
+
+
+void _tnl_eval_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
+ vfmt->EvalMesh1 = _tnl_exec_EvalMesh1;
+ vfmt->EvalMesh2 = _tnl_exec_EvalMesh2;
+}
diff --git a/src/mesa/tnl/t_eval_api.h b/src/mesa/tnl/t_eval_api.h
new file mode 100644
index 0000000000..fab6108c8d
--- /dev/null
+++ b/src/mesa/tnl/t_eval_api.h
@@ -0,0 +1,44 @@
+/* $Id: t_eval_api.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_EVAL_H
+#define _T_EVAL_H
+
+
+#include "mtypes.h"
+#include "t_context.h"
+
+/* Use _mesa_save_EvalMesh{1,2} to save these to display lists.
+ */
+extern void _tnl_exec_EvalMesh1( GLenum mode, GLint i1, GLint i2 );
+
+extern void _tnl_exec_EvalMesh2( GLenum mode, GLint i1, GLint i2,
+ GLint j1, GLint j2 );
+
+void _tnl_eval_init( GLcontext *ctx );
+
+#endif
diff --git a/src/mesa/tnl/t_imm_alloc.c b/src/mesa/tnl/t_imm_alloc.c
new file mode 100644
index 0000000000..44e3a598ec
--- /dev/null
+++ b/src/mesa/tnl/t_imm_alloc.c
@@ -0,0 +1,104 @@
+/* $Id: t_imm_alloc.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+#include "glheader.h"
+#include "mem.h"
+#include "mtypes.h"
+
+#include "t_imm_alloc.h"
+
+
+
+struct immediate *_tnl_alloc_immediate( GLcontext *ctx )
+{
+ static int id = 0;
+ struct immediate *IM = ALIGN_MALLOC_STRUCT( immediate, 32 );
+ GLuint j;
+
+ if (!IM)
+ return 0;
+
+ IM->id = id++;
+ IM->ref_count = 0;
+ IM->backref = ctx;
+ IM->NormalLengths = 0;
+ IM->FlushElt = 0;
+ IM->LastPrimitive = IMM_MAX_COPIED_VERTS;
+ IM->Count = IMM_MAX_COPIED_VERTS;
+ IM->Start = IMM_MAX_COPIED_VERTS;
+ IM->Material = 0;
+ IM->MaterialMask = 0;
+ IM->MaxTextureUnits = ctx->Const.MaxTextureUnits;
+ IM->TexSize = 0;
+
+ IM->CopyTexSize = 0;
+ IM->CopyStart = IM->Start;
+
+
+ /* TexCoord0 is special.
+ */
+ IM->TexCoord[0] = IM->TexCoord0;
+
+ for (j = 1; j < ctx->Const.MaxTextureUnits; j++)
+ IM->TexCoord[j] = ALIGN_MALLOC( IMM_SIZE * sizeof(GLfloat) * 4, 32 );
+
+ /* KW: Removed initialization of normals as these are now treated
+ * identically to all other data types.
+ */
+
+ MEMSET(IM->Flag, 0, sizeof(IM->Flag));
+
+ return IM;
+}
+
+
+void _tnl_free_immediate( struct immediate *IM )
+{
+ GLuint j;
+
+ if (IM->NormalLengths) {
+ FREE( IM->NormalLengths );
+ IM->NormalLengths = 0;
+ }
+
+ if (IM->Material) {
+ FREE( IM->Material );
+ FREE( IM->MaterialMask );
+ IM->Material = 0;
+ IM->MaterialMask = 0;
+
+ for (j = 1; j < IM->MaxTextureUnits; j++)
+ ALIGN_FREE( IM->TexCoord[j] );
+ }
+
+ ALIGN_FREE( IM );
+}
+
+
+
diff --git a/src/mesa/tnl/t_imm_alloc.h b/src/mesa/tnl/t_imm_alloc.h
new file mode 100644
index 0000000000..5640f80cea
--- /dev/null
+++ b/src/mesa/tnl/t_imm_alloc.h
@@ -0,0 +1,40 @@
+/* $Id: t_imm_alloc.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_IMM_ALLOC_H
+#define _T_IMM_ALLOC_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+extern struct immediate *_tnl_alloc_immediate( GLcontext *ctx );
+
+extern void _tnl_free_immediate( struct immediate *im );
+
+
+#endif
diff --git a/src/mesa/tnl/t_imm_api.c b/src/mesa/tnl/t_imm_api.c
new file mode 100644
index 0000000000..6224bff3cb
--- /dev/null
+++ b/src/mesa/tnl/t_imm_api.c
@@ -0,0 +1,1398 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.3
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keith@precisioninsight.com>
+ */
+
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "enums.h"
+#include "light.h"
+#include "mem.h"
+#include "state.h"
+#include "colormac.h"
+#include "macros.h"
+
+#include "t_context.h"
+#include "t_imm_api.h"
+#include "t_imm_elt.h"
+#include "t_imm_exec.h"
+#include "t_imm_dlist.h"
+
+
+/* A cassette is full or flushed on a statechange.
+ */
+void _tnl_flush_immediate( struct immediate *IM )
+{
+ GLcontext *ctx = IM->backref;
+
+ if (ctx->CompileFlag)
+ _tnl_compile_cassette( ctx, IM );
+ else
+ _tnl_execute_cassette( ctx, IM );
+}
+
+
+void _tnl_flush_vertices( GLcontext *ctx, GLuint flags )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ if (IM->Flag[IM->Start])
+ if ((flags & FLUSH_UPDATE_CURRENT) || IM->Count > IM->Start)
+ _tnl_flush_immediate( IM );
+}
+
+
+void
+_tnl_begin( GLcontext *ctx, GLenum p )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint inflags, state;
+
+ if (MESA_VERBOSE&VERBOSE_API)
+ fprintf(stderr, "glBegin(IM %d) %s\n", IM->id, gl_lookup_enum_by_nr(p));
+
+ if (ctx->NewState)
+ gl_update_state(ctx);
+
+ /* if only a very few slots left, might as well flush now
+ */
+ if (IM->Count > IMM_MAXDATA-8) {
+ _tnl_flush_immediate( IM );
+ IM = TNL_CURRENT_IM(ctx);
+ }
+
+ /* Check for and flush buffered vertices from internal operations.
+ */
+ if (IM->SavedBeginState) {
+ _tnl_flush_immediate( IM );
+ IM = TNL_CURRENT_IM(ctx);
+ IM->BeginState = IM->SavedBeginState;
+ IM->SavedBeginState = 0;
+ }
+
+ state = IM->BeginState;
+ inflags = state & (VERT_BEGIN_0|VERT_BEGIN_1);
+ state |= inflags << 2; /* set error conditions */
+
+ if (inflags != (VERT_BEGIN_0|VERT_BEGIN_1))
+ {
+ GLuint count = IM->Count;
+ GLuint last = IM->LastPrimitive;
+
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+ state |= (VERT_BEGIN_0|VERT_BEGIN_1);
+ IM->Flag[count] |= VERT_BEGIN;
+ IM->Primitive[IM->LastPrimitive] &= ~PRIM_LAST;
+ IM->Primitive[count] = p | PRIM_BEGIN | PRIM_LAST;
+ IM->PrimitiveLength[IM->LastPrimitive] = count - IM->LastPrimitive;
+ IM->LastPrimitive = count;
+
+ /* Not quite right. Need to use the fallback '_aa_ArrayElement'
+ * when not known to be inside begin/end and arrays are unlocked.
+ */
+ if (IM->FlushElt) {
+ _tnl_translate_array_elts( ctx, IM, last, count );
+ IM->FlushElt = 0;
+ }
+ }
+
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ IM->BeginState = state;
+}
+
+
+
+static void
+_tnl_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (mode > GL_POLYGON) {
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ _tnl_begin(ctx, mode);
+
+ /* If compiling update SavePrimitive now.
+ *
+ * In compile_and_exec mode, exec_primitive will be updated when
+ * the cassette is finished.
+ *
+ * If not compiling, update exec_primitive now.
+ */
+ if (ctx->CompileFlag) {
+ if (ctx->Driver.CurrentSavePrimitive == PRIM_UNKNOWN)
+ ctx->Driver.CurrentSavePrimitive = PRIM_INSIDE_UNKNOWN_PRIM;
+ else if (ctx->Driver.CurrentSavePrimitive == PRIM_OUTSIDE_BEGIN_END)
+ ctx->Driver.CurrentSavePrimitive = mode;
+ }
+ else if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
+ ctx->Driver.CurrentExecPrimitive = mode;
+}
+
+
+GLboolean
+_tnl_hard_begin( GLcontext *ctx, GLenum p )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint count, last;
+
+ if (ctx->NewState)
+ gl_update_state(ctx);
+
+ /* If not compiling, treat as a normal begin().
+ */
+ if (!ctx->CompileFlag) {
+ _tnl_begin( ctx, p );
+ return GL_TRUE;
+ }
+
+ if (IM->Count > IMM_MAXDATA-8) {
+ _tnl_flush_immediate( IM );
+ IM = TNL_CURRENT_IM(ctx);
+ }
+
+ switch (IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1)) {
+ case VERT_BEGIN_0|VERT_BEGIN_1:
+ /* In this case we know for sure that the list is going to be
+ * inside a begin/end object at this point when run. Rather
+ * than saving the redundant data, compile in an error and
+ * return.
+ */
+ IM->BeginState |= (VERT_ERROR_1|VERT_ERROR_0);
+ return GL_FALSE;
+
+ case VERT_BEGIN_0:
+ case VERT_BEGIN_1:
+ /* This is a normal (non-hard) immediate, in an unknown
+ * begin/end state. Assert it is empty and conviert it to a
+ * 'hard' one.
+ */
+ ASSERT (IM->SavedBeginState == 0);
+
+/* ASSERT (ctx->Driver.CurrentSavePrimitive >= GL_POLYGON+1); */
+
+ /* Push current beginstate, to be restored later. Don't worry
+ * about raising errors.
+ */
+ IM->SavedBeginState = IM->BeginState;
+
+ /* FALLTHROUGH */
+ case 0:
+
+ IM->BeginState |= VERT_BEGIN_0|VERT_BEGIN_1;
+
+
+ count = IM->Count;
+ last = IM->LastPrimitive;
+
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+ IM->Flag[count] |= VERT_BEGIN;
+ IM->Primitive[last] &= ~PRIM_LAST;
+ IM->Primitive[count] = p | PRIM_BEGIN | PRIM_LAST;
+ IM->PrimitiveLength[last] = count - last;
+ IM->LastPrimitive = count;
+
+ ASSERT (!IM->FlushElt);
+
+ /* This is necessary as this immediate will not be flushed in
+ * _tnl_end() -- we leave it active, hoping to pick up more
+ * vertices before the next state change.
+ */
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ return GL_TRUE;
+
+ default:
+ ASSERT (0);
+ return GL_TRUE;
+ }
+}
+
+/* Note the continuation of a partially completed primitive. For
+ * driver t&l fallbacks between begin/end primitives. Has basically
+ * the same effects as a primitive wrapping onto a second immediate
+ * struct.
+ *
+ * ==> Can actually call this from _tnl_wakeup_exec, taking mode from
+ * ctx->Driver.CurrentExecPrimitive.
+ */
+#if 0
+void _tnl_fallback_begin( GLcontext *ctx, GLenum mode )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ ASSERT( IM->Count == IM->Start );
+ ASSERT( IM->Flag[IM->Start] == 0 );
+ ASSERT( mode < GL_POLYGON+1 );
+ _tnl_begin( ctx, mode );
+ IM->Primitive[IM->Start] &= ~PRIM_BEGIN;
+}
+#endif
+
+
+/* Both streams now outside begin/end.
+ *
+ * Leave SavedBeginState untouched -- attempt to gather several
+ * rects/arrays together in a single immediate struct.
+ */
+void
+_tnl_end( GLcontext *ctx )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint state = IM->BeginState;
+ GLuint inflags = (~state) & (VERT_BEGIN_0|VERT_BEGIN_1);
+
+ state |= inflags << 2; /* errors */
+
+ if (inflags != (VERT_BEGIN_0|VERT_BEGIN_1))
+ {
+ GLuint count = IM->Count;
+ GLuint last = IM->LastPrimitive;
+
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+ state &= ~(VERT_BEGIN_0|VERT_BEGIN_1); /* update state */
+ IM->Flag[count] |= VERT_END;
+ IM->Primitive[last] |= PRIM_END;
+ IM->Primitive[last] &= ~PRIM_LAST;
+ IM->PrimitiveLength[last] = count - last;
+ IM->Primitive[count] = (GL_POLYGON+1) | PRIM_LAST;
+ IM->LastPrimitive = count;
+
+ if (IM->FlushElt) {
+ _tnl_translate_array_elts( ctx, IM, last, count );
+ IM->FlushElt = 0;
+ }
+
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ }
+
+ IM->BeginState = state;
+
+ /* You can set this flag to get the old 'flush_vb on glEnd()'
+ * behaviour.
+ */
+ if ((MESA_DEBUG_FLAGS&DEBUG_ALWAYS_FLUSH))
+ _tnl_flush_immediate( IM );
+}
+
+static void
+_tnl_End(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _tnl_end( ctx );
+
+ /* Need to keep save primitive uptodate in COMPILE and
+ * COMPILE_AND_EXEC modes, need to keep exec primitive uptodate
+ * otherwise.
+ */
+ if (ctx->CompileFlag)
+ ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+ else
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+
+
+}
+
+
+#define COLOR( IM, r, g, b, a ) \
+{ \
+ GLuint count = IM->Count; \
+ IM->Flag[count] |= VERT_RGBA; \
+ IM->Color[count][0] = r; \
+ IM->Color[count][1] = g; \
+ IM->Color[count][2] = b; \
+ IM->Color[count][3] = a; \
+}
+
+#define COLORV( IM, v ) \
+{ \
+ GLuint count = IM->Count; \
+ IM->Flag[count] |= VERT_RGBA; \
+ COPY_CHAN4(IM->Color[count], v); \
+}
+
+
+static void
+_tnl_Color3f( GLfloat red, GLfloat green, GLfloat blue )
+{
+#if CHAN_BITS == 8
+ GLubyte col[4];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue);
+ col[3] = CHAN_MAX;
+ COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(red),
+ UNCLAMPED_FLOAT_TO_CHAN(green),
+ UNCLAMPED_FLOAT_TO_CHAN(blue),
+ CHAN_MAX);
+#endif
+}
+
+
+static void
+_tnl_Color3ub( GLubyte red, GLubyte green, GLubyte blue )
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ COLOR( IM, red, green, blue, CHAN_MAX );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UBYTE_TO_CHAN(red),
+ UBYTE_TO_CHAN(green),
+ UBYTE_TO_CHAN(blue),
+ CHAN_MAX);
+#endif
+}
+
+
+
+
+static void
+_tnl_Color4f( GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha )
+{
+#if CHAN_BITS == 8
+ GLubyte col[4];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[3], alpha);
+ COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(red),
+ UNCLAMPED_FLOAT_TO_CHAN(green),
+ UNCLAMPED_FLOAT_TO_CHAN(blue),
+ UNCLAMPED_FLOAT_TO_CHAN(alpha));
+#endif
+}
+
+static void
+_tnl_Color4ub( GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha )
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ COLOR( IM, red, green, blue, alpha );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UBYTE_TO_CHAN(red),
+ UBYTE_TO_CHAN(green),
+ UBYTE_TO_CHAN(blue),
+ UBYTE_TO_CHAN(alpha));
+#endif
+}
+
+
+static void
+_tnl_Color3fv( const GLfloat *v )
+{
+#if CHAN_BITS == 8
+ GLubyte col[4];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]);
+ col[3] = CHAN_MAX;
+ COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(v[0]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[1]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[2]),
+ CHAN_MAX);
+
+#endif
+}
+
+
+
+static void
+_tnl_Color3ubv( const GLubyte *v )
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ COLOR( IM, v[0], v[1], v[2], CHAN_MAX );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UBYTE_TO_CHAN(v[0]),
+ UBYTE_TO_CHAN(v[1]),
+ UBYTE_TO_CHAN(v[2]),
+ CHAN_MAX);
+#endif
+}
+
+static void
+_tnl_Color4fv( const GLfloat *v )
+{
+#if CHAN_BITS == 8
+ GLubyte col[4];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[3], v[3]);
+ COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(v[0]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[1]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[2]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[3]));
+#endif
+}
+
+
+
+static void
+_tnl_Color4ubv( const GLubyte *v)
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ COLORV( IM, v );
+#else
+ GET_IMMEDIATE;
+ COLOR(IM,
+ UBYTE_TO_CHAN(v[0]),
+ UBYTE_TO_CHAN(v[1]),
+ UBYTE_TO_CHAN(v[2]),
+ UBYTE_TO_CHAN(v[3]));
+#endif
+}
+
+
+
+
+#define SECONDARY_COLOR( IM, r, g, b ) \
+{ \
+ GLuint count = IM->Count; \
+ IM->Flag[count] |= VERT_SPEC_RGB; \
+ IM->SecondaryColor[count][0] = r; \
+ IM->SecondaryColor[count][1] = g; \
+ IM->SecondaryColor[count][2] = b; \
+}
+
+#define SECONDARY_COLORV( IM, v ) \
+{ \
+ GLuint count = IM->Count; \
+ IM->Flag[count] |= VERT_SPEC_RGB; \
+ IM->SecondaryColor[count][0] = v[0]; \
+ IM->SecondaryColor[count][1] = v[1]; \
+ IM->SecondaryColor[count][2] = v[2]; \
+}
+
+
+
+
+static void
+_tnl_SecondaryColor3fEXT( GLfloat red, GLfloat green, GLfloat blue )
+{
+#if CHAN_BITS == 8
+ GLubyte col[3];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], red);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], green);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], blue);
+ SECONDARY_COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ SECONDARY_COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(red),
+ UNCLAMPED_FLOAT_TO_CHAN(green),
+ UNCLAMPED_FLOAT_TO_CHAN(blue));
+#endif
+}
+
+
+
+static void
+_tnl_SecondaryColor3ubEXT( GLubyte red, GLubyte green, GLubyte blue )
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ SECONDARY_COLOR( IM, red, green, blue );
+#else
+ GET_IMMEDIATE;
+ SECONDARY_COLOR(IM,
+ UBYTE_TO_CHAN(red),
+ UBYTE_TO_CHAN(green),
+ UBYTE_TO_CHAN(blue));
+#endif
+}
+
+
+
+
+static void
+_tnl_SecondaryColor3fvEXT( const GLfloat *v )
+{
+#if CHAN_BITS == 8
+ GLubyte col[3];
+ GET_IMMEDIATE;
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[0], v[0]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[1], v[1]);
+ FLOAT_COLOR_TO_UBYTE_COLOR(col[2], v[2]);
+ SECONDARY_COLORV( IM, col );
+#else
+ GET_IMMEDIATE;
+ SECONDARY_COLOR(IM,
+ UNCLAMPED_FLOAT_TO_CHAN(v[0]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[1]),
+ UNCLAMPED_FLOAT_TO_CHAN(v[2]));
+#endif
+}
+
+
+
+static void
+_tnl_SecondaryColor3ubvEXT( const GLubyte *v )
+{
+#if CHAN_BITS == 8
+ GET_IMMEDIATE;
+ SECONDARY_COLOR( IM, v[0], v[1], v[2] );
+#else
+ GET_IMMEDIATE;
+ SECONDARY_COLOR(IM,
+ UBYTE_TO_CHAN(v[0]),
+ UBYTE_TO_CHAN(v[1]),
+ UBYTE_TO_CHAN(v[2]));
+#endif
+}
+
+
+
+
+static void
+_tnl_EdgeFlag( GLboolean flag )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->EdgeFlag[count] = flag;
+ IM->Flag[count] |= VERT_EDGE;
+}
+
+
+static void
+_tnl_EdgeFlagv( const GLboolean *flag )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->EdgeFlag[count] = *flag;
+ IM->Flag[count] |= VERT_EDGE;
+}
+
+
+static void
+_tnl_FogCoordfEXT( GLfloat f )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->FogCoord[count] = f;
+ IM->Flag[count] |= VERT_FOG_COORD;
+}
+
+static void
+_tnl_FogCoordfvEXT( const GLfloat *v )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->FogCoord[count] = v[0];
+ IM->Flag[count] |= VERT_FOG_COORD;
+}
+
+
+static void
+_tnl_Indexi( GLint c )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->Index[count] = c;
+ IM->Flag[count] |= VERT_INDEX;
+}
+
+
+static void
+_tnl_Indexiv( const GLint *c )
+{
+ GLuint count;
+ GET_IMMEDIATE;
+ count = IM->Count;
+ IM->Index[count] = *c;
+ IM->Flag[count] |= VERT_INDEX;
+}
+
+
+#define NORMAL( x, y, z ) \
+{ \
+ GLuint count; \
+ GLfloat *normal; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_NORM; \
+ normal = IM->Normal[count]; \
+ ASSIGN_3V(normal, x,y,z); \
+}
+
+#if defined(USE_IEEE)
+#define NORMALF( x, y, z ) \
+{ \
+ GLuint count; \
+ GLint *normal; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_NORM; \
+ normal = (GLint *)IM->Normal[count]; \
+ ASSIGN_3V(normal, *(int*)&(x), *(int*)&(y), *(int*)&(z)); \
+}
+#else
+#define NORMALF NORMAL
+#endif
+
+static void
+_tnl_Normal3f( GLfloat nx, GLfloat ny, GLfloat nz )
+{
+ NORMALF(nx, ny, nz);
+}
+
+
+static void
+_tnl_Normal3fv( const GLfloat *v )
+{
+ NORMALF( v[0], v[1], v[2] );
+}
+
+
+
+#define TEXCOORD1(s) \
+{ \
+ GLuint count; \
+ GLfloat *tc; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_TEX0; \
+ tc = IM->TexCoord0[count]; \
+ ASSIGN_4V(tc,s,0,0,1); \
+}
+
+#define TEXCOORD2(s,t) \
+{ \
+ GLuint count; \
+ GLfloat *tc; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_TEX0; \
+ tc = IM->TexCoord0[count]; \
+ ASSIGN_4V(tc, s,t,0,1); \
+}
+
+#define TEXCOORD3(s,t,u) \
+{ \
+ GLuint count; \
+ GLfloat *tc; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_TEX0; \
+ IM->TexSize |= TEX_0_SIZE_3; \
+ tc = IM->TexCoord0[count]; \
+ ASSIGN_4V(tc, s,t,u,1); \
+}
+
+#define TEXCOORD4(s,t,u,v) \
+{ \
+ GLuint count; \
+ GLfloat *tc; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_TEX0; \
+ IM->TexSize |= TEX_0_SIZE_4; \
+ tc = IM->TexCoord0[count]; \
+ ASSIGN_4V(tc, s,t,u,v); \
+}
+
+#if defined(USE_IEEE)
+#define TEXCOORD2F(s,t) \
+{ \
+ GLuint count; \
+ GLint *tc; \
+ GET_IMMEDIATE; \
+ count = IM->Count; \
+ IM->Flag[count] |= VERT_TEX0; \
+ tc = (GLint *)IM->TexCoord0[count]; \
+ tc[0] = *(GLint *)&(s); \
+ tc[1] = *(GLint *)&(t); \
+ tc[2] = 0; \
+ tc[3] = IEEE_ONE; \
+}
+#else
+#define TEXCOORD2F TEXCOORD2
+#endif
+
+static void
+_tnl_TexCoord1f( GLfloat s )
+{
+ TEXCOORD1(s);
+}
+
+
+static void
+_tnl_TexCoord2f( GLfloat s, GLfloat t )
+{
+ TEXCOORD2F(s,t);
+}
+
+
+static void
+_tnl_TexCoord3f( GLfloat s, GLfloat t, GLfloat r )
+{
+ TEXCOORD3(s,t,r);
+}
+
+static void
+_tnl_TexCoord4f( GLfloat s, GLfloat t, GLfloat r, GLfloat q )
+{
+ TEXCOORD4(s,t,r,q)
+}
+
+static void
+_tnl_TexCoord1fv( const GLfloat *v )
+{
+ TEXCOORD1(v[0]);
+}
+
+static void
+_tnl_TexCoord2fv( const GLfloat *v )
+{
+ TEXCOORD2F(v[0],v[1]);
+}
+
+static void
+_tnl_TexCoord3fv( const GLfloat *v )
+{
+ TEXCOORD3(v[0],v[1],v[2]);
+}
+
+static void
+_tnl_TexCoord4fv( const GLfloat *v )
+{
+ TEXCOORD4(v[0],v[1],v[2],v[3]);
+}
+
+
+
+/* KW: Run into bad problems in vertex copying if we don't fully pad
+ * the incoming vertices.
+ */
+#define VERTEX2(IM, x,y) \
+{ \
+ GLuint count = IM->Count++; \
+ GLfloat *dest = IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ; \
+ ASSIGN_4V(dest, x, y, 0, 1); \
+/* ASSERT(IM->Flag[IM->Count]==0); */\
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#define VERTEX3(IM,x,y,z) \
+{ \
+ GLuint count = IM->Count++; \
+ GLfloat *dest = IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ_23; \
+ ASSIGN_4V(dest, x, y, z, 1); \
+/* ASSERT(IM->Flag[IM->Count]==0); */ \
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#define VERTEX4(IM, x,y,z,w) \
+{ \
+ GLuint count = IM->Count++; \
+ GLfloat *dest = IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ_234; \
+ ASSIGN_4V(dest, x, y, z, w); \
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#if defined(USE_IEEE)
+#define VERTEX2F(IM, x, y) \
+{ \
+ GLuint count = IM->Count++; \
+ GLint *dest = (GLint *)IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ; \
+ dest[0] = *(GLint *)&(x); \
+ dest[1] = *(GLint *)&(y); \
+ dest[2] = 0; \
+ dest[3] = IEEE_ONE; \
+/* ASSERT(IM->Flag[IM->Count]==0); */ \
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+#else
+#define VERTEX2F VERTEX2
+#endif
+
+#if defined(USE_IEEE)
+#define VERTEX3F(IM, x, y, z) \
+{ \
+ GLuint count = IM->Count++; \
+ GLint *dest = (GLint *)IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ_23; \
+ dest[0] = *(GLint *)&(x); \
+ dest[1] = *(GLint *)&(y); \
+ dest[2] = *(GLint *)&(z); \
+ dest[3] = IEEE_ONE; \
+/* ASSERT(IM->Flag[IM->Count]==0); */ \
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+#else
+#define VERTEX3F VERTEX3
+#endif
+
+#if defined(USE_IEEE)
+#define VERTEX4F(IM, x, y, z, w) \
+{ \
+ GLuint count = IM->Count++; \
+ GLint *dest = (GLint *)IM->Obj[count]; \
+ IM->Flag[count] |= VERT_OBJ_234; \
+ dest[0] = *(GLint *)&(x); \
+ dest[1] = *(GLint *)&(y); \
+ dest[2] = *(GLint *)&(z); \
+ dest[3] = *(GLint *)&(w); \
+ if (count == IMM_MAXDATA - 1) \
+ _tnl_flush_immediate( IM ); \
+}
+#else
+#define VERTEX4F VERTEX4
+#endif
+
+
+
+static void
+_tnl_Vertex2f( GLfloat x, GLfloat y )
+{
+ GET_IMMEDIATE;
+ VERTEX2F( IM, x, y );
+}
+
+static void
+_tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ GET_IMMEDIATE;
+ VERTEX3F( IM, x, y, z );
+}
+static void
+_tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ GET_IMMEDIATE;
+ VERTEX4F( IM, x, y, z, w );
+}
+
+static void
+_tnl_Vertex2fv( const GLfloat *v )
+{
+ GET_IMMEDIATE;
+ VERTEX2F( IM, v[0], v[1] );
+}
+
+static void
+_tnl_Vertex3fv( const GLfloat *v )
+{
+ GET_IMMEDIATE;
+ VERTEX3F( IM, v[0], v[1], v[2] );
+}
+
+static void
+_tnl_Vertex4fv( const GLfloat *v )
+{
+ GET_IMMEDIATE;
+ VERTEX4F( IM, v[0], v[1], v[2], v[3] );
+}
+
+
+
+
+/*
+ * GL_ARB_multitexture
+ *
+ * Note: the multitexture spec says that specifying an invalid target
+ * has undefined results and does not have to generate an error. Just
+ * don't crash. We no-op on invalid targets.
+ */
+
+#define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_UNITS)
+
+#define MULTI_TEXCOORD1(target, s) \
+{ \
+ GET_IMMEDIATE; \
+ GLuint texunit = target - GL_TEXTURE0_ARB; \
+ if (texunit < IM->MaxTextureUnits) { \
+ GLuint count = IM->Count; \
+ GLfloat *tc = IM->TexCoord[texunit][count]; \
+ ASSIGN_4V(tc, s, 0.0F, 0.0F, 1.0F); \
+ IM->Flag[count] |= VERT_TEX(texunit); \
+ } \
+}
+
+#define MULTI_TEXCOORD2(target, s, t) \
+{ \
+ GET_IMMEDIATE; \
+ GLuint texunit = target - GL_TEXTURE0_ARB; \
+ if (texunit < IM->MaxTextureUnits) { \
+ GLuint count = IM->Count; \
+ GLfloat *tc = IM->TexCoord[texunit][count]; \
+ ASSIGN_4V(tc, s, t, 0.0F, 1.0F); \
+ IM->Flag[count] |= VERT_TEX(texunit); \
+ } \
+}
+
+#define MULTI_TEXCOORD3(target, s, t, u) \
+{ \
+ GET_IMMEDIATE; \
+ GLuint texunit = target - GL_TEXTURE0_ARB; \
+ if (texunit < IM->MaxTextureUnits) { \
+ GLuint count = IM->Count; \
+ GLfloat *tc = IM->TexCoord[texunit][count]; \
+ ASSIGN_4V(tc, s, t, u, 1.0F); \
+ IM->Flag[count] |= VERT_TEX(texunit); \
+ IM->TexSize |= TEX_SIZE_3(texunit); \
+ } \
+}
+
+#define MULTI_TEXCOORD4(target, s, t, u, v) \
+{ \
+ GET_IMMEDIATE; \
+ GLuint texunit = target - GL_TEXTURE0_ARB; \
+ if (texunit < IM->MaxTextureUnits) { \
+ GLuint count = IM->Count; \
+ GLfloat *tc = IM->TexCoord[texunit][count]; \
+ ASSIGN_4V(tc, s, t, u, v); \
+ IM->Flag[count] |= VERT_TEX(texunit); \
+ IM->TexSize |= TEX_SIZE_4(texunit); \
+ } \
+}
+
+#if defined(USE_IEEE)
+#define MULTI_TEXCOORD2F(target, s, t) \
+{ \
+ GET_IMMEDIATE; \
+ GLuint texunit = target - GL_TEXTURE0_ARB; \
+ if (texunit < IM->MaxTextureUnits) { \
+ GLuint count = IM->Count; \
+ GLint *tc = (GLint *)IM->TexCoord[texunit][count]; \
+ IM->Flag[count] |= VERT_TEX(texunit); \
+ tc[0] = *(int *)&(s); \
+ tc[1] = *(int *)&(t); \
+ tc[2] = 0; \
+ tc[3] = IEEE_ONE; \
+ } \
+}
+#else
+#define MULTI_TEXCOORD2F MULTI_TEXCOORD2
+#endif
+
+static void
+_tnl_MultiTexCoord1fARB(GLenum target, GLfloat s)
+{
+ MULTI_TEXCOORD1( target, s );
+}
+
+static void
+_tnl_MultiTexCoord1fvARB(GLenum target, const GLfloat *v)
+{
+ MULTI_TEXCOORD1( target, v[0] );
+}
+
+static void
+_tnl_MultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t)
+{
+ MULTI_TEXCOORD2F( target, s, t );
+}
+
+static void
+_tnl_MultiTexCoord2fvARB(GLenum target, const GLfloat *v)
+{
+ MULTI_TEXCOORD2F( target, v[0], v[1] );
+}
+
+static void
+_tnl_MultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r)
+{
+ MULTI_TEXCOORD3( target, s, t, r );
+}
+
+static void
+_tnl_MultiTexCoord3fvARB(GLenum target, const GLfloat *v)
+{
+ MULTI_TEXCOORD3( target, v[0], v[1], v[2] );
+}
+
+static void
+_tnl_MultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+ MULTI_TEXCOORD4( target, s, t, r, q );
+}
+
+static void
+_tnl_MultiTexCoord4fvARB(GLenum target, const GLfloat *v)
+{
+ MULTI_TEXCOORD4( target, v[0], v[1], v[2], v[3] );
+}
+
+
+
+/* KW: Because the eval values don't become 'current', fixup will flow
+ * through these vertices, and then evaluation will write on top
+ * of the fixup results.
+ *
+ * Note: using Obj to hold eval coord data.
+ */
+#define EVALCOORD1(IM, x) \
+{ \
+ GLuint count = IM->Count++; \
+ IM->Flag[count] |= VERT_EVAL_C1; \
+ ASSIGN_4V(IM->Obj[count], x, 0, 0, 1); \
+ if (count == IMM_MAXDATA-1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#define EVALCOORD2(IM, x, y) \
+{ \
+ GLuint count = IM->Count++; \
+ IM->Flag[count] |= VERT_EVAL_C2; \
+ ASSIGN_4V(IM->Obj[count], x, y, 0, 1); \
+ if (count == IMM_MAXDATA-1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#define EVALPOINT1(IM, x) \
+{ \
+ GLuint count = IM->Count++; \
+ IM->Flag[count] |= VERT_EVAL_P1; \
+ ASSIGN_4V(IM->Obj[count], x, 0, 0, 1); \
+ if (count == IMM_MAXDATA-1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+#define EVALPOINT2(IM, x, y) \
+{ \
+ GLuint count = IM->Count++; \
+ IM->Flag[count] |= VERT_EVAL_P2; \
+ ASSIGN_4V(IM->Obj[count], x, y, 0, 1); \
+ if (count == IMM_MAXDATA-1) \
+ _tnl_flush_immediate( IM ); \
+}
+
+static void
+_tnl_EvalCoord1f( GLfloat u )
+{
+ GET_IMMEDIATE;
+ EVALCOORD1( IM, u );
+}
+
+static void
+_tnl_EvalCoord1fv( const GLfloat *u )
+{
+ GET_IMMEDIATE;
+ EVALCOORD1( IM, (GLfloat) *u );
+}
+
+static void
+_tnl_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_IMMEDIATE;
+ EVALCOORD2( IM, u, v );
+}
+
+static void
+_tnl_EvalCoord2fv( const GLfloat *u )
+{
+ GET_IMMEDIATE;
+ EVALCOORD2( IM, u[0], u[1] );
+}
+
+
+static void
+_tnl_EvalPoint1( GLint i )
+{
+ GET_IMMEDIATE;
+ EVALPOINT1( IM, i );
+}
+
+
+static void
+_tnl_EvalPoint2( GLint i, GLint j )
+{
+ GET_IMMEDIATE;
+ EVALPOINT2( IM, i, j );
+}
+
+
+/* Need to use the default array-elt outside begin/end for strict
+ * conformance.
+ */
+#define ARRAY_ELT( IM, i ) \
+{ \
+ GLuint count = IM->Count; \
+ IM->Elt[count] = i; \
+ IM->Flag[count] &= IM->ArrayEltFlags; \
+ IM->Flag[count] |= VERT_ELT; \
+ IM->FlushElt |= IM->ArrayEltFlush; \
+ IM->Count += IM->ArrayEltIncr; \
+ if (IM->Count == IMM_MAXDATA) \
+ _tnl_flush_immediate( IM ); \
+}
+
+
+static void
+_tnl_ArrayElement( GLint i )
+{
+ GET_IMMEDIATE;
+ ARRAY_ELT( IM, i );
+}
+
+
+/* Internal functions. These are safe to use providing either:
+ *
+ * - It is determined that a display list is not being compiled, or
+ * if so that these commands won't be compiled into the list (see
+ * t_eval.c for an example).
+ *
+ * - _tnl_hard_begin() is used instead of _tnl_[bB]egin, and tested
+ * for a GL_TRUE return value. See _tnl_Rectf, below.
+ */
+void
+_tnl_eval_coord1f( GLcontext *CC, GLfloat u )
+{
+ struct immediate *i = TNL_CURRENT_IM(CC);
+ EVALCOORD1( i, u );
+}
+
+void
+_tnl_eval_coord2f( GLcontext *CC, GLfloat u, GLfloat v )
+{
+ struct immediate *i = TNL_CURRENT_IM(CC);
+ EVALCOORD2( i, u, v );
+}
+
+void
+_tnl_array_element( GLcontext *CC, GLint i )
+{
+ struct immediate *im = TNL_CURRENT_IM(CC);
+ ARRAY_ELT( im, i );
+}
+
+void
+_tnl_vertex2f( GLcontext *ctx, GLfloat x, GLfloat y )
+{
+ struct immediate *im = TNL_CURRENT_IM(ctx);
+ VERTEX2( im, x, y );
+}
+
+
+
+
+
+/* Execute a glRectf() function. _tnl_hard_begin() ensures the check
+ * on outside_begin_end is executed even in compiled lists. These
+ * vertices can now participate in the same VB as regular ones, even
+ * in most display lists.
+ */
+static void
+_tnl_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (_tnl_hard_begin( ctx, GL_QUADS )) {
+ _tnl_vertex2f( ctx, x1, y1 );
+ _tnl_vertex2f( ctx, x2, y1 );
+ _tnl_vertex2f( ctx, x2, y2 );
+ _tnl_vertex2f( ctx, x1, y2 );
+ _tnl_end( ctx );
+ }
+}
+
+static void
+_tnl_Materialfv( GLenum face, GLenum pname, const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+ GLuint count = IM->Count;
+ struct gl_material *mat;
+ GLuint bitmask = gl_material_bitmask( ctx, face, pname, ~0, "Materialfv" );
+
+ if (bitmask == 0)
+ return;
+
+ if (!IM->Material) {
+ IM->Material = (GLmaterial (*)[2]) MALLOC( sizeof(GLmaterial) *
+ IMM_SIZE * 2 );
+ IM->MaterialMask = (GLuint *) MALLOC( sizeof(GLuint) * IMM_SIZE );
+ }
+
+ if (!(IM->Flag[count] & VERT_MATERIAL)) {
+ IM->Flag[count] |= VERT_MATERIAL;
+ IM->MaterialMask[count] = 0;
+ }
+
+ IM->MaterialMask[count] |= bitmask;
+ mat = IM->Material[count];
+
+ if (bitmask & FRONT_AMBIENT_BIT) {
+ COPY_4FV( mat[0].Ambient, params );
+ }
+ if (bitmask & BACK_AMBIENT_BIT) {
+ COPY_4FV( mat[1].Ambient, params );
+ }
+ if (bitmask & FRONT_DIFFUSE_BIT) {
+ COPY_4FV( mat[0].Diffuse, params );
+ }
+ if (bitmask & BACK_DIFFUSE_BIT) {
+ COPY_4FV( mat[1].Diffuse, params );
+ }
+ if (bitmask & FRONT_SPECULAR_BIT) {
+ COPY_4FV( mat[0].Specular, params );
+ }
+ if (bitmask & BACK_SPECULAR_BIT) {
+ COPY_4FV( mat[1].Specular, params );
+ }
+ if (bitmask & FRONT_EMISSION_BIT) {
+ COPY_4FV( mat[0].Emission, params );
+ }
+ if (bitmask & BACK_EMISSION_BIT) {
+ COPY_4FV( mat[1].Emission, params );
+ }
+ if (bitmask & FRONT_SHININESS_BIT) {
+ GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F );
+ mat[0].Shininess = shininess;
+ }
+ if (bitmask & BACK_SHININESS_BIT) {
+ GLfloat shininess = CLAMP( params[0], 0.0F, 128.0F );
+ mat[1].Shininess = shininess;
+ }
+ if (bitmask & FRONT_INDEXES_BIT) {
+ mat[0].AmbientIndex = params[0];
+ mat[0].DiffuseIndex = params[1];
+ mat[0].SpecularIndex = params[2];
+ }
+ if (bitmask & BACK_INDEXES_BIT) {
+ mat[1].AmbientIndex = params[0];
+ mat[1].DiffuseIndex = params[1];
+ mat[1].SpecularIndex = params[2];
+ }
+}
+
+void _tnl_imm_vtxfmt_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->vtxfmt);
+
+ /* All begin/end operations are handled by this vertex format:
+ */
+ vfmt->ArrayElement = _tnl_ArrayElement;
+ vfmt->Begin = _tnl_Begin;
+ vfmt->Color3f = _tnl_Color3f;
+ vfmt->Color3fv = _tnl_Color3fv;
+ vfmt->Color3ub = _tnl_Color3ub;
+ vfmt->Color3ubv = _tnl_Color3ubv;
+ vfmt->Color4f = _tnl_Color4f;
+ vfmt->Color4fv = _tnl_Color4fv;
+ vfmt->Color4ub = _tnl_Color4ub;
+ vfmt->Color4ubv = _tnl_Color4ubv;
+ vfmt->EdgeFlag = _tnl_EdgeFlag;
+ vfmt->EdgeFlagv = _tnl_EdgeFlagv;
+ vfmt->End = _tnl_End;
+ vfmt->EvalCoord1f = _tnl_EvalCoord1f;
+ vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
+ vfmt->EvalCoord2f = _tnl_EvalCoord2f;
+ vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
+ vfmt->EvalPoint1 = _tnl_EvalPoint1;
+ vfmt->EvalPoint2 = _tnl_EvalPoint2;
+ vfmt->FogCoordfEXT = _tnl_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = _tnl_FogCoordfvEXT;
+ vfmt->Indexi = _tnl_Indexi;
+ vfmt->Indexiv = _tnl_Indexiv;
+ vfmt->Materialfv = _tnl_Materialfv;
+ vfmt->MultiTexCoord1fARB = _tnl_MultiTexCoord1fARB;
+ vfmt->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fvARB;
+ vfmt->MultiTexCoord2fARB = _tnl_MultiTexCoord2fARB;
+ vfmt->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fvARB;
+ vfmt->MultiTexCoord3fARB = _tnl_MultiTexCoord3fARB;
+ vfmt->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fvARB;
+ vfmt->MultiTexCoord4fARB = _tnl_MultiTexCoord4fARB;
+ vfmt->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fvARB;
+ vfmt->Normal3f = _tnl_Normal3f;
+ vfmt->Normal3fv = _tnl_Normal3fv;
+ vfmt->SecondaryColor3fEXT = _tnl_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = _tnl_SecondaryColor3fvEXT;
+ vfmt->SecondaryColor3ubEXT = _tnl_SecondaryColor3ubEXT;
+ vfmt->SecondaryColor3ubvEXT = _tnl_SecondaryColor3ubvEXT;
+ vfmt->TexCoord1f = _tnl_TexCoord1f;
+ vfmt->TexCoord1fv = _tnl_TexCoord1fv;
+ vfmt->TexCoord2f = _tnl_TexCoord2f;
+ vfmt->TexCoord2fv = _tnl_TexCoord2fv;
+ vfmt->TexCoord3f = _tnl_TexCoord3f;
+ vfmt->TexCoord3fv = _tnl_TexCoord3fv;
+ vfmt->TexCoord4f = _tnl_TexCoord4f;
+ vfmt->TexCoord4fv = _tnl_TexCoord4fv;
+ vfmt->Vertex2f = _tnl_Vertex2f;
+ vfmt->Vertex2fv = _tnl_Vertex2fv;
+ vfmt->Vertex3f = _tnl_Vertex3f;
+ vfmt->Vertex3fv = _tnl_Vertex3fv;
+ vfmt->Vertex4f = _tnl_Vertex4f;
+ vfmt->Vertex4fv = _tnl_Vertex4fv;
+
+ /* Outside begin/end functions (from t_varray.c, t_eval.c, ...):
+ */
+ vfmt->Rectf = _tnl_Rectf;
+
+ /* Just use the core function:
+ */
+ vfmt->CallList = _mesa_CallList;
+
+ vfmt->prefer_float_colors = GL_FALSE;
+}
diff --git a/src/mesa/tnl/t_imm_api.h b/src/mesa/tnl/t_imm_api.h
new file mode 100644
index 0000000000..8e4c9943d2
--- /dev/null
+++ b/src/mesa/tnl/t_imm_api.h
@@ -0,0 +1,50 @@
+/* $Id: t_imm_api.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_VTXFMT_H
+#define _T_VTXFMT_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+/* TNL-private internal functions for building higher-level operations:
+ */
+extern void _tnl_begin( GLcontext *ctx, GLenum p );
+extern GLboolean _tnl_hard_begin( GLcontext *ctx, GLenum p );
+extern void _tnl_end( GLcontext *ctx );
+extern void _tnl_vertex2f( GLcontext *ctx, GLfloat x, GLfloat y );
+extern void _tnl_eval_coord1f( GLcontext *CC, GLfloat u );
+extern void _tnl_eval_coord2f( GLcontext *CC, GLfloat u, GLfloat v );
+extern void _tnl_array_element( GLcontext *CC, GLint i );
+
+/* Initialize our part of the vtxfmt struct:
+ */
+extern void _tnl_imm_vtxfmt_init( GLcontext *ctx );
+
+
+#endif
diff --git a/src/mesa/tnl/t_imm_debug.c b/src/mesa/tnl/t_imm_debug.c
new file mode 100644
index 0000000000..192259afcd
--- /dev/null
+++ b/src/mesa/tnl/t_imm_debug.c
@@ -0,0 +1,169 @@
+/* $Id: t_imm_debug.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "mtypes.h"
+#include "t_context.h"
+#include "t_imm_debug.h"
+
+void _tnl_print_vert_flags( const char *name, GLuint flags )
+{
+ fprintf(stderr,
+ "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ name,
+ flags,
+ (flags & VERT_CLIP) ? "clip/proj-clip/glend, " : "",
+ (flags & VERT_EDGE) ? "edgeflag, " : "",
+ (flags & VERT_ELT) ? "array-elt, " : "",
+ (flags & VERT_END_VB) ? "end-vb, " : "",
+ (flags & VERT_EVAL_ANY) ? "eval-coord, " : "",
+ (flags & VERT_EYE) ? "eye/glbegin, " : "",
+ (flags & VERT_FOG_COORD) ? "fog-coord, " : "",
+ (flags & VERT_INDEX) ? "index, " : "",
+ (flags & VERT_MATERIAL) ? "material, " : "",
+ (flags & VERT_NORM) ? "normals, " : "",
+ (flags & VERT_OBJ) ? "obj, " : "",
+ (flags & VERT_OBJ_3) ? "obj-3, " : "",
+ (flags & VERT_OBJ_4) ? "obj-4, " : "",
+ (flags & VERT_POINT_SIZE) ? "point-size, " : "",
+ (flags & VERT_RGBA) ? "colors, " : "",
+ (flags & VERT_SPEC_RGB) ? "specular, " : "",
+ (flags & VERT_TEX0) ? "texcoord0, " : "",
+ (flags & VERT_TEX1) ? "texcoord1, " : "",
+ (flags & VERT_TEX2) ? "texcoord2, " : "",
+ (flags & VERT_TEX3) ? "texcoord3, " : "",
+ (flags & VERT_TEX4) ? "texcoord4, " : "",
+ (flags & VERT_TEX5) ? "texcoord5, " : "",
+ (flags & VERT_TEX6) ? "texcoord6, " : "",
+ (flags & VERT_TEX7) ? "texcoord7, " : ""
+ );
+}
+
+void _tnl_print_cassette( struct immediate *IM )
+{
+ GLuint i;
+ GLuint *flags = IM->Flag;
+ GLuint andflag = IM->CopyAndFlag;
+ GLuint orflag = IM->CopyOrFlag;
+ GLuint state = IM->BeginState;
+ GLuint req = ~0;
+
+ fprintf(stderr, "Cassette id %d, %u rows.\n", IM->id,
+ IM->Count - IM->CopyStart);
+
+ _tnl_print_vert_flags("Contains at least one", orflag);
+
+ if (IM->Count != IM->CopyStart)
+ {
+ _tnl_print_vert_flags("Contains a full complement of", andflag);
+
+ fprintf(stderr, "Final begin/end state %s/%s, errors %s/%s\n",
+ (state & VERT_BEGIN_0) ? "in" : "out",
+ (state & VERT_BEGIN_1) ? "in" : "out",
+ (state & VERT_ERROR_0) ? "y" : "n",
+ (state & VERT_ERROR_1) ? "y" : "n");
+
+ }
+
+ for (i = IM->CopyStart ; i <= IM->Count ; i++) {
+ fprintf(stderr, "%u: ", i);
+ if (req & VERT_OBJ_234) {
+ if (flags[i] & VERT_EVAL_C1)
+ fprintf(stderr, "EvalCoord %f ", IM->Obj[i][0]);
+ else if (flags[i] & VERT_EVAL_P1)
+ fprintf(stderr, "EvalPoint %.0f ", IM->Obj[i][0]);
+ else if (flags[i] & VERT_EVAL_C2)
+ fprintf(stderr, "EvalCoord %f %f ", IM->Obj[i][0], IM->Obj[i][1]);
+ else if (flags[i] & VERT_EVAL_P2)
+ fprintf(stderr, "EvalPoint %.0f %.0f ", IM->Obj[i][0], IM->Obj[i][1]);
+ else if (i < IM->Count && (flags[i]&VERT_OBJ_234)) {
+ fprintf(stderr, "Obj %f %f %f %f",
+ IM->Obj[i][0], IM->Obj[i][1], IM->Obj[i][2], IM->Obj[i][3]);
+ }
+ }
+
+ if (req & flags[i] & VERT_ELT)
+ fprintf(stderr, " Elt %u\t", IM->Elt[i]);
+
+ if (req & flags[i] & VERT_NORM)
+ fprintf(stderr, " Norm %f %f %f ",
+ IM->Normal[i][0], IM->Normal[i][1], IM->Normal[i][2]);
+
+ if (req & flags[i] & VERT_TEX_ANY) {
+ GLuint j;
+ for (j = 0 ; j < MAX_TEXTURE_UNITS ; j++) {
+ if (req & flags[i] & VERT_TEX(j)) {
+ fprintf(stderr,
+ "TC%d %f %f %f %f",
+ j,
+ IM->TexCoord[j][i][0], IM->TexCoord[j][i][1],
+ IM->TexCoord[j][i][2], IM->TexCoord[j][i][2]);
+ }
+ }
+ }
+
+ if (req & flags[i] & VERT_RGBA)
+ fprintf(stderr, " Rgba %d %d %d %d ",
+ IM->Color[i][0], IM->Color[i][1],
+ IM->Color[i][2], IM->Color[i][3]);
+
+ if (req & flags[i] & VERT_SPEC_RGB)
+ fprintf(stderr, " Spec %d %d %d ",
+ IM->SecondaryColor[i][0], IM->SecondaryColor[i][1],
+ IM->SecondaryColor[i][2]);
+
+ if (req & flags[i] & VERT_FOG_COORD)
+ fprintf(stderr, " Fog %f ", IM->FogCoord[i]);
+
+ if (req & flags[i] & VERT_INDEX)
+ fprintf(stderr, " Index %u ", IM->Index[i]);
+
+ if (req & flags[i] & VERT_EDGE)
+ fprintf(stderr, " Edgeflag %d ", IM->EdgeFlag[i]);
+
+ if (req & flags[i] & VERT_MATERIAL)
+ fprintf(stderr, " Material ");
+
+
+ /* The order of these two is not easily knowable, but this is
+ * the usually correct way to look at them.
+ */
+ if (req & flags[i] & VERT_END)
+ fprintf(stderr, " END ");
+
+ if (req & flags[i] & VERT_BEGIN)
+ fprintf(stderr, " BEGIN(%s) (%s%s%s%s)",
+ _mesa_prim_name[IM->Primitive[i] & PRIM_MODE_MASK],
+ (IM->Primitive[i] & PRIM_LAST) ? "LAST," : "",
+ (IM->Primitive[i] & PRIM_BEGIN) ? "BEGIN," : "",
+ (IM->Primitive[i] & PRIM_END) ? "END," : "",
+ (IM->Primitive[i] & PRIM_PARITY) ? "PARITY," : "");
+
+ fprintf(stderr, "\n");
+ }
+}
+
+
+
diff --git a/src/mesa/tnl/t_imm_debug.h b/src/mesa/tnl/t_imm_debug.h
new file mode 100644
index 0000000000..aaae5c11da
--- /dev/null
+++ b/src/mesa/tnl/t_imm_debug.h
@@ -0,0 +1,11 @@
+
+#ifndef _T_DEBUG_H
+#define _T_DEBUG_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+void _tnl_print_cassette( struct immediate *IM );
+void _tnl_print_vert_flags( const char *name, GLuint flags );
+
+#endif
diff --git a/src/mesa/tnl/t_imm_dlist.c b/src/mesa/tnl/t_imm_dlist.c
new file mode 100644
index 0000000000..f5f3bca5cd
--- /dev/null
+++ b/src/mesa/tnl/t_imm_dlist.c
@@ -0,0 +1,415 @@
+/* $Id: t_imm_dlist.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "debug.h"
+#include "mmath.h"
+#include "mem.h"
+#include "state.h"
+
+#include "t_context.h"
+#include "t_imm_api.h"
+#include "t_imm_elt.h"
+#include "t_imm_alloc.h"
+#include "t_imm_dlist.h"
+#include "t_imm_debug.h"
+#include "t_imm_exec.h"
+#include "t_imm_fixup.h"
+#include "t_pipeline.h"
+
+typedef struct {
+ struct immediate *IM;
+ GLuint Start;
+ GLuint Count;
+ GLuint BeginState;
+ GLuint SavedBeginState;
+ GLuint OrFlag;
+ GLuint AndFlag;
+ GLuint TexSize;
+ GLuint LastData;
+ GLuint LastPrimitive;
+ GLboolean have_normal_lengths;
+} TNLvertexcassette;
+
+static void execute_compiled_cassette( GLcontext *ctx, void *data );
+
+
+/* Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+void
+_tnl_compile_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ struct immediate *im = TNL_CURRENT_IM(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ TNLvertexcassette *node;
+ GLuint new_beginstate;
+
+
+ _tnl_compute_orflag( IM );
+
+ IM->CopyStart = IM->Start;
+
+ if (IM->OrFlag & VERT_ELT) {
+ GLuint andflag = ~0;
+ GLuint i;
+ GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
+ _tnl_translate_array_elts( ctx, IM, start, IM->Count );
+
+ /* Need to recompute andflag.
+ */
+ if (IM->AndFlag & VERT_ELT)
+ IM->CopyAndFlag = IM->AndFlag |= ctx->Array._Enabled;
+ else {
+ for (i = IM->CopyStart ; i < IM->Count ; i++)
+ andflag &= IM->Flag[i];
+ IM->CopyAndFlag = IM->AndFlag = andflag;
+ }
+ }
+
+ _tnl_fixup_input( ctx, IM );
+
+ /* Mark the last primitive:
+ */
+ IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+
+ node = (TNLvertexcassette *)
+ _mesa_alloc_instruction(ctx,
+ tnl->opcode_vertex_cassette,
+ sizeof(TNLvertexcassette));
+ if (!node)
+ return;
+
+ node->IM = im; im->ref_count++;
+ node->Start = im->Start;
+ node->Count = im->Count;
+ node->BeginState = im->BeginState;
+ node->SavedBeginState = im->SavedBeginState;
+ node->OrFlag = im->OrFlag;
+ node->TexSize = im->TexSize;
+ node->AndFlag = im->AndFlag;
+ node->LastData = im->LastData;
+ node->LastPrimitive = im->LastPrimitive;
+ node->have_normal_lengths = GL_FALSE;
+
+ if (ctx->ExecuteFlag) {
+ execute_compiled_cassette( ctx, (void *)node );
+ }
+
+
+ /* Discard any errors raised in the last cassette.
+ */
+ new_beginstate = node->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1);
+
+ /* Decide whether this immediate struct is full, or can be used for
+ * the next batch of vertices as well.
+ */
+ if (im->Count > IMM_MAXDATA - 16) {
+ /* Call it full...
+ */
+ struct immediate *new_im = _tnl_alloc_immediate(ctx);
+ if (!new_im) return;
+ new_im->ref_count++;
+ im->ref_count--; /* remove CURRENT_IM reference */
+ ASSERT(im->ref_count > 0);
+ SET_IMMEDIATE( ctx, new_im );
+ _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS,
+ new_beginstate, node->SavedBeginState );
+ } else {
+ /* Still some room in the current immediate.
+ */
+ _tnl_reset_input( ctx, im->Count+1+IMM_MAX_COPIED_VERTS,
+ new_beginstate, node->SavedBeginState);
+ }
+}
+
+
+
+static void calc_normal_lengths( GLfloat *dest,
+ CONST GLfloat (*data)[3],
+ GLuint *flags,
+ GLuint count )
+{
+ GLuint i;
+ GLint tmpflag = flags[0];
+
+ flags[0] |= VERT_NORM;
+
+ for (i = 0 ; i < count ; i++ )
+ if (flags[i] & VERT_NORM) {
+ GLfloat tmp = (GLfloat) LEN_3FV( data[i] );
+ dest[i] = 0;
+ if (tmp > 0)
+ dest[i] = 1.0F / tmp;
+ } else
+ dest[i] = dest[i-1];
+
+ flags[0] = tmpflag;
+}
+
+
+
+static void
+execute_compiled_cassette( GLcontext *ctx, void *data )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ TNLvertexcassette *node = (TNLvertexcassette *)data;
+ struct immediate *IM = node->IM;
+
+ FLUSH_VERTICES( ctx, 0 );
+
+ if (ctx->NewState)
+ gl_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;
+ IM->BeginState = node->BeginState;
+ IM->SavedBeginState = node->SavedBeginState;
+ IM->OrFlag = node->OrFlag;
+ IM->TexSize = node->TexSize;
+ IM->AndFlag = node->AndFlag;
+ IM->LastData = node->LastData;
+ IM->LastPrimitive = node->LastPrimitive;
+
+ if ((MESA_VERBOSE & VERBOSE_DISPLAY_LIST) &&
+ (MESA_VERBOSE & VERBOSE_IMMEDIATE))
+ _tnl_print_cassette( IM );
+
+ if (MESA_VERBOSE & VERBOSE_DISPLAY_LIST) {
+ fprintf(stderr, "Run cassette %d, rows %d..%d, beginstate %x ",
+ IM->id,
+ IM->Start, IM->Count, IM->BeginState);
+/* _tnl_print_vert_flags("orflag", IM->OrFlag); */
+ }
+
+ if (IM->SavedBeginState) {
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
+ tnl->ReplayHardBeginEnd = 1;
+ if (!tnl->ReplayHardBeginEnd) {
+ gl_error(ctx, GL_INVALID_OPERATION, "hard replay");
+ return;
+ }
+ }
+
+
+
+ /* Lazy optimization of the cassette.
+ */
+/* if (ctx->Transform.Normalize && !node->have_normal_lengths) { */
+
+/* if (!IM->NormalLengths) */
+/* IM->NormalLengths = (GLfloat *)MALLOC(sizeof(GLfloat) * IMM_SIZE); */
+
+/* calc_normal_lengths( IM->NormalLengths + IM->Start, */
+/* (const GLfloat (*)[3])(IM->Normal + IM->Start), */
+/* IM->Flag + IM->Start, */
+/* IM->Count - IM->Start); */
+
+/* node->have_normal_lengths = GL_TRUE; */
+/* } */
+
+
+#if 0
+ if (0 && im->v.Obj.size < 4 && im->Count > 15) {
+ im->Bounds = (GLfloat (*)[3]) MALLOC(6 * sizeof(GLfloat));
+ (_tnl_calc_bound_tab[im->v.Obj.size])( im->Bounds, &im->v.Obj );
+ }
+#endif
+
+
+ _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 (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1)
+ tnl->ReplayHardBeginEnd = 0;
+}
+
+static void
+destroy_compiled_cassette( GLcontext *ctx, void *data )
+{
+ TNLvertexcassette *node = (TNLvertexcassette *)data;
+
+ if ( --node->IM->ref_count == 0 )
+ _tnl_free_immediate( node->IM );
+}
+
+
+static void
+print_compiled_cassette( GLcontext *ctx, void *data )
+{
+ TNLvertexcassette *node = (TNLvertexcassette *)data;
+ struct immediate *IM = node->IM;
+
+ fprintf(stderr, "TNL-VERTEX-CASSETTE, id %u, rows %u..%u\n",
+ node->IM->id, node->Start, node->Count);
+
+ IM->Start = node->Start;
+ IM->Count = node->Count;
+ IM->BeginState = node->BeginState;
+ IM->OrFlag = node->OrFlag;
+ IM->TexSize = node->TexSize;
+ IM->AndFlag = node->AndFlag;
+ IM->LastData = node->LastData;
+ IM->LastPrimitive = node->LastPrimitive;
+
+ _tnl_print_cassette( node->IM );
+}
+
+void
+_tnl_BeginCallList( GLcontext *ctx, GLuint list )
+{
+ (void) ctx;
+ (void) list;
+ FLUSH_CURRENT(ctx, 0);
+}
+
+
+/* Called at the tail of a CallList. Copy vertices out of the display
+ * list if necessary.
+ */
+void
+_tnl_EndCallList( GLcontext *ctx )
+{
+ /* May have to copy vertices from a dangling begin/end inside the
+ * list to the current immediate.
+ */
+ if (ctx->CallDepth == 0) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ if (tnl->ExecCopySource != IM)
+ _tnl_copy_immediate_vertices( ctx, IM );
+ }
+}
+
+
+void
+_tnl_EndList( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ IM->ref_count--;
+ if (IM == tnl->ExecCopySource)
+ IM->ref_count--;
+
+ /* If this one isn't free, get a clean one. (Otherwise we'll be
+ * using one that's already half full).
+ */
+ if (IM->ref_count != 0)
+ IM = _tnl_alloc_immediate( ctx );
+
+ ASSERT(IM->ref_count == 0);
+
+ tnl->ExecCopySource = IM;
+ IM->ref_count++;
+
+ SET_IMMEDIATE( ctx, IM );
+ IM->ref_count++;
+
+ _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
+
+ /* outside begin/end, even in COMPILE_AND_EXEC,
+ * so no vertices to copy, right?
+ */
+ ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
+}
+
+
+void
+_tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ /* Use the installed immediate struct. No vertices in the current
+ * immediate, no copied vertices in the system.
+ */
+ ASSERT(TNL_CURRENT_IM(ctx));
+ ASSERT(TNL_CURRENT_IM(ctx)->Start == IMM_MAX_COPIED_VERTS);
+ ASSERT(TNL_CURRENT_IM(ctx)->Start == TNL_CURRENT_IM(ctx)->Count);
+ ASSERT(TNL_CONTEXT(ctx)->ExecCopyCount == 0);
+
+ /* Set current Begin/End state to unknown:
+ */
+ IM->BeginState = VERT_BEGIN_0;
+}
+
+
+void
+_tnl_dlist_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ tnl->opcode_vertex_cassette =
+ _mesa_alloc_opcode( ctx,
+ sizeof(TNLvertexcassette),
+ execute_compiled_cassette,
+ destroy_compiled_cassette,
+ print_compiled_cassette );
+}
+
+/* Need to do this to get the correct begin/end error behaviour from
+ * functions like ColorPointerEXT which are still active in
+ * SAVE_AND_EXEC modes.
+ */
+void
+_tnl_save_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (mode > GL_POLYGON) {
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glBegin" );
+ return;
+ }
+
+ if (ctx->ExecuteFlag) {
+ /* Preserve vtxfmt invarient:
+ */
+ if (ctx->NewState)
+ gl_update_state( ctx );
+
+ /* Slot in geomexec: No need to call setdispatch as we know
+ * CurrentDispatch is Save.
+ */
+ ASSERT(ctx->CurrentDispatch == ctx->Save);
+ }
+
+ _tnl_begin( ctx, mode );
+}
diff --git a/src/mesa/tnl/t_imm_dlist.h b/src/mesa/tnl/t_imm_dlist.h
new file mode 100644
index 0000000000..1b6c4a778a
--- /dev/null
+++ b/src/mesa/tnl/t_imm_dlist.h
@@ -0,0 +1,46 @@
+/* $Id: t_imm_dlist.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+#ifndef _T_DLIST_H
+#define _T_DLIST_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+extern void _tnl_dlist_init( GLcontext *ctx );
+
+extern void _tnl_compile_cassette( GLcontext *ctx, struct immediate *IM );
+extern void _tnl_EndList( GLcontext *ctx );
+extern void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode );
+extern void _tnl_save_Begin( GLenum mode );
+
+extern void _tnl_EndCallList( GLcontext *ctx );
+extern void _tnl_BeginCallList( GLcontext *ctx, GLuint list );
+
+#endif
diff --git a/src/mesa/tnl/t_imm_elt.c b/src/mesa/tnl/t_imm_elt.c
new file mode 100644
index 0000000000..67fbdbe907
--- /dev/null
+++ b/src/mesa/tnl/t_imm_elt.c
@@ -0,0 +1,759 @@
+/* $Id: t_imm_elt.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+#include "glheader.h"
+#include "colormac.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+
+#include "math/m_translate.h"
+
+#include "t_context.h"
+#include "t_imm_elt.h"
+
+
+
+typedef void (*trans_elt_1f_func)(GLfloat *to,
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+typedef void (*trans_elt_1ui_func)(GLuint *to,
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+typedef void (*trans_elt_1ub_func)(GLubyte *to,
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+typedef void (*trans_elt_4ub_func)(GLubyte (*to)[4],
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+typedef void (*trans_elt_4f_func)(GLfloat (*to)[4],
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+typedef void (*trans_elt_3f_func)(GLfloat (*to)[3],
+ CONST void *ptr,
+ GLuint stride,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n );
+
+
+
+
+static trans_elt_1f_func _tnl_trans_elt_1f_tab[MAX_TYPES];
+static trans_elt_1ui_func _tnl_trans_elt_1ui_tab[MAX_TYPES];
+static trans_elt_1ub_func _tnl_trans_elt_1ub_tab[MAX_TYPES];
+static trans_elt_3f_func _tnl_trans_elt_3f_tab[MAX_TYPES];
+static trans_elt_4ub_func _tnl_trans_elt_4ub_tab[5][MAX_TYPES];
+static trans_elt_4f_func _tnl_trans_elt_4f_tab[5][MAX_TYPES];
+
+
+#define PTR_ELT(ptr, elt) (((SRC *)ptr)[elt])
+
+
+
+
+
+/* Code specific to array element implementation. There is a small
+ * subtlety in the bits CHECK() tests, and the way bits are set in
+ * glArrayElement which ensures that if, eg, in the case that the
+ * vertex array is disabled and normal array is enabled, and we get
+ * either sequence:
+ *
+ * ArrayElement() OR Normal()
+ * Normal() ArrayElement()
+ * Vertex() Vertex()
+ *
+ * That the correct value for normal is used.
+ */
+#define TAB(x) _tnl_trans_elt##x##_tab
+#define ARGS GLuint *flags, GLuint *elts, GLuint match, \
+ GLuint start, GLuint n
+#define SRC_START 0
+#define DST_START start
+#undef CHECK
+#define CHECK if ((flags[i]&match) == VERT_ELT)
+#define NEXT_F (void)1
+#define NEXT_F2 f = first + elts[i] * stride;
+
+
+/* GL_BYTE
+ */
+#define SRC GLbyte
+#define SRC_IDX TYPE_IDX(GL_BYTE)
+#define TRX_3F(f,n) BYTE_TO_FLOAT( PTR_ELT(f,n) )
+#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) )
+#define TRX_UB(ub, f,n) ub = BYTE_TO_UBYTE( PTR_ELT(f,n) )
+#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n))
+
+
+#define SZ 4
+#define INIT init_trans_4_GLbyte_elt
+#define DEST_4F trans_4_GLbyte_4f_elt
+#define DEST_4UB trans_4_GLbyte_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLbyte_elt
+#define DEST_4F trans_3_GLbyte_4f_elt
+#define DEST_4UB trans_3_GLbyte_4ub_elt
+#define DEST_3F trans_3_GLbyte_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLbyte_elt
+#define DEST_4F trans_2_GLbyte_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLbyte_elt
+#define DEST_4F trans_1_GLbyte_4f_elt
+#define DEST_1UB trans_1_GLbyte_1ub_elt
+#define DEST_1UI trans_1_GLbyte_1ui_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+#undef SRC_IDX
+
+/* GL_UNSIGNED_BYTE
+ */
+#define SRC GLubyte
+#define SRC_IDX TYPE_IDX(GL_UNSIGNED_BYTE)
+#define TRX_3F(f,n) /* unused */
+#define TRX_4F(f,n) /* unused */
+#define TRX_UB(ub, f,n) ub = PTR_ELT(f,n)
+#define TRX_UI(f,n) (GLuint)PTR_ELT(f,n)
+
+/* 4ub->4ub handled in special case below.
+ */
+
+#define SZ 3
+#define INIT init_trans_3_GLubyte_elt
+#define DEST_4UB trans_3_GLubyte_4ub_elt
+#include "math/m_trans_tmp.h"
+
+
+#define SZ 1
+#define INIT init_trans_1_GLubyte_elt
+#define DEST_1UI trans_1_GLubyte_1ui_elt
+#define DEST_1UB trans_1_GLubyte_1ub_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+/* GL_SHORT
+ */
+#define SRC GLshort
+#define SRC_IDX TYPE_IDX(GL_SHORT)
+#define TRX_3F(f,n) SHORT_TO_FLOAT( PTR_ELT(f,n) )
+#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) )
+#define TRX_UB(ub, f,n) ub = SHORT_TO_UBYTE(PTR_ELT(f,n))
+#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n))
+
+
+#define SZ 4
+#define INIT init_trans_4_GLshort_elt
+#define DEST_4F trans_4_GLshort_4f_elt
+#define DEST_4UB trans_4_GLshort_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLshort_elt
+#define DEST_4F trans_3_GLshort_4f_elt
+#define DEST_4UB trans_3_GLshort_4ub_elt
+#define DEST_3F trans_3_GLshort_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLshort_elt
+#define DEST_4F trans_2_GLshort_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLshort_elt
+#define DEST_4F trans_1_GLshort_4f_elt
+#define DEST_1UB trans_1_GLshort_1ub_elt
+#define DEST_1UI trans_1_GLshort_1ui_elt
+#include "math/m_trans_tmp.h"
+
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+/* GL_UNSIGNED_SHORT
+ */
+#define SRC GLushort
+#define SRC_IDX TYPE_IDX(GL_UNSIGNED_SHORT)
+#define TRX_3F(f,n) USHORT_TO_FLOAT( PTR_ELT(f,n) )
+#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) )
+#define TRX_UB(ub,f,n) ub = (GLubyte) (PTR_ELT(f,n) >> 8)
+#define TRX_UI(f,n) (GLuint) PTR_ELT(f,n)
+
+
+#define SZ 4
+#define INIT init_trans_4_GLushort_elt
+#define DEST_4F trans_4_GLushort_4f_elt
+#define DEST_4UB trans_4_GLushort_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLushort_elt
+#define DEST_4F trans_3_GLushort_4f_elt
+#define DEST_4UB trans_3_GLushort_4ub_elt
+#define DEST_3F trans_3_GLushort_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLushort_elt
+#define DEST_4F trans_2_GLushort_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLushort_elt
+#define DEST_4F trans_1_GLushort_4f_elt
+#define DEST_1UB trans_1_GLushort_1ub_elt
+#define DEST_1UI trans_1_GLushort_1ui_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+/* GL_INT
+ */
+#define SRC GLint
+#define SRC_IDX TYPE_IDX(GL_INT)
+#define TRX_3F(f,n) INT_TO_FLOAT( PTR_ELT(f,n) )
+#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) )
+#define TRX_UB(ub, f,n) ub = INT_TO_UBYTE(PTR_ELT(f,n))
+#define TRX_UI(f,n) (PTR_ELT(f,n) < 0 ? 0 : (GLuint) PTR_ELT(f,n))
+
+
+#define SZ 4
+#define INIT init_trans_4_GLint_elt
+#define DEST_4F trans_4_GLint_4f_elt
+#define DEST_4UB trans_4_GLint_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLint_elt
+#define DEST_4F trans_3_GLint_4f_elt
+#define DEST_4UB trans_3_GLint_4ub_elt
+#define DEST_3F trans_3_GLint_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLint_elt
+#define DEST_4F trans_2_GLint_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLint_elt
+#define DEST_4F trans_1_GLint_4f_elt
+#define DEST_1UB trans_1_GLint_1ub_elt
+#define DEST_1UI trans_1_GLint_1ui_elt
+#include "math/m_trans_tmp.h"
+
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+/* GL_UNSIGNED_INT
+ */
+#define SRC GLuint
+#define SRC_IDX TYPE_IDX(GL_UNSIGNED_INT)
+#define TRX_3F(f,n) UINT_TO_FLOAT( PTR_ELT(f,n) )
+#define TRX_4F(f,n) (GLfloat)( PTR_ELT(f,n) )
+#define TRX_UB(ub, f,n) ub = (GLubyte) (PTR_ELT(f,n) >> 24)
+#define TRX_UI(f,n) PTR_ELT(f,n)
+
+
+#define SZ 4
+#define INIT init_trans_4_GLuint_elt
+#define DEST_4F trans_4_GLuint_4f_elt
+#define DEST_4UB trans_4_GLuint_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLuint_elt
+#define DEST_4F trans_3_GLuint_4f_elt
+#define DEST_4UB trans_3_GLuint_4ub_elt
+#define DEST_3F trans_3_GLuint_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLuint_elt
+#define DEST_4F trans_2_GLuint_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLuint_elt
+#define DEST_4F trans_1_GLuint_4f_elt
+#define DEST_1UB trans_1_GLuint_1ub_elt
+#define DEST_1UI trans_1_GLuint_1ui_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+/* GL_DOUBLE
+ */
+#define SRC GLdouble
+#define SRC_IDX TYPE_IDX(GL_DOUBLE)
+#define TRX_3F(f,n) PTR_ELT(f,n)
+#define TRX_4F(f,n) PTR_ELT(f,n)
+#define TRX_UB(ub,f,n) FLOAT_COLOR_TO_CHAN(ub, PTR_ELT(f,n))
+#define TRX_UI(f,n) (GLuint) (GLint) PTR_ELT(f,n)
+#define TRX_1F(f,n) PTR_ELT(f,n)
+
+
+#define SZ 4
+#define INIT init_trans_4_GLdouble_elt
+#define DEST_4F trans_4_GLdouble_4f_elt
+#define DEST_4UB trans_4_GLdouble_4ub_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLdouble_elt
+#define DEST_4F trans_3_GLdouble_4f_elt
+#define DEST_4UB trans_3_GLdouble_4ub_elt
+#define DEST_3F trans_3_GLdouble_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLdouble_elt
+#define DEST_4F trans_2_GLdouble_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLdouble_elt
+#define DEST_4F trans_1_GLdouble_4f_elt
+#define DEST_1UB trans_1_GLdouble_1ub_elt
+#define DEST_1UI trans_1_GLdouble_1ui_elt
+#define DEST_1F trans_1_GLdouble_1f_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef SRC_IDX
+
+/* GL_FLOAT
+ */
+#define SRC GLfloat
+#define SRC_IDX TYPE_IDX(GL_FLOAT)
+#define SZ 4
+#define INIT init_trans_4_GLfloat_elt
+#define DEST_4UB trans_4_GLfloat_4ub_elt
+#define DEST_4F trans_4_GLfloat_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 3
+#define INIT init_trans_3_GLfloat_elt
+#define DEST_4F trans_3_GLfloat_4f_elt
+#define DEST_4UB trans_3_GLfloat_4ub_elt
+#define DEST_3F trans_3_GLfloat_3f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 2
+#define INIT init_trans_2_GLfloat_elt
+#define DEST_4F trans_2_GLfloat_4f_elt
+#include "math/m_trans_tmp.h"
+
+#define SZ 1
+#define INIT init_trans_1_GLfloat_elt
+#define DEST_4F trans_1_GLfloat_3f_elt
+#define DEST_1UB trans_1_GLfloat_1ub_elt
+#define DEST_1UI trans_1_GLfloat_1ui_elt
+#define DEST_1F trans_1_GLfloat_1f_elt
+#include "math/m_trans_tmp.h"
+
+#undef SRC
+#undef SRC_IDX
+#undef TRX_3F
+#undef TRX_4F
+#undef TRX_UB
+#undef TRX_UI
+
+
+static void trans_4_GLubyte_4ub(GLubyte (*t)[4],
+ CONST void *Ptr,
+ GLuint stride,
+ ARGS )
+{
+ const GLubyte *f = (GLubyte *) Ptr + SRC_START * stride;
+ const GLubyte *first = f;
+ GLuint i;
+ (void) start;
+ if (((((long) f | (long) stride)) & 3L) == 0L) {
+ /* Aligned.
+ */
+ for (i = DST_START ; i < n ; i++, NEXT_F) {
+ CHECK {
+ NEXT_F2;
+ COPY_4UBV( t[i], f );
+ }
+ }
+ } else {
+ for (i = DST_START ; i < n ; i++, NEXT_F) {
+ CHECK {
+ NEXT_F2;
+ t[i][0] = f[0];
+ t[i][1] = f[1];
+ t[i][2] = f[2];
+ t[i][3] = f[3];
+ }
+ }
+ }
+}
+
+
+static void init_translate_elt(void)
+{
+ MEMSET( TAB(_1ui), 0, sizeof(TAB(_1ui)) );
+ MEMSET( TAB(_1ub), 0, sizeof(TAB(_1ub)) );
+ MEMSET( TAB(_3f), 0, sizeof(TAB(_3f)) );
+ MEMSET( TAB(_4ub), 0, sizeof(TAB(_4ub)) );
+ MEMSET( TAB(_4f), 0, sizeof(TAB(_4f)) );
+
+ TAB(_4ub)[4][TYPE_IDX(GL_UNSIGNED_BYTE)] = trans_4_GLubyte_4ub;
+
+ init_trans_4_GLbyte_elt();
+ init_trans_3_GLbyte_elt();
+ init_trans_2_GLbyte_elt();
+ init_trans_1_GLbyte_elt();
+ init_trans_1_GLubyte_elt();
+ init_trans_3_GLubyte_elt();
+ init_trans_4_GLshort_elt();
+ init_trans_3_GLshort_elt();
+ init_trans_2_GLshort_elt();
+ init_trans_1_GLshort_elt();
+ init_trans_4_GLushort_elt();
+ init_trans_3_GLushort_elt();
+ init_trans_2_GLushort_elt();
+ init_trans_1_GLushort_elt();
+ init_trans_4_GLint_elt();
+ init_trans_3_GLint_elt();
+ init_trans_2_GLint_elt();
+ init_trans_1_GLint_elt();
+ init_trans_4_GLuint_elt();
+ init_trans_3_GLuint_elt();
+ init_trans_2_GLuint_elt();
+ init_trans_1_GLuint_elt();
+ init_trans_4_GLdouble_elt();
+ init_trans_3_GLdouble_elt();
+ init_trans_2_GLdouble_elt();
+ init_trans_1_GLdouble_elt();
+ init_trans_4_GLfloat_elt();
+ init_trans_3_GLfloat_elt();
+ init_trans_2_GLfloat_elt();
+ init_trans_1_GLfloat_elt();
+}
+
+
+#undef TAB
+#undef CLASS
+#undef ARGS
+#undef CHECK
+#undef START
+
+
+
+
+void _tnl_imm_elt_init( void )
+{
+ init_translate_elt();
+}
+
+
+static void _tnl_trans_elt_1f(GLfloat *to,
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_1f_tab[TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+
+}
+
+static void _tnl_trans_elt_1ui(GLuint *to,
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_1ui_tab[TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+
+}
+
+
+static void _tnl_trans_elt_1ub(GLubyte *to,
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_1ub_tab[TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+
+}
+
+
+static void _tnl_trans_elt_4ub(GLubyte (*to)[4],
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_4ub_tab[from->Size][TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+
+}
+
+static void _tnl_trans_elt_4f(GLfloat (*to)[4],
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_4f_tab[from->Size][TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+
+}
+
+static void _tnl_trans_elt_3f(GLfloat (*to)[3],
+ const struct gl_client_array *from,
+ GLuint *flags,
+ GLuint *elts,
+ GLuint match,
+ GLuint start,
+ GLuint n )
+{
+ _tnl_trans_elt_3f_tab[TYPE_IDX(from->Type)]( to,
+ from->Ptr,
+ from->StrideB,
+ flags,
+ elts,
+ match,
+ start,
+ n );
+}
+
+
+
+
+/* Batch function to translate away all the array elements in the
+ * input buffer prior to transform. Done only the first time a vertex
+ * buffer is executed or compiled.
+ *
+ * KW: Have to do this after each glEnd if arrays aren't locked.
+ */
+void _tnl_translate_array_elts( GLcontext *ctx, struct immediate *IM,
+ GLuint start, GLuint count )
+{
+ GLuint *flags = IM->Flag;
+ GLuint *elts = IM->Elt;
+ GLuint translate = ctx->Array._Enabled;
+ GLuint i;
+
+ if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
+ fprintf(stderr, "exec_array_elements %d .. %d\n", start, count);
+
+ if (translate & VERT_OBJ) {
+ _tnl_trans_elt_4f( IM->Obj,
+ &ctx->Array.Vertex,
+ flags, elts, (VERT_ELT|VERT_OBJ),
+ start, count);
+
+ if (ctx->Array.Vertex.Size == 4)
+ translate |= VERT_OBJ_234;
+ else if (ctx->Array.Vertex.Size == 3)
+ translate |= VERT_OBJ_23;
+ }
+
+
+ if (translate & VERT_NORM)
+ _tnl_trans_elt_3f( IM->Normal,
+ &ctx->Array.Normal,
+ flags, elts, (VERT_ELT|VERT_NORM),
+ start, count);
+
+ if (translate & VERT_EDGE)
+ _tnl_trans_elt_1ub( IM->EdgeFlag,
+ &ctx->Array.EdgeFlag,
+ flags, elts, (VERT_ELT|VERT_EDGE),
+ start, count);
+
+ if (translate & VERT_RGBA)
+ _tnl_trans_elt_4ub( IM->Color,
+ &ctx->Array.Color,
+ flags, elts, (VERT_ELT|VERT_RGBA),
+ start, count);
+
+
+ if (translate & VERT_SPEC_RGB)
+ _tnl_trans_elt_4ub( IM->SecondaryColor,
+ &ctx->Array.SecondaryColor,
+ flags, elts, (VERT_ELT|VERT_SPEC_RGB),
+ start, count);
+
+ if (translate & VERT_FOG_COORD)
+ _tnl_trans_elt_1f( IM->FogCoord,
+ &ctx->Array.FogCoord,
+ flags, elts, (VERT_ELT|VERT_FOG_COORD),
+ start, count);
+
+ if (translate & VERT_INDEX)
+ _tnl_trans_elt_1ui( IM->Index,
+ &ctx->Array.Index,
+ flags, elts, (VERT_ELT|VERT_INDEX),
+ start, count);
+
+ if (translate & VERT_TEX_ANY) {
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if (translate & VERT_TEX(i)) {
+ _tnl_trans_elt_4f( IM->TexCoord[i],
+ &ctx->Array.TexCoord[i],
+ flags, elts, (VERT_ELT|VERT_TEX(i)),
+ start, count);
+
+ if (ctx->Array.TexCoord[i].Size == 4)
+ IM->TexSize |= TEX_SIZE_4(i);
+ else if (ctx->Array.TexCoord[i].Size == 3)
+ IM->TexSize |= TEX_SIZE_3(i);
+ }
+ }
+
+ for (i = start ; i < count ; i++)
+ if (flags[i] & VERT_ELT) flags[i] |= translate;
+
+ IM->CopyOrFlag |= translate;
+}
+
+
diff --git a/src/mesa/tnl/t_imm_elt.h b/src/mesa/tnl/t_imm_elt.h
new file mode 100644
index 0000000000..180b75fbee
--- /dev/null
+++ b/src/mesa/tnl/t_imm_elt.h
@@ -0,0 +1,46 @@
+/* $Id: t_imm_elt.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#ifndef _T_IMM_ELT_H_
+#define _T_IMM_ELT_H_
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+extern void _tnl_imm_elt_init( void );
+
+extern void _tnl_translate_array_elts( GLcontext *ctx,
+ struct immediate *IM,
+ GLuint start,
+ GLuint end );
+
+
+#endif
diff --git a/src/mesa/tnl/t_imm_eval.c b/src/mesa/tnl/t_imm_eval.c
new file mode 100644
index 0000000000..ed8af649aa
--- /dev/null
+++ b/src/mesa/tnl/t_imm_eval.c
@@ -0,0 +1,623 @@
+/* $Id: t_imm_eval.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+#include "math/m_eval.h"
+
+#include "t_context.h"
+#include "t_imm_eval.h"
+#include "t_imm_exec.h"
+#include "t_imm_fixup.h"
+
+
+static void eval_points1( GLfloat outcoord[][4],
+ GLfloat coord[][4],
+ const GLuint *flags,
+ GLfloat du, GLfloat u1 )
+{
+ GLuint i;
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & VERT_EVAL_ANY) {
+ outcoord[i][0] = coord[i][0];
+ outcoord[i][1] = coord[i][1];
+ if (flags[i] & VERT_EVAL_P1)
+ outcoord[i][0] = coord[i][0] * du + u1;
+ }
+}
+
+static void eval_points2( GLfloat outcoord[][4],
+ GLfloat coord[][4],
+ const GLuint *flags,
+ GLfloat du, GLfloat u1,
+ GLfloat dv, GLfloat v1 )
+{
+ GLuint i;
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++) {
+ if (flags[i] & VERT_EVAL_ANY) {
+ outcoord[i][0] = coord[i][0];
+ outcoord[i][1] = coord[i][1];
+ if (flags[i] & VERT_EVAL_P2) {
+ outcoord[i][0] = coord[i][0] * du + u1;
+ outcoord[i][1] = coord[i][1] * dv + v1;
+ }
+ }
+ }
+}
+
+static const GLubyte dirty_flags[5] = {
+ 0, /* not possible */
+ VEC_DIRTY_0,
+ VEC_DIRTY_1,
+ VEC_DIRTY_2,
+ VEC_DIRTY_3
+};
+
+
+static void eval1_4f( GLvector4f *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ GLuint dimension,
+ struct gl_1d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ GLfloat (*to)[4] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ ASSIGN_4V(to[i], 0,0,0,1);
+ _math_horner_bezier_curve(map->Points, to[i], u,
+ dimension, map->Order);
+ }
+
+ dest->size = MAX2(dest->size, dimension);
+ dest->flags |= dirty_flags[dimension];
+}
+
+
+static void eval1_1ui( GLvector1ui *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ struct gl_1d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ GLuint *to = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat tmp;
+ _math_horner_bezier_curve(map->Points, &tmp, u, 1, map->Order);
+ to[i] = (GLuint) (GLint) tmp;
+ }
+
+}
+
+static void eval1_norm( GLvector3f *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ struct gl_1d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ GLfloat (*to)[3] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ _math_horner_bezier_curve(map->Points, to[i], u, 3, map->Order);
+ }
+}
+
+static void eval1_color( GLvector4ub *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ struct gl_1d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ GLubyte (*to)[4] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C1|VERT_EVAL_P1)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat fcolor[4];
+ _math_horner_bezier_curve(map->Points, fcolor, u, 4, map->Order);
+ FLOAT_RGBA_TO_CHAN_RGBA(to[i], fcolor);
+ }
+}
+
+
+
+
+static void eval2_obj_norm( GLvector4f *obj_ptr,
+ GLvector3f *norm_ptr,
+ GLfloat coord[][4],
+ GLuint *flags,
+ GLuint dimension,
+ struct gl_2d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ const GLfloat v1 = map->v1;
+ const GLfloat dv = map->dv;
+ GLfloat (*obj)[4] = obj_ptr->data;
+ GLfloat (*normal)[3] = norm_ptr->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat v = (coord[i][1] - v1) * dv;
+ GLfloat du[4], dv[4];
+
+ ASSIGN_4V(obj[i], 0,0,0,1);
+ _math_de_casteljau_surf(map->Points, obj[i], du, dv, u, v, dimension,
+ map->Uorder, map->Vorder);
+
+ CROSS3(normal[i], du, dv);
+ NORMALIZE_3FV(normal[i]);
+ }
+
+ obj_ptr->size = MAX2(obj_ptr->size, dimension);
+ obj_ptr->flags |= dirty_flags[dimension];
+}
+
+
+static void eval2_4f( GLvector4f *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ GLuint dimension,
+ struct gl_2d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ const GLfloat v1 = map->v1;
+ const GLfloat dv = map->dv;
+ GLfloat (*to)[4] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat v = (coord[i][1] - v1) * dv;
+ _math_horner_bezier_surf(map->Points, to[i], u, v, dimension,
+ map->Uorder, map->Vorder);
+ }
+
+ dest->size = MAX2(dest->size, dimension);
+ dest->flags |= dirty_flags[dimension];
+}
+
+
+static void eval2_norm( GLvector3f *dest,
+ GLfloat coord[][4],
+ GLuint *flags,
+ struct gl_2d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ const GLfloat v1 = map->v1;
+ const GLfloat dv = map->dv;
+ GLfloat (*to)[3] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat v = (coord[i][1] - v1) * dv;
+ _math_horner_bezier_surf(map->Points, to[i], u, v, 3,
+ map->Uorder, map->Vorder);
+ }
+
+}
+
+
+static void eval2_1ui( GLvector1ui *dest,
+ GLfloat coord[][4],
+ const GLuint *flags,
+ struct gl_2d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ const GLfloat v1 = map->v1;
+ const GLfloat dv = map->dv;
+ GLuint *to = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat v = (coord[i][1] - v1) * dv;
+ GLfloat tmp;
+ _math_horner_bezier_surf(map->Points, &tmp, u, v, 1,
+ map->Uorder, map->Vorder);
+
+ to[i] = (GLuint) (GLint) tmp;
+ }
+}
+
+
+
+static void eval2_color( GLvector4ub *dest,
+ GLfloat coord[][4],
+ GLuint *flags,
+ struct gl_2d_map *map )
+{
+ const GLfloat u1 = map->u1;
+ const GLfloat du = map->du;
+ const GLfloat v1 = map->v1;
+ const GLfloat dv = map->dv;
+ GLubyte (*to)[4] = dest->data;
+ GLuint i;
+
+ for (i = 0 ; !(flags[i] & VERT_END_VB) ; i++)
+ if (flags[i] & (VERT_EVAL_C2|VERT_EVAL_P2)) {
+ GLfloat u = (coord[i][0] - u1) * du;
+ GLfloat v = (coord[i][1] - v1) * dv;
+ GLfloat fcolor[4];
+ _math_horner_bezier_surf(map->Points, fcolor, u, v, 4,
+ map->Uorder, map->Vorder);
+ FLOAT_RGBA_TO_CHAN_RGBA(to[i], fcolor);
+ }
+
+}
+
+
+
+static void copy_4f( GLfloat to[][4], GLfloat from[][4], GLuint count )
+{
+ MEMCPY( to, from, count * sizeof(to[0]));
+}
+
+static void copy_3f( GLfloat to[][3], GLfloat from[][3], GLuint count )
+{
+ MEMCPY( to, from, (count) * sizeof(to[0]));
+}
+
+static void copy_4ub( GLubyte to[][4], GLubyte from[][4], GLuint count )
+{
+ MEMCPY( to, from, (count) * sizeof(to[0]));
+}
+
+static void copy_1ui( GLuint to[], GLuint from[], GLuint count )
+{
+ MEMCPY( to, from, (count) * sizeof(to[0]));
+}
+
+
+
+/* Translate eval enabled flags to VERT_* flags.
+ */
+static void update_eval( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint eval1 = 0, eval2 = 0;
+
+ if (ctx->Eval.Map1Index)
+ eval1 |= VERT_INDEX;
+
+ if (ctx->Eval.Map2Index)
+ eval2 |= VERT_INDEX;
+
+ if (ctx->Eval.Map1Color4)
+ eval1 |= VERT_RGBA;
+
+ if (ctx->Eval.Map2Color4)
+ eval2 |= VERT_RGBA;
+
+ if (ctx->Eval.Map1Normal)
+ eval1 |= VERT_NORM;
+
+ if (ctx->Eval.Map2Normal)
+ eval2 |= VERT_NORM;
+
+ if (ctx->Eval.Map1TextureCoord4 ||
+ ctx->Eval.Map1TextureCoord3 ||
+ ctx->Eval.Map1TextureCoord2 ||
+ ctx->Eval.Map1TextureCoord1)
+ eval1 |= VERT_TEX0;
+
+ if (ctx->Eval.Map2TextureCoord4 ||
+ ctx->Eval.Map2TextureCoord3 ||
+ ctx->Eval.Map2TextureCoord2 ||
+ ctx->Eval.Map2TextureCoord1)
+ eval2 |= VERT_TEX0;
+
+ if (ctx->Eval.Map1Vertex4)
+ eval1 |= VERT_OBJ_234;
+
+ if (ctx->Eval.Map1Vertex3)
+ eval1 |= VERT_OBJ_23;
+
+ if (ctx->Eval.Map2Vertex4) {
+ if (ctx->Eval.AutoNormal)
+ eval2 |= VERT_OBJ_234 | VERT_NORM;
+ else
+ eval2 |= VERT_OBJ_234;
+ }
+ else if (ctx->Eval.Map2Vertex3) {
+ if (ctx->Eval.AutoNormal)
+ eval2 |= VERT_OBJ_23 | VERT_NORM;
+ else
+ eval2 |= VERT_OBJ_23;
+ }
+
+ tnl->eval.EvalMap1Flags = eval1;
+ tnl->eval.EvalMap2Flags = eval2;
+ tnl->eval.EvalNewState = 0;
+}
+
+
+/* This looks a lot like a pipeline stage, but for various reasons is
+ * better handled outside the pipeline, and considered the final stage
+ * of fixing up an immediate struct for execution.
+ *
+ * Really want to cache the results of this function in display lists,
+ * at least for EvalMesh commands.
+ */
+void _tnl_eval_vb( GLcontext *ctx,
+ GLfloat (*coord)[4],
+ GLuint orflag,
+ GLuint andflag )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_arrays *tmp = &tnl->imm_inputs;
+ struct tnl_eval_store *store = &tnl->eval;
+ GLuint *flags = tnl->vb.Flag;
+ GLuint count = tnl->vb.Count;
+ GLuint any_eval1 = orflag & (VERT_EVAL_C1|VERT_EVAL_P1);
+ GLuint any_eval2 = orflag & (VERT_EVAL_C2|VERT_EVAL_P2);
+ GLuint all_eval = andflag & VERT_EVAL_ANY; /* may have false negatives */
+ GLuint req = 0;
+ GLuint purge_flags = 0;
+
+ if (tnl->eval.EvalNewState & _NEW_EVAL)
+ update_eval( ctx );
+
+ /* Handle the degenerate cases.
+ */
+ if (any_eval1 && !ctx->Eval.Map1Vertex4 && !ctx->Eval.Map1Vertex3)
+ purge_flags = (VERT_EVAL_P1|VERT_EVAL_C1);
+
+ if (any_eval2 && !ctx->Eval.Map2Vertex4 && !ctx->Eval.Map2Vertex3)
+ purge_flags |= (VERT_EVAL_P1|VERT_EVAL_C1);
+
+ if (any_eval1)
+ req |= tnl->pipeline.inputs & tnl->eval.EvalMap1Flags;
+
+ if (any_eval2)
+ req |= tnl->pipeline.inputs & tnl->eval.EvalMap2Flags;
+
+
+ /* Translate points into coords. Use store->Obj to hold the
+ * new data.
+ */
+ if (any_eval1 && (orflag & VERT_EVAL_P1))
+ {
+ eval_points1( store->Obj, coord, flags,
+ ctx->Eval.MapGrid1du,
+ ctx->Eval.MapGrid1u1);
+
+ coord = store->Obj;
+ }
+
+ if (any_eval2 && (orflag & VERT_EVAL_P2))
+ {
+ eval_points2( store->Obj, coord, flags,
+ ctx->Eval.MapGrid2du,
+ ctx->Eval.MapGrid2u1,
+ ctx->Eval.MapGrid2dv,
+ ctx->Eval.MapGrid2v1 );
+
+ coord = store->Obj;
+ }
+
+
+ /* Perform the evaluations on active data elements.
+ */
+ if (req & VERT_INDEX)
+ {
+ if (!all_eval)
+ copy_1ui( store->Index, tmp->Index.data, count );
+
+ tmp->Index.data = store->Index;
+ tmp->Index.start = store->Index;
+
+ if (ctx->Eval.Map1Index && any_eval1)
+ eval1_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map1Index );
+
+ if (ctx->Eval.Map2Index && any_eval2)
+ eval2_1ui( &tmp->Index, coord, flags, &ctx->EvalMap.Map2Index );
+
+ }
+
+ if (req & VERT_RGBA)
+ {
+ if (!all_eval)
+ copy_4ub( store->Color, tmp->Color.data, count );
+
+ tmp->Color.data = store->Color;
+ tmp->Color.start = (GLubyte *)store->Color;
+
+ if (ctx->Eval.Map1Color4 && any_eval1)
+ eval1_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map1Color4 );
+
+ if (ctx->Eval.Map2Color4 && any_eval2)
+ eval2_color( &tmp->Color, coord, flags, &ctx->EvalMap.Map2Color4 );
+ }
+
+
+ if (req & VERT_TEX(0))
+ {
+ if (!all_eval)
+ copy_4f( store->TexCoord, tmp->TexCoord[0].data, count );
+ else
+ tmp->TexCoord[0].size = 0;
+
+ tmp->TexCoord[0].data = store->TexCoord;
+ tmp->TexCoord[0].start = (GLfloat *)store->TexCoord;
+
+ if (any_eval1) {
+ if (ctx->Eval.Map1TextureCoord4) {
+ eval1_4f( &tmp->TexCoord[0], coord, flags, 4,
+ &ctx->EvalMap.Map1Texture4 );
+ }
+ else if (ctx->Eval.Map1TextureCoord3) {
+ eval1_4f( &tmp->TexCoord[0], coord, flags, 3,
+ &ctx->EvalMap.Map1Texture3 );
+ }
+ else if (ctx->Eval.Map1TextureCoord2) {
+ eval1_4f( &tmp->TexCoord[0], coord, flags, 2,
+ &ctx->EvalMap.Map1Texture2 );
+ }
+ else if (ctx->Eval.Map1TextureCoord1) {
+ eval1_4f( &tmp->TexCoord[0], coord, flags, 1,
+ &ctx->EvalMap.Map1Texture1 );
+ }
+ }
+
+ if (any_eval2) {
+ if (ctx->Eval.Map2TextureCoord4) {
+ eval2_4f( &tmp->TexCoord[0], coord, flags, 4,
+ &ctx->EvalMap.Map2Texture4 );
+ }
+ else if (ctx->Eval.Map2TextureCoord3) {
+ eval2_4f( &tmp->TexCoord[0], coord, flags, 3,
+ &ctx->EvalMap.Map2Texture3 );
+ }
+ else if (ctx->Eval.Map2TextureCoord2) {
+ eval2_4f( &tmp->TexCoord[0], coord, flags, 2,
+ &ctx->EvalMap.Map2Texture2 );
+ }
+ else if (ctx->Eval.Map2TextureCoord1) {
+ eval2_4f( &tmp->TexCoord[0], coord, flags, 1,
+ &ctx->EvalMap.Map2Texture1 );
+ }
+ }
+ }
+
+
+ if (req & VERT_NORM)
+ {
+ if (!all_eval)
+ copy_3f( store->Normal, tmp->Normal.data, count );
+
+ tmp->Normal.data = store->Normal;
+ tmp->Normal.start = (GLfloat *)store->Normal;
+
+ if (ctx->Eval.Map1Normal && any_eval1)
+ eval1_norm( &tmp->Normal, coord, flags,
+ &ctx->EvalMap.Map1Normal );
+
+ if (ctx->Eval.Map2Normal && any_eval2)
+ eval2_norm( &tmp->Normal, coord, flags,
+ &ctx->EvalMap.Map2Normal );
+ }
+
+
+
+ /* In the AutoNormal case, the copy and assignment of tmp->NormalPtr
+ * are done above.
+ */
+ if (req & VERT_OBJ)
+ {
+ if (!all_eval) {
+ copy_4f( store->Obj, tmp->Obj.data, count );
+ } else
+ tmp->Obj.size = 0;
+
+ tmp->Obj.data = store->Obj;
+ tmp->Obj.start = (GLfloat *)store->Obj;
+
+ if (any_eval1) {
+ if (ctx->Eval.Map1Vertex4) {
+ eval1_4f( &tmp->Obj, coord, flags, 4,
+ &ctx->EvalMap.Map1Vertex4 );
+ }
+ else if (ctx->Eval.Map1Vertex3) {
+ eval1_4f( &tmp->Obj, coord, flags, 3,
+ &ctx->EvalMap.Map1Vertex3 );
+ }
+ }
+
+ if (any_eval2) {
+ if (ctx->Eval.Map2Vertex4)
+ {
+ if (ctx->Eval.AutoNormal && (req & VERT_NORM))
+ eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 4,
+ &ctx->EvalMap.Map2Vertex4 );
+ else
+ eval2_4f( &tmp->Obj, coord, flags, 4,
+ &ctx->EvalMap.Map2Vertex4 );
+ }
+ else if (ctx->Eval.Map2Vertex3)
+ {
+ if (ctx->Eval.AutoNormal && (req & VERT_NORM))
+ eval2_obj_norm( &tmp->Obj, &tmp->Normal, coord, flags, 3,
+ &ctx->EvalMap.Map2Vertex3 );
+ else
+ eval2_4f( &tmp->Obj, coord, flags, 3,
+ &ctx->EvalMap.Map2Vertex3 );
+ }
+ }
+ }
+
+
+ {
+ GLuint i;
+ copy_1ui( store->Flag, flags, count );
+ tnl->vb.Flag = store->Flag;
+
+ /* This is overkill, but correct as fixup will have copied the
+ * values to all vertices in the VB - we may be falsely stating
+ * that some repeated values are new, but doing so is fairly
+ * harmless.
+ */
+ for (i = 0 ; i < count ; i++)
+ store->Flag[i] |= req;
+ }
+}
+
+
+
+
+
+
+
diff --git a/src/mesa/tnl/t_imm_eval.h b/src/mesa/tnl/t_imm_eval.h
new file mode 100644
index 0000000000..06a91e0cd5
--- /dev/null
+++ b/src/mesa/tnl/t_imm_eval.h
@@ -0,0 +1,40 @@
+/* $Id: t_imm_eval.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_IMM_EVAL_H
+#define _T_IMM_EVAL_H
+
+
+#include "mtypes.h"
+#include "t_context.h"
+
+extern void _tnl_eval_init( void );
+
+extern void _tnl_eval_vb( GLcontext *ctx, GLfloat (*coord)[4],
+ GLuint orflag, GLuint andflag );
+
+#endif
diff --git a/src/mesa/tnl/t_imm_exec.c b/src/mesa/tnl/t_imm_exec.c
new file mode 100644
index 0000000000..97f23d86e6
--- /dev/null
+++ b/src/mesa/tnl/t_imm_exec.c
@@ -0,0 +1,507 @@
+/* $Id: t_imm_exec.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "dlist.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "light.h"
+#include "state.h"
+#include "texture.h"
+#include "mtypes.h"
+
+#include "math/m_matrix.h"
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_array_import.h"
+#include "t_imm_alloc.h"
+#include "t_imm_api.h"
+#include "t_imm_debug.h"
+#include "t_imm_dlist.h"
+#include "t_imm_eval.h"
+#include "t_imm_elt.h"
+#include "t_imm_exec.h"
+#include "t_imm_fixup.h"
+#include "t_pipeline.h"
+
+
+
+/* Called to initialize new buffers, and to recycle old ones.
+ */
+void _tnl_reset_input( GLcontext *ctx,
+ GLuint start,
+ GLuint beginstate,
+ GLuint savedbeginstate )
+{
+ struct immediate *IM = TNL_CURRENT_IM(ctx);
+
+ /* Clear the dirty part of the flag array.
+ */
+ if (start < IM->Count+2)
+ MEMSET(IM->Flag + start, 0, sizeof(GLuint) * (IM->Count+2-start));
+
+ IM->CopyStart = IM->Start = IM->Count = start;
+ IM->Primitive[IM->Start] = (ctx->Driver.CurrentExecPrimitive | PRIM_LAST);
+ IM->LastPrimitive = IM->Start;
+ IM->BeginState = beginstate;
+ IM->SavedBeginState = savedbeginstate;
+ IM->TexSize = 0;
+
+ IM->ArrayEltFlags = ~ctx->Array._Enabled;
+ IM->ArrayEltIncr = ctx->Array.Vertex.Enabled ? 1 : 0;
+ IM->ArrayEltFlush = !ctx->Array.LockCount;
+}
+
+
+
+static void copy_to_current( GLcontext *ctx, struct immediate *IM,
+ GLuint flag )
+{
+ GLuint count = IM->LastData;
+
+ if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
+ _tnl_print_vert_flags("copy to current", flag);
+
+ if (flag & VERT_NORM)
+ COPY_3FV( ctx->Current.Normal, IM->Normal[count]);
+
+ if (flag & VERT_INDEX)
+ ctx->Current.Index = IM->Index[count];
+
+ if (flag & VERT_EDGE)
+ ctx->Current.EdgeFlag = IM->EdgeFlag[count];
+
+ if (flag & VERT_RGBA)
+ COPY_4UBV(ctx->Current.Color, IM->Color[count]);
+
+ if (flag & VERT_SPEC_RGB)
+ COPY_4UBV(ctx->Current.SecondaryColor, IM->SecondaryColor[count]);
+
+ if (flag & VERT_FOG_COORD)
+ ctx->Current.FogCoord = IM->FogCoord[count];
+
+ if (flag & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (flag & VERT_TEX(i)) {
+ COPY_4FV( ctx->Current.Texcoord[0], IM->TexCoord[0][count]);
+ }
+ }
+ }
+}
+
+
+
+void _tnl_compute_orflag( struct immediate *IM )
+{
+ GLuint count = IM->Count;
+ GLuint orflag = 0;
+ GLuint andflag = ~0U;
+ GLuint i;
+
+ IM->LastData = count-1;
+
+
+ /* Compute the flags for the whole buffer.
+ */
+ for (i = IM->CopyStart ; i < count ; i++) {
+ andflag &= IM->Flag[i];
+ orflag |= IM->Flag[i];
+ }
+
+ /* It is possible there will be data in the buffer arising from
+ * calls like 'glNormal', 'glMaterial' that occur after the final
+ * glVertex, glEval, etc. Additionally, a buffer can consist of
+ * only a single glMaterial call, in which case IM->Start ==
+ * IM->Count, but the buffer is definitely not empty.
+ */
+ if (IM->Flag[i] & VERT_DATA) {
+ IM->LastData++;
+ orflag |= IM->Flag[i];
+ }
+
+ IM->Flag[IM->LastData+1] |= VERT_END_VB;
+ IM->CopyAndFlag = IM->AndFlag = andflag;
+ IM->CopyOrFlag = IM->OrFlag = orflag;
+}
+
+
+
+
+
+/* Note: The 'start' member of the GLvector structs is now redundant
+ * because we always re-transform copied vertices, and the vectors
+ * below are set up so that the first copied vertex (if any) appears
+ * at position zero.
+ */
+static void _tnl_vb_bind_immediate( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct vertex_arrays *tmp = &tnl->imm_inputs;
+ GLuint inputs = tnl->pipeline.inputs; /* for copy-to-current */
+ GLuint start = IM->CopyStart;
+ GLuint count = IM->Count - start;
+
+ /* TODO: optimize the case where nothing has changed. (Just bind
+ * tmp to vb).
+ */
+
+ /* Setup constant data in the VB.
+ */
+ VB->Count = count;
+ VB->FirstClipped = IMM_MAXDATA - IM->CopyStart;
+ VB->import_data = 0;
+ VB->importable_data = 0;
+
+ /* Need an IM->FirstPrimitive?
+ */
+ VB->Primitive = IM->Primitive + IM->CopyStart;
+ VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
+ VB->FirstPrimitive = 0;
+
+ VB->Flag = IM->Flag + start;
+
+ /* TexCoordPtr's are zeroed in loop below.
+ */
+ VB->NormalPtr = 0;
+ VB->NormalLengthPtr = 0;
+ VB->FogCoordPtr = 0;
+ VB->EdgeFlagPtr = 0;
+ VB->IndexPtr[0] = 0;
+ VB->IndexPtr[1] = 0;
+ VB->ColorPtr[0] = 0;
+ VB->ColorPtr[1] = 0;
+ VB->SecondaryColorPtr[0] = 0;
+ VB->SecondaryColorPtr[1] = 0;
+ VB->Elts = 0;
+ VB->MaterialMask = 0;
+ VB->Material = 0;
+
+/* _tnl_print_vert_flags("copy-orflag", IM->CopyOrFlag); */
+/* _tnl_print_vert_flags("orflag", IM->OrFlag); */
+/* _tnl_print_vert_flags("inputs", inputs); */
+
+ /* Setup the initial values of array pointers in the vb.
+ */
+ if (inputs & VERT_OBJ) {
+ tmp->Obj.data = IM->Obj + start;
+ tmp->Obj.start = (GLfloat *)(IM->Obj + start);
+ tmp->Obj.count = count;
+ VB->ObjPtr = &tmp->Obj;
+ if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_234)
+ tmp->Obj.size = 4;
+ else if ((IM->CopyOrFlag & VERT_OBJ_234) == VERT_OBJ_23)
+ tmp->Obj.size = 3;
+ else
+ tmp->Obj.size = 2;
+ }
+
+ if (inputs & VERT_NORM) {
+ tmp->Normal.data = IM->Normal + start;
+ tmp->Normal.start = (GLfloat *)(IM->Normal + start);
+ tmp->Normal.count = count;
+ VB->NormalPtr = &tmp->Normal;
+ if (IM->NormalLengths)
+ VB->NormalLengthPtr = IM->NormalLengths + start;
+ }
+
+ if (inputs & VERT_INDEX) {
+ tmp->Index.count = count;
+ tmp->Index.data = IM->Index + start;
+ tmp->Index.start = IM->Index + start;
+ VB->IndexPtr[0] = &tmp->Index;
+ }
+
+ if (inputs & VERT_FOG_COORD) {
+ tmp->FogCoord.data = IM->FogCoord + start;
+ tmp->FogCoord.start = IM->FogCoord + start;
+ tmp->FogCoord.count = count;
+ VB->FogCoordPtr = &tmp->FogCoord;
+ }
+
+ if (inputs & VERT_SPEC_RGB) {
+ tmp->SecondaryColor.data = IM->SecondaryColor + start;
+ tmp->SecondaryColor.start = (GLubyte *)(IM->SecondaryColor + start);
+ tmp->SecondaryColor.count = count;
+ VB->SecondaryColorPtr[0] = &tmp->SecondaryColor;
+ }
+
+ if (inputs & VERT_EDGE) {
+ tmp->EdgeFlag.data = IM->EdgeFlag + start;
+ tmp->EdgeFlag.start = IM->EdgeFlag + start;
+ tmp->EdgeFlag.count = count;
+ VB->EdgeFlagPtr = &tmp->EdgeFlag;
+ }
+
+ if (inputs & VERT_RGBA) {
+ tmp->Color.data = IM->Color + start;
+ tmp->Color.start = (GLubyte *)(IM->Color + start);
+ tmp->Color.count = count;
+ VB->ColorPtr[0] = &tmp->Color;
+ }
+
+ if (inputs & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ VB->TexCoordPtr[i] = 0;
+ if (inputs & VERT_TEX(i)) {
+ tmp->TexCoord[i].count = count;
+ tmp->TexCoord[i].data = IM->TexCoord[i] + start;
+ tmp->TexCoord[i].start = (GLfloat *)(IM->TexCoord[i] + start);
+ tmp->TexCoord[i].size = 2;
+ if (IM->TexSize & i) {
+ tmp->TexCoord[i].size = 3;
+ if (IM->TexSize & (i<<16))
+ tmp->TexCoord[i].size = 4;
+ }
+ VB->TexCoordPtr[i] = &tmp->TexCoord[i];
+ }
+ }
+ }
+
+ if ((inputs & VERT_MATERIAL) && IM->Material) {
+ VB->MaterialMask = IM->MaterialMask + start;
+ VB->Material = IM->Material + start;
+ }
+}
+
+
+
+
+/* Called by exec_cassette and execute_compiled_cassette.
+ */
+void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ _tnl_vb_bind_immediate( ctx, IM );
+
+ if (IM->CopyOrFlag & VERT_EVAL_ANY)
+ _tnl_eval_vb( ctx,
+ IM->Obj + IM->CopyStart,
+ IM->CopyOrFlag,
+ IM->CopyAndFlag );
+
+
+ /* Invalidate all stored data before and after run:
+ */
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+ _tnl_run_pipeline( ctx );
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+
+ copy_to_current( ctx, IM, IM->OrFlag );
+}
+
+
+
+
+/* Called for pure, locked VERT_ELT cassettes instead of
+ * _tnl_run_cassette.
+ */
+static void exec_elt_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+
+ _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst, ctx->Array.LockCount );
+
+ VB->Elts = IM->Elt + IM->CopyStart;
+ VB->Primitive = IM->Primitive + IM->CopyStart;
+ VB->PrimitiveLength = IM->PrimitiveLength + IM->CopyStart;
+ VB->FirstPrimitive = 0;
+
+ /* Run the pipeline. No input changes as a result of this action.
+ */
+ _tnl_run_pipeline( ctx );
+
+ /* Still need to update current values: (TODO - copy from VB)
+ * TODO: delay this until FlushVertices
+ */
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ _tnl_translate_array_elts( ctx, IM, IM->LastData, IM->LastData );
+ copy_to_current( ctx, IM, ctx->Array._Enabled );
+ }
+}
+
+/* Called for cassettes where CopyStart == Count -- no need to run the
+ * pipeline.
+ */
+static void exec_empty_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ GLuint start = IM->CopyStart;
+
+ if (IM->OrFlag & VERT_ELT)
+ _tnl_translate_array_elts( ctx, IM, start, start );
+
+ _tnl_fixup_input( ctx, IM ); /* shouldn't be needed? (demos/fire) */
+ copy_to_current( ctx, IM, IM->OrFlag );
+
+ if (IM->OrFlag & VERT_MATERIAL)
+ gl_update_material( ctx, IM->Material[start], IM->MaterialMask[start] );
+
+ if (IM->OrFlag & VERT_RGBA)
+ if (ctx->Light.ColorMaterialEnabled)
+ gl_update_color_material( ctx, ctx->Current.Color );
+}
+
+
+/* Called for regular vertex cassettes.
+ */
+static void exec_vert_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ if (IM->OrFlag & VERT_ELT) {
+ GLuint andflag = ~0;
+ GLuint i;
+ GLuint start = IM->FlushElt ? IM->LastPrimitive : IM->CopyStart;
+ _tnl_translate_array_elts( ctx, IM, start, IM->Count );
+
+ /* Need to recompute andflag.
+ */
+ if (IM->CopyAndFlag & VERT_ELT)
+ IM->CopyAndFlag |= ctx->Array._Enabled;
+ else {
+ for (i = IM->CopyStart ; i < IM->Count ; i++)
+ andflag &= IM->Flag[i];
+ IM->CopyAndFlag = andflag;
+ }
+ }
+
+ _tnl_fixup_input( ctx, IM );
+/* _tnl_print_cassette( IM ); */
+ _tnl_run_cassette( ctx, IM );
+}
+
+
+
+/* Called for all cassettes when not compiling or playing a display
+ * list.
+ */
+void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ ASSERT(tnl->ExecCopySource == IM);
+
+ _tnl_compute_orflag( IM );
+
+ /* Mark the last primitive:
+ */
+ IM->PrimitiveLength[IM->LastPrimitive] = IM->Count - IM->LastPrimitive;
+ ASSERT(IM->Primitive[IM->LastPrimitive] & PRIM_LAST);
+
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ _tnl_get_exec_copy_verts( ctx, IM );
+
+ if (IM->CopyStart == IM->Count) {
+ exec_empty_cassette( ctx, IM );
+ }
+ else if ((IM->OrFlag & VERT_DATA) == VERT_ELT &&
+ ctx->Array.LockCount &&
+ ctx->Array.Vertex.Enabled) {
+ exec_elt_cassette( ctx, IM );
+ }
+ else {
+ exec_vert_cassette( ctx, IM );
+ }
+
+ _tnl_reset_input( ctx,
+ IMM_MAX_COPIED_VERTS,
+ IM->BeginState & (VERT_BEGIN_0|VERT_BEGIN_1),
+ IM->SavedBeginState );
+
+ /* Copy vertices and primitive information to immediate before it
+ * can be overwritten.
+ */
+ _tnl_copy_immediate_vertices( ctx, IM );
+
+/* if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) */
+/* ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES; */
+}
+
+
+
+
+/* Setup vector pointers that will be used to bind immediates to VB's.
+ */
+void _tnl_imm_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_arrays *tmp = &tnl->imm_inputs;
+ GLuint i;
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+ _tnl_imm_elt_init();
+ }
+
+ ctx->swtnl_im = _tnl_alloc_immediate( ctx );
+ TNL_CURRENT_IM(ctx)->ref_count++;
+
+ tnl->ExecCopyTexSize = 0;
+ tnl->ExecCopyCount = 0;
+ tnl->ExecCopySource = TNL_CURRENT_IM(ctx);
+ TNL_CURRENT_IM(ctx)->ref_count++;
+ TNL_CURRENT_IM(ctx)->CopyStart = IMM_MAX_COPIED_VERTS;
+
+ gl_vector4f_init( &tmp->Obj, 0, 0 );
+ gl_vector3f_init( &tmp->Normal, 0, 0 );
+ gl_vector4ub_init( &tmp->Color, 0, 0 );
+ gl_vector4ub_init( &tmp->SecondaryColor, 0, 0 );
+ gl_vector1f_init( &tmp->FogCoord, 0, 0 );
+ gl_vector1ui_init( &tmp->Index, 0, 0 );
+ gl_vector1ub_init( &tmp->EdgeFlag, 0, 0 );
+
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
+ gl_vector4f_init( &tmp->TexCoord[i], 0, 0);
+
+ /* Install the first immediate. Intially outside begin/end.
+ */
+ _tnl_reset_input( ctx, IMM_MAX_COPIED_VERTS, 0, 0 );
+ tnl->ReplayHardBeginEnd = 0;
+
+ _tnl_imm_vtxfmt_init( ctx );
+}
+
+
+void _tnl_imm_destroy( GLcontext *ctx )
+{
+ if (TNL_CURRENT_IM(ctx))
+ _tnl_free_immediate( TNL_CURRENT_IM(ctx) );
+
+}
diff --git a/src/mesa/tnl/t_imm_exec.h b/src/mesa/tnl/t_imm_exec.h
new file mode 100644
index 0000000000..3a7284ccfd
--- /dev/null
+++ b/src/mesa/tnl/t_imm_exec.h
@@ -0,0 +1,62 @@
+/* $Id: t_imm_exec.h,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_VBXFORM_H
+#define _T_VBXFORM_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+/* Hook for ctx->Driver.FlushVertices:
+ */
+extern void _tnl_flush_vertices( GLcontext *ctx, GLuint flush_flags );
+
+/* Called from imm_api.c and _tnl_flush_vertices:
+ */
+extern void _tnl_flush_immediate( struct immediate *IM );
+
+/* Called from imm_dlist.c and _tnl_flush_immediate:
+ */
+extern void _tnl_run_cassette( GLcontext *ctx, struct immediate *IM );
+
+/* Initialize some stuff:
+ */
+extern void _tnl_imm_init( GLcontext *ctx );
+
+extern void _tnl_imm_destroy( GLcontext *ctx );
+
+extern void _tnl_reset_input( GLcontext *ctx,
+ GLuint start,
+ GLuint beginstate,
+ GLuint savedbeginstate );
+
+extern void _tnl_compute_orflag( struct immediate *IM );
+extern void _tnl_execute_cassette( GLcontext *ctx, struct immediate *IM );
+
+
+#endif
diff --git a/src/mesa/tnl/t_imm_fixup.c b/src/mesa/tnl/t_imm_fixup.c
new file mode 100644
index 0000000000..d55ab48c56
--- /dev/null
+++ b/src/mesa/tnl/t_imm_fixup.c
@@ -0,0 +1,811 @@
+/* $Id: t_imm_fixup.c,v 1.1 2000/12/26 05:09:32 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Authors:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "dlist.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "state.h"
+#include "texture.h"
+#include "mtypes.h"
+
+#include "math/m_matrix.h"
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_imm_alloc.h"
+#include "t_imm_debug.h"
+#include "t_imm_fixup.h"
+#include "t_pipeline.h"
+
+
+
+static void
+fixup_4f( GLfloat data[][4], GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ COPY_4FV(data[i], data[i-1]);
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+}
+
+static void
+fixup_3f( float data[][3], GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ COPY_3V(data[i], data[i-1]);
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+}
+
+
+static void
+fixup_1ui( GLuint *data, GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ data[i] = data[i-1];
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+ flag[i] |= match;
+}
+
+
+static void
+fixup_1f( GLfloat *data, GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ data[i] = data[i-1];
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+ flag[i] |= match;
+}
+
+static void
+fixup_1ub( GLubyte *data, GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ data[i] = data[i-1];
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+ flag[i] |= match;
+}
+
+
+static void
+fixup_4ub( GLubyte data[][4], GLuint flag[], GLuint start, GLuint match )
+{
+ GLuint i = start;
+
+ for (;;) {
+ if ((flag[++i] & match) == 0) {
+ COPY_4UBV(data[i], data[i-1]);
+ if (flag[i] & VERT_END_VB) break;
+ }
+ }
+ flag[i] |= match;
+}
+
+
+static void
+fixup_first_4f( GLfloat data[][4], GLuint flag[], GLuint match,
+ GLuint start, GLfloat *dflt )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ COPY_4FV(data[i], dflt);
+}
+
+static void
+fixup_first_3f( GLfloat data[][3], GLuint flag[], GLuint match,
+ GLuint start, GLfloat *dflt )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ COPY_3FV(data[i], dflt);
+}
+
+
+static void
+fixup_first_1ui( GLuint data[], GLuint flag[], GLuint match,
+ GLuint start, GLuint dflt )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ data[i] = dflt;
+}
+
+static void
+fixup_first_1f( GLfloat data[], GLuint flag[], GLuint match,
+ GLuint start, GLfloat dflt )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ data[i] = dflt;
+}
+
+
+static void
+fixup_first_1ub( GLubyte data[], GLuint flag[], GLuint match,
+ GLuint start, GLubyte dflt )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ data[i] = dflt;
+}
+
+
+static void
+fixup_first_4ub( GLubyte data[][4], GLuint flag[], GLuint match,
+ GLuint start, GLubyte dflt[4] )
+{
+ GLuint i = start-1;
+ match |= VERT_END_VB;
+
+ while ((flag[++i]&match) == 0)
+ COPY_4UBV(data[i], dflt);
+}
+
+
+void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint start = IM->CopyStart;
+ GLuint andflag = IM->CopyAndFlag;
+ GLuint orflag = IM->CopyOrFlag;
+ GLuint fixup;
+
+ IM->CopyTexSize = IM->TexSize;
+
+/* fprintf(stderr, "Fixup input, Start: %u Count: %u LastData: %u\n", */
+/* IM->Start, IM->Count, IM->LastData); */
+/* _tnl_print_vert_flags("Orflag", orflag); */
+/* _tnl_print_vert_flags("Andflag", andflag); */
+
+
+ fixup = ~andflag & VERT_FIXUP;
+
+ if (!ctx->CompileFlag)
+ fixup &= tnl->pipeline.inputs;
+
+ if (!ctx->ExecuteFlag)
+ fixup &= orflag;
+
+ if ((orflag & (VERT_OBJ|VERT_EVAL_ANY)) == 0)
+ fixup = 0;
+
+ if (fixup) {
+ GLuint copy = fixup & ~IM->Flag[start];
+
+
+ /* Equivalent to a lazy copy-from-current when setting up the
+ * immediate.
+ */
+ if (ctx->ExecuteFlag && copy) {
+/* _tnl_print_vert_flags("copy from current", copy); */
+
+ if (copy & VERT_NORM) {
+ COPY_3V( IM->Normal[start], ctx->Current.Normal );
+ }
+
+ if (copy & VERT_RGBA) {
+ COPY_4UBV( IM->Color[start], ctx->Current.Color);
+ }
+
+ if (copy & VERT_SPEC_RGB)
+ COPY_4UBV( IM->SecondaryColor[start], ctx->Current.SecondaryColor);
+
+ if (copy & VERT_FOG_COORD)
+ IM->FogCoord[start] = ctx->Current.FogCoord;
+
+ if (copy & VERT_INDEX)
+ IM->Index[start] = ctx->Current.Index;
+
+ if (copy & VERT_EDGE)
+ IM->EdgeFlag[start] = ctx->Current.EdgeFlag;
+
+ if (copy & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (copy & VERT_TEX(i))
+ COPY_4FV( IM->TexCoord[i][start], ctx->Current.Texcoord[i] );
+ }
+ }
+ }
+
+ if (MESA_VERBOSE&VERBOSE_IMMEDIATE)
+/* _tnl_print_vert_flags("fixup", fixup); */
+
+ if (fixup & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (fixup & VERT_TEX(i)) {
+ if (orflag & VERT_TEX(i))
+ fixup_4f( IM->TexCoord[i], IM->Flag, start, VERT_TEX(i) );
+ else
+ fixup_first_4f( IM->TexCoord[i], IM->Flag, VERT_END_VB, start,
+ IM->TexCoord[i][start]);
+ }
+ }
+ }
+ }
+
+ if (fixup & VERT_EDGE) {
+ if (orflag & VERT_EDGE)
+ fixup_1ub( IM->EdgeFlag, IM->Flag, start, VERT_EDGE );
+ else
+ fixup_first_1ub( IM->EdgeFlag, IM->Flag, VERT_END_VB, start,
+ IM->EdgeFlag[start] );
+ }
+
+ if (fixup & VERT_INDEX) {
+ if (orflag & VERT_INDEX)
+ fixup_1ui( IM->Index, IM->Flag, start, VERT_INDEX );
+ else
+ fixup_first_1ui( IM->Index, IM->Flag, VERT_END_VB, start, IM->Index[start] );
+ }
+
+ if (fixup & VERT_RGBA) {
+ if (orflag & VERT_RGBA)
+ fixup_4ub( IM->Color, IM->Flag, start, VERT_RGBA );
+ else
+ fixup_first_4ub( IM->Color, IM->Flag, VERT_END_VB, start, IM->Color[start] );
+ }
+
+ if (fixup & VERT_SPEC_RGB) {
+ if (orflag & VERT_SPEC_RGB)
+ fixup_4ub( IM->SecondaryColor, IM->Flag, start, VERT_SPEC_RGB );
+ else
+ fixup_first_4ub( IM->SecondaryColor, IM->Flag, VERT_END_VB, start,
+ IM->SecondaryColor[start] );
+ }
+
+ if (fixup & VERT_FOG_COORD) {
+ if (orflag & VERT_FOG_COORD)
+ fixup_1f( IM->FogCoord, IM->Flag, start, VERT_FOG_COORD );
+ else
+ fixup_first_1f( IM->FogCoord, IM->Flag, VERT_END_VB, start,
+ IM->FogCoord[start] );
+ }
+
+ if (fixup & VERT_NORM) {
+ if (orflag & VERT_NORM)
+ fixup_3f( IM->Normal, IM->Flag, start, VERT_NORM );
+ else
+ fixup_first_3f( IM->Normal, IM->Flag, VERT_END_VB, start,
+ IM->Normal[start] );
+ }
+
+ /* Prune possible half-filled slot.
+ */
+ IM->Flag[IM->LastData+1] &= ~VERT_END_VB;
+ IM->Flag[IM->Count] |= VERT_END_VB;
+
+}
+
+
+
+
+static void copy_material( struct immediate *next,
+ struct immediate *prev,
+ GLuint dst, GLuint src )
+{
+ if (next->Material == 0) {
+ next->Material = (GLmaterial (*)[2]) MALLOC( sizeof(GLmaterial) *
+ IMM_SIZE * 2 );
+ next->MaterialMask = (GLuint *) MALLOC( sizeof(GLuint) * IMM_SIZE );
+ }
+
+ next->MaterialMask[dst] = prev->MaterialMask[src];
+ MEMCPY(next->Material[dst], prev->Material[src], 2*sizeof(GLmaterial));
+}
+
+
+
+/* Copy the untransformed data from the shared vertices of a primitive
+ * that wraps over two immediate structs. This is done prior to
+ * set_immediate so that prev and next may point to the same
+ * structure. In general it's difficult to avoid this copy on long
+ * primitives.
+ *
+ * Have to be careful with the transitions between display list
+ * replay, compile and normal execute modes.
+ */
+static void copy_vertices( GLcontext *ctx,
+ struct immediate *next,
+ struct immediate *prev,
+ GLuint count,
+ GLuint *elts )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint offset = IMM_MAX_COPIED_VERTS - count;
+ GLuint i;
+
+ next->CopyStart = next->Start - count;
+
+ /* Copy the vertices
+ */
+ for (i = 0 ; i < count ; i++)
+ {
+ GLuint src = elts[i+offset];
+ GLuint dst = next->CopyStart+i;
+
+ COPY_4FV( next->Obj[dst], prev->Obj[src] );
+ COPY_3FV( next->Normal[dst], prev->Normal[src] );
+ COPY_4UBV( next->Color[dst], prev->Color[src] );
+
+ if (prev->OrFlag & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0 ; i < prev->MaxTextureUnits ; i++) {
+ if (prev->OrFlag & VERT_TEX(i))
+ COPY_4FV( next->TexCoord[i][dst], prev->TexCoord[i][src] );
+ }
+ }
+
+ if (prev->Flag[src] & VERT_MATERIAL)
+ copy_material(next, prev, dst, src);
+
+ next->Elt[dst] = prev->Elt[src];
+ next->EdgeFlag[dst] = prev->EdgeFlag[src];
+ next->Index[dst] = prev->Index[src];
+ COPY_4UBV( next->SecondaryColor[dst], prev->SecondaryColor[src] );
+ next->FogCoord[dst] = prev->FogCoord[src];
+ next->Flag[dst] = (prev->CopyOrFlag & VERT_FIXUP);
+ next->CopyOrFlag |= prev->Flag[src]; /* redundant for current_im */
+ next->CopyAndFlag &= prev->Flag[src]; /* redundant for current_im */
+ }
+
+ /* Only needed when copying to a compiled cassette
+ */
+ if (next->NormalLengths) {
+ for (i = 0 ; i < count ; i++)
+ {
+ GLuint src = elts[i+offset];
+ GLuint dst = next->CopyStart+i;
+
+ if (prev->NormalLengths)
+ next->NormalLengths[dst] = prev->NormalLengths[src];
+ else
+ next->NormalLengths[dst] = 1.0/LEN_3FV(prev->Normal[src]);
+ }
+ }
+
+ ASSERT(prev == tnl->ExecCopySource);
+ if (--tnl->ExecCopySource->ref_count == 0)
+ _tnl_free_immediate( tnl->ExecCopySource );
+
+ next->ref_count++;
+ tnl->ExecCopySource = next;
+ tnl->ExecCopyElts[0] = next->Start-3;
+ tnl->ExecCopyElts[1] = next->Start-2;
+ tnl->ExecCopyElts[2] = next->Start-1;
+}
+
+/* Copy vertices to an empty immediate struct.
+ */
+void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ ASSERT(IM == TNL_CURRENT_IM(ctx));
+ ASSERT(IM->Count == IM->Start);
+
+ /* Need to push this in now as it won't be computed anywhere else/
+ */
+ IM->TexSize = tnl->ExecCopyTexSize;
+
+ /* A wrapped primitive. We may be copying into a revived
+ * display list immediate, or onto the front of a new execute-mode
+ * immediate.
+ */
+ copy_vertices( ctx, IM,
+ tnl->ExecCopySource,
+ tnl->ExecCopyCount,
+ tnl->ExecCopyElts );
+
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ /* Immediates are built by default to be correct in this state,
+ * and copying to the first slots of an immediate doesn't remove
+ * this property.
+ */
+ ASSERT(tnl->ExecCopyTexSize == 0);
+ ASSERT(tnl->ExecCopyCount == 0);
+ ASSERT(IM->CopyStart == IM->Start);
+ }
+
+ /* Copy the primitive information:
+ */
+ IM->Primitive[IM->CopyStart] = (ctx->Driver.CurrentExecPrimitive | PRIM_LAST);
+ IM->LastPrimitive = IM->CopyStart;
+ if (tnl->ExecParity)
+ IM->Primitive[IM->CopyStart] |= PRIM_PARITY;
+}
+
+
+/* Revive a compiled immediate struct - propogate new 'Current'
+ * values. Often this is redundant because the current values were
+ * known and fixed up at compile time.
+ */
+void _tnl_fixup_compiled_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint fixup;
+ GLuint count = IM->Count;
+ GLuint start = IM->Start;
+
+ if (count == start)
+ return;
+
+ IM->CopyOrFlag = IM->OrFlag; /* redundant for current_im */
+ IM->CopyAndFlag = IM->AndFlag; /* redundant for current_im */
+ IM->CopyTexSize = IM->TexSize | tnl->ExecCopyTexSize;
+
+ copy_vertices( ctx, IM,
+ tnl->ExecCopySource,
+ tnl->ExecCopyCount,
+ tnl->ExecCopyElts );
+
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ ASSERT(tnl->ExecCopyTexSize == 0);
+ ASSERT(tnl->ExecCopyCount == 0);
+ ASSERT(IM->CopyStart == IM->Start);
+ }
+
+ fixup = tnl->pipeline.inputs & ~IM->Flag[start] & VERT_FIXUP;
+
+ if (fixup) {
+ if (fixup & VERT_TEX_ANY) {
+ GLuint i;
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (fixup & VERT_TEX(i))
+ fixup_first_4f( IM->TexCoord[i], IM->Flag, VERT_TEX(i), start,
+ ctx->Current.Texcoord[i] );
+ }
+ }
+
+ if (fixup & VERT_EDGE)
+ fixup_first_1ub(IM->EdgeFlag, IM->Flag, VERT_EDGE, start,
+ ctx->Current.EdgeFlag );
+
+ if (fixup & VERT_INDEX)
+ fixup_first_1ui(IM->Index, IM->Flag, VERT_INDEX, start,
+ ctx->Current.Index );
+
+ if (fixup & VERT_RGBA)
+ fixup_first_4ub(IM->Color, IM->Flag, VERT_RGBA, start,
+ ctx->Current.Color );
+
+ if (fixup & VERT_SPEC_RGB)
+ fixup_first_4ub(IM->SecondaryColor, IM->Flag, VERT_SPEC_RGB, start,
+ ctx->Current.SecondaryColor );
+
+ if (fixup & VERT_FOG_COORD)
+ fixup_first_1f(IM->FogCoord, IM->Flag, VERT_FOG_COORD, start,
+ ctx->Current.FogCoord );
+
+ if (fixup & VERT_NORM) {
+ fixup_first_3f(IM->Normal, IM->Flag, VERT_NORM, start,
+ ctx->Current.Normal );
+ if (IM->NormalLengths)
+ fixup_first_1f(IM->NormalLengths, IM->Flag, VERT_NORM, start,
+ 1.0F / (GLfloat) LEN_3FV(ctx->Current.Normal) );
+ }
+ }
+
+
+ /* 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)
+ gl_error( ctx, GL_INVALID_OPERATION, "begin/end");
+
+ 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;
+ }
+ }
+ /* Shouldn't immediates be set up to have this structure *by default*?
+ */
+ } else {
+ GLuint i;
+
+ if (IM->BeginState & VERT_ERROR_0)
+ gl_error( ctx, GL_INVALID_OPERATION, "begin/end");
+
+ 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;
+
+
+ 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;
+ }
+ }
+ }
+
+ if (IM->Primitive[IM->LastPrimitive] & PRIM_END)
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+ else
+ ctx->Driver.CurrentExecPrimitive =
+ IM->Primitive[IM->LastPrimitive] & PRIM_MODE_MASK;
+}
+
+
+/* Undo any changes potentially made to the immediate in the range
+ * IM->Start..IM->Count above.
+ */
+void _tnl_restore_compiled_cassette( GLcontext *ctx, struct immediate *IM )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ IM->Primitive[IM->Start] = tnl->DlistPrimitive;
+ IM->PrimitiveLength[IM->Start] = tnl->DlistPrimitiveLength;
+}
+
+
+
+
+
+
+static void copy_none( TNLcontext *tnl, GLuint start, GLuint count, GLuint ovf)
+{
+ (void) (start && ovf && tnl && count);
+}
+
+static void copy_last( TNLcontext *tnl, GLuint start, GLuint count, GLuint ovf)
+{
+ (void) start; (void) ovf;
+ tnl->ExecCopyCount = 1;
+ tnl->ExecCopyElts[2] = count-1;
+}
+
+static void copy_first_and_last( TNLcontext *tnl, GLuint start, GLuint count,
+ GLuint ovf)
+{
+ (void) ovf;
+ tnl->ExecCopyCount = 2;
+ tnl->ExecCopyElts[1] = start;
+ tnl->ExecCopyElts[2] = count-1;
+}
+
+static void copy_last_two( TNLcontext *tnl, GLuint start, GLuint count,
+ GLuint ovf )
+{
+ (void) start;
+ tnl->ExecCopyCount = 2+ovf;
+ tnl->ExecCopyElts[0] = count-3;
+ tnl->ExecCopyElts[1] = count-2;
+ tnl->ExecCopyElts[2] = count-1;
+}
+
+static void copy_overflow( TNLcontext *tnl, GLuint start, GLuint count,
+ GLuint ovf )
+{
+ (void) start;
+ tnl->ExecCopyCount = ovf;
+ tnl->ExecCopyElts[0] = count-3;
+ tnl->ExecCopyElts[1] = count-2;
+ tnl->ExecCopyElts[2] = count-1;
+}
+
+
+typedef void (*copy_func)( TNLcontext *tnl, GLuint start, GLuint count,
+ GLuint ovf );
+
+static copy_func copy_tab[GL_POLYGON+2] =
+{
+ copy_none,
+ copy_overflow,
+ copy_first_and_last,
+ copy_last,
+ copy_overflow,
+ copy_last_two,
+ copy_first_and_last,
+ copy_overflow,
+ copy_last_two,
+ copy_first_and_last,
+ copy_none
+};
+
+
+
+
+
+/* Figure out what vertices need to be copied next time.
+ */
+void
+_tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM )
+{
+ static const GLuint increment[GL_POLYGON+2] = { 1,2,1,1,3,1,1,4,2,1,1 };
+ static const GLuint intro[GL_POLYGON+2] = { 0,0,2,2,0,2,2,0,2,2,0 };
+
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint last = IM->LastPrimitive;
+ GLuint prim = ctx->Driver.CurrentExecPrimitive;
+ GLuint pincr = increment[prim];
+ GLuint pintro = intro[prim];
+ GLuint ovf = 0;
+
+
+ if (tnl->ExecCopySource != IM) {
+ if (--tnl->ExecCopySource->ref_count == 0)
+ _tnl_free_immediate( tnl->ExecCopySource );
+ IM->ref_count++;
+ tnl->ExecCopySource = IM;
+ }
+
+ if (prim == GL_POLYGON+1) {
+ tnl->ExecCopyCount = 0;
+ tnl->ExecCopyTexSize = 0;
+ tnl->ExecParity = 0;
+ } else {
+ tnl->ExecCopyCount = 0;
+ tnl->ExecCopyTexSize = IM->CopyTexSize;
+ tnl->ExecParity = IM->PrimitiveLength[IM->LastPrimitive] & 1;
+
+ if (pincr != 1 && (IM->Count - last - pintro))
+ ovf = (IM->Count - last - pintro) % pincr;
+
+ if (last < IM->Count)
+ copy_tab[prim]( tnl, last, IM->Count, ovf );
+ }
+}
+
+
+/* If we receive evalcoords in an immediate struct for maps which
+ * don't have a vertex enabled, need to do an additional fixup, as
+ * those rows containing evalcoords must now be ignored. The
+ * evalcoords may still generate colors, normals, etc, so have to
+ * respect the relative order between calls to EvalCoord and Normal
+ * etc.
+ *
+ * Generate the index list that will be used to render this immediate
+ * struct.
+ *
+ * Finally, generate a new primitives list for rendering the indices.
+ */
+#if 0
+void _tnl_fixup_purged_eval( GLcontext *ctx,
+ GLuint fixup, GLuint purge )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_eval_store *store = &tnl->eval;
+ GLuint *flags = tnl->vb.Flag;
+ GLuint i, j, nextprim;
+ GLuint fixup_fence = purge|VERT_OBJ;
+ GLuint good_index = (VERT_EVAL_ANY & ~purge)|VERT_OBJ;
+ GLuint prim_length = 0, lastprim = 0, nextprim = 0;
+
+ if (fixup & VERT_TEX0)
+ fixup_4f( store->TexCoord, flags, 0, VERT_TEX0|fixup_fence );
+
+ if (fixup & VERT_INDEX)
+ fixup_1ui( store->Index, flags, 0, VERT_INDEX|fixup_fence );
+
+ if (fixup & VERT_RGBA)
+ fixup_4ub( store->Color, flags, 0, VERT_RGBA|fixup_fence );
+
+ if (fixup & VERT_NORM)
+ fixup_3f( store->Normal, flags, 0, VERT_NORM|fixup_fence );
+
+ for (i = 0, j = 0 ; i < tnl->vb.Count ; i++) {
+ if (flags[i] & good_index) {
+ store->Elts[j++] = i;
+ prim_length++;
+ }
+ if (i == nextprim) {
+ VB->PrimitiveLength[lastprim] = prim_length;
+ VB->Primitive[j] = VB->Primitive[i];
+ nextprim += lastprimlen;
+ lastprim = i;
+ lastprimlen = VB->PrimitiveLength[i];
+ }
+ }
+
+ VB->Elts = store->Elts;
+
+ /* What about copying??? No immediate exists with the right
+ * vertices in place...
+ */
+ if (tnl->CurrentPrimitive != GL_POLYGON+1) {
+ }
+}
+#endif
diff --git a/src/mesa/tnl/t_imm_fixup.h b/src/mesa/tnl/t_imm_fixup.h
new file mode 100644
index 0000000000..a6740a2a55
--- /dev/null
+++ b/src/mesa/tnl/t_imm_fixup.h
@@ -0,0 +1,52 @@
+/* $Id: t_imm_fixup.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _T_IMM_FIXUP_H
+#define _T_IMM_FIXUP_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+
+
+extern void _tnl_fixup_input( GLcontext *ctx, struct immediate *IM );
+
+extern void _tnl_fixup_compiled_cassette( GLcontext *ctx,
+ struct immediate *IM );
+
+extern void _tnl_restore_compiled_cassette( GLcontext *ctx,
+ struct immediate *IM );
+
+
+extern void _tnl_fixup_purged_eval( GLcontext *ctx,
+ GLuint fixup, GLuint purge );
+
+
+extern void _tnl_copy_immediate_vertices( GLcontext *ctx, struct immediate *IM );
+extern void _tnl_get_exec_copy_verts( GLcontext *ctx, struct immediate *IM );
+
+#endif
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c
index 60e375d753..457b160eb9 100644
--- a/src/mesa/tnl/t_pipeline.c
+++ b/src/mesa/tnl/t_pipeline.c
@@ -1,4 +1,4 @@
-/* $Id: t_pipeline.c,v 1.6 2000/11/27 09:05:52 joukj Exp $ */
+/* $Id: t_pipeline.c,v 1.7 2000/12/26 05:09:33 keithw Exp $ */
/*
* Mesa 3-D graphics library
@@ -22,10 +22,9 @@
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/* Dynamic pipelines, support for CVA.
- * Copyright (C) 1999 Keith Whitwell.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
*/
#include "glheader.h"
@@ -38,435 +37,165 @@
#include "math/m_translate.h"
#include "math/m_xform.h"
-#include "t_bbox.h"
-#include "t_clip.h"
-#include "t_cva.h"
-#include "t_debug.h"
-#include "t_fog.h"
-#include "t_light.h"
+#include "t_context.h"
#include "t_pipeline.h"
-#include "t_shade.h"
-#include "t_stages.h"
-#include "t_vbcull.h"
-#include "t_vbindirect.h"
-#include "t_vbrender.h"
-#include "t_vbxform.h"
-
-
-
-
-
-void _tnl_print_pipe_ops( const char *msg, GLuint flags )
-{
- fprintf(stderr,
- "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n",
- msg,
- flags,
- (flags & PIPE_OP_CVA_PREPARE) ? "cva-prepare, " : "",
- (flags & PIPE_OP_VERT_XFORM) ? "vert-xform, " : "",
- (flags & PIPE_OP_NORM_XFORM) ? "norm-xform, " : "",
- (flags & PIPE_OP_LIGHT) ? "light, " : "",
- (flags & PIPE_OP_FOG) ? "fog, " : "",
- (flags & PIPE_OP_TEX) ? "tex-gen/tex-mat, " : "",
- (flags & PIPE_OP_RAST_SETUP_0) ? "rast-0, " : "",
- (flags & PIPE_OP_RAST_SETUP_1) ? "rast-1, " : "",
- (flags & PIPE_OP_RENDER) ? "render, " : "");
-
-}
-
-/* Have to reset only those parts of the vb which are being recalculated.
- */
-void _tnl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages )
+void _tnl_install_pipeline( GLcontext *ctx,
+ const struct gl_pipeline_stage **stages )
{
- GLcontext *ctx = VB->ctx;
TNLcontext *tnl = TNL_CONTEXT(ctx);
-
- if (MESA_VERBOSE&VERBOSE_PIPELINE)
- _tnl_print_pipe_ops( "reset cva vb", stages );
-
- if (stages & PIPE_OP_VERT_XFORM)
- {
- if (VB->ClipOrMask & CLIP_USER_BIT)
- MEMSET(VB->UserClipMask, 0, VB->Count);
-
- VB->ClipOrMask = 0;
- VB->ClipAndMask = CLIP_ALL_BITS;
- VB->CullMode = 0;
- VB->CullFlag[0] = VB->CullFlag[1] = 0;
- VB->Culled = 0;
- }
-
- if (stages & PIPE_OP_NORM_XFORM) {
- VB->NormalPtr = &tnl->CVA.v.Normal;
- }
-
- if (stages & PIPE_OP_LIGHT)
- {
- VB->ColorPtr = VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color;
- VB->IndexPtr = VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index;
- }
- else if (stages & PIPE_OP_FOG)
- {
- if (ctx->Light.Enabled) {
- VB->Color[0] = VB->LitColor[0];
- VB->Color[1] = VB->LitColor[1];
- VB->Index[0] = VB->LitIndex[0];
- VB->Index[1] = VB->LitIndex[1];
- } else {
- VB->Color[0] = VB->Color[1] = &tnl->CVA.v.Color;
- VB->Index[0] = VB->Index[1] = &tnl->CVA.v.Index;
- }
- VB->ColorPtr = VB->Color[0];
- VB->IndexPtr = VB->Index[0];
- }
-}
-
-
-
-
-
-
-static void pipeline_ctr( struct gl_pipeline *p, GLcontext *ctx, GLuint type )
-{
+ struct gl_pipeline *pipe = &tnl->pipeline;
GLuint i;
- (void) ctx;
-
- p->state_change = 0;
- p->cva_state_change = 0;
- p->inputs = 0;
- p->outputs = 0;
- p->type = type;
- p->ops = 0;
-
- for (i = 0 ; i < _tnl_default_nr_stages ; i++)
- p->state_change |= _tnl_default_pipeline[i].state_change;
-}
-
-
-void _tnl_pipeline_init( GLcontext *ctx )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
-
- MEMCPY( tnl->PipelineStage,
- _tnl_default_pipeline,
- sizeof(*_tnl_default_pipeline) * _tnl_default_nr_stages );
-
- tnl->NrPipelineStages = _tnl_default_nr_stages;
-
- pipeline_ctr( &tnl->CVA.elt, ctx, PIPE_IMMEDIATE);
- pipeline_ctr( &tnl->CVA.pre, ctx, PIPE_PRECALC );
-}
-
+ ASSERT(pipe->nr_stages == 0);
-#define MINIMAL_VERT_DATA (VERT_DATA & ~VERT_EVAL_ANY)
+ pipe->run_state_changes = ~0;
+ pipe->run_input_changes = ~0;
+ pipe->build_state_changes = ~0;
+ pipe->build_state_trigger = 0;
+ pipe->inputs = 0;
-#define VERT_CURRENT_DATA (VERT_TEX_ANY | \
- VERT_RGBA | \
- VERT_SPEC_RGB | \
- VERT_FOG_COORD | \
- VERT_INDEX | \
- VERT_EDGE | \
- VERT_NORM | \
- VERT_MATERIAL)
-
-/* Called prior to every recomputation of the CVA precalc data, except where
- * the driver is able to calculate the pipeline unassisted.
- */
-static void build_full_precalc_pipeline( GLcontext *ctx )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct gl_pipeline_stage *pipeline = tnl->PipelineStage;
- struct gl_cva *cva = &tnl->CVA;
- struct gl_pipeline *pre = &cva->pre;
- struct gl_pipeline_stage **stages = pre->stages;
- GLuint i;
- GLuint newstate = pre->new_state;
- GLuint changed_ops = 0;
- GLuint oldoutputs = pre->outputs;
- GLuint oldinputs = pre->inputs;
- GLuint fallback = (VERT_CURRENT_DATA &
- ~tnl->_ArraySummary);
- GLuint changed_outputs = (tnl->_ArrayNewState |
- (fallback & cva->orflag));
- GLuint available = fallback | tnl->_ArrayFlags;
-
- pre->cva_state_change = 0;
- pre->ops = 0;
- pre->outputs = 0;
- pre->inputs = 0;
- pre->forbidden_inputs = 0;
- pre->fallback = 0;
-
- /* KW: Disable data reuse during Mesa reorg. Make this more readable...
+ /* Create a writeable copy of each stage.
*/
- newstate = ~0;
-
- if (tnl->_ArraySummary & VERT_ELT)
- cva->orflag &= VERT_MATERIAL;
-
- cva->orflag &= ~(tnl->_ArraySummary & ~VERT_OBJ_ANY);
- available &= ~cva->orflag;
-
- pre->outputs = available;
- pre->inputs = available;
-
- if (MESA_VERBOSE & VERBOSE_PIPELINE) {
- fprintf(stderr, ": Rebuild pipeline\n");
- _tnl_print_vert_flags("orflag", cva->orflag);
+ for (i = 0 ; i < MAX_PIPELINE_STAGES && stages[i] ; i++) {
+ MEMCPY( &pipe->stages[i], stages[i], sizeof( **stages ));
+ pipe->build_state_trigger |= pipe->stages[i].check_state;
}
-
-
- /* If something changes in the pipeline, tag all subsequent stages
- * using this value for recalcuation. Also used to build the full
- * pipeline by setting newstate and newinputs to ~0.
- *
- * Because all intermediate values are buffered, the new inputs
- * are enough to fully specify what needs to be calculated, and a
- * single pass identifies all stages requiring recalculation.
- */
- for (i = 0 ; i < tnl->NrPipelineStages ; i++)
- {
- pipeline[i].check(ctx, &pipeline[i]);
-
- if (pipeline[i].type & PIPE_PRECALC)
- {
- if ((newstate & pipeline[i].cva_state_change) ||
- (changed_outputs & pipeline[i].inputs) ||
- !pipeline[i].inputs)
- {
- changed_ops |= pipeline[i].ops;
- changed_outputs |= pipeline[i].outputs;
- pipeline[i].active &= ~PIPE_PRECALC;
-
- if ((pipeline[i].inputs & ~available) == 0 &&
- (pipeline[i].ops & pre->ops) == 0)
- {
- pipeline[i].active |= PIPE_PRECALC;
- *stages++ = &pipeline[i];
- }
- }
-
- /* Incompatible with multiple stages structs implementing
- * the same stage.
- */
- available &= ~pipeline[i].outputs;
- pre->outputs &= ~pipeline[i].outputs;
-
- if (pipeline[i].active & PIPE_PRECALC) {
- pre->ops |= pipeline[i].ops;
- pre->outputs |= pipeline[i].outputs;
- available |= pipeline[i].outputs;
- pre->forbidden_inputs |= pipeline[i].pre_forbidden_inputs;
- }
- }
- else if (pipeline[i].active & PIPE_PRECALC)
- {
- pipeline[i].active &= ~PIPE_PRECALC;
- changed_outputs |= pipeline[i].outputs;
- changed_ops |= pipeline[i].ops;
- }
- }
-
- *stages = 0;
-
- pre->new_outputs = pre->outputs & (changed_outputs | ~oldoutputs);
- pre->new_inputs = pre->inputs & ~oldinputs;
- pre->fallback = pre->inputs & fallback;
- pre->forbidden_inputs |= pre->inputs & fallback;
-
- pre->changed_ops = changed_ops;
+ pipe->nr_stages = i;
}
-void _tnl_build_precalc_pipeline( GLcontext *ctx )
+void _tnl_destroy_pipeline( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct gl_pipeline *pre = &tnl->CVA.pre;
- struct gl_pipeline *elt = &tnl->CVA.elt;
-
- if (!ctx->Driver.BuildPrecalcPipeline ||
- !ctx->Driver.BuildPrecalcPipeline( ctx ))
- build_full_precalc_pipeline( ctx );
-
- pre->data_valid = 0;
- pre->pipeline_valid = 1;
- elt->pipeline_valid = 0;
+ GLuint i;
- tnl->CVA.orflag = 0;
+ for (i = 0 ; i < tnl->pipeline.nr_stages ; i++)
+ tnl->pipeline.stages[i].destroy( &tnl->pipeline.stages[i] );
- if (MESA_VERBOSE&VERBOSE_PIPELINE)
- _tnl_print_pipeline( ctx, pre );
+ tnl->pipeline.nr_stages = 0;
}
-static void build_full_immediate_pipeline( GLcontext *ctx )
+
+void _tnl_validate_pipeline( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct gl_pipeline_stage *pipeline = tnl->PipelineStage;
- struct gl_cva *cva = &tnl->CVA;
- struct gl_pipeline *pre = &cva->pre;
- struct gl_pipeline *elt = &cva->elt;
- struct gl_pipeline_stage **stages = elt->stages;
- GLuint i;
- GLuint newstate = elt->new_state;
- GLuint active_ops = 0;
- GLuint available = cva->orflag | MINIMAL_VERT_DATA;
+ struct gl_pipeline *pipe = &tnl->pipeline;
+ struct gl_pipeline_stage *stage = pipe->stages;
+ GLuint newstate = pipe->build_state_changes;
GLuint generated = 0;
- GLuint is_elt = 0;
-
- if (pre->data_valid && tnl->CompileCVAFlag) {
- is_elt = 1;
- active_ops = cva->pre.ops;
- available |= pre->outputs | VERT_PRECALC_DATA;
- }
-
-
- elt->outputs = 0; /* not used */
- elt->inputs = 0;
+ GLuint i;
- for (i = 0 ; i < tnl->NrPipelineStages ; i++) {
- pipeline[i].active &= ~PIPE_IMMEDIATE;
+ pipe->inputs = 0;
+ pipe->build_state_changes = 0;
- if ((pipeline[i].state_change & newstate) ||
- (pipeline[i].elt_forbidden_inputs & available))
- {
- pipeline[i].check(ctx, &pipeline[i]);
+ for (i = 0 ; i < pipe->nr_stages ; i++) {
+ if (stage[i].check_state & newstate) {
+ stage[i].check(ctx, &stage[i]);
}
- if ((pipeline[i].type & PIPE_IMMEDIATE) &&
- (pipeline[i].ops & active_ops) == 0 &&
- (pipeline[i].elt_forbidden_inputs & available) == 0
- )
- {
- if (pipeline[i].inputs & ~available)
- elt->forbidden_inputs |= pipeline[i].inputs & ~available;
- else
- {
- elt->inputs |= pipeline[i].inputs & ~generated;
- elt->forbidden_inputs |= pipeline[i].elt_forbidden_inputs;
- pipeline[i].active |= PIPE_IMMEDIATE;
- *stages++ = &pipeline[i];
- generated |= pipeline[i].outputs;
- available |= pipeline[i].outputs;
- active_ops |= pipeline[i].ops;
- }
- }
- }
-
- *stages = 0;
-
- elt->copy_transformed_data = 1;
- elt->replay_copied_vertices = 0;
-
- if (is_elt) {
- cva->merge = elt->inputs & pre->outputs;
- elt->ops = active_ops & ~pre->ops;
+ if (stage[i].active) {
+ pipe->inputs |= stage[i].inputs & ~generated;
+ generated |= stage[i].outputs;
+ }
}
}
-void _tnl_build_immediate_pipeline( GLcontext *ctx )
+
+void _tnl_run_pipeline( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct gl_pipeline *elt = &tnl->CVA.elt;
+ struct gl_pipeline *pipe = &tnl->pipeline;
+ struct gl_pipeline_stage *stage = pipe->stages;
+ GLuint changed_state = pipe->run_state_changes;
+ GLuint changed_inputs = pipe->run_input_changes;
+ GLboolean running = GL_TRUE;
+ GLuint i;
- if (!ctx->Driver.BuildEltPipeline ||
- !ctx->Driver.BuildEltPipeline( ctx )) {
- build_full_immediate_pipeline( ctx );
- }
+ unsigned short __tmp;
- elt->pipeline_valid = 1;
- tnl->CVA.orflag = 0;
+ /* Done elsewhere.
+ */
+ ASSERT(pipe->build_state_changes == 0);
- if (MESA_VERBOSE&VERBOSE_PIPELINE)
- _tnl_print_pipeline( ctx, elt );
-}
+ START_FAST_MATH(__tmp);
-#define INTERESTED ~0
+ /* If something changes in the pipeline, tag all subsequent stages
+ * using this value for recalculation.
+ *
+ * Even inactive stages have their state and inputs examined to try
+ * to keep cached data alive over state-changes.
+ */
+ for (i = 0 ; i < pipe->nr_stages ; i++) {
+
+ stage[i].changed_inputs |= stage[i].inputs & changed_inputs;
-void _tnl_update_pipelines( GLcontext *ctx )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- GLuint newstate = ctx->NewState;
- struct gl_cva *cva = &tnl->CVA;
-
- newstate &= INTERESTED;
-
- if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_STATE))
- gl_print_enable_flags("enabled", ctx->_Enabled);
-
- if (newstate ||
- cva->lock_changed ||
- cva->orflag != cva->last_orflag ||
- tnl->_ArrayFlags != cva->last_array_flags)
- {
- GLuint j;
- GLuint flags = VERT_WIN;
-
- if (ctx->Visual.RGBAflag) {
- flags |= VERT_RGBA;
- if (ctx->_TriangleCaps && DD_SEPERATE_SPECULAR)
- flags |= VERT_SPEC_RGB;
- } else
- flags |= VERT_INDEX;
-
- for (j = 0 ; j < ctx->Const.MaxTextureUnits ; j++) {
- if (ctx->Texture.Unit[j]._ReallyEnabled)
- flags |= VERT_TEX(j);
+ if (stage[i].run_state & changed_state) {
+ stage[i].changed_inputs = stage[i].inputs;
}
- if (ctx->Polygon._Unfilled)
- flags |= VERT_EDGE;
-
- if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
- flags |= VERT_FOG_COORD;
+ if (stage[i].active) {
+ if (stage[i].changed_inputs)
+ changed_inputs |= stage[i].outputs;
- if (ctx->RenderMode==GL_FEEDBACK) {
- flags = (VERT_WIN | VERT_RGBA | VERT_INDEX | VERT_NORM |
- VERT_EDGE | VERT_TEX_ANY);
+ if (running) {
+ running = stage[i].run( ctx, &stage[i] );
+ }
}
-
- tnl->_RenderFlags = flags;
-
- cva->elt.new_state |= newstate;
- cva->elt.pipeline_valid = 0;
-
- cva->pre.new_state |= newstate;
- cva->pre.forbidden_inputs = 0;
- cva->pre.pipeline_valid = 0;
- cva->lock_changed = 0;
}
+ END_FAST_MATH(__tmp);
- if (tnl->_ArrayNewState != cva->last_array_new_state)
- cva->pre.pipeline_valid = 0;
-
- cva->pre.data_valid = 0;
- cva->last_array_new_state = tnl->_ArrayNewState;
- cva->last_orflag = cva->orflag;
- cva->last_array_flags = tnl->_ArrayFlags;
+ pipe->run_state_changes = 0;
+ pipe->run_input_changes = 0;
}
-void _tnl_run_pipeline( struct vertex_buffer *VB )
-{
- struct gl_pipeline *pipe = VB->pipeline;
- struct gl_pipeline_stage **stages = pipe->stages;
- unsigned short x;
-
- pipe->data_valid = 1; /* optimized stages might want to reset this. */
- if (0) _tnl_print_pipeline( VB->ctx, pipe );
-
- START_FAST_MATH(x);
- for ( VB->Culled = 0; *stages && !VB->Culled ; stages++ )
- (*stages)->run( VB );
-
- END_FAST_MATH(x);
-
- pipe->new_state = 0;
-}
+/* The default pipeline. This is useful for software rasterizers, and
+ * simple hardware rasterizers. For customization, I don't recommend
+ * tampering with the internals of these stages in the way that
+ * drivers did in Mesa 3.4. These stages are basically black boxes,
+ * and should be left intact.
+ *
+ * To customize the pipeline, consider:
+ *
+ * - removing redundant stages (making sure that the software rasterizer
+ * can cope with this on fallback paths). An example is fog
+ * coordinate generation, which is not required in the FX driver.
+ *
+ * - replacing general-purpose machine-independent stages with
+ * general-purpose machine-specific stages. There is no example of
+ * this to date, though it must be borne in mind that all subsequent
+ * stages that reference the output of the new stage must cope with
+ * any machine-specific data introduced. This may not be easy
+ * unless there are no such stages (ie the new stage is the last in
+ * the pipe).
+ *
+ * - inserting optimized (but specialized) stages ahead of the
+ * general-purpose fallback implementation. For example, the old
+ * fastpath mechanism, which only works when the VERT_ELT input is
+ * available, can be duplicated by placing the fastpath stage at the
+ * head of this pipeline. Such specialized stages are currently
+ * constrained to have no outputs (ie. they must either finish the *
+ * pipeline by returning GL_FALSE from run(), or do nothing).
+ *
+ * Some work can be done to lift some of the restrictions in the final
+ * case, if it becomes necessary to do so.
+ */
+const struct gl_pipeline_stage *_tnl_default_pipeline[] = {
+ &_tnl_update_material_stage,
+ &_tnl_vertex_transform_stage,
+ &_tnl_normal_transform_stage,
+ &_tnl_lighting_stage,
+ &_tnl_fog_coordinate_stage,
+ &_tnl_texgen_stage,
+ &_tnl_texture_transform_stage,
+ &_tnl_point_attenuation_stage,
+ &_tnl_render_stage,
+ 0
+};
diff --git a/src/mesa/tnl/t_pipeline.h b/src/mesa/tnl/t_pipeline.h
index b9ae641894..9d433bde0a 100644
--- a/src/mesa/tnl/t_pipeline.h
+++ b/src/mesa/tnl/t_pipeline.h
@@ -1,4 +1,4 @@
-/* $Id: t_pipeline.h,v 1.3 2000/11/24 10:25:12 keithw Exp $ */
+/* $Id: t_pipeline.h,v 1.4 2000/12/26 05:09:33 keithw Exp $ */
/*
* Mesa 3-D graphics library
@@ -36,25 +36,30 @@
#include "mtypes.h"
#include "t_context.h"
-extern void _tnl_pipeline_init( GLcontext *ctx );
+extern void _tnl_run_pipeline( GLcontext *ctx );
-extern void _tnl_update_materials( struct vertex_buffer *VB);
+extern void _tnl_validate_pipeline( GLcontext *ctx );
-extern void _tnl_update_pipelines( GLcontext *ctx );
+extern void _tnl_destroy_pipeline( GLcontext *ctx );
-extern void _tnl_build_precalc_pipeline( GLcontext *ctx );
-extern void _tnl_build_immediate_pipeline( GLcontext *ctx );
+extern void _tnl_install_pipeline( GLcontext *ctx,
+ const struct gl_pipeline_stage **stages );
-extern void _tnl_print_vert_flags( const char *name, GLuint flags );
-extern void _tnl_print_pipeline( GLcontext *ctx, struct gl_pipeline *p );
-extern void _tnl_print_active_pipeline( GLcontext *ctx, struct gl_pipeline *p );
-extern void _tnl_run_pipeline( struct vertex_buffer *VB );
-
-extern void _tnl_clean_color( struct vertex_buffer *VB );
-
-extern void _tnl_reset_cva_vb( struct vertex_buffer *VB, GLuint stages );
+/* These are implemented in the t_vb_*.c files:
+ */
+extern const struct gl_pipeline_stage _tnl_update_material_stage;
+extern const struct gl_pipeline_stage _tnl_vertex_transform_stage;
+extern const struct gl_pipeline_stage _tnl_normal_transform_stage;
+extern const struct gl_pipeline_stage _tnl_lighting_stage;
+extern const struct gl_pipeline_stage _tnl_fog_coordinate_stage;
+extern const struct gl_pipeline_stage _tnl_texgen_stage;
+extern const struct gl_pipeline_stage _tnl_texture_transform_stage;
+extern const struct gl_pipeline_stage _tnl_point_attenuation_stage;
+extern const struct gl_pipeline_stage _tnl_render_stage;
-extern void _tnl_print_pipe_ops( const char *msg, GLuint flags );
+/* Shorthand to plug in the default pipeline:
+ */
+extern const struct gl_pipeline_stage *_tnl_default_pipeline[];
#endif
diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h
new file mode 100644
index 0000000000..8a73e87de3
--- /dev/null
+++ b/src/mesa/tnl/t_vb_cliptmp.h
@@ -0,0 +1,477 @@
+/* $Id: t_vb_cliptmp.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#define INSIDE( J ) !NEGATIVE(J)
+#define OUTSIDE( J ) NEGATIVE(J)
+
+
+
+
+static GLuint TAG(userclip_line)( GLcontext *ctx,
+ GLuint *i, GLuint *j,
+ interp_func interp )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint ii = *i;
+ GLuint jj = *j;
+ GLuint p;
+
+ for (p=0;p<MAX_CLIP_PLANES;p++) {
+ if (ctx->Transform.ClipEnabled[p]) {
+ GLfloat a = ctx->Transform._ClipUserPlane[p][0];
+ GLfloat b = ctx->Transform._ClipUserPlane[p][1];
+ GLfloat c = ctx->Transform._ClipUserPlane[p][2];
+ GLfloat d = ctx->Transform._ClipUserPlane[p][3];
+
+ GLfloat dpI = d*W(ii) + c*Z(ii) + b*Y(ii) + a*X(ii);
+ GLfloat dpJ = d*W(jj) + c*Z(jj) + b*Y(jj) + a*X(jj);
+
+ GLuint flagI = OUTSIDE( dpI );
+ GLuint flagJ = OUTSIDE( dpJ );
+
+ if (flagI ^ flagJ) {
+ if (flagJ) {
+ GLfloat t = dpI / (dpI - dpJ);
+ jj = interp( ctx, t, ii, jj, GL_FALSE );
+ } else {
+ GLfloat t = dpJ / (dpJ - dpI);
+ ii = interp( ctx, t, jj, ii, GL_FALSE );
+ }
+ }
+ else if (flagI)
+ return 0;
+ }
+ }
+
+ *i = ii;
+ *j = jj;
+ return 1;
+}
+
+
+static GLuint TAG(userclip_polygon)( GLcontext *ctx,
+ GLuint n,
+ GLuint vlist[],
+ interp_func interp )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint vlist2[MAX_CLIPPED_VERTICES];
+ GLuint *inlist = vlist, *outlist = vlist2;
+ GLuint p;
+
+ for (p=0;p<MAX_CLIP_PLANES;p++) {
+ if (ctx->Transform.ClipEnabled[p]) {
+ register float a = ctx->Transform._ClipUserPlane[p][0];
+ register float b = ctx->Transform._ClipUserPlane[p][1];
+ register float c = ctx->Transform._ClipUserPlane[p][2];
+ register float d = ctx->Transform._ClipUserPlane[p][3];
+
+ /* initialize prev to be last in the input list */
+ GLuint prevj = inlist[0];
+ GLfloat dpJ = d*W(prevj) + c*Z(prevj) + b*Y(prevj) + a*X(prevj);
+ GLuint outcount = 0;
+ GLuint curri;
+
+ inlist[n] = inlist[0];
+
+ for (curri=1;curri<n+1;curri++) { GLuint currj = inlist[curri];
+ GLfloat dpI = d*W(currj) + c*Z(currj) + b*Y(currj) + a*X(currj);
+
+ if (!NEGATIVE(dpJ)) {
+ outlist[outcount++] = prevj;
+ VB->ClipMask[prevj] &= ~CLIP_USER_BIT;
+ } else {
+ VB->ClipMask[prevj] |= CLIP_USER_BIT;
+ }
+
+ if (DIFFERENT_SIGNS(dpI, dpJ)) {
+ if (NEGATIVE(dpI)) {
+ GLfloat t = dpI/(dpI-dpJ);
+ outlist[outcount++] = interp( ctx, t, currj, prevj, GL_TRUE);
+ } else {
+ GLfloat t = dpJ/(dpJ-dpI);
+ outlist[outcount++] = interp( ctx, t, prevj, currj, GL_FALSE);
+ }
+ }
+
+ prevj = currj;
+ dpJ = dpI;
+ }
+
+ if (outcount < 3)
+ return 0;
+ else {
+ GLuint *tmp;
+ tmp = inlist;
+ inlist = outlist;
+ outlist = tmp;
+ n = outcount;
+ }
+
+ } /* if */
+ } /* for p */
+
+ if (inlist!=vlist) {
+ GLuint i;
+ for (i = 0 ; i < n ; i++)
+ vlist[i] = inlist[i];
+ }
+
+ return n;
+}
+
+
+/* This now calls the user clip functions if required.
+ */
+static void TAG(viewclip_line)( GLcontext *ctx,
+ GLuint i, GLuint j,
+ GLubyte mask )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ interp_func interp = (interp_func) VB->interpfunc;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint ii = i, jj = j;
+ GLuint vlist[2];
+ GLuint n;
+
+ VB->LastClipped = VB->FirstClipped;
+
+/*
+ * We use 6 instances of this code to clip against the 6 planes.
+ */
+#define GENERAL_CLIP \
+ if (mask & PLANE) { \
+ GLfloat dpI = CLIP_DOTPROD( ii ); \
+ GLfloat dpJ = CLIP_DOTPROD( jj ); \
+ \
+ if (DIFFERENT_SIGNS(dpI, dpJ)) { \
+ if (NEGATIVE(dpJ)) { \
+ GLfloat t = dpI / (dpI - dpJ); \
+ jj = interp( ctx, t, ii, jj, GL_FALSE ); \
+ } else { \
+ GLfloat t = dpJ / (dpJ - dpI); \
+ ii = interp( ctx, t, jj, ii, GL_FALSE ); \
+ } \
+ } \
+ else if (NEGATIVE(dpI)) \
+ return; \
+ }
+
+
+#define PLANE CLIP_RIGHT_BIT
+#define CLIP_DOTPROD(K) (- X(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#define PLANE CLIP_LEFT_BIT
+#define CLIP_DOTPROD(K) (X(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#define PLANE CLIP_TOP_BIT
+#define CLIP_DOTPROD(K) (- Y(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#define PLANE CLIP_BOTTOM_BIT
+#define CLIP_DOTPROD(K) (Y(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#define PLANE CLIP_FAR_BIT
+#define CLIP_DOTPROD(K) (- Z(K) + W(K))
+
+ if (SIZE >= 3) {
+ GENERAL_CLIP
+ }
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#define PLANE CLIP_NEAR_BIT
+#define CLIP_DOTPROD(K) (Z(K) + W(K))
+
+ if (SIZE >=3 ) {
+ GENERAL_CLIP
+ }
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#undef GENERAL_CLIP
+
+
+ if (mask & CLIP_USER_BIT) {
+ if ( TAG(userclip_line)( ctx, &ii, &jj, interp ) == 0 )
+ return;
+ }
+
+ vlist[0] = ii;
+ vlist[1] = jj;
+ n = 2;
+
+ /* If necessary, project new vertices.
+ */
+ {
+ GLuint i, j;
+ GLfloat (*proj)[4] = VB->ProjectedClipPtr->data;
+ GLuint start = VB->FirstClipped;
+
+ for (i = 0; i < n; i++) {
+ j = vlist[i];
+ if (j >= start) {
+ if (SIZE == 4 && W(j) != 0.0F) {
+ GLfloat wInv = 1.0F / W(j);
+ proj[j][0] = X(j) * wInv;
+ proj[j][1] = Y(j) * wInv;
+ proj[j][2] = Z(j) * wInv;
+ proj[j][3] = wInv;
+ } else {
+ proj[j][0] = X(j);
+ proj[j][1] = Y(j);
+ proj[j][2] = Z(j);
+ proj[j][3] = W(j);
+ }
+ }
+ }
+ }
+
+ if (ctx->Driver.BuildProjectedVertices)
+ ctx->Driver.BuildProjectedVertices(ctx,
+ VB->FirstClipped,
+ VB->LastClipped,
+ ~0);
+
+ /* Render the new line.
+ */
+ ctx->Driver.LineFunc( ctx, ii, jj, j );
+}
+
+/* We now clip polygon triangles individually. This is necessary to
+ * avoid artifacts dependent on where the boundary of the VB falls
+ * within the polygon. As a result, there is an upper bound on the
+ * number of vertices which may be created, and the test against VB_SIZE
+ * is redundant.
+ */
+static void TAG(viewclip_polygon)( GLcontext *ctx,
+ GLuint n, GLuint vlist[], GLuint pv,
+ GLubyte mask )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ interp_func interp = (interp_func) VB->interpfunc;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint vlist2[MAX_CLIPPED_VERTICES];
+ GLuint *inlist = vlist, *outlist = vlist2;
+ GLuint i;
+ GLubyte *clipmask = VB->ClipMask;
+
+ VB->LastClipped = VB->FirstClipped;
+
+ if (mask & CLIP_ALL_BITS) {
+
+#define GENERAL_CLIP \
+ if (mask & PLANE) { \
+ GLuint idxPrev = inlist[n-1]; \
+ GLfloat dpPrev = CLIP_DOTPROD(idxPrev); \
+ GLuint outcount = 0; \
+ GLuint i; \
+ \
+ mask &= ~PLANE; \
+ \
+ for (i = 0; i < n; i++) { \
+ GLuint idx = inlist[i]; \
+ GLfloat dp = CLIP_DOTPROD(idx); \
+ \
+ if (!NEGATIVE(dpPrev)) { \
+ outlist[outcount++] = idxPrev; \
+ clipmask[idxPrev] &= ~PLANE; \
+ } \
+ \
+ if (DIFFERENT_SIGNS(dp, dpPrev)) { \
+ GLuint newvert; \
+ if (NEGATIVE(dp)) { \
+ /* Going out of bounds. Avoid division by zero as we \
+ * know dp != dpPrev from DIFFERENT_SIGNS, above. \
+ */ \
+ GLfloat t = dp / (dp - dpPrev); \
+ newvert = interp( ctx, t, idx, idxPrev, GL_TRUE ); \
+ } else { \
+ /* Coming back in. \
+ */ \
+ GLfloat t = dpPrev / (dpPrev - dp); \
+ newvert = interp( ctx, t, idxPrev, idx, GL_FALSE ); \
+ } \
+ clipmask[newvert] = mask; \
+ outlist[outcount++] = newvert; \
+ } \
+ \
+ idxPrev = idx; \
+ dpPrev = dp; \
+ } \
+ \
+ if (outcount < 3) \
+ return; \
+ \
+ { \
+ GLuint *tmp = inlist; \
+ inlist = outlist; \
+ outlist = tmp; \
+ n = outcount; \
+ } \
+ }
+
+
+#define PLANE CLIP_RIGHT_BIT
+#define CLIP_DOTPROD(K) (- X(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+
+
+#define PLANE CLIP_LEFT_BIT
+#define CLIP_DOTPROD(K) (X(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+
+#define PLANE CLIP_TOP_BIT
+#define CLIP_DOTPROD(K) (- Y(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+
+#define PLANE CLIP_BOTTOM_BIT
+#define CLIP_DOTPROD(K) (Y(K) + W(K))
+
+ GENERAL_CLIP
+
+#undef CLIP_DOTPROD
+#undef PLANE
+
+#define PLANE CLIP_FAR_BIT
+#define CLIP_DOTPROD(K) (- Z(K) + W(K))
+
+ if (SIZE >= 3) {
+ GENERAL_CLIP
+ }
+
+#undef CLIP_DOTPROD
+#undef PLANE
+
+#define PLANE CLIP_NEAR_BIT
+#define CLIP_DOTPROD(K) (Z(K) + W(K))
+
+ if (SIZE >=3 ) {
+ GENERAL_CLIP
+ }
+
+#undef CLIP_DOTPROD
+#undef PLANE
+#undef GENERAL_CLIP
+
+ if (inlist != vlist)
+ for (i = 0 ; i < n ; i++)
+ vlist[i] = inlist[i];
+ }
+
+ /* Clip against user clipping planes in clip space.
+ */
+ if (mask & CLIP_USER_BIT) {
+ n = TAG(userclip_polygon)( ctx, n, vlist, interp );
+ if (n < 3) return;
+ }
+
+ /* Project if necessary.
+ */
+ {
+ GLuint i;
+ GLfloat (*proj)[4] = VB->ProjectedClipPtr->data;
+ GLuint first = VB->FirstClipped;
+
+ for (i = 0; i < n; i++) {
+ GLuint j = vlist[i];
+ if (j >= first) {
+ if (SIZE == 4 && W(j) != 0.0F) {
+ GLfloat wInv = 1.0F / W(j);
+ proj[j][0] = X(j) * wInv;
+ proj[j][1] = Y(j) * wInv;
+ proj[j][2] = Z(j) * wInv;
+ proj[j][3] = wInv;
+ } else {
+ proj[j][0] = X(j);
+ proj[j][1] = Y(j);
+ proj[j][2] = Z(j);
+ proj[j][3] = W(j);
+ }
+ }
+ }
+ }
+
+ if (ctx->Driver.BuildProjectedVertices)
+ ctx->Driver.BuildProjectedVertices(ctx,
+ VB->FirstClipped,
+ VB->LastClipped,
+ ~0);
+
+ /* Render the new vertices as an unclipped polygon.
+ * Argh - need to pass in pv...
+ */
+ {
+ GLuint *tmp = VB->Elts;
+ VB->Elts = vlist;
+ render_poly_pv_raw_elts( ctx, 0, n, PRIM_BEGIN|PRIM_END, pv );
+ VB->Elts = tmp;
+ }
+}
+
+
+
+#undef W
+#undef Z
+#undef Y
+#undef X
+#undef SIZE
+#undef TAG
+#undef INSIDE
+#undef OUTSIDE
diff --git a/src/mesa/tnl/t_vb_fog.c b/src/mesa/tnl/t_vb_fog.c
new file mode 100644
index 0000000000..38a80702ab
--- /dev/null
+++ b/src/mesa/tnl/t_vb_fog.c
@@ -0,0 +1,201 @@
+/* $Id: t_vb_fog.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+struct fog_stage_data {
+ GLvector1f fogcoord; /* has actual storage allocated */
+ GLvector1f input; /* points into VB->EyePtr Z values */
+};
+
+#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->private)
+
+
+
+/* Use lookup table & interpolation?
+ */
+static void make_win_fog_coords( GLcontext *ctx, GLvector1f *out,
+ const GLvector1f *in )
+{
+ GLfloat end = ctx->Fog.End;
+ GLfloat *v = in->start;
+ GLuint stride = in->stride;
+ GLuint n = in->count;
+ GLfloat *data = out->data;
+ GLfloat d;
+ GLuint i;
+
+ out->count = in->count;
+
+ switch (ctx->Fog.Mode) {
+ case GL_LINEAR:
+ d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride))
+ data[i] = (end - ABSF(*v)) * d;
+ break;
+ case GL_EXP:
+ d = -ctx->Fog.Density;
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride))
+ data[i] = exp( d*ABSF(*v) );
+ break;
+ case GL_EXP2:
+ d = -(ctx->Fog.Density*ctx->Fog.Density);
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
+ GLfloat z = *v;
+ data[i] = exp( d*z*z );
+ }
+ break;
+ default:
+ gl_problem(ctx, "Bad fog mode in make_fog_coord");
+ return;
+ }
+}
+
+
+static GLboolean run_fog_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct fog_stage_data *store = FOG_STAGE_DATA(stage);
+ GLvector1f *input;
+
+ VB->FogCoordPtr = &store->fogcoord;
+
+ if (stage->changed_inputs == 0)
+ return GL_TRUE;
+
+ if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
+ if (!ctx->_NeedEyeCoords) {
+ GLfloat *m = ctx->ModelView.m;
+ GLfloat plane[4];
+
+ /* Use this to store calculated eye z values:
+ */
+ input = &store->fogcoord;
+
+ plane[0] = m[2];
+ plane[1] = m[6];
+ plane[2] = m[10];
+ plane[3] = m[14];
+
+ /* Full eye coords weren't required, just calculate the
+ * eye Z values.
+ */
+ gl_dotprod_tab[0][VB->ObjPtr->size](input->data, sizeof(GLfloat),
+ VB->ObjPtr, plane, 0 );
+
+ input->count = VB->ObjPtr->count;
+ }
+ else
+ {
+ input = &store->input;
+
+ if (VB->EyePtr->size < 2)
+ gl_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 );
+
+ input->data = &(VB->EyePtr->data[0][2]);
+ input->start = VB->EyePtr->start+2;
+ input->stride = VB->EyePtr->stride;
+ input->count = VB->EyePtr->count;
+ }
+ } else
+ input = VB->FogCoordPtr;
+
+ make_win_fog_coords( ctx, VB->FogCoordPtr, input );
+ return GL_TRUE;
+}
+
+static void check_fog_stage( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ stage->active = ctx->Fog.Enabled;
+
+ if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT)
+ stage->inputs = VERT_EYE;
+ else
+ stage->inputs = VERT_FOG_COORD;
+}
+
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean alloc_fog_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct fog_stage_data *store;
+ stage->private = MALLOC(sizeof(*store));
+ store = FOG_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ gl_vector1f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 );
+ gl_vector1f_init( &store->input, 0, 0 );
+
+ /* Now run the stage.
+ */
+ stage->run = run_fog_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void free_fog_data( struct gl_pipeline_stage *stage )
+{
+ struct fog_stage_data *store = FOG_STAGE_DATA(stage);
+ if (store) {
+ gl_vector1f_free( &store->fogcoord );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+
+const struct gl_pipeline_stage _tnl_fog_coordinate_stage =
+{
+ "build fog coordinates",
+ _NEW_FOG,
+ _NEW_FOG,
+ 0, 0, VERT_FOG_COORD, /* active, inputs, outputs */
+ 0, 0, /* changed_inputs, private_data */
+ free_fog_data, /* dtr */
+ check_fog_stage, /* check */
+ alloc_fog_data /* run -- initially set to init. */
+};
diff --git a/src/mesa/tnl/t_vb_light.c b/src/mesa/tnl/t_vb_light.c
new file mode 100644
index 0000000000..b55cda3858
--- /dev/null
+++ b/src/mesa/tnl/t_vb_light.c
@@ -0,0 +1,280 @@
+/* $Id: t_vb_light.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "light.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "simple_list.h"
+#include "mtypes.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+#define LIGHT_FLAGS 0x1 /* must be first */
+#define LIGHT_TWOSIDE 0x2
+#define LIGHT_COLORMATERIAL 0x4
+#define MAX_LIGHT_FUNC 0x8
+
+typedef void (*light_func)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input );
+
+struct light_stage_data {
+ GLvector4ub LitColor[2];
+ GLvector1ui LitIndex[2];
+ GLvector4ub LitSecondary[2];
+
+ light_func *light_func_tab;
+};
+
+#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->private))
+
+/* Tables for all the shading functions.
+ */
+static light_func _tnl_light_tab[MAX_LIGHT_FUNC];
+static light_func _tnl_light_fast_tab[MAX_LIGHT_FUNC];
+static light_func _tnl_light_fast_single_tab[MAX_LIGHT_FUNC];
+static light_func _tnl_light_spec_tab[MAX_LIGHT_FUNC];
+static light_func _tnl_light_ci_tab[MAX_LIGHT_FUNC];
+
+#define TAG(x) x
+#define IDX (0)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_tw
+#define IDX (LIGHT_TWOSIDE)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_fl
+#define IDX (LIGHT_FLAGS)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_tw_fl
+#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_cm
+#define IDX (LIGHT_COLORMATERIAL)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_tw_cm
+#define IDX (LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_fl_cm
+#define IDX (LIGHT_FLAGS|LIGHT_COLORMATERIAL)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_tw_fl_cm
+#define IDX (LIGHT_FLAGS|LIGHT_TWOSIDE|LIGHT_COLORMATERIAL)
+#include "t_vb_lighttmp.h"
+
+
+static void init_lighting( void )
+{
+ static int done;
+
+ if (!done) {
+ init_light_tab();
+ init_light_tab_tw();
+ init_light_tab_fl();
+ init_light_tab_tw_fl();
+ init_light_tab_cm();
+ init_light_tab_tw_cm();
+ init_light_tab_fl_cm();
+ init_light_tab_tw_fl_cm();
+ done = 1;
+ }
+}
+
+
+static GLboolean run_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
+ GLuint ind;
+
+ /* Make sure we can talk about elements 0..2 in the vector we are
+ * lighting. TODO: Don't repeat this in CVA!
+ */
+ if (input->size <= 2) {
+ if (input->flags & VEC_NOT_WRITEABLE) {
+ ASSERT(VB->importable_data & VERT_OBJ);
+ VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE );
+ input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
+ ASSERT((input->flags & VEC_NOT_WRITEABLE) == 0);
+ }
+
+ gl_vector4f_clean_elem(input, VB->Count, 2);
+ }
+
+ if (VB->Flag)
+ ind = LIGHT_FLAGS;
+ else
+ ind = 0;
+
+ /* The individual tabs know about replaying side-effects vs. full
+ * re-execution.
+ */
+ store->light_func_tab[ind]( ctx, VB, stage, input );
+
+ return GL_TRUE;
+}
+
+
+/* Called in place of do_lighting when the light table may have changed.
+ */
+static GLboolean run_validate_lighting( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ GLuint ind = 0;
+ light_func *tab;
+
+ if (ctx->Visual.RGBAflag) {
+ if (ctx->Light._NeedVertices) {
+ if (ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR)
+ tab = _tnl_light_spec_tab;
+ else
+ tab = _tnl_light_tab;
+ }
+ else {
+ if (ctx->Light.EnabledList.next == ctx->Light.EnabledList.prev)
+ tab = _tnl_light_fast_single_tab;
+ else
+ tab = _tnl_light_fast_tab;
+ }
+/* tab = _tnl_light_tab; */
+ }
+
+ if (ctx->Light.ColorMaterialEnabled)
+ ind |= LIGHT_COLORMATERIAL;
+
+ if (ctx->Light.Model.TwoSide)
+ ind |= LIGHT_TWOSIDE;
+
+ LIGHT_STAGE_DATA(stage)->light_func_tab = &tab[ind];
+
+ /* This and the above should only be done on _NEW_LIGHT:
+ */
+ gl_validate_all_lighting_tables( ctx );
+
+ /* Now run the stage...
+ */
+ stage->run = run_lighting;
+ return stage->run( ctx, stage );
+}
+
+/* Called the first time stage->run is called. In effect, don't
+ * allocate data until the first time the stage is run.
+ */
+static GLboolean run_init_lighting( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct light_stage_data *store;
+ GLuint size = tnl->vb.Size;
+
+ stage->private = MALLOC(sizeof(*store));
+ store = LIGHT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ /* Do onetime init.
+ */
+ init_lighting();
+
+ gl_vector4ub_alloc( &store->LitColor[0], 0, size, 32 );
+ gl_vector4ub_alloc( &store->LitColor[1], 0, size, 32 );
+ gl_vector4ub_alloc( &store->LitSecondary[0], 0, size, 32 );
+ gl_vector4ub_alloc( &store->LitSecondary[1], 0, size, 32 );
+ gl_vector1ui_alloc( &store->LitIndex[0], 0, size, 32 );
+ gl_vector1ui_alloc( &store->LitIndex[1], 0, size, 32 );
+
+ /* Now validate the stage derived data...
+ */
+ stage->run = run_validate_lighting;
+ return stage->run( ctx, stage );
+}
+
+
+
+/*
+ * Check if lighting is enabled. If so, configure the pipeline stage's
+ * type, inputs, and outputs.
+ */
+static void check_lighting( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ stage->active = ctx->Light.Enabled;
+ if (stage->active) {
+ if (stage->private)
+ stage->run = run_validate_lighting;
+ stage->inputs = VERT_NORM|VERT_MATERIAL;
+ if (ctx->Light._NeedVertices)
+ stage->inputs |= VERT_EYE; /* effectively, even when lighting in obj */
+ if (ctx->Light.ColorMaterialEnabled)
+ stage->inputs |= VERT_RGBA;
+ }
+}
+
+
+static void dtr( struct gl_pipeline_stage *stage )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+
+ if (store) {
+ gl_vector4ub_free( &store->LitColor[0] );
+ gl_vector4ub_free( &store->LitColor[1] );
+ gl_vector1ui_free( &store->LitIndex[0] );
+ gl_vector1ui_free( &store->LitIndex[1] );
+ gl_vector4ub_free( &store->LitSecondary[0] );
+ gl_vector4ub_free( &store->LitSecondary[1] );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+const struct gl_pipeline_stage _tnl_lighting_stage =
+{
+ "lighting",
+ _NEW_LIGHT, /* recheck */
+ _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency
+ * otherwise not captured by inputs
+ * (which may be VERT_OBJ) */
+ 0,0,VERT_RGBA, /* active, inputs, outputs */
+ 0,0, /* changed_inputs, private_data */
+ dtr, /* destroy */
+ check_lighting, /* check */
+ run_init_lighting /* run -- initially set to ctr */
+};
+
diff --git a/src/mesa/tnl/t_vb_lighttmp.h b/src/mesa/tnl/t_vb_lighttmp.h
new file mode 100644
index 0000000000..f2bcde6714
--- /dev/null
+++ b/src/mesa/tnl/t_vb_lighttmp.h
@@ -0,0 +1,965 @@
+/* $Id: t_vb_lighttmp.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Authors:
+ * Brian Paul <brianp@valinux.com>
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#if (IDX & LIGHT_FLAGS)
+# define VSTRIDE (4 * sizeof(GLfloat))
+# define NSTRIDE (3 * sizeof(GLfloat))
+# define CHECK_MATERIAL(x) (flags[x] & VERT_MATERIAL)
+# define CHECK_END_VB(x) (flags[x] & VERT_END_VB)
+# if (IDX & LIGHT_COLORMATERIAL)
+# define CMSTRIDE STRIDE_4UB(CMcolor, (4 * sizeof(GLubyte)))
+# define CHECK_COLOR_MATERIAL(x) (flags[x] & VERT_RGBA)
+# define CHECK_VALIDATE(x) (flags[x] & (VERT_RGBA|VERT_MATERIAL))
+# define DO_ANOTHER_NORMAL(x) \
+ ((flags[x] & (VERT_RGBA|VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == VERT_NORM)
+# define REUSE_LIGHT_RESULTS(x) \
+ ((flags[x] & (VERT_RGBA|VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == 0)
+# else
+# define CMSTRIDE 0
+# define CHECK_COLOR_MATERIAL(x) 0
+# define CHECK_VALIDATE(x) (flags[x] & (VERT_MATERIAL))
+# define DO_ANOTHER_NORMAL(x) \
+ ((flags[x] & (VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == VERT_NORM)
+# define REUSE_LIGHT_RESULTS(x) \
+ ((flags[x] & (VERT_NORM|VERT_END_VB|VERT_MATERIAL)) == 0)
+# endif
+#else
+# define VSTRIDE vstride
+# define NSTRIDE nstride
+# define CHECK_MATERIAL(x) 0 /* no materials on array paths */
+# define CHECK_END_VB(XX) (XX >= nr)
+# if (IDX & LIGHT_COLORMATERIAL)
+# define CMSTRIDE STRIDE_4UB(CMcolor, CMstride)
+# define CHECK_COLOR_MATERIAL(x) (x < nr) /* always have colormaterial */
+# define CHECK_VALIDATE(x) (x < nr)
+# define DO_ANOTHER_NORMAL(x) 0 /* always stop to recalc colormat */
+# else
+# define CMSTRIDE 0
+# define CHECK_COLOR_MATERIAL(x) 0 /* no colormaterial */
+# define CHECK_VALIDATE(x) (0)
+# define DO_ANOTHER_NORMAL(XX) (XX < nr) /* keep going to end of vb */
+# endif
+# define REUSE_LIGHT_RESULTS(x) 0 /* always have a new normal */
+#endif
+
+
+
+#if (IDX & LIGHT_TWOSIDE)
+# define NR_SIDES 2
+#else
+# define NR_SIDES 1
+#endif
+
+
+
+static void TAG(light_rgba_spec)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLfloat (*base)[3] = ctx->Light._BaseColor;
+ const GLchan *sumA = ctx->Light._BaseAlpha;
+
+ GLuint j;
+
+ GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *)input->data;
+ GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+
+ GLchan (*CMcolor)[4];
+ GLuint CMstride;
+
+ GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data;
+ GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data;
+ GLchan (*Fspec)[4] = (GLchan (*)[4]) store->LitSecondary[0].data;
+ GLchan (*Bspec)[4] = (GLchan (*)[4]) store->LitSecondary[1].data;
+ GLuint nr = VB->Count;
+
+ GLuint *flags = VB->Flag;
+ struct gl_material (*new_material)[2] = VB->Material;
+ GLuint *new_material_mask = VB->MaterialMask;
+
+ (void) flags;
+ (void) nstride;
+ (void) vstride;
+
+ if (IDX & LIGHT_COLORMATERIAL) {
+ CMcolor = (GLchan (*)[4]) VB->ColorPtr[0]->data;
+ CMstride = VB->ColorPtr[0]->stride;
+ }
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ VB->SecondaryColorPtr[0] = &store->LitSecondary[0];
+
+ if (IDX & LIGHT_TWOSIDE) {
+ VB->ColorPtr[1] = &store->LitColor[1];
+ VB->SecondaryColorPtr[1] = &store->LitSecondary[1];
+ }
+
+ /* Side-effects done, can we finish now?
+ */
+ if (stage->changed_inputs == 0)
+ return;
+
+ for ( j=0 ;
+ j<nr ;
+ j++,STRIDE_F(vertex,VSTRIDE),STRIDE_F(normal,NSTRIDE),CMSTRIDE)
+ {
+ GLfloat sum[2][3], spec[2][3];
+ struct gl_light *light;
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ COPY_3V(sum[0], base[0]);
+ ZERO_3V(spec[0]);
+
+ if (IDX & LIGHT_TWOSIDE) {
+ COPY_3V(sum[1], base[1]);
+ ZERO_3V(spec[1]);
+ }
+
+ /* Add contribution from each enabled light source */
+ foreach (light, &ctx->Light.EnabledList) {
+ GLfloat n_dot_h;
+ GLfloat correction;
+ GLint side;
+ GLfloat contrib[3];
+ GLfloat attenuation;
+ GLfloat VP[3]; /* unit vector from vertex to light */
+ GLfloat n_dot_VP; /* n dot VP */
+ GLfloat *h;
+
+ /* compute VP and attenuation */
+ if (!(light->_Flags & LIGHT_POSITIONAL)) {
+ /* directional light */
+ COPY_3V(VP, light->_VP_inf_norm);
+ attenuation = light->_VP_inf_spot_attenuation;
+ }
+ else {
+ GLfloat d; /* distance from vertex to light */
+
+ SUB_3V(VP, light->_Position, vertex);
+
+ d = (GLfloat) LEN_3FV( VP );
+
+ if (d > 1e-6) {
+ GLfloat invd = 1.0F / d;
+ SELF_SCALE_SCALAR_3V(VP, invd);
+ }
+
+ attenuation = 1.0F / (light->ConstantAttenuation + d *
+ (light->LinearAttenuation + d *
+ light->QuadraticAttenuation));
+
+ /* spotlight attenuation */
+ if (light->_Flags & LIGHT_SPOT) {
+ GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
+
+ if (PV_dot_dir<light->_CosCutoff) {
+ continue; /* this light makes no contribution */
+ }
+ else {
+ double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ int k = (int) x;
+ GLfloat spot = (GLfloat) (light->_SpotExpTable[k][0]
+ + (x-k)*light->_SpotExpTable[k][1]);
+ attenuation *= spot;
+ }
+ }
+ }
+
+
+ if (attenuation < 1e-3)
+ continue; /* this light makes no contribution */
+
+ /* Compute dot product or normal and vector from V to light pos */
+ n_dot_VP = DOT3( normal, VP );
+
+ /* Which side gets the diffuse & specular terms? */
+ if (n_dot_VP < 0.0F) {
+ ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]);
+ if (!(IDX & LIGHT_TWOSIDE)) {
+ continue;
+ }
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+ }
+ else {
+ if (IDX & LIGHT_TWOSIDE) {
+ ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
+ }
+ side = 0;
+ correction = 1;
+ }
+
+ /* diffuse term */
+ COPY_3V(contrib, light->_MatAmbient[side]);
+ ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]);
+ ACC_SCALE_SCALAR_3V(sum[side], attenuation, contrib );
+
+ /* specular term - cannibalize VP... */
+ if (ctx->Light.Model.LocalViewer) {
+ GLfloat v[3];
+ COPY_3V(v, vertex);
+ NORMALIZE_3FV(v);
+ SUB_3V(VP, VP, v); /* h = VP + VPe */
+ h = VP;
+ NORMALIZE_3FV(h);
+ }
+ else if (light->_Flags & LIGHT_POSITIONAL) {
+ h = VP;
+ ACC_3V(h, ctx->_EyeZDir);
+ NORMALIZE_3FV(h);
+ }
+ else {
+ h = light->_h_inf_norm;
+ }
+
+ n_dot_h = correction * DOT3(normal, h);
+
+ if (n_dot_h > 0.0F) {
+ GLfloat spec_coef;
+ struct gl_shine_tab *tab = ctx->_ShineTable[side];
+ GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
+
+ if (spec_coef > 1.0e-10) {
+ spec_coef *= attenuation;
+ ACC_SCALE_SCALAR_3V( spec[side], spec_coef,
+ light->_MatSpecular[side]);
+ }
+ }
+ } /*loop over lights*/
+
+ FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] );
+ FLOAT_RGB_TO_CHAN_RGB( Fspec[j], spec[0] );
+ Fcolor[j][3] = sumA[0];
+
+ if (IDX & LIGHT_TWOSIDE) {
+ FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] );
+ FLOAT_RGB_TO_CHAN_RGB( Bspec[j], spec[1] );
+ Bcolor[j][3] = sumA[1];
+ }
+ }
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+}
+
+
+static void TAG(light_rgba)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLuint j;
+
+ GLfloat (*base)[3] = ctx->Light._BaseColor;
+ const GLchan *sumA = ctx->Light._BaseAlpha;
+
+ GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *) input->data;
+ GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+
+ GLubyte (*CMcolor)[4];
+ GLuint CMstride;
+
+ GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data;
+ GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data;
+ GLuint *flags = VB->Flag;
+
+ struct gl_material (*new_material)[2] = VB->Material;
+ GLuint *new_material_mask = VB->MaterialMask;
+ GLuint nr = VB->Count;
+
+ (void) flags;
+ (void) nstride;
+ (void) vstride;
+
+ if (IDX & LIGHT_COLORMATERIAL) {
+ CMcolor = VB->ColorPtr[0]->data;
+ CMstride = VB->ColorPtr[0]->stride;
+ }
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ if (IDX & LIGHT_TWOSIDE)
+ VB->ColorPtr[1] = &store->LitColor[1];
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ for ( j=0 ;
+ j<nr ;
+ j++,STRIDE_F(vertex,VSTRIDE), STRIDE_F(normal,NSTRIDE),CMSTRIDE)
+ {
+ GLfloat sum[2][3];
+ struct gl_light *light;
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, (GLchan *)CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ COPY_3V(sum[0], base[0]);
+
+ if ( IDX & LIGHT_TWOSIDE )
+ COPY_3V(sum[1], base[1]);
+
+ /* Add contribution from each enabled light source */
+ foreach (light, &ctx->Light.EnabledList) {
+
+ GLfloat n_dot_h;
+ GLfloat correction;
+ GLint side;
+ GLfloat contrib[3];
+ GLfloat attenuation = 1.0;
+ GLfloat VP[3]; /* unit vector from vertex to light */
+ GLfloat n_dot_VP; /* n dot VP */
+ GLfloat *h;
+
+ /* compute VP and attenuation */
+ if (!(light->_Flags & LIGHT_POSITIONAL)) {
+ /* directional light */
+ COPY_3V(VP, light->_VP_inf_norm);
+ attenuation = light->_VP_inf_spot_attenuation;
+ }
+ else {
+ GLfloat d; /* distance from vertex to light */
+
+
+ SUB_3V(VP, light->_Position, vertex);
+
+ d = LEN_3FV( VP );
+
+ if ( d > 1e-6) {
+ GLfloat invd = 1.0F / d;
+ SELF_SCALE_SCALAR_3V(VP, invd);
+ }
+
+ attenuation = 1.0F / (light->ConstantAttenuation + d *
+ (light->LinearAttenuation + d *
+ light->QuadraticAttenuation));
+
+ /* spotlight attenuation */
+ if (light->_Flags & LIGHT_SPOT) {
+ GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
+
+ if (PV_dot_dir<light->_CosCutoff) {
+ continue; /* this light makes no contribution */
+ }
+ else {
+ double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ int k = (int) x;
+ GLfloat spot = (light->_SpotExpTable[k][0]
+ + (x-k)*light->_SpotExpTable[k][1]);
+ attenuation *= spot;
+ }
+ }
+ }
+
+
+ if (attenuation < 1e-3)
+ continue; /* this light makes no contribution */
+
+
+ /* Compute dot product or normal and vector from V to light pos */
+ n_dot_VP = DOT3( normal, VP );
+
+ /* which side are we lighting? */
+ if (n_dot_VP < 0.0F) {
+ ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]);
+
+ if (!(IDX & LIGHT_TWOSIDE))
+ continue;
+
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+ }
+ else {
+ if (IDX & LIGHT_TWOSIDE) {
+ ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
+ }
+ side = 0;
+ correction = 1;
+ }
+
+ COPY_3V(contrib, light->_MatAmbient[side]);
+
+ /* diffuse term */
+ ACC_SCALE_SCALAR_3V(contrib, n_dot_VP, light->_MatDiffuse[side]);
+
+ /* specular term - cannibalize VP... */
+ {
+ if (ctx->Light.Model.LocalViewer) {
+ GLfloat v[3];
+ COPY_3V(v, vertex);
+ NORMALIZE_3FV(v);
+ SUB_3V(VP, VP, v); /* h = VP + VPe */
+ h = VP;
+ NORMALIZE_3FV(h);
+ }
+ else if (light->_Flags & LIGHT_POSITIONAL) {
+ h = VP;
+ ACC_3V(h, ctx->_EyeZDir);
+ NORMALIZE_3FV(h);
+ }
+ else {
+ h = light->_h_inf_norm;
+ }
+
+ n_dot_h = correction * DOT3(normal, h);
+
+ if (n_dot_h > 0.0F)
+ {
+ GLfloat spec_coef;
+ struct gl_shine_tab *tab = ctx->_ShineTable[side];
+
+ GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef );
+
+ ACC_SCALE_SCALAR_3V( contrib, spec_coef,
+ light->_MatSpecular[side]);
+ }
+ }
+
+ ACC_SCALE_SCALAR_3V( sum[side], attenuation, contrib );
+ }
+
+ FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] );
+ Fcolor[j][3] = sumA[0];
+
+ if (IDX & LIGHT_TWOSIDE) {
+ FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] );
+ Bcolor[j][3] = sumA[1];
+ }
+ }
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, (GLchan *)CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+}
+
+
+
+
+/* As below, but with just a single light.
+ */
+static void TAG(light_fast_rgba_single)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input )
+
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLubyte (*CMcolor)[4];
+ GLuint CMstride;
+ GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data;
+ GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data;
+ struct gl_light *light = ctx->Light.EnabledList.next;
+ GLuint *flags = VB->Flag;
+ GLchan baseubyte[2][4];
+ GLuint j = 0;
+ struct gl_material (*new_material)[2] = VB->Material;
+ GLuint *new_material_mask = VB->MaterialMask;
+ GLfloat base[2][3];
+ GLuint nr = VB->Count;
+
+ (void) input; /* doesn't refer to Eye or Obj */
+ (void) flags;
+ (void) nr;
+ (void) nstride;
+
+ if (IDX & LIGHT_COLORMATERIAL) {
+ CMcolor = VB->ColorPtr[0]->data;
+ CMstride = VB->ColorPtr[0]->stride;
+ }
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ if (IDX & LIGHT_TWOSIDE)
+ VB->ColorPtr[1] = &store->LitColor[1];
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, (GLchan *)CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ baseubyte[0][3] = ctx->Light._BaseAlpha[0];
+ baseubyte[1][3] = ctx->Light._BaseAlpha[1];
+
+ do {
+ /* No attenuation, so incoporate _MatAmbient into base color.
+ */
+ {
+ COPY_3V(base[0], light->_MatAmbient[0]);
+ ACC_3V(base[0], ctx->Light._BaseColor[0] );
+ FLOAT_RGB_TO_CHAN_RGB( baseubyte[0], base[0] );
+
+ if (IDX & LIGHT_TWOSIDE) {
+ COPY_3V(base[1], light->_MatAmbient[1]);
+ ACC_3V(base[1], ctx->Light._BaseColor[1]);
+ FLOAT_RGB_TO_CHAN_RGB( baseubyte[1], base[1]);
+ }
+ }
+
+ do {
+ GLfloat n_dot_VP = DOT3(normal, light->_VP_inf_norm);
+
+ COPY_CHAN4(Fcolor[j], baseubyte[0]);
+ if (IDX & LIGHT_TWOSIDE) COPY_CHAN4(Bcolor[j], baseubyte[1]);
+
+ if (n_dot_VP < 0.0F) {
+ if (IDX & LIGHT_TWOSIDE) {
+ GLfloat n_dot_h = -DOT3(normal, light->_h_inf_norm);
+ GLfloat sum[3];
+ COPY_3V(sum, base[1]);
+ ACC_SCALE_SCALAR_3V(sum, -n_dot_VP, light->_MatDiffuse[1]);
+ if (n_dot_h > 0.0F) {
+ GLfloat spec;
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[1], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[1]);
+ }
+ FLOAT_RGB_TO_CHAN_RGB(Bcolor[j], sum );
+ }
+ } else {
+ GLfloat n_dot_h = DOT3(normal, light->_h_inf_norm);
+ GLfloat sum[3];
+ COPY_3V(sum, base[0]);
+ ACC_SCALE_SCALAR_3V(sum, n_dot_VP, light->_MatDiffuse[0]);
+ if (n_dot_h > 0.0F) {
+ GLfloat spec;
+ GET_SHINE_TAB_ENTRY( ctx->_ShineTable[0], n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V(sum, spec, light->_MatSpecular[0]);
+
+ }
+ FLOAT_RGB_TO_CHAN_RGB(Fcolor[j], sum );
+ }
+
+ j++;
+ STRIDE_F(normal, NSTRIDE);
+ } while (DO_ANOTHER_NORMAL(j));
+
+
+ for ( ; REUSE_LIGHT_RESULTS(j) ; j++ ) {
+ COPY_CHAN4(Fcolor[j], Fcolor[j-1]);
+ if (IDX & LIGHT_TWOSIDE)
+ COPY_CHAN4(Bcolor[j], Bcolor[j-1]);
+ STRIDE_F(normal, NSTRIDE);
+ }
+
+ /* Have to recompute our base colors on material change.
+ */
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, (GLchan *)CMcolor[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ } while (!CHECK_END_VB(j));
+}
+
+
+/* Light infinite lights
+ */
+static void TAG(light_fast_rgba)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ const GLchan *sumA = ctx->Light._BaseAlpha;
+ GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLubyte (*CMcolor)[4];
+ GLuint CMstride;
+ GLchan (*Fcolor)[4] = (GLchan (*)[4]) store->LitColor[0].data;
+ GLchan (*Bcolor)[4] = (GLchan (*)[4]) store->LitColor[1].data;
+ GLuint *flags = VB->Flag;
+ GLuint j = 0;
+ struct gl_material (*new_material)[2] = VB->Material;
+ GLuint *new_material_mask = VB->MaterialMask;
+ GLuint nr = VB->Count;
+ struct gl_light *light;
+
+ (void) flags;
+ (void) input;
+ (void) nr;
+ (void) nstride;
+
+ if (IDX & LIGHT_COLORMATERIAL) {
+ CMcolor = VB->ColorPtr[0]->data;
+ CMstride = VB->ColorPtr[0]->stride;
+ }
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ if (IDX & LIGHT_TWOSIDE)
+ VB->ColorPtr[1] = &store->LitColor[1];
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, *CMcolor );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ do {
+ do {
+ GLfloat sum[2][3];
+
+ COPY_3V(sum[0], ctx->Light._BaseColor[0]);
+ if (IDX & LIGHT_TWOSIDE)
+ COPY_3V(sum[1], ctx->Light._BaseColor[1]);
+
+ foreach (light, &ctx->Light.EnabledList) {
+ GLfloat n_dot_h, n_dot_VP, spec;
+
+ ACC_3V(sum[0], light->_MatAmbient[0]);
+ if (IDX & LIGHT_TWOSIDE)
+ ACC_3V(sum[1], light->_MatAmbient[1]);
+
+ n_dot_VP = DOT3(normal, light->_VP_inf_norm);
+
+ if (n_dot_VP > 0.0F) {
+ ACC_SCALE_SCALAR_3V(sum[0], n_dot_VP, light->_MatDiffuse[0]);
+ n_dot_h = DOT3(normal, light->_h_inf_norm);
+ if (n_dot_h > 0.0F) {
+ struct gl_shine_tab *tab = ctx->_ShineTable[0];
+ GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum[0], spec,
+ light->_MatSpecular[0]);
+ }
+ }
+ else if (IDX & LIGHT_TWOSIDE) {
+ ACC_SCALE_SCALAR_3V(sum[1], -n_dot_VP, light->_MatDiffuse[1]);
+ n_dot_h = -DOT3(normal, light->_h_inf_norm);
+ if (n_dot_h > 0.0F) {
+ struct gl_shine_tab *tab = ctx->_ShineTable[1];
+ GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec );
+ ACC_SCALE_SCALAR_3V( sum[1], spec,
+ light->_MatSpecular[1]);
+ }
+ }
+ }
+
+ FLOAT_RGB_TO_CHAN_RGB( Fcolor[j], sum[0] );
+ Fcolor[j][3] = sumA[0];
+
+ if (IDX & LIGHT_TWOSIDE) {
+ FLOAT_RGB_TO_CHAN_RGB( Bcolor[j], sum[1] );
+ Bcolor[j][3] = sumA[1];
+ }
+
+ j++;
+ STRIDE_F(normal, NSTRIDE);
+ } while (DO_ANOTHER_NORMAL(j));
+
+ /* Reuse the shading results while there is no change to
+ * normal or material values.
+ */
+ for ( ; REUSE_LIGHT_RESULTS(j) ; j++ ) {
+ COPY_CHAN4(Fcolor[j], Fcolor[j-1]);
+ if (IDX & LIGHT_TWOSIDE)
+ COPY_CHAN4(Bcolor[j], Bcolor[j-1]);
+ STRIDE_F(normal, NSTRIDE);
+ }
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ } while (!CHECK_END_VB(j));
+}
+
+
+
+
+
+/*
+ * Use current lighting/material settings to compute the color indexes
+ * for an array of vertices.
+ * Input: n - number of vertices to light
+ * side - 0=use front material, 1=use back material
+ * vertex - array of [n] vertex position in eye coordinates
+ * normal - array of [n] surface normal vector
+ * Output: indexResult - resulting array of [n] color indexes
+ */
+static void TAG(light_ci)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct gl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLuint j;
+ GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *) input->data;
+ GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLubyte (*CMcolor)[4];
+ GLuint CMstride;
+ GLuint *flags = VB->Flag;
+ GLuint *indexResult[2];
+ struct gl_material (*new_material)[2] = VB->Material;
+ GLuint *new_material_mask = VB->MaterialMask;
+ GLuint nr = VB->Count;
+
+ (void) flags;
+ (void) nstride;
+ (void) vstride;
+
+ VB->IndexPtr[0] = &store->LitIndex[0];
+ if (IDX & LIGHT_TWOSIDE)
+ VB->IndexPtr[1] = &store->LitIndex[1];
+
+ indexResult[0] = VB->IndexPtr[0]->data;
+ indexResult[1] = VB->IndexPtr[1]->data;
+
+ if (IDX & LIGHT_COLORMATERIAL) {
+ CMcolor = VB->ColorPtr[0]->data;
+ CMstride = VB->ColorPtr[0]->stride;
+ }
+
+ /* loop over vertices */
+ for ( j=0 ;
+ j<nr ;
+ j++,STRIDE_F(vertex,VSTRIDE),STRIDE_F(normal, NSTRIDE), CMSTRIDE)
+ {
+ GLfloat diffuse[2], specular[2];
+ GLuint side = 0;
+ struct gl_light *light;
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, (GLchan *)CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+
+ diffuse[0] = specular[0] = 0.0F;
+
+ if ( IDX & LIGHT_TWOSIDE ) {
+ diffuse[1] = specular[1] = 0.0F;
+ }
+
+ /* Accumulate diffuse and specular from each light source */
+ foreach (light, &ctx->Light.EnabledList) {
+
+ GLfloat attenuation = 1.0F;
+ GLfloat VP[3]; /* unit vector from vertex to light */
+ GLfloat n_dot_VP; /* dot product of l and n */
+ GLfloat *h, n_dot_h, correction = 1.0;
+
+ /* compute l and attenuation */
+ if (!(light->_Flags & LIGHT_POSITIONAL)) {
+ /* directional light */
+ COPY_3V(VP, light->_VP_inf_norm);
+ }
+ else {
+ GLfloat d; /* distance from vertex to light */
+
+ SUB_3V(VP, light->_Position, vertex);
+
+ d = LEN_3FV( VP );
+ if ( d > 1e-6) {
+ GLfloat invd = 1.0F / d;
+ SELF_SCALE_SCALAR_3V(VP, invd);
+ }
+
+ attenuation = 1.0F / (light->ConstantAttenuation + d *
+ (light->LinearAttenuation + d *
+ light->QuadraticAttenuation));
+
+ /* spotlight attenuation */
+ if (light->_Flags & LIGHT_SPOT) {
+ GLfloat PV_dot_dir = - DOT3(VP, light->_NormDirection);
+ if (PV_dot_dir<light->_CosCutoff) {
+ continue; /* this light makes no contribution */
+ }
+ else {
+ double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ int k = (int) x;
+ GLfloat spot = (light->_SpotExpTable[k][0]
+ + (x-k)*light->_SpotExpTable[k][1]);
+ attenuation *= spot;
+ }
+ }
+ }
+
+ if (attenuation < 1e-3)
+ continue; /* this light makes no contribution */
+
+ n_dot_VP = DOT3( normal, VP );
+
+ /* which side are we lighting? */
+ if (n_dot_VP < 0.0F) {
+ if (!(IDX & LIGHT_TWOSIDE))
+ continue;
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+ }
+
+ /* accumulate diffuse term */
+ diffuse[side] += n_dot_VP * light->_dli * attenuation;
+
+ /* specular term */
+ if (ctx->Light.Model.LocalViewer) {
+ GLfloat v[3];
+ COPY_3V(v, vertex);
+ NORMALIZE_3FV(v);
+ SUB_3V(VP, VP, v); /* h = VP + VPe */
+ h = VP;
+ NORMALIZE_3FV(h);
+ }
+ else if (light->_Flags & LIGHT_POSITIONAL) {
+ h = VP;
+ ACC_3V(h, ctx->_EyeZDir);
+ NORMALIZE_3FV(h);
+ }
+ else {
+ h = light->_h_inf_norm;
+ }
+
+ n_dot_h = correction * DOT3(normal, h);
+
+ if (n_dot_h > 0.0F)
+ {
+ GLfloat spec_coef;
+ struct gl_shine_tab *tab = ctx->_ShineTable[side];
+ GET_SHINE_TAB_ENTRY( tab, n_dot_h, spec_coef);
+ specular[side] += spec_coef * light->_sli * attenuation;
+ }
+ } /*loop over lights*/
+
+ /* Now compute final color index */
+ for (side = 0 ; side < NR_SIDES ; side++) {
+ struct gl_material *mat = &ctx->Light.Material[side];
+ GLfloat index;
+
+ if (specular[side] > 1.0F) {
+ index = mat->SpecularIndex;
+ }
+ else {
+ GLfloat d_a = mat->DiffuseIndex - mat->AmbientIndex;
+ GLfloat s_a = mat->SpecularIndex - mat->AmbientIndex;
+
+ index = mat->AmbientIndex
+ + diffuse[side] * (1.0F-specular[side]) * d_a
+ + specular[side] * s_a;
+
+ if (index > mat->SpecularIndex) {
+ index = mat->SpecularIndex;
+ }
+ }
+ indexResult[side][j] = (GLuint) (GLint) index;
+ }
+ } /*for vertex*/
+
+ if ( CHECK_COLOR_MATERIAL(j) )
+ gl_update_color_material( ctx, CMcolor[j] );
+
+ if ( CHECK_MATERIAL(j) )
+ gl_update_material( ctx, new_material[j], new_material_mask[j] );
+
+ if ( CHECK_VALIDATE(j) )
+ gl_validate_all_lighting_tables( ctx );
+}
+
+
+
+static void TAG(init_light_tab)( void )
+{
+ _tnl_light_tab[IDX] = TAG(light_rgba);
+ _tnl_light_fast_tab[IDX] = TAG(light_fast_rgba);
+ _tnl_light_fast_single_tab[IDX] = TAG(light_fast_rgba_single);
+ _tnl_light_spec_tab[IDX] = TAG(light_rgba_spec);
+ _tnl_light_ci_tab[IDX] = TAG(light_ci);
+}
+
+
+#undef TAG
+#undef IDX
+#undef NR_SIDES
+#undef NSTRIDE
+#undef VSTRIDE
+#undef CHECK_MATERIAL
+#undef CHECK_END_VB
+#undef DO_ANOTHER_NORMAL
+#undef REUSE_LIGHT_RESULTS
+#undef CMSTRIDE
+#undef CHECK_COLOR_MATERIAL
+#undef CHECK_VALIDATE
diff --git a/src/mesa/tnl/t_vb_normals.c b/src/mesa/tnl/t_vb_normals.c
new file mode 100644
index 0000000000..97e7b9bb35
--- /dev/null
+++ b/src/mesa/tnl/t_vb_normals.c
@@ -0,0 +1,193 @@
+/* $Id: t_vb_normals.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+
+struct normal_stage_data {
+ normal_func *NormalTransform;
+ GLvector3f normal;
+};
+
+#define NORMAL_STAGE_DATA(stage) ((struct normal_stage_data *)stage->private)
+
+
+
+
+static GLboolean run_normal_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ ASSERT(store->NormalTransform);
+
+ if (VB->NormalLengthPtr) {
+ GLfloat diff = VB->NormalLengthPtr[0] -
+ 1.0/LEN_3FV(VB->NormalPtr->data[0]);
+ ASSERT((diff*diff) < .01);
+ }
+
+ if (stage->changed_inputs)
+ (store->NormalTransform[0])(&ctx->ModelView,
+ ctx->_ModelViewInvScale,
+ VB->NormalPtr,
+ VB->NormalLengthPtr,
+ 0,
+ &store->normal);
+
+ VB->NormalPtr = &store->normal;
+ return GL_TRUE;
+}
+
+
+static GLboolean run_validate_normal_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage)
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+
+ ASSERT(ctx->_NeedNormals);
+
+ if (ctx->_NeedEyeCoords) {
+ GLuint transform = NORM_TRANSFORM_NO_ROT;
+
+ if (ctx->ModelView.flags & (MAT_FLAG_GENERAL |
+ MAT_FLAG_ROTATION |
+ MAT_FLAG_GENERAL_3D |
+ MAT_FLAG_PERSPECTIVE))
+ transform = NORM_TRANSFORM;
+
+
+ if (ctx->Transform.Normalize) {
+ store->NormalTransform = gl_normal_tab[transform | NORM_NORMALIZE];
+ }
+ else if (ctx->Transform.RescaleNormals &&
+ ctx->_ModelViewInvScale != 1.0) {
+ store->NormalTransform = gl_normal_tab[transform | NORM_RESCALE];
+ }
+ else {
+ store->NormalTransform = gl_normal_tab[transform];
+ }
+ }
+ else {
+ if (ctx->Transform.Normalize) {
+ store->NormalTransform = gl_normal_tab[NORM_NORMALIZE];
+ }
+ else if (!ctx->Transform.RescaleNormals &&
+ ctx->_ModelViewInvScale != 1.0) {
+ store->NormalTransform = gl_normal_tab[NORM_RESCALE];
+ }
+ else {
+ store->NormalTransform = 0;
+ }
+ }
+
+ if (store->NormalTransform) {
+ stage->run = run_normal_stage;
+ return stage->run( ctx, stage );
+ } else {
+ stage->active = GL_FALSE; /* !!! */
+ return GL_TRUE;
+ }
+}
+
+
+static void check_normal_transform( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ stage->active = ctx->_NeedNormals;
+ /* Don't clobber the initialize function:
+ */
+ if (stage->private)
+ stage->run = run_validate_normal_stage;
+}
+
+
+static GLboolean alloc_normal_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct normal_stage_data *store;
+ stage->private = MALLOC(sizeof(*store));
+ store = NORMAL_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ gl_vector3f_alloc( &store->normal, 0, tnl->vb.Size, 32 );
+
+ /* Now run the stage.
+ */
+ stage->run = run_validate_normal_stage;
+ return stage->run( ctx, stage );
+}
+
+
+
+static void free_normal_data( struct gl_pipeline_stage *stage )
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+ if (store) {
+ gl_vector3f_free( &store->normal );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+#define _TNL_NEW_NORMAL_TRANSFORM (_NEW_MODELVIEW| \
+ _NEW_TRANSFORM| \
+ _MESA_NEW_NEED_NORMALS| \
+ _MESA_NEW_NEED_EYE_COORDS)
+
+
+
+const struct gl_pipeline_stage _tnl_normal_transform_stage =
+{
+ "normal transform",
+ _TNL_NEW_NORMAL_TRANSFORM, /* re-check */
+ _TNL_NEW_NORMAL_TRANSFORM, /* re-run */
+ 0,VERT_NORM,VERT_NORM, /* active, inputs, outputs */
+ 0, 0, /* changed_inputs, private */
+ free_normal_data, /* destructor */
+ check_normal_transform, /* check */
+ alloc_normal_data /* run -- initially set to alloc */
+};
+
diff --git a/src/mesa/tnl/t_vb_points.c b/src/mesa/tnl/t_vb_points.c
new file mode 100644
index 0000000000..16f9ca9722
--- /dev/null
+++ b/src/mesa/tnl/t_vb_points.c
@@ -0,0 +1,124 @@
+/* $Id: t_vb_points.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Brian Paul <brian@valinux.com>
+ */
+
+#include "mtypes.h"
+#include "mem.h"
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+struct point_stage_data {
+ GLvector1f PointSize;
+};
+
+#define POINT_STAGE_DATA(stage) ((struct point_stage_data *)stage->private)
+
+
+/*
+ * Compute attenuated point sizes
+ */
+static GLboolean run_point_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct point_stage_data *store = POINT_STAGE_DATA(stage);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ const GLfloat (*eye)[4] = (const GLfloat (*)[4]) VB->EyePtr->data;
+ const GLfloat p0 = ctx->Point.Params[0];
+ const GLfloat p1 = ctx->Point.Params[1];
+ const GLfloat p2 = ctx->Point.Params[2];
+ const GLfloat pointSize = ctx->Point._Size;
+ GLfloat *size = store->PointSize.data;
+ GLuint i;
+
+ if (stage->changed_inputs) {
+ /* XXX do threshold and min/max clamping here? */
+ for (i = 0; i < VB->Count; i++) {
+ const GLfloat dist = -eye[i][2];
+ /* GLfloat dist = GL_SQRT(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]);*/
+ size[i] = pointSize / (p0 + dist * (p1 + dist * p2));
+ }
+ }
+
+ VB->PointSizePtr = &store->PointSize;
+
+ return GL_TRUE;
+}
+
+
+/* If point size attenuation is on we'll compute the point size for
+ * each vertex in a special pipeline stage.
+ */
+static void check_point_size( GLcontext *ctx, struct gl_pipeline_stage *d )
+{
+ d->active = ctx->Point._Attenuated;
+}
+
+static GLboolean alloc_point_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct point_stage_data *store;
+ stage->private = MALLOC(sizeof(*store));
+ store = POINT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ gl_vector1f_alloc( &store->PointSize, 0, VB->Size, 32 );
+
+ /* Now run the stage.
+ */
+ stage->run = run_point_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void free_point_data( struct gl_pipeline_stage *stage )
+{
+ struct point_stage_data *store = POINT_STAGE_DATA(stage);
+ if (store) {
+ gl_vector1f_free( &store->PointSize );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+const struct gl_pipeline_stage _tnl_point_attenuation_stage =
+{
+ "point size attenuation", /* name */
+ _NEW_POINT, /* build_state_change */
+ _NEW_POINT, /* run_state_change */
+ 0, /* active */
+ VERT_EYE, /* inputs */
+ VERT_POINT_SIZE, /* outputs */
+ 0, /* changed_inputs (temporary value) */
+ 0, /* stage private data */
+ free_point_data, /* destructor */
+ check_point_size, /* check */
+ alloc_point_data /* run -- initially set to alloc data */
+};
diff --git a/src/mesa/tnl/t_vb_render.c b/src/mesa/tnl/t_vb_render.c
new file mode 100644
index 0000000000..5707f21c90
--- /dev/null
+++ b/src/mesa/tnl/t_vb_render.c
@@ -0,0 +1,698 @@
+/* $Id: t_vb_render.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*
+ * Render whole vertex buffers, including projection of vertices from
+ * clip space and clipping of primitives.
+ *
+ * This file makes calls to project vertices and to the point, line
+ * and triangle rasterizers via the function pointers:
+ *
+ * context->Driver.BuildProjectedVertices()
+ * context->Driver.PointsFunc()
+ * context->Driver.LineFunc()
+ * context->Driver.TriangleFunc()
+ * context->Driver.QuadFunc()
+ *
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+#include "macros.h"
+#include "mem.h"
+#include "mtypes.h"
+#include "mmath.h"
+
+#include "math/m_matrix.h"
+#include "math/m_xform.h"
+
+#include "t_pipeline.h"
+
+
+typedef GLuint (*interp_func)( GLcontext *ctx,
+ GLfloat t, GLuint in, GLuint out,
+ GLboolean force_boundary );
+
+typedef void (*clip_line_func)( GLcontext *ctx,
+ GLuint i, GLuint j,
+ GLubyte mask);
+
+typedef void (*clip_poly_func)( GLcontext *ctx,
+ GLuint n, GLuint vlist[],
+ GLuint pv, GLubyte mask );
+
+
+typedef void (*render_func)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags );
+
+
+
+struct render_stage_data {
+
+ /* Clipping functions for current state.
+ */
+ interp_func interp; /* Clip interpolation function */
+ GLuint _ClipInputs; /* Inputs referenced by interpfunc */
+
+};
+
+#define RENDER_STAGE_DATA(stage) ((struct render_stage_data *)stage->private)
+
+static void render_poly_pv_raw_elts( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags,
+ GLuint pv );
+
+/**********************************************************************/
+/* Interpolate between pairs of vertices */
+/**********************************************************************/
+
+
+#define INTERP_RGBA 0x1
+#define INTERP_TEX 0x2
+#define INTERP_INDEX 0x4
+#define INTERP_SPEC 0x8
+#define INTERP_FOG 0x10
+#define INTERP_EDGE 0x20
+#define MAX_INTERP 0x40
+
+
+#define LINTERP_SZ( t, vec, to, a, b, sz ) \
+do { \
+ switch (sz) { \
+ case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
+ case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
+ case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
+ case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
+ } \
+} while(0)
+
+
+#if 1
+
+#define LINTERP_RGBA(nr, t, out, a, b) { \
+ int i; \
+ for (i = 0; i < nr; i++) { \
+ GLfloat fa = CHAN_TO_FLOAT(a[i]); \
+ GLfloat fb = CHAN_TO_FLOAT(b[i]); \
+ GLfloat fo = LINTERP(t, fa, fb); \
+ FLOAT_COLOR_TO_CHAN(out[i], fo); \
+ } \
+}
+
+#else
+
+#define LINTERP_RGBA(nr, t, out, a, b) { \
+ int n; \
+ const GLuint ti = FloatToInt(t*256.0F); \
+ const GLubyte *Ib = (const GLubyte *)&a[0]; \
+ const GLubyte *Jb = (const GLubyte *)&b[0]; \
+ GLubyte *Ob = (GLubyte *)&out[0]; \
+ \
+ for (n = 0 ; n < nr ; n++) \
+ Ob[n] = (GLubyte) (Ib[n] + ((ti * (Jb[n] - Ib[n]))/256)); \
+}
+
+#endif
+
+
+
+static interp_func interp_tab[0x80];
+
+
+#define IND (INTERP_RGBA)
+#define NAME interp_RGBA
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC)
+#define NAME interp_RGBA_SPEC
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_FOG)
+#define NAME interp_RGBA_FOG
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG)
+#define NAME interp_RGBA_SPEC_FOG
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_TEX)
+#define NAME interp_RGBA_TEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX)
+#define NAME interp_RGBA_SPEC_TEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX)
+#define NAME interp_RGBA_FOG_TEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX)
+#define NAME interp_RGBA_SPEC_FOG_TEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_INDEX)
+#define NAME interp_INDEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_FOG|INTERP_INDEX)
+#define NAME interp_FOG_INDEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_TEX|INTERP_INDEX)
+#define NAME interp_TEX_INDEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX)
+#define NAME interp_FOG_TEX_INDEX
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_EDGE)
+#define NAME interp_RGBA_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_EDGE)
+#define NAME interp_RGBA_SPEC_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_FOG|INTERP_EDGE)
+#define NAME interp_RGBA_FOG_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_EDGE)
+#define NAME interp_RGBA_SPEC_FOG_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_TEX|INTERP_EDGE)
+#define NAME interp_RGBA_TEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX|INTERP_EDGE)
+#define NAME interp_RGBA_SPEC_TEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX|INTERP_EDGE)
+#define NAME interp_RGBA_FOG_TEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX|INTERP_EDGE)
+#define NAME interp_RGBA_SPEC_FOG_TEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_INDEX|INTERP_EDGE)
+#define NAME interp_INDEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_FOG|INTERP_INDEX|INTERP_EDGE)
+#define NAME interp_FOG_INDEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_TEX|INTERP_INDEX|INTERP_EDGE)
+#define NAME interp_TEX_INDEX_EDGE
+#include "t_vb_interptmp.h"
+
+#define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX|INTERP_EDGE)
+#define NAME interp_FOG_TEX_INDEX_EDGE
+#include "t_vb_interptmp.h"
+
+
+
+static GLuint interp_invalid( GLcontext *ctx,
+ GLfloat t,
+ GLuint in, GLuint out,
+ GLboolean boundary )
+{
+ (void)(ctx && t && in && out && boundary);
+ fprintf(stderr, "Invalid interpolation function in t_vbrender.c\n");
+ return in;
+}
+
+
+static void interp_init( void )
+{
+ GLuint i;
+
+ /* Use the maximal function as the default. I don't believe any of
+ * the non-implemented combinations are reachable, but this gives
+ * some safety from crashes.
+ */
+ for (i = 0 ; i < Elements(interp_tab) ; i++)
+ interp_tab[i] = interp_invalid;
+
+ interp_tab[INTERP_RGBA] = interp_RGBA;
+ interp_tab[INTERP_RGBA|INTERP_SPEC] = interp_RGBA_SPEC;
+ interp_tab[INTERP_RGBA|INTERP_FOG] = interp_RGBA_FOG;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG] = interp_RGBA_SPEC_FOG;
+ interp_tab[INTERP_RGBA|INTERP_TEX] = interp_RGBA_TEX;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_TEX] = interp_RGBA_SPEC_TEX;
+ interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_TEX] = interp_RGBA_FOG_TEX;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX] = interp_RGBA_SPEC_FOG_TEX;
+ interp_tab[INTERP_INDEX] = interp_INDEX;
+ interp_tab[INTERP_FOG|INTERP_INDEX] = interp_FOG_INDEX;
+ interp_tab[INTERP_TEX|INTERP_INDEX] = interp_TEX_INDEX;
+ interp_tab[INTERP_FOG|INTERP_TEX|INTERP_INDEX] = interp_FOG_TEX_INDEX;
+ interp_tab[INTERP_RGBA|INTERP_EDGE] = interp_RGBA_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_EDGE] = interp_RGBA_SPEC_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_EDGE] = interp_RGBA_FOG_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_EDGE] = interp_RGBA_SPEC_FOG_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_TEX|INTERP_EDGE] = interp_RGBA_TEX_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_TEX|INTERP_EDGE] = interp_RGBA_SPEC_TEX_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_FOG|INTERP_TEX|INTERP_EDGE] = interp_RGBA_FOG_TEX_EDGE;
+ interp_tab[INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX|INTERP_EDGE] = interp_RGBA_SPEC_FOG_TEX_EDGE;
+ interp_tab[INTERP_INDEX|INTERP_EDGE] = interp_INDEX_EDGE;
+ interp_tab[INTERP_FOG|INTERP_INDEX|INTERP_EDGE] = interp_FOG_INDEX_EDGE;
+ interp_tab[INTERP_TEX|INTERP_INDEX|INTERP_EDGE] = interp_TEX_INDEX_EDGE;
+ interp_tab[INTERP_FOG|INTERP_TEX|INTERP_INDEX|INTERP_EDGE] = interp_FOG_TEX_INDEX_EDGE;
+}
+
+
+/**********************************************************************/
+/* Clip single primitives */
+/**********************************************************************/
+
+
+#if 0
+#define NEGATIVE(x) ((*(int *)&x)<0)
+#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
+#else
+#define NEGATIVE(x) (x < 0)
+#define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
+#endif
+
+#define W(i) coord[i][3]
+#define Z(i) coord[i][2]
+#define Y(i) coord[i][1]
+#define X(i) coord[i][0]
+#define SIZE 4
+#define TAG(x) x##_4
+#include "t_vb_cliptmp.h"
+
+#define W(i) 1.0
+#define Z(i) coord[i][2]
+#define Y(i) coord[i][1]
+#define X(i) coord[i][0]
+#define SIZE 3
+#define TAG(x) x##_3
+#include "t_vb_cliptmp.h"
+
+#define W(i) 1.0
+#define Z(i) 0.0
+#define Y(i) coord[i][1]
+#define X(i) coord[i][0]
+#define SIZE 2
+#define TAG(x) x##_2
+#include "t_vb_cliptmp.h"
+
+static clip_poly_func clip_poly_tab[5] = {
+ 0,
+ 0,
+ viewclip_polygon_2,
+ viewclip_polygon_3,
+ viewclip_polygon_4
+};
+
+static clip_line_func clip_line_tab[5] = {
+ 0,
+ 0,
+ viewclip_line_2,
+ viewclip_line_3,
+ viewclip_line_4
+};
+
+
+
+/**********************************************************************/
+/* Clip and render single primitives */
+/**********************************************************************/
+
+
+
+static INLINE void draw_line(GLcontext *ctx, GLuint v1, GLuint v2 )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2];
+ GLubyte ormask = c1|c2;
+ if (!ormask)
+ ctx->Driver.LineFunc( ctx, v1, v2, v2 );
+ else if (!(c1 & c2 & 0x3f))
+ clip_line_tab[VB->ClipPtr->size]( ctx, v1, v2, ormask );
+}
+
+static INLINE void draw_triangle(GLcontext *ctx,
+ GLuint v1, GLuint v2, GLuint v3,
+ GLuint pv )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2], c3 = VB->ClipMask[v3];
+ GLubyte ormask = c1|c2|c3;
+ if (!ormask)
+ ctx->Driver.TriangleFunc( ctx, v1, v2, v3, pv );
+ else if (!(c1 & c2 & c3 & 0x3f)) {
+ GLuint vlist[MAX_CLIPPED_VERTICES];
+ ASSIGN_3V(vlist, v1, v2, v3 );
+ clip_poly_tab[VB->ClipPtr->size]( ctx, 3, vlist, pv, ormask );
+ }
+}
+
+
+static INLINE void draw_quad( GLcontext *ctx,
+ GLuint v1, GLuint v2, GLuint v3,
+ GLuint v4, GLuint pv )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLubyte c1 = VB->ClipMask[v1], c2 = VB->ClipMask[v2];
+ GLubyte c3 = VB->ClipMask[v3], c4 = VB->ClipMask[v4];
+ GLubyte ormask = c1|c2|c3|c4;
+ if (!ormask)
+ ctx->Driver.QuadFunc( ctx, v1, v2, v3, v4, pv );
+ else if (!(c1 & c2 & c3 & c4 & 0x3f)) {
+ GLuint vlist[MAX_CLIPPED_VERTICES];
+ ASSIGN_4V(vlist, v1, v2, v3, v4 );
+ clip_poly_tab[VB->ClipPtr->size]( ctx, 4, vlist, pv, ormask );
+ }
+}
+
+
+/**********************************************************************/
+/* Clip and render whole begin/end objects */
+/**********************************************************************/
+
+#define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
+#define EDGEFLAG_GET(idx) VB->EdgeFlagPtr->data[idx]
+#define EDGEFLAG_SET(idx, val) VB->EdgeFlagPtr->data[idx] = val
+
+
+/* Vertices, no clipping.
+ */
+#define RENDER_POINTS( start, count ) \
+ ctx->Driver.PointsFunc( ctx, start, count-1 )
+
+#define RENDER_LINE( i1, i ) \
+ ctx->Driver.LineFunc( ctx, i1, i, i )
+
+#define RENDER_TRI( i2, i1, i, pv, parity ) \
+do { \
+ if (parity) \
+ ctx->Driver.TriangleFunc( ctx, i1, i2, i, pv ); \
+ else \
+ ctx->Driver.TriangleFunc( ctx, i2, i1, i, pv ); \
+} while (0)
+
+#define RENDER_QUAD( i3, i2, i1, i, pv ) \
+ ctx->Driver.QuadFunc( ctx, i3, i2, i1, i, pv );
+
+#define TAG(x) x##_raw
+
+#define LOCAL_VARS \
+ struct vertex_buffer *VB = &(TNL_CONTEXT(ctx)->vb); \
+ (void) VB;
+
+#define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx )
+#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE;
+#define PRESERVE_VB_DEFS
+#include "t_vb_rendertmp.h"
+
+
+/* Elts, no clipping.
+ */
+#undef ELT
+#undef TAG
+#undef LOCAL_VARS
+#define TAG(x) x##_raw_elts
+#define ELT(x) elt[x]
+#define LOCAL_VARS \
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
+ const GLuint * const elt = VB->Elts; \
+ (void) elt;
+#include "t_vb_rendertmp.h"
+
+
+
+
+/* Vertices, with the possibility of clipping.
+ */
+#define RENDER_POINTS( start, count ) \
+ ctx->Driver.PointsFunc( ctx, start, count-1 )
+
+#define RENDER_LINE( i1, i ) \
+ draw_line( ctx, i1, i )
+
+#define RENDER_TRI( i2, i1, i, pv, parity) \
+do { \
+ GLuint e2=i2, e1=i1; \
+ if (parity) { GLuint t=e2; e2=e1; e1=t; } \
+ draw_triangle(ctx,e2,e1,i,pv); \
+} while (0)
+
+#define RENDER_QUAD( i3, i2, i1, i, pv) \
+ draw_quad(ctx,i3,i2,i1,i,pv)
+
+
+#define LOCAL_VARS \
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
+ (void)VB;
+
+#define TAG(x) x##_clipped
+#define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx )
+#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE;
+#define PRESERVE_VB_DEFS
+#include "t_vb_rendertmp.h"
+
+
+
+/* Elts, with the possibility of clipping.
+ */
+#undef ELT
+#undef TAG
+#undef LOCAL_VARS
+#define ELT(x) elt[x]
+#define LOCAL_VARS \
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
+ const GLuint * const elt = VB->Elts; \
+ (void) elt;
+#define TAG(x) x##_clipped_elts
+
+#include "t_vb_rendertmp.h"
+
+
+
+/**********************************************************************/
+/* Clip and render whole vertex buffers */
+/**********************************************************************/
+
+
+static GLboolean run_render( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint new_inputs = stage->changed_inputs;
+ render_func *tab;
+ GLint pass = 0;
+
+ VB->interpfunc = (void *)RENDER_STAGE_DATA(stage)->interp;
+
+ if (new_inputs) {
+ GLuint importable = new_inputs & VB->importable_data;
+ GLuint interested = 0;
+
+ if (VB->ClipOrMask)
+ interested = ~0;
+
+ if (ctx->_TriangleCaps & DD_TRI_UNFILLED)
+ interested |= VERT_EDGE;
+
+ importable &= interested;
+
+ if (importable)
+ VB->import_data( ctx, importable, VEC_NOT_WRITEABLE|VEC_BAD_STRIDE);
+
+ if (ctx->Driver.BuildProjectedVertices)
+ ctx->Driver.BuildProjectedVertices( ctx, 0, VB->Count, new_inputs);
+ }
+
+ /* Rendering is considered a side-effect, and must be repeated each
+ * time the stage is run, even if no inputs have changed.
+ */
+ if (VB->Elts) {
+ tab = VB->ClipOrMask ? render_tab_clipped_elts : render_tab_raw_elts;
+ } else {
+ tab = VB->ClipOrMask ? render_tab_clipped : render_tab_raw;
+ }
+
+ if (ctx->Driver.RenderStart)
+ ctx->Driver.RenderStart( ctx );
+
+ do
+ {
+ GLuint i, length, flags = 0;
+ for (i = 0 ; !(flags & PRIM_LAST) ; i += length)
+ {
+ flags = VB->Primitive[i];
+ length= VB->PrimitiveLength[i];
+ ASSERT(length || (flags & PRIM_LAST));
+ ASSERT((flags & PRIM_MODE_MASK) <= GL_POLYGON+1);
+ if (length)
+ tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags );
+ }
+ } while (ctx->Driver.MultipassFunc &&
+ ctx->Driver.MultipassFunc( ctx, ++pass ));
+
+ if (ctx->Driver.RenderFinish)
+ ctx->Driver.RenderFinish( ctx );
+
+ return GL_FALSE; /* finished the pipe */
+}
+
+
+/**********************************************************************/
+/* Render pipeline stage */
+/**********************************************************************/
+
+
+
+/* Quite a bit of work involved in finding out the inputs for the
+ * render stage. This function also identifies which vertex
+ * interpolation function to use, as these are essentially the same
+ * question.
+ */
+static void check_render( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ struct render_stage_data *store = RENDER_STAGE_DATA(stage);
+ GLuint interp = 0;
+ GLuint inputs = VERT_CLIP;
+ GLuint i;
+
+ if (ctx->Visual.RGBAflag)
+ {
+ interp |= INTERP_RGBA;
+ inputs |= VERT_RGBA;
+
+ if (ctx->_TriangleCaps & DD_SEPERATE_SPECULAR) {
+ interp |= INTERP_SPEC;
+ inputs |= VERT_SPEC_RGB;
+ }
+
+ if (ctx->Texture._ReallyEnabled) {
+ interp |= INTERP_TEX;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ if (ctx->Texture.Unit[i]._ReallyEnabled)
+ inputs |= VERT_TEX(i);
+ }
+ }
+ }
+ else if (ctx->Light.ShadeModel==GL_SMOOTH)
+ {
+ interp |= INTERP_INDEX;
+ inputs |= VERT_INDEX;
+ }
+
+ if (ctx->Point._Attenuated)
+ inputs |= VERT_POINT_SIZE;
+
+ /* How do drivers turn this off?
+ */
+ if (ctx->Fog.Enabled) {
+ interp |= INTERP_FOG;
+ inputs |= VERT_FOG_COORD;
+ }
+
+ if (ctx->_TriangleCaps & DD_TRI_UNFILLED) {
+ inputs |= VERT_EDGE;
+ }
+
+ if (ctx->RenderMode==GL_FEEDBACK) {
+ interp |= INTERP_TEX;
+ inputs |= VERT_TEX_ANY;
+ }
+
+ store->interp = interp_tab[interp];
+ stage->inputs = inputs;
+}
+
+
+/* Called the first time stage->check() is invoked.
+ */
+static void alloc_render_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct render_stage_data *store;
+ static GLboolean first_time = 1;
+
+ if (first_time) {
+ interp_init();
+ first_time = 0;
+ }
+
+ stage->private = MALLOC(sizeof(*store));
+ if (!stage->private)
+ return;
+
+ /* Now do the check.
+ */
+ stage->check = check_render;
+ stage->check( ctx, stage );
+}
+
+
+
+static void dtr( struct gl_pipeline_stage *stage )
+{
+ struct render_stage_data *store = RENDER_STAGE_DATA(stage);
+ if (store) {
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+
+const struct gl_pipeline_stage _tnl_render_stage =
+{
+ "render",
+ (_NEW_BUFFERS |
+ _DD_NEW_SEPERATE_SPECULAR |
+ _NEW_TEXTURE|
+ _NEW_LIGHT|
+ _NEW_POINT|
+ _NEW_FOG|
+ _DD_NEW_TRI_UNFILLED |
+ _NEW_RENDERMODE), /* re-check (new inputs, interp function) */
+ 0, /* re-run (always runs) */
+ GL_TRUE, /* active */
+ 0, 0, /* inputs (set in check_render), outputs */
+ 0, 0, /* changed_inputs, private */
+ dtr, /* destructor */
+ alloc_render_data, /* check - initially set to alloc data */
+ run_render /* run */
+};
diff --git a/src/mesa/tnl/t_vb_rendertmp.h b/src/mesa/tnl/t_vb_rendertmp.h
new file mode 100644
index 0000000000..de8adb23ec
--- /dev/null
+++ b/src/mesa/tnl/t_vb_rendertmp.h
@@ -0,0 +1,452 @@
+/* $Id: t_vb_rendertmp.h,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#ifndef POSTFIX
+#define POSTFIX
+#endif
+
+#ifndef INIT
+#define INIT(x)
+#endif
+
+#ifndef NEED_EDGEFLAG_SETUP
+#define NEED_EDGEFLAG_SETUP 0
+#define EDGEFLAG_GET(a) 0
+#define EDGEFLAG_SET(a,b)
+#endif
+
+#ifndef RESET_STIPPLE
+#define RESET_STIPPLE
+#endif
+
+#ifndef RESET_OCCLUSION
+#define RESET_OCCLUSION
+#endif
+
+#ifndef TEST_PRIM_END
+#define TEST_PRIM_END(flags) (flags & PRIM_END)
+#define TEST_PRIM_BEGIN(flags) (flags & PRIM_BEGIN)
+#define TEST_PRIM_PARITY(flags) (flags & PRIM_PARITY)
+#endif
+
+#ifndef ELT
+#define ELT(x) x
+#endif
+
+static void TAG(render_points)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_POINTS);
+ RENDER_POINTS( start, count );
+ POSTFIX;
+}
+
+static void TAG(render_lines)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINES);
+ for (j=start+1; j<count; j+=2 ) {
+ RENDER_LINE( ELT(j-1), ELT(j) );
+ RESET_STIPPLE;
+ }
+ POSTFIX;
+}
+
+
+static void TAG(render_line_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINES);
+
+ for (j=start+1; j<count; j++ ) {
+ RENDER_LINE( ELT(j-1), ELT(j) );
+ }
+
+ if (TEST_PRIM_END(flags))
+ RESET_STIPPLE;
+
+ POSTFIX;
+}
+
+
+static void TAG(render_line_loop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint i;
+ LOCAL_VARS;
+
+ (void) flags;
+
+ RESET_OCCLUSION;
+ INIT(GL_LINES);
+
+ if (start+1 < count) {
+ if (TEST_PRIM_BEGIN(flags)) {
+ RENDER_LINE( ELT(start), ELT(start+1) );
+ }
+
+ for ( i = start+2 ; i < count ; i++) {
+ RENDER_LINE( ELT(i-1), ELT(i) );
+ }
+
+ if ( TEST_PRIM_END(flags)) {
+ RENDER_LINE( ELT(count-1), ELT(start) );
+ RESET_STIPPLE;
+ }
+ }
+
+ POSTFIX;
+}
+
+
+static void TAG(render_triangles)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2; j<count; j+=3) {
+ /* Leave the edgeflags as supplied by the user.
+ */
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), 0 );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2; j<count; j+=3) {
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), 0 );
+ }
+ }
+ POSTFIX;
+}
+
+
+
+static void TAG(render_tri_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ GLuint parity = 0;
+ LOCAL_VARS;
+
+ if (TEST_PRIM_PARITY(flags))
+ parity = 1;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2;j<count;j++,parity^=1) {
+ /* All edges are boundary. Set edgeflags to 1, draw the
+ * triangle, and restore them to the original values.
+ */
+ GLuint ej2 = ELT(j-2);
+ GLuint ej1 = ELT(j-1);
+ GLuint ej = ELT(j);
+ GLboolean ef2 = EDGEFLAG_GET( ej2 );
+ GLboolean ef1 = EDGEFLAG_GET( ej1 );
+ GLboolean ef = EDGEFLAG_GET( ej );
+ EDGEFLAG_SET( ej2, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ej2, ej1, ej, ej, parity );
+ EDGEFLAG_SET( ej2, ef2 );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2;j<count;j++,parity^=1) {
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j), ELT(j), parity );
+ }
+ }
+ POSTFIX;
+}
+
+
+static void TAG(render_tri_fan)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2;j<count;j++) {
+ /* For trifans, all edges are boundary.
+ */
+ GLuint ejs = ELT(start);
+ GLuint ej1 = ELT(j-1);
+ GLuint ej = ELT(j);
+ GLboolean efs = EDGEFLAG_GET( ejs );
+ GLboolean ef1 = EDGEFLAG_GET( ej1 );
+ GLboolean ef = EDGEFLAG_GET( ej );
+ EDGEFLAG_SET( ejs, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ejs, ej1, ej, ej, 0);
+ EDGEFLAG_SET( ejs, efs );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(j), 0 );
+ }
+ }
+
+ POSTFIX;
+}
+
+
+/* This is a bit of a hack. Clipping produces polygons and really
+ * wants to use this function to render them (in particular to get the
+ * edgeflags right). However, the rule that pv==start for polys
+ * doens't hold there, hence the extra arg and the wrapper below.
+ */
+static void TAG(render_poly_pv)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags,
+ GLuint pv )
+{
+ GLuint j = start+2;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ if (start+3 < count) {
+ GLboolean efstart = EDGEFLAG_GET( ELT(start) );
+ GLboolean efcount = EDGEFLAG_GET( ELT(count-1) );
+
+
+ /* If the primitive does not begin here, the first edge
+ * is non-boundary.
+ */
+ if (!TEST_PRIM_BEGIN(flags))
+ EDGEFLAG_SET( ELT(start), GL_FALSE );
+
+ /* If the primitive does not end here, the final edge is
+ * non-boundary.
+ */
+ if (!TEST_PRIM_END(flags))
+ EDGEFLAG_SET( ELT(count-1), GL_FALSE );
+
+ /* Draw the first triangle (possibly also the last).
+ */
+ if (j<count) {
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 );
+ EDGEFLAG_SET( ELT(j), ef );
+ j++;
+ }
+
+ /* For internal tris, the first and last edges are non-boundary.
+ */
+ EDGEFLAG_SET( ELT(start), GL_FALSE );
+ for (;j<count-1;j++) {
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 );
+ EDGEFLAG_SET( ELT(j), ef );
+ }
+
+ /* Draw the last triangle
+ */
+ if (j < count) {
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(pv), 0 );
+ j++;
+ }
+
+ /* Restore the first, last edgeflags:
+ */
+ EDGEFLAG_SET( ELT(count-1), efcount );
+ EDGEFLAG_SET( ELT(start), efstart );
+ }
+
+ if (TEST_PRIM_END(flags)) {
+ RESET_STIPPLE;
+ }
+ }
+ else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j), ELT(start), 0 );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_poly)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ TAG(render_poly_pv)( ctx, start, count, flags, start );
+}
+
+static void TAG(render_quads)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+3; j<count; j+=4) {
+ /* Use user-specified edgeflags for quads.
+ */
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j), ELT(j) );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+3; j<count; j+=4) {
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_quad_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+3;j<count;j+=2) {
+ /* All edges are boundary. Set edgeflags to 1, draw the
+ * quad, and restore them to the original values.
+ */
+ GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) );
+ GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) );
+ GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) );
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j-3), GL_TRUE );
+ EDGEFLAG_SET( ELT(j-2), GL_TRUE );
+ EDGEFLAG_SET( ELT(j-1), GL_TRUE );
+ EDGEFLAG_SET( ELT(j), GL_TRUE );
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j), ELT(j-1), ELT(j) );
+ EDGEFLAG_SET( ELT(j-3), ef3 );
+ EDGEFLAG_SET( ELT(j-2), ef2 );
+ EDGEFLAG_SET( ELT(j-1), ef1 );
+ EDGEFLAG_SET( ELT(j), ef );
+ RESET_STIPPLE;
+ }
+ } else {
+ for (j=start+3;j<count;j+=2) {
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j), ELT(j-1), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_noop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ (void)(ctx && start && count && flags);
+}
+
+static render_func TAG(render_tab)[GL_POLYGON+2] = {
+ TAG(render_points),
+ TAG(render_lines),
+ TAG(render_line_loop),
+ TAG(render_line_strip),
+ TAG(render_triangles),
+ TAG(render_tri_strip),
+ TAG(render_tri_fan),
+ TAG(render_quads),
+ TAG(render_quad_strip),
+ TAG(render_poly),
+ TAG(render_noop),
+};
+
+
+
+#ifndef PRESERVE_VB_DEFS
+#undef RENDER_TRI
+#undef RENDER_QUAD
+#undef RENDER_LINE
+#undef RENDER_POINTS
+#undef LOCAL_VARS
+#undef INIT
+#undef POSTFIX
+#undef RESET_STIPPLE
+#undef DBG
+#undef ELT
+#endif
+
+#ifndef PRESERVE_TAG
+#undef TAG
+#endif
+
+#undef PRESERVE_VB_DEFS
+#undef PRESERVE_TAG
+
diff --git a/src/mesa/tnl/t_vb_texgen.c b/src/mesa/tnl/t_vb_texgen.c
new file mode 100644
index 0000000000..e975665e8a
--- /dev/null
+++ b/src/mesa/tnl/t_vb_texgen.c
@@ -0,0 +1,685 @@
+/* $Id: t_vb_texgen.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Brian Paul <brian@valinux.com>
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mmath.h"
+#include "mem.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+/***********************************************************************
+ * Automatic texture coordinate generation (texgen) code.
+ */
+
+
+struct texgen_stage_data;
+
+typedef void (*texgen_func)( GLcontext *ctx,
+ struct texgen_stage_data *store,
+ GLuint unit);
+
+
+struct texgen_stage_data {
+
+ /* Per-texunit derived state.
+ */
+ GLuint TexgenSize[MAX_TEXTURE_UNITS];
+ GLuint TexgenHoles[MAX_TEXTURE_UNITS];
+ texgen_func TexgenFunc[MAX_TEXTURE_UNITS];
+
+ /* Temporary values used in texgen.
+ */
+ GLfloat (*tmp_f)[3];
+ GLfloat *tmp_m;
+
+ /* Buffered outputs of the stage.
+ */
+ GLvector4f texcoord[MAX_TEXTURE_UNITS];
+};
+
+
+#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->private)
+
+
+
+
+static GLuint all_bits[5] = {
+ 0,
+ VEC_SIZE_1,
+ VEC_SIZE_2,
+ VEC_SIZE_3,
+ VEC_SIZE_4,
+};
+
+#define VEC_SIZE_FLAGS (VEC_SIZE_1|VEC_SIZE_2|VEC_SIZE_3|VEC_SIZE_4)
+
+/*
+ */
+static void build_m3(GLfloat f[][3], GLfloat m[],
+ const GLvector3f *normal,
+ const GLvector4f *eye )
+{
+ GLuint stride = eye->stride;
+ GLfloat *coord = (GLfloat *)eye->start;
+ GLuint count = eye->count;
+ const GLfloat *norm = normal->start;
+ GLuint i;
+
+
+ /* KW: Had to rearrange this loop to avoid a compiler bug with gcc
+ * 2.7.3.1 at -O3 optimization. Using -fno-strength-reduce
+ * also fixed the bug - is this generally necessary?
+ */
+ for (i=0;i<count;i++,STRIDE_F(coord,stride)) {
+ GLfloat u[3], two_nu, fx, fy, fz;
+ COPY_3V( u, coord );
+ NORMALIZE_3FV( u );
+ two_nu = 2.0F * DOT3(norm,u);
+ fx = f[i][0] = u[0] - norm[0] * two_nu;
+ fy = f[i][1] = u[1] - norm[1] * two_nu;
+ fz = f[i][2] = u[2] - norm[2] * two_nu;
+ m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F);
+ if (m[i] != 0.0F) {
+ m[i] = 0.5F / (GLfloat) GL_SQRT(m[i]);
+ }
+
+ STRIDE_F(norm, normal->stride);
+ }
+}
+
+
+
+static void build_m2(GLfloat f[][3], GLfloat m[],
+ const GLvector3f *normal,
+ const GLvector4f *eye )
+{
+ GLuint stride = eye->stride;
+ GLfloat *coord = eye->start;
+ GLuint count = eye->count;
+
+ GLfloat *norm = normal->start;
+ GLuint i;
+
+ for (i=0;i<count;i++,STRIDE_F(coord,stride)) {
+
+ GLfloat u[3], two_nu, fx, fy, fz;
+ COPY_2V( u, coord );
+ u[2] = 0;
+ NORMALIZE_3FV( u );
+ two_nu = 2.0F * DOT3(norm,u);
+ fx = f[i][0] = u[0] - norm[0] * two_nu;
+ fy = f[i][1] = u[1] - norm[1] * two_nu;
+ fz = f[i][2] = u[2] - norm[2] * two_nu;
+ m[i] = fx * fx + fy * fy + (fz + 1.0F) * (fz + 1.0F);
+ if (m[i] != 0.0F) {
+ m[i] = 0.5F / (GLfloat) GL_SQRT(m[i]);
+ }
+
+ STRIDE_F(norm, normal->stride);
+ }
+}
+
+
+
+typedef void (*build_m_func)(GLfloat f[][3],
+ GLfloat m[],
+ const GLvector3f *normal,
+ const GLvector4f *eye );
+
+
+
+static build_m_func build_m_tab[5] = {
+ 0,
+ 0,
+ build_m2,
+ build_m3,
+ build_m3
+};
+
+
+/* This is unusual in that we respect the stride of the output vector
+ * (f). This allows us to pass in either a texcoord vector4f, or a
+ * temporary vector3f.
+ */
+static void build_f3( GLfloat *f,
+ GLuint fstride,
+ const GLvector3f *normal,
+ const GLvector4f *eye )
+{
+ GLuint stride = eye->stride;
+ GLfloat *coord = eye->start;
+ GLuint count = eye->count;
+
+ GLfloat *norm = normal->start;
+ GLuint i;
+
+ for (i=0;i<count;i++) {
+ GLfloat u[3], two_nu;
+ COPY_3V( u, coord );
+ NORMALIZE_3FV( u );
+ two_nu = 2.0F * DOT3(norm,u);
+ f[0] = u[0] - norm[0] * two_nu;
+ f[1] = u[1] - norm[1] * two_nu;
+ f[2] = u[2] - norm[2] * two_nu;
+ STRIDE_F(coord,stride);
+ STRIDE_F(f,fstride);
+ STRIDE_F(norm, normal->stride);
+ }
+}
+
+
+static void build_f2( GLfloat *f,
+ GLuint fstride,
+ const GLvector3f *normal,
+ const GLvector4f *eye )
+{
+ GLuint stride = eye->stride;
+ GLfloat *coord = eye->start;
+ GLuint count = eye->count;
+ GLfloat *norm = normal->start;
+ GLuint i;
+
+ for (i=0;i<count;i++) {
+
+ GLfloat u[3], two_nu;
+ COPY_2V( u, coord );
+ u[2] = 0;
+ NORMALIZE_3FV( u );
+ two_nu = 2.0F * DOT3(norm,u);
+ f[0] = u[0] - norm[0] * two_nu;
+ f[1] = u[1] - norm[1] * two_nu;
+ f[2] = u[2] - norm[2] * two_nu;
+
+ STRIDE_F(coord,stride);
+ STRIDE_F(f,fstride);
+ STRIDE_F(norm, normal->stride);
+ }
+}
+
+typedef void (*build_f_func)( GLfloat *f,
+ GLuint fstride,
+ const GLvector3f *normal_vec,
+ const GLvector4f *eye );
+
+
+
+/* Just treat 4-vectors as 3-vectors.
+ */
+static build_f_func build_f_tab[5] = {
+ 0,
+ 0,
+ build_f2,
+ build_f3,
+ build_f3
+};
+
+
+/* Special case texgen functions.
+ */
+static void texgen_reflection_map_nv( GLcontext *ctx,
+ struct texgen_stage_data *store,
+ GLuint unit )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLvector4f *in = VB->TexCoordPtr[unit];
+ GLvector4f *out = &store->texcoord[unit];
+
+ build_f_tab[VB->EyePtr->size]( out->start,
+ out->stride,
+ VB->NormalPtr,
+ VB->EyePtr );
+
+ if (in) {
+ out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3;
+ out->count = in->count;
+ out->size = MAX2(in->size, 3);
+ if (in->size == 4)
+ gl_copy_tab[0][0x8](out, in, 0);
+ }
+ else {
+ out->flags |= VEC_SIZE_3;
+ out->size = 3;
+ out->count = in->count;
+ }
+
+}
+
+
+
+static void texgen_normal_map_nv( GLcontext *ctx,
+ struct texgen_stage_data *store,
+ GLuint unit )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLvector4f *in = VB->TexCoordPtr[unit];
+ GLvector4f *out = &store->texcoord[unit];
+ GLvector3f *normal = VB->NormalPtr;
+ GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->start;
+ GLuint count = VB->Count;
+ GLuint i;
+ const GLfloat *norm = normal->start;
+
+ for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) {
+ texcoord[i][0] = norm[0];
+ texcoord[i][1] = norm[1];
+ texcoord[i][2] = norm[2];
+ }
+
+
+ if (in) {
+ out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_3;
+ out->count = in->count;
+ out->size = MAX2(in->size, 3);
+ if (in->size == 4)
+ gl_copy_tab[0][0x8](out, in, 0);
+ }
+ else {
+ out->flags |= VEC_SIZE_3;
+ out->size = 3;
+ out->count = in->count;
+ }
+}
+
+
+static void texgen_sphere_map( GLcontext *ctx,
+ struct texgen_stage_data *store,
+ GLuint unit )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLvector4f *in = VB->TexCoordPtr[unit];
+ GLvector4f *out = &store->texcoord[unit];
+ GLfloat (*texcoord)[4] = (GLfloat (*)[4]) out->start;
+ GLuint count = VB->Count;
+ GLuint i;
+ GLfloat (*f)[3] = store->tmp_f;
+ GLfloat *m = store->tmp_m;
+
+ (build_m_tab[VB->EyePtr->size])( store->tmp_f,
+ store->tmp_m,
+ VB->NormalPtr,
+ VB->EyePtr );
+
+ for (i=0;i<count;i++) {
+ texcoord[i][0] = f[i][0] * m[i] + 0.5F;
+ texcoord[i][1] = f[i][1] * m[i] + 0.5F;
+ }
+
+ if (in) {
+ out->size = MAX2(in->size,2);
+ out->count = in->count;
+ out->flags |= (in->flags & VEC_SIZE_FLAGS) | VEC_SIZE_2;
+ if (in->size > 2)
+ gl_copy_tab[0][all_bits[in->size] & ~0x3](out, in, 0);
+ } else {
+ out->size = 2;
+ out->flags |= VEC_SIZE_2;
+ out->count = in->count;
+ }
+}
+
+
+
+static void texgen( GLcontext *ctx,
+ struct texgen_stage_data *store,
+ GLuint unit )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLvector4f *in = VB->TexCoordPtr[unit];
+ GLvector4f *out = &store->texcoord[unit];
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ const GLvector4f *obj = VB->ObjPtr;
+ const GLvector4f *eye = VB->EyePtr;
+ const GLvector3f *normal = VB->NormalPtr;
+ GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data;
+ GLfloat *indata;
+ GLuint count = VB->Count;
+ GLfloat (*f)[3] = store->tmp_f;
+ GLfloat *m = store->tmp_m;
+
+
+ if (texUnit->_GenFlags & TEXGEN_NEED_M) {
+ build_m_tab[in->size]( store->tmp_f, store->tmp_m, normal, eye );
+ } else if (texUnit->_GenFlags & TEXGEN_NEED_F) {
+ build_f_tab[in->size]( (GLfloat *)store->tmp_f, 3, normal, eye );
+ }
+
+ if (in != out) {
+ GLuint copy = (all_bits[in->size] & ~texUnit->TexGenEnabled);
+ if (copy)
+ gl_copy_tab[0][copy](out, in, 0);
+ }
+
+ if (store->TexgenHoles[unit])
+ {
+ GLuint holes = (~all_bits[in->size] & store->TexgenHoles[unit]);
+ if (holes) {
+ if (holes & VEC_DIRTY_2) gl_vector4f_clean_elem(out, count, 2);
+ if (holes & VEC_DIRTY_1) gl_vector4f_clean_elem(out, count, 1);
+ if (holes & VEC_DIRTY_0) gl_vector4f_clean_elem(out, count, 0);
+ }
+ }
+
+ out->size = MAX2(in->size, store->TexgenSize[unit]);
+ out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled;
+ out->count = in->count;
+
+ if (texUnit->TexGenEnabled & S_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeS) {
+ case GL_OBJECT_LINEAR:
+ (gl_dotprod_tab[0][obj->size])((GLfloat *)out->data,
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneS, 0);
+ break;
+ case GL_EYE_LINEAR:
+ (gl_dotprod_tab[0][eye->size])((GLfloat *)out->data,
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneS, 0);
+ break;
+ case GL_SPHERE_MAP:
+ for (indata=in->start,i=0 ; i<count ; i++, STRIDE_F(indata,in->stride))
+ texcoord[i][0] = indata[0] * m[i] + 0.5F;
+ break;
+ case GL_REFLECTION_MAP_NV:
+ for (i=0;i<count;i++)
+ texcoord[i][0] = f[i][0];
+ break;
+ case GL_NORMAL_MAP_NV: {
+ const GLfloat *norm = normal->start;
+ for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) {
+ texcoord[i][0] = norm[0];
+ }
+ break;
+ }
+ default:
+ gl_problem(ctx, "Bad S texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & T_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeT) {
+ case GL_OBJECT_LINEAR:
+ (gl_dotprod_tab[0][obj->size])(&(out->data[0][1]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneT, 0);
+ break;
+ case GL_EYE_LINEAR:
+ (gl_dotprod_tab[0][eye->size])(&(out->data[0][1]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneT, 0);
+ break;
+ case GL_SPHERE_MAP:
+ for (indata=in->start,i=0; i<count ;i++,STRIDE_F(indata,in->stride))
+ texcoord[i][1] = indata[1] * m[i] + 0.5F;
+ break;
+ case GL_REFLECTION_MAP_NV:
+ for (i=0;i<count;i++)
+ texcoord[i][0] = f[i][0];
+ break;
+ case GL_NORMAL_MAP_NV: {
+ const GLfloat *norm = normal->start;
+ for (i=0;i<count;i++, STRIDE_F(norm, normal->stride)) {
+ texcoord[i][1] = norm[1];
+ }
+ break;
+ }
+ default:
+ gl_problem(ctx, "Bad T texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & R_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeR) {
+ case GL_OBJECT_LINEAR:
+ (gl_dotprod_tab[0][obj->size])(&(out->data[0][2]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneR, 0);
+ break;
+ case GL_EYE_LINEAR:
+ (gl_dotprod_tab[0][eye->size])(&(out->data[0][2]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneR, 0);
+ break;
+ case GL_REFLECTION_MAP_NV:
+ for (i=0;i<count;i++)
+ texcoord[i][2] = f[i][2];
+ break;
+ case GL_NORMAL_MAP_NV: {
+ const GLfloat *norm = normal->start;
+ for (i=0;i<count;i++,STRIDE_F(norm, normal->stride)) {
+ texcoord[i][2] = norm[2];
+ }
+ break;
+ }
+ default:
+ gl_problem(ctx, "Bad R texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & Q_BIT) {
+ switch (texUnit->GenModeQ) {
+ case GL_OBJECT_LINEAR:
+ (gl_dotprod_tab[0][obj->size])(&(out->data[0][3]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneQ, 0);
+ break;
+ case GL_EYE_LINEAR:
+ (gl_dotprod_tab[0][eye->size])(&(out->data[0][3]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneQ, 0);
+ break;
+ default:
+ gl_problem(ctx, "Bad Q texgen");
+ }
+ }
+}
+
+
+
+static GLboolean run_texgen_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texgen_stage_data *store = TEXGEN_STAGE_DATA( stage );
+ GLuint i;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if (ctx->_Enabled & ENABLE_TEXGEN(i)) {
+ if (stage->changed_inputs & (VERT_EYE | VERT_NORM | VERT_TEX(i)))
+ store->TexgenFunc[i]( ctx, store, i );
+
+ VB->TexCoordPtr[i] = &store->texcoord[i];
+ }
+
+ return GL_TRUE;
+}
+
+
+
+
+static GLboolean run_validate_texgen_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
+ GLuint i;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+
+ if (texUnit->TexGenEnabled) {
+ GLuint sz;
+
+ if (texUnit->TexGenEnabled & R_BIT)
+ sz = 4;
+ else if (texUnit->TexGenEnabled & Q_BIT)
+ sz = 3;
+ else if (texUnit->TexGenEnabled & T_BIT)
+ sz = 2;
+ else
+ sz = 1;
+
+ store->TexgenSize[i] = sz;
+ store->TexgenHoles[i] = (all_bits[sz] & ~texUnit->TexGenEnabled);
+ store->TexgenFunc[i] = texgen;
+
+ if (texUnit->TexGenEnabled == (S_BIT|T_BIT|R_BIT)) {
+ if (texUnit->_GenFlags == TEXGEN_REFLECTION_MAP_NV) {
+ store->TexgenFunc[i] = texgen_reflection_map_nv;
+ }
+ else if (texUnit->_GenFlags == TEXGEN_NORMAL_MAP_NV) {
+ store->TexgenFunc[i] = texgen_normal_map_nv;
+ }
+ }
+ else if (texUnit->TexGenEnabled == (S_BIT|T_BIT) &&
+ texUnit->_GenFlags == TEXGEN_SPHERE_MAP) {
+ store->TexgenFunc[i] = texgen_sphere_map;
+ }
+ }
+ }
+
+ stage->run = run_texgen_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void check_texgen( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ GLuint i;
+ stage->active = 0;
+
+ if (ctx->_Enabled & ENABLE_TEXGEN_ANY) {
+ GLuint inputs = 0;
+ GLuint outputs = 0;
+
+ if (ctx->Texture._GenFlags & TEXGEN_NEED_VERTICES)
+ inputs |= VERT_EYE;
+
+ if (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS)
+ inputs |= VERT_NORM;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if (ctx->_Enabled & ENABLE_TEXGEN(i))
+ {
+ outputs |= VERT_TEX(i);
+
+ /* Need the original input in case it contains a Q coord:
+ * (sigh)
+ */
+ if ((ctx->Texture.Unit[i]._ReallyEnabled|Q_BIT) &
+ ~ctx->Texture.Unit[i].TexGenEnabled)
+ inputs |= VERT_TEX(i);
+
+ /* Something for Feedback? */
+ }
+
+ if (stage->private)
+ stage->run = run_validate_texgen_stage;
+ stage->active = 1;
+ stage->inputs = inputs;
+ stage->outputs = outputs;
+ }
+}
+
+
+
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean alloc_texgen_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texgen_stage_data *store;
+ GLuint i;
+
+ stage->private = CALLOC(sizeof(*store));
+ store = TEXGEN_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ gl_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
+
+ store->tmp_f = (GLfloat (*)[3]) MALLOC(VB->Size * sizeof(GLfloat) * 3);
+ store->tmp_m = (GLfloat *) MALLOC(VB->Size * sizeof(GLfloat));
+
+ /* Now validate and run the stage.
+ */
+ stage->run = run_validate_texgen_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void free_texgen_data( struct gl_pipeline_stage *stage )
+
+{
+ struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+ if (store->texcoord[i].data)
+ gl_vector4f_free( &store->texcoord[i] );
+
+
+ if (store->tmp_f) FREE( store->tmp_f );
+ if (store->tmp_m) FREE( store->tmp_m );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+
+
+const struct gl_pipeline_stage _tnl_texgen_stage =
+{
+ "texgen",
+ _NEW_TEXTURE, /* when to call check() */
+ _NEW_TEXTURE, /* when to invalidate stored data */
+ 0,0,0, /* active, inputs, outputs */
+ 0,0, /* changed_inputs, private */
+ free_texgen_data, /* destructor */
+ check_texgen, /* check */
+ alloc_texgen_data /* run -- initially set to alloc data */
+};
+
+
diff --git a/src/mesa/tnl/t_vb_texmat.c b/src/mesa/tnl/t_vb_texmat.c
new file mode 100644
index 0000000000..ea415a550e
--- /dev/null
+++ b/src/mesa/tnl/t_vb_texmat.c
@@ -0,0 +1,148 @@
+/* $Id: t_vb_texmat.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+/* Is there any real benefit seperating texmat from texgen? It means
+ * we need two lots of intermediate storage. Any changes to
+ * _NEW_TEXTURE will invalidate both sets -- it's only on changes to
+ * *only* _NEW_TEXTURE_MATRIX that texgen survives but texmat doesn't.
+ *
+ * However, the seperation of this code from the complex texgen stuff
+ * is very appealing.
+ */
+struct texmat_stage_data {
+ GLvector4f texcoord[MAX_TEXTURE_UNITS];
+};
+
+#define TEXMAT_STAGE_DATA(stage) ((struct texmat_stage_data *)stage->private)
+
+static void check_texmat( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ GLuint i;
+ stage->active = 0;
+
+ if (ctx->_Enabled & ENABLE_TEXMAT_ANY) {
+ GLuint flags = 0;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if (ctx->_Enabled & ENABLE_TEXMAT(i))
+ flags |= VERT_TEX(i);
+
+ stage->active = 1;
+ stage->inputs = flags;
+ stage->outputs = flags;
+ }
+}
+
+static GLboolean run_texmat_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ GLuint i;
+
+ /* ENABLE_TEXMAT implies that the texture matrix is not the
+ * identity, so we don't have to check that here.
+ */
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ if (ctx->_Enabled & ENABLE_TEXMAT(i)) {
+ if (stage->changed_inputs & VERT_TEX(i))
+ (void) TransformRaw( &store->texcoord[i], &ctx->TextureMatrix[i],
+ VB->TexCoordPtr[i]);
+
+ VB->TexCoordPtr[i] = &store->texcoord[i];
+ }
+ return GL_TRUE;
+}
+
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean alloc_texmat_data( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texmat_stage_data *store;
+ GLuint i;
+
+ stage->private = CALLOC(sizeof(*store));
+ store = TEXMAT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++)
+ gl_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 );
+
+ /* Now run the stage.
+ */
+ stage->run = run_texmat_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void free_texmat_data( struct gl_pipeline_stage *stage )
+{
+ struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++)
+ if (store->texcoord[i].data)
+ gl_vector4f_free( &store->texcoord[i] );
+ FREE( store );
+ stage->private = 0;
+ }
+}
+
+
+
+const struct gl_pipeline_stage _tnl_texture_transform_stage =
+{
+ "texture transform",
+ _NEW_TEXTURE|_NEW_TEXTURE_MATRIX,
+ _NEW_TEXTURE|_NEW_TEXTURE_MATRIX,
+ 0,0,0, /* active, inputs, outputs */
+ 0,0, /* changed_inputs, private */
+ free_texmat_data, /* destructor */
+ check_texmat, /* check */
+ alloc_texmat_data, /* run -- initially set to init */
+};
diff --git a/src/mesa/tnl/t_vb_vertex.c b/src/mesa/tnl/t_vb_vertex.c
new file mode 100644
index 0000000000..7667d423a8
--- /dev/null
+++ b/src/mesa/tnl/t_vb_vertex.c
@@ -0,0 +1,311 @@
+/* $Id: t_vb_vertex.c,v 1.1 2000/12/26 05:09:33 keithw Exp $ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Author:
+ * Keith Whitwell <keithw@valinux.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "mem.h"
+#include "mmath.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+
+struct vertex_stage_data {
+ GLvector4f eye;
+ GLvector4f clip;
+ GLvector4f proj;
+ GLubyte *clipmask;
+ GLubyte ormask;
+ GLubyte andmask;
+
+
+ /* Need these because it's difficult to replay the sideeffects
+ * analytically.
+ */
+ GLvector4f *save_eyeptr;
+ GLvector4f *save_clipptr;
+ GLvector4f *save_projptr;
+};
+
+#define VERTEX_STAGE_DATA(stage) ((struct vertex_stage_data *)stage->private)
+
+
+
+
+/* This function implements cliptesting for user-defined clip planes.
+ * The clipping of primitives to these planes is implemented in
+ * t_render_clip.h.
+ */
+#define USER_CLIPTEST(NAME, SZ) \
+static void NAME( GLcontext *ctx, \
+ GLvector4f *clip, \
+ GLubyte *clipmask, \
+ GLubyte *clipormask, \
+ GLubyte *clipandmask ) \
+{ \
+ GLuint p; \
+ \
+ for (p = 0; p < ctx->Const.MaxClipPlanes; p++) \
+ if (ctx->Transform.ClipEnabled[p]) { \
+ GLuint nr, i; \
+ const GLfloat a = ctx->Transform._ClipUserPlane[p][0]; \
+ const GLfloat b = ctx->Transform._ClipUserPlane[p][1]; \
+ const GLfloat c = ctx->Transform._ClipUserPlane[p][2]; \
+ const GLfloat d = ctx->Transform._ClipUserPlane[p][3]; \
+ GLfloat *coord = (GLfloat *)clip->data; \
+ GLuint stride = clip->stride; \
+ GLuint count = clip->count; \
+ \
+ for (nr = 0, i = 0 ; i < count ; i++) { \
+ GLfloat dp = coord[0] * a + coord[1] * b; \
+ if (SZ > 2) dp += coord[2] * c; \
+ if (SZ > 3) dp += coord[3] * d; else dp += d; \
+ \
+ if (dp < 0) { \
+ nr++; \
+ clipmask[i] |= CLIP_USER_BIT; \
+ } \
+ \
+ STRIDE_F(coord, stride); \
+ } \
+ \
+ if (nr > 0) { \
+ *clipormask |= CLIP_USER_BIT; \
+ if (nr == count) { \
+ *clipandmask |= CLIP_USER_BIT; \
+ return; \
+ } \
+ } \
+ } \
+}
+
+
+USER_CLIPTEST(userclip2, 2)
+USER_CLIPTEST(userclip3, 3)
+USER_CLIPTEST(userclip4, 4)
+
+static void (*(usercliptab[5]))( GLcontext *,
+ GLvector4f *, GLubyte *,
+ GLubyte *, GLubyte * ) =
+{
+ 0,
+ 0,
+ userclip2,
+ userclip3,
+ userclip4
+};
+
+
+
+static GLboolean run_vertex_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_stage_data *store = (struct vertex_stage_data *)stage->private;
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ if (stage->changed_inputs)
+ {
+/* VB->ObjPtr->size = 4; */
+
+ if (ctx->_NeedEyeCoords) {
+ /* Seperate modelview and project transformations:
+ */
+ if (ctx->ModelView.type == MATRIX_IDENTITY)
+ VB->EyePtr = VB->ObjPtr;
+ else
+ VB->EyePtr = TransformRaw( &store->eye, &ctx->ModelView,
+ VB->ObjPtr);
+
+ if (ctx->ProjectionMatrix.type == MATRIX_IDENTITY)
+ VB->ClipPtr = VB->EyePtr;
+ else
+ VB->ClipPtr = TransformRaw( &store->clip, &ctx->ProjectionMatrix,
+ VB->EyePtr );
+ }
+ else
+ {
+ /* Combined modelviewproject transform:
+ */
+ if (ctx->_ModelProjectMatrix.type == MATRIX_IDENTITY)
+ VB->ClipPtr = VB->ObjPtr;
+ else
+ VB->ClipPtr = TransformRaw( &store->clip, &ctx->_ModelProjectMatrix,
+ VB->ObjPtr );
+ }
+
+ /* Cliptest and perspective divide. Clip functions must clear
+ * the clipmask.
+ */
+ store->ormask = 0;
+ store->andmask = CLIP_ALL_BITS;
+
+ VB->ProjectedClipPtr =
+ gl_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
+ &store->proj,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+
+ if (store->andmask)
+ return GL_FALSE;
+
+
+ /* Test userclip planes. This contributes to VB->ClipMask, so
+ * is essentially required to be in this stage.
+ */
+ if (ctx->Transform._AnyClip) {
+ usercliptab[VB->ClipPtr->size]( ctx,
+ VB->ClipPtr,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+
+ if (store->andmask)
+ return GL_FALSE;
+ }
+
+ VB->ClipOrMask = store->ormask;
+ VB->ClipMask = store->clipmask;
+
+ if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_OBJ))
+ VB->importable_data |= VERT_CLIP;
+
+ /* Drivers expect this to be size 4...
+ */
+ if (VB->ProjectedClipPtr->size < 4) {
+ ASSERT(VB->ProjectedClipPtr == VB->ClipPtr);
+ if (VB->ProjectedClipPtr->flags & VEC_NOT_WRITEABLE) {
+ ASSERT(VB->ProjectedClipPtr == VB->ObjPtr);
+ VB->import_data( ctx, VERT_OBJ, VEC_NOT_WRITEABLE );
+ VB->ProjectedClipPtr = VB->ClipPtr = VB->ObjPtr;
+ }
+ if (VB->ClipPtr->size == 2)
+ gl_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
+ gl_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
+ VB->ClipPtr->size = 4;
+ }
+
+ store->save_eyeptr = VB->EyePtr;
+ store->save_clipptr = VB->ClipPtr;
+ store->save_projptr = VB->ProjectedClipPtr;
+ }
+ else {
+ /* Replay the sideeffects.
+ */
+ VB->EyePtr = store->save_eyeptr;
+ VB->ClipPtr = store->save_clipptr;
+ VB->ProjectedClipPtr = store->save_projptr;
+ VB->ClipMask = store->clipmask;
+ VB->ClipOrMask = store->ormask;
+ if (VB->ClipPtr == VB->ObjPtr && (VB->importable_data & VERT_OBJ))
+ VB->importable_data |= VERT_CLIP;
+ if (store->andmask)
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+static void check_vertex( GLcontext *ctx, struct gl_pipeline_stage *stage )
+{
+ (void) ctx;
+ (void) stage;
+}
+
+static GLboolean init_vertex_stage( GLcontext *ctx,
+ struct gl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct vertex_stage_data *store;
+ GLuint size = VB->Size;
+
+ stage->private = CALLOC(sizeof(*store));
+ store = VERTEX_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ gl_vector4f_alloc( &store->eye, 0, size, 32 );
+ gl_vector4f_alloc( &store->clip, 0, size, 32 );
+ gl_vector4f_alloc( &store->proj, 0, size, 32 );
+
+ store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
+
+ if (!store->clipmask ||
+ !store->eye.data ||
+ !store->clip.data ||
+ !store->proj.data)
+ return GL_FALSE;
+
+ /* Now run the stage.
+ */
+ stage->run = run_vertex_stage;
+ return stage->run( ctx, stage );
+}
+
+static void dtr( struct gl_pipeline_stage *stage )
+{
+ struct vertex_stage_data *store = VERTEX_STAGE_DATA(stage);
+
+ if (store) {
+ gl_vector4f_free( &store->eye );
+ gl_vector4f_free( &store->clip );
+ gl_vector4f_free( &store->proj );
+ ALIGN_FREE( store->clipmask );
+ FREE(store);
+ stage->private = 0;
+ stage->run = init_vertex_stage;
+ }
+}
+
+
+const struct gl_pipeline_stage _tnl_vertex_transform_stage =
+{
+ "modelview/project/cliptest/divide",
+ 0, /* re-check -- always on */
+ _NEW_MODELVIEW|
+ _NEW_PROJECTION|
+ _NEW_TRANSFORM, /* re-run */
+ GL_TRUE, /* active */
+ VERT_OBJ, /* inputs */
+ VERT_EYE|VERT_CLIP, /* outputs */
+ 0, 0, /* changed_inputs, private */
+ dtr, /* destructor */
+ check_vertex, /* check */
+ init_vertex_stage /* run -- initially set to init */
+};
+
+
diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h
index c14ed296ad..f95ce0e503 100644
--- a/src/mesa/tnl/tnl.h
+++ b/src/mesa/tnl/tnl.h
@@ -32,8 +32,9 @@
-/* These are the public-access functions exported from tnl. (Many
- * more are currently hooked into dispatch directly by core code.)
+/* These are the public-access functions exported from tnl. (A few
+ * more are currently hooked into dispatch directly by the module
+ * itself.)
*/
extern GLboolean
_tnl_CreateContext( GLcontext *ctx );
@@ -59,4 +60,16 @@ extern void
_tnl_wakeup_save_exec( GLcontext *ctx );
+/* Functions to assist driver t&l modules which have to fallback to
+ * this module in the middle of a begin/end pair. Use this instead of
+ * glBegin() to identify the primitive as wrapped:
+ *
+ * Even with this it's difficult to see how the drivers are going to
+ * replay any glMaterial commands received in the few vertices before
+ * the fallback.
+ */
+extern void
+_tnl_fallback_begin( GLcontext *ctx, GLenum mode );
+
+
#endif