• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
48 static void
FUNC(FUNC_VARS)49 FUNC(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