Fixed MAXFIFO_S4. Removed WAIT_IDLE_EMPTY from savage_BCI_swap which resulted
[mesa.git] / src / mesa / tnl / t_vtx_api.c
1 /* $XFree86$ */
2 /**************************************************************************
3
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
5
6 All Rights Reserved.
7
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:
14
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
17 Software.
18
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.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell <keith@tungstengraphics.com>
32 */
33
34 #include "glheader.h"
35 #include "context.h"
36 #include "macros.h"
37 #include "vtxfmt.h"
38 #include "dlist.h"
39 #include "state.h"
40 #include "light.h"
41 #include "api_arrayelt.h"
42 #include "api_noop.h"
43 #include "t_vtx_api.h"
44
45
46 static void init_attrfv( TNLcontext *tnl );
47
48
49 /* Close off the last primitive, execute the buffer, restart the
50 * primitive.
51 */
52 static void _tnl_wrap_buffers( GLcontext *ctx )
53 {
54 TNLcontext *tnl = TNL_CONTEXT(ctx);
55
56
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;
61 }
62 else {
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;
65
66 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
67 GLint i = tnl->vtx.prim_count - 1;
68 assert(i >= 0);
69 tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter -
70 tnl->vtx.counter) -
71 tnl->vtx.prim[i].start);
72 }
73
74 /* Execute the buffer and save copied vertices.
75 */
76 if (tnl->vtx.counter != tnl->vtx.initial_counter)
77 _tnl_flush_vtx( ctx );
78 else {
79 tnl->vtx.prim_count = 0;
80 tnl->vtx.copied.nr = 0;
81 }
82
83 /* Emit a glBegin to start the new list.
84 */
85 assert(tnl->vtx.prim_count == 0);
86
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++;
92
93 if (tnl->vtx.copied.nr == last_count)
94 tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
95 }
96 }
97 }
98
99
100 /* Deal with buffer wrapping where provoked by the vertex buffer
101 * filling up, as opposed to upgrade_vertex().
102 */
103 static void _tnl_wrap_filled_vertex( GLcontext *ctx )
104 {
105 TNLcontext *tnl = TNL_CONTEXT(ctx);
106 GLfloat *data = tnl->vtx.copied.buffer;
107 GLuint i;
108
109 /* Run pipeline on current vertices, copy wrapped vertices
110 * to tnl->copied.
111 */
112 _tnl_wrap_buffers( ctx );
113
114 /* Copy stored stored vertices to start of new list.
115 */
116 assert(tnl->vtx.counter > tnl->vtx.copied.nr);
117
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;
123 tnl->vtx.counter--;
124 }
125
126 tnl->vtx.copied.nr = 0;
127 }
128
129
130 /*
131 * Copy the active vertex's values to the ctx->Current fields.
132 */
133 static void _tnl_copy_to_current( GLcontext *ctx )
134 {
135 TNLcontext *tnl = TNL_CONTEXT(ctx);
136 GLuint i;
137
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.
142 */
143 ASSIGN_4V( tnl->vtx.current[i], 0, 0, 0, 1 );
144 COPY_SZ_4V(tnl->vtx.current[i],
145 tnl->vtx.attrsz[i],
146 tnl->vtx.attrptr[i]);
147 }
148
149 /* Edgeflag requires special treatment:
150 */
151 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
152 ctx->Current.EdgeFlag =
153 (tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
154
155
156 /* Colormaterial -- this kindof sucks.
157 */
158 if (ctx->Light.ColorMaterialEnabled) {
159 _mesa_update_color_material(ctx, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
160 }
161
162 if (tnl->vtx.have_materials) {
163 tnl->Driver.NotifyMaterialChange( ctx );
164 }
165
166 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
167 }
168
169
170 static void _tnl_copy_from_current( GLcontext *ctx )
171 {
172 TNLcontext *tnl = TNL_CONTEXT(ctx);
173 GLint i;
174
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];
181 break;
182 }
183
184 /* Edgeflag requires special treatment:
185 */
186 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
187 tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
188 (GLfloat)ctx->Current.EdgeFlag;
189
190
191 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
192 }
193
194
195 /* Flush existing data, set new attrib size, replay copied vertices.
196 */
197 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
198 GLuint attr,
199 GLuint newsz )
200 {
201 TNLcontext *tnl = TNL_CONTEXT(ctx);
202 GLuint oldsz;
203 GLuint i;
204 GLfloat *tmp;
205 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
206
207
208 /* Run pipeline on current vertices, copy wrapped vertices
209 * to tnl->vtx.copied.
210 */
211 _tnl_wrap_buffers( ctx );
212
213
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.
217 */
218 _tnl_copy_to_current( ctx );
219
220
221 /* Heuristic: Attempt to isolate attributes received outside
222 * begin/end so that they don't bloat the vertices.
223 */
224 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
225 tnl->vtx.attrsz[attr] == 0
226 && lastcount > 8
227 ) {
228 init_attrfv( tnl );
229 }
230
231 /* Fix up sizes:
232 */
233 oldsz = tnl->vtx.attrsz[attr];
234 tnl->vtx.attrsz[attr] = newsz;
235
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;
241
242
243 /* Recalculate all the attrptr[] values
244 */
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];
249 }
250 else
251 tnl->vtx.attrptr[i] = 0; /* will not be dereferenced */
252 }
253
254 /* Copy from current to repopulate the vertex with correct values.
255 */
256 _tnl_copy_from_current( ctx );
257
258 /* Replay stored vertices to translate them
259 * to new format here.
260 *
261 * -- No need to replay - just copy piecewise
262 */
263 if (tnl->vtx.copied.nr)
264 {
265 GLfloat *data = tnl->vtx.copied.buffer;
266 GLfloat *dest = tnl->vtx.buffer;
267 GLuint j;
268
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]) {
272 if (j == attr) {
273 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
274 COPY_SZ_4V( dest, oldsz, data );
275 data += oldsz;
276 dest += newsz;
277 }
278 else {
279 GLuint sz = tnl->vtx.attrsz[j];
280 COPY_SZ_4V( dest, sz, data );
281 dest += sz;
282 data += sz;
283 }
284 }
285 }
286 }
287
288 tnl->vtx.vbptr = dest;
289 tnl->vtx.counter -= tnl->vtx.copied.nr;
290 tnl->vtx.copied.nr = 0;
291 }
292 }
293
294
295 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
296 {
297 TNLcontext *tnl = TNL_CONTEXT(ctx);
298 static const GLfloat id[4] = { 0, 0, 0, 1 };
299 int i;
300
301 if (tnl->vtx.attrsz[attr] < sz) {
302 /* New size is larger. Need to flush existing vertices and get
303 * an enlarged vertex format.
304 */
305 _tnl_wrap_upgrade_vertex( ctx, attr, sz );
306 }
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.
310 */
311 for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
312 tnl->vtx.attrptr[attr][i-1] = id[i-1];
313 }
314 }
315
316
317
318
319 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
320 * entrypoint is called for the first time.
321 */
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 *),
328 const GLfloat *v )
329 {
330 GET_CURRENT_CONTEXT( ctx );
331 TNLcontext *tnl = TNL_CONTEXT(ctx);
332
333 if (tnl->vtx.attrsz[attr] != sz)
334 _tnl_fixup_vertex( ctx, attr, sz );
335
336 /* Does this belong here? Necessitates resetting vtxfmt on each
337 * flush (otherwise flags won't get reset afterwards).
338 */
339 if (attr == 0)
340 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
341 else
342 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
343
344 /* Reset any active pointers for this attribute
345 */
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;
350
351 /* Update the secondary dispatch table with the new function
352 */
353 tnl->vtx.tabfv[attr][sz-1] = fallback_attr_func;
354
355 (*fallback_attr_func)(v);
356 }
357
358
359 /* Versions of all the entrypoints for situations where codegen isn't
360 * available.
361 *
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
367 * and Color3f.
368 */
369 #define ATTRFV( ATTR, N ) \
370 static void choose_##ATTR##_##N( const GLfloat *v ); \
371 \
372 static void attrib_##ATTR##_##N( const GLfloat *v ) \
373 { \
374 GET_CURRENT_CONTEXT( ctx ); \
375 TNLcontext *tnl = TNL_CONTEXT(ctx); \
376 \
377 if ((ATTR) == 0) { \
378 GLuint i; \
379 \
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]; \
384 \
385 for (i = N; i < tnl->vtx.vertex_size; i++) \
386 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
387 \
388 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
389 \
390 if (--tnl->vtx.counter == 0) \
391 _tnl_wrap_filled_vertex( ctx ); \
392 } \
393 else { \
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]; \
399 } \
400 }
401
402 #define CHOOSE( ATTR, N ) \
403 static void choose_##ATTR##_##N( const GLfloat *v ) \
404 { \
405 do_choose(ATTR, N, \
406 attrib_##ATTR##_##N, \
407 choose_##ATTR##_1, \
408 choose_##ATTR##_2, \
409 choose_##ATTR##_3, \
410 choose_##ATTR##_4, \
411 v ); \
412 }
413
414 #define INIT(ATTR) \
415 static void init_##ATTR( TNLcontext *tnl ) \
416 { \
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; \
421 }
422
423
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 ) \
433 INIT( ATTRIB ) \
434
435
436 /* Generate a lot of functions. These are the actual worker
437 * functions, which are equivalent to those generated via codegen
438 * elsewhere.
439 */
440 ATTRS( 0 )
441 ATTRS( 1 )
442 ATTRS( 2 )
443 ATTRS( 3 )
444 ATTRS( 4 )
445 ATTRS( 5 )
446 ATTRS( 6 )
447 ATTRS( 7 )
448 ATTRS( 8 )
449 ATTRS( 9 )
450 ATTRS( 10 )
451 ATTRS( 11 )
452 ATTRS( 12 )
453 ATTRS( 13 )
454 ATTRS( 14 )
455 ATTRS( 15 )
456
457
458 static void error_attrib( const GLfloat *unused )
459 {
460 GET_CURRENT_CONTEXT( ctx );
461 (void) unused;
462 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
463 }
464
465 static void init_error_attrib( TNLcontext *tnl )
466 {
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;
471 }
472
473
474
475 static void init_attrfv( TNLcontext *tnl )
476 {
477 if (tnl->vtx.vertex_size) {
478 GLuint i;
479
480 init_0( tnl );
481 init_1( tnl );
482 init_2( tnl );
483 init_3( tnl );
484 init_4( tnl );
485 init_5( tnl );
486 init_6( tnl );
487 init_7( tnl );
488 init_8( tnl );
489 init_9( tnl );
490 init_10( tnl );
491 init_11( tnl );
492 init_12( tnl );
493 init_13( tnl );
494 init_14( tnl );
495 init_15( tnl );
496 init_error_attrib( tnl );
497
498 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
499 tnl->vtx.attrsz[i] = 0;
500
501 tnl->vtx.vertex_size = 0;
502 tnl->vtx.have_materials = 0;
503 }
504 }
505
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.
509 */
510 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
511 do { \
512 GET_CURRENT_CONTEXT( ctx ); \
513 TNLcontext *tnl = TNL_CONTEXT(ctx); \
514 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
515 } while (0)
516
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 )
521
522 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
523
524 #define DISPATCH_ATTR2F( ATTR, S,T ) \
525 do { \
526 GLfloat v[2]; \
527 v[0] = S; v[1] = T; \
528 DISPATCH_ATTR2FV( ATTR, v ); \
529 } while (0)
530 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
531 do { \
532 GLfloat v[3]; \
533 v[0] = S; v[1] = T; v[2] = R; \
534 DISPATCH_ATTR3FV( ATTR, v ); \
535 } while (0)
536 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
537 do { \
538 GLfloat v[4]; \
539 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
540 DISPATCH_ATTR4FV( ATTR, v ); \
541 } while (0)
542
543
544 static void enum_error( void )
545 {
546 GET_CURRENT_CONTEXT( ctx );
547 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
548 }
549
550 static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y )
551 {
552 DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
553 }
554
555 static void GLAPIENTRY _tnl_Vertex2fv( const GLfloat *v )
556 {
557 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
558 }
559
560 static void GLAPIENTRY _tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
561 {
562 DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
563 }
564
565 static void GLAPIENTRY _tnl_Vertex3fv( const GLfloat *v )
566 {
567 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
568 }
569
570 static void GLAPIENTRY _tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z,
571 GLfloat w )
572 {
573 DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
574 }
575
576 static void GLAPIENTRY _tnl_Vertex4fv( const GLfloat *v )
577 {
578 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
579 }
580
581 static void GLAPIENTRY _tnl_TexCoord1f( GLfloat x )
582 {
583 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
584 }
585
586 static void GLAPIENTRY _tnl_TexCoord1fv( const GLfloat *v )
587 {
588 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
589 }
590
591 static void GLAPIENTRY _tnl_TexCoord2f( GLfloat x, GLfloat y )
592 {
593 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
594 }
595
596 static void GLAPIENTRY _tnl_TexCoord2fv( const GLfloat *v )
597 {
598 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
599 }
600
601 static void GLAPIENTRY _tnl_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
602 {
603 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
604 }
605
606 static void GLAPIENTRY _tnl_TexCoord3fv( const GLfloat *v )
607 {
608 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
609 }
610
611 static void GLAPIENTRY _tnl_TexCoord4f( GLfloat x, GLfloat y, GLfloat z,
612 GLfloat w )
613 {
614 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
615 }
616
617 static void GLAPIENTRY _tnl_TexCoord4fv( const GLfloat *v )
618 {
619 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
620 }
621
622 static void GLAPIENTRY _tnl_Normal3f( GLfloat x, GLfloat y, GLfloat z )
623 {
624 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
625 }
626
627 static void GLAPIENTRY _tnl_Normal3fv( const GLfloat *v )
628 {
629 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
630 }
631
632 static void GLAPIENTRY _tnl_FogCoordfEXT( GLfloat x )
633 {
634 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
635 }
636
637 static void GLAPIENTRY _tnl_FogCoordfvEXT( const GLfloat *v )
638 {
639 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
640 }
641
642 static void GLAPIENTRY _tnl_Color3f( GLfloat x, GLfloat y, GLfloat z )
643 {
644 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
645 }
646
647 static void GLAPIENTRY _tnl_Color3fv( const GLfloat *v )
648 {
649 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
650 }
651
652 static void GLAPIENTRY _tnl_Color4f( GLfloat x, GLfloat y, GLfloat z,
653 GLfloat w )
654 {
655 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
656 }
657
658 static void GLAPIENTRY _tnl_Color4fv( const GLfloat *v )
659 {
660 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
661 }
662
663 static void GLAPIENTRY _tnl_SecondaryColor3fEXT( GLfloat x, GLfloat y,
664 GLfloat z )
665 {
666 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
667 }
668
669 static void GLAPIENTRY _tnl_SecondaryColor3fvEXT( const GLfloat *v )
670 {
671 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
672 }
673
674 static void GLAPIENTRY _tnl_MultiTexCoord1f( GLenum target, GLfloat x )
675 {
676 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
677 DISPATCH_ATTR1F( attr, x );
678 }
679
680 static void GLAPIENTRY _tnl_MultiTexCoord1fv( GLenum target,
681 const GLfloat *v )
682 {
683 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
684 DISPATCH_ATTR1FV( attr, v );
685 }
686
687 static void GLAPIENTRY _tnl_MultiTexCoord2f( GLenum target, GLfloat x,
688 GLfloat y )
689 {
690 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
691 DISPATCH_ATTR2F( attr, x, y );
692 }
693
694 static void GLAPIENTRY _tnl_MultiTexCoord2fv( GLenum target,
695 const GLfloat *v )
696 {
697 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
698 DISPATCH_ATTR2FV( attr, v );
699 }
700
701 static void GLAPIENTRY _tnl_MultiTexCoord3f( GLenum target, GLfloat x,
702 GLfloat y, GLfloat z)
703 {
704 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
705 DISPATCH_ATTR3F( attr, x, y, z );
706 }
707
708 static void GLAPIENTRY _tnl_MultiTexCoord3fv( GLenum target,
709 const GLfloat *v )
710 {
711 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
712 DISPATCH_ATTR3FV( attr, v );
713 }
714
715 static void GLAPIENTRY _tnl_MultiTexCoord4f( GLenum target, GLfloat x,
716 GLfloat y, GLfloat z,
717 GLfloat w )
718 {
719 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
720 DISPATCH_ATTR4F( attr, x, y, z, w );
721 }
722
723 static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target,
724 const GLfloat *v )
725 {
726 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
727 DISPATCH_ATTR4FV( attr, v );
728 }
729
730 static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x )
731 {
732 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
733 DISPATCH_ATTR1F( index, x );
734 }
735
736 static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index,
737 const GLfloat *v )
738 {
739 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
740 DISPATCH_ATTR1FV( index, v );
741 }
742
743 static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x,
744 GLfloat y )
745 {
746 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
747 DISPATCH_ATTR2F( index, x, y );
748 }
749
750 static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index,
751 const GLfloat *v )
752 {
753 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
754 DISPATCH_ATTR2FV( index, v );
755 }
756
757 static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x,
758 GLfloat y, GLfloat z )
759 {
760 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
761 DISPATCH_ATTR3F( index, x, y, z );
762 }
763
764 static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index,
765 const GLfloat *v )
766 {
767 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
768 DISPATCH_ATTR3FV( index, v );
769 }
770
771 static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x,
772 GLfloat y, GLfloat z,
773 GLfloat w )
774 {
775 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
776 DISPATCH_ATTR4F( index, x, y, z, w );
777 }
778
779 static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index,
780 const GLfloat *v )
781 {
782 if (index >= VERT_ATTRIB_MAX) index = ERROR_ATTRIB;
783 DISPATCH_ATTR4FV( index, v );
784 }
785
786
787 /* Materials:
788 *
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.
792 *
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.
797 *
798 * There is no aliasing of material attributes with other entrypoints.
799 */
800 #define MAT_ATTR( A, N, params ) \
801 do { \
802 if (tnl->vtx.attrsz[A] != N) { \
803 _tnl_fixup_vertex( ctx, A, N ); \
804 tnl->vtx.have_materials = GL_TRUE; \
805 } \
806 \
807 { \
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; \
814 } \
815 } while (0)
816
817
818 #define MAT( ATTR, N, face, params ) \
819 do { \
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 */ \
824 } while (0)
825
826
827 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
828 * later on - in the meantime just store everything.
829 */
830 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
831 const GLfloat *params )
832 {
833 GET_CURRENT_CONTEXT( ctx );
834 TNLcontext *tnl = TNL_CONTEXT(ctx);
835
836 switch (face) {
837 case GL_FRONT:
838 case GL_BACK:
839 case GL_FRONT_AND_BACK:
840 break;
841
842 default:
843 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
844 return;
845 }
846
847 switch (pname) {
848 case GL_EMISSION:
849 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
850 break;
851 case GL_AMBIENT:
852 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
853 break;
854 case GL_DIFFUSE:
855 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
856 break;
857 case GL_SPECULAR:
858 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
859 break;
860 case GL_SHININESS:
861 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
862 break;
863 case GL_COLOR_INDEXES:
864 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
865 break;
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 );
869 break;
870 default:
871 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
872 return;
873 }
874 }
875
876
877 #define IDX_ATTR( A, IDX ) \
878 do { \
879 GET_CURRENT_CONTEXT( ctx ); \
880 TNLcontext *tnl = TNL_CONTEXT(ctx); \
881 \
882 if (tnl->vtx.attrsz[A] != 1) { \
883 _tnl_fixup_vertex( ctx, A, 1 ); \
884 } \
885 \
886 { \
887 GLfloat *dest = tnl->vtx.attrptr[A]; \
888 dest[0] = IDX; \
889 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
890 } \
891 } while (0)
892
893
894 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
895 {
896 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
897 }
898
899 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
900 {
901 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)v[0] );
902 }
903
904 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
905 {
906 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
907 }
908
909 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
910 {
911 IDX_ATTR( _TNL_ATTRIB_INDEX, v[0] );
912 }
913
914 /* Eval
915 */
916 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
917 {
918 GET_CURRENT_CONTEXT( ctx );
919 TNLcontext *tnl = TNL_CONTEXT(ctx);
920
921 /* TODO: use a CHOOSE() function for this: */
922 {
923 GLint i;
924 if (tnl->vtx.eval.new_state)
925 _tnl_update_eval( ctx );
926
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 );
931 }
932 }
933
934
935 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
936 tnl->vtx.vertex_size * sizeof(GLfloat));
937
938 _tnl_do_EvalCoord1f( ctx, u );
939
940 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
941 tnl->vtx.vertex_size * sizeof(GLfloat));
942 }
943
944 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
945 {
946 GET_CURRENT_CONTEXT( ctx );
947 TNLcontext *tnl = TNL_CONTEXT(ctx);
948
949 /* TODO: use a CHOOSE() function for this: */
950 {
951 GLint i;
952 if (tnl->vtx.eval.new_state)
953 _tnl_update_eval( ctx );
954
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 );
959 }
960
961 if (ctx->Eval.AutoNormal)
962 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] < 3)
963 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
964 }
965
966 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
967 tnl->vtx.vertex_size * sizeof(GLfloat));
968
969 _tnl_do_EvalCoord2f( ctx, u, v );
970
971 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
972 tnl->vtx.vertex_size * sizeof(GLfloat));
973 }
974
975 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
976 {
977 _tnl_EvalCoord1f( u[0] );
978 }
979
980 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
981 {
982 _tnl_EvalCoord2f( u[0], u[1] );
983 }
984
985 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
986 {
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;
991
992 _tnl_EvalCoord1f( u );
993 }
994
995
996 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
997 {
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;
1005
1006 _tnl_EvalCoord2f( u, v );
1007 }
1008
1009
1010 /* Build a list of primitives on the fly. Keep
1011 * ctx->Driver.CurrentExecPrimitive uptodate as well.
1012 */
1013 static void GLAPIENTRY _tnl_Begin( GLenum mode )
1014 {
1015 GET_CURRENT_CONTEXT( ctx );
1016
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)");
1023 return;
1024 }
1025
1026 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
1027 TNLcontext *tnl = TNL_CONTEXT(ctx);
1028 int i;
1029
1030 if (ctx->NewState) {
1031 _mesa_update_state( ctx );
1032 if (!(tnl->Driver.NotifyBegin && tnl->Driver.NotifyBegin( ctx, mode )))
1033 ctx->Exec->Begin(mode);
1034 return;
1035 }
1036
1037 /* Heuristic: attempt to isolate attributes occuring outside
1038 * begin/end pairs.
1039 */
1040 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
1041 _tnl_FlushVertices( ctx, ~0 );
1042
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;
1047
1048 ctx->Driver.CurrentExecPrimitive = mode;
1049 }
1050 else
1051 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
1052
1053 }
1054
1055 static void GLAPIENTRY _tnl_End( void )
1056 {
1057 GET_CURRENT_CONTEXT( ctx );
1058
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;
1063
1064 tnl->vtx.prim[i].mode |= PRIM_END;
1065 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
1066
1067 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
1068
1069 /* Two choices which effect the way vertex attributes are
1070 * carried over (or not) between adjacent primitives.
1071 */
1072 #if 0
1073 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1074 _tnl_FlushVertices( ctx, ~0 );
1075 #else
1076 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1077 _tnl_flush_vtx( ctx );
1078 #endif
1079
1080 }
1081 else
1082 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
1083 }
1084
1085
1086 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
1087 {
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;
1145
1146 vfmt->Rectf = _mesa_noop_Rectf;
1147 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
1148 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
1149 }
1150
1151
1152
1153 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
1154 {
1155 TNLcontext *tnl = TNL_CONTEXT(ctx);
1156
1157 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
1158 return;
1159
1160 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
1161 _tnl_flush_vtx( ctx );
1162 }
1163
1164 {
1165 _tnl_copy_to_current( ctx );
1166
1167 /* reset attrfv table
1168 */
1169 init_attrfv( tnl );
1170 flags |= FLUSH_UPDATE_CURRENT;
1171 }
1172
1173 ctx->Driver.NeedFlush = 0;
1174 }
1175
1176
1177 static void _tnl_current_init( GLcontext *ctx )
1178 {
1179 TNLcontext *tnl = TNL_CONTEXT(ctx);
1180 GLint i;
1181
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];
1185
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];
1190
1191 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
1192 }
1193
1194
1195 void _tnl_vtx_init( GLcontext *ctx )
1196 {
1197 TNLcontext *tnl = TNL_CONTEXT(ctx);
1198 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
1199 GLuint i;
1200
1201 for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
1202 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
1203
1204 _tnl_current_init( ctx );
1205 _tnl_exec_vtxfmt_init( ctx );
1206
1207 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
1208 tnl->vtx.vertex_size = 1; init_attrfv( tnl );
1209 }
1210
1211
1212
1213 void _tnl_vtx_destroy( GLcontext *ctx )
1214 {
1215 }
1216