diff --git a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java index 068f6ea31..98ecf0473 100644 --- a/src/main/java/com/jozufozu/flywheel/FlywheelClient.java +++ b/src/main/java/com/jozufozu/flywheel/FlywheelClient.java @@ -5,6 +5,8 @@ import com.jozufozu.flywheel.core.AtlasStitcher; import com.jozufozu.flywheel.core.Contexts; import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.vanilla.VanillaInstances; + import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -20,5 +22,7 @@ public class FlywheelClient { modEventBus.addListener(Contexts::flwInit); modEventBus.addListener(Materials::flwInit); + + VanillaInstances.init(); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java index 2c6a24f14..984bfaf37 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceManager.java @@ -40,6 +40,12 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL materialManager.addListener(this); } + protected abstract boolean canInstance(T obj); + + protected abstract IInstance createRaw(T obj); + + protected abstract boolean canCreateInstance(T entity); + public void tick(double cameraX, double cameraY, double cameraZ) { tick++; @@ -100,7 +106,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL if (!Backend.getInstance() .canUseInstancing()) return; - if (obj instanceof IInstanceRendered) { + if (canInstance(obj)) { addInternal(obj); } } @@ -116,7 +122,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL if (!Backend.getInstance() .canUseInstancing()) return; - if (obj instanceof IInstanceRendered) { + if (canInstance(obj)) { IInstance instance = getInstance(obj, false); if (instance != null) { @@ -143,7 +149,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL if (!Backend.getInstance() .canUseInstancing()) return; - if (obj instanceof IInstanceRendered) { + if (canInstance(obj)) { IInstance instance = getInstance(obj, false); if (instance != null) instance.updateLight(); @@ -154,7 +160,7 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL if (!Backend.getInstance() .canUseInstancing()) return; - if (obj instanceof IInstanceRendered) { + if (canInstance(obj)) { IInstance instance = getInstance(obj, false); if (instance != null) removeInternal(obj, instance); } @@ -241,8 +247,4 @@ public abstract class InstanceManager implements MaterialManager.OriginShiftL invalidate(); instancedTiles.forEach(this::add); } - - protected abstract IInstance createRaw(T obj); - - protected abstract boolean canCreateInstance(T entity); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderRegistry.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderRegistry.java index 31f2b5611..f30a2aae5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderRegistry.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstancedRenderRegistry.java @@ -10,6 +10,8 @@ import com.jozufozu.flywheel.backend.instancing.entity.IEntityInstanceFactory; import com.jozufozu.flywheel.backend.instancing.tile.ITileInstanceFactory; import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance; +import it.unimi.dsi.fastutil.objects.Object2BooleanLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2BooleanMap; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.tileentity.TileEntity; @@ -22,15 +24,36 @@ public class InstancedRenderRegistry { return INSTANCE; } + private final Object2BooleanMap skipRender = new Object2BooleanLinkedOpenHashMap<>(); private final Map, ITileInstanceFactory> tiles = Maps.newHashMap(); private final Map, IEntityInstanceFactory> entities = Maps.newHashMap(); - public void register(TileEntityType type, ITileInstanceFactory rendererFactory) { - this.tiles.put(type, rendererFactory); + protected InstancedRenderRegistry() { + skipRender.defaultReturnValue(false); } - public void register(EntityType type, IEntityInstanceFactory rendererFactory) { - this.entities.put(type, rendererFactory); + public boolean shouldSkipRender(T type) { + return _skipRender(type.getType()) || ((type instanceof IInstanceRendered) && !((IInstanceRendered) type).shouldRenderNormally()); + } + + public boolean shouldSkipRender(T type) { + return _skipRender(type.getType()) || ((type instanceof IInstanceRendered) && !((IInstanceRendered) type).shouldRenderNormally()); + } + + public boolean canInstance(TileEntityType type) { + return tiles.containsKey(type); + } + + public boolean canInstance(EntityType type) { + return entities.containsKey(type); + } + + public TileRegistrater tile(TileEntityType type) { + return new TileRegistrater<>(type); + } + + public EntityRegistrater entity(EntityType type) { + return new EntityRegistrater<>(type); } @SuppressWarnings("unchecked") @@ -54,4 +77,64 @@ public class InstancedRenderRegistry { else return factory.create(manager, tile); } + private boolean _skipRender(Object o) { + return skipRender.getBoolean(o); + } + + public class TileRegistrater { + + private final TileEntityType type; + private ITileInstanceFactory factory; + private boolean skipRender = false; + + public TileRegistrater(TileEntityType type) { + this.type = type; + } + + public TileRegistrater factory(ITileInstanceFactory rendererFactory) { + factory = rendererFactory; + return this; + } + + public TileRegistrater setSkipRender(boolean skipRender) { + this.skipRender = skipRender; + return this; + } + + public InstancedRenderRegistry build() { + tiles.put(type, factory); + InstancedRenderRegistry.this.skipRender.put(type, skipRender); + + return InstancedRenderRegistry.this; + } + } + + public class EntityRegistrater { + + private final EntityType type; + private IEntityInstanceFactory factory; + private boolean skipRender = false; + + public EntityRegistrater(EntityType type) { + this.type = type; + } + + public EntityRegistrater factory(IEntityInstanceFactory rendererFactory) { + factory = rendererFactory; + return this; + } + + public EntityRegistrater setSkipRender(boolean skipRender) { + this.skipRender = skipRender; + return this; + } + + public InstancedRenderRegistry build() { + entities.put(type, factory); + InstancedRenderRegistry.this.skipRender.put(type, skipRender); + + return InstancedRenderRegistry.this; + } + } + } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java index 55d52e66e..a2b5bc186 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/entity/EntityInstanceManager.java @@ -7,6 +7,7 @@ import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; import com.jozufozu.flywheel.backend.instancing.MaterialManager; import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; @@ -17,6 +18,11 @@ public class EntityInstanceManager extends InstanceManager { super(materialManager); } + @Override + protected boolean canInstance(Entity obj) { + return obj != null && InstancedRenderRegistry.getInstance().canInstance(obj.getType()); + } + @Override protected IInstance createRaw(Entity obj) { return InstancedRenderRegistry.getInstance() diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileInstanceManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileInstanceManager.java index 4c8f3079a..07b957ac7 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileInstanceManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/tile/TileInstanceManager.java @@ -17,6 +17,11 @@ public class TileInstanceManager extends InstanceManager { super(materialManager); } + @Override + protected boolean canInstance(TileEntity obj) { + return obj != null && InstancedRenderRegistry.getInstance().canInstance(obj.getType()); + } + @Override protected IInstance createRaw(TileEntity obj) { return InstancedRenderRegistry.getInstance() diff --git a/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java b/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java index 2d9cca280..1541b42b4 100644 --- a/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java +++ b/src/main/java/com/jozufozu/flywheel/core/materials/OrientedData.java @@ -19,7 +19,7 @@ public class OrientedData extends BasicData { private float qX; private float qY; private float qZ; - private float qW; + private float qW = 1; public OrientedData(Instancer owner) { super(owner); diff --git a/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java b/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java new file mode 100644 index 000000000..05ec25cdf --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/ModelPart.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.core.model; + +public class ModelPart { + + public static PartBuilder builder(int sizeU, int sizeV) { + return new PartBuilder(sizeU, sizeV); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java new file mode 100644 index 000000000..178b34f5f --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java @@ -0,0 +1,199 @@ +package com.jozufozu.flywheel.core.model; + +import static com.jozufozu.flywheel.util.RenderMath.*; + +import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; +import com.jozufozu.flywheel.backend.model.BufferedModel; + +import com.jozufozu.flywheel.backend.model.IndexedModel; + +import com.jozufozu.flywheel.core.Formats; + +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3f; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; + +public class PartBuilder { + + private float sizeU = 64.0F; + private float sizeV = 32.0F; + + private TextureAtlasSprite sprite; + + private final List cuboids = new ArrayList<>(); + + public PartBuilder() { } + + public PartBuilder(int sizeU, int sizeV) { + this.setTextureSize(sizeU, sizeV); + } + + public PartBuilder setTextureSize(int textureWidth, int textureHeight) { + this.sizeU = (float)textureWidth; + this.sizeV = (float)textureHeight; + return this; + } + + public PartBuilder sprite(TextureAtlasSprite sprite) { + this.sprite = sprite; + return this; + } + + public CuboidBuilder cuboid() { + return new CuboidBuilder(this); + } + + public BufferedModel build() { + int vertices = 0; + + for (CuboidBuilder cuboid : cuboids) { + vertices += cuboid.vertices(); + } + + VecBuffer buffer = VecBuffer.allocate(vertices * Formats.UNLIT_MODEL.getStride()); + + for (CuboidBuilder cuboid : cuboids) { + cuboid.buffer(buffer); + } + + buffer.rewind(); + + return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer.unwrap(), vertices); + } + + private PartBuilder addCuboid(CuboidBuilder builder) { + cuboids.add(builder); + return this; + } + + public static class CuboidBuilder { + + TextureAtlasSprite sprite; + + Set visibleFaces = EnumSet.allOf(Direction.class); + int textureOffsetU; + int textureOffsetV; + + float posX1; + float posY1; + float posZ1; + float posX2; + float posY2; + float posZ2; + + final PartBuilder partBuilder; + + CuboidBuilder(PartBuilder partBuilder) { + this.partBuilder = partBuilder; + this.sprite = partBuilder.sprite; + } + + public CuboidBuilder textureOffset(int u, int v) { + this.textureOffsetU = u; + this.textureOffsetV = v; + return this; + } + + public CuboidBuilder start(float x, float y, float z) { + this.posX1 = x; + this.posY1 = y; + this.posZ1 = z; + return this; + } + + public CuboidBuilder end(float x, float y, float z) { + this.posX2 = x; + this.posY2 = y; + this.posZ2 = z; + return this; + } + + public CuboidBuilder size(float x, float y, float z) { + this.posX2 = posX1 + x; + this.posY2 = posY1 + y; + this.posZ2 = posZ1 + z; + return this; + } + + public CuboidBuilder sprite(TextureAtlasSprite sprite) { + this.sprite = sprite; + return this; + } + + public PartBuilder endCuboid() { + return partBuilder.addCuboid(this); + } + + public int vertices() { + return visibleFaces.size() * 4; + } + + public void buffer(VecBuffer buffer) { + + float sizeX = posX2 - posX1; + float sizeY = posY2 - posY1; + float sizeZ = posZ2 - posZ1; + + Vector3f lll = new Vector3f(posX1 / 16f, posY1 / 16f, posZ1 / 16f); + Vector3f hll = new Vector3f(posX2 / 16f, posY1 / 16f, posZ1 / 16f); + Vector3f hhl = new Vector3f(posX2 / 16f, posY2 / 16f, posZ1 / 16f); + Vector3f lhl = new Vector3f(posX1 / 16f, posY2 / 16f, posZ1 / 16f); + Vector3f llh = new Vector3f(posX1 / 16f, posY1 / 16f, posZ2 / 16f); + Vector3f hlh = new Vector3f(posX2 / 16f, posY1 / 16f, posZ2 / 16f); + Vector3f hhh = new Vector3f(posX2 / 16f, posY2 / 16f, posZ2 / 16f); + Vector3f lhh = new Vector3f(posX1 / 16f, posY2 / 16f, posZ2 / 16f); + float f4 = getU((float)textureOffsetU); + float f5 = getU((float)textureOffsetU + sizeZ); + float f6 = getU((float)textureOffsetU + sizeZ + sizeX); + float f7 = getU((float)textureOffsetU + sizeZ + sizeX + sizeX); + float f8 = getU((float)textureOffsetU + sizeZ + sizeX + sizeZ); + float f9 = getU((float)textureOffsetU + sizeZ + sizeX + sizeZ + sizeX); + float f10 = getV((float)textureOffsetV); + float f11 = getV((float)textureOffsetV + sizeZ); + float f12 = getV((float)textureOffsetV + sizeZ + sizeY); + + + float textureWidth = partBuilder.sizeU; + float textureHeight = partBuilder.sizeV; + quad(buffer, new Vector3f[]{hlh, llh, lll, hll}, f5, f10, f6, f11, textureWidth, textureHeight, Direction.DOWN); + quad(buffer, new Vector3f[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, textureWidth, textureHeight, Direction.UP); + quad(buffer, new Vector3f[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, textureWidth, textureHeight, Direction.WEST); + quad(buffer, new Vector3f[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, textureWidth, textureHeight, Direction.NORTH); + quad(buffer, new Vector3f[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, textureWidth, textureHeight, Direction.EAST); + quad(buffer, new Vector3f[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, textureWidth, textureHeight, Direction.SOUTH); + } + + + public void quad(VecBuffer buffer, Vector3f[] vertices, float minU, float minV, float maxU, float maxV, float texWidth, float texHeight, Direction dir) { + + Vector3f normal = dir.getUnitVector(); + + buffer.putVec3(vertices[0].getX(), vertices[0].getY(), vertices[0].getZ()).putVec3(nb(normal.getX()), nb(normal.getY()), nb(normal.getZ())).putVec2(maxU, minV); + buffer.putVec3(vertices[1].getX(), vertices[1].getY(), vertices[1].getZ()).putVec3(nb(normal.getX()), nb(normal.getY()), nb(normal.getZ())).putVec2(minU, minV); + buffer.putVec3(vertices[2].getX(), vertices[2].getY(), vertices[2].getZ()).putVec3(nb(normal.getX()), nb(normal.getY()), nb(normal.getZ())).putVec2(minU, maxV); + buffer.putVec3(vertices[3].getX(), vertices[3].getY(), vertices[3].getZ()).putVec3(nb(normal.getX()), nb(normal.getY()), nb(normal.getZ())).putVec2(maxU, maxV); + + } + + public float getU(float u) { + if (sprite != null) + return sprite.getInterpolatedU(u / 4.); + else + return u; + } + + public float getV(float v) { + if (sprite != null) + return sprite.getInterpolatedV(v / 4.); + else + return v; + } + } + + +} diff --git a/src/main/java/com/jozufozu/flywheel/core/model/Readable.java b/src/main/java/com/jozufozu/flywheel/core/model/Readable.java new file mode 100644 index 000000000..6d6d569b1 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/core/model/Readable.java @@ -0,0 +1,118 @@ +package com.jozufozu.flywheel.core.model; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Vector3f; + +public class Readable { + public static class ModelBox { + private final TexturedQuad[] quads; + public final float posX1; + public final float posY1; + public final float posZ1; + public final float posX2; + public final float posY2; + public final float posZ2; + + public ModelBox(int texOffU, int texOffV, float posX1, float posY1, float posZ1, float sizeX, float sizeY, float sizeZ, float growX, float growY, float growZ, boolean mirror, float texWidth, float texHeight) { + this.posX1 = posX1; + this.posY1 = posY1; + this.posZ1 = posZ1; + this.posX2 = posX1 + sizeX; + this.posY2 = posY1 + sizeY; + this.posZ2 = posZ1 + sizeZ; + this.quads = new TexturedQuad[6]; + float posX2 = posX1 + sizeX; + float posY2 = posY1 + sizeY; + float posZ2 = posZ1 + sizeZ; + posX1 = posX1 - growX; + posY1 = posY1 - growY; + posZ1 = posZ1 - growZ; + posX2 = posX2 + growX; + posY2 = posY2 + growY; + posZ2 = posZ2 + growZ; + if (mirror) { + float tmp = posX2; + posX2 = posX1; + posX1 = tmp; + } + + PositionTextureVertex lll = new PositionTextureVertex(posX1, posY1, posZ1, 0.0F, 0.0F); + PositionTextureVertex hll = new PositionTextureVertex(posX2, posY1, posZ1, 0.0F, 8.0F); + PositionTextureVertex hhl = new PositionTextureVertex(posX2, posY2, posZ1, 8.0F, 8.0F); + PositionTextureVertex lhl = new PositionTextureVertex(posX1, posY2, posZ1, 8.0F, 0.0F); + PositionTextureVertex llh = new PositionTextureVertex(posX1, posY1, posZ2, 0.0F, 0.0F); + PositionTextureVertex hlh = new PositionTextureVertex(posX2, posY1, posZ2, 0.0F, 8.0F); + PositionTextureVertex hhh = new PositionTextureVertex(posX2, posY2, posZ2, 8.0F, 8.0F); + PositionTextureVertex lhh = new PositionTextureVertex(posX1, posY2, posZ2, 8.0F, 0.0F); + float f4 = (float)texOffU; + float f5 = (float)texOffU + sizeZ; + float f6 = (float)texOffU + sizeZ + sizeX; + float f7 = (float)texOffU + sizeZ + sizeX + sizeX; + float f8 = (float)texOffU + sizeZ + sizeX + sizeZ; + float f9 = (float)texOffU + sizeZ + sizeX + sizeZ + sizeX; + float f10 = (float)texOffV; + float f11 = (float)texOffV + sizeZ; + float f12 = (float)texOffV + sizeZ + sizeY; + this.quads[2] = new TexturedQuad(new PositionTextureVertex[]{hlh, llh, lll, hll}, f5, f10, f6, f11, texWidth, texHeight, mirror, Direction.DOWN); + this.quads[3] = new TexturedQuad(new PositionTextureVertex[]{hhl, lhl, lhh, hhh}, f6, f11, f7, f10, texWidth, texHeight, mirror, Direction.UP); + this.quads[1] = new TexturedQuad(new PositionTextureVertex[]{lll, llh, lhh, lhl}, f4, f11, f5, f12, texWidth, texHeight, mirror, Direction.WEST); + this.quads[4] = new TexturedQuad(new PositionTextureVertex[]{hll, lll, lhl, hhl}, f5, f11, f6, f12, texWidth, texHeight, mirror, Direction.NORTH); + this.quads[0] = new TexturedQuad(new PositionTextureVertex[]{hlh, hll, hhl, hhh}, f6, f11, f8, f12, texWidth, texHeight, mirror, Direction.EAST); + this.quads[5] = new TexturedQuad(new PositionTextureVertex[]{llh, hlh, hhh, lhh}, f8, f11, f9, f12, texWidth, texHeight, mirror, Direction.SOUTH); + } + } + + public static class PositionTextureVertex { + public final float x; + public final float y; + public final float z; + public final float u; + public final float v; + + public PositionTextureVertex(float x, float y, float z) { + this(x, y, z, 0, 0); + } + + public PositionTextureVertex(float x, float y, float z, float u, float v) { + this.x = x; + this.y = y; + this.z = z; + this.u = u; + this.v = v; + } + + public PositionTextureVertex setTexturePosition(float u, float v) { + return new PositionTextureVertex(x, y, z, u, v); + } + } + + public static class TexturedQuad { + public final PositionTextureVertex[] vertices; + public final Vector3f normal; + + public TexturedQuad(PositionTextureVertex[] vertices, float minU, float minV, float maxU, float maxV, float texWidth, float texHeight, boolean p_i225951_8_, Direction p_i225951_9_) { + this.vertices = vertices; + float w = 0.0F / texWidth; + float h = 0.0F / texHeight; + vertices[0] = vertices[0].setTexturePosition(maxU / texWidth - w, minV / texHeight + h); + vertices[1] = vertices[1].setTexturePosition(minU / texWidth + w, minV / texHeight + h); + vertices[2] = vertices[2].setTexturePosition(minU / texWidth + w, maxV / texHeight - h); + vertices[3] = vertices[3].setTexturePosition(maxU / texWidth - w, maxV / texHeight - h); + if (p_i225951_8_) { + int i = vertices.length; + + for(int j = 0; j < i / 2; ++j) { + PositionTextureVertex modelrenderer$positiontexturevertex = vertices[j]; + vertices[j] = vertices[i - 1 - j]; + vertices[i - 1 - j] = modelrenderer$positiontexturevertex; + } + } + + this.normal = p_i225951_9_.getUnitVector(); + if (p_i225951_8_) { + this.normal.multiplyComponentwise(-1.0F, 1.0F, 1.0F); + } + + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/mixin/CancelEntityRenderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/CancelEntityRenderMixin.java index f87155d22..1042fccc7 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/CancelEntityRenderMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/CancelEntityRenderMixin.java @@ -3,6 +3,8 @@ package com.jozufozu.flywheel.mixin; import java.util.ArrayList; import java.util.Iterator; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Group; @@ -10,7 +12,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; import com.google.common.collect.Lists; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.instancing.IInstanceRendered; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.world.ClientWorld; @@ -28,7 +29,9 @@ public class CancelEntityRenderMixin { .canUseInstancing()) { ArrayList filtered = Lists.newArrayList(entities); - filtered.removeIf(entity -> entity instanceof IInstanceRendered && !((IInstanceRendered) entity).shouldRenderNormally()); + + InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); + filtered.removeIf(r::shouldSkipRender); return filtered; } @@ -42,7 +45,9 @@ public class CancelEntityRenderMixin { .canUseInstancing()) { ArrayList filtered = Lists.newArrayList(classInheritanceMultiMap); - filtered.removeIf(entity -> entity instanceof IInstanceRendered && !((IInstanceRendered) entity).shouldRenderNormally()); + + InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); + filtered.removeIf(r::shouldSkipRender); return filtered.iterator(); } diff --git a/src/main/java/com/jozufozu/flywheel/mixin/CancelTileEntityRenderMixin.java b/src/main/java/com/jozufozu/flywheel/mixin/CancelTileEntityRenderMixin.java index 88247741b..7a73e73ee 100644 --- a/src/main/java/com/jozufozu/flywheel/mixin/CancelTileEntityRenderMixin.java +++ b/src/main/java/com/jozufozu/flywheel/mixin/CancelTileEntityRenderMixin.java @@ -2,13 +2,14 @@ package com.jozufozu.flywheel.mixin; import java.util.List; +import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; + import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.jozufozu.flywheel.backend.Backend; -import com.jozufozu.flywheel.backend.instancing.IInstanceRendered; import net.minecraft.client.renderer.chunk.ChunkRenderDispatcher; import net.minecraft.tileentity.TileEntity; @@ -31,7 +32,8 @@ public class CancelTileEntityRenderMixin { .canUseInstancing()) { List tiles = cir.getReturnValue(); - tiles.removeIf(tile -> tile instanceof IInstanceRendered && !((IInstanceRendered) tile).shouldRenderNormally()); + InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); + tiles.removeIf(r::shouldSkipRender); } } } diff --git a/src/main/java/com/jozufozu/flywheel/util/RenderMath.java b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java new file mode 100644 index 000000000..79028b953 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/RenderMath.java @@ -0,0 +1,8 @@ +package com.jozufozu.flywheel.util; + +public class RenderMath { + + public static byte nb(float f) { + return (byte) (f * 127); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/QuaternionTransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/QuaternionTransformStack.java new file mode 100644 index 000000000..7e4fb84b0 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/transform/QuaternionTransformStack.java @@ -0,0 +1,97 @@ +package com.jozufozu.flywheel.util.transform; + +import com.google.common.collect.Lists; + +import net.minecraft.util.math.vector.Quaternion; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3f; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Stack; +import java.util.Vector; + +public class QuaternionTransformStack implements TransformStack { + + private final Deque stack; + + public QuaternionTransformStack() { + stack = new ArrayDeque<>(); + stack.add(new Transform()); + } + + @Override + public TransformStack translate(double x, double y, double z) { + + Transform peek = stack.peek(); + + double qx = peek.qx; + double qy = peek.qy; + double qz = peek.qz; + double qw = peek.qw; + peek.x += qw * x + qy * z - qz * y; + peek.y += qw * y - qx * z + qz * x; + peek.z += qw * z + qx * y - qy * x; + + return this; + } + + @Override + public TransformStack multiply(Quaternion quaternion) { + return this; + } + + @Override + public TransformStack push() { + stack.push(stack.peek().copy()); + return this; + } + + @Override + public TransformStack pop() { + + if (stack.size() == 1) { + stack.peek().loadIdentity(); + } else { + stack.pop(); + } + + return this; + } + + private static class Transform { + public double qx; + public double qy; + public double qz; + public double qw; + public double x; + public double y; + public double z; + + public Transform() { + qw = 1.0; + } + + public void loadIdentity() { + x = y = z = 0.0; + + qx = qy = qz = 0.0; + qw = 1.0; + } + + public Transform copy() { + Transform transform = new Transform(); + + transform.qx = this.qx; + transform.qy = this.qy; + transform.qz = this.qz; + transform.qw = this.qw; + transform.x = this.x; + transform.y = this.y; + transform.z = this.z; + + return transform; + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java new file mode 100644 index 000000000..547b07c70 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java @@ -0,0 +1,80 @@ +package com.jozufozu.flywheel.util.transform; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Quaternion; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3f; +import net.minecraft.util.math.vector.Vector3i; + +public interface TransformStack { + public static final Vector3d center = new Vector3d(0.5, 0.5, 0.5); + + TransformStack translate(double x, double y, double z); + + TransformStack multiply(Quaternion quaternion); + + TransformStack push(); + + TransformStack pop(); + + default TransformStack rotate(Direction axis, float radians) { + if (radians == 0) + return this; + return multiply(axis.getUnitVector() + .getRadialQuaternion(radians)); + } + + default TransformStack rotate(double angle, Direction.Axis axis) { + Vector3f vec = + axis == Direction.Axis.X ? Vector3f.POSITIVE_X : axis == Direction.Axis.Y ? Vector3f.POSITIVE_Y : Vector3f.POSITIVE_Z; + return multiply(vec, angle); + } + + default TransformStack rotateX(double angle) { + return multiply(Vector3f.POSITIVE_X, angle); + } + + default TransformStack rotateY(double angle) { + return multiply(Vector3f.POSITIVE_Y, angle); + } + + default TransformStack rotateZ(double angle) { + return multiply(Vector3f.POSITIVE_Z, angle); + } + + default TransformStack centre() { + return translate(center); + } + + default TransformStack unCentre() { + return translateBack(center); + } + + default TransformStack translate(Vector3i vec) { + return translate(vec.getX(), vec.getY(), vec.getZ()); + } + + default TransformStack translate(Vector3d vec) { + return translate(vec.x, vec.y, vec.z); + } + + default TransformStack translateBack(Vector3d vec) { + return translate(-vec.x, -vec.y, -vec.z); + } + + default TransformStack nudge(int id) { + long randomBits = (long) id * 31L * 493286711L; + randomBits = randomBits * randomBits * 4392167121L + randomBits * 98761L; + float xNudge = (((float) (randomBits >> 16 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; + float yNudge = (((float) (randomBits >> 20 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; + float zNudge = (((float) (randomBits >> 24 & 7L) + 0.5F) / 8.0F - 0.5F) * 0.004F; + return translate(xNudge, yNudge, zNudge); + } + + default TransformStack multiply(Vector3f axis, double angle) { + if (angle == 0) + return this; + return multiply(axis.getDegreesQuaternion((float) angle)); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java new file mode 100644 index 000000000..9a7831b0c --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ChestInstance.java @@ -0,0 +1,136 @@ +package com.jozufozu.flywheel.vanilla; + +import com.jozufozu.flywheel.backend.instancing.IDynamicInstance; +import com.jozufozu.flywheel.backend.instancing.MaterialManager; +import com.jozufozu.flywheel.backend.instancing.tile.TileEntityInstance; + +import com.jozufozu.flywheel.backend.model.BufferedModel; +import com.jozufozu.flywheel.core.Materials; +import com.jozufozu.flywheel.core.materials.OrientedData; + +import com.jozufozu.flywheel.core.model.ModelPart; +import com.jozufozu.flywheel.util.AnimationTickHolder; + +import it.unimi.dsi.fastutil.floats.Float2FloatFunction; +import net.minecraft.block.Block; +import net.minecraft.block.ChestBlock; +import net.minecraft.client.renderer.Atlases; +import net.minecraft.client.renderer.model.RenderMaterial; +import net.minecraft.state.properties.ChestType; +import net.minecraft.tileentity.ChestTileEntity; +import net.minecraft.tileentity.TileEntityMerger; +import net.minecraft.util.math.vector.Quaternion; +import net.minecraft.util.math.vector.Vector3f; + +import java.util.Calendar; + +public class ChestInstance extends TileEntityInstance implements IDynamicInstance { + + private final OrientedData body; + private final OrientedData lid; + + private final Float2FloatFunction lidProgress; + private final RenderMaterial renderMaterial; + + public ChestInstance(MaterialManager materialManager, ChestTileEntity tile) { + super(materialManager, tile); + + Block block = blockState.getBlock(); + + ChestType chestType = blockState.contains(ChestBlock.TYPE) ? blockState.get(ChestBlock.TYPE) : ChestType.SINGLE; + renderMaterial = Atlases.getChestTexture(tile, chestType, isChristmas()); + + body = baseInstance() + .setPosition(getInstancePosition()); + lid = lidInstance() + .setPosition(getInstancePosition()) + .nudge(0, 9f/16f, 0); + + if (block instanceof ChestBlock) { + + ChestBlock chestBlock = (ChestBlock) block; + + TileEntityMerger.ICallbackWrapper wrapper = chestBlock.getBlockEntitySource(blockState, world, getWorldPosition(), true); + + this.lidProgress = wrapper.apply(ChestBlock.getAnimationProgressRetriever(tile)); + + + } else { + lidProgress = $ -> 0f; + } + } + + @Override + public void beginFrame() { + float progress = lidProgress.get(AnimationTickHolder.getPartialTicks()); + + progress = 1.0F - progress; + progress = 1.0F - progress * progress * progress; + + float angleX = -(progress * ((float) Math.PI / 2F)); + + Quaternion quaternion = new Quaternion(Vector3f.POSITIVE_X, angleX, false); + + lid.setRotation(quaternion) + .setPivot(0, 0, 1f / 16f); + + } + + @Override + public void updateLight() { + relight(getWorldPosition(), body, lid); + } + + @Override + public void remove() { + body.delete(); + lid.delete(); + } + + private OrientedData baseInstance() { + + return materialManager.getMaterial(Materials.ORIENTED, renderMaterial.getAtlasId()) + .get("base_" + renderMaterial.getTextureId(), this::getBaseModel) + .createInstance(); + } + + private OrientedData lidInstance() { + + return materialManager.getMaterial(Materials.ORIENTED, renderMaterial.getAtlasId()) + .get("lid_" + renderMaterial.getTextureId(), this::getLidModel) + .createInstance(); + } + + private BufferedModel getBaseModel() { + + return ModelPart.builder(64, 64) + .sprite(renderMaterial.getSprite()) + .cuboid() + .textureOffset(0, 19) + .start(1, 0, 1) + .end(15, 10, 15) + .endCuboid() + .build(); + } + + private BufferedModel getLidModel() { + + return ModelPart.builder(64, 64) + .sprite(renderMaterial.getSprite()) + .cuboid() + .textureOffset(0, 0) + .start(1, 0, 1) + .end(15, 5, 15) + .endCuboid() + .cuboid() + .start(7, -2, 15) + .size(2, 4, 1) + .endCuboid() + .build(); + } + + public static boolean isChristmas() { + Calendar calendar = Calendar.getInstance(); + return calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DATE) >= 24 && calendar.get(Calendar.DATE) <= 26; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java new file mode 100644 index 000000000..fd2aae00d --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java @@ -0,0 +1,17 @@ +package com.jozufozu.flywheel.vanilla; + +import com.jozufozu.flywheel.backend.instancing.InstancedRenderRegistry; + +import net.minecraft.tileentity.TileEntityType; + +public class VanillaInstances { + + public static void init() { + InstancedRenderRegistry r = InstancedRenderRegistry.getInstance(); + + r.tile(TileEntityType.CHEST) + .setSkipRender(true) + .factory(ChestInstance::new) + .build(); + } +}