Fix TCL_LIGHT_MODEL_CTL setting in radeonColorMaterial.
[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 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;
57
58 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
59 GLint i = tnl->vtx.prim_count - 1;
60 assert(i >= 0);
61 tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter - tnl->vtx.counter) -
62 tnl->vtx.prim[i].start);
63 }
64
65 /* Execute the buffer and save copied vertices.
66 */
67 _tnl_flush_vtx( ctx );
68
69 /* Emit a glBegin to start the new list.
70 */
71 assert(tnl->vtx.prim_count == 0);
72
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++;
78
79 if (tnl->vtx.copied.nr == last_count)
80 tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
81 }
82 }
83
84
85 static void _tnl_wrap_filled_vertex( GLcontext *ctx )
86 {
87 TNLcontext *tnl = TNL_CONTEXT(ctx);
88 GLfloat *data = tnl->vtx.copied.buffer;
89 GLuint i;
90
91 /* Run pipeline on current vertices, copy wrapped vertices
92 * to tnl->copied.
93 */
94 _tnl_wrap_buffers( ctx );
95
96 /* Copy stored stored vertices to start of new list.
97 */
98 assert(tnl->vtx.counter > tnl->vtx.copied.nr);
99
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;
104 tnl->vtx.counter--;
105 }
106
107 tnl->vtx.copied.nr = 0;
108 }
109
110 static void _tnl_copy_to_current( GLcontext *ctx )
111 {
112 TNLcontext *tnl = TNL_CONTEXT(ctx);
113 GLuint i;
114
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],
119 tnl->vtx.attrsz[i],
120 tnl->vtx.attrptr[i]);
121 }
122
123 /* Edgeflag requires special treatment:
124 */
125 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
126 ctx->Current.EdgeFlag =
127 (tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
128
129
130 /* Colormaterial -- this kindof sucks.
131 */
132 if (ctx->Light.ColorMaterialEnabled) {
133 _mesa_update_color_material(ctx, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
134 }
135
136 if (tnl->vtx.have_materials) {
137 tnl->Driver.NotifyMaterialChange( ctx );
138 }
139
140 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
141 }
142
143
144 static void _tnl_copy_from_current( GLcontext *ctx )
145 {
146 TNLcontext *tnl = TNL_CONTEXT(ctx);
147 GLint i;
148
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];
155 break;
156 }
157
158 /* Edgeflag requires special treatment:
159 */
160 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
161 tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
162 (GLfloat)ctx->Current.EdgeFlag;
163
164
165 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
166 }
167
168
169
170
171
172 /* Flush existing data, set new attrib size, replay copied vertices.
173 */
174 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
175 GLuint attr,
176 GLuint newsz )
177 {
178 TNLcontext *tnl = TNL_CONTEXT(ctx);
179 GLuint oldsz;
180 GLuint i;
181 GLfloat *tmp;
182 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
183
184
185 /* Run pipeline on current vertices, copy wrapped vertices
186 * to tnl->vtx.copied.
187 */
188 _tnl_wrap_buffers( ctx );
189
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.
193 */
194 _tnl_copy_to_current( ctx );
195
196
197 /* Heuristic: Attempt to isolate attributes received outside
198 * begin/end so that they don't bloat the vertices.
199 */
200 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
201 tnl->vtx.attrsz[attr] == 0
202 && lastcount > 8
203 ) {
204 init_attrfv( tnl );
205 }
206
207 /* Fix up sizes:
208 */
209 oldsz = tnl->vtx.attrsz[attr];
210 tnl->vtx.attrsz[attr] = newsz;
211
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;
217
218
219 /* Recalculate all the attrptr[] values
220 */
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];
225 }
226 else
227 tnl->vtx.attrptr[i] = 0; /* will not be dereferenced */
228 }
229
230 /* Copy from current to repopulate the vertex with correct values.
231 */
232 _tnl_copy_from_current( ctx );
233
234 /* Replay stored vertices to translate them
235 * to new format here.
236 *
237 * -- No need to replay - just copy piecewise
238 */
239 if (tnl->vtx.copied.nr)
240 {
241 GLfloat *data = tnl->vtx.copied.buffer;
242 GLfloat *dest = tnl->vtx.buffer;
243 GLuint j;
244
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]) {
248 if (j == attr) {
249 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
250 COPY_SZ_4V( dest, oldsz, data );
251 data += oldsz;
252 dest += newsz;
253 }
254 else {
255 GLuint sz = tnl->vtx.attrsz[j];
256 COPY_SZ_4V( dest, sz, data );
257 dest += sz;
258 data += sz;
259 }
260 }
261 }
262 }
263
264 tnl->vtx.vbptr = dest;
265 tnl->vtx.counter -= tnl->vtx.copied.nr;
266 tnl->vtx.copied.nr = 0;
267 }
268 }
269
270
271 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
272 {
273 TNLcontext *tnl = TNL_CONTEXT(ctx);
274 static float id[4] = { 0, 0, 0, 1 };
275 int i;
276
277 if (tnl->vtx.attrsz[attr] < sz) {
278 /* New size is larger. Need to flush existing vertices and get
279 * an enlarged vertex format.
280 */
281 _tnl_wrap_upgrade_vertex( ctx, attr, sz );
282 }
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.
286 */
287 for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
288 tnl->vtx.attrptr[attr][i-1] = id[i-1];
289 }
290 }
291
292
293
294
295 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
296 * entrypoint is called for the first time.
297 */
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 *),
304 const GLfloat *v )
305 {
306 GET_CURRENT_CONTEXT( ctx );
307 TNLcontext *tnl = TNL_CONTEXT(ctx);
308
309 if (tnl->vtx.attrsz[attr] != sz)
310 _tnl_fixup_vertex( ctx, attr, sz );
311
312 /* Does this belong here? Necessitates resetting vtxfmt on each
313 * flush (otherwise flags won't get reset afterwards).
314 */
315 if (attr == 0)
316 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
317 else
318 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
319
320 /* Reset any active pointers for this attribute
321 */
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;
326
327 /* Update the secondary dispatch table with the new function
328 */
329 tnl->vtx.tabfv[attr][sz-1] = fallback_attr_func;
330
331 (*fallback_attr_func)(v);
332 }
333
334
335 /* Versions of all the entrypoints for situations where codegen isn't
336 * available.
337 *
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
343 * and Color3f.
344 */
345 #define ATTRFV( ATTR, N ) \
346 static void choose_##ATTR##_##N( const GLfloat *v ); \
347 \
348 static void attrib_##ATTR##_##N( const GLfloat *v ) \
349 { \
350 GET_CURRENT_CONTEXT( ctx ); \
351 TNLcontext *tnl = TNL_CONTEXT(ctx); \
352 \
353 if ((ATTR) == 0) { \
354 GLuint i; \
355 \
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]; \
360 \
361 for (i = N; i < tnl->vtx.vertex_size; i++) \
362 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
363 \
364 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
365 \
366 if (--tnl->vtx.counter == 0) \
367 _tnl_wrap_filled_vertex( ctx ); \
368 } \
369 else { \
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]; \
375 } \
376 }
377
378 #define CHOOSE( ATTR, N ) \
379 static void choose_##ATTR##_##N( const GLfloat *v ) \
380 { \
381 do_choose(ATTR, N, \
382 attrib_##ATTR##_##N, \
383 choose_##ATTR##_1, \
384 choose_##ATTR##_2, \
385 choose_##ATTR##_3, \
386 choose_##ATTR##_4, \
387 v ); \
388 }
389
390 #define INIT(ATTR) \
391 static void init_##ATTR( TNLcontext *tnl ) \
392 { \
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; \
397 }
398
399
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 ) \
409 INIT( ATTRIB ) \
410
411
412 /* Generate a lot of functions. These are the actual worker
413 * functions, which are equivalent to those generated via codegen
414 * elsewhere.
415 */
416 ATTRS( 0 )
417 ATTRS( 1 )
418 ATTRS( 2 )
419 ATTRS( 3 )
420 ATTRS( 4 )
421 ATTRS( 5 )
422 ATTRS( 6 )
423 ATTRS( 7 )
424 ATTRS( 8 )
425 ATTRS( 9 )
426 ATTRS( 10 )
427 ATTRS( 11 )
428 ATTRS( 12 )
429 ATTRS( 13 )
430 ATTRS( 14 )
431 ATTRS( 15 )
432
433 static void init_attrfv( TNLcontext *tnl )
434 {
435 if (tnl->vtx.vertex_size) {
436 GLuint i;
437
438 init_0( tnl );
439 init_1( tnl );
440 init_2( tnl );
441 init_3( tnl );
442 init_4( tnl );
443 init_5( tnl );
444 init_6( tnl );
445 init_7( tnl );
446 init_8( tnl );
447 init_9( tnl );
448 init_10( tnl );
449 init_11( tnl );
450 init_12( tnl );
451 init_13( tnl );
452 init_14( tnl );
453 init_15( tnl );
454
455 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
456 tnl->vtx.attrsz[i] = 0;
457
458 tnl->vtx.vertex_size = 0;
459 tnl->vtx.have_materials = 0;
460 }
461 }
462
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.
466 */
467 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
468 do { \
469 GET_CURRENT_CONTEXT( ctx ); \
470 TNLcontext *tnl = TNL_CONTEXT(ctx); \
471 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
472 } while (0)
473
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 )
478
479 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
480
481 #define DISPATCH_ATTR2F( ATTR, S,T ) \
482 do { \
483 GLfloat v[2]; \
484 v[0] = S; v[1] = T; \
485 DISPATCH_ATTR2FV( ATTR, v ); \
486 } while (0)
487 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
488 do { \
489 GLfloat v[3]; \
490 v[0] = S; v[1] = T; v[2] = R; \
491 DISPATCH_ATTR3FV( ATTR, v ); \
492 } while (0)
493 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
494 do { \
495 GLfloat v[4]; \
496 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
497 DISPATCH_ATTR4FV( ATTR, v ); \
498 } while (0)
499
500
501 static void enum_error( void )
502 {
503 GET_CURRENT_CONTEXT( ctx );
504 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
505 }
506
507 static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y )
508 {
509 DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
510 }
511
512 static void GLAPIENTRY _tnl_Vertex2fv( const GLfloat *v )
513 {
514 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
515 }
516
517 static void GLAPIENTRY _tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
518 {
519 DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
520 }
521
522 static void GLAPIENTRY _tnl_Vertex3fv( const GLfloat *v )
523 {
524 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
525 }
526
527 static void GLAPIENTRY _tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
528 {
529 DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
530 }
531
532 static void GLAPIENTRY _tnl_Vertex4fv( const GLfloat *v )
533 {
534 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
535 }
536
537 static void GLAPIENTRY _tnl_TexCoord1f( GLfloat x )
538 {
539 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
540 }
541
542 static void GLAPIENTRY _tnl_TexCoord1fv( const GLfloat *v )
543 {
544 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
545 }
546
547 static void GLAPIENTRY _tnl_TexCoord2f( GLfloat x, GLfloat y )
548 {
549 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
550 }
551
552 static void GLAPIENTRY _tnl_TexCoord2fv( const GLfloat *v )
553 {
554 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
555 }
556
557 static void GLAPIENTRY _tnl_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
558 {
559 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
560 }
561
562 static void GLAPIENTRY _tnl_TexCoord3fv( const GLfloat *v )
563 {
564 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
565 }
566
567 static void GLAPIENTRY _tnl_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
568 {
569 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
570 }
571
572 static void GLAPIENTRY _tnl_TexCoord4fv( const GLfloat *v )
573 {
574 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
575 }
576
577 static void GLAPIENTRY _tnl_Normal3f( GLfloat x, GLfloat y, GLfloat z )
578 {
579 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
580 }
581
582 static void GLAPIENTRY _tnl_Normal3fv( const GLfloat *v )
583 {
584 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
585 }
586
587 static void GLAPIENTRY _tnl_FogCoordfEXT( GLfloat x )
588 {
589 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
590 }
591
592 static void GLAPIENTRY _tnl_FogCoordfvEXT( const GLfloat *v )
593 {
594 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
595 }
596
597 static void GLAPIENTRY _tnl_Color3f( GLfloat x, GLfloat y, GLfloat z )
598 {
599 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
600 }
601
602 static void GLAPIENTRY _tnl_Color3fv( const GLfloat *v )
603 {
604 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
605 }
606
607 static void GLAPIENTRY _tnl_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
608 {
609 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
610 }
611
612 static void GLAPIENTRY _tnl_Color4fv( const GLfloat *v )
613 {
614 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
615 }
616
617 static void GLAPIENTRY _tnl_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
618 {
619 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
620 }
621
622 static void GLAPIENTRY _tnl_SecondaryColor3fvEXT( const GLfloat *v )
623 {
624 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
625 }
626
627 static void GLAPIENTRY _tnl_MultiTexCoord1f( GLenum target, GLfloat x )
628 {
629 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
630 DISPATCH_ATTR1F( attr, x );
631 }
632
633 static void GLAPIENTRY _tnl_MultiTexCoord1fv( GLenum target, const GLfloat *v )
634 {
635 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
636 DISPATCH_ATTR1FV( attr, v );
637 }
638
639 static void GLAPIENTRY _tnl_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
640 {
641 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
642 DISPATCH_ATTR2F( attr, x, y );
643 }
644
645 static void GLAPIENTRY _tnl_MultiTexCoord2fv( GLenum target, const GLfloat *v )
646 {
647 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
648 DISPATCH_ATTR2FV( attr, v );
649 }
650
651 static void GLAPIENTRY _tnl_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
652 GLfloat z)
653 {
654 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
655 DISPATCH_ATTR3F( attr, x, y, z );
656 }
657
658 static void GLAPIENTRY _tnl_MultiTexCoord3fv( GLenum target, const GLfloat *v )
659 {
660 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
661 DISPATCH_ATTR3FV( attr, v );
662 }
663
664 static void GLAPIENTRY _tnl_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
665 GLfloat z, GLfloat w )
666 {
667 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
668 DISPATCH_ATTR4F( attr, x, y, z, w );
669 }
670
671 static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target, const GLfloat *v )
672 {
673 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
674 DISPATCH_ATTR4FV( attr, v );
675 }
676
677 static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x )
678 {
679 if (index < VERT_ATTRIB_MAX)
680 DISPATCH_ATTR1F( index, x );
681 else
682 enum_error();
683 }
684
685 static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
686 {
687 if (index < VERT_ATTRIB_MAX)
688 DISPATCH_ATTR1FV( index, v );
689 else
690 enum_error();
691 }
692
693 static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
694 {
695 if (index < VERT_ATTRIB_MAX)
696 DISPATCH_ATTR2F( index, x, y );
697 else
698 enum_error();
699 }
700
701 static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
702 {
703 if (index < VERT_ATTRIB_MAX)
704 DISPATCH_ATTR2FV( index, v );
705 else
706 enum_error();
707 }
708
709 static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y,
710 GLfloat z )
711 {
712 if (index < VERT_ATTRIB_MAX)
713 DISPATCH_ATTR3F( index, x, y, z );
714 else
715 enum_error();
716 }
717
718 static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
719 {
720 if (index < VERT_ATTRIB_MAX)
721 DISPATCH_ATTR3FV( index, v );
722 else
723 enum_error();
724 }
725
726 static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
727 GLfloat z, GLfloat w )
728 {
729 if (index < VERT_ATTRIB_MAX)
730 DISPATCH_ATTR4F( index, x, y, z, w );
731 else
732 enum_error();
733 }
734
735 static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
736 {
737 if (index < VERT_ATTRIB_MAX)
738 DISPATCH_ATTR4FV( index, v );
739 else
740 enum_error();
741 }
742
743
744 /* Materials:
745 *
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.
749 *
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.
754 *
755 * There is no aliasing of material attributes with other entrypoints.
756 */
757 #define MAT_ATTR( A, N, params ) \
758 do { \
759 if (tnl->vtx.attrsz[A] != N) { \
760 _tnl_fixup_vertex( ctx, A, N ); \
761 tnl->vtx.have_materials = GL_TRUE; \
762 } \
763 \
764 { \
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; \
771 } \
772 } while (0)
773
774
775 #define MAT( ATTR, N, face, params ) \
776 do { \
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 */ \
781 } while (0)
782
783
784 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
785 * later on - in the meantime just store everything.
786 */
787 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
788 const GLfloat *params )
789 {
790 GET_CURRENT_CONTEXT( ctx );
791 TNLcontext *tnl = TNL_CONTEXT(ctx);
792
793 switch (face) {
794 case GL_FRONT:
795 case GL_BACK:
796 case GL_FRONT_AND_BACK:
797 break;
798
799 default:
800 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
801 return;
802 }
803
804 switch (pname) {
805 case GL_EMISSION:
806 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
807 break;
808 case GL_AMBIENT:
809 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
810 break;
811 case GL_DIFFUSE:
812 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
813 break;
814 case GL_SPECULAR:
815 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
816 break;
817 case GL_SHININESS:
818 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
819 break;
820 case GL_COLOR_INDEXES:
821 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
822 break;
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 );
826 break;
827 default:
828 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
829 return;
830 }
831 }
832
833
834 #define IDX_ATTR( A, IDX ) \
835 do { \
836 GET_CURRENT_CONTEXT( ctx ); \
837 TNLcontext *tnl = TNL_CONTEXT(ctx); \
838 \
839 if (tnl->vtx.attrsz[A] != 1) { \
840 _tnl_fixup_vertex( ctx, A, 1 ); \
841 } \
842 \
843 { \
844 GLfloat *dest = tnl->vtx.attrptr[A]; \
845 dest[0] = IDX; \
846 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
847 } \
848 } while (0)
849
850
851 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
852 {
853 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
854 }
855
856 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
857 {
858 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)v[0] );
859 }
860
861 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
862 {
863 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
864 }
865
866 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
867 {
868 IDX_ATTR( _TNL_ATTRIB_INDEX, v[0] );
869 }
870
871 /* Eval
872 */
873 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
874 {
875 GET_CURRENT_CONTEXT( ctx );
876 TNLcontext *tnl = TNL_CONTEXT(ctx);
877
878 /* TODO: use a CHOOSE() function for this: */
879 {
880 GLint i;
881 if (tnl->vtx.eval.new_state)
882 _tnl_update_eval( ctx );
883
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 );
888 }
889 }
890
891
892 memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
893 tnl->vtx.vertex_size * sizeof(GLfloat));
894
895 _tnl_do_EvalCoord1f( ctx, u );
896
897 memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
898 tnl->vtx.vertex_size * sizeof(GLfloat));
899 }
900
901 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
902 {
903 GET_CURRENT_CONTEXT( ctx );
904 TNLcontext *tnl = TNL_CONTEXT(ctx);
905
906 /* TODO: use a CHOOSE() function for this: */
907 {
908 GLint i;
909 if (tnl->vtx.eval.new_state)
910 _tnl_update_eval( ctx );
911
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 );
916 }
917
918 if (ctx->Eval.AutoNormal)
919 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] < 3)
920 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
921 }
922
923 memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
924 tnl->vtx.vertex_size * sizeof(GLfloat));
925
926 _tnl_do_EvalCoord2f( ctx, u, v );
927
928 memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
929 tnl->vtx.vertex_size * sizeof(GLfloat));
930 }
931
932 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
933 {
934 _tnl_EvalCoord1f( u[0] );
935 }
936
937 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
938 {
939 _tnl_EvalCoord2f( u[0], u[1] );
940 }
941
942 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
943 {
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;
948
949 _tnl_EvalCoord1f( u );
950 }
951
952
953 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
954 {
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;
962
963 _tnl_EvalCoord2f( u, v );
964 }
965
966
967 /* Build a list of primitives on the fly. Keep
968 * ctx->Driver.CurrentExecPrimitive uptodate as well.
969 */
970 static void GLAPIENTRY _tnl_Begin( GLenum mode )
971 {
972 GET_CURRENT_CONTEXT( ctx );
973
974 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
975 TNLcontext *tnl = TNL_CONTEXT(ctx);
976 int i;
977
978 if (ctx->NewState) {
979 _mesa_update_state( ctx );
980 ctx->Exec->Begin(mode);
981 return;
982 }
983
984 /* Heuristic: attempt to isolate attributes occuring outside
985 * begin/end pairs.
986 */
987 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
988 _tnl_FlushVertices( ctx, ~0 );
989
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;
994
995 ctx->Driver.CurrentExecPrimitive = mode;
996 }
997 else
998 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
999
1000 }
1001
1002 static void GLAPIENTRY _tnl_End( void )
1003 {
1004 GET_CURRENT_CONTEXT( ctx );
1005
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;
1010
1011 tnl->vtx.prim[i].mode |= PRIM_END;
1012 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
1013
1014 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
1015
1016 /* Two choices which effect the way vertex attributes are
1017 * carried over (or not) between adjacent primitives.
1018 */
1019 #if 0
1020 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1021 _tnl_FlushVertices( ctx, ~0 );
1022 #else
1023 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1024 _tnl_flush_vtx( ctx );
1025 #endif
1026
1027 }
1028 else
1029 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
1030 }
1031
1032
1033 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
1034 {
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;
1092
1093 vfmt->Rectf = _mesa_noop_Rectf;
1094 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
1095 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
1096 }
1097
1098
1099
1100 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
1101 {
1102 TNLcontext *tnl = TNL_CONTEXT(ctx);
1103
1104 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
1105 return;
1106
1107 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
1108 _tnl_flush_vtx( ctx );
1109 }
1110
1111 {
1112 _tnl_copy_to_current( ctx );
1113
1114 /* reset attrfv table
1115 */
1116 init_attrfv( tnl );
1117 flags |= FLUSH_UPDATE_CURRENT;
1118 }
1119
1120 ctx->Driver.NeedFlush = 0;
1121 }
1122
1123 static void _tnl_current_init( GLcontext *ctx )
1124 {
1125 TNLcontext *tnl = TNL_CONTEXT(ctx);
1126 GLint i;
1127
1128 for (i = 0; i < VERT_ATTRIB_MAX; i++)
1129 tnl->vtx.current[i] = ctx->Current.Attrib[i];
1130
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];
1134
1135 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
1136 }
1137
1138
1139
1140
1141 void _tnl_vtx_init( GLcontext *ctx )
1142 {
1143 TNLcontext *tnl = TNL_CONTEXT(ctx);
1144 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
1145 GLuint i;
1146
1147 for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
1148 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
1149
1150 _tnl_current_init( ctx );
1151 _tnl_exec_vtxfmt_init( ctx );
1152
1153 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
1154 tnl->vtx.vertex_size = 1; init_attrfv( tnl );
1155 }
1156
1157
1158
1159 void _tnl_vtx_destroy( GLcontext *ctx )
1160 {
1161 }
1162