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