1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2005  Brian Paul   All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Keith Whitwell <keithw@vmware.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   INIT(GL_LINE_LOOP);
128
129   if (start+1 < count) {
130      if (TEST_PRIM_BEGIN(flags)) {
131	 RESET_STIPPLE;
132         /* draw the first line from v[0] to v[1] */
133         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
134            RENDER_LINE( ELT(start), ELT(start+1) );
135         else
136            RENDER_LINE( ELT(start+1), ELT(start) );
137      }
138
139      /* draw lines from v[1] to v[n-1] */
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         /* draw final line from v[n-1] to v[0] (the very first vertex) */
149         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
150            RENDER_LINE( ELT(count-1), ELT(start) );
151         else
152            RENDER_LINE( ELT(start), ELT(count-1) );
153      }
154   }
155
156   POSTFIX;
157}
158
159
160static void TAG(render_triangles)( struct gl_context *ctx,
161				   GLuint start,
162				   GLuint count,
163				   GLuint flags )
164{
165   GLuint j;
166   LOCAL_VARS;
167   (void) flags;
168
169   INIT(GL_TRIANGLES);
170   if (NEED_EDGEFLAG_SETUP) {
171      for (j=start+2; j<count; j+=3) {
172	 /* Leave the edgeflags as supplied by the user.
173	  */
174	 RESET_STIPPLE;
175         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
176            RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
177         else
178            RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) );
179      }
180   } else {
181      for (j=start+2; j<count; j+=3) {
182         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
183            RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) );
184         else
185            RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) );
186      }
187   }
188   POSTFIX;
189}
190
191
192
193static void TAG(render_tri_strip)( struct gl_context *ctx,
194				   GLuint start,
195				   GLuint count,
196				   GLuint flags )
197{
198   GLuint j;
199   GLuint parity = 0;
200   LOCAL_VARS;
201
202   INIT(GL_TRIANGLE_STRIP);
203   if (NEED_EDGEFLAG_SETUP) {
204      for (j=start+2;j<count;j++,parity^=1) {
205         GLuint ej2, ej1, ej;
206         GLboolean ef2, ef1, ef;
207         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) {
208            ej2 = ELT(j-2+parity);
209            ej1 = ELT(j-1-parity);
210            ej = ELT(j);
211         }
212         else {
213            ej2 = ELT(j-1+parity);
214            ej1 = ELT(j-parity);
215            ej = ELT(j-2);
216         }
217	 ef2 = EDGEFLAG_GET( ej2 );
218	 ef1 = EDGEFLAG_GET( ej1 );
219	 ef = EDGEFLAG_GET( ej );
220	 if (TEST_PRIM_BEGIN(flags)) {
221	    RESET_STIPPLE;
222	 }
223	 EDGEFLAG_SET( ej2, GL_TRUE );
224	 EDGEFLAG_SET( ej1, GL_TRUE );
225	 EDGEFLAG_SET( ej, GL_TRUE );
226         RENDER_TRI( ej2, ej1, ej );
227	 EDGEFLAG_SET( ej2, ef2 );
228	 EDGEFLAG_SET( ej1, ef1 );
229	 EDGEFLAG_SET( ej, ef );
230      }
231   } else {
232      for (j=start+2; j<count ; j++, parity^=1) {
233         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
234            RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) );
235         else
236            RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) );
237      }
238   }
239   POSTFIX;
240}
241
242
243static void TAG(render_tri_fan)( struct gl_context *ctx,
244				 GLuint start,
245				 GLuint count,
246				 GLuint flags )
247{
248   GLuint j;
249   LOCAL_VARS;
250   (void) flags;
251
252   INIT(GL_TRIANGLE_FAN);
253   if (NEED_EDGEFLAG_SETUP) {
254      for (j=start+2;j<count;j++) {
255	 /* For trifans, all edges are boundary.
256	  */
257	 GLuint ejs = ELT(start);
258	 GLuint ej1 = ELT(j-1);
259	 GLuint ej = ELT(j);
260	 GLboolean efs = EDGEFLAG_GET( ejs );
261	 GLboolean ef1 = EDGEFLAG_GET( ej1 );
262	 GLboolean ef = EDGEFLAG_GET( ej );
263	 if (TEST_PRIM_BEGIN(flags)) {
264	    RESET_STIPPLE;
265	 }
266	 EDGEFLAG_SET( ejs, GL_TRUE );
267	 EDGEFLAG_SET( ej1, GL_TRUE );
268	 EDGEFLAG_SET( ej, GL_TRUE );
269         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
270            RENDER_TRI( ejs, ej1, ej);
271         else
272            RENDER_TRI( ej, ejs, ej1);
273	 EDGEFLAG_SET( ejs, efs );
274	 EDGEFLAG_SET( ej1, ef1 );
275	 EDGEFLAG_SET( ej, ef );
276      }
277   } else {
278      for (j=start+2;j<count;j++) {
279         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT)
280            RENDER_TRI( ELT(start), ELT(j-1), ELT(j) );
281         else
282            RENDER_TRI( ELT(j), ELT(start), ELT(j-1) );
283      }
284   }
285
286   POSTFIX;
287}
288
289
290static void TAG(render_poly)( struct gl_context *ctx,
291			      GLuint start,
292			      GLuint count,
293			      GLuint flags )
294{
295   GLuint j = start+2;
296   LOCAL_VARS;
297   (void) flags;
298
299   INIT(GL_POLYGON);
300   if (NEED_EDGEFLAG_SETUP) {
301      GLboolean efstart = EDGEFLAG_GET( ELT(start) );
302      GLboolean efcount = EDGEFLAG_GET( ELT(count-1) );
303
304      /* If the primitive does not begin here, the first edge
305       * is non-boundary.
306       */
307      if (!TEST_PRIM_BEGIN(flags))
308	 EDGEFLAG_SET( ELT(start), GL_FALSE );
309      else {
310	 RESET_STIPPLE;
311      }
312
313      /* If the primitive does not end here, the final edge is
314       * non-boundary.
315       */
316      if (!TEST_PRIM_END(flags))
317	 EDGEFLAG_SET( ELT(count-1), GL_FALSE );
318
319      /* Draw the first triangles (possibly zero)
320       */
321      if (j+1<count) {
322	 GLboolean ef = EDGEFLAG_GET( ELT(j) );
323	 EDGEFLAG_SET( ELT(j), GL_FALSE );
324	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
325	 EDGEFLAG_SET( ELT(j), ef );
326	 j++;
327
328	 /* Don't render the first edge again:
329	  */
330	 EDGEFLAG_SET( ELT(start), GL_FALSE );
331
332	 for (;j+1<count;j++) {
333	    GLboolean efj = EDGEFLAG_GET( ELT(j) );
334	    EDGEFLAG_SET( ELT(j), GL_FALSE );
335	    RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
336	    EDGEFLAG_SET( ELT(j), efj );
337	 }
338      }
339
340      /* Draw the last or only triangle
341       */
342      if (j < count)
343	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
344
345      /* Restore the first and last edgeflags:
346       */
347      EDGEFLAG_SET( ELT(count-1), efcount );
348      EDGEFLAG_SET( ELT(start), efstart );
349
350   }
351   else {
352      for (j=start+2;j<count;j++) {
353	 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) );
354      }
355   }
356   POSTFIX;
357}
358
359static void TAG(render_quads)( struct gl_context *ctx,
360			       GLuint start,
361			       GLuint count,
362			       GLuint flags )
363{
364   GLuint j;
365   LOCAL_VARS;
366   (void) flags;
367
368   INIT(GL_QUADS);
369   if (NEED_EDGEFLAG_SETUP) {
370      for (j=start+3; j<count; j+=4) {
371	 /* Use user-specified edgeflags for quads.
372	  */
373	 RESET_STIPPLE;
374         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
375             !ctx->Const.QuadsFollowProvokingVertexConvention)
376            RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
377         else
378            RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
379      }
380   } else {
381      for (j=start+3; j<count; j+=4) {
382         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
383             !ctx->Const.QuadsFollowProvokingVertexConvention)
384            RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) );
385         else
386            RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) );
387      }
388   }
389   POSTFIX;
390}
391
392static void TAG(render_quad_strip)( struct gl_context *ctx,
393				    GLuint start,
394				    GLuint count,
395				    GLuint flags )
396{
397   GLuint j;
398   LOCAL_VARS;
399   (void) flags;
400
401   INIT(GL_QUAD_STRIP);
402   if (NEED_EDGEFLAG_SETUP) {
403      for (j=start+3;j<count;j+=2) {
404	 /* All edges are boundary.  Set edgeflags to 1, draw the
405	  * quad, and restore them to the original values.
406	  */
407	 GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) );
408	 GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) );
409	 GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) );
410	 GLboolean ef = EDGEFLAG_GET( ELT(j) );
411	 if (TEST_PRIM_BEGIN(flags)) {
412	    RESET_STIPPLE;
413	 }
414	 EDGEFLAG_SET( ELT(j-3), GL_TRUE );
415	 EDGEFLAG_SET( ELT(j-2), GL_TRUE );
416	 EDGEFLAG_SET( ELT(j-1), GL_TRUE );
417	 EDGEFLAG_SET( ELT(j), GL_TRUE );
418         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
419             !ctx->Const.QuadsFollowProvokingVertexConvention)
420            RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
421         else
422            RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
423	 EDGEFLAG_SET( ELT(j-3), ef3 );
424	 EDGEFLAG_SET( ELT(j-2), ef2 );
425	 EDGEFLAG_SET( ELT(j-1), ef1 );
426	 EDGEFLAG_SET( ELT(j), ef );
427      }
428   } else {
429      for (j=start+3;j<count;j+=2) {
430         if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT ||
431             !ctx->Const.QuadsFollowProvokingVertexConvention)
432            RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) );
433         else
434            RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) );
435      }
436   }
437   POSTFIX;
438}
439
440static void TAG(render_noop)( struct gl_context *ctx,
441			      GLuint start,
442			      GLuint count,
443			      GLuint flags )
444{
445   (void)(ctx && start && count && flags);
446}
447
448RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(struct gl_context *,
449							   GLuint,
450							   GLuint,
451							   GLuint) =
452{
453   TAG(render_points),
454   TAG(render_lines),
455   TAG(render_line_loop),
456   TAG(render_line_strip),
457   TAG(render_triangles),
458   TAG(render_tri_strip),
459   TAG(render_tri_fan),
460   TAG(render_quads),
461   TAG(render_quad_strip),
462   TAG(render_poly),
463   TAG(render_noop),
464};
465
466
467
468#ifndef PRESERVE_VB_DEFS
469#undef RENDER_TRI
470#undef RENDER_QUAD
471#undef RENDER_LINE
472#undef RENDER_POINTS
473#undef LOCAL_VARS
474#undef INIT
475#undef POSTFIX
476#undef RESET_STIPPLE
477#undef DBG
478#undef ELT
479#undef RENDER_TAB_QUALIFIER
480#endif
481
482#ifndef PRESERVE_TAG
483#undef TAG
484#endif
485
486#undef PRESERVE_VB_DEFS
487#undef PRESERVE_TAG
488