2 /**************************************************************************
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
27 **************************************************************************/
31 * Keith Whitwell <keith@tungstengraphics.com>
41 #include "api_arrayelt.h"
43 #include "t_vtx_api.h"
46 static void init_attrfv( TNLcontext
*tnl
);
49 /* Close off the last primitive, execute the buffer, restart the
52 static void _tnl_wrap_buffers( GLcontext
*ctx
)
54 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
55 GLuint last_prim
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].mode
;
56 GLuint last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
58 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
59 GLint i
= tnl
->vtx
.prim_count
- 1;
61 tnl
->vtx
.prim
[i
].count
= ((tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
) -
62 tnl
->vtx
.prim
[i
].start
);
65 /* Execute the buffer and save copied vertices.
67 _tnl_flush_vtx( ctx
);
69 /* Emit a glBegin to start the new list.
71 assert(tnl
->vtx
.prim_count
== 0);
73 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
74 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
75 tnl
->vtx
.prim
[0].start
= 0;
76 tnl
->vtx
.prim
[0].count
= 0;
77 tnl
->vtx
.prim_count
++;
79 if (tnl
->vtx
.copied
.nr
== last_count
)
80 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
85 static void _tnl_wrap_filled_vertex( GLcontext
*ctx
)
87 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
88 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
91 /* Run pipeline on current vertices, copy wrapped vertices
94 _tnl_wrap_buffers( ctx
);
96 /* Copy stored stored vertices to start of new list.
98 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
100 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
101 _mesa_memcpy( tnl
->vtx
.vbptr
, data
, tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
102 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
103 data
+= tnl
->vtx
.vertex_size
;
107 tnl
->vtx
.copied
.nr
= 0;
112 * Copy the active vertex's values to the ctx->Current fields.
114 static void _tnl_copy_to_current( GLcontext
*ctx
)
116 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
119 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
120 if (tnl
->vtx
.attrsz
[i
]) {
121 /* Note: the tnl->vtx.current[i] pointers points to
122 * the ctx->Current fields. The first 16 or so, anyway.
124 ASSIGN_4V( tnl
->vtx
.current
[i
], 0, 0, 0, 1 );
125 COPY_SZ_4V(tnl
->vtx
.current
[i
],
127 tnl
->vtx
.attrptr
[i
]);
130 /* Edgeflag requires special treatment:
132 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
133 ctx
->Current
.EdgeFlag
=
134 (tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
137 /* Colormaterial -- this kindof sucks.
139 if (ctx
->Light
.ColorMaterialEnabled
) {
140 _mesa_update_color_material(ctx
, ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
143 if (tnl
->vtx
.have_materials
) {
144 tnl
->Driver
.NotifyMaterialChange( ctx
);
147 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
151 static void _tnl_copy_from_current( GLcontext
*ctx
)
153 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
156 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
157 switch (tnl
->vtx
.attrsz
[i
]) {
158 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
159 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
160 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
161 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
165 /* Edgeflag requires special treatment:
167 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
168 tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
169 (GLfloat
)ctx
->Current
.EdgeFlag
;
172 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
176 /* Flush existing data, set new attrib size, replay copied vertices.
178 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
182 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
186 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
189 /* Run pipeline on current vertices, copy wrapped vertices
190 * to tnl->vtx.copied.
192 _tnl_wrap_buffers( ctx
);
194 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
195 * when the attribute already exists in the vertex and is having
196 * its size increased.
198 _tnl_copy_to_current( ctx
);
201 /* Heuristic: Attempt to isolate attributes received outside
202 * begin/end so that they don't bloat the vertices.
204 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
205 tnl
->vtx
.attrsz
[attr
] == 0
213 oldsz
= tnl
->vtx
.attrsz
[attr
];
214 tnl
->vtx
.attrsz
[attr
] = newsz
;
216 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
217 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
218 ctx
->Const
.MaxArrayLockSize
);
219 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
220 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
223 /* Recalculate all the attrptr[] values
225 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
226 if (tnl
->vtx
.attrsz
[i
]) {
227 tnl
->vtx
.attrptr
[i
] = tmp
;
228 tmp
+= tnl
->vtx
.attrsz
[i
];
231 tnl
->vtx
.attrptr
[i
] = 0; /* will not be dereferenced */
234 /* Copy from current to repopulate the vertex with correct values.
236 _tnl_copy_from_current( ctx
);
238 /* Replay stored vertices to translate them
239 * to new format here.
241 * -- No need to replay - just copy piecewise
243 if (tnl
->vtx
.copied
.nr
)
245 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
246 GLfloat
*dest
= tnl
->vtx
.buffer
;
249 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
250 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
251 if (tnl
->vtx
.attrsz
[j
]) {
253 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
254 COPY_SZ_4V( dest
, oldsz
, data
);
259 GLuint sz
= tnl
->vtx
.attrsz
[j
];
260 COPY_SZ_4V( dest
, sz
, data
);
268 tnl
->vtx
.vbptr
= dest
;
269 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
270 tnl
->vtx
.copied
.nr
= 0;
275 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
277 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
278 static const GLfloat id
[4] = { 0, 0, 0, 1 };
281 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
282 /* New size is larger. Need to flush existing vertices and get
283 * an enlarged vertex format.
285 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
287 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
288 /* New size is smaller - just need to fill in some
289 * zeros. Don't need to flush or wrap.
291 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
292 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
299 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
300 * entrypoint is called for the first time.
302 static void do_choose( GLuint attr
, GLuint sz
,
303 void (*fallback_attr_func
)( const GLfloat
*),
304 void (*choose1
)( const GLfloat
*),
305 void (*choose2
)( const GLfloat
*),
306 void (*choose3
)( const GLfloat
*),
307 void (*choose4
)( const GLfloat
*),
310 GET_CURRENT_CONTEXT( ctx
);
311 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
313 if (tnl
->vtx
.attrsz
[attr
] != sz
)
314 _tnl_fixup_vertex( ctx
, attr
, sz
);
316 /* Does this belong here? Necessitates resetting vtxfmt on each
317 * flush (otherwise flags won't get reset afterwards).
320 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
322 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
324 /* Reset any active pointers for this attribute
326 tnl
->vtx
.tabfv
[attr
][0] = choose1
;
327 tnl
->vtx
.tabfv
[attr
][1] = choose2
;
328 tnl
->vtx
.tabfv
[attr
][2] = choose3
;
329 tnl
->vtx
.tabfv
[attr
][3] = choose4
;
331 /* Update the secondary dispatch table with the new function
333 tnl
->vtx
.tabfv
[attr
][sz
-1] = fallback_attr_func
;
335 (*fallback_attr_func
)(v
);
339 /* Versions of all the entrypoints for situations where codegen isn't
342 * Note: Only one size for each attribute may be active at once.
343 * Eg. if Color3f is installed/active, then Color4f may not be, even
344 * if the vertex actually contains 4 color coordinates. This is
345 * because the 3f version won't otherwise set color[3] to 1.0 -- this
346 * is the job of the chooser function when switching between Color4f
349 #define ATTRFV( ATTR, N ) \
350 static void choose_##ATTR##_##N( const GLfloat *v ); \
352 static void attrib_##ATTR##_##N( const GLfloat *v ) \
354 GET_CURRENT_CONTEXT( ctx ); \
355 TNLcontext *tnl = TNL_CONTEXT(ctx); \
360 if (N>0) tnl->vtx.vbptr[0] = v[0]; \
361 if (N>1) tnl->vtx.vbptr[1] = v[1]; \
362 if (N>2) tnl->vtx.vbptr[2] = v[2]; \
363 if (N>3) tnl->vtx.vbptr[3] = v[3]; \
365 for (i = N; i < tnl->vtx.vertex_size; i++) \
366 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
368 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
370 if (--tnl->vtx.counter == 0) \
371 _tnl_wrap_filled_vertex( ctx ); \
374 GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
375 if (N>0) dest[0] = v[0]; \
376 if (N>1) dest[1] = v[1]; \
377 if (N>2) dest[2] = v[2]; \
378 if (N>3) dest[3] = v[3]; \
382 #define CHOOSE( ATTR, N ) \
383 static void choose_##ATTR##_##N( const GLfloat *v ) \
386 attrib_##ATTR##_##N, \
395 static void init_##ATTR( TNLcontext *tnl ) \
397 tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1; \
398 tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2; \
399 tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3; \
400 tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4; \
404 #define ATTRS( ATTRIB ) \
405 ATTRFV( ATTRIB, 1 ) \
406 ATTRFV( ATTRIB, 2 ) \
407 ATTRFV( ATTRIB, 3 ) \
408 ATTRFV( ATTRIB, 4 ) \
409 CHOOSE( ATTRIB, 1 ) \
410 CHOOSE( ATTRIB, 2 ) \
411 CHOOSE( ATTRIB, 3 ) \
412 CHOOSE( ATTRIB, 4 ) \
416 /* Generate a lot of functions. These are the actual worker
417 * functions, which are equivalent to those generated via codegen
437 static void init_attrfv( TNLcontext
*tnl
)
439 if (tnl
->vtx
.vertex_size
) {
459 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
460 tnl
->vtx
.attrsz
[i
] = 0;
462 tnl
->vtx
.vertex_size
= 0;
463 tnl
->vtx
.have_materials
= 0;
467 /* These can be made efficient with codegen. Further, by adding more
468 * logic to do_choose(), the double-dispatch for legacy entrypoints
469 * like glVertex3f() can be removed.
471 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
473 GET_CURRENT_CONTEXT( ctx ); \
474 TNLcontext *tnl = TNL_CONTEXT(ctx); \
475 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
478 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
479 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
480 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
481 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
483 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
485 #define DISPATCH_ATTR2F( ATTR, S,T ) \
488 v[0] = S; v[1] = T; \
489 DISPATCH_ATTR2FV( ATTR, v ); \
491 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
494 v[0] = S; v[1] = T; v[2] = R; \
495 DISPATCH_ATTR3FV( ATTR, v ); \
497 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
500 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
501 DISPATCH_ATTR4FV( ATTR, v ); \
505 static void enum_error( void )
507 GET_CURRENT_CONTEXT( ctx
);
508 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
511 static void GLAPIENTRY
_tnl_Vertex2f( GLfloat x
, GLfloat y
)
513 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
516 static void GLAPIENTRY
_tnl_Vertex2fv( const GLfloat
*v
)
518 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
521 static void GLAPIENTRY
_tnl_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
523 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
526 static void GLAPIENTRY
_tnl_Vertex3fv( const GLfloat
*v
)
528 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
531 static void GLAPIENTRY
_tnl_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
533 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
536 static void GLAPIENTRY
_tnl_Vertex4fv( const GLfloat
*v
)
538 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
541 static void GLAPIENTRY
_tnl_TexCoord1f( GLfloat x
)
543 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
546 static void GLAPIENTRY
_tnl_TexCoord1fv( const GLfloat
*v
)
548 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
551 static void GLAPIENTRY
_tnl_TexCoord2f( GLfloat x
, GLfloat y
)
553 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
556 static void GLAPIENTRY
_tnl_TexCoord2fv( const GLfloat
*v
)
558 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
561 static void GLAPIENTRY
_tnl_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
563 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
566 static void GLAPIENTRY
_tnl_TexCoord3fv( const GLfloat
*v
)
568 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
571 static void GLAPIENTRY
_tnl_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
573 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
576 static void GLAPIENTRY
_tnl_TexCoord4fv( const GLfloat
*v
)
578 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
581 static void GLAPIENTRY
_tnl_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
583 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
586 static void GLAPIENTRY
_tnl_Normal3fv( const GLfloat
*v
)
588 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
591 static void GLAPIENTRY
_tnl_FogCoordfEXT( GLfloat x
)
593 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
596 static void GLAPIENTRY
_tnl_FogCoordfvEXT( const GLfloat
*v
)
598 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
601 static void GLAPIENTRY
_tnl_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
603 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
606 static void GLAPIENTRY
_tnl_Color3fv( const GLfloat
*v
)
608 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
611 static void GLAPIENTRY
_tnl_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
613 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
616 static void GLAPIENTRY
_tnl_Color4fv( const GLfloat
*v
)
618 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
621 static void GLAPIENTRY
_tnl_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
623 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
626 static void GLAPIENTRY
_tnl_SecondaryColor3fvEXT( const GLfloat
*v
)
628 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
631 static void GLAPIENTRY
_tnl_MultiTexCoord1f( GLenum target
, GLfloat x
)
633 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
634 DISPATCH_ATTR1F( attr
, x
);
637 static void GLAPIENTRY
_tnl_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
639 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
640 DISPATCH_ATTR1FV( attr
, v
);
643 static void GLAPIENTRY
_tnl_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
645 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
646 DISPATCH_ATTR2F( attr
, x
, y
);
649 static void GLAPIENTRY
_tnl_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
651 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
652 DISPATCH_ATTR2FV( attr
, v
);
655 static void GLAPIENTRY
_tnl_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
658 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
659 DISPATCH_ATTR3F( attr
, x
, y
, z
);
662 static void GLAPIENTRY
_tnl_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
664 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
665 DISPATCH_ATTR3FV( attr
, v
);
668 static void GLAPIENTRY
_tnl_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
669 GLfloat z
, GLfloat w
)
671 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
672 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
675 static void GLAPIENTRY
_tnl_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
677 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
678 DISPATCH_ATTR4FV( attr
, v
);
681 static void GLAPIENTRY
_tnl_VertexAttrib1fNV( GLuint index
, GLfloat x
)
683 if (index
< VERT_ATTRIB_MAX
)
684 DISPATCH_ATTR1F( index
, x
);
689 static void GLAPIENTRY
_tnl_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
691 if (index
< VERT_ATTRIB_MAX
)
692 DISPATCH_ATTR1FV( index
, v
);
697 static void GLAPIENTRY
_tnl_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
699 if (index
< VERT_ATTRIB_MAX
)
700 DISPATCH_ATTR2F( index
, x
, y
);
705 static void GLAPIENTRY
_tnl_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
707 if (index
< VERT_ATTRIB_MAX
)
708 DISPATCH_ATTR2FV( index
, v
);
713 static void GLAPIENTRY
_tnl_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
716 if (index
< VERT_ATTRIB_MAX
)
717 DISPATCH_ATTR3F( index
, x
, y
, z
);
722 static void GLAPIENTRY
_tnl_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
724 if (index
< VERT_ATTRIB_MAX
)
725 DISPATCH_ATTR3FV( index
, v
);
730 static void GLAPIENTRY
_tnl_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
731 GLfloat z
, GLfloat w
)
733 if (index
< VERT_ATTRIB_MAX
)
734 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
739 static void GLAPIENTRY
_tnl_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
741 if (index
< VERT_ATTRIB_MAX
)
742 DISPATCH_ATTR4FV( index
, v
);
750 * These are treated as per-vertex attributes, at indices above where
751 * the NV_vertex_program leaves off. There are a lot of good things
752 * about treating materials this way.
754 * However: I don't want to double the number of generated functions
755 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
756 * ATTRF into this function, and dispense with codegen and
757 * second-level dispatch.
759 * There is no aliasing of material attributes with other entrypoints.
761 #define MAT_ATTR( A, N, params ) \
763 if (tnl->vtx.attrsz[A] != N) { \
764 _tnl_fixup_vertex( ctx, A, N ); \
765 tnl->vtx.have_materials = GL_TRUE; \
769 GLfloat *dest = tnl->vtx.attrptr[A]; \
770 if (N>0) dest[0] = params[0]; \
771 if (N>1) dest[1] = params[1]; \
772 if (N>2) dest[2] = params[2]; \
773 if (N>3) dest[3] = params[3]; \
774 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
779 #define MAT( ATTR, N, face, params ) \
781 if (face != GL_BACK) \
782 MAT_ATTR( ATTR, N, params ); /* front */ \
783 if (face != GL_FRONT) \
784 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
788 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
789 * later on - in the meantime just store everything.
791 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
792 const GLfloat
*params
)
794 GET_CURRENT_CONTEXT( ctx
);
795 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
800 case GL_FRONT_AND_BACK
:
804 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
810 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
813 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
816 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
819 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
822 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
824 case GL_COLOR_INDEXES
:
825 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
827 case GL_AMBIENT_AND_DIFFUSE
:
828 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
829 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
832 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
838 #define IDX_ATTR( A, IDX ) \
840 GET_CURRENT_CONTEXT( ctx ); \
841 TNLcontext *tnl = TNL_CONTEXT(ctx); \
843 if (tnl->vtx.attrsz[A] != 1) { \
844 _tnl_fixup_vertex( ctx, A, 1 ); \
848 GLfloat *dest = tnl->vtx.attrptr[A]; \
850 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
855 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
857 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
860 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
862 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)v
[0] );
865 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
867 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
870 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
872 IDX_ATTR( _TNL_ATTRIB_INDEX
, v
[0] );
877 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
879 GET_CURRENT_CONTEXT( ctx
);
880 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
882 /* TODO: use a CHOOSE() function for this: */
885 if (tnl
->vtx
.eval
.new_state
)
886 _tnl_update_eval( ctx
);
888 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
889 if (tnl
->vtx
.eval
.map1
[i
].map
)
890 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map1
[i
].sz
)
891 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
896 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
897 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
899 _tnl_do_EvalCoord1f( ctx
, u
);
901 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
902 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
905 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
907 GET_CURRENT_CONTEXT( ctx
);
908 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
910 /* TODO: use a CHOOSE() function for this: */
913 if (tnl
->vtx
.eval
.new_state
)
914 _tnl_update_eval( ctx
);
916 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
917 if (tnl
->vtx
.eval
.map2
[i
].map
)
918 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map2
[i
].sz
)
919 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
922 if (ctx
->Eval
.AutoNormal
)
923 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] < 3)
924 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
927 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
928 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
930 _tnl_do_EvalCoord2f( ctx
, u
, v
);
932 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
933 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
936 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
938 _tnl_EvalCoord1f( u
[0] );
941 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
943 _tnl_EvalCoord2f( u
[0], u
[1] );
946 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
948 GET_CURRENT_CONTEXT( ctx
);
949 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
950 (GLfloat
) ctx
->Eval
.MapGrid1un
);
951 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
953 _tnl_EvalCoord1f( u
);
957 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
959 GET_CURRENT_CONTEXT( ctx
);
960 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
961 (GLfloat
) ctx
->Eval
.MapGrid2un
);
962 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
963 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
964 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
965 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
967 _tnl_EvalCoord2f( u
, v
);
971 /* Build a list of primitives on the fly. Keep
972 * ctx->Driver.CurrentExecPrimitive uptodate as well.
974 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
976 GET_CURRENT_CONTEXT( ctx
);
978 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
979 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
983 _mesa_update_state( ctx
);
984 if (!(tnl
->Driver
.NotifyBegin
&& tnl
->Driver
.NotifyBegin( ctx
, mode
)))
985 ctx
->Exec
->Begin(mode
);
989 /* Heuristic: attempt to isolate attributes occuring outside
992 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
993 _tnl_FlushVertices( ctx
, ~0 );
995 i
= tnl
->vtx
.prim_count
++;
996 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
997 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
998 tnl
->vtx
.prim
[i
].count
= 0;
1000 ctx
->Driver
.CurrentExecPrimitive
= mode
;
1003 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
1007 static void GLAPIENTRY
_tnl_End( void )
1009 GET_CURRENT_CONTEXT( ctx
);
1011 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
1012 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1013 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
1014 int i
= tnl
->vtx
.prim_count
- 1;
1016 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
1017 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
1019 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
1021 /* Two choices which effect the way vertex attributes are
1022 * carried over (or not) between adjacent primitives.
1025 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1026 _tnl_FlushVertices( ctx
, ~0 );
1028 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1029 _tnl_flush_vtx( ctx
);
1034 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
1038 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
1040 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
1041 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1042 vfmt
->Begin
= _tnl_Begin
;
1043 vfmt
->CallList
= _mesa_CallList
;
1044 vfmt
->CallLists
= _mesa_CallLists
;
1045 vfmt
->Color3f
= _tnl_Color3f
;
1046 vfmt
->Color3fv
= _tnl_Color3fv
;
1047 vfmt
->Color4f
= _tnl_Color4f
;
1048 vfmt
->Color4fv
= _tnl_Color4fv
;
1049 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
1050 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
1051 vfmt
->End
= _tnl_End
;
1052 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
1053 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
1054 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
1055 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
1056 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
1057 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
1058 vfmt
->FogCoordfEXT
= _tnl_FogCoordfEXT
;
1059 vfmt
->FogCoordfvEXT
= _tnl_FogCoordfvEXT
;
1060 vfmt
->Indexf
= _tnl_Indexf
;
1061 vfmt
->Indexfv
= _tnl_Indexfv
;
1062 vfmt
->Materialfv
= _tnl_Materialfv
;
1063 vfmt
->MultiTexCoord1fARB
= _tnl_MultiTexCoord1f
;
1064 vfmt
->MultiTexCoord1fvARB
= _tnl_MultiTexCoord1fv
;
1065 vfmt
->MultiTexCoord2fARB
= _tnl_MultiTexCoord2f
;
1066 vfmt
->MultiTexCoord2fvARB
= _tnl_MultiTexCoord2fv
;
1067 vfmt
->MultiTexCoord3fARB
= _tnl_MultiTexCoord3f
;
1068 vfmt
->MultiTexCoord3fvARB
= _tnl_MultiTexCoord3fv
;
1069 vfmt
->MultiTexCoord4fARB
= _tnl_MultiTexCoord4f
;
1070 vfmt
->MultiTexCoord4fvARB
= _tnl_MultiTexCoord4fv
;
1071 vfmt
->Normal3f
= _tnl_Normal3f
;
1072 vfmt
->Normal3fv
= _tnl_Normal3fv
;
1073 vfmt
->SecondaryColor3fEXT
= _tnl_SecondaryColor3fEXT
;
1074 vfmt
->SecondaryColor3fvEXT
= _tnl_SecondaryColor3fvEXT
;
1075 vfmt
->TexCoord1f
= _tnl_TexCoord1f
;
1076 vfmt
->TexCoord1fv
= _tnl_TexCoord1fv
;
1077 vfmt
->TexCoord2f
= _tnl_TexCoord2f
;
1078 vfmt
->TexCoord2fv
= _tnl_TexCoord2fv
;
1079 vfmt
->TexCoord3f
= _tnl_TexCoord3f
;
1080 vfmt
->TexCoord3fv
= _tnl_TexCoord3fv
;
1081 vfmt
->TexCoord4f
= _tnl_TexCoord4f
;
1082 vfmt
->TexCoord4fv
= _tnl_TexCoord4fv
;
1083 vfmt
->Vertex2f
= _tnl_Vertex2f
;
1084 vfmt
->Vertex2fv
= _tnl_Vertex2fv
;
1085 vfmt
->Vertex3f
= _tnl_Vertex3f
;
1086 vfmt
->Vertex3fv
= _tnl_Vertex3fv
;
1087 vfmt
->Vertex4f
= _tnl_Vertex4f
;
1088 vfmt
->Vertex4fv
= _tnl_Vertex4fv
;
1089 vfmt
->VertexAttrib1fNV
= _tnl_VertexAttrib1fNV
;
1090 vfmt
->VertexAttrib1fvNV
= _tnl_VertexAttrib1fvNV
;
1091 vfmt
->VertexAttrib2fNV
= _tnl_VertexAttrib2fNV
;
1092 vfmt
->VertexAttrib2fvNV
= _tnl_VertexAttrib2fvNV
;
1093 vfmt
->VertexAttrib3fNV
= _tnl_VertexAttrib3fNV
;
1094 vfmt
->VertexAttrib3fvNV
= _tnl_VertexAttrib3fvNV
;
1095 vfmt
->VertexAttrib4fNV
= _tnl_VertexAttrib4fNV
;
1096 vfmt
->VertexAttrib4fvNV
= _tnl_VertexAttrib4fvNV
;
1098 vfmt
->Rectf
= _mesa_noop_Rectf
;
1099 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
1100 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
1105 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
1107 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1109 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
1112 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
1113 _tnl_flush_vtx( ctx
);
1117 _tnl_copy_to_current( ctx
);
1119 /* reset attrfv table
1122 flags
|= FLUSH_UPDATE_CURRENT
;
1125 ctx
->Driver
.NeedFlush
= 0;
1129 static void _tnl_current_init( GLcontext
*ctx
)
1131 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1134 /* setup the pointers for the typical 16 vertex attributes */
1135 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
1136 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
1138 /* setup pointers for the 12 material attributes */
1139 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
1140 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
1141 ctx
->Light
.Material
.Attrib
[i
];
1143 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
1147 void _tnl_vtx_init( GLcontext
*ctx
)
1149 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1150 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
1153 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
1154 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1156 _tnl_current_init( ctx
);
1157 _tnl_exec_vtxfmt_init( ctx
);
1159 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
1160 tnl
->vtx
.vertex_size
= 1; init_attrfv( tnl
);
1165 void _tnl_vtx_destroy( GLcontext
*ctx
)