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
);
57 if (tnl
->vtx
.prim_count
== 0) {
58 tnl
->vtx
.copied
.nr
= 0;
59 tnl
->vtx
.counter
= tnl
->vtx
.initial_counter
;
60 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
63 GLuint last_prim
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].mode
;
64 GLuint last_count
= tnl
->vtx
.prim
[tnl
->vtx
.prim_count
-1].count
;
66 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
67 GLint i
= tnl
->vtx
.prim_count
- 1;
69 tnl
->vtx
.prim
[i
].count
= ((tnl
->vtx
.initial_counter
-
71 tnl
->vtx
.prim
[i
].start
);
74 /* Execute the buffer and save copied vertices.
76 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
)
77 _tnl_flush_vtx( ctx
);
79 tnl
->vtx
.prim_count
= 0;
80 tnl
->vtx
.copied
.nr
= 0;
83 /* Emit a glBegin to start the new list.
85 assert(tnl
->vtx
.prim_count
== 0);
87 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
88 tnl
->vtx
.prim
[0].mode
= ctx
->Driver
.CurrentExecPrimitive
;
89 tnl
->vtx
.prim
[0].start
= 0;
90 tnl
->vtx
.prim
[0].count
= 0;
91 tnl
->vtx
.prim_count
++;
93 if (tnl
->vtx
.copied
.nr
== last_count
)
94 tnl
->vtx
.prim
[0].mode
|= last_prim
& PRIM_BEGIN
;
100 /* Deal with buffer wrapping where provoked by the vertex buffer
101 * filling up, as opposed to upgrade_vertex().
103 static void _tnl_wrap_filled_vertex( GLcontext
*ctx
)
105 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
106 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
109 /* Run pipeline on current vertices, copy wrapped vertices
112 _tnl_wrap_buffers( ctx
);
114 /* Copy stored stored vertices to start of new list.
116 assert(tnl
->vtx
.counter
> tnl
->vtx
.copied
.nr
);
118 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
119 _mesa_memcpy( tnl
->vtx
.vbptr
, data
,
120 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
121 tnl
->vtx
.vbptr
+= tnl
->vtx
.vertex_size
;
122 data
+= tnl
->vtx
.vertex_size
;
126 tnl
->vtx
.copied
.nr
= 0;
131 * Copy the active vertex's values to the ctx->Current fields.
133 static void _tnl_copy_to_current( GLcontext
*ctx
)
135 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
138 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
139 if (tnl
->vtx
.attrsz
[i
]) {
140 /* Note: the tnl->vtx.current[i] pointers points to
141 * the ctx->Current fields. The first 16 or so, anyway.
143 ASSIGN_4V( tnl
->vtx
.current
[i
], 0, 0, 0, 1 );
144 COPY_SZ_4V(tnl
->vtx
.current
[i
],
146 tnl
->vtx
.attrptr
[i
]);
149 /* Edgeflag requires special treatment:
151 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
152 ctx
->Current
.EdgeFlag
=
153 (tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
156 /* Colormaterial -- this kindof sucks.
158 if (ctx
->Light
.ColorMaterialEnabled
) {
159 _mesa_update_color_material(ctx
, ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
162 if (tnl
->vtx
.have_materials
) {
163 tnl
->Driver
.NotifyMaterialChange( ctx
);
166 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
170 static void _tnl_copy_from_current( GLcontext
*ctx
)
172 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
175 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
176 switch (tnl
->vtx
.attrsz
[i
]) {
177 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
178 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
179 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
180 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
184 /* Edgeflag requires special treatment:
186 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
187 tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
188 (GLfloat
)ctx
->Current
.EdgeFlag
;
191 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
195 /* Flush existing data, set new attrib size, replay copied vertices.
197 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
201 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
205 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
208 /* Run pipeline on current vertices, copy wrapped vertices
209 * to tnl->vtx.copied.
211 _tnl_wrap_buffers( ctx
);
214 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
215 * when the attribute already exists in the vertex and is having
216 * its size increased.
218 _tnl_copy_to_current( ctx
);
221 /* Heuristic: Attempt to isolate attributes received outside
222 * begin/end so that they don't bloat the vertices.
224 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
225 tnl
->vtx
.attrsz
[attr
] == 0
233 oldsz
= tnl
->vtx
.attrsz
[attr
];
234 tnl
->vtx
.attrsz
[attr
] = newsz
;
236 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
237 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
238 ctx
->Const
.MaxArrayLockSize
);
239 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
240 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
243 /* Recalculate all the attrptr[] values
245 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
246 if (tnl
->vtx
.attrsz
[i
]) {
247 tnl
->vtx
.attrptr
[i
] = tmp
;
248 tmp
+= tnl
->vtx
.attrsz
[i
];
251 tnl
->vtx
.attrptr
[i
] = 0; /* will not be dereferenced */
254 /* Copy from current to repopulate the vertex with correct values.
256 _tnl_copy_from_current( ctx
);
258 /* Replay stored vertices to translate them
259 * to new format here.
261 * -- No need to replay - just copy piecewise
263 if (tnl
->vtx
.copied
.nr
)
265 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
266 GLfloat
*dest
= tnl
->vtx
.buffer
;
269 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
270 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
271 if (tnl
->vtx
.attrsz
[j
]) {
273 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
274 COPY_SZ_4V( dest
, oldsz
, data
);
279 GLuint sz
= tnl
->vtx
.attrsz
[j
];
280 COPY_SZ_4V( dest
, sz
, data
);
288 tnl
->vtx
.vbptr
= dest
;
289 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
290 tnl
->vtx
.copied
.nr
= 0;
295 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
297 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
298 static const GLfloat id
[4] = { 0, 0, 0, 1 };
301 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
302 /* New size is larger. Need to flush existing vertices and get
303 * an enlarged vertex format.
305 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
307 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
308 /* New size is smaller - just need to fill in some
309 * zeros. Don't need to flush or wrap.
311 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
312 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
319 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
320 * entrypoint is called for the first time.
322 static void do_choose( GLuint attr
, GLuint sz
,
323 void (*fallback_attr_func
)( const GLfloat
*),
324 void (*choose1
)( const GLfloat
*),
325 void (*choose2
)( const GLfloat
*),
326 void (*choose3
)( const GLfloat
*),
327 void (*choose4
)( const GLfloat
*),
330 GET_CURRENT_CONTEXT( ctx
);
331 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
333 if (tnl
->vtx
.attrsz
[attr
] != sz
)
334 _tnl_fixup_vertex( ctx
, attr
, sz
);
336 /* Does this belong here? Necessitates resetting vtxfmt on each
337 * flush (otherwise flags won't get reset afterwards).
340 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
342 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
344 /* Reset any active pointers for this attribute
346 tnl
->vtx
.tabfv
[attr
][0] = choose1
;
347 tnl
->vtx
.tabfv
[attr
][1] = choose2
;
348 tnl
->vtx
.tabfv
[attr
][2] = choose3
;
349 tnl
->vtx
.tabfv
[attr
][3] = choose4
;
351 /* Update the secondary dispatch table with the new function
353 tnl
->vtx
.tabfv
[attr
][sz
-1] = fallback_attr_func
;
355 (*fallback_attr_func
)(v
);
359 /* Versions of all the entrypoints for situations where codegen isn't
362 * Note: Only one size for each attribute may be active at once.
363 * Eg. if Color3f is installed/active, then Color4f may not be, even
364 * if the vertex actually contains 4 color coordinates. This is
365 * because the 3f version won't otherwise set color[3] to 1.0 -- this
366 * is the job of the chooser function when switching between Color4f
369 #define ATTRFV( ATTR, N ) \
370 static void choose_##ATTR##_##N( const GLfloat *v ); \
372 static void attrib_##ATTR##_##N( const GLfloat *v ) \
374 GET_CURRENT_CONTEXT( ctx ); \
375 TNLcontext *tnl = TNL_CONTEXT(ctx); \
380 if (N>0) tnl->vtx.vbptr[0] = v[0]; \
381 if (N>1) tnl->vtx.vbptr[1] = v[1]; \
382 if (N>2) tnl->vtx.vbptr[2] = v[2]; \
383 if (N>3) tnl->vtx.vbptr[3] = v[3]; \
385 for (i = N; i < tnl->vtx.vertex_size; i++) \
386 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
388 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
390 if (--tnl->vtx.counter == 0) \
391 _tnl_wrap_filled_vertex( ctx ); \
394 GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
395 if (N>0) dest[0] = v[0]; \
396 if (N>1) dest[1] = v[1]; \
397 if (N>2) dest[2] = v[2]; \
398 if (N>3) dest[3] = v[3]; \
402 #define CHOOSE( ATTR, N ) \
403 static void choose_##ATTR##_##N( const GLfloat *v ) \
406 attrib_##ATTR##_##N, \
415 static void init_##ATTR( TNLcontext *tnl ) \
417 tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1; \
418 tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2; \
419 tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3; \
420 tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4; \
424 #define ATTRS( ATTRIB ) \
425 ATTRFV( ATTRIB, 1 ) \
426 ATTRFV( ATTRIB, 2 ) \
427 ATTRFV( ATTRIB, 3 ) \
428 ATTRFV( ATTRIB, 4 ) \
429 CHOOSE( ATTRIB, 1 ) \
430 CHOOSE( ATTRIB, 2 ) \
431 CHOOSE( ATTRIB, 3 ) \
432 CHOOSE( ATTRIB, 4 ) \
436 /* Generate a lot of functions. These are the actual worker
437 * functions, which are equivalent to those generated via codegen
458 static void error_attrib( const GLfloat
*unused
)
460 GET_CURRENT_CONTEXT( ctx
);
462 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
465 static void init_error_attrib( TNLcontext
*tnl
)
467 tnl
->vtx
.tabfv
[ERROR_ATTRIB
][0] = error_attrib
;
468 tnl
->vtx
.tabfv
[ERROR_ATTRIB
][1] = error_attrib
;
469 tnl
->vtx
.tabfv
[ERROR_ATTRIB
][2] = error_attrib
;
470 tnl
->vtx
.tabfv
[ERROR_ATTRIB
][3] = error_attrib
;
475 static void init_attrfv( TNLcontext
*tnl
)
477 if (tnl
->vtx
.vertex_size
) {
496 init_error_attrib( tnl
);
498 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
499 tnl
->vtx
.attrsz
[i
] = 0;
501 tnl
->vtx
.vertex_size
= 0;
502 tnl
->vtx
.have_materials
= 0;
506 /* These can be made efficient with codegen. Further, by adding more
507 * logic to do_choose(), the double-dispatch for legacy entrypoints
508 * like glVertex3f() can be removed.
510 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
512 GET_CURRENT_CONTEXT( ctx ); \
513 TNLcontext *tnl = TNL_CONTEXT(ctx); \
514 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
517 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
518 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
519 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
520 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
522 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
524 #define DISPATCH_ATTR2F( ATTR, S,T ) \
527 v[0] = S; v[1] = T; \
528 DISPATCH_ATTR2FV( ATTR, v ); \
530 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
533 v[0] = S; v[1] = T; v[2] = R; \
534 DISPATCH_ATTR3FV( ATTR, v ); \
536 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
539 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
540 DISPATCH_ATTR4FV( ATTR, v ); \
544 static void enum_error( void )
546 GET_CURRENT_CONTEXT( ctx
);
547 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
550 static void GLAPIENTRY
_tnl_Vertex2f( GLfloat x
, GLfloat y
)
552 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
555 static void GLAPIENTRY
_tnl_Vertex2fv( const GLfloat
*v
)
557 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
560 static void GLAPIENTRY
_tnl_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
562 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
565 static void GLAPIENTRY
_tnl_Vertex3fv( const GLfloat
*v
)
567 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
570 static void GLAPIENTRY
_tnl_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
,
573 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
576 static void GLAPIENTRY
_tnl_Vertex4fv( const GLfloat
*v
)
578 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
581 static void GLAPIENTRY
_tnl_TexCoord1f( GLfloat x
)
583 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
586 static void GLAPIENTRY
_tnl_TexCoord1fv( const GLfloat
*v
)
588 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
591 static void GLAPIENTRY
_tnl_TexCoord2f( GLfloat x
, GLfloat y
)
593 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
596 static void GLAPIENTRY
_tnl_TexCoord2fv( const GLfloat
*v
)
598 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
601 static void GLAPIENTRY
_tnl_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
603 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
606 static void GLAPIENTRY
_tnl_TexCoord3fv( const GLfloat
*v
)
608 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
611 static void GLAPIENTRY
_tnl_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
,
614 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
617 static void GLAPIENTRY
_tnl_TexCoord4fv( const GLfloat
*v
)
619 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
622 static void GLAPIENTRY
_tnl_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
624 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
627 static void GLAPIENTRY
_tnl_Normal3fv( const GLfloat
*v
)
629 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
632 static void GLAPIENTRY
_tnl_FogCoordfEXT( GLfloat x
)
634 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
637 static void GLAPIENTRY
_tnl_FogCoordfvEXT( const GLfloat
*v
)
639 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
642 static void GLAPIENTRY
_tnl_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
644 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
647 static void GLAPIENTRY
_tnl_Color3fv( const GLfloat
*v
)
649 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
652 static void GLAPIENTRY
_tnl_Color4f( GLfloat x
, GLfloat y
, GLfloat z
,
655 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
658 static void GLAPIENTRY
_tnl_Color4fv( const GLfloat
*v
)
660 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
663 static void GLAPIENTRY
_tnl_SecondaryColor3fEXT( GLfloat x
, GLfloat y
,
666 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
669 static void GLAPIENTRY
_tnl_SecondaryColor3fvEXT( const GLfloat
*v
)
671 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
674 static void GLAPIENTRY
_tnl_MultiTexCoord1f( GLenum target
, GLfloat x
)
676 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
677 DISPATCH_ATTR1F( attr
, x
);
680 static void GLAPIENTRY
_tnl_MultiTexCoord1fv( GLenum target
,
683 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
684 DISPATCH_ATTR1FV( attr
, v
);
687 static void GLAPIENTRY
_tnl_MultiTexCoord2f( GLenum target
, GLfloat x
,
690 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
691 DISPATCH_ATTR2F( attr
, x
, y
);
694 static void GLAPIENTRY
_tnl_MultiTexCoord2fv( GLenum target
,
697 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
698 DISPATCH_ATTR2FV( attr
, v
);
701 static void GLAPIENTRY
_tnl_MultiTexCoord3f( GLenum target
, GLfloat x
,
702 GLfloat y
, GLfloat z
)
704 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
705 DISPATCH_ATTR3F( attr
, x
, y
, z
);
708 static void GLAPIENTRY
_tnl_MultiTexCoord3fv( GLenum target
,
711 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
712 DISPATCH_ATTR3FV( attr
, v
);
715 static void GLAPIENTRY
_tnl_MultiTexCoord4f( GLenum target
, GLfloat x
,
716 GLfloat y
, GLfloat z
,
719 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
720 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
723 static void GLAPIENTRY
_tnl_MultiTexCoord4fv( GLenum target
,
726 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
727 DISPATCH_ATTR4FV( attr
, v
);
730 static void GLAPIENTRY
_tnl_VertexAttrib1fNV( GLuint index
, GLfloat x
)
732 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
733 DISPATCH_ATTR1F( index
, x
);
736 static void GLAPIENTRY
_tnl_VertexAttrib1fvNV( GLuint index
,
739 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
740 DISPATCH_ATTR1FV( index
, v
);
743 static void GLAPIENTRY
_tnl_VertexAttrib2fNV( GLuint index
, GLfloat x
,
746 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
747 DISPATCH_ATTR2F( index
, x
, y
);
750 static void GLAPIENTRY
_tnl_VertexAttrib2fvNV( GLuint index
,
753 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
754 DISPATCH_ATTR2FV( index
, v
);
757 static void GLAPIENTRY
_tnl_VertexAttrib3fNV( GLuint index
, GLfloat x
,
758 GLfloat y
, GLfloat z
)
760 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
761 DISPATCH_ATTR3F( index
, x
, y
, z
);
764 static void GLAPIENTRY
_tnl_VertexAttrib3fvNV( GLuint index
,
767 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
768 DISPATCH_ATTR3FV( index
, v
);
771 static void GLAPIENTRY
_tnl_VertexAttrib4fNV( GLuint index
, GLfloat x
,
772 GLfloat y
, GLfloat z
,
775 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
776 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
779 static void GLAPIENTRY
_tnl_VertexAttrib4fvNV( GLuint index
,
782 if (index
>= VERT_ATTRIB_MAX
) index
= ERROR_ATTRIB
;
783 DISPATCH_ATTR4FV( index
, v
);
789 * These are treated as per-vertex attributes, at indices above where
790 * the NV_vertex_program leaves off. There are a lot of good things
791 * about treating materials this way.
793 * However: I don't want to double the number of generated functions
794 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
795 * ATTRF into this function, and dispense with codegen and
796 * second-level dispatch.
798 * There is no aliasing of material attributes with other entrypoints.
800 #define MAT_ATTR( A, N, params ) \
802 if (tnl->vtx.attrsz[A] != N) { \
803 _tnl_fixup_vertex( ctx, A, N ); \
804 tnl->vtx.have_materials = GL_TRUE; \
808 GLfloat *dest = tnl->vtx.attrptr[A]; \
809 if (N>0) dest[0] = params[0]; \
810 if (N>1) dest[1] = params[1]; \
811 if (N>2) dest[2] = params[2]; \
812 if (N>3) dest[3] = params[3]; \
813 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
818 #define MAT( ATTR, N, face, params ) \
820 if (face != GL_BACK) \
821 MAT_ATTR( ATTR, N, params ); /* front */ \
822 if (face != GL_FRONT) \
823 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
827 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
828 * later on - in the meantime just store everything.
830 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
831 const GLfloat
*params
)
833 GET_CURRENT_CONTEXT( ctx
);
834 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
839 case GL_FRONT_AND_BACK
:
843 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
849 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
852 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
855 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
858 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
861 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
863 case GL_COLOR_INDEXES
:
864 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
866 case GL_AMBIENT_AND_DIFFUSE
:
867 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
868 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
871 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
877 #define IDX_ATTR( A, IDX ) \
879 GET_CURRENT_CONTEXT( ctx ); \
880 TNLcontext *tnl = TNL_CONTEXT(ctx); \
882 if (tnl->vtx.attrsz[A] != 1) { \
883 _tnl_fixup_vertex( ctx, A, 1 ); \
887 GLfloat *dest = tnl->vtx.attrptr[A]; \
889 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
894 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
896 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
899 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
901 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)v
[0] );
904 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
906 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
909 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
911 IDX_ATTR( _TNL_ATTRIB_INDEX
, v
[0] );
916 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
918 GET_CURRENT_CONTEXT( ctx
);
919 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
921 /* TODO: use a CHOOSE() function for this: */
924 if (tnl
->vtx
.eval
.new_state
)
925 _tnl_update_eval( ctx
);
927 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
928 if (tnl
->vtx
.eval
.map1
[i
].map
)
929 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map1
[i
].sz
)
930 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
935 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
936 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
938 _tnl_do_EvalCoord1f( ctx
, u
);
940 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
941 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
944 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
946 GET_CURRENT_CONTEXT( ctx
);
947 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
949 /* TODO: use a CHOOSE() function for this: */
952 if (tnl
->vtx
.eval
.new_state
)
953 _tnl_update_eval( ctx
);
955 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
956 if (tnl
->vtx
.eval
.map2
[i
].map
)
957 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map2
[i
].sz
)
958 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
961 if (ctx
->Eval
.AutoNormal
)
962 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] < 3)
963 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
966 _mesa_memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
967 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
969 _tnl_do_EvalCoord2f( ctx
, u
, v
);
971 _mesa_memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
972 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
975 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
977 _tnl_EvalCoord1f( u
[0] );
980 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
982 _tnl_EvalCoord2f( u
[0], u
[1] );
985 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
987 GET_CURRENT_CONTEXT( ctx
);
988 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
989 (GLfloat
) ctx
->Eval
.MapGrid1un
);
990 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
992 _tnl_EvalCoord1f( u
);
996 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
998 GET_CURRENT_CONTEXT( ctx
);
999 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
1000 (GLfloat
) ctx
->Eval
.MapGrid2un
);
1001 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
1002 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
1003 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
1004 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
1006 _tnl_EvalCoord2f( u
, v
);
1010 /* Build a list of primitives on the fly. Keep
1011 * ctx->Driver.CurrentExecPrimitive uptodate as well.
1013 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
1015 GET_CURRENT_CONTEXT( ctx
);
1017 if ((ctx
->VertexProgram
.Enabled
1018 && !ctx
->VertexProgram
.Current
->Instructions
) ||
1019 (ctx
->FragmentProgram
.Enabled
1020 && !ctx
->FragmentProgram
.Current
->Instructions
)) {
1021 _mesa_error(ctx
, GL_INVALID_OPERATION
,
1022 "glBegin (invalid vertex/fragment program)");
1026 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
1027 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1030 if (ctx
->NewState
) {
1031 _mesa_update_state( ctx
);
1032 if (!(tnl
->Driver
.NotifyBegin
&& tnl
->Driver
.NotifyBegin( ctx
, mode
)))
1033 ctx
->Exec
->Begin(mode
);
1037 /* Heuristic: attempt to isolate attributes occuring outside
1040 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
1041 _tnl_FlushVertices( ctx
, ~0 );
1043 i
= tnl
->vtx
.prim_count
++;
1044 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
1045 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
1046 tnl
->vtx
.prim
[i
].count
= 0;
1048 ctx
->Driver
.CurrentExecPrimitive
= mode
;
1051 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
1055 static void GLAPIENTRY
_tnl_End( void )
1057 GET_CURRENT_CONTEXT( ctx
);
1059 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
1060 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1061 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
1062 int i
= tnl
->vtx
.prim_count
- 1;
1064 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
1065 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
1067 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
1069 /* Two choices which effect the way vertex attributes are
1070 * carried over (or not) between adjacent primitives.
1073 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1074 _tnl_FlushVertices( ctx
, ~0 );
1076 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1077 _tnl_flush_vtx( ctx
);
1082 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
1086 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
1088 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
1089 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1090 vfmt
->Begin
= _tnl_Begin
;
1091 vfmt
->CallList
= _mesa_CallList
;
1092 vfmt
->CallLists
= _mesa_CallLists
;
1093 vfmt
->Color3f
= _tnl_Color3f
;
1094 vfmt
->Color3fv
= _tnl_Color3fv
;
1095 vfmt
->Color4f
= _tnl_Color4f
;
1096 vfmt
->Color4fv
= _tnl_Color4fv
;
1097 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
1098 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
1099 vfmt
->End
= _tnl_End
;
1100 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
1101 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
1102 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
1103 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
1104 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
1105 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
1106 vfmt
->FogCoordfEXT
= _tnl_FogCoordfEXT
;
1107 vfmt
->FogCoordfvEXT
= _tnl_FogCoordfvEXT
;
1108 vfmt
->Indexf
= _tnl_Indexf
;
1109 vfmt
->Indexfv
= _tnl_Indexfv
;
1110 vfmt
->Materialfv
= _tnl_Materialfv
;
1111 vfmt
->MultiTexCoord1fARB
= _tnl_MultiTexCoord1f
;
1112 vfmt
->MultiTexCoord1fvARB
= _tnl_MultiTexCoord1fv
;
1113 vfmt
->MultiTexCoord2fARB
= _tnl_MultiTexCoord2f
;
1114 vfmt
->MultiTexCoord2fvARB
= _tnl_MultiTexCoord2fv
;
1115 vfmt
->MultiTexCoord3fARB
= _tnl_MultiTexCoord3f
;
1116 vfmt
->MultiTexCoord3fvARB
= _tnl_MultiTexCoord3fv
;
1117 vfmt
->MultiTexCoord4fARB
= _tnl_MultiTexCoord4f
;
1118 vfmt
->MultiTexCoord4fvARB
= _tnl_MultiTexCoord4fv
;
1119 vfmt
->Normal3f
= _tnl_Normal3f
;
1120 vfmt
->Normal3fv
= _tnl_Normal3fv
;
1121 vfmt
->SecondaryColor3fEXT
= _tnl_SecondaryColor3fEXT
;
1122 vfmt
->SecondaryColor3fvEXT
= _tnl_SecondaryColor3fvEXT
;
1123 vfmt
->TexCoord1f
= _tnl_TexCoord1f
;
1124 vfmt
->TexCoord1fv
= _tnl_TexCoord1fv
;
1125 vfmt
->TexCoord2f
= _tnl_TexCoord2f
;
1126 vfmt
->TexCoord2fv
= _tnl_TexCoord2fv
;
1127 vfmt
->TexCoord3f
= _tnl_TexCoord3f
;
1128 vfmt
->TexCoord3fv
= _tnl_TexCoord3fv
;
1129 vfmt
->TexCoord4f
= _tnl_TexCoord4f
;
1130 vfmt
->TexCoord4fv
= _tnl_TexCoord4fv
;
1131 vfmt
->Vertex2f
= _tnl_Vertex2f
;
1132 vfmt
->Vertex2fv
= _tnl_Vertex2fv
;
1133 vfmt
->Vertex3f
= _tnl_Vertex3f
;
1134 vfmt
->Vertex3fv
= _tnl_Vertex3fv
;
1135 vfmt
->Vertex4f
= _tnl_Vertex4f
;
1136 vfmt
->Vertex4fv
= _tnl_Vertex4fv
;
1137 vfmt
->VertexAttrib1fNV
= _tnl_VertexAttrib1fNV
;
1138 vfmt
->VertexAttrib1fvNV
= _tnl_VertexAttrib1fvNV
;
1139 vfmt
->VertexAttrib2fNV
= _tnl_VertexAttrib2fNV
;
1140 vfmt
->VertexAttrib2fvNV
= _tnl_VertexAttrib2fvNV
;
1141 vfmt
->VertexAttrib3fNV
= _tnl_VertexAttrib3fNV
;
1142 vfmt
->VertexAttrib3fvNV
= _tnl_VertexAttrib3fvNV
;
1143 vfmt
->VertexAttrib4fNV
= _tnl_VertexAttrib4fNV
;
1144 vfmt
->VertexAttrib4fvNV
= _tnl_VertexAttrib4fvNV
;
1146 vfmt
->Rectf
= _mesa_noop_Rectf
;
1147 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
1148 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
1153 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
1155 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1157 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
1160 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
1161 _tnl_flush_vtx( ctx
);
1165 _tnl_copy_to_current( ctx
);
1167 /* reset attrfv table
1170 flags
|= FLUSH_UPDATE_CURRENT
;
1173 ctx
->Driver
.NeedFlush
= 0;
1177 static void _tnl_current_init( GLcontext
*ctx
)
1179 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1182 /* setup the pointers for the typical 16 vertex attributes */
1183 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
1184 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
1186 /* setup pointers for the 12 material attributes */
1187 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
1188 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
1189 ctx
->Light
.Material
.Attrib
[i
];
1191 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
1195 void _tnl_vtx_init( GLcontext
*ctx
)
1197 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1198 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
1201 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
1202 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1204 _tnl_current_init( ctx
);
1205 _tnl_exec_vtxfmt_init( ctx
);
1207 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
1208 tnl
->vtx
.vertex_size
= 1; init_attrfv( tnl
);
1213 void _tnl_vtx_destroy( GLcontext
*ctx
)