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 (at) tungstengraphics.com> 28 * Chia-I Wu <olv (at) 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 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