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