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 
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