Merge pull request #1521 from RainWarrior/model-system

Model loader registry
This commit is contained in:
RainWarrior committed 2015-01-29 13:25:47 +03:00
commit 67121d9ebc
31 files changed
+3773 -5

No files matched your search

@@ -0,0 +1,70 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/WorldVertexBufferUploader.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/WorldVertexBufferUploader.java
@@ -29,35 +29,9 @@
while (iterator.hasNext())
{
+ // moved to VertexFormatElement.preDraw
vertexformatelement = (VertexFormatElement)iterator.next();
- enumusage = vertexformatelement.func_177375_c();
- k = vertexformatelement.func_177367_b().func_177397_c();
- int l = vertexformatelement.func_177369_e();
-
- switch (WorldVertexBufferUploader.SwitchEnumUsage.field_178958_a[enumusage.ordinal()])
- {
- case 1:
- bytebuffer.position(vertexformatelement.func_177373_a());
- GL11.glVertexPointer(vertexformatelement.func_177370_d(), k, j, bytebuffer);
- GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY);
- break;
- case 2:
- bytebuffer.position(vertexformatelement.func_177373_a());
- OpenGlHelper.func_77472_b(OpenGlHelper.field_77478_a + l);
- GL11.glTexCoordPointer(vertexformatelement.func_177370_d(), k, j, bytebuffer);
- GL11.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
- OpenGlHelper.func_77472_b(OpenGlHelper.field_77478_a);
- break;
- case 3:
- bytebuffer.position(vertexformatelement.func_177373_a());
- GL11.glColorPointer(vertexformatelement.func_177370_d(), k, j, bytebuffer);
- GL11.glEnableClientState(GL11.GL_COLOR_ARRAY);
- break;
- case 4:
- bytebuffer.position(vertexformatelement.func_177373_a());
- GL11.glNormalPointer(k, j, bytebuffer);
- GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY);
- }
+ vertexformatelement.func_177375_c().preDraw(vertexformatelement, j, bytebuffer);
}
GL11.glDrawArrays(p_178177_1_.func_178979_i(), 0, p_178177_1_.func_178989_h());
@@ -65,27 +39,9 @@
while (iterator.hasNext())
{
+ // moved to VertexFormatElement.postDraw
vertexformatelement = (VertexFormatElement)iterator.next();
- enumusage = vertexformatelement.func_177375_c();
- k = vertexformatelement.func_177369_e();
-
- switch (WorldVertexBufferUploader.SwitchEnumUsage.field_178958_a[enumusage.ordinal()])
- {
- case 1:
- GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY);
- break;
- case 2:
- OpenGlHelper.func_77472_b(OpenGlHelper.field_77478_a + k);
- GL11.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
- OpenGlHelper.func_77472_b(OpenGlHelper.field_77478_a);
- break;
- case 3:
- GL11.glDisableClientState(GL11.GL_COLOR_ARRAY);
- GlStateManager.func_179117_G();
- break;
- case 4:
- GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY);
- }
+ vertexformatelement.func_177375_c().postDraw(vertexformatelement, j, bytebuffer);
}
}
@@ -0,0 +1,76 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/block/model/FaceBakery.java
@@ -22,7 +22,12 @@
public BakedQuad func_178414_a(Vector3f p_178414_1_, Vector3f p_178414_2_, BlockPartFace p_178414_3_, TextureAtlasSprite p_178414_4_, EnumFacing p_178414_5_, ModelRotation p_178414_6_, BlockPartRotation p_178414_7_, boolean p_178414_8_, boolean p_178414_9_)
{
- int[] aint = this.func_178405_a(p_178414_3_, p_178414_4_, p_178414_5_, this.func_178403_a(p_178414_1_, p_178414_2_), p_178414_6_, p_178414_7_, p_178414_8_, p_178414_9_);
+ return makeBakedQuad(p_178414_1_, p_178414_2_, p_178414_3_, p_178414_4_, p_178414_5_, (net.minecraftforge.client.model.ITransformation)p_178414_6_, p_178414_7_, p_178414_8_, p_178414_9_);
+ }
+
+ public BakedQuad makeBakedQuad(Vector3f p_178414_1_, Vector3f p_178414_2_, BlockPartFace p_178414_3_, TextureAtlasSprite p_178414_4_, EnumFacing p_178414_5_, net.minecraftforge.client.model.ITransformation p_178414_6_, BlockPartRotation p_178414_7_, boolean p_178414_8_, boolean p_178414_9_)
+ {
+ int[] aint = this.makeQuadVertexData(p_178414_3_, p_178414_4_, p_178414_5_, this.func_178403_a(p_178414_1_, p_178414_2_), p_178414_6_, p_178414_7_, p_178414_8_, p_178414_9_);
EnumFacing enumfacing1 = func_178410_a(aint);
if (p_178414_8_)
@@ -40,11 +45,16 @@
private int[] func_178405_a(BlockPartFace p_178405_1_, TextureAtlasSprite p_178405_2_, EnumFacing p_178405_3_, float[] p_178405_4_, ModelRotation p_178405_5_, BlockPartRotation p_178405_6_, boolean p_178405_7_, boolean p_178405_8_)
{
+ return makeQuadVertexData(p_178405_1_, p_178405_2_, p_178405_3_, p_178405_4_, (net.minecraftforge.client.model.ITransformation)p_178405_5_, p_178405_6_, p_178405_7_, p_178405_8_);
+ }
+
+ private int[] makeQuadVertexData(BlockPartFace p_178405_1_, TextureAtlasSprite p_178405_2_, EnumFacing p_178405_3_, float[] p_178405_4_, net.minecraftforge.client.model.ITransformation p_178405_5_, BlockPartRotation p_178405_6_, boolean p_178405_7_, boolean p_178405_8_)
+ {
int[] aint = new int[28];
for (int i = 0; i < 4; ++i)
{
- this.func_178402_a(aint, i, p_178405_3_, p_178405_1_, p_178405_4_, p_178405_2_, p_178405_5_, p_178405_6_, p_178405_7_, p_178405_8_);
+ this.fillVertexData(aint, i, p_178405_3_, p_178405_1_, p_178405_4_, p_178405_2_, p_178405_5_, p_178405_6_, p_178405_7_, p_178405_8_);
}
return aint;
@@ -90,12 +100,17 @@
private void func_178402_a(int[] p_178402_1_, int p_178402_2_, EnumFacing p_178402_3_, BlockPartFace p_178402_4_, float[] p_178402_5_, TextureAtlasSprite p_178402_6_, ModelRotation p_178402_7_, BlockPartRotation p_178402_8_, boolean p_178402_9_, boolean p_178402_10_)
{
- EnumFacing enumfacing1 = p_178402_7_.func_177523_a(p_178402_3_);
+ fillVertexData(p_178402_1_, p_178402_2_, p_178402_3_, p_178402_4_, p_178402_5_, p_178402_6_, (net.minecraftforge.client.model.ITransformation)p_178402_7_, p_178402_8_, p_178402_9_, p_178402_10_);
+ }
+
+ private void fillVertexData(int[] p_178402_1_, int p_178402_2_, EnumFacing p_178402_3_, BlockPartFace p_178402_4_, float[] p_178402_5_, TextureAtlasSprite p_178402_6_, net.minecraftforge.client.model.ITransformation p_178402_7_, BlockPartRotation p_178402_8_, boolean p_178402_9_, boolean p_178402_10_)
+ {
+ EnumFacing enumfacing1 = p_178402_7_.rotate(p_178402_3_);
int j = p_178402_10_ ? this.func_178413_a(enumfacing1) : -1;
EnumFaceDirection.VertexInformation vertexinformation = EnumFaceDirection.func_179027_a(p_178402_3_).func_179025_a(p_178402_2_);
Vector3d vector3d = new Vector3d((double)p_178402_5_[vertexinformation.field_179184_a], (double)p_178402_5_[vertexinformation.field_179182_b], (double)p_178402_5_[vertexinformation.field_179183_c]);
this.func_178407_a(vector3d, p_178402_8_);
- int k = this.func_178415_a(vector3d, p_178402_3_, p_178402_2_, p_178402_7_, p_178402_9_);
+ int k = this.rotateVertex(vector3d, p_178402_3_, p_178402_2_, p_178402_7_, p_178402_9_);
this.func_178404_a(p_178402_1_, k, p_178402_2_, vector3d, j, p_178402_6_, p_178402_4_.field_178243_e);
}
@@ -156,14 +171,19 @@
public int func_178415_a(Vector3d p_178415_1_, EnumFacing p_178415_2_, int p_178415_3_, ModelRotation p_178415_4_, boolean p_178415_5_)
{
+ return rotateVertex(p_178415_1_, p_178415_2_, p_178415_3_, (net.minecraftforge.client.model.ITransformation)p_178415_4_, p_178415_5_);
+ }
+
+ public int rotateVertex(Vector3d p_178415_1_, EnumFacing p_178415_2_, int p_178415_3_, net.minecraftforge.client.model.ITransformation p_178415_4_, boolean p_178415_5_)
+ {
if (p_178415_4_ == ModelRotation.X0_Y0)
{
return p_178415_3_;
}
else
{
- this.func_178406_a(p_178415_1_, new Vector3d(0.5D, 0.5D, 0.5D), p_178415_4_.func_177525_a(), new Vector3d(1.0D, 1.0D, 1.0D));
- return p_178415_4_.func_177520_a(p_178415_2_, p_178415_3_);
+ this.func_178406_a(p_178415_1_, new Vector3d(0.5D, 0.5D, 0.5D), new Matrix4d(p_178415_4_.getMatrix()), new Vector3d(1.0D, 1.0D, 1.0D));
+ return p_178415_4_.rotate(p_178415_2_, p_178415_3_);
}
}
@@ -0,0 +1,14 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/block/model/ItemCameraTransforms.java
@@ -8,7 +8,11 @@
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+/*
+ * @deprecated use {@link net.minecraftforge.client.model.IPerspectiveAwareModel} instead
+ */
@SideOnly(Side.CLIENT)
+@Deprecated
public class ItemCameraTransforms
{
public static final ItemCameraTransforms field_178357_a = new ItemCameraTransforms(ItemTransformVec3f.field_178366_a, ItemTransformVec3f.field_178366_a, ItemTransformVec3f.field_178366_a, ItemTransformVec3f.field_178366_a);
@@ -0,0 +1,18 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/block/model/ItemTransformVec3f.java
@@ -13,9 +13,14 @@
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+/*
+ * @deprecated use {@link net.minecraftforge.client.model.IModelState} and {@link net.minecraftforge.client.model.TRSRTransformation}
+ */
@SideOnly(Side.CLIENT)
-public class ItemTransformVec3f
+@Deprecated
+public class ItemTransformVec3f implements net.minecraftforge.client.model.IModelState
{
+ public net.minecraftforge.client.model.TRSRTransformation apply(net.minecraftforge.client.model.IModelPart part) { return new net.minecraftforge.client.model.TRSRTransformation(this); }
public static final ItemTransformVec3f field_178366_a = new ItemTransformVec3f(new Vector3f(), new Vector3f(), new Vector3f(1.0F, 1.0F, 1.0F));
public final Vector3f field_178364_b;
public final Vector3f field_178365_c;
@@ -20,7 +20,44 @@
if (modelresourcelocation != null)
{
@@ -485,10 +489,11 @@
@@ -314,6 +318,11 @@
protected void func_175034_a(ItemTransformVec3f p_175034_1_)
{
+ applyVanillaTransform(p_175034_1_);
+ }
+
+ public static void applyVanillaTransform(ItemTransformVec3f p_175034_1_)
+ {
if (p_175034_1_ != ItemTransformVec3f.field_178366_a)
{
GlStateManager.func_179109_b(p_175034_1_.field_178365_c.x + field_175055_b, p_175034_1_.field_178365_c.y + field_175056_c, p_175034_1_.field_178365_c.z + field_175053_d);
@@ -335,23 +344,7 @@
GlStateManager.func_179120_a(770, 771, 1, 0);
GlStateManager.func_179094_E();
- switch (RenderItem.SwitchTransformType.field_178640_a[p_175040_3_.ordinal()])
- {
- case 1:
- default:
- break;
- case 2:
- this.func_175034_a(p_175040_2_.func_177552_f().field_178355_b);
- break;
- case 3:
- this.func_175034_a(p_175040_2_.func_177552_f().field_178356_c);
- break;
- case 4:
- this.func_175034_a(p_175040_2_.func_177552_f().field_178353_d);
- break;
- case 5:
- this.func_175034_a(p_175040_2_.func_177552_f().field_178354_e);
- }
+ p_175040_2_ = net.minecraftforge.client.ForgeHooksClient.handleCameraTransforms(p_175040_2_, p_175040_3_);
this.func_180454_a(p_175040_1_, p_175040_2_);
GlStateManager.func_179121_F();
@@ -485,10 +478,11 @@
GlStateManager.func_179126_j();
}
@@ -35,7 +72,7 @@
GlStateManager.func_179140_f();
GlStateManager.func_179097_i();
GlStateManager.func_179090_x();
@@ -501,7 +506,7 @@
@@ -501,7 +495,7 @@
this.func_175044_a(worldrenderer, p_180453_3_ + 2, p_180453_4_ + 13, 13, 2, 0);
this.func_175044_a(worldrenderer, p_180453_3_ + 2, p_180453_4_ + 13, 12, 1, i1);
this.func_175044_a(worldrenderer, p_180453_3_ + 2, p_180453_4_ + 13, j1, 1, l);
@@ -44,7 +81,7 @@
GlStateManager.func_179141_d();
GlStateManager.func_179098_w();
GlStateManager.func_179145_e();
@@ -1078,6 +1083,19 @@
@@ -1078,6 +1072,19 @@
{
this.field_175059_m.func_178085_b();
}
@@ -0,0 +1,49 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/vertex/VertexFormatElement.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/vertex/VertexFormatElement.java
@@ -114,13 +114,20 @@
@SideOnly(Side.CLIENT)
public static enum EnumType
{
- FLOAT(4, "Float", 5126),
- UBYTE(1, "Unsigned Byte", 5121),
- BYTE(1, "Byte", 5120),
- USHORT(2, "Unsigned Short", 5123),
- SHORT(2, "Short", 5122),
- UINT(4, "Unsigned Int", 5125),
- INT(4, "Int", 5124);
+ FLOAT(4, "Float", org.lwjgl.opengl.GL11.GL_FLOAT),
+ UBYTE(1, "Unsigned Byte", org.lwjgl.opengl.GL11.GL_UNSIGNED_BYTE),
+ BYTE(1, "Byte", org.lwjgl.opengl.GL11.GL_BYTE),
+ USHORT(2, "Unsigned Short", org.lwjgl.opengl.GL11.GL_UNSIGNED_SHORT),
+ SHORT(2, "Short", org.lwjgl.opengl.GL11.GL_SHORT),
+ UINT(4, "Unsigned Int", org.lwjgl.opengl.GL11.GL_UNSIGNED_INT),
+ INT(4, "Int", org.lwjgl.opengl.GL11.GL_INT);
+ // Commented for now, might be added in the future if anyone needs them
+ //HALF_FLOAT(2, "Half Float", org.lwjgl.opengl.GL30.GL_HALF_FLOAT),
+ //DOUBLE(8, "Double", org.lwjgl.opengl.GL11.GL_DOUBLE),
+ //INT_2_10_10_10_REV(4, "Int 2-10-10-10 reversed", org.lwjgl.opengl.GL33.GL_INT_2_10_10_10_REV),
+ //UINT_2_10_10_10_REV(4, "Unsigned Int 2-10-10-10 reversed", org.lwjgl.opengl.GL12.GL_UNSIGNED_INT_2_10_10_10_REV),
+ //UINT_10F_11F_11F_REV(4, "Unsigned Int 10F 11F 11F reversed", GL_UNSIGNED_INT_10F_11F_11F_REV);
+
private final int field_177407_h;
private final String field_177408_i;
private final int field_177405_j;
@@ -157,9 +164,17 @@
NORMAL("Normal"),
COLOR("Vertex Color"),
UV("UV"),
+ // As of 1.8 - unused in vanilla; use GENERIC for now
+ @Deprecated
MATRIX("Bone Matrix"),
+ @Deprecated
BLEND_WEIGHT("Blend Weight"),
- PADDING("Padding");
+ PADDING("Padding"),
+ GENERIC("Generic Attribute");
+
+ public void preDraw(VertexFormatElement element, int stride, java.nio.ByteBuffer buffer) { net.minecraftforge.client.ForgeHooksClient.preDraw(this, element, stride, buffer); }
+ public void postDraw(VertexFormatElement element, int stride, java.nio.ByteBuffer buffer) { net.minecraftforge.client.ForgeHooksClient.postDraw(this, element, stride, buffer); }
+
private final String field_177392_h;
private static final String __OBFID = "CL_00002397";
@@ -0,0 +1,21 @@
--- ../src-base/minecraft/net/minecraft/client/resources/model/IBakedModel.java
+++ ../src-work/minecraft/net/minecraft/client/resources/model/IBakedModel.java
@@ -7,7 +7,11 @@
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
+/*
+ * @deprecated use {@link net.minecraftforge.client.model.IFlexibleBakedModel}, {@link net.minecraftforge.client.model.IPerspectiveAwareModel}
+ */
@SideOnly(Side.CLIENT)
+@Deprecated
public interface IBakedModel
{
List func_177551_a(EnumFacing p_177551_1_);
@@ -22,5 +26,6 @@
TextureAtlasSprite func_177554_e();
+ @Deprecated
ItemCameraTransforms func_177552_f();
}
@@ -0,0 +1,53 @@
--- ../src-base/minecraft/net/minecraft/client/resources/model/ModelBakery.java
+++ ../src-work/minecraft/net/minecraft/client/resources/model/ModelBakery.java
@@ -123,7 +123,7 @@
}
catch (Exception exception)
{
- field_177603_c.warn("Unable to load variant: " + modelresourcelocation.func_177518_c() + " from " + modelresourcelocation);
+ field_177603_c.warn("Unable to load variant: " + modelresourcelocation.func_177518_c() + " from " + modelresourcelocation, exception);
}
}
catch (Exception exception1)
@@ -499,6 +499,11 @@
private IBakedModel func_177578_a(ModelBlock p_177578_1_, ModelRotation p_177578_2_, boolean p_177578_3_)
{
+ return bakeModel(p_177578_1_, (net.minecraftforge.client.model.ITransformation)p_177578_2_, p_177578_3_);
+ }
+
+ protected IBakedModel bakeModel(ModelBlock p_177578_1_, net.minecraftforge.client.model.ITransformation p_177578_2_, boolean p_177578_3_)
+ {
TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)this.field_177599_g.get(new ResourceLocation(p_177578_1_.func_178308_c("particle")));
SimpleBakedModel.Builder builder = (new SimpleBakedModel.Builder(p_177578_1_)).func_177646_a(textureatlassprite);
Iterator iterator = p_177578_1_.func_178298_a().iterator();
@@ -516,11 +521,11 @@
if (blockpartface.field_178244_b == null)
{
- builder.func_177648_a(this.func_177589_a(blockpart, blockpartface, textureatlassprite1, enumfacing, p_177578_2_, p_177578_3_));
+ builder.func_177648_a(this.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, enumfacing, p_177578_2_, p_177578_3_));
}
else
{
- builder.func_177650_a(p_177578_2_.func_177523_a(blockpartface.field_178244_b), this.func_177589_a(blockpart, blockpartface, textureatlassprite1, enumfacing, p_177578_2_, p_177578_3_));
+ builder.func_177650_a(p_177578_2_.rotate(blockpartface.field_178244_b), this.makeBakedQuad(blockpart, blockpartface, textureatlassprite1, enumfacing, p_177578_2_, p_177578_3_));
}
}
}
@@ -530,9 +535,14 @@
private BakedQuad func_177589_a(BlockPart p_177589_1_, BlockPartFace p_177589_2_, TextureAtlasSprite p_177589_3_, EnumFacing p_177589_4_, ModelRotation p_177589_5_, boolean p_177589_6_)
{
- return this.field_177607_l.func_178414_a(p_177589_1_.field_178241_a, p_177589_1_.field_178239_b, p_177589_2_, p_177589_3_, p_177589_4_, p_177589_5_, p_177589_1_.field_178237_d, p_177589_6_, p_177589_1_.field_178238_e);
+ return makeBakedQuad(p_177589_1_, p_177589_2_, p_177589_3_, p_177589_4_, (net.minecraftforge.client.model.ITransformation)p_177589_5_, p_177589_6_);
}
+ private BakedQuad makeBakedQuad(BlockPart p_177589_1_, BlockPartFace p_177589_2_, TextureAtlasSprite p_177589_3_, EnumFacing p_177589_4_, net.minecraftforge.client.model.ITransformation p_177589_5_, boolean p_177589_6_)
+ {
+ return this.field_177607_l.makeBakedQuad(p_177589_1_.field_178241_a, p_177589_1_.field_178239_b, p_177589_2_, p_177589_3_, p_177589_4_, p_177589_5_, p_177589_1_.field_178237_d, p_177589_6_, p_177589_1_.field_178238_e);
+ }
+
private void func_177597_h()
{
this.func_177574_i();
@@ -1,7 +1,11 @@
--- ../src-base/minecraft/net/minecraft/client/resources/model/ModelManager.java
+++ ../src-work/minecraft/net/minecraft/client/resources/model/ModelManager.java
@@ -28,6 +28,7 @@
ModelBakery modelbakery = new ModelBakery(p_110549_1_, this.field_174956_b, this.field_174957_c);
@@ -25,9 +25,10 @@
public void func_110549_a(IResourceManager p_110549_1_)
{
- ModelBakery modelbakery = new ModelBakery(p_110549_1_, this.field_174956_b, this.field_174957_c);
+ ModelBakery modelbakery = new net.minecraftforge.client.model.ModelLoader(p_110549_1_, this.field_174956_b, this.field_174957_c);
this.field_174958_a = modelbakery.func_177570_a();
this.field_174955_d = (IBakedModel)this.field_174958_a.func_82594_a(ModelBakery.field_177604_a);
+ net.minecraftforge.client.ForgeHooksClient.onModelBake(this, this.field_174958_a, modelbakery);
@@ -0,0 +1,21 @@
--- ../src-base/minecraft/net/minecraft/client/resources/model/ModelRotation.java
+++ ../src-work/minecraft/net/minecraft/client/resources/model/ModelRotation.java
@@ -10,7 +10,7 @@
import net.minecraftforge.fml.relauncher.SideOnly;
@SideOnly(Side.CLIENT)
-public enum ModelRotation
+public enum ModelRotation implements net.minecraftforge.client.model.IModelState, net.minecraftforge.client.model.ITransformation
{
X0_Y0(0, 0),
X0_Y90(0, 90),
@@ -122,4 +122,9 @@
field_177546_q.put(Integer.valueOf(var3.field_177545_r), var3);
}
}
+
+ public net.minecraftforge.client.model.TRSRTransformation apply(net.minecraftforge.client.model.IModelPart part) { return new net.minecraftforge.client.model.TRSRTransformation(getMatrix()); }
+ public javax.vecmath.Matrix4f getMatrix() { return new javax.vecmath.Matrix4f(func_177525_a()); }
+ public EnumFacing rotate(EnumFacing facing) { return func_177523_a(facing); }
+ public int rotate(EnumFacing facing, int vertexIndex) { return func_177520_a(facing, vertexIndex); }
}
@@ -2,6 +2,14 @@ package net.minecraftforge.client;
import static net.minecraftforge.common.ForgeVersion.Status.BETA;
import static net.minecraftforge.common.ForgeVersion.Status.BETA_OUTDATED;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.opengl.GL20.*;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import javax.vecmath.Matrix4f;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -13,10 +21,18 @@ import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.model.ModelBase;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemTransformVec3f;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelManager;
import net.minecraft.client.settings.GameSettings;
@@ -42,13 +58,17 @@ import net.minecraftforge.client.event.RenderHandEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.client.event.sound.PlaySoundEvent;
import net.minecraftforge.client.model.IPerspectiveAwareModel;
import net.minecraftforge.common.ForgeModContainer;
import net.minecraftforge.common.ForgeVersion;
import net.minecraftforge.common.ForgeVersion.Status;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
//import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
//import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
@@ -469,4 +489,138 @@ public class ForgeHooksClient
{
MinecraftForge.EVENT_BUS.post(new ModelBakeEvent(modelManager, modelRegistry, modelBakery));
}
public static Matrix4f getMatrix(ItemTransformVec3f transform)
{
javax.vecmath.Matrix4f m = new javax.vecmath.Matrix4f(), t = new javax.vecmath.Matrix4f();
m.setIdentity();
m.setTranslation(transform.translation);
t.setIdentity();
t.rotY(transform.rotation.y);
m.mul(t);
t.setIdentity();
t.rotX(transform.rotation.x);
m.mul(t);
t.setIdentity();
t.rotZ(transform.rotation.z);
m.mul(t);
t.setIdentity();
t.m00 = transform.scale.x;
t.m11 = transform.scale.y;
t.m22 = transform.scale.z;
m.mul(t);
return m;
}
public static IBakedModel handleCameraTransforms(IBakedModel model, ItemCameraTransforms.TransformType cameraTransformType)
{
if(model instanceof IPerspectiveAwareModel)
{
Pair<IBakedModel, Matrix4f> pair = ((IPerspectiveAwareModel)model).handlePerspective(cameraTransformType);
if(pair.getRight() != null) multiplyCurrentGlMatrix(pair.getRight());
return pair.getLeft();
}
switch(cameraTransformType)
{
case FIRST_PERSON:
RenderItem.applyVanillaTransform(model.getItemCameraTransforms().firstPerson);
break;
case GUI:
RenderItem.applyVanillaTransform(model.getItemCameraTransforms().gui);
break;
case HEAD:
RenderItem.applyVanillaTransform(model.getItemCameraTransforms().head);
break;
case THIRD_PERSON:
RenderItem.applyVanillaTransform(model.getItemCameraTransforms().thirdPerson);
break;
default:
break;
}
return model;
}
private static final FloatBuffer matrixBuf = BufferUtils.createFloatBuffer(16);
public static void multiplyCurrentGlMatrix(Matrix4f matrix)
{
matrixBuf.clear();
float[] t = new float[4];
for(int i = 0; i < 4; i++)
{
matrix.getColumn(i, t);
matrixBuf.put(t);
}
matrixBuf.flip();
GL11.glMultMatrix(matrixBuf);
}
// moved and expanded from WorldVertexBufferUploader.draw
public static void preDraw(EnumUsage attrType, VertexFormatElement attr, int stride, ByteBuffer buffer)
{
buffer.position(attr.getOffset());
switch(attrType)
{
case POSITION:
glVertexPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glEnableClientState(GL_VERTEX_ARRAY);
break;
case NORMAL:
if(attr.getElementCount() != 3)
{
throw new IllegalArgumentException("Normal attribute should have the size 3: " + attr);
}
glNormalPointer(attr.getType().getGlConstant(), stride, buffer);
glEnableClientState(GL_NORMAL_ARRAY);
break;
case COLOR:
glColorPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glEnableClientState(GL_COLOR_ARRAY);
break;
case UV:
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + attr.getIndex());
glTexCoordPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
break;
case PADDING:
break;
case GENERIC:
glEnableVertexAttribArray(attr.getIndex());
glVertexAttribPointer(attr.getIndex(), attr.getElementCount(), attr.getType().getGlConstant(), false, stride, buffer);
default:
FMLLog.severe("Unimplemented vanilla attribute upload: %s", attrType.getDisplayName());
}
}
public static void postDraw(EnumUsage attrType, VertexFormatElement attr, int stride, ByteBuffer buffer)
{
switch(attrType)
{
case POSITION:
glDisableClientState(GL_VERTEX_ARRAY);
break;
case NORMAL:
glDisableClientState(GL_NORMAL_ARRAY);
break;
case COLOR:
glDisableClientState(GL_COLOR_ARRAY);
// is this really needed?
GlStateManager.resetColor();
break;
case UV:
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + attr.getIndex());
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit);
break;
case PADDING:
break;
case GENERIC:
glDisableVertexAttribArray(attr.getIndex());
default:
FMLLog.severe("Unimplemented vanilla attribute upload: %s", attrType.getDisplayName());
}
}
}
@@ -0,0 +1,107 @@
package net.minecraftforge.client.model;
import java.nio.ByteBuffer;
import java.util.List;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumType;
import net.minecraft.client.renderer.vertex.VertexFormatElement.EnumUsage;
public class Attributes
{
/*
* Default format of the data in IBakedModel
*/
public static final VertexFormat DEFAULT_BAKED_FORMAT;
static
{
DEFAULT_BAKED_FORMAT = new VertexFormat();
DEFAULT_BAKED_FORMAT.setElement(new VertexFormatElement(0, EnumType.FLOAT, EnumUsage.POSITION, 3));
DEFAULT_BAKED_FORMAT.setElement(new VertexFormatElement(0, EnumType.UBYTE, EnumUsage.COLOR, 4));
DEFAULT_BAKED_FORMAT.setElement(new VertexFormatElement(0, EnumType.FLOAT, EnumUsage.UV, 2));
DEFAULT_BAKED_FORMAT.setElement(new VertexFormatElement(0, EnumType.BYTE, EnumUsage.PADDING, 4));
}
/*
* Can first format be used where second is expected
*/
public static boolean moreSpecific(VertexFormat first, VertexFormat second)
{
int size = first.getNextOffset();
if(size != second.getNextOffset()) return false;
int padding = 0;
int j = 0;
for(VertexFormatElement firstAttr : (List<VertexFormatElement>)first.getElements())
{
while(j < second.getElementCount() && second.getElement(j).getUsage() == EnumUsage.PADDING)
{
padding += second.getElement(j++).getSize();
}
if(j >= second.getElementCount() && padding == 0)
{
// if no padding is left, but there are still elements in first (we're processing one) - it doesn't fit
return false;
}
if(padding == 0)
{
// no padding - attributes have to match
VertexFormatElement secondAttr = second.getElement(j++);
if(
firstAttr.getIndex() != secondAttr.getIndex() ||
firstAttr.getElementCount() != secondAttr.getElementCount() ||
firstAttr.getType() != secondAttr.getType() ||
firstAttr.getUsage() != secondAttr.getUsage())
{
return false;
}
}
else
{
// padding - attribute should fit in it
padding -= firstAttr.getSize();
if(padding < 0) return false;
}
}
if(padding != 0 || j != second.getElementCount()) return false;
return true;
}
public static void put(ByteBuffer buf, VertexFormatElement e, boolean normalize, Number fill, Number... ns)
{
if(e.getElementCount() > ns.length && fill == null) throw new IllegalArgumentException("not enough elements");
Number n;
for(int i = 0; i < e.getElementCount(); i++)
{
if(i < ns.length) n = ns[i];
else n = fill;
switch(e.getType())
{
case BYTE:
buf.put(normalize ? (byte)(n.floatValue() / (Byte.MAX_VALUE - 1)) : n.byteValue());
break;
case UBYTE:
buf.put(normalize ? (byte)(n.floatValue() / ((byte) -1)) : n.byteValue());
break;
case SHORT:
buf.putShort(normalize ? (short)(n.floatValue() / (Short.MAX_VALUE - 1)) : n.shortValue());
break;
case USHORT:
buf.putShort(normalize ? (short)(n.floatValue() / ((short) -1)) : n.shortValue());
break;
case INT:
buf.putInt(normalize ? (int)(n.doubleValue() / (Integer.MAX_VALUE - 1)) : n.intValue());
break;
case UINT:
buf.putInt(normalize ? (int)(n.doubleValue() / ((int) - 1)) : n.intValue());
break;
case FLOAT:
buf.putFloat(n.floatValue());
break;
}
}
}
}
@@ -0,0 +1,18 @@
package net.minecraftforge.client.model;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
public interface ICustomModelLoader extends IResourceManagerReloadListener
{
/*
* Checks if given model should be loaded by this loader.
* Reading file contents is inadvisable, if possible decision should be made based on the location alone.
*/
public boolean accepts(ResourceLocation modelLocation);
/*
* loads (or reloads) specified model
*/
public IModel loadModel(ResourceLocation modelLocation);
}
@@ -0,0 +1,82 @@
package net.minecraftforge.client.model;
import java.util.List;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.util.EnumFacing;
/*
* Version of IBakedModel with less restriction on camera transformations and with explicit format of the baked array.
*/
public interface IFlexibleBakedModel extends IBakedModel
{
// non-erased versions of the IBakedModel methods
List<BakedQuad> getFaceQuads(EnumFacing side);
List<BakedQuad> getGeneralQuads();
/*
* Specifies the format which BakedQuads' getVertexData will have.
*/
VertexFormat getFormat();
/*
* Default implementation of IFlexibleBakedModel that should be useful in most cases
*/
public static class Wrapper implements IFlexibleBakedModel
{
private final IBakedModel parent;
VertexFormat format;
public Wrapper(IBakedModel parent, VertexFormat format)
{
this.parent = parent;
this.format = format;
}
@SuppressWarnings("unchecked")
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return parent.getFaceQuads(side);
}
@SuppressWarnings("unchecked")
public List<BakedQuad> getGeneralQuads()
{
return parent.getGeneralQuads();
}
public boolean isAmbientOcclusion()
{
return parent.isAmbientOcclusion();
}
public boolean isGui3d()
{
return parent.isGui3d();
}
public boolean isBuiltInRenderer()
{
return parent.isBuiltInRenderer();
}
public TextureAtlasSprite getTexture()
{
return parent.getTexture();
}
@Deprecated
public ItemCameraTransforms getItemCameraTransforms()
{
return parent.getItemCameraTransforms();
}
public VertexFormat getFormat()
{
return new VertexFormat(format);
}
}
}
@@ -0,0 +1,45 @@
package net.minecraftforge.client.model;
import java.util.Collection;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation;
import com.google.common.base.Function;
/*
* Interface for models that can be baked
* (possibly to different vertex formats and with different state).
*/
public interface IModel extends IModelPart
{
/*
* Returns all model locations that this model depends on.
* Assume that returned collection is immutable.
*/
Collection<ResourceLocation> getDependencies();
/*
* Returns all texture locations that this model depends on.
* Assume that returned collection is immutable.
*/
Collection<ResourceLocation> getTextures();
/*
* All model texture coordinates should be resolved at this method.
* Returned model should be in the simplest form possible, for performance
* reasons (if it's not ISmartBlock/ItemModel - then it should be
* represented by List<BakedQuad> internally).
* Returned model's getFormat() can me less specific than the passed
* format argument (some attributes can be replaced with padding),
* if there's no such info in this model.
*/
IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter);
/*
* Default state this model will be baked with.
* See IModelState.
*/
IModelState getDefaultState();
}
@@ -0,0 +1,8 @@
package net.minecraftforge.client.model;
/*
* Represents the part of the model you can refer to, for example: mesh,
* skeleton, bone or some separately animated submodel.
* Primary function of this interface is the argument type of IModelState.apply.
*/
public interface IModelPart {}
@@ -0,0 +1,18 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix4f;
import com.google.common.base.Function;
/*
* Represents the dynamic information associated with the model.
* Common use case is (possibly interpolated) animation frame.
*/
public interface IModelState extends Function<IModelPart, TRSRTransformation>
{
/*
* returns the transformation (in the local coordinates) that needs to be applied to the specific part of the model.
*/
@Override
TRSRTransformation apply(IModelPart part);
}
@@ -0,0 +1,22 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix4f;
import org.apache.commons.lang3.tuple.Pair;
import net.minecraft.item.ItemStack;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.resources.model.IBakedModel;
/*
* Model that changes based on the rendering perspective
* (first-person, GUI, e.t.c - see TransformType)
*/
public interface IPerspectiveAwareModel extends IBakedModel
{
/*
* Returns the pair of the model for the given perspective, and the matrix
* that should be applied to the GL state before rendering it (matrix may be null).
*/
Pair<IBakedModel, Matrix4f> handlePerspective(TransformType cameraTransformType);
}
@@ -0,0 +1,18 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix4f;
import net.minecraft.util.EnumFacing;
/*
* Replacement interface for ModelRotation to allow custom transformations of vanilla models.
* You should probably use TRSRTransformation directly.
*/
public interface ITransformation
{
public Matrix4f getMatrix();
public EnumFacing rotate(EnumFacing facing);
public int rotate(EnumFacing facing, int vertexIndex);
}
@@ -0,0 +1,31 @@
package net.minecraftforge.client.model;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
/*
* Simple implementation of IModelState via a map and a default value.
*/
public class MapModelState implements IModelState
{
private final ImmutableMap<IModelPart, TRSRTransformation> map;
private final TRSRTransformation def;
public MapModelState(Map<IModelPart, TRSRTransformation> map)
{
this(map, TRSRTransformation.identity());
}
public MapModelState(Map<IModelPart, TRSRTransformation> map, TRSRTransformation def)
{
this.map = ImmutableMap.copyOf(map);
this.def = def;
}
public TRSRTransformation apply(IModelPart part)
{
if(!map.containsKey(part)) return def;
return map.get(part);
}
}
@@ -0,0 +1,399 @@
package net.minecraftforge.client.model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.BlockModelShapes;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.block.model.ItemModelGenerator;
import net.minecraft.client.renderer.block.model.ModelBlock;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition.MissingVariantException;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition.Variant;
import net.minecraft.client.renderer.block.model.ModelBlockDefinition.Variants;
import net.minecraft.client.renderer.texture.IIconCreator;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.model.BuiltInModel;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.ModelRotation;
import net.minecraft.client.resources.model.WeightedBakedModel;
import net.minecraft.item.Item;
import net.minecraft.util.IRegistry;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraftforge.fml.common.registry.GameData;
import org.apache.logging.log4j.Level;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
public class ModelLoader extends ModelBakery
{
private final Map<ModelResourceLocation, IModel> stateModels = new HashMap<ModelResourceLocation, IModel>();
private final Set<ResourceLocation> resolveTextures = new HashSet<ResourceLocation>();
private final Set<ResourceLocation> uvLocked = new HashSet<ResourceLocation>();
private final Set<ResourceLocation> textures = new HashSet<ResourceLocation>();
private final Set<ResourceLocation> loadingModels = new HashSet<ResourceLocation>();
public ModelLoader(IResourceManager manager, TextureMap map, BlockModelShapes shapes)
{
super(manager, map, shapes);
VanillaLoader.instance.setLoader(this);
ModelLoaderRegistry.clearModelCache();
}
@Override
public IRegistry setupModelRegistry()
{
loadBlocks();
loadItems();
stateModels.put(MODEL_MISSING, getModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath())));
textures.remove(TextureMap.LOCATION_MISSING_TEXTURE);
textures.addAll(LOCATIONS_BUILTIN_TEXTURES);
textureMap.loadSprites(resourceManager, new IIconCreator()
{
public void registerSprites(TextureMap map)
{
for(ResourceLocation t : textures)
{
sprites.put(t, map.registerSprite(t));
}
}
});
sprites.put(new ResourceLocation("missingno"), textureMap.getMissingSprite());
Function<ResourceLocation, TextureAtlasSprite> textureGetter = Functions.forMap(sprites, textureMap.getMissingSprite());
for(Entry<ModelResourceLocation, IModel> e : stateModels.entrySet())
{
bakedRegistry.putObject(e.getKey(), e.getValue().bake(e.getValue().getDefaultState(), Attributes.DEFAULT_BAKED_FORMAT, textureGetter));
}
return bakedRegistry;
}
private void loadBlocks()
{
Map<IBlockState, ModelResourceLocation> stateMap = blockModelShapes.getBlockStateMapper().putAllStateModelLocations();
loadVariants(stateMap.values());
}
@Override
protected void registerVariant(ModelBlockDefinition definition, ModelResourceLocation location)
{
Variants variants = null;
try
{
variants = definition.getVariants(location.getVariant());
}
catch(MissingVariantException e) {}
if(variants == null)
{
// adding default variant for simple blocks
ResourceLocation loc = new ResourceLocation(location.getResourceDomain(), "block/" + location.getResourcePath());
variants = new Variants("normal", Lists.newArrayList(new Variant(loc, ModelRotation.X0_Y0, false, 1)));
}
if(!variants.getVariants().isEmpty())
{
try
{
stateModels.put(location, new WeightedRandomModel(variants));
}
catch(Throwable e)
{
throw new RuntimeException(e);
}
}
}
private void loadItems()
{
registerVariantNames();
for(Item item : GameData.getItemRegistry().typeSafeIterable())
{
for(String s : (List<String>)getVariantNames(item))
{
ResourceLocation file = getItemLocation(s);
ModelResourceLocation memory = new ModelResourceLocation(s, "inventory");
resolveTextures.add(ModelLoaderRegistry.getActualLocation(file));
IModel model = getModel(file);
if(model != null) stateModels.put(memory, model);
}
}
}
public IModel getModel(ResourceLocation location)
{
if(!ModelLoaderRegistry.loaded(location)) loadAnyModel(location);
return ModelLoaderRegistry.getModel(location);
}
@Override
protected ResourceLocation getModelLocation(ResourceLocation model)
{
return new ResourceLocation(model.getResourceDomain(), model.getResourcePath() + ".json");
}
private void loadAnyModel(ResourceLocation location)
{
if(loadingModels.contains(location))
{
throw new IllegalStateException("circular model dependencies involving model " + location);
}
loadingModels.add(location);
IModel model = ModelLoaderRegistry.getModel(location);
for(ResourceLocation dep : model.getDependencies())
{
getModel(dep);
}
textures.addAll(model.getTextures());
loadingModels.remove(location);
}
private class VanillaModelWrapper implements IModel
{
private final ResourceLocation location;
private final ModelBlock model;
public VanillaModelWrapper(ResourceLocation location, ModelBlock model)
{
this.location = location;
this.model = model;
}
public Collection<ResourceLocation> getDependencies()
{
if(model.getParentLocation() == null || model.getParentLocation().getResourcePath().startsWith("builtin/")) return Collections.emptyList();
return Collections.singletonList(model.getParentLocation());
}
public Collection<ResourceLocation> getTextures()
{
// setting parent here to make textures resolve properly
if(model.getParentLocation() != null)
{
IModel parent = getModel(model.getParentLocation());
if(parent instanceof VanillaModelWrapper)
{
model.parent = ((VanillaModelWrapper) parent).model;
}
else
{
throw new IllegalStateException("vanilla model" + model + "can't have non-vanilla parent");
}
}
if(!resolveTextures.contains(location)) return Collections.emptyList();
ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder();
builder.add(new ResourceLocation(model.resolveTextureName("particle")));
if(hasItemModel(model))
{
for(String s : (List<String>)ItemModelGenerator.LAYERS)
{
String r = model.resolveTextureName(s);
ResourceLocation loc = new ResourceLocation(r);
if(!r.equals(s))
{
builder.add(loc);
}
// mojang hardcode
if(model.getRootModel() == MODEL_COMPASS && !loc.equals(TextureMap.LOCATION_MISSING_TEXTURE))
{
TextureAtlasSprite.setLocationNameCompass(loc.toString());
}
else if(model.getRootModel() == MODEL_CLOCK && !loc.equals(TextureMap.LOCATION_MISSING_TEXTURE))
{
TextureAtlasSprite.setLocationNameClock(loc.toString());
}
}
}
if(location.getResourcePath().startsWith("models/block/") || !ModelLoader.this.isBuiltinModel(model.getRootModel()))
{
builder.addAll(ModelLoader.this.getTextureLocations(model));
}
return builder.build();
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT))
{
throw new IllegalArgumentException("can't bake vanilla models to the format that doesn't fit into the default one: " + format);
}
ModelBlock model = this.model;
if(hasItemModel(model)) model = makeItemModel(model);
if(isCustomRenderer(model)) return new IFlexibleBakedModel.Wrapper(new BuiltInModel(new ItemCameraTransforms(model.getThirdPersonTransform(), model.getFirstPersonTransform(), model.getHeadTransform(), model.getInGuiTransform())), Attributes.DEFAULT_BAKED_FORMAT);
return new IFlexibleBakedModel.Wrapper(bakeModel(model, state.apply(this), uvLocked.contains(location)), Attributes.DEFAULT_BAKED_FORMAT);
}
public IModelState getDefaultState()
{
return ModelRotation.X0_Y0;
}
}
// Weighted models can contain multiple copies of 1 model with different rotations - this is to make it work with IModelState (different copies will be different objects).
private static class WeightedPartWrapper implements IModel
{
private final IModel model;
public WeightedPartWrapper(IModel model)
{
this.model = model;
}
public Collection<ResourceLocation> getDependencies()
{
return model.getDependencies();
}
public Collection<ResourceLocation> getTextures()
{
return model.getTextures();
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
return model.bake(state, format, bakedTextureGetter);
}
public IModelState getDefaultState()
{
return model.getDefaultState();
}
}
private class WeightedRandomModel implements IModel
{
private final List<Variant> variants;
private final List<ResourceLocation> locations = new ArrayList<ResourceLocation>();
private final List<IModel> models = new ArrayList<IModel>();
private final IModelState defaultState;
public WeightedRandomModel(Variants variants)
{
this.variants = variants.getVariants();
ImmutableMap.Builder<IModelPart, TRSRTransformation> builder = ImmutableMap.builder();
for(Variant v : (List<Variant>)variants.getVariants())
{
ResourceLocation loc = v.getModelLocation();
resolveTextures.add(ModelLoaderRegistry.getActualLocation(loc));
locations.add(loc);
IModel model = new WeightedPartWrapper(getModel(loc));
models.add(model);
builder.put(model, new TRSRTransformation(v.getRotation()));
if(v.isUvLocked()) uvLocked.add(ModelLoaderRegistry.getActualLocation(loc));
}
defaultState = new MapModelState(builder.build());
}
public Collection<ResourceLocation> getDependencies()
{
return ImmutableList.copyOf(locations);
}
public Collection<ResourceLocation> getTextures()
{
/*ImmutableSet.Builder<ResourceLocation> builder = ImmutableSet.builder();
for(ResourceLocation loc : locations)
{
builder.addAll(getModel(loc).getTextures());
}
return builder.build();*/
return Collections.emptyList();
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
if(!Attributes.moreSpecific(format, Attributes.DEFAULT_BAKED_FORMAT))
{
throw new IllegalArgumentException("can't bake vanilla weighted models to the format that doesn't fit into the default one: " + format);
}
if(variants.size() == 1)
{
Variant v = variants.get(0);
IModel model = models.get(0);
return model.bake(state.apply(model), format, bakedTextureGetter);
}
WeightedBakedModel.Builder builder = new WeightedBakedModel.Builder();
for(int i = 0; i < variants.size(); i++)
{
IModel model = models.get(i);
builder.add(model.bake(state.apply(model), format, bakedTextureGetter), variants.get(i).getWeight());
}
return new IFlexibleBakedModel.Wrapper(builder.build(), Attributes.DEFAULT_BAKED_FORMAT);
}
public IModelState getDefaultState()
{
return defaultState;
}
}
private boolean isBuiltinModel(ModelBlock model)
{
return model == MODEL_GENERATED || model == MODEL_COMPASS || model == MODEL_CLOCK || model == MODEL_ENTITY;
}
public IModel getMissingModel()
{
return getModel(new ResourceLocation(MODEL_MISSING.getResourceDomain(), MODEL_MISSING.getResourcePath()));
}
static enum VanillaLoader implements ICustomModelLoader
{
instance;
private ModelLoader loader;
void setLoader(ModelLoader loader)
{
this.loader = loader;
}
ModelLoader getLoader()
{
return loader;
}
public void onResourceManagerReload(IResourceManager resourceManager)
{
// do nothing, cause loader will store the reference to the resourceManager
}
public boolean accepts(ResourceLocation modelLocation)
{
return true;
}
public IModel loadModel(ResourceLocation modelLocation)
{
try
{
return loader.new VanillaModelWrapper(modelLocation, loader.loadModel(modelLocation));
}
catch(IOException e)
{
FMLLog.log(Level.ERROR, e, "Exception loading model %s with vanilla loader, skipping", modelLocation);
return loader.getMissingModel();
}
}
}
}
@@ -0,0 +1,112 @@
package net.minecraftforge.client.model;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader.VanillaLoader;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.Level;
/*
* Central hub for custom model loaders.
*/
public class ModelLoaderRegistry
{
private static final Set<ICustomModelLoader> loaders = new HashSet<ICustomModelLoader>();
private static final Map<ResourceLocation, IModel> cache = new HashMap<ResourceLocation, IModel>();
/*
* Makes system aware of your loader.
*/
public static void registerLoader(ICustomModelLoader loader)
{
loaders.add(loader);
((IReloadableResourceManager)Minecraft.getMinecraft().getResourceManager()).registerReloadListener(new IResourceManagerReloadListener()
{
public void onResourceManagerReload(IResourceManager manager)
{
for(ICustomModelLoader loader : loaders) loader.onResourceManagerReload(manager);
}
});
}
public static boolean loaded(ResourceLocation location)
{
return cache.containsKey(location);
}
public static ResourceLocation getActualLocation(ResourceLocation location)
{
if(location.getResourcePath().startsWith("builtin/")) return location;
return new ResourceLocation(location.getResourceDomain(), "models/" + location.getResourcePath());
}
public static IModel getModel(ResourceLocation location)
{
ResourceLocation actual = getActualLocation(location);
if(cache.containsKey(location)) return cache.get(location);
ICustomModelLoader accepted = null;
for(ICustomModelLoader loader : loaders)
{
try
{
if(loader.accepts(actual))
{
if(accepted != null)
{
FMLLog.severe("2 loaders (%s and %s) want to load the same model %s", accepted, loader, location);
throw new IllegalStateException("2 loaders want to load the same model");
}
accepted = loader;
}
}
catch(Exception e)
{
FMLLog.log(Level.ERROR, e, "Exception checking if model %s can be loaded with loader %s, skipping", location, loader);
}
}
// no custom loaders found, try vanilla one
if(accepted == null)
{
if(VanillaLoader.instance.accepts(actual)) accepted = VanillaLoader.instance;
}
IModel model;
if(accepted == null)
{
FMLLog.severe("no suitable loader found for the model %s, skipping", location);
model = getMissingModel();
}
else try
{
model = accepted.loadModel(actual);
}
catch(Exception e)
{
FMLLog.log(Level.ERROR, e, "Exception loading model %s with loader %s, skipping", location, accepted);
model = getMissingModel();
}
cache.put(location, model);
return model;
}
public static IModel getMissingModel()
{
return ModelLoader.VanillaLoader.instance.getLoader().getMissingModel();
}
public static void clearModelCache()
{
cache.clear();
}
}
@@ -0,0 +1,445 @@
package net.minecraftforge.client.model;
import javax.vecmath.Matrix3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3f;
import javax.vecmath.Vector4f;
import net.minecraft.client.renderer.block.model.ItemTransformVec3f;
import net.minecraft.client.resources.model.ModelRotation;
import net.minecraft.util.EnumFacing;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
/*
* Interpolation-friendly affine transformation.
* If created with matrix, should successfully decompose it to a composition
* of easily interpolatable transformations (translation, first rotation, scale
* (with generally speaking different factors for each axis) and second rotation.
* If the inpit matrix is a composition of translation, rotation and scale (in
* any order), then the interpolation of the derived primitive transformations
* should result in the same transformation as the interpolation of the originals.
* Decomposition happens lazily (and is hopefully fast enough), so performance
* should be comparable to using Matrix4f directly.
* Immutable.
*/
public class TRSRTransformation implements IModelState, ITransformation
{
private final Matrix4f matrix;
private boolean full;
private Vector3f translation;
private Quat4f leftRot;
private Vector3f scale;
private Quat4f rightRot;
public TRSRTransformation(Matrix4f matrix)
{
this.matrix = matrix;
}
public TRSRTransformation(Vector3f translation, Quat4f leftRot, Vector3f scale, Quat4f rightRot)
{
this.matrix = mul(translation, leftRot, scale, rightRot);
this.translation = translation != null ? translation : new Vector3f();
this.leftRot = leftRot != null ? leftRot : new Quat4f(0, 0, 0, 1);
this.scale = scale != null ? scale : new Vector3f(1, 1, 1);
this.rightRot = rightRot!= null ? rightRot : new Quat4f(0, 0, 0, 1);
full = true;
}
public TRSRTransformation(ItemTransformVec3f transform)
{
this(transform.translation, quatFromYXZ(transform.rotation), transform.scale, null);
}
public TRSRTransformation(ModelRotation rotation)
{
this(new Matrix4f(rotation.getMatrix4d()));
}
private static final TRSRTransformation identity;
static
{
Matrix4f m = new Matrix4f();
m.setIdentity();
identity = new TRSRTransformation(m);
identity.getLeftRot();
}
public static TRSRTransformation identity()
{
return identity;
}
public TRSRTransformation compose(TRSRTransformation b)
{
Matrix4f m = getMatrix();
m.mul(b.getMatrix());
return new TRSRTransformation(m);
}
private void genCheck()
{
if(!full)
{
Pair<Matrix3f, Vector3f> pair = toAffine(matrix);
Triple<Quat4f, Vector3f, Quat4f> triple = svdDecompose(pair.getLeft());
this.translation = pair.getRight();
this.leftRot = triple.getLeft();
this.scale = triple.getMiddle();
this.rightRot = triple.getRight();
full = true;
}
}
public static Quat4f quatFromYXZ(Vector3f yxz)
{
return quatFromYXZ(yxz.y, yxz.x, yxz.z);
}
public static Quat4f quatFromYXZ(float y, float x, float z)
{
Quat4f ret = new Quat4f(0, 0, 0, 1), t = new Quat4f();
t.set(0, (float)Math.sin(y/2), 0, (float)Math.cos(y/2));
ret.mul(t);
t.set((float)Math.sin(x/2), 0, 0, (float)Math.cos(x/2));
ret.mul(t);
t.set(0, 0, (float)Math.sin(z/2), (float)Math.cos(z/2));
ret.mul(t);
return ret;
}
public static Vector3f toYXZ(Quat4f q)
{
float w2 = q.w * q.w;
float x2 = q.x * q.x;
float y2 = q.y * q.y;
float z2 = q.z * q.z;
float l = w2 + x2 + y2 + z2;
float sx = 2 * q.y * q.z - 2 * q.w * q.x;
float x = (float)Math.asin(sx / l);
if(Math.abs(sx) > .999f * l)
{
return new Vector3f(
2 * (float)Math.atan2(q.y, q.w),
x,
0
);
}
return new Vector3f(
(float)Math.atan2(2 * q.x * q.z + 2 * q.y * q.w, w2 - x2 - y2 + z2),
x,
(float)Math.atan2(2 * q.x * q.y + 2 * q.w * q.z, w2 - x2 + y2 - z2)
);
}
public static Matrix4f mul(Vector3f translation, Quat4f leftRot, Vector3f scale, Quat4f rightRot)
{
Matrix4f res = new Matrix4f(), t = new Matrix4f();
res.setIdentity();
if(translation != null) res.setTranslation(translation);
if(leftRot != null)
{
t.set(leftRot);
res.mul(t);
}
if(scale != null)
{
t.setIdentity();
t.m00 = scale.x;
t.m11 = scale.y;
t.m22 = scale.z;
res.mul(t);
}
if(rightRot != null)
{
t.set(rightRot);
res.mul(t);
}
return res;
}
/*
* Performs SVD decomposition of m, accumulating reflection in the scale (U and V are pure rotations).
*/
public static Triple<Quat4f, Vector3f, Quat4f> svdDecompose(Matrix3f m)
{
// determine V by doing 5 steps of Jacobi iteration on MT * M
Quat4f u = new Quat4f(0, 0, 0, 1), v = new Quat4f(0, 0, 0, 1), qt = new Quat4f();
Matrix3f b = new Matrix3f(m), t = new Matrix3f();
t.transpose(m);
b.mul(t, b);
for(int i = 0; i < 5; i++) v.mul(stepJacobi(b));
v.normalize();
t.set(v);
b.set(m);
b.mul(t);
sortSingularValues(b, v);
Pair<Float, Float> p;
float ul = 1f;
p = qrGivensQuat(b.m00, b.m10);
qt.set(0, 0, p.getLeft(), p.getRight());
u.mul(qt);
t.setIdentity();
t.m00 = qt.w * qt.w - qt.z * qt.z;
t.m11 = t.m00;
t.m10 = -2 * qt.z * qt.w;
t.m01 = -t.m10;
t.m22 = qt.w * qt.w + qt.z * qt.z;
ul *= t.m22;
b.mul(t, b);
p = qrGivensQuat(b.m00, b.m20);
qt.set(0, -p.getLeft(), 0, p.getRight());
u.mul(qt);
t.setIdentity();
t.m00 = qt.w * qt.w - qt.y * qt.y;
t.m22 = t.m00;
t.m20 = 2 * qt.y * qt.w;
t.m02 = -t.m20;
t.m11 = qt.w * qt.w + qt.y * qt.y;
ul *= t.m11;
b.mul(t, b);
p = qrGivensQuat(b.m11, b.m21);
qt.set(p.getLeft(), 0, 0, p.getRight());
u.mul(qt);
t.setIdentity();
t.m11 = qt.w * qt.w - qt.x * qt.x;
t.m22 = t.m11;
t.m21 = -2 * qt.x * qt.w;
t.m12 = -t.m21;
t.m00 = qt.w * qt.w + qt.x * qt.x;
ul *= t.m00;
b.mul(t, b);
ul = 1f / ul;
u.scale((float)Math.sqrt(ul));
Vector3f s = new Vector3f(b.m00 * ul, b.m11 * ul, b.m22 * ul);
return Triple.of(u, s, v);
}
private static float rsqrt(float f)
{
float f2 = .5f * f;
int i = Float.floatToIntBits(f);
i = 0x5f3759df - (i >> 1);
f = Float.intBitsToFloat(i);
f *= 1.5f - f2 * f * f;
return f;
}
private static final float eps = 1e-7f;
private static final float g = 3f + 2f * (float)Math.sqrt(2);
private static final float cs = (float)Math.cos(Math.PI / 8);
private static final float ss = (float)Math.sin(Math.PI / 8);
private static final float sq2 = 1f / (float)Math.sqrt(2);
private static Pair<Float, Float> approxGivensQuat(float a11, float a12, float a22)
{
float ch = 2f * (a11 - a22);
float sh = a12;
boolean b = g * sh * sh < ch * ch;
float w = rsqrt(sh * sh + ch * ch);
ch = b ? w * ch : cs;
sh = b ? w * sh : ss;
return Pair.of(sh, ch);
}
private static final void swapNeg(Matrix3f m, int i, int j)
{
float[] t = new float[3];
m.getColumn(j, t);
for(int k = 0; k < 3; k++)
{
m.setElement(k, j, -m.getElement(k, i));
}
m.setColumn(i, t);
}
private static void sortSingularValues(Matrix3f b, Quat4f v)
{
float p0 = b.m00 * b.m00 + b.m10 * b.m10 + b.m20 * b.m20;
float p1 = b.m01 * b.m01 + b.m11 * b.m11 + b.m21 * b.m21;
float p2 = b.m02 * b.m02 + b.m12 * b.m12 + b.m22 * b.m22;
Quat4f t = new Quat4f();
if(p0 < p1)
{
swapNeg(b, 0, 1);
t.set(0, 0, sq2, sq2);
v.mul(t);
float f = p0;
p0 = p1;
p1 = f;
}
if(p0 < p2)
{
swapNeg(b, 0, 2);
t.set(0, sq2, 0, sq2);
v.mul(t);
float f = p0;
p0 = p2;
p2 = f;
}
if(p1 < p2)
{
swapNeg(b, 1, 2);
t.set(sq2, 0, 0, sq2);
v.mul(t);
}
}
private static Pair<Float, Float> qrGivensQuat(float a1, float a2)
{
float p = (float)Math.sqrt(a1 * a1 + a2 * a2);
float sh = p > eps ? a2 : 0;
float ch = Math.abs(a1) + Math.max(p, eps);
if(a1 < 0)
{
float f = sh;
sh = ch;
ch = f;
}
//float w = 1.f / (float)Math.sqrt(ch * ch + sh * sh);
float w = rsqrt(ch * ch + sh * sh);
ch *= w;
sh *= w;
return Pair.of(sh, ch);
}
private static Quat4f stepJacobi(Matrix3f m)
{
Matrix3f t = new Matrix3f();
Quat4f qt = new Quat4f(), ret = new Quat4f(0, 0, 0, 1);
Pair<Float, Float> p;
// 01
p = approxGivensQuat(m.m00, .5f * (m.m01 + m.m10), m.m11);
qt.set(0, 0, p.getLeft(), p.getRight());
//qt.normalize();
ret.mul(qt);
//t.set(qt);
t.setIdentity();
t.m00 = qt.w * qt.w - qt.z * qt.z;
t.m11 = t.m00;
t.m10 = 2 * qt.z * qt.w;
t.m01 = -t.m10;
t.m22 = qt.w * qt.w + qt.z * qt.z;
m.mul(m, t);
t.transpose();
m.mul(t, m);
// 02
p = approxGivensQuat(m.m00, .5f * (m.m02 + m.m20), m.m22);
qt.set(0, -p.getLeft(), 0, p.getRight());
//qt.normalize();
ret.mul(qt);
//t.set(qt);
t.setIdentity();
t.m00 = qt.w * qt.w - qt.y * qt.y;
t.m22 = t.m00;
t.m20 = -2 * qt.y * qt.w;
t.m02 = -t.m20;
t.m11 = qt.w * qt.w + qt.y * qt.y;
m.mul(m, t);
t.transpose();
m.mul(t, m);
// 12
p = approxGivensQuat(m.m11, .5f * (m.m12 + m.m21), m.m22);
qt.set(p.getLeft(), 0, 0, p.getRight());
//qt.normalize();
ret.mul(qt);
//t.set(qt);
t.setIdentity();
t.m11 = qt.w * qt.w - qt.x * qt.x;
t.m22 = t.m11;
t.m21 = 2 * qt.x * qt.w;
t.m12 = -t.m21;
t.m00 = qt.w * qt.w + qt.x * qt.x;
m.mul(m, t);
t.transpose();
m.mul(t, m);
return ret;
}
/*
* Divides m by m33, sets last row to (0, 0, 0, 1), extracts linear and translation parts
*/
public static Pair<Matrix3f, Vector3f> toAffine(Matrix4f m)
{
m.mul(1.f / m.m33);
Vector3f trans = new Vector3f(m.m03, m.m13, m.m23);
Matrix3f linear = new Matrix3f(m.m00, m.m01, m.m02, m.m10, m.m11, m.m12, m.m20, m.m21, m.m22);
return Pair.of(linear, trans);
}
/*
* Don't use this if you don't need to, conversion is lossy (second rotation component is lost).
*/
public ItemTransformVec3f toItemTransform()
{
return new ItemTransformVec3f(getTranslation(), toYXZ(getLeftRot()), getScale());
}
public Matrix4f getMatrix()
{
return (Matrix4f)matrix.clone();
}
public Vector3f getTranslation()
{
genCheck();
return (Vector3f)translation.clone();
}
public Quat4f getLeftRot()
{
genCheck();
return (Quat4f)leftRot.clone();
}
public Vector3f getScale()
{
genCheck();
return (Vector3f)scale.clone();
}
public Quat4f getRightRot()
{
genCheck();
return (Quat4f)rightRot.clone();
}
public TRSRTransformation apply(IModelPart part)
{
return this;
}
public EnumFacing rotate(EnumFacing facing)
{
return rotate(matrix, facing);
}
public static EnumFacing rotate(Matrix4f matrix, EnumFacing facing)
{
Vector4f vec = new Vector4f(facing.getDirectionVec().getX(), facing.getDirectionVec().getY(), facing.getDirectionVec().getZ(), 1);
matrix.transform(vec);
return EnumFacing.getFacingFromVector(vec.x / vec.w, vec.y / vec.w, vec.z / vec.w);
}
public int rotate(EnumFacing facing, int vertexIndex)
{
// FIXME check if this is good enough
return vertexIndex;
}
}
@@ -0,0 +1,607 @@
package net.minecraftforge.client.model.b3d;
import static net.minecraftforge.client.model.b3d.B3DModel.logger;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.vecmath.Matrix4f;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.resources.IResource;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.Attributes;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IFlexibleBakedModel;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.IModelPart;
import net.minecraftforge.client.model.IModelState;
import net.minecraftforge.client.model.ISmartBlockModel;
import net.minecraftforge.client.model.ISmartItemModel;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.TRSRTransformation;
import net.minecraftforge.client.model.b3d.B3DModel.Animation;
import net.minecraftforge.client.model.b3d.B3DModel.Bone;
import net.minecraftforge.client.model.b3d.B3DModel.Face;
import net.minecraftforge.client.model.b3d.B3DModel.IKind;
import net.minecraftforge.client.model.b3d.B3DModel.Key;
import net.minecraftforge.client.model.b3d.B3DModel.Mesh;
import net.minecraftforge.client.model.b3d.B3DModel.Node;
import net.minecraftforge.client.model.b3d.B3DModel.Texture;
import net.minecraftforge.client.model.b3d.B3DModel.Vertex;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.apache.logging.log4j.Level;
import org.lwjgl.BufferUtils;
import com.google.common.base.Function;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
/*
* Loader for Blitz3D models.
* To enable for your mod call instance.addDomain(modid).
* If you need more control over accepted resources - extend the class, and register a new instance with ModelLoaderRegistry.
*/
public class B3DLoader implements ICustomModelLoader
{
public static final B3DLoader instance = new B3DLoader();
private IResourceManager manager;
private final Set<String> enabledDomains = new HashSet<String>();
private final Map<ResourceLocation, B3DModel> cache = new HashMap<ResourceLocation, B3DModel>();
public B3DLoader()
{
ModelLoaderRegistry.registerLoader(this);
}
public void addDomain(String domain)
{
enabledDomains.add(domain.toLowerCase());
}
public void onResourceManagerReload(IResourceManager manager)
{
this.manager = manager;
cache.clear();
}
public boolean accepts(ResourceLocation modelLocation)
{
return enabledDomains.contains(modelLocation.getResourceDomain()) && modelLocation.getResourcePath().endsWith(".b3d");
}
@SuppressWarnings("unchecked")
public IModel loadModel(ResourceLocation modelLocation)
{
ResourceLocation file = new ResourceLocation(modelLocation.getResourceDomain(), modelLocation.getResourcePath());
if(!cache.containsKey(file))
{
try
{
IResource resource = null;
try
{
resource = manager.getResource(file);
}
catch(FileNotFoundException e)
{
if(modelLocation.getResourcePath().startsWith("models/block/"))
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/item/" + file.getResourcePath().substring("models/block/".length())));
else if(modelLocation.getResourcePath().startsWith("models/item/"))
resource = manager.getResource(new ResourceLocation(file.getResourceDomain(), "models/block/" + file.getResourcePath().substring("models/item/".length())));
else throw e;
}
B3DModel.Parser parser = new B3DModel.Parser(resource.getInputStream());
B3DModel model = parser.parse();
cache.put(modelLocation, model);
}
catch(IOException e)
{
FMLLog.log(Level.ERROR, e, "Exception loading model %s with B3D loader, skipping", modelLocation);
cache.put(modelLocation, null);
}
}
B3DModel model = cache.get(file);
if(model == null) return ModelLoaderRegistry.getMissingModel();
if(modelLocation instanceof B3DMeshLocation)
{
String mesh = ((B3DMeshLocation)modelLocation).getMesh();
if(!model.getMeshes().containsKey(mesh))
{
FMLLog.severe("No mesh named %s in model %s, skipping", mesh, modelLocation);
return ModelLoaderRegistry.getMissingModel();
}
return new Wrapper(modelLocation, model.getTextures(), model.getMeshes().get(mesh));
}
if(!(model.getRoot().getKind() instanceof Mesh))
{
FMLLog.severe("No root mesh in model %s and no mesh name in location, skipping", modelLocation);
return ModelLoaderRegistry.getMissingModel();
}
return new Wrapper(modelLocation, model.getTextures(), (Node<Mesh>)model.getRoot());
}
public static class B3DMeshLocation extends ResourceLocation
{
public final String mesh;
public B3DMeshLocation(String domain, String path, String mesh)
{
super(domain, path);
this.mesh = mesh;
}
public String getMesh()
{
return mesh;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((mesh == null) ? 0 : mesh.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (!super.equals(obj)) return false;
if (getClass() != obj.getClass()) return false;
B3DMeshLocation other = (B3DMeshLocation) obj;
if (mesh == null)
{
if (other.mesh != null) return false;
}
else if (!mesh.equals(other.mesh)) return false;
return true;
}
}
public static class B3DState implements IModelState
{
private final Animation animation;
private final int frame;
public B3DState(Animation animation, int frame)
{
this.animation = animation;
this.frame = frame;
}
public Animation getAnimation()
{
return animation;
}
public int getFrame()
{
return frame;
}
public TRSRTransformation apply(IModelPart part)
{
if(!(part instanceof PartWrapper<?>))
{
throw new IllegalArgumentException("B3DState can only be applied to b3d models");
}
return getNodeMatrix(((PartWrapper<?>)part).getNode());
}
private static LoadingCache<Triple<Animation, Node<?>, Integer>, TRSRTransformation> cache = CacheBuilder.newBuilder()
.maximumSize(16384)
.expireAfterAccess(2, TimeUnit.MINUTES)
.build(new CacheLoader<Triple<Animation, Node<?>, Integer>, TRSRTransformation>()
{
public TRSRTransformation load(Triple<Animation, Node<?>, Integer> key) throws Exception
{
return getNodeMatrix(key.getLeft(), key.getMiddle(), key.getRight());
}
});
public TRSRTransformation getNodeMatrix(Node<?> node)
{
return cache.getUnchecked(Triple.<Animation, Node<?>, Integer>of(animation, node, frame));
}
public static TRSRTransformation getNodeMatrix(Animation animation, Node<?> node, int frame)
{
TRSRTransformation ret = TRSRTransformation.identity();
Key key = null;
if(animation != null) key = animation.getKeys().get(frame, node);
else if(key == null && node.getAnimation() != null && node.getAnimation() != animation) key = node.getAnimation().getKeys().get(frame, node);
if(key == null)
{
FMLLog.severe("invalid key index: " + frame);
logger.debug(String.format("getMatrix: %s %s\n%s %s %s\n%s", frame, node, node.getPos(), node.getScale(), node.getRot(), ret));
}
else
{
ret = ret.compose(new TRSRTransformation(key.getPos(), key.getRot(), key.getScale(), null));
Matrix4f rm = new TRSRTransformation(node.getPos(), node.getRot(), node.getScale(), null).getMatrix();
rm.invert();
ret = ret.compose(new TRSRTransformation(rm));
logger.debug(String.format("getMatrix: %s %s\n%s %s %s\n%s %s %s\n%s", frame, node, node.getPos(), node.getScale(), node.getRot(), key.getPos(), key.getScale(), key.getRot(), ret));
}
return ret;
}
}
public static enum B3DFrameProperty implements IUnlistedProperty<B3DState>
{
instance;
public String getName()
{
return "B3DFrame";
}
public boolean isValid(B3DState value)
{
return value instanceof B3DState;
}
public Class<B3DState> getType()
{
return B3DState.class;
}
public String valueToString(B3DState value)
{
return value.toString();
}
}
public static class PartWrapper<K extends IKind<K>> implements IModelPart
{
private final Node<K> node;
public static <K extends IKind<K>> PartWrapper<K> create(Node<K> node)
{
return new PartWrapper<K>(node);
}
public PartWrapper(Node<K> node)
{
this.node = node;
}
public Node<K> getNode()
{
return node;
}
}
public static class Wrapper extends PartWrapper<Mesh> implements IModel
{
private final ResourceLocation location;
private final ImmutableMap<String, ResourceLocation> textures;
public Wrapper(ResourceLocation location, List<Texture> textures, B3DModel.Node<Mesh> mesh)
{
this(location, buildTextures(location, textures), mesh);
}
public Wrapper(ResourceLocation location, ImmutableMap<String, ResourceLocation> textures, B3DModel.Node<Mesh> mesh)
{
super(mesh);
this.location = location;
this.textures = textures;
}
private static ImmutableMap<String, ResourceLocation> buildTextures(ResourceLocation location, List<Texture> textures)
{
ImmutableMap.Builder<String, ResourceLocation> builder = ImmutableMap.builder();
for(Texture t : textures)
{
String path = t.getPath();
if(path.endsWith(".png")) path = path.substring(0, path.length() - ".png".length());
builder.put(t.getPath(), new ResourceLocation(location.getResourceDomain(), path));
System.out.println("Texture: " + path);
}
return builder.build();
}
public Collection<ResourceLocation> getDependencies()
{
// no dependencies for in-file models
// FIXME maybe add child meshes
return Collections.emptyList();
}
public Collection<ResourceLocation> getTextures()
{
return textures.values();
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
ImmutableMap.Builder<String, TextureAtlasSprite> builder = ImmutableMap.builder();
for(String path : textures.keySet())
{
builder.put(path, bakedTextureGetter.apply(textures.get(path)));
}
builder.put("missingno", bakedTextureGetter.apply(new ResourceLocation("missingno")));
return new BakedWrapper(this, state, format, builder.build());
}
public B3DState getDefaultState()
{
return new B3DState(getNode().getAnimation(), 1);
}
public ResourceLocation getLocation()
{
return location;
}
public ImmutableMap<String, ResourceLocation> getTextureMap()
{
return textures;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((location == null) ? 0 : location.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Wrapper other = (Wrapper) obj;
if (location == null)
{
if (other.location != null) return false;
}
else if (!location.equals(other.location)) return false;
return true;
}
}
private static class BakedWrapper implements IFlexibleBakedModel, ISmartBlockModel, ISmartItemModel
{
private final B3DLoader.Wrapper model;
private final IModelState state;
private final VertexFormat format;
private final ImmutableMap<String, TextureAtlasSprite> textures;
private final ByteBuffer buf;
private ImmutableList<BakedQuad> quads;
private static final int BYTES_IN_INT = Integer.SIZE / Byte.SIZE;
private static final int VERTICES_IN_QUAD = 4;
public BakedWrapper(B3DLoader.Wrapper model, IModelState state, VertexFormat format, ImmutableMap<String, TextureAtlasSprite> textures)
{
this.model = model;
this.state = state;
this.format = format;
this.textures = textures;
buf = BufferUtils.createByteBuffer(VERTICES_IN_QUAD * format.getNextOffset());
}
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return Collections.emptyList();
}
@SuppressWarnings("unchecked")
public List<BakedQuad> getGeneralQuads()
{
if(quads == null)
{
Node<Mesh> mesh = model.getNode();
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
for(Node<?> child : mesh.getNodes().values())
{
if(child.getKind() instanceof Mesh)
{
Node<Mesh> childMesh = (Node<Mesh>)child;
builder.addAll(new BakedWrapper(new B3DLoader.Wrapper(model.getLocation(), model.getTextureMap(), childMesh), state, format, textures).getGeneralQuads());
}
}
Multimap<Vertex, Pair<Float, Node<Bone>>> weightMap = mesh.getKind().getWeightMap();
Collection<Face> faces = mesh.getKind().getFaces();
faces = mesh.getKind().bake(new Function<Node<?>, Matrix4f>()
{
// gets transformation in global space
public Matrix4f apply(Node<?> node)
{
TRSRTransformation ret = TRSRTransformation.identity(), pm = null;
if(node.getParent() != null) pm = new TRSRTransformation(apply(node.getParent()));
if(pm != null)
{
ret = ret.compose(pm);
}
ret = ret.compose(state.apply(PartWrapper.create(node)));
return ret.getMatrix();
}
});
for(Face f : faces)
{
buf.clear();
List<Texture> textures = f.getBrush().getTextures();
TextureAtlasSprite sprite;
if(textures.isEmpty()) sprite = this.textures.get("missingno");
else sprite = this.textures.get(textures.get(0).getPath());
putVertexData(f.getV1(), sprite);
putVertexData(f.getV2(), sprite);
putVertexData(f.getV3(), sprite);
putVertexData(f.getV3(), sprite);
buf.flip();
int[] data = new int[VERTICES_IN_QUAD * format.getNextOffset() / BYTES_IN_INT];
buf.asIntBuffer().get(data);
builder.add(new BakedQuad(data, -1, EnumFacing.getFacingFromVector(f.getNormal().x, f.getNormal().y, f.getNormal().z)));
}
quads = builder.build();
}
return quads;
}
private void put(VertexFormatElement e, Number... ns)
{
Attributes.put(buf, e, true, 0, ns);
}
@SuppressWarnings("unchecked")
private final void putVertexData(Vertex v, TextureAtlasSprite sprite)
{
// TODO handle everything not handled (texture transformations, bones, transformations, normals, e.t.c)
int oldPos = buf.position();
Number[] ns = new Number[16];
for(int i = 0; i < ns.length; i++) ns[i] = 0f;
for(VertexFormatElement e : (List<VertexFormatElement>)format.getElements())
{
switch(e.getUsage())
{
case POSITION:
put(e, v.getPos().x, v.getPos().y, v.getPos().z, 1);
break;
case COLOR:
if(v.getColor() != null)
{
put(e, v.getColor().x, v.getColor().y, v.getColor().z, v.getColor().w);
}
else
{
put(e, 1, 1, 1, 0);
}
break;
case UV:
// TODO handle more brushes
if(e.getIndex() < v.getTexCoords().length)
{
put(e,
sprite.getInterpolatedU(v.getTexCoords()[0].x * 16),
sprite.getInterpolatedV(v.getTexCoords()[0].y * 16),
0,
1
);
}
else
{
put(e, 0, 0, 0, 1);
}
break;
case NORMAL:
// TODO
put(e, 0, 1, 0, 1);
break;
case GENERIC:
// TODO
put(e, 0, 0, 0, 1);
break;
default:
break;
}
}
buf.position(oldPos + format.getNextOffset());
}
public boolean isAmbientOcclusion()
{
return true;
}
public boolean isGui3d()
{
return true;
}
public boolean isBuiltInRenderer()
{
return false;
}
public TextureAtlasSprite getTexture()
{
// FIXME somehow specify particle texture in the model
return textures.values().asList().get(0);
}
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
@Override
public BakedWrapper handleBlockState(IBlockState state)
{
System.out.println("handleBlockState " + state);
if(state instanceof IExtendedBlockState)
{
IExtendedBlockState exState = (IExtendedBlockState)state;
if(exState.getUnlistedNames().contains(B3DFrameProperty.instance))
{
B3DState s = (B3DState)exState.getValue(B3DFrameProperty.instance);
if(s != null)
{
return getCachedModel(s.getFrame());
}
}
}
return this;
}
private final Map<Integer, BakedWrapper> cache = new HashMap<Integer, BakedWrapper>();
public BakedWrapper getCachedModel(int frame)
{
if(!cache.containsKey(frame))
{
cache.put(frame, new BakedWrapper(model, new B3DState(model.getNode().getAnimation(), frame), format, textures));
}
return cache.get(frame);
}
public VertexFormat getFormat()
{
return format;
}
public BakedWrapper handleItemState(ItemStack stack)
{
// TODO specify how to get B3DState from ItemStack
return this;
}
}
}
File diff suppressed because it is too large. Load diff
+7
View File
@@ -28,3 +28,10 @@ net/minecraft/item/ItemDye.applyBonemeal(Lnet/minecraft/item/ItemStack;Lnet/mine
net/minecraft/server/management/ItemInWorldManager.removeBlock(Lnet/minecraft/util/BlockPos;Z)Z=|p_180235_1_,canHarvest
net/minecraft/client/gui/GuiScreen.drawHoveringText(Ljava/util/List;IILnet/minecraft/client/gui/FontRenderer;)V=|p_146283_1_,p_146283_2_,p_146283_3_,font
net/minecraft/block/state/BlockState.<init>(Lnet/minecraft/block/Block;[Lnet/minecraft/block/properties/IProperty;Lcom/google/common/collect/ImmutableMap;)V=|p_i45663_1_,p_i45663_2_,unlistedProperties
net/minecraft/client/renderer/entity/RenderItem.applyVanillaTransform(Lnet/minecraft/client/renderer/block/model/ItemTransformVec3f;)V=|p_175034_1_
net/minecraft/client/resources/model/ModelBakery.bakeModel(Lnet/minecraft/client/renderer/block/model/ModelBlock;Lnet/minecraftforge/client/model/ITransformation;Z)Lnet/minecraft/client/resources/model/IBakedModel;=|p_177578_1_,p_177578_2_,p_177578_3_
net/minecraft/client/resources/model/ModelBakery.makeBakedQuad(Lnet/minecraft/client/renderer/block/model/BlockPart;Lnet/minecraft/client/renderer/block/model/BlockPartFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/util/EnumFacing;Lnet/minecraftforge/client/model/ITransformation;Z)Lnet/minecraft/client/renderer/block/model/BakedQuad;=|p_177589_1_,p_177589_2_,p_177589_3_,p_177589_4_,p_177589_5_,p_177589_6_
net/minecraft/client/renderer/block/model/FaceBakery.makeBakedQuad(Ljavax/vecmath/Vector3f;Ljavax/vecmath/Vector3f;Lnet/minecraft/client/renderer/block/model/BlockPartFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/util/EnumFacing;Lnet/minecraftforge/client/model/ITransformation;Lnet/minecraft/client/renderer/block/model/BlockPartRotation;ZZ)Lnet/minecraft/client/renderer/block/model/BakedQuad;=|p_178414_1_,p_178414_2_,p_178414_3_,p_178414_4_,p_178414_5_,p_178414_6_,p_178414_7_,p_178414_8_,p_178414_9_
net/minecraft/client/renderer/block/model/FaceBakery.makeQuadVertexData(Lnet/minecraft/client/renderer/block/model/BlockPartFace;Lnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraft/util/EnumFacing;[FLnet/minecraftforge/client/model/ITransformation;Lnet/minecraft/client/renderer/block/model/BlockPartRotation;ZZ)[I=|p_178405_1_,p_178405_2_,p_178405_3_,p_178405_4_,p_178405_5_,p_178405_6_,p_178405_7_,p_178405_8_
net/minecraft/client/renderer/block/model/FaceBakery.fillVertexData([IILnet/minecraft/util/EnumFacing;Lnet/minecraft/client/renderer/block/model/BlockPartFace;[FLnet/minecraft/client/renderer/texture/TextureAtlasSprite;Lnet/minecraftforge/client/model/ITransformation;Lnet/minecraft/client/renderer/block/model/BlockPartRotation;ZZ)V=|p_178402_1_,p_178402_2_,p_178402_3_,p_178402_4_,p_178402_5_,p_178402_6_,p_178402_7_,p_178402_8_,p_178402_9_,p_178402_10_
net/minecraft/client/renderer/block/model/FaceBakery.rotateVertex(Ljavax/vecmath/Vector3d;Lnet/minecraft/util/EnumFacing;ILnet/minecraftforge/client/model/ITransformation;Z)I=|p_178415_1_,p_178415_2_,p_178415_3_,p_178415_4_,p_178415_5_
+24
View File
@@ -123,3 +123,27 @@ public net.minecraft.item.crafting.RecipesBanners$RecipeDuplicatePattern
public net.minecraft.block.state.BlockState$StateImplementation
protected net.minecraft.block.state.BlockState$StateImplementation <init>(Lnet/minecraft/block/Block;Lcom/google/common/collect/ImmutableMap;)V
protected net.minecraft.block.state.BlockState$StateImplementation field_177238_c # propertyValueTable
public net.minecraft.client.renderer.block.model.ModelBlock field_178315_d # parent
protected net.minecraft.client.resources.model.ModelBakery field_177602_b # LOCATIONS_BUILTIN_TEXTURES
protected net.minecraft.client.resources.model.ModelBakery field_177598_f # resourceManager
protected net.minecraft.client.resources.model.ModelBakery field_177599_g # sprites
protected net.minecraft.client.resources.model.ModelBakery field_177609_j # textureMap
protected net.minecraft.client.resources.model.ModelBakery field_177610_k # blockModelShapes
protected net.minecraft.client.resources.model.ModelBakery field_177605_n # bakedRegistry
protected net.minecraft.client.resources.model.ModelBakery field_177606_o # MODEL_GENERATED
protected net.minecraft.client.resources.model.ModelBakery field_177618_p # MODEL_COMPASS
protected net.minecraft.client.resources.model.ModelBakery field_177617_q # MODEL_CLOCK
protected net.minecraft.client.resources.model.ModelBakery field_177616_r # MODEL_ENTITY
protected net.minecraft.client.resources.model.ModelBakery func_177591_a(Ljava/util/Collection;)V # loadVariants
protected net.minecraft.client.resources.model.ModelBakery func_177569_a(Lnet/minecraft/client/renderer/block/model/ModelBlockDefinition;Lnet/minecraft/client/resources/model/ModelResourceLocation;)V # registerVariant
protected net.minecraft.client.resources.model.ModelBakery func_177596_a(Lnet/minecraft/item/Item;)Ljava/util/List; # getVariantNames
protected net.minecraft.client.resources.model.ModelBakery func_177583_a(Ljava/lang/String;)Lnet/minecraft/util/ResourceLocation; # getItemLocation
protected net.minecraft.client.resources.model.ModelBakery func_177594_c(Lnet/minecraft/util/ResourceLocation;)Lnet/minecraft/client/renderer/block/model/ModelBlock; # loadModel
protected net.minecraft.client.resources.model.ModelBakery func_177592_e()V # registerVariantNames
protected net.minecraft.client.resources.model.ModelBakery func_177596_a(Lnet/minecraft/item/Item;)Ljava/util/List; # getVariantNames
protected net.minecraft.client.resources.model.ModelBakery func_177583_a(Ljava/lang/String;)Lnet/minecraft/util/ResourceLocation; # getItemLocation
protected net.minecraft.client.resources.model.ModelBakery func_177585_a(Lnet/minecraft/client/renderer/block/model/ModelBlock;)Ljava/util/Set; # getTextureLocations
protected net.minecraft.client.resources.model.ModelBakery func_177581_b(Lnet/minecraft/client/renderer/block/model/ModelBlock;)Z # hasItemModel
protected net.minecraft.client.resources.model.ModelBakery func_177587_c(Lnet/minecraft/client/renderer/block/model/ModelBlock;)Z # isCustomRenderer
protected net.minecraft.client.resources.model.ModelBakery func_177582_d(Lnet/minecraft/client/renderer/block/model/ModelBlock;)Lnet/minecraft/client/renderer/block/model/ModelBlock; # makeItemModel
protected net.minecraft.client.resources.model.ModelBakery func_177580_d(Lnet/minecraft/util/ResourceLocation;)Lnet/minecraft/util/ResourceLocation; # getModelLocation
@@ -0,0 +1,220 @@
package net.minecraftforge.debug;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.client.resources.model.ModelRotation;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.client.model.Attributes;
import net.minecraftforge.client.model.ICustomModelLoader;
import net.minecraftforge.client.model.IFlexibleBakedModel;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.client.model.IModelState;
import net.minecraftforge.client.model.ModelLoaderRegistry;
import net.minecraftforge.client.model.b3d.B3DLoader;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
import com.google.common.base.Function;
import com.google.common.primitives.Ints;
@Mod(modid = ModelLoaderRegistryDebug.MODID, version = ModelLoaderRegistryDebug.VERSION)
public class ModelLoaderRegistryDebug
{
public static final String MODID = "ForgeDebugModelLoaderRegistry";
public static final String VERSION = "1.0";
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
//ModelLoaderRegistry.registerLoader(DummyModelLoader.instance);
B3DLoader.instance.addDomain(MODID.toLowerCase());
GameRegistry.registerBlock(CustomModelBlock.instance, CustomModelBlock.name);
//ModelBakery.addVariantName(Item.getItemFromBlock(CustomModelBlock.instance), "forgedebug:dummymodel");
ModelBakery.addVariantName(Item.getItemFromBlock(CustomModelBlock.instance), MODID.toLowerCase() + ":untitled2.b3d");
}
@EventHandler
public void init(FMLInitializationEvent event)
{
Item item = Item.getItemFromBlock(CustomModelBlock.instance);
//Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation("forgedebug:dummymodel", "inventory"));
Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item, 0, new ModelResourceLocation(MODID.toLowerCase() + ":untitled2.b3d", "inventory"));
}
public static class CustomModelBlock extends Block
{
public static final CustomModelBlock instance = new CustomModelBlock();
public static final String name = "CustomModelBlock";
private int counter = 1;
private ExtendedBlockState state = new ExtendedBlockState(this, new IProperty[0], new IUnlistedProperty[]{ B3DLoader.B3DFrameProperty.instance });
private CustomModelBlock()
{
super(Material.iron);
setCreativeTab(CreativeTabs.tabBlock);
setUnlocalizedName(MODID + ":" + name);
}
@Override
public boolean isOpaqueCube() { return false; }
@Override
public boolean isFullCube() { return false; }
@Override
public boolean isVisuallyOpaque() { return false; }
@Override
public IBlockState getExtendedState(IBlockState state, IBlockAccess world, BlockPos pos)
{
IModel model = ModelLoaderRegistry.getModel(new ResourceLocation(MODID.toLowerCase(),"block/untitled2.b3d"));
B3DLoader.B3DState defaultState = ((B3DLoader.Wrapper)model).getDefaultState();
B3DLoader.B3DState newState = new B3DLoader.B3DState(defaultState.getAnimation(), counter);
return ((IExtendedBlockState)this.state.getBaseState()).withProperty(B3DLoader.B3DFrameProperty.instance, newState);
}
@Override
public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumFacing side, float hitX, float hitY, float hitZ)
{
if(world.isRemote)
{
System.out.println("click " + counter);
if(player.isSneaking()) counter--;
else counter++;
//if(counter >= model.getNode().getKeys().size()) counter = 0;
world.markBlockRangeForRenderUpdate(pos, pos);
}
return false;
}
}
public static class DummyModelLoader implements ICustomModelLoader
{
public static final DummyModelLoader instance = new DummyModelLoader();
public static final ResourceLocation dummyTexture = new ResourceLocation("minecraft:blocks/dirt");
public boolean accepts(ResourceLocation modelLocation)
{
return modelLocation.getResourceDomain().equals("forgedebug") && modelLocation.getResourcePath().contains("dummymodel");
}
public IModel loadModel(ResourceLocation model)
{
return DummyModel.instance;
}
public static enum DummyModel implements IModel
{
instance;
public Collection<ResourceLocation> getDependencies()
{
return Collections.emptyList();
}
public Collection<ResourceLocation> getTextures()
{
return Collections.singletonList(dummyTexture);
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> textures)
{
return new DummyBakedModel(textures.apply(dummyTexture));
}
public IModelState getDefaultState()
{
return ModelRotation.X0_Y0;
}
}
public static class DummyBakedModel implements IFlexibleBakedModel
{
private final TextureAtlasSprite texture;
public DummyBakedModel(TextureAtlasSprite texture)
{
this.texture = texture;
}
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return Collections.emptyList();
}
private int[] vertexToInts(float x, float y, float z, int color, float u, float v)
{
return new int[] {
Float.floatToRawIntBits(x),
Float.floatToRawIntBits(y),
Float.floatToRawIntBits(z),
color,
Float.floatToRawIntBits(texture.getInterpolatedU(u)),
Float.floatToRawIntBits(texture.getInterpolatedV(v)),
0
};
}
public List<BakedQuad> getGeneralQuads()
{
List<BakedQuad> ret = new ArrayList<BakedQuad>();
// 1 half-way rotated quad looking UP
ret.add(new BakedQuad(Ints.concat(
vertexToInts(0, .5f, .5f, -1, 0, 0),
vertexToInts(.5f, .5f, 1, -1, 0, 16),
vertexToInts(1, .5f, .5f, -1, 16, 16),
vertexToInts(.5f, .5f, 0, -1, 16, 0)
), -1, EnumFacing.UP));
return ret;
}
public boolean isGui3d() { return true; }
public boolean isAmbientOcclusion() { return true; }
public boolean isBuiltInRenderer() { return false; }
public TextureAtlasSprite getTexture() { return this.texture; }
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
public VertexFormat getFormat()
{
return Attributes.DEFAULT_BAKED_FORMAT;
}
}
public void onResourceManagerReload(IResourceManager resourceManager) {}
}
}
@@ -0,0 +1,5 @@
{
"variants": {
"normal" : { "model" : "forgedebugmodelloaderregistry:untitled2.b3d" }
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B