Skip to content
Permalink
Browse files

Model animation system.

Main things of interest:
  * IAnimationStateMachine - state machine for animations; can load
    from json.
  * AnimationTESR - automatic TESR for animated models.
  * AnimationModelBase - same for entities.
  * ITimeValue - time-varying value, used to control animation
    parameters from code.

  * TESRs can now be batched - look at TESR.renderTileEntityFast +
    TE.hasFastRenderer.
  * RegionRenderCache is not accessible to TESRs and other client-side
    logic - MinecraftForgeClient.getRegionRenderCache.
  • Loading branch information...
RainWarrior committed Jan 1, 2016
1 parent e9a86f2 commit 0710bdf3f5a64e5fe1c725a30421b2c7523dca44
Showing with 3,182 additions and 249 deletions.
  1. +19 −7 patches/minecraft/net/minecraft/client/renderer/RenderGlobal.java.patch
  2. +8 −6 patches/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.java.patch
  3. +79 −0 patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java.patch
  4. +9 −0 patches/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java.patch
  5. +10 −1 patches/minecraft/net/minecraft/tileentity/TileEntity.java.patch
  6. +8 −6 src/main/java/net/minecraftforge/client/ForgeHooksClient.java
  7. +36 −0 src/main/java/net/minecraftforge/client/MinecraftForgeClient.java
  8. +67 −17 src/main/java/net/minecraftforge/client/model/ModelLoader.java
  9. +184 −0 src/main/java/net/minecraftforge/client/model/animation/Animation.java
  10. +108 −0 src/main/java/net/minecraftforge/client/model/animation/AnimationModelBase.java
  11. +169 −0 src/main/java/net/minecraftforge/client/model/animation/AnimationStateMachine.java
  12. +79 −0 src/main/java/net/minecraftforge/client/model/animation/AnimationTESR.java
  13. +538 −0 src/main/java/net/minecraftforge/client/model/animation/Clips.java
  14. +46 −0 src/main/java/net/minecraftforge/client/model/animation/Event.java
  15. +49 −0 src/main/java/net/minecraftforge/client/model/animation/FastTESR.java
  16. +13 −0 src/main/java/net/minecraftforge/client/model/animation/IAnimatedModel.java
  17. +12 −0 src/main/java/net/minecraftforge/client/model/animation/IAnimationProvider.java
  18. +12 −0 src/main/java/net/minecraftforge/client/model/animation/IClip.java
  19. +10 −0 src/main/java/net/minecraftforge/client/model/animation/IEventHandler.java
  20. +16 −0 src/main/java/net/minecraftforge/client/model/animation/IJoint.java
  21. +11 −0 src/main/java/net/minecraftforge/client/model/animation/IJointClip.java
  22. +12 −0 src/main/java/net/minecraftforge/client/model/animation/ITimeValue.java
  23. +36 −0 src/main/java/net/minecraftforge/client/model/animation/JointClips.java
  24. +509 −0 src/main/java/net/minecraftforge/client/model/animation/ModelBlockAnimation.java
  25. +370 −0 src/main/java/net/minecraftforge/client/model/animation/TimeValues.java
  26. +80 −0 src/main/java/net/minecraftforge/client/model/b3d/B3DClip.java
  27. +54 −14 src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java
  28. +30 −0 src/main/java/net/minecraftforge/client/model/b3d/B3DModel.java
  29. +64 −48 src/main/java/net/minecraftforge/client/model/pipeline/LightUtil.java
  30. +7 −3 src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterFlat.java
  31. +12 −9 src/main/java/net/minecraftforge/client/model/pipeline/VertexLighterSmoothAo.java
  32. +2 −4 src/main/java/net/minecraftforge/client/model/pipeline/WorldRendererConsumer.java
  33. +36 −0 src/main/java/net/minecraftforge/common/model/animation/IAnimationStateMachine.java
  34. +18 −0 src/main/java/net/minecraftforge/common/property/Properties.java
  35. +73 −0 src/main/java/net/minecraftforge/common/util/JsonUtils.java
  36. +3 −0 src/main/java/net/minecraftforge/fml/client/FMLClientHandler.java
  37. +214 −121 src/test/java/net/minecraftforge/debug/ModelAnimationDebug.java
  38. +64 −0 src/test/resources/assets/forgedebugmodelanimation/armatures/block/engine_ring.json
  39. +37 −0 src/test/resources/assets/forgedebugmodelanimation/asms/block/chest.json
  40. +26 −0 src/test/resources/assets/forgedebugmodelanimation/asms/block/engine.json
  41. +23 −0 src/test/resources/assets/forgedebugmodelanimation/asms/block/engine2.json
  42. +19 −9 src/test/resources/assets/forgedebugmodelanimation/blockstates/test_animation_block.json
  43. +2 −2 src/test/resources/assets/forgedebugmodelanimation/models/block/engine_ring.json
  44. +8 −2 src/test/resources/assets/forgedebugmodelloaderregistry/blockstates/CustomModelBlock.json
