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 
47 static void
FUNC(FUNC_VARS)48 FUNC(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 #ifdef PASS_QUADS
174             QUAD(0, idx[0], idx[1],
175                   idx[2], idx[3]);
176 #else
177             flags = DRAW_PIPE_RESET_STIPPLE |
178                     DRAW_PIPE_EDGE_FLAG_0 |
179                     DRAW_PIPE_EDGE_FLAG_2;
180             /* always emit idx[3] last */
181             TRIANGLE(flags, idx[0], idx[1], idx[3]);
182 
183             flags = DRAW_PIPE_EDGE_FLAG_0 |
184                     DRAW_PIPE_EDGE_FLAG_1;
185             TRIANGLE(flags, idx[1], idx[2], idx[3]);
186 #endif
187          }
188       }
189       else {
190          for (i = 0; i + 3 < count; i += 4) {
191             idx[0] = GET_ELT(i);
192             idx[1] = GET_ELT(i + 1);
193             idx[2] = GET_ELT(i + 2);
194             idx[3] = GET_ELT(i + 3);
195 #ifdef PASS_QUADS
196             QUAD(0, idx[0], idx[1],
197                   idx[2], idx[3]);
198 #else
199             flags = DRAW_PIPE_RESET_STIPPLE |
200                     DRAW_PIPE_EDGE_FLAG_0 |
201                     DRAW_PIPE_EDGE_FLAG_1;
202             /* always emit idx[3] / idx[0] first */
203             if (quads_flatshade_last)
204                TRIANGLE(flags, idx[3], idx[0], idx[1]);
205             else
206                TRIANGLE(flags, idx[0], idx[1], idx[2]);
207 
208             flags = DRAW_PIPE_EDGE_FLAG_1 |
209                     DRAW_PIPE_EDGE_FLAG_2;
210             if (quads_flatshade_last)
211                TRIANGLE(flags, idx[3], idx[1], idx[2]);
212             else
213                TRIANGLE(flags, idx[0], idx[2], idx[3]);
214 #endif
215          }
216       }
217       break;
218 
219    case PIPE_PRIM_QUAD_STRIP:
220       if (count >= 4) {
221          idx[2] = GET_ELT(0);
222          idx[3] = GET_ELT(1);
223 
224          if (last_vertex_last) {
225             for (i = 0; i + 3 < count; i += 2) {
226                idx[0] = idx[2];
227                idx[1] = idx[3];
228                idx[2] = GET_ELT(i + 2);
229                idx[3] = GET_ELT(i + 3);
230 
231 #ifdef PASS_QUADS
232                QUAD(0, idx[2], idx[0],
233                     idx[1], idx[3]);
234 #else
235                /* always emit idx[3] last */
236                flags = DRAW_PIPE_RESET_STIPPLE |
237                        DRAW_PIPE_EDGE_FLAG_0 |
238                        DRAW_PIPE_EDGE_FLAG_2;
239                TRIANGLE(flags, idx[2], idx[0], idx[3]);
240 
241                flags = DRAW_PIPE_EDGE_FLAG_0 |
242                        DRAW_PIPE_EDGE_FLAG_1;
243                TRIANGLE(flags, idx[0], idx[1], idx[3]);
244 #endif
245             }
246          }
247          else {
248             for (i = 0; i + 3 < count; i += 2) {
249                idx[0] = idx[2];
250                idx[1] = idx[3];
251                idx[2] = GET_ELT(i + 2);
252                idx[3] = GET_ELT(i + 3);
253 
254 #ifdef PASS_QUADS
255                QUAD(0, idx[3], idx[2],
256                     idx[0], idx[1]);
257 #else
258                flags = DRAW_PIPE_RESET_STIPPLE |
259                        DRAW_PIPE_EDGE_FLAG_0 |
260                        DRAW_PIPE_EDGE_FLAG_1;
261                /* always emit idx[3] / idx[0 first */
262                if (quads_flatshade_last)
263                   TRIANGLE(flags, idx[3], idx[2], idx[0]);
264                else
265                   TRIANGLE(flags, idx[0], idx[3], idx[2]);
266 
267                flags = DRAW_PIPE_EDGE_FLAG_1 |
268                        DRAW_PIPE_EDGE_FLAG_2;
269                if (quads_flatshade_last)
270                   TRIANGLE(flags, idx[3], idx[0], idx[1]);
271                else
272                   TRIANGLE(flags, idx[0], idx[1], idx[3]);
273 #endif
274             }
275          }
276       }
277       break;
278 
279    case PIPE_PRIM_POLYGON:
280       if (count >= 3) {
281          ushort edge_next, edge_finish;
282 
283          if (last_vertex_last) {
284             flags = (DRAW_PIPE_RESET_STIPPLE |
285                      DRAW_PIPE_EDGE_FLAG_0);
286             if (!(prim_flags & DRAW_SPLIT_BEFORE))
287                flags |= DRAW_PIPE_EDGE_FLAG_2;
288 
289             edge_next = DRAW_PIPE_EDGE_FLAG_0;
290             edge_finish =
291                (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_1;
292          }
293          else {
294             flags = (DRAW_PIPE_RESET_STIPPLE |
295                      DRAW_PIPE_EDGE_FLAG_1);
296             if (!(prim_flags & DRAW_SPLIT_BEFORE))
297                flags |= DRAW_PIPE_EDGE_FLAG_0;
298 
299             edge_next = DRAW_PIPE_EDGE_FLAG_1;
300             edge_finish =
301                (prim_flags & DRAW_SPLIT_AFTER) ? 0 : DRAW_PIPE_EDGE_FLAG_2;
302          }
303 
304          idx[0] = GET_ELT(0);
305          idx[2] = GET_ELT(1);
306 
307          for (i = 0; i + 2 < count; i++, flags = edge_next) {
308             idx[1] = idx[2];
309             idx[2] = GET_ELT(i + 2);
310 
311             if (i + 3 == count)
312                flags |= edge_finish;
313 
314             /* idx[0] is both the first and the last vertex */
315             if (last_vertex_last)
316                TRIANGLE(flags, idx[1], idx[2], idx[0]);
317             else
318                TRIANGLE(flags, idx[0], idx[1], idx[2]);
319          }
320       }
321       break;
322 
323    case PIPE_PRIM_LINES_ADJACENCY:
324       flags = DRAW_PIPE_RESET_STIPPLE;
325       for (i = 0; i + 3 < count; i += 4) {
326          idx[0] = GET_ELT(i);
327          idx[1] = GET_ELT(i + 1);
328          idx[2] = GET_ELT(i + 2);
329          idx[3] = GET_ELT(i + 3);
330          LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
331       }
332       break;
333 
334    case PIPE_PRIM_LINE_STRIP_ADJACENCY:
335       if (count >= 4) {
336          flags = (prim_flags & DRAW_SPLIT_BEFORE) ? 0 : DRAW_PIPE_RESET_STIPPLE;
337          idx[1] = GET_ELT(0);
338          idx[2] = GET_ELT(1);
339          idx[3] = GET_ELT(2);
340 
341          for (i = 1; i + 2 < count; i++, flags = 0) {
342             idx[0] = idx[1];
343             idx[1] = idx[2];
344             idx[2] = idx[3];
345             idx[3] = GET_ELT(i + 2);
346             LINE_ADJ(flags, idx[0], idx[1], idx[2], idx[3]);
347          }
348       }
349       break;
350 
351    case PIPE_PRIM_TRIANGLES_ADJACENCY:
352       flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
353       for (i = 0; i + 5 < count; i += 6) {
354          idx[0] = GET_ELT(i);
355          idx[1] = GET_ELT(i + 1);
356          idx[2] = GET_ELT(i + 2);
357          idx[3] = GET_ELT(i + 3);
358          idx[4] = GET_ELT(i + 4);
359          idx[5] = GET_ELT(i + 5);
360          TRIANGLE_ADJ(flags, idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
361       }
362       break;
363 
364    case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
365       if (count >= 6) {
366          flags = DRAW_PIPE_RESET_STIPPLE | DRAW_PIPE_EDGE_FLAG_ALL;
367          idx[0] = GET_ELT(1);
368          idx[2] = GET_ELT(0);
369          idx[4] = GET_ELT(2);
370          idx[3] = GET_ELT(4);
371 
372          /*
373           * The vertices of the i-th triangle are stored in
374           * idx[0,2,4] = { 2*i, 2*i+2, 2*i+4 };
375           *
376           * The adjacent vertices are stored in
377           * idx[1,3,5] = { 2*i-2, 2*i+6, 2*i+3 }.
378           *
379           * However, there are two exceptions:
380           *
381           * For the first triangle, idx[1] = 1;
382           * For the  last triangle, idx[3] = 2*i+5.
383           */
384          if (last_vertex_last) {
385             for (i = 0; i + 5 < count; i += 2) {
386                idx[1] = idx[0];
387 
388                idx[0] = idx[2];
389                idx[2] = idx[4];
390                idx[4] = idx[3];
391 
392                idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
393                idx[5] = GET_ELT(i + 3);
394 
395                /*
396                 * alternate the first two vertices (idx[0] and idx[2]) and the
397                 * corresponding adjacent vertices (idx[3] and idx[5]) to have
398                 * the correct orientation
399                 */
400                if (i & 2) {
401                   TRIANGLE_ADJ(flags,
402                         idx[2], idx[1], idx[0], idx[5], idx[4], idx[3]);
403                }
404                else {
405                   TRIANGLE_ADJ(flags,
406                         idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
407                }
408             }
409          }
410          else {
411             for (i = 0; i + 5 < count; i += 2) {
412                idx[1] = idx[0];
413 
414                idx[0] = idx[2];
415                idx[2] = idx[4];
416                idx[4] = idx[3];
417 
418                idx[3] = GET_ELT(i + ((i + 7 < count) ? 6 : 5));
419                idx[5] = GET_ELT(i + 3);
420 
421                /*
422                 * alternate the last two vertices (idx[2] and idx[4]) and the
423                 * corresponding adjacent vertices (idx[1] and idx[5]) to have
424                 * the correct orientation
425                 */
426                if (i & 2) {
427                   TRIANGLE_ADJ(flags,
428                         idx[0], idx[5], idx[4], idx[3], idx[2], idx[1]);
429                }
430                else {
431                   TRIANGLE_ADJ(flags,
432                         idx[0], idx[1], idx[2], idx[3], idx[4], idx[5]);
433                }
434             }
435          }
436       }
437       break;
438 
439    default:
440       assert(0);
441       break;
442    }
443 
444    FUNC_EXIT;
445 }
446 
447 #undef LOCAL_VARS
448 #undef FUNC_ENTER
449 #undef FUNC_EXIT
450 #undef LINE_ADJ
451 #undef TRIANGLE_ADJ
452 
453 #undef FUNC
454 #undef FUNC_VARS
455 #undef GET_ELT
456 #undef POINT
457 #undef LINE
458 #undef TRIANGLE
459