mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 00:07:45 +00:00
Merge pull request #1521 from RainWarrior/model-system
Model loader registry
This commit is contained in:
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_);
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -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);
|
||||
+18
@@ -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
@@ -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_
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"variants": {
|
||||
"normal" : { "model" : "forgedebugmodelloaderregistry:untitled2.b3d" }
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 168 B |
Reference in new issue
Block a user