@@ -56,23 +56,35 @@
flag2 = this.field_175010_j.func_178635_a(entity2, p_180446_2_, d0, d1, d2) || entity2.field_70153_n == this.field_72777_q.field_71439_g;

if (!flag2)
@@ -662,6 +673,7 @@
@@ -654,6 +665,7 @@
this.field_72769_h.field_72984_F.func_76318_c("blockentities");
RenderHelper.func_74519_b();

+ TileEntityRendererDispatcher.field_147556_a.preDrawBatch();
for (RenderGlobal.ContainerLocalRenderInformation renderglobal$containerlocalrenderinformation1 : this.field_72755_R)
{
List<TileEntity> list1 = renderglobal$containerlocalrenderinformation1.field_178036_a.func_178571_g().func_178485_b();
@@ -662,6 +674,7 @@
{
for (TileEntity tileentity2 : list1)
{
+ if (!tileentity2.shouldRenderInPass(pass) || !p_180446_2_.func_78546_a(tileentity2.getRenderBoundingBox())) continue;
TileEntityRendererDispatcher.field_147556_a.func_180546_a(tileentity2, p_180446_3_, -1);
}
}
@@ -671,6 +683,7 @@
@@ -671,9 +684,11 @@
{
for (TileEntity tileentity : this.field_181024_n)
{
+ if (!tileentity.shouldRenderInPass(pass) || !p_180446_2_.func_78546_a(tileentity.getRenderBoundingBox())) continue;
TileEntityRendererDispatcher.field_147556_a.func_180546_a(tileentity, p_180446_3_, -1);
}
}
@@ -700,7 +713,7 @@
+ TileEntityRendererDispatcher.field_147556_a.drawBatch(pass);

this.func_180443_s();

@@ -700,7 +715,7 @@

Block block = this.field_72769_h.func_180495_p(blockpos).func_177230_c();

@@ -81,7 +93,7 @@
{
TileEntityRendererDispatcher.field_147556_a.func_180546_a(tileentity1, p_180446_3_, destroyblockprogress.func_73106_e());
}
@@ -1161,6 +1174,12 @@
@@ -1161,6 +1176,12 @@

public void func_174976_a(float p_174976_1_, int p_174976_2_)
{
@@ -94,7 +106,7 @@
if (this.field_72777_q.field_71441_e.field_73011_w.func_177502_q() == 1)
{
this.func_180448_r();
@@ -1378,6 +1397,12 @@
@@ -1378,6 +1399,12 @@

public void func_180447_b(float p_180447_1_, int p_180447_2_)
{
@@ -107,7 +119,7 @@
if (this.field_72777_q.field_71441_e.field_73011_w.func_76569_d())
{
if (this.field_72777_q.field_71474_y.func_181147_e() == 2)
@@ -1793,8 +1818,11 @@
@@ -1793,8 +1820,11 @@
double d4 = (double)blockpos.func_177956_o() - d1;
double d5 = (double)blockpos.func_177952_p() - d2;
Block block = this.field_72769_h.func_180495_p(blockpos).func_177230_c();
@@ -120,7 +132,7 @@
{
if (d3 * d3 + d4 * d4 + d5 * d5 > 1024.0D)
{
@@ -1949,13 +1977,16 @@
@@ -1949,13 +1979,16 @@
if (p_174961_1_ != null)
{
ItemRecord itemrecord = ItemRecord.func_150926_b(p_174961_1_);
@@ -1,15 +1,17 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/chunk/RenderChunk.java
@@ -131,7 +131,7 @@
@@ -131,7 +131,9 @@
return;
}

- iblockaccess = new RegionRenderCache(this.field_178588_d, blockpos.func_177982_a(-1, -1, -1), blockpos1.func_177982_a(1, 1, 1), 1);
+ iblockaccess = createRegionRenderCache(this.field_178588_d, blockpos.func_177982_a(-1, -1, -1), blockpos1.func_177982_a(1, 1, 1), 1);
+ RegionRenderCache cache = createRegionRenderCache(this.field_178588_d, blockpos.func_177982_a(-1, -1, -1), blockpos1.func_177982_a(1, 1, 1), 1);
+ net.minecraftforge.client.MinecraftForgeClient.onRebuildChunk(field_178588_d, field_178586_f, cache);
+ iblockaccess = cache;
p_178581_4_.func_178543_a(compiledchunk);
}
finally
@@ -158,7 +158,7 @@
@@ -158,7 +160,7 @@
lvt_10_1_.func_178606_a(blockpos$mutableblockpos);
}

@@ -18,7 +20,7 @@
{
TileEntity tileentity = iblockaccess.func_175625_s(new BlockPos(blockpos$mutableblockpos));
TileEntitySpecialRenderer<TileEntity> tileentityspecialrenderer = TileEntityRendererDispatcher.field_147556_a.<TileEntity>func_147547_b(tileentity);
@@ -174,7 +174,9 @@
@@ -174,7 +176,9 @@
}
}

@@ -29,15 +31,15 @@
int j = enumworldblocklayer1.ordinal();

if (block.func_149645_b() != -1)
@@ -189,6 +191,7 @@
@@ -189,6 +193,7 @@

aboolean[j] |= blockrendererdispatcher.func_175018_a(iblockstate, blockpos$mutableblockpos, iblockaccess, worldrenderer);
}
+ }
}

for (EnumWorldBlockLayer enumworldblocklayer : EnumWorldBlockLayer.values())
@@ -385,6 +388,26 @@
@@ -385,6 +390,26 @@
return this.field_178593_n;
}

