reindent, doxygen-style comments
[mesa.git] / src / mesa / tnl / t_save_loopback.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /* Author:
26 * Keith Whitwell <keith@tungstengraphics.com>
27 */
28
29 #include "glheader.h"
30 #include "context.h"
31 #include "enums.h"
32 #include "glapi.h"
33 #include "imports.h"
34 #include "macros.h"
35 #include "mtypes.h"
36 #include "t_context.h"
37 #include "t_save_api.h"
38 #include "dispatch.h"
39
40 /* If someone compiles a display list like:
41 * glBegin(Triangles)
42 * glVertex()
43 * ... lots of vertices ...
44 * glEnd()
45 *
46 * or:
47 * glDrawArrays(...)
48 *
49 * and then tries to execute it like this:
50 *
51 * glBegin(Lines)
52 * glCallList()
53 * glEnd()
54 *
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).
58 *
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
62 * usage.
63 *
64 * Further, replaying degenerately-called lists in this fashion is
65 * probably still faster than the replay using opcodes.
66 */
67
68 typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
69
70
71 /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
72 static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
73 {
74 CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
75 }
76
77 static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
78 {
79 CALL_VertexAttrib2fvNV(ctx->Exec, (target, v));
80 }
81
82 static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
83 {
84 CALL_VertexAttrib3fvNV(ctx->Exec, (target, v));
85 }
86
87 static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
88 {
89 CALL_VertexAttrib4fvNV(ctx->Exec, (target, v));
90 }
91
92 static attr_func vert_attrfunc[4] = {
93 VertexAttrib1fvNV,
94 VertexAttrib2fvNV,
95 VertexAttrib3fvNV,
96 VertexAttrib4fvNV
97 };
98
99
100 static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
101 {
102 CALL_VertexAttrib1fvARB(ctx->Exec, (target, v));
103 }
104
105 static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
106 {
107 CALL_VertexAttrib2fvARB(ctx->Exec, (target, v));
108 }
109
110 static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
111 {
112 CALL_VertexAttrib3fvARB(ctx->Exec, (target, v));
113 }
114
115 static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
116 {
117 CALL_VertexAttrib4fvARB(ctx->Exec, (target, v));
118 }
119
120 static attr_func vert_attrfunc_arb[4] = {
121 VertexAttrib1fvARB,
122 VertexAttrib2fvARB,
123 VertexAttrib3fvARB,
124 VertexAttrib4fvARB
125 };
126
127
128
129
130
131
132
133 static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
134 {
135 switch (target) {
136 case _TNL_ATTRIB_MAT_FRONT_SHININESS:
137 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SHININESS, v ));
138 break;
139 case _TNL_ATTRIB_MAT_BACK_SHININESS:
140 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SHININESS, v ));
141 break;
142 }
143 }
144
145
146 static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
147 {
148 switch (target) {
149 case _TNL_ATTRIB_MAT_FRONT_INDEXES:
150 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_COLOR_INDEXES, v ));
151 break;
152 case _TNL_ATTRIB_MAT_BACK_INDEXES:
153 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_COLOR_INDEXES, v ));
154 break;
155 }
156 }
157
158
159 static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
160 {
161 switch (target) {
162 case _TNL_ATTRIB_MAT_FRONT_EMISSION:
163 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_EMISSION, v ));
164 break;
165 case _TNL_ATTRIB_MAT_BACK_EMISSION:
166 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_EMISSION, v ));
167 break;
168 case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
169 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_AMBIENT, v ));
170 break;
171 case _TNL_ATTRIB_MAT_BACK_AMBIENT:
172 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_AMBIENT, v ));
173 break;
174 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
175 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_DIFFUSE, v ));
176 break;
177 case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
178 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_DIFFUSE, v ));
179 break;
180 case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
181 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SPECULAR, v ));
182 break;
183 case _TNL_ATTRIB_MAT_BACK_SPECULAR:
184 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SPECULAR, v ));
185 break;
186 }
187 }
188
189
190 static attr_func mat_attrfunc[4] = {
191 mat_attr1fv,
192 NULL,
193 mat_attr3fv,
194 mat_attr4fv
195 };
196
197
198 static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
199 {
200 (void) target;
201 CALL_EdgeFlag(ctx->Exec, ((GLboolean)(v[0] == 1.0)));
202 }
203
204 struct loopback_attr {
205 GLint target;
206 GLint sz;
207 attr_func func;
208 };
209
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.
213 */
214 static void loopback_prim( GLcontext *ctx,
215 const struct tnl_vertex_list *list, GLuint i,
216 const struct loopback_attr *la, GLuint nr )
217 {
218 struct tnl_prim *prim = &list->prim[i];
219 GLint begin = prim->start;
220 GLint end = begin + prim->count;
221 GLfloat *data;
222 GLint j;
223 GLuint k;
224
225 if (prim->mode & PRIM_BEGIN) {
226 CALL_Begin(GET_DISPATCH(), ( prim->mode & PRIM_MODE_MASK ));
227 }
228 else {
229 assert(i == 0);
230 assert(begin == 0);
231 begin += list->wrap_count;
232 }
233
234 data = list->buffer + begin * list->vertex_size;
235
236 for (j = begin ; j < end ; j++) {
237 GLfloat *tmp = data + la[0].sz;
238
239 for (k = 1 ; k < nr ; k++) {
240 la[k].func( ctx, la[k].target, tmp );
241 tmp += la[k].sz;
242 }
243
244 /* Fire the vertex
245 */
246 la[0].func( ctx, VERT_ATTRIB_POS, data );
247 data = tmp;
248 }
249
250 if (prim->mode & PRIM_END) {
251 CALL_End(GET_DISPATCH(), ());
252 }
253 else {
254 assert (i == list->prim_count-1);
255 }
256 }
257
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
261 * primitives.
262 */
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 )
266 {
267 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
268 loopback_prim( ctx, list, i, la, nr );
269 else {
270 struct tnl_prim *prim = &list->prim[i];
271
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.
275 *
276 * While this flag is set, we are simply disposing of data
277 * generated by an operation now known to be a noop.
278 */
279 if (prim->mode & PRIM_BEGIN)
280 ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
281 if (prim->mode & PRIM_END)
282 ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
283 }
284 }
285
286
287
288 void _tnl_loopback_vertex_list( GLcontext *ctx,
289 const struct tnl_vertex_list *list )
290 {
291 struct loopback_attr la[_TNL_ATTRIB_MAX];
292 GLuint i, nr = 0;
293
294 /* conventional + generic attributes */
295 for (i = 0 ; i <= _TNL_ATTRIB_GENERIC15 ; i++) {
296 if (list->attrsz[i]) {
297 la[nr].target = i;
298 la[nr].sz = list->attrsz[i];
299 la[nr].func = vert_attrfunc[list->attrsz[i]-1];
300 nr++;
301 }
302 }
303
304 /* material attributes */
305 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
306 i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
307 i++) {
308 if (list->attrsz[i]) {
309 la[nr].target = i;
310 la[nr].sz = list->attrsz[i];
311 la[nr].func = mat_attrfunc[list->attrsz[i]-1];
312 nr++;
313 }
314 }
315
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;
321 nr++;
322 }
323
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 );
327 else
328 loopback_prim( ctx, list, i, la, nr );
329 }
330 }