001 package net.minecraft.client.renderer; 002 003 import cpw.mods.fml.relauncher.Side; 004 import cpw.mods.fml.relauncher.SideOnly; 005 import java.nio.ByteBuffer; 006 import java.nio.ByteOrder; 007 import java.nio.FloatBuffer; 008 import java.nio.IntBuffer; 009 import java.nio.ShortBuffer; 010 import java.util.Arrays; 011 012 import org.lwjgl.opengl.ARBVertexBufferObject; 013 import org.lwjgl.opengl.GL11; 014 import org.lwjgl.opengl.GLContext; 015 016 @SideOnly(Side.CLIENT) 017 public class Tessellator 018 { 019 private static int nativeBufferSize = 0x200000; 020 private static int trivertsInBuffer = (nativeBufferSize / 48) * 6; 021 public static boolean renderingWorldRenderer = false; 022 public boolean defaultTexture = false; 023 private int rawBufferSize = 0; 024 public int textureID = 0; 025 /** 026 * Boolean used to check whether quads should be drawn as two triangles. Initialized to false and never changed. 027 */ 028 private static boolean convertQuadsToTriangles = false; 029 030 /** 031 * Boolean used to check if we should use vertex buffers. Initialized to false and never changed. 032 */ 033 private static boolean tryVBO = false; 034 035 /** The byte buffer used for GL allocation. */ 036 private static ByteBuffer byteBuffer = GLAllocation.createDirectByteBuffer(nativeBufferSize * 4); 037 038 /** The same memory as byteBuffer, but referenced as an integer buffer. */ 039 private static IntBuffer intBuffer = byteBuffer.asIntBuffer(); 040 041 /** The same memory as byteBuffer, but referenced as an float buffer. */ 042 private static FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); 043 044 /** Short buffer */ 045 private static ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); 046 047 /** Raw integer array. */ 048 private int[] rawBuffer; 049 050 /** 051 * The number of vertices to be drawn in the next draw call. Reset to 0 between draw calls. 052 */ 053 private int vertexCount = 0; 054 055 /** The first coordinate to be used for the texture. */ 056 private double textureU; 057 058 /** The second coordinate to be used for the texture. */ 059 private double textureV; 060 private int brightness; 061 062 /** The color (RGBA) value to be used for the following draw call. */ 063 private int color; 064 065 /** 066 * Whether the current draw object for this tessellator has color values. 067 */ 068 private boolean hasColor = false; 069 070 /** 071 * Whether the current draw object for this tessellator has texture coordinates. 072 */ 073 private boolean hasTexture = false; 074 private boolean hasBrightness = false; 075 076 /** 077 * Whether the current draw object for this tessellator has normal values. 078 */ 079 private boolean hasNormals = false; 080 081 /** The index into the raw buffer to be used for the next data. */ 082 private int rawBufferIndex = 0; 083 084 /** 085 * The number of vertices manually added to the given draw call. This differs from vertexCount because it adds extra 086 * vertices when converting quads to triangles. 087 */ 088 private int addedVertices = 0; 089 090 /** Disables all color information for the following draw call. */ 091 private boolean isColorDisabled = false; 092 093 /** The draw mode currently being used by the tessellator. */ 094 public int drawMode; 095 096 /** 097 * An offset to be applied along the x-axis for all vertices in this draw call. 098 */ 099 public double xOffset; 100 101 /** 102 * An offset to be applied along the y-axis for all vertices in this draw call. 103 */ 104 public double yOffset; 105 106 /** 107 * An offset to be applied along the z-axis for all vertices in this draw call. 108 */ 109 public double zOffset; 110 111 /** The normal to be applied to the face being drawn. */ 112 private int normal; 113 114 /** The static instance of the Tessellator. */ 115 public static Tessellator instance = new Tessellator(2097152); 116 117 /** Whether this tessellator is currently in draw mode. */ 118 public boolean isDrawing = false; 119 120 /** Whether we are currently using VBO or not. */ 121 private static boolean useVBO = false; 122 123 /** An IntBuffer used to store the indices of vertex buffer objects. */ 124 private static IntBuffer vertexBuffers; 125 126 /** 127 * The index of the last VBO used. This is used in round-robin fashion, sequentially, through the vboCount vertex 128 * buffers. 129 */ 130 private int vboIndex = 0; 131 132 /** Number of vertex buffer objects allocated for use. */ 133 private static int vboCount = 10; 134 135 /** The size of the buffers used (in integers). */ 136 private int bufferSize; 137 138 private Tessellator(int par1) 139 { 140 } 141 142 public Tessellator() 143 { 144 } 145 146 static 147 { 148 instance.defaultTexture = true; 149 useVBO = tryVBO && GLContext.getCapabilities().GL_ARB_vertex_buffer_object; 150 151 if (useVBO) 152 { 153 vertexBuffers = GLAllocation.createDirectIntBuffer(vboCount); 154 ARBVertexBufferObject.glGenBuffersARB(vertexBuffers); 155 } 156 } 157 158 /** 159 * Draws the data set up in this tessellator and resets the state to prepare for new drawing. 160 */ 161 public int draw() 162 { 163 if (!this.isDrawing) 164 { 165 throw new IllegalStateException("Not tesselating!"); 166 } 167 else 168 { 169 this.isDrawing = false; 170 171 int offs = 0; 172 while (offs < vertexCount) 173 { 174 int vtc = 0; 175 if (drawMode == 7 && convertQuadsToTriangles) 176 { 177 vtc = Math.min(vertexCount - offs, trivertsInBuffer); 178 } 179 else 180 { 181 vtc = Math.min(vertexCount - offs, nativeBufferSize >> 5); 182 } 183 this.intBuffer.clear(); 184 this.intBuffer.put(this.rawBuffer, offs * 8, vtc * 8); 185 this.byteBuffer.position(0); 186 this.byteBuffer.limit(vtc * 32); 187 offs += vtc; 188 189 if (this.useVBO) 190 { 191 this.vboIndex = (this.vboIndex + 1) % this.vboCount; 192 ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, this.vertexBuffers.get(this.vboIndex)); 193 ARBVertexBufferObject.glBufferDataARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, this.byteBuffer, ARBVertexBufferObject.GL_STREAM_DRAW_ARB); 194 } 195 196 if (this.hasTexture) 197 { 198 if (this.useVBO) 199 { 200 GL11.glTexCoordPointer(2, GL11.GL_FLOAT, 32, 12L); 201 } 202 else 203 { 204 this.floatBuffer.position(3); 205 GL11.glTexCoordPointer(2, 32, this.floatBuffer); 206 } 207 208 GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); 209 } 210 211 if (this.hasBrightness) 212 { 213 OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); 214 215 if (this.useVBO) 216 { 217 GL11.glTexCoordPointer(2, GL11.GL_SHORT, 32, 28L); 218 } 219 else 220 { 221 this.shortBuffer.position(14); 222 GL11.glTexCoordPointer(2, 32, this.shortBuffer); 223 } 224 225 GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY); 226 OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); 227 } 228 229 if (this.hasColor) 230 { 231 if (this.useVBO) 232 { 233 GL11.glColorPointer(4, GL11.GL_UNSIGNED_BYTE, 32, 20L); 234 } 235 else 236 { 237 this.byteBuffer.position(20); 238 GL11.glColorPointer(4, true, 32, this.byteBuffer); 239 } 240 241 GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); 242 } 243 244 if (this.hasNormals) 245 { 246 if (this.useVBO) 247 { 248 GL11.glNormalPointer(GL11.GL_UNSIGNED_BYTE, 32, 24L); 249 } 250 else 251 { 252 this.byteBuffer.position(24); 253 GL11.glNormalPointer(32, this.byteBuffer); 254 } 255 256 GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); 257 } 258 259 if (this.useVBO) 260 { 261 GL11.glVertexPointer(3, GL11.GL_FLOAT, 32, 0L); 262 } 263 else 264 { 265 this.floatBuffer.position(0); 266 GL11.glVertexPointer(3, 32, this.floatBuffer); 267 } 268 269 GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); 270 271 if (this.drawMode == 7 && convertQuadsToTriangles) 272 { 273 GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, vtc); 274 } 275 else 276 { 277 GL11.glDrawArrays(this.drawMode, 0, vtc); 278 } 279 280 GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); 281 282 if (this.hasTexture) 283 { 284 GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); 285 } 286 287 if (this.hasBrightness) 288 { 289 OpenGlHelper.setClientActiveTexture(OpenGlHelper.lightmapTexUnit); 290 GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY); 291 OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit); 292 } 293 294 if (this.hasColor) 295 { 296 GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); 297 } 298 299 if (this.hasNormals) 300 { 301 GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); 302 } 303 } 304 305 if (rawBufferSize > 0x20000 && rawBufferIndex < (rawBufferSize << 3)) 306 { 307 rawBufferSize = 0; 308 rawBuffer = null; 309 } 310 311 int var1 = this.rawBufferIndex * 4; 312 this.reset(); 313 return var1; 314 } 315 } 316 317 /** 318 * Clears the tessellator state in preparation for new drawing. 319 */ 320 private void reset() 321 { 322 this.vertexCount = 0; 323 this.byteBuffer.clear(); 324 this.rawBufferIndex = 0; 325 this.addedVertices = 0; 326 } 327 328 /** 329 * Sets draw mode in the tessellator to draw quads. 330 */ 331 public void startDrawingQuads() 332 { 333 this.startDrawing(7); 334 } 335 336 /** 337 * Resets tessellator state and prepares for drawing (with the specified draw mode). 338 */ 339 public void startDrawing(int par1) 340 { 341 if (this.isDrawing) 342 { 343 throw new IllegalStateException("Already tesselating!"); 344 } 345 else 346 { 347 this.isDrawing = true; 348 this.reset(); 349 this.drawMode = par1; 350 this.hasNormals = false; 351 this.hasColor = false; 352 this.hasTexture = false; 353 this.hasBrightness = false; 354 this.isColorDisabled = false; 355 } 356 } 357 358 /** 359 * Sets the texture coordinates. 360 */ 361 public void setTextureUV(double par1, double par3) 362 { 363 this.hasTexture = true; 364 this.textureU = par1; 365 this.textureV = par3; 366 } 367 368 public void setBrightness(int par1) 369 { 370 this.hasBrightness = true; 371 this.brightness = par1; 372 } 373 374 /** 375 * Sets the RGB values as specified, converting from floats between 0 and 1 to integers from 0-255. 376 */ 377 public void setColorOpaque_F(float par1, float par2, float par3) 378 { 379 this.setColorOpaque((int)(par1 * 255.0F), (int)(par2 * 255.0F), (int)(par3 * 255.0F)); 380 } 381 382 /** 383 * Sets the RGBA values for the color, converting from floats between 0 and 1 to integers from 0-255. 384 */ 385 public void setColorRGBA_F(float par1, float par2, float par3, float par4) 386 { 387 this.setColorRGBA((int)(par1 * 255.0F), (int)(par2 * 255.0F), (int)(par3 * 255.0F), (int)(par4 * 255.0F)); 388 } 389 390 /** 391 * Sets the RGB values as specified, and sets alpha to opaque. 392 */ 393 public void setColorOpaque(int par1, int par2, int par3) 394 { 395 this.setColorRGBA(par1, par2, par3, 255); 396 } 397 398 /** 399 * Sets the RGBA values for the color. Also clamps them to 0-255. 400 */ 401 public void setColorRGBA(int par1, int par2, int par3, int par4) 402 { 403 if (!this.isColorDisabled) 404 { 405 if (par1 > 255) 406 { 407 par1 = 255; 408 } 409 410 if (par2 > 255) 411 { 412 par2 = 255; 413 } 414 415 if (par3 > 255) 416 { 417 par3 = 255; 418 } 419 420 if (par4 > 255) 421 { 422 par4 = 255; 423 } 424 425 if (par1 < 0) 426 { 427 par1 = 0; 428 } 429 430 if (par2 < 0) 431 { 432 par2 = 0; 433 } 434 435 if (par3 < 0) 436 { 437 par3 = 0; 438 } 439 440 if (par4 < 0) 441 { 442 par4 = 0; 443 } 444 445 this.hasColor = true; 446 447 if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) 448 { 449 this.color = par4 << 24 | par3 << 16 | par2 << 8 | par1; 450 } 451 else 452 { 453 this.color = par1 << 24 | par2 << 16 | par3 << 8 | par4; 454 } 455 } 456 } 457 458 /** 459 * Adds a vertex specifying both x,y,z and the texture u,v for it. 460 */ 461 public void addVertexWithUV(double par1, double par3, double par5, double par7, double par9) 462 { 463 this.setTextureUV(par7, par9); 464 this.addVertex(par1, par3, par5); 465 } 466 467 /** 468 * Adds a vertex with the specified x,y,z to the current draw call. It will trigger a draw() if the buffer gets 469 * full. 470 */ 471 public void addVertex(double par1, double par3, double par5) 472 { 473 if (rawBufferIndex >= rawBufferSize - 32) 474 { 475 if (rawBufferSize == 0) 476 { 477 rawBufferSize = 0x10000; 478 rawBuffer = new int[rawBufferSize]; 479 } 480 else 481 { 482 rawBufferSize *= 2; 483 rawBuffer = Arrays.copyOf(rawBuffer, rawBufferSize); 484 } 485 } 486 ++this.addedVertices; 487 488 if (this.drawMode == 7 && convertQuadsToTriangles && this.addedVertices % 4 == 0) 489 { 490 for (int var7 = 0; var7 < 2; ++var7) 491 { 492 int var8 = 8 * (3 - var7); 493 494 if (this.hasTexture) 495 { 496 this.rawBuffer[this.rawBufferIndex + 3] = this.rawBuffer[this.rawBufferIndex - var8 + 3]; 497 this.rawBuffer[this.rawBufferIndex + 4] = this.rawBuffer[this.rawBufferIndex - var8 + 4]; 498 } 499 500 if (this.hasBrightness) 501 { 502 this.rawBuffer[this.rawBufferIndex + 7] = this.rawBuffer[this.rawBufferIndex - var8 + 7]; 503 } 504 505 if (this.hasColor) 506 { 507 this.rawBuffer[this.rawBufferIndex + 5] = this.rawBuffer[this.rawBufferIndex - var8 + 5]; 508 } 509 510 this.rawBuffer[this.rawBufferIndex + 0] = this.rawBuffer[this.rawBufferIndex - var8 + 0]; 511 this.rawBuffer[this.rawBufferIndex + 1] = this.rawBuffer[this.rawBufferIndex - var8 + 1]; 512 this.rawBuffer[this.rawBufferIndex + 2] = this.rawBuffer[this.rawBufferIndex - var8 + 2]; 513 ++this.vertexCount; 514 this.rawBufferIndex += 8; 515 } 516 } 517 518 if (this.hasTexture) 519 { 520 this.rawBuffer[this.rawBufferIndex + 3] = Float.floatToRawIntBits((float)this.textureU); 521 this.rawBuffer[this.rawBufferIndex + 4] = Float.floatToRawIntBits((float)this.textureV); 522 } 523 524 if (this.hasBrightness) 525 { 526 this.rawBuffer[this.rawBufferIndex + 7] = this.brightness; 527 } 528 529 if (this.hasColor) 530 { 531 this.rawBuffer[this.rawBufferIndex + 5] = this.color; 532 } 533 534 if (this.hasNormals) 535 { 536 this.rawBuffer[this.rawBufferIndex + 6] = this.normal; 537 } 538 539 this.rawBuffer[this.rawBufferIndex + 0] = Float.floatToRawIntBits((float)(par1 + this.xOffset)); 540 this.rawBuffer[this.rawBufferIndex + 1] = Float.floatToRawIntBits((float)(par3 + this.yOffset)); 541 this.rawBuffer[this.rawBufferIndex + 2] = Float.floatToRawIntBits((float)(par5 + this.zOffset)); 542 this.rawBufferIndex += 8; 543 ++this.vertexCount; 544 } 545 546 /** 547 * Sets the color to the given opaque value (stored as byte values packed in an integer). 548 */ 549 public void setColorOpaque_I(int par1) 550 { 551 int var2 = par1 >> 16 & 255; 552 int var3 = par1 >> 8 & 255; 553 int var4 = par1 & 255; 554 this.setColorOpaque(var2, var3, var4); 555 } 556 557 /** 558 * Sets the color to the given color (packed as bytes in integer) and alpha values. 559 */ 560 public void setColorRGBA_I(int par1, int par2) 561 { 562 int var3 = par1 >> 16 & 255; 563 int var4 = par1 >> 8 & 255; 564 int var5 = par1 & 255; 565 this.setColorRGBA(var3, var4, var5, par2); 566 } 567 568 /** 569 * Disables colors for the current draw call. 570 */ 571 public void disableColor() 572 { 573 this.isColorDisabled = true; 574 } 575 576 /** 577 * Sets the normal for the current draw call. 578 */ 579 public void setNormal(float par1, float par2, float par3) 580 { 581 this.hasNormals = true; 582 byte var4 = (byte)((int)(par1 * 127.0F)); 583 byte var5 = (byte)((int)(par2 * 127.0F)); 584 byte var6 = (byte)((int)(par3 * 127.0F)); 585 this.normal = var4 & 255 | (var5 & 255) << 8 | (var6 & 255) << 16; 586 } 587 588 /** 589 * Sets the translation for all vertices in the current draw call. 590 */ 591 public void setTranslation(double par1, double par3, double par5) 592 { 593 this.xOffset = par1; 594 this.yOffset = par3; 595 this.zOffset = par5; 596 } 597 598 /** 599 * Offsets the translation for all vertices in the current draw call. 600 */ 601 public void addTranslation(float par1, float par2, float par3) 602 { 603 this.xOffset += (double)par1; 604 this.yOffset += (double)par2; 605 this.zOffset += (double)par3; 606 } 607 }