3 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
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 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keith@tungstengraphics.com>
37 #include "t_context.h"
38 #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 ctx
->Exec
->VertexAttrib1fvNV(target
, v
);
77 static void VertexAttrib2fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
79 ctx
->Exec
->VertexAttrib2fvNV(target
, v
);
82 static void VertexAttrib3fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
84 ctx
->Exec
->VertexAttrib3fvNV(target
, v
);
87 static void VertexAttrib4fvNV(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
89 ctx
->Exec
->VertexAttrib4fvNV(target
, v
);
92 static attr_func vert_attrfunc
[4] = {
100 static void mat_attr1fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
103 case _TNL_ATTRIB_MAT_FRONT_SHININESS
:
104 ctx
->Exec
->Materialfv( GL_FRONT
, GL_SHININESS
, v
);
106 case _TNL_ATTRIB_MAT_BACK_SHININESS
:
107 ctx
->Exec
->Materialfv( GL_BACK
, GL_SHININESS
, v
);
113 static void mat_attr3fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
116 case _TNL_ATTRIB_MAT_FRONT_INDEXES
:
117 ctx
->Exec
->Materialfv( GL_FRONT
, GL_COLOR_INDEXES
, v
);
119 case _TNL_ATTRIB_MAT_BACK_INDEXES
:
120 ctx
->Exec
->Materialfv( GL_BACK
, GL_COLOR_INDEXES
, v
);
126 static void mat_attr4fv( GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
129 case _TNL_ATTRIB_MAT_FRONT_EMISSION
:
130 ctx
->Exec
->Materialfv( GL_FRONT
, GL_EMISSION
, v
);
132 case _TNL_ATTRIB_MAT_BACK_EMISSION
:
133 ctx
->Exec
->Materialfv( GL_BACK
, GL_EMISSION
, v
);
135 case _TNL_ATTRIB_MAT_FRONT_AMBIENT
:
136 ctx
->Exec
->Materialfv( GL_FRONT
, GL_AMBIENT
, v
);
138 case _TNL_ATTRIB_MAT_BACK_AMBIENT
:
139 ctx
->Exec
->Materialfv( GL_BACK
, GL_AMBIENT
, v
);
141 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE
:
142 ctx
->Exec
->Materialfv( GL_FRONT
, GL_DIFFUSE
, v
);
144 case _TNL_ATTRIB_MAT_BACK_DIFFUSE
:
145 ctx
->Exec
->Materialfv( GL_BACK
, GL_DIFFUSE
, v
);
147 case _TNL_ATTRIB_MAT_FRONT_SPECULAR
:
148 ctx
->Exec
->Materialfv( GL_FRONT
, GL_SPECULAR
, v
);
150 case _TNL_ATTRIB_MAT_BACK_SPECULAR
:
151 ctx
->Exec
->Materialfv( GL_BACK
, GL_SPECULAR
, v
);
157 static attr_func mat_attrfunc
[4] = {
165 static void index_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
168 ctx
->Exec
->Indexf(v
[0]);
171 static void edgeflag_attr1fv(GLcontext
*ctx
, GLint target
, const GLfloat
*v
)
174 ctx
->Exec
->EdgeFlag((GLboolean
)(v
[0] == 1.0));
177 struct loopback_attr
{
183 /* Don't emit ends and begins on wrapped primitives. Don't replay
184 * wrapped vertices. If we get here, it's probably because the the
185 * precalculated wrapping is wrong.
187 static void loopback_prim( GLcontext
*ctx
,
188 const struct tnl_vertex_list
*list
, GLuint i
,
189 const struct loopback_attr
*la
, GLuint nr
)
191 struct tnl_prim
*prim
= &list
->prim
[i
];
192 GLint begin
= prim
->start
;
193 GLint end
= begin
+ prim
->count
;
198 if (prim
->mode
& PRIM_BEGIN
) {
199 glBegin( prim
->mode
& PRIM_MODE_MASK
);
204 begin
+= list
->wrap_count
;
207 data
= list
->buffer
+ begin
* list
->vertex_size
;
209 for (j
= begin
; j
< end
; j
++) {
210 GLfloat
*tmp
= data
+ la
[0].sz
;
212 for (k
= 1 ; k
< nr
; k
++) {
213 la
[k
].func( ctx
, la
[k
].target
, tmp
);
219 la
[0].func( ctx
, VERT_ATTRIB_POS
, data
);
223 if (prim
->mode
& PRIM_END
) {
227 assert (i
== list
->prim_count
-1);
231 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
232 * caught here. If there is no primitive in progress, execute them
233 * normally, otherwise need to track and discard the generated
236 static void loopback_weak_prim( GLcontext
*ctx
,
237 const struct tnl_vertex_list
*list
, GLuint i
,
238 const struct loopback_attr
*la
, GLuint nr
)
240 if (ctx
->Driver
.CurrentExecPrimitive
== PRIM_OUTSIDE_BEGIN_END
)
241 loopback_prim( ctx
, list
, i
, la
, nr
);
243 struct tnl_prim
*prim
= &list
->prim
[i
];
245 /* Use the prim_weak flag to ensure that if this primitive
246 * wraps, we don't mistake future vertex_lists for part of the
247 * surrounding primitive.
249 * While this flag is set, we are simply disposing of data
250 * generated by an operation now known to be a noop.
252 if (prim
->mode
& PRIM_BEGIN
)
253 ctx
->Driver
.CurrentExecPrimitive
|= PRIM_WEAK
;
254 if (prim
->mode
& PRIM_END
)
255 ctx
->Driver
.CurrentExecPrimitive
&= ~PRIM_WEAK
;
261 void _tnl_loopback_vertex_list( GLcontext
*ctx
,
262 const struct tnl_vertex_list
*list
)
264 struct loopback_attr la
[_TNL_ATTRIB_MAX
];
267 for (i
= 0 ; i
<= _TNL_ATTRIB_TEX7
; i
++) {
268 if (list
->attrsz
[i
]) {
270 la
[nr
].sz
= list
->attrsz
[i
];
271 la
[nr
].func
= vert_attrfunc
[list
->attrsz
[i
]-1];
276 for (i
= _TNL_ATTRIB_MAT_FRONT_AMBIENT
;
277 i
<= _TNL_ATTRIB_MAT_BACK_INDEXES
;
279 if (list
->attrsz
[i
]) {
281 la
[nr
].sz
= list
->attrsz
[i
];
282 la
[nr
].func
= mat_attrfunc
[list
->attrsz
[i
]-1];
287 if (list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
]) {
288 la
[nr
].target
= _TNL_ATTRIB_EDGEFLAG
;
289 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_EDGEFLAG
];
290 la
[nr
].func
= edgeflag_attr1fv
;
294 if (list
->attrsz
[_TNL_ATTRIB_INDEX
]) {
295 la
[nr
].target
= _TNL_ATTRIB_INDEX
;
296 la
[nr
].sz
= list
->attrsz
[_TNL_ATTRIB_INDEX
];
297 la
[nr
].func
= index_attr1fv
;
301 for (i
= 0 ; i
< list
->prim_count
; i
++) {
302 if (list
->prim
[i
].mode
& PRIM_WEAK
)
303 loopback_weak_prim( ctx
, list
, i
, la
, nr
);
305 loopback_prim( ctx
, list
, i
, la
, nr
);