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