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 edgeflag_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
201 CALL_EdgeFlag(ctx
->Exec
, ((GLboolean
)(v
[0] == 1.0)));
204 struct loopback_attr
{
210 /* Don't emit ends and begins on wrapped primitives. Don't replay
211 * wrapped vertices. If we get here, it's probably because the the
212 * precalculated wrapping is wrong.
214 static void loopback_prim( GLcontext
*ctx
,
215 const struct tnl_vertex_list
*list
, GLuint i
,
216 const struct loopback_attr
*la
, GLuint nr
)
218 struct tnl_prim
*prim
= &list
->prim
[i
];
219 GLint begin
= prim
->start
;
220 GLint end
= begin
+ prim
->count
;
225 if (prim
->mode
& PRIM_BEGIN
) {
226 CALL_Begin(GET_DISPATCH(), ( prim
->mode
& PRIM_MODE_MASK
));
231 begin
+= list
->wrap_count
;
234 data
= list
->buffer
+ begin
* list
->vertex_size
;
236 for (j
= begin
; j
< end
; j
++) {
237 GLfloat
*tmp
= data
+ la
[0].sz
;
239 for (k
= 1 ; k
< nr
; k
++) {
240 la
[k
].func( ctx
, la
[k
].target
, tmp
);
246 la
[0].func( ctx
, VERT_ATTRIB_POS
, data
);
250 if (prim
->mode
& PRIM_END
) {
251 CALL_End(GET_DISPATCH(), ());
254 assert (i
== list
->prim_count
-1);
258 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
259 * caught here. If there is no primitive in progress, execute them
260 * normally, otherwise need to track and discard the generated
263 static void loopback_weak_prim( GLcontext
*ctx
,
264 const struct tnl_vertex_list
*list
, GLuint i
,
265 const struct loopback_attr
*la
, GLuint nr
)
267 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
)
268 loopback_prim( ctx
, list
, i
, la
, nr
);
270 struct tnl_prim
*prim
= &list
->prim
[i
];
272 /* Use the prim_weak flag to ensure that if this primitive
273 * wraps, we don't mistake future vertex_lists for part of the
274 * surrounding primitive.
276 * While this flag is set, we are simply disposing of data
277 * generated by an operation now known to be a noop.
279 if (prim
->mode
& PRIM_BEGIN
)
280 ctx
->Driver
.CurrentExecPrimitive
|= PRIM_WEAK
;
281 if (prim
->mode
& PRIM_END
)
282 ctx
->Driver
.CurrentExecPrimitive
&= ~PRIM_WEAK
;
288 void _tnl_loopback_vertex_list( GLcontext
*ctx
,
289 const struct tnl_vertex_list
*list
)
291 struct loopback_attr la
[_TNL_ATTRIB_MAX
];
294 /* conventional + generic attributes */
295 for (i
= 0 ; i
<= _TNL_ATTRIB_GENERIC15
; i
++) {
296 if (list
->attrsz
[i
]) {
298 la
[nr
].sz
= list
->attrsz
[i
];
299 la
[nr
].func
= vert_attrfunc
[list
->attrsz
[i
]-1];
304 /* material attributes */
305 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
306 i
<= _TNL_ATTRIB_MAT_BACK_INDEXES
;
308 if (list
->attrsz
[i
]) {
310 la
[nr
].sz
= list
->attrsz
[i
];
311 la
[nr
].func
= mat_attrfunc
[list
->attrsz
[i
]-1];
316 /* special-case: edgeflag */
317 if (list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
318 la
[nr
].target
= _TNL_ATTRIB_EDGEFLAG
;
319 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
];
320 la
[nr
].func
= edgeflag_attr1fv
;
324 for (i
= 0 ; i
< list
->prim_count
; i
++) {
325 if (list
->prim
[i
].mode
& PRIM_WEAK
)
326 loopback_weak_prim( ctx
, list
, i
, la
, nr
);
328 loopback_prim( ctx
, list
, i
, la
, nr
);