1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keithw@vmware.com> 26 */ 27 28 29#ifndef POSTFIX 30#define POSTFIX 31#endif 32 33#ifndef INIT 34#define INIT(x) 35#endif 36 37#ifndef NEED_EDGEFLAG_SETUP 38#define NEED_EDGEFLAG_SETUP 0 39#define EDGEFLAG_GET(a) 0 40#define EDGEFLAG_SET(a,b) (void)b 41#endif 42 43#ifndef RESET_STIPPLE 44#define RESET_STIPPLE 45#endif 46 47#ifndef TEST_PRIM_END 48#define TEST_PRIM_END(prim) (flags & PRIM_END) 49#define TEST_PRIM_BEGIN(prim) (flags & PRIM_BEGIN) 50#endif 51 52#ifndef ELT 53#define ELT(x) x 54#endif 55 56#ifndef RENDER_TAB_QUALIFIER 57#define RENDER_TAB_QUALIFIER static 58#endif 59 60static void TAG(render_points)( struct gl_context *ctx, 61 GLuint start, 62 GLuint count, 63 GLuint flags ) 64{ 65 LOCAL_VARS; 66 (void) flags; 67 68 INIT(GL_POINTS); 69 RENDER_POINTS( start, count ); 70 POSTFIX; 71} 72 73static void TAG(render_lines)( struct gl_context *ctx, 74 GLuint start, 75 GLuint count, 76 GLuint flags ) 77{ 78 GLuint j; 79 LOCAL_VARS; 80 (void) flags; 81 82 INIT(GL_LINES); 83 for (j=start+1; j<count; j+=2 ) { 84 RESET_STIPPLE; 85 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 86 RENDER_LINE( ELT(j-1), ELT(j) ); 87 else 88 RENDER_LINE( ELT(j), ELT(j-1) ); 89 } 90 POSTFIX; 91} 92 93 94static void TAG(render_line_strip)( struct gl_context *ctx, 95 GLuint start, 96 GLuint count, 97 GLuint flags ) 98{ 99 GLuint j; 100 LOCAL_VARS; 101 (void) flags; 102 103 INIT(GL_LINE_STRIP); 104 105 if (TEST_PRIM_BEGIN(flags)) { 106 RESET_STIPPLE; 107 } 108 109 for (j=start+1; j<count; j++ ) { 110 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 111 RENDER_LINE( ELT(j-1), ELT(j) ); 112 else 113 RENDER_LINE( ELT(j), ELT(j-1) ); 114 } 115 POSTFIX; 116} 117 118 119static void TAG(render_line_loop)( struct gl_context *ctx, 120 GLuint start, 121 GLuint count, 122 GLuint flags ) 123{ 124 GLuint i; 125 LOCAL_VARS; 126 127 INIT(GL_LINE_LOOP); 128 129 if (start+1 < count) { 130 if (TEST_PRIM_BEGIN(flags)) { 131 RESET_STIPPLE; 132 /* draw the first line from v[0] to v[1] */ 133 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 134 RENDER_LINE( ELT(start), ELT(start+1) ); 135 else 136 RENDER_LINE( ELT(start+1), ELT(start) ); 137 } 138 139 /* draw lines from v[1] to v[n-1] */ 140 for ( i = start+2 ; i < count ; i++) { 141 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 142 RENDER_LINE( ELT(i-1), ELT(i) ); 143 else 144 RENDER_LINE( ELT(i), ELT(i-1) ); 145 } 146 147 if ( TEST_PRIM_END(flags)) { 148 /* draw final line from v[n-1] to v[0] (the very first vertex) */ 149 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 150 RENDER_LINE( ELT(count-1), ELT(start) ); 151 else 152 RENDER_LINE( ELT(start), ELT(count-1) ); 153 } 154 } 155 156 POSTFIX; 157} 158 159 160static void TAG(render_triangles)( struct gl_context *ctx, 161 GLuint start, 162 GLuint count, 163 GLuint flags ) 164{ 165 GLuint j; 166 LOCAL_VARS; 167 (void) flags; 168 169 INIT(GL_TRIANGLES); 170 if (NEED_EDGEFLAG_SETUP) { 171 for (j=start+2; j<count; j+=3) { 172 /* Leave the edgeflags as supplied by the user. 173 */ 174 RESET_STIPPLE; 175 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 176 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); 177 else 178 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); 179 } 180 } else { 181 for (j=start+2; j<count; j+=3) { 182 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 183 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); 184 else 185 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); 186 } 187 } 188 POSTFIX; 189} 190 191 192 193static void TAG(render_tri_strip)( struct gl_context *ctx, 194 GLuint start, 195 GLuint count, 196 GLuint flags ) 197{ 198 GLuint j; 199 GLuint parity = 0; 200 LOCAL_VARS; 201 202 INIT(GL_TRIANGLE_STRIP); 203 if (NEED_EDGEFLAG_SETUP) { 204 for (j=start+2;j<count;j++,parity^=1) { 205 GLuint ej2, ej1, ej; 206 GLboolean ef2, ef1, ef; 207 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) { 208 ej2 = ELT(j-2+parity); 209 ej1 = ELT(j-1-parity); 210 ej = ELT(j); 211 } 212 else { 213 ej2 = ELT(j-1+parity); 214 ej1 = ELT(j-parity); 215 ej = ELT(j-2); 216 } 217 ef2 = EDGEFLAG_GET( ej2 ); 218 ef1 = EDGEFLAG_GET( ej1 ); 219 ef = EDGEFLAG_GET( ej ); 220 if (TEST_PRIM_BEGIN(flags)) { 221 RESET_STIPPLE; 222 } 223 EDGEFLAG_SET( ej2, GL_TRUE ); 224 EDGEFLAG_SET( ej1, GL_TRUE ); 225 EDGEFLAG_SET( ej, GL_TRUE ); 226 RENDER_TRI( ej2, ej1, ej ); 227 EDGEFLAG_SET( ej2, ef2 ); 228 EDGEFLAG_SET( ej1, ef1 ); 229 EDGEFLAG_SET( ej, ef ); 230 } 231 } else { 232 for (j=start+2; j<count ; j++, parity^=1) { 233 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 234 RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) ); 235 else 236 RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) ); 237 } 238 } 239 POSTFIX; 240} 241 242 243static void TAG(render_tri_fan)( struct gl_context *ctx, 244 GLuint start, 245 GLuint count, 246 GLuint flags ) 247{ 248 GLuint j; 249 LOCAL_VARS; 250 (void) flags; 251 252 INIT(GL_TRIANGLE_FAN); 253 if (NEED_EDGEFLAG_SETUP) { 254 for (j=start+2;j<count;j++) { 255 /* For trifans, all edges are boundary. 256 */ 257 GLuint ejs = ELT(start); 258 GLuint ej1 = ELT(j-1); 259 GLuint ej = ELT(j); 260 GLboolean efs = EDGEFLAG_GET( ejs ); 261 GLboolean ef1 = EDGEFLAG_GET( ej1 ); 262 GLboolean ef = EDGEFLAG_GET( ej ); 263 if (TEST_PRIM_BEGIN(flags)) { 264 RESET_STIPPLE; 265 } 266 EDGEFLAG_SET( ejs, GL_TRUE ); 267 EDGEFLAG_SET( ej1, GL_TRUE ); 268 EDGEFLAG_SET( ej, GL_TRUE ); 269 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 270 RENDER_TRI( ejs, ej1, ej); 271 else 272 RENDER_TRI( ej, ejs, ej1); 273 EDGEFLAG_SET( ejs, efs ); 274 EDGEFLAG_SET( ej1, ef1 ); 275 EDGEFLAG_SET( ej, ef ); 276 } 277 } else { 278 for (j=start+2;j<count;j++) { 279 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 280 RENDER_TRI( ELT(start), ELT(j-1), ELT(j) ); 281 else 282 RENDER_TRI( ELT(j), ELT(start), ELT(j-1) ); 283 } 284 } 285 286 POSTFIX; 287} 288 289 290static void TAG(render_poly)( struct gl_context *ctx, 291 GLuint start, 292 GLuint count, 293 GLuint flags ) 294{ 295 GLuint j = start+2; 296 LOCAL_VARS; 297 (void) flags; 298 299 INIT(GL_POLYGON); 300 if (NEED_EDGEFLAG_SETUP) { 301 GLboolean efstart = EDGEFLAG_GET( ELT(start) ); 302 GLboolean efcount = EDGEFLAG_GET( ELT(count-1) ); 303 304 /* If the primitive does not begin here, the first edge 305 * is non-boundary. 306 */ 307 if (!TEST_PRIM_BEGIN(flags)) 308 EDGEFLAG_SET( ELT(start), GL_FALSE ); 309 else { 310 RESET_STIPPLE; 311 } 312 313 /* If the primitive does not end here, the final edge is 314 * non-boundary. 315 */ 316 if (!TEST_PRIM_END(flags)) 317 EDGEFLAG_SET( ELT(count-1), GL_FALSE ); 318 319 /* Draw the first triangles (possibly zero) 320 */ 321 if (j+1<count) { 322 GLboolean ef = EDGEFLAG_GET( ELT(j) ); 323 EDGEFLAG_SET( ELT(j), GL_FALSE ); 324 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 325 EDGEFLAG_SET( ELT(j), ef ); 326 j++; 327 328 /* Don't render the first edge again: 329 */ 330 EDGEFLAG_SET( ELT(start), GL_FALSE ); 331 332 for (;j+1<count;j++) { 333 GLboolean efj = EDGEFLAG_GET( ELT(j) ); 334 EDGEFLAG_SET( ELT(j), GL_FALSE ); 335 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 336 EDGEFLAG_SET( ELT(j), efj ); 337 } 338 } 339 340 /* Draw the last or only triangle 341 */ 342 if (j < count) 343 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 344 345 /* Restore the first and last edgeflags: 346 */ 347 EDGEFLAG_SET( ELT(count-1), efcount ); 348 EDGEFLAG_SET( ELT(start), efstart ); 349 350 } 351 else { 352 for (j=start+2;j<count;j++) { 353 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 354 } 355 } 356 POSTFIX; 357} 358 359static void TAG(render_quads)( struct gl_context *ctx, 360 GLuint start, 361 GLuint count, 362 GLuint flags ) 363{ 364 GLuint j; 365 LOCAL_VARS; 366 (void) flags; 367 368 INIT(GL_QUADS); 369 if (NEED_EDGEFLAG_SETUP) { 370 for (j=start+3; j<count; j+=4) { 371 /* Use user-specified edgeflags for quads. 372 */ 373 RESET_STIPPLE; 374 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 375 !ctx->Const.QuadsFollowProvokingVertexConvention) 376 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); 377 else 378 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); 379 } 380 } else { 381 for (j=start+3; j<count; j+=4) { 382 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 383 !ctx->Const.QuadsFollowProvokingVertexConvention) 384 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); 385 else 386 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); 387 } 388 } 389 POSTFIX; 390} 391 392static void TAG(render_quad_strip)( struct gl_context *ctx, 393 GLuint start, 394 GLuint count, 395 GLuint flags ) 396{ 397 GLuint j; 398 LOCAL_VARS; 399 (void) flags; 400 401 INIT(GL_QUAD_STRIP); 402 if (NEED_EDGEFLAG_SETUP) { 403 for (j=start+3;j<count;j+=2) { 404 /* All edges are boundary. Set edgeflags to 1, draw the 405 * quad, and restore them to the original values. 406 */ 407 GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) ); 408 GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) ); 409 GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) ); 410 GLboolean ef = EDGEFLAG_GET( ELT(j) ); 411 if (TEST_PRIM_BEGIN(flags)) { 412 RESET_STIPPLE; 413 } 414 EDGEFLAG_SET( ELT(j-3), GL_TRUE ); 415 EDGEFLAG_SET( ELT(j-2), GL_TRUE ); 416 EDGEFLAG_SET( ELT(j-1), GL_TRUE ); 417 EDGEFLAG_SET( ELT(j), GL_TRUE ); 418 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 419 !ctx->Const.QuadsFollowProvokingVertexConvention) 420 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); 421 else 422 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); 423 EDGEFLAG_SET( ELT(j-3), ef3 ); 424 EDGEFLAG_SET( ELT(j-2), ef2 ); 425 EDGEFLAG_SET( ELT(j-1), ef1 ); 426 EDGEFLAG_SET( ELT(j), ef ); 427 } 428 } else { 429 for (j=start+3;j<count;j+=2) { 430 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 431 !ctx->Const.QuadsFollowProvokingVertexConvention) 432 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); 433 else 434 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); 435 } 436 } 437 POSTFIX; 438} 439 440static void TAG(render_noop)( struct gl_context *ctx, 441 GLuint start, 442 GLuint count, 443 GLuint flags ) 444{ 445 (void)(ctx && start && count && flags); 446} 447 448RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(struct gl_context *, 449 GLuint, 450 GLuint, 451 GLuint) = 452{ 453 TAG(render_points), 454 TAG(render_lines), 455 TAG(render_line_loop), 456 TAG(render_line_strip), 457 TAG(render_triangles), 458 TAG(render_tri_strip), 459 TAG(render_tri_fan), 460 TAG(render_quads), 461 TAG(render_quad_strip), 462 TAG(render_poly), 463 TAG(render_noop), 464}; 465 466 467 468#ifndef PRESERVE_VB_DEFS 469#undef RENDER_TRI 470#undef RENDER_QUAD 471#undef RENDER_LINE 472#undef RENDER_POINTS 473#undef LOCAL_VARS 474#undef INIT 475#undef POSTFIX 476#undef RESET_STIPPLE 477#undef DBG 478#undef ELT 479#undef RENDER_TAB_QUALIFIER 480#endif 481 482#ifndef PRESERVE_TAG 483#undef TAG 484#endif 485 486#undef PRESERVE_VB_DEFS 487#undef PRESERVE_TAG 488