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