1 /* 2 * Copyright (c) 2002-2008 LWJGL Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * * Neither the name of 'LWJGL' nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Portions Copyright (C) 2003-2006 Sun Microsystems, Inc. 35 * All rights reserved. 36 */ 37 38 /* 39 ** License Applicability. Except to the extent portions of this file are 40 ** made subject to an alternative license as permitted in the SGI Free 41 ** Software License B, Version 1.1 (the "License"), the contents of this 42 ** file are subject only to the provisions of the License. You may not use 43 ** this file except in compliance with the License. You may obtain a copy 44 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 45 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: 46 ** 47 ** http://oss.sgi.com/projects/FreeB 48 ** 49 ** Note that, as provided in the License, the Software is distributed on an 50 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS 51 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND 52 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A 53 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. 54 ** 55 ** NOTE: The Original Code (as defined below) has been licensed to Sun 56 ** Microsystems, Inc. ("Sun") under the SGI Free Software License B 57 ** (Version 1.1), shown above ("SGI License"). Pursuant to Section 58 ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to 59 ** you under an alternative license ("Alternative License"). This 60 ** Alternative License includes all of the provisions of the SGI License 61 ** except that Section 2.2 and 11 are omitted. Any differences between 62 ** the Alternative License and the SGI License are offered solely by Sun 63 ** and not by SGI. 64 ** 65 ** Original Code. The Original Code is: OpenGL Sample Implementation, 66 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, 67 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. 68 ** Copyright in any portions created by third parties is as indicated 69 ** elsewhere herein. All Rights Reserved. 70 ** 71 ** Additional Notice Provisions: The application programming interfaces 72 ** established by SGI in conjunction with the Original Code are The 73 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released 74 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version 75 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X 76 ** Window System(R) (Version 1.3), released October 19, 1998. This software 77 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation 78 ** published by SGI, but has not been independently verified as being 79 ** compliant with the OpenGL(R) version 1.2.1 Specification. 80 ** 81 ** Author: Eric Veach, July 1994 82 ** Java Port: Pepijn Van Eeckhoudt, July 2003 83 ** Java Port: Nathan Parker Burg, August 2003 84 */ 85 package org.lwjgl.util.glu.tessellation; 86 87 import static org.lwjgl.opengl.GL11.*; 88 import static org.lwjgl.util.glu.GLU.*; 89 90 class Render { 91 private static final boolean USE_OPTIMIZED_CODE_PATH = false; 92 Render()93 private Render() { 94 } 95 96 private static final RenderFan renderFan = new RenderFan(); 97 private static final RenderStrip renderStrip = new RenderStrip(); 98 private static final RenderTriangle renderTriangle = new RenderTriangle(); 99 100 /* This structure remembers the information we need about a primitive 101 * to be able to render it later, once we have determined which 102 * primitive is able to use the most triangles. 103 */ 104 private static class FaceCount { FaceCount()105 private FaceCount() { 106 } 107 FaceCount(long size, GLUhalfEdge eStart, renderCallBack render)108 private FaceCount(long size, GLUhalfEdge eStart, renderCallBack render) { 109 this.size = size; 110 this.eStart = eStart; 111 this.render = render; 112 } 113 114 long size; /* number of triangles used */ 115 GLUhalfEdge eStart; /* edge where this primitive starts */ 116 renderCallBack render; 117 }; 118 119 private interface renderCallBack { render(GLUtessellatorImpl tess, GLUhalfEdge e, long size)120 void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size); 121 } 122 123 /************************ Strips and Fans decomposition ******************/ 124 125 /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle 126 * fans, strips, and separate triangles. A substantial effort is made 127 * to use as few rendering primitives as possible (ie. to make the fans 128 * and strips as large as possible). 129 * 130 * The rendering output is provided as callbacks (see the api). 131 */ __gl_renderMesh(GLUtessellatorImpl tess, GLUmesh mesh)132 public static void __gl_renderMesh(GLUtessellatorImpl tess, GLUmesh mesh) { 133 GLUface f; 134 135 /* Make a list of separate triangles so we can render them all at once */ 136 tess.lonelyTriList = null; 137 138 for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) { 139 f.marked = false; 140 } 141 for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) { 142 143 /* We examine all faces in an arbitrary order. Whenever we find 144 * an unprocessed face F, we output a group of faces including F 145 * whose size is maximum. 146 */ 147 if (f.inside && !f.marked) { 148 RenderMaximumFaceGroup(tess, f); 149 assert (f.marked); 150 } 151 } 152 if (tess.lonelyTriList != null) { 153 RenderLonelyTriangles(tess, tess.lonelyTriList); 154 tess.lonelyTriList = null; 155 } 156 } 157 158 RenderMaximumFaceGroup(GLUtessellatorImpl tess, GLUface fOrig)159 static void RenderMaximumFaceGroup(GLUtessellatorImpl tess, GLUface fOrig) { 160 /* We want to find the largest triangle fan or strip of unmarked faces 161 * which includes the given face fOrig. There are 3 possible fans 162 * passing through fOrig (one centered at each vertex), and 3 possible 163 * strips (one for each CCW permutation of the vertices). Our strategy 164 * is to try all of these, and take the primitive which uses the most 165 * triangles (a greedy approach). 166 */ 167 GLUhalfEdge e = fOrig.anEdge; 168 FaceCount max = new FaceCount(); 169 FaceCount newFace; 170 171 max.size = 1; 172 max.eStart = e; 173 max.render = renderTriangle; 174 175 if (!tess.flagBoundary) { 176 newFace = MaximumFan(e); 177 if (newFace.size > max.size) { 178 max = newFace; 179 } 180 newFace = MaximumFan(e.Lnext); 181 if (newFace.size > max.size) { 182 max = newFace; 183 } 184 newFace = MaximumFan(e.Onext.Sym); 185 if (newFace.size > max.size) { 186 max = newFace; 187 } 188 189 newFace = MaximumStrip(e); 190 if (newFace.size > max.size) { 191 max = newFace; 192 } 193 newFace = MaximumStrip(e.Lnext); 194 if (newFace.size > max.size) { 195 max = newFace; 196 } 197 newFace = MaximumStrip(e.Onext.Sym); 198 if (newFace.size > max.size) { 199 max = newFace; 200 } 201 } 202 max.render.render(tess, max.eStart, max.size); 203 } 204 205 206 /* Macros which keep track of faces we have marked temporarily, and allow 207 * us to backtrack when necessary. With triangle fans, this is not 208 * really necessary, since the only awkward case is a loop of triangles 209 * around a single origin vertex. However with strips the situation is 210 * more complicated, and we need a general tracking method like the 211 * one here. 212 */ Marked(GLUface f)213 private static boolean Marked(GLUface f) { 214 return !f.inside || f.marked; 215 } 216 AddToTrail(GLUface f, GLUface t)217 private static GLUface AddToTrail(GLUface f, GLUface t) { 218 f.trail = t; 219 f.marked = true; 220 return f; 221 } 222 FreeTrail(GLUface t)223 private static void FreeTrail(GLUface t) { 224 if (true) { 225 while (t != null) { 226 t.marked = false; 227 t = t.trail; 228 } 229 } else { 230 /* absorb trailing semicolon */ 231 } 232 } 233 MaximumFan(GLUhalfEdge eOrig)234 static FaceCount MaximumFan(GLUhalfEdge eOrig) { 235 /* eOrig.Lface is the face we want to render. We want to find the size 236 * of a maximal fan around eOrig.Org. To do this we just walk around 237 * the origin vertex as far as possible in both directions. 238 */ 239 FaceCount newFace = new FaceCount(0, null, renderFan); 240 GLUface trail = null; 241 GLUhalfEdge e; 242 243 for (e = eOrig; !Marked(e.Lface); e = e.Onext) { 244 trail = AddToTrail(e.Lface, trail); 245 ++newFace.size; 246 } 247 for (e = eOrig; !Marked(e.Sym.Lface); e = e.Sym.Lnext) { 248 trail = AddToTrail(e.Sym.Lface, trail); 249 ++newFace.size; 250 } 251 newFace.eStart = e; 252 /*LINTED*/ 253 FreeTrail(trail); 254 return newFace; 255 } 256 257 IsEven(long n)258 private static boolean IsEven(long n) { 259 return (n & 0x1L) == 0; 260 } 261 MaximumStrip(GLUhalfEdge eOrig)262 static FaceCount MaximumStrip(GLUhalfEdge eOrig) { 263 /* Here we are looking for a maximal strip that contains the vertices 264 * eOrig.Org, eOrig.Dst, eOrig.Lnext.Dst (in that order or the 265 * reverse, such that all triangles are oriented CCW). 266 * 267 * Again we walk forward and backward as far as possible. However for 268 * strips there is a twist: to get CCW orientations, there must be 269 * an *even* number of triangles in the strip on one side of eOrig. 270 * We walk the strip starting on a side with an even number of triangles; 271 * if both side have an odd number, we are forced to shorten one side. 272 */ 273 FaceCount newFace = new FaceCount(0, null, renderStrip); 274 long headSize = 0, tailSize = 0; 275 GLUface trail = null; 276 GLUhalfEdge e, eTail, eHead; 277 278 for (e = eOrig; !Marked(e.Lface); ++tailSize, e = e.Onext) { 279 trail = AddToTrail(e.Lface, trail); 280 ++tailSize; 281 e = e.Lnext.Sym; 282 if (Marked(e.Lface)) break; 283 trail = AddToTrail(e.Lface, trail); 284 } 285 eTail = e; 286 287 for (e = eOrig; !Marked(e.Sym.Lface); ++headSize, e = e.Sym.Onext.Sym) { 288 trail = AddToTrail(e.Sym.Lface, trail); 289 ++headSize; 290 e = e.Sym.Lnext; 291 if (Marked(e.Sym.Lface)) break; 292 trail = AddToTrail(e.Sym.Lface, trail); 293 } 294 eHead = e; 295 296 newFace.size = tailSize + headSize; 297 if (IsEven(tailSize)) { 298 newFace.eStart = eTail.Sym; 299 } else if (IsEven(headSize)) { 300 newFace.eStart = eHead; 301 } else { 302 /* Both sides have odd length, we must shorten one of them. In fact, 303 * we must start from eHead to guarantee inclusion of eOrig.Lface. 304 */ 305 --newFace.size; 306 newFace.eStart = eHead.Onext; 307 } 308 /*LINTED*/ 309 FreeTrail(trail); 310 return newFace; 311 } 312 313 private static class RenderTriangle implements renderCallBack { render(GLUtessellatorImpl tess, GLUhalfEdge e, long size)314 public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) { 315 /* Just add the triangle to a triangle list, so we can render all 316 * the separate triangles at once. 317 */ 318 assert (size == 1); 319 tess.lonelyTriList = AddToTrail(e.Lface, tess.lonelyTriList); 320 } 321 } 322 323 RenderLonelyTriangles(GLUtessellatorImpl tess, GLUface f)324 static void RenderLonelyTriangles(GLUtessellatorImpl tess, GLUface f) { 325 /* Now we render all the separate triangles which could not be 326 * grouped into a triangle fan or strip. 327 */ 328 GLUhalfEdge e; 329 int newState; 330 int edgeState = -1; /* force edge state output for first vertex */ 331 332 tess.callBeginOrBeginData(GL_TRIANGLES); 333 334 for (; f != null; f = f.trail) { 335 /* Loop once for each edge (there will always be 3 edges) */ 336 337 e = f.anEdge; 338 do { 339 if (tess.flagBoundary) { 340 /* Set the "edge state" to true just before we output the 341 * first vertex of each edge on the polygon boundary. 342 */ 343 newState = (!e.Sym.Lface.inside) ? 1 : 0; 344 if (edgeState != newState) { 345 edgeState = newState; 346 tess.callEdgeFlagOrEdgeFlagData( edgeState != 0); 347 } 348 } 349 tess.callVertexOrVertexData( e.Org.data); 350 351 e = e.Lnext; 352 } while (e != f.anEdge); 353 } 354 tess.callEndOrEndData(); 355 } 356 357 private static class RenderFan implements renderCallBack { render(GLUtessellatorImpl tess, GLUhalfEdge e, long size)358 public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) { 359 /* Render as many CCW triangles as possible in a fan starting from 360 * edge "e". The fan *should* contain exactly "size" triangles 361 * (otherwise we've goofed up somewhere). 362 */ 363 tess.callBeginOrBeginData(GL_TRIANGLE_FAN); 364 tess.callVertexOrVertexData( e.Org.data); 365 tess.callVertexOrVertexData( e.Sym.Org.data); 366 367 while (!Marked(e.Lface)) { 368 e.Lface.marked = true; 369 --size; 370 e = e.Onext; 371 tess.callVertexOrVertexData( e.Sym.Org.data); 372 } 373 374 assert (size == 0); 375 tess.callEndOrEndData(); 376 } 377 } 378 379 private static class RenderStrip implements renderCallBack { render(GLUtessellatorImpl tess, GLUhalfEdge e, long size)380 public void render(GLUtessellatorImpl tess, GLUhalfEdge e, long size) { 381 /* Render as many CCW triangles as possible in a strip starting from 382 * edge "e". The strip *should* contain exactly "size" triangles 383 * (otherwise we've goofed up somewhere). 384 */ 385 tess.callBeginOrBeginData(GL_TRIANGLE_STRIP); 386 tess.callVertexOrVertexData( e.Org.data); 387 tess.callVertexOrVertexData( e.Sym.Org.data); 388 389 while (!Marked(e.Lface)) { 390 e.Lface.marked = true; 391 --size; 392 e = e.Lnext.Sym; 393 tess.callVertexOrVertexData( e.Org.data); 394 if (Marked(e.Lface)) break; 395 396 e.Lface.marked = true; 397 --size; 398 e = e.Onext; 399 tess.callVertexOrVertexData( e.Sym.Org.data); 400 } 401 402 assert (size == 0); 403 tess.callEndOrEndData(); 404 } 405 } 406 407 /************************ Boundary contour decomposition ******************/ 408 409 /* __gl_renderBoundary( tess, mesh ) takes a mesh, and outputs one 410 * contour for each face marked "inside". The rendering output is 411 * provided as callbacks (see the api). 412 */ __gl_renderBoundary(GLUtessellatorImpl tess, GLUmesh mesh)413 public static void __gl_renderBoundary(GLUtessellatorImpl tess, GLUmesh mesh) { 414 GLUface f; 415 GLUhalfEdge e; 416 417 for (f = mesh.fHead.next; f != mesh.fHead; f = f.next) { 418 if (f.inside) { 419 tess.callBeginOrBeginData(GL_LINE_LOOP); 420 e = f.anEdge; 421 do { 422 tess.callVertexOrVertexData( e.Org.data); 423 e = e.Lnext; 424 } while (e != f.anEdge); 425 tess.callEndOrEndData(); 426 } 427 } 428 } 429 430 431 /************************ Quick-and-dirty decomposition ******************/ 432 433 private static final int SIGN_INCONSISTENT = 2; 434 ComputeNormal(GLUtessellatorImpl tess, double[] norm, boolean check)435 static int ComputeNormal(GLUtessellatorImpl tess, double[] norm, boolean check) 436 /* 437 * If check==false, we compute the polygon normal and place it in norm[]. 438 * If check==true, we check that each triangle in the fan from v0 has a 439 * consistent orientation with respect to norm[]. If triangles are 440 * consistently oriented CCW, return 1; if CW, return -1; if all triangles 441 * are degenerate return 0; otherwise (no consistent orientation) return 442 * SIGN_INCONSISTENT. 443 */ { 444 CachedVertex[] v = tess.cache; 445 // CachedVertex vn = v0 + tess.cacheCount; 446 int vn = tess.cacheCount; 447 // CachedVertex vc; 448 int vc; 449 double dot, xc, yc, zc, xp, yp, zp; 450 double[] n = new double[3]; 451 int sign = 0; 452 453 /* Find the polygon normal. It is important to get a reasonable 454 * normal even when the polygon is self-intersecting (eg. a bowtie). 455 * Otherwise, the computed normal could be very tiny, but perpendicular 456 * to the true plane of the polygon due to numerical noise. Then all 457 * the triangles would appear to be degenerate and we would incorrectly 458 * decompose the polygon as a fan (or simply not render it at all). 459 * 460 * We use a sum-of-triangles normal algorithm rather than the more 461 * efficient sum-of-trapezoids method (used in CheckOrientation() 462 * in normal.c). This lets us explicitly reverse the signed area 463 * of some triangles to get a reasonable normal in the self-intersecting 464 * case. 465 */ 466 if (!check) { 467 norm[0] = norm[1] = norm[2] = 0.0; 468 } 469 470 vc = 1; 471 xc = v[vc].coords[0] - v[0].coords[0]; 472 yc = v[vc].coords[1] - v[0].coords[1]; 473 zc = v[vc].coords[2] - v[0].coords[2]; 474 while (++vc < vn) { 475 xp = xc; 476 yp = yc; 477 zp = zc; 478 xc = v[vc].coords[0] - v[0].coords[0]; 479 yc = v[vc].coords[1] - v[0].coords[1]; 480 zc = v[vc].coords[2] - v[0].coords[2]; 481 482 /* Compute (vp - v0) cross (vc - v0) */ 483 n[0] = yp * zc - zp * yc; 484 n[1] = zp * xc - xp * zc; 485 n[2] = xp * yc - yp * xc; 486 487 dot = n[0] * norm[0] + n[1] * norm[1] + n[2] * norm[2]; 488 if (!check) { 489 /* Reverse the contribution of back-facing triangles to get 490 * a reasonable normal for self-intersecting polygons (see above) 491 */ 492 if (dot >= 0) { 493 norm[0] += n[0]; 494 norm[1] += n[1]; 495 norm[2] += n[2]; 496 } else { 497 norm[0] -= n[0]; 498 norm[1] -= n[1]; 499 norm[2] -= n[2]; 500 } 501 } else if (dot != 0) { 502 /* Check the new orientation for consistency with previous triangles */ 503 if (dot > 0) { 504 if (sign < 0) return SIGN_INCONSISTENT; 505 sign = 1; 506 } else { 507 if (sign > 0) return SIGN_INCONSISTENT; 508 sign = -1; 509 } 510 } 511 } 512 return sign; 513 } 514 515 /* __gl_renderCache( tess ) takes a single contour and tries to render it 516 * as a triangle fan. This handles convex polygons, as well as some 517 * non-convex polygons if we get lucky. 518 * 519 * Returns true if the polygon was successfully rendered. The rendering 520 * output is provided as callbacks (see the api). 521 */ __gl_renderCache(GLUtessellatorImpl tess)522 public static boolean __gl_renderCache(GLUtessellatorImpl tess) { 523 CachedVertex[] v = tess.cache; 524 // CachedVertex vn = v0 + tess.cacheCount; 525 int vn = tess.cacheCount; 526 // CachedVertex vc; 527 int vc; 528 double[] norm = new double[3]; 529 int sign; 530 531 if (tess.cacheCount < 3) { 532 /* Degenerate contour -- no output */ 533 return true; 534 } 535 536 norm[0] = tess.normal[0]; 537 norm[1] = tess.normal[1]; 538 norm[2] = tess.normal[2]; 539 if (norm[0] == 0 && norm[1] == 0 && norm[2] == 0) { 540 ComputeNormal( tess, norm, false); 541 } 542 543 sign = ComputeNormal( tess, norm, true); 544 if (sign == SIGN_INCONSISTENT) { 545 /* Fan triangles did not have a consistent orientation */ 546 return false; 547 } 548 if (sign == 0) { 549 /* All triangles were degenerate */ 550 return true; 551 } 552 553 if ( !USE_OPTIMIZED_CODE_PATH ) { 554 return false; 555 } else { 556 /* Make sure we do the right thing for each winding rule */ 557 switch (tess.windingRule) { 558 case GLU_TESS_WINDING_ODD: 559 case GLU_TESS_WINDING_NONZERO: 560 break; 561 case GLU_TESS_WINDING_POSITIVE: 562 if (sign < 0) return true; 563 break; 564 case GLU_TESS_WINDING_NEGATIVE: 565 if (sign > 0) return true; 566 break; 567 case GLU_TESS_WINDING_ABS_GEQ_TWO: 568 return true; 569 } 570 571 tess.callBeginOrBeginData( tess.boundaryOnly ? GL_LINE_LOOP 572 : (tess.cacheCount > 3) ? GL_TRIANGLE_FAN 573 : GL_TRIANGLES); 574 575 tess.callVertexOrVertexData( v[0].data); 576 if (sign > 0) { 577 for (vc = 1; vc < vn; ++vc) { 578 tess.callVertexOrVertexData( v[vc].data); 579 } 580 } else { 581 for (vc = vn - 1; vc > 0; --vc) { 582 tess.callVertexOrVertexData( v[vc].data); 583 } 584 } 585 tess.callEndOrEndData(); 586 return true; 587 } 588 } 589 } 590