1/*
2 * Mesa 3-D graphics library
3 * Version:  7.9
4 *
5 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Copyright (C) 2010 LunarG Inc.
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 OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 *
26 * Authors:
27  *   Keith Whitwell <keith@tungstengraphics.com>
28 *    Chia-I Wu <olv@lunarg.com>
29 */
30
31/* these macros are optional */
32#ifndef LOCAL_VARS
33#define LOCAL_VARS
34#endif
35#ifndef FUNC_ENTER
36#define FUNC_ENTER do {} while (0)
37#endif
38#ifndef FUNC_EXIT
39#define FUNC_EXIT do {} while (0)
40#endif
41#ifndef LINE_ADJ
42#define LINE_ADJ(flags, a0, i0, i1, a1) LINE(flags, i0, i1)
43#endif
44#ifndef TRIANGLE_ADJ
45#define TRIANGLE_ADJ(flags, i0, a0, i1, a1, i2, a2) TRIANGLE(flags, i0, i1, i2)
46#endif
47
48static void
49FUNC(FUNC_VARS)
50{
51   unsigned idx[6], i;
52   ushort flags;
53   LOCAL_VARS
54
55   FUNC_ENTER;
56
57   /* prim, prim_flags, count, and last_vertex_last should have been defined */
58   if (0) {
59      debug_printf("%s: prim 0x%x, prim_flags 0x%x, count %d, last_vertex_last %d\n",
60            __FUNCTION__, prim, prim_flags, count, last_vertex_last);
61   }
62
63   switch (prim) {
64   case PIPE_PRIM_POINTS:
65      for (i = 0; i < count; i++) {
66         idx[0] = GET_ELT(i);
67         POINT(idx[0]);
68      }
69      break;
70
71   case PIPE_PRIM_LINES:
72      flags = DRAW_PIPE_RESET_STIPPLE;
73      for (i = 0; i + 1 < count; i += 2) {
74         idx[0] = GET_ELT(i);
75         idx[1] = GET_ELT(i + 1);
76         LINE(flags, idx[0], idx[1]);
77      }
78      break;
79
80   case PIPE_PRIM_LINE_LOOP:
81   case PIPE_PRIM_LINE_STRIP:
82      if (count >= 2) {
83         flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
84         idx[1] = GET_ELT(0);
85         idx[2] = idx[1];
86
87         for (i = 1; i < count; i++, flags = 0) {
88            idx[0] = idx[1];
89            idx[1] = GET_ELT(i);
90            LINE(flags, idx[0], idx[1]);
91         }
92         /* close the loop */
93         if (prim == PIPE_PRIM_LINE_LOOP && !prim_flags)
94            LINE(flags, idx[1], idx[2]);
95      }
96      break;
97
98   case PIPE_PRIM_TRIANGLES:
99      flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
100      for (i = 0; i + 2 < count; i += 3) {
101         idx[0] = GET_ELT(i);
102         idx[1] = GET_ELT(i + 1);
103         idx[2] = GET_ELT(i + 2);
104         TRIANGLE(flags, idx[0], idx[1], idx[2]);
105      }
106      break;
107
108   case PIPE_PRIM_TRIANGLE_STRIP:
109      if (count >= 3) {
110         flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
111         idx[1] = GET_ELT(0);
112         idx[2] = GET_ELT(1);
113
114         if (last_vertex_last) {
115            for (i = 0; i + 2 < count; i++) {
116               idx[0] = idx[1];
117               idx[1] = idx[2];
118               idx[2] = GET_ELT(i + 2);
119               /* always emit idx[2] last */
120               if (i & 1)
121                  TRIANGLE(flags, idx[1], idx[0], idx[2]);
122               else
123                  TRIANGLE(flags, idx[0], idx[1], idx[2]);
124            }
125         }
126         else {
127            for (i = 0; i + 2 < count; i++) {
128               idx[0] = idx[1];
129               idx[1] = idx[2];
130               idx[2] = GET_ELT(i + 2);
131               /* always emit idx[0] first */
132               if (i & 1)
133                  TRIANGLE(flags, idx[0], idx[2], idx[1]);
134               else
135                  TRIANGLE(flags, idx[0], idx[1], idx[2]);
136            }
137         }
138      }
139      break;
140
141   case PIPE_PRIM_TRIANGLE_FAN:
142      if (count >= 3) {
143         flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
144         idx[0] = GET_ELT(0);
145         idx[2] = GET_ELT(1);
146
147         /* idx[0] is neither the first nor the last vertex */
148         if (last_vertex_last) {
149            for (i = 0; i + 2 < count; i++) {
150               idx[1] = idx[2];
151               idx[2] = GET_ELT(i + 2);
152               /* always emit idx[2] last */
153               TRIANGLE(flags, idx[0], idx[1], idx[2]);
154            }
155         }
156         else {
157            for (i = 0; i + 2 < count; i++) {
158               idx[1] = idx[2];
159               idx[2] = GET_ELT(i + 2);
160               /* always emit idx[1] first */
161               TRIANGLE(flags, idx[1], idx[2], idx[0]);
162            }
163         }
164      }
165      break;
166
167   case PIPE_PRIM_QUADS:
168      if (last_vertex_last) {
169         for (i = 0; i + 3 < count; i += 4) {
170            idx[0] = GET_ELT(i);
171            idx[1] = GET_ELT(i + 1);
172            idx[2] = GET_ELT(i + 2);
173            idx[3] = GET_ELT(i + 3);
174
175            flags = DRAW_PIPE_RESET_STIPPLE |
176                    DRAW_PIPE_EDGE_FLAG_0 |
177                    DRAW_PIPE_EDGE_FLAG_2;
178            /* always emit idx[3] last */
179            TRIANGLE(flags, idx[0], idx[1], idx[3]);
180
181            flags = DRAW_PIPE_EDGE_FLAG_0 |
182                    DRAW_PIPE_EDGE_FLAG_1;
183            TRIANGLE(flags, idx[1], idx[2], idx[3]);
184         }
185      }
186      else {
187         for (i = 0; i + 3 < count; i += 4) {
188            idx[0] = GET_ELT(i);
189            idx[1] = GET_ELT(i + 1);
190            idx[2] = GET_ELT(i + 2);
191            idx[3] = GET_ELT(i + 3);
192
193            flags = DRAW_PIPE_RESET_STIPPLE |
194                    DRAW_PIPE_EDGE_FLAG_0 |
195                    DRAW_PIPE_EDGE_FLAG_1;
196            /* always emit idx[3] / idx[0] first */
197            if (quads_flatshade_last)
198               TRIANGLE(flags, idx[3], idx[0], idx[1]);
199            else
200               TRIANGLE(flags, idx[0], idx[1], idx[2]);
201
202            flags = DRAW_PIPE_EDGE_FLAG_1 |
203                    DRAW_PIPE_EDGE_FLAG_2;
204            if (quads_flatshade_last)
205               TRIANGLE(flags, idx[3], idx[1], idx[2]);
206            else
207               TRIANGLE(flags, idx[0], idx[2], idx[3]);
208         }
209      }
210      break;
211
212   case PIPE_PRIM_QUAD_STRIP:
213      if (count >= 4) {
214         idx[2] = GET_ELT(0);
215         idx[3] = GET_ELT(1);
216
217         if (last_vertex_last) {
218            for (i = 0; i + 3 < count; i += 2) {
219               idx[0] = idx[2];
220               idx[1] = idx[3];
221               idx[2] = GET_ELT(i + 2);
222               idx[3] = GET_ELT(i + 3);
223
224               /* always emit idx[3] last */
225               flags = DRAW_PIPE_RESET_STIPPLE |
226                       DRAW_PIPE_EDGE_FLAG_0 |
227                       DRAW_PIPE_EDGE_FLAG_2;
228               TRIANGLE(flags, idx[2], idx[0], idx[3]);
229
230               flags = DRAW_PIPE_EDGE_FLAG_0 |
231                       DRAW_PIPE_EDGE_FLAG_1;
232               TRIANGLE(flags, idx[0], idx[1], idx[3]);
233            }
234         }
235         else {
236            for (i = 0; i + 3 < count; i += 2) {
237               idx[0] = idx[2];
238               idx[1] = idx[3];
239               idx[2] = GET_ELT(i + 2);
240               idx[3] = GET_ELT(i + 3);
241
242               flags = DRAW_PIPE_RESET_STIPPLE |
243                       DRAW_PIPE_EDGE_FLAG_0 |
244                       DRAW_PIPE_EDGE_FLAG_1;
245               /* always emit idx[3] / idx[0 first */
246               if (quads_flatshade_last)
247                  TRIANGLE(flags, idx[3], idx[2], idx[0]);
248               else
249                  TRIANGLE(flags, idx[0], idx[3], idx[2]);
250
251               flags = DRAW_PIPE_EDGE_FLAG_1 |
252                       DRAW_PIPE_EDGE_FLAG_2;
253               if (quads_flatshade_last)
254                  TRIANGLE(flags, idx[3], idx[0], idx[1]);
255               else
256                  TRIANGLE(flags, idx[0], idx[1], idx[3]);
257            }
258         }
259      }
260      break;
261
262   case PIPE_PRIM_POLYGON:
263      if (count >= 3) {
264         ushort edge_next, edge_finish;
265
266         if (last_vertex_last) {
267            flags = (DRAW_PIPE_RESET_STIPPLE |
268                     DRAW_PIPE_EDGE_FLAG_0);
269            if (!(prim_flags & DRAW_SPLIT_BEFORE))
270               flags |= DRAW_PIPE_EDGE_FLAG_2;
271
272            edge_next = DRAW_PIPE_EDGE_FLAG_0;
273            edge_finish =
274               (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1;
275         }
276         else {
277            flags = (DRAW_PIPE_RESET_STIPPLE |
278                     DRAW_PIPE_EDGE_FLAG_1);
279            if (!(prim_flags & DRAW_SPLIT_BEFORE))
280               flags |= DRAW_PIPE_EDGE_FLAG_0;
281
282            edge_next = DRAW_PIPE_EDGE_FLAG_1;
283            edge_finish =
284               (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2;
285         }
286
287         idx[0] = GET_ELT(0);
288         idx[2] = GET_ELT(1);
289
290         for (i = 0; i + 2 < count; i++, flags = edge_next) {
291            idx[1] = idx[2];
292            idx[2] = GET_ELT(i + 2);
293
294            if (i + 3 == count)
295               flags |= edge_finish;
296
297            /* idx[0] is both the first and the last vertex */
298            if (last_vertex_last)
299               TRIANGLE(flags, idx[1], idx[2], idx[0]);
300            else
301               TRIANGLE(flags, idx[0], idx[1], idx[2]);
302         }
303      }
304      break;
305
306   case PIPE_PRIM_LINES_ADJACENCY:
307      flags = DRAW_PIPE_RESET_STIPPLE;
308      for (i = 0; i + 3 < count; i += 4) {
309         idx[0] = GET_ELT(i);
310         idx[1] = GET_ELT(i + 1);
311         idx[2] = GET_ELT(i + 2);
312         idx[3] = GET_ELT(i + 3);
313         LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
314      }
315      break;
316
317   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
318      if (count >= 4) {
319         flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
320         idx[1] = GET_ELT(0);
321         idx[2] = GET_ELT(1);
322         idx[3] = GET_ELT(2);
323
324         for (i = 1; i + 2 < count; i++, flags = 0) {
325            idx[0] = idx[1];
326            idx[1] = idx[2];
327            idx[2] = idx[3];
328            idx[3] = GET_ELT(i + 2);
329            LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
330         }
331      }
332      break;
333
334   case PIPE_PRIM_TRIANGLES_ADJACENCY:
335      flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
336      for (i = 0; i + 5 < count; i += 6) {
337         idx[0] = GET_ELT(i);
338         idx[1] = GET_ELT(i + 1);
339         idx[2] = GET_ELT(i + 2);
340         idx[3] = GET_ELT(i + 3);
341         idx[4] = GET_ELT(i + 4);
342         idx[5] = GET_ELT(i + 5);
343         TRIANGLE_ADJ(flags, idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
344      }
345      break;
346
347   case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
348      if (count >= 6) {
349         flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
350         idx[0] = GET_ELT(1);
351         idx[2] = GET_ELT(0);
352         idx[4] = GET_ELT(2);
353         idx[3] = GET_ELT(4);
354
355         /*
356          * The vertices of the i-th triangle are stored in
357          * idx[0,2,4] = { 2*i, 2*i+2, 2*i+4 };
358          *
359          * The adjacent vertices are stored in
360          * idx[1,3,5] = { 2*i-2, 2*i+6, 2*i+3 }.
361          *
362          * However, there are two exceptions:
363          *
364          * For the first triangle, idx[1] = 1;
365          * For the  last triangle, idx[3] = 2*i+5.
366          */
367         if (last_vertex_last) {
368            for (i = 0; i + 5 < count; i += 2) {
369               idx[1] = idx[0];
370
371               idx[0] = idx[2];
372               idx[2] = idx[4];
373               idx[4] = idx[3];
374
375               idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
376               idx[5] = GET_ELT(i + 3);
377
378               /*
379                * alternate the first two vertices (idx[0] and idx[2]) and the
380                * corresponding adjacent vertices (idx[3] and idx[5]) to have
381                * the correct orientation
382                */
383               if (i & 2) {
384                  TRIANGLE_ADJ(flags,
385                        idx[2], idx[1], idx[0], idx[5], idx[4], idx[3]);
386               }
387               else {
388                  TRIANGLE_ADJ(flags,
389                        idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
390               }
391            }
392         }
393         else {
394            for (i = 0; i + 5 < count; i += 2) {
395               idx[1] = idx[0];
396
397               idx[0] = idx[2];
398               idx[2] = idx[4];
399               idx[4] = idx[3];
400
401               idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
402               idx[5] = GET_ELT(i + 3);
403
404               /*
405                * alternate the last two vertices (idx[2] and idx[4]) and the
406                * corresponding adjacent vertices (idx[1] and idx[5]) to have
407                * the correct orientation
408                */
409               if (i & 2) {
410                  TRIANGLE_ADJ(flags,
411                        idx[0], idx[5], idx[4], idx[3], idx[2], idx[1]);
412               }
413               else {
414                  TRIANGLE_ADJ(flags,
415                        idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
416               }
417            }
418         }
419      }
420      break;
421
422   default:
423      assert(0);
424      break;
425   }
426
427   FUNC_EXIT;
428}
429
430#undef LOCAL_VARS
431#undef FUNC_ENTER
432#undef FUNC_EXIT
433#undef LINE_ADJ
434#undef TRIANGLE_ADJ
435
436#undef FUNC
437#undef FUNC_VARS
438#undef GET_ELT
439#undef POINT
440#undef LINE
441#undef TRIANGLE
442