@@ -0,0 +1,79 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/tileentity/TileEntityRendererDispatcher.java
@@ -102,11 +102,14 @@
{
if (p_180546_1_.func_145835_a(this.field_147560_j, this.field_147561_k, this.field_147558_l) < p_180546_1_.func_145833_n())
{
+ if(!p_180546_1_.hasFastRenderer())
+ {
int i = this.field_147550_f.func_175626_b(p_180546_1_.func_174877_v(), 0);
int j = i % 65536;
int k = i / 65536;
OpenGlHelper.func_77475_a(OpenGlHelper.field_77476_b, (float)j / 1.0F, (float)k / 1.0F);
GlStateManager.func_179131_c(1.0F, 1.0F, 1.0F, 1.0F);
+ }
BlockPos blockpos = p_180546_1_.func_174877_v();
this.func_178469_a(p_180546_1_, (double)blockpos.func_177958_n() - field_147554_b, (double)blockpos.func_177956_o() - field_147555_c, (double)blockpos.func_177952_p() - field_147552_d, p_180546_2_, p_180546_3_);
}
@@ -125,6 +128,11 @@
{
try
{
+ if(p_178469_1_.hasFastRenderer())
+ {
+ tileentityspecialrenderer.renderTileEntityFast(p_178469_1_, p_178469_2_, p_178469_4_, p_178469_6_, p_178469_8_, p_178469_9_, batchBuffer.func_178180_c());
+ }
+ else
tileentityspecialrenderer.func_180535_a(p_178469_1_, p_178469_2_, p_178469_4_, p_178469_6_, p_178469_8_, p_178469_9_);
}
catch (Throwable throwable)
@@ -146,4 +154,49 @@
{
return this.field_147557_n;
}
+
+ /* ======================================== FORGE START =====================================*/
+ /**
+ * Buffer used for batched TESRs
+ */
+ private net.minecraft.client.renderer.Tessellator batchBuffer = new net.minecraft.client.renderer.Tessellator(0x200000);
+
+ /**
+ * Prepare for a batched TESR rendering.
+ * You probably shouldn't call this manually.
+ */
+ public void preDrawBatch()
+ {
+ batchBuffer.func_178180_c().func_181668_a(org.lwjgl.opengl.GL11.GL_QUADS, net.minecraft.client.renderer.vertex.DefaultVertexFormats.field_176600_a);
+ }
+
+ /**
+ * Render all TESRs batched so far.
+ * You probably shouldn't call this manually.
+ */
+ public void drawBatch(int pass)
+ {
+ field_147553_e.func_110577_a(net.minecraft.client.renderer.texture.TextureMap.field_110575_b);
+ net.minecraft.client.renderer.RenderHelper.func_74518_a();
+ GlStateManager.func_179112_b(org.lwjgl.opengl.GL11.GL_SRC_ALPHA, org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA);
+ GlStateManager.func_179147_l();
+ GlStateManager.func_179129_p();
+
+ if (net.minecraft.client.Minecraft.func_71379_u())
+ {
+ GlStateManager.func_179103_j(org.lwjgl.opengl.GL11.GL_SMOOTH);
+ }
+ else
+ {
+ GlStateManager.func_179103_j(org.lwjgl.opengl.GL11.GL_FLAT);
+ }
+
+ if(pass > 0)
+ {
+ batchBuffer.func_178180_c().func_181674_a((float)field_147554_b, (float)field_147555_c, (float)field_147552_d);
+ }
+ batchBuffer.func_78381_a();
+
+ net.minecraft.client.renderer.RenderHelper.func_74519_b();
+ }
}
@@ -0,0 +1,9 @@
--- ../src-base/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java
+++ ../src-work/minecraft/net/minecraft/client/renderer/tileentity/TileEntitySpecialRenderer.java
@@ -45,4 +45,6 @@
{
return false;
}
+
+ public void renderTileEntityFast(T te, double x, double y, double z, float partialTicks, int destroyStage, net.minecraft.client.renderer.WorldRenderer worldRenderer) {}
}
@@ -65,7 +65,7 @@
public double func_145835_a(double p_145835_1_, double p_145835_3_, double p_145835_5_)
{
double d0 = (double)this.field_174879_c.func_177958_n() + 0.5D - p_145835_1_;
@@ -279,4 +293,176 @@
@@ -279,4 +293,185 @@
func_145826_a(TileEntityFlowerPot.class, "FlowerPot");
func_145826_a(TileEntityBanner.class, "Banner");
}
@@ -212,6 +212,15 @@
+ // NOOP
+ }
+
+ /**
+ * If the TileEntitySpecialRenderer associated with this TileEntity can be batched in with another renderers, and won't access the GL state.
+ * If TileEntity returns true, then TESR should have the same functionality as (and probably extend) the FastTESR class.
+ */
+ public boolean hasFastRenderer()
+ {
+ return false;
+ }
+
+ private net.minecraftforge.common.capabilities.CapabilityDispatcher capabilities;
+ public TileEntity()
+ {
@@ -412,36 +412,38 @@ public static void multiplyCurrentGlMatrix(Matrix4f matrix)
public static void preDraw(EnumUsage attrType, VertexFormat format, int element, int stride, ByteBuffer buffer)
{
VertexFormatElement attr = format.getElement(element);
int count = attr.getElementCount();
int constant = attr.getType().getGlConstant();
buffer.position(format.func_181720_d(element));
switch(attrType)
{
case POSITION:
glVertexPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glVertexPointer(count, constant, stride, buffer);
glEnableClientState(GL_VERTEX_ARRAY);
break;
case NORMAL:
if(attr.getElementCount() != 3)
if(count != 3)
{
throw new IllegalArgumentException("Normal attribute should have the size 3: " + attr);
}
glNormalPointer(attr.getType().getGlConstant(), stride, buffer);
glNormalPointer(constant, stride, buffer);
glEnableClientState(GL_NORMAL_ARRAY);
break;
case COLOR:
glColorPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glColorPointer(count, constant, stride, buffer);
glEnableClientState(GL_COLOR_ARRAY);
break;
case UV:
OpenGlHelper.setClientActiveTexture(OpenGlHelper.defaultTexUnit + attr.getIndex());
glTexCoordPointer(attr.getElementCount(), attr.getType().getGlConstant(), stride, buffer);
glTexCoordPointer(count, constant, 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);
glVertexAttribPointer(attr.getIndex(), count, constant, false, stride, buffer);
default:
FMLLog.severe("Unimplemented vanilla attribute upload: %s", attrType.getDisplayName());
}
@@ -6,7 +6,18 @@
package net.minecraftforge.client;

import java.util.BitSet;
import java.util.concurrent.TimeUnit;

import net.minecraft.client.renderer.RegionRenderCache;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumWorldBlockLayer;
import net.minecraft.world.World;

import org.apache.commons.lang3.tuple.Pair;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class MinecraftForgeClient
{
@@ -56,4 +67,29 @@ public static void releaseStencilBit(int bit)
stencilBits.set(bit);
}
}

private static final LoadingCache<Pair<World, BlockPos>, RegionRenderCache> regionCache = CacheBuilder.newBuilder()
.maximumSize(500)
.concurrencyLevel(5)
.expireAfterAccess(1, TimeUnit.SECONDS)
.build(new CacheLoader<Pair<World, BlockPos>, RegionRenderCache>()
{
public RegionRenderCache load(Pair<World, BlockPos> key) throws Exception
{
return new RegionRenderCache(key.getLeft(), key.getRight().add(-1, -1, -1), key.getRight().add(16, 16, 16), 1);
}
});

public static void onRebuildChunk(World world, BlockPos position, RegionRenderCache cache)
{
regionCache.put(Pair.of(world, position), cache);
}

public static RegionRenderCache getRegionRenderCache(World world, BlockPos pos)
{
int x = pos.getX() & ~0xF;
int y = pos.getY() & ~0xF;
int z = pos.getZ() & ~0xF;
return regionCache.getUnchecked(Pair.of(world, new BlockPos(x, y, z)));
}
}

1 comment on commit 0710bdf

@grondag

This comment has been minimized.

Copy link

commented on 0710bdf Jan 24, 2016

Wow. You been busy. Looks amazing. Thank you!

Please sign in to comment.
You can’t perform that action at this time.