aboutsummaryrefslogtreecommitdiff
path: root/src/mesa/tnl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/descrip.mms69
-rw-r--r--src/mesa/tnl/t_array_api.c442
-rw-r--r--src/mesa/tnl/t_array_api.h46
-rw-r--r--src/mesa/tnl/t_array_import.c361
-rw-r--r--src/mesa/tnl/t_array_import.h36
-rw-r--r--src/mesa/tnl/t_context.c290
-rw-r--r--src/mesa/tnl/t_context.h811
-rw-r--r--src/mesa/tnl/t_pipeline.c216
-rw-r--r--src/mesa/tnl/t_pipeline.h76
-rw-r--r--src/mesa/tnl/t_save_api.c1617
-rw-r--r--src/mesa/tnl/t_save_api.h58
-rw-r--r--src/mesa/tnl/t_save_loopback.c307
-rw-r--r--src/mesa/tnl/t_save_playback.c224
-rw-r--r--src/mesa/tnl/t_vb_cliptmp.h270
-rw-r--r--src/mesa/tnl/t_vb_cull.c111
-rw-r--r--src/mesa/tnl/t_vb_fog.c278
-rw-r--r--src/mesa/tnl/t_vb_light.c368
-rw-r--r--src/mesa/tnl/t_vb_lighttmp.h821
-rw-r--r--src/mesa/tnl/t_vb_normals.c200
-rw-r--r--src/mesa/tnl/t_vb_points.c123
-rw-r--r--src/mesa/tnl/t_vb_program.c368
-rw-r--r--src/mesa/tnl/t_vb_render.c381
-rw-r--r--src/mesa/tnl/t_vb_rendertmp.h440
-rw-r--r--src/mesa/tnl/t_vb_texgen.c691
-rw-r--r--src/mesa/tnl/t_vb_texmat.c150
-rw-r--r--src/mesa/tnl/t_vb_vertex.c331
-rw-r--r--src/mesa/tnl/t_vertex.c1294
-rw-r--r--src/mesa/tnl/t_vertex.h150
-rw-r--r--src/mesa/tnl/t_vertex_c.c259
-rw-r--r--src/mesa/tnl/t_vertex_codegen.c510
-rw-r--r--src/mesa/tnl/t_vtx_api.c975
-rw-r--r--src/mesa/tnl/t_vtx_api.h90
-rw-r--r--src/mesa/tnl/t_vtx_eval.c253
-rw-r--r--src/mesa/tnl/t_vtx_exec.c289
-rw-r--r--src/mesa/tnl/t_vtx_generic.c468
-rw-r--r--src/mesa/tnl/t_vtx_x86.c384
-rw-r--r--src/mesa/tnl/t_vtx_x86_gcc.S557
-rw-r--r--src/mesa/tnl/tnl.dsp228
-rw-r--r--src/mesa/tnl/tnl.h87
39 files changed, 14629 insertions, 0 deletions
diff --git a/src/mesa/tnl/descrip.mms b/src/mesa/tnl/descrip.mms
new file mode 100644
index 0000000..c2e3540
--- /dev/null
+++ b/src/mesa/tnl/descrip.mms
@@ -0,0 +1,69 @@
+# Makefile for core library for VMS
+# contributed by Jouk Jansen joukj@hrem.stm.tudelft.nl
+# Last revision : 18 August 2004
+
+.first
+ define gl [---.include.gl]
+ define math [-.math]
+ define array_cache [-.array_cache]
+
+.include [---]mms-config.
+
+##### MACROS #####
+
+VPATH = RCS
+
+INCDIR = [---.include],[-.main],[-.glapi],[-.shader]
+LIBDIR = [---.lib]
+CFLAGS = /include=($(INCDIR),[])/define=(PTHREADS=1)/name=(as_is,short)
+
+SOURCES = t_array_api.c t_array_import.c t_context.c \
+ t_pipeline.c t_vb_fog.c t_save_api.c t_vtx_api.c \
+ t_vb_light.c t_vb_normals.c t_vb_points.c t_vb_program.c \
+ t_vb_render.c t_vb_texgen.c t_vb_texmat.c t_vb_vertex.c \
+ t_vtx_eval.c t_vtx_exec.c t_save_playback.c t_save_loopback.c \
+ t_vertex.c t_vtx_generic.c t_vtx_x86.c t_vertex_c.c;
+
+OBJECTS = t_array_api.obj,t_array_import.obj,t_context.obj,\
+ t_pipeline.obj,t_vb_fog.obj,t_vb_light.obj,t_vb_normals.obj,\
+ t_vb_points.obj,t_vb_program.obj,t_vb_render.obj,t_vb_texgen.obj,\
+ t_vb_texmat.obj,t_vb_vertex.obj,t_save_api.obj,t_vtx_api.obj,\
+ t_vtx_eval.obj,t_vtx_exec.obj,t_save_playback.obj,t_save_loopback.obj,\
+ t_vertex.obj,t_vtx_generic.obj,t_vtx_x86.obj,t_vertex_c.obj
+
+##### RULES #####
+
+VERSION=Mesa V3.4
+
+##### TARGETS #####
+# Make the library
+$(LIBDIR)$(GL_LIB) : $(OBJECTS)
+ @ library $(LIBDIR)$(GL_LIB) $(OBJECTS)
+
+clean :
+ purge
+ delete *.obj;*
+
+t_array_api.obj : t_array_api.c
+t_array_import.obj : t_array_import.c
+t_context.obj : t_context.c
+t_pipeline.obj : t_pipeline.c
+t_vb_fog.obj : t_vb_fog.c
+t_vb_light.obj : t_vb_light.c
+t_vb_normals.obj : t_vb_normals.c
+t_vb_points.obj : t_vb_points.c
+t_vb_program.obj : t_vb_program.c
+t_vb_render.obj : t_vb_render.c
+t_vb_texgen.obj : t_vb_texgen.c
+t_vb_texmat.obj : t_vb_texmat.c
+t_vb_vertex.obj : t_vb_vertex.c
+t_save_api.obj : t_save_api.c
+t_vtx_api.obj : t_vtx_api.c
+t_vtx_eval.obj : t_vtx_eval.c
+t_vtx_exec.obj : t_vtx_exec.c
+t_save_playback.obj : t_save_playback.c
+t_save_loopback.obj : t_save_loopback.c
+t_vertex.obj : t_vertex.c
+t_vtx_x86.obj : t_vtx_x86.c
+t_vtx_generic.obj : t_vtx_generic.c
+t_vertex_c.obj : t_vertex_c.c
diff --git a/src/mesa/tnl/t_array_api.c b/src/mesa/tnl/t_array_api.c
new file mode 100644
index 0000000..c3e6358
--- /dev/null
+++ b/src/mesa/tnl/t_array_api.c
@@ -0,0 +1,442 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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.
+ */
+
+/**
+ * \file t_array_api.c
+ * \brief Vertex array API functions (glDrawArrays, etc)
+ * \author Keith Whitwell
+ */
+
+#include "glheader.h"
+#include "api_validate.h"
+#include "context.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "state.h"
+
+#include "array_cache/acache.h"
+
+#include "t_array_api.h"
+#include "t_array_import.h"
+#include "t_save_api.h"
+#include "t_context.h"
+#include "t_pipeline.h"
+
+static void fallback_drawarrays( GLcontext *ctx, GLenum mode, GLint start,
+ GLsizei count )
+{
+ GLint i;
+
+ assert(!ctx->CompileFlag);
+ assert(ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1);
+
+ GL_CALL(Begin)(mode);
+ for (i = 0; i < count; i++)
+ GL_CALL(ArrayElement)( start + i );
+ GL_CALL(End)();
+}
+
+
+static void fallback_drawelements( GLcontext *ctx, GLenum mode, GLsizei count,
+ const GLuint *indices)
+{
+ GLint i;
+
+ assert(!ctx->CompileFlag);
+ assert(ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1);
+
+ /* Here, indices will already reflect the buffer object if active */
+
+ GL_CALL(Begin)(mode);
+ for (i = 0 ; i < count ; i++) {
+ GL_CALL(ArrayElement)( indices[i] );
+ }
+ GL_CALL(End)();
+}
+
+
+/* Note this function no longer takes a 'start' value, the range is
+ * assumed to start at zero. The old trick of subtracting 'start'
+ * from each index won't work if the indices are not in writeable
+ * memory.
+ */
+static void _tnl_draw_range_elements( GLcontext *ctx, GLenum mode,
+ GLuint max_index,
+ GLsizei index_count, GLuint *indices )
+
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_prim prim;
+ FLUSH_CURRENT( ctx, 0 );
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ _tnl_vb_bind_arrays( ctx, 0, max_index );
+
+ tnl->vb.Primitive = &prim;
+ tnl->vb.Primitive[0].mode = mode | PRIM_BEGIN | PRIM_END;
+ tnl->vb.Primitive[0].start = 0;
+ tnl->vb.Primitive[0].count = index_count;
+ tnl->vb.PrimitiveCount = 1;
+
+ tnl->vb.Elts = (GLuint *)indices;
+
+ if (ctx->Array.LockCount)
+ tnl->Driver.RunPipeline( ctx );
+ else {
+ /* The lower 16 bits represent the conventional arrays while the
+ * upper 16 bits represent the generic arrays. OR those bits
+ * together to indicate which vertex attribs are in effect.
+ */
+ GLuint enabledArrays = ctx->Array._Enabled | (ctx->Array._Enabled >> 16);
+ /* Note that arrays may have changed before/after execution.
+ */
+ tnl->pipeline.run_input_changes |= enabledArrays & 0xffff;
+ tnl->Driver.RunPipeline( ctx );
+ tnl->pipeline.run_input_changes |= enabledArrays & 0xffff;
+ }
+}
+
+
+
+/**
+ * Called via the GL API dispatcher.
+ */
+void GLAPIENTRY
+_tnl_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint thresh = (ctx->Driver.NeedFlush & FLUSH_STORED_VERTICES) ? 30 : 10;
+ GLuint enabledArrays;
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(NULL, "_tnl_DrawArrays %d %d\n", start, count);
+
+ /* Check arguments, etc.
+ */
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ assert(!ctx->CompileFlag);
+
+ if (!ctx->Array.LockCount && (GLuint) count < thresh) {
+ /* Small primitives: attempt to share a vb (at the expense of
+ * using the immediate interface).
+ */
+ fallback_drawarrays( ctx, mode, start, count );
+ }
+ else if (start >= (GLint) ctx->Array.LockFirst &&
+ start + count <= (GLint)(ctx->Array.LockFirst + ctx->Array.LockCount)) {
+
+ struct tnl_prim prim;
+
+ /* Locked primitives which can fit in a single vertex buffer:
+ */
+ FLUSH_CURRENT( ctx, 0 );
+
+ /* Locked drawarrays. Reuse any previously transformed data.
+ */
+ _tnl_vb_bind_arrays( ctx, ctx->Array.LockFirst,
+ ctx->Array.LockFirst + ctx->Array.LockCount );
+
+ tnl->vb.Primitive = &prim;
+ tnl->vb.Primitive[0].mode = mode | PRIM_BEGIN | PRIM_END;
+ tnl->vb.Primitive[0].start = start;
+ tnl->vb.Primitive[0].count = count;
+ tnl->vb.PrimitiveCount = 1;
+
+ tnl->Driver.RunPipeline( ctx );
+ }
+ else {
+ int bufsz = 256; /* Use a small buffer for cache goodness */
+ int j, nr;
+ int minimum, modulo, skip;
+
+ /* Large primitives requiring decomposition to multiple vertex
+ * buffers:
+ */
+ switch (mode) {
+ case GL_POINTS:
+ minimum = 0;
+ modulo = 1;
+ skip = 0;
+ break;
+ case GL_LINES:
+ minimum = 1;
+ modulo = 2;
+ skip = 1;
+ break;
+ case GL_LINE_STRIP:
+ minimum = 1;
+ modulo = 1;
+ skip = 0;
+ break;
+ case GL_TRIANGLES:
+ minimum = 2;
+ modulo = 3;
+ skip = 2;
+ break;
+ case GL_TRIANGLE_STRIP:
+ minimum = 2;
+ modulo = 1;
+ skip = 0;
+ break;
+ case GL_QUADS:
+ minimum = 3;
+ modulo = 4;
+ skip = 3;
+ break;
+ case GL_QUAD_STRIP:
+ minimum = 3;
+ modulo = 2;
+ skip = 0;
+ break;
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ default:
+ /* Primitives requiring a copied vertex (fan-like primitives)
+ * must use the slow path if they cannot fit in a single
+ * vertex buffer.
+ */
+ if (count <= (GLint) ctx->Const.MaxArrayLockSize) {
+ bufsz = ctx->Const.MaxArrayLockSize;
+ minimum = 0;
+ modulo = 1;
+ skip = 0;
+ }
+ else {
+ fallback_drawarrays( ctx, mode, start, count );
+ return;
+ }
+ }
+
+ FLUSH_CURRENT( ctx, 0 );
+
+ bufsz -= bufsz % modulo;
+ bufsz -= minimum;
+ count += start;
+
+ for (j = start + minimum ; j < count ; j += nr + skip ) {
+
+ struct tnl_prim prim;
+
+ nr = MIN2( bufsz, count - j );
+
+ /* XXX is the last parameter a count or index into the array??? */
+ _tnl_vb_bind_arrays( ctx, j - minimum, j + nr );
+
+ tnl->vb.Primitive = &prim;
+ tnl->vb.Primitive[0].mode = mode;
+
+ if (j == start + minimum)
+ tnl->vb.Primitive[0].mode |= PRIM_BEGIN;
+
+ if (j + nr + skip >= count)
+ tnl->vb.Primitive[0].mode |= PRIM_END;
+
+ tnl->vb.Primitive[0].start = 0;
+ tnl->vb.Primitive[0].count = nr + minimum;
+ tnl->vb.PrimitiveCount = 1;
+
+ /* The lower 16 bits represent the conventional arrays while the
+ * upper 16 bits represent the generic arrays. OR those bits
+ * together to indicate which vertex attribs are in effect.
+ */
+ enabledArrays = ctx->Array._Enabled | (ctx->Array._Enabled >> 16);
+ /* Note that arrays may have changed before/after execution.
+ */
+ tnl->pipeline.run_input_changes |= enabledArrays;
+ tnl->Driver.RunPipeline( ctx );
+ tnl->pipeline.run_input_changes |= enabledArrays;
+ }
+ }
+}
+
+
+/**
+ * Called via the GL API dispatcher.
+ */
+void GLAPIENTRY
+_tnl_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type, const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint *ui_indices;
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(NULL, "_tnl_DrawRangeElements %d %d %d\n", start, end, count);
+
+ if (ctx->Array.ElementArrayBufferObj->Name) {
+ /* use indices in the buffer object */
+ if (!ctx->Array.ElementArrayBufferObj->Data) {
+ _mesa_warning(ctx,
+ "DrawRangeElements with empty vertex elements buffer!");
+ return;
+ }
+ /* actual address is the sum of pointers */
+ indices = (const GLvoid *)
+ ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Data,
+ (const GLubyte *) indices);
+ }
+
+ /* Check arguments, etc.
+ */
+ if (!_mesa_validate_DrawRangeElements( ctx, mode, start, end, count,
+ type, indices ))
+ return;
+
+ ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
+ count, type, indices );
+
+
+ assert(!ctx->CompileFlag);
+
+ if (ctx->Array.LockCount) {
+ /* Are the arrays already locked? If so we currently have to look
+ * at the whole locked range.
+ */
+
+ if (start == 0 && ctx->Array.LockFirst == 0 &&
+ end < (ctx->Array.LockFirst + ctx->Array.LockCount))
+ _tnl_draw_range_elements( ctx, mode,
+ ctx->Array.LockCount,
+ count, ui_indices );
+ else {
+ fallback_drawelements( ctx, mode, count, ui_indices );
+ }
+ }
+ else if (start == 0 && end < ctx->Const.MaxArrayLockSize) {
+ /* The arrays aren't locked but we can still fit them inside a
+ * single vertexbuffer.
+ */
+ _tnl_draw_range_elements( ctx, mode, end + 1, count, ui_indices );
+ }
+ else {
+ /* Range is too big to optimize:
+ */
+ fallback_drawelements( ctx, mode, count, ui_indices );
+ }
+}
+
+
+
+/**
+ * Called via the GL API dispatcher.
+ */
+void GLAPIENTRY
+_tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint *ui_indices;
+
+ if (MESA_VERBOSE & VERBOSE_API)
+ _mesa_debug(NULL, "_tnl_DrawElements %d\n", count);
+
+ /* Check arguments, etc. */
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+ return;
+
+ if (ctx->Array.ElementArrayBufferObj->Name) {
+ /* actual address is the sum of pointers */
+ indices = (const GLvoid *)
+ ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Data,
+ (const GLubyte *) indices);
+ }
+
+ ui_indices = (GLuint *)_ac_import_elements( ctx, GL_UNSIGNED_INT,
+ count, type, indices );
+
+ assert(!ctx->CompileFlag);
+
+ if (ctx->Array.LockCount) {
+ if (ctx->Array.LockFirst == 0)
+ _tnl_draw_range_elements( ctx, mode,
+ ctx->Array.LockCount,
+ count, ui_indices );
+ else
+ fallback_drawelements( ctx, mode, count, ui_indices );
+ }
+ else {
+ /* Scan the index list and see if we can use the locked path anyway.
+ */
+ GLuint max_elt = 0;
+ GLint 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 < (GLuint) count) /* do we want to use it? */
+ _tnl_draw_range_elements( ctx, mode, max_elt+1, count, ui_indices );
+ else
+ fallback_drawelements( ctx, mode, count, ui_indices );
+ }
+}
+
+
+/**
+ * Initialize context's vertex array fields. Called during T 'n L context
+ * creation.
+ */
+void _tnl_array_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_arrays *tmp = &tnl->array_inputs;
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_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.
+ */
+ _mesa_vector4f_init( &tmp->Obj, 0, 0 );
+ _mesa_vector4f_init( &tmp->Normal, 0, 0 );
+ _mesa_vector4f_init( &tmp->FogCoord, 0, 0 );
+ _mesa_vector4f_init( &tmp->Index, 0, 0 );
+
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++)
+ _mesa_vector4f_init( &tmp->TexCoord[i], 0, 0);
+}
+
+
+/**
+ * Destroy the context's vertex array stuff.
+ * Called during T 'n L context destruction.
+ */
+void _tnl_array_destroy( GLcontext *ctx )
+{
+ (void) ctx;
+}
diff --git a/src/mesa/tnl/t_array_api.h b/src/mesa/tnl/t_array_api.h
new file mode 100644
index 0000000..61d1f69
--- /dev/null
+++ b/src/mesa/tnl/t_array_api.h
@@ -0,0 +1,46 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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 GLAPIENTRY _tnl_DrawArrays(GLenum mode, GLint first, GLsizei count);
+
+extern void GLAPIENTRY _tnl_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices);
+
+extern void GLAPIENTRY _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 0000000..dac6463
--- /dev/null
+++ b/src/mesa/tnl/t_array_import.c
@@ -0,0 +1,361 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.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 tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ const GLubyte *data;
+
+ tmp = _ac_import_vertex(ctx,
+ GL_FLOAT,
+ stride ? 4*sizeof(GLfloat) : 0,
+ 0,
+ writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->Obj.data = (GLfloat (*)[4]) data;
+ inputs->Obj.start = (GLfloat *) data;
+ inputs->Obj.stride = tmp->StrideB;
+ inputs->Obj.size = tmp->Size;
+}
+
+static void _tnl_import_normal( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ const GLubyte *data;
+
+ tmp = _ac_import_normal(ctx, GL_FLOAT,
+ stride ? 3*sizeof(GLfloat) : 0, writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->Normal.data = (GLfloat (*)[4]) data;
+ inputs->Normal.start = (GLfloat *) data;
+ inputs->Normal.stride = tmp->StrideB;
+ inputs->Normal.size = 3;
+}
+
+
+static void _tnl_import_color( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ const GLubyte *data;
+
+ tmp = _ac_import_color(ctx,
+ GL_FLOAT,
+ stride ? 4*sizeof(GLfloat) : 0,
+ 4,
+ writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->Color.data = (GLfloat (*)[4]) data;
+ inputs->Color.start = (GLfloat *) data;
+ inputs->Color.stride = tmp->StrideB;
+ inputs->Color.size = tmp->Size;
+}
+
+
+static void _tnl_import_secondarycolor( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ const GLubyte *data;
+
+ tmp = _ac_import_secondarycolor(ctx,
+ GL_FLOAT,
+ stride ? 4*sizeof(GLfloat) : 0,
+ 4,
+ writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->SecondaryColor.data = (GLfloat (*)[4]) data;
+ inputs->SecondaryColor.start = (GLfloat *) data;
+ inputs->SecondaryColor.stride = tmp->StrideB;
+ inputs->SecondaryColor.size = tmp->Size;
+}
+
+static void _tnl_import_fogcoord( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ const GLubyte *data;
+
+ tmp = _ac_import_fogcoord(ctx, GL_FLOAT,
+ stride ? sizeof(GLfloat) : 0, writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->FogCoord.data = (GLfloat (*)[4]) data;
+ inputs->FogCoord.start = (GLfloat *) data;
+ inputs->FogCoord.stride = tmp->StrideB;
+}
+
+static void _tnl_import_index( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ const GLubyte *data;
+
+ tmp = _ac_import_index(ctx, GL_FLOAT,
+ stride ? sizeof(GLfloat) : 0, writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->Index.data = (GLfloat (*)[4]) data;
+ inputs->Index.start = (GLfloat *) data;
+ inputs->Index.stride = tmp->StrideB;
+}
+
+
+static void _tnl_import_texcoord( GLcontext *ctx,
+ GLuint unit,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ const GLubyte *data;
+
+ tmp = _ac_import_texcoord(ctx, unit, GL_FLOAT,
+ stride ? 4 * sizeof(GLfloat) : 0,
+ 0,
+ writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->TexCoord[unit].data = (GLfloat (*)[4]) data;
+ inputs->TexCoord[unit].start = (GLfloat *) data;
+ inputs->TexCoord[unit].stride = tmp->StrideB;
+ inputs->TexCoord[unit].size = tmp->Size;
+}
+
+
+static void _tnl_import_edgeflag( GLcontext *ctx,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ const GLubyte *data;
+ (void) writeable; (void) stride;
+
+ tmp = _ac_import_edgeflag(ctx, GL_UNSIGNED_BYTE,
+ sizeof(GLubyte),
+ 0,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->EdgeFlag = (GLubyte *) data;
+}
+
+
+
+static void _tnl_import_attrib( GLcontext *ctx,
+ GLuint index,
+ GLboolean writeable,
+ GLboolean stride )
+{
+ struct tnl_vertex_arrays *inputs = &TNL_CONTEXT(ctx)->array_inputs;
+ struct gl_client_array *tmp;
+ GLboolean is_writeable = 0;
+ const GLubyte *data;
+
+ tmp = _ac_import_attrib(ctx, index, GL_FLOAT,
+ stride ? 4 * sizeof(GLfloat) : 0,
+ 4, /* want GLfloat[4] */
+ writeable,
+ &is_writeable);
+
+ data = tmp->Ptr;
+ inputs->Attribs[index].data = (GLfloat (*)[4]) data;
+ inputs->Attribs[index].start = (GLfloat *) data;
+ inputs->Attribs[index].stride = tmp->StrideB;
+ inputs->Attribs[index].size = tmp->Size;
+}
+
+
+
+
+void _tnl_vb_bind_arrays( GLcontext *ctx, GLint start, GLint end)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint inputs = tnl->pipeline.inputs;
+ struct tnl_vertex_arrays *tmp = &tnl->array_inputs;
+ GLuint i, index;
+
+ VB->Count = end - start;
+ VB->Elts = NULL;
+
+ _ac_import_range( ctx, start, end );
+
+ /* When vertex program mode is enabled, the generic vertex program
+ * attribute arrays have priority over the conventional attributes.
+ * Try to use them now.
+ */
+ for (index = 0; index < VERT_ATTRIB_MAX; index++) {
+ /* When vertex program mode is enabled, the generic vertex attribute
+ * arrays have priority over the conventional vertex arrays.
+ */
+ if (ctx->VertexProgram._Enabled
+ && ctx->Array.VertexAttrib[index].Enabled) {
+ /* Use generic attribute array */
+ _tnl_import_attrib( ctx, index, GL_FALSE, GL_TRUE );
+ VB->AttribPtr[index] = &tmp->Attribs[index];
+ }
+ /* use conventional arrays... */
+ else if (index == VERT_ATTRIB_POS) {
+ if (inputs & _TNL_BIT_POS) {
+ _tnl_import_vertex( ctx, 0, 0 );
+ tmp->Obj.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_POS] = &tmp->Obj;
+ }
+ }
+ else if (index == VERT_ATTRIB_NORMAL) {
+ if (inputs & _TNL_BIT_NORMAL) {
+ _tnl_import_normal( ctx, 0, 0 );
+ tmp->Normal.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_NORMAL] = &tmp->Normal;
+ }
+ }
+ else if (index == VERT_ATTRIB_COLOR0) {
+ if (inputs & _TNL_BIT_COLOR0) {
+ _tnl_import_color( ctx, 0, 0 );
+ tmp->Color.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_COLOR0] = &tmp->Color;
+ }
+ }
+ else if (index == VERT_ATTRIB_COLOR1) {
+ if (inputs & _TNL_BIT_COLOR1) {
+ _tnl_import_secondarycolor( ctx, 0, 0 );
+ tmp->SecondaryColor.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_COLOR1] = &tmp->SecondaryColor;
+ }
+ }
+ else if (index == VERT_ATTRIB_FOG) {
+ if (inputs & _TNL_BIT_FOG) {
+ _tnl_import_fogcoord( ctx, 0, 0 );
+ tmp->FogCoord.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_FOG] = &tmp->FogCoord;
+ }
+ }
+ else if (index >= VERT_ATTRIB_TEX0 && index <= VERT_ATTRIB_TEX7) {
+ if (inputs & _TNL_BITS_TEX_ANY) {
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ if (inputs & _TNL_BIT_TEX(i)) {
+ _tnl_import_texcoord( ctx, i, GL_FALSE, GL_FALSE );
+ tmp->TexCoord[i].count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_TEX0 + i] = &tmp->TexCoord[i];
+ }
+ }
+ }
+ }
+ }
+
+ /* odd-ball vertex attributes */
+ if (inputs & _TNL_BIT_INDEX) {
+ _tnl_import_index( ctx, 0, 0 );
+ tmp->Index.count = VB->Count;
+ VB->AttribPtr[_TNL_ATTRIB_INDEX] = &tmp->Index;
+ }
+
+ if (inputs & _TNL_BIT_EDGEFLAG) {
+ _tnl_import_edgeflag( ctx, GL_TRUE, sizeof(GLboolean) );
+ VB->EdgeFlag = (GLboolean *) tmp->EdgeFlag;
+ }
+
+ /* These are constant & can be precalculated:
+ */
+ if (inputs & _TNL_BITS_MAT_ANY) {
+ for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT; i < _TNL_ATTRIB_INDEX; i++) {
+ tmp->Attribs[i].count = VB->Count;
+ tmp->Attribs[i].data = (GLfloat (*)[4]) tnl->vtx.current[i];
+ tmp->Attribs[i].start = tnl->vtx.current[i];
+ tmp->Attribs[i].size = 4;
+ tmp->Attribs[i].stride = 0;
+ VB->AttribPtr[i] = &tmp->Attribs[i];
+ }
+ }
+
+
+ /* Legacy pointers -- remove one day.
+ */
+ VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
+ VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
+ VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
+ VB->ColorPtr[1] = 0;
+ VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_INDEX];
+ VB->IndexPtr[1] = 0;
+ VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1];
+ VB->SecondaryColorPtr[1] = 0;
+ VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG];
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i];
+ }
+
+}
diff --git a/src/mesa/tnl/t_array_import.h b/src/mesa/tnl/t_array_import.h
new file mode 100644
index 0000000..39b7764
--- /dev/null
+++ b/src/mesa/tnl/t_array_import.h
@@ -0,0 +1,36 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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, GLint end );
+
+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
new file mode 100644
index 0000000..e4d0d04
--- /dev/null
+++ b/src/mesa/tnl/t_context.c
@@ -0,0 +1,290 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "api_arrayelt.h"
+#include "glheader.h"
+#include "imports.h"
+#include "context.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "dlist.h"
+#include "light.h"
+#include "vtxfmt.h"
+#include "nvfragprog.h"
+
+#include "t_context.h"
+#include "t_array_api.h"
+#include "t_vtx_api.h"
+#include "t_save_api.h"
+#include "t_pipeline.h"
+#include "tnl.h"
+
+
+
+void
+_tnl_MakeCurrent( GLcontext *ctx,
+ GLframebuffer *drawBuffer,
+ GLframebuffer *readBuffer )
+{
+ (void) ctx; (void) drawBuffer; (void) readBuffer;
+}
+
+
+static void
+install_driver_callbacks( GLcontext *ctx )
+{
+ ctx->Driver.NewList = _tnl_NewList;
+ ctx->Driver.EndList = _tnl_EndList;
+ ctx->Driver.FlushVertices = _tnl_FlushVertices;
+ ctx->Driver.SaveFlushVertices = _tnl_SaveFlushVertices;
+ ctx->Driver.MakeCurrent = _tnl_MakeCurrent;
+ ctx->Driver.BeginCallList = _tnl_BeginCallList;
+ ctx->Driver.EndCallList = _tnl_EndCallList;
+}
+
+
+
+GLboolean
+_tnl_CreateContext( GLcontext *ctx )
+{
+ TNLcontext *tnl;
+
+ /* Create the TNLcontext structure
+ */
+ ctx->swtnl_context = tnl = (TNLcontext *) CALLOC( sizeof(TNLcontext) );
+
+ if (!tnl) {
+ return GL_FALSE;
+ }
+
+ if (getenv("MESA_CODEGEN"))
+ tnl->AllowCodegen = GL_TRUE;
+
+ /* Initialize the VB.
+ */
+ tnl->vb.Size = ctx->Const.MaxArrayLockSize + MAX_CLIPPED_VERTICES;
+
+
+ /* Initialize tnl state and tnl->vtxfmt.
+ */
+ _tnl_save_init( ctx );
+ _tnl_array_init( ctx );
+ _tnl_vtx_init( ctx );
+ _tnl_install_pipeline( ctx, _tnl_default_pipeline );
+
+ /* Initialize the arrayelt helper
+ */
+ if (!_ae_create_context( ctx ))
+ return GL_FALSE;
+
+
+ tnl->NeedNdcCoords = GL_TRUE;
+ tnl->LoopbackDListCassettes = GL_FALSE;
+ tnl->CalcDListNormalLengths = GL_TRUE;
+ tnl->AllowVertexFog = GL_TRUE;
+ tnl->AllowPixelFog = GL_TRUE;
+
+ /* Hook our functions into exec and compile dispatch tables.
+ */
+ _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
+
+
+ /* Set a few default values in the driver struct.
+ */
+ install_driver_callbacks(ctx);
+ ctx->Driver.NeedFlush = 0;
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ ctx->Driver.CurrentSavePrimitive = PRIM_UNKNOWN;
+
+ tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
+ tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
+ tnl->Driver.NotifyMaterialChange = _mesa_validate_all_lighting_tables;
+
+ return GL_TRUE;
+}
+
+
+void
+_tnl_DestroyContext( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ _tnl_array_destroy( ctx );
+ _tnl_vtx_destroy( ctx );
+ _tnl_save_destroy( ctx );
+ _tnl_destroy_pipeline( ctx );
+ _ae_destroy_context( ctx );
+
+ FREE(tnl);
+ ctx->swtnl_context = 0;
+}
+
+
+void
+_tnl_InvalidateState( GLcontext *ctx, GLuint new_state )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (new_state & (_NEW_HINT)) {
+ ASSERT(tnl->AllowVertexFog || tnl->AllowPixelFog);
+ tnl->_DoVertexFog = (tnl->AllowVertexFog && (ctx->Hint.Fog != GL_NICEST))
+ || !tnl->AllowPixelFog;
+ }
+
+ if (new_state & _NEW_ARRAY) {
+ tnl->pipeline.run_input_changes |= ctx->Array.NewState; /* overkill */
+ }
+
+ _ae_invalidate_state(ctx, new_state);
+
+ tnl->pipeline.run_state_changes |= new_state;
+ tnl->pipeline.build_state_changes |= (new_state &
+ tnl->pipeline.build_state_trigger);
+
+ tnl->vtx.eval.new_state |= new_state;
+
+ /* Calculate tnl->render_inputs:
+ */
+ if (ctx->Visual.rgbMode) {
+ tnl->render_inputs = (_TNL_BIT_POS|
+ _TNL_BIT_COLOR0|
+ (ctx->Texture._EnabledCoordUnits << _TNL_ATTRIB_TEX0));
+
+ if (NEED_SECONDARY_COLOR(ctx))
+ tnl->render_inputs |= _TNL_BIT_COLOR1;
+ }
+ else {
+ tnl->render_inputs |= (_TNL_BIT_POS|_TNL_BIT_INDEX);
+ }
+
+ if (ctx->Fog.Enabled ||
+ (ctx->FragmentProgram.Enabled &&
+ ctx->FragmentProgram.Current->FogOption != GL_NONE))
+ tnl->render_inputs |= _TNL_BIT_FOG;
+
+ if (ctx->Polygon.FrontMode != GL_FILL ||
+ ctx->Polygon.BackMode != GL_FILL)
+ tnl->render_inputs |= _TNL_BIT_EDGEFLAG;
+
+ if (ctx->RenderMode == GL_FEEDBACK)
+ tnl->render_inputs |= _TNL_BIT_TEX0;
+
+ if (ctx->Point._Attenuated ||
+ (ctx->VertexProgram._Enabled && ctx->VertexProgram.PointSizeEnabled))
+ tnl->render_inputs |= _TNL_BIT_POINTSIZE;
+}
+
+
+void
+_tnl_wakeup_exec( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ install_driver_callbacks(ctx);
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+
+ /* Hook our functions into exec and compile dispatch tables.
+ */
+ _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
+
+ /* Call all appropriate driver callbacks to revive state.
+ */
+ _tnl_MakeCurrent( ctx, ctx->DrawBuffer, ctx->ReadBuffer );
+
+ /* Assume we haven't been getting state updates either:
+ */
+ _tnl_InvalidateState( ctx, ~0 );
+ tnl->pipeline.run_input_changes = ~0;
+
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material( ctx,
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0] );
+ }
+}
+
+
+void
+_tnl_wakeup_save_exec( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ _tnl_wakeup_exec( ctx );
+ _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );
+}
+
+
+/**
+ * Drivers call this function to tell the TCL module whether or not
+ * it wants Normalized Device Coords (NDC) computed. I.e. whether
+ * we should "Divide-by-W". Software renders will want that.
+ */
+void
+_tnl_need_projected_coords( GLcontext *ctx, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ if (tnl->NeedNdcCoords != mode) {
+ tnl->NeedNdcCoords = mode;
+ _tnl_InvalidateState( ctx, _NEW_PROJECTION );
+ }
+}
+
+void
+_tnl_need_dlist_loopback( GLcontext *ctx, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->LoopbackDListCassettes = mode;
+}
+
+void
+_tnl_need_dlist_norm_lengths( GLcontext *ctx, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->CalcDListNormalLengths = mode;
+}
+
+void
+_tnl_isolate_materials( GLcontext *ctx, GLboolean mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->IsolateMaterials = mode;
+}
+
+void
+_tnl_allow_vertex_fog( GLcontext *ctx, GLboolean value )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->AllowVertexFog = value;
+}
+
+void
+_tnl_allow_pixel_fog( GLcontext *ctx, GLboolean value )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->AllowPixelFog = value;
+}
+
diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h
new file mode 100644
index 0000000..55b405e
--- /dev/null
+++ b/src/mesa/tnl/t_context.h
@@ -0,0 +1,811 @@
+/*
+ * mesa 3-D graphics library
+ * Version: 6.2.2
+ *
+ * Copyright (C) 1999-2005 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.
+ */
+
+/**
+ * \file t_context.h
+ * \brief TnL module datatypes and definitions.
+ * \author Keith Whitwell
+ */
+
+
+/**
+ * \mainpage The TNL-module
+ *
+ * TNL stands for "transform and lighting", i.e. this module implements
+ * a pipeline that receives as input a buffer of vertices and does all
+ * necessary transformations (rotations, clipping, vertex shader etc.)
+ * and passes then the output to the rasterizer.
+ *
+ * The tnl_pipeline contains the array of all stages, which should be
+ * applied. Each stage is a black-box, which is described by an
+ * tnl_pipeline_stage. The function ::_tnl_run_pipeline applies all the
+ * stages to the vertex_buffer TNLcontext::vb, where the vertex data
+ * is stored. The last stage in the pipeline is the rasterizer.
+ *
+ * The initial vertex_buffer data may either come from an ::immediate
+ * structure or client vertex_arrays or display lists:
+ *
+ *
+ * - The ::immediate structure records all the GL commands issued between
+ * glBegin and glEnd. \n
+ * The structure accumulates data, until it is either full or it is
+ * flushed (usually by a state change). Before starting then the pipeline,
+ * the collected vertex data in ::immediate has to be pushed into
+ * TNLcontext::vb.
+ * This happens in ::_tnl_vb_bind_immediate. The pipeline is then run by
+ * calling tnl_device_driver::RunPipeline = ::_tnl_run_pipeline, which
+ * is stored in TNLcontext::Driver. \n
+ * An ::immediate does (for performance reasons) usually not finish with a
+ * glEnd, and hence it also does not need to start with a glBegin.
+ * This means that the last vertices of one ::immediate may need to be
+ * saved for the next one.
+ *
+ *
+ * - NOT SURE ABOUT THIS: The vertex_arrays structure is used to handle
+ * glDrawArrays etc. \n
+ * Here, the data of the vertex_arrays is copied by ::_tnl_vb_bind_arrays
+ * into TNLcontext::vb, so that the pipeline can be started.
+ */
+
+
+#ifndef _T_CONTEXT_H
+#define _T_CONTEXT_H
+
+#include "glheader.h"
+#include "mtypes.h"
+
+#include "math/m_matrix.h"
+#include "math/m_vector.h"
+#include "math/m_xform.h"
+
+
+#define MAX_PIPELINE_STAGES 30
+
+
+/*
+ * Note: The first attributes match the VERT_ATTRIB_* definitions
+ * in mtypes.h. However, the tnl module has additional attributes
+ * for materials, color indexes, edge flags, etc.
+ */
+/* Note: These are currently being used to define both inputs and
+ * outputs from the tnl pipeline. A better solution (which would also
+ * releive the congestion to slightly prolong the life of the bitmask
+ * below) is to have the fixed function pipeline populate a set of
+ * arrays named after those produced by the vertex program stage, and
+ * have the rest the mesa backend work on those.
+ */
+enum {
+ _TNL_ATTRIB_POS = 0,
+ _TNL_ATTRIB_WEIGHT = 1,
+ _TNL_ATTRIB_NORMAL = 2,
+ _TNL_ATTRIB_COLOR0 = 3,
+ _TNL_ATTRIB_COLOR1 = 4,
+ _TNL_ATTRIB_FOG = 5,
+ _TNL_ATTRIB_SIX = 6,
+ _TNL_ATTRIB_SEVEN = 7,
+ _TNL_ATTRIB_TEX0 = 8,
+ _TNL_ATTRIB_TEX1 = 9,
+ _TNL_ATTRIB_TEX2 = 10,
+ _TNL_ATTRIB_TEX3 = 11,
+ _TNL_ATTRIB_TEX4 = 12,
+ _TNL_ATTRIB_TEX5 = 13,
+ _TNL_ATTRIB_TEX6 = 14,
+ _TNL_ATTRIB_TEX7 = 15,
+ _TNL_ATTRIB_MAT_FRONT_AMBIENT = 16,
+ _TNL_ATTRIB_MAT_BACK_AMBIENT = 17,
+ _TNL_ATTRIB_MAT_FRONT_DIFFUSE = 18,
+ _TNL_ATTRIB_MAT_BACK_DIFFUSE = 19,
+ _TNL_ATTRIB_MAT_FRONT_SPECULAR = 20,
+ _TNL_ATTRIB_MAT_BACK_SPECULAR = 21,
+ _TNL_ATTRIB_MAT_FRONT_EMISSION = 22,
+ _TNL_ATTRIB_MAT_BACK_EMISSION = 23,
+ _TNL_ATTRIB_MAT_FRONT_SHININESS = 24,
+ _TNL_ATTRIB_MAT_BACK_SHININESS = 25,
+ _TNL_ATTRIB_MAT_FRONT_INDEXES = 26,
+ _TNL_ATTRIB_MAT_BACK_INDEXES = 27,
+ _TNL_ATTRIB_INDEX = 28,
+ _TNL_ATTRIB_EDGEFLAG = 29,
+ _TNL_ATTRIB_POINTSIZE = 30,
+ _TNL_ATTRIB_MAX = 31
+} ;
+
+/* Will probably have to revise this scheme fairly shortly, eg. by
+ * compacting all the MAT flags down to one bit, or by using two
+ * dwords to store the flags.
+ */
+#define _TNL_BIT_POS (1<<0)
+#define _TNL_BIT_WEIGHT (1<<1)
+#define _TNL_BIT_NORMAL (1<<2)
+#define _TNL_BIT_COLOR0 (1<<3)
+#define _TNL_BIT_COLOR1 (1<<4)
+#define _TNL_BIT_FOG (1<<5)
+#define _TNL_BIT_SIX (1<<6)
+#define _TNL_BIT_SEVEN (1<<7)
+#define _TNL_BIT_TEX0 (1<<8)
+#define _TNL_BIT_TEX1 (1<<9)
+#define _TNL_BIT_TEX2 (1<<10)
+#define _TNL_BIT_TEX3 (1<<11)
+#define _TNL_BIT_TEX4 (1<<12)
+#define _TNL_BIT_TEX5 (1<<13)
+#define _TNL_BIT_TEX6 (1<<14)
+#define _TNL_BIT_TEX7 (1<<15)
+#define _TNL_BIT_MAT_FRONT_AMBIENT (1<<16)
+#define _TNL_BIT_MAT_BACK_AMBIENT (1<<17)
+#define _TNL_BIT_MAT_FRONT_DIFFUSE (1<<18)
+#define _TNL_BIT_MAT_BACK_DIFFUSE (1<<19)
+#define _TNL_BIT_MAT_FRONT_SPECULAR (1<<20)
+#define _TNL_BIT_MAT_BACK_SPECULAR (1<<21)
+#define _TNL_BIT_MAT_FRONT_EMISSION (1<<22)
+#define _TNL_BIT_MAT_BACK_EMISSION (1<<23)
+#define _TNL_BIT_MAT_FRONT_SHININESS (1<<24)
+#define _TNL_BIT_MAT_BACK_SHININESS (1<<25)
+#define _TNL_BIT_MAT_FRONT_INDEXES (1<<26)
+#define _TNL_BIT_MAT_BACK_INDEXES (1<<27)
+#define _TNL_BIT_INDEX (1<<28)
+#define _TNL_BIT_EDGEFLAG (1<<29)
+#define _TNL_BIT_POINTSIZE (1<<30)
+
+#define _TNL_BIT_TEX(u) (1 << (_TNL_ATTRIB_TEX0 + (u)))
+
+
+
+#define _TNL_BITS_MAT_ANY (_TNL_BIT_MAT_FRONT_AMBIENT | \
+ _TNL_BIT_MAT_BACK_AMBIENT | \
+ _TNL_BIT_MAT_FRONT_DIFFUSE | \
+ _TNL_BIT_MAT_BACK_DIFFUSE | \
+ _TNL_BIT_MAT_FRONT_SPECULAR | \
+ _TNL_BIT_MAT_BACK_SPECULAR | \
+ _TNL_BIT_MAT_FRONT_EMISSION | \
+ _TNL_BIT_MAT_BACK_EMISSION | \
+ _TNL_BIT_MAT_FRONT_SHININESS | \
+ _TNL_BIT_MAT_BACK_SHININESS | \
+ _TNL_BIT_MAT_FRONT_INDEXES | \
+ _TNL_BIT_MAT_BACK_INDEXES)
+
+
+#define _TNL_BITS_TEX_ANY (_TNL_BIT_TEX0 | \
+ _TNL_BIT_TEX1 | \
+ _TNL_BIT_TEX2 | \
+ _TNL_BIT_TEX3 | \
+ _TNL_BIT_TEX4 | \
+ _TNL_BIT_TEX5 | \
+ _TNL_BIT_TEX6 | \
+ _TNL_BIT_TEX7)
+
+
+#define _TNL_BITS_PROG_ANY (_TNL_BIT_POS | \
+ _TNL_BIT_WEIGHT | \
+ _TNL_BIT_NORMAL | \
+ _TNL_BIT_COLOR0 | \
+ _TNL_BIT_COLOR1 | \
+ _TNL_BIT_FOG | \
+ _TNL_BIT_SIX | \
+ _TNL_BIT_SEVEN | \
+ _TNL_BITS_TEX_ANY)
+
+
+
+#define PRIM_BEGIN 0x10
+#define PRIM_END 0x20
+#define PRIM_WEAK 0x40
+#define PRIM_MODE_MASK 0x0f
+
+/*
+ */
+struct tnl_prim {
+ GLuint mode;
+ GLuint start;
+ GLuint count;
+};
+
+
+
+struct tnl_eval1_map {
+ struct gl_1d_map *map;
+ GLuint sz;
+};
+
+struct tnl_eval2_map {
+ struct gl_2d_map *map;
+ GLuint sz;
+};
+
+struct tnl_eval {
+ GLuint new_state;
+ struct tnl_eval1_map map1[_TNL_ATTRIB_INDEX + 1];
+ struct tnl_eval2_map map2[_TNL_ATTRIB_INDEX + 1];
+};
+
+
+#define TNL_MAX_PRIM 16
+#define TNL_MAX_COPIED_VERTS 3
+
+struct tnl_copied_vtx {
+ GLfloat buffer[_TNL_ATTRIB_MAX * 4 * TNL_MAX_COPIED_VERTS];
+ GLuint nr;
+};
+
+#define VERT_BUFFER_SIZE 2048 /* 8kbytes */
+
+
+typedef void (*tnl_attrfv_func)( const GLfloat * );
+
+struct _tnl_dynfn {
+ struct _tnl_dynfn *next, *prev;
+ GLuint key;
+ char *code;
+};
+
+struct _tnl_dynfn_lists {
+ struct _tnl_dynfn Vertex[4];
+ struct _tnl_dynfn Attribute[4];
+};
+
+struct _tnl_dynfn_generators {
+ struct _tnl_dynfn *(*Vertex[4])( GLcontext *ctx, int key );
+ struct _tnl_dynfn *(*Attribute[4])( GLcontext *ctx, int key );
+};
+
+#define _TNL_MAX_ATTR_CODEGEN 16
+
+
+/* The assembly of vertices in immediate mode is separated from
+ * display list compilation. This allows a simpler immediate mode
+ * treatment and a display list compiler better suited to
+ * hardware-acceleration.
+ */
+struct tnl_vtx {
+ GLfloat buffer[VERT_BUFFER_SIZE];
+ GLubyte attrsz[_TNL_ATTRIB_MAX];
+ GLuint vertex_size;
+ struct tnl_prim prim[TNL_MAX_PRIM];
+ GLuint prim_count;
+ GLfloat *vbptr; /* cursor, points into buffer */
+ GLfloat vertex[_TNL_ATTRIB_MAX*4]; /* current vertex */
+ GLfloat *attrptr[_TNL_ATTRIB_MAX]; /* points into vertex */
+ GLfloat *current[_TNL_ATTRIB_MAX]; /* points into ctx->Current, etc */
+ GLuint counter, initial_counter;
+ struct tnl_copied_vtx copied;
+
+ tnl_attrfv_func tabfv[_TNL_MAX_ATTR_CODEGEN+1][4]; /* plus 1 for ERROR_ATTRIB */
+
+ struct _tnl_dynfn_lists cache;
+ struct _tnl_dynfn_generators gen;
+
+ struct tnl_eval eval;
+ GLboolean *edgeflag_tmp;
+ GLboolean have_materials;
+};
+
+
+
+
+/* For display lists, this structure holds a run of vertices of the
+ * same format, and a strictly well-formed set of begin/end pairs,
+ * starting on the first vertex and ending at the last. Vertex
+ * copying on buffer breaks is precomputed according to these
+ * primitives, though there are situations where the copying will need
+ * correction at execute-time, perhaps by replaying the list as
+ * immediate mode commands.
+ *
+ * On executing this list, the 'current' values may be updated with
+ * the values of the final vertex, and often no fixup of the start of
+ * the vertex list is required.
+ *
+ * Eval and other commands that don't fit into these vertex lists are
+ * compiled using the fallback opcode mechanism provided by dlist.c.
+ */
+struct tnl_vertex_list {
+ GLubyte attrsz[_TNL_ATTRIB_MAX];
+ GLuint vertex_size;
+
+ GLfloat *buffer;
+ GLuint count;
+ GLuint wrap_count; /* number of copied vertices at start */
+ GLboolean have_materials; /* bit of a hack - quick check for materials */
+ GLboolean dangling_attr_ref; /* current attr implicitly referenced
+ outside the list */
+
+ GLfloat *normal_lengths;
+ struct tnl_prim *prim;
+ GLuint prim_count;
+
+ struct tnl_vertex_store *vertex_store;
+ struct tnl_primitive_store *prim_store;
+};
+
+/* These buffers should be a reasonable size to support upload to
+ * hardware? Maybe drivers should stitch them back together, or
+ * specify a desired size?
+ */
+#define SAVE_BUFFER_SIZE (16*1024)
+#define SAVE_PRIM_SIZE 128
+
+/* Storage to be shared among several vertex_lists.
+ */
+struct tnl_vertex_store {
+ GLfloat buffer[SAVE_BUFFER_SIZE];
+ GLuint used;
+ GLuint refcount;
+};
+
+struct tnl_primitive_store {
+ struct tnl_prim buffer[SAVE_PRIM_SIZE];
+ GLuint used;
+ GLuint refcount;
+};
+
+
+struct tnl_save {
+ GLubyte attrsz[_TNL_ATTRIB_MAX];
+ GLuint vertex_size;
+
+ GLfloat *buffer;
+ GLuint count;
+ GLuint wrap_count;
+
+ struct tnl_prim *prim;
+ GLuint prim_count, prim_max;
+
+ struct tnl_vertex_store *vertex_store;
+ struct tnl_primitive_store *prim_store;
+
+ GLfloat *vbptr; /* cursor, points into buffer */
+ GLfloat vertex[_TNL_ATTRIB_MAX*4]; /* current values */
+ GLfloat *attrptr[_TNL_ATTRIB_MAX];
+ GLuint counter, initial_counter;
+ GLboolean dangling_attr_ref;
+ GLboolean have_materials;
+
+ GLuint opcode_vertex_list;
+
+ struct tnl_copied_vtx copied;
+
+ GLfloat *current[_TNL_ATTRIB_MAX]; /* points into ctx->ListState */
+ GLubyte *currentsz[_TNL_ATTRIB_MAX];
+
+ void (*tabfv[_TNL_ATTRIB_MAX][4])( const GLfloat * );
+};
+
+
+struct tnl_vertex_arrays
+{
+ /* Conventional vertex attribute arrays */
+ GLvector4f Obj;
+ GLvector4f Normal;
+ GLvector4f Color;
+ GLvector4f SecondaryColor;
+ GLvector4f FogCoord;
+ GLvector4f TexCoord[MAX_TEXTURE_COORD_UNITS];
+ GLvector4f Index;
+
+ GLubyte *EdgeFlag;
+ GLuint *Elt;
+
+ /* These attributes don't alias with the conventional attributes.
+ * The GL_NV_vertex_program extension defines 16 extra sets of vertex
+ * arrays which have precedent over the conventional arrays when enabled.
+ */
+ GLvector4f Attribs[_TNL_ATTRIB_MAX];
+};
+
+
+/**
+ * Contains the current state of a running pipeline.
+ */
+struct vertex_buffer
+{
+ /* Constant over life of the vertex_buffer.
+ */
+ GLuint Size;
+
+ /* Constant over the pipeline.
+ */
+ GLuint Count; /* for everything except Elts */
+
+ /* Pointers to current data.
+ */
+ GLuint *Elts;
+ GLvector4f *ObjPtr; /* _TNL_BIT_POS */
+ GLvector4f *EyePtr; /* _TNL_BIT_POS */
+ GLvector4f *ClipPtr; /* _TNL_BIT_POS */
+ GLvector4f *NdcPtr; /* _TNL_BIT_POS */
+ GLubyte ClipOrMask; /* _TNL_BIT_POS */
+ GLubyte ClipAndMask; /* _TNL_BIT_POS */
+ GLubyte *ClipMask; /* _TNL_BIT_POS */
+ GLvector4f *NormalPtr; /* _TNL_BIT_NORMAL */
+ GLfloat *NormalLengthPtr; /* _TNL_BIT_NORMAL */
+ GLboolean *EdgeFlag; /* _TNL_BIT_EDGEFLAG */
+ GLvector4f *TexCoordPtr[MAX_TEXTURE_COORD_UNITS]; /* VERT_TEX_0..n */
+ GLvector4f *IndexPtr[2]; /* _TNL_BIT_INDEX */
+ GLvector4f *ColorPtr[2]; /* _TNL_BIT_COLOR0 */
+ GLvector4f *SecondaryColorPtr[2]; /* _TNL_BIT_COLOR1 */
+ GLvector4f *PointSizePtr; /* _TNL_BIT_POS */
+ GLvector4f *FogCoordPtr; /* _TNL_BIT_FOG */
+
+ struct tnl_prim *Primitive;
+ GLuint PrimitiveCount;
+
+ /* Inputs to the vertex program stage */
+ GLvector4f *AttribPtr[_TNL_ATTRIB_MAX]; /* GL_NV_vertex_program */
+
+ GLuint LastClipped;
+ /* Private data from _tnl_render_stage that has no business being
+ * in this struct.
+ */
+};
+
+
+/** Describes an individual operation on the pipeline.
+ */
+struct tnl_pipeline_stage
+{
+ const char *name;
+ GLuint check_state; /* All state referenced in check() --
+ * When is the pipeline_stage struct
+ * itself invalidated? Must be
+ * constant.
+ */
+
+ /* Usually constant or set by the 'check' callback:
+ */
+ 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():
+ */
+ GLuint changed_inputs; /* Generated value -- inputs to the
+ * stage that have changed since last
+ * call to 'run'.
+ */
+
+
+ /* Private data for the pipeline stage:
+ */
+ void *privatePtr;
+
+ /* Free private data. May not be null.
+ */
+ void (*destroy)( struct tnl_pipeline_stage * );
+
+ /* Called from _tnl_validate_pipeline(). Must update all fields in
+ * the pipeline_stage struct for the current state.
+ */
+ void (*check)( GLcontext *ctx, struct tnl_pipeline_stage * );
+
+ /* 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 tnl_pipeline_stage * );
+};
+
+/** Contains the array of all pipeline stages.
+ * The default values are defined at the end of t_pipeline.c */
+struct tnl_pipeline {
+ 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 */
+ /** This array has to end with a NULL-pointer. */
+ struct tnl_pipeline_stage stages[MAX_PIPELINE_STAGES+1];
+ GLuint nr_stages;
+};
+
+struct tnl_clipspace;
+struct tnl_clipspace_attr;
+
+typedef void (*tnl_extract_func)( const struct tnl_clipspace_attr *a,
+ GLfloat *out,
+ const GLubyte *v );
+
+typedef void (*tnl_insert_func)( const struct tnl_clipspace_attr *a,
+ GLubyte *v,
+ const GLfloat *in );
+
+typedef void (*tnl_emit_func)( GLcontext *ctx,
+ GLuint start,
+ GLuint end, void *dest );
+
+
+/**
+ * Describes how to convert/move a vertex attribute from a vertex array
+ * to a vertex structure.
+ */
+struct tnl_clipspace_attr
+{
+ GLuint attrib; /* which vertex attrib (0=position, etc) */
+ GLuint format;
+ GLuint vertoffset; /* position of the attrib in the vertex struct */
+ GLuint vertattrsize; /* size of the attribute in bytes */
+ GLubyte *inputptr;
+ GLuint inputstride;
+ tnl_insert_func *insert;
+ tnl_insert_func emit;
+ tnl_extract_func extract;
+ const GLfloat *vp; /* NDC->Viewport mapping matrix */
+};
+
+
+struct tnl_clipspace_codegen {
+ GLboolean (*emit_header)( struct tnl_clipspace_codegen *,
+ struct tnl_clipspace *);
+ GLboolean (*emit_footer)( struct tnl_clipspace_codegen * );
+ GLboolean (*emit_attr_header)( struct tnl_clipspace_codegen *,
+ struct tnl_clipspace_attr *,
+ GLint j, GLenum out_type,
+ GLboolean need_vp );
+ GLboolean (*emit_attr_footer)( struct tnl_clipspace_codegen * );
+ GLboolean (*emit_mov)( struct tnl_clipspace_codegen *,
+ GLint, GLint );
+ GLboolean (*emit_const)( struct tnl_clipspace_codegen *,
+ GLint, GLfloat );
+ GLboolean (*emit_mad)( struct tnl_clipspace_codegen *,
+ GLint, GLint, GLint, GLint );
+ GLboolean (*emit_float_to_chan)( struct tnl_clipspace_codegen *,
+ GLint, GLint );
+ GLboolean (*emit_const_chan)( struct tnl_clipspace_codegen *,
+ GLint, GLchan );
+ GLboolean (*emit_float_to_ubyte)( struct tnl_clipspace_codegen *,
+ GLint, GLint );
+ GLboolean (*emit_const_ubyte)( struct tnl_clipspace_codegen *,
+ GLint, GLubyte );
+ tnl_emit_func (*emit_store_func)( struct tnl_clipspace_codegen * );
+
+ struct _tnl_dynfn codegen_list;
+
+ char *buf;
+ int buf_size;
+ int buf_used;
+ int out_offset;
+};
+
+
+
+typedef void (*tnl_points_func)( GLcontext *ctx, GLuint first, GLuint last );
+typedef void (*tnl_line_func)( GLcontext *ctx, GLuint v1, GLuint v2 );
+typedef void (*tnl_triangle_func)( GLcontext *ctx,
+ GLuint v1, GLuint v2, GLuint v3 );
+typedef void (*tnl_quad_func)( GLcontext *ctx, GLuint v1, GLuint v2,
+ GLuint v3, GLuint v4 );
+typedef void (*tnl_render_func)( GLcontext *ctx, GLuint start, GLuint count,
+ GLuint flags );
+typedef void (*tnl_interp_func)( GLcontext *ctx,
+ GLfloat t, GLuint dst, GLuint out, GLuint in,
+ GLboolean force_boundary );
+typedef void (*tnl_copy_pv_func)( GLcontext *ctx, GLuint dst, GLuint src );
+typedef void (*tnl_setup_func)( GLcontext *ctx,
+ GLuint start, GLuint end,
+ GLuint new_inputs);
+
+
+/**
+ * Used to describe conversion of vertex arrays to vertex structures.
+ * I.e. Structure of arrays to arrays of structs.
+ */
+struct tnl_clipspace
+{
+ GLboolean need_extras;
+
+ GLuint new_inputs;
+
+ GLubyte *vertex_buf;
+ GLuint vertex_size;
+ GLuint max_vertex_size;
+
+ struct tnl_clipspace_attr attr[_TNL_ATTRIB_MAX];
+ GLuint attr_count;
+
+ tnl_emit_func emit;
+ tnl_interp_func interp;
+ tnl_copy_pv_func copy_pv;
+
+ struct tnl_clipspace_codegen codegen;
+};
+
+
+struct tnl_device_driver
+{
+ /***
+ *** TNL Pipeline
+ ***/
+
+ void (*RunPipeline)(GLcontext *ctx);
+ /* Replaces PipelineStart/PipelineFinish -- intended to allow
+ * drivers to wrap _tnl_run_pipeline() with code to validate state
+ * and grab/release hardware locks.
+ */
+
+ void (*NotifyMaterialChange)(GLcontext *ctx);
+ /* Alert tnl-aware drivers of changes to material.
+ */
+
+ GLboolean (*NotifyBegin)(GLcontext *ctx, GLenum p);
+ /* Allow drivers to hook in optimized begin/end engines.
+ * Return value: GL_TRUE - driver handled the begin
+ * GL_FALSE - driver didn't handle the begin
+ */
+
+ /***
+ *** Rendering -- These functions called only from t_vb_render.c
+ ***/
+ struct
+ {
+ void (*Start)(GLcontext *ctx);
+ void (*Finish)(GLcontext *ctx);
+ /* Called before and after all rendering operations, including DrawPixels,
+ * ReadPixels, Bitmap, span functions, and CopyTexImage, etc commands.
+ * These are a suitable place for grabbing/releasing hardware locks.
+ */
+
+ void (*PrimitiveNotify)(GLcontext *ctx, GLenum mode);
+ /* Called between RenderStart() and RenderFinish() to indicate the
+ * type of primitive we're about to draw. Mode will be one of the
+ * modes accepted by glBegin().
+ */
+
+ tnl_interp_func Interp;
+ /* The interp function is called by the clipping routines when we need
+ * to generate an interpolated vertex. All pertinant vertex ancilliary
+ * data should be computed by interpolating between the 'in' and 'out'
+ * vertices.
+ */
+
+ tnl_copy_pv_func CopyPV;
+ /* The copy function is used to make a copy of a vertex. All pertinant
+ * vertex attributes should be copied.
+ */
+
+ void (*ClippedPolygon)( GLcontext *ctx, const GLuint *elts, GLuint n );
+ /* Render a polygon with <n> vertices whose indexes are in the <elts>
+ * array.
+ */
+
+ void (*ClippedLine)( GLcontext *ctx, GLuint v0, GLuint v1 );
+ /* Render a line between the two vertices given by indexes v0 and v1. */
+
+ tnl_points_func Points; /* must now respect vb->elts */
+ tnl_line_func Line;
+ tnl_triangle_func Triangle;
+ tnl_quad_func Quad;
+ /* These functions are called in order to render points, lines,
+ * triangles and quads. These are only called via the T&L module.
+ */
+
+ tnl_render_func *PrimTabVerts;
+ tnl_render_func *PrimTabElts;
+ /* Render whole unclipped primitives (points, lines, linestrips,
+ * lineloops, etc). The tables are indexed by the GL enum of the
+ * primitive to be rendered. RenderTabVerts is used for non-indexed
+ * arrays of vertices. RenderTabElts is used for indexed arrays of
+ * vertices.
+ */
+
+ void (*ResetLineStipple)( GLcontext *ctx );
+ /* Reset the hardware's line stipple counter.
+ */
+
+ tnl_setup_func BuildVertices;
+ /* This function is called whenever new vertices are required for
+ * rendering. The vertices in question are those n such that start
+ * <= n < end. The new_inputs parameter indicates those fields of
+ * the vertex which need to be updated, if only a partial repair of
+ * the vertex is required.
+ *
+ * This function is called only from _tnl_render_stage in tnl/t_render.c.
+ */
+
+
+ GLboolean (*Multipass)( GLcontext *ctx, GLuint passno );
+ /* Driver may request additional render passes by returning GL_TRUE
+ * when this function is called. This function will be called
+ * after the first pass, and passes will be made until the function
+ * returns GL_FALSE. If no function is registered, only one pass
+ * is made.
+ *
+ * This function will be first invoked with passno == 1.
+ */
+ } Render;
+};
+
+
+/**
+ * Context state for T&L context.
+ */
+typedef struct
+{
+ /* Driver interface.
+ */
+ struct tnl_device_driver Driver;
+
+ /* Execute:
+ */
+ struct tnl_vtx vtx;
+
+ /* Compile:
+ */
+ struct tnl_save save;
+
+ /* Pipeline
+ */
+ struct tnl_pipeline pipeline;
+ struct vertex_buffer vb;
+
+ /* GLvectors for binding to vb:
+ */
+ struct tnl_vertex_arrays vtx_inputs;
+ struct tnl_vertex_arrays save_inputs;
+ struct tnl_vertex_arrays current;
+ struct tnl_vertex_arrays array_inputs;
+
+ /* Clipspace/ndc/window vertex managment:
+ */
+ struct tnl_clipspace clipspace;
+
+ /* Probably need a better configuration mechanism:
+ */
+ GLboolean NeedNdcCoords;
+ GLboolean LoopbackDListCassettes;
+ GLboolean CalcDListNormalLengths;
+ GLboolean IsolateMaterials;
+ GLboolean AllowVertexFog;
+ GLboolean AllowPixelFog;
+ GLboolean AllowCodegen;
+
+ GLboolean _DoVertexFog; /* eval fog function at each vertex? */
+
+ GLuint render_inputs;
+
+ GLvertexformat exec_vtxfmt;
+ GLvertexformat save_vtxfmt;
+
+} TNLcontext;
+
+
+
+#define TNL_CONTEXT(ctx) ((TNLcontext *)((ctx)->swtnl_context))
+
+
+#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 );
+
+
+
+
+#endif
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c
new file mode 100644
index 0000000..e90e21b
--- /dev/null
+++ b/src/mesa/tnl/t_pipeline.c
@@ -0,0 +1,216 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2003 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "state.h"
+#include "mtypes.h"
+
+#include "math/m_translate.h"
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+void _tnl_install_pipeline( GLcontext *ctx,
+ const struct tnl_pipeline_stage **stages )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_pipeline *pipe = &tnl->pipeline;
+ GLuint i;
+
+ ASSERT(pipe->nr_stages == 0);
+
+ pipe->run_state_changes = ~0;
+ pipe->run_input_changes = ~0;
+ pipe->build_state_changes = ~0;
+ pipe->build_state_trigger = 0;
+ pipe->inputs = 0;
+
+ /* Create a writeable copy of each stage.
+ */
+ 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;
+ }
+
+ MEMSET( &pipe->stages[i], 0, sizeof( **stages ));
+
+ pipe->nr_stages = i;
+}
+
+void _tnl_destroy_pipeline( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = 0 ; i < tnl->pipeline.nr_stages ; i++)
+ tnl->pipeline.stages[i].destroy( &tnl->pipeline.stages[i] );
+
+ tnl->pipeline.nr_stages = 0;
+}
+
+/* TODO: merge validate with run.
+ */
+void _tnl_validate_pipeline( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_pipeline *pipe = &tnl->pipeline;
+ struct tnl_pipeline_stage *s = pipe->stages;
+ GLuint newstate = pipe->build_state_changes;
+ GLuint generated = 0;
+ GLuint changed_inputs = 0;
+
+ pipe->inputs = 0;
+ pipe->build_state_changes = 0;
+
+ for ( ; s->check ; s++) {
+
+ s->changed_inputs |= s->inputs & changed_inputs;
+
+ if (s->check_state & newstate) {
+ if (s->active) {
+ GLuint old_outputs = s->outputs;
+ s->check(ctx, s);
+ if (!s->active)
+ changed_inputs |= old_outputs;
+ }
+ else
+ s->check(ctx, s);
+ }
+
+ if (s->active) {
+ pipe->inputs |= s->inputs & ~generated;
+ generated |= s->outputs;
+ }
+ }
+}
+
+
+
+void _tnl_run_pipeline( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_pipeline *pipe = &tnl->pipeline;
+ struct tnl_pipeline_stage *s = pipe->stages;
+ GLuint changed_state = pipe->run_state_changes;
+ GLuint changed_inputs = pipe->run_input_changes;
+ GLboolean running = GL_TRUE;
+#ifdef HAVE_FAST_MATH
+ unsigned short __tmp;
+#endif
+
+ if (!tnl->vb.Count)
+ return;
+
+ pipe->run_state_changes = 0;
+ pipe->run_input_changes = 0;
+
+ /* Done elsewhere.
+ */
+ ASSERT(pipe->build_state_changes == 0);
+
+#ifdef HAVE_FAST_MATH
+ START_FAST_MATH(__tmp);
+#endif
+
+ /* If something changes in the pipeline, tag all subsequent stages
+ * using this value for recalculation. Inactive stages have their
+ * state and inputs examined to try to keep cached data alive over
+ * state-changes.
+ */
+ for ( ; s->run ; s++) {
+ s->changed_inputs |= s->inputs & changed_inputs;
+
+ if (s->run_state & changed_state)
+ s->changed_inputs = s->inputs;
+
+ if (s->active && running) {
+ if (s->changed_inputs)
+ changed_inputs |= s->outputs;
+
+ running = s->run( ctx, s );
+
+ s->changed_inputs = 0;
+ }
+ }
+
+#ifdef HAVE_FAST_MATH
+ END_FAST_MATH(__tmp);
+#endif
+}
+
+
+
+/* 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 VB->Elts 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 tnl_pipeline_stage *_tnl_default_pipeline[] = {
+ &_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,
+#if defined(FEATURE_NV_vertex_program) || defined(FEATURE_ARB_vertex_program)
+ &_tnl_vertex_program_stage,
+#endif
+ &_tnl_render_stage,
+ 0
+};
diff --git a/src/mesa/tnl/t_pipeline.h b/src/mesa/tnl/t_pipeline.h
new file mode 100644
index 0000000..9efb5b8
--- /dev/null
+++ b/src/mesa/tnl/t_pipeline.h
@@ -0,0 +1,76 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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 <keith@tungstengraphics.com>
+ */
+
+
+
+#ifndef _T_PIPELINE_H_
+#define _T_PIPELINE_H_
+
+#include "mtypes.h"
+#include "t_context.h"
+
+extern void _tnl_run_pipeline( GLcontext *ctx );
+
+extern void _tnl_validate_pipeline( GLcontext *ctx );
+
+extern void _tnl_destroy_pipeline( GLcontext *ctx );
+
+extern void _tnl_install_pipeline( GLcontext *ctx,
+ const struct tnl_pipeline_stage **stages );
+
+
+/* These are implemented in the t_vb_*.c files:
+ */
+extern const struct tnl_pipeline_stage _tnl_vertex_transform_stage;
+extern const struct tnl_pipeline_stage _tnl_vertex_cull_stage;
+extern const struct tnl_pipeline_stage _tnl_normal_transform_stage;
+extern const struct tnl_pipeline_stage _tnl_lighting_stage;
+extern const struct tnl_pipeline_stage _tnl_fog_coordinate_stage;
+extern const struct tnl_pipeline_stage _tnl_texgen_stage;
+extern const struct tnl_pipeline_stage _tnl_texture_transform_stage;
+extern const struct tnl_pipeline_stage _tnl_point_attenuation_stage;
+extern const struct tnl_pipeline_stage _tnl_vertex_program_stage;
+extern const struct tnl_pipeline_stage _tnl_render_stage;
+
+/* Shorthand to plug in the default pipeline:
+ */
+extern const struct tnl_pipeline_stage *_tnl_default_pipeline[];
+
+
+/* Convenience routines provided by t_vb_render.c:
+ */
+extern tnl_render_func _tnl_render_tab_elts[];
+extern tnl_render_func _tnl_render_tab_verts[];
+
+extern void _tnl_RenderClippedPolygon( GLcontext *ctx,
+ const GLuint *elts, GLuint n );
+
+extern void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj );
+
+
+#endif
diff --git a/src/mesa/tnl/t_save_api.c b/src/mesa/tnl/t_save_api.c
new file mode 100644
index 0000000..5a7e6b5
--- /dev/null
+++ b/src/mesa/tnl/t_save_api.c
@@ -0,0 +1,1617 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ */
+
+
+
+/* Display list compiler attempts to store lists of vertices with the
+ * same vertex layout. Additionally it attempts to minimize the need
+ * for execute-time fixup of these vertex lists, allowing them to be
+ * cached on hardware.
+ *
+ * There are still some circumstances where this can be thwarted, for
+ * example by building a list that consists of one very long primitive
+ * (eg Begin(Triangles), 1000 vertices, End), and calling that list
+ * from inside a different begin/end object (Begin(Lines), CallList,
+ * End).
+ *
+ * In that case the code will have to replay the list as individual
+ * commands through the Exec dispatch table, or fix up the copied
+ * vertices at execute-time.
+ *
+ * The other case where fixup is required is when a vertex attribute
+ * is introduced in the middle of a primitive. Eg:
+ * Begin(Lines)
+ * TexCoord1f() Vertex2f()
+ * TexCoord1f() Color3f() Vertex2f()
+ * End()
+ *
+ * If the current value of Color isn't known at compile-time, this
+ * primitive will require fixup.
+ *
+ *
+ * The list compiler currently doesn't attempt to compile lists
+ * containing EvalCoord or EvalPoint commands. On encountering one of
+ * these, compilation falls back to opcodes.
+ *
+ * This could be improved to fallback only when a mix of EvalCoord and
+ * Vertex commands are issued within a single primitive.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "enums.h"
+#include "macros.h"
+#include "api_validate.h"
+#include "api_arrayelt.h"
+#include "vtxfmt.h"
+#include "t_save_api.h"
+
+/*
+ * NOTE: Old 'parity' issue is gone, but copying can still be
+ * wrong-footed on replay.
+ */
+static GLuint _save_copy_vertices( GLcontext *ctx,
+ const struct tnl_vertex_list *node )
+{
+ TNLcontext *tnl = TNL_CONTEXT( ctx );
+ const struct tnl_prim *prim = &node->prim[node->prim_count-1];
+ GLuint nr = prim->count;
+ GLuint sz = tnl->save.vertex_size;
+ const GLfloat *src = node->buffer + prim->start * sz;
+ GLfloat *dst = tnl->save.copied.buffer;
+ GLuint ovf, i;
+
+ if (prim->mode & PRIM_END)
+ return 0;
+
+ switch( prim->mode & PRIM_MODE_MASK )
+ {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_TRIANGLES:
+ ovf = nr%3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_QUADS:
+ ovf = nr&3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ else {
+ _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+ return 1;
+ }
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0)
+ return 0;
+ else if (nr == 1) {
+ _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+ return 1;
+ } else {
+ _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+ _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+ return 2;
+ }
+ case GL_TRIANGLE_STRIP:
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0: ovf = 0; break;
+ case 1: ovf = 1; break;
+ default: ovf = 2 + (nr&1); break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+static void
+build_normal_lengths( struct tnl_vertex_list *node )
+{
+ GLuint i;
+ GLfloat *len;
+ GLfloat *n = node->buffer;
+ GLuint stride = node->vertex_size;
+ GLuint count = node->count;
+
+ len = node->normal_lengths = (GLfloat *) MALLOC( count * sizeof(GLfloat) );
+ if (!len)
+ return;
+
+ /* Find the normal of the first vertex:
+ */
+ for (i = 0 ; i < _TNL_ATTRIB_NORMAL ; i++)
+ n += node->attrsz[i];
+
+ for (i = 0 ; i < count ; i++, n += stride) {
+ len[i] = LEN_3FV( n );
+ if (len[i] > 0.0F) len[i] = 1.0F / len[i];
+ }
+}
+
+static struct tnl_vertex_store *alloc_vertex_store( GLcontext *ctx )
+{
+ struct tnl_vertex_store *store = MALLOC_STRUCT(tnl_vertex_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+static struct tnl_primitive_store *alloc_prim_store( GLcontext *ctx )
+{
+ struct tnl_primitive_store *store = MALLOC_STRUCT(tnl_primitive_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+static void _save_reset_counters( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ tnl->save.prim = tnl->save.prim_store->buffer + tnl->save.prim_store->used;
+ tnl->save.buffer = (tnl->save.vertex_store->buffer +
+ tnl->save.vertex_store->used);
+
+ if (tnl->save.vertex_size)
+ tnl->save.initial_counter = ((SAVE_BUFFER_SIZE -
+ tnl->save.vertex_store->used) /
+ tnl->save.vertex_size);
+ else
+ tnl->save.initial_counter = 0;
+
+ if (tnl->save.initial_counter > ctx->Const.MaxArrayLockSize )
+ tnl->save.initial_counter = ctx->Const.MaxArrayLockSize;
+
+ tnl->save.counter = tnl->save.initial_counter;
+ tnl->save.prim_count = 0;
+ tnl->save.prim_max = SAVE_PRIM_SIZE - tnl->save.prim_store->used;
+ tnl->save.copied.nr = 0;
+ tnl->save.dangling_attr_ref = 0;
+}
+
+
+/* Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+static void _save_compile_vertex_list( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_list *node;
+
+ /* Allocate space for this structure in the display list currently
+ * being compiled.
+ */
+ node = (struct tnl_vertex_list *)
+ _mesa_alloc_instruction(ctx, tnl->save.opcode_vertex_list, sizeof(*node));
+
+ if (!node)
+ return;
+
+ /* Duplicate our template, increment refcounts to the storage structs:
+ */
+ _mesa_memcpy(node->attrsz, tnl->save.attrsz, sizeof(node->attrsz));
+ node->vertex_size = tnl->save.vertex_size;
+ node->buffer = tnl->save.buffer;
+ node->wrap_count = tnl->save.copied.nr;
+ node->count = tnl->save.initial_counter - tnl->save.counter;
+ node->prim = tnl->save.prim;
+ node->prim_count = tnl->save.prim_count;
+ node->vertex_store = tnl->save.vertex_store;
+ node->prim_store = tnl->save.prim_store;
+ node->dangling_attr_ref = tnl->save.dangling_attr_ref;
+ node->normal_lengths = 0;
+
+ node->vertex_store->refcount++;
+ node->prim_store->refcount++;
+
+ assert(node->attrsz[_TNL_ATTRIB_POS] != 0 ||
+ node->count == 0);
+
+ /* Maybe calculate normal lengths:
+ */
+ if (tnl->CalcDListNormalLengths &&
+ node->attrsz[_TNL_ATTRIB_NORMAL] == 3 &&
+ !node->dangling_attr_ref)
+ build_normal_lengths( node );
+
+ tnl->save.vertex_store->used += tnl->save.vertex_size * node->count;
+ tnl->save.prim_store->used += node->prim_count;
+
+ /* Decide whether the storage structs are full, or can be used for
+ * the next vertex lists as well.
+ */
+ if (tnl->save.vertex_store->used >
+ SAVE_BUFFER_SIZE - 16 * (tnl->save.vertex_size + 4)) {
+
+ tnl->save.vertex_store->refcount--;
+ assert(tnl->save.vertex_store->refcount != 0);
+ tnl->save.vertex_store = alloc_vertex_store( ctx );
+ tnl->save.vbptr = tnl->save.vertex_store->buffer;
+ }
+
+ if (tnl->save.prim_store->used > SAVE_PRIM_SIZE - 6) {
+ tnl->save.prim_store->refcount--;
+ assert(tnl->save.prim_store->refcount != 0);
+ tnl->save.prim_store = alloc_prim_store( ctx );
+ }
+
+ /* Reset our structures for the next run of vertices:
+ */
+ _save_reset_counters( ctx );
+
+ /* Copy duplicated vertices
+ */
+ tnl->save.copied.nr = _save_copy_vertices( ctx, node );
+
+
+ /* Deal with GL_COMPILE_AND_EXECUTE:
+ */
+ if (ctx->ExecuteFlag) {
+ _tnl_playback_vertex_list( ctx, (void *) node );
+ }
+}
+
+
+/* TODO -- If no new vertices have been stored, don't bother saving
+ * it.
+ */
+static void _save_wrap_buffers( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i = tnl->save.prim_count - 1;
+ GLenum mode;
+
+ assert(i < (GLint) tnl->save.prim_max);
+ assert(i >= 0);
+
+ /* Close off in-progress primitive.
+ */
+ tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
+ tnl->save.prim[i].start);
+ mode = tnl->save.prim[i].mode & ~(PRIM_BEGIN|PRIM_END);
+
+ /* store the copied vertices, and allocate a new list.
+ */
+ _save_compile_vertex_list( ctx );
+
+ /* Restart interrupted primitive
+ */
+ tnl->save.prim[0].mode = mode;
+ tnl->save.prim[0].start = 0;
+ tnl->save.prim[0].count = 0;
+ tnl->save.prim_count = 1;
+}
+
+
+
+/* Called only when buffers are wrapped as the result of filling the
+ * vertex_store struct.
+ */
+static void _save_wrap_filled_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat *data = tnl->save.copied.buffer;
+ GLuint i;
+
+ /* Emit a glEnd to close off the last vertex list.
+ */
+ _save_wrap_buffers( ctx );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(tnl->save.counter > tnl->save.copied.nr);
+
+ for (i = 0 ; i < tnl->save.copied.nr ; i++) {
+ _mesa_memcpy( tnl->save.vbptr, data, tnl->save.vertex_size * sizeof(GLfloat));
+ data += tnl->save.vertex_size;
+ tnl->save.vbptr += tnl->save.vertex_size;
+ tnl->save.counter--;
+ }
+}
+
+
+static void _save_copy_to_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->save.attrsz[i]) {
+ tnl->save.currentsz[i][0] = tnl->save.attrsz[i];
+ ASSIGN_4V(tnl->save.current[i], 0, 0, 0, 1);
+ COPY_SZ_4V(tnl->save.current[i],
+ tnl->save.attrsz[i],
+ tnl->save.attrptr[i]);
+ }
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ ctx->ListState.ActiveEdgeFlag = 1;
+ ctx->ListState.CurrentEdgeFlag =
+ (tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
+ }
+}
+
+
+static void _save_copy_from_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
+ switch (tnl->save.attrsz[i]) {
+ case 4: tnl->save.attrptr[i][3] = tnl->save.current[i][3];
+ case 3: tnl->save.attrptr[i][2] = tnl->save.current[i][2];
+ case 2: tnl->save.attrptr[i][1] = tnl->save.current[i][1];
+ case 1: tnl->save.attrptr[i][0] = tnl->save.current[i][0];
+ case 0: break;
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG])
+ tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
+ (GLfloat)ctx->ListState.CurrentEdgeFlag;
+}
+
+
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void _save_upgrade_vertex( GLcontext *ctx,
+ GLuint attr,
+ GLuint newsz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldsz;
+ GLuint i;
+ GLfloat *tmp;
+
+ /* Store the current run of vertices, and emit a GL_END. Emit a
+ * BEGIN in the new buffer.
+ */
+ if (tnl->save.initial_counter != tnl->save.counter)
+ _save_wrap_buffers( ctx );
+ else
+ assert( tnl->save.copied.nr == 0 );
+
+ /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
+ * when the attribute already exists in the vertex and is having
+ * its size increased.
+ */
+ _save_copy_to_current( ctx );
+
+ /* Fix up sizes:
+ */
+ oldsz = tnl->save.attrsz[attr];
+ tnl->save.attrsz[attr] = newsz;
+
+ tnl->save.vertex_size += newsz - oldsz;
+ tnl->save.counter = ((SAVE_BUFFER_SIZE - tnl->save.vertex_store->used) /
+ tnl->save.vertex_size);
+ if (tnl->save.counter > ctx->Const.MaxArrayLockSize )
+ tnl->save.counter = ctx->Const.MaxArrayLockSize;
+ tnl->save.initial_counter = tnl->save.counter;
+
+ /* Recalculate all the attrptr[] values:
+ */
+ for (i = 0, tmp = tnl->save.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
+ if (tnl->save.attrsz[i]) {
+ tnl->save.attrptr[i] = tmp;
+ tmp += tnl->save.attrsz[i];
+ }
+ else
+ tnl->save.attrptr[i] = 0; /* will not be dereferenced. */
+ }
+
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ _save_copy_from_current( ctx );
+
+ /* Replay stored vertices to translate them to new format here.
+ *
+ * If there are copied vertices and the new (upgraded) attribute
+ * has not been defined before, this list is somewhat degenerate,
+ * and will need fixup at runtime.
+ */
+ if (tnl->save.copied.nr)
+ {
+ GLfloat *data = tnl->save.copied.buffer;
+ GLfloat *dest = tnl->save.buffer;
+ GLuint j;
+
+ /* Need to note this and fix up at runtime (or loopback):
+ */
+ if (tnl->save.currentsz[attr][0] == 0) {
+ assert(oldsz == 0);
+ tnl->save.dangling_attr_ref = GL_TRUE;
+ _mesa_debug(0, "_save_upgrade_vertex: dangling reference attr %d\n",
+ attr);
+
+#if 0
+ /* The current strategy is to punt these degenerate cases
+ * through _tnl_loopback_vertex_list(), a lower-performance
+ * option. To minimize the impact of this, artificially
+ * reduce the size of this vertex_list.
+ */
+ if (t->save.counter > 10) {
+ t->save.initial_counter = 10;
+ t->save.counter = 10;
+ }
+#endif
+ }
+
+ for (i = 0 ; i < tnl->save.copied.nr ; i++) {
+ for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
+ if (tnl->save.attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ ASSIGN_4V( dest, 0, 0, 0, 1 );
+ COPY_SZ_4V( dest, oldsz, data );
+ data += oldsz;
+ dest += newsz;
+ }
+ else {
+ COPY_SZ_4V( dest, newsz, tnl->save.current[attr] );
+ dest += newsz;
+ }
+ }
+ else {
+ GLint sz = tnl->save.attrsz[j];
+ COPY_SZ_4V( dest, sz, data );
+ data += sz;
+ dest += sz;
+ }
+ }
+ }
+ }
+
+ tnl->save.vbptr = dest;
+ tnl->save.counter -= tnl->save.copied.nr;
+ }
+}
+
+
+
+
+/* Helper function for 'CHOOSE' macro. Do what's necessary when an
+ * entrypoint is called for the first time.
+ */
+static void do_choose( GLuint attr, GLuint sz,
+ void (*attr_func)( const GLfloat *),
+ void (*choose1)( const GLfloat *),
+ void (*choose2)( const GLfloat *),
+ void (*choose3)( const GLfloat *),
+ void (*choose4)( const GLfloat *),
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ static GLfloat id[4] = { 0, 0, 0, 1 };
+ int i;
+
+ if (tnl->save.attrsz[attr] < sz) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ _save_upgrade_vertex( ctx, attr, sz );
+ }
+ else {
+ /* New size is equal or smaller - just need to fill in some
+ * zeros.
+ */
+ for (i = sz ; i <= tnl->save.attrsz[attr] ; i++)
+ tnl->save.attrptr[attr][i-1] = id[i-1];
+ }
+
+ /* Reset any active pointers for this attribute
+ */
+ tnl->save.tabfv[attr][0] = choose1;
+ tnl->save.tabfv[attr][1] = choose2;
+ tnl->save.tabfv[attr][2] = choose3;
+ tnl->save.tabfv[attr][3] = choose4;
+
+ /* Update the secondary dispatch table with the new function
+ */
+ tnl->save.tabfv[attr][sz-1] = attr_func;
+
+ (*attr_func)(v);
+}
+
+
+
+/* Only one size for each attribute may be active at once. Eg. if
+ * Color3f is installed/active, then Color4f may not be, even if the
+ * vertex actually contains 4 color coordinates. This is because the
+ * 3f version won't otherwise set color[3] to 1.0 -- this is the job
+ * of the chooser function when switching between Color4f and Color3f.
+ */
+#define ATTRFV( ATTR, N ) \
+static void save_choose_##ATTR##_##N( const GLfloat *v ); \
+ \
+static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if ((ATTR) == 0) { \
+ GLuint i; \
+ \
+ if (N>0) tnl->save.vbptr[0] = v[0]; \
+ if (N>1) tnl->save.vbptr[1] = v[1]; \
+ if (N>2) tnl->save.vbptr[2] = v[2]; \
+ if (N>3) tnl->save.vbptr[3] = v[3]; \
+ \
+ for (i = N; i < tnl->save.vertex_size; i++) \
+ tnl->save.vbptr[i] = tnl->save.vertex[i]; \
+ \
+ tnl->save.vbptr += tnl->save.vertex_size; \
+ \
+ if (--tnl->save.counter == 0) \
+ _save_wrap_filled_vertex( ctx ); \
+ } \
+ else { \
+ GLfloat *dest = tnl->save.attrptr[ATTR]; \
+ if (N>0) dest[0] = v[0]; \
+ if (N>1) dest[1] = v[1]; \
+ if (N>2) dest[2] = v[2]; \
+ if (N>3) dest[3] = v[3]; \
+ } \
+}
+
+#define CHOOSE( ATTR, N ) \
+static void save_choose_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ do_choose(ATTR, N, \
+ save_attrib_##ATTR##_##N, \
+ save_choose_##ATTR##_1, \
+ save_choose_##ATTR##_2, \
+ save_choose_##ATTR##_3, \
+ save_choose_##ATTR##_4, \
+ v ); \
+}
+
+#define INIT(ATTR) \
+static void save_init_##ATTR( TNLcontext *tnl ) \
+{ \
+ tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
+ tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
+ tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
+ tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
+}
+
+#define ATTRS( ATTRIB ) \
+ ATTRFV( ATTRIB, 1 ) \
+ ATTRFV( ATTRIB, 2 ) \
+ ATTRFV( ATTRIB, 3 ) \
+ ATTRFV( ATTRIB, 4 ) \
+ CHOOSE( ATTRIB, 1 ) \
+ CHOOSE( ATTRIB, 2 ) \
+ CHOOSE( ATTRIB, 3 ) \
+ CHOOSE( ATTRIB, 4 ) \
+ INIT( ATTRIB ) \
+
+
+/* Generate a lot of functions. These are the actual worker
+ * functions, which are equivalent to those generated via codegen
+ * elsewhere.
+ */
+ATTRS( 0 )
+ATTRS( 1 )
+ATTRS( 2 )
+ATTRS( 3 )
+ATTRS( 4 )
+ATTRS( 5 )
+ATTRS( 6 )
+ATTRS( 7 )
+ATTRS( 8 )
+ATTRS( 9 )
+ATTRS( 10 )
+ATTRS( 11 )
+ATTRS( 12 )
+ATTRS( 13 )
+ATTRS( 14 )
+ATTRS( 15 )
+
+
+static void _save_reset_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ save_init_0( tnl );
+ save_init_1( tnl );
+ save_init_2( tnl );
+ save_init_3( tnl );
+ save_init_4( tnl );
+ save_init_5( tnl );
+ save_init_6( tnl );
+ save_init_7( tnl );
+ save_init_8( tnl );
+ save_init_9( tnl );
+ save_init_10( tnl );
+ save_init_11( tnl );
+ save_init_12( tnl );
+ save_init_13( tnl );
+ save_init_14( tnl );
+ save_init_15( tnl );
+
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ tnl->save.attrsz[i] = 0;
+
+ tnl->save.vertex_size = 0;
+ tnl->save.have_materials = 0;
+
+ _save_reset_counters( ctx );
+}
+
+
+
+/* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
+ * of glMultTexCoord and glProgramParamterNV by routing all these
+ * through a second level dispatch table.
+ */
+#define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
+do { \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ tnl->save.tabfv[ATTR][COUNT-1]( P ); \
+} while (0)
+
+#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
+#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
+#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
+#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
+
+#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
+
+#if defined(USE_X86_ASM) && 0 /* will break register calling convention */
+/* Naughty cheat:
+ */
+#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
+#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
+#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
+#else
+/* Safe:
+ */
+#define DISPATCH_ATTR2F( ATTR, S,T ) \
+do { \
+ GLfloat v[2]; \
+ v[0] = S; v[1] = T; \
+ DISPATCH_ATTR2FV( ATTR, v ); \
+} while (0)
+#define DISPATCH_ATTR3F( ATTR, S,T,R ) \
+do { \
+ GLfloat v[3]; \
+ v[0] = S; v[1] = T; v[2] = R; \
+ DISPATCH_ATTR3FV( ATTR, v ); \
+} while (0)
+#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
+do { \
+ GLfloat v[4]; \
+ v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
+ DISPATCH_ATTR4FV( ATTR, v ); \
+} while (0)
+#endif
+
+
+static void enum_error( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
+}
+
+static void GLAPIENTRY _save_Vertex2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
+}
+
+static void GLAPIENTRY _save_Vertex2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
+}
+
+static void GLAPIENTRY _save_Vertex3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_Vertex4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_TexCoord1f( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
+}
+
+static void GLAPIENTRY _save_TexCoord1fv( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
+}
+
+static void GLAPIENTRY _save_TexCoord2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
+}
+
+static void GLAPIENTRY _save_TexCoord3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_TexCoord4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_Normal3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
+}
+
+static void GLAPIENTRY _save_Normal3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
+}
+
+static void GLAPIENTRY _save_FogCoordfEXT( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
+}
+
+static void GLAPIENTRY _save_FogCoordfvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
+}
+
+static void GLAPIENTRY _save_Color3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
+}
+
+static void GLAPIENTRY _save_Color3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _save_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_Color4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _save_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
+}
+
+static void GLAPIENTRY _save_SecondaryColor3fvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord1f( GLenum target, GLfloat x )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1F( attr, x );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord1fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2F( attr, x, y );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord2fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z)
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3F( attr, x, y, z );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord3fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4F( attr, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord4fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4FV( attr, v );
+}
+
+static void GLAPIENTRY _save_VertexAttrib1fNV( GLuint index, GLfloat x )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR1F( index, x );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR1FV( index, v );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR2F( index, x, y );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR2FV( index, v );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y,
+ GLfloat z )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR3F( index, x, y, z );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR3FV( index, v );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR4F( index, x, y, z, w );
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY _save_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
+{
+ if (index < VERT_ATTRIB_MAX)
+ DISPATCH_ATTR4FV( index, v );
+ else
+ enum_error();
+}
+
+
+/* Materials:
+ *
+ * These are treated as per-vertex attributes, at indices above where
+ * the NV_vertex_program leaves off. There are a lot of good things
+ * about treating materials this way.
+ *
+ * However: I don't want to double the number of generated functions
+ * just to cope with this, so I unroll the 'C' varients of CHOOSE and
+ * ATTRF into this function, and dispense with codegen and
+ * second-level dispatch.
+ *
+ * There is no aliasing of material attributes with other entrypoints.
+ */
+#define MAT_ATTR( A, N, params ) \
+do { \
+ if (tnl->save.attrsz[A] < N) { \
+ _save_upgrade_vertex( ctx, A, N ); \
+ tnl->save.have_materials = GL_TRUE; \
+ } \
+ \
+ { \
+ GLfloat *dest = tnl->save.attrptr[A]; \
+ if (N>0) dest[0] = params[0]; \
+ if (N>1) dest[1] = params[1]; \
+ if (N>2) dest[2] = params[2]; \
+ if (N>3) dest[3] = params[3]; \
+ } \
+} while (0)
+
+
+#define MAT( ATTR, N, face, params ) \
+do { \
+ if (face != GL_BACK) \
+ MAT_ATTR( ATTR, N, params ); /* front */ \
+ if (face != GL_FRONT) \
+ MAT_ATTR( ATTR + 1, N, params ); /* back */ \
+} while (0)
+
+
+/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
+ * later on - in the meantime just store everything.
+ */
+static void GLAPIENTRY _save_Materialfv( GLenum face, GLenum pname,
+ const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ switch (pname) {
+ case GL_EMISSION:
+ MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+ break;
+ case GL_AMBIENT:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ break;
+ case GL_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ case GL_SPECULAR:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+ break;
+ case GL_SHININESS:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+ break;
+ case GL_COLOR_INDEXES:
+ MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ default:
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
+ return;
+ }
+}
+
+
+#define IDX_ATTR( A, IDX ) \
+do { \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if (tnl->save.attrsz[A] < 1) { \
+ _save_upgrade_vertex( ctx, A, 1 ); \
+ } \
+ \
+ { \
+ GLfloat *dest = tnl->save.attrptr[A]; \
+ dest[0] = IDX; \
+ } \
+} while (0)
+
+
+static void GLAPIENTRY _save_EdgeFlag( GLboolean b )
+{
+ IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
+}
+
+static void GLAPIENTRY _save_EdgeFlagv( const GLboolean *v )
+{
+ IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)(v[0]) );
+}
+
+static void GLAPIENTRY _save_Indexf( GLfloat f )
+{
+ IDX_ATTR( _TNL_ATTRIB_INDEX, f );
+}
+
+static void GLAPIENTRY _save_Indexfv( const GLfloat *f )
+{
+ IDX_ATTR( _TNL_ATTRIB_INDEX, f[0] );
+}
+
+
+
+
+/* Cope with EvalCoord/CallList called within a begin/end object:
+ * -- Flush current buffer
+ * -- Fallback to opcodes for the rest of the begin/end object.
+ */
+#define FALLBACK(ctx) \
+do { \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
+ \
+ if (tnl->save.initial_counter != tnl->save.counter || \
+ tnl->save.prim_count) \
+ _save_compile_vertex_list( ctx ); \
+ \
+ _save_copy_to_current( ctx ); \
+ _save_reset_vertex( ctx ); \
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
+ ctx->Driver.SaveNeedFlush = 0; \
+} while (0)
+
+static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalCoord1f( u );
+}
+
+static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalCoord1fv( v );
+}
+
+static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalCoord2f( u, v );
+}
+
+static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalCoord2fv( v );
+}
+
+static void GLAPIENTRY _save_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalPoint1( i );
+}
+
+static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->EvalPoint2( i, j );
+}
+
+static void GLAPIENTRY _save_CallList( GLuint l )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->CallList( l );
+}
+
+static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ ctx->Save->CallLists( n, type, v );
+}
+
+
+
+
+/* This begin is hooked into ... Updating of
+ * ctx->Driver.CurrentSavePrimitive is already taken care of.
+ */
+static GLboolean _save_NotifyBegin( GLcontext *ctx, GLenum mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (1) {
+ GLuint i = tnl->save.prim_count++;
+
+ assert(i < tnl->save.prim_max);
+ tnl->save.prim[i].mode = mode | PRIM_BEGIN;
+ tnl->save.prim[i].start = tnl->save.initial_counter - tnl->save.counter;
+ tnl->save.prim[i].count = 0;
+
+ _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );
+ ctx->Driver.SaveNeedFlush = 1;
+ return GL_TRUE;
+ }
+ else
+ return GL_FALSE;
+}
+
+
+
+static void GLAPIENTRY _save_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i = tnl->save.prim_count - 1;
+
+ ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+ tnl->save.prim[i].mode |= PRIM_END;
+ tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
+ tnl->save.prim[i].start);
+
+ if (i == (GLint) tnl->save.prim_max - 1) {
+ _save_compile_vertex_list( ctx );
+ assert(tnl->save.copied.nr == 0);
+ }
+
+ /* Swap out this vertex format while outside begin/end. Any color,
+ * etc. received between here and the next begin will be compiled
+ * as opcodes.
+ */
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
+
+/* These are all errors as this vtxfmt is only installed inside
+ * begin/end pairs.
+ */
+static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) count; (void) type; (void) indices;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
+}
+
+
+static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
+}
+
+static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) start; (void) count;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
+}
+
+static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) x1; (void) y1; (void) x2; (void) y2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
+}
+
+static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) i1; (void) i2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
+}
+
+static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
+ GLint j1, GLint j2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
+}
+
+static void GLAPIENTRY _save_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ (void) mode;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
+}
+
+
+/* Unlike the functions above, these are to be hooked into the vtxfmt
+ * maintained in ctx->ListState, active when the list is known or
+ * suspected to be outside any begin/end primitive.
+ */
+static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _save_NotifyBegin( ctx, GL_QUADS | PRIM_WEAK );
+ GL_CALL(Vertex2f)( x1, y1 );
+ GL_CALL(Vertex2f)( x2, y1 );
+ GL_CALL(Vertex2f)( x2, y2 );
+ GL_CALL(Vertex2f)( x1, y2 );
+ GL_CALL(End)();
+}
+
+
+static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ _save_NotifyBegin( ctx, mode | PRIM_WEAK );
+ for (i = 0; i < count; i++)
+ GL_CALL(ArrayElement)(start + i);
+ GL_CALL(End)();
+}
+
+
+static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+ return;
+
+ _save_NotifyBegin( ctx, mode | PRIM_WEAK );
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ for (i = 0 ; i < count ; i++)
+ GL_CALL(ArrayElement)( ((GLubyte *)indices)[i] );
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (i = 0 ; i < count ; i++)
+ GL_CALL(ArrayElement)( ((GLushort *)indices)[i] );
+ break;
+ case GL_UNSIGNED_INT:
+ for (i = 0 ; i < count ; i++)
+ GL_CALL(ArrayElement)( ((GLuint *)indices)[i] );
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
+ break;
+ }
+
+ GL_CALL(End)();
+}
+
+static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (_mesa_validate_DrawRangeElements( ctx, mode,
+ start, end,
+ count, type, indices ))
+ _save_OBE_DrawElements( mode, count, type, indices );
+}
+
+
+
+
+
+static void _save_vtxfmt_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLvertexformat *vfmt = &tnl->save_vtxfmt;
+
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Begin = _save_Begin;
+ vfmt->Color3f = _save_Color3f;
+ vfmt->Color3fv = _save_Color3fv;
+ vfmt->Color4f = _save_Color4f;
+ vfmt->Color4fv = _save_Color4fv;
+ vfmt->EdgeFlag = _save_EdgeFlag;
+ vfmt->EdgeFlagv = _save_EdgeFlagv;
+ vfmt->End = _save_End;
+ vfmt->FogCoordfEXT = _save_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
+ vfmt->Indexf = _save_Indexf;
+ vfmt->Indexfv = _save_Indexfv;
+ vfmt->Materialfv = _save_Materialfv;
+ vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
+ vfmt->Normal3f = _save_Normal3f;
+ vfmt->Normal3fv = _save_Normal3fv;
+ vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
+ vfmt->TexCoord1f = _save_TexCoord1f;
+ vfmt->TexCoord1fv = _save_TexCoord1fv;
+ vfmt->TexCoord2f = _save_TexCoord2f;
+ vfmt->TexCoord2fv = _save_TexCoord2fv;
+ vfmt->TexCoord3f = _save_TexCoord3f;
+ vfmt->TexCoord3fv = _save_TexCoord3fv;
+ vfmt->TexCoord4f = _save_TexCoord4f;
+ vfmt->TexCoord4fv = _save_TexCoord4fv;
+ vfmt->Vertex2f = _save_Vertex2f;
+ vfmt->Vertex2fv = _save_Vertex2fv;
+ vfmt->Vertex3f = _save_Vertex3f;
+ vfmt->Vertex3fv = _save_Vertex3fv;
+ vfmt->Vertex4f = _save_Vertex4f;
+ vfmt->Vertex4fv = _save_Vertex4fv;
+ vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
+
+ /* This will all require us to fallback to saving the list as opcodes:
+ */
+ vfmt->CallList = _save_CallList; /* inside begin/end */
+ vfmt->CallLists = _save_CallLists; /* inside begin/end */
+ vfmt->EvalCoord1f = _save_EvalCoord1f;
+ vfmt->EvalCoord1fv = _save_EvalCoord1fv;
+ vfmt->EvalCoord2f = _save_EvalCoord2f;
+ vfmt->EvalCoord2fv = _save_EvalCoord2fv;
+ vfmt->EvalPoint1 = _save_EvalPoint1;
+ vfmt->EvalPoint2 = _save_EvalPoint2;
+
+ /* These are all errors as we at least know we are in some sort of
+ * begin/end pair:
+ */
+ vfmt->EvalMesh1 = _save_EvalMesh1;
+ vfmt->EvalMesh2 = _save_EvalMesh2;
+ vfmt->Begin = _save_Begin;
+ vfmt->Rectf = _save_Rectf;
+ vfmt->DrawArrays = _save_DrawArrays;
+ vfmt->DrawElements = _save_DrawElements;
+ vfmt->DrawRangeElements = _save_DrawRangeElements;
+
+}
+
+
+void _tnl_SaveFlushVertices( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* Noop when we are actually active:
+ */
+ if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
+ ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
+ return;
+
+ if (tnl->save.initial_counter != tnl->save.counter ||
+ tnl->save.prim_count)
+ _save_compile_vertex_list( ctx );
+
+ _save_copy_to_current( ctx );
+ _save_reset_vertex( ctx );
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ (void) list; (void) mode;
+
+ if (!tnl->save.prim_store)
+ tnl->save.prim_store = alloc_prim_store( ctx );
+
+ if (!tnl->save.vertex_store) {
+ tnl->save.vertex_store = alloc_vertex_store( ctx );
+ tnl->save.vbptr = tnl->save.vertex_store->buffer;
+ }
+
+ _save_reset_vertex( ctx );
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+void _tnl_EndList( GLcontext *ctx )
+{
+ (void) ctx;
+ assert(TNL_CONTEXT(ctx)->save.vertex_size == 0);
+}
+
+void _tnl_BeginCallList( GLcontext *ctx, GLuint list )
+{
+ (void) ctx; (void) list;
+}
+
+void _tnl_EndCallList( GLcontext *ctx )
+{
+ (void) ctx;
+}
+
+
+static void _tnl_destroy_vertex_list( GLcontext *ctx, void *data )
+{
+ struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
+ (void) ctx;
+
+ if ( --node->vertex_store->refcount == 0 )
+ FREE( node->vertex_store );
+
+ if ( --node->prim_store->refcount == 0 )
+ FREE( node->prim_store );
+
+ if ( node->normal_lengths )
+ FREE( node->normal_lengths );
+}
+
+
+static void _tnl_print_vertex_list( GLcontext *ctx, void *data )
+{
+ struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
+ GLuint i;
+ (void) ctx;
+
+ _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
+ node->count,
+ node->prim_count,
+ node->vertex_size);
+
+ for (i = 0 ; i < node->prim_count ; i++) {
+ struct tnl_prim *prim = &node->prim[i];
+ _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
+ i,
+ _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
+ prim->start,
+ prim->start + prim->count,
+ (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
+ (prim->mode & PRIM_END) ? "END" : "(wrap)");
+ }
+}
+
+
+static void _save_current_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ for (i = 0; i < _TNL_ATTRIB_MAT_FRONT_AMBIENT; i++) {
+ ASSERT(i < VERT_ATTRIB_MAX);
+ tnl->save.currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
+ tnl->save.current[i] = ctx->ListState.CurrentAttrib[i];
+ }
+
+ for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT; i < _TNL_ATTRIB_INDEX; i++) {
+ const GLuint j = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
+ ASSERT(j < MAT_ATTRIB_MAX);
+ tnl->save.currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
+ tnl->save.current[i] = ctx->ListState.CurrentMaterial[j];
+ }
+
+ tnl->save.currentsz[_TNL_ATTRIB_INDEX] = &ctx->ListState.ActiveIndex;
+ tnl->save.current[_TNL_ATTRIB_INDEX] = &ctx->ListState.CurrentIndex;
+
+ /* Current edgeflag is handled individually */
+}
+
+/**
+ * Initialize the display list compiler
+ */
+void _tnl_save_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
+ GLuint i;
+
+
+ for (i = 0; i < _TNL_ATTRIB_MAX; i++)
+ _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
+
+ tnl->save.opcode_vertex_list =
+ _mesa_alloc_opcode( ctx,
+ sizeof(struct tnl_vertex_list),
+ _tnl_playback_vertex_list,
+ _tnl_destroy_vertex_list,
+ _tnl_print_vertex_list );
+
+ ctx->Driver.NotifySaveBegin = _save_NotifyBegin;
+
+ _save_vtxfmt_init( ctx );
+ _save_current_init( ctx );
+
+ /* Hook our array functions into the outside-begin-end vtxfmt in
+ * ctx->ListState.
+ */
+ ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
+ ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
+ ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
+ ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
+
+/**
+ * Deallocate the immediate-mode buffer for the given context, if
+ * its reference count goes to zero.
+ */
+void _tnl_save_destroy( GLcontext *ctx )
+{
+ (void) ctx;
+}
diff --git a/src/mesa/tnl/t_save_api.h b/src/mesa/tnl/t_save_api.h
new file mode 100644
index 0000000..eec2d68
--- /dev/null
+++ b/src/mesa/tnl/t_save_api.h
@@ -0,0 +1,58 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __T_SAVE_API_H__
+#define __T_SAVE_API_H__
+
+#include "t_context.h"
+
+extern GLboolean _tnl_weak_begin( GLcontext *ctx, GLenum mode );
+
+extern void _tnl_EndList( GLcontext *ctx );
+extern void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode );
+
+extern void _tnl_EndCallList( GLcontext *ctx );
+extern void _tnl_BeginCallList( GLcontext *ctx, GLuint list );
+
+extern void _tnl_SaveFlushVertices( GLcontext *ctx );
+
+extern void _tnl_save_init( GLcontext *ctx );
+extern void _tnl_save_destroy( GLcontext *ctx );
+
+extern void _tnl_loopback_vertex_list( GLcontext *ctx,
+ const struct tnl_vertex_list *list );
+
+extern void _tnl_playback_vertex_list( GLcontext *ctx, void *data );
+
+#endif
diff --git a/src/mesa/tnl/t_save_loopback.c b/src/mesa/tnl/t_save_loopback.c
new file mode 100644
index 0000000..2e752c8
--- /dev/null
+++ b/src/mesa/tnl/t_save_loopback.c
@@ -0,0 +1,307 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2003 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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "glapi.h"
+#include "imports.h"
+#include "macros.h"
+#include "mtypes.h"
+#include "t_context.h"
+#include "t_save_api.h"
+
+/* If someone compiles a display list like:
+ * glBegin(Triangles)
+ * glVertex()
+ * ... lots of vertices ...
+ * glEnd()
+ *
+ * or:
+ * glDrawArrays(...)
+ *
+ * and then tries to execute it like this:
+ *
+ * glBegin(Lines)
+ * glCallList()
+ * glEnd()
+ *
+ * it will wind up in here, as the vertex copying used when wrapping
+ * buffers in list compilation (Triangles) won't be right for how the
+ * list is being executed (as Lines).
+ *
+ * This could be avoided by not compiling as vertex_lists until after
+ * the first glEnd() has been seen. However, that would miss an
+ * important category of display lists, for the sake of a degenerate
+ * usage.
+ *
+ * Further, replaying degenerately-called lists in this fashion is
+ * probably still faster than the replay using opcodes.
+ */
+
+typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
+
+
+/* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
+static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ ctx->Exec->VertexAttrib1fvNV(target, v);
+}
+
+static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ ctx->Exec->VertexAttrib2fvNV(target, v);
+}
+
+static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ ctx->Exec->VertexAttrib3fvNV(target, v);
+}
+
+static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ ctx->Exec->VertexAttrib4fvNV(target, v);
+}
+
+static attr_func vert_attrfunc[4] = {
+ VertexAttrib1fvNV,
+ VertexAttrib2fvNV,
+ VertexAttrib3fvNV,
+ VertexAttrib4fvNV
+};
+
+
+static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
+{
+ switch (target) {
+ case _TNL_ATTRIB_MAT_FRONT_SHININESS:
+ ctx->Exec->Materialfv( GL_FRONT, GL_SHININESS, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_SHININESS:
+ ctx->Exec->Materialfv( GL_BACK, GL_SHININESS, v );
+ break;
+ }
+}
+
+
+static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
+{
+ switch (target) {
+ case _TNL_ATTRIB_MAT_FRONT_INDEXES:
+ ctx->Exec->Materialfv( GL_FRONT, GL_COLOR_INDEXES, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_INDEXES:
+ ctx->Exec->Materialfv( GL_BACK, GL_COLOR_INDEXES, v );
+ break;
+ }
+}
+
+
+static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
+{
+ switch (target) {
+ case _TNL_ATTRIB_MAT_FRONT_EMISSION:
+ ctx->Exec->Materialfv( GL_FRONT, GL_EMISSION, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_EMISSION:
+ ctx->Exec->Materialfv( GL_BACK, GL_EMISSION, v );
+ break;
+ case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
+ ctx->Exec->Materialfv( GL_FRONT, GL_AMBIENT, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_AMBIENT:
+ ctx->Exec->Materialfv( GL_BACK, GL_AMBIENT, v );
+ break;
+ case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
+ ctx->Exec->Materialfv( GL_FRONT, GL_DIFFUSE, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
+ ctx->Exec->Materialfv( GL_BACK, GL_DIFFUSE, v );
+ break;
+ case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
+ ctx->Exec->Materialfv( GL_FRONT, GL_SPECULAR, v );
+ break;
+ case _TNL_ATTRIB_MAT_BACK_SPECULAR:
+ ctx->Exec->Materialfv( GL_BACK, GL_SPECULAR, v );
+ break;
+ }
+}
+
+
+static attr_func mat_attrfunc[4] = {
+ mat_attr1fv,
+ 0,
+ mat_attr3fv,
+ mat_attr4fv
+};
+
+
+static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ (void) target;
+ ctx->Exec->Indexf(v[0]);
+}
+
+static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
+{
+ (void) target;
+ ctx->Exec->EdgeFlag((GLboolean)(v[0] == 1.0));
+}
+
+struct loopback_attr {
+ GLint target;
+ GLint sz;
+ attr_func func;
+};
+
+/* Don't emit ends and begins on wrapped primitives. Don't replay
+ * wrapped vertices. If we get here, it's probably because the the
+ * precalculated wrapping is wrong.
+ */
+static void loopback_prim( GLcontext *ctx,
+ const struct tnl_vertex_list *list, GLuint i,
+ const struct loopback_attr *la, GLuint nr )
+{
+ struct tnl_prim *prim = &list->prim[i];
+ GLint begin = prim->start;
+ GLint end = begin + prim->count;
+ GLfloat *data;
+ GLint j;
+ GLuint k;
+
+ if (prim->mode & PRIM_BEGIN) {
+ GL_CALL(Begin)( prim->mode & PRIM_MODE_MASK );
+ }
+ else {
+ assert(i == 0);
+ assert(begin == 0);
+ begin += list->wrap_count;
+ }
+
+ data = list->buffer + begin * list->vertex_size;
+
+ for (j = begin ; j < end ; j++) {
+ GLfloat *tmp = data + la[0].sz;
+
+ for (k = 1 ; k < nr ; k++) {
+ la[k].func( ctx, la[k].target, tmp );
+ tmp += la[k].sz;
+ }
+
+ /* Fire the vertex
+ */
+ la[0].func( ctx, VERT_ATTRIB_POS, data );
+ data = tmp;
+ }
+
+ if (prim->mode & PRIM_END) {
+ GL_CALL(End)();
+ }
+ else {
+ assert (i == list->prim_count-1);
+ }
+}
+
+/* Primitives generated by DrawArrays/DrawElements/Rectf may be
+ * caught here. If there is no primitive in progress, execute them
+ * normally, otherwise need to track and discard the generated
+ * primitives.
+ */
+static void loopback_weak_prim( GLcontext *ctx,
+ const struct tnl_vertex_list *list, GLuint i,
+ const struct loopback_attr *la, GLuint nr )
+{
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
+ loopback_prim( ctx, list, i, la, nr );
+ else {
+ struct tnl_prim *prim = &list->prim[i];
+
+ /* Use the prim_weak flag to ensure that if this primitive
+ * wraps, we don't mistake future vertex_lists for part of the
+ * surrounding primitive.
+ *
+ * While this flag is set, we are simply disposing of data
+ * generated by an operation now known to be a noop.
+ */
+ if (prim->mode & PRIM_BEGIN)
+ ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
+ if (prim->mode & PRIM_END)
+ ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
+ }
+}
+
+
+
+void _tnl_loopback_vertex_list( GLcontext *ctx,
+ const struct tnl_vertex_list *list )
+{
+ struct loopback_attr la[_TNL_ATTRIB_MAX];
+ GLuint i, nr = 0;
+
+ for (i = 0 ; i <= _TNL_ATTRIB_TEX7 ; i++) {
+ if (list->attrsz[i]) {
+ la[nr].target = i;
+ la[nr].sz = list->attrsz[i];
+ la[nr].func = vert_attrfunc[list->attrsz[i]-1];
+ nr++;
+ }
+ }
+
+ for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
+ i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
+ i++) {
+ if (list->attrsz[i]) {
+ la[nr].target = i;
+ la[nr].sz = list->attrsz[i];
+ la[nr].func = mat_attrfunc[list->attrsz[i]-1];
+ nr++;
+ }
+ }
+
+ if (list->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ la[nr].target = _TNL_ATTRIB_EDGEFLAG;
+ la[nr].sz = list->attrsz[_TNL_ATTRIB_EDGEFLAG];
+ la[nr].func = edgeflag_attr1fv;
+ nr++;
+ }
+
+ if (list->attrsz[_TNL_ATTRIB_INDEX]) {
+ la[nr].target = _TNL_ATTRIB_INDEX;
+ la[nr].sz = list->attrsz[_TNL_ATTRIB_INDEX];
+ la[nr].func = index_attr1fv;
+ nr++;
+ }
+
+ for (i = 0 ; i < list->prim_count ; i++) {
+ if (list->prim[i].mode & PRIM_WEAK)
+ loopback_weak_prim( ctx, list, i, la, nr );
+ else
+ loopback_prim( ctx, list, i, la, nr );
+ }
+}
diff --git a/src/mesa/tnl/t_save_playback.c b/src/mesa/tnl/t_save_playback.c
new file mode 100644
index 0000000..dc9ffa8
--- /dev/null
+++ b/src/mesa/tnl/t_save_playback.c
@@ -0,0 +1,224 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "macros.h"
+#include "light.h"
+#include "state.h"
+#include "t_pipeline.h"
+#include "t_save_api.h"
+#include "t_vtx_api.h"
+
+static INLINE GLint get_size( const GLfloat *f )
+{
+ if (f[3] != 1.0) return 4;
+ if (f[2] != 0.0) return 3;
+ return 2;
+}
+
+
+/* Some nasty stuff still hanging on here.
+ *
+ * TODO - remove VB->ColorPtr, etc and just use the AttrPtr's.
+ */
+static void _tnl_bind_vertex_list( GLcontext *ctx,
+ const struct tnl_vertex_list *node )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
+ GLfloat *data = node->buffer;
+ GLuint attr, i;
+
+ /* Setup constant data in the VB.
+ */
+ VB->Count = node->count;
+ VB->Primitive = node->prim;
+ VB->PrimitiveCount = node->prim_count;
+ VB->Elts = NULL;
+ VB->NormalLengthPtr = node->normal_lengths;
+
+ for (attr = 0; attr <= _TNL_ATTRIB_INDEX; attr++) {
+ if (node->attrsz[attr]) {
+ tmp->Attribs[attr].count = node->count;
+ tmp->Attribs[attr].data = (GLfloat (*)[4]) data;
+ tmp->Attribs[attr].start = data;
+ tmp->Attribs[attr].size = node->attrsz[attr];
+ tmp->Attribs[attr].stride = node->vertex_size * sizeof(GLfloat);
+ VB->AttribPtr[attr] = &tmp->Attribs[attr];
+ data += node->attrsz[attr];
+ }
+ else {
+ tmp->Attribs[attr].count = node->count;
+ tmp->Attribs[attr].data = (GLfloat (*)[4]) tnl->vtx.current[attr];
+ tmp->Attribs[attr].start = tnl->vtx.current[attr];
+ tmp->Attribs[attr].size = get_size( tnl->vtx.current[attr] );
+ tmp->Attribs[attr].stride = 0;
+ VB->AttribPtr[attr] = &tmp->Attribs[attr];
+ }
+ }
+
+
+ /* Copy edgeflag to a contiguous array
+ */
+ if (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) {
+ if (node->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ VB->EdgeFlag = _tnl_translate_edgeflag( ctx, data,
+ node->count,
+ node->vertex_size );
+ data++;
+ }
+ else
+ VB->EdgeFlag = _tnl_import_current_edgeflag( ctx, node->count );
+ }
+
+ /* Legacy pointers -- remove one day.
+ */
+ VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
+ VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
+ VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
+ VB->ColorPtr[1] = 0;
+ VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_INDEX];
+ VB->IndexPtr[1] = 0;
+ VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1];
+ VB->SecondaryColorPtr[1] = 0;
+ VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG];
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i];
+ }
+}
+
+static void _playback_copy_to_current( GLcontext *ctx,
+ const struct tnl_vertex_list *node )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ const GLfloat *data;
+ GLuint i;
+
+ if (node->count)
+ data = node->buffer + (node->count-1) * node->vertex_size;
+ else
+ data = node->buffer;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (node->attrsz[i]) {
+ ASSIGN_4V(tnl->vtx.current[i], 0, 0, 0, 1);
+ COPY_SZ_4V(tnl->vtx.current[i], node->attrsz[i], data);
+ data += node->attrsz[i];
+ }
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (node->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ ctx->Current.EdgeFlag = (data[0] == 1.0);
+ }
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
+ }
+
+ if (node->have_materials) {
+ tnl->Driver.NotifyMaterialChange( ctx );
+ }
+
+ /* CurrentExecPrimitive
+ */
+ if (node->prim_count) {
+ GLenum mode = node->prim[node->prim_count - 1].mode;
+ if (mode & PRIM_END)
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ else
+ ctx->Driver.CurrentExecPrimitive = (mode & PRIM_MODE_MASK);
+ }
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ */
+void _tnl_playback_vertex_list( GLcontext *ctx, void *data )
+{
+ const struct tnl_vertex_list *node = (const struct tnl_vertex_list *) data;
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ FLUSH_CURRENT(ctx, 0);
+
+ if (node->prim_count > 0 && node->count > 0) {
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
+ (node->prim[0].mode & PRIM_BEGIN)) {
+
+ /* Degenerate case: list is called inside begin/end pair and
+ * includes operations such as glBegin or glDrawArrays.
+ */
+ _mesa_error( ctx, GL_INVALID_OPERATION, "displaylist recursive begin");
+ _tnl_loopback_vertex_list( ctx, node );
+ return;
+ }
+ else if (tnl->LoopbackDListCassettes ||
+ node->dangling_attr_ref) {
+ /* Degenerate case: list references current data and would
+ * require fixup. Take the easier option & loop it back.
+ */
+ _tnl_loopback_vertex_list( ctx, node );
+ return;
+ }
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ _tnl_bind_vertex_list( ctx, node );
+
+ /* Invalidate all stored data before and after run:
+ */
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+ tnl->Driver.RunPipeline( ctx );
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+ }
+
+ /* Copy to current?
+ */
+ _playback_copy_to_current( ctx, node );
+}
diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h
new file mode 100644
index 0000000..1e3a6b0
--- /dev/null
+++ b/src/mesa/tnl/t_vb_cliptmp.h
@@ -0,0 +1,270 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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 <keith@tungstengraphics.com>
+ */
+
+
+#define CLIP_DOTPROD(K, A, B, C, D) X(K)*A + Y(K)*B + Z(K)*C + W(K)*D
+
+#define POLY_CLIP( PLANE, A, B, C, D ) \
+do { \
+ if (mask & PLANE) { \
+ GLuint idxPrev = inlist[0]; \
+ GLfloat dpPrev = CLIP_DOTPROD(idxPrev, A, B, C, D ); \
+ GLuint outcount = 0; \
+ GLuint i; \
+ \
+ inlist[n] = inlist[0]; /* prevent rotation of vertices */ \
+ for (i = 1; i <= n; i++) { \
+ GLuint idx = inlist[i]; \
+ GLfloat dp = CLIP_DOTPROD(idx, A, B, C, D ); \
+ \
+ clipmask[idxPrev] |= PLANE; \
+ if (!IS_NEGATIVE(dpPrev)) { \
+ outlist[outcount++] = idxPrev; \
+ clipmask[idxPrev] &= ~PLANE; \
+ } \
+ \
+ if (DIFFERENT_SIGNS(dp, dpPrev)) { \
+ GLuint newvert = VB->LastClipped++; \
+ VB->ClipMask[newvert] = 0; \
+ outlist[outcount++] = newvert; \
+ if (IS_NEGATIVE(dp)) { \
+ /* Going out of bounds. Avoid division by zero as we \
+ * know dp != dpPrev from DIFFERENT_SIGNS, above. \
+ */ \
+ GLfloat t = dp / (dp - dpPrev); \
+ INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
+ interp( ctx, t, newvert, idx, idxPrev, GL_TRUE ); \
+ } else { \
+ /* Coming back in. \
+ */ \
+ GLfloat t = dpPrev / (dpPrev - dp); \
+ INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
+ interp( ctx, t, newvert, idxPrev, idx, GL_FALSE ); \
+ } \
+ } \
+ \
+ idxPrev = idx; \
+ dpPrev = dp; \
+ } \
+ \
+ if (outcount < 3) \
+ return; \
+ \
+ { \
+ GLuint *tmp = inlist; \
+ inlist = outlist; \
+ outlist = tmp; \
+ n = outcount; \
+ } \
+ } \
+} while (0)
+
+
+#define LINE_CLIP(PLANE, A, B, C, D ) \
+do { \
+ if (mask & PLANE) { \
+ GLfloat dpI = CLIP_DOTPROD( ii, A, B, C, D ); \
+ GLfloat dpJ = CLIP_DOTPROD( jj, A, B, C, D ); \
+ \
+ if (DIFFERENT_SIGNS(dpI, dpJ)) { \
+ GLuint newvert = VB->LastClipped++; \
+ VB->ClipMask[newvert] = 0; \
+ if (IS_NEGATIVE(dpJ)) { \
+ GLfloat t = dpI / (dpI - dpJ); \
+ VB->ClipMask[jj] |= PLANE; \
+ INTERP_4F( t, coord[newvert], coord[ii], coord[jj] ); \
+ interp( ctx, t, newvert, ii, jj, GL_FALSE ); \
+ jj = newvert; \
+ } else { \
+ GLfloat t = dpJ / (dpJ - dpI); \
+ VB->ClipMask[ii] |= PLANE; \
+ INTERP_4F( t, coord[newvert], coord[jj], coord[ii] ); \
+ interp( ctx, t, newvert, jj, ii, GL_FALSE ); \
+ ii = newvert; \
+ } \
+ } \
+ else if (IS_NEGATIVE(dpI)) \
+ return; \
+ } \
+} while (0)
+
+
+
+/* Clip a line against the viewport and user clip planes.
+ */
+static INLINE void
+TAG(clip_line)( GLcontext *ctx, GLuint i, GLuint j, GLubyte mask )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ tnl_interp_func interp = tnl->Driver.Render.Interp;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint ii = i, jj = j, p;
+
+ VB->LastClipped = VB->Count;
+
+ if (mask & 0x3f) {
+ LINE_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
+ LINE_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
+ LINE_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
+ LINE_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
+ LINE_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
+ LINE_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
+ }
+
+ if (mask & CLIP_USER_BIT) {
+ for (p=0;p<MAX_CLIP_PLANES;p++) {
+ if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
+ 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];
+ LINE_CLIP( CLIP_USER_BIT, a, b, c, d );
+ }
+ }
+ }
+
+ if ((ctx->_TriangleCaps & DD_FLATSHADE) && j != jj)
+ tnl->Driver.Render.CopyPV( ctx, jj, j );
+
+ tnl->Driver.Render.ClippedLine( ctx, ii, jj );
+}
+
+
+/* Clip a triangle against the viewport and user clip planes.
+ */
+static INLINE void
+TAG(clip_tri)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ tnl_interp_func interp = tnl->Driver.Render.Interp;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint pv = v2;
+ GLuint vlist[2][MAX_CLIPPED_VERTICES];
+ GLuint *inlist = vlist[0], *outlist = vlist[1];
+ GLuint p;
+ GLubyte *clipmask = VB->ClipMask;
+ GLuint n = 3;
+
+ ASSIGN_3V(inlist, v2, v0, v1 ); /* pv rotated to slot zero */
+
+ VB->LastClipped = VB->Count;
+
+ if (mask & 0x3f) {
+ POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
+ POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
+ POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
+ POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
+ POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
+ POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
+ }
+
+ if (mask & CLIP_USER_BIT) {
+ for (p=0;p<MAX_CLIP_PLANES;p++) {
+ if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
+ 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];
+ POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
+ }
+ }
+ }
+
+ if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ if (pv != inlist[0]) {
+ ASSERT( inlist[0] >= VB->Count );
+ tnl->Driver.Render.CopyPV( ctx, inlist[0], pv );
+ }
+ }
+
+ tnl->Driver.Render.ClippedPolygon( ctx, inlist, n );
+}
+
+
+/* Clip a quad against the viewport and user clip planes.
+ */
+static INLINE void
+TAG(clip_quad)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3,
+ GLubyte mask )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ tnl_interp_func interp = tnl->Driver.Render.Interp;
+ GLfloat (*coord)[4] = VB->ClipPtr->data;
+ GLuint pv = v3;
+ GLuint vlist[2][MAX_CLIPPED_VERTICES];
+ GLuint *inlist = vlist[0], *outlist = vlist[1];
+ GLuint p;
+ GLubyte *clipmask = VB->ClipMask;
+ GLuint n = 4;
+
+ ASSIGN_4V(inlist, v3, v0, v1, v2 ); /* pv rotated to slot zero */
+
+ VB->LastClipped = VB->Count;
+
+ if (mask & 0x3f) {
+ POLY_CLIP( CLIP_RIGHT_BIT, -1, 0, 0, 1 );
+ POLY_CLIP( CLIP_LEFT_BIT, 1, 0, 0, 1 );
+ POLY_CLIP( CLIP_TOP_BIT, 0, -1, 0, 1 );
+ POLY_CLIP( CLIP_BOTTOM_BIT, 0, 1, 0, 1 );
+ POLY_CLIP( CLIP_FAR_BIT, 0, 0, -1, 1 );
+ POLY_CLIP( CLIP_NEAR_BIT, 0, 0, 1, 1 );
+ }
+
+ if (mask & CLIP_USER_BIT) {
+ for (p=0;p<MAX_CLIP_PLANES;p++) {
+ if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
+ 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];
+ POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
+ }
+ }
+ }
+
+ if (ctx->_TriangleCaps & DD_FLATSHADE) {
+ if (pv != inlist[0]) {
+ ASSERT( inlist[0] >= VB->Count );
+ tnl->Driver.Render.CopyPV( ctx, inlist[0], pv );
+ }
+ }
+
+ tnl->Driver.Render.ClippedPolygon( ctx, inlist, n );
+}
+
+#undef W
+#undef Z
+#undef Y
+#undef X
+#undef SIZE
+#undef TAG
+#undef POLY_CLIP
+#undef LINE_CLIP
diff --git a/src/mesa/tnl/t_vb_cull.c b/src/mesa/tnl/t_vb_cull.c
new file mode 100644
index 0000000..9527ead
--- /dev/null
+++ b/src/mesa/tnl/t_vb_cull.c
@@ -0,0 +1,111 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+
+/* EXT_vertex_cull. Not really a big win, but probably depends on
+ * your application. This stage not included in the default pipeline.
+ */
+static GLboolean run_cull_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+
+ const GLfloat a = ctx->Transform.CullObjPos[0];
+ const GLfloat b = ctx->Transform.CullObjPos[1];
+ const GLfloat c = ctx->Transform.CullObjPos[2];
+ GLfloat *norm = (GLfloat *)VB->NormalPtr->data;
+ GLuint stride = VB->NormalPtr->stride;
+ GLuint count = VB->Count;
+ GLuint i;
+
+ VB->ClipOrMask &= ~CLIP_CULL_BIT;
+ VB->ClipAndMask |= CLIP_CULL_BIT;
+
+ for (i = 0 ; i < count ; i++) {
+ GLfloat dp = (norm[0] * a +
+ norm[1] * b +
+ norm[2] * c);
+
+ if (dp < 0) {
+ VB->ClipMask[i] |= CLIP_CULL_BIT;
+ VB->ClipOrMask |= CLIP_CULL_BIT;
+ }
+ else {
+ VB->ClipMask[i] &= ~CLIP_CULL_BIT;
+ VB->ClipAndMask &= ~CLIP_CULL_BIT;
+ }
+
+ STRIDE_F(norm, stride);
+ }
+
+ return !(VB->ClipAndMask & CLIP_CULL_BIT);
+}
+
+
+static void check_cull( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ stage->active = (!ctx->VertexProgram._Enabled &&
+ ctx->Transform.CullVertexFlag);
+}
+
+
+static void dtr( struct tnl_pipeline_stage *stage )
+{
+}
+
+
+const struct tnl_pipeline_stage _tnl_vertex_cull_stage =
+{
+ "EXT_cull_vertex",
+ _NEW_PROGRAM |
+ _NEW_TRANSFORM,
+ _NEW_TRANSFORM,
+ GL_TRUE, /* active */
+ _TNL_BIT_NORMAL |
+ _TNL_BIT_POS, /* inputs */
+ _TNL_BIT_POS, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ dtr, /* destructor */
+ check_cull, /* check */
+ run_cull_stage /* run -- initially set to init */
+};
diff --git a/src/mesa/tnl/t_vb_fog.c b/src/mesa/tnl/t_vb_fog.c
new file mode 100644
index 0000000..13a2cbb
--- /dev/null
+++ b/src/mesa/tnl/t_vb_fog.c
@@ -0,0 +1,278 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+struct fog_stage_data {
+ GLvector4f fogcoord; /* has actual storage allocated */
+ GLvector4f input; /* points into VB->EyePtr Z values */
+};
+
+#define FOG_STAGE_DATA(stage) ((struct fog_stage_data *)stage->privatePtr)
+
+#define FOG_EXP_TABLE_SIZE 256
+#define FOG_MAX (10.0)
+#define EXP_FOG_MAX .0006595
+#define FOG_INCR (FOG_MAX/FOG_EXP_TABLE_SIZE)
+static GLfloat exp_table[FOG_EXP_TABLE_SIZE];
+static GLfloat inited = 0;
+
+#if 1
+#define NEG_EXP( result, narg ) \
+do { \
+ GLfloat f = (GLfloat) (narg * (1.0/FOG_INCR)); \
+ GLint k = (GLint) f; \
+ if (k > FOG_EXP_TABLE_SIZE-2) \
+ result = (GLfloat) EXP_FOG_MAX; \
+ else \
+ result = exp_table[k] + (f-k)*(exp_table[k+1]-exp_table[k]); \
+} while (0)
+#else
+#define NEG_EXP( result, narg ) \
+do { \
+ result = exp(-narg); \
+} while (0)
+#endif
+
+
+/**
+ * Initialize the exp_table[] lookup table for approximating exp().
+ */
+static void
+init_static_data( void )
+{
+ GLfloat f = 0.0F;
+ GLint i = 0;
+ for ( ; i < FOG_EXP_TABLE_SIZE ; i++, f += FOG_INCR) {
+ exp_table[i] = (GLfloat) exp(-f);
+ }
+ inited = 1;
+}
+
+
+/**
+ * Compute per-vertex fog blend factors from fog coordinates by
+ * evaluating the GL_LINEAR, GL_EXP or GL_EXP2 fog function.
+ * Fog coordinates are distances from the eye (typically between the
+ * near and far clip plane distances).
+ * Note the fog (eye Z) coords may be negative so we use ABS(z) below.
+ * Fog blend factors are in the range [0,1].
+ */
+static void
+compute_fog_blend_factors(GLcontext *ctx, GLvector4f *out, const GLvector4f *in)
+{
+ GLfloat end = ctx->Fog.End;
+ GLfloat *v = in->start;
+ GLuint stride = in->stride;
+ GLuint n = in->count;
+ GLfloat (*data)[4] = out->data;
+ GLfloat d;
+ GLuint i;
+
+ out->count = in->count;
+
+ switch (ctx->Fog.Mode) {
+ case GL_LINEAR:
+ if (ctx->Fog.Start == ctx->Fog.End)
+ d = 1.0F;
+ else
+ d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
+ const GLfloat z = FABSF(*v);
+ GLfloat f = (end - z) * d;
+ data[i][0] = CLAMP(f, 0.0F, 1.0F);
+ }
+ break;
+ case GL_EXP:
+ d = ctx->Fog.Density;
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
+ const GLfloat z = FABSF(*v);
+ NEG_EXP( data[i][0], d * z );
+ }
+ break;
+ case GL_EXP2:
+ d = ctx->Fog.Density*ctx->Fog.Density;
+ for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
+ const GLfloat z = FABSF(*v);
+ NEG_EXP( data[i][0], d * z * z );
+ }
+ break;
+ default:
+ _mesa_problem(ctx, "Bad fog mode in make_fog_coord");
+ return;
+ }
+}
+
+
+static GLboolean
+run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct fog_stage_data *store = FOG_STAGE_DATA(stage);
+ GLvector4f *input;
+
+ if (stage->changed_inputs == 0)
+ return GL_TRUE;
+
+ if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
+ /* Fog is computed from vertex or fragment Z values */
+ /* source = VB->ObjPtr or VB->EyePtr coords */
+ /* dest = VB->FogCoordPtr = fog stage private storage */
+ VB->FogCoordPtr = &store->fogcoord;
+
+ if (!ctx->_NeedEyeCoords) {
+ /* compute fog coords from object coords */
+ const GLfloat *m = ctx->ModelviewMatrixStack.Top->m;
+ GLfloat plane[4];
+
+ /* Use this to store calculated eye z values:
+ */
+ input = &store->fogcoord;
+
+ /* NOTE: negate plane here so we get positive fog coords! */
+ 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.
+ */
+ _mesa_dotprod_tab[VB->ObjPtr->size]( (GLfloat *) input->data,
+ 4 * sizeof(GLfloat),
+ VB->ObjPtr, plane );
+
+ input->count = VB->ObjPtr->count;
+ }
+ else {
+ /* fog coordinates = eye Z coordinates (use ABS later) */
+ input = &store->input;
+
+ if (VB->EyePtr->size < 2)
+ _mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 );
+
+ input->data = (GLfloat (*)[4]) &(VB->EyePtr->data[0][2]);
+ input->start = VB->EyePtr->start+2;
+ input->stride = VB->EyePtr->stride;
+ input->count = VB->EyePtr->count;
+ }
+ }
+ else {
+ /* use glFogCoord() coordinates */
+ input = VB->FogCoordPtr; /* source data */
+ VB->FogCoordPtr = &store->fogcoord; /* dest data */
+ }
+
+ if (tnl->_DoVertexFog) {
+ /* compute blend factors from fog coordinates */
+ compute_fog_blend_factors( ctx, VB->FogCoordPtr, input );
+ }
+ else {
+ /* results = incoming fog coords (compute fog per-fragment later) */
+ VB->FogCoordPtr = input;
+ }
+
+ VB->AttribPtr[_TNL_ATTRIB_FOG] = VB->FogCoordPtr;
+ return GL_TRUE;
+}
+
+
+static void
+check_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+{
+ stage->active = ctx->Fog.Enabled && !ctx->VertexProgram._Enabled;
+
+ if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT)
+ stage->inputs = _TNL_BIT_POS;
+ else
+ stage->inputs = _TNL_BIT_FOG;
+}
+
+
+/* Called the first time stage->run() is invoked.
+ */
+static GLboolean
+alloc_fog_data(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct fog_stage_data *store;
+ stage->privatePtr = MALLOC(sizeof(*store));
+ store = FOG_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ _mesa_vector4f_alloc( &store->fogcoord, 0, tnl->vb.Size, 32 );
+ _mesa_vector4f_init( &store->input, 0, 0 );
+
+ if (!inited)
+ init_static_data();
+
+ /* Now run the stage.
+ */
+ stage->run = run_fog_stage;
+ return stage->run( ctx, stage );
+}
+
+
+static void
+free_fog_data(struct tnl_pipeline_stage *stage)
+{
+ struct fog_stage_data *store = FOG_STAGE_DATA(stage);
+ if (store) {
+ _mesa_vector4f_free( &store->fogcoord );
+ FREE( store );
+ stage->privatePtr = NULL;
+ }
+}
+
+
+const struct tnl_pipeline_stage _tnl_fog_coordinate_stage =
+{
+ "build fog coordinates", /* name */
+ _NEW_FOG|_NEW_PROGRAM, /* check_state */
+ _NEW_FOG, /* run_state */
+ GL_FALSE, /* active? */
+ 0, /* inputs */
+ _TNL_BIT_FOG, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* 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 0000000..1a89bf3
--- /dev/null
+++ b/src/mesa/tnl/t_vb_light.c
@@ -0,0 +1,368 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.2.2
+ *
+ * Copyright (C) 1999-2005 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 "imports.h"
+#include "simple_list.h"
+#include "mtypes.h"
+
+#include "math/m_translate.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+#define LIGHT_TWOSIDE 0x1
+#define LIGHT_MATERIAL 0x2
+#define MAX_LIGHT_FUNC 0x4
+
+typedef void (*light_func)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct tnl_pipeline_stage *stage,
+ GLvector4f *input );
+
+struct material_cursor {
+ const GLfloat *ptr;
+ GLuint stride;
+ GLfloat *current;
+ GLuint size; /* 1, 2, 3 or 4 */
+};
+
+struct light_stage_data {
+ GLvector4f Input;
+ GLvector4f LitColor[2];
+ GLvector4f LitSecondary[2];
+ GLvector4f LitIndex[2];
+ light_func *light_func_tab;
+
+ struct material_cursor mat[MAT_ATTRIB_MAX];
+ GLuint mat_count;
+ GLuint mat_bitmask;
+};
+
+
+#define LIGHT_STAGE_DATA(stage) ((struct light_stage_data *)(stage->privatePtr))
+
+
+
+/* In the case of colormaterial, the effected material attributes
+ * should already have been bound to point to the incoming color data,
+ * prior to running the pipeline.
+ */
+static void update_materials( GLcontext *ctx,
+ struct light_stage_data *store )
+{
+ GLuint i;
+
+ for (i = 0 ; i < store->mat_count ; i++) {
+ COPY_CLEAN_4V(store->mat[i].current, store->mat[i].size, store->mat[i].ptr);
+ STRIDE_F(store->mat[i].ptr, store->mat[i].stride);
+ }
+
+ _mesa_update_material( ctx, store->mat_bitmask );
+ _mesa_validate_all_lighting_tables( ctx );
+}
+
+static GLuint prepare_materials( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct light_stage_data *store )
+{
+ GLuint i;
+
+ store->mat_count = 0;
+ store->mat_bitmask = 0;
+
+ /* If ColorMaterial enabled, overwrite affected AttrPtr's with
+ * the color pointer. This could be done earlier.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ GLuint bitmask = ctx->Light.ColorMaterialBitmask;
+ for (i = 0 ; i < MAT_ATTRIB_MAX ; i++)
+ if (bitmask & (1<<i))
+ VB->AttribPtr[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] = VB->ColorPtr[0];
+ }
+
+ for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ; i < _TNL_ATTRIB_INDEX ; i++) {
+ if (VB->AttribPtr[i]->stride) {
+ GLuint j = store->mat_count++;
+ GLuint attr = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
+ store->mat[j].ptr = VB->AttribPtr[i]->start;
+ store->mat[j].stride = VB->AttribPtr[i]->stride;
+ store->mat[j].size = VB->AttribPtr[i]->size;
+ store->mat[j].current = ctx->Light.Material.Attrib[attr];
+ store->mat_bitmask |= (1<<attr);
+ }
+ }
+
+
+ /* FIXME: Is this already done?
+ */
+ _mesa_update_material( ctx, ~0 );
+ _mesa_validate_all_lighting_tables( ctx );
+
+ return store->mat_count;
+}
+
+/* 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##_twoside
+#define IDX (LIGHT_TWOSIDE)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_material
+#define IDX (LIGHT_MATERIAL)
+#include "t_vb_lighttmp.h"
+
+#define TAG(x) x##_twoside_material
+#define IDX (LIGHT_TWOSIDE|LIGHT_MATERIAL)
+#include "t_vb_lighttmp.h"
+
+
+static void init_lighting( void )
+{
+ static int done;
+
+ if (!done) {
+ init_light_tab();
+ init_light_tab_twoside();
+ init_light_tab_material();
+ init_light_tab_twoside_material();
+ done = 1;
+ }
+}
+
+
+static GLboolean run_lighting( GLcontext *ctx,
+ struct tnl_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 idx;
+
+ /* Make sure we can talk about position x,y and z:
+ */
+ if (stage->changed_inputs & _TNL_BIT_POS) {
+ if (input->size <= 2 && input == VB->ObjPtr) {
+
+ _math_trans_4f( store->Input.data,
+ VB->ObjPtr->data,
+ VB->ObjPtr->stride,
+ GL_FLOAT,
+ VB->ObjPtr->size,
+ 0,
+ VB->Count );
+
+ if (input->size <= 2) {
+ /* Clean z.
+ */
+ _mesa_vector4f_clean_elem(&store->Input, VB->Count, 2);
+ }
+
+ if (input->size <= 1) {
+ /* Clean y.
+ */
+ _mesa_vector4f_clean_elem(&store->Input, VB->Count, 1);
+ }
+
+ input = &store->Input;
+ }
+ }
+
+ idx = 0;
+
+ if (prepare_materials( ctx, VB, store ))
+ idx |= LIGHT_MATERIAL;
+
+ if (ctx->Light.Model.TwoSide)
+ idx |= LIGHT_TWOSIDE;
+
+ /* The individual functions know about replaying side-effects
+ * vs. full re-execution.
+ */
+ store->light_func_tab[idx]( ctx, VB, stage, input );
+
+ VB->AttribPtr[_TNL_ATTRIB_COLOR0] = VB->ColorPtr[0];
+ VB->AttribPtr[_TNL_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
+ VB->AttribPtr[_TNL_ATTRIB_INDEX] = VB->IndexPtr[0];
+
+ return GL_TRUE;
+}
+
+
+/* Called in place of do_lighting when the light table may have changed.
+ */
+static GLboolean run_validate_lighting( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ light_func *tab;
+
+ if (ctx->Visual.rgbMode) {
+ 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;
+ }
+ }
+ else
+ tab = _tnl_light_ci_tab;
+
+
+ LIGHT_STAGE_DATA(stage)->light_func_tab = tab;
+
+ /* This and the above should only be done on _NEW_LIGHT:
+ */
+ TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( 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 tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct light_stage_data *store;
+ GLuint size = tnl->vb.Size;
+
+ stage->privatePtr = MALLOC(sizeof(*store));
+ store = LIGHT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ /* Do onetime init.
+ */
+ init_lighting();
+
+ _mesa_vector4f_alloc( &store->Input, 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitColor[0], 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitColor[1], 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitSecondary[0], 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitSecondary[1], 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitIndex[0], 0, size, 32 );
+ _mesa_vector4f_alloc( &store->LitIndex[1], 0, size, 32 );
+
+ store->LitColor[0].size = 4;
+ store->LitColor[1].size = 4;
+ store->LitSecondary[0].size = 3;
+ store->LitSecondary[1].size = 3;
+
+ store->LitIndex[0].size = 1;
+ store->LitIndex[0].stride = sizeof(GLfloat);
+ store->LitIndex[1].size = 1;
+ store->LitIndex[1].stride = sizeof(GLfloat);
+
+ /* 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 tnl_pipeline_stage *stage )
+{
+ stage->active = ctx->Light.Enabled && !ctx->VertexProgram._Enabled;
+ if (stage->active) {
+ if (stage->privatePtr)
+ stage->run = run_validate_lighting;
+ stage->inputs = _TNL_BIT_NORMAL|_TNL_BITS_MAT_ANY;
+ if (ctx->Light._NeedVertices)
+ stage->inputs |= _TNL_BIT_POS;
+ if (ctx->Light.ColorMaterialEnabled)
+ stage->inputs |= _TNL_BIT_COLOR0;
+
+ stage->outputs = _TNL_BIT_COLOR0;
+ if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
+ stage->outputs |= _TNL_BIT_COLOR1;
+ }
+}
+
+
+static void dtr( struct tnl_pipeline_stage *stage )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+
+ if (store) {
+ _mesa_vector4f_free( &store->Input );
+ _mesa_vector4f_free( &store->LitColor[0] );
+ _mesa_vector4f_free( &store->LitColor[1] );
+ _mesa_vector4f_free( &store->LitSecondary[0] );
+ _mesa_vector4f_free( &store->LitSecondary[1] );
+ _mesa_vector4f_free( &store->LitIndex[0] );
+ _mesa_vector4f_free( &store->LitIndex[1] );
+ FREE( store );
+ stage->privatePtr = NULL;
+ }
+}
+
+const struct tnl_pipeline_stage _tnl_lighting_stage =
+{
+ "lighting", /* name */
+ _NEW_LIGHT|_NEW_PROGRAM, /* recheck */
+ _NEW_LIGHT|_NEW_MODELVIEW, /* recalc -- modelview dependency
+ * otherwise not captured by inputs
+ * (which may be _TNL_BIT_POS) */
+ GL_FALSE, /* active? */
+ 0, /* inputs */
+ 0, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* 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 0000000..d8094e2
--- /dev/null
+++ b/src/mesa/tnl/t_vb_lighttmp.h
@@ -0,0 +1,821 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2003 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
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+
+#if IDX & LIGHT_TWOSIDE
+# define NR_SIDES 2
+#else
+# define NR_SIDES 1
+#endif
+
+
+/* define TRACE to trace lighting code */
+/* #define TRACE 1 */
+
+/*
+ * ctx is the current context
+ * VB is the vertex buffer
+ * stage is the lighting stage-private data
+ * input is the vector of eye or object-space vertex coordinates
+ */
+static void TAG(light_rgba_spec)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct tnl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLfloat (*base)[3] = ctx->Light._BaseColor;
+ GLfloat sumA[2];
+ GLuint j;
+
+ const GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *)input->data;
+ const GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+
+ GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
+ GLfloat (*Fspec)[4] = (GLfloat (*)[4]) store->LitSecondary[0].data;
+#if IDX & LIGHT_TWOSIDE
+ GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
+ GLfloat (*Bspec)[4] = (GLfloat (*)[4]) store->LitSecondary[1].data;
+#endif
+
+ const GLuint nr = VB->Count;
+
+ (void) nstride;
+ (void) vstride;
+
+#ifdef TRACE
+ fprintf(stderr, "%s\n", __FUNCTION__ );
+#endif
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ VB->SecondaryColorPtr[0] = &store->LitSecondary[0];
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+
+#if IDX & LIGHT_TWOSIDE
+ VB->ColorPtr[1] = &store->LitColor[1];
+ VB->SecondaryColorPtr[1] = &store->LitSecondary[1];
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+
+ /* 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)) {
+ GLfloat sum[2][3], spec[2][3];
+ struct gl_light *light;
+
+#if IDX & LIGHT_MATERIAL
+ update_materials( ctx, store );
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+#if IDX & LIGHT_TWOSIDE
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+#endif
+
+ COPY_3V(sum[0], base[0]);
+ ZERO_3V(spec[0]);
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V(sum[1], base[1]);
+ ZERO_3V(spec[1]);
+#endif
+
+ /* 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 {
+ GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ GLint k = (GLint) 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
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+#else
+ continue;
+#endif
+ }
+ else {
+#if IDX & LIGHT_TWOSIDE
+ ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
+#endif
+ 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*/
+
+ COPY_3V( Fcolor[j], sum[0] );
+ COPY_3V( Fspec[j], spec[0] );
+ Fcolor[j][3] = sumA[0];
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V( Bcolor[j], sum[1] );
+ COPY_3V( Bspec[j], spec[1] );
+ Bcolor[j][3] = sumA[1];
+#endif
+ }
+}
+
+
+static void TAG(light_rgba)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct tnl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLuint j;
+
+ GLfloat (*base)[3] = ctx->Light._BaseColor;
+ GLfloat sumA[2];
+
+ const GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *) input->data;
+ const GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+
+ GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
+#if IDX & LIGHT_TWOSIDE
+ GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
+#endif
+
+ const GLuint nr = VB->Count;
+
+#ifdef TRACE
+ fprintf(stderr, "%s\n", __FUNCTION__ );
+#endif
+
+ (void) nstride;
+ (void) vstride;
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+
+#if IDX & LIGHT_TWOSIDE
+ VB->ColorPtr[1] = &store->LitColor[1];
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ for (j = 0; j < nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal,nstride)) {
+ GLfloat sum[2][3];
+ struct gl_light *light;
+
+#if IDX & LIGHT_MATERIAL
+ update_materials( ctx, store );
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+#if IDX & LIGHT_TWOSIDE
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+#endif
+
+ COPY_3V(sum[0], base[0]);
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V(sum[1], base[1]);
+#endif
+
+ /* 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 = (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 {
+ GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ GLint k = (GLint) 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 are we lighting? */
+ if (n_dot_VP < 0.0F) {
+ ACC_SCALE_SCALAR_3V(sum[0], attenuation, light->_MatAmbient[0]);
+#if IDX & LIGHT_TWOSIDE
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+#else
+ continue;
+#endif
+ }
+ else {
+#if IDX & LIGHT_TWOSIDE
+ ACC_SCALE_SCALAR_3V( sum[1], attenuation, light->_MatAmbient[1]);
+#endif
+ 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 );
+ }
+
+ COPY_3V( Fcolor[j], sum[0] );
+ Fcolor[j][3] = sumA[0];
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V( Bcolor[j], sum[1] );
+ Bcolor[j][3] = sumA[1];
+#endif
+ }
+}
+
+
+
+
+/* As below, but with just a single light.
+ */
+static void TAG(light_fast_rgba_single)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct tnl_pipeline_stage *stage,
+ GLvector4f *input )
+
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ const GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
+#if IDX & LIGHT_TWOSIDE
+ GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
+#endif
+ const struct gl_light *light = ctx->Light.EnabledList.next;
+ GLuint j = 0;
+ GLfloat base[2][4];
+ const GLuint nr = VB->Count;
+
+#ifdef TRACE
+ fprintf(stderr, "%s\n", __FUNCTION__ );
+#endif
+
+ (void) input; /* doesn't refer to Eye or Obj */
+ (void) nr;
+ (void) nstride;
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+#if IDX & LIGHT_TWOSIDE
+ VB->ColorPtr[1] = &store->LitColor[1];
+#endif
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
+
+ GLfloat n_dot_VP;
+
+#if IDX & LIGHT_MATERIAL
+ update_materials( ctx, store );
+#endif
+
+ /* No attenuation, so incoporate _MatAmbient into base color.
+ */
+#if !(IDX & LIGHT_MATERIAL)
+ if ( j == 0 )
+#endif
+ {
+ COPY_3V(base[0], light->_MatAmbient[0]);
+ ACC_3V(base[0], ctx->Light._BaseColor[0] );
+ base[0][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V(base[1], light->_MatAmbient[1]);
+ ACC_3V(base[1], ctx->Light._BaseColor[1]);
+ base[1][3] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+ }
+
+ n_dot_VP = DOT3(normal, light->_VP_inf_norm);
+
+ 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]);
+ }
+ COPY_3V(Bcolor[j], sum );
+ Bcolor[j][3] = base[1][3];
+#endif
+ COPY_4FV(Fcolor[j], base[0]);
+ }
+ 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]);
+
+ }
+ COPY_3V(Fcolor[j], sum );
+ Fcolor[j][3] = base[0][3];
+#if IDX & LIGHT_TWOSIDE
+ COPY_4FV(Bcolor[j], base[1]);
+#endif
+ }
+ }
+}
+
+
+/* Light infinite lights
+ */
+static void TAG(light_fast_rgba)( GLcontext *ctx,
+ struct vertex_buffer *VB,
+ struct tnl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLfloat sumA[2];
+ const GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLfloat (*Fcolor)[4] = (GLfloat (*)[4]) store->LitColor[0].data;
+#if IDX & LIGHT_TWOSIDE
+ GLfloat (*Bcolor)[4] = (GLfloat (*)[4]) store->LitColor[1].data;
+#endif
+ GLuint j = 0;
+ const GLuint nr = VB->Count;
+ const struct gl_light *light;
+
+#ifdef TRACE
+ fprintf(stderr, "%s %d\n", __FUNCTION__, nr );
+#endif
+
+ (void) input;
+ (void) nr;
+ (void) nstride;
+
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+
+ VB->ColorPtr[0] = &store->LitColor[0];
+#if IDX & LIGHT_TWOSIDE
+ VB->ColorPtr[1] = &store->LitColor[1];
+#endif
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ for (j = 0; j < nr; j++, STRIDE_F(normal,nstride)) {
+
+ GLfloat sum[2][3];
+
+#if IDX & LIGHT_MATERIAL
+ update_materials( ctx, store );
+
+ sumA[0] = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_DIFFUSE][3];
+#if IDX & LIGHT_TWOSIDE
+ sumA[1] = ctx->Light.Material.Attrib[MAT_ATTRIB_BACK_DIFFUSE][3];
+#endif
+#endif
+
+
+ COPY_3V(sum[0], ctx->Light._BaseColor[0]);
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V(sum[1], ctx->Light._BaseColor[1]);
+#endif
+
+ 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]);
+#endif
+
+ 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]);
+ }
+ }
+#if IDX & LIGHT_TWOSIDE
+ else {
+ 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]);
+ }
+ }
+#endif
+ }
+
+ COPY_3V( Fcolor[j], sum[0] );
+ Fcolor[j][3] = sumA[0];
+
+#if IDX & LIGHT_TWOSIDE
+ COPY_3V( Bcolor[j], sum[1] );
+ Bcolor[j][3] = sumA[1];
+#endif
+ }
+}
+
+
+
+
+
+/*
+ * 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 tnl_pipeline_stage *stage,
+ GLvector4f *input )
+{
+ struct light_stage_data *store = LIGHT_STAGE_DATA(stage);
+ GLuint j;
+ const GLuint vstride = input->stride;
+ const GLfloat *vertex = (GLfloat *) input->data;
+ const GLuint nstride = VB->NormalPtr->stride;
+ const GLfloat *normal = (GLfloat *)VB->NormalPtr->data;
+ GLfloat *indexResult[2];
+ const GLuint nr = VB->Count;
+
+#ifdef TRACE
+ fprintf(stderr, "%s\n", __FUNCTION__ );
+#endif
+
+ (void) nstride;
+ (void) vstride;
+
+ VB->IndexPtr[0] = &store->LitIndex[0];
+#if IDX & LIGHT_TWOSIDE
+ VB->IndexPtr[1] = &store->LitIndex[1];
+#endif
+
+ if (stage->changed_inputs == 0)
+ return;
+
+ indexResult[0] = (GLfloat *)VB->IndexPtr[0]->data;
+#if IDX & LIGHT_TWOSIDE
+ indexResult[1] = (GLfloat *)VB->IndexPtr[1]->data;
+#endif
+
+ /* loop over vertices */
+ for (j=0; j<nr; j++,STRIDE_F(vertex,vstride),STRIDE_F(normal, nstride)) {
+ GLfloat diffuse[2], specular[2];
+ GLuint side = 0;
+ struct gl_light *light;
+
+#if IDX & LIGHT_MATERIAL
+ update_materials( ctx, store );
+#endif
+
+ diffuse[0] = specular[0] = 0.0F;
+
+#if IDX & LIGHT_TWOSIDE
+ diffuse[1] = specular[1] = 0.0F;
+#endif
+
+ /* 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 = (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 {
+ GLdouble x = PV_dot_dir * (EXP_TABLE_SIZE-1);
+ GLint k = (GLint) 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 */
+
+ n_dot_VP = DOT3( normal, VP );
+
+ /* which side are we lighting? */
+ if (n_dot_VP < 0.0F) {
+#if IDX & LIGHT_TWOSIDE
+ side = 1;
+ correction = -1;
+ n_dot_VP = -n_dot_VP;
+#else
+ continue;
+#endif
+ }
+
+ /* 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;
+ /* Strangely, disabling this addition fixes a conformance
+ * problem. If this code is enabled, l_sed.c fails.
+ */
+ /*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++) {
+ const GLfloat *ind = ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_INDEXES + side];
+ GLfloat index;
+
+ if (specular[side] > 1.0F) {
+ index = ind[MAT_INDEX_SPECULAR];
+ }
+ else {
+ GLfloat d_a = ind[MAT_INDEX_DIFFUSE] - ind[MAT_INDEX_AMBIENT];
+ GLfloat s_a = ind[MAT_INDEX_SPECULAR] - ind[MAT_INDEX_AMBIENT];
+ index = (ind[MAT_INDEX_AMBIENT]
+ + diffuse[side] * (1.0F-specular[side]) * d_a
+ + specular[side] * s_a);
+ if (index > ind[MAT_INDEX_SPECULAR]) {
+ index = ind[MAT_INDEX_SPECULAR];
+ }
+ }
+ indexResult[side][j] = index;
+ }
+ } /*for vertex*/
+}
+
+
+
+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
diff --git a/src/mesa/tnl/t_vb_normals.c b/src/mesa/tnl/t_vb_normals.c
new file mode 100644
index 0000000..732e7c6
--- /dev/null
+++ b/src/mesa/tnl/t_vb_normals.c
@@ -0,0 +1,200 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+
+#include "math/m_xform.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+
+struct normal_stage_data {
+ normal_func NormalTransform;
+ GLvector4f normal;
+};
+
+#define NORMAL_STAGE_DATA(stage) ((struct normal_stage_data *)stage->privatePtr)
+
+
+
+
+static GLboolean run_normal_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ ASSERT(store->NormalTransform);
+
+ if (stage->changed_inputs) {
+ /* We can only use the display list's saved normal lengths if we've
+ * got a transformation matrix with uniform scaling.
+ */
+ const GLfloat *lengths;
+ if (ctx->ModelviewMatrixStack.Top->flags & MAT_FLAG_GENERAL_SCALE)
+ lengths = NULL;
+ else
+ lengths = VB->NormalLengthPtr;
+
+ store->NormalTransform( ctx->ModelviewMatrixStack.Top,
+ ctx->_ModelViewInvScale,
+ VB->NormalPtr, /* input normals */
+ lengths,
+ &store->normal ); /* resulting normals */
+ }
+
+ VB->NormalPtr = &store->normal;
+ VB->AttribPtr[_TNL_ATTRIB_NORMAL] = VB->NormalPtr;
+
+ VB->NormalLengthPtr = 0; /* no longer valid */
+ return GL_TRUE;
+}
+
+
+static GLboolean run_validate_normal_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+
+
+ if (ctx->_NeedEyeCoords) {
+ GLuint transform = NORM_TRANSFORM_NO_ROT;
+
+ if (ctx->ModelviewMatrixStack.Top->flags & (MAT_FLAG_GENERAL |
+ MAT_FLAG_ROTATION |
+ MAT_FLAG_GENERAL_3D |
+ MAT_FLAG_PERSPECTIVE))
+ transform = NORM_TRANSFORM;
+
+
+ if (ctx->Transform.Normalize) {
+ store->NormalTransform = _mesa_normal_tab[transform | NORM_NORMALIZE];
+ }
+ else if (ctx->Transform.RescaleNormals &&
+ ctx->_ModelViewInvScale != 1.0) {
+ store->NormalTransform = _mesa_normal_tab[transform | NORM_RESCALE];
+ }
+ else {
+ store->NormalTransform = _mesa_normal_tab[transform];
+ }
+ }
+ else {
+ if (ctx->Transform.Normalize) {
+ store->NormalTransform = _mesa_normal_tab[NORM_NORMALIZE];
+ }
+ else if (!ctx->Transform.RescaleNormals &&
+ ctx->_ModelViewInvScale != 1.0) {
+ store->NormalTransform = _mesa_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 tnl_pipeline_stage *stage )
+{
+ stage->active = !ctx->VertexProgram._Enabled &&
+ (ctx->Light.Enabled || (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS));
+
+ /* Don't clobber the initialize function:
+ */
+ if (stage->privatePtr)
+ stage->run = run_validate_normal_stage;
+}
+
+
+static GLboolean alloc_normal_data( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct normal_stage_data *store;
+ stage->privatePtr = MALLOC(sizeof(*store));
+ store = NORMAL_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ _mesa_vector4f_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 tnl_pipeline_stage *stage )
+{
+ struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
+ if (store) {
+ _mesa_vector4f_free( &store->normal );
+ FREE( store );
+ stage->privatePtr = NULL;
+ }
+}
+
+#define _TNL_NEW_NORMAL_TRANSFORM (_NEW_MODELVIEW| \
+ _NEW_TRANSFORM| \
+ _NEW_PROGRAM| \
+ _MESA_NEW_NEED_NORMALS| \
+ _MESA_NEW_NEED_EYE_COORDS)
+
+
+
+const struct tnl_pipeline_stage _tnl_normal_transform_stage =
+{
+ "normal transform", /* name */
+ _TNL_NEW_NORMAL_TRANSFORM, /* re-check */
+ _TNL_NEW_NORMAL_TRANSFORM, /* re-run */
+ GL_FALSE, /* active? */
+ _TNL_BIT_NORMAL, /* inputs */
+ _TNL_BIT_NORMAL, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ 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 0000000..746ea8b
--- /dev/null
+++ b/src/mesa/tnl/t_vb_points.c
@@ -0,0 +1,123 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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
+ */
+
+#include "mtypes.h"
+#include "imports.h"
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+struct point_stage_data {
+ GLvector4f PointSize;
+};
+
+#define POINT_STAGE_DATA(stage) ((struct point_stage_data *)stage->privatePtr)
+
+
+/*
+ * Compute attenuated point sizes
+ */
+static GLboolean run_point_stage( GLcontext *ctx,
+ struct tnl_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)[4] = 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 = SQRTF(pos[0]*pos[0]+pos[1]*pos[1]+pos[2]*pos[2]);*/
+ size[i][0] = pointSize / (p0 + dist * (p1 + dist * p2));
+ }
+ }
+
+ VB->PointSizePtr = &store->PointSize;
+ VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &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 tnl_pipeline_stage *d )
+{
+ d->active = ctx->Point._Attenuated && !ctx->VertexProgram._Enabled;
+}
+
+static GLboolean alloc_point_data( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct point_stage_data *store;
+ stage->privatePtr = MALLOC(sizeof(*store));
+ store = POINT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ _mesa_vector4f_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 tnl_pipeline_stage *stage )
+{
+ struct point_stage_data *store = POINT_STAGE_DATA(stage);
+ if (store) {
+ _mesa_vector4f_free( &store->PointSize );
+ FREE( store );
+ stage->privatePtr = 0;
+ }
+}
+
+const struct tnl_pipeline_stage _tnl_point_attenuation_stage =
+{
+ "point size attenuation", /* name */
+ _NEW_POINT|_NEW_PROGRAM, /* check_state */
+ _NEW_POINT, /* run_state */
+ GL_FALSE, /* active */
+ _TNL_BIT_POS, /* inputs */
+ _TNL_BIT_POS, /* outputs */
+ 0, /* changed_inputs (temporary value) */
+ NULL, /* 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_program.c b/src/mesa/tnl/t_vb_program.c
new file mode 100644
index 0000000..38b04b4
--- /dev/null
+++ b/src/mesa/tnl/t_vb_program.c
@@ -0,0 +1,368 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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.
+ */
+
+
+/**
+ * \file tnl/t_vb_program.c
+ * \brief Pipeline stage for executing NVIDIA vertex programs.
+ * \author Brian Paul, Keith Whitwell
+ */
+
+
+#include "glheader.h"
+#include "api_noop.h"
+#include "colormac.h"
+#include "context.h"
+#include "dlist.h"
+#include "hash.h"
+#include "light.h"
+#include "macros.h"
+#include "imports.h"
+#include "simple_list.h"
+#include "mtypes.h"
+#include "nvvertprog.h"
+#include "nvvertexec.h"
+#include "nvprogram.h"
+
+#include "math/m_translate.h"
+
+#include "t_context.h"
+#include "t_pipeline.h"
+
+
+/**
+ * \warning These values _MUST_ match the values in the OutputRegisters[]
+ * array in vpparse.c!!!
+ */
+#define VERT_RESULT_HPOS 0
+#define VERT_RESULT_COL0 1
+#define VERT_RESULT_COL1 2
+#define VERT_RESULT_BFC0 3
+#define VERT_RESULT_BFC1 4
+#define VERT_RESULT_FOGC 5
+#define VERT_RESULT_PSIZ 6
+#define VERT_RESULT_TEX0 7
+#define VERT_RESULT_TEX1 8
+#define VERT_RESULT_TEX2 9
+#define VERT_RESULT_TEX3 10
+#define VERT_RESULT_TEX4 11
+#define VERT_RESULT_TEX5 12
+#define VERT_RESULT_TEX6 13
+#define VERT_RESULT_TEX7 14
+
+
+/*!
+ * Private storage for the vertex program pipeline stage.
+ */
+struct vp_stage_data {
+ /** The results of running the vertex program go into these arrays. */
+ GLvector4f attribs[15];
+
+ GLvector4f ndcCoords; /**< normalized device coords */
+ GLubyte *clipmask; /**< clip flags */
+ GLubyte ormask, andmask; /**< for clipping */
+};
+
+
+#define VP_STAGE_DATA(stage) ((struct vp_stage_data *)(stage->privatePtr))
+
+
+/**
+ * This function executes vertex programs
+ */
+static GLboolean
+run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vp_stage_data *store = VP_STAGE_DATA(stage);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct vertex_program *program = ctx->VertexProgram.Current;
+ GLuint i;
+
+ /* load program parameter registers (they're read-only) */
+ _mesa_init_vp_per_primitive_registers(ctx);
+
+ for (i = 0; i < VB->Count; i++) {
+ GLuint attr;
+
+ _mesa_init_vp_per_vertex_registers(ctx);
+
+#if 0
+ printf("Input %d: %f, %f, %f, %f\n", i,
+ VB->AttribPtr[0]->data[i][0],
+ VB->AttribPtr[0]->data[i][1],
+ VB->AttribPtr[0]->data[i][2],
+ VB->AttribPtr[0]->data[i][3]);
+ printf(" color: %f, %f, %f, %f\n",
+ VB->AttribPtr[3]->data[i][0],
+ VB->AttribPtr[3]->data[i][1],
+ VB->AttribPtr[3]->data[i][2],
+ VB->AttribPtr[3]->data[i][3]);
+ printf(" normal: %f, %f, %f, %f\n",
+ VB->AttribPtr[2]->data[i][0],
+ VB->AttribPtr[2]->data[i][1],
+ VB->AttribPtr[2]->data[i][2],
+ VB->AttribPtr[2]->data[i][3]);
+#endif
+
+ /* the vertex array case */
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ if (program->InputsRead & (1 << attr)) {
+ const GLubyte *ptr = (const GLubyte*) VB->AttribPtr[attr]->data;
+ const GLuint size = VB->AttribPtr[attr]->size;
+ const GLuint stride = VB->AttribPtr[attr]->stride;
+ const GLfloat *data = (GLfloat *) (ptr + stride * i);
+ ASSIGN_4V(ctx->VertexProgram.Inputs[attr], 0, 0, 0, 1);
+ COPY_SZ_4V(ctx->VertexProgram.Inputs[attr], size, data);
+ }
+ }
+
+ /* execute the program */
+ ASSERT(program);
+ _mesa_exec_vertex_program(ctx, program);
+
+ /* Fixup fog an point size results if needed */
+ if (ctx->Fog.Enabled &&
+ (program->OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
+ ctx->VertexProgram.Outputs[VERT_RESULT_FOGC][0] = 1.0;
+ }
+
+ if (ctx->VertexProgram.PointSizeEnabled &&
+ (program->OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
+ ctx->VertexProgram.Outputs[VERT_RESULT_PSIZ][0] = ctx->Point.Size;
+ }
+
+ /* copy the output registers into the VB->attribs arrays */
+ /* XXX (optimize) could use a conditional and smaller loop limit here */
+ for (attr = 0; attr < 15; attr++) {
+ COPY_4V(store->attribs[attr].data[i],
+ ctx->VertexProgram.Outputs[attr]);
+ }
+ }
+
+ /* Setup the VB pointers so that the next pipeline stages get
+ * their data from the right place (the program output arrays).
+ */
+ VB->ClipPtr = &store->attribs[VERT_RESULT_HPOS];
+ VB->ClipPtr->size = 4;
+ VB->ClipPtr->count = VB->Count;
+ VB->ColorPtr[0] = &store->attribs[VERT_RESULT_COL0];
+ VB->ColorPtr[1] = &store->attribs[VERT_RESULT_BFC0];
+ VB->SecondaryColorPtr[0] = &store->attribs[VERT_RESULT_COL1];
+ VB->SecondaryColorPtr[1] = &store->attribs[VERT_RESULT_BFC1];
+ VB->FogCoordPtr = &store->attribs[VERT_RESULT_FOGC];
+ VB->PointSizePtr = &store->attribs[VERT_RESULT_PSIZ];
+
+ VB->AttribPtr[VERT_ATTRIB_COLOR0] = VB->ColorPtr[0];
+ VB->AttribPtr[VERT_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
+ VB->AttribPtr[VERT_ATTRIB_FOG] = VB->FogCoordPtr;
+ VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->attribs[VERT_RESULT_PSIZ];
+
+ for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
+ VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i] =
+ &store->attribs[VERT_RESULT_TEX0 + i];
+ }
+
+
+
+ /* Cliptest and perspective divide. Clip functions must clear
+ * the clipmask.
+ */
+ store->ormask = 0;
+ store->andmask = CLIP_ALL_BITS;
+
+ if (tnl->NeedNdcCoords) {
+ VB->NdcPtr =
+ _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
+ &store->ndcCoords,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+ }
+ else {
+ VB->NdcPtr = 0;
+ _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
+ 0,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+ }
+
+ if (store->andmask) /* All vertices are outside the frustum */
+ return GL_FALSE;
+
+
+ /* This is where we'd do clip testing against the user-defined
+ * clipping planes, but they're not supported by vertex programs.
+ */
+
+ VB->ClipOrMask = store->ormask;
+ VB->ClipMask = store->clipmask;
+
+ return GL_TRUE;
+}
+
+
+/**
+ * This function validates stuff.
+ */
+static GLboolean run_validate_program( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+#if 000
+ /* XXX do we need any validation for vertex programs? */
+ GLuint ind = 0;
+ light_func *tab;
+
+ if (ctx->Visual.rgbMode) {
+ 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;
+ }
+ }
+ else
+ tab = _tnl_light_ci_tab;
+
+ if (ctx->Light.ColorMaterialEnabled)
+ ind |= LIGHT_COLORMATERIAL;
+
+ if (ctx->Light.Model.TwoSide)
+ ind |= LIGHT_TWOSIDE;
+
+ VP_STAGE_DATA(stage)->light_func_tab = &tab[ind];
+
+ /* This and the above should only be done on _NEW_LIGHT:
+ */
+ _mesa_validate_all_lighting_tables( ctx );
+#endif
+
+ /* Now run the stage...
+ */
+ stage->run = run_vp;
+ 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_vp( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &(tnl->vb);
+ struct vp_stage_data *store;
+ const GLuint size = VB->Size;
+ GLuint i;
+
+ stage->privatePtr = MALLOC(sizeof(*store));
+ store = VP_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ /* Allocate arrays of vertex output values */
+ for (i = 0; i < 15; i++) {
+ _mesa_vector4f_alloc( &store->attribs[i], 0, size, 32 );
+ store->attribs[i].size = 4;
+ }
+
+ /* a few other misc allocations */
+ _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
+ store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
+
+ /* Now validate the stage derived data...
+ */
+ stage->run = run_validate_program;
+ return stage->run( ctx, stage );
+}
+
+
+
+/**
+ * Check if vertex program mode is enabled.
+ * If so, configure the pipeline stage's type, inputs, and outputs.
+ */
+static void check_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ stage->active = ctx->VertexProgram._Enabled;
+
+ if (stage->active) {
+ /* Set stage->inputs equal to the bitmask of vertex attributes
+ * which the program needs for inputs.
+ */
+ stage->inputs = ctx->VertexProgram.Current->InputsRead;
+ }
+}
+
+
+/**
+ * Destructor for this pipeline stage.
+ */
+static void dtr( struct tnl_pipeline_stage *stage )
+{
+ struct vp_stage_data *store = VP_STAGE_DATA(stage);
+
+ if (store) {
+ GLuint i;
+
+ /* free the vertex program result arrays */
+ for (i = 0; i < 15; i++)
+ _mesa_vector4f_free( &store->attribs[i] );
+
+ /* free misc arrays */
+ _mesa_vector4f_free( &store->ndcCoords );
+ ALIGN_FREE( store->clipmask );
+
+ FREE( store );
+ stage->privatePtr = 0;
+ }
+}
+
+/**
+ * Public description of this pipeline stage.
+ */
+const struct tnl_pipeline_stage _tnl_vertex_program_stage =
+{
+ "vertex-program",
+ _NEW_ALL, /*XXX FIX */ /* recheck */
+ _NEW_ALL, /*XXX FIX */ /* recalc */
+ GL_FALSE, /* active */
+ 0, /* inputs - calculated on the fly */
+ _TNL_BITS_PROG_ANY, /* outputs -- could calculate */
+ 0, /* changed_inputs */
+ NULL, /* private_data */
+ dtr, /* destroy */
+ check_vp, /* check */
+ run_init_vp /* run -- initially set to ctr */
+};
diff --git a/src/mesa/tnl/t_vb_render.c b/src/mesa/tnl/t_vb_render.c
new file mode 100644
index 0000000..44a09f5
--- /dev/null
+++ b/src/mesa/tnl/t_vb_render.c
@@ -0,0 +1,381 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2003 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 <keith@tungstengraphics.com>
+ */
+
+
+/*
+ * 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.Render.*
+ *
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "enums.h"
+#include "macros.h"
+#include "imports.h"
+#include "mtypes.h"
+#include "nvfragprog.h"
+#include "math/m_matrix.h"
+#include "math/m_xform.h"
+
+#include "t_pipeline.h"
+
+
+
+/**********************************************************************/
+/* Clip single primitives */
+/**********************************************************************/
+
+
+#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"
+
+
+
+/**********************************************************************/
+/* Clip and render whole begin/end objects */
+/**********************************************************************/
+
+#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
+#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
+#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
+
+
+#define CLIPMASK (CLIP_ALL_BITS|CLIP_CULL_BIT)
+
+
+/* Vertices, with the possibility of clipping.
+ */
+#define RENDER_POINTS( start, count ) \
+ tnl->Driver.Render.Points( ctx, start, count )
+
+#define RENDER_LINE( v1, v2 ) \
+do { \
+ GLubyte c1 = mask[v1], c2 = mask[v2]; \
+ GLubyte ormask = c1|c2; \
+ if (!ormask) \
+ LineFunc( ctx, v1, v2 ); \
+ else if (!(c1 & c2 & CLIPMASK)) \
+ clip_line_4( ctx, v1, v2, ormask ); \
+} while (0)
+
+#define RENDER_TRI( v1, v2, v3 ) \
+do { \
+ GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
+ GLubyte ormask = c1|c2|c3; \
+ if (!ormask) \
+ TriangleFunc( ctx, v1, v2, v3 ); \
+ else if (!(c1 & c2 & c3 & CLIPMASK)) \
+ clip_tri_4( ctx, v1, v2, v3, ormask ); \
+} while (0)
+
+#define RENDER_QUAD( v1, v2, v3, v4 ) \
+do { \
+ GLubyte c1 = mask[v1], c2 = mask[v2]; \
+ GLubyte c3 = mask[v3], c4 = mask[v4]; \
+ GLubyte ormask = c1|c2|c3|c4; \
+ if (!ormask) \
+ QuadFunc( ctx, v1, v2, v3, v4 ); \
+ else if (!(c1 & c2 & c3 & c4 & CLIPMASK)) \
+ clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \
+} while (0)
+
+
+#define LOCAL_VARS \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ struct vertex_buffer *VB = &tnl->vb; \
+ const GLuint * const elt = VB->Elts; \
+ const GLubyte *mask = VB->ClipMask; \
+ const GLuint sz = VB->ClipPtr->size; \
+ const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
+ const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
+ const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
+ const GLboolean stipple = ctx->Line.StippleFlag; \
+ (void) (LineFunc && TriangleFunc && QuadFunc); \
+ (void) elt; (void) mask; (void) sz; (void) stipple;
+
+#define TAG(x) clip_##x##_verts
+#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
+#define RESET_STIPPLE if (stipple) tnl->Driver.Render.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
+#define ELT(x) elt[x]
+#define TAG(x) clip_##x##_elts
+#include "t_vb_rendertmp.h"
+
+/* TODO: do this for all primitives, verts and elts:
+ */
+static void clip_elt_triangles( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl_render_func render_tris = tnl->Driver.Render.PrimTabElts[GL_TRIANGLES];
+ struct vertex_buffer *VB = &tnl->vb;
+ const GLuint * const elt = VB->Elts;
+ GLubyte *mask = VB->ClipMask;
+ GLuint last = count-2;
+ GLuint j;
+ (void) flags;
+
+ tnl->Driver.Render.PrimitiveNotify( ctx, GL_TRIANGLES );
+
+ for (j=start; j < last; j+=3 ) {
+ GLubyte c1 = mask[elt[j]];
+ GLubyte c2 = mask[elt[j+1]];
+ GLubyte c3 = mask[elt[j+2]];
+ GLubyte ormask = c1|c2|c3;
+ if (ormask) {
+ if (start < j)
+ render_tris( ctx, start, j, 0 );
+ if (!(c1&c2&c3&CLIPMASK))
+ clip_tri_4( ctx, elt[j], elt[j+1], elt[j+2], ormask );
+ start = j+3;
+ }
+ }
+
+ if (start < j)
+ render_tris( ctx, start, j, 0 );
+}
+
+/**********************************************************************/
+/* Render whole begin/end objects */
+/**********************************************************************/
+
+#define NEED_EDGEFLAG_SETUP (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL)
+#define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
+#define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
+
+
+/* Vertices, no clipping.
+ */
+#define RENDER_POINTS( start, count ) \
+ tnl->Driver.Render.Points( ctx, start, count )
+
+#define RENDER_LINE( v1, v2 ) \
+ LineFunc( ctx, v1, v2 )
+
+#define RENDER_TRI( v1, v2, v3 ) \
+ TriangleFunc( ctx, v1, v2, v3 )
+
+#define RENDER_QUAD( v1, v2, v3, v4 ) \
+ QuadFunc( ctx, v1, v2, v3, v4 )
+
+#define TAG(x) _tnl_##x##_verts
+
+#define LOCAL_VARS \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ struct vertex_buffer *VB = &tnl->vb; \
+ const GLuint * const elt = VB->Elts; \
+ const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
+ const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
+ const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
+ const GLboolean stipple = ctx->Line.StippleFlag; \
+ (void) (LineFunc && TriangleFunc && QuadFunc); \
+ (void) elt; (void) stipple
+
+#define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
+#define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
+#define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
+#define RENDER_TAB_QUALIFIER
+#define PRESERVE_VB_DEFS
+#include "t_vb_rendertmp.h"
+
+
+/* Elts, no clipping.
+ */
+#undef ELT
+#define TAG(x) _tnl_##x##_elts
+#define ELT(x) elt[x]
+#include "t_vb_rendertmp.h"
+
+
+/**********************************************************************/
+/* Helper functions for drivers */
+/**********************************************************************/
+
+void _tnl_RenderClippedPolygon( GLcontext *ctx, const GLuint *elts, GLuint n )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint *tmp = VB->Elts;
+
+ VB->Elts = (GLuint *)elts;
+ tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
+ VB->Elts = tmp;
+}
+
+void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->Driver.Render.Line( ctx, ii, jj );
+}
+
+
+
+/**********************************************************************/
+/* Clip and render whole vertex buffers */
+/**********************************************************************/
+
+
+static GLboolean run_render( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ GLuint new_inputs = stage->changed_inputs;
+ tnl_render_func *tab;
+ GLint pass = 0;
+
+ /* Allow the drivers to lock before projected verts are built so
+ * that window coordinates are guarenteed not to change before
+ * rendering.
+ */
+ ASSERT(tnl->Driver.Render.Start);
+
+ tnl->Driver.Render.Start( ctx );
+
+ ASSERT(tnl->Driver.Render.BuildVertices);
+ ASSERT(tnl->Driver.Render.PrimitiveNotify);
+ ASSERT(tnl->Driver.Render.Points);
+ ASSERT(tnl->Driver.Render.Line);
+ ASSERT(tnl->Driver.Render.Triangle);
+ ASSERT(tnl->Driver.Render.Quad);
+ ASSERT(tnl->Driver.Render.ResetLineStipple);
+ ASSERT(tnl->Driver.Render.Interp);
+ ASSERT(tnl->Driver.Render.CopyPV);
+ ASSERT(tnl->Driver.Render.ClippedLine);
+ ASSERT(tnl->Driver.Render.ClippedPolygon);
+ ASSERT(tnl->Driver.Render.Finish);
+
+ tnl->Driver.Render.BuildVertices( ctx, 0, VB->Count, new_inputs );
+
+ if (VB->ClipOrMask) {
+ tab = VB->Elts ? clip_render_tab_elts : clip_render_tab_verts;
+ clip_render_tab_elts[GL_TRIANGLES] = clip_elt_triangles;
+ }
+ else {
+ tab = (VB->Elts ?
+ tnl->Driver.Render.PrimTabElts :
+ tnl->Driver.Render.PrimTabVerts);
+ }
+
+ do
+ {
+ GLuint i;
+
+ for (i = 0 ; i < VB->PrimitiveCount ; i++)
+ {
+ GLuint prim = VB->Primitive[i].mode;
+ GLuint start = VB->Primitive[i].start;
+ GLuint length = VB->Primitive[i].count;
+
+ assert((prim & PRIM_MODE_MASK) < GL_POLYGON+1);
+
+ if (MESA_VERBOSE & VERBOSE_PRIMS)
+ _mesa_debug(NULL, "MESA prim %s %d..%d\n",
+ _mesa_lookup_enum_by_nr(prim & PRIM_MODE_MASK),
+ start, start+length);
+
+ if (length)
+ tab[prim & PRIM_MODE_MASK]( ctx, start, start + length, prim );
+ }
+ } while (tnl->Driver.Render.Multipass &&
+ tnl->Driver.Render.Multipass( ctx, ++pass ));
+
+ tnl->Driver.Render.Finish( 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.
+ */
+static void check_render( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ stage->inputs = TNL_CONTEXT(ctx)->render_inputs;
+}
+
+
+
+
+static void dtr( struct tnl_pipeline_stage *stage )
+{
+ (void) stage;
+}
+
+
+const struct tnl_pipeline_stage _tnl_render_stage =
+{
+ "render", /* name */
+ (_NEW_BUFFERS |
+ _DD_NEW_SEPARATE_SPECULAR |
+ _DD_NEW_FLATSHADE |
+ _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, /* inputs (set in check_render) */
+ 0, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ dtr, /* destructor */
+ check_render, /* check */
+ 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 0000000..3db94bc
--- /dev/null
+++ b/src/mesa/tnl/t_vb_rendertmp.h
@@ -0,0 +1,440 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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 <keith@tungstengraphics.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) (void)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)
+#endif
+
+#ifndef ELT
+#define ELT(x) x
+#endif
+
+#ifndef RENDER_TAB_QUALIFIER
+#define RENDER_TAB_QUALIFIER static
+#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 ) {
+ RESET_STIPPLE;
+ RENDER_LINE( ELT(j-1), ELT(j) );
+ }
+ 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_LINE_STRIP);
+
+ if (TEST_PRIM_BEGIN(flags)) {
+ RESET_STIPPLE;
+ }
+
+ for (j=start+1; j<count; j++ )
+ RENDER_LINE( ELT(j-1), ELT(j) );
+
+ 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_LINE_LOOP);
+
+ if (start+1 < count) {
+ if (TEST_PRIM_BEGIN(flags)) {
+ RESET_STIPPLE;
+ 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) );
+ }
+ }
+
+ POSTFIX;
+}
+
+
+static void TAG(render_triangles)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_TRIANGLES);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2; j<count; j+=3) {
+ /* Leave the edgeflags as supplied by the user.
+ */
+ RESET_STIPPLE;
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
+ }
+ } else {
+ for (j=start+2; j<count; j+=3) {
+ RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+
+
+static void TAG(render_tri_strip)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ GLuint parity = 0;
+ LOCAL_VARS;
+
+ INIT(GL_TRIANGLE_STRIP);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+2;j<count;j++,parity^=1) {
+ GLuint ej2 = ELT(j-2+parity);
+ GLuint ej1 = ELT(j-1-parity);
+ GLuint ej = ELT(j);
+ GLboolean ef2 = EDGEFLAG_GET( ej2 );
+ GLboolean ef1 = EDGEFLAG_GET( ej1 );
+ GLboolean ef = EDGEFLAG_GET( ej );
+ if (TEST_PRIM_BEGIN(flags)) {
+ RESET_STIPPLE;
+ }
+ EDGEFLAG_SET( ej2, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ej2, ej1, ej );
+ EDGEFLAG_SET( ej2, ef2 );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ }
+ } else {
+ for (j=start+2; j<count ; j++, parity^=1) {
+ RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+
+static void TAG(render_tri_fan)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_TRIANGLE_FAN);
+ 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 );
+ if (TEST_PRIM_BEGIN(flags)) {
+ RESET_STIPPLE;
+ }
+ EDGEFLAG_SET( ejs, GL_TRUE );
+ EDGEFLAG_SET( ej1, GL_TRUE );
+ EDGEFLAG_SET( ej, GL_TRUE );
+ RENDER_TRI( ejs, ej1, ej);
+ EDGEFLAG_SET( ejs, efs );
+ EDGEFLAG_SET( ej1, ef1 );
+ EDGEFLAG_SET( ej, ef );
+ }
+ } else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(start), ELT(j-1), ELT(j) );
+ }
+ }
+
+ POSTFIX;
+}
+
+
+static void TAG(render_poly)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j = start+2;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_POLYGON);
+ if (NEED_EDGEFLAG_SETUP) {
+ 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 );
+ else {
+ RESET_STIPPLE;
+ }
+
+ /* 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 triangles (possibly zero)
+ */
+ if (j+1<count) {
+ GLboolean ef = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ EDGEFLAG_SET( ELT(j), ef );
+ j++;
+
+ /* Don't render the first edge again:
+ */
+ EDGEFLAG_SET( ELT(start), GL_FALSE );
+
+ for (;j+1<count;j++) {
+ GLboolean efj = EDGEFLAG_GET( ELT(j) );
+ EDGEFLAG_SET( ELT(j), GL_FALSE );
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ EDGEFLAG_SET( ELT(j), efj );
+ }
+ }
+
+ /* Draw the last or only triangle
+ */
+ if (j < count)
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+
+ /* Restore the first and last edgeflags:
+ */
+ EDGEFLAG_SET( ELT(count-1), efcount );
+ EDGEFLAG_SET( ELT(start), efstart );
+
+ }
+ else {
+ for (j=start+2;j<count;j++) {
+ RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_quads)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ GLuint j;
+ LOCAL_VARS;
+ (void) flags;
+
+ INIT(GL_QUADS);
+ if (NEED_EDGEFLAG_SETUP) {
+ for (j=start+3; j<count; j+=4) {
+ /* Use user-specified edgeflags for quads.
+ */
+ RESET_STIPPLE;
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
+ }
+ } else {
+ for (j=start+3; j<count; j+=4) {
+ RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), 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_QUAD_STRIP);
+ 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) );
+ if (TEST_PRIM_BEGIN(flags)) {
+ RESET_STIPPLE;
+ }
+ 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-1), ELT(j-3), ELT(j-2), 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 );
+ }
+ } else {
+ for (j=start+3;j<count;j+=2) {
+ RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
+ }
+ }
+ POSTFIX;
+}
+
+static void TAG(render_noop)( GLcontext *ctx,
+ GLuint start,
+ GLuint count,
+ GLuint flags )
+{
+ (void)(ctx && start && count && flags);
+}
+
+RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(GLcontext *,
+ GLuint,
+ GLuint,
+ GLuint) =
+{
+ 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
+#undef RENDER_TAB_QUALIFIER
+#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 0000000..e9719b3
--- /dev/null
+++ b/src/mesa/tnl/t_vb_texgen.c
@@ -0,0 +1,691 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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
+ * Keith Whitwell <keith@tungstengraphics.com>
+ */
+
+/*
+ * Regarding GL_NV_texgen_reflection:
+ *
+ * Portions of this software may use or implement intellectual
+ * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
+ * any and all warranties with respect to such intellectual property,
+ * including any use thereof or modifications thereto.
+ */
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.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_COORD_UNITS];
+ GLuint TexgenHoles[MAX_TEXTURE_COORD_UNITS];
+ texgen_func TexgenFunc[MAX_TEXTURE_COORD_UNITS];
+
+ /* Temporary values used in texgen.
+ */
+ GLfloat (*tmp_f)[3];
+ GLfloat *tmp_m;
+
+ /* Buffered outputs of the stage.
+ */
+ GLvector4f texcoord[MAX_TEXTURE_COORD_UNITS];
+};
+
+
+#define TEXGEN_STAGE_DATA(stage) ((struct texgen_stage_data *)stage->privatePtr)
+
+
+
+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)
+
+#define TEXGEN_NEED_M (TEXGEN_SPHERE_MAP)
+#define TEXGEN_NEED_F (TEXGEN_SPHERE_MAP | \
+ TEXGEN_REFLECTION_MAP_NV)
+
+
+
+static void build_m3( GLfloat f[][3], GLfloat m[],
+ const GLvector4f *normal,
+ const GLvector4f *eye )
+{
+ GLuint stride = eye->stride;
+ GLfloat *coord = (GLfloat *)eye->start;
+ GLuint count = eye->count;
+ const GLfloat *norm = normal->start;
+ GLuint i;
+
+ for (i=0;i<count;i++,STRIDE_F(coord,stride),STRIDE_F(norm,normal->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 * _mesa_inv_sqrtf(m[i]);
+ }
+ }
+}
+
+
+
+static void build_m2( GLfloat f[][3], GLfloat m[],
+ const GLvector4f *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),STRIDE_F(norm,normal->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 * _mesa_inv_sqrtf(m[i]);
+ }
+ }
+}
+
+
+
+typedef void (*build_m_func)( GLfloat f[][3],
+ GLfloat m[],
+ const GLvector4f *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 GLvector4f *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 GLvector4f *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 GLvector4f *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)
+ _mesa_copy_tab[0x8]( out, in );
+ }
+ 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];
+ GLvector4f *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)
+ _mesa_copy_tab[0x8]( out, in );
+ }
+ 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)
+ _mesa_copy_tab[all_bits[in->size] & ~0x3]( out, in );
+ } 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];
+ const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+ const GLvector4f *obj = VB->ObjPtr;
+ const GLvector4f *eye = VB->EyePtr;
+ const GLvector4f *normal = VB->NormalPtr;
+ const GLfloat *m = store->tmp_m;
+ const GLuint count = VB->Count;
+ GLfloat (*texcoord)[4] = (GLfloat (*)[4])out->data;
+ GLfloat (*f)[3] = store->tmp_f;
+ GLuint holes = 0;
+
+ if (texUnit->_GenFlags & TEXGEN_NEED_M) {
+ build_m_tab[eye->size]( store->tmp_f, store->tmp_m, normal, eye );
+ } else if (texUnit->_GenFlags & TEXGEN_NEED_F) {
+ build_f_tab[eye->size]( (GLfloat *)store->tmp_f, 3, normal, eye );
+ }
+
+ if (!in) {
+ ASSERT(0);
+ in = out;
+ in->count = VB->Count;
+
+ out->size = store->TexgenSize[unit];
+ out->flags |= texUnit->TexGenEnabled;
+ out->count = VB->Count;
+ holes = store->TexgenHoles[unit];
+ }
+ else {
+ GLuint copy = (all_bits[in->size] & ~texUnit->TexGenEnabled);
+ if (copy)
+ _mesa_copy_tab[copy]( out, in );
+
+ out->size = MAX2(in->size, store->TexgenSize[unit]);
+ out->flags |= (in->flags & VEC_SIZE_FLAGS) | texUnit->TexGenEnabled;
+ out->count = in->count;
+
+ holes = ~all_bits[in->size] & store->TexgenHoles[unit];
+ }
+
+ if (holes) {
+ if (holes & VEC_DIRTY_3) _mesa_vector4f_clean_elem(out, count, 3);
+ if (holes & VEC_DIRTY_2) _mesa_vector4f_clean_elem(out, count, 2);
+ if (holes & VEC_DIRTY_1) _mesa_vector4f_clean_elem(out, count, 1);
+ if (holes & VEC_DIRTY_0) _mesa_vector4f_clean_elem(out, count, 0);
+ }
+
+ if (texUnit->TexGenEnabled & S_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeS) {
+ case GL_OBJECT_LINEAR:
+ _mesa_dotprod_tab[obj->size]( (GLfloat *)out->data,
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneS );
+ break;
+ case GL_EYE_LINEAR:
+ _mesa_dotprod_tab[eye->size]( (GLfloat *)out->data,
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneS );
+ break;
+ case GL_SPHERE_MAP:
+ for (i = 0; i < count; i++)
+ texcoord[i][0] = f[i][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:
+ _mesa_problem(ctx, "Bad S texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & T_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeT) {
+ case GL_OBJECT_LINEAR:
+ _mesa_dotprod_tab[obj->size]( &(out->data[0][1]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneT );
+ break;
+ case GL_EYE_LINEAR:
+ _mesa_dotprod_tab[eye->size]( &(out->data[0][1]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneT );
+ break;
+ case GL_SPHERE_MAP:
+ for (i = 0; i < count; i++)
+ texcoord[i][1] = f[i][1] * m[i] + 0.5F;
+ break;
+ case GL_REFLECTION_MAP_NV:
+ for (i=0;i<count;i++)
+ texcoord[i][1] = f[i][1];
+ 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:
+ _mesa_problem(ctx, "Bad T texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & R_BIT) {
+ GLuint i;
+ switch (texUnit->GenModeR) {
+ case GL_OBJECT_LINEAR:
+ _mesa_dotprod_tab[obj->size]( &(out->data[0][2]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneR );
+ break;
+ case GL_EYE_LINEAR:
+ _mesa_dotprod_tab[eye->size]( &(out->data[0][2]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneR );
+ 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:
+ _mesa_problem(ctx, "Bad R texgen");
+ }
+ }
+
+ if (texUnit->TexGenEnabled & Q_BIT) {
+ switch (texUnit->GenModeQ) {
+ case GL_OBJECT_LINEAR:
+ _mesa_dotprod_tab[obj->size]( &(out->data[0][3]),
+ sizeof(out->data[0]), obj,
+ texUnit->ObjectPlaneQ );
+ break;
+ case GL_EYE_LINEAR:
+ _mesa_dotprod_tab[eye->size]( &(out->data[0][3]),
+ sizeof(out->data[0]), eye,
+ texUnit->EyePlaneQ );
+ break;
+ default:
+ _mesa_problem(ctx, "Bad Q texgen");
+ }
+ }
+}
+
+
+
+static GLboolean run_texgen_stage( GLcontext *ctx,
+ struct tnl_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.MaxTextureCoordUnits ; i++)
+ if (ctx->Texture._TexGenEnabled & ENABLE_TEXGEN(i)) {
+ if (stage->changed_inputs & (_TNL_BIT_POS | _TNL_BIT_NORMAL | _TNL_BIT_TEX(i)))
+ store->TexgenFunc[i]( ctx, store, i );
+
+ VB->AttribPtr[VERT_ATTRIB_TEX0+i] =
+ VB->TexCoordPtr[i] = &store->texcoord[i];
+ }
+
+ return GL_TRUE;
+}
+
+
+
+
+static GLboolean run_validate_texgen_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
+ GLuint i;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[i];
+
+ if (texUnit->TexGenEnabled) {
+ GLuint sz;
+
+ if (texUnit->TexGenEnabled & Q_BIT)
+ sz = 4;
+ else if (texUnit->TexGenEnabled & R_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; /* general solution */
+
+ /* look for special texgen cases */
+ 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 tnl_pipeline_stage *stage )
+{
+ GLuint i;
+ stage->active = 0;
+
+ if (ctx->Texture._TexGenEnabled && !ctx->VertexProgram._Enabled) {
+ GLuint inputs = 0;
+ GLuint outputs = 0;
+
+ if (ctx->Texture._GenFlags & (TEXGEN_OBJ_LINEAR | TEXGEN_NEED_EYE_COORD))
+ inputs |= _TNL_BIT_POS;
+
+ if (ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS)
+ inputs |= _TNL_BIT_NORMAL;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
+ if (ctx->Texture._TexGenEnabled & ENABLE_TEXGEN(i))
+ {
+ outputs |= _TNL_BIT_TEX(i);
+
+ /* Need the original input in case it contains a Q coord:
+ * (sigh)
+ */
+ inputs |= _TNL_BIT_TEX(i);
+
+ /* Something for Feedback? */
+ }
+
+ if (stage->privatePtr)
+ 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 tnl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texgen_stage_data *store;
+ GLuint i;
+
+ stage->privatePtr = CALLOC(sizeof(*store));
+ store = TEXGEN_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
+ _mesa_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 tnl_pipeline_stage *stage )
+
+{
+ struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0 ; i < MAX_TEXTURE_COORD_UNITS ; i++)
+ if (store->texcoord[i].data)
+ _mesa_vector4f_free( &store->texcoord[i] );
+
+
+ if (store->tmp_f) FREE( store->tmp_f );
+ if (store->tmp_m) FREE( store->tmp_m );
+ FREE( store );
+ stage->privatePtr = NULL;
+ }
+}
+
+
+
+const struct tnl_pipeline_stage _tnl_texgen_stage =
+{
+ "texgen", /* name */
+ _NEW_TEXTURE|_NEW_PROGRAM, /* when to call check() */
+ _NEW_TEXTURE, /* when to invalidate stored data */
+ GL_FALSE, /* active? */
+ 0, /* inputs */
+ 0, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ 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 0000000..8f6ca89
--- /dev/null
+++ b/src/mesa/tnl/t_vb_texmat.c
@@ -0,0 +1,150 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.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_COORD_UNITS];
+};
+
+#define TEXMAT_STAGE_DATA(stage) ((struct texmat_stage_data *)stage->privatePtr)
+
+static void check_texmat( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ GLuint i;
+ stage->active = 0;
+
+ if (ctx->Texture._TexMatEnabled && !ctx->VertexProgram._Enabled) {
+ GLuint flags = 0;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
+ if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i))
+ flags |= _TNL_BIT_TEX(i);
+
+ stage->active = 1;
+ stage->inputs = flags;
+ stage->outputs = flags;
+ }
+}
+
+static GLboolean run_texmat_stage( GLcontext *ctx,
+ struct tnl_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.MaxTextureCoordUnits ; i++)
+ if (ctx->Texture._TexMatEnabled & ENABLE_TEXMAT(i)) {
+ if (stage->changed_inputs & _TNL_BIT_TEX(i))
+ (void) TransformRaw( &store->texcoord[i],
+ ctx->TextureMatrixStack[i].Top,
+ VB->TexCoordPtr[i]);
+
+ VB->AttribPtr[VERT_ATTRIB_TEX0+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 tnl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct texmat_stage_data *store;
+ GLuint i;
+
+ stage->privatePtr = CALLOC(sizeof(*store));
+ store = TEXMAT_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
+ _mesa_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 tnl_pipeline_stage *stage )
+{
+ struct texmat_stage_data *store = TEXMAT_STAGE_DATA(stage);
+ GLuint i;
+
+ if (store) {
+ for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++)
+ if (store->texcoord[i].data)
+ _mesa_vector4f_free( &store->texcoord[i] );
+ FREE( store );
+ stage->privatePtr = 0;
+ }
+}
+
+
+
+const struct tnl_pipeline_stage _tnl_texture_transform_stage =
+{
+ "texture transform", /* name */
+ _NEW_TEXTURE|_NEW_TEXTURE_MATRIX|_NEW_PROGRAM, /* check_state */
+ _NEW_TEXTURE|_NEW_TEXTURE_MATRIX, /* run_state */
+ GL_FALSE, /* active? */
+ 0, /* inputs */
+ 0, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ 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 0000000..3951439
--- /dev/null
+++ b/src/mesa/tnl/t_vb_vertex.c
@@ -0,0 +1,331 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+
+#include "glheader.h"
+#include "colormac.h"
+#include "context.h"
+#include "macros.h"
+#include "imports.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_ndcptr;
+};
+
+#define VERTEX_STAGE_DATA(stage) ((struct vertex_stage_data *)stage->privatePtr)
+
+
+
+
+/* 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.ClipPlanesEnabled & (1 << 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 tnl_pipeline_stage *stage )
+{
+ struct vertex_stage_data *store = (struct vertex_stage_data *)stage->privatePtr;
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+
+ ASSERT(!ctx->VertexProgram._Enabled);
+
+ if (stage->changed_inputs) {
+
+ if (ctx->_NeedEyeCoords) {
+ /* Separate modelview transformation:
+ * Use combined ModelProject to avoid some depth artifacts
+ */
+ if (ctx->ModelviewMatrixStack.Top->type == MATRIX_IDENTITY)
+ VB->EyePtr = VB->ObjPtr;
+ else
+ VB->EyePtr = TransformRaw( &store->eye,
+ ctx->ModelviewMatrixStack.Top,
+ VB->ObjPtr);
+#if 0
+ /* examine some eye coordinates */
+ {
+ GLuint i;
+ GLfloat *v = VB->EyePtr->start;
+ for (i = 0; i < 4; i++) {
+ _mesa_printf("eye[%d] = %g, %g, %g, %g\n",
+ i, v[0], v[1], v[2], v[3]);
+ v += 4;
+ }
+ }
+#endif
+ }
+
+ VB->ClipPtr = TransformRaw( &store->clip,
+ &ctx->_ModelProjectMatrix,
+ VB->ObjPtr );
+
+ /* Drivers expect this to be clean to element 4...
+ */
+ switch (VB->ClipPtr->size) {
+ case 1:
+ /* impossible */
+ case 2:
+ _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
+ /* fall-through */
+ case 3:
+ _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
+ /* fall-through */
+ case 4:
+ break;
+ }
+
+#if 0
+ /* examine some clip coordinates */
+ {
+ GLuint i;
+ GLfloat *v = VB->ClipPtr->start;
+ for (i = 0; i < 4; i++) {
+ _mesa_printf("clip[%d] = %g, %g, %g, %g\n",
+ i, v[0], v[1], v[2], v[3]);
+ v += 4;
+ }
+ }
+#endif
+
+ /* Cliptest and perspective divide. Clip functions must clear
+ * the clipmask.
+ */
+ store->ormask = 0;
+ store->andmask = CLIP_ALL_BITS;
+
+ if (tnl->NeedNdcCoords) {
+ VB->NdcPtr =
+ _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
+ &store->proj,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+ }
+ else {
+ VB->NdcPtr = 0;
+ _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
+ 0,
+ 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.ClipPlanesEnabled) {
+ usercliptab[VB->ClipPtr->size]( ctx,
+ VB->ClipPtr,
+ store->clipmask,
+ &store->ormask,
+ &store->andmask );
+
+ if (store->andmask)
+ return GL_FALSE;
+ }
+
+ VB->ClipAndMask = store->andmask;
+ VB->ClipOrMask = store->ormask;
+ VB->ClipMask = store->clipmask;
+
+ store->save_eyeptr = VB->EyePtr;
+ store->save_clipptr = VB->ClipPtr;
+ store->save_ndcptr = VB->NdcPtr;
+ }
+ else {
+ /* Replay the sideeffects.
+ */
+ VB->EyePtr = store->save_eyeptr;
+ VB->ClipPtr = store->save_clipptr;
+ VB->NdcPtr = store->save_ndcptr;
+ VB->ClipMask = store->clipmask;
+ VB->ClipAndMask = store->andmask;
+ VB->ClipOrMask = store->ormask;
+ if (store->andmask)
+ return GL_FALSE;
+ }
+
+ return GL_TRUE;
+}
+
+
+static void check_vertex( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+{
+ stage->active = !ctx->VertexProgram._Enabled;
+}
+
+static GLboolean init_vertex_stage( GLcontext *ctx,
+ struct tnl_pipeline_stage *stage )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct vertex_stage_data *store;
+ GLuint size = VB->Size;
+
+ stage->privatePtr = CALLOC(sizeof(*store));
+ store = VERTEX_STAGE_DATA(stage);
+ if (!store)
+ return GL_FALSE;
+
+ _mesa_vector4f_alloc( &store->eye, 0, size, 32 );
+ _mesa_vector4f_alloc( &store->clip, 0, size, 32 );
+ _mesa_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 tnl_pipeline_stage *stage )
+{
+ struct vertex_stage_data *store = VERTEX_STAGE_DATA(stage);
+
+ if (store) {
+ _mesa_vector4f_free( &store->eye );
+ _mesa_vector4f_free( &store->clip );
+ _mesa_vector4f_free( &store->proj );
+ ALIGN_FREE( store->clipmask );
+ FREE(store);
+ stage->privatePtr = NULL;
+ stage->run = init_vertex_stage;
+ }
+}
+
+
+const struct tnl_pipeline_stage _tnl_vertex_transform_stage =
+{
+ "modelview/project/cliptest/divide",
+ _NEW_PROGRAM, /* check_state: only care about vertex prog */
+ _MESA_NEW_NEED_EYE_COORDS | /* run_state: when to invalidate / re-run */
+ _NEW_MODELVIEW|
+ _NEW_PROJECTION|
+ _NEW_PROGRAM|
+ _NEW_TRANSFORM,
+ GL_TRUE, /* active */
+ _TNL_BIT_POS, /* inputs */
+ _TNL_BIT_POS, /* outputs */
+ 0, /* changed_inputs */
+ NULL, /* private data */
+ dtr, /* destructor */
+ check_vertex, /* check */
+ init_vertex_stage /* run -- initially set to init */
+};
diff --git a/src/mesa/tnl/t_vertex.c b/src/mesa/tnl/t_vertex.c
new file mode 100644
index 0000000..900648a
--- /dev/null
+++ b/src/mesa/tnl/t_vertex.c
@@ -0,0 +1,1294 @@
+/*
+ * Copyright 2003 Tungsten Graphics, inc.
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 (including the next
+ * paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+
+#include "t_context.h"
+#include "t_vertex.h"
+
+
+/* Build and manage clipspace/ndc/window vertices.
+ *
+ * Another new mechanism designed and crying out for codegen. Before
+ * that, it would be very interesting to investigate the merger of
+ * these vertices and those built in t_vtx_*.
+ */
+
+
+
+
+
+
+/*
+ * These functions take the NDC coordinates pointed to by 'in', apply the
+ * NDC->Viewport mapping and store the results at 'v'.
+ */
+
+static void
+insert_4f_viewport_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+ out[2] = vp[10] * in[2] + vp[14];
+ out[3] = in[3];
+}
+
+static void insert_4f_viewport_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+ out[2] = vp[10] * in[2] + vp[14];
+ out[3] = 1;
+}
+
+static void insert_4f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+ out[2] = vp[14];
+ out[3] = 1;
+}
+
+static void insert_4f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[13];
+ out[2] = vp[14];
+ out[3] = 1;
+}
+
+static void insert_3f_viewport_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+ out[2] = vp[10] * in[2] + vp[14];
+}
+
+static void insert_3f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+ out[2] = vp[10] * in[2] + vp[14];
+}
+
+static void insert_3f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[13];
+ out[2] = vp[14];
+}
+
+static void insert_2f_viewport_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[5] * in[1] + vp[13];
+}
+
+static void insert_2f_viewport_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = vp[0] * in[0] + vp[12];
+ out[1] = vp[13];
+}
+
+
+/*
+ * These functions do the same as above, except for the viewport mapping.
+ */
+
+static void insert_4f_4( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+static void insert_4f_3( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1;
+}
+
+static void insert_4f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = 0;
+ out[3] = 1;
+}
+
+static void insert_4f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+}
+
+static void insert_3f_xyw_4( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[3];
+}
+
+static void insert_3f_xyw_err( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ (void) a; (void) v; (void) in;
+ abort();
+}
+
+static void insert_3f_3( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+}
+
+static void insert_3f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = 0;
+}
+
+static void insert_3f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = 0;
+ out[2] = 0;
+}
+
+
+static void insert_2f_2( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+}
+
+static void insert_2f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = 0;
+}
+
+static void insert_1f_1( const struct tnl_clipspace_attr *a, GLubyte *v, const GLfloat *in )
+{
+ GLfloat *out = (GLfloat *)(v);
+ (void) a;
+
+ out[0] = in[0];
+}
+
+static void insert_4chan_4f_rgba_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLchan *c = (GLchan *)v;
+ (void) a;
+ UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[3], in[3]);
+}
+
+static void insert_4chan_4f_rgba_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLchan *c = (GLchan *)v;
+ (void) a;
+ UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[2], in[2]);
+ c[3] = CHAN_MAX;
+}
+
+static void insert_4chan_4f_rgba_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLchan *c = (GLchan *)v;
+ (void) a;
+ UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);
+ UNCLAMPED_FLOAT_TO_CHAN(c[1], in[1]);
+ c[2] = 0;
+ c[3] = CHAN_MAX;
+}
+
+static void insert_4chan_4f_rgba_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ GLchan *c = (GLchan *)v;
+ (void) a;
+ UNCLAMPED_FLOAT_TO_CHAN(c[0], in[0]);
+ c[1] = 0;
+ c[2] = 0;
+ c[3] = CHAN_MAX;
+}
+
+static void insert_4ub_4f_rgba_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
+}
+
+static void insert_4ub_4f_rgba_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_rgba_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ v[2] = 0;
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_rgba_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ v[1] = 0;
+ v[2] = 0;
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_bgra_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[3]);
+}
+
+static void insert_4ub_4f_bgra_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_bgra_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ v[0] = 0;
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_bgra_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ v[1] = 0;
+ v[0] = 0;
+ v[3] = 0xff;
+}
+
+static void insert_4ub_4f_argb_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]);
+}
+
+static void insert_4ub_4f_argb_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[2]);
+ v[0] = 0xff;
+}
+
+static void insert_4ub_4f_argb_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ v[3] = 0x00;
+ v[0] = 0xff;
+}
+
+static void insert_4ub_4f_argb_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[0]);
+ v[2] = 0x00;
+ v[3] = 0x00;
+ v[0] = 0xff;
+}
+
+static void insert_4ub_4f_abgr_4( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[3]);
+}
+
+static void insert_4ub_4f_abgr_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[2]);
+ v[0] = 0xff;
+}
+
+static void insert_4ub_4f_abgr_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[1]);
+ v[1] = 0x00;
+ v[0] = 0xff;
+}
+
+static void insert_4ub_4f_abgr_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[3], in[0]);
+ v[2] = 0x00;
+ v[1] = 0x00;
+ v[0] = 0xff;
+}
+
+static void insert_3ub_3f_rgb_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[2]);
+}
+
+static void insert_3ub_3f_rgb_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ v[2] = 0;
+}
+
+static void insert_3ub_3f_rgb_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+ v[1] = 0;
+ v[2] = 0;
+}
+
+static void insert_3ub_3f_bgr_3( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[2]);
+}
+
+static void insert_3ub_3f_bgr_2( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ UNCLAMPED_FLOAT_TO_UBYTE(v[1], in[1]);
+ v[0] = 0;
+}
+
+static void insert_3ub_3f_bgr_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[2], in[0]);
+ v[1] = 0;
+ v[0] = 0;
+}
+
+
+static void insert_1ub_1f_1( const struct tnl_clipspace_attr *a, GLubyte *v,
+ const GLfloat *in )
+{
+ (void) a;
+ UNCLAMPED_FLOAT_TO_UBYTE(v[0], in[0]);
+}
+
+
+/***********************************************************************
+ * Functions to perform the reverse operations to the above, for
+ * swrast translation and clip-interpolation.
+ *
+ * Currently always extracts a full 4 floats.
+ */
+
+static void extract_4f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ /* Although included for completeness, the position coordinate is
+ * usually handled differently during clipping.
+ */
+ out[0] = (in[0] - vp[12]) / vp[0];
+ out[1] = (in[1] - vp[13]) / vp[5];
+ out[2] = (in[2] - vp[14]) / vp[10];
+ out[3] = in[3];
+}
+
+static void extract_3f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = (in[0] - vp[12]) / vp[0];
+ out[1] = (in[1] - vp[13]) / vp[5];
+ out[2] = (in[2] - vp[14]) / vp[10];
+ out[3] = 1;
+}
+
+
+static void extract_2f_viewport( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ const GLfloat * const vp = a->vp;
+
+ out[0] = (in[0] - vp[12]) / vp[0];
+ out[1] = (in[1] - vp[13]) / vp[5];
+ out[2] = 0;
+ out[3] = 1;
+}
+
+
+static void extract_4f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = in[3];
+}
+
+static void extract_3f_xyw( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = 0;
+ out[3] = in[2];
+}
+
+
+static void extract_3f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = in[2];
+ out[3] = 1;
+}
+
+
+static void extract_2f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = in[1];
+ out[2] = 0;
+ out[3] = 1;
+}
+
+static void extract_1f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ const GLfloat *in = (const GLfloat *)v;
+ (void) a;
+
+ out[0] = in[0];
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+}
+
+static void extract_4chan_4f_rgba( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ GLchan *c = (GLchan *)v;
+ (void) a;
+
+ out[0] = CHAN_TO_FLOAT(c[0]);
+ out[1] = CHAN_TO_FLOAT(c[1]);
+ out[2] = CHAN_TO_FLOAT(c[2]);
+ out[3] = CHAN_TO_FLOAT(c[3]);
+}
+
+static void extract_4ub_4f_rgba( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[0] = UBYTE_TO_FLOAT(v[0]);
+ out[1] = UBYTE_TO_FLOAT(v[1]);
+ out[2] = UBYTE_TO_FLOAT(v[2]);
+ out[3] = UBYTE_TO_FLOAT(v[3]);
+}
+
+static void extract_4ub_4f_bgra( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[2] = UBYTE_TO_FLOAT(v[0]);
+ out[1] = UBYTE_TO_FLOAT(v[1]);
+ out[0] = UBYTE_TO_FLOAT(v[2]);
+ out[3] = UBYTE_TO_FLOAT(v[3]);
+}
+
+static void extract_4ub_4f_argb( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[3] = UBYTE_TO_FLOAT(v[0]);
+ out[0] = UBYTE_TO_FLOAT(v[1]);
+ out[1] = UBYTE_TO_FLOAT(v[2]);
+ out[2] = UBYTE_TO_FLOAT(v[3]);
+}
+
+static void extract_4ub_4f_abgr( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[3] = UBYTE_TO_FLOAT(v[0]);
+ out[2] = UBYTE_TO_FLOAT(v[1]);
+ out[1] = UBYTE_TO_FLOAT(v[2]);
+ out[0] = UBYTE_TO_FLOAT(v[3]);
+}
+
+static void extract_3ub_3f_rgb( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[0] = UBYTE_TO_FLOAT(v[0]);
+ out[1] = UBYTE_TO_FLOAT(v[1]);
+ out[2] = UBYTE_TO_FLOAT(v[2]);
+ out[3] = 1;
+}
+
+static void extract_3ub_3f_bgr( const struct tnl_clipspace_attr *a, GLfloat *out,
+ const GLubyte *v )
+{
+ (void) a;
+ out[2] = UBYTE_TO_FLOAT(v[0]);
+ out[1] = UBYTE_TO_FLOAT(v[1]);
+ out[0] = UBYTE_TO_FLOAT(v[2]);
+ out[3] = 1;
+}
+
+static void extract_1ub_1f( const struct tnl_clipspace_attr *a, GLfloat *out, const GLubyte *v )
+{
+ (void) a;
+ out[0] = UBYTE_TO_FLOAT(v[0]);
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+}
+
+
+static struct {
+ const char *name;
+ tnl_extract_func extract;
+ tnl_insert_func insert[4];
+ const GLuint attrsize;
+} format_info[EMIT_MAX] = {
+
+ { "1f",
+ extract_1f,
+ { insert_1f_1, insert_1f_1, insert_1f_1, insert_1f_1 },
+ sizeof(GLfloat) },
+
+ { "2f",
+ extract_2f,
+ { insert_2f_1, insert_2f_2, insert_2f_2, insert_2f_2 },
+ 2 * sizeof(GLfloat) },
+
+ { "3f",
+ extract_3f,
+ { insert_3f_1, insert_3f_2, insert_3f_3, insert_3f_3 },
+ 3 * sizeof(GLfloat) },
+
+ { "4f",
+ extract_4f,
+ { insert_4f_1, insert_4f_2, insert_4f_3, insert_4f_4 },
+ 4 * sizeof(GLfloat) },
+
+ { "2f_viewport",
+ extract_2f_viewport,
+ { insert_2f_viewport_1, insert_2f_viewport_2, insert_2f_viewport_2,
+ insert_2f_viewport_2 },
+ 2 * sizeof(GLfloat) },
+
+ { "3f_viewport",
+ extract_3f_viewport,
+ { insert_3f_viewport_1, insert_3f_viewport_2, insert_3f_viewport_3,
+ insert_3f_viewport_3 },
+ 3 * sizeof(GLfloat) },
+
+ { "4f_viewport",
+ extract_4f_viewport,
+ { insert_4f_viewport_1, insert_4f_viewport_2, insert_4f_viewport_3,
+ insert_4f_viewport_4 },
+ 4 * sizeof(GLfloat) },
+
+ { "3f_xyw",
+ extract_3f_xyw,
+ { insert_3f_xyw_err, insert_3f_xyw_err, insert_3f_xyw_err,
+ insert_3f_xyw_4 },
+ 3 * sizeof(GLfloat) },
+
+ { "1ub_1f",
+ extract_1ub_1f,
+ { insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1, insert_1ub_1f_1 },
+ sizeof(GLubyte) },
+
+ { "3ub_3f_rgb",
+ extract_3ub_3f_rgb,
+ { insert_3ub_3f_rgb_1, insert_3ub_3f_rgb_2, insert_3ub_3f_rgb_3,
+ insert_3ub_3f_rgb_3 },
+ 3 * sizeof(GLubyte) },
+
+ { "3ub_3f_bgr",
+ extract_3ub_3f_bgr,
+ { insert_3ub_3f_bgr_1, insert_3ub_3f_bgr_2, insert_3ub_3f_bgr_3,
+ insert_3ub_3f_bgr_3 },
+ 3 * sizeof(GLubyte) },
+
+ { "4ub_4f_rgba",
+ extract_4ub_4f_rgba,
+ { insert_4ub_4f_rgba_1, insert_4ub_4f_rgba_2, insert_4ub_4f_rgba_3,
+ insert_4ub_4f_rgba_4 },
+ 4 * sizeof(GLubyte) },
+
+ { "4ub_4f_bgra",
+ extract_4ub_4f_bgra,
+ { insert_4ub_4f_bgra_1, insert_4ub_4f_bgra_2, insert_4ub_4f_bgra_3,
+ insert_4ub_4f_bgra_4 },
+ 4 * sizeof(GLubyte) },
+
+ { "4ub_4f_argb",
+ extract_4ub_4f_argb,
+ { insert_4ub_4f_argb_1, insert_4ub_4f_argb_2, insert_4ub_4f_argb_3,
+ insert_4ub_4f_argb_4 },
+ 4 * sizeof(GLubyte) },
+
+ { "4ub_4f_abgr",
+ extract_4ub_4f_abgr,
+ { insert_4ub_4f_abgr_1, insert_4ub_4f_abgr_2, insert_4ub_4f_abgr_3,
+ insert_4ub_4f_abgr_4 },
+ 4 * sizeof(GLubyte) },
+
+ { "4chan_4f_rgba",
+ extract_4chan_4f_rgba,
+ { insert_4chan_4f_rgba_1, insert_4chan_4f_rgba_2, insert_4chan_4f_rgba_3,
+ insert_4chan_4f_rgba_4 },
+ 4 * sizeof(GLchan) },
+
+ { "pad",
+ 0,
+ { 0, 0, 0, 0 },
+ 0 }
+
+};
+
+
+/***********************************************************************
+ * Generic (non-codegen) functions for whole vertices or groups of
+ * vertices
+ */
+
+static void generic_emit( GLcontext *ctx,
+ GLuint start, GLuint end,
+ void *dest )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ struct tnl_clipspace_attr *a = vtx->attr;
+ GLubyte *v = (GLubyte *)dest;
+ GLuint i, j;
+ const GLuint count = vtx->attr_count;
+ GLuint stride;
+
+ for (j = 0; j < count; j++) {
+ GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
+ a[j].inputstride = vptr->stride;
+ a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
+ a[j].emit = a[j].insert[vptr->size - 1];
+ }
+
+ end -= start;
+ stride = vtx->vertex_size;
+
+ for (i = 0 ; i < end ; i++, v += stride) {
+ for (j = 0; j < count; j++) {
+ GLfloat *in = (GLfloat *)a[j].inputptr;
+ a[j].inputptr += a[j].inputstride;
+ a[j].emit( &a[j], v + a[j].vertoffset, in );
+ }
+ }
+}
+
+
+static void generic_interp( GLcontext *ctx,
+ GLfloat t,
+ GLuint edst, GLuint eout, GLuint ein,
+ GLboolean force_boundary )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ const GLubyte *vin = vtx->vertex_buf + ein * vtx->vertex_size;
+ const GLubyte *vout = vtx->vertex_buf + eout * vtx->vertex_size;
+ GLubyte *vdst = vtx->vertex_buf + edst * vtx->vertex_size;
+ const struct tnl_clipspace_attr *a = vtx->attr;
+ const GLuint attr_count = vtx->attr_count;
+ GLuint j;
+ (void) force_boundary;
+
+ if (tnl->NeedNdcCoords) {
+ const GLfloat *dstclip = VB->ClipPtr->data[edst];
+ if (dstclip[3] != 0.0) {
+ const GLfloat w = 1.0f / dstclip[3];
+ GLfloat pos[4];
+
+ pos[0] = dstclip[0] * w;
+ pos[1] = dstclip[1] * w;
+ pos[2] = dstclip[2] * w;
+ pos[3] = w;
+
+ a[0].insert[4-1]( &a[0], vdst, pos );
+ }
+ }
+ else {
+ a[0].insert[4-1]( &a[0], vdst, VB->ClipPtr->data[edst] );
+ }
+
+
+ for (j = 1; j < attr_count; j++) {
+ GLfloat fin[4], fout[4], fdst[4];
+
+ a[j].extract( &a[j], fin, vin + a[j].vertoffset );
+ a[j].extract( &a[j], fout, vout + a[j].vertoffset );
+
+ INTERP_F( t, fdst[3], fout[3], fin[3] );
+ INTERP_F( t, fdst[2], fout[2], fin[2] );
+ INTERP_F( t, fdst[1], fout[1], fin[1] );
+ INTERP_F( t, fdst[0], fout[0], fin[0] );
+
+ a[j].insert[4-1]( &a[j], vdst + a[j].vertoffset, fdst );
+ }
+}
+
+
+/* Extract color attributes from one vertex and insert them into
+ * another. (Shortcircuit extract/insert with memcpy).
+ */
+static void generic_copy_pv( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ GLubyte *vsrc = vtx->vertex_buf + esrc * vtx->vertex_size;
+ GLubyte *vdst = vtx->vertex_buf + edst * vtx->vertex_size;
+ const struct tnl_clipspace_attr *a = vtx->attr;
+ const GLuint attr_count = vtx->attr_count;
+ GLuint j;
+
+ for (j = 0; j < attr_count; j++) {
+ if (a[j].attrib == VERT_ATTRIB_COLOR0 ||
+ a[j].attrib == VERT_ATTRIB_COLOR1) {
+
+ _mesa_memcpy( vdst + a[j].vertoffset,
+ vsrc + a[j].vertoffset,
+ a[j].vertattrsize );
+ }
+ }
+}
+
+
+/* Helper functions for hardware which doesn't put back colors and/or
+ * edgeflags into vertices.
+ */
+static void generic_interp_extras( GLcontext *ctx,
+ GLfloat t,
+ GLuint dst, GLuint out, GLuint in,
+ GLboolean force_boundary )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ if (VB->ColorPtr[1]) {
+ assert(VB->ColorPtr[1]->stride == 4 * sizeof(GLfloat));
+
+ INTERP_4F( t,
+ VB->ColorPtr[1]->data[dst],
+ VB->ColorPtr[1]->data[out],
+ VB->ColorPtr[1]->data[in] );
+
+ if (VB->SecondaryColorPtr[1]) {
+ INTERP_3F( t,
+ VB->SecondaryColorPtr[1]->data[dst],
+ VB->SecondaryColorPtr[1]->data[out],
+ VB->SecondaryColorPtr[1]->data[in] );
+ }
+ }
+ else if (VB->IndexPtr[1]) {
+ VB->IndexPtr[1]->data[dst][0] = LINTERP( t,
+ VB->IndexPtr[1]->data[out][0],
+ VB->IndexPtr[1]->data[in][0] );
+ }
+
+ if (VB->EdgeFlag) {
+ VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary;
+ }
+
+ generic_interp(ctx, t, dst, out, in, force_boundary);
+}
+
+static void generic_copy_pv_extras( GLcontext *ctx,
+ GLuint dst, GLuint src )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+
+ if (VB->ColorPtr[1]) {
+ COPY_4FV( VB->ColorPtr[1]->data[dst],
+ VB->ColorPtr[1]->data[src] );
+
+ if (VB->SecondaryColorPtr[1]) {
+ COPY_4FV( VB->SecondaryColorPtr[1]->data[dst],
+ VB->SecondaryColorPtr[1]->data[src] );
+ }
+ }
+ else if (VB->IndexPtr[1]) {
+ VB->IndexPtr[1]->data[dst][0] = VB->IndexPtr[1]->data[src][0];
+ }
+
+ generic_copy_pv(ctx, dst, src);
+}
+
+
+
+
+/***********************************************************************
+ * Build codegen functions or return generic ones:
+ */
+
+
+static void do_emit( GLcontext *ctx, GLuint start, GLuint end,
+ void *dest)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ struct tnl_clipspace_attr *a = vtx->attr;
+ const GLuint count = vtx->attr_count;
+ GLuint j;
+
+ for (j = 0; j < count; j++) {
+ GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
+ a[j].inputstride = vptr->stride;
+ a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
+ a[j].emit = a[j].insert[vptr->size - 1];
+ }
+
+ vtx->emit = 0;
+
+ if (0)
+ vtx->emit = _tnl_codegen_emit(ctx);
+
+ if (!vtx->emit)
+ vtx->emit = generic_emit;
+
+ vtx->emit( ctx, start, end, dest );
+}
+
+
+
+static void choose_interp_func( GLcontext *ctx,
+ GLfloat t,
+ GLuint edst, GLuint eout, GLuint ein,
+ GLboolean force_boundary )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+
+ if (vtx->need_extras &&
+ (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+ vtx->interp = generic_interp_extras;
+ } else {
+ vtx->interp = generic_interp;
+ }
+
+ vtx->interp( ctx, t, edst, eout, ein, force_boundary );
+}
+
+
+static void choose_copy_pv_func( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+
+ if (vtx->need_extras &&
+ (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
+ vtx->copy_pv = generic_copy_pv_extras;
+ } else {
+ vtx->copy_pv = generic_copy_pv;
+ }
+
+ vtx->copy_pv( ctx, edst, esrc );
+}
+
+
+/***********************************************************************
+ * Public entrypoints, mostly dispatch to the above:
+ */
+
+
+/* Interpolate between two vertices to produce a third:
+ */
+void _tnl_interp( GLcontext *ctx,
+ GLfloat t,
+ GLuint edst, GLuint eout, GLuint ein,
+ GLboolean force_boundary )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ vtx->interp( ctx, t, edst, eout, ein, force_boundary );
+}
+
+/* Copy colors from one vertex to another:
+ */
+void _tnl_copy_pv( GLcontext *ctx, GLuint edst, GLuint esrc )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ vtx->copy_pv( ctx, edst, esrc );
+}
+
+
+/* Extract a named attribute from a hardware vertex. Will have to
+ * reverse any viewport transformation, swizzling or other conversions
+ * which may have been applied:
+ */
+void _tnl_get_attr( GLcontext *ctx, const void *vin,
+ GLenum attr, GLfloat *dest )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ const struct tnl_clipspace_attr *a = vtx->attr;
+ const GLuint attr_count = vtx->attr_count;
+ GLuint j;
+
+ for (j = 0; j < attr_count; j++) {
+ if (a[j].attrib == attr) {
+ a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset );
+ return;
+ }
+ }
+
+ /* Else return the value from ctx->Current -- dangerous???
+ */
+ _mesa_memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
+}
+
+
+/* Complementary operation to the above.
+ */
+void _tnl_set_attr( GLcontext *ctx, void *vout,
+ GLenum attr, const GLfloat *src )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ const struct tnl_clipspace_attr *a = vtx->attr;
+ const GLuint attr_count = vtx->attr_count;
+ GLuint j;
+
+ for (j = 0; j < attr_count; j++) {
+ if (a[j].attrib == attr) {
+ a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src );
+ return;
+ }
+ }
+}
+
+
+void *_tnl_get_vertex( GLcontext *ctx, GLuint nr )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+
+ return vtx->vertex_buf + nr * vtx->vertex_size;
+}
+
+void _tnl_invalidate_vertex_state( GLcontext *ctx, GLuint new_state )
+{
+ if (new_state & (_DD_NEW_TRI_LIGHT_TWOSIDE|_DD_NEW_TRI_UNFILLED) ) {
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ vtx->new_inputs = ~0;
+ vtx->interp = choose_interp_func;
+ vtx->copy_pv = choose_copy_pv_func;
+ }
+}
+
+
+GLuint _tnl_install_attrs( GLcontext *ctx, const struct tnl_attr_map *map,
+ GLuint nr, const GLfloat *vp,
+ GLuint unpacked_size )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ GLuint offset = 0;
+ GLuint i, j;
+
+ assert(nr < _TNL_ATTRIB_MAX);
+ assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS);
+
+ vtx->emit = 0;
+ vtx->interp = choose_interp_func;
+ vtx->copy_pv = choose_copy_pv_func;
+ vtx->new_inputs = ~0;
+
+ for (j = 0, i = 0; i < nr; i++) {
+ const GLuint format = map[i].format;
+ if (format == EMIT_PAD) {
+ /*
+ fprintf(stderr, "%d: pad %d, offset %d\n", i,
+ map[i].offset, offset);
+ */
+ offset += map[i].offset;
+
+ }
+ else {
+ vtx->attr[j].attrib = map[i].attrib;
+ vtx->attr[j].format = format;
+ vtx->attr[j].vp = vp;
+ vtx->attr[j].insert = format_info[format].insert;
+ vtx->attr[j].extract = format_info[format].extract;
+ vtx->attr[j].vertattrsize = format_info[format].attrsize;
+
+ if (unpacked_size)
+ vtx->attr[j].vertoffset = map[i].offset;
+ else
+ vtx->attr[j].vertoffset = offset;
+
+ /*
+ fprintf(stderr, "%d: %s, vp %p, offset %d\n", i,
+ format_info[format].name, (void *)vp,
+ vtx->attr[j].vertoffset);
+ */
+ offset += format_info[format].attrsize;
+ j++;
+ }
+ }
+
+ vtx->attr_count = j;
+
+ if (unpacked_size)
+ vtx->vertex_size = unpacked_size;
+ else
+ vtx->vertex_size = offset;
+
+ assert(vtx->vertex_size <= vtx->max_vertex_size);
+
+ return vtx->vertex_size;
+}
+
+
+
+void _tnl_invalidate_vertices( GLcontext *ctx, GLuint newinputs )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ vtx->new_inputs |= newinputs;
+}
+
+
+void _tnl_build_vertices( GLcontext *ctx,
+ GLuint start,
+ GLuint end,
+ GLuint newinputs )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ const GLuint stride = vtx->vertex_size;
+ GLubyte *vDest = ((GLubyte *)vtx->vertex_buf + (start*stride));
+
+ newinputs |= vtx->new_inputs;
+ vtx->new_inputs = 0;
+
+ if (newinputs)
+ do_emit( ctx, start, end, vDest );
+}
+
+
+void *_tnl_emit_vertices_to_buffer( GLcontext *ctx,
+ GLuint start,
+ GLuint end,
+ void *dest )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ do_emit( ctx, start, end, dest );
+ return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start));
+}
+
+
+void _tnl_init_vertices( GLcontext *ctx,
+ GLuint vb_size,
+ GLuint max_vertex_size )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+
+ _tnl_install_attrs( ctx, 0, 0, 0, 0 );
+
+ vtx->need_extras = GL_TRUE;
+ if (max_vertex_size > vtx->max_vertex_size) {
+ _tnl_free_vertices( ctx );
+ vtx->max_vertex_size = max_vertex_size;
+ vtx->vertex_buf = (GLubyte *)ALIGN_CALLOC(vb_size * max_vertex_size, 32 );
+ }
+
+ _tnl_init_c_codegen( &vtx->codegen );
+}
+
+
+void _tnl_free_vertices( GLcontext *ctx )
+{
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ if (vtx->vertex_buf) {
+ ALIGN_FREE(vtx->vertex_buf);
+ vtx->vertex_buf = 0;
+ if (vtx->codegen.buf) {
+ _mesa_free(vtx->codegen.buf);
+ vtx->codegen.buf = NULL;
+ }
+ }
+}
diff --git a/src/mesa/tnl/t_vertex.h b/src/mesa/tnl/t_vertex.h
new file mode 100644
index 0000000..caa2220
--- /dev/null
+++ b/src/mesa/tnl/t_vertex.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2003 Tungsten Graphics, inc.
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 (including the next
+ * paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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@tungstengraphics.com>
+ */
+
+#ifndef _TNL_VERTEX_H
+#define _TNL_VERTEX_H
+
+#include "mtypes.h"
+#include "t_context.h"
+
+/* New mechanism to specify hardware vertices so that tnl can build
+ * and manipulate them directly.
+ */
+
+
+/* It will probably be necessary to allow drivers to specify new
+ * emit-styles to cover all the wierd and wacky things out there.
+ */
+enum tnl_attr_format {
+ EMIT_1F,
+ EMIT_2F,
+ EMIT_3F,
+ EMIT_4F,
+ EMIT_2F_VIEWPORT, /* do viewport transform and emit */
+ EMIT_3F_VIEWPORT, /* do viewport transform and emit */
+ EMIT_4F_VIEWPORT, /* do viewport transform and emit */
+ EMIT_3F_XYW, /* for projective texture */
+ EMIT_1UB_1F, /* for fog coordinate */
+ EMIT_3UB_3F_RGB, /* for specular color */
+ EMIT_3UB_3F_BGR, /* for specular color */
+ EMIT_4UB_4F_RGBA, /* for color */
+ EMIT_4UB_4F_BGRA, /* for color */
+ EMIT_4UB_4F_ARGB, /* for color */
+ EMIT_4UB_4F_ABGR, /* for color */
+ EMIT_4CHAN_4F_RGBA, /* for swrast color */
+ EMIT_PAD, /* leave a hole of 'offset' bytes */
+ EMIT_MAX
+};
+
+struct tnl_attr_map {
+ GLuint attrib; /* _TNL_ATTRIB_ enum */
+ enum tnl_attr_format format;
+ GLuint offset;
+};
+
+
+
+/* Interpolate between two vertices to produce a third:
+ */
+extern void _tnl_interp( GLcontext *ctx,
+ GLfloat t,
+ GLuint edst, GLuint eout, GLuint ein,
+ GLboolean force_boundary );
+
+/* Copy colors from one vertex to another:
+ */
+extern void _tnl_copy_pv( GLcontext *ctx, GLuint edst, GLuint esrc );
+
+
+/* Extract a named attribute from a hardware vertex. Will have to
+ * reverse any viewport transformation, swizzling or other conversions
+ * which may have been applied:
+ */
+extern void _tnl_get_attr( GLcontext *ctx, const void *vertex, GLenum attrib,
+ GLfloat *dest );
+
+/* Complementary to the above.
+ */
+extern void _tnl_set_attr( GLcontext *ctx, void *vout, GLenum attrib,
+ const GLfloat *src );
+
+
+extern void *_tnl_get_vertex( GLcontext *ctx, GLuint nr );
+
+
+/*
+ */
+extern GLuint _tnl_install_attrs( GLcontext *ctx,
+ const struct tnl_attr_map *map,
+ GLuint nr, const GLfloat *vp,
+ GLuint unpacked_size );
+
+
+
+
+
+extern void _tnl_free_vertices( GLcontext *ctx );
+
+extern void _tnl_init_vertices( GLcontext *ctx,
+ GLuint vb_size,
+ GLuint max_vertex_size );
+
+extern void *_tnl_emit_vertices_to_buffer( GLcontext *ctx,
+ GLuint start,
+ GLuint end,
+ void *dest );
+
+extern void _tnl_build_vertices( GLcontext *ctx,
+ GLuint start,
+ GLuint end,
+ GLuint newinputs );
+
+extern void _tnl_invalidate_vertices( GLcontext *ctx, GLuint newinputs );
+
+extern void _tnl_invalidate_vertex_state( GLcontext *ctx, GLuint new_state );
+
+extern tnl_emit_func _tnl_codegen_emit( GLcontext *ctx );
+
+#define REG_IN (0<<16)
+#define REG_OUT (1<<16)
+#define REG_VP (2<<16)
+#define REG_TMP (3<<16)
+#define REG_MASK (3<<16)
+
+#define REG_OFFSET_MASK 0xffff
+
+#define in( offset ) (REG_IN | (offset))
+#define out( offset ) (REG_OUT | (offset))
+#define vp( offset ) (REG_VP | (offset))
+#define tmp( offset ) (REG_TMP | (offset))
+
+
+extern void _tnl_init_c_codegen( struct tnl_clipspace_codegen *p );
+
+#define GET_VERTEX_STATE(ctx) &(TNL_CONTEXT(ctx)->clipspace)
+
+#endif
diff --git a/src/mesa/tnl/t_vertex_c.c b/src/mesa/tnl/t_vertex_c.c
new file mode 100644
index 0000000..5109026
--- /dev/null
+++ b/src/mesa/tnl/t_vertex_c.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2003 Tungsten Graphics, inc.
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 (including the next
+ * paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+
+#include "t_context.h"
+#include "t_vertex.h"
+
+#include "simple_list.h"
+
+#ifdef WIN32
+#define vsnprintf _vsnprintf
+#endif
+
+/* A version of code generation for t_clipspace_codegen.c which prints
+ * out 'c' code to implement the generated function. A useful
+ * debugging tool, and in concert with something like tcc or a
+ * library-ized gcc, could do the whole job.
+ */
+
+
+static GLboolean emit( struct tnl_clipspace_codegen *p,
+ const char *fmt,
+ ... )
+{
+ if (p->buf_used < p->buf_size) {
+ va_list ap;
+ va_start( ap, fmt );
+ p->buf_used += vsnprintf( p->buf + p->buf_used,
+ p->buf_size - p->buf_used,
+ fmt, ap );
+ va_end( ap );
+ }
+
+ return p->buf_used < p->buf_size;
+}
+
+
+static GLboolean print_header( struct tnl_clipspace_codegen *p,
+ struct tnl_clipspace *vtx )
+{
+ p->buf_used = 0;
+ p->out_offset = 0;
+
+ return
+ emit(p,
+ "struct tnl_clipspace_attr\n"
+ "{\n"
+ " unsigned int attrib; \n"
+ " unsigned int format;\n"
+ " unsigned int vertoffset; \n"
+ " unsigned int vertattrsize; \n"
+ " char *inputptr;\n"
+ " unsigned int inputstride;\n"
+ " void *insert;\n"
+ " void *emit;\n"
+ " void * extract;\n"
+ " const float *vp; \n"
+ "};\n"
+ "\n"
+ ) &&
+ emit(p,
+ "void emit_vertices( int start, int end, char *dest, \n"
+ " struct tnl_clipspace_attr *a) \n"
+ "{\n"
+ " int i;"
+ " for (i = start ; i < end ; i++, dest += %d) {\n",
+ vtx->vertex_size);
+
+}
+
+static GLboolean print_footer( struct tnl_clipspace_codegen *p )
+{
+ return
+ emit(p,
+ " }\n"
+ "}\n"
+ );
+}
+
+static GLboolean emit_reg( struct tnl_clipspace_codegen *p, GLint reg )
+{
+ int idx = reg & REG_OFFSET_MASK;
+
+ switch (reg & REG_MASK) {
+ case REG_IN: return emit(p, "in[%d]", idx);
+ case REG_VP: return emit(p, "vp[%d]", idx);
+ case REG_TMP: return emit(p, "temp[%d]", idx); /* not used? */
+ case REG_OUT: return emit(p, "out[%d]", idx);
+ }
+
+ return GL_FALSE;
+}
+
+static GLboolean print_mov( struct tnl_clipspace_codegen *p, GLint dest, GLint src )
+{
+ return
+ emit(p, " ") &&
+ emit_reg(p, dest) &&
+ emit(p, " = ") &&
+ emit_reg(p, src) &&
+ emit(p, ";\n");
+}
+
+
+static GLboolean print_const( struct tnl_clipspace_codegen *p,
+ GLint dest, GLfloat c )
+{
+ return
+ emit(p, " ") &&
+ emit_reg(p, dest) &&
+ emit(p, " = %g;\n", c);
+}
+
+static GLboolean print_const_chan( struct tnl_clipspace_codegen *p,
+ GLint dest, GLchan c )
+{
+ return
+ emit(p, " ") &&
+ emit_reg(p, dest) &&
+ emit(p, " = ") &&
+#if CHAN_TYPE == GL_FLOAT
+ emit(p, "%f", c) &&
+#else
+ emit(p, "%d", c) &&
+#endif
+ emit(p, ";\n");
+}
+
+static GLboolean print_const_ubyte( struct tnl_clipspace_codegen *p,
+ GLint dest, GLubyte c )
+{
+ return
+ emit(p, " ") &&
+ emit_reg(p, dest) &&
+ emit(p, " = %x;\n", c);
+}
+
+static GLboolean print_mad( struct tnl_clipspace_codegen *p,
+ GLint dest, GLint src0, GLint src1, GLint src2 )
+{
+ return
+ emit(p, " ") &&
+ emit_reg(p, dest) &&
+ emit(p, " = ") &&
+ emit_reg(p, src0) &&
+ emit(p, " * ") &&
+ emit_reg(p, src1) &&
+ emit(p, " + ") &&
+ emit_reg(p, src2) &&
+ emit(p, ";\n");
+}
+
+static GLboolean print_float_to_ubyte( struct tnl_clipspace_codegen *p,
+ GLint dest, GLint src )
+{
+ return
+ emit(p, " ") &&
+ emit(p, "UNCLAMPED_FLOAT_TO_UBYTE(") &&
+ emit_reg(p, dest) &&
+ emit(p, ", ") &&
+ emit_reg(p, src) &&
+ emit(p, ");\n");
+}
+
+static GLboolean print_float_to_chan( struct tnl_clipspace_codegen *p,
+ GLint dest, GLint src )
+{
+ return
+ emit(p, " ") &&
+ emit(p, "UNCLAMPED_FLOAT_TO_CHAN(") &&
+ emit_reg(p, dest) &&
+ emit(p, ", ") &&
+ emit_reg(p, src) &&
+ emit(p, ");\n");
+}
+
+
+static GLboolean print_attr_header( struct tnl_clipspace_codegen *p,
+ struct tnl_clipspace_attr *a,
+ GLint j,
+ GLenum out_type,
+ GLboolean need_vp)
+{
+ char *out_type_str = "void";
+
+ switch(out_type) {
+ case GL_FLOAT: out_type_str = "float"; break;
+ case GL_UNSIGNED_BYTE: out_type_str = "unsigned char"; break;
+ case GL_UNSIGNED_SHORT: out_type_str = "unsigned short"; break;
+ }
+
+ return
+ emit(p, " {\n") &&
+ (need_vp ? emit(p, " const float *vp = a[%d].vp;\n", j) : 1) &&
+ emit(p, " %s *out = (%s *)(dest + %d);\n",
+ out_type_str, out_type_str, a[j].vertoffset) &&
+ emit(p, " const float *in = (const float *)a[%d].inputptr;\n",
+ j) &&
+ emit(p, " a[%d].inputptr += a[%d].inputstride;\n", j, j);
+}
+
+static GLboolean print_attr_footer( struct tnl_clipspace_codegen *p )
+{
+ return emit(p, " }\n");
+}
+
+static tnl_emit_func print_store_func( struct tnl_clipspace_codegen *p )
+{
+ fprintf(stderr, "print_store_func: emitted:\n%s\n", p->buf);
+ return 0;
+}
+
+void _tnl_init_c_codegen( struct tnl_clipspace_codegen *p )
+{
+ p->emit_header = print_header;
+ p->emit_footer = print_footer;
+ p->emit_attr_header = print_attr_header;
+ p->emit_attr_footer = print_attr_footer;
+ p->emit_mov = print_mov;
+ p->emit_const = print_const;
+ p->emit_mad = print_mad;
+ p->emit_float_to_chan = print_float_to_chan;
+ p->emit_const_chan = print_const_chan;
+ p->emit_float_to_ubyte = print_float_to_ubyte;
+ p->emit_const_ubyte = print_const_ubyte;
+ p->emit_store_func = print_store_func;
+
+ make_empty_list(&p->codegen_list);
+
+ p->buf_size = 2048;
+ p->buf = MALLOC(p->buf_size);
+}
diff --git a/src/mesa/tnl/t_vertex_codegen.c b/src/mesa/tnl/t_vertex_codegen.c
new file mode 100644
index 0000000..4ff9643
--- /dev/null
+++ b/src/mesa/tnl/t_vertex_codegen.c
@@ -0,0 +1,510 @@
+/*
+ * Copyright 2003 Tungsten Graphics, inc.
+ * 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
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, 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 (including the next
+ * paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "colormac.h"
+
+#include "t_context.h"
+#include "t_vertex.h"
+
+#include "simple_list.h"
+
+/* Another codegen scheme, hopefully portable to a few different
+ * architectures without too much work.
+ */
+
+
+
+
+static GLboolean emit_4f_viewport_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13)) &&
+ p->emit_mad(p, out(2), vp(10), in(2), vp(14)) &&
+ p->emit_mov(p, out(3), in(3));
+}
+
+static GLboolean emit_4f_viewport_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13)) &&
+ p->emit_mad(p, out(2), vp(10), in(2), vp(14)) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_4f_viewport_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13)) &&
+ p->emit_mov(p, out(2), vp(14)) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_4f_viewport_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mov(p, out(1), vp(13)) &&
+ p->emit_mov(p, out(2), vp(14)) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_3f_viewport_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13)) &&
+ p->emit_mad(p, out(2), vp(10), in(2), vp(14));
+}
+
+static GLboolean emit_3f_viewport_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13)) &&
+ p->emit_mov(p, out(2), vp(14));
+}
+
+static GLboolean emit_3f_viewport_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mov(p, out(1), vp(13)) &&
+ p->emit_mov(p, out(2), vp(14));
+}
+
+static GLboolean emit_2f_viewport_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12)) &&
+ p->emit_mad(p, out(1), vp(5), in(1), vp(13));
+}
+
+static GLboolean emit_2f_viewport_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mad(p, out(0), vp(0), in(0), vp(12));
+}
+
+
+static GLboolean emit_4f_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_mov(p, out(2), in(2)) &&
+ p->emit_mov(p, out(3), in(3));
+}
+
+static GLboolean emit_4f_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_mov(p, out(2), in(2)) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_4f_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_const(p, out(2), 0.0) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_4f_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_const(p, out(1), 0.0) &&
+ p->emit_const(p, out(2), 0.0) &&
+ p->emit_const(p, out(3), 1.0);
+}
+
+static GLboolean emit_3f_xyw_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_mov(p, out(2), in(3));
+}
+
+static GLboolean emit_3f_xyw_err( struct tnl_clipspace_codegen *p )
+{
+ (void) p;
+ assert(0);
+ return GL_FALSE;
+}
+
+static GLboolean emit_3f_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_mov(p, out(2), in(2));
+}
+
+static GLboolean emit_3f_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1)) &&
+ p->emit_const(p, out(2), 0.0);
+}
+
+static GLboolean emit_3f_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_const(p, out(1), 0.0) &&
+ p->emit_const(p, out(2), 0.0);
+}
+
+
+static GLboolean emit_2f_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_mov(p, out(1), in(1));
+}
+
+static GLboolean emit_2f_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0)) &&
+ p->emit_const(p, out(1), 0.0);
+}
+
+static GLboolean emit_1f_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_mov(p, out(0), in(0));
+}
+
+static GLboolean emit_4chan_4f_rgba_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_chan(p, out(0), in(0)) &&
+ p->emit_float_to_chan(p, out(1), in(1)) &&
+ p->emit_float_to_chan(p, out(2), in(2)) &&
+ p->emit_float_to_chan(p, out(3), in(3));
+}
+
+static GLboolean emit_4chan_4f_rgba_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_chan(p, out(0), in(0)) &&
+ p->emit_float_to_chan(p, out(1), in(1)) &&
+ p->emit_float_to_chan(p, out(2), in(2)) &&
+ p->emit_const_chan(p, out(3), CHAN_MAX);
+}
+
+static GLboolean emit_4chan_4f_rgba_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_chan(p, out(0), in(0)) &&
+ p->emit_float_to_chan(p, out(1), in(1)) &&
+ p->emit_const_chan(p, out(2), 0) &&
+ p->emit_const_chan(p, out(3), CHAN_MAX);
+}
+
+static GLboolean emit_4chan_4f_rgba_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_chan(p, out(0), in(0)) &&
+ p->emit_const_chan(p, out(1), 0) &&
+ p->emit_const_chan(p, out(2), 0) &&
+ p->emit_const_chan(p, out(3), CHAN_MAX);
+}
+
+static GLboolean emit_4ub_4f_rgba_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(2), in(2)) &&
+ p->emit_float_to_ubyte(p, out(3), in(3));
+}
+
+static GLboolean emit_4ub_4f_rgba_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(2), in(2)) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_4ub_4f_rgba_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_const_ubyte(p, out(2), 0) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_4ub_4f_rgba_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_const_ubyte(p, out(1), 0) &&
+ p->emit_const_ubyte(p, out(2), 0) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_4ub_4f_bgra_4( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(0), in(2)) &&
+ p->emit_float_to_ubyte(p, out(3), in(3));
+}
+
+static GLboolean emit_4ub_4f_bgra_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(0), in(2)) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_4ub_4f_bgra_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_const_ubyte(p, out(0), 0) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_4ub_4f_bgra_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_const_ubyte(p, out(1), 0) &&
+ p->emit_const_ubyte(p, out(0), 0) &&
+ p->emit_const_ubyte(p, out(3), 0xff);
+}
+
+static GLboolean emit_3ub_3f_rgb_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(2), in(2));
+}
+
+static GLboolean emit_3ub_3f_rgb_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_const_ubyte(p, out(2), 0);
+}
+
+static GLboolean emit_3ub_3f_rgb_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0)) &&
+ p->emit_const_ubyte(p, out(1), 0) &&
+ p->emit_const_ubyte(p, out(2), 0);
+}
+
+static GLboolean emit_3ub_3f_bgr_3( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_float_to_ubyte(p, out(0), in(2));
+}
+
+static GLboolean emit_3ub_3f_bgr_2( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_float_to_ubyte(p, out(1), in(1)) &&
+ p->emit_const_ubyte(p, out(0), 0);
+}
+
+static GLboolean emit_3ub_3f_bgr_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(2), in(0)) &&
+ p->emit_const_ubyte(p, out(1), 0) &&
+ p->emit_const_ubyte(p, out(0), 0);
+}
+
+
+static GLboolean emit_1ub_1f_1( struct tnl_clipspace_codegen *p )
+{
+ return
+ p->emit_float_to_ubyte(p, out(0), in(0));
+}
+
+
+
+
+static struct {
+ const char *name;
+ GLenum out_type;
+ GLboolean need_vp;
+ GLboolean (*emit[4])( struct tnl_clipspace_codegen * );
+} emit_info[EMIT_MAX] = {
+
+ { "1f", GL_FLOAT, GL_FALSE,
+ { emit_1f_1, emit_1f_1, emit_1f_1, emit_1f_1 } },
+
+ { "2f", GL_FLOAT, GL_FALSE,
+ { emit_2f_1, emit_2f_2, emit_2f_2, emit_2f_2 } },
+
+ { "3f", GL_FLOAT, GL_FALSE,
+ { emit_3f_1, emit_3f_2, emit_3f_3, emit_3f_3 } },
+
+ { "4f", GL_FLOAT, GL_FALSE,
+ { emit_4f_1, emit_4f_2, emit_4f_3, emit_4f_4 } },
+
+ { "2f_viewport", GL_FLOAT, GL_TRUE,
+ { emit_2f_viewport_1, emit_2f_viewport_2, emit_2f_viewport_2,
+ emit_2f_viewport_2 } },
+
+ { "3f_viewport", GL_FLOAT, GL_TRUE,
+ { emit_3f_viewport_1, emit_3f_viewport_2, emit_3f_viewport_3,
+ emit_3f_viewport_3 } },
+
+ { "4f_viewport", GL_FLOAT, GL_TRUE,
+ { emit_4f_viewport_1, emit_4f_viewport_2, emit_4f_viewport_3,
+ emit_4f_viewport_4 } },
+
+ { "3f_xyw", GL_FLOAT, GL_FALSE,
+ { emit_3f_xyw_err, emit_3f_xyw_err, emit_3f_xyw_err,
+ emit_3f_xyw_4 } },
+
+ { "1ub_1f", GL_UNSIGNED_BYTE, GL_FALSE,
+ { emit_1ub_1f_1, emit_1ub_1f_1, emit_1ub_1f_1, emit_1ub_1f_1 } },
+
+ { "3ub_3f_rgb", GL_UNSIGNED_BYTE, GL_FALSE,
+ { emit_3ub_3f_rgb_1, emit_3ub_3f_rgb_2, emit_3ub_3f_rgb_3,
+ emit_3ub_3f_rgb_3 } },
+
+ { "3ub_3f_bgr", GL_UNSIGNED_BYTE, GL_FALSE,
+ { emit_3ub_3f_bgr_1, emit_3ub_3f_bgr_2, emit_3ub_3f_bgr_3,
+ emit_3ub_3f_bgr_3 } },
+
+ { "4ub_4f_rgba", GL_UNSIGNED_BYTE, GL_FALSE,
+ { emit_4ub_4f_rgba_1, emit_4ub_4f_rgba_2, emit_4ub_4f_rgba_3,
+ emit_4ub_4f_rgba_4 } },
+
+ { "4ub_4f_bgra", GL_UNSIGNED_BYTE, GL_FALSE,
+ { emit_4ub_4f_bgra_1, emit_4ub_4f_bgra_2, emit_4ub_4f_bgra_3,
+ emit_4ub_4f_bgra_4 } },
+
+ { "4chan_4f_rgba", CHAN_TYPE, GL_FALSE,
+ { emit_4chan_4f_rgba_1, emit_4chan_4f_rgba_2, emit_4chan_4f_rgba_3,
+ emit_4chan_4f_rgba_4 } },
+
+ { "pad", 0, 0,
+ { 0, 0, 0, 0 } }
+
+};
+
+
+/***********************************************************************
+ * list(attrib, size) --> function
+ *
+ * Because of the dependence of size, this all has to take place after
+ * the pipeline has been run.
+ */
+
+tnl_emit_func _tnl_codegen_emit( GLcontext *ctx )
+{
+ struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+ struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
+ struct tnl_clipspace_attr *a = vtx->attr;
+ struct tnl_clipspace_codegen *p = &vtx->codegen;
+ const GLuint count = vtx->attr_count;
+ GLuint j;
+
+ /* Need a faster lookup, or is this linear scan of an MRU list good
+ * enough? MRU chosen based on the guess that consecutive VB's are
+ * likely to be of the same format. A hash of attributes and sizes
+ * might be a better technique.
+ *
+ * With the vtx code now in place, it should be possible to track
+ * changes to the sizes of input arrays (and state, of course) and
+ * only invalidate this function when those sizes have changed.
+ */
+#if 0
+ foreach (l, p->codegen_list) {
+ if (l->attr_count != count)
+ continue;
+
+ /* Assumptions:
+ * a[j].vp will not change for a given attrib
+ * a[j].vertex_offset will not change nothing else has changed.
+ */
+ for (j = 0; j < count; j++)
+ if (a[j].attrib != l->a[j].attrib ||
+ a[j].sz != l->a[j].sz)
+ break;
+
+ if (j == count) {
+ move_to_head(l, p->codegen_list);
+ return l->func;
+ }
+ }
+#endif
+
+ p->emit_header( p, vtx );
+
+ for (j = 0; j < count; j++) {
+ GLuint sz = VB->AttribPtr[a[j].attrib]->size - 1;
+ p->emit_attr_header( p, a, j,
+ emit_info[a[j].format].out_type,
+ emit_info[a[j].format].need_vp );
+
+ if (!emit_info[a[j].format].emit[sz]( p )) {
+ fprintf(stderr, "codegen failed\n");
+ return 0;
+ }
+
+ p->emit_attr_footer( p );
+ }
+
+ p->emit_footer( p );
+
+ return p->emit_store_func( p );
+}
+
diff --git a/src/mesa/tnl/t_vtx_api.c b/src/mesa/tnl/t_vtx_api.c
new file mode 100644
index 0000000..56b1e9f
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_api.c
@@ -0,0 +1,975 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "vtxfmt.h"
+#include "dlist.h"
+#include "state.h"
+#include "light.h"
+#include "api_arrayelt.h"
+#include "api_noop.h"
+#include "t_vtx_api.h"
+#include "simple_list.h"
+
+static void reset_attrfv( TNLcontext *tnl );
+
+static tnl_attrfv_func choose[_TNL_MAX_ATTR_CODEGEN+1][4]; /* +1 for ERROR_ATTRIB */
+static tnl_attrfv_func generic_attr_func[_TNL_MAX_ATTR_CODEGEN][4];
+
+
+/* Close off the last primitive, execute the buffer, restart the
+ * primitive.
+ */
+static void _tnl_wrap_buffers( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+
+ if (tnl->vtx.prim_count == 0) {
+ tnl->vtx.copied.nr = 0;
+ tnl->vtx.counter = tnl->vtx.initial_counter;
+ tnl->vtx.vbptr = tnl->vtx.buffer;
+ }
+ else {
+ GLuint last_prim = tnl->vtx.prim[tnl->vtx.prim_count-1].mode;
+ GLuint last_count = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ GLint i = tnl->vtx.prim_count - 1;
+ assert(i >= 0);
+ tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter -
+ tnl->vtx.counter) -
+ tnl->vtx.prim[i].start);
+ }
+
+ /* Execute the buffer and save copied vertices.
+ */
+ if (tnl->vtx.counter != tnl->vtx.initial_counter)
+ _tnl_flush_vtx( ctx );
+ else {
+ tnl->vtx.prim_count = 0;
+ tnl->vtx.copied.nr = 0;
+ }
+
+ /* Emit a glBegin to start the new list.
+ */
+ assert(tnl->vtx.prim_count == 0);
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ tnl->vtx.prim[0].mode = ctx->Driver.CurrentExecPrimitive;
+ tnl->vtx.prim[0].start = 0;
+ tnl->vtx.prim[0].count = 0;
+ tnl->vtx.prim_count++;
+
+ if (tnl->vtx.copied.nr == last_count)
+ tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
+ }
+ }
+}
+
+
+/* Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
+ *
+ * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
+ */
+void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat *data = tnl->vtx.copied.buffer;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to tnl->copied.
+ */
+ _tnl_wrap_buffers( ctx );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(tnl->vtx.counter > tnl->vtx.copied.nr);
+
+ for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
+ _mesa_memcpy( tnl->vtx.vbptr, data,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+ tnl->vtx.vbptr += tnl->vtx.vertex_size;
+ data += tnl->vtx.vertex_size;
+ tnl->vtx.counter--;
+ }
+
+ tnl->vtx.copied.nr = 0;
+}
+
+
+/*
+ * Copy the active vertex's values to the ctx->Current fields.
+ */
+static void _tnl_copy_to_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i < _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.attrsz[i]) {
+ /* Note: the tnl->vtx.current[i] pointers points to
+ * the ctx->Current fields. The first 16 or so, anyway.
+ */
+ ASSIGN_4V( tnl->vtx.current[i], 0, 0, 0, 1 );
+ COPY_SZ_4V(tnl->vtx.current[i],
+ tnl->vtx.attrsz[i],
+ tnl->vtx.attrptr[i]);
+ }
+ }
+
+ /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
+ * will trash adjacent memory!)
+ */
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_INDEX]) {
+ ctx->Current.Index = tnl->vtx.attrptr[_TNL_ATTRIB_INDEX][0];
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
+ ctx->Current.EdgeFlag =
+ (tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
+
+
+ /* Colormaterial -- this kindof sucks.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx,
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
+ }
+
+ if (tnl->vtx.have_materials) {
+ tnl->Driver.NotifyMaterialChange( ctx );
+ }
+
+ ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
+}
+
+
+static void _tnl_copy_from_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
+ switch (tnl->vtx.attrsz[i]) {
+ case 4: tnl->vtx.attrptr[i][3] = tnl->vtx.current[i][3];
+ case 3: tnl->vtx.attrptr[i][2] = tnl->vtx.current[i][2];
+ case 2: tnl->vtx.attrptr[i][1] = tnl->vtx.current[i][1];
+ case 1: tnl->vtx.attrptr[i][0] = tnl->vtx.current[i][0];
+ break;
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
+ tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
+ (GLfloat)ctx->Current.EdgeFlag;
+
+
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
+ GLuint attr,
+ GLuint newsz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldsz;
+ GLuint i;
+ GLfloat *tmp;
+ GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to tnl->vtx.copied.
+ */
+ _tnl_wrap_buffers( ctx );
+
+
+ /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
+ * when the attribute already exists in the vertex and is having
+ * its size increased.
+ */
+ _tnl_copy_to_current( ctx );
+
+
+ /* Heuristic: Attempt to isolate attributes received outside
+ * begin/end so that they don't bloat the vertices.
+ */
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+ tnl->vtx.attrsz[attr] == 0 &&
+ lastcount > 8 &&
+ tnl->vtx.vertex_size) {
+ reset_attrfv( tnl );
+ }
+
+ /* Fix up sizes:
+ */
+ oldsz = tnl->vtx.attrsz[attr];
+ tnl->vtx.attrsz[attr] = newsz;
+
+ tnl->vtx.vertex_size += newsz - oldsz;
+ tnl->vtx.counter = MIN2( VERT_BUFFER_SIZE / tnl->vtx.vertex_size,
+ ctx->Const.MaxArrayLockSize );
+ tnl->vtx.initial_counter = tnl->vtx.counter;
+ tnl->vtx.vbptr = tnl->vtx.buffer;
+
+
+ /* Recalculate all the attrptr[] values
+ */
+ for (i = 0, tmp = tnl->vtx.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
+ if (tnl->vtx.attrsz[i]) {
+ tnl->vtx.attrptr[i] = tmp;
+ tmp += tnl->vtx.attrsz[i];
+ }
+ else
+ tnl->vtx.attrptr[i] = 0; /* will not be dereferenced */
+ }
+
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ _tnl_copy_from_current( ctx );
+
+ /* Replay stored vertices to translate them
+ * to new format here.
+ *
+ * -- No need to replay - just copy piecewise
+ */
+ if (tnl->vtx.copied.nr)
+ {
+ GLfloat *data = tnl->vtx.copied.buffer;
+ GLfloat *dest = tnl->vtx.buffer;
+ GLuint j;
+
+ for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
+ for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
+ if (tnl->vtx.attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ ASSIGN_4V( dest, 0, 0, 0, 1 );
+ COPY_SZ_4V( dest, oldsz, data );
+ data += oldsz;
+ dest += newsz;
+ } else {
+ COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
+ dest += newsz;
+ }
+ }
+ else {
+ GLuint sz = tnl->vtx.attrsz[j];
+ COPY_SZ_4V( dest, sz, data );
+ dest += sz;
+ data += sz;
+ }
+ }
+ }
+ }
+
+ tnl->vtx.vbptr = dest;
+ tnl->vtx.counter -= tnl->vtx.copied.nr;
+ tnl->vtx.copied.nr = 0;
+ }
+
+ /* For codegen - attrptr's may have changed, so need to redo
+ * codegen. Might be a reasonable place to try & detect attributes
+ * in the vertex which aren't being submitted any more.
+ */
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ if (tnl->vtx.attrsz[i]) {
+ GLuint j = tnl->vtx.attrsz[i] - 1;
+
+ if (i < _TNL_MAX_ATTR_CODEGEN)
+ tnl->vtx.tabfv[i][j] = choose[i][j];
+ }
+
+}
+
+
+static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ static const GLfloat id[4] = { 0, 0, 0, 1 };
+ int i;
+
+ if (tnl->vtx.attrsz[attr] < sz) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ _tnl_wrap_upgrade_vertex( ctx, attr, sz );
+ }
+ else if (tnl->vtx.attrsz[attr] > sz) {
+ /* New size is smaller - just need to fill in some
+ * zeros. Don't need to flush or wrap.
+ */
+ for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
+ tnl->vtx.attrptr[attr][i-1] = id[i-1];
+ }
+
+ /* Does setting NeedFlush belong here? Necessitates resetting
+ * vtxfmt on each flush (otherwise flags won't get reset
+ * afterwards).
+ */
+ if (attr == 0)
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ else
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+#ifdef USE_X86_ASM
+
+static struct _tnl_dynfn *lookup( struct _tnl_dynfn *l, GLuint key )
+{
+ struct _tnl_dynfn *f;
+
+ foreach( f, l ) {
+ if (f->key == key)
+ return f;
+ }
+
+ return 0;
+}
+
+
+static tnl_attrfv_func do_codegen( GLcontext *ctx, GLuint attr, GLuint sz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct _tnl_dynfn *dfn = 0;
+
+ if (attr == 0) {
+ GLuint key = tnl->vtx.vertex_size;
+
+ dfn = lookup( &tnl->vtx.cache.Vertex[sz-1], key );
+
+ if (!dfn)
+ dfn = tnl->vtx.gen.Vertex[sz-1]( ctx, key );
+ }
+ else {
+ GLuint key = (GLuint) tnl->vtx.attrptr[attr];
+
+ dfn = lookup( &tnl->vtx.cache.Attribute[sz-1], key );
+
+ if (!dfn)
+ dfn = tnl->vtx.gen.Attribute[sz-1]( ctx, key );
+ }
+
+ if (dfn)
+ return *(tnl_attrfv_func *) &dfn->code;
+ else
+ return 0;
+}
+
+#endif /* USE_X86_ASM */
+
+/* Helper function for 'CHOOSE' macro. Do what's necessary when an
+ * entrypoint is called for the first time.
+ */
+
+static tnl_attrfv_func do_choose( GLuint attr, GLuint sz )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldsz = tnl->vtx.attrsz[attr];
+
+ assert(attr < _TNL_MAX_ATTR_CODEGEN);
+
+ if (oldsz != sz) {
+ /* Reset any active pointers for this attribute
+ */
+ if (oldsz)
+ tnl->vtx.tabfv[attr][oldsz-1] = choose[attr][oldsz-1];
+
+ _tnl_fixup_vertex( ctx, attr, sz );
+
+ }
+
+
+ /* Try to use codegen:
+ */
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen)
+ tnl->vtx.tabfv[attr][sz-1] = do_codegen( ctx, attr, sz );
+ else
+#endif
+ tnl->vtx.tabfv[attr][sz-1] = 0;
+
+ /* Else use generic version:
+ */
+ if (!tnl->vtx.tabfv[attr][sz-1])
+ tnl->vtx.tabfv[attr][sz-1] = generic_attr_func[attr][sz-1];
+
+ return tnl->vtx.tabfv[attr][sz-1];
+}
+
+
+
+#define CHOOSE( ATTR, N ) \
+static void choose_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ tnl_attrfv_func f = do_choose(ATTR, N); \
+ f( v ); \
+}
+
+#define CHOOSERS( ATTRIB ) \
+ CHOOSE( ATTRIB, 1 ) \
+ CHOOSE( ATTRIB, 2 ) \
+ CHOOSE( ATTRIB, 3 ) \
+ CHOOSE( ATTRIB, 4 ) \
+
+
+#define INIT_CHOOSERS(ATTR) \
+ choose[ATTR][0] = choose_##ATTR##_1; \
+ choose[ATTR][1] = choose_##ATTR##_2; \
+ choose[ATTR][2] = choose_##ATTR##_3; \
+ choose[ATTR][3] = choose_##ATTR##_4;
+
+CHOOSERS( 0 )
+CHOOSERS( 1 )
+CHOOSERS( 2 )
+CHOOSERS( 3 )
+CHOOSERS( 4 )
+CHOOSERS( 5 )
+CHOOSERS( 6 )
+CHOOSERS( 7 )
+CHOOSERS( 8 )
+CHOOSERS( 9 )
+CHOOSERS( 10 )
+CHOOSERS( 11 )
+CHOOSERS( 12 )
+CHOOSERS( 13 )
+CHOOSERS( 14 )
+CHOOSERS( 15 )
+
+static void error_attrib( const GLfloat *unused )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ (void) unused;
+ _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
+}
+
+
+
+static void reset_attrfv( TNLcontext *tnl )
+{
+ GLuint i;
+
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ if (tnl->vtx.attrsz[i]) {
+ GLint j = tnl->vtx.attrsz[i] - 1;
+ tnl->vtx.attrsz[i] = 0;
+
+ if (i < _TNL_MAX_ATTR_CODEGEN) {
+ while (j >= 0) {
+ tnl->vtx.tabfv[i][j] = choose[i][j];
+ j--;
+ }
+ }
+ }
+
+ tnl->vtx.vertex_size = 0;
+ tnl->vtx.have_materials = 0;
+}
+
+
+
+/* Materials:
+ *
+ * These are treated as per-vertex attributes, at indices above where
+ * the NV_vertex_program leaves off. There are a lot of good things
+ * about treating materials this way.
+ *
+ * However: I don't want to double the number of generated functions
+ * just to cope with this, so I unroll the 'C' varients of CHOOSE and
+ * ATTRF into this function, and dispense with codegen and
+ * second-level dispatch.
+ *
+ * There is no aliasing of material attributes with other entrypoints.
+ */
+#define OTHER_ATTR( A, N, params ) \
+do { \
+ if (tnl->vtx.attrsz[A] != N) { \
+ _tnl_fixup_vertex( ctx, A, N ); \
+ } \
+ \
+ { \
+ GLfloat *dest = tnl->vtx.attrptr[A]; \
+ if (N>0) dest[0] = (params)[0]; \
+ if (N>1) dest[1] = (params)[1]; \
+ if (N>2) dest[2] = (params)[2]; \
+ if (N>3) dest[3] = (params)[3]; \
+ } \
+} while (0)
+
+
+#define MAT( ATTR, N, face, params ) \
+do { \
+ if (face != GL_BACK) \
+ OTHER_ATTR( ATTR, N, params ); /* front */ \
+ if (face != GL_FRONT) \
+ OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
+} while (0)
+
+
+/* Colormaterial is dealt with later on.
+ */
+static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
+ const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ switch (face) {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
+ return;
+ }
+
+ switch (pname) {
+ case GL_EMISSION:
+ MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+ break;
+ case GL_AMBIENT:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ break;
+ case GL_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ case GL_SPECULAR:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+ break;
+ case GL_SHININESS:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+ break;
+ case GL_COLOR_INDEXES:
+ MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
+ return;
+ }
+
+ tnl->vtx.have_materials = GL_TRUE;
+}
+
+
+static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat f = (GLfloat)b;
+
+ OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
+}
+
+static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat f = (GLfloat)v[0];
+
+ OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
+}
+
+static void GLAPIENTRY _tnl_Indexf( GLfloat f )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, &f );
+}
+
+static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, v );
+}
+
+/* Eval
+ */
+static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* TODO: use a CHOOSE() function for this: */
+ {
+ GLint i;
+ if (tnl->vtx.eval.new_state)
+ _tnl_update_eval( ctx );
+
+ for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.eval.map1[i].map)
+ if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map1[i].sz)
+ _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
+ }
+ }
+
+
+ _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+
+ _tnl_do_EvalCoord1f( ctx, u );
+
+ _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* TODO: use a CHOOSE() function for this: */
+ {
+ GLint i;
+ if (tnl->vtx.eval.new_state)
+ _tnl_update_eval( ctx );
+
+ for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.eval.map2[i].map)
+ if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map2[i].sz)
+ _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
+ }
+
+ if (ctx->Eval.AutoNormal)
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] != 3)
+ _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
+ }
+
+ _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+
+ _tnl_do_EvalCoord2f( ctx, u, v );
+
+ _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+}
+
+static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
+{
+ _tnl_EvalCoord1f( u[0] );
+}
+
+static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
+{
+ _tnl_EvalCoord2f( u[0], u[1] );
+}
+
+static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+ (GLfloat) ctx->Eval.MapGrid1un);
+ GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+ _tnl_EvalCoord1f( u );
+}
+
+
+static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
+ (GLfloat) ctx->Eval.MapGrid2un);
+ GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
+ (GLfloat) ctx->Eval.MapGrid2vn);
+ GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+ GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+ _tnl_EvalCoord2f( u, v );
+}
+
+
+/* Build a list of primitives on the fly. Keep
+ * ctx->Driver.CurrentExecPrimitive uptodate as well.
+ */
+static void GLAPIENTRY _tnl_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ int i;
+
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ if (!(tnl->Driver.NotifyBegin &&
+ tnl->Driver.NotifyBegin( ctx, mode )))
+ ctx->Exec->Begin(mode);
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
+ _tnl_FlushVertices( ctx, ~0 );
+
+ i = tnl->vtx.prim_count++;
+ tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
+ tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
+ tnl->vtx.prim[i].count = 0;
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+
+}
+
+static void GLAPIENTRY _tnl_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
+ int i = tnl->vtx.prim_count - 1;
+
+ tnl->vtx.prim[i].mode |= PRIM_END;
+ tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
+
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+
+ /* Two choices which effect the way vertex attributes are
+ * carried over (or not) between adjacent primitives.
+ */
+#if 0
+ if (tnl->vtx.prim_count == TNL_MAX_PRIM)
+ _tnl_FlushVertices( ctx, ~0 );
+#else
+ if (tnl->vtx.prim_count == TNL_MAX_PRIM)
+ _tnl_flush_vtx( ctx );
+#endif
+
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
+}
+
+
+static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
+
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Begin = _tnl_Begin;
+ vfmt->CallList = _mesa_CallList;
+ vfmt->CallLists = _mesa_CallLists;
+ 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->Indexf = _tnl_Indexf;
+ vfmt->Indexfv = _tnl_Indexfv;
+ vfmt->Materialfv = _tnl_Materialfv;
+
+ vfmt->Rectf = _mesa_noop_Rectf;
+ vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
+ vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
+}
+
+
+
+void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ (void) flags;
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
+ return;
+
+ if (tnl->vtx.counter != tnl->vtx.initial_counter) {
+ _tnl_flush_vtx( ctx );
+ }
+
+ if (tnl->vtx.vertex_size) {
+ _tnl_copy_to_current( ctx );
+ reset_attrfv( tnl );
+ }
+
+ ctx->Driver.NeedFlush = 0;
+}
+
+
+static void _tnl_current_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ /* setup the pointers for the typical 16 vertex attributes */
+ for (i = 0; i < VERT_ATTRIB_MAX; i++)
+ tnl->vtx.current[i] = ctx->Current.Attrib[i];
+
+ /* setup pointers for the 12 material attributes */
+ for (i = 0; i < MAT_ATTRIB_MAX; i++)
+ tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
+ ctx->Light.Material.Attrib[i];
+
+ tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
+}
+
+static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
+{
+ (void) ctx; (void) key;
+ return 0;
+}
+
+void _tnl_vtx_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
+ GLuint i;
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+
+ INIT_CHOOSERS( 0 );
+ INIT_CHOOSERS( 1 );
+ INIT_CHOOSERS( 2 );
+ INIT_CHOOSERS( 3 );
+ INIT_CHOOSERS( 4 );
+ INIT_CHOOSERS( 5 );
+ INIT_CHOOSERS( 6 );
+ INIT_CHOOSERS( 7 );
+ INIT_CHOOSERS( 8 );
+ INIT_CHOOSERS( 9 );
+ INIT_CHOOSERS( 10 );
+ INIT_CHOOSERS( 11 );
+ INIT_CHOOSERS( 12 );
+ INIT_CHOOSERS( 13 );
+ INIT_CHOOSERS( 14 );
+ INIT_CHOOSERS( 15 );
+
+ choose[ERROR_ATTRIB][0] = error_attrib;
+ choose[ERROR_ATTRIB][1] = error_attrib;
+ choose[ERROR_ATTRIB][2] = error_attrib;
+ choose[ERROR_ATTRIB][3] = error_attrib;
+
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen) {
+ _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
+ }
+#endif
+
+ _tnl_generic_attr_table_init( generic_attr_func );
+ }
+
+ for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
+ _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
+
+ for (i = 0; i < 4; i++) {
+ make_empty_list( &tnl->vtx.cache.Vertex[i] );
+ make_empty_list( &tnl->vtx.cache.Attribute[i] );
+ tnl->vtx.gen.Vertex[i] = no_codegen;
+ tnl->vtx.gen.Attribute[i] = no_codegen;
+ }
+
+#ifdef USE_X86_ASM
+ _tnl_InitX86Codegen( &tnl->vtx.gen );
+#endif
+
+ _tnl_current_init( ctx );
+ _tnl_exec_vtxfmt_init( ctx );
+ _tnl_generic_exec_vtxfmt_init( ctx );
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen) {
+ _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
+ }
+#endif
+
+ _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
+
+ memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
+
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ tnl->vtx.attrsz[i] = 0;
+
+ tnl->vtx.vertex_size = 0;
+ tnl->vtx.have_materials = 0;
+}
+
+static void free_funcs( struct _tnl_dynfn *l )
+{
+ struct _tnl_dynfn *f, *tmp;
+ foreach_s (f, tmp, l) {
+ remove_from_list( f );
+ ALIGN_FREE( f->code );
+ FREE( f );
+ }
+}
+
+
+void _tnl_vtx_destroy( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = 0; i < 4; i++) {
+ free_funcs( &tnl->vtx.cache.Vertex[i] );
+ free_funcs( &tnl->vtx.cache.Attribute[i] );
+ }
+}
+
diff --git a/src/mesa/tnl/t_vtx_api.h b/src/mesa/tnl/t_vtx_api.h
new file mode 100644
index 0000000..9818c08
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_api.h
@@ -0,0 +1,90 @@
+/* $XFree86$ */
+/**************************************************************************
+
+Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ *
+ */
+
+#ifndef __T_VTX_API_H__
+#define __T_VTX_API_H__
+
+#include "t_context.h"
+
+#define ERROR_ATTRIB 16
+
+
+
+/* t_vtx_api.c:
+ */
+extern void _tnl_vtx_init( GLcontext *ctx );
+extern void _tnl_vtx_destroy( GLcontext *ctx );
+
+extern void _tnl_FlushVertices( GLcontext *ctx, GLuint flags );
+extern void _tnl_flush_vtx( GLcontext *ctx );
+
+extern void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx );
+
+/* t_vtx_exec.c:
+ */
+
+extern void _tnl_do_EvalCoord2f( GLcontext* ctx, GLfloat u, GLfloat v );
+extern void _tnl_do_EvalCoord1f(GLcontext* ctx, GLfloat u);
+extern void _tnl_update_eval( GLcontext *ctx );
+
+extern GLboolean *_tnl_translate_edgeflag( GLcontext *ctx,
+ const GLfloat *data,
+ GLuint count,
+ GLuint stride );
+
+extern GLboolean *_tnl_import_current_edgeflag( GLcontext *ctx,
+ GLuint count );
+
+
+
+/* t_vtx_generic.c:
+ */
+extern void _tnl_generic_exec_vtxfmt_init( GLcontext *ctx );
+
+extern void _tnl_generic_attr_table_init( tnl_attrfv_func (*tab)[4] );
+
+/* t_vtx_x86.c:
+ */
+extern void _tnl_InitX86Codegen( struct _tnl_dynfn_generators *gen );
+
+extern void _tnl_x86_exec_vtxfmt_init( GLcontext *ctx );
+
+extern void _tnl_x86choosers( tnl_attrfv_func (*choose)[4],
+ tnl_attrfv_func (*do_choose)( GLuint attr,
+ GLuint sz ));
+
+
+
+
+#endif
diff --git a/src/mesa/tnl/t_vtx_eval.c b/src/mesa/tnl/t_vtx_eval.c
new file mode 100644
index 0000000..5a24c70
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_eval.c
@@ -0,0 +1,253 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 6.1
+ *
+ * Copyright (C) 1999-2004 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "api_eval.h"
+#include "context.h"
+#include "macros.h"
+#include "math/m_eval.h"
+#include "t_vtx_api.h"
+
+
+static void clear_active_eval1( TNLcontext *tnl, GLuint attr )
+{
+ tnl->vtx.eval.map1[attr].map = 0;
+}
+
+static void clear_active_eval2( TNLcontext *tnl, GLuint attr )
+{
+ tnl->vtx.eval.map2[attr].map = 0;
+}
+
+static void set_active_eval1( TNLcontext *tnl, GLuint attr, GLuint dim,
+ struct gl_1d_map *map )
+{
+ if (!tnl->vtx.eval.map1[attr].map) {
+ tnl->vtx.eval.map1[attr].map = map;
+ tnl->vtx.eval.map1[attr].sz = dim;
+ }
+}
+
+static void set_active_eval2( TNLcontext *tnl, GLuint attr, GLuint dim,
+ struct gl_2d_map *map )
+{
+ if (!tnl->vtx.eval.map2[attr].map) {
+ tnl->vtx.eval.map2[attr].map = map;
+ tnl->vtx.eval.map2[attr].sz = dim;
+ }
+}
+
+void _tnl_update_eval( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint attr;
+
+ /* Vertex program maps have priority over conventional attribs */
+
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ clear_active_eval1( tnl, attr );
+ clear_active_eval2( tnl, attr );
+ }
+
+ if (ctx->VertexProgram._Enabled) {
+ for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
+ if (ctx->Eval.Map1Attrib[attr])
+ set_active_eval1( tnl, attr, 4, &ctx->EvalMap.Map1Attrib[attr] );
+
+ if (ctx->Eval.Map2Attrib[attr])
+ set_active_eval2( tnl, attr, 4, &ctx->EvalMap.Map2Attrib[attr] );
+ }
+ }
+
+ if (ctx->Eval.Map1Color4)
+ set_active_eval1( tnl, VERT_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map1Color4 );
+
+ if (ctx->Eval.Map2Color4)
+ set_active_eval2( tnl, VERT_ATTRIB_COLOR0, 4, &ctx->EvalMap.Map2Color4 );
+
+ if (ctx->Eval.Map1TextureCoord4)
+ set_active_eval1( tnl, VERT_ATTRIB_TEX0, 4, &ctx->EvalMap.Map1Texture4 );
+ else if (ctx->Eval.Map1TextureCoord3)
+ set_active_eval1( tnl, VERT_ATTRIB_TEX0, 3, &ctx->EvalMap.Map1Texture3 );
+ else if (ctx->Eval.Map1TextureCoord2)
+ set_active_eval1( tnl, VERT_ATTRIB_TEX0, 2, &ctx->EvalMap.Map1Texture2 );
+ else if (ctx->Eval.Map1TextureCoord1)
+ set_active_eval1( tnl, VERT_ATTRIB_TEX0, 1, &ctx->EvalMap.Map1Texture1 );
+
+ if (ctx->Eval.Map2TextureCoord4)
+ set_active_eval2( tnl, VERT_ATTRIB_TEX0, 4, &ctx->EvalMap.Map2Texture4 );
+ else if (ctx->Eval.Map2TextureCoord3)
+ set_active_eval2( tnl, VERT_ATTRIB_TEX0, 3, &ctx->EvalMap.Map2Texture3 );
+ else if (ctx->Eval.Map2TextureCoord2)
+ set_active_eval2( tnl, VERT_ATTRIB_TEX0, 2, &ctx->EvalMap.Map2Texture2 );
+ else if (ctx->Eval.Map2TextureCoord1)
+ set_active_eval2( tnl, VERT_ATTRIB_TEX0, 1, &ctx->EvalMap.Map2Texture1 );
+
+ if (ctx->Eval.Map1Normal)
+ set_active_eval1( tnl, VERT_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map1Normal );
+
+ if (ctx->Eval.Map2Normal)
+ set_active_eval2( tnl, VERT_ATTRIB_NORMAL, 3, &ctx->EvalMap.Map2Normal );
+
+ if (ctx->Eval.Map1Vertex4)
+ set_active_eval1( tnl, VERT_ATTRIB_POS, 4, &ctx->EvalMap.Map1Vertex4 );
+ else if (ctx->Eval.Map1Vertex3)
+ set_active_eval1( tnl, VERT_ATTRIB_POS, 3, &ctx->EvalMap.Map1Vertex3 );
+
+ if (ctx->Eval.Map2Vertex4)
+ set_active_eval2( tnl, VERT_ATTRIB_POS, 4, &ctx->EvalMap.Map2Vertex4 );
+ else if (ctx->Eval.Map2Vertex3)
+ set_active_eval2( tnl, VERT_ATTRIB_POS, 3, &ctx->EvalMap.Map2Vertex3 );
+
+ tnl->vtx.eval.new_state = 0;
+}
+
+
+
+void _tnl_do_EvalCoord1f(GLcontext* ctx, GLfloat u)
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint attr;
+
+ for (attr = 1; attr <= _TNL_ATTRIB_INDEX; attr++) {
+ struct gl_1d_map *map = tnl->vtx.eval.map1[attr].map;
+ if (map) {
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat data[4];
+
+ ASSIGN_4V(data, 0, 0, 0, 1);
+
+ _math_horner_bezier_curve(map->Points, data, uu,
+ tnl->vtx.eval.map1[attr].sz,
+ map->Order);
+
+ COPY_SZ_4V( tnl->vtx.attrptr[attr],
+ tnl->vtx.attrsz[attr],
+ data );
+ }
+ }
+
+ /** Vertex -- EvalCoord1f is a noop if this map not enabled:
+ **/
+ if (tnl->vtx.eval.map1[0].map) {
+ struct gl_1d_map *map = tnl->vtx.eval.map1[0].map;
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vertex[4];
+
+ ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+ _math_horner_bezier_curve(map->Points, vertex, uu,
+ tnl->vtx.eval.map1[0].sz,
+ map->Order);
+
+ if (tnl->vtx.eval.map1[0].sz == 4)
+ GL_CALL(Vertex4fv)( vertex );
+ else
+ GL_CALL(Vertex3fv)( vertex );
+ }
+}
+
+
+
+void _tnl_do_EvalCoord2f( GLcontext* ctx, GLfloat u, GLfloat v )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint attr;
+
+ for (attr = 1; attr <= _TNL_ATTRIB_INDEX; attr++) {
+ struct gl_2d_map *map = tnl->vtx.eval.map2[attr].map;
+ if (map) {
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vv = (v - map->v1) * map->dv;
+ GLfloat data[4];
+
+ ASSIGN_4V(data, 0, 0, 0, 1);
+
+ _math_horner_bezier_surf(map->Points,
+ data,
+ uu, vv,
+ tnl->vtx.eval.map2[attr].sz,
+ map->Uorder, map->Vorder);
+
+ COPY_SZ_4V( tnl->vtx.attrptr[attr],
+ tnl->vtx.attrsz[attr],
+ data );
+ }
+ }
+
+ /** Vertex -- EvalCoord2f is a noop if this map not enabled:
+ **/
+ if (tnl->vtx.eval.map2[0].map) {
+ struct gl_2d_map *map = tnl->vtx.eval.map2[0].map;
+ GLfloat uu = (u - map->u1) * map->du;
+ GLfloat vv = (v - map->v1) * map->dv;
+ GLfloat vertex[4];
+
+ ASSIGN_4V(vertex, 0, 0, 0, 1);
+
+ if (ctx->Eval.AutoNormal) {
+ GLfloat normal[4];
+ GLfloat du[4], dv[4];
+
+ _math_de_casteljau_surf(map->Points, vertex, du, dv, uu, vv,
+ tnl->vtx.eval.map2[0].sz,
+ map->Uorder, map->Vorder);
+
+ if (tnl->vtx.eval.map2[0].sz == 4) {
+ du[0] = du[0]*vertex[3] - du[3]*vertex[0];
+ du[1] = du[1]*vertex[3] - du[3]*vertex[1];
+ du[2] = du[2]*vertex[3] - du[3]*vertex[2];
+
+ dv[0] = dv[0]*vertex[3] - dv[3]*vertex[0];
+ dv[1] = dv[1]*vertex[3] - dv[3]*vertex[1];
+ dv[2] = dv[2]*vertex[3] - dv[3]*vertex[2];
+ }
+
+
+ CROSS3(normal, du, dv);
+ NORMALIZE_3FV(normal);
+ normal[3] = 1.0;
+
+ COPY_SZ_4V( tnl->vtx.attrptr[_TNL_ATTRIB_NORMAL],
+ tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL],
+ normal );
+
+ }
+ else {
+ _math_horner_bezier_surf(map->Points, vertex, uu, vv,
+ tnl->vtx.eval.map2[0].sz,
+ map->Uorder, map->Vorder);
+ }
+
+ if (tnl->vtx.attrsz[0] == 4)
+ GL_CALL(Vertex4fv)( vertex );
+ else
+ GL_CALL(Vertex3fv)( vertex );
+ }
+}
+
+
diff --git a/src/mesa/tnl/t_vtx_exec.c b/src/mesa/tnl/t_vtx_exec.c
new file mode 100644
index 0000000..6925850
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_exec.c
@@ -0,0 +1,289 @@
+/*
+ * Mesa 3-D graphics library
+ * Version: 5.1
+ *
+ * Copyright (C) 1999-2003 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "api_eval.h"
+#include "context.h"
+#include "enums.h"
+#include "state.h"
+#include "macros.h"
+#include "math/m_eval.h"
+#include "t_vtx_api.h"
+#include "t_pipeline.h"
+
+
+static void _tnl_print_vtx( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint count = tnl->vtx.initial_counter - tnl->vtx.counter;
+ GLuint i;
+
+ _mesa_debug(ctx, "_tnl_print_vtx: %u vertices %d primitives, %d vertsize\n",
+ count,
+ tnl->vtx.prim_count,
+ tnl->vtx.vertex_size);
+
+ for (i = 0 ; i < tnl->vtx.prim_count ; i++) {
+ struct tnl_prim *prim = &tnl->vtx.prim[i];
+ _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
+ i,
+ _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
+ prim->start,
+ prim->start + prim->count,
+ (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
+ (prim->mode & PRIM_END) ? "END" : "(wrap)");
+ }
+}
+
+GLboolean *_tnl_translate_edgeflag( GLcontext *ctx, const GLfloat *data,
+ GLuint count, GLuint stride )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLboolean *ef = tnl->vtx.edgeflag_tmp;
+ GLuint i;
+
+ if (!ef)
+ ef = tnl->vtx.edgeflag_tmp = (GLboolean *) MALLOC( tnl->vb.Size );
+
+ for (i = 0 ; i < count ; i++, data += stride)
+ ef[i] = (data[0] == 1.0);
+
+ return ef;
+}
+
+
+GLboolean *_tnl_import_current_edgeflag( GLcontext *ctx,
+ GLuint count )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLboolean *ef = tnl->vtx.edgeflag_tmp;
+ GLboolean tmp = ctx->Current.EdgeFlag;
+ GLuint i;
+
+ if (!ef)
+ ef = tnl->vtx.edgeflag_tmp = (GLboolean *) MALLOC( tnl->vb.Size );
+
+ for (i = 0 ; i < count ; i++)
+ ef[i] = tmp;
+
+ return ef;
+}
+
+static INLINE GLint get_size( const GLfloat *f )
+{
+ if (f[3] != 1.0) return 4;
+ if (f[2] != 0.0) return 3;
+ return 2;
+}
+
+/* Some nasty stuff still hanging on here.
+ *
+ * TODO - remove VB->NormalPtr, etc and just use the AttrPtr's.
+ */
+static void _tnl_vb_bind_vtx( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct vertex_buffer *VB = &tnl->vb;
+ struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
+ GLfloat *data = tnl->vtx.buffer;
+ GLuint count = tnl->vtx.initial_counter - tnl->vtx.counter;
+ GLuint attr, i;
+
+ if (0) fprintf(stderr, "_tnl_vb_bind_vtx(): %d verts %d vertsize\n",
+ count, tnl->vtx.vertex_size);
+
+
+ /* Setup constant data in the VB.
+ */
+ VB->Count = count;
+ VB->Primitive = tnl->vtx.prim;
+ VB->PrimitiveCount = tnl->vtx.prim_count;
+ VB->Elts = NULL;
+ VB->NormalLengthPtr = NULL;
+
+ for (attr = 0; attr <= _TNL_ATTRIB_INDEX ; attr++) {
+ if (tnl->vtx.attrsz[attr]) {
+ tmp->Attribs[attr].count = count;
+ tmp->Attribs[attr].data = (GLfloat (*)[4]) data;
+ tmp->Attribs[attr].start = data;
+ tmp->Attribs[attr].size = tnl->vtx.attrsz[attr];
+ tmp->Attribs[attr].stride = tnl->vtx.vertex_size * sizeof(GLfloat);
+ VB->AttribPtr[attr] = &tmp->Attribs[attr];
+ data += tnl->vtx.attrsz[attr];
+ }
+ else {
+/* VB->AttribPtr[attr] = &tnl->current.Attribs[attr]; */
+
+
+ tmp->Attribs[attr].count = count;
+ tmp->Attribs[attr].data = (GLfloat (*)[4]) tnl->vtx.current[attr];
+ tmp->Attribs[attr].start = tnl->vtx.current[attr];
+ tmp->Attribs[attr].size = get_size( tnl->vtx.current[attr] );
+ tmp->Attribs[attr].stride = 0;
+ VB->AttribPtr[attr] = &tmp->Attribs[attr];
+ }
+ }
+
+
+ /* Copy and translate EdgeFlag to a contiguous array of GLbooleans
+ */
+ if (ctx->Polygon.FrontMode != GL_FILL || ctx->Polygon.BackMode != GL_FILL) {
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ VB->EdgeFlag = _tnl_translate_edgeflag( ctx, data, count,
+ tnl->vtx.vertex_size );
+ data++;
+ }
+ else
+ VB->EdgeFlag = _tnl_import_current_edgeflag( ctx, count );
+ }
+
+ /* Legacy pointers -- remove one day.
+ */
+ VB->ObjPtr = VB->AttribPtr[_TNL_ATTRIB_POS];
+ VB->NormalPtr = VB->AttribPtr[_TNL_ATTRIB_NORMAL];
+ VB->ColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR0];
+ VB->ColorPtr[1] = 0;
+ VB->IndexPtr[0] = VB->AttribPtr[_TNL_ATTRIB_INDEX];
+ VB->IndexPtr[1] = 0;
+ VB->SecondaryColorPtr[0] = VB->AttribPtr[_TNL_ATTRIB_COLOR1];
+ VB->SecondaryColorPtr[1] = 0;
+ VB->FogCoordPtr = VB->AttribPtr[_TNL_ATTRIB_FOG];
+
+ for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+ VB->TexCoordPtr[i] = VB->AttribPtr[_TNL_ATTRIB_TEX0 + i];
+ }
+}
+
+
+/*
+ * NOTE: Need to have calculated primitives by this point -- do it on the fly.
+ * NOTE: Old 'parity' issue is gone.
+ */
+static GLuint _tnl_copy_vertices( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT( ctx );
+ GLuint nr = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
+ GLuint ovf, i;
+ GLuint sz = tnl->vtx.vertex_size;
+ GLfloat *dst = tnl->vtx.copied.buffer;
+ GLfloat *src = (tnl->vtx.buffer +
+ tnl->vtx.prim[tnl->vtx.prim_count-1].start *
+ tnl->vtx.vertex_size);
+
+
+ switch( ctx->Driver.CurrentExecPrimitive )
+ {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_TRIANGLES:
+ ovf = nr%3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_QUADS:
+ ovf = nr&3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ else {
+ _mesa_memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+ return 1;
+ }
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0)
+ return 0;
+ else if (nr == 1) {
+ _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) );
+ return 1;
+ } else {
+ _mesa_memcpy( dst, src+0, sz * sizeof(GLfloat) );
+ _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
+ return 2;
+ }
+ case GL_TRIANGLE_STRIP:
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0: ovf = 0; break;
+ case 1: ovf = 1; break;
+ default: ovf = 2 + (nr&1); break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
+ return i;
+ case GL_POLYGON+1:
+ return 0;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+/**
+ * Execute the buffer and save copied verts.
+ */
+void _tnl_flush_vtx( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (0)
+ _tnl_print_vtx( ctx );
+
+ if (tnl->vtx.prim_count &&
+ tnl->vtx.counter != tnl->vtx.initial_counter) {
+
+ tnl->vtx.copied.nr = _tnl_copy_vertices( ctx );
+
+ if (ctx->NewState)
+ _mesa_update_state( ctx );
+
+ if (tnl->pipeline.build_state_changes)
+ _tnl_validate_pipeline( ctx );
+
+ _tnl_vb_bind_vtx( ctx );
+
+ /* Invalidate all stored data before and after run:
+ */
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+ tnl->Driver.RunPipeline( ctx );
+ tnl->pipeline.run_input_changes |= tnl->pipeline.inputs;
+ }
+
+ tnl->vtx.prim_count = 0;
+ tnl->vtx.counter = tnl->vtx.initial_counter;
+ tnl->vtx.vbptr = tnl->vtx.buffer;
+}
diff --git a/src/mesa/tnl/t_vtx_generic.c b/src/mesa/tnl/t_vtx_generic.c
new file mode 100644
index 0000000..daa7dea
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_generic.c
@@ -0,0 +1,468 @@
+/**************************************************************************
+
+Copyright 2004 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ */
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "vtxfmt.h"
+#include "dlist.h"
+#include "state.h"
+#include "light.h"
+#include "api_arrayelt.h"
+#include "api_noop.h"
+#include "t_vtx_api.h"
+
+
+/* Versions of all the entrypoints for situations where codegen isn't
+ * available.
+ *
+ * Note: Only one size for each attribute may be active at once.
+ * Eg. if Color3f is installed/active, then Color4f may not be, even
+ * if the vertex actually contains 4 color coordinates. This is
+ * because the 3f version won't otherwise set color[3] to 1.0 -- this
+ * is the job of the chooser function when switching between Color4f
+ * and Color3f.
+ */
+#define ATTRFV( ATTR, N ) \
+static void attrib_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if ((ATTR) == 0) { \
+ GLuint i; \
+ \
+ if (N>0) tnl->vtx.vbptr[0] = v[0]; \
+ if (N>1) tnl->vtx.vbptr[1] = v[1]; \
+ if (N>2) tnl->vtx.vbptr[2] = v[2]; \
+ if (N>3) tnl->vtx.vbptr[3] = v[3]; \
+ \
+ for (i = N; i < tnl->vtx.vertex_size; i++) \
+ tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
+ \
+ tnl->vtx.vbptr += tnl->vtx.vertex_size; \
+ \
+ if (--tnl->vtx.counter == 0) \
+ _tnl_wrap_filled_vertex( ctx ); \
+ } \
+ else { \
+ GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
+ if (N>0) dest[0] = v[0]; \
+ if (N>1) dest[1] = v[1]; \
+ if (N>2) dest[2] = v[2]; \
+ if (N>3) dest[3] = v[3]; \
+ } \
+}
+
+#define INIT(TAB, ATTR) \
+ TAB[ATTR][0] = attrib_##ATTR##_1; \
+ TAB[ATTR][1] = attrib_##ATTR##_2; \
+ TAB[ATTR][2] = attrib_##ATTR##_3; \
+ TAB[ATTR][3] = attrib_##ATTR##_4;
+
+
+#define ATTRS( ATTRIB ) \
+ ATTRFV( ATTRIB, 1 ) \
+ ATTRFV( ATTRIB, 2 ) \
+ ATTRFV( ATTRIB, 3 ) \
+ ATTRFV( ATTRIB, 4 )
+
+ATTRS( 0 )
+ATTRS( 1 )
+ATTRS( 2 )
+ATTRS( 3 )
+ATTRS( 4 )
+ATTRS( 5 )
+ATTRS( 6 )
+ATTRS( 7 )
+ATTRS( 8 )
+ATTRS( 9 )
+ATTRS( 10 )
+ATTRS( 11 )
+ATTRS( 12 )
+ATTRS( 13 )
+ATTRS( 14 )
+ATTRS( 15 )
+
+void _tnl_generic_attr_table_init( tnl_attrfv_func (*tab)[4] )
+{
+ INIT( tab, 0 );
+ INIT( tab, 1 );
+ INIT( tab, 2 );
+ INIT( tab, 3 );
+ INIT( tab, 4 );
+ INIT( tab, 5 );
+ INIT( tab, 6 );
+ INIT( tab, 7 );
+ INIT( tab, 8 );
+ INIT( tab, 9 );
+ INIT( tab, 10 );
+ INIT( tab, 11 );
+ INIT( tab, 12 );
+ INIT( tab, 13 );
+ INIT( tab, 14 );
+ INIT( tab, 15 );
+}
+
+/* These can be made efficient with codegen. Further, by adding more
+ * logic to do_choose(), the double-dispatch for legacy entrypoints
+ * like glVertex3f() can be removed.
+ */
+#define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
+do { \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
+} while (0)
+
+#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
+#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
+#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
+#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
+
+#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
+
+#if defined(USE_X86_ASM) && 0 /* will break register calling convention */
+/* Naughty cheat:
+ */
+#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
+#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
+#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
+#else
+/* Safe:
+ */
+#define DISPATCH_ATTR2F( ATTR, S,T ) \
+do { \
+ GLfloat v[2]; \
+ v[0] = S; v[1] = T; \
+ DISPATCH_ATTR2FV( ATTR, v ); \
+} while (0)
+#define DISPATCH_ATTR3F( ATTR, S,T,R ) \
+do { \
+ GLfloat v[3]; \
+ v[0] = S; v[1] = T; v[2] = R; \
+ DISPATCH_ATTR3FV( ATTR, v ); \
+} while (0)
+#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
+do { \
+ GLfloat v[4]; \
+ v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
+ DISPATCH_ATTR4FV( ATTR, v ); \
+} while (0)
+#endif
+
+
+static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
+}
+
+static void GLAPIENTRY _tnl_Vertex2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_Vertex3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
+}
+
+static void GLAPIENTRY _tnl_Vertex4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _tnl_TexCoord1f( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
+}
+
+static void GLAPIENTRY _tnl_TexCoord1fv( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _tnl_TexCoord2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
+}
+
+static void GLAPIENTRY _tnl_TexCoord2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _tnl_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_TexCoord3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _tnl_TexCoord4f( GLfloat x, GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
+}
+
+static void GLAPIENTRY _tnl_TexCoord4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _tnl_Normal3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_Normal3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
+}
+
+static void GLAPIENTRY _tnl_FogCoordfEXT( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
+}
+
+static void GLAPIENTRY _tnl_FogCoordfvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
+}
+
+static void GLAPIENTRY _tnl_Color3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_Color3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _tnl_Color4f( GLfloat x, GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
+}
+
+static void GLAPIENTRY _tnl_Color4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _tnl_SecondaryColor3fEXT( GLfloat x, GLfloat y,
+ GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_SecondaryColor3fvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord1f( GLenum target, GLfloat x )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1F( attr, x );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord1fv( GLenum target,
+ const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1FV( attr, v );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord2f( GLenum target, GLfloat x,
+ GLfloat y )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2F( attr, x, y );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord2fv( GLenum target,
+ const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2FV( attr, v );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord3f( GLenum target, GLfloat x,
+ GLfloat y, GLfloat z)
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3F( attr, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord3fv( GLenum target,
+ const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3FV( attr, v );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord4f( GLenum target, GLfloat x,
+ GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4F( attr, x, y, z, w );
+}
+
+static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target,
+ const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4FV( attr, v );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR1F( index, x );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index,
+ const GLfloat *v )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR1FV( index, v );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x,
+ GLfloat y )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR2F( index, x, y );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index,
+ const GLfloat *v )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR2FV( index, v );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR3F( index, x, y, z );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index,
+ const GLfloat *v )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR3FV( index, v );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x,
+ GLfloat y, GLfloat z,
+ GLfloat w )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR4F( index, x, y, z, w );
+}
+
+static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index,
+ const GLfloat *v )
+{
+ if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
+ DISPATCH_ATTR4FV( index, v );
+}
+
+
+/* Install the generic versions of the 2nd level dispatch
+ * functions. Some of these have a codegen alternative.
+ */
+void _tnl_generic_exec_vtxfmt_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
+
+ vfmt->Color3f = _tnl_Color3f;
+ vfmt->Color3fv = _tnl_Color3fv;
+ vfmt->Color4f = _tnl_Color4f;
+ vfmt->Color4fv = _tnl_Color4fv;
+ vfmt->FogCoordfEXT = _tnl_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = _tnl_FogCoordfvEXT;
+ vfmt->MultiTexCoord1fARB = _tnl_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = _tnl_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = _tnl_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = _tnl_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fv;
+ vfmt->Normal3f = _tnl_Normal3f;
+ vfmt->Normal3fv = _tnl_Normal3fv;
+ vfmt->SecondaryColor3fEXT = _tnl_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = _tnl_SecondaryColor3fvEXT;
+ 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;
+ vfmt->VertexAttrib1fNV = _tnl_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = _tnl_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = _tnl_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = _tnl_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = _tnl_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = _tnl_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = _tnl_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = _tnl_VertexAttrib4fvNV;
+}
diff --git a/src/mesa/tnl/t_vtx_x86.c b/src/mesa/tnl/t_vtx_x86.c
new file mode 100644
index 0000000..59a8698
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_x86.c
@@ -0,0 +1,384 @@
+/**************************************************************************
+
+Copyright 2004 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ * Daniel Borca <dborca@yahoo.com>
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "macros.h"
+#include "vtxfmt.h"
+#include "dlist.h"
+#include "state.h"
+#include "light.h"
+#include "api_arrayelt.h"
+#include "api_noop.h"
+#include "t_vtx_api.h"
+#include "simple_list.h"
+
+
+#if defined(USE_X86_ASM) && !defined(HAVE_NONSTANDARD_GLAPIENTRY)
+
+#define EXTERN( FUNC ) \
+extern const char *FUNC; \
+extern const char *FUNC##_end
+
+EXTERN( _tnl_x86_Attribute1fv );
+EXTERN( _tnl_x86_Attribute2fv );
+EXTERN( _tnl_x86_Attribute3fv );
+EXTERN( _tnl_x86_Attribute4fv );
+EXTERN( _tnl_x86_Vertex1fv );
+EXTERN( _tnl_x86_Vertex2fv );
+EXTERN( _tnl_x86_Vertex3fv );
+EXTERN( _tnl_x86_Vertex4fv );
+
+EXTERN( _tnl_x86_dispatch_attrf1 );
+EXTERN( _tnl_x86_dispatch_attrf2 );
+EXTERN( _tnl_x86_dispatch_attrf3 );
+EXTERN( _tnl_x86_dispatch_attrf4 );
+EXTERN( _tnl_x86_dispatch_attrfv );
+EXTERN( _tnl_x86_dispatch_multitexcoordf1 );
+EXTERN( _tnl_x86_dispatch_multitexcoordf2 );
+EXTERN( _tnl_x86_dispatch_multitexcoordf3 );
+EXTERN( _tnl_x86_dispatch_multitexcoordf4 );
+EXTERN( _tnl_x86_dispatch_multitexcoordfv );
+EXTERN( _tnl_x86_dispatch_vertexattribf1 );
+EXTERN( _tnl_x86_dispatch_vertexattribf2 );
+EXTERN( _tnl_x86_dispatch_vertexattribf3 );
+EXTERN( _tnl_x86_dispatch_vertexattribf4 );
+EXTERN( _tnl_x86_dispatch_vertexattribfv );
+
+EXTERN( _tnl_x86_choose_fv );
+
+
+#define DONT_KNOW_OFFSETS 1
+
+
+#define DFN( FUNC, CACHE, KEY ) \
+ struct _tnl_dynfn *dfn = MALLOC_STRUCT( _tnl_dynfn );\
+ char *start = (char *)&FUNC; \
+ char *end = (char *)&FUNC##_end; \
+ int offset = 0; \
+ insert_at_head( &CACHE, dfn ); \
+ dfn->key = KEY; \
+ dfn->code = ALIGN_MALLOC( end - start, 16 ); \
+ memcpy (dfn->code, start, end - start)
+
+
+
+#define FIXUP( CODE, KNOWN_OFFSET, CHECKVAL, NEWVAL ) \
+do { \
+ GLint subst = 0x10101010 + CHECKVAL; \
+ \
+ if (DONT_KNOW_OFFSETS) { \
+ while (*(int *)(CODE+offset) != subst) offset++; \
+ *(int *)(CODE+offset) = (int)(NEWVAL); \
+ if (0) fprintf(stderr, "%s/%d: offset %d, new value: 0x%x\n", __FILE__, __LINE__, offset, (int)(NEWVAL)); \
+ offset += 4; \
+ } \
+ else { \
+ int *icode = (int *)(CODE+KNOWN_OFFSET); \
+ assert (*icode == subst); \
+ *icode = (int)NEWVAL; \
+ } \
+} while (0)
+
+
+
+#define FIXUPREL( CODE, KNOWN_OFFSET, CHECKVAL, NEWVAL )\
+do { \
+ GLint subst = 0x10101010 + CHECKVAL; \
+ \
+ if (DONT_KNOW_OFFSETS) { \
+ while (*(int *)(CODE+offset) != subst) offset++; \
+ *(int *)(CODE+offset) = (int)(NEWVAL) - ((int)(CODE)+offset) - 4; \
+ if (0) fprintf(stderr, "%s/%d: offset %d, new value: 0x%x\n", __FILE__, __LINE__, offset, (int)(NEWVAL) - ((int)(CODE)+offset) - 4); \
+ offset += 4; \
+ } \
+ else { \
+ int *icode = (int *)(CODE+KNOWN_OFFSET); \
+ assert (*icode == subst); \
+ *icode = (int)(NEWVAL) - (int)(icode) - 4; \
+ } \
+} while (0)
+
+
+
+
+/* Build specialized versions of the immediate calls on the fly for
+ * the current state. Generic x86 versions.
+ */
+
+static struct _tnl_dynfn *makeX86Vertex1fv( GLcontext *ctx, int vertex_size )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Vertex1fv, tnl->vtx.cache.Vertex[1-1], vertex_size );
+
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 1, vertex_size - 1);
+ FIXUP(dfn->code, 0, 2, (int)&tnl->vtx.vertex[1]);
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 4, (int)ctx);
+ FIXUPREL(dfn->code, 0, 5, (int)&_tnl_wrap_filled_vertex);
+
+ return dfn;
+}
+
+static struct _tnl_dynfn *makeX86Vertex2fv( GLcontext *ctx, int vertex_size )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Vertex2fv, tnl->vtx.cache.Vertex[2-1], vertex_size );
+
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 1, vertex_size - 2);
+ FIXUP(dfn->code, 0, 2, (int)&tnl->vtx.vertex[2]);
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 4, (int)ctx);
+ FIXUPREL(dfn->code, 0, 5, (int)&_tnl_wrap_filled_vertex);
+
+ return dfn;
+}
+
+static struct _tnl_dynfn *makeX86Vertex3fv( GLcontext *ctx, int vertex_size )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Vertex3fv, tnl->vtx.cache.Vertex[3-1], vertex_size );
+
+ switch (vertex_size) {
+ default: {
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 1, vertex_size - 3);
+ FIXUP(dfn->code, 0, 2, (int)&tnl->vtx.vertex[3]);
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 4, (int)ctx);
+ FIXUPREL(dfn->code, 0, 5, (int)&_tnl_wrap_filled_vertex);
+ return dfn;
+ }
+ }
+}
+
+static struct _tnl_dynfn *makeX86Vertex4fv( GLcontext *ctx, int vertex_size )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Vertex4fv, tnl->vtx.cache.Vertex[4-1], vertex_size );
+
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 1, vertex_size - 4);
+ FIXUP(dfn->code, 0, 2, (int)&tnl->vtx.vertex[4]);
+ FIXUP(dfn->code, 0, 0, (int)&tnl->vtx.vbptr);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 3, (int)&tnl->vtx.counter);
+ FIXUP(dfn->code, 0, 4, (int)ctx);
+ FIXUPREL(dfn->code, 0, 5, (int)&_tnl_wrap_filled_vertex);
+
+ return dfn;
+}
+
+
+static struct _tnl_dynfn *makeX86Attribute1fv( GLcontext *ctx, int dest )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Attribute1fv, tnl->vtx.cache.Attribute[1-1], dest );
+
+ FIXUP(dfn->code, 0, 0, dest);
+
+ return dfn;
+}
+
+static struct _tnl_dynfn *makeX86Attribute2fv( GLcontext *ctx, int dest )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Attribute2fv, tnl->vtx.cache.Attribute[2-1], dest );
+
+ FIXUP(dfn->code, 0, 0, dest);
+ FIXUP(dfn->code, 0, 1, 4+dest);
+
+ return dfn;
+}
+
+static struct _tnl_dynfn *makeX86Attribute3fv( GLcontext *ctx, int dest )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Attribute3fv, tnl->vtx.cache.Attribute[3-1], dest );
+
+ FIXUP(dfn->code, 0, 0, dest);
+ FIXUP(dfn->code, 0, 1, 4+dest);
+ FIXUP(dfn->code, 0, 2, 8+dest);
+
+ return dfn;
+}
+
+static struct _tnl_dynfn *makeX86Attribute4fv( GLcontext *ctx, int dest )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ DFN ( _tnl_x86_Attribute4fv, tnl->vtx.cache.Attribute[4-1], dest );
+
+ FIXUP(dfn->code, 0, 0, dest);
+ FIXUP(dfn->code, 0, 1, 4+dest);
+ FIXUP(dfn->code, 0, 2, 8+dest);
+ FIXUP(dfn->code, 0, 3, 12+dest);
+
+ return dfn;
+}
+
+
+void _tnl_InitX86Codegen( struct _tnl_dynfn_generators *gen )
+{
+ gen->Vertex[0] = makeX86Vertex1fv;
+ gen->Vertex[1] = makeX86Vertex2fv;
+ gen->Vertex[2] = makeX86Vertex3fv;
+ gen->Vertex[3] = makeX86Vertex4fv;
+ gen->Attribute[0] = makeX86Attribute1fv;
+ gen->Attribute[1] = makeX86Attribute2fv;
+ gen->Attribute[2] = makeX86Attribute3fv;
+ gen->Attribute[3] = makeX86Attribute4fv;
+}
+
+
+#define MKDISP(FUNC, SIZE, ATTR, WARP) \
+do { \
+ char *code; \
+ char *start = (char *)&WARP; \
+ char *end = (char *)&WARP##_end; \
+ int offset = 0; \
+ code = ALIGN_MALLOC( end - start, 16 ); \
+ memcpy (code, start, end - start); \
+ FIXUP(code, 0, 0, (int)&(TNL_CONTEXT(ctx)->vtx.tabfv[ATTR][SIZE-1]));\
+ *(void **)&vfmt->FUNC = code; \
+} while (0)
+
+
+/* Install the codegen'ed versions of the 2nd level dispatch
+ * functions. We should keep a list and free them in the end...
+ */
+void _tnl_x86_exec_vtxfmt_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
+
+ MKDISP(Color3f, 3, _TNL_ATTRIB_COLOR0, _tnl_x86_dispatch_attrf3);
+ MKDISP(Color3fv, 3, _TNL_ATTRIB_COLOR0, _tnl_x86_dispatch_attrfv);
+ MKDISP(Color4f, 4, _TNL_ATTRIB_COLOR0, _tnl_x86_dispatch_attrf4);
+ MKDISP(Color4fv, 4, _TNL_ATTRIB_COLOR0, _tnl_x86_dispatch_attrfv);
+ MKDISP(FogCoordfEXT, 1, _TNL_ATTRIB_FOG, _tnl_x86_dispatch_attrf1);
+ MKDISP(FogCoordfvEXT, 1, _TNL_ATTRIB_FOG, _tnl_x86_dispatch_attrfv);
+ MKDISP(Normal3f, 3, _TNL_ATTRIB_NORMAL, _tnl_x86_dispatch_attrf3);
+ MKDISP(Normal3fv, 3, _TNL_ATTRIB_NORMAL, _tnl_x86_dispatch_attrfv);
+ MKDISP(SecondaryColor3fEXT, 3, _TNL_ATTRIB_COLOR1, _tnl_x86_dispatch_attrf3);
+ MKDISP(SecondaryColor3fvEXT,3, _TNL_ATTRIB_COLOR1, _tnl_x86_dispatch_attrfv);
+ MKDISP(TexCoord1f, 1, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrf1);
+ MKDISP(TexCoord1fv, 1, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrfv);
+ MKDISP(TexCoord2f, 2, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrf2);
+ MKDISP(TexCoord2fv, 2, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrfv);
+ MKDISP(TexCoord3f, 3, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrf3);
+ MKDISP(TexCoord3fv, 3, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrfv);
+ MKDISP(TexCoord4f, 4, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrf4);
+ MKDISP(TexCoord4fv, 4, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_attrfv);
+ MKDISP(Vertex2f, 2, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrf2);
+ MKDISP(Vertex2fv, 2, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrfv);
+ MKDISP(Vertex3f, 3, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrf3);
+ MKDISP(Vertex3fv, 3, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrfv);
+ MKDISP(Vertex4f, 4, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrf4);
+ MKDISP(Vertex4fv, 4, _TNL_ATTRIB_POS, _tnl_x86_dispatch_attrfv);
+
+ MKDISP(MultiTexCoord1fARB, 1, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordf1);
+ MKDISP(MultiTexCoord1fvARB, 1, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordfv);
+ MKDISP(MultiTexCoord2fARB, 2, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordf2);
+ MKDISP(MultiTexCoord2fvARB, 2, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordfv);
+ MKDISP(MultiTexCoord3fARB, 3, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordf3);
+ MKDISP(MultiTexCoord3fvARB, 3, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordfv);
+ MKDISP(MultiTexCoord4fARB, 4, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordf4);
+ MKDISP(MultiTexCoord4fvARB, 4, _TNL_ATTRIB_TEX0, _tnl_x86_dispatch_multitexcoordfv);
+
+ MKDISP(VertexAttrib1fNV, 1, 0, _tnl_x86_dispatch_vertexattribf1);
+ MKDISP(VertexAttrib1fvNV, 1, 0, _tnl_x86_dispatch_vertexattribfv);
+ MKDISP(VertexAttrib2fNV, 2, 0, _tnl_x86_dispatch_vertexattribf2);
+ MKDISP(VertexAttrib2fvNV, 2, 0, _tnl_x86_dispatch_vertexattribfv);
+ MKDISP(VertexAttrib3fNV, 3, 0, _tnl_x86_dispatch_vertexattribf3);
+ MKDISP(VertexAttrib3fvNV, 3, 0, _tnl_x86_dispatch_vertexattribfv);
+ MKDISP(VertexAttrib4fNV, 4, 0, _tnl_x86_dispatch_vertexattribf4);
+ MKDISP(VertexAttrib4fvNV, 4, 0, _tnl_x86_dispatch_vertexattribfv);
+}
+
+
+/* Install the codegen'ed choosers.
+ * We should keep a list and free them in the end...
+ */
+void _tnl_x86choosers( tnl_attrfv_func (*choose)[4],
+ tnl_attrfv_func (*do_choose)( GLuint attr,
+ GLuint sz ))
+{
+ int attr, size;
+
+ for (attr = 0; attr < _TNL_MAX_ATTR_CODEGEN; attr++) {
+ for (size = 0; size < 4; size++) {
+ char *code;
+ char *start = (char *)&_tnl_x86_choose_fv;
+ char *end = (char *)&_tnl_x86_choose_fv_end;
+ int offset = 0;
+ code = ALIGN_MALLOC( end - start, 16 );
+ memcpy (code, start, end - start);
+ FIXUP(code, 0, 0, attr);
+ FIXUP(code, 0, 1, size + 1);
+ FIXUPREL(code, 0, 2, do_choose);
+ choose[attr][size] = (tnl_attrfv_func)code;
+ }
+ }
+}
+
+#else
+
+void _tnl_InitX86Codegen( struct _tnl_dynfn_generators *gen )
+{
+ (void) gen;
+}
+
+
+void _tnl_x86_exec_vtxfmt_init( GLcontext *ctx )
+{
+ (void) ctx;
+}
+
+
+void _tnl_x86choosers( tnl_attrfv_func (*choose)[4],
+ tnl_attrfv_func (*do_choose)( GLuint attr,
+ GLuint sz ))
+{
+ (void) choose;
+ (void) do_choose;
+}
+
+#endif
diff --git a/src/mesa/tnl/t_vtx_x86_gcc.S b/src/mesa/tnl/t_vtx_x86_gcc.S
new file mode 100644
index 0000000..5f79197
--- /dev/null
+++ b/src/mesa/tnl/t_vtx_x86_gcc.S
@@ -0,0 +1,557 @@
+/**************************************************************************
+
+Copyright 2004 Tungsten Graphics Inc., Cedar Park, Texas.
+
+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
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, 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 (including the next
+paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS 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 <keith@tungstengraphics.com>
+ * Daniel Borca <dborca@yahoo.com>
+ */
+
+#if defined (__DJGPP__) || defined (__MINGW32__) || defined (__CYGWIN__)
+#define GLOBL( x ) \
+.globl _##x; \
+_##x:
+#else /* !defined (__DJGPP__) && !defined (__MINGW32__) && !defined (__CYGWIN__) */
+#define GLOBL( x ) \
+.globl x; \
+x:
+#endif /* !defined (__DJGPP__) && !defined (__MINGW32__) && !defined (__CYGWIN__) */
+
+
+#if !defined (STDCALL_API)
+#define RETCLEAN( x ) ret
+#else
+#define RETCLEAN( x ) ret $x
+#endif
+
+
+#define _JMP(x) \
+.byte 0xe9; \
+.long x
+
+#define _CALL(x) \
+.byte 0xe8; \
+.long x
+
+
+/* Someone who knew a lot about this sort of thing would use this
+ * macro to note current offsets, etc in a special region of the
+ * object file & just make everything work out neat. I don't know
+ * enough to do that...
+ */
+
+#define SUBST( x ) (0x10101010 + x)
+
+
+.data
+
+
+/* [dBorca] TODO
+ * Unfold functions for each vertex size?
+ * Build super-specialized SSE versions?
+ *
+ * There is a trick in Vertex*fv: under certain conditions,
+ * we tail to _tnl_wrap_filled_vertex(ctx). This means that
+ * if Vertex*fv is STDCALL, then _tnl_wrap_filled_vertex must
+ * be STDCALL as well, because (GLcontext *) and (GLfloat *)
+ * have the same size.
+ */
+.align 4
+GLOBL ( _tnl_x86_Vertex1fv )
+ movl 4(%esp), %ecx
+ push %edi
+ push %esi
+ movl SUBST(0), %edi /* 0x0 --> tnl->vtx.vbptr */
+ movl (%ecx), %edx /* load v[0] */
+ movl %edx, (%edi) /* tnl->vtx.vbptr[0] = v[0] */
+ addl $4, %edi /* tnl->vtx.vbptr += 1 */
+ movl $SUBST(1), %ecx /* 0x1 --> (tnl->vtx.vertex_size - 1) */
+ movl $SUBST(2), %esi /* 0x2 --> (tnl->vtx.vertex + 1) */
+ repz
+ movsl %ds:(%esi), %es:(%edi)
+ movl %edi, SUBST(0) /* 0x0 --> tnl->vtx.vbptr */
+ movl SUBST(3), %edx /* 0x3 --> counter */
+ pop %esi
+ pop %edi
+ dec %edx /* counter-- */
+ movl %edx, SUBST(3) /* 0x3 --> counter */
+ je .0 /* if (counter == 0) goto .0 */
+ RETCLEAN(4) /* return */
+ .balign 16
+.0:
+ movl $SUBST(4), %eax /* load ctx */
+ movl %eax, 4(%esp) /* push ctx */
+ _JMP (SUBST(5)) /* jmp _tnl_wrap_filled_vertex */
+GLOBL ( _tnl_x86_Vertex1fv_end )
+
+.align 4
+GLOBL ( _tnl_x86_Vertex2fv )
+ movl 4(%esp), %ecx
+ push %edi
+ push %esi
+ movl SUBST(0), %edi /* load tnl->vtx.vbptr */
+ movl (%ecx), %edx /* load v[0] */
+ movl 4(%ecx), %eax /* load v[1] */
+ movl %edx, (%edi) /* tnl->vtx.vbptr[0] = v[0] */
+ movl %eax, 4(%edi) /* tnl->vtx.vbptr[1] = v[1] */
+ addl $8, %edi /* tnl->vtx.vbptr += 2 */
+ movl $SUBST(1), %ecx /* vertex_size - 2 */
+ movl $SUBST(2), %esi /* tnl->vtx.vertex + 2 */
+ repz
+ movsl %ds:(%esi), %es:(%edi)
+ movl %edi, SUBST(0) /* save tnl->vtx.vbptr */
+ movl SUBST(3), %edx /* load counter */
+ pop %esi
+ pop %edi
+ dec %edx /* counter-- */
+ movl %edx, SUBST(3) /* save counter */
+ je .1 /* if (counter == 0) goto .1 */
+ RETCLEAN(4) /* return */
+ .balign 16
+.1:
+ movl $SUBST(4), %eax /* load ctx */
+ movl %eax, 4(%esp) /* push ctx */
+ _JMP (SUBST(5)) /* jmp _tnl_wrap_filled_vertex */
+GLOBL ( _tnl_x86_Vertex2fv_end )
+
+.align 4
+GLOBL ( _tnl_x86_Vertex3fv )
+ movl 4(%esp), %ecx
+ push %edi
+ push %esi
+ movl SUBST(0), %edi /* load tnl->vtx.vbptr */
+ movl (%ecx), %edx /* load v[0] */
+ movl 4(%ecx), %eax /* load v[1] */
+ movl 8(%ecx), %esi /* load v[2] */
+ movl %edx, (%edi) /* tnl->vtx.vbptr[0] = v[0] */
+ movl %eax, 4(%edi) /* tnl->vtx.vbptr[1] = v[1] */
+ movl %esi, 8(%edi) /* tnl->vtx.vbptr[2] = v[2] */
+ addl $12, %edi /* tnl->vtx.vbptr += 3 */
+ movl $SUBST(1), %ecx /* vertex_size - 3 */
+ movl $SUBST(2), %esi /* tnl->vtx.vertex + 3 */
+ repz
+ movsl %ds:(%esi), %es:(%edi)
+ movl %edi, SUBST(0) /* save tnl->vtx.vbptr */
+ movl SUBST(3), %edx /* load counter */
+ pop %esi
+ pop %edi
+ dec %edx /* counter-- */
+ movl %edx, SUBST(3) /* save counter */
+ je .2 /* if (counter == 0) goto .2 */
+ RETCLEAN(4) /* return */
+ .balign 16
+.2:
+ movl $SUBST(4), %eax /* load ctx */
+ movl %eax, 4(%esp) /* push ctx */
+ _JMP (SUBST(5)) /* jmp _tnl_wrap_filled_vertex */
+GLOBL ( _tnl_x86_Vertex3fv_end )
+
+.align 4
+GLOBL ( _tnl_x86_Vertex4fv )
+ movl 4(%esp), %ecx
+ push %edi
+ push %esi
+ movl SUBST(0), %edi /* load tnl->vtx.vbptr */
+ movl (%ecx), %edx /* load v[0] */
+ movl 4(%ecx), %eax /* load v[1] */
+ movl 8(%ecx), %esi /* load v[2] */
+ movl 12(%ecx), %ecx /* load v[3] */
+ movl %edx, (%edi) /* tnl->vtx.vbptr[0] = v[0] */
+ movl %eax, 4(%edi) /* tnl->vtx.vbptr[1] = v[1] */
+ movl %esi, 8(%edi) /* tnl->vtx.vbptr[2] = v[2] */
+ movl %ecx, 12(%edi) /* tnl->vtx.vbptr[3] = v[3] */
+ addl $16, %edi /* tnl->vtx.vbptr += 4 */
+ movl $SUBST(1), %ecx /* vertex_size - 4 */
+ movl $SUBST(2), %esi /* tnl->vtx.vertex + 4 */
+ repz
+ movsl %ds:(%esi), %es:(%edi)
+ movl %edi, SUBST(0) /* save tnl->vtx.vbptr */
+ movl SUBST(3), %edx /* load counter */
+ pop %esi
+ pop %edi
+ dec %edx /* counter-- */
+ movl %edx, SUBST(3) /* save counter */
+ je .3 /* if (counter == 0) goto .3 */
+ RETCLEAN(4) /* return */
+ .balign 16
+.3:
+ movl $SUBST(4), %eax /* load ctx */
+ movl %eax, 4(%esp) /* push ctx */
+ _JMP (SUBST(5)) /* jmp _tnl_wrap_filled_vertex */
+GLOBL ( _tnl_x86_Vertex4fv_end )
+
+
+/**
+ * Generic handlers for vector format data.
+ */
+GLOBL( _tnl_x86_Attribute1fv )
+ movl 4(%esp), %ecx
+ movl (%ecx), %eax /* load v[0] */
+ movl %eax, SUBST(0) /* store v[0] to current vertex */
+ RETCLEAN(4)
+GLOBL ( _tnl_x86_Attribute1fv_end )
+
+GLOBL( _tnl_x86_Attribute2fv )
+ movl 4(%esp), %ecx
+ movl (%ecx), %eax /* load v[0] */
+ movl 4(%ecx), %edx /* load v[1] */
+ movl %eax, SUBST(0) /* store v[0] to current vertex */
+ movl %edx, SUBST(1) /* store v[1] to current vertex */
+ RETCLEAN(4)
+GLOBL ( _tnl_x86_Attribute2fv_end )
+
+GLOBL( _tnl_x86_Attribute3fv )
+ movl 4(%esp), %ecx
+ movl (%ecx), %eax /* load v[0] */
+ movl 4(%ecx), %edx /* load v[1] */
+ movl 8(%ecx), %ecx /* load v[2] */
+ movl %eax, SUBST(0) /* store v[0] to current vertex */
+ movl %edx, SUBST(1) /* store v[1] to current vertex */
+ movl %ecx, SUBST(2) /* store v[2] to current vertex */
+ RETCLEAN(4)
+GLOBL ( _tnl_x86_Attribute3fv_end )
+
+GLOBL( _tnl_x86_Attribute4fv )
+ movl 4(%esp), %ecx
+ movl (%ecx), %eax /* load v[0] */
+ movl 4(%ecx), %edx /* load v[1] */
+ movl %eax, SUBST(0) /* store v[0] to current vertex */
+ movl %edx, SUBST(1) /* store v[1] to current vertex */
+ movl 8(%ecx), %eax /* load v[2] */
+ movl 12(%ecx), %edx /* load v[3] */
+ movl %eax, SUBST(2) /* store v[2] to current vertex */
+ movl %edx, SUBST(3) /* store v[3] to current vertex */
+ RETCLEAN(4)
+GLOBL ( _tnl_x86_Attribute4fv_end )
+
+
+/* Choosers:
+ *
+ * Must generate all of these ahead of first usage. Generate at
+ * compile-time?
+ */
+GLOBL( _tnl_x86_choose_fv )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl $SUBST(0), (%esp) /* arg 0 - attrib */
+ movl $SUBST(1), 4(%esp) /* arg 1 - N */
+ _CALL (SUBST(2)) /* call do_choose */
+ add $12, %esp /* tear down stack frame */
+ jmp *%eax /* jump to new func */
+GLOBL ( _tnl_x86_choose_fv_end )
+
+
+/* FIRST LEVEL FUNCTIONS -- these are plugged directly into GL dispatch.
+ *
+ * In the 1st level dispatch functions, switch to a different
+ * calling convention -- (const GLfloat *v) in %ecx.
+ *
+ * As with regular (x86) dispatch, don't create a new stack frame -
+ * just let the 'ret' in the dispatched function return straight
+ * back to the original caller.
+ *
+ * Vertex/Normal/Color, etc: the address of the function pointer
+ * is known at codegen time.
+ */
+
+/* Unfortunately, have to play with the stack in the non-fv case:
+ */
+#if !defined (STDCALL_API)
+GLOBL( _tnl_x86_dispatch_attrf1 )
+GLOBL( _tnl_x86_dispatch_attrf2 )
+GLOBL( _tnl_x86_dispatch_attrf3 )
+GLOBL( _tnl_x86_dispatch_attrf4 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ leal 16(%esp), %edx /* address of first float on stack */
+ movl %edx, (%esp) /* save as 'v' */
+ call *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+ addl $12, %esp /* tear down frame */
+ ret /* return */
+GLOBL( _tnl_x86_dispatch_attrf4_end )
+GLOBL( _tnl_x86_dispatch_attrf3_end )
+GLOBL( _tnl_x86_dispatch_attrf2_end )
+GLOBL( _tnl_x86_dispatch_attrf1_end )
+
+#else /* defined(STDCALL_API) */
+
+GLOBL( _tnl_x86_dispatch_attrf1 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ leal 16(%esp), %edx /* address of first float on stack */
+ movl %edx, (%esp) /* save as 'v' */
+ call *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $4 /* return */
+GLOBL( _tnl_x86_dispatch_attrf1_end )
+
+GLOBL( _tnl_x86_dispatch_attrf2 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ leal 16(%esp), %edx /* address of first float on stack */
+ movl %edx, (%esp) /* save as 'v' */
+ call *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $8 /* return */
+GLOBL( _tnl_x86_dispatch_attrf2_end )
+
+GLOBL( _tnl_x86_dispatch_attrf3 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ leal 16(%esp), %edx /* address of first float on stack */
+ movl %edx, (%esp) /* save as 'v' */
+ call *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $12 /* return */
+GLOBL( _tnl_x86_dispatch_attrf3_end )
+
+GLOBL( _tnl_x86_dispatch_attrf4 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ leal 16(%esp), %edx /* address of first float on stack */
+ movl %edx, (%esp) /* save as 'v' */
+ call *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $16 /* return */
+GLOBL( _tnl_x86_dispatch_attrf4_end )
+#endif /* defined(STDCALL_API) */
+
+/* The fv case is simpler:
+ */
+GLOBL( _tnl_x86_dispatch_attrfv )
+ jmp *SUBST(0) /* 0x0 --> tabfv[attr][n] */
+GLOBL( _tnl_x86_dispatch_attrfv_end )
+
+
+/* MultiTexcoord: the address of the function pointer must be
+ * calculated, but can use the index argument slot to hold 'v', and
+ * avoid setting up a new stack frame.
+ *
+ * [dBorca]
+ * right, this would be the preferred approach, but gcc does not
+ * clean up the stack after each function call when optimizing (-fdefer-pop);
+ * can it make assumptions about what's already on the stack? I dunno,
+ * but in this case, we can't mess with the caller's stack frame, and
+ * we must use a model like `_x86_dispatch_attrfv' above. Caveat emptor!
+ */
+
+/* Also, will only need a maximum of four of each of these per context:
+ */
+#if !defined (STDCALL_API)
+GLOBL( _tnl_x86_dispatch_multitexcoordf1 )
+GLOBL( _tnl_x86_dispatch_multitexcoordf2 )
+GLOBL( _tnl_x86_dispatch_multitexcoordf3 )
+GLOBL( _tnl_x86_dispatch_multitexcoordf4 )
+ movl 4(%esp), %ecx
+ leal 8(%esp), %edx
+ andl $7, %ecx
+ movl %edx, 4(%esp)
+ sall $4, %ecx
+ jmp *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+GLOBL( _tnl_x86_dispatch_multitexcoordf4_end )
+GLOBL( _tnl_x86_dispatch_multitexcoordf3_end )
+GLOBL( _tnl_x86_dispatch_multitexcoordf2_end )
+GLOBL( _tnl_x86_dispatch_multitexcoordf1_end )
+
+GLOBL( _tnl_x86_dispatch_multitexcoordfv )
+ movl 4(%esp), %ecx
+ movl 8(%esp), %edx
+ andl $7, %ecx
+ movl %edx, 4(%esp)
+ sall $4, %ecx
+ jmp *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+GLOBL( _tnl_x86_dispatch_multitexcoordfv_end )
+
+#else /* defined (STDCALL_API) */
+
+GLOBL( _tnl_x86_dispatch_multitexcoordf1 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %ecx
+ leal 20(%esp), %edx
+ andl $7, %ecx
+ movl %edx, (%esp)
+ sall $4, %ecx
+ call *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $8 /* return */
+GLOBL( _tnl_x86_dispatch_multitexcoordf1_end )
+
+GLOBL( _tnl_x86_dispatch_multitexcoordf2 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %ecx
+ leal 20(%esp), %edx
+ andl $7, %ecx
+ movl %edx, (%esp)
+ sall $4, %ecx
+ call *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $12 /* return */
+GLOBL( _tnl_x86_dispatch_multitexcoordf2_end )
+
+GLOBL( _tnl_x86_dispatch_multitexcoordf3 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %ecx
+ leal 20(%esp), %edx
+ andl $7, %ecx
+ movl %edx, (%esp)
+ sall $4, %ecx
+ call *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $16 /* return */
+GLOBL( _tnl_x86_dispatch_multitexcoordf3_end )
+
+GLOBL( _tnl_x86_dispatch_multitexcoordf4 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %ecx
+ leal 20(%esp), %edx
+ andl $7, %ecx
+ movl %edx, (%esp)
+ sall $4, %ecx
+ call *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $20 /* return */
+GLOBL( _tnl_x86_dispatch_multitexcoordf4_end )
+
+GLOBL( _tnl_x86_dispatch_multitexcoordfv )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %ecx
+ movl 20(%esp), %edx
+ andl $7, %ecx
+ movl %edx, (%esp)
+ sall $4, %ecx
+ call *SUBST(0)(%ecx) /* 0x0 - tabfv[tex0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $8 /* return */
+GLOBL( _tnl_x86_dispatch_multitexcoordfv_end )
+#endif /* defined (STDCALL_API) */
+
+
+/* VertexAttrib: the address of the function pointer must be
+ * calculated.
+ */
+#if !defined (STDCALL_API)
+GLOBL( _tnl_x86_dispatch_vertexattribf1 )
+GLOBL( _tnl_x86_dispatch_vertexattribf2 )
+GLOBL( _tnl_x86_dispatch_vertexattribf3 )
+GLOBL( _tnl_x86_dispatch_vertexattribf4 )
+ movl 4(%esp), %eax
+ cmpl $16, %eax
+ jb .8 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.8:
+ leal 8(%esp), %ecx /* calculate 'v' */
+ movl %ecx, 4(%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ jmp *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+GLOBL( _tnl_x86_dispatch_vertexattribf4_end )
+GLOBL( _tnl_x86_dispatch_vertexattribf3_end )
+GLOBL( _tnl_x86_dispatch_vertexattribf2_end )
+GLOBL( _tnl_x86_dispatch_vertexattribf1_end )
+
+GLOBL( _tnl_x86_dispatch_vertexattribfv )
+ movl 4(%esp), %eax
+ cmpl $16, %eax
+ jb .9 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.9:
+ movl 8(%esp), %ecx /* load 'v' */
+ movl %ecx, 4(%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ jmp *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+GLOBL( _tnl_x86_dispatch_vertexattribfv_end )
+
+#else /* defined (STDCALL_API) */
+
+GLOBL( _tnl_x86_dispatch_vertexattribf1 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %eax
+ cmpl $16, %eax
+ jb .81 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.81:
+ leal 20(%esp), %ecx /* load 'v' */
+ movl %ecx, (%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ call *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $8 /* return */
+GLOBL( _tnl_x86_dispatch_vertexattribf1_end )
+
+GLOBL( _tnl_x86_dispatch_vertexattribf2 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %eax
+ cmpl $16, %eax
+ jb .82 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.82:
+ leal 20(%esp), %ecx /* load 'v' */
+ movl %ecx, (%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ call *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $12 /* return */
+GLOBL( _tnl_x86_dispatch_vertexattribf2_end )
+
+GLOBL( _tnl_x86_dispatch_vertexattribf3 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %eax
+ cmpl $16, %eax
+ jb .83 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.83:
+ leal 20(%esp), %ecx /* load 'v' */
+ movl %ecx, (%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ call *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $16 /* return */
+GLOBL( _tnl_x86_dispatch_vertexattribf3_end )
+
+GLOBL( _tnl_x86_dispatch_vertexattribf4 )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %eax
+ cmpl $16, %eax
+ jb .84 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.84:
+ leal 20(%esp), %ecx /* load 'v' */
+ movl %ecx, (%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ call *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $20 /* return */
+GLOBL( _tnl_x86_dispatch_vertexattribf4_end )
+
+GLOBL( _tnl_x86_dispatch_vertexattribfv )
+ subl $12, %esp /* gcc does 16 byte alignment of stack frames? */
+ movl 16(%esp), %eax
+ cmpl $16, %eax
+ jb .9 /* "cmovge" is not supported on all CPUs */
+ movl $16, %eax
+.9:
+ movl 20(%esp), %ecx /* load 'v' */
+ movl %ecx, (%esp) /* save in 1st arg slot */
+ sall $4, %eax
+ call *SUBST(0)(%eax) /* 0x0 - tabfv[0][n] */
+ addl $8, %esp /* tear down frame (4 shaved off by the callee) */
+ ret $8 /* return */
+GLOBL( _tnl_x86_dispatch_vertexattribfv_end )
+#endif /* defined (STDCALL_API) */
diff --git a/src/mesa/tnl/tnl.dsp b/src/mesa/tnl/tnl.dsp
new file mode 100644
index 0000000..0499d12
--- /dev/null
+++ b/src/mesa/tnl/tnl.dsp
@@ -0,0 +1,228 @@
+# Microsoft Developer Studio Project File - Name="tnl" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Static Library" 0x0104
+
+CFG=tnl - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "tnl.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "tnl.mak" CFG="tnl - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "tnl - Win32 Release" (based on "Win32 (x86) Static Library")
+!MESSAGE "tnl - Win32 Debug" (based on "Win32 (x86) Static Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "tnl - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD CPP /nologo /W3 /GX /O2 /I "../../../include" /I "../" /I "../main" /I "../glapi" /I "../shader" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ELSEIF "$(CFG)" == "tnl - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
+# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "../../../include" /I "../" /I "../main" /I "../glapi" /I "../shader" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /YX /FD /GZ /c
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LIB32=link.exe -lib
+# ADD BASE LIB32 /nologo
+# ADD LIB32 /nologo
+
+!ENDIF
+
+# Begin Target
+
+# Name "tnl - Win32 Release"
+# Name "tnl - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\t_array_api.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_array_import.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_context.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_pipeline.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_save_api.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_save_loopback.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_save_playback.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_cull.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_fog.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_light.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_normals.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_points.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_program.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_render.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_texgen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_texmat.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_vertex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vertex.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vertex_c.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vertex_codegen.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vtx_api.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vtx_eval.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vtx_exec.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vtx_generic.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\t_array_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_array_import.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_context.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_pipeline.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_save_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_cliptmp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_lighttmp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vb_rendertmp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\t_vtx_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tnl.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h
new file mode 100644
index 0000000..d04310f
--- /dev/null
+++ b/src/mesa/tnl/tnl.h
@@ -0,0 +1,87 @@
+
+/*
+ * Mesa 3-D graphics library
+ * Version: 3.5
+ *
+ * Copyright (C) 1999-2001 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 <keith@tungstengraphics.com>
+ */
+
+#ifndef _TNL_H
+#define _TNL_H
+
+#include "mtypes.h"
+
+
+
+/* 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 );
+
+extern void
+_tnl_DestroyContext( GLcontext *ctx );
+
+extern void
+_tnl_InvalidateState( GLcontext *ctx, GLuint new_state );
+
+/* Functions to revive the tnl module after being unhooked from
+ * dispatch and/or driver callbacks.
+ */
+
+/* Restore just the ctx->Exec table:
+ */
+extern void
+_tnl_wakeup_exec( GLcontext *ctx );
+
+/* Restore both ctx->Exec and ctx->Save:
+ */
+extern void
+_tnl_wakeup_save_exec( GLcontext *ctx );
+
+/* Driver configuration options:
+ */
+extern void
+_tnl_need_projected_coords( GLcontext *ctx, GLboolean flag );
+
+extern void
+_tnl_need_dlist_loopback( GLcontext *ctx, GLboolean flag );
+
+extern void
+_tnl_need_dlist_norm_lengths( GLcontext *ctx, GLboolean flag );
+
+extern void
+_tnl_isolate_materials( GLcontext *ctx, GLboolean flag );
+
+
+/* Control whether T&L does per-vertex fog
+ */
+extern void
+_tnl_allow_vertex_fog( GLcontext *ctx, GLboolean value );
+
+extern void
+_tnl_allow_pixel_fog( GLcontext *ctx, GLboolean value );
+
+
+#endif