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