1/* 2 * Mesa 3-D graphics library 3 * Version: 6.5 4 * 5 * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. 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 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Authors: 25 * Keith Whitwell <keith@tungstengraphics.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 (void) flags; 128 129 INIT(GL_LINE_LOOP); 130 131 if (start+1 < count) { 132 if (TEST_PRIM_BEGIN(flags)) { 133 RESET_STIPPLE; 134 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 135 RENDER_LINE( ELT(start), ELT(start+1) ); 136 else 137 RENDER_LINE( ELT(start+1), ELT(start) ); 138 } 139 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 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 149 RENDER_LINE( ELT(count-1), ELT(start) ); 150 else 151 RENDER_LINE( ELT(start), ELT(count-1) ); 152 } 153 } 154 155 POSTFIX; 156} 157 158 159static void TAG(render_triangles)( struct gl_context *ctx, 160 GLuint start, 161 GLuint count, 162 GLuint flags ) 163{ 164 GLuint j; 165 LOCAL_VARS; 166 (void) flags; 167 168 INIT(GL_TRIANGLES); 169 if (NEED_EDGEFLAG_SETUP) { 170 for (j=start+2; j<count; j+=3) { 171 /* Leave the edgeflags as supplied by the user. 172 */ 173 RESET_STIPPLE; 174 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 175 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); 176 else 177 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); 178 } 179 } else { 180 for (j=start+2; j<count; j+=3) { 181 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 182 RENDER_TRI( ELT(j-2), ELT(j-1), ELT(j) ); 183 else 184 RENDER_TRI( ELT(j-1), ELT(j), ELT(j-2) ); 185 } 186 } 187 POSTFIX; 188} 189 190 191 192static void TAG(render_tri_strip)( struct gl_context *ctx, 193 GLuint start, 194 GLuint count, 195 GLuint flags ) 196{ 197 GLuint j; 198 GLuint parity = 0; 199 LOCAL_VARS; 200 201 INIT(GL_TRIANGLE_STRIP); 202 if (NEED_EDGEFLAG_SETUP) { 203 for (j=start+2;j<count;j++,parity^=1) { 204 GLuint ej2, ej1, ej; 205 GLboolean ef2, ef1, ef; 206 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) { 207 ej2 = ELT(j-2+parity); 208 ej1 = ELT(j-1-parity); 209 ej = ELT(j); 210 } 211 else { 212 ej2 = ELT(j-1+parity); 213 ej1 = ELT(j-parity); 214 ej = ELT(j-2); 215 } 216 ef2 = EDGEFLAG_GET( ej2 ); 217 ef1 = EDGEFLAG_GET( ej1 ); 218 ef = EDGEFLAG_GET( ej ); 219 if (TEST_PRIM_BEGIN(flags)) { 220 RESET_STIPPLE; 221 } 222 EDGEFLAG_SET( ej2, GL_TRUE ); 223 EDGEFLAG_SET( ej1, GL_TRUE ); 224 EDGEFLAG_SET( ej, GL_TRUE ); 225 RENDER_TRI( ej2, ej1, ej ); 226 EDGEFLAG_SET( ej2, ef2 ); 227 EDGEFLAG_SET( ej1, ef1 ); 228 EDGEFLAG_SET( ej, ef ); 229 } 230 } else { 231 for (j=start+2; j<count ; j++, parity^=1) { 232 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 233 RENDER_TRI( ELT(j-2+parity), ELT(j-1-parity), ELT(j) ); 234 else 235 RENDER_TRI( ELT(j-1+parity), ELT(j-parity), ELT(j-2) ); 236 } 237 } 238 POSTFIX; 239} 240 241 242static void TAG(render_tri_fan)( struct gl_context *ctx, 243 GLuint start, 244 GLuint count, 245 GLuint flags ) 246{ 247 GLuint j; 248 LOCAL_VARS; 249 (void) flags; 250 251 INIT(GL_TRIANGLE_FAN); 252 if (NEED_EDGEFLAG_SETUP) { 253 for (j=start+2;j<count;j++) { 254 /* For trifans, all edges are boundary. 255 */ 256 GLuint ejs = ELT(start); 257 GLuint ej1 = ELT(j-1); 258 GLuint ej = ELT(j); 259 GLboolean efs = EDGEFLAG_GET( ejs ); 260 GLboolean ef1 = EDGEFLAG_GET( ej1 ); 261 GLboolean ef = EDGEFLAG_GET( ej ); 262 if (TEST_PRIM_BEGIN(flags)) { 263 RESET_STIPPLE; 264 } 265 EDGEFLAG_SET( ejs, GL_TRUE ); 266 EDGEFLAG_SET( ej1, GL_TRUE ); 267 EDGEFLAG_SET( ej, GL_TRUE ); 268 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 269 RENDER_TRI( ejs, ej1, ej); 270 else 271 RENDER_TRI( ej, ejs, ej1); 272 EDGEFLAG_SET( ejs, efs ); 273 EDGEFLAG_SET( ej1, ef1 ); 274 EDGEFLAG_SET( ej, ef ); 275 } 276 } else { 277 for (j=start+2;j<count;j++) { 278 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT) 279 RENDER_TRI( ELT(start), ELT(j-1), ELT(j) ); 280 else 281 RENDER_TRI( ELT(j), ELT(start), ELT(j-1) ); 282 } 283 } 284 285 POSTFIX; 286} 287 288 289static void TAG(render_poly)( struct gl_context *ctx, 290 GLuint start, 291 GLuint count, 292 GLuint flags ) 293{ 294 GLuint j = start+2; 295 LOCAL_VARS; 296 (void) flags; 297 298 INIT(GL_POLYGON); 299 if (NEED_EDGEFLAG_SETUP) { 300 GLboolean efstart = EDGEFLAG_GET( ELT(start) ); 301 GLboolean efcount = EDGEFLAG_GET( ELT(count-1) ); 302 303 /* If the primitive does not begin here, the first edge 304 * is non-boundary. 305 */ 306 if (!TEST_PRIM_BEGIN(flags)) 307 EDGEFLAG_SET( ELT(start), GL_FALSE ); 308 else { 309 RESET_STIPPLE; 310 } 311 312 /* If the primitive does not end here, the final edge is 313 * non-boundary. 314 */ 315 if (!TEST_PRIM_END(flags)) 316 EDGEFLAG_SET( ELT(count-1), GL_FALSE ); 317 318 /* Draw the first triangles (possibly zero) 319 */ 320 if (j+1<count) { 321 GLboolean ef = EDGEFLAG_GET( ELT(j) ); 322 EDGEFLAG_SET( ELT(j), GL_FALSE ); 323 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 324 EDGEFLAG_SET( ELT(j), ef ); 325 j++; 326 327 /* Don't render the first edge again: 328 */ 329 EDGEFLAG_SET( ELT(start), GL_FALSE ); 330 331 for (;j+1<count;j++) { 332 GLboolean efj = EDGEFLAG_GET( ELT(j) ); 333 EDGEFLAG_SET( ELT(j), GL_FALSE ); 334 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 335 EDGEFLAG_SET( ELT(j), efj ); 336 } 337 } 338 339 /* Draw the last or only triangle 340 */ 341 if (j < count) 342 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 343 344 /* Restore the first and last edgeflags: 345 */ 346 EDGEFLAG_SET( ELT(count-1), efcount ); 347 EDGEFLAG_SET( ELT(start), efstart ); 348 349 } 350 else { 351 for (j=start+2;j<count;j++) { 352 RENDER_TRI( ELT(j-1), ELT(j), ELT(start) ); 353 } 354 } 355 POSTFIX; 356} 357 358static void TAG(render_quads)( struct gl_context *ctx, 359 GLuint start, 360 GLuint count, 361 GLuint flags ) 362{ 363 GLuint j; 364 LOCAL_VARS; 365 (void) flags; 366 367 INIT(GL_QUADS); 368 if (NEED_EDGEFLAG_SETUP) { 369 for (j=start+3; j<count; j+=4) { 370 /* Use user-specified edgeflags for quads. 371 */ 372 RESET_STIPPLE; 373 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 374 !ctx->Const.QuadsFollowProvokingVertexConvention) 375 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); 376 else 377 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); 378 } 379 } else { 380 for (j=start+3; j<count; j+=4) { 381 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 382 !ctx->Const.QuadsFollowProvokingVertexConvention) 383 RENDER_QUAD( ELT(j-3), ELT(j-2), ELT(j-1), ELT(j) ); 384 else 385 RENDER_QUAD( ELT(j-2), ELT(j-1), ELT(j), ELT(j-3) ); 386 } 387 } 388 POSTFIX; 389} 390 391static void TAG(render_quad_strip)( struct gl_context *ctx, 392 GLuint start, 393 GLuint count, 394 GLuint flags ) 395{ 396 GLuint j; 397 LOCAL_VARS; 398 (void) flags; 399 400 INIT(GL_QUAD_STRIP); 401 if (NEED_EDGEFLAG_SETUP) { 402 for (j=start+3;j<count;j+=2) { 403 /* All edges are boundary. Set edgeflags to 1, draw the 404 * quad, and restore them to the original values. 405 */ 406 GLboolean ef3 = EDGEFLAG_GET( ELT(j-3) ); 407 GLboolean ef2 = EDGEFLAG_GET( ELT(j-2) ); 408 GLboolean ef1 = EDGEFLAG_GET( ELT(j-1) ); 409 GLboolean ef = EDGEFLAG_GET( ELT(j) ); 410 if (TEST_PRIM_BEGIN(flags)) { 411 RESET_STIPPLE; 412 } 413 EDGEFLAG_SET( ELT(j-3), GL_TRUE ); 414 EDGEFLAG_SET( ELT(j-2), GL_TRUE ); 415 EDGEFLAG_SET( ELT(j-1), GL_TRUE ); 416 EDGEFLAG_SET( ELT(j), GL_TRUE ); 417 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 418 !ctx->Const.QuadsFollowProvokingVertexConvention) 419 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); 420 else 421 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); 422 EDGEFLAG_SET( ELT(j-3), ef3 ); 423 EDGEFLAG_SET( ELT(j-2), ef2 ); 424 EDGEFLAG_SET( ELT(j-1), ef1 ); 425 EDGEFLAG_SET( ELT(j), ef ); 426 } 427 } else { 428 for (j=start+3;j<count;j+=2) { 429 if (ctx->Light.ProvokingVertex == GL_LAST_VERTEX_CONVENTION_EXT || 430 !ctx->Const.QuadsFollowProvokingVertexConvention) 431 RENDER_QUAD( ELT(j-1), ELT(j-3), ELT(j-2), ELT(j) ); 432 else 433 RENDER_QUAD( ELT(j-2), ELT(j), ELT(j-1), ELT(j-3) ); 434 } 435 } 436 POSTFIX; 437} 438 439static void TAG(render_noop)( struct gl_context *ctx, 440 GLuint start, 441 GLuint count, 442 GLuint flags ) 443{ 444 (void)(ctx && start && count && flags); 445} 446 447RENDER_TAB_QUALIFIER void (*TAG(render_tab)[GL_POLYGON+2])(struct gl_context *, 448 GLuint, 449 GLuint, 450 GLuint) = 451{ 452 TAG(render_points), 453 TAG(render_lines), 454 TAG(render_line_loop), 455 TAG(render_line_strip), 456 TAG(render_triangles), 457 TAG(render_tri_strip), 458 TAG(render_tri_fan), 459 TAG(render_quads), 460 TAG(render_quad_strip), 461 TAG(render_poly), 462 TAG(render_noop), 463}; 464 465 466 467#ifndef PRESERVE_VB_DEFS 468#undef RENDER_TRI 469#undef RENDER_QUAD 470#undef RENDER_LINE 471#undef RENDER_POINTS 472#undef LOCAL_VARS 473#undef INIT 474#undef POSTFIX 475#undef RESET_STIPPLE 476#undef DBG 477#undef ELT 478#undef RENDER_TAB_QUALIFIER 479#endif 480 481#ifndef PRESERVE_TAG 482#undef TAG 483#endif 484 485#undef PRESERVE_VB_DEFS 486#undef PRESERVE_TAG 487