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 }