mesa: fix parity error for tri strips with 1st provoking vertex
[mesa.git] / src / mesa / tnl / t_vb_rendertmp.h
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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 * Authors:
25 * Keith Whitwell <keith@tungstengraphics.com>
26 */
27
28
29 #ifndef POSTFIX
30 #define POSTFIX
31 #endif
32
33 #ifndef INIT
34 #define INIT(x)
35 #endif
36
37 #ifndef NEED_EDGEFLAG_SETUP
38 #define NEED_EDGEFLAG_SETUP 0
39 #define EDGEFLAG_GET(a) 0
40 #define EDGEFLAG_SET(a,b) (void)b
41 #endif
42
43 #ifndef RESET_STIPPLE
44 #define RESET_STIPPLE
45 #endif
46
47 #ifndef TEST_PRIM_END
48 #define TEST_PRIM_END(prim) (flags & PRIM_END)
49 #define TEST_PRIM_BEGIN(prim) (flags & PRIM_BEGIN)
50 #endif
51
52 #ifndef ELT
53 #define ELT(x) x
54 #endif
55
56 #ifndef RENDER_TAB_QUALIFIER
57 #define RENDER_TAB_QUALIFIER static
58 #endif
59
60 static void TAG(render_points)( GLcontext *ctx,
61 GLuint start,
62 GLuint count,
63 GLuint flags )
64 {
65 LOCAL_VARS;
66 (void) flags;
67
68 INIT(GL_POINTS);
69 RENDER_POINTS( start, count );
70 POSTFIX;
71 }
72
73 static void TAG(render_lines)( GLcontext *ctx,
74 GLuint start,
75 GLuint count,
76 GLuint flags )
77 {
78 GLuint j;
79 LOCAL_VARS;
80 (void) flags;
81
82 INIT(GL_LINES);
83 for (j=start+1; j<count; j+=2 ) {
84 RESET_STIPPLE;
85 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
86 RENDER_LINE( ELT(j-1), ELT(j) );
87 else
88 RENDER_LINE( ELT(j), ELT(j-1) );
89 }
90 POSTFIX;
91 }
92
93
94 static void TAG(render_line_strip)( GLcontext *ctx,
95 GLuint start,
96 GLuint count,
97 GLuint flags )
98 {
99 GLuint j;
100 LOCAL_VARS;
101 (void) flags;
102
103 INIT(GL_LINE_STRIP);
104
105 if (TEST_PRIM_BEGIN(flags)) {
106 RESET_STIPPLE;
107 }
108
109 for (j=start+1; j<count; j++ ) {
110 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
111 RENDER_LINE( ELT(j-1), ELT(j) );
112 else
113 RENDER_LINE( ELT(j), ELT(j-1) );
114 }
115 POSTFIX;
116 }
117
118
119 static void TAG(render_line_loop)( GLcontext *ctx,
120 GLuint start,
121 GLuint count,
122 GLuint flags )
123 {
124 GLuint i;
125 LOCAL_VARS;
126
127 (void) flags;
128
129 INIT(GL_LINE_LOOP);
130
131 if (start+1 < count) {
132 if (TEST_PRIM_BEGIN(flags)) {
133 RESET_STIPPLE;
134 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
135 RENDER_LINE( ELT(start), ELT(start+1) );
136 else
137 RENDER_LINE( ELT(start+1), ELT(start) );
138 }
139
140 for ( i = start+2 ; i < count ; i++) {
141 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
142 RENDER_LINE( ELT(i-1), ELT(i) );
143 else
144 RENDER_LINE( ELT(i), ELT(i-1) );
145 }
146
147 if ( TEST_PRIM_END(flags)) {
148 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
149 RENDER_LINE( ELT(count-1), ELT(start) );
150 else
151 RENDER_LINE( ELT(start), ELT(count-1) );
152 }
153 }
154
155 POSTFIX;
156 }
157
158
159 static void TAG(render_triangles)( GLcontext *ctx,
160 GLuint start,
161 GLuint count,
162 GLuint flags )
163 {
164 GLuint j;
165 LOCAL_VARS;
166 (void) flags;
167
168 INIT(GL_TRIANGLES);
169 if (NEED_EDGEFLAG_SETUP) {
170 for (j=start+2; j<count; j+=3) {
171 /* Leave the edgeflags as supplied by the user.
172 */
173 RESET_STIPPLE;
174 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
175 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
176 else
177 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) );
178 }
179 } else {
180 for (j=start+2; j<count; j+=3) {
181 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
182 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
183 else
184 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) );
185 }
186 }
187 POSTFIX;
188 }
189
190
191
192 static void TAG(render_tri_strip)( GLcontext *ctx,
193 GLuint start,
194 GLuint count,
195 GLuint flags )
196 {
197 GLuint j;
198 GLuint parity = 0;
199 LOCAL_VARS;
200
201 INIT(GL_TRIANGLE_STRIP);
202 if (NEED_EDGEFLAG_SETUP) {
203 for (j=start+2;j<count;j++,parity^=1) {
204 GLuint ej2 = ELT(j-2+parity);
205 GLuint ej1 = ELT(j-1-parity);
206 GLuint ej = ELT(j);
207 GLboolean ef2 = EDGEFLAG_GET( ej2 );
208 GLboolean ef1 = EDGEFLAG_GET( ej1 );
209 GLboolean ef = EDGEFLAG_GET( ej );
210 if (TEST_PRIM_BEGIN(flags)) {
211 RESET_STIPPLE;
212 }
213 EDGEFLAG_SET( ej2, GL_TRUE );
214 EDGEFLAG_SET( ej1, GL_TRUE );
215 EDGEFLAG_SET( ej, GL_TRUE );
216 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
217 RENDER_TRI( ej2, ej1, ej );
218 else
219 RENDER_TRI( ej, ej2, ej1 );
220 EDGEFLAG_SET( ej2, ef2 );
221 EDGEFLAG_SET( ej1, ef1 );
222 EDGEFLAG_SET( ej, ef );
223 }
224 } else {
225 for (j=start+2; j<count ; j++, parity^=1) {
226 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
227 RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) );
228 else
229 RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) );
230 }
231 }
232 POSTFIX;
233 }
234
235
236 static void TAG(render_tri_fan)( GLcontext *ctx,
237 GLuint start,
238 GLuint count,
239 GLuint flags )
240 {
241 GLuint j;
242 LOCAL_VARS;
243 (void) flags;
244
245 INIT(GL_TRIANGLE_FAN);
246 if (NEED_EDGEFLAG_SETUP) {
247 for (j=start+2;j<count;j++) {
248 /* For trifans, all edges are boundary.
249 */
250 GLuint ejs = ELT(start);
251 GLuint ej1 = ELT(j-1);
252 GLuint ej = ELT(j);
253 GLboolean efs = EDGEFLAG_GET( ejs );
254 GLboolean ef1 = EDGEFLAG_GET( ej1 );
255 GLboolean ef = EDGEFLAG_GET( ej );
256 if (TEST_PRIM_BEGIN(flags)) {
257 RESET_STIPPLE;
258 }
259 EDGEFLAG_SET( ejs, GL_TRUE );
260 EDGEFLAG_SET( ej1, GL_TRUE );
261 EDGEFLAG_SET( ej, GL_TRUE );
262 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
263 RENDER_TRI( ejs, ej1, ej);
264 else
265 RENDER_TRI( ej, ejs, ej1);
266 EDGEFLAG_SET( ejs, efs );
267 EDGEFLAG_SET( ej1, ef1 );
268 EDGEFLAG_SET( ej, ef );
269 }
270 } else {
271 for (j=start+2;j<count;j++) {
272 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
273 RENDER_TRI( ELT(start), ELT(j-1), ELT(j) );
274 else
275 RENDER_TRI( ELT(j), ELT(start), ELT(j-1) );
276 }
277 }
278
279 POSTFIX;
280 }
281
282
283 static void TAG(render_poly)( GLcontext *ctx,
284 GLuint start,
285 GLuint count,
286 GLuint flags )
287 {
288 GLuint j = start+2;
289 LOCAL_VARS;
290 (void) flags;
291
292 INIT(GL_POLYGON);
293 if (NEED_EDGEFLAG_SETUP) {
294 GLboolean efstart = EDGEFLAG_GET( ELT(start) );
295 GLboolean efcount = EDGEFLAG_GET( ELT(count-1) );
296
297 /* If the primitive does not begin here, the first edge
298 * is non-boundary.
299 */
300 if (!TEST_PRIM_BEGIN(flags))
301 EDGEFLAG_SET( ELT(start), GL_FALSE );
302 else {
303 RESET_STIPPLE;
304 }
305
306 /* If the primitive does not end here, the final edge is
307 * non-boundary.
308 */
309 if (!TEST_PRIM_END(flags))
310 EDGEFLAG_SET( ELT(count-1), GL_FALSE );
311
312 /* Draw the first triangles (possibly zero)
313 */
314 if (j+1<count) {
315 GLboolean ef = EDGEFLAG_GET( ELT(j) );
316 EDGEFLAG_SET( ELT(j), GL_FALSE );
317 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
318 EDGEFLAG_SET( ELT(j), ef );
319 j++;
320
321 /* Don't render the first edge again:
322 */
323 EDGEFLAG_SET( ELT(start), GL_FALSE );
324
325 for (;j+1<count;j++) {
326 GLboolean efj = EDGEFLAG_GET( ELT(j) );
327 EDGEFLAG_SET( ELT(j), GL_FALSE );
328 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
329 EDGEFLAG_SET( ELT(j), efj );
330 }
331 }
332
333 /* Draw the last or only triangle
334 */
335 if (j < count)
336 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
337
338 /* Restore the first and last edgeflags:
339 */
340 EDGEFLAG_SET( ELT(count-1), efcount );
341 EDGEFLAG_SET( ELT(start), efstart );
342
343 }
344 else {
345 for (j=start+2;j<count;j++) {
346 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
347 }
348 }
349 POSTFIX;
350 }
351
352 static void TAG(render_quads)( GLcontext *ctx,
353 GLuint start,
354 GLuint count,
355 GLuint flags )
356 {
357 GLuint j;
358 LOCAL_VARS;
359 (void) flags;
360
361 INIT(GL_QUADS);
362 if (NEED_EDGEFLAG_SETUP) {
363 for (j=start+3; j<count; j+=4) {
364 /* Use user-specified edgeflags for quads.
365 */
366 RESET_STIPPLE;
367 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
368 !ctx->Const.QuadsFollowProvokingVertexConvention)
369 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
370 else
371 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
372 }
373 } else {
374 for (j=start+3; j<count; j+=4) {
375 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
376 !ctx->Const.QuadsFollowProvokingVertexConvention)
377 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
378 else
379 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
380 }
381 }
382 POSTFIX;
383 }
384
385 static void TAG(render_quad_strip)( GLcontext *ctx,
386 GLuint start,
387 GLuint count,
388 GLuint flags )
389 {
390 GLuint j;
391 LOCAL_VARS;
392 (void) flags;
393
394 INIT(GL_QUAD_STRIP);
395 if (NEED_EDGEFLAG_SETUP) {
396 for (j=start+3;j<count;j+=2) {
397 /* All edges are boundary. Set edgeflags to 1, draw the
398 * quad, and restore them to the original values.
399 */
400 GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) );
401 GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) );
402 GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) );
403 GLboolean ef = EDGEFLAG_GET( ELT(j) );
404 if (TEST_PRIM_BEGIN(flags)) {
405 RESET_STIPPLE;
406 }
407 EDGEFLAG_SET( ELT(j-3), GL_TRUE );
408 EDGEFLAG_SET( ELT(j-2), GL_TRUE );
409 EDGEFLAG_SET( ELT(j-1), GL_TRUE );
410 EDGEFLAG_SET( ELT(j), GL_TRUE );
411 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
412 !ctx->Const.QuadsFollowProvokingVertexConvention)
413 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
414 else
415 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
416 EDGEFLAG_SET( ELT(j-3), ef3 );
417 EDGEFLAG_SET( ELT(j-2), ef2 );
418 EDGEFLAG_SET( ELT(j-1), ef1 );
419 EDGEFLAG_SET( ELT(j), ef );
420 }
421 } else {
422 for (j=start+3;j<count;j+=2) {
423 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
424 !ctx->Const.QuadsFollowProvokingVertexConvention)
425 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
426 else
427 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
428 }
429 }
430 POSTFIX;
431 }
432
433 static void TAG(render_noop)( GLcontext *ctx,
434 GLuint start,
435 GLuint count,
436 GLuint flags )
437 {
438 (void)(ctx && start && count && flags);
439 }
440
441 RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(GLcontext *,
442 GLuint,
443 GLuint,
444 GLuint) =
445 {
446 TAG(render_points),
447 TAG(render_lines),
448 TAG(render_line_loop),
449 TAG(render_line_strip),
450 TAG(render_triangles),
451 TAG(render_tri_strip),
452 TAG(render_tri_fan),
453 TAG(render_quads),
454 TAG(render_quad_strip),
455 TAG(render_poly),
456 TAG(render_noop),
457 };
458
459
460
461 #ifndef PRESERVE_VB_DEFS
462 #undef RENDER_TRI
463 #undef RENDER_QUAD
464 #undef RENDER_LINE
465 #undef RENDER_POINTS
466 #undef LOCAL_VARS
467 #undef INIT
468 #undef POSTFIX
469 #undef RESET_STIPPLE
470 #undef DBG
471 #undef ELT
472 #undef RENDER_TAB_QUALIFIER
473 #endif
474
475 #ifndef PRESERVE_TAG
476 #undef TAG
477 #endif
478
479 #undef PRESERVE_VB_DEFS
480 #undef PRESERVE_TAG