Updates for OpenVMS : New makefiles
[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
39 /* If someone compiles a display list like:
40 * glBegin(Triangles)
41 * glVertex()
42 * ... lots of vertices ...
43 * glEnd()
44 *
45 * or:
46 * glDrawArrays(...)
47 *
48 * and then tries to execute it like this:
49 *
50 * glBegin(Lines)
51 * glCallList()
52 * glEnd()
53 *
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).
57 *
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
61 * usage.
62 *
63 * Further, replaying degenerately-called lists in this fashion is
64 * probably still faster than the replay using opcodes.
65 */
66
67 typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
68
69
70 /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
71 static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
72 {
73 ctx->Exec->VertexAttrib1fvNV(target, v);
74 }
75
76 static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
77 {
78 ctx->Exec->VertexAttrib2fvNV(target, v);
79 }
80
81 static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
82 {
83 ctx->Exec->VertexAttrib3fvNV(target, v);
84 }
85
86 static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
87 {
88 ctx->Exec->VertexAttrib4fvNV(target, v);
89 }
90
91 static attr_func vert_attrfunc[4] = {
92 VertexAttrib1fvNV,
93 VertexAttrib2fvNV,
94 VertexAttrib3fvNV,
95 VertexAttrib4fvNV
96 };
97
98
99 static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
100 {
101 ctx->Exec->VertexAttrib1fvARB(target, v);
102 }
103
104 static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
105 {
106 ctx->Exec->VertexAttrib2fvARB(target, v);
107 }
108
109 static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
110 {
111 ctx->Exec->VertexAttrib3fvARB(target, v);
112 }
113
114 static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
115 {
116 ctx->Exec->VertexAttrib4fvARB(target, v);
117 }
118
119 static attr_func vert_attrfunc_arb[4] = {
120 VertexAttrib1fvARB,
121 VertexAttrib2fvARB,
122 VertexAttrib3fvARB,
123 VertexAttrib4fvARB
124 };
125
126
127
128
129
130
131
132 static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
133 {
134 switch (target) {
135 case _TNL_ATTRIB_MAT_FRONT_SHININESS:
136 ctx->Exec->Materialfv( GL_FRONT, GL_SHININESS, v );
137 break;
138 case _TNL_ATTRIB_MAT_BACK_SHININESS:
139 ctx->Exec->Materialfv( GL_BACK, GL_SHININESS, v );
140 break;
141 }
142 }
143
144
145 static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
146 {
147 switch (target) {
148 case _TNL_ATTRIB_MAT_FRONT_INDEXES:
149 ctx->Exec->Materialfv( GL_FRONT, GL_COLOR_INDEXES, v );
150 break;
151 case _TNL_ATTRIB_MAT_BACK_INDEXES:
152 ctx->Exec->Materialfv( GL_BACK, GL_COLOR_INDEXES, v );
153 break;
154 }
155 }
156
157
158 static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
159 {
160 switch (target) {
161 case _TNL_ATTRIB_MAT_FRONT_EMISSION:
162 ctx->Exec->Materialfv( GL_FRONT, GL_EMISSION, v );
163 break;
164 case _TNL_ATTRIB_MAT_BACK_EMISSION:
165 ctx->Exec->Materialfv( GL_BACK, GL_EMISSION, v );
166 break;
167 case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
168 ctx->Exec->Materialfv( GL_FRONT, GL_AMBIENT, v );
169 break;
170 case _TNL_ATTRIB_MAT_BACK_AMBIENT:
171 ctx->Exec->Materialfv( GL_BACK, GL_AMBIENT, v );
172 break;
173 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
174 ctx->Exec->Materialfv( GL_FRONT, GL_DIFFUSE, v );
175 break;
176 case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
177 ctx->Exec->Materialfv( GL_BACK, GL_DIFFUSE, v );
178 break;
179 case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
180 ctx->Exec->Materialfv( GL_FRONT, GL_SPECULAR, v );
181 break;
182 case _TNL_ATTRIB_MAT_BACK_SPECULAR:
183 ctx->Exec->Materialfv( GL_BACK, GL_SPECULAR, v );
184 break;
185 }
186 }
187
188
189 static attr_func mat_attrfunc[4] = {
190 mat_attr1fv,
191 NULL,
192 mat_attr3fv,
193 mat_attr4fv
194 };
195
196
197 static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
198 {
199 (void) target;
200 ctx->Exec->Indexf(v[0]);
201 }
202
203 static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
204 {
205 (void) target;
206 ctx->Exec->EdgeFlag((GLboolean)(v[0] == 1.0));
207 }
208
209 struct loopback_attr {
210 GLint target;
211 GLint sz;
212 attr_func func;
213 };
214
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.
218 */
219 static void loopback_prim( GLcontext *ctx,
220 const struct tnl_vertex_list *list, GLuint i,
221 const struct loopback_attr *la, GLuint nr )
222 {
223 struct tnl_prim *prim = &list->prim[i];
224 GLint begin = prim->start;
225 GLint end = begin + prim->count;
226 GLfloat *data;
227 GLint j;
228 GLuint k;
229
230 if (prim->mode & PRIM_BEGIN) {
231 GL_CALL(Begin)( prim->mode & PRIM_MODE_MASK );
232 }
233 else {
234 assert(i == 0);
235 assert(begin == 0);
236 begin += list->wrap_count;
237 }
238
239 data = list->buffer + begin * list->vertex_size;
240
241 for (j = begin ; j < end ; j++) {
242 GLfloat *tmp = data + la[0].sz;
243
244 for (k = 1 ; k < nr ; k++) {
245 la[k].func( ctx, la[k].target, tmp );
246 tmp += la[k].sz;
247 }
248
249 /* Fire the vertex
250 */
251 la[0].func( ctx, VERT_ATTRIB_POS, data );
252 data = tmp;
253 }
254
255 if (prim->mode & PRIM_END) {
256 GL_CALL(End)();
257 }
258 else {
259 assert (i == list->prim_count-1);
260 }
261 }
262
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
266 * primitives.
267 */
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 )
271 {
272 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
273 loopback_prim( ctx, list, i, la, nr );
274 else {
275 struct tnl_prim *prim = &list->prim[i];
276
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.
280 *
281 * While this flag is set, we are simply disposing of data
282 * generated by an operation now known to be a noop.
283 */
284 if (prim->mode & PRIM_BEGIN)
285 ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
286 if (prim->mode & PRIM_END)
287 ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
288 }
289 }
290
291
292
293 void _tnl_loopback_vertex_list( GLcontext *ctx,
294 const struct tnl_vertex_list *list )
295 {
296 struct loopback_attr la[_TNL_ATTRIB_MAX];
297 GLuint i, nr = 0;
298
299 for (i = 0 ; i <= _TNL_ATTRIB_TEX7 ; i++) {
300 if (list->attrsz[i]) {
301 la[nr].target = i;
302 la[nr].sz = list->attrsz[i];
303 la[nr].func = vert_attrfunc[list->attrsz[i]-1];
304 nr++;
305 }
306 }
307
308 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
309 i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
310 i++) {
311 if (list->attrsz[i]) {
312 la[nr].target = i;
313 la[nr].sz = list->attrsz[i];
314 la[nr].func = mat_attrfunc[list->attrsz[i]-1];
315 nr++;
316 }
317 }
318
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;
323 nr++;
324 }
325
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;
330 nr++;
331 }
332
333 /* XXX ARB vertex attribs */
334
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 );
338 else
339 loopback_prim( ctx, list, i, la, nr );
340 }
341 }