diff --git a/src/main/java/com/jozufozu/flywheel/backend/IShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/IShaderContext.java index dd880b92b..733ed5739 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/IShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/IShaderContext.java @@ -1,12 +1,18 @@ package com.jozufozu.flywheel.backend; +import java.util.function.Supplier; + import com.jozufozu.flywheel.backend.gl.shader.GlProgram; import net.minecraft.util.ResourceLocation; public interface IShaderContext

{ - P getProgram(ResourceLocation loc); + default P getProgram(ResourceLocation loc) { + return this.getProgramSupplier(loc).get(); + } + + Supplier

getProgramSupplier(ResourceLocation loc); /** * Load all programs associated with this context. This might be just one, if the context is very specialized. diff --git a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java index c899108b5..9cbfe3d54 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java +++ b/src/main/java/com/jozufozu/flywheel/backend/ShaderContext.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.Supplier; import javax.annotation.Nullable; @@ -30,8 +31,8 @@ public abstract class ShaderContext

implements IShaderConte } @Override - public P getProgram(ResourceLocation spec) { - return programs.get(spec).get(); + public Supplier

getProgramSupplier(ResourceLocation spec) { + return programs.get(spec); } public Program loadAndLink(ProgramSpec spec, @Nullable ProgramState state) { diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java index 8d6878dd1..2c8762452 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/MappedBuffer.java @@ -4,20 +4,15 @@ import java.nio.ByteBuffer; import org.lwjgl.opengl.GL15; -public abstract class MappedBuffer implements AutoCloseable { +public abstract class MappedBuffer extends VecBuffer implements AutoCloseable { protected boolean mapped; protected final GlBuffer owner; - protected ByteBuffer internal; public MappedBuffer(GlBuffer owner) { this.owner = owner; } - public void setInternal(ByteBuffer internal) { - this.internal = internal; - } - protected abstract void checkAndMap(); /** @@ -38,20 +33,13 @@ public abstract class MappedBuffer implements AutoCloseable { public MappedBuffer putFloatArray(float[] floats) { checkAndMap(); - - for (float f : floats) { - internal.putFloat(f); - } -// internal.asFloatBuffer().put(floats); -// internal.position(internal.position() + floats.length * 4); - + super.putFloatArray(floats); return this; } public MappedBuffer putByteArray(byte[] bytes) { checkAndMap(); - internal.put(bytes); - + super.putByteArray(bytes); return this; } @@ -62,75 +50,61 @@ public abstract class MappedBuffer implements AutoCloseable { */ public MappedBuffer position(int p) { checkAndMap(); - internal.position(p); + super.position(p); return this; } public MappedBuffer putFloat(float f) { checkAndMap(); - internal.putFloat(f); + super.putFloat(f); return this; } public MappedBuffer putInt(int i) { checkAndMap(); - internal.putInt(i); + super.putInt(i); return this; } public MappedBuffer put(byte b) { checkAndMap(); - internal.put(b); + super.put(b); return this; } public MappedBuffer put(ByteBuffer b) { checkAndMap(); - internal.put(b); + super.put(b); return this; } public MappedBuffer putVec4(float x, float y, float z, float w) { checkAndMap(); - internal.putFloat(x); - internal.putFloat(y); - internal.putFloat(z); - internal.putFloat(w); - + super.putVec4(x, y, z, w); return this; } public MappedBuffer putVec3(float x, float y, float z) { checkAndMap(); - internal.putFloat(x); - internal.putFloat(y); - internal.putFloat(z); - + super.putVec3(x, y, z); return this; } public MappedBuffer putVec2(float x, float y) { checkAndMap(); - internal.putFloat(x); - internal.putFloat(y); - + super.putVec2(x, y); return this; } public MappedBuffer putVec3(byte x, byte y, byte z) { checkAndMap(); - internal.put(x); - internal.put(y); - internal.put(z); - + super.putVec3(x, y, z); return this; } public MappedBuffer putVec2(byte x, byte y) { checkAndMap(); - internal.put(x); - internal.put(y); - + super.putVec2(x, y); return this; } } diff --git a/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/VecBuffer.java b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/VecBuffer.java new file mode 100644 index 000000000..03540e7fb --- /dev/null +++ b/src/main/java/com/jozufozu/flywheel/backend/gl/buffer/VecBuffer.java @@ -0,0 +1,116 @@ +package com.jozufozu.flywheel.backend.gl.buffer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class VecBuffer { + + protected ByteBuffer internal; + + public VecBuffer() { + } + + public VecBuffer(ByteBuffer internal) { + this.internal = internal; + } + + public static VecBuffer allocate(int bytes) { + ByteBuffer buffer = ByteBuffer.allocate(bytes); + buffer.order(ByteOrder.nativeOrder()); + return new VecBuffer(buffer); + } + + protected void setInternal(ByteBuffer internal) { + this.internal = internal; + } + + public ByteBuffer unwrap() { + return internal; + } + + public VecBuffer rewind() { + internal.rewind(); + + return this; + } + + public VecBuffer putFloatArray(float[] floats) { + + for (float f : floats) { + internal.putFloat(f); + } +// internal.asFloatBuffer().put(floats); +// internal.position(internal.position() + floats.length * 4); + + return this; + } + + public VecBuffer putByteArray(byte[] bytes) { + internal.put(bytes); + return this; + } + + /** + * Position this buffer relative to the 0-index in GPU memory. + * + * @return This buffer. + */ + public VecBuffer position(int p) { + internal.position(p); + return this; + } + + public VecBuffer putFloat(float f) { + internal.putFloat(f); + return this; + } + + public VecBuffer putInt(int i) { + internal.putInt(i); + return this; + } + + public VecBuffer put(byte b) { + internal.put(b); + return this; + } + + public VecBuffer put(ByteBuffer b) { + internal.put(b); + return this; + } + + public VecBuffer putVec4(float x, float y, float z, float w) { + internal.putFloat(x); + internal.putFloat(y); + internal.putFloat(z); + internal.putFloat(w); + return this; + } + + public VecBuffer putVec3(float x, float y, float z) { + internal.putFloat(x); + internal.putFloat(y); + internal.putFloat(z); + return this; + } + + public VecBuffer putVec2(float x, float y) { + internal.putFloat(x); + internal.putFloat(y); + return this; + } + + public VecBuffer putVec3(byte x, byte y, byte z) { + internal.put(x); + internal.put(y); + internal.put(z); + return this; + } + + public VecBuffer putVec2(byte x, byte y) { + internal.put(x); + internal.put(y); + return this; + } +} diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceMaterial.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceMaterial.java index cea5c9094..6f1a1a63e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceMaterial.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/InstanceMaterial.java @@ -54,6 +54,10 @@ public class InstanceMaterial { modelFormat = this.spec.getModelFormat(); } + public boolean nothingToRender() { + return models.size() > 0 && models.asMap().values().stream().allMatch(Instancer::empty); + } + public void delete() { models.invalidateAll(); } diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java index 1a35ba4ff..7cb3fafc5 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/Instancer.java @@ -80,6 +80,10 @@ public class Instancer { return instanceData; } + public boolean empty() { + return !anyToUpdate && !anyToRemove && glInstanceCount == 0; + } + /** * Clear all instance data without freeing resources. */ 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 8f64b5e79..96c18077e 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialManager.java @@ -13,6 +13,7 @@ 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.util.ResourceLocation; @@ -25,25 +26,28 @@ public class MaterialManager

{ public static int MAX_ORIGIN_DISTANCE = 100; - protected final ArrayList> renderers; - protected final Map> materials; + protected final WorldContext

context; + + protected final Map, InstanceMaterial> atlasMaterials; + protected final ArrayList> atlasRenderers; + + protected final Map>> renderers; + protected final Map, InstanceMaterial>> materials; private BlockPos originCoordinate = BlockPos.ZERO; private final WeakHashSet listeners; 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 ArrayList<>(Backend.getInstance().allMaterials().size()); + this.renderers = new HashMap<>(); + this.listeners = new WeakHashSet<>(); - - for (MaterialSpec spec : Backend.getInstance().allMaterials()) { - InstanceMaterial material = new InstanceMaterial<>(this::getOriginCoordinate, spec); - materials.put(spec.name, material); - MaterialRenderer

renderer = new MaterialRenderer<>(context.getProgram(spec.getProgramName()), material); - renderers.add(renderer); - } - } /** @@ -72,20 +76,47 @@ public class MaterialManager

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

material : renderers) { + for (MaterialRenderer

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

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

{ originCoordinate = new BlockPos(cX, cY, cZ); - materials.values().forEach(InstanceMaterial::clear); + materials.values().stream().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/instancing/MaterialRenderer.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialRenderer.java index 85f4a3581..1a8b8d1da 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialRenderer.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialRenderer.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.backend.instancing; +import java.util.function.Supplier; + import com.jozufozu.flywheel.core.shader.IProgramCallback; import com.jozufozu.flywheel.core.shader.WorldProgram; @@ -8,17 +10,21 @@ import net.minecraft.util.math.vector.Matrix4f; public class MaterialRenderer

{ - private final P program; + private final Supplier

program; private final InstanceMaterial material; - public MaterialRenderer(P program, InstanceMaterial material) { - this.program = program; + public MaterialRenderer(Supplier

programSupplier, InstanceMaterial material) { + this.program = programSupplier; this.material = material; } public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ, IProgramCallback

setup) { if (!(layer == RenderType.getCutoutMipped())) return; + if (material.nothingToRender()) return; + + P program = this.program.get(); + program.bind(); program.uploadViewProjection(viewProjection); program.uploadCameraPos(camX, camY, camZ); diff --git a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialSpec.java b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialSpec.java index b50b3e214..405bc4772 100644 --- a/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialSpec.java +++ b/src/main/java/com/jozufozu/flywheel/backend/instancing/MaterialSpec.java @@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing; import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat; +import net.minecraft.inventory.container.PlayerContainer; import net.minecraft.util.ResourceLocation; public class MaterialSpec { @@ -12,13 +13,19 @@ public class MaterialSpec { private final VertexFormat modelFormat; private final VertexFormat instanceFormat; private final IInstanceFactory instanceFactory; + private final ResourceLocation texture; public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, IInstanceFactory instanceFactory) { + this(name, programSpec, modelFormat, instanceFormat, PlayerContainer.BLOCK_ATLAS_TEXTURE, instanceFactory); + } + + public MaterialSpec(ResourceLocation name, ResourceLocation programSpec, VertexFormat modelFormat, VertexFormat instanceFormat, ResourceLocation texture, IInstanceFactory instanceFactory) { this.name = name; this.programSpec = programSpec; this.modelFormat = modelFormat; this.instanceFormat = instanceFormat; this.instanceFactory = instanceFactory; + this.texture = texture; } public ResourceLocation getProgramName() { diff --git a/src/main/java/com/jozufozu/flywheel/core/shader/IMultiProgram.java b/src/main/java/com/jozufozu/flywheel/core/shader/IMultiProgram.java index 6b009a968..924a989a5 100644 --- a/src/main/java/com/jozufozu/flywheel/core/shader/IMultiProgram.java +++ b/src/main/java/com/jozufozu/flywheel/core/shader/IMultiProgram.java @@ -1,5 +1,7 @@ package com.jozufozu.flywheel.core.shader; +import java.util.function.Supplier; + import com.jozufozu.flywheel.backend.gl.shader.GlProgram; /** @@ -8,7 +10,7 @@ import com.jozufozu.flywheel.backend.gl.shader.GlProgram; * * @param

*/ -public interface IMultiProgram

{ +public interface IMultiProgram

extends Supplier

{ /** * Get the shader program most suited for the current game state. diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java index 2c8b9e65e..f05438baa 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/GlueInstance.java @@ -1,8 +1,6 @@ package com.simibubi.create.content.contraptions.components.structureMovement.glue; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - +import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; import com.jozufozu.flywheel.backend.instancing.ITickableInstance; import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.backend.instancing.MaterialManager; @@ -14,23 +12,28 @@ import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.instancing.ConditionalInstance; import com.jozufozu.flywheel.core.materials.OrientedData; import com.simibubi.create.AllItems; +import com.simibubi.create.Create; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.vector.Quaternion; import net.minecraft.util.math.vector.Vector3d; public class GlueInstance extends EntityInstance implements ITickableInstance { + private static final ResourceLocation TEXTURE = new ResourceLocation(Create.ID, "textures/entity/super_glue/slime.png"); + private final Quaternion rotation; protected ConditionalInstance model; - public GlueInstance(MaterialManager renderer, SuperGlueEntity entity) { - super(renderer, entity); - Instancer instancer = renderer.getMaterial(Materials.ORIENTED) + public GlueInstance(MaterialManager materialManager, SuperGlueEntity entity) { + super(materialManager, entity); + + Instancer instancer = materialManager.getMaterial(Materials.ORIENTED, TEXTURE) .get(entity.getType(), GlueInstance::supplyModel); Direction face = entity.getFacingDirection(); @@ -55,6 +58,7 @@ public class GlueInstance extends EntityInstance implements ITi private void positionModel(OrientedData model) { model.setPosition(getInstancePosition()) + .setPivot(0, 0, 0) .setRotation(rotation) .setSkyLight(15) .setBlockLight(15); @@ -93,24 +97,23 @@ public class GlueInstance extends EntityInstance implements ITi Vector3d a4 = plane.add(start); Vector3d b4 = plane.add(end); - ByteBuffer buffer = ByteBuffer.allocate(Formats.UNLIT_MODEL.getStride() * 8); - buffer.order(ByteOrder.nativeOrder()); + VecBuffer buffer = VecBuffer.allocate(Formats.UNLIT_MODEL.getStride() * 8); - // x, y, z,nx, ny,nz, u, v + // pos normal uv // inside quad - buffer.putFloat((float) a1.x).putFloat((float) a1.y).putFloat((float) a1.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(1f).putFloat(0f); - buffer.putFloat((float) a2.x).putFloat((float) a2.y).putFloat((float) a2.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(1f).putFloat(1f); - buffer.putFloat((float) a3.x).putFloat((float) a3.y).putFloat((float) a3.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(0f).putFloat(1f); - buffer.putFloat((float) a4.x).putFloat((float) a4.y).putFloat((float) a4.z).put((byte) 0).put((byte) 127).put((byte) 0).putFloat(0f).putFloat(0f); + buffer.putVec3((float) a1.x, (float) a1.y, (float) a1.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 0f); + buffer.putVec3((float) a2.x, (float) a2.y, (float) a2.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(1f, 1f); + buffer.putVec3((float) a3.x, (float) a3.y, (float) a3.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 1f); + buffer.putVec3((float) a4.x, (float) a4.y, (float) a4.z).putVec3((byte) 0, (byte) 0, (byte) -127).putVec2(0f, 0f); // outside quad - buffer.putFloat((float) b4.x).putFloat((float) b4.y).putFloat((float) b4.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(0f).putFloat(0f); - buffer.putFloat((float) b3.x).putFloat((float) b3.y).putFloat((float) b3.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(0f).putFloat(1f); - buffer.putFloat((float) b2.x).putFloat((float) b2.y).putFloat((float) b2.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(1f).putFloat(1f); - buffer.putFloat((float) b1.x).putFloat((float) b1.y).putFloat((float) b1.z).put((byte) 0).put((byte) -127).put((byte) 0).putFloat(1f).putFloat(0f); + buffer.putVec3((float) b4.x, (float) b4.y, (float) b4.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 0f); + buffer.putVec3((float) b3.x, (float) b3.y, (float) b3.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(0f, 1f); + buffer.putVec3((float) b2.x, (float) b2.y, (float) b2.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 1f); + buffer.putVec3((float) b1.x, (float) b1.y, (float) b1.z).putVec3((byte) 0, (byte) 0, (byte) 127).putVec2(1f, 0f); buffer.rewind(); - return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer, 8); + return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer.unwrap(), 8); } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMaterialManager.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMaterialManager.java index a6e6e2888..fc66294b9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMaterialManager.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/render/ContraptionMaterialManager.java @@ -15,7 +15,7 @@ public class ContraptionMaterialManager extends MaterialManager callback) { - for (MaterialRenderer material : renderers) { + for (MaterialRenderer material : atlasRenderers) { material.render(layer, viewProjection, camX, camY, camZ, callback); } }