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