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"
39 /* If someone compiles a display list like:
42 * ... lots of vertices ...
48 * and then tries to execute it like this:
54 * it will wind up in here, as the vertex copying used when wrapping
55 * buffers in list compilation (Triangles) won't be right for how the
56 * list is being executed (as Lines).
58 * This could be avoided by not compiling as vertex_lists until after
59 * the first glEnd() has been seen. However, that would miss an
60 * important category of display lists, for the sake of a degenerate
63 * Further, replaying degenerately-called lists in this fashion is
64 * probably still faster than the replay using opcodes.
67 typedef void (*attr_func
)( GLcontext
*ctx
, GLint target
, const GLfloat
* );
70 /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
71 static void VertexAttrib1fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
73 ctx
->Exec
->VertexAttrib1fvNV(target
, v
);
76 static void VertexAttrib2fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
78 ctx
->Exec
->VertexAttrib2fvNV(target
, v
);
81 static void VertexAttrib3fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
83 ctx
->Exec
->VertexAttrib3fvNV(target
, v
);
86 static void VertexAttrib4fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
88 ctx
->Exec
->VertexAttrib4fvNV(target
, v
);
91 static attr_func vert_attrfunc
[4] = {
99 static void VertexAttrib1fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
101 ctx
->Exec
->VertexAttrib1fvARB(target
, v
);
104 static void VertexAttrib2fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
106 ctx
->Exec
->VertexAttrib2fvARB(target
, v
);
109 static void VertexAttrib3fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
111 ctx
->Exec
->VertexAttrib3fvARB(target
, v
);
114 static void VertexAttrib4fvARB(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
116 ctx
->Exec
->VertexAttrib4fvARB(target
, v
);
119 static attr_func vert_attrfunc_arb
[4] = {
132 static void mat_attr1fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
135 case _TNL_ATTRIB_MAT_FRONT_SHININESS
:
136 ctx
->Exec
->Materialfv( GL_FRONT
, GL_SHININESS
, v
);
138 case _TNL_ATTRIB_MAT_BACK_SHININESS
:
139 ctx
->Exec
->Materialfv( GL_BACK
, GL_SHININESS
, v
);
145 static void mat_attr3fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
148 case _TNL_ATTRIB_MAT_FRONT_INDEXES
:
149 ctx
->Exec
->Materialfv( GL_FRONT
, GL_COLOR_INDEXES
, v
);
151 case _TNL_ATTRIB_MAT_BACK_INDEXES
:
152 ctx
->Exec
->Materialfv( GL_BACK
, GL_COLOR_INDEXES
, v
);
158 static void mat_attr4fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
161 case _TNL_ATTRIB_MAT_FRONT_EMISSION
:
162 ctx
->Exec
->Materialfv( GL_FRONT
, GL_EMISSION
, v
);
164 case _TNL_ATTRIB_MAT_BACK_EMISSION
:
165 ctx
->Exec
->Materialfv( GL_BACK
, GL_EMISSION
, v
);
167 case _TNL_ATTRIB_MAT_FRONT_AMBIENT
:
168 ctx
->Exec
->Materialfv( GL_FRONT
, GL_AMBIENT
, v
);
170 case _TNL_ATTRIB_MAT_BACK_AMBIENT
:
171 ctx
->Exec
->Materialfv( GL_BACK
, GL_AMBIENT
, v
);
173 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE
:
174 ctx
->Exec
->Materialfv( GL_FRONT
, GL_DIFFUSE
, v
);
176 case _TNL_ATTRIB_MAT_BACK_DIFFUSE
:
177 ctx
->Exec
->Materialfv( GL_BACK
, GL_DIFFUSE
, v
);
179 case _TNL_ATTRIB_MAT_FRONT_SPECULAR
:
180 ctx
->Exec
->Materialfv( GL_FRONT
, GL_SPECULAR
, v
);
182 case _TNL_ATTRIB_MAT_BACK_SPECULAR
:
183 ctx
->Exec
->Materialfv( GL_BACK
, GL_SPECULAR
, v
);
189 static attr_func mat_attrfunc
[4] = {
197 static void index_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
200 ctx
->Exec
->Indexf(v
[0]);
203 static void edgeflag_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
206 ctx
->Exec
->EdgeFlag((GLboolean
)(v
[0] == 1.0));
209 struct loopback_attr
{
215 /* Don't emit ends and begins on wrapped primitives. Don't replay
216 * wrapped vertices. If we get here, it's probably because the the
217 * precalculated wrapping is wrong.
219 static void loopback_prim( GLcontext
*ctx
,
220 const struct tnl_vertex_list
*list
, GLuint i
,
221 const struct loopback_attr
*la
, GLuint nr
)
223 struct tnl_prim
*prim
= &list
->prim
[i
];
224 GLint begin
= prim
->start
;
225 GLint end
= begin
+ prim
->count
;
230 if (prim
->mode
& PRIM_BEGIN
) {
231 GL_CALL(Begin
)( prim
->mode
& PRIM_MODE_MASK
);
236 begin
+= list
->wrap_count
;
239 data
= list
->buffer
+ begin
* list
->vertex_size
;
241 for (j
= begin
; j
< end
; j
++) {
242 GLfloat
*tmp
= data
+ la
[0].sz
;
244 for (k
= 1 ; k
< nr
; k
++) {
245 la
[k
].func( ctx
, la
[k
].target
, tmp
);
251 la
[0].func( ctx
, VERT_ATTRIB_POS
, data
);
255 if (prim
->mode
& PRIM_END
) {
259 assert (i
== list
->prim_count
-1);
263 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
264 * caught here. If there is no primitive in progress, execute them
265 * normally, otherwise need to track and discard the generated
268 static void loopback_weak_prim( GLcontext
*ctx
,
269 const struct tnl_vertex_list
*list
, GLuint i
,
270 const struct loopback_attr
*la
, GLuint nr
)
272 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
)
273 loopback_prim( ctx
, list
, i
, la
, nr
);
275 struct tnl_prim
*prim
= &list
->prim
[i
];
277 /* Use the prim_weak flag to ensure that if this primitive
278 * wraps, we don't mistake future vertex_lists for part of the
279 * surrounding primitive.
281 * While this flag is set, we are simply disposing of data
282 * generated by an operation now known to be a noop.
284 if (prim
->mode
& PRIM_BEGIN
)
285 ctx
->Driver
.CurrentExecPrimitive
|= PRIM_WEAK
;
286 if (prim
->mode
& PRIM_END
)
287 ctx
->Driver
.CurrentExecPrimitive
&= ~PRIM_WEAK
;
293 void _tnl_loopback_vertex_list( GLcontext
*ctx
,
294 const struct tnl_vertex_list
*list
)
296 struct loopback_attr la
[_TNL_ATTRIB_MAX
];
299 for (i
= 0 ; i
<= _TNL_ATTRIB_TEX7
; i
++) {
300 if (list
->attrsz
[i
]) {
302 la
[nr
].sz
= list
->attrsz
[i
];
303 la
[nr
].func
= vert_attrfunc
[list
->attrsz
[i
]-1];
308 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
309 i
<= _TNL_ATTRIB_MAT_BACK_INDEXES
;
311 if (list
->attrsz
[i
]) {
313 la
[nr
].sz
= list
->attrsz
[i
];
314 la
[nr
].func
= mat_attrfunc
[list
->attrsz
[i
]-1];
319 if (list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
320 la
[nr
].target
= _TNL_ATTRIB_EDGEFLAG
;
321 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
];
322 la
[nr
].func
= edgeflag_attr1fv
;
326 if (list
->attrsz
[_TNL_ATTRIB_INDEX
]) {
327 la
[nr
].target
= _TNL_ATTRIB_INDEX
;
328 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_INDEX
];
329 la
[nr
].func
= index_attr1fv
;
333 /* XXX ARB vertex attribs */
335 for (i
= 0 ; i
< list
->prim_count
; i
++) {
336 if (list
->prim
[i
].mode
& PRIM_WEAK
)
337 loopback_weak_prim( ctx
, list
, i
, la
, nr
);
339 loopback_prim( ctx
, list
, i
, la
, nr
);