Cosmetic changes.
[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 _mesa_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
111 /*
112 * Copy the active vertex's values to the ctx->Current fields.
113 */
114 static void _tnl_copy_to_current( GLcontext *ctx )
115 {
116 TNLcontext *tnl = TNL_CONTEXT(ctx);
117 GLuint i;
118
119 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
120 if (tnl->vtx.attrsz[i]) {
121 /* Note: the tnl->vtx.current[i] pointers points to
122 * the ctx->Current fields. The first 16 or so, anyway.
123 */
124 ASSIGN_4V( tnl->vtx.current[i], 0, 0, 0, 1 );
125 COPY_SZ_4V(tnl->vtx.current[i],
126 tnl->vtx.attrsz[i],
127 tnl->vtx.attrptr[i]);
128 }
129
130 /* Edgeflag requires special treatment:
131 */
132 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
133 ctx->Current.EdgeFlag =
134 (tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
135
136
137 /* Colormaterial -- this kindof sucks.
138 */
139 if (ctx->Light.ColorMaterialEnabled) {
140 _mesa_update_color_material(ctx, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
141 }
142
143 if (tnl->vtx.have_materials) {
144 tnl->Driver.NotifyMaterialChange( ctx );
145 }
146
147 ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
148 }
149
150
151 static void _tnl_copy_from_current( GLcontext *ctx )
152 {
153 TNLcontext *tnl = TNL_CONTEXT(ctx);
154 GLint i;
155
156 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
157 switch (tnl->vtx.attrsz[i]) {
158 case 4: tnl->vtx.attrptr[i][3] = tnl->vtx.current[i][3];
159 case 3: tnl->vtx.attrptr[i][2] = tnl->vtx.current[i][2];
160 case 2: tnl->vtx.attrptr[i][1] = tnl->vtx.current[i][1];
161 case 1: tnl->vtx.attrptr[i][0] = tnl->vtx.current[i][0];
162 break;
163 }
164
165 /* Edgeflag requires special treatment:
166 */
167 if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG])
168 tnl->vtx.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
169 (GLfloat)ctx->Current.EdgeFlag;
170
171
172 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
173 }
174
175
176 /* Flush existing data, set new attrib size, replay copied vertices.
177 */
178 static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
179 GLuint attr,
180 GLuint newsz )
181 {
182 TNLcontext *tnl = TNL_CONTEXT(ctx);
183 GLuint oldsz;
184 GLuint i;
185 GLfloat *tmp;
186 GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
187
188
189 /* Run pipeline on current vertices, copy wrapped vertices
190 * to tnl->vtx.copied.
191 */
192 _tnl_wrap_buffers( ctx );
193
194 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
195 * when the attribute already exists in the vertex and is having
196 * its size increased.
197 */
198 _tnl_copy_to_current( ctx );
199
200
201 /* Heuristic: Attempt to isolate attributes received outside
202 * begin/end so that they don't bloat the vertices.
203 */
204 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
205 tnl->vtx.attrsz[attr] == 0
206 && lastcount > 8
207 ) {
208 init_attrfv( tnl );
209 }
210
211 /* Fix up sizes:
212 */
213 oldsz = tnl->vtx.attrsz[attr];
214 tnl->vtx.attrsz[attr] = newsz;
215
216 tnl->vtx.vertex_size += newsz - oldsz;
217 tnl->vtx.counter = MIN2( VERT_BUFFER_SIZE / tnl->vtx.vertex_size,
218 ctx->Const.MaxArrayLockSize );
219 tnl->vtx.initial_counter = tnl->vtx.counter;
220 tnl->vtx.vbptr = tnl->vtx.buffer;
221
222
223 /* Recalculate all the attrptr[] values
224 */
225 for (i = 0, tmp = tnl->vtx.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
226 if (tnl->vtx.attrsz[i]) {
227 tnl->vtx.attrptr[i] = tmp;
228 tmp += tnl->vtx.attrsz[i];
229 }
230 else
231 tnl->vtx.attrptr[i] = 0; /* will not be dereferenced */
232 }
233
234 /* Copy from current to repopulate the vertex with correct values.
235 */
236 _tnl_copy_from_current( ctx );
237
238 /* Replay stored vertices to translate them
239 * to new format here.
240 *
241 * -- No need to replay - just copy piecewise
242 */
243 if (tnl->vtx.copied.nr)
244 {
245 GLfloat *data = tnl->vtx.copied.buffer;
246 GLfloat *dest = tnl->vtx.buffer;
247 GLuint j;
248
249 for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
250 for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
251 if (tnl->vtx.attrsz[j]) {
252 if (j == attr) {
253 COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
254 COPY_SZ_4V( dest, oldsz, data );
255 data += oldsz;
256 dest += newsz;
257 }
258 else {
259 GLuint sz = tnl->vtx.attrsz[j];
260 COPY_SZ_4V( dest, sz, data );
261 dest += sz;
262 data += sz;
263 }
264 }
265 }
266 }
267
268 tnl->vtx.vbptr = dest;
269 tnl->vtx.counter -= tnl->vtx.copied.nr;
270 tnl->vtx.copied.nr = 0;
271 }
272 }
273
274
275 static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
276 {
277 TNLcontext *tnl = TNL_CONTEXT(ctx);
278 static const GLfloat id[4] = { 0, 0, 0, 1 };
279 int i;
280
281 if (tnl->vtx.attrsz[attr] < sz) {
282 /* New size is larger. Need to flush existing vertices and get
283 * an enlarged vertex format.
284 */
285 _tnl_wrap_upgrade_vertex( ctx, attr, sz );
286 }
287 else if (tnl->vtx.attrsz[attr] > sz) {
288 /* New size is smaller - just need to fill in some
289 * zeros. Don't need to flush or wrap.
290 */
291 for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
292 tnl->vtx.attrptr[attr][i-1] = id[i-1];
293 }
294 }
295
296
297
298
299 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
300 * entrypoint is called for the first time.
301 */
302 static void do_choose( GLuint attr, GLuint sz,
303 void (*fallback_attr_func)( const GLfloat *),
304 void (*choose1)( const GLfloat *),
305 void (*choose2)( const GLfloat *),
306 void (*choose3)( const GLfloat *),
307 void (*choose4)( const GLfloat *),
308 const GLfloat *v )
309 {
310 GET_CURRENT_CONTEXT( ctx );
311 TNLcontext *tnl = TNL_CONTEXT(ctx);
312
313 if (tnl->vtx.attrsz[attr] != sz)
314 _tnl_fixup_vertex( ctx, attr, sz );
315
316 /* Does this belong here? Necessitates resetting vtxfmt on each
317 * flush (otherwise flags won't get reset afterwards).
318 */
319 if (attr == 0)
320 ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
321 else
322 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
323
324 /* Reset any active pointers for this attribute
325 */
326 tnl->vtx.tabfv[attr][0] = choose1;
327 tnl->vtx.tabfv[attr][1] = choose2;
328 tnl->vtx.tabfv[attr][2] = choose3;
329 tnl->vtx.tabfv[attr][3] = choose4;
330
331 /* Update the secondary dispatch table with the new function
332 */
333 tnl->vtx.tabfv[attr][sz-1] = fallback_attr_func;
334
335 (*fallback_attr_func)(v);
336 }
337
338
339 /* Versions of all the entrypoints for situations where codegen isn't
340 * available.
341 *
342 * Note: Only one size for each attribute may be active at once.
343 * Eg. if Color3f is installed/active, then Color4f may not be, even
344 * if the vertex actually contains 4 color coordinates. This is
345 * because the 3f version won't otherwise set color[3] to 1.0 -- this
346 * is the job of the chooser function when switching between Color4f
347 * and Color3f.
348 */
349 #define ATTRFV( ATTR, N ) \
350 static void choose_##ATTR##_##N( const GLfloat *v ); \
351 \
352 static void attrib_##ATTR##_##N( const GLfloat *v ) \
353 { \
354 GET_CURRENT_CONTEXT( ctx ); \
355 TNLcontext *tnl = TNL_CONTEXT(ctx); \
356 \
357 if ((ATTR) == 0) { \
358 GLuint i; \
359 \
360 if (N>0) tnl->vtx.vbptr[0] = v[0]; \
361 if (N>1) tnl->vtx.vbptr[1] = v[1]; \
362 if (N>2) tnl->vtx.vbptr[2] = v[2]; \
363 if (N>3) tnl->vtx.vbptr[3] = v[3]; \
364 \
365 for (i = N; i < tnl->vtx.vertex_size; i++) \
366 tnl->vtx.vbptr[i] = tnl->vtx.vertex[i]; \
367 \
368 tnl->vtx.vbptr += tnl->vtx.vertex_size; \
369 \
370 if (--tnl->vtx.counter == 0) \
371 _tnl_wrap_filled_vertex( ctx ); \
372 } \
373 else { \
374 GLfloat *dest = tnl->vtx.attrptr[ATTR]; \
375 if (N>0) dest[0] = v[0]; \
376 if (N>1) dest[1] = v[1]; \
377 if (N>2) dest[2] = v[2]; \
378 if (N>3) dest[3] = v[3]; \
379 } \
380 }
381
382 #define CHOOSE( ATTR, N ) \
383 static void choose_##ATTR##_##N( const GLfloat *v ) \
384 { \
385 do_choose(ATTR, N, \
386 attrib_##ATTR##_##N, \
387 choose_##ATTR##_1, \
388 choose_##ATTR##_2, \
389 choose_##ATTR##_3, \
390 choose_##ATTR##_4, \
391 v ); \
392 }
393
394 #define INIT(ATTR) \
395 static void init_##ATTR( TNLcontext *tnl ) \
396 { \
397 tnl->vtx.tabfv[ATTR][0] = choose_##ATTR##_1; \
398 tnl->vtx.tabfv[ATTR][1] = choose_##ATTR##_2; \
399 tnl->vtx.tabfv[ATTR][2] = choose_##ATTR##_3; \
400 tnl->vtx.tabfv[ATTR][3] = choose_##ATTR##_4; \
401 }
402
403
404 #define ATTRS( ATTRIB ) \
405 ATTRFV( ATTRIB, 1 ) \
406 ATTRFV( ATTRIB, 2 ) \
407 ATTRFV( ATTRIB, 3 ) \
408 ATTRFV( ATTRIB, 4 ) \
409 CHOOSE( ATTRIB, 1 ) \
410 CHOOSE( ATTRIB, 2 ) \
411 CHOOSE( ATTRIB, 3 ) \
412 CHOOSE( ATTRIB, 4 ) \
413 INIT( ATTRIB ) \
414
415
416 /* Generate a lot of functions. These are the actual worker
417 * functions, which are equivalent to those generated via codegen
418 * elsewhere.
419 */
420 ATTRS( 0 )
421 ATTRS( 1 )
422 ATTRS( 2 )
423 ATTRS( 3 )
424 ATTRS( 4 )
425 ATTRS( 5 )
426 ATTRS( 6 )
427 ATTRS( 7 )
428 ATTRS( 8 )
429 ATTRS( 9 )
430 ATTRS( 10 )
431 ATTRS( 11 )
432 ATTRS( 12 )
433 ATTRS( 13 )
434 ATTRS( 14 )
435 ATTRS( 15 )
436
437 static void init_attrfv( TNLcontext *tnl )
438 {
439 if (tnl->vtx.vertex_size) {
440 GLuint i;
441
442 init_0( tnl );
443 init_1( tnl );
444 init_2( tnl );
445 init_3( tnl );
446 init_4( tnl );
447 init_5( tnl );
448 init_6( tnl );
449 init_7( tnl );
450 init_8( tnl );
451 init_9( tnl );
452 init_10( tnl );
453 init_11( tnl );
454 init_12( tnl );
455 init_13( tnl );
456 init_14( tnl );
457 init_15( tnl );
458
459 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
460 tnl->vtx.attrsz[i] = 0;
461
462 tnl->vtx.vertex_size = 0;
463 tnl->vtx.have_materials = 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 tnl->vtx.have_materials = GL_TRUE; \
766 } \
767 \
768 { \
769 GLfloat *dest = tnl->vtx.attrptr[A]; \
770 if (N>0) dest[0] = params[0]; \
771 if (N>1) dest[1] = params[1]; \
772 if (N>2) dest[2] = params[2]; \
773 if (N>3) dest[3] = params[3]; \
774 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
775 } \
776 } while (0)
777
778
779 #define MAT( ATTR, N, face, params ) \
780 do { \
781 if (face != GL_BACK) \
782 MAT_ATTR( ATTR, N, params ); /* front */ \
783 if (face != GL_FRONT) \
784 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
785 } while (0)
786
787
788 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
789 * later on - in the meantime just store everything.
790 */
791 static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
792 const GLfloat *params )
793 {
794 GET_CURRENT_CONTEXT( ctx );
795 TNLcontext *tnl = TNL_CONTEXT(ctx);
796
797 switch (face) {
798 case GL_FRONT:
799 case GL_BACK:
800 case GL_FRONT_AND_BACK:
801 break;
802
803 default:
804 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
805 return;
806 }
807
808 switch (pname) {
809 case GL_EMISSION:
810 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
811 break;
812 case GL_AMBIENT:
813 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
814 break;
815 case GL_DIFFUSE:
816 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
817 break;
818 case GL_SPECULAR:
819 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
820 break;
821 case GL_SHININESS:
822 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
823 break;
824 case GL_COLOR_INDEXES:
825 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
826 break;
827 case GL_AMBIENT_AND_DIFFUSE:
828 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
829 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
830 break;
831 default:
832 _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
833 return;
834 }
835 }
836
837
838 #define IDX_ATTR( A, IDX ) \
839 do { \
840 GET_CURRENT_CONTEXT( ctx ); \
841 TNLcontext *tnl = TNL_CONTEXT(ctx); \
842 \
843 if (tnl->vtx.attrsz[A] != 1) { \
844 _tnl_fixup_vertex( ctx, A, 1 ); \
845 } \
846 \
847 { \
848 GLfloat *dest = tnl->vtx.attrptr[A]; \
849 dest[0] = IDX; \
850 ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
851 } \
852 } while (0)
853
854
855 static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
856 {
857 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
858 }
859
860 static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
861 {
862 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)v[0] );
863 }
864
865 static void GLAPIENTRY _tnl_Indexf( GLfloat f )
866 {
867 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
868 }
869
870 static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
871 {
872 IDX_ATTR( _TNL_ATTRIB_INDEX, v[0] );
873 }
874
875 /* Eval
876 */
877 static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
878 {
879 GET_CURRENT_CONTEXT( ctx );
880 TNLcontext *tnl = TNL_CONTEXT(ctx);
881
882 /* TODO: use a CHOOSE() function for this: */
883 {
884 GLint i;
885 if (tnl->vtx.eval.new_state)
886 _tnl_update_eval( ctx );
887
888 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
889 if (tnl->vtx.eval.map1[i].map)
890 if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map1[i].sz)
891 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
892 }
893 }
894
895
896 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
897 tnl->vtx.vertex_size * sizeof(GLfloat));
898
899 _tnl_do_EvalCoord1f( ctx, u );
900
901 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
902 tnl->vtx.vertex_size * sizeof(GLfloat));
903 }
904
905 static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
906 {
907 GET_CURRENT_CONTEXT( ctx );
908 TNLcontext *tnl = TNL_CONTEXT(ctx);
909
910 /* TODO: use a CHOOSE() function for this: */
911 {
912 GLint i;
913 if (tnl->vtx.eval.new_state)
914 _tnl_update_eval( ctx );
915
916 for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
917 if (tnl->vtx.eval.map2[i].map)
918 if (tnl->vtx.attrsz[i] < tnl->vtx.eval.map2[i].sz)
919 _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
920 }
921
922 if (ctx->Eval.AutoNormal)
923 if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] < 3)
924 _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
925 }
926
927 _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
928 tnl->vtx.vertex_size * sizeof(GLfloat));
929
930 _tnl_do_EvalCoord2f( ctx, u, v );
931
932 _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
933 tnl->vtx.vertex_size * sizeof(GLfloat));
934 }
935
936 static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
937 {
938 _tnl_EvalCoord1f( u[0] );
939 }
940
941 static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
942 {
943 _tnl_EvalCoord2f( u[0], u[1] );
944 }
945
946 static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
947 {
948 GET_CURRENT_CONTEXT( ctx );
949 GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
950 (GLfloat) ctx->Eval.MapGrid1un);
951 GLfloat u = i * du + ctx->Eval.MapGrid1u1;
952
953 _tnl_EvalCoord1f( u );
954 }
955
956
957 static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
958 {
959 GET_CURRENT_CONTEXT( ctx );
960 GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
961 (GLfloat) ctx->Eval.MapGrid2un);
962 GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
963 (GLfloat) ctx->Eval.MapGrid2vn);
964 GLfloat u = i * du + ctx->Eval.MapGrid2u1;
965 GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
966
967 _tnl_EvalCoord2f( u, v );
968 }
969
970
971 /* Build a list of primitives on the fly. Keep
972 * ctx->Driver.CurrentExecPrimitive uptodate as well.
973 */
974 static void GLAPIENTRY _tnl_Begin( GLenum mode )
975 {
976 GET_CURRENT_CONTEXT( ctx );
977
978 if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
979 TNLcontext *tnl = TNL_CONTEXT(ctx);
980 int i;
981
982 if (ctx->NewState) {
983 _mesa_update_state( ctx );
984 if (!(tnl->Driver.NotifyBegin && tnl->Driver.NotifyBegin( ctx, mode )))
985 ctx->Exec->Begin(mode);
986 return;
987 }
988
989 /* Heuristic: attempt to isolate attributes occuring outside
990 * begin/end pairs.
991 */
992 if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
993 _tnl_FlushVertices( ctx, ~0 );
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 }
1115
1116 {
1117 _tnl_copy_to_current( ctx );
1118
1119 /* reset attrfv table
1120 */
1121 init_attrfv( tnl );
1122 flags |= FLUSH_UPDATE_CURRENT;
1123 }
1124
1125 ctx->Driver.NeedFlush = 0;
1126 }
1127
1128
1129 static void _tnl_current_init( GLcontext *ctx )
1130 {
1131 TNLcontext *tnl = TNL_CONTEXT(ctx);
1132 GLint i;
1133
1134 /* setup the pointers for the typical 16 vertex attributes */
1135 for (i = 0; i < VERT_ATTRIB_MAX; i++)
1136 tnl->vtx.current[i] = ctx->Current.Attrib[i];
1137
1138 /* setup pointers for the 12 material attributes */
1139 for (i = 0; i < MAT_ATTRIB_MAX; i++)
1140 tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
1141 ctx->Light.Material.Attrib[i];
1142
1143 tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
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