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 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;
110 static void _tnl_copy_to_current( GLcontext
*ctx
)
112 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
115 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
116 if (tnl
->vtx
.attrsz
[i
]) {
117 ASSIGN_4V( tnl
->vtx
.current
[i
], 0, 0, 0, 1 );
118 COPY_SZ_4V(tnl
->vtx
.current
[i
],
120 tnl
->vtx
.attrptr
[i
]);
123 /* Edgeflag requires special treatment:
125 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
126 ctx
->Current
.EdgeFlag
=
127 (tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] == 1.0);
130 /* Colormaterial -- this kindof sucks.
132 if (ctx
->Light
.ColorMaterialEnabled
) {
133 _mesa_update_color_material(ctx
, ctx
->Current
.Attrib
[VERT_ATTRIB_COLOR0
]);
136 if (tnl
->vtx
.have_materials
) {
137 tnl
->Driver
.NotifyMaterialChange( ctx
);
140 ctx
->Driver
.NeedFlush
&= ~FLUSH_UPDATE_CURRENT
;
144 static void _tnl_copy_from_current( GLcontext
*ctx
)
146 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
149 for (i
= _TNL_ATTRIB_POS
+1 ; i
<= _TNL_ATTRIB_INDEX
; i
++)
150 switch (tnl
->vtx
.attrsz
[i
]) {
151 case 4: tnl
->vtx
.attrptr
[i
][3] = tnl
->vtx
.current
[i
][3];
152 case 3: tnl
->vtx
.attrptr
[i
][2] = tnl
->vtx
.current
[i
][2];
153 case 2: tnl
->vtx
.attrptr
[i
][1] = tnl
->vtx
.current
[i
][1];
154 case 1: tnl
->vtx
.attrptr
[i
][0] = tnl
->vtx
.current
[i
][0];
158 /* Edgeflag requires special treatment:
160 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_EDGEFLAG
])
161 tnl
->vtx
.attrptr
[_TNL_ATTRIB_EDGEFLAG
][0] =
162 (GLfloat
)ctx
->Current
.EdgeFlag
;
165 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
172 /* Flush existing data, set new attrib size, replay copied vertices.
174 static void _tnl_wrap_upgrade_vertex( GLcontext
*ctx
,
178 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
182 GLint lastcount
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
185 /* Run pipeline on current vertices, copy wrapped vertices
186 * to tnl->vtx.copied.
188 _tnl_wrap_buffers( ctx
);
190 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
191 * when the attribute already exists in the vertex and is having
192 * its size increased.
194 _tnl_copy_to_current( ctx
);
197 /* Heuristic: Attempt to isolate attributes received outside
198 * begin/end so that they don't bloat the vertices.
200 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
&&
201 tnl
->vtx
.attrsz
[attr
] == 0
209 oldsz
= tnl
->vtx
.attrsz
[attr
];
210 tnl
->vtx
.attrsz
[attr
] = newsz
;
212 tnl
->vtx
.vertex_size
+= newsz
- oldsz
;
213 tnl
->vtx
.counter
= MIN2( VERT_BUFFER_SIZE
/ tnl
->vtx
.vertex_size
,
214 ctx
->Const
.MaxArrayLockSize
);
215 tnl
->vtx
.initial_counter
= tnl
->vtx
.counter
;
216 tnl
->vtx
.vbptr
= tnl
->vtx
.buffer
;
219 /* Recalculate all the attrptr[] values
221 for (i
= 0, tmp
= tnl
->vtx
.vertex
; i
< _TNL_ATTRIB_MAX
; i
++) {
222 if (tnl
->vtx
.attrsz
[i
]) {
223 tnl
->vtx
.attrptr
[i
] = tmp
;
224 tmp
+= tnl
->vtx
.attrsz
[i
];
227 tnl
->vtx
.attrptr
[i
] = 0; /* will not be dereferenced */
230 /* Copy from current to repopulate the vertex with correct values.
232 _tnl_copy_from_current( ctx
);
234 /* Replay stored vertices to translate them
235 * to new format here.
237 * -- No need to replay - just copy piecewise
239 if (tnl
->vtx
.copied
.nr
)
241 GLfloat
*data
= tnl
->vtx
.copied
.buffer
;
242 GLfloat
*dest
= tnl
->vtx
.buffer
;
245 for (i
= 0 ; i
< tnl
->vtx
.copied
.nr
; i
++) {
246 for (j
= 0 ; j
< _TNL_ATTRIB_MAX
; j
++) {
247 if (tnl
->vtx
.attrsz
[j
]) {
249 COPY_SZ_4V( dest
, newsz
, tnl
->vtx
.current
[j
] );
250 COPY_SZ_4V( dest
, oldsz
, data
);
255 GLuint sz
= tnl
->vtx
.attrsz
[j
];
256 COPY_SZ_4V( dest
, sz
, data
);
264 tnl
->vtx
.vbptr
= dest
;
265 tnl
->vtx
.counter
-= tnl
->vtx
.copied
.nr
;
266 tnl
->vtx
.copied
.nr
= 0;
271 static void _tnl_fixup_vertex( GLcontext
*ctx
, GLuint attr
, GLuint sz
)
273 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
274 static float id
[4] = { 0, 0, 0, 1 };
277 if (tnl
->vtx
.attrsz
[attr
] < sz
) {
278 /* New size is larger. Need to flush existing vertices and get
279 * an enlarged vertex format.
281 _tnl_wrap_upgrade_vertex( ctx
, attr
, sz
);
283 else if (tnl
->vtx
.attrsz
[attr
] > sz
) {
284 /* New size is smaller - just need to fill in some
285 * zeros. Don't need to flush or wrap.
287 for (i
= sz
; i
<= tnl
->vtx
.attrsz
[attr
] ; i
++)
288 tnl
->vtx
.attrptr
[attr
][i
-1] = id
[i
-1];
295 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
296 * entrypoint is called for the first time.
298 static void do_choose( GLuint attr
, GLuint sz
,
299 void (*fallback_attr_func
)( const GLfloat
*),
300 void (*choose1
)( const GLfloat
*),
301 void (*choose2
)( const GLfloat
*),
302 void (*choose3
)( const GLfloat
*),
303 void (*choose4
)( const GLfloat
*),
306 GET_CURRENT_CONTEXT( ctx
);
307 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
309 if (tnl
->vtx
.attrsz
[attr
] != sz
)
310 _tnl_fixup_vertex( ctx
, attr
, sz
);
312 /* Does this belong here? Necessitates resetting vtxfmt on each
313 * flush (otherwise flags won't get reset afterwards).
316 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
318 ctx
->Driver
.NeedFlush
|= FLUSH_UPDATE_CURRENT
;
320 /* Reset any active pointers for this attribute
322 tnl
->vtx
.tabfv
[attr
][0] = choose1
;
323 tnl
->vtx
.tabfv
[attr
][1] = choose2
;
324 tnl
->vtx
.tabfv
[attr
][2] = choose3
;
325 tnl
->vtx
.tabfv
[attr
][3] = choose4
;
327 /* Update the secondary dispatch table with the new function
329 tnl
->vtx
.tabfv
[attr
][sz
-1] = fallback_attr_func
;
331 (*fallback_attr_func
)(v
);
335 /* Versions of all the entrypoints for situations where codegen isn't
338 * Note: Only one size for each attribute may be active at once.
339 * Eg. if Color3f is installed/active, then Color4f may not be, even
340 * if the vertex actually contains 4 color coordinates. This is
341 * because the 3f version won't otherwise set color[3] to 1.0 -- this
342 * is the job of the chooser function when switching between Color4f
345 #define ATTRFV( ATTR, N ) \
346 static void choose_##ATTR##_##N( const GLfloat *v ); \
348 static void attrib_##ATTR##_##N( const GLfloat *v ) \
350 GET_CURRENT_CONTEXT( ctx ); \
351 TNLcontext *tnl = TNL_CONTEXT(ctx); \
356 if (N>0) tnl->vtx.vbptr[0] = v[0]; \
357 if (N>1) tnl->vtx.vbptr[1] = v[1]; \
358 if (N>2) tnl->vtx.vbptr[2] = v[2]; \
359 if (N>3) tnl->vtx.vbptr[3] = v[3]; \
361 for (i = N; i < tnl->vtx.vertex_size; i++) \
362 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
364 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
366 if (--tnl->vtx.counter == 0) \
367 _tnl_wrap_filled_vertex( ctx ); \
370 GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
371 if (N>0) dest[0] = v[0]; \
372 if (N>1) dest[1] = v[1]; \
373 if (N>2) dest[2] = v[2]; \
374 if (N>3) dest[3] = v[3]; \
378 #define CHOOSE( ATTR, N ) \
379 static void choose_##ATTR##_##N( const GLfloat *v ) \
382 attrib_##ATTR##_##N, \
391 static void init_##ATTR( TNLcontext *tnl ) \
393 tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1; \
394 tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2; \
395 tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3; \
396 tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4; \
400 #define ATTRS( ATTRIB ) \
401 ATTRFV( ATTRIB, 1 ) \
402 ATTRFV( ATTRIB, 2 ) \
403 ATTRFV( ATTRIB, 3 ) \
404 ATTRFV( ATTRIB, 4 ) \
405 CHOOSE( ATTRIB, 1 ) \
406 CHOOSE( ATTRIB, 2 ) \
407 CHOOSE( ATTRIB, 3 ) \
408 CHOOSE( ATTRIB, 4 ) \
412 /* Generate a lot of functions. These are the actual worker
413 * functions, which are equivalent to those generated via codegen
433 static void init_attrfv( TNLcontext
*tnl
)
435 if (tnl
->vtx
.vertex_size
) {
455 for (i
= 0 ; i
< _TNL_ATTRIB_MAX
; i
++)
456 tnl
->vtx
.attrsz
[i
] = 0;
458 tnl
->vtx
.vertex_size
= 0;
459 tnl
->vtx
.have_materials
= 0;
463 /* These can be made efficient with codegen. Further, by adding more
464 * logic to do_choose(), the double-dispatch for legacy entrypoints
465 * like glVertex3f() can be removed.
467 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
469 GET_CURRENT_CONTEXT( ctx ); \
470 TNLcontext *tnl = TNL_CONTEXT(ctx); \
471 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
474 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
475 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
476 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
477 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
479 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
481 #define DISPATCH_ATTR2F( ATTR, S,T ) \
484 v[0] = S; v[1] = T; \
485 DISPATCH_ATTR2FV( ATTR, v ); \
487 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
490 v[0] = S; v[1] = T; v[2] = R; \
491 DISPATCH_ATTR3FV( ATTR, v ); \
493 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
496 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
497 DISPATCH_ATTR4FV( ATTR, v ); \
501 static void enum_error( void )
503 GET_CURRENT_CONTEXT( ctx
);
504 _mesa_error( ctx
, GL_INVALID_ENUM
, "glVertexAttrib" );
507 static void GLAPIENTRY
_tnl_Vertex2f( GLfloat x
, GLfloat y
)
509 DISPATCH_ATTR2F( _TNL_ATTRIB_POS
, x
, y
);
512 static void GLAPIENTRY
_tnl_Vertex2fv( const GLfloat
*v
)
514 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS
, v
);
517 static void GLAPIENTRY
_tnl_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
519 DISPATCH_ATTR3F( _TNL_ATTRIB_POS
, x
, y
, z
);
522 static void GLAPIENTRY
_tnl_Vertex3fv( const GLfloat
*v
)
524 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS
, v
);
527 static void GLAPIENTRY
_tnl_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
529 DISPATCH_ATTR4F( _TNL_ATTRIB_POS
, x
, y
, z
, w
);
532 static void GLAPIENTRY
_tnl_Vertex4fv( const GLfloat
*v
)
534 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS
, v
);
537 static void GLAPIENTRY
_tnl_TexCoord1f( GLfloat x
)
539 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0
, x
);
542 static void GLAPIENTRY
_tnl_TexCoord1fv( const GLfloat
*v
)
544 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0
, v
);
547 static void GLAPIENTRY
_tnl_TexCoord2f( GLfloat x
, GLfloat y
)
549 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0
, x
, y
);
552 static void GLAPIENTRY
_tnl_TexCoord2fv( const GLfloat
*v
)
554 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0
, v
);
557 static void GLAPIENTRY
_tnl_TexCoord3f( GLfloat x
, GLfloat y
, GLfloat z
)
559 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0
, x
, y
, z
);
562 static void GLAPIENTRY
_tnl_TexCoord3fv( const GLfloat
*v
)
564 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0
, v
);
567 static void GLAPIENTRY
_tnl_TexCoord4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
569 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0
, x
, y
, z
, w
);
572 static void GLAPIENTRY
_tnl_TexCoord4fv( const GLfloat
*v
)
574 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0
, v
);
577 static void GLAPIENTRY
_tnl_Normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
579 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL
, x
, y
, z
);
582 static void GLAPIENTRY
_tnl_Normal3fv( const GLfloat
*v
)
584 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL
, v
);
587 static void GLAPIENTRY
_tnl_FogCoordfEXT( GLfloat x
)
589 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG
, x
);
592 static void GLAPIENTRY
_tnl_FogCoordfvEXT( const GLfloat
*v
)
594 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG
, v
);
597 static void GLAPIENTRY
_tnl_Color3f( GLfloat x
, GLfloat y
, GLfloat z
)
599 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0
, x
, y
, z
);
602 static void GLAPIENTRY
_tnl_Color3fv( const GLfloat
*v
)
604 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0
, v
);
607 static void GLAPIENTRY
_tnl_Color4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
609 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0
, x
, y
, z
, w
);
612 static void GLAPIENTRY
_tnl_Color4fv( const GLfloat
*v
)
614 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0
, v
);
617 static void GLAPIENTRY
_tnl_SecondaryColor3fEXT( GLfloat x
, GLfloat y
, GLfloat z
)
619 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1
, x
, y
, z
);
622 static void GLAPIENTRY
_tnl_SecondaryColor3fvEXT( const GLfloat
*v
)
624 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1
, v
);
627 static void GLAPIENTRY
_tnl_MultiTexCoord1f( GLenum target
, GLfloat x
)
629 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
630 DISPATCH_ATTR1F( attr
, x
);
633 static void GLAPIENTRY
_tnl_MultiTexCoord1fv( GLenum target
, const GLfloat
*v
)
635 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
636 DISPATCH_ATTR1FV( attr
, v
);
639 static void GLAPIENTRY
_tnl_MultiTexCoord2f( GLenum target
, GLfloat x
, GLfloat y
)
641 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
642 DISPATCH_ATTR2F( attr
, x
, y
);
645 static void GLAPIENTRY
_tnl_MultiTexCoord2fv( GLenum target
, const GLfloat
*v
)
647 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
648 DISPATCH_ATTR2FV( attr
, v
);
651 static void GLAPIENTRY
_tnl_MultiTexCoord3f( GLenum target
, GLfloat x
, GLfloat y
,
654 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
655 DISPATCH_ATTR3F( attr
, x
, y
, z
);
658 static void GLAPIENTRY
_tnl_MultiTexCoord3fv( GLenum target
, const GLfloat
*v
)
660 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
661 DISPATCH_ATTR3FV( attr
, v
);
664 static void GLAPIENTRY
_tnl_MultiTexCoord4f( GLenum target
, GLfloat x
, GLfloat y
,
665 GLfloat z
, GLfloat w
)
667 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
668 DISPATCH_ATTR4F( attr
, x
, y
, z
, w
);
671 static void GLAPIENTRY
_tnl_MultiTexCoord4fv( GLenum target
, const GLfloat
*v
)
673 GLuint attr
= (target
& 0x7) + _TNL_ATTRIB_TEX0
;
674 DISPATCH_ATTR4FV( attr
, v
);
677 static void GLAPIENTRY
_tnl_VertexAttrib1fNV( GLuint index
, GLfloat x
)
679 if (index
< VERT_ATTRIB_MAX
)
680 DISPATCH_ATTR1F( index
, x
);
685 static void GLAPIENTRY
_tnl_VertexAttrib1fvNV( GLuint index
, const GLfloat
*v
)
687 if (index
< VERT_ATTRIB_MAX
)
688 DISPATCH_ATTR1FV( index
, v
);
693 static void GLAPIENTRY
_tnl_VertexAttrib2fNV( GLuint index
, GLfloat x
, GLfloat y
)
695 if (index
< VERT_ATTRIB_MAX
)
696 DISPATCH_ATTR2F( index
, x
, y
);
701 static void GLAPIENTRY
_tnl_VertexAttrib2fvNV( GLuint index
, const GLfloat
*v
)
703 if (index
< VERT_ATTRIB_MAX
)
704 DISPATCH_ATTR2FV( index
, v
);
709 static void GLAPIENTRY
_tnl_VertexAttrib3fNV( GLuint index
, GLfloat x
, GLfloat y
,
712 if (index
< VERT_ATTRIB_MAX
)
713 DISPATCH_ATTR3F( index
, x
, y
, z
);
718 static void GLAPIENTRY
_tnl_VertexAttrib3fvNV( GLuint index
, const GLfloat
*v
)
720 if (index
< VERT_ATTRIB_MAX
)
721 DISPATCH_ATTR3FV( index
, v
);
726 static void GLAPIENTRY
_tnl_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
,
727 GLfloat z
, GLfloat w
)
729 if (index
< VERT_ATTRIB_MAX
)
730 DISPATCH_ATTR4F( index
, x
, y
, z
, w
);
735 static void GLAPIENTRY
_tnl_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
737 if (index
< VERT_ATTRIB_MAX
)
738 DISPATCH_ATTR4FV( index
, v
);
746 * These are treated as per-vertex attributes, at indices above where
747 * the NV_vertex_program leaves off. There are a lot of good things
748 * about treating materials this way.
750 * However: I don't want to double the number of generated functions
751 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
752 * ATTRF into this function, and dispense with codegen and
753 * second-level dispatch.
755 * There is no aliasing of material attributes with other entrypoints.
757 #define MAT_ATTR( A, N, params ) \
759 if (tnl->vtx.attrsz[A] != N) { \
760 _tnl_fixup_vertex( ctx, A, N ); \
761 tnl->vtx.have_materials = GL_TRUE; \
765 GLfloat *dest = tnl->vtx.attrptr[A]; \
766 if (N>0) dest[0] = params[0]; \
767 if (N>1) dest[1] = params[1]; \
768 if (N>2) dest[2] = params[2]; \
769 if (N>3) dest[3] = params[3]; \
770 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
775 #define MAT( ATTR, N, face, params ) \
777 if (face != GL_BACK) \
778 MAT_ATTR( ATTR, N, params ); /* front */ \
779 if (face != GL_FRONT) \
780 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
784 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
785 * later on - in the meantime just store everything.
787 static void GLAPIENTRY
_tnl_Materialfv( GLenum face
, GLenum pname
,
788 const GLfloat
*params
)
790 GET_CURRENT_CONTEXT( ctx
);
791 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
796 case GL_FRONT_AND_BACK
:
800 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
806 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION
, 4, face
, params
);
809 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
812 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
815 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR
, 4, face
, params
);
818 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS
, 1, face
, params
);
820 case GL_COLOR_INDEXES
:
821 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES
, 3, face
, params
);
823 case GL_AMBIENT_AND_DIFFUSE
:
824 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT
, 4, face
, params
);
825 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE
, 4, face
, params
);
828 _mesa_error( ctx
, GL_INVALID_ENUM
, "glMaterialfv" );
834 #define IDX_ATTR( A, IDX ) \
836 GET_CURRENT_CONTEXT( ctx ); \
837 TNLcontext *tnl = TNL_CONTEXT(ctx); \
839 if (tnl->vtx.attrsz[A] != 1) { \
840 _tnl_fixup_vertex( ctx, A, 1 ); \
844 GLfloat *dest = tnl->vtx.attrptr[A]; \
846 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
851 static void GLAPIENTRY
_tnl_EdgeFlag( GLboolean b
)
853 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)b
);
856 static void GLAPIENTRY
_tnl_EdgeFlagv( const GLboolean
*v
)
858 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG
, (GLfloat
)v
[0] );
861 static void GLAPIENTRY
_tnl_Indexf( GLfloat f
)
863 IDX_ATTR( _TNL_ATTRIB_INDEX
, f
);
866 static void GLAPIENTRY
_tnl_Indexfv( const GLfloat
*v
)
868 IDX_ATTR( _TNL_ATTRIB_INDEX
, v
[0] );
873 static void GLAPIENTRY
_tnl_EvalCoord1f( GLfloat u
)
875 GET_CURRENT_CONTEXT( ctx
);
876 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
878 /* TODO: use a CHOOSE() function for this: */
881 if (tnl
->vtx
.eval
.new_state
)
882 _tnl_update_eval( ctx
);
884 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
885 if (tnl
->vtx
.eval
.map1
[i
].map
)
886 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map1
[i
].sz
)
887 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map1
[i
].sz
);
892 memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
893 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
895 _tnl_do_EvalCoord1f( ctx
, u
);
897 memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
898 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
901 static void GLAPIENTRY
_tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
903 GET_CURRENT_CONTEXT( ctx
);
904 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
906 /* TODO: use a CHOOSE() function for this: */
909 if (tnl
->vtx
.eval
.new_state
)
910 _tnl_update_eval( ctx
);
912 for (i
= 0 ; i
<= _TNL_ATTRIB_INDEX
; i
++) {
913 if (tnl
->vtx
.eval
.map2
[i
].map
)
914 if (tnl
->vtx
.attrsz
[i
] < tnl
->vtx
.eval
.map2
[i
].sz
)
915 _tnl_fixup_vertex( ctx
, i
, tnl
->vtx
.eval
.map2
[i
].sz
);
918 if (ctx
->Eval
.AutoNormal
)
919 if (tnl
->vtx
.attrsz
[_TNL_ATTRIB_NORMAL
] < 3)
920 _tnl_fixup_vertex( ctx
, _TNL_ATTRIB_NORMAL
, 3 );
923 memcpy( tnl
->vtx
.copied
.buffer
, tnl
->vtx
.vertex
,
924 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
926 _tnl_do_EvalCoord2f( ctx
, u
, v
);
928 memcpy( tnl
->vtx
.vertex
, tnl
->vtx
.copied
.buffer
,
929 tnl
->vtx
.vertex_size
* sizeof(GLfloat
));
932 static void GLAPIENTRY
_tnl_EvalCoord1fv( const GLfloat
*u
)
934 _tnl_EvalCoord1f( u
[0] );
937 static void GLAPIENTRY
_tnl_EvalCoord2fv( const GLfloat
*u
)
939 _tnl_EvalCoord2f( u
[0], u
[1] );
942 static void GLAPIENTRY
_tnl_EvalPoint1( GLint i
)
944 GET_CURRENT_CONTEXT( ctx
);
945 GLfloat du
= ((ctx
->Eval
.MapGrid1u2
- ctx
->Eval
.MapGrid1u1
) /
946 (GLfloat
) ctx
->Eval
.MapGrid1un
);
947 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid1u1
;
949 _tnl_EvalCoord1f( u
);
953 static void GLAPIENTRY
_tnl_EvalPoint2( GLint i
, GLint j
)
955 GET_CURRENT_CONTEXT( ctx
);
956 GLfloat du
= ((ctx
->Eval
.MapGrid2u2
- ctx
->Eval
.MapGrid2u1
) /
957 (GLfloat
) ctx
->Eval
.MapGrid2un
);
958 GLfloat dv
= ((ctx
->Eval
.MapGrid2v2
- ctx
->Eval
.MapGrid2v1
) /
959 (GLfloat
) ctx
->Eval
.MapGrid2vn
);
960 GLfloat u
= i
* du
+ ctx
->Eval
.MapGrid2u1
;
961 GLfloat v
= j
* dv
+ ctx
->Eval
.MapGrid2v1
;
963 _tnl_EvalCoord2f( u
, v
);
967 /* Build a list of primitives on the fly. Keep
968 * ctx->Driver.CurrentExecPrimitive uptodate as well.
970 static void GLAPIENTRY
_tnl_Begin( GLenum mode
)
972 GET_CURRENT_CONTEXT( ctx
);
974 if (ctx
->Driver
.CurrentExecPrimitive
== GL_POLYGON
+1) {
975 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
979 _mesa_update_state( ctx
);
980 ctx
->Exec
->Begin(mode
);
984 /* Heuristic: attempt to isolate attributes occuring outside
987 if (tnl
->vtx
.vertex_size
&& !tnl
->vtx
.attrsz
[0])
988 _tnl_FlushVertices( ctx
, ~0 );
990 i
= tnl
->vtx
.prim_count
++;
991 tnl
->vtx
.prim
[i
].mode
= mode
| PRIM_BEGIN
;
992 tnl
->vtx
.prim
[i
].start
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
993 tnl
->vtx
.prim
[i
].count
= 0;
995 ctx
->Driver
.CurrentExecPrimitive
= mode
;
998 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glBegin" );
1002 static void GLAPIENTRY
_tnl_End( void )
1004 GET_CURRENT_CONTEXT( ctx
);
1006 if (ctx
->Driver
.CurrentExecPrimitive
!= GL_POLYGON
+1) {
1007 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1008 int idx
= tnl
->vtx
.initial_counter
- tnl
->vtx
.counter
;
1009 int i
= tnl
->vtx
.prim_count
- 1;
1011 tnl
->vtx
.prim
[i
].mode
|= PRIM_END
;
1012 tnl
->vtx
.prim
[i
].count
= idx
- tnl
->vtx
.prim
[i
].start
;
1014 ctx
->Driver
.CurrentExecPrimitive
= GL_POLYGON
+1;
1016 /* Two choices which effect the way vertex attributes are
1017 * carried over (or not) between adjacent primitives.
1020 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1021 _tnl_FlushVertices( ctx
, ~0 );
1023 if (tnl
->vtx
.prim_count
== TNL_MAX_PRIM
)
1024 _tnl_flush_vtx( ctx
);
1029 _mesa_error( ctx
, GL_INVALID_OPERATION
, "glEnd" );
1033 static void _tnl_exec_vtxfmt_init( GLcontext
*ctx
)
1035 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->exec_vtxfmt
);
1036 vfmt
->ArrayElement
= _ae_loopback_array_elt
; /* generic helper */
1037 vfmt
->Begin
= _tnl_Begin
;
1038 vfmt
->CallList
= _mesa_CallList
;
1039 vfmt
->CallLists
= _mesa_CallLists
;
1040 vfmt
->Color3f
= _tnl_Color3f
;
1041 vfmt
->Color3fv
= _tnl_Color3fv
;
1042 vfmt
->Color4f
= _tnl_Color4f
;
1043 vfmt
->Color4fv
= _tnl_Color4fv
;
1044 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
1045 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
1046 vfmt
->End
= _tnl_End
;
1047 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
1048 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
1049 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
1050 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
1051 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
1052 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
1053 vfmt
->FogCoordfEXT
= _tnl_FogCoordfEXT
;
1054 vfmt
->FogCoordfvEXT
= _tnl_FogCoordfvEXT
;
1055 vfmt
->Indexf
= _tnl_Indexf
;
1056 vfmt
->Indexfv
= _tnl_Indexfv
;
1057 vfmt
->Materialfv
= _tnl_Materialfv
;
1058 vfmt
->MultiTexCoord1fARB
= _tnl_MultiTexCoord1f
;
1059 vfmt
->MultiTexCoord1fvARB
= _tnl_MultiTexCoord1fv
;
1060 vfmt
->MultiTexCoord2fARB
= _tnl_MultiTexCoord2f
;
1061 vfmt
->MultiTexCoord2fvARB
= _tnl_MultiTexCoord2fv
;
1062 vfmt
->MultiTexCoord3fARB
= _tnl_MultiTexCoord3f
;
1063 vfmt
->MultiTexCoord3fvARB
= _tnl_MultiTexCoord3fv
;
1064 vfmt
->MultiTexCoord4fARB
= _tnl_MultiTexCoord4f
;
1065 vfmt
->MultiTexCoord4fvARB
= _tnl_MultiTexCoord4fv
;
1066 vfmt
->Normal3f
= _tnl_Normal3f
;
1067 vfmt
->Normal3fv
= _tnl_Normal3fv
;
1068 vfmt
->SecondaryColor3fEXT
= _tnl_SecondaryColor3fEXT
;
1069 vfmt
->SecondaryColor3fvEXT
= _tnl_SecondaryColor3fvEXT
;
1070 vfmt
->TexCoord1f
= _tnl_TexCoord1f
;
1071 vfmt
->TexCoord1fv
= _tnl_TexCoord1fv
;
1072 vfmt
->TexCoord2f
= _tnl_TexCoord2f
;
1073 vfmt
->TexCoord2fv
= _tnl_TexCoord2fv
;
1074 vfmt
->TexCoord3f
= _tnl_TexCoord3f
;
1075 vfmt
->TexCoord3fv
= _tnl_TexCoord3fv
;
1076 vfmt
->TexCoord4f
= _tnl_TexCoord4f
;
1077 vfmt
->TexCoord4fv
= _tnl_TexCoord4fv
;
1078 vfmt
->Vertex2f
= _tnl_Vertex2f
;
1079 vfmt
->Vertex2fv
= _tnl_Vertex2fv
;
1080 vfmt
->Vertex3f
= _tnl_Vertex3f
;
1081 vfmt
->Vertex3fv
= _tnl_Vertex3fv
;
1082 vfmt
->Vertex4f
= _tnl_Vertex4f
;
1083 vfmt
->Vertex4fv
= _tnl_Vertex4fv
;
1084 vfmt
->VertexAttrib1fNV
= _tnl_VertexAttrib1fNV
;
1085 vfmt
->VertexAttrib1fvNV
= _tnl_VertexAttrib1fvNV
;
1086 vfmt
->VertexAttrib2fNV
= _tnl_VertexAttrib2fNV
;
1087 vfmt
->VertexAttrib2fvNV
= _tnl_VertexAttrib2fvNV
;
1088 vfmt
->VertexAttrib3fNV
= _tnl_VertexAttrib3fNV
;
1089 vfmt
->VertexAttrib3fvNV
= _tnl_VertexAttrib3fvNV
;
1090 vfmt
->VertexAttrib4fNV
= _tnl_VertexAttrib4fNV
;
1091 vfmt
->VertexAttrib4fvNV
= _tnl_VertexAttrib4fvNV
;
1093 vfmt
->Rectf
= _mesa_noop_Rectf
;
1094 vfmt
->EvalMesh1
= _mesa_noop_EvalMesh1
;
1095 vfmt
->EvalMesh2
= _mesa_noop_EvalMesh2
;
1100 void _tnl_FlushVertices( GLcontext
*ctx
, GLuint flags
)
1102 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1104 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
)
1107 if (tnl
->vtx
.counter
!= tnl
->vtx
.initial_counter
) {
1108 _tnl_flush_vtx( ctx
);
1112 _tnl_copy_to_current( ctx
);
1114 /* reset attrfv table
1117 flags
|= FLUSH_UPDATE_CURRENT
;
1120 ctx
->Driver
.NeedFlush
= 0;
1123 static void _tnl_current_init( GLcontext
*ctx
)
1125 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1128 for (i
= 0; i
< VERT_ATTRIB_MAX
; i
++)
1129 tnl
->vtx
.current
[i
] = ctx
->Current
.Attrib
[i
];
1131 for (i
= 0; i
< MAT_ATTRIB_MAX
; i
++)
1132 tnl
->vtx
.current
[_TNL_ATTRIB_MAT_FRONT_AMBIENT
+ i
] =
1133 ctx
->Light
.Material
.Attrib
[i
];
1135 tnl
->vtx
.current
[_TNL_ATTRIB_INDEX
] = &ctx
->Current
.Index
;
1141 void _tnl_vtx_init( GLcontext
*ctx
)
1143 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1144 struct tnl_vertex_arrays
*tmp
= &tnl
->vtx_inputs
;
1147 for (i
= 0; i
< _TNL_ATTRIB_INDEX
; i
++)
1148 _mesa_vector4f_init( &tmp
->Attribs
[i
], 0, 0);
1150 _tnl_current_init( ctx
);
1151 _tnl_exec_vtxfmt_init( ctx
);
1153 _mesa_install_exec_vtxfmt( ctx
, &tnl
->exec_vtxfmt
);
1154 tnl
->vtx
.vertex_size
= 1; init_attrfv( tnl
);
1159 void _tnl_vtx_destroy( GLcontext
*ctx
)