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
60static void TAG(render_points)( struct gl_context *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
73static void TAG(render_lines)( struct gl_context *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
94static void TAG(render_line_strip)( struct gl_context *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
119static void TAG(render_line_loop)( struct gl_context *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
159static void TAG(render_triangles)( struct gl_context *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
192static void TAG(render_tri_strip)( struct gl_context *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, ej1, ej;
205         GLboolean ef2, ef1, ef;
206         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) {
207            ej2 = ELT(j-2+parity);
208            ej1 = ELT(j-1-parity);
209            ej = ELT(j);
210         }
211         else {
212            ej2 = ELT(j-1+parity);
213            ej1 = ELT(j-parity);
214            ej = ELT(j-2);
215         }
216	 ef2 = EDGEFLAG_GET( ej2 );
217	 ef1 = EDGEFLAG_GET( ej1 );
218	 ef = EDGEFLAG_GET( ej );
219	 if (TEST_PRIM_BEGIN(flags)) {
220	    RESET_STIPPLE;
221	 }
222	 EDGEFLAG_SET( ej2, GL_TRUE );
223	 EDGEFLAG_SET( ej1, GL_TRUE );
224	 EDGEFLAG_SET( ej, GL_TRUE );
225         RENDER_TRI( ej2, ej1, ej );
226	 EDGEFLAG_SET( ej2, ef2 );
227	 EDGEFLAG_SET( ej1, ef1 );
228	 EDGEFLAG_SET( ej, ef );
229      }
230   } else {
231      for (j=start+2; j<count ; j++, parity^=1) {
232         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
233            RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) );
234         else
235            RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) );
236      }
237   }
238   POSTFIX;
239}
240
241
242static void TAG(render_tri_fan)( struct gl_context *ctx,
243				 GLuint start,
244				 GLuint count,
245				 GLuint flags )
246{
247   GLuint j;
248   LOCAL_VARS;
249   (void) flags;
250
251   INIT(GL_TRIANGLE_FAN);
252   if (NEED_EDGEFLAG_SETUP) {
253      for (j=start+2;j<count;j++) {
254	 /* For trifans, all edges are boundary.
255	  */
256	 GLuint ejs = ELT(start);
257	 GLuint ej1 = ELT(j-1);
258	 GLuint ej = ELT(j);
259	 GLboolean efs = EDGEFLAG_GET( ejs );
260	 GLboolean ef1 = EDGEFLAG_GET( ej1 );
261	 GLboolean ef = EDGEFLAG_GET( ej );
262	 if (TEST_PRIM_BEGIN(flags)) {
263	    RESET_STIPPLE;
264	 }
265	 EDGEFLAG_SET( ejs, GL_TRUE );
266	 EDGEFLAG_SET( ej1, GL_TRUE );
267	 EDGEFLAG_SET( ej, GL_TRUE );
268         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
269            RENDER_TRI( ejs, ej1, ej);
270         else
271            RENDER_TRI( ej, ejs, ej1);
272	 EDGEFLAG_SET( ejs, efs );
273	 EDGEFLAG_SET( ej1, ef1 );
274	 EDGEFLAG_SET( ej, ef );
275      }
276   } else {
277      for (j=start+2;j<count;j++) {
278         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
279            RENDER_TRI( ELT(start), ELT(j-1), ELT(j) );
280         else
281            RENDER_TRI( ELT(j), ELT(start), ELT(j-1) );
282      }
283   }
284
285   POSTFIX;
286}
287
288
289static void TAG(render_poly)( struct gl_context *ctx,
290			      GLuint start,
291			      GLuint count,
292			      GLuint flags )
293{
294   GLuint j = start+2;
295   LOCAL_VARS;
296   (void) flags;
297
298   INIT(GL_POLYGON);
299   if (NEED_EDGEFLAG_SETUP) {
300      GLboolean efstart = EDGEFLAG_GET( ELT(start) );
301      GLboolean efcount = EDGEFLAG_GET( ELT(count-1) );
302
303      /* If the primitive does not begin here, the first edge
304       * is non-boundary.
305       */
306      if (!TEST_PRIM_BEGIN(flags))
307	 EDGEFLAG_SET( ELT(start), GL_FALSE );
308      else {
309	 RESET_STIPPLE;
310      }
311
312      /* If the primitive does not end here, the final edge is
313       * non-boundary.
314       */
315      if (!TEST_PRIM_END(flags))
316	 EDGEFLAG_SET( ELT(count-1), GL_FALSE );
317
318      /* Draw the first triangles (possibly zero)
319       */
320      if (j+1<count) {
321	 GLboolean ef = EDGEFLAG_GET( ELT(j) );
322	 EDGEFLAG_SET( ELT(j), GL_FALSE );
323	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
324	 EDGEFLAG_SET( ELT(j), ef );
325	 j++;
326
327	 /* Don't render the first edge again:
328	  */
329	 EDGEFLAG_SET( ELT(start), GL_FALSE );
330
331	 for (;j+1<count;j++) {
332	    GLboolean efj = EDGEFLAG_GET( ELT(j) );
333	    EDGEFLAG_SET( ELT(j), GL_FALSE );
334	    RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
335	    EDGEFLAG_SET( ELT(j), efj );
336	 }
337      }
338
339      /* Draw the last or only triangle
340       */
341      if (j < count)
342	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
343
344      /* Restore the first and last edgeflags:
345       */
346      EDGEFLAG_SET( ELT(count-1), efcount );
347      EDGEFLAG_SET( ELT(start), efstart );
348
349   }
350   else {
351      for (j=start+2;j<count;j++) {
352	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
353      }
354   }
355   POSTFIX;
356}
357
358static void TAG(render_quads)( struct gl_context *ctx,
359			       GLuint start,
360			       GLuint count,
361			       GLuint flags )
362{
363   GLuint j;
364   LOCAL_VARS;
365   (void) flags;
366
367   INIT(GL_QUADS);
368   if (NEED_EDGEFLAG_SETUP) {
369      for (j=start+3; j<count; j+=4) {
370	 /* Use user-specified edgeflags for quads.
371	  */
372	 RESET_STIPPLE;
373         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
374             !ctx->Const.QuadsFollowProvokingVertexConvention)
375            RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
376         else
377            RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
378      }
379   } else {
380      for (j=start+3; j<count; j+=4) {
381         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
382             !ctx->Const.QuadsFollowProvokingVertexConvention)
383            RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
384         else
385            RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
386      }
387   }
388   POSTFIX;
389}
390
391static void TAG(render_quad_strip)( struct gl_context *ctx,
392				    GLuint start,
393				    GLuint count,
394				    GLuint flags )
395{
396   GLuint j;
397   LOCAL_VARS;
398   (void) flags;
399
400   INIT(GL_QUAD_STRIP);
401   if (NEED_EDGEFLAG_SETUP) {
402      for (j=start+3;j<count;j+=2) {
403	 /* All edges are boundary.  Set edgeflags to 1, draw the
404	  * quad, and restore them to the original values.
405	  */
406	 GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) );
407	 GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) );
408	 GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) );
409	 GLboolean ef = EDGEFLAG_GET( ELT(j) );
410	 if (TEST_PRIM_BEGIN(flags)) {
411	    RESET_STIPPLE;
412	 }
413	 EDGEFLAG_SET( ELT(j-3), GL_TRUE );
414	 EDGEFLAG_SET( ELT(j-2), GL_TRUE );
415	 EDGEFLAG_SET( ELT(j-1), GL_TRUE );
416	 EDGEFLAG_SET( ELT(j), GL_TRUE );
417         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
418             !ctx->Const.QuadsFollowProvokingVertexConvention)
419            RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
420         else
421            RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
422	 EDGEFLAG_SET( ELT(j-3), ef3 );
423	 EDGEFLAG_SET( ELT(j-2), ef2 );
424	 EDGEFLAG_SET( ELT(j-1), ef1 );
425	 EDGEFLAG_SET( ELT(j), ef );
426      }
427   } else {
428      for (j=start+3;j<count;j+=2) {
429         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
430             !ctx->Const.QuadsFollowProvokingVertexConvention)
431            RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
432         else
433            RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
434      }
435   }
436   POSTFIX;
437}
438
439static void TAG(render_noop)( struct gl_context *ctx,
440			      GLuint start,
441			      GLuint count,
442			      GLuint flags )
443{
444   (void)(ctx && start && count && flags);
445}
446
447RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(struct gl_context *,
448							   GLuint,
449							   GLuint,
450							   GLuint) =
451{
452   TAG(render_points),
453   TAG(render_lines),
454   TAG(render_line_loop),
455   TAG(render_line_strip),
456   TAG(render_triangles),
457   TAG(render_tri_strip),
458   TAG(render_tri_fan),
459   TAG(render_quads),
460   TAG(render_quad_strip),
461   TAG(render_poly),
462   TAG(render_noop),
463};
464
465
466
467#ifndef PRESERVE_VB_DEFS
468#undef RENDER_TRI
469#undef RENDER_QUAD
470#undef RENDER_LINE
471#undef RENDER_POINTS
472#undef LOCAL_VARS
473#undef INIT
474#undef POSTFIX
475#undef RESET_STIPPLE
476#undef DBG
477#undef ELT
478#undef RENDER_TAB_QUALIFIER
479#endif
480
481#ifndef PRESERVE_TAG
482#undef TAG
483#endif
484
485#undef PRESERVE_VB_DEFS
486#undef PRESERVE_TAG
487