2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Keith Whitwell <keith@tungstengraphics.com>
36 #include "t_context.h"
37 #include "t_save_api.h"
40 /* If someone compiles a display list like:
43 * ... lots of vertices ...
49 * and then tries to execute it like this:
55 * it will wind up in here, as the vertex copying used when wrapping
56 * buffers in list compilation (Triangles) won't be right for how the
57 * list is being executed (as Lines).
59 * This could be avoided by not compiling as vertex_lists until after
60 * the first glEnd() has been seen. However, that would miss an
61 * important category of display lists, for the sake of a degenerate
64 * Further, replaying degenerately-called lists in this fashion is
65 * probably still faster than the replay using opcodes.
68 typedef void (*attr_func
)( GLcontext
*ctx
, GLint target
, const GLfloat
* );
71 /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
72 static void VertexAttrib1fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
74 CALL_VertexAttrib1fvNV(ctx
->Exec
, (target
, v
));
77 static void VertexAttrib2fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
79 CALL_VertexAttrib2fvNV(ctx
->Exec
, (target
, v
));
82 static void VertexAttrib3fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
84 CALL_VertexAttrib3fvNV(ctx
->Exec
, (target
, v
));
87 static void VertexAttrib4fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
89 CALL_VertexAttrib4fvNV(ctx
->Exec
, (target
, v
));
92 static attr_func vert_attrfunc
[4] = {
100 static void VertexAttrib1fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
102 CALL_VertexAttrib1fvARB(ctx
->Exec
, (target
, v
));
105 static void VertexAttrib2fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
107 CALL_VertexAttrib2fvARB(ctx
->Exec
, (target
, v
));
110 static void VertexAttrib3fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
112 CALL_VertexAttrib3fvARB(ctx
->Exec
, (target
, v
));
115 static void VertexAttrib4fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
117 CALL_VertexAttrib4fvARB(ctx
->Exec
, (target
, v
));
120 static attr_func vert_attrfunc_arb
[4] = {
133 static void mat_attr1fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
136 case _TNL_ATTRIB_MAT_FRONT_SHININESS
:
137 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_SHININESS
, v
));
139 case _TNL_ATTRIB_MAT_BACK_SHININESS
:
140 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_SHININESS
, v
));
146 static void mat_attr3fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
149 case _TNL_ATTRIB_MAT_FRONT_INDEXES
:
150 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_COLOR_INDEXES
, v
));
152 case _TNL_ATTRIB_MAT_BACK_INDEXES
:
153 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_COLOR_INDEXES
, v
));
159 static void mat_attr4fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
162 case _TNL_ATTRIB_MAT_FRONT_EMISSION
:
163 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_EMISSION
, v
));
165 case _TNL_ATTRIB_MAT_BACK_EMISSION
:
166 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_EMISSION
, v
));
168 case _TNL_ATTRIB_MAT_FRONT_AMBIENT
:
169 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_AMBIENT
, v
));
171 case _TNL_ATTRIB_MAT_BACK_AMBIENT
:
172 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_AMBIENT
, v
));
174 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE
:
175 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_DIFFUSE
, v
));
177 case _TNL_ATTRIB_MAT_BACK_DIFFUSE
:
178 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_DIFFUSE
, v
));
180 case _TNL_ATTRIB_MAT_FRONT_SPECULAR
:
181 CALL_Materialfv(ctx
->Exec
, ( GL_FRONT
, GL_SPECULAR
, v
));
183 case _TNL_ATTRIB_MAT_BACK_SPECULAR
:
184 CALL_Materialfv(ctx
->Exec
, ( GL_BACK
, GL_SPECULAR
, v
));
190 static attr_func mat_attrfunc
[4] = {
198 static void index_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
201 CALL_Indexf(ctx
->Exec
, (v
[0]));
204 static void edgeflag_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
207 CALL_EdgeFlag(ctx
->Exec
, ((GLboolean
)(v
[0] == 1.0)));
210 struct loopback_attr
{
216 /* Don't emit ends and begins on wrapped primitives. Don't replay
217 * wrapped vertices. If we get here, it's probably because the the
218 * precalculated wrapping is wrong.
220 static void loopback_prim( GLcontext
*ctx
,
221 const struct tnl_vertex_list
*list
, GLuint i
,
222 const struct loopback_attr
*la
, GLuint nr
)
224 struct tnl_prim
*prim
= &list
->prim
[i
];
225 GLint begin
= prim
->start
;
226 GLint end
= begin
+ prim
->count
;
231 if (prim
->mode
& PRIM_BEGIN
) {
232 CALL_Begin(GET_DISPATCH(), ( prim
->mode
& PRIM_MODE_MASK
));
237 begin
+= list
->wrap_count
;
240 data
= list
->buffer
+ begin
* list
->vertex_size
;
242 for (j
= begin
; j
< end
; j
++) {
243 GLfloat
*tmp
= data
+ la
[0].sz
;
245 for (k
= 1 ; k
< nr
; k
++) {
246 la
[k
].func( ctx
, la
[k
].target
, tmp
);
252 la
[0].func( ctx
, VERT_ATTRIB_POS
, data
);
256 if (prim
->mode
& PRIM_END
) {
257 CALL_End(GET_DISPATCH(), ());
260 assert (i
== list
->prim_count
-1);
264 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
265 * caught here. If there is no primitive in progress, execute them
266 * normally, otherwise need to track and discard the generated
269 static void loopback_weak_prim( GLcontext
*ctx
,
270 const struct tnl_vertex_list
*list
, GLuint i
,
271 const struct loopback_attr
*la
, GLuint nr
)
273 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
)
274 loopback_prim( ctx
, list
, i
, la
, nr
);
276 struct tnl_prim
*prim
= &list
->prim
[i
];
278 /* Use the prim_weak flag to ensure that if this primitive
279 * wraps, we don't mistake future vertex_lists for part of the
280 * surrounding primitive.
282 * While this flag is set, we are simply disposing of data
283 * generated by an operation now known to be a noop.
285 if (prim
->mode
& PRIM_BEGIN
)
286 ctx
->Driver
.CurrentExecPrimitive
|= PRIM_WEAK
;
287 if (prim
->mode
& PRIM_END
)
288 ctx
->Driver
.CurrentExecPrimitive
&= ~PRIM_WEAK
;
294 void _tnl_loopback_vertex_list( GLcontext
*ctx
,
295 const struct tnl_vertex_list
*list
)
297 struct loopback_attr la
[_TNL_ATTRIB_MAX
];
300 for (i
= 0 ; i
<= _TNL_ATTRIB_TEX7
; i
++) {
301 if (list
->attrsz
[i
]) {
303 la
[nr
].sz
= list
->attrsz
[i
];
304 la
[nr
].func
= vert_attrfunc
[list
->attrsz
[i
]-1];
309 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
310 i
<= _TNL_ATTRIB_MAT_BACK_INDEXES
;
312 if (list
->attrsz
[i
]) {
314 la
[nr
].sz
= list
->attrsz
[i
];
315 la
[nr
].func
= mat_attrfunc
[list
->attrsz
[i
]-1];
320 if (list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
321 la
[nr
].target
= _TNL_ATTRIB_EDGEFLAG
;
322 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
];
323 la
[nr
].func
= edgeflag_attr1fv
;
327 if (list
->attrsz
[_TNL_ATTRIB_INDEX
]) {
328 la
[nr
].target
= _TNL_ATTRIB_INDEX
;
329 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_INDEX
];
330 la
[nr
].func
= index_attr1fv
;
334 /* XXX ARB vertex attribs */
336 for (i
= 0 ; i
< list
->prim_count
; i
++) {
337 if (list
->prim
[i
].mode
& PRIM_WEAK
)
338 loopback_weak_prim( ctx
, list
, i
, la
, nr
);
340 loopback_prim( ctx
, list
, i
, la
, nr
);