1 /* $Id: t_imm_api.c,v 1.31 2002/09/03 18:05:52 brianp Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keithw@valinux.com>
43 #include "t_context.h"
44 #include "t_imm_api.h"
45 #include "t_imm_elt.h"
46 #include "t_imm_exec.h"
47 #include "t_imm_dlist.h"
50 /* A cassette is full or flushed on a statechange.
52 void _tnl_flush_immediate( GLcontext
*ctx
, struct immediate
*IM
)
55 /* We were called by glVertex, glEvalCoord, glArrayElement, etc.
56 * The current context is corresponds to the IM structure.
58 GET_CURRENT_CONTEXT(context
);
62 if (MESA_VERBOSE
& VERBOSE_IMMEDIATE
)
63 _mesa_debug(ctx
, "_tnl_flush_immediate IM: %d compiling: %d\n",
64 IM
->id
, ctx
->CompileFlag
);
66 if (IM
->FlushElt
== FLUSH_ELT_EAGER
) {
67 _tnl_translate_array_elts( ctx
, IM
, IM
->LastPrimitive
, IM
->Count
);
70 /* Mark the last primitive:
72 IM
->PrimitiveLength
[IM
->LastPrimitive
] = IM
->Count
- IM
->LastPrimitive
;
73 IM
->Primitive
[IM
->LastPrimitive
] |= PRIM_LAST
;
76 _tnl_compile_cassette( ctx
, IM
);
78 _tnl_execute_cassette( ctx
, IM
);
82 /* Hook for ctx->Driver.FlushVertices:
84 void _tnl_flush_vertices( GLcontext
*ctx
, GLuint flags
)
86 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
88 if (MESA_VERBOSE
& VERBOSE_IMMEDIATE
)
90 "_tnl_flush_vertices flags %x IM(%d) %d..%d Flag[%d]: %x\n",
91 flags
, IM
->id
, IM
->Start
, IM
->Count
, IM
->Start
,
94 if (IM
->Flag
[IM
->Start
]) {
95 if ((flags
& FLUSH_UPDATE_CURRENT
) ||
96 IM
->Count
> IM
->Start
||
97 (IM
->Flag
[IM
->Start
] & (VERT_BEGIN
|VERT_END
))) {
98 _tnl_flush_immediate( ctx
, IM
);
105 _tnl_save_Begin( GLenum mode
)
107 GET_CURRENT_CONTEXT(ctx
);
108 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
109 GLuint inflags
, state
;
111 /* _mesa_debug(ctx, "%s: before: %x\n", __FUNCTION__, IM->BeginState); */
113 if (mode
> GL_POLYGON
) {
114 _mesa_compile_error( ctx
, GL_INVALID_ENUM
, "_tnl_Begin" );
119 _mesa_update_state(ctx
);
122 /* if only a very few slots left, might as well flush now
124 if (IM
->Count
> IMM_MAXDATA
-8) {
125 _tnl_flush_immediate( ctx
, IM
);
126 IM
= TNL_CURRENT_IM(ctx
);
130 /* Check for and flush buffered vertices from internal operations.
132 if (IM
->SavedBeginState
) {
133 _tnl_flush_immediate( ctx
, IM
);
134 IM
= TNL_CURRENT_IM(ctx
);
135 IM
->BeginState
= IM
->SavedBeginState
;
136 IM
->SavedBeginState
= 0;
139 state
= IM
->BeginState
;
140 inflags
= state
& (VERT_BEGIN_0
|VERT_BEGIN_1
);
141 state
|= inflags
<< 2; /* set error conditions */
143 if (inflags
!= (VERT_BEGIN_0
|VERT_BEGIN_1
))
145 GLuint count
= IM
->Count
;
146 GLuint last
= IM
->LastPrimitive
;
148 state
|= (VERT_BEGIN_0
|VERT_BEGIN_1
);
149 IM
->Flag
[count
] |= VERT_BIT_BEGIN
;
150 IM
->Primitive
[count
] = mode
| PRIM_BEGIN
;
151 IM
->PrimitiveLength
[IM
->LastPrimitive
] = count
- IM
->LastPrimitive
;
152 IM
->LastPrimitive
= count
;
154 /* Not quite right. Need to use the fallback '_aa_ArrayElement'
155 * when not known to be inside begin/end and arrays are
158 if (IM
->FlushElt
== FLUSH_ELT_EAGER
) {
159 _tnl_translate_array_elts( ctx
, IM
, last
, count
);
163 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
164 IM
->BeginState
= state
;
166 /* Update save_primitive now. Don't touch ExecPrimitive as this is
167 * updated in the replay of this cassette if we are in
168 * COMPILE_AND_EXECUTE mode.
170 if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_UNKNOWN
)
171 ctx
->Driver
.CurrentSavePrimitive
= PRIM_INSIDE_UNKNOWN_PRIM
;
172 else if (ctx
->Driver
.CurrentSavePrimitive
== PRIM_OUTSIDE_BEGIN_END
)
173 ctx
->Driver
.CurrentSavePrimitive
= mode
;
178 _tnl_Begin( GLenum mode
)
180 GET_CURRENT_CONTEXT(ctx
);
181 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
182 ASSERT (!ctx
->CompileFlag
);
184 if (mode
> GL_POLYGON
) {
185 _mesa_error( ctx
, GL_INVALID_ENUM
, "_tnl_Begin(0x%x)", mode
);
189 if (ctx
->Driver
.CurrentExecPrimitive
!= PRIM_OUTSIDE_BEGIN_END
) {
190 _mesa_error( ctx
, GL_INVALID_OPERATION
, "_tnl_Begin" );
195 _mesa_update_state(ctx
);
198 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
199 GLuint count
= IM
->Count
;
200 GLuint last
= IM
->LastPrimitive
;
202 if (IM
->Start
== IM
->Count
&&
203 tnl
->Driver
.NotifyBegin
&&
204 tnl
->Driver
.NotifyBegin( ctx
, mode
)) {
208 assert( IM
->SavedBeginState
== 0 );
209 assert( IM
->BeginState
== 0 );
211 /* Not quite right. Need to use the fallback '_aa_ArrayElement'
212 * when not known to be inside begin/end and arrays are
215 if (IM
->FlushElt
== FLUSH_ELT_EAGER
) {
216 _tnl_translate_array_elts( ctx
, IM
, last
, count
);
219 IM
->Flag
[count
] |= VERT_BIT_BEGIN
;
220 IM
->Primitive
[count
] = mode
| PRIM_BEGIN
;
221 IM
->PrimitiveLength
[last
] = count
- last
;
222 IM
->LastPrimitive
= count
;
223 IM
->BeginState
= (VERT_BEGIN_0
|VERT_BEGIN_1
);
225 /* _mesa_debug(ctx, "%s: %x\n", __FUNCTION__, IM->BeginState); */
227 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
228 ctx
->Driver
.CurrentExecPrimitive
= mode
;
233 /* Function which allows operations like 'glRectf' to decompose to a
234 * begin/end object and vertices without worrying about what happens
235 * with display lists.
238 _tnl_hard_begin( GLcontext
*ctx
, GLenum p
)
240 /* _mesa_debug(ctx, "%s\n", __FUNCTION__); */
242 if (!ctx
->CompileFlag
) {
243 /* If not compiling, treat as a normal begin().
245 /* _mesa_debug(ctx, "%s: treating as glBegin\n", __FUNCTION__); */
250 /* Otherwise, need to do special processing to preserve the
251 * condition that these vertices will only be replayed outside
252 * future begin/end objects.
254 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
257 _mesa_update_state(ctx
);
259 if (IM
->Count
> IMM_MAXDATA
-8) {
260 _tnl_flush_immediate( ctx
, IM
);
261 IM
= TNL_CURRENT_IM(ctx
);
264 /* A lot depends on the degree to which the display list has
265 * constrained the possible begin/end states at this point:
267 switch (IM
->BeginState
& (VERT_BEGIN_0
|VERT_BEGIN_1
)) {
268 case VERT_BEGIN_0
|VERT_BEGIN_1
:
269 /* This is an immediate known to be inside a begin/end object.
271 ASSERT(ctx
->Driver
.CurrentSavePrimitive
<= GL_POLYGON
);
272 IM
->BeginState
|= (VERT_ERROR_1
|VERT_ERROR_0
);
277 /* This is a display-list immediate in an unknown begin/end
278 * state. Assert it is empty and convert it to a 'hard' one.
280 ASSERT(IM
->SavedBeginState
== 0);
281 ASSERT(ctx
->Driver
.CurrentSavePrimitive
== PRIM_UNKNOWN
);
283 /* Push current beginstate, to be restored later. Don't worry
284 * about raising errors.
286 IM
->SavedBeginState
= IM
->BeginState
;
291 /* Unless we have fallen through, this is an immediate known to
292 * be outside begin/end objects.
294 ASSERT(ctx
->Driver
.CurrentSavePrimitive
== PRIM_UNKNOWN
||
295 ctx
->Driver
.CurrentSavePrimitive
== PRIM_OUTSIDE_BEGIN_END
);
296 ASSERT (IM
->FlushElt
!= FLUSH_ELT_EAGER
);
298 IM
->BeginState
|= VERT_BEGIN_0
|VERT_BEGIN_1
;
299 IM
->Flag
[IM
->Count
] |= VERT_BIT_BEGIN
;
300 IM
->Primitive
[IM
->Count
] = p
| PRIM_BEGIN
;
301 IM
->PrimitiveLength
[IM
->LastPrimitive
] = IM
->Count
- IM
->LastPrimitive
;
302 IM
->LastPrimitive
= IM
->Count
;
304 /* This is necessary as this immediate will not be flushed in
305 * _tnl_end() -- we leave it active, hoping to pick up more
306 * vertices before the next state change.
308 ctx
->Driver
.NeedFlush
|= FLUSH_STORED_VERTICES
;
323 /* Both streams now outside begin/end.
325 * Leave SavedBeginState untouched -- attempt to gather several
326 * rects/arrays together in a single immediate struct.
329 _tnl_end( GLcontext
*ctx
)
331 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
332 GLuint state
= IM
->BeginState
;
333 GLuint inflags
= (~state
) & (VERT_BEGIN_0
|VERT_BEGIN_1
);
335 assert( ctx
->Driver
.NeedFlush
& FLUSH_STORED_VERTICES
);
337 state
|= inflags
<< 2; /* errors */
339 if (inflags
!= (VERT_BEGIN_0
|VERT_BEGIN_1
))
341 GLuint count
= IM
->Count
;
342 GLuint last
= IM
->LastPrimitive
;
344 state
&= ~(VERT_BEGIN_0
|VERT_BEGIN_1
); /* update state */
345 IM
->Flag
[count
] |= VERT_BIT_END
;
346 IM
->Primitive
[last
] |= PRIM_END
;
347 IM
->PrimitiveLength
[last
] = count
- last
;
348 IM
->Primitive
[count
] = PRIM_OUTSIDE_BEGIN_END
; /* removes PRIM_BEGIN
349 * flag if length == 0
351 IM
->LastPrimitive
= count
;
353 if (IM
->FlushElt
== FLUSH_ELT_EAGER
) {
354 _tnl_translate_array_elts( ctx
, IM
, last
, count
);
358 IM
->BeginState
= state
;
360 if (!ctx
->CompileFlag
) {
361 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
)
362 _mesa_error( ctx
, GL_INVALID_OPERATION
, "_tnl_End" );
364 ctx
->Driver
.CurrentExecPrimitive
= PRIM_OUTSIDE_BEGIN_END
;
367 /* You can set this flag to get the old 'flush_vb on glEnd()'
370 if (MESA_DEBUG_FLAGS
& DEBUG_ALWAYS_FLUSH
)
371 _tnl_flush_immediate( ctx
, IM
);
377 GET_CURRENT_CONTEXT(ctx
);
380 /* Need to keep save primitive uptodate in COMPILE and
381 * COMPILE_AND_EXEC modes, need to keep exec primitive uptodate
384 if (ctx
->CompileFlag
)
385 ctx
->Driver
.CurrentSavePrimitive
= PRIM_OUTSIDE_BEGIN_END
;
389 #define COLOR( r, g, b, a ) \
392 GLuint count = IM->Count; \
393 GLfloat *color = IM->Attrib[VERT_ATTRIB_COLOR0][count]; \
394 IM->Flag[count] |= VERT_BIT_COLOR0; \
402 _tnl_Color3f( GLfloat red
, GLfloat green
, GLfloat blue
)
404 COLOR( red
, green
, blue
, 1.0 );
408 _tnl_Color3ub( GLubyte red
, GLubyte green
, GLubyte blue
)
410 COLOR(UBYTE_TO_FLOAT(red
),
411 UBYTE_TO_FLOAT(green
),
412 UBYTE_TO_FLOAT(blue
),
417 _tnl_Color4f( GLfloat red
, GLfloat green
, GLfloat blue
, GLfloat alpha
)
419 COLOR( red
, green
, blue
, alpha
);
423 _tnl_Color4ub( GLubyte red
, GLubyte green
, GLubyte blue
, GLubyte alpha
)
425 COLOR(UBYTE_TO_FLOAT(red
),
426 UBYTE_TO_FLOAT(green
),
427 UBYTE_TO_FLOAT(blue
),
428 UBYTE_TO_FLOAT(alpha
));
432 _tnl_Color3fv( const GLfloat
*v
)
434 COLOR( v
[0], v
[1], v
[2], 1.0 );
438 _tnl_Color3ubv( const GLubyte
*v
)
440 COLOR(UBYTE_TO_FLOAT(v
[0]),
441 UBYTE_TO_FLOAT(v
[1]),
442 UBYTE_TO_FLOAT(v
[2]),
447 _tnl_Color4fv( const GLfloat
*v
)
449 COLOR( v
[0], v
[1], v
[2], v
[3] );
453 _tnl_Color4ubv( const GLubyte
*v
)
455 COLOR(UBYTE_TO_FLOAT(v
[0]),
456 UBYTE_TO_FLOAT(v
[1]),
457 UBYTE_TO_FLOAT(v
[2]),
458 UBYTE_TO_FLOAT(v
[3]));
464 #define SECONDARY_COLOR( r, g, b ) \
469 IM->Flag[count] |= VERT_BIT_COLOR1; \
470 IM->Attrib[VERT_ATTRIB_COLOR1][count][0] = r; \
471 IM->Attrib[VERT_ATTRIB_COLOR1][count][1] = g; \
472 IM->Attrib[VERT_ATTRIB_COLOR1][count][2] = b; \
476 _tnl_SecondaryColor3fEXT( GLfloat red
, GLfloat green
, GLfloat blue
)
478 SECONDARY_COLOR( red
, green
, blue
);
482 _tnl_SecondaryColor3ubEXT( GLubyte red
, GLubyte green
, GLubyte blue
)
484 SECONDARY_COLOR(UBYTE_TO_FLOAT(red
),
485 UBYTE_TO_FLOAT(green
),
486 UBYTE_TO_FLOAT(blue
));
490 _tnl_SecondaryColor3fvEXT( const GLfloat
*v
)
492 SECONDARY_COLOR( v
[0], v
[1], v
[2] );
496 _tnl_SecondaryColor3ubvEXT( const GLubyte
*v
)
498 SECONDARY_COLOR(UBYTE_TO_FLOAT(v
[0]),
499 UBYTE_TO_FLOAT(v
[1]),
500 UBYTE_TO_FLOAT(v
[2]));
505 _tnl_EdgeFlag( GLboolean flag
)
510 IM
->EdgeFlag
[count
] = flag
;
511 IM
->Flag
[count
] |= VERT_BIT_EDGEFLAG
;
516 _tnl_EdgeFlagv( const GLboolean
*flag
)
521 IM
->EdgeFlag
[count
] = *flag
;
522 IM
->Flag
[count
] |= VERT_BIT_EDGEFLAG
;
527 _tnl_FogCoordfEXT( GLfloat f
)
532 IM
->Attrib
[VERT_ATTRIB_FOG
][count
][0] = f
; /*FogCoord[count] = f;*/
533 IM
->Flag
[count
] |= VERT_BIT_FOG
;
537 _tnl_FogCoordfvEXT( const GLfloat
*v
)
542 IM
->Attrib
[VERT_ATTRIB_FOG
][count
][0] = v
[0]; /*FogCoord[count] = v[0];*/
543 IM
->Flag
[count
] |= VERT_BIT_FOG
;
548 _tnl_Indexi( GLint c
)
553 IM
->Index
[count
] = c
;
554 IM
->Flag
[count
] |= VERT_BIT_INDEX
;
559 _tnl_Indexiv( const GLint
*c
)
564 IM
->Index
[count
] = *c
;
565 IM
->Flag
[count
] |= VERT_BIT_INDEX
;
569 #define NORMAL( x, y, z ) \
575 IM->Flag[count] |= VERT_BIT_NORMAL; \
576 normal = IM->Attrib[VERT_ATTRIB_NORMAL][count]; \
577 ASSIGN_3V(normal, x,y,z); \
580 #if defined(USE_IEEE)
581 #define NORMALF( x, y, z ) \
587 IM->Flag[count] |= VERT_BIT_NORMAL; \
588 normal = (fi_type *)IM->Attrib[VERT_ATTRIB_NORMAL][count]; \
589 normal[0].i = ((fi_type *)&(x))->i; \
590 normal[1].i = ((fi_type *)&(y))->i; \
591 normal[2].i = ((fi_type *)&(z))->i; \
594 #define NORMALF NORMAL
598 _tnl_Normal3f( GLfloat nx
, GLfloat ny
, GLfloat nz
)
605 _tnl_Normal3fv( const GLfloat
*v
)
607 NORMALF( v
[0], v
[1], v
[2] );
608 /* struct immediate *IM = (struct immediate *)(((GLcontext *) _glapi_Context)->swtnl_im); */
609 /* IM->Flag[IM->Count] = VERT_NORM; */
614 #define TEXCOORD1(s) \
620 IM->Flag[count] |= VERT_BIT_TEX0; \
621 tc = IM->Attrib[VERT_ATTRIB_TEX0][count]; \
622 ASSIGN_4V(tc,s,0,0,1); \
625 #define TEXCOORD2(s, t) \
631 IM->Flag[count] |= VERT_BIT_TEX0; \
632 tc = IM->Attrib[VERT_ATTRIB_TEX0][count]; \
633 ASSIGN_4V(tc, s, t, 0, 1); \
636 #define TEXCOORD3(s, t, u) \
642 IM->Flag[count] |= VERT_BIT_TEX0; \
643 IM->TexSize |= TEX_0_SIZE_3; \
644 tc = IM->Attrib[VERT_ATTRIB_TEX0][count]; \
645 ASSIGN_4V(tc, s, t, u, 1); \
648 #define TEXCOORD4(s, t, u, v) \
654 IM->Flag[count] |= VERT_BIT_TEX0; \
655 IM->TexSize |= TEX_0_SIZE_4; \
656 tc = IM->Attrib[VERT_ATTRIB_TEX0][count]; \
657 ASSIGN_4V(tc, s, t, u, v); \
660 #if defined(USE_IEEE)
661 #define TEXCOORD2F(s, t) \
667 IM->Flag[count] |= VERT_BIT_TEX0; \
668 tc = (fi_type *)IM->Attrib[VERT_ATTRIB_TEX0][count]; \
669 tc[0].i = ((fi_type *)&(s))->i; \
670 tc[1].i = ((fi_type *)&(t))->i; \
672 tc[3].i = IEEE_ONE; \
675 #define TEXCOORD2F TEXCOORD2
679 _tnl_TexCoord1f( GLfloat s
)
686 _tnl_TexCoord2f( GLfloat s
, GLfloat t
)
693 _tnl_TexCoord3f( GLfloat s
, GLfloat t
, GLfloat r
)
699 _tnl_TexCoord4f( GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
701 TEXCOORD4(s
, t
, r
, q
)
705 _tnl_TexCoord1fv( const GLfloat
*v
)
711 _tnl_TexCoord2fv( const GLfloat
*v
)
713 TEXCOORD2F(v
[0], v
[1]);
717 _tnl_TexCoord3fv( const GLfloat
*v
)
719 TEXCOORD3(v
[0], v
[1], v
[2]);
723 _tnl_TexCoord4fv( const GLfloat
*v
)
725 TEXCOORD4(v
[0], v
[1], v
[2], v
[3]);
730 /* KW: Run into bad problems in vertex copying if we don't fully pad
731 * the incoming vertices.
733 #define VERTEX2(IM, x,y) \
735 GLuint count = IM->Count++; \
736 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
737 IM->Flag[count] |= VERT_BIT_POS; \
738 ASSIGN_4V(dest, x, y, 0, 1); \
739 /* ASSERT(IM->Flag[IM->Count]==0); */ \
740 if (count == IMM_MAXDATA - 1) \
741 _tnl_flush_immediate( NULL, IM ); \
744 #define VERTEX3(IM,x,y,z) \
746 GLuint count = IM->Count++; \
747 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
748 IM->Flag[count] |= VERT_BITS_OBJ_23; \
749 ASSIGN_4V(dest, x, y, z, 1); \
750 /* ASSERT(IM->Flag[IM->Count]==0); */ \
751 if (count == IMM_MAXDATA - 1) \
752 _tnl_flush_immediate( NULL, IM ); \
755 #define VERTEX4(IM, x,y,z,w) \
757 GLuint count = IM->Count++; \
758 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
759 IM->Flag[count] |= VERT_BITS_OBJ_234; \
760 ASSIGN_4V(dest, x, y, z, w); \
761 if (count == IMM_MAXDATA - 1) \
762 _tnl_flush_immediate( NULL, IM ); \
765 #if defined(USE_IEEE)
766 #define VERTEX2F(IM, x, y) \
768 GLuint count = IM->Count++; \
769 fi_type *dest = (fi_type *)IM->Attrib[VERT_ATTRIB_POS][count]; \
770 IM->Flag[count] |= VERT_BIT_POS; \
771 dest[0].i = ((fi_type *)&(x))->i; \
772 dest[1].i = ((fi_type *)&(y))->i; \
774 dest[3].i = IEEE_ONE; \
775 /* ASSERT(IM->Flag[IM->Count]==0); */ \
776 if (count == IMM_MAXDATA - 1) \
777 _tnl_flush_immediate( NULL, IM ); \
780 #define VERTEX2F VERTEX2
783 #if defined(USE_IEEE)
784 #define VERTEX3F(IM, x, y, z) \
786 GLuint count = IM->Count++; \
787 fi_type *dest = (fi_type *)IM->Attrib[VERT_ATTRIB_POS][count]; \
788 IM->Flag[count] |= VERT_BITS_OBJ_23; \
789 dest[0].i = ((fi_type *)&(x))->i; \
790 dest[1].i = ((fi_type *)&(y))->i; \
791 dest[2].i = ((fi_type *)&(z))->i; \
792 dest[3].i = IEEE_ONE; \
793 /* ASSERT(IM->Flag[IM->Count]==0); */ \
794 if (count == IMM_MAXDATA - 1) \
795 _tnl_flush_immediate( NULL, IM ); \
798 #define VERTEX3F VERTEX3
801 #if defined(USE_IEEE)
802 #define VERTEX4F(IM, x, y, z, w) \
804 GLuint count = IM->Count++; \
805 fi_type *dest = (fi_type *)IM->Attrib[VERT_ATTRIB_POS][count]; \
806 IM->Flag[count] |= VERT_BITS_OBJ_234; \
807 dest[0].i = ((fi_type *)&(x))->i; \
808 dest[1].i = ((fi_type *)&(y))->i; \
809 dest[2].i = ((fi_type *)&(z))->i; \
810 dest[3].i = ((fi_type *)&(w))->i; \
811 if (count == IMM_MAXDATA - 1) \
812 _tnl_flush_immediate( NULL, IM ); \
815 #define VERTEX4F VERTEX4
821 _tnl_Vertex2f( GLfloat x
, GLfloat y
)
824 VERTEX2F( IM
, x
, y
);
828 _tnl_Vertex3f( GLfloat x
, GLfloat y
, GLfloat z
)
831 VERTEX3F( IM
, x
, y
, z
);
834 _tnl_Vertex4f( GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
837 VERTEX4F( IM
, x
, y
, z
, w
);
841 _tnl_Vertex2fv( const GLfloat
*v
)
844 VERTEX2F( IM
, v
[0], v
[1] );
848 _tnl_Vertex3fv( const GLfloat
*v
)
851 VERTEX3F( IM
, v
[0], v
[1], v
[2] );
855 _tnl_Vertex4fv( const GLfloat
*v
)
858 VERTEX4F( IM
, v
[0], v
[1], v
[2], v
[3] );
865 * GL_ARB_multitexture
867 * Note: the multitexture spec says that specifying an invalid target
868 * has undefined results and does not have to generate an error. Just
869 * don't crash. We no-op on invalid targets.
872 #define MAX_TARGET (GL_TEXTURE0_ARB + MAX_TEXTURE_UNITS)
874 #define MULTI_TEXCOORD1(target, s) \
877 GLuint texunit = target - GL_TEXTURE0_ARB; \
878 if (texunit < IM->MaxTextureUnits) { \
879 GLuint count = IM->Count; \
880 GLfloat *tc = IM->Attrib[VERT_ATTRIB_TEX0 + texunit][count]; \
881 ASSIGN_4V(tc, s, 0.0F, 0.0F, 1.0F); \
882 IM->Flag[count] |= VERT_BIT_TEX(texunit); \
886 #define MULTI_TEXCOORD2(target, s, t) \
889 GLuint texunit = target - GL_TEXTURE0_ARB; \
890 if (texunit < IM->MaxTextureUnits) { \
891 GLuint count = IM->Count; \
892 GLfloat *tc = IM->Attrib[VERT_ATTRIB_TEX0 + texunit][count]; \
893 ASSIGN_4V(tc, s, t, 0.0F, 1.0F); \
894 IM->Flag[count] |= VERT_BIT_TEX(texunit); \
898 #define MULTI_TEXCOORD3(target, s, t, u) \
901 GLuint texunit = target - GL_TEXTURE0_ARB; \
902 if (texunit < IM->MaxTextureUnits) { \
903 GLuint count = IM->Count; \
904 GLfloat *tc = IM->Attrib[VERT_ATTRIB_TEX0 + texunit][count]; \
905 ASSIGN_4V(tc, s, t, u, 1.0F); \
906 IM->Flag[count] |= VERT_BIT_TEX(texunit); \
907 IM->TexSize |= TEX_SIZE_3(texunit); \
911 #define MULTI_TEXCOORD4(target, s, t, u, v) \
914 GLuint texunit = target - GL_TEXTURE0_ARB; \
915 if (texunit < IM->MaxTextureUnits) { \
916 GLuint count = IM->Count; \
917 GLfloat *tc = IM->Attrib[VERT_ATTRIB_TEX0 + texunit][count]; \
918 ASSIGN_4V(tc, s, t, u, v); \
919 IM->Flag[count] |= VERT_BIT_TEX(texunit); \
920 IM->TexSize |= TEX_SIZE_4(texunit); \
924 #if defined(USE_IEEE)
925 #define MULTI_TEXCOORD2F(target, s, t) \
928 GLuint texunit = target - GL_TEXTURE0_ARB; \
929 if (texunit < IM->MaxTextureUnits) { \
930 GLuint count = IM->Count; \
931 fi_type *tc = (fi_type *)IM->Attrib[VERT_ATTRIB_TEX0 + texunit][count];\
932 IM->Flag[count] |= VERT_BIT_TEX(texunit); \
933 tc[0].i = ((fi_type *)&(s))->i; \
934 tc[1].i = ((fi_type *)&(t))->i; \
936 tc[3].i = IEEE_ONE; \
940 #define MULTI_TEXCOORD2F MULTI_TEXCOORD2
944 _tnl_MultiTexCoord1fARB(GLenum target
, GLfloat s
)
946 MULTI_TEXCOORD1( target
, s
);
950 _tnl_MultiTexCoord1fvARB(GLenum target
, const GLfloat
*v
)
952 MULTI_TEXCOORD1( target
, v
[0] );
956 _tnl_MultiTexCoord2fARB(GLenum target
, GLfloat s
, GLfloat t
)
958 MULTI_TEXCOORD2F( target
, s
, t
);
962 _tnl_MultiTexCoord2fvARB(GLenum target
, const GLfloat
*v
)
964 MULTI_TEXCOORD2F( target
, v
[0], v
[1] );
968 _tnl_MultiTexCoord3fARB(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
)
970 MULTI_TEXCOORD3( target
, s
, t
, r
);
974 _tnl_MultiTexCoord3fvARB(GLenum target
, const GLfloat
*v
)
976 MULTI_TEXCOORD3( target
, v
[0], v
[1], v
[2] );
980 _tnl_MultiTexCoord4fARB(GLenum target
, GLfloat s
, GLfloat t
, GLfloat r
, GLfloat q
)
982 MULTI_TEXCOORD4( target
, s
, t
, r
, q
);
986 _tnl_MultiTexCoord4fvARB(GLenum target
, const GLfloat
*v
)
988 MULTI_TEXCOORD4( target
, v
[0], v
[1], v
[2], v
[3] );
993 /* KW: Because the eval values don't become 'current', fixup will flow
994 * through these vertices, and then evaluation will write on top
995 * of the fixup results.
997 * Note: using Obj to hold eval coord data.
999 #define EVALCOORD1(IM, x) \
1001 GLuint count = IM->Count++; \
1002 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
1003 IM->Flag[count] |= VERT_BIT_EVAL_C1; \
1004 ASSIGN_4V(dest, x, 0, 0, 1); \
1005 if (count == IMM_MAXDATA-1) \
1006 _tnl_flush_immediate( NULL, IM ); \
1009 #define EVALCOORD2(IM, x, y) \
1011 GLuint count = IM->Count++; \
1012 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
1013 IM->Flag[count] |= VERT_BIT_EVAL_C2; \
1014 ASSIGN_4V(dest, x, y, 0, 1); \
1015 if (count == IMM_MAXDATA-1) \
1016 _tnl_flush_immediate( NULL, IM ); \
1019 #define EVALPOINT1(IM, x) \
1021 GLuint count = IM->Count++; \
1022 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
1023 IM->Flag[count] |= VERT_BIT_EVAL_P1; \
1024 ASSIGN_4V(dest, x, 0, 0, 1); \
1025 if (count == IMM_MAXDATA-1) \
1026 _tnl_flush_immediate( NULL, IM ); \
1029 #define EVALPOINT2(IM, x, y) \
1031 GLuint count = IM->Count++; \
1032 GLfloat *dest = IM->Attrib[VERT_ATTRIB_POS][count]; \
1033 IM->Flag[count] |= VERT_BIT_EVAL_P2; \
1034 ASSIGN_4V(dest, x, y, 0, 1); \
1035 if (count == IMM_MAXDATA-1) \
1036 _tnl_flush_immediate( NULL, IM ); \
1040 _tnl_EvalCoord1f( GLfloat u
)
1043 EVALCOORD1( IM
, u
);
1047 _tnl_EvalCoord1fv( const GLfloat
*u
)
1050 EVALCOORD1( IM
, (GLfloat
) *u
);
1054 _tnl_EvalCoord2f( GLfloat u
, GLfloat v
)
1057 EVALCOORD2( IM
, u
, v
);
1061 _tnl_EvalCoord2fv( const GLfloat
*u
)
1064 EVALCOORD2( IM
, u
[0], u
[1] );
1069 _tnl_EvalPoint1( GLint i
)
1072 EVALPOINT1( IM
, (GLfloat
) i
);
1077 _tnl_EvalPoint2( GLint i
, GLint j
)
1080 EVALPOINT2( IM
, (GLfloat
) i
, (GLfloat
) j
);
1084 /* Need to use the default array-elt outside begin/end for strict
1087 #define ARRAY_ELT( IM, i ) \
1089 GLuint count = IM->Count; \
1090 IM->Elt[count] = i; \
1091 IM->Flag[count] &= IM->ArrayEltFlags; \
1092 IM->Flag[count] |= VERT_BIT_ELT; \
1093 IM->FlushElt = IM->ArrayEltFlush; \
1094 IM->Count += IM->ArrayEltIncr; \
1095 if (IM->Count == IMM_MAXDATA) \
1096 _tnl_flush_immediate( NULL, IM ); \
1101 _tnl_ArrayElement( GLint i
)
1108 /* Internal functions. These are safe to use providing either:
1110 * - It is determined that a display list is not being compiled, or
1111 * if so that these commands won't be compiled into the list (see
1112 * t_eval.c for an example).
1114 * - _tnl_hard_begin() is used instead of _tnl_[bB]egin, and tested
1115 * for a GL_TRUE return value. See _tnl_Rectf, below.
1118 _tnl_eval_coord1f( GLcontext
*CC
, GLfloat u
)
1120 struct immediate
*i
= TNL_CURRENT_IM(CC
);
1125 _tnl_eval_coord2f( GLcontext
*CC
, GLfloat u
, GLfloat v
)
1127 struct immediate
*i
= TNL_CURRENT_IM(CC
);
1128 EVALCOORD2( i
, u
, v
);
1139 _tnl_VertexAttrib4fNV( GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
, GLfloat w
)
1143 const GLuint count
= IM
->Count
;
1144 GLfloat
*attrib
= IM
->Attrib
[index
][count
];
1145 ASSIGN_4V(attrib
, x
, y
, z
, w
);
1146 IM
->Flag
[count
] |= (1 << index
);
1149 if (count
== IMM_MAXDATA
- 1)
1150 _tnl_flush_immediate( NULL
, IM
);
1156 _tnl_VertexAttrib4fvNV( GLuint index
, const GLfloat
*v
)
1160 const GLuint count
= IM
->Count
;
1161 GLfloat
*attrib
= IM
->Attrib
[index
][count
];
1163 IM
->Flag
[count
] |= (1 << index
);
1166 if (count
== IMM_MAXDATA
- 1)
1167 _tnl_flush_immediate( NULL
, IM
);
1173 /* Execute a glRectf() function. _tnl_hard_begin() ensures the check
1174 * on outside_begin_end is executed even in compiled lists. These
1175 * vertices can now participate in the same immediate as regular ones,
1176 * even in most display lists.
1179 _tnl_Rectf( GLfloat x1
, GLfloat y1
, GLfloat x2
, GLfloat y2
)
1181 GET_CURRENT_CONTEXT(ctx
);
1183 if (_tnl_hard_begin( ctx
, GL_QUADS
)) {
1184 glVertex2f( x1
, y1
);
1185 glVertex2f( x2
, y1
);
1186 glVertex2f( x2
, y2
);
1187 glVertex2f( x1
, y2
);
1193 _tnl_Materialfv( GLenum face
, GLenum pname
, const GLfloat
*params
)
1195 GET_CURRENT_CONTEXT(ctx
);
1196 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
1197 struct immediate
*IM
= TNL_CURRENT_IM(ctx
);
1198 GLuint count
= IM
->Count
;
1199 struct gl_material
*mat
;
1200 GLuint bitmask
= _mesa_material_bitmask(ctx
, face
, pname
, ~0, "Materialfv");
1205 if (MESA_VERBOSE
& VERBOSE_API
)
1206 _mesa_debug(ctx
, "_tnl_Materialfv\n");
1208 if (tnl
->IsolateMaterials
&&
1209 !(IM
->BeginState
& VERT_BEGIN_1
)) /* heuristic */
1211 _tnl_flush_immediate( ctx
, IM
);
1212 IM
= TNL_CURRENT_IM(ctx
);
1216 if (!(IM
->Flag
[count
] & VERT_BIT_MATERIAL
)) {
1217 if (!IM
->Material
) {
1218 IM
->Material
= (struct gl_material (*)[2])
1219 MALLOC( sizeof(struct gl_material
) * IMM_SIZE
* 2 );
1220 IM
->MaterialMask
= (GLuint
*) MALLOC( sizeof(GLuint
) * IMM_SIZE
);
1221 IM
->MaterialMask
[IM
->LastMaterial
] = 0;
1223 else if (IM
->MaterialOrMask
& ~bitmask
) {
1224 _mesa_copy_material_pairs( IM
->Material
[count
],
1225 IM
->Material
[IM
->LastMaterial
],
1226 IM
->MaterialOrMask
& ~bitmask
);
1229 IM
->Flag
[count
] |= VERT_BIT_MATERIAL
;
1230 IM
->MaterialMask
[count
] = 0;
1231 IM
->MaterialAndMask
&= IM
->MaterialMask
[IM
->LastMaterial
];
1232 IM
->LastMaterial
= count
;
1235 IM
->MaterialOrMask
|= bitmask
;
1236 IM
->MaterialMask
[count
] |= bitmask
;
1237 mat
= IM
->Material
[count
];
1239 if (bitmask
& FRONT_AMBIENT_BIT
) {
1240 COPY_4FV( mat
[0].Ambient
, params
);
1242 if (bitmask
& BACK_AMBIENT_BIT
) {
1243 COPY_4FV( mat
[1].Ambient
, params
);
1245 if (bitmask
& FRONT_DIFFUSE_BIT
) {
1246 COPY_4FV( mat
[0].Diffuse
, params
);
1248 if (bitmask
& BACK_DIFFUSE_BIT
) {
1249 COPY_4FV( mat
[1].Diffuse
, params
);
1251 if (bitmask
& FRONT_SPECULAR_BIT
) {
1252 COPY_4FV( mat
[0].Specular
, params
);
1254 if (bitmask
& BACK_SPECULAR_BIT
) {
1255 COPY_4FV( mat
[1].Specular
, params
);
1257 if (bitmask
& FRONT_EMISSION_BIT
) {
1258 COPY_4FV( mat
[0].Emission
, params
);
1260 if (bitmask
& BACK_EMISSION_BIT
) {
1261 COPY_4FV( mat
[1].Emission
, params
);
1263 if (bitmask
& FRONT_SHININESS_BIT
) {
1264 GLfloat shininess
= CLAMP( params
[0], 0.0F
, 128.0F
);
1265 mat
[0].Shininess
= shininess
;
1267 if (bitmask
& BACK_SHININESS_BIT
) {
1268 GLfloat shininess
= CLAMP( params
[0], 0.0F
, 128.0F
);
1269 mat
[1].Shininess
= shininess
;
1271 if (bitmask
& FRONT_INDEXES_BIT
) {
1272 mat
[0].AmbientIndex
= params
[0];
1273 mat
[0].DiffuseIndex
= params
[1];
1274 mat
[0].SpecularIndex
= params
[2];
1276 if (bitmask
& BACK_INDEXES_BIT
) {
1277 mat
[1].AmbientIndex
= params
[0];
1278 mat
[1].DiffuseIndex
= params
[1];
1279 mat
[1].SpecularIndex
= params
[2];
1282 if (tnl
->IsolateMaterials
&&
1283 !(IM
->BeginState
& VERT_BEGIN_1
)) /* heuristic */
1285 _tnl_flush_immediate( ctx
, IM
);
1289 void _tnl_imm_vtxfmt_init( GLcontext
*ctx
)
1291 GLvertexformat
*vfmt
= &(TNL_CONTEXT(ctx
)->vtxfmt
);
1293 /* All begin/end operations are handled by this vertex format:
1295 vfmt
->ArrayElement
= _tnl_ArrayElement
;
1296 vfmt
->Begin
= _tnl_Begin
;
1297 vfmt
->Color3f
= _tnl_Color3f
;
1298 vfmt
->Color3fv
= _tnl_Color3fv
;
1299 vfmt
->Color3ub
= _tnl_Color3ub
;
1300 vfmt
->Color3ubv
= _tnl_Color3ubv
;
1301 vfmt
->Color4f
= _tnl_Color4f
;
1302 vfmt
->Color4fv
= _tnl_Color4fv
;
1303 vfmt
->Color4ub
= _tnl_Color4ub
;
1304 vfmt
->Color4ubv
= _tnl_Color4ubv
;
1305 vfmt
->EdgeFlag
= _tnl_EdgeFlag
;
1306 vfmt
->EdgeFlagv
= _tnl_EdgeFlagv
;
1307 vfmt
->End
= _tnl_End
;
1308 vfmt
->EvalCoord1f
= _tnl_EvalCoord1f
;
1309 vfmt
->EvalCoord1fv
= _tnl_EvalCoord1fv
;
1310 vfmt
->EvalCoord2f
= _tnl_EvalCoord2f
;
1311 vfmt
->EvalCoord2fv
= _tnl_EvalCoord2fv
;
1312 vfmt
->EvalPoint1
= _tnl_EvalPoint1
;
1313 vfmt
->EvalPoint2
= _tnl_EvalPoint2
;
1314 vfmt
->FogCoordfEXT
= _tnl_FogCoordfEXT
;
1315 vfmt
->FogCoordfvEXT
= _tnl_FogCoordfvEXT
;
1316 vfmt
->Indexi
= _tnl_Indexi
;
1317 vfmt
->Indexiv
= _tnl_Indexiv
;
1318 vfmt
->Materialfv
= _tnl_Materialfv
;
1319 vfmt
->MultiTexCoord1fARB
= _tnl_MultiTexCoord1fARB
;
1320 vfmt
->MultiTexCoord1fvARB
= _tnl_MultiTexCoord1fvARB
;
1321 vfmt
->MultiTexCoord2fARB
= _tnl_MultiTexCoord2fARB
;
1322 vfmt
->MultiTexCoord2fvARB
= _tnl_MultiTexCoord2fvARB
;
1323 vfmt
->MultiTexCoord3fARB
= _tnl_MultiTexCoord3fARB
;
1324 vfmt
->MultiTexCoord3fvARB
= _tnl_MultiTexCoord3fvARB
;
1325 vfmt
->MultiTexCoord4fARB
= _tnl_MultiTexCoord4fARB
;
1326 vfmt
->MultiTexCoord4fvARB
= _tnl_MultiTexCoord4fvARB
;
1327 vfmt
->Normal3f
= _tnl_Normal3f
;
1328 vfmt
->Normal3fv
= _tnl_Normal3fv
;
1329 vfmt
->SecondaryColor3fEXT
= _tnl_SecondaryColor3fEXT
;
1330 vfmt
->SecondaryColor3fvEXT
= _tnl_SecondaryColor3fvEXT
;
1331 vfmt
->SecondaryColor3ubEXT
= _tnl_SecondaryColor3ubEXT
;
1332 vfmt
->SecondaryColor3ubvEXT
= _tnl_SecondaryColor3ubvEXT
;
1333 vfmt
->TexCoord1f
= _tnl_TexCoord1f
;
1334 vfmt
->TexCoord1fv
= _tnl_TexCoord1fv
;
1335 vfmt
->TexCoord2f
= _tnl_TexCoord2f
;
1336 vfmt
->TexCoord2fv
= _tnl_TexCoord2fv
;
1337 vfmt
->TexCoord3f
= _tnl_TexCoord3f
;
1338 vfmt
->TexCoord3fv
= _tnl_TexCoord3fv
;
1339 vfmt
->TexCoord4f
= _tnl_TexCoord4f
;
1340 vfmt
->TexCoord4fv
= _tnl_TexCoord4fv
;
1341 vfmt
->Vertex2f
= _tnl_Vertex2f
;
1342 vfmt
->Vertex2fv
= _tnl_Vertex2fv
;
1343 vfmt
->Vertex3f
= _tnl_Vertex3f
;
1344 vfmt
->Vertex3fv
= _tnl_Vertex3fv
;
1345 vfmt
->Vertex4f
= _tnl_Vertex4f
;
1346 vfmt
->Vertex4fv
= _tnl_Vertex4fv
;
1347 vfmt
->VertexAttrib4fNV
= _tnl_VertexAttrib4fNV
;
1348 vfmt
->VertexAttrib4fvNV
= _tnl_VertexAttrib4fvNV
;
1350 /* Outside begin/end functions (from t_varray.c, t_eval.c, ...):
1352 vfmt
->Rectf
= _tnl_Rectf
;
1354 /* Just use the core function:
1356 vfmt
->CallList
= _mesa_CallList
;
1358 vfmt
->prefer_float_colors
= GL_FALSE
;