2fd5ccab1f32a1ea2cc475ea3153e19190160f15
[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 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
137 }
138
139
140 static void _tnl_copy_from_current( GLcontext *ctx )
141 {
142 TNLcontext *tnl = TNL_CONTEXT(ctx);
143 GLint i;
144
145 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
146 switch (tnl->vtx.attrsz[i]) {
147 case 4: tnl->vtx.attrptr[i][3] = tnl->vtx.current[i][3];
148 case 3: tnl->vtx.attrptr[i][2] = tnl->vtx.current[i][2];
149 case 2: tnl->vtx.attrptr[i][1] = tnl->vtx.current[i][1];
150 case 1: tnl->vtx.attrptr[i][0] = tnl->vtx.current[i][0];
151 break;
152 }
153
154 /* Edgeflag requires special treatment:
155 */
156 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
157 tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
158 (GLfloat)ctx->Current.EdgeFlag;
159
160
161 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
162 }
163
164
165
166
167
168 /* Flush existing data, set new attrib size, replay copied vertices.
169 */
170 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
171 GLuint attr,
172 GLuint newsz )
173 {
174 TNLcontext *tnl = TNL_CONTEXT(ctx);
175 GLuint oldsz;
176 GLuint i;
177 GLfloat *tmp;
178 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
179
180
181 /* Run pipeline on current vertices, copy wrapped vertices
182 * to tnl->vtx.copied.
183 */
184 _tnl_wrap_buffers( ctx );
185
186 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
187 * when the attribute already exists in the vertex and is having
188 * its size increased.
189 */
190 _tnl_copy_to_current( ctx );
191
192
193 /* Heuristic: Attempt to isolate attributes received outside
194 * begin/end so that they don't bloat the vertices.
195 */
196 #if 1
197 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
198 tnl->vtx.attrsz[attr] == 0
199 && lastcount > 8
200 ) {
201 init_attrfv( tnl );
202 }
203 #endif
204
205
206 /* Fix up sizes:
207 */
208 oldsz = tnl->vtx.attrsz[attr];
209 tnl->vtx.attrsz[attr] = newsz;
210
211 tnl->vtx.vertex_size += newsz - oldsz;
212 tnl->vtx.counter = MIN2( VERT_BUFFER_SIZE / tnl->vtx.vertex_size,
213 ctx->Const.MaxArrayLockSize );
214 tnl->vtx.initial_counter = tnl->vtx.counter;
215 tnl->vtx.vbptr = tnl->vtx.buffer;
216
217
218 /* Recalculate all the attrptr[] values
219 */
220 for (i = 0, tmp = tnl->vtx.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
221 if (tnl->vtx.attrsz[i]) {
222 tnl->vtx.attrptr[i] = tmp;
223 tmp += tnl->vtx.attrsz[i];
224 }
225 else
226 tnl->vtx.attrptr[i] = 0; /* will not be dereferenced */
227 }
228
229 /* Copy from current to repopulate the vertex with correct values.
230 */
231 _tnl_copy_from_current( ctx );
232
233 /* Replay stored vertices to translate them
234 * to new format here.
235 *
236 * -- No need to replay - just copy piecewise
237 */
238 if (tnl->vtx.copied.nr)
239 {
240 GLfloat *data = tnl->vtx.copied.buffer;
241 GLfloat *dest = tnl->vtx.buffer;
242 GLuint j;
243
244 for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
245 for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
246 if (tnl->vtx.attrsz[j]) {
247 if (j == attr) {
248 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
249 COPY_SZ_4V( dest, oldsz, data );
250 data += oldsz;
251 dest += newsz;
252 }
253 else {
254 GLuint sz = tnl->vtx.attrsz[j];
255 COPY_SZ_4V( dest, sz, data );
256 dest += sz;
257 data += sz;
258 }
259 }
260 }
261 }
262
263 tnl->vtx.vbptr = dest;
264 tnl->vtx.counter -= tnl->vtx.copied.nr;
265 tnl->vtx.copied.nr = 0;
266 }
267 }
268
269
270 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
271 {
272 TNLcontext *tnl = TNL_CONTEXT(ctx);
273 static float id[4] = { 0, 0, 0, 1 };
274 int i;
275
276 if (tnl->vtx.attrsz[attr] < sz) {
277 /* New size is larger. Need to flush existing vertices and get
278 * an enlarged vertex format.
279 */
280 _tnl_wrap_upgrade_vertex( ctx, attr, sz );
281 }
282 else if (tnl->vtx.attrsz[attr] > sz) {
283 /* New size is smaller - just need to fill in some
284 * zeros. Don't need to flush or wrap.
285 */
286 for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
287 tnl->vtx.attrptr[attr][i-1] = id[i-1];
288 }
289 }
290
291
292
293
294 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
295 * entrypoint is called for the first time.
296 */
297 static void do_choose( GLuint attr, GLuint sz,
298 void (*fallback_attr_func)( const GLfloat *),
299 void (*choose1)( const GLfloat *),
300 void (*choose2)( const GLfloat *),
301 void (*choose3)( const GLfloat *),
302 void (*choose4)( const GLfloat *),
303 const GLfloat *v )
304 {
305 GET_CURRENT_CONTEXT( ctx );
306 TNLcontext *tnl = TNL_CONTEXT(ctx);
307
308 if (tnl->vtx.attrsz[attr] != sz)
309 _tnl_fixup_vertex( ctx, attr, sz );
310
311 /* Does this belong here? Necessitates resetting vtxfmt on each
312 * flush (otherwise flags won't get reset afterwards).
313 */
314 if (attr == 0)
315 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
316 else
317 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
318
319 /* Reset any active pointers for this attribute
320 */
321 tnl->vtx.tabfv[attr][0] = choose1;
322 tnl->vtx.tabfv[attr][1] = choose2;
323 tnl->vtx.tabfv[attr][2] = choose3;
324 tnl->vtx.tabfv[attr][3] = choose4;
325
326 /* Update the secondary dispatch table with the new function
327 */
328 tnl->vtx.tabfv[attr][sz-1] = fallback_attr_func;
329
330 (*fallback_attr_func)(v);
331 }
332
333
334 /* Versions of all the entrypoints for situations where codegen isn't
335 * available.
336 *
337 * Note: Only one size for each attribute may be active at once.
338 * Eg. if Color3f is installed/active, then Color4f may not be, even
339 * if the vertex actually contains 4 color coordinates. This is
340 * because the 3f version won't otherwise set color[3] to 1.0 -- this
341 * is the job of the chooser function when switching between Color4f
342 * and Color3f.
343 */
344 #define ATTRFV( ATTR, N ) \
345 static void choose_##ATTR##_##N( const GLfloat *v ); \
346 \
347 static void attrib_##ATTR##_##N( const GLfloat *v ) \
348 { \
349 GET_CURRENT_CONTEXT( ctx ); \
350 TNLcontext *tnl = TNL_CONTEXT(ctx); \
351 \
352 if ((ATTR) == 0) { \
353 GLuint i; \
354 \
355 if (N>0) tnl->vtx.vbptr[0] = v[0]; \
356 if (N>1) tnl->vtx.vbptr[1] = v[1]; \
357 if (N>2) tnl->vtx.vbptr[2] = v[2]; \
358 if (N>3) tnl->vtx.vbptr[3] = v[3]; \
359 \
360 for (i = N; i < tnl->vtx.vertex_size; i++) \
361 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
362 \
363 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
364 \
365 if (--tnl->vtx.counter == 0) \
366 _tnl_wrap_filled_vertex( ctx ); \
367 } \
368 else { \
369 GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
370 if (N>0) dest[0] = v[0]; \
371 if (N>1) dest[1] = v[1]; \
372 if (N>2) dest[2] = v[2]; \
373 if (N>3) dest[3] = v[3]; \
374 } \
375 }
376
377 #define CHOOSE( ATTR, N ) \
378 static void choose_##ATTR##_##N( const GLfloat *v ) \
379 { \
380 do_choose(ATTR, N, \
381 attrib_##ATTR##_##N, \
382 choose_##ATTR##_1, \
383 choose_##ATTR##_2, \
384 choose_##ATTR##_3, \
385 choose_##ATTR##_4, \
386 v ); \
387 }
388
389 #define INIT(ATTR) \
390 static void init_##ATTR( TNLcontext *tnl ) \
391 { \
392 tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1; \
393 tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2; \
394 tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3; \
395 tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4; \
396 }
397
398
399 #define ATTRS( ATTRIB ) \
400 ATTRFV( ATTRIB, 1 ) \
401 ATTRFV( ATTRIB, 2 ) \
402 ATTRFV( ATTRIB, 3 ) \
403 ATTRFV( ATTRIB, 4 ) \
404 CHOOSE( ATTRIB, 1 ) \
405 CHOOSE( ATTRIB, 2 ) \
406 CHOOSE( ATTRIB, 3 ) \
407 CHOOSE( ATTRIB, 4 ) \
408 INIT( ATTRIB ) \
409
410
411 /* Generate a lot of functions. These are the actual worker
412 * functions, which are equivalent to those generated via codegen
413 * elsewhere.
414 */
415 ATTRS( 0 )
416 ATTRS( 1 )
417 ATTRS( 2 )
418 ATTRS( 3 )
419 ATTRS( 4 )
420 ATTRS( 5 )
421 ATTRS( 6 )
422 ATTRS( 7 )
423 ATTRS( 8 )
424 ATTRS( 9 )
425 ATTRS( 10 )
426 ATTRS( 11 )
427 ATTRS( 12 )
428 ATTRS( 13 )
429 ATTRS( 14 )
430 ATTRS( 15 )
431
432 static void init_attrfv( TNLcontext *tnl )
433 {
434 #if defined( WIN32 ) || defined( __VMS )
435 if (0) fprintf(stderr, "%s %d\n", "init_attrfv", tnl->vtx.vertex_size);
436 #else
437 if (0) fprintf(stderr, "%s %d\n", __FUNCTION__, tnl->vtx.vertex_size);
438 #endif
439
440 if (tnl->vtx.vertex_size) {
441 GLuint i;
442
443 init_0( tnl );
444 init_1( tnl );
445 init_2( tnl );
446 init_3( tnl );
447 init_4( tnl );
448 init_5( tnl );
449 init_6( tnl );
450 init_7( tnl );
451 init_8( tnl );
452 init_9( tnl );
453 init_10( tnl );
454 init_11( tnl );
455 init_12( tnl );
456 init_13( tnl );
457 init_14( tnl );
458 init_15( tnl );
459
460 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
461 tnl->vtx.attrsz[i] = 0;
462
463 tnl->vtx.vertex_size = 0;
464 }
465 }
466
467 /* These can be made efficient with codegen. Further, by adding more
468 * logic to do_choose(), the double-dispatch for legacy entrypoints
469 * like glVertex3f() can be removed.
470 */
471 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
472 do { \
473 GET_CURRENT_CONTEXT( ctx ); \
474 TNLcontext *tnl = TNL_CONTEXT(ctx); \
475 tnl->vtx.tabfv[ATTR][COUNT-1]( P ); \
476 } while (0)
477
478 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
479 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
480 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
481 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
482
483 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
484
485 #define DISPATCH_ATTR2F( ATTR, S,T ) \
486 do { \
487 GLfloat v[2]; \
488 v[0] = S; v[1] = T; \
489 DISPATCH_ATTR2FV( ATTR, v ); \
490 } while (0)
491 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
492 do { \
493 GLfloat v[3]; \
494 v[0] = S; v[1] = T; v[2] = R; \
495 DISPATCH_ATTR3FV( ATTR, v ); \
496 } while (0)
497 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
498 do { \
499 GLfloat v[4]; \
500 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
501 DISPATCH_ATTR4FV( ATTR, v ); \
502 } while (0)
503
504
505 static void enum_error( void )
506 {
507 GET_CURRENT_CONTEXT( ctx );
508 _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
509 }
510
511 static void GLAPIENTRY _tnl_Vertex2f( GLfloat x, GLfloat y )
512 {
513 DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
514 }
515
516 static void GLAPIENTRY _tnl_Vertex2fv( const GLfloat *v )
517 {
518 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
519 }
520
521 static void GLAPIENTRY _tnl_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
522 {
523 DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
524 }
525
526 static void GLAPIENTRY _tnl_Vertex3fv( const GLfloat *v )
527 {
528 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
529 }
530
531 static void GLAPIENTRY _tnl_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
532 {
533 DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
534 }
535
536 static void GLAPIENTRY _tnl_Vertex4fv( const GLfloat *v )
537 {
538 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
539 }
540
541 static void GLAPIENTRY _tnl_TexCoord1f( GLfloat x )
542 {
543 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
544 }
545
546 static void GLAPIENTRY _tnl_TexCoord1fv( const GLfloat *v )
547 {
548 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
549 }
550
551 static void GLAPIENTRY _tnl_TexCoord2f( GLfloat x, GLfloat y )
552 {
553 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
554 }
555
556 static void GLAPIENTRY _tnl_TexCoord2fv( const GLfloat *v )
557 {
558 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
559 }
560
561 static void GLAPIENTRY _tnl_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
562 {
563 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
564 }
565
566 static void GLAPIENTRY _tnl_TexCoord3fv( const GLfloat *v )
567 {
568 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
569 }
570
571 static void GLAPIENTRY _tnl_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
572 {
573 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
574 }
575
576 static void GLAPIENTRY _tnl_TexCoord4fv( const GLfloat *v )
577 {
578 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
579 }
580
581 static void GLAPIENTRY _tnl_Normal3f( GLfloat x, GLfloat y, GLfloat z )
582 {
583 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
584 }
585
586 static void GLAPIENTRY _tnl_Normal3fv( const GLfloat *v )
587 {
588 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
589 }
590
591 static void GLAPIENTRY _tnl_FogCoordfEXT( GLfloat x )
592 {
593 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
594 }
595
596 static void GLAPIENTRY _tnl_FogCoordfvEXT( const GLfloat *v )
597 {
598 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
599 }
600
601 static void GLAPIENTRY _tnl_Color3f( GLfloat x, GLfloat y, GLfloat z )
602 {
603 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
604 }
605
606 static void GLAPIENTRY _tnl_Color3fv( const GLfloat *v )
607 {
608 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
609 }
610
611 static void GLAPIENTRY _tnl_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
612 {
613 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
614 }
615
616 static void GLAPIENTRY _tnl_Color4fv( const GLfloat *v )
617 {
618 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
619 }
620
621 static void GLAPIENTRY _tnl_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
622 {
623 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
624 }
625
626 static void GLAPIENTRY _tnl_SecondaryColor3fvEXT( const GLfloat *v )
627 {
628 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
629 }
630
631 static void GLAPIENTRY _tnl_MultiTexCoord1f( GLenum target, GLfloat x )
632 {
633 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
634 DISPATCH_ATTR1F( attr, x );
635 }
636
637 static void GLAPIENTRY _tnl_MultiTexCoord1fv( GLenum target, const GLfloat *v )
638 {
639 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
640 DISPATCH_ATTR1FV( attr, v );
641 }
642
643 static void GLAPIENTRY _tnl_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
644 {
645 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
646 DISPATCH_ATTR2F( attr, x, y );
647 }
648
649 static void GLAPIENTRY _tnl_MultiTexCoord2fv( GLenum target, const GLfloat *v )
650 {
651 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
652 DISPATCH_ATTR2FV( attr, v );
653 }
654
655 static void GLAPIENTRY _tnl_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
656 GLfloat z)
657 {
658 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
659 DISPATCH_ATTR3F( attr, x, y, z );
660 }
661
662 static void GLAPIENTRY _tnl_MultiTexCoord3fv( GLenum target, const GLfloat *v )
663 {
664 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
665 DISPATCH_ATTR3FV( attr, v );
666 }
667
668 static void GLAPIENTRY _tnl_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
669 GLfloat z, GLfloat w )
670 {
671 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
672 DISPATCH_ATTR4F( attr, x, y, z, w );
673 }
674
675 static void GLAPIENTRY _tnl_MultiTexCoord4fv( GLenum target, const GLfloat *v )
676 {
677 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
678 DISPATCH_ATTR4FV( attr, v );
679 }
680
681 static void GLAPIENTRY _tnl_VertexAttrib1fNV( GLuint index, GLfloat x )
682 {
683 if (index < VERT_ATTRIB_MAX)
684 DISPATCH_ATTR1F( index, x );
685 else
686 enum_error();
687 }
688
689 static void GLAPIENTRY _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
690 {
691 if (index < VERT_ATTRIB_MAX)
692 DISPATCH_ATTR1FV( index, v );
693 else
694 enum_error();
695 }
696
697 static void GLAPIENTRY _tnl_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
698 {
699 if (index < VERT_ATTRIB_MAX)
700 DISPATCH_ATTR2F( index, x, y );
701 else
702 enum_error();
703 }
704
705 static void GLAPIENTRY _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
706 {
707 if (index < VERT_ATTRIB_MAX)
708 DISPATCH_ATTR2FV( index, v );
709 else
710 enum_error();
711 }
712
713 static void GLAPIENTRY _tnl_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y,
714 GLfloat z )
715 {
716 if (index < VERT_ATTRIB_MAX)
717 DISPATCH_ATTR3F( index, x, y, z );
718 else
719 enum_error();
720 }
721
722 static void GLAPIENTRY _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
723 {
724 if (index < VERT_ATTRIB_MAX)
725 DISPATCH_ATTR3FV( index, v );
726 else
727 enum_error();
728 }
729
730 static void GLAPIENTRY _tnl_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
731 GLfloat z, GLfloat w )
732 {
733 if (index < VERT_ATTRIB_MAX)
734 DISPATCH_ATTR4F( index, x, y, z, w );
735 else
736 enum_error();
737 }
738
739 static void GLAPIENTRY _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
740 {
741 if (index < VERT_ATTRIB_MAX)
742 DISPATCH_ATTR4FV( index, v );
743 else
744 enum_error();
745 }
746
747
748 /* Materials:
749 *
750 * These are treated as per-vertex attributes, at indices above where
751 * the NV_vertex_program leaves off. There are a lot of good things
752 * about treating materials this way.
753 *
754 * However: I don't want to double the number of generated functions
755 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
756 * ATTRF into this function, and dispense with codegen and
757 * second-level dispatch.
758 *
759 * There is no aliasing of material attributes with other entrypoints.
760 */
761 #define MAT_ATTR( A, N, params ) \
762 do { \
763 if (tnl->vtx.attrsz[A] != N) { \
764 _tnl_fixup_vertex( ctx, A, N ); \
765 } \
766 \
767 { \
768 GLfloat *dest = tnl->vtx.attrptr[A]; \
769 if (N>0) dest[0] = params[0]; \
770 if (N>1) dest[1] = params[1]; \
771 if (N>2) dest[2] = params[2]; \
772 if (N>3) dest[3] = params[3]; \
773 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
774 } \
775 } while (0)
776
777
778 #define MAT( ATTR, N, face, params ) \
779 do { \
780 if (face != GL_BACK) \
781 MAT_ATTR( ATTR, N, params ); /* front */ \
782 if (face != GL_FRONT) \
783 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
784 } while (0)
785
786
787 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
788 * later on - in the meantime just store everything.
789 */
790 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
791 const GLfloat *params )
792 {
793 GET_CURRENT_CONTEXT( ctx );
794 TNLcontext *tnl = TNL_CONTEXT(ctx);
795
796 switch (face) {
797 case GL_FRONT:
798 case GL_BACK:
799 case GL_FRONT_AND_BACK:
800 break;
801
802 default:
803 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
804 return;
805 }
806
807 switch (pname) {
808 case GL_EMISSION:
809 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
810 break;
811 case GL_AMBIENT:
812 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
813 break;
814 case GL_DIFFUSE:
815 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
816 break;
817 case GL_SPECULAR:
818 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
819 break;
820 case GL_SHININESS:
821 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
822 break;
823 case GL_COLOR_INDEXES:
824 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
825 break;
826 case GL_AMBIENT_AND_DIFFUSE:
827 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
828 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
829 break;
830 default:
831 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
832 return;
833 }
834 }
835
836
837 #define IDX_ATTR( A, IDX ) \
838 do { \
839 GET_CURRENT_CONTEXT( ctx ); \
840 TNLcontext *tnl = TNL_CONTEXT(ctx); \
841 \
842 if (tnl->vtx.attrsz[A] != 1) { \
843 _tnl_fixup_vertex( ctx, A, 1 ); \
844 } \
845 \
846 { \
847 GLfloat *dest = tnl->vtx.attrptr[A]; \
848 dest[0] = IDX; \
849 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
850 } \
851 } while (0)
852
853
854 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
855 {
856 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
857 }
858
859 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
860 {
861 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)v[0] );
862 }
863
864 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
865 {
866 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
867 }
868
869 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
870 {
871 IDX_ATTR( _TNL_ATTRIB_INDEX, v[0] );
872 }
873
874 /* Eval
875 */
876 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
877 {
878 GET_CURRENT_CONTEXT( ctx );
879 TNLcontext *tnl = TNL_CONTEXT(ctx);
880
881 /* TODO: use a CHOOSE() function for this: */
882 {
883 GLint i;
884 if (tnl->vtx.eval.new_state)
885 _tnl_update_eval( ctx );
886
887 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
888 if (tnl->vtx.eval.map1[i].map)
889 if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map1[i].sz)
890 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
891 }
892 }
893
894
895 memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
896 tnl->vtx.vertex_size * sizeof(GLfloat));
897
898 _tnl_do_EvalCoord1f( ctx, u );
899
900 memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
901 tnl->vtx.vertex_size * sizeof(GLfloat));
902 }
903
904 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
905 {
906 GET_CURRENT_CONTEXT( ctx );
907 TNLcontext *tnl = TNL_CONTEXT(ctx);
908
909 /* TODO: use a CHOOSE() function for this: */
910 {
911 GLint i;
912 if (tnl->vtx.eval.new_state)
913 _tnl_update_eval( ctx );
914
915 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
916 if (tnl->vtx.eval.map2[i].map)
917 if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map2[i].sz)
918 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
919 }
920
921 if (ctx->Eval.AutoNormal)
922 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] < 3)
923 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
924 }
925
926 memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
927 tnl->vtx.vertex_size * sizeof(GLfloat));
928
929 _tnl_do_EvalCoord2f( ctx, u, v );
930
931 memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
932 tnl->vtx.vertex_size * sizeof(GLfloat));
933 }
934
935 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
936 {
937 _tnl_EvalCoord1f( u[0] );
938 }
939
940 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
941 {
942 _tnl_EvalCoord2f( u[0], u[1] );
943 }
944
945 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
946 {
947 GET_CURRENT_CONTEXT( ctx );
948 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
949 (GLfloat) ctx->Eval.MapGrid1un);
950 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
951
952 _tnl_EvalCoord1f( u );
953 }
954
955
956 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
957 {
958 GET_CURRENT_CONTEXT( ctx );
959 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
960 (GLfloat) ctx->Eval.MapGrid2un);
961 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
962 (GLfloat) ctx->Eval.MapGrid2vn);
963 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
964 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
965
966 _tnl_EvalCoord2f( u, v );
967 }
968
969
970 /* Build a list of primitives on the fly. Keep
971 * ctx->Driver.CurrentExecPrimitive uptodate as well.
972 */
973 static void GLAPIENTRY _tnl_Begin( GLenum mode )
974 {
975 GET_CURRENT_CONTEXT( ctx );
976
977 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
978 TNLcontext *tnl = TNL_CONTEXT(ctx);
979 int i;
980
981 if (ctx->NewState) {
982 _mesa_update_state( ctx );
983 ctx->Exec->Begin(mode);
984 return;
985 }
986
987 #if 1
988 /* Heuristic: attempt to isolate attributes occuring outside
989 * begin/end pairs.
990 */
991 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
992 _tnl_FlushVertices( ctx, ~0 );
993 #endif
994
995 i = tnl->vtx.prim_count++;
996 tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
997 tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
998 tnl->vtx.prim[i].count = 0;
999
1000 ctx->Driver.CurrentExecPrimitive = mode;
1001 }
1002 else
1003 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
1004
1005 }
1006
1007 static void GLAPIENTRY _tnl_End( void )
1008 {
1009 GET_CURRENT_CONTEXT( ctx );
1010
1011 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
1012 TNLcontext *tnl = TNL_CONTEXT(ctx);
1013 int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
1014 int i = tnl->vtx.prim_count - 1;
1015
1016 tnl->vtx.prim[i].mode |= PRIM_END;
1017 tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
1018
1019 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
1020
1021 /* Two choices which effect the way vertex attributes are
1022 * carried over (or not) between adjacent primitives.
1023 */
1024 #if 0
1025 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1026 _tnl_FlushVertices( ctx, ~0 );
1027 #else
1028 if (tnl->vtx.prim_count == TNL_MAX_PRIM)
1029 _tnl_flush_vtx( ctx );
1030 #endif
1031
1032 }
1033 else
1034 _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
1035 }
1036
1037
1038 static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
1039 {
1040 GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
1041 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
1042 vfmt->Begin = _tnl_Begin;
1043 vfmt->CallList = _mesa_CallList;
1044 vfmt->CallLists = _mesa_CallLists;
1045 vfmt->Color3f = _tnl_Color3f;
1046 vfmt->Color3fv = _tnl_Color3fv;
1047 vfmt->Color4f = _tnl_Color4f;
1048 vfmt->Color4fv = _tnl_Color4fv;
1049 vfmt->EdgeFlag = _tnl_EdgeFlag;
1050 vfmt->EdgeFlagv = _tnl_EdgeFlagv;
1051 vfmt->End = _tnl_End;
1052 vfmt->EvalCoord1f = _tnl_EvalCoord1f;
1053 vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
1054 vfmt->EvalCoord2f = _tnl_EvalCoord2f;
1055 vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
1056 vfmt->EvalPoint1 = _tnl_EvalPoint1;
1057 vfmt->EvalPoint2 = _tnl_EvalPoint2;
1058 vfmt->FogCoordfEXT = _tnl_FogCoordfEXT;
1059 vfmt->FogCoordfvEXT = _tnl_FogCoordfvEXT;
1060 vfmt->Indexf = _tnl_Indexf;
1061 vfmt->Indexfv = _tnl_Indexfv;
1062 vfmt->Materialfv = _tnl_Materialfv;
1063 vfmt->MultiTexCoord1fARB = _tnl_MultiTexCoord1f;
1064 vfmt->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fv;
1065 vfmt->MultiTexCoord2fARB = _tnl_MultiTexCoord2f;
1066 vfmt->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fv;
1067 vfmt->MultiTexCoord3fARB = _tnl_MultiTexCoord3f;
1068 vfmt->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fv;
1069 vfmt->MultiTexCoord4fARB = _tnl_MultiTexCoord4f;
1070 vfmt->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fv;
1071 vfmt->Normal3f = _tnl_Normal3f;
1072 vfmt->Normal3fv = _tnl_Normal3fv;
1073 vfmt->SecondaryColor3fEXT = _tnl_SecondaryColor3fEXT;
1074 vfmt->SecondaryColor3fvEXT = _tnl_SecondaryColor3fvEXT;
1075 vfmt->TexCoord1f = _tnl_TexCoord1f;
1076 vfmt->TexCoord1fv = _tnl_TexCoord1fv;
1077 vfmt->TexCoord2f = _tnl_TexCoord2f;
1078 vfmt->TexCoord2fv = _tnl_TexCoord2fv;
1079 vfmt->TexCoord3f = _tnl_TexCoord3f;
1080 vfmt->TexCoord3fv = _tnl_TexCoord3fv;
1081 vfmt->TexCoord4f = _tnl_TexCoord4f;
1082 vfmt->TexCoord4fv = _tnl_TexCoord4fv;
1083 vfmt->Vertex2f = _tnl_Vertex2f;
1084 vfmt->Vertex2fv = _tnl_Vertex2fv;
1085 vfmt->Vertex3f = _tnl_Vertex3f;
1086 vfmt->Vertex3fv = _tnl_Vertex3fv;
1087 vfmt->Vertex4f = _tnl_Vertex4f;
1088 vfmt->Vertex4fv = _tnl_Vertex4fv;
1089 vfmt->VertexAttrib1fNV = _tnl_VertexAttrib1fNV;
1090 vfmt->VertexAttrib1fvNV = _tnl_VertexAttrib1fvNV;
1091 vfmt->VertexAttrib2fNV = _tnl_VertexAttrib2fNV;
1092 vfmt->VertexAttrib2fvNV = _tnl_VertexAttrib2fvNV;
1093 vfmt->VertexAttrib3fNV = _tnl_VertexAttrib3fNV;
1094 vfmt->VertexAttrib3fvNV = _tnl_VertexAttrib3fvNV;
1095 vfmt->VertexAttrib4fNV = _tnl_VertexAttrib4fNV;
1096 vfmt->VertexAttrib4fvNV = _tnl_VertexAttrib4fvNV;
1097
1098 vfmt->Rectf = _mesa_noop_Rectf;
1099 vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
1100 vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
1101 }
1102
1103
1104
1105 void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
1106 {
1107 TNLcontext *tnl = TNL_CONTEXT(ctx);
1108
1109 if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
1110 return;
1111
1112 if (tnl->vtx.counter != tnl->vtx.initial_counter) {
1113 _tnl_flush_vtx( ctx );
1114 #if 0
1115 init_0(tnl);
1116 #endif
1117 }
1118
1119 #if 0
1120 if (flags & FLUSH_UPDATE_CURRENT)
1121 #endif
1122 {
1123 _tnl_copy_to_current( ctx );
1124
1125 /* reset attrfv table
1126 */
1127 init_attrfv( tnl );
1128 flags |= FLUSH_UPDATE_CURRENT;
1129 }
1130
1131 ctx->Driver.NeedFlush = 0;
1132 }
1133
1134 static void _tnl_current_init( GLcontext *ctx )
1135 {
1136 TNLcontext *tnl = TNL_CONTEXT(ctx);
1137 GLint i;
1138
1139 for (i = 0; i < VERT_ATTRIB_MAX; i++)
1140 tnl->vtx.current[i] = ctx->Current.Attrib[i];
1141
1142 for (i = 0; i < MAT_ATTRIB_MAX; i++)
1143 tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
1144 ctx->Light.Material.Attrib[i];
1145
1146 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
1147 }
1148
1149
1150
1151
1152 void _tnl_vtx_init( GLcontext *ctx )
1153 {
1154 TNLcontext *tnl = TNL_CONTEXT(ctx);
1155 struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
1156 GLuint i;
1157
1158 for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
1159 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
1160
1161 _tnl_current_init( ctx );
1162 _tnl_exec_vtxfmt_init( ctx );
1163
1164 _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
1165 tnl->vtx.vertex_size = 1; init_attrfv( tnl );
1166 }
1167
1168
1169
1170 void _tnl_vtx_destroy( GLcontext *ctx )
1171 {
1172 }
1173