diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/GlTextureUnit.java b/src/main/java/com/jozufozu/flywheel/backend/gl/GlTextureUnit.java new file mode 100644 index 000000000..bdae7486a --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/GlTextureUnit.java @@ -0,0 +1,55 @@ +package com.jozufozu.flywheel.backend.gl; + +import static org.lwjgl.opengl.GL13.GL_TEXTURE0; +import static org.lwjgl.opengl.GL13.glActiveTexture; + +import com.mojang.blaze3d.platform.GlStateManager; + +public enum GlTextureUnit { + T0(0), + T1(1), + T2(2), + T3(3), + T4(4), + T5(5), + T6(6), + T7(7), + T8(8), + T9(9), + T10(10), + T11(11), + T12(12), + T13(13), + T14(14), + T15(15), + T16(16), + T17(17), + T18(18), + T19(19), + T20(20), + T21(21), + T22(22), + T23(23), + T24(24), + T25(25), + T26(26), + T27(27), + T28(28), + T29(29), + T30(30), + T31(31), + + ; + + public final int number; + public final int glEnum; + + GlTextureUnit(int unit) { + this.number = unit; + this.glEnum = GL_TEXTURE0 + unit; + } + + public void makeActive() { + GlStateManager._activeTexture(glEnum); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java index 568c1f21e..7b6f2690b 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java @@ -4,7 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import com.jozufozu.flywheel.backend.Backend; +import com.jozufozu.flywheel.backend.state.IRenderState; +import com.jozufozu.flywheel.backend.state.TextureRenderState; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.WorldContext; import com.jozufozu.flywheel.core.materials.ModelData; @@ -13,7 +14,6 @@ import com.jozufozu.flywheel.core.shader.IProgramCallback; import com.jozufozu.flywheel.core.shader.WorldProgram; import com.jozufozu.flywheel.util.WeakHashSet; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.ActiveRenderInfo; import net.minecraft.client.renderer.RenderType; import net.minecraft.inventory.container.PlayerContainer; @@ -30,11 +30,8 @@ public class MaterialManager

{ protected final WorldContext

context; - protected final Map, InstanceMaterial> atlasMaterials; - protected final ArrayList> atlasRenderers; - - protected final Map>> renderers; - protected final Map, InstanceMaterial>> materials; + protected final Map>> renderers; + protected final Map, InstanceMaterial>> materials; protected BlockPos originCoordinate = BlockPos.ZERO; @@ -43,11 +40,6 @@ public class MaterialManager

{ public MaterialManager(WorldContext

context) { this.context = context; - this.atlasMaterials = new HashMap<>(); - this.atlasRenderers = new ArrayList<>(Backend.getInstance() - .allMaterials() - .size()); - this.materials = new HashMap<>(); this.renderers = new HashMap<>(); @@ -80,52 +72,43 @@ public class MaterialManager

{ translate.multiplyBackward(viewProjection); - for (MaterialRenderer

material : atlasRenderers) { - material.render(layer, translate, camX, camY, camZ, callback); - } - - for (Map.Entry>> entry : renderers.entrySet()) { - Minecraft.getInstance().textureManager.bind(entry.getKey()); + for (Map.Entry>> entry : renderers.entrySet()) { + entry.getKey().bind(); for (MaterialRenderer

materialRenderer : entry.getValue()) { materialRenderer.render(layer, translate, camX, camY, camZ, callback); } + + entry.getKey().unbind(); } } public void delete() { - atlasMaterials.values() - .forEach(InstanceMaterial::delete); materials.values() .stream() .flatMap(m -> m.values() .stream()) .forEach(InstanceMaterial::delete); - atlasMaterials.clear(); - atlasRenderers.clear(); materials.clear(); renderers.clear(); } - @SuppressWarnings("unchecked") public InstanceMaterial getMaterial(MaterialSpec materialType) { - return (InstanceMaterial) this.atlasMaterials.computeIfAbsent(materialType, type -> { - InstanceMaterial material = new InstanceMaterial<>(this::getOriginCoordinate, type); + return getMaterial(materialType, PlayerContainer.BLOCK_ATLAS); + } - this.atlasRenderers.add(new MaterialRenderer<>(context.getProgramSupplier(type.getProgramName()), material)); - - return material; - }); + public InstanceMaterial getMaterial(MaterialSpec materialType, ResourceLocation texture) { + return getMaterial(materialType, TextureRenderState.get(texture)); } @SuppressWarnings("unchecked") - public InstanceMaterial getMaterial(MaterialSpec materialType, ResourceLocation texture) { - return (InstanceMaterial) materials.computeIfAbsent(texture, $ -> new HashMap<>()) + public InstanceMaterial getMaterial(MaterialSpec materialType, IRenderState state) { + return (InstanceMaterial) materials.computeIfAbsent(state, $ -> new HashMap<>()) .computeIfAbsent(materialType, type -> { InstanceMaterial material = new InstanceMaterial<>(this::getOriginCoordinate, type); - this.renderers.computeIfAbsent(texture, $ -> new ArrayList<>()) + this.renderers.computeIfAbsent(state, $ -> new ArrayList<>()) .add(new MaterialRenderer<>(context.getProgramSupplier(type.getProgramName()), material)); return material; @@ -166,8 +149,7 @@ public class MaterialManager

{ .flatMap(m -> m.values() .stream()) .forEach(InstanceMaterial::clear); - atlasMaterials.values() - .forEach(InstanceMaterial::clear); + listeners.forEach(OriginShiftListener::onOriginShift); } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/IRenderState.java b/src/main/java/com/jozufozu/flywheel/backend/state/IRenderState.java new file mode 100644 index 000000000..f312ab881 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/state/IRenderState.java @@ -0,0 +1,19 @@ +package com.jozufozu.flywheel.backend.state; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; + +import net.minecraft.util.ResourceLocation; + +public interface IRenderState { + + void bind(); + + void unbind(); + + @Nullable + default ResourceLocation getTexture(GlTextureUnit textureUnit) { + return null; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/NoCullRenderState.java b/src/main/java/com/jozufozu/flywheel/backend/state/NoCullRenderState.java new file mode 100644 index 000000000..dc5f6ff10 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/state/NoCullRenderState.java @@ -0,0 +1,20 @@ +package com.jozufozu.flywheel.backend.state; + +import com.mojang.blaze3d.platform.GlStateManager; + +public class NoCullRenderState implements IRenderState { + + public static final NoCullRenderState INSTANCE = new NoCullRenderState(); + + protected NoCullRenderState() { } + + @Override + public void bind() { + GlStateManager._disableCull(); + } + + @Override + public void unbind() { + GlStateManager._enableCull(); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/RenderState.java b/src/main/java/com/jozufozu/flywheel/backend/state/RenderState.java new file mode 100644 index 000000000..c72f61643 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/state/RenderState.java @@ -0,0 +1,81 @@ +package com.jozufozu.flywheel.backend.state; + +import java.util.EnumMap; +import java.util.Map; +import java.util.Objects; + +import javax.annotation.Nullable; + +import com.google.common.collect.ImmutableList; +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; + +import net.minecraft.util.ResourceLocation; + +public class RenderState implements IRenderState { + + private final Map textures; + private final ImmutableList states; + + public RenderState(Map textures, ImmutableList states) { + this.textures = textures; + this.states = states; + } + + @Override + public void bind() { + states.forEach(IRenderState::bind); + } + + @Override + public void unbind() { + states.forEach(IRenderState::unbind); + } + + @Nullable + @Override + public ResourceLocation getTexture(GlTextureUnit textureUnit) { + return textures.get(textureUnit); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + RenderState that = (RenderState) o; + return states.equals(that.states); + } + + @Override + public int hashCode() { + return Objects.hash(states); + } + + public static StateBuilder builder() { + return new StateBuilder(); + } + + public static class StateBuilder { + private final ImmutableList.Builder states = ImmutableList.builder(); + private final Map textures = new EnumMap<>(GlTextureUnit.class); + + public StateBuilder texture(ResourceLocation name) { + return addState(TextureRenderState.get(name)); + } + + public StateBuilder addState(IRenderState state) { + if (state instanceof TextureRenderState) { + TextureRenderState tex = (TextureRenderState) state; + if (textures.put(tex.unit, tex.location) == null) { + states.add(state); + } + } else { + states.add(state); + } + return this; + } + + public RenderState build() { + return new RenderState(textures, states.build()); + } + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/state/TextureRenderState.java b/src/main/java/com/jozufozu/flywheel/backend/state/TextureRenderState.java new file mode 100644 index 000000000..7c34ea096 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/state/TextureRenderState.java @@ -0,0 +1,64 @@ +package com.jozufozu.flywheel.backend.state; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import javax.annotation.Nullable; + +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; +import com.jozufozu.flywheel.util.Pair; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +public class TextureRenderState implements IRenderState { + private static final Map, TextureRenderState> states = new HashMap<>(); + + public final GlTextureUnit unit; + public final ResourceLocation location; + + private TextureRenderState(GlTextureUnit unit, ResourceLocation location) { + this.unit = unit; + this.location = location; + } + + public static TextureRenderState get(ResourceLocation texture) { + return get(GlTextureUnit.T0, texture); + } + + public static TextureRenderState get(GlTextureUnit unit, ResourceLocation texture) { + return states.computeIfAbsent(Pair.of(unit, texture), p -> new TextureRenderState(p.getFirst(), p.getSecond())); + } + + @Override + public void bind() { + unit.makeActive(); + Minecraft.getInstance().textureManager.bind(location); + } + + @Override + public void unbind() { + + } + + @Nullable + @Override + public ResourceLocation getTexture(GlTextureUnit textureUnit) { + if (textureUnit == unit) return location; + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TextureRenderState that = (TextureRenderState) o; + return location.equals(that.location); + } + + @Override + public int hashCode() { + return Objects.hash(location); + } +} diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingMaterialManager.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingMaterialManager.java index b85640569..b846a2f43 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingMaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingMaterialManager.java @@ -1,24 +1,18 @@ package com.jozufozu.flywheel.core.crumbling; -import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D; -import static org.lwjgl.opengl.GL11.glBindTexture; -import static org.lwjgl.opengl.GL13.GL_TEXTURE0; -import static org.lwjgl.opengl.GL13.glActiveTexture; - import java.util.ArrayList; import java.util.Map; +import com.jozufozu.flywheel.backend.gl.GlTextureUnit; import com.jozufozu.flywheel.backend.instancing.MaterialManager; import com.jozufozu.flywheel.backend.instancing.MaterialRenderer; +import com.jozufozu.flywheel.backend.state.IRenderState; import com.jozufozu.flywheel.core.WorldContext; import com.jozufozu.flywheel.core.atlas.AtlasInfo; import com.jozufozu.flywheel.core.atlas.SheetData; import com.jozufozu.flywheel.core.shader.IProgramCallback; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.vector.Matrix4f; @@ -44,23 +38,29 @@ public class CrumblingMaterialManager extends MaterialManager translate.multiplyBackward(viewProjection); - TextureManager textureManager = Minecraft.getInstance().textureManager; + for (Map.Entry>> entry : renderers.entrySet()) { + IRenderState key = entry.getKey(); + key.bind(); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(PlayerContainer.BLOCK_ATLAS) - .getId()); + int width; + int height; - for (MaterialRenderer material : atlasRenderers) { - material.render(layer, translate, camX, camY, camZ, CrumblingProgram::setDefaultAtlasSize); - } + ResourceLocation texture = key.getTexture(GlTextureUnit.T0); - for (Map.Entry>> entry : renderers.entrySet()) { - glBindTexture(GL_TEXTURE_2D, textureManager.getTexture(entry.getKey()) - .getId()); - SheetData atlasData = AtlasInfo.getAtlasData(entry.getKey()); - for (MaterialRenderer materialRenderer : entry.getValue()) { - materialRenderer.render(layer, translate, camX, camY, camZ, p -> p.setAtlasSize(atlasData.width, atlasData.height)); + if (texture != null) { + SheetData atlasData = AtlasInfo.getAtlasData(texture); + + width = atlasData.width; + height = atlasData.height; + } else { + width = height = 256; } + + for (MaterialRenderer materialRenderer : entry.getValue()) { + materialRenderer.render(layer, translate, camX, camY, camZ, p -> p.setAtlasSize(width, height)); + } + + key.unbind(); } } } diff --git a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java index b7d53d891..c1b51e6aa 100644 --- a/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/crumbling/CrumblingProgram.java @@ -35,16 +35,6 @@ public class CrumblingProgram extends WorldProgram { glUniform2f(uTextureScale, x, y); } - public void setDefaultAtlasSize() { - SheetData atlasData = AtlasInfo.getAtlasData(PlayerContainer.BLOCK_ATLAS); - if (atlasData == null) return; - - int width = atlasData.width; - int height = atlasData.height; - - setAtlasSize(width, height); - } - public void setAtlasSize(int width, int height) { AtlasTexture blockAtlas = AtlasInfo.getAtlas(PlayerContainer.BLOCK_ATLAS); if (blockAtlas == null) return; diff --git a/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java index 13cbf1833..3c143222e 100644 --- a/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java +++ b/src/main/java/com/jozufozu/flywheel/core/model/PartBuilder.java @@ -127,8 +127,6 @@ public class PartBuilder { /** * Pulls the cuboid "inside out" through the Y and Z axes. - * - * See the {@link com.jozufozu.flywheel.vanilla.SignInstance sign} renderer for the use case. */ public CuboidBuilder invertYZ() { this.invertYZ = true; diff --git a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java index 23edcfcf8..1962bcf26 100644 --- a/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java +++ b/src/main/java/com/jozufozu/flywheel/util/transform/TransformStack.java @@ -45,11 +45,27 @@ public interface TransformStack { } default TransformStack centre() { - return translate(CENTER); + return translateAll(0.5); } default TransformStack unCentre() { - return translateBack(CENTER); + return translateAll(-0.5); + } + + default TransformStack translateAll(double v) { + return translate(v, v, v); + } + + default TransformStack translateX(double x) { + return translate(x, 0, 0); + } + + default TransformStack translateY(double y) { + return translate(0, y, 0); + } + + default TransformStack translateZ(double z) { + return translate(0, 0, z); } default TransformStack translate(Vector3i vec) { diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/RenderStates.java b/src/main/java/com/jozufozu/flywheel/vanilla/RenderStates.java new file mode 100644 index 000000000..55aed1b32 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/vanilla/RenderStates.java @@ -0,0 +1,18 @@ +package com.jozufozu.flywheel.vanilla; + +import java.util.List; +import java.util.stream.Collectors; + +import com.jozufozu.flywheel.backend.state.IRenderState; +import com.jozufozu.flywheel.backend.state.NoCullRenderState; +import com.jozufozu.flywheel.backend.state.RenderState; + +import net.minecraft.client.renderer.Atlases; +import net.minecraft.client.renderer.model.RenderMaterial; + +public class RenderStates { + public static final IRenderState SHULKER = RenderState.builder() + .texture(Atlases.SHULKER_SHEET) + .addState(NoCullRenderState.INSTANCE) + .build(); +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java new file mode 100644 index 000000000..f4c3589c2 --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/vanilla/ShulkerBoxInstance.java @@ -0,0 +1,130 @@ +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.ModelData; +import com.jozufozu.flywheel.core.model.ModelPart; +import com.jozufozu.flywheel.util.AnimationTickHolder; +import com.jozufozu.flywheel.util.transform.MatrixTransformStack; + +import net.minecraft.block.ShulkerBoxBlock; +import net.minecraft.client.renderer.Atlases; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.item.DyeColor; +import net.minecraft.tileentity.ShulkerBoxTileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.vector.Quaternion; +import net.minecraft.util.math.vector.Vector3f; + +public class ShulkerBoxInstance extends TileEntityInstance implements IDynamicInstance { + + private final TextureAtlasSprite texture; + + private final ModelData base; + private final ModelData lid; + private final MatrixTransformStack stack; + + private float lastProgress = Float.NaN; + + public ShulkerBoxInstance(MaterialManager materialManager, ShulkerBoxTileEntity tile) { + super(materialManager, tile); + + DyeColor color = tile.getColor(); + if (color == null) { + texture = Atlases.DEFAULT_SHULKER_TEXTURE_LOCATION.sprite(); + } else { + texture = Atlases.SHULKER_TEXTURE_LOCATION.get(color.getId()).sprite(); + } + Quaternion rotation = getDirection().getRotation(); + + stack = new MatrixTransformStack(); + + stack.translate(getInstancePosition()) + .scale(0.9995f) + .translateAll(0.00025) + .centre() + .multiply(rotation) + .unCentre(); + + base = makeBaseInstance().setTransform(stack.unwrap()); + + stack.translateY(0.25); + + lid = makeLidInstance().setTransform(stack.unwrap()); + } + + @Override + public void beginFrame() { + float progress = tile.getProgress(AnimationTickHolder.getPartialTicks()); + + if (progress == lastProgress) return; + lastProgress = progress; + + Quaternion spin = Vector3f.YP.rotationDegrees(270.0F * progress); + + stack.push() + .centre() + .multiply(spin) + .unCentre() + .translateY(progress * 0.5f); + + lid.setTransform(stack.unwrap()); + + stack.pop(); + } + + @Override + public void remove() { + base.delete(); + lid.delete(); + } + + @Override + public void updateLight() { + relight(pos, base, lid); + } + + private ModelData makeBaseInstance() { + return materialManager.getMaterial(Materials.TRANSFORMED, RenderStates.SHULKER) + .get("base_" + texture.getName(), this::makeBaseModel) + .createInstance(); + } + + private ModelData makeLidInstance() { + return materialManager.getMaterial(Materials.TRANSFORMED, RenderStates.SHULKER) + .get("lid_" + texture.getName(), this::makeLidModel) + .createInstance(); + } + + private BufferedModel makeBaseModel() { + return ModelPart.builder(64, 64) + .sprite(texture) + .cuboid() + .textureOffset(0, 28) + .size(16, 8, 16) + .invertYZ() + .endCuboid() + .build(); + } + + private BufferedModel makeLidModel() { + return ModelPart.builder(64, 64) + .sprite(texture) + .cuboid() + .size(16, 12, 16) + .invertYZ() + .endCuboid() + .build(); + } + + private Direction getDirection() { + if (blockState.getBlock() instanceof ShulkerBoxBlock) { + return blockState.getValue(ShulkerBoxBlock.FACING); + } + + return Direction.UP; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java index 225cc5b30..3ce2d3e0a 100644 --- a/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java +++ b/src/main/java/com/jozufozu/flywheel/vanilla/VanillaInstances.java @@ -7,7 +7,6 @@ import net.minecraft.tileentity.TileEntityType; /** * TODO: * - * * * * @@ -43,5 +42,9 @@ public class VanillaInstances { r.tile(TileEntityType.BELL) .setSkipRender(true) .factory(BellInstance::new); + + r.tile(TileEntityType.SHULKER_BOX) + .setSkipRender(true) + .factory(ShulkerBoxInstance::new); } }
{@link TileEntityType#SHULKER_BOX} {@link net.minecraft.client.renderer.tileentity.ShulkerBoxTileEntityRenderer ShulkerBoxTileEntityRenderer}
{@link TileEntityType#SIGN} {@link net.minecraft.client.renderer.tileentity.SignTileEntityRenderer SignTileEntityRenderer}
{@link TileEntityType#PISTON} {@link net.minecraft.client.renderer.tileentity.PistonTileEntityRenderer PistonTileEntityRenderer}
{@link TileEntityType#CONDUIT} {@link net.minecraft.client.renderer.tileentity.ConduitTileEntityRenderer ConduitTileEntityRenderer}