new files
[mesa.git] / src / mesa / tnl / t_save_loopback.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 5.1
5 *
6 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
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.
24 */
25
26 /* Author:
27 * Keith Whitwell <keith@tungstengraphics.com>
28 */
29
30 #include "glheader.h"
31 #include "context.h"
32 #include "enums.h"
33 #include "glapi.h"
34 #include "imports.h"
35 #include "macros.h"
36 #include "mtypes.h"
37 #include "t_context.h"
38 #include "t_save_api.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 ctx->Exec->VertexAttrib1fvNV(target, v);
75 }
76
77 static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
78 {
79 ctx->Exec->VertexAttrib2fvNV(target, v);
80 }
81
82 static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
83 {
84 ctx->Exec->VertexAttrib3fvNV(target, v);
85 }
86
87 static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
88 {
89 ctx->Exec->VertexAttrib4fvNV(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 mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
101 {
102 switch (target) {
103 case _TNL_ATTRIB_MAT_FRONT_SHININESS:
104 ctx->Exec->Materialfv( GL_FRONT, GL_SHININESS, v );
105 break;
106 case _TNL_ATTRIB_MAT_BACK_SHININESS:
107 ctx->Exec->Materialfv( GL_BACK, GL_SHININESS, v );
108 break;
109 }
110 }
111
112
113 static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
114 {
115 switch (target) {
116 case _TNL_ATTRIB_MAT_FRONT_INDEXES:
117 ctx->Exec->Materialfv( GL_FRONT, GL_COLOR_INDEXES, v );
118 break;
119 case _TNL_ATTRIB_MAT_BACK_INDEXES:
120 ctx->Exec->Materialfv( GL_BACK, GL_COLOR_INDEXES, v );
121 break;
122 }
123 }
124
125
126 static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
127 {
128 switch (target) {
129 case _TNL_ATTRIB_MAT_FRONT_EMISSION:
130 ctx->Exec->Materialfv( GL_FRONT, GL_EMISSION, v );
131 break;
132 case _TNL_ATTRIB_MAT_BACK_EMISSION:
133 ctx->Exec->Materialfv( GL_BACK, GL_EMISSION, v );
134 break;
135 case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
136 ctx->Exec->Materialfv( GL_FRONT, GL_AMBIENT, v );
137 break;
138 case _TNL_ATTRIB_MAT_BACK_AMBIENT:
139 ctx->Exec->Materialfv( GL_BACK, GL_AMBIENT, v );
140 break;
141 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
142 ctx->Exec->Materialfv( GL_FRONT, GL_DIFFUSE, v );
143 break;
144 case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
145 ctx->Exec->Materialfv( GL_BACK, GL_DIFFUSE, v );
146 break;
147 case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
148 ctx->Exec->Materialfv( GL_FRONT, GL_SPECULAR, v );
149 break;
150 case _TNL_ATTRIB_MAT_BACK_SPECULAR:
151 ctx->Exec->Materialfv( GL_BACK, GL_SPECULAR, v );
152 break;
153 }
154 }
155
156
157 static attr_func mat_attrfunc[4] = {
158 mat_attr1fv,
159 0,
160 mat_attr3fv,
161 mat_attr4fv
162 };
163
164
165 static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
166 {
167 ctx->Exec->Indexf(v[0]);
168 }
169
170 static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
171 {
172 ctx->Exec->EdgeFlag((v[0] == 1.0));
173 }
174
175 struct loopback_attr {
176 GLint target;
177 GLint sz;
178 attr_func func;
179 };
180
181 /* Don't emit ends and begins on wrapped primitives. Don't replay
182 * wrapped vertices. If we get here, it's probably because the the
183 * precalculated wrapping is wrong.
184 */
185 static void loopback_prim( GLcontext *ctx,
186 struct tnl_vertex_list *list, GLuint i,
187 struct loopback_attr *la, GLuint nr )
188 {
189 struct tnl_prim *prim = &list->prim[i];
190 GLint begin = prim->start;
191 GLint end = begin + prim->count;
192 GLfloat *data;
193 GLint j;
194 GLuint k;
195
196 if (prim->mode & PRIM_BEGIN) {
197 glBegin( prim->mode & PRIM_MODE_MASK );
198 } else {
199 assert(i == 0);
200 assert(begin == 0);
201 begin += list->wrap_count;
202 }
203
204 data = list->buffer + begin * list->vertex_size;
205
206 for (j = begin ; j < end ; j++) {
207 GLfloat *tmp = data + la[0].sz;
208
209 for (k = 1 ; k < nr ; k++) {
210 la[k].func( ctx, la[k].target, tmp );
211 tmp += la[k].sz;
212 }
213
214 /* Fire the vertex
215 */
216 la[0].func( ctx, VERT_ATTRIB_POS, data );
217 data = tmp;
218 }
219
220 if (prim->mode & PRIM_END) {
221 glEnd();
222 }
223 else {
224 assert (i == list->prim_count-1);
225 }
226 }
227
228 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
229 * caught here. If there is no primitive in progress, execute them
230 * normally, otherwise need to track and discard the generated
231 * primitives.
232 */
233 static void loopback_weak_prim( GLcontext *ctx,
234 struct tnl_vertex_list *list, GLuint i,
235 struct loopback_attr *la, GLuint nr )
236 {
237 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
238 loopback_prim( ctx, list, i, la, nr );
239 else {
240 struct tnl_prim *prim = &list->prim[i];
241
242 /* Use the prim_weak flag to ensure that if this primitive
243 * wraps, we don't mistake future vertex_lists for part of the
244 * surrounding primitive.
245 *
246 * While this flag is set, we are simply disposing of data
247 * generated by an operation now known to be a noop.
248 */
249 if (prim->mode & PRIM_BEGIN)
250 ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
251 if (prim->mode & PRIM_END)
252 ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
253 }
254 }
255
256
257
258 void _tnl_loopback_vertex_list( GLcontext *ctx, struct tnl_vertex_list *list )
259 {
260 struct loopback_attr la[_TNL_ATTRIB_MAX];
261 GLuint i, nr = 0;
262
263 for (i = 0 ; i <= _TNL_ATTRIB_TEX7 ; i++) {
264 if (list->attrsz[i]) {
265 la[nr].target = i;
266 la[nr].sz = list->attrsz[i];
267 la[nr].func = vert_attrfunc[list->attrsz[i]-1];
268 nr++;
269 }
270 }
271
272 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
273 i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
274 i++) {
275 if (list->attrsz[i]) {
276 la[nr].target = i;
277 la[nr].sz = list->attrsz[i];
278 la[nr].func = mat_attrfunc[list->attrsz[i]-1];
279 nr++;
280 }
281 }
282
283 if (list->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
284 la[nr].target = _TNL_ATTRIB_EDGEFLAG;
285 la[nr].sz = list->attrsz[_TNL_ATTRIB_EDGEFLAG];
286 la[nr].func = edgeflag_attr1fv;
287 nr++;
288 }
289
290 if (list->attrsz[_TNL_ATTRIB_INDEX]) {
291 la[nr].target = _TNL_ATTRIB_INDEX;
292 la[nr].sz = list->attrsz[_TNL_ATTRIB_INDEX];
293 la[nr].func = index_attr1fv;
294 nr++;
295 }
296
297 for (i = 0 ; i < list->prim_count ; i++) {
298 if (list->prim[i].mode & PRIM_WEAK)
299 loopback_weak_prim( ctx, list, i, la, nr );
300 else
301 loopback_prim( ctx, list, i, la, nr );
302 }
303 }