package mods.tinker.tconstruct.client.tmt; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import net.minecraft.client.model.ModelBase; import net.minecraft.client.model.ModelRenderer; import net.minecraft.client.model.PositionTextureVertex; import net.minecraft.client.model.TexturedQuad; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.client.renderer.RenderEngine; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.RenderManager; import net.minecraft.util.MathHelper; import org.lwjgl.opengl.GL11; /** * An extension to the ModelRenderer class. It basically is a copy to ModelRenderer, * however, it contains various new methods to make your models. *

* Since the ModelRendererTurbo class gets loaded during startup, the models made * can be very complex. This is why I can afford to add, for example, Wavefont OBJ * support or have the addSprite method, methods that add a lot of vertices and * polygons. * @author GaryCXJk * */ public class ModelRendererTurbo extends ModelRenderer { public ModelRendererTurbo(ModelBase modelbase, String s) { super(modelbase, s); flip = false; compiled = false; displayList = 0; mirror = false; showModel = true; field_1402_i = false; vertices = new PositionTextureVertex[0]; faces = new TexturedPolygon[0]; forcedRecompile = false; transformGroup = new HashMap(); transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); textureGroup = new HashMap(); textureGroup.put("0", new TextureGroup()); currentTextureGroup = textureGroup.get("0"); boxName = s; defaultTexture = ""; useLegacyCompiler = false; } public ModelRendererTurbo(ModelBase modelbase) { this(modelbase, null); } /** * Creates a new ModelRenderTurbo object. It requires the coordinates of the * position of the texture. * @param modelbase * @param textureX the x-coordinate on the texture * @param textureY the y-coordinate on the texture */ public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY) { this(modelbase, textureX, textureY, 64, 32); } /** * Creates a new ModelRenderTurbo object. It requires the coordinates of the * position of the texture, but also allows you to specify the width and height * of the texture, allowing you to use bigger textures instead. * @param modelbase * @param textureX * @param textureY * @param textureU * @param textureV */ public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV) { this(modelbase); textureOffsetX = textureX; textureOffsetY = textureY; textureWidth = textureU; textureHeight = textureV; } /** * Creates a new polygon. * @param verts an array of vertices */ public void addPolygon(PositionTextureVertex[] verts) { copyTo(verts, new TexturedPolygon[] {new TexturedPolygon(verts)}); } /** * Creates a new polygon, and adds UV mapping to it. * @param verts an array of vertices * @param uv an array of UV coordinates */ public void addPolygon(PositionTextureVertex[] verts, int[][] uv) { try { for(int i = 0; i < verts.length; i++) { verts[i] = verts[i].setTexturePosition((float)uv[i][0] / textureWidth, (float)uv[i][1] / textureHeight); } } finally { addPolygon(verts); } } /** * Creates a new polygon with a given UV. * @param verts an array of vertices * @param u1 * @param v1 * @param u2 * @param v2 */ public void addPolygon(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { copyTo(verts, new TexturedPolygon[] {addPolygonReturn(verts, u1, v1, u2, v2)}); } private TexturedPolygon addPolygonReturn(PositionTextureVertex[] verts, int u1, int v1, int u2, int v2) { if(verts.length < 3) return null; float uOffs = 1.0F / ((float) textureWidth * 10.0F); float vOffs = 1.0F / ((float) textureHeight * 10.0F); if(verts.length < 4) { float xMin = -1; float yMin = -1; float xMax = 0; float yMax = 0; for(int i = 0; i < verts.length; i++) { float xPos = verts[i].texturePositionX; float yPos = verts[i].texturePositionY; xMax = Math.max(xMax, xPos); xMin = (xMin < -1 ? xPos : Math.min(xMin, xPos)); yMax = Math.max(yMax, yPos); yMin = (yMin < -1 ? yPos : Math.min(yMin, yPos)); } float uMin = (float) u1 / (float) textureWidth + uOffs; float vMin = (float) v1 / (float) textureHeight + vOffs; float uSize = (float) (u2 - u1) / (float) textureWidth - uOffs * 2; float vSize = (float) (v2 - v1) / (float) textureHeight - vOffs * 2; float xSize = xMax - xMin; float ySize = yMax - yMin; for(int i = 0; i < verts.length; i++) { float xPos = verts[i].texturePositionX; float yPos = verts[i].texturePositionY; xPos = (xPos - xMin) / xSize; yPos = (yPos - yMin) / ySize; verts[i] = verts[i].setTexturePosition(uMin + (xPos * uSize), vMin + (yPos * vSize)); } } else { verts[0] = verts[0].setTexturePosition((float)u2 / (float) textureWidth - uOffs, (float)v1 / (float)textureHeight + vOffs); verts[1] = verts[1].setTexturePosition((float)u1 / (float) textureWidth + uOffs, (float)v1 / (float)textureHeight + vOffs); verts[2] = verts[2].setTexturePosition((float)u1 / (float) textureWidth + uOffs, (float)v2 / (float)textureHeight - vOffs); verts[3] = verts[3].setTexturePosition((float)u2 / (float) textureWidth - uOffs, (float)v2 / (float)textureHeight - vOffs); } return new TexturedPolygon(verts); } /** * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, * as the method requires eight vector coordinates. * @param v a float array with three values, the x, y and z coordinates of the vertex * @param v1 a float array with three values, the x, y and z coordinates of the vertex * @param v2 a float array with three values, the x, y and z coordinates of the vertex * @param v3 a float array with three values, the x, y and z coordinates of the vertex * @param v4 a float array with three values, the x, y and z coordinates of the vertex * @param v5 a float array with three values, the x, y and z coordinates of the vertex * @param v6 a float array with three values, the x, y and z coordinates of the vertex * @param v7 a float array with three values, the x, y and z coordinates of the vertex * @param w the width of the shape, used in determining the texture * @param h the height of the shape, used in determining the texture * @param d the depth of the shape, used in determining the texture */ public void addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, int w, int h, int d) { PositionTextureVertex[] verts = new PositionTextureVertex[8]; TexturedPolygon[] poly = new TexturedPolygon[6]; PositionTextureVertex positionTexturevertex = new PositionTextureVertex(v[0], v[1], v[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(v1[0], v1[1], v1[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(v2[0], v2[1], v2[2], 8F, 8F); PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(v3[0], v3[1], v3[2], 8F, 0.0F); PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(v4[0], v4[1], v4[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(v5[0], v5[1], v5[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(v6[0], v6[1], v6[2], 8F, 8F); PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(v7[0], v7[1], v7[2], 8F, 0.0F); verts[0] = positionTexturevertex; verts[1] = positionTexturevertex1; verts[2] = positionTexturevertex2; verts[3] = positionTexturevertex3; verts[4] = positionTexturevertex4; verts[5] = positionTexturevertex5; verts[6] = positionTexturevertex6; verts[7] = positionTexturevertex7; poly[0] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 }, textureOffsetX + d + w, textureOffsetY + d, textureOffsetX + d + w + d, textureOffsetY + d + h); poly[1] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 }, textureOffsetX + 0, textureOffsetY + d, textureOffsetX + d, textureOffsetY + d + h); poly[2] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 }, textureOffsetX + d, textureOffsetY + 0, textureOffsetX + d + w, textureOffsetY + d); poly[3] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 }, textureOffsetX + d + w, textureOffsetY + 0, textureOffsetX + d + w + w, textureOffsetY + d); poly[4] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 }, textureOffsetX + d, textureOffsetY + d, textureOffsetX + d + w, textureOffsetY + d + h); poly[5] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 }, textureOffsetX + d + w + d, textureOffsetY + d, textureOffsetX + d + w + d + w, textureOffsetY + d + h); if(mirror ^ flip) { for(int l = 0; l < poly.length; l++) { poly[l].flipFace(); } } copyTo(verts, poly); } /** * Adds a new box to the model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) */ public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d) { addBox(x, y, z, w, h, d, 0.0F); return this; } /** * Adds a new box to the model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param expansion the expansion of the box. It increases the size in each direction by that many. */ public void addBox(float x, float y, float z, int w, int h, int d, float expansion) { addBox(x, y, z, w, h, d, expansion, 1F); } /** * Adds a new box to the model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param expansion the expansion of the box. It increases the size in each direction by that many. It's independent from the scale. * @param scale */ public void addBox(float x, float y, float z, int w, int h, int d, float expansion, float scale) { float scaleX = (float)w * scale; float scaleY = (float)h * scale; float scaleZ = (float)d * scale; float x1 = x + scaleX; float y1 = y + scaleY; float z1 = z + scaleZ; float expX = expansion + scaleX - (float)w; float expY = expansion + scaleY - (float)h; float expZ = expansion + scaleZ - (float)d; x -= expX; y -= expY; z -= expZ; x1 += expansion; y1 += expansion; z1 += expansion; if(mirror) { float xTemp = x1; x1 = x; x = xTemp; } float[] v = {x, y, z}; float[] v1 = {x1, y, z}; float[] v2 = {x1, y1, z}; float[] v3 = {x, y1, z}; float[] v4 = {x, y, z1}; float[] v5 = {x1, y, z1}; float[] v6 = {x1, y1, z1}; float[] v7 = {x, y1, z1}; addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param bottomScale the "scale" of the bottom * @param dir the side the scaling is applied to */ public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir) { float width = x + (float)w; float height = y + (float)h; float depth = z + (float)d; x -= scale; y -= scale; z -= scale; width += scale; height += scale; depth += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = width; width = x; x = f7; } float[] v = {x, y, z}; float[] v1 = {width, y, z}; float[] v2 = {width, height, z}; float[] v3 = {x, height, z}; float[] v4 = {x, y, depth}; float[] v5 = {width, y, depth}; float[] v6 = {width, height, depth}; float[] v7 = {x, height, depth}; switch(dir) { case MR_RIGHT: v[1] -= bottomScale; v[2] -= bottomScale; v3[1] += bottomScale; v3[2] -= bottomScale; v4[1] -= bottomScale; v4[2] += bottomScale; v7[1] += bottomScale; v7[2] += bottomScale; break; case MR_LEFT: v1[1] -= bottomScale; v1[2] -= bottomScale; v2[1] += bottomScale; v2[2] -= bottomScale; v5[1] -= bottomScale; v5[2] += bottomScale; v6[1] += bottomScale; v6[2] += bottomScale; break; case MR_FRONT: v[0] -= m * bottomScale; v[1] -= bottomScale; v1[0] += m * bottomScale; v1[1] -= bottomScale; v2[0] += m * bottomScale; v2[1] += bottomScale; v3[0] -= m * bottomScale; v3[1] += bottomScale; break; case MR_BACK: v4[0] -= m * bottomScale; v4[1] -= bottomScale; v5[0] += m * bottomScale; v5[1] -= bottomScale; v6[0] += m * bottomScale; v6[1] += bottomScale; v7[0] -= m * bottomScale; v7[1] += bottomScale; break; case MR_TOP: v[0] -= m * bottomScale; v[2] -= bottomScale; v1[0] += m * bottomScale; v1[2] -= bottomScale; v4[0] -= m * bottomScale; v4[2] += bottomScale; v5[0] += m * bottomScale; v5[2] += bottomScale; break; case MR_BOTTOM: v2[0] += m * bottomScale; v2[2] -= bottomScale; v3[0] -= m * bottomScale; v3[2] -= bottomScale; v6[0] += m * bottomScale; v6[2] += bottomScale; v7[0] -= m * bottomScale; v7[2] += bottomScale; break; } addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); } /** * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. * You can use the static variables MR_RIGHT, MR_LEFT, * MR_FRONT, MR_BACK, MR_TOP and * MR_BOTTOM. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width (over the x-direction) * @param h the height (over the y-direction) * @param d the depth (over the z-direction) * @param scale the "scale" of the box. It only increases the size in each direction by that many. * @param bottomScale the "scale" of the bottom * @param dir the side the scaling is applied to */ /*public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir) { float width = x + (float)w; float height = y + (float)h; float depth = z + (float)d; x -= scale; y -= scale; z -= scale; width += scale; height += scale; depth += scale; int m = (mirror ? -1 : 1); if(mirror) { float f7 = width; width = x; x = f7; } float[] v = {x, y, z}; float[] v1 = {width, y, z}; float[] v2 = {width, height, z}; float[] v3 = {x, height, z}; float[] v4 = {x, y, depth}; float[] v5 = {width, y, depth}; float[] v6 = {width, height, depth}; float[] v7 = {x, height, depth}; switch(dir) { case MR_RIGHT: v[1] -= bottomScale; v[2] -= bottomScale; v3[1] += bottomScale; v3[2] -= bottomScale; v4[1] -= bottomScale; v4[2] += bottomScale; v7[1] += bottomScale; v7[2] += bottomScale; break; case MR_LEFT: v1[1] -= bottomScale; v1[2] -= bottomScale; v2[1] += bottomScale; v2[2] -= bottomScale; v5[1] -= bottomScale; v5[2] += bottomScale; v6[1] += bottomScale; v6[2] += bottomScale; break; case MR_FRONT: v[0] -= m * bottomScale; v[1] -= bottomScale; v1[0] += m * bottomScale; v1[1] -= bottomScale; v2[0] += m * bottomScale; v2[1] += bottomScale; v3[0] -= m * bottomScale; v3[1] += bottomScale; break; case MR_BACK: v4[0] -= m * bottomScale; v4[1] -= bottomScale; v5[0] += m * bottomScale; v5[1] -= bottomScale; v6[0] += m * bottomScale; v6[1] += bottomScale; v7[0] -= m * bottomScale; v7[1] += bottomScale; break; case MR_TOP: v[0] -= m * bottomScale; v[2] -= bottomScale; v1[0] += m * bottomScale; v1[2] -= bottomScale; v4[0] -= m * bottomScale; v4[2] += bottomScale; v5[0] += m * bottomScale; v5[2] += bottomScale; break; case MR_BOTTOM: v2[0] += m * bottomScale; v2[2] -= bottomScale; v3[0] -= m * bottomScale; v3[2] -= bottomScale; v6[0] += m * bottomScale; v6[2] += bottomScale; v7[0] -= m * bottomScale; v7[2] += bottomScale; break; } addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d); }*/ /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an array of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an array of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an ArrayList of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param coordinates an ArrayList of coordinates that form the shape * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction) { addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param direction the direction the starting point of the shape is facing * @param faceLengths An array with the length of each face. Used to set * the texture width of each face on the side manually. */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths) { float rotX = 0; float rotY = 0; float rotZ = 0; switch(direction) { case MR_LEFT: rotY = pi / 2; break; case MR_RIGHT: rotY = -pi / 2; break; case MR_TOP: rotX = pi / 2; break; case MR_BOTTOM: rotX = -pi / 2; break; case MR_FRONT: rotY = pi; break; case MR_BACK: break; } addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, faceLengths); } /** * Creates a shape from a 2D vector shape. * @param x the starting x position * @param y the starting y position * @param z the starting z position * @param shape a Shape2D which contains the coordinates of the shape points * @param depth the depth of the shape * @param shapeTextureWidth the width of the texture of one side of the shape * @param shapeTextureHeight the height of the texture the shape * @param sideTextureWidth the width of the texture of the side of the shape * @param sideTextureHeight the height of the texture of the side of the shape * @param rotX the rotation around the x-axis * @param rotY the rotation around the y-axis * @param rotZ the rotation around the z-axis */ public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ) { addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, null); } public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ, float[] faceLengths) { Shape3D shape3D = shape.extrude(x, y, z, rotX, rotY, rotZ, depth, textureOffsetX, textureOffsetY, textureWidth, textureHeight, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, faceLengths); if(flip) { for(int idx = 0; idx < shape3D.faces.length; idx++) { shape3D.faces[idx].flipFace(); } } copyTo(shape3D.vertices, shape3D.faces); } /** * Adds a cube the size of one pixel. It will take a pixel from the texture and * uses that as the texture of said cube. The accurate name would actually be * "addVoxel". This method has been added to make it more compatible with Techne, * and allows for easy single-colored boxes. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param width the width of the box * @param height the height of the box * @param length the length of the box */ public void addPixel(float x, float y, float z, float width, float height, float length) { addPixel(x, y, z, new float[] {width, height, length}, textureOffsetX, textureOffsetY); } /** * Adds a cube the size of one pixel. It will take a pixel from the texture and * uses that as the texture of said cube. The accurate name would actually be * "addVoxel". It will not overwrite the model data, but rather, it will add to * the model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param scale the "scale" of the cube, where scale is a float integer consisting of three values * @param w the x-coordinate on the texture * @param h the y-coordinate on the texture */ public void addPixel(float x, float y, float z, float[] scale, int w, int h) { PositionTextureVertex[] verts = new PositionTextureVertex[8]; TexturedPolygon[] poly = new TexturedPolygon[6]; float x1 = x + scale[0]; float y1 = y + scale[1]; float z1 = z + scale[2]; float[] f = {x, y, z}; float[] f1 = {x1, y, z}; float[] f2 = {x1, y1, z}; float[] f3 = {x, y1, z}; float[] f4 = {x, y, z1}; float[] f5 = {x1, y, z1}; float[] f6 = {x1, y1, z1}; float[] f7 = {x, y1, z1}; PositionTextureVertex positionTexturevertex = new PositionTextureVertex(f[0], f[1], f[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex1 = new PositionTextureVertex(f1[0], f1[1], f1[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex2 = new PositionTextureVertex(f2[0], f2[1], f2[2], 8F, 8F); PositionTextureVertex positionTexturevertex3 = new PositionTextureVertex(f3[0], f3[1], f3[2], 8F, 0.0F); PositionTextureVertex positionTexturevertex4 = new PositionTextureVertex(f4[0], f4[1], f4[2], 0.0F, 0.0F); PositionTextureVertex positionTexturevertex5 = new PositionTextureVertex(f5[0], f5[1], f5[2], 0.0F, 8F); PositionTextureVertex positionTexturevertex6 = new PositionTextureVertex(f6[0], f6[1], f6[2], 8F, 8F); PositionTextureVertex positionTexturevertex7 = new PositionTextureVertex(f7[0], f7[1], f7[2], 8F, 0.0F); verts[0] = positionTexturevertex; verts[1] = positionTexturevertex1; verts[2] = positionTexturevertex2; verts[3] = positionTexturevertex3; verts[4] = positionTexturevertex4; verts[5] = positionTexturevertex5; verts[6] = positionTexturevertex6; verts[7] = positionTexturevertex7; poly[0] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex5, positionTexturevertex1, positionTexturevertex2, positionTexturevertex6 }, w, h, w + 1, h + 1); poly[1] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex, positionTexturevertex4, positionTexturevertex7, positionTexturevertex3 }, w, h, w + 1, h + 1); poly[2] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex5, positionTexturevertex4, positionTexturevertex, positionTexturevertex1 }, w, h, w + 1, h + 1); poly[3] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex2, positionTexturevertex3, positionTexturevertex7, positionTexturevertex6 }, w, h, w + 1, h + 1); poly[4] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex1, positionTexturevertex, positionTexturevertex3, positionTexturevertex2 }, w, h, w + 1, h + 1); poly[5] = addPolygonReturn(new PositionTextureVertex[] { positionTexturevertex4, positionTexturevertex5, positionTexturevertex6, positionTexturevertex7 }, w, h, w + 1, h + 1); copyTo(verts, poly); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, float expansion) { addSprite(x, y, z, w, h, 1, false, false, false, false, false, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { addSprite(x, y, z, w, h, 1, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param d the depth of the shape itself * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, int d, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { addSprite(x, y, z, w, h, d, 1.0F, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param w the width of the sprite * @param h the height of the sprite * @param d the depth of the shape itself * @param pixelScale the scale of each individual pixel * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, int w, int h, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { String[] mask = new String[h]; char[] str = new char[w]; Arrays.fill(str, '1'); Arrays.fill(mask, new String(str)); addSprite(x, y, z, mask, d, pixelScale, rotX, rotY, rotZ, mirrorX, mirrorY, expansion); } /** * Creates a model shaped like the exact image on the texture. Note that this method will * increase the amount of quads on your model, which could effectively slow down your * PC, so unless it is really a necessity to use it, I'd suggest you avoid using this * method to create your model. *

* This method uses a mask string. This way you can reduce the amount of quads used. To * use this, create a String array, where you use a 1 to signify that the pixel will be * drawn. Any other character will cause that pixel to not be drawn. * @param x the starting x-position * @param y the starting y-position * @param z the starting z-position * @param mask an array with the mask string * @param d the depth of the shape itself * @param pixelScale the scale of each individual pixel * @param rotX a boolean to define if it rotates 90 degrees around its yaw-axis * @param rotY a boolean to define if it rotates 90 degrees around its pitch-axis * @param rotZ a boolean to define if it rotates 90 degrees around its roll-axis * @param mirrorX a boolean to define if the sprite should be mirrored * @param mirrorY a boolean to define if the sprite should be flipped * @param expansion the expansion of the sprite. It only increases the size in each direction by that many. */ public void addSprite(float x, float y, float z, String[] mask, int d, float pixelScale, boolean rotX, boolean rotY, boolean rotZ, boolean mirrorX, boolean mirrorY, float expansion) { int w = mask[0].length(); int h = mask.length; float x1 = x - expansion; float y1 = y - expansion; float z1 = z - expansion; int wDir = 0; int hDir = 0; int dDir = 0; float wScale = 1F + (expansion / ((float) w * pixelScale)); float hScale = 1F + (expansion / ((float) h * pixelScale)); if(!rotX) { if(!rotY) { if(!rotZ) { wDir = 0; hDir = 1; dDir = 2; } else { wDir = 1; hDir = 0; dDir = 2; } } else { if(!rotZ) { wDir = 2; hDir = 1; dDir = 0; } else { wDir = 2; hDir = 0; dDir = 1; } } } else { if(!rotY) { if(!rotZ) { wDir = 0; hDir = 2; dDir = 1; } else { wDir = 1; hDir = 2; dDir = 0; } } else { if(!rotZ) { wDir = 2; hDir = 0; dDir = 1; } else { wDir = 2; hDir = 1; dDir = 0; } } } int texStartX = textureOffsetX + (mirrorX ? w * 1 - 1 : 0); int texStartY = textureOffsetY + (mirrorY ? h * 1 - 1 : 0); int texDirX = (mirrorX ? -1 : 1); int texDirY = (mirrorY ? -1 : 1); float wVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, wDir, 1, 1); float hVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, hDir, 1, 1); float dVoxSize = getPixelSize(wScale, hScale, d * pixelScale + expansion * 2, 0, 1, dDir, 1, 1); for(int i = 0; i < w; i++) { for(int j = 0; j < h; j++) { if(mask[j].charAt(i) == '1') { addPixel(x1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 0, i, j), y1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 1, i, j), z1 + getPixelSize(wScale, hScale, 0, wDir, hDir, 2, i, j), new float[] {wVoxSize, hVoxSize, dVoxSize}, texStartX + texDirX * i, texStartY + texDirY * j); } } } } private float getPixelSize(float wScale, float hScale, float dScale, int wDir, int hDir, int checkDir, int texPosX, int texPosY) { return (wDir == checkDir ? wScale * texPosX : (hDir == checkDir ? hScale * texPosY : dScale)); } /** * Adds a spherical shape. * @param x * @param y * @param z * @param r * @param segs * @param rings * @param textureW * @param textureH */ public void addSphere(float x, float y, float z, float r, int segs, int rings, int textureW, int textureH) { if(segs < 3) segs = 3; rings++; PositionTextureVertex[] tempVerts = new PositionTextureVertex[segs * (rings - 1) + 2]; TexturedPolygon[] poly = new TexturedPolygon[segs * rings]; tempVerts[0] = new PositionTextureVertex(x, y - r, z, 0, 0); tempVerts[tempVerts.length - 1] = new PositionTextureVertex(x, y + r, z, 0, 0); float uOffs = 1.0F / ((float) textureWidth * 10.0F); float vOffs = 1.0F / ((float) textureHeight * 10.0F); float texW = (float) textureW / (float)textureWidth - 2F * uOffs; float texH = (float) textureH / (float)textureHeight - 2F * vOffs; float segW = texW / (float) segs; float segH = texH / (float) rings; float startU = (float) textureOffsetX / (float) textureWidth; float startV = (float) textureOffsetY / (float) textureHeight; int currentFace = 0; for(int j = 1; j < rings; j++) { for(int i = 0; i < segs; i++) { float yWidth = MathHelper.cos(-pi / 2 + (pi / (float)rings) * (float) j); float yHeight = MathHelper.sin(-pi / 2 + (pi / (float)rings) * (float) j); float xSize = MathHelper.sin((pi / (float)segs) * i * 2F + pi) * yWidth; float zSize = -MathHelper.cos((pi / (float)segs) * i * 2F + pi) * yWidth; int curVert = 1 + i + segs * (j - 1); tempVerts[curVert] = new PositionTextureVertex(x + xSize * r, y + yHeight * r, z + zSize * r, 0, 0); if(i > 0) { PositionTextureVertex[] verts; if(j == 1) { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); verts[2] = tempVerts[0].setTexturePosition(startU + segW * (i - 1), startV); verts[3] = tempVerts[0].setTexturePosition(startU + segW + segW * i, startV); } else { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j); verts[1] = tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j); verts[2] = tempVerts[curVert - 1 - segs].setTexturePosition(startU + segW * (i - 1), startV + segH * (j - 1)); verts[3] = tempVerts[curVert - segs].setTexturePosition(startU + segW * i, startV + segH * (j - 1)); } poly[currentFace] = new TexturedPolygon(verts); currentFace++; } } PositionTextureVertex[] verts; if(j == 1) { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[1].setTexturePosition(startU + segW * segs, startV + segH * j); verts[1] = tempVerts[segs].setTexturePosition(startU + segW * (segs - 1), startV + segH * j); verts[2] = tempVerts[0].setTexturePosition(startU + segW * (segs - 1), startV); verts[3] = tempVerts[0].setTexturePosition(startU + segW * segs, startV); } else { verts = new PositionTextureVertex[4]; verts[0] = tempVerts[1 + segs * (j - 1)].setTexturePosition(startU + texW, startV + segH * j); verts[1] = tempVerts[segs * (j - 1) + segs].setTexturePosition(startU + texW - segW, startV + segH * j); verts[2] = tempVerts[segs * (j - 1)].setTexturePosition(startU + texW - segW, startV + segH * (j - 1)); verts[3] = tempVerts[1 + segs * (j - 1) - segs].setTexturePosition(startU + texW, startV + segH * (j - 1)); } poly[currentFace] = new TexturedPolygon(verts); currentFace++; } for(int i = 0; i < segs; i++) { PositionTextureVertex[] verts = new PositionTextureVertex[3]; int curVert = tempVerts.length - (segs + 1); verts[0] = tempVerts[tempVerts.length - 1].setTexturePosition(startU + segW * (i + 0.5F), startV + texH); verts[1] = tempVerts[curVert + i].setTexturePosition(startU + segW * i, startV + texH - segH); verts[2] = tempVerts[curVert + ((i + 1) % segs)].setTexturePosition(startU + segW * (i + 1), startV + texH - segH); poly[currentFace] = new TexturedPolygon(verts); currentFace++; } copyTo(tempVerts, poly); } /** * Adds a cone. * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of */ public void addCone(float x, float y, float z, float radius, float length, int segments) { addCone(x, y, z, radius, length, segments, 1F); } /** * Adds a cone. * * baseScale cannot be zero. If it is, it will automatically be set to 1F. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale) { addCone(x, y, z, radius, length, segments, baseScale, MR_TOP); } /** * Adds a cone. * * baseScale cannot be zero. If it is, it will automatically be set to 1F. * * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param baseDirection the direction it faces */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection) { addCone(x, y, z, radius, length, segments, baseScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F)); } /** * Adds a cone. * * baseScale cannot be zero. If it is, it will automatically be set to 1F. * * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * The textures for the sides are placed next to each other. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param baseDirection the direction it faces * @param textureCircleDiameterW the diameter width of the circle on the texture * @param textureCircleDiameterH the diameter height of the circle on the texture */ public void addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH) { addCylinder(x, y, z, radius, length, segments, baseScale, 0.0F, baseDirection, textureCircleDiameterW, textureCircleDiameterH, 1); } /** * Adds a cylinder. * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of */ public void addCylinder(float x, float y, float z, float radius, float length, int segments) { addCylinder(x, y, z, radius, length, segments, 1F, 1F); } /** * Adds a cylinder. * * You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale) { addCylinder(x, y, z, radius, length, segments, baseScale, topScale, MR_TOP); } /** * Adds a cylinder. * * You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. * * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. * @param baseDirection the direction it faces */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection) { addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length)); } /** * Adds a cylinder. * * You can make cones by either setting baseScale or topScale to zero. Setting both * to zero will set the baseScale to 1F. * * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in * the top being placed at the (x,y,z). * * The textures for the base and top are placed next to each other, while the body * will be placed below the circles. * * @param x the x-position of the base * @param y the y-position of the base * @param z the z-position of the base * @param radius the radius of the cylinder * @param length the length of the cylinder * @param segments the amount of segments the cylinder is made of * @param baseScale the scaling of the base. Can be negative. * @param topScale the scaling of the top. Can be negative. * @param baseDirection the direction it faces * @param textureCircleDiameterW the diameter width of the circle on the texture * @param textureCircleDiameterH the diameter height of the circle on the texture * @param textureH the height of the texture of the body */ public void addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH) { boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); boolean coneBase = (baseScale == 0); boolean coneTop = (topScale == 0); if(coneBase && coneTop) { baseScale = 1F; coneBase = false; } PositionTextureVertex[] tempVerts = new PositionTextureVertex[segments * (coneBase || coneTop ? 1 : 2) + 2]; TexturedPolygon[] poly = new TexturedPolygon[segments * (coneBase || coneTop ? 2 : 3)]; float xLength = (dirSide ? length : 0); float yLength = (dirTop ? length : 0); float zLength = (dirFront ? length : 0); float xStart = (dirMirror ? x + xLength : x); float yStart = (dirMirror ? y + yLength : y); float zStart = (dirMirror ? z + zLength : z); float xEnd = (!dirMirror ? x + xLength : x); float yEnd = (!dirMirror ? y + yLength : y); float zEnd = (!dirMirror ? z + zLength : z); tempVerts[0] = new PositionTextureVertex(xStart, yStart, zStart, 0, 0); tempVerts[tempVerts.length - 1] = new PositionTextureVertex(xEnd, yEnd, zEnd, 0, 0); float xCur = xStart; float yCur = yStart; float zCur = zStart; float sCur = (coneBase ? topScale : baseScale); for(int repeat = 0; repeat < (coneBase || coneTop ? 1 : 2); repeat++) { for(int index = 0; index < segments; index++) { float xSize = (mirror ^ dirMirror ? -1 : 1) * MathHelper.sin((pi / (float)segments) * index * 2F + pi) * radius * sCur; float zSize = -MathHelper.cos((pi / (float)segments) * index * 2F + pi) * radius * sCur; float xPlace = xCur + (!dirSide ? xSize : 0); float yPlace = yCur + (!dirTop ? zSize : 0); float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); tempVerts[1 + index + repeat * segments] = new PositionTextureVertex(xPlace, yPlace, zPlace, 0, 0 ); } xCur = xEnd; yCur = yEnd; zCur = zEnd; sCur = topScale; } float uScale = 1.0F / (float) textureWidth; float vScale = 1.0F / (float) textureHeight; float uOffset = uScale / 20.0F; float vOffset = vScale / 20.0F; float uCircle = (float)textureCircleDiameterW * uScale; float vCircle = (float)textureCircleDiameterH * vScale; float uWidth = (uCircle * 2F - uOffset * 2F) / (float) segments; float vHeight = (float)textureH * vScale - uOffset * 2f; float uStart = (float)textureOffsetX * uScale; float vStart = (float)textureOffsetY * vScale; PositionTextureVertex[] vert; for(int index = 0; index < segments; index++) { int index2 = (index + 1) % segments; float uSize = MathHelper.sin((pi / (float)segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); float vSize = MathHelper.cos((pi / (float)segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); float uSize1 = MathHelper.sin((pi / (float)segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset); float vSize1 = MathHelper.cos((pi / (float)segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset); vert = new PositionTextureVertex[3]; vert[0] = tempVerts[0].setTexturePosition(uStart + 0.5F * uCircle, vStart + 0.5F * vCircle); vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + 0.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); vert[2] = tempVerts[1 + index].setTexturePosition(uStart + 0.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); poly[index] = new TexturedPolygon(vert); if(mirror ^ flip) poly[index].flipFace(); if(!coneBase && !coneTop) { vert = new PositionTextureVertex[4]; vert[0] = tempVerts[1 + index].setTexturePosition(uStart + uOffset + uWidth * (float)index, vStart + vOffset + vCircle); vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + uOffset + uWidth * (float)(index + 1), vStart + vOffset + vCircle); vert[2] = tempVerts[1 + segments + index2].setTexturePosition(uStart + uOffset + uWidth * (float)(index + 1), vStart + vOffset + vCircle + vHeight); vert[3] = tempVerts[1 + segments + index].setTexturePosition(uStart + uOffset + uWidth * (float)index, vStart + vOffset + vCircle + vHeight); poly[index + segments] = new TexturedPolygon(vert); if(mirror ^ flip) poly[index + segments].flipFace(); } vert = new PositionTextureVertex[3]; vert[0] = tempVerts[tempVerts.length - 1].setTexturePosition(uStart + 1.5F * uCircle, vStart + 0.5F * vCircle); vert[1] = tempVerts[tempVerts.length - 2 - index].setTexturePosition(uStart + 1.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); vert[2] = tempVerts[tempVerts.length - (1 + segments) + ((segments - index) % segments)].setTexturePosition(uStart + 1.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); poly[poly.length - segments + index] = new TexturedPolygon(vert); if(mirror ^ flip) poly[poly.length - segments + index].flipFace(); } copyTo(tempVerts, poly); } /** * Adds a Waveform .obj file as a model. Model files use the entire texture file. * @param file the location of the .obj file. The location is relative to the base directories, * which are either resources/models or resources/mods/models. */ public void addObj(String file) { addModel(file, ModelPool.OBJ); } /** * Adds model format support. Model files use the entire texture file. * @param file the location of the model file. The location is relative to the base directories, * which are either resources/models or resources/mods/models. * @param modelFormat the class of the model format interpreter */ public void addModel(String file, Class modelFormat) { ModelPoolEntry entry = ModelPool.addFile(file, modelFormat, transformGroup, textureGroup); if(entry == null) return; PositionTextureVertex[] verts = Arrays.copyOf(entry.vertices, entry.vertices.length); TexturedPolygon[] poly = Arrays.copyOf(entry.faces, entry.faces.length); if(flip) { for(int l = 0; l < faces.length; l++) { faces[l].flipFace(); } } copyTo(verts, poly, false); } /** * Sets a new position for the texture offset. * @param x the x-coordinate of the texture start * @param y the y-coordinate of the texture start */ public ModelRendererTurbo setTextureOffset(int x, int y) { textureOffsetX = x; textureOffsetY = y; return this; } /** * Sets the position of the shape, relative to the model's origins. Note that changing * the offsets will not change the pivot of the model. * @param x the x-position of the shape * @param y the y-position of the shape * @param z the z-position of the shape */ public void setPosition(float x, float y, float z) { rotationPointX = x; rotationPointY = y; rotationPointZ = z; } /** * Mirrors the model in any direction. * @param x whether the model should be mirrored in the x-direction * @param y whether the model should be mirrored in the y-direction * @param z whether the model should be mirrored in the z-direction */ public void doMirror(boolean x, boolean y, boolean z) { for(int i = 0; i < faces.length; i++) { PositionTextureVertex[] verts = faces[i].vertexPositions; for(int j = 0; j < verts.length; j++) { verts[j].vector3D.xCoord *= (x ? -1 : 1); verts[j].vector3D.yCoord *= (y ? -1 : 1); verts[j].vector3D.zCoord *= (z ? -1 : 1); } if(x^y^z) faces[i].flipFace(); } } /** * Sets whether the shape is mirrored or not. This has effect on the way the textures * get displayed. When working with addSprite, addPixel and addObj, it will be ignored. * @param isMirrored a boolean to define whether the shape is mirrored */ public void setMirrored(boolean isMirrored) { mirror = isMirrored; } /** * Sets whether the shape's faces are flipped or not. When GL_CULL_FACE is enabled, * it won't render the back faces, effectively giving you the possibility to make * "hollow" shapes. When working with addSprite and addPixel, it will be ignored. * @param isFlipped a boolean to define whether the shape is flipped */ public void setFlipped(boolean isFlipped) { flip = isFlipped; } /** * Clears the current shape. Since all shapes are stacked into one shape, you can't * just replace a shape by overwriting the shape with another one. In this case you * would need to clear the shape first. */ public void clear() { vertices = new PositionTextureVertex[0]; faces = new TexturedPolygon[0]; transformGroup.clear(); transformGroup.put("0", new TransformGroupBone(new Bone(0, 0, 0, 0), 1D)); currentGroup = transformGroup.get("0"); } /** * Copies an array of vertices and polygons to the current shape. This mainly is * used to copy each shape to the main class, but you can just use it to copy * your own shapes, for example from other classes, into the current class. * @param verts the array of vertices you want to copy * @param poly the array of polygons you want to copy */ public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly) { copyTo(verts, poly, true); } public void copyTo(PositionTextureVertex[] verts, TexturedPolygon[] poly, boolean copyGroup) { vertices = Arrays.copyOf(vertices, vertices.length + verts.length); faces = Arrays.copyOf(faces, faces.length + poly.length); for(int idx = 0; idx < verts.length; idx++) { vertices[vertices.length - verts.length + idx] = verts[idx]; if(copyGroup && verts[idx] instanceof PositionTransformVertex) ((PositionTransformVertex)verts[idx]).addGroup(currentGroup); } for(int idx = 0; idx < poly.length; idx++) { faces[faces.length - poly.length + idx] = poly[idx]; if(copyGroup) currentTextureGroup.addPoly(poly[idx]); } } /** * Copies an array of vertices and quads to the current shape. This method * converts quads to polygons and then calls the main copyTo method. * @param verts the array of vertices you want to copy * @param quad the array of quads you want to copy */ public void copyTo(PositionTextureVertex[] verts, TexturedQuad[] quad) { TexturedPolygon[] poly = new TexturedPolygon[quad.length]; for(int idx = 0; idx < quad.length; idx++) { poly[idx] = new TexturedPolygon(quad[idx].vertexPositions); } copyTo(verts, poly); } /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * @param groupName the name of the transformation group you want to switch to */ public void setGroup(String groupName) { setGroup(groupName, new Bone(0, 0, 0, 0), 1D); } /** * Sets the current transformation group. The transformation group is used * to allow for vertex transformation. If a transformation group does not exist, * a new one will be created. * @param groupName the name of the transformation group you want to switch to * @param bone the Bone this transformation group is attached to * @param weight the weight of the transformation group */ public void setGroup(String groupName, Bone bone, double weight) { if(!transformGroup.containsKey(groupName)) transformGroup.put(groupName, new TransformGroupBone(bone, weight)); currentGroup = transformGroup.get(groupName); } /** * Gets the current transformation group. * @return the current PositionTransformGroup. */ public TransformGroup getGroup() { return currentGroup; } /** * Gets the transformation group with a given group name. * @return the current PositionTransformGroup. */ public TransformGroup getGroup(String groupName) { if(!transformGroup.containsKey(groupName)) return null; return transformGroup.get(groupName); } /** * Sets the current texture group, which is used to switch the * textures on a per-model base. Do note that any model that is * rendered afterwards will use the same texture. To counter it, * set a default texture, either at initialization or before * rendering. * @param groupName The name of the texture group. If the texture * group doesn't exist, it creates a new group automatically. */ public void setTextureGroup(String groupName) { if(!textureGroup.containsKey(groupName)) { textureGroup.put(groupName, new TextureGroup()); } currentTextureGroup = textureGroup.get(groupName); } /** * Gets the current texture group. * @return a TextureGroup object. */ public TextureGroup getTextureGroup() { return currentTextureGroup; } /** * Gets the texture group with the given name. * @param groupName the name of the texture group to return * @return a TextureGroup object. */ public TextureGroup getTextureGroup(String groupName) { if(!textureGroup.containsKey(groupName)) return null; return textureGroup.get(groupName); } /** * Sets the texture of the current texture group. * @param s the filename */ public void setGroupTexture(String s) { currentTextureGroup.texture = s; } /** * Sets the default texture. When left as an empty string, * it will use the texture that has been set previously. * Note that this will also move on to other rendered models * of the same entity. * @param s the filename */ public void setDefaultTexture(String s) { defaultTexture = s; } /** * Renders the shape. * @param worldScale the scale of the shape. Usually is 0.0625. */ public void render(float worldScale) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled || forcedRecompile) { compileDisplayList(worldScale); } if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { GL11.glPushMatrix(); GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); if(rotateAngleZ != 0.0F) { GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } if(rotateAngleY != 0.0F) { GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } callDisplayList(); if(childModels != null) { for(int i = 0; i < childModels.size(); i++) { ((ModelRenderer)childModels.get(i)).render(worldScale); } } GL11.glPopMatrix(); } else if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { GL11.glTranslatef(rotationPointX * worldScale, rotationPointY * worldScale, rotationPointZ * worldScale); callDisplayList(); if(childModels != null) { for(int i = 0; i < childModels.size(); i++) { ((ModelRenderer)childModels.get(i)).render(worldScale); } } GL11.glTranslatef(-rotationPointX * worldScale, -rotationPointY * worldScale, -rotationPointZ * worldScale); } else { callDisplayList(); if(childModels != null) { for(int i = 0; i < childModels.size(); i++) { ((ModelRenderer)childModels.get(i)).render(worldScale); } } } } public void renderWithRotation(float f) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled) { compileDisplayList(f); } GL11.glPushMatrix(); GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); if(rotateAngleY != 0.0F) { GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } if(rotateAngleZ != 0.0F) { GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } callDisplayList(); GL11.glPopMatrix(); } public void postRender(float f) { if(field_1402_i) { return; } if(!showModel) { return; } if(!compiled || forcedRecompile) { compileDisplayList(f); } if(rotateAngleX != 0.0F || rotateAngleY != 0.0F || rotateAngleZ != 0.0F) { GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); if(rotateAngleZ != 0.0F) { GL11.glRotatef(rotateAngleZ * 57.29578F, 0.0F, 0.0F, 1.0F); } if(rotateAngleY != 0.0F) { GL11.glRotatef(rotateAngleY * 57.29578F, 0.0F, 1.0F, 0.0F); } if(rotateAngleX != 0.0F) { GL11.glRotatef(rotateAngleX * 57.29578F, 1.0F, 0.0F, 0.0F); } } else if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F) { GL11.glTranslatef(rotationPointX * f, rotationPointY * f, rotationPointZ * f); } } private void callDisplayList() { if(useLegacyCompiler) GL11.glCallList(displayList); else { RenderEngine renderEngine = RenderManager.instance.renderEngine; Collection textures = textureGroup.values(); Iterator itr = textures.iterator(); for(int i = 0; itr.hasNext(); i++) { TextureGroup curTexGroup = (TextureGroup)itr.next(); curTexGroup.loadTexture(); GL11.glCallList(displayListArray[i]); if(!defaultTexture.equals("")) renderEngine.bindTexture(defaultTexture); } } } private void compileDisplayList(float worldScale) { if(useLegacyCompiler) compileLegacyDisplayList(worldScale); else { Collection textures = textureGroup.values(); Iterator itr = textures.iterator(); displayListArray = new int[textureGroup.size()]; for(int i = 0; itr.hasNext(); i++) { displayListArray[i] = GLAllocation.generateDisplayLists(1); GL11.glNewList(displayListArray[i], 4864); Tessellator tessellator = Tessellator.instance; TextureGroup usedGroup = (TextureGroup)itr.next(); for(int j = 0; j < usedGroup.poly.size(); j++) { usedGroup.poly.get(j).draw(tessellator, worldScale); } GL11.glEndList(); } } compiled = true; } private void compileLegacyDisplayList(float worldScale) { displayList = GLAllocation.generateDisplayLists(1); GL11.glNewList(displayList, 4864 /*GL_COMPILE*/); Tessellator tessellator = Tessellator.instance; for(int i = 0; i < faces.length; i++) { faces[i].draw(tessellator, worldScale); } GL11.glEndList(); } private PositionTextureVertex vertices[]; private TexturedPolygon faces[]; private int textureOffsetX; private int textureOffsetY; private boolean compiled; private int displayList; private int displayListArray[]; private Map transformGroup; private Map textureGroup; private TransformGroup currentGroup; private TextureGroup currentTextureGroup; public boolean mirror; public boolean flip; public boolean showModel; public boolean field_1402_i; public boolean forcedRecompile; public boolean useLegacyCompiler; public List cubeList; public List childModels; public final String boxName; private String defaultTexture; public static final int MR_FRONT = 0; public static final int MR_BACK = 1; public static final int MR_LEFT = 2; public static final int MR_RIGHT = 3; public static final int MR_TOP = 4; public static final int MR_BOTTOM = 5; private static final float pi = (float) Math.PI; }