diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 5340cbce7..e882743a2 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -78,6 +78,7 @@ public class ClientEvents { return; CreateClient.kineticRenderer.tick(); + FastContraptionRenderer.tick(); CreateClient.schematicSender.tick(); CreateClient.schematicAndQuillHandler.tick(); diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/ContraptionLighter.java b/src/main/java/com/simibubi/create/foundation/utility/render/ContraptionLighter.java index 3e2dd318b..1f7c3169d 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/render/ContraptionLighter.java +++ b/src/main/java/com/simibubi/create/foundation/utility/render/ContraptionLighter.java @@ -1,15 +1,16 @@ package com.simibubi.create.foundation.utility.render; +import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import net.minecraft.client.renderer.GLAllocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.Vec3i; import net.minecraft.world.LightType; import net.minecraft.world.World; import net.minecraft.world.lighting.WorldLightManager; -import org.lwjgl.opengl.GL11; -import org.lwjgl.opengl.GL12; -import org.lwjgl.opengl.GL40; +import org.lwjgl.opengl.*; import java.nio.ByteBuffer; import java.nio.FloatBuffer; @@ -27,6 +28,8 @@ public class ContraptionLighter { ByteBuffer lightVolume; + boolean dirty; + int texture; public ContraptionLighter(Contraption contraption) { @@ -34,53 +37,114 @@ public class ContraptionLighter { AxisAlignedBB bounds = contraption.bounds; - int minX = (int) Math.floor(bounds.minX); - int minY = (int) Math.floor(bounds.minY); - int minZ = (int) Math.floor(bounds.minZ); - int maxX = (int) Math.ceil(bounds.maxX); - int maxY = (int) Math.ceil(bounds.maxY); - int maxZ = (int) Math.ceil(bounds.maxZ); + int minX = (int) Math.floor(bounds.minX) - 1; + int minY = (int) Math.floor(bounds.minY) - 1; + int minZ = (int) Math.floor(bounds.minZ) - 1; + int maxX = (int) Math.ceil(bounds.maxX) + 1; + int maxY = (int) Math.ceil(bounds.maxY) + 1; + int maxZ = (int) Math.ceil(bounds.maxZ) + 1; - sizeX = maxX - minX; - sizeY = maxY - minY; - sizeZ = maxZ - minZ; + sizeX = nextPowerOf2(maxX - minX); + sizeY = nextPowerOf2(maxY - minY); + sizeZ = nextPowerOf2(maxZ - minZ); lightVolume = GLAllocation.createDirectByteBuffer(sizeX * sizeY * sizeZ * 2); + + tick(contraption); + } + + public static int nextPowerOf2(int a) { + int h = Integer.highestOneBit(a); + return (h == a) ? h : (h << 1); + } + + public int getSizeX() { + return sizeX; + } + + public int getSizeY() { + return sizeY; + } + + public int getSizeZ() { + return sizeZ; + } + + public int getMinX() { + return minX; + } + + public int getMinY() { + return minY; + } + + public int getMinZ() { + return minZ; } public void delete() { - GL11.glDeleteTextures(texture); + CreateClient.kineticRenderer.enqueue(() -> { + GL15.glDeleteTextures(texture); + }); } - public void tick() { - + private void setupPosition(Contraption c) { + Vec3d positionVec = c.entity.getPositionVec(); + minX = (int) (Math.floor(positionVec.x) - sizeX / 2); + minY = (int) (Math.floor(positionVec.y)); + minZ = (int) (Math.floor(positionVec.z) - sizeZ / 2); } - public void addLightData(World world, BlockPos pos) { + public void tick(Contraption c) { + setupPosition(c); - int contraptionX = pos.getX() - minX; - int contraptionY = pos.getY() - minY; - int contraptionZ = pos.getZ() - minZ; + World world = c.entity.world; - if (contraptionX < 0 || contraptionX >= sizeX || contraptionY < 0 || contraptionY >= sizeY || contraptionZ < 0 || contraptionZ >= sizeZ) - return; + BlockPos.Mutable pos = new BlockPos.Mutable(); - int blockLight = world.getLightLevel(LightType.BLOCK, pos); - int skyLight = world.getLightLevel(LightType.SKY, pos); + for (int x = 0; x < sizeX; x++) { + for (int y = 0; y < sizeY; y++) { + for (int z = 0; z < sizeZ; z++) { + pos.setPos(minX + x, minY + y, minZ + z); - writeLight(contraptionX, contraptionY, contraptionZ, blockLight, skyLight); + int blockLight = world.getLightLevel(LightType.BLOCK, pos); + int skyLight = world.getLightLevel(LightType.SKY, pos); + + writeLight(x, y, z, blockLight, skyLight); + } + } + } + + dirty = true; } private void writeLight(int x, int y, int z, int block, int sky) { - int i = (x + y * sizeX + z * sizeX * sizeY) * 2; + int i = (x + sizeX * (y + z * sizeY)) * 2; - lightVolume.put(i, (byte) (block * 16)); - lightVolume.put(i + 1, (byte) (sky * 16)); + byte b = (byte) ((block & 0xF) << 4); + byte s = (byte) ((sky & 0xF) << 4); + + lightVolume.put(i, b); + lightVolume.put(i + 1, s); } public void use() { + GL13.glEnable(GL31.GL_TEXTURE_3D); + GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4); GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture); - lightVolume.rewind(); - GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume); + if (dirty) { + GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume); + dirty = false; + } + GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR); + GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR); + GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP); + GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL13.GL_CLAMP); + GL40.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP); + } + + public void release() { + GL13.glActiveTexture(GL40.GL_TEXTURE0 + 4); + GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0); } } diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/FastContraptionRenderer.java b/src/main/java/com/simibubi/create/foundation/utility/render/FastContraptionRenderer.java index 7871e86de..fe42d7368 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/render/FastContraptionRenderer.java +++ b/src/main/java/com/simibubi/create/foundation/utility/render/FastContraptionRenderer.java @@ -14,18 +14,20 @@ import net.minecraft.client.renderer.color.BlockColors; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraftforge.client.event.RenderWorldLastEvent; +import org.lwjgl.opengl.GL12; import org.lwjgl.opengl.GL13; import org.lwjgl.opengl.GL40; import java.nio.FloatBuffer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; public class FastContraptionRenderer extends ContraptionRenderer { - private static final Cache renderers = CacheBuilder.newBuilder().build(); + private static final HashMap renderers = new HashMap<>(); private ArrayList renderLayers = new ArrayList<>(); @@ -43,33 +45,48 @@ public class FastContraptionRenderer extends ContraptionRenderer { buildLayers(); } + public static void tick() { + if (Minecraft.getInstance().isGamePaused()) return; + + CreateClient.kineticRenderer.enqueue(() -> { + for (FastContraptionRenderer renderer : renderers.values()) { + renderer.lighter.tick(renderer.c); + } + }); + } + private void setRenderSettings(Vec3d position, Vec3d rotation) { renderPos = position; renderRot = rotation; } private void render(int shader) { -// GL13.glActiveTexture(GL40.GL_TEXTURE2); -// lighter.use(); - - int cSize = GlStateManager.getUniformLocation(shader, "cSize"); - int cPos = GlStateManager.getUniformLocation(shader, "cPos"); - int cRot = GlStateManager.getUniformLocation(shader, "cRot"); + lighter.use(); FloatBuffer buf = ShaderHelper.VEC3_BUFFER; - buf.put(0, (float) c.bounds.getXSize()); - buf.put(1, (float) c.bounds.getYSize()); - buf.put(2, (float) c.bounds.getZSize()); + int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize"); + buf.put(0, (float) lighter.getSizeX()); + buf.put(1, (float) lighter.getSizeY()); + buf.put(2, (float) lighter.getSizeZ()); buf.rewind(); - GlStateManager.uniform3(cSize, buf); + GlStateManager.uniform3(lightBoxSize, buf); + int lightBoxMin = GlStateManager.getUniformLocation(shader, "lightBoxMin"); + buf.put(0, (float) lighter.getMinX()); + buf.put(1, (float) lighter.getMinY()); + buf.put(2, (float) lighter.getMinZ()); + buf.rewind(); + GlStateManager.uniform3(lightBoxMin, buf); + + int cPos = GlStateManager.getUniformLocation(shader, "cPos"); buf.put(0, (float) renderPos.x); buf.put(1, (float) renderPos.y); buf.put(2, (float) renderPos.z); buf.rewind(); GlStateManager.uniform3(cPos, buf); + int cRot = GlStateManager.getUniformLocation(shader, "cRot"); buf.put(0, (float) renderRot.x); buf.put(1, (float) renderRot.y); buf.put(2, (float) renderRot.z); @@ -79,6 +96,8 @@ public class FastContraptionRenderer extends ContraptionRenderer { for (ContraptionBuffer layer : renderLayers) { layer.render(); } + + lighter.release(); } private void buildLayers() { @@ -86,8 +105,7 @@ public class FastContraptionRenderer extends ContraptionRenderer { List blockLayers = RenderType.getBlockLayers(); - for (int i = 0; i < blockLayers.size(); i++) { - RenderType layer = blockLayers.get(i); + for (RenderType layer : blockLayers) { renderLayers.add(buildStructureBuffer(c, layer)); } } @@ -96,6 +114,7 @@ public class FastContraptionRenderer extends ContraptionRenderer { for (ContraptionBuffer buffer : renderLayers) { buffer.invalidate(); } + lighter.delete(); renderLayers.clear(); } @@ -105,12 +124,16 @@ public class FastContraptionRenderer extends ContraptionRenderer { } private static FastContraptionRenderer getRenderer(World world, Contraption c) { - try { - return renderers.get(c.entity.getEntityId(), () -> new FastContraptionRenderer(world, c)); - } catch (ExecutionException e) { - e.printStackTrace(); - return null; + FastContraptionRenderer renderer; + int entityId = c.entity.getEntityId(); + if (renderers.containsKey(entityId)) { + renderer = renderers.get(entityId); + } else { + renderer = new FastContraptionRenderer(world, c); + renderers.put(entityId, renderer); } + + return renderer; } public static void renderAll(RenderWorldLastEvent event) { @@ -123,7 +146,7 @@ public class FastContraptionRenderer extends ContraptionRenderer { ArrayList toRemove = new ArrayList<>(); - for (FastContraptionRenderer renderer : renderers.asMap().values()) { + for (FastContraptionRenderer renderer : renderers.values()) { if (renderer.c.entity.isAlive()) renderer.render(shader); else @@ -134,15 +157,17 @@ public class FastContraptionRenderer extends ContraptionRenderer { CreateClient.kineticRenderer.teardown(); - renderers.invalidateAll(toRemove); + for (Integer id : toRemove) { + renderers.remove(id); + } } public static void invalidateAll() { - for (FastContraptionRenderer renderer : renderers.asMap().values()) { + for (FastContraptionRenderer renderer : renderers.values()) { renderer.invalidate(); } - renderers.invalidateAll(); + renderers.clear(); } private static ContraptionBuffer buildStructureBuffer(Contraption c, RenderType layer) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/instancing/InstanceBuffer.java b/src/main/java/com/simibubi/create/foundation/utility/render/instancing/InstanceBuffer.java index ec46b91f6..e849f5dfa 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/render/instancing/InstanceBuffer.java +++ b/src/main/java/com/simibubi/create/foundation/utility/render/instancing/InstanceBuffer.java @@ -124,7 +124,7 @@ public abstract class InstanceBuffer extends TemplateBuf GL30.glBindVertexArray(vao); finishBuffering(); - int numAttributes = getInstanceFormat().getNumAttributes() + 3; + int numAttributes = getInstanceFormat().getNumAttributes() + FORMAT.getNumAttributes(); for (int i = 0; i <= numAttributes; i++) { GL40.glEnableVertexAttribArray(i); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/render/shader/Shader.java b/src/main/java/com/simibubi/create/foundation/utility/render/shader/Shader.java index 0820adff9..e3f06bee5 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/render/shader/Shader.java +++ b/src/main/java/com/simibubi/create/foundation/utility/render/shader/Shader.java @@ -3,7 +3,7 @@ package com.simibubi.create.foundation.utility.render.shader; public enum Shader { ROTATING_INSTANCED("shader/rotating.vert", "shader/instanced.frag"), BELT_INSTANCED("shader/belt.vert", "shader/instanced.frag"), - CONTRAPTION_STRUCTURE("shader/contraption_static.vert", "shader/instanced.frag"), + CONTRAPTION_STRUCTURE("shader/contraption.vert", "shader/contraption.frag"), ; public final String vert; diff --git a/src/main/resources/assets/create/shader/belt.vert b/src/main/resources/assets/create/shader/belt.vert index fa9a03d32..c40dfd83f 100644 --- a/src/main/resources/assets/create/shader/belt.vert +++ b/src/main/resources/assets/create/shader/belt.vert @@ -15,7 +15,6 @@ layout (location = 9) in float scrollMult; out vec2 TexCoords; out vec2 Light; -out vec4 Color; out float Diffuse; uniform float time; @@ -54,7 +53,6 @@ void main() { float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult; Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); - Color = vec4(1f); Light = light; TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll); gl_Position = projection * view * renderPos; diff --git a/src/main/resources/assets/create/shader/contraption.frag b/src/main/resources/assets/create/shader/contraption.frag new file mode 100644 index 000000000..0d5fbe4a3 --- /dev/null +++ b/src/main/resources/assets/create/shader/contraption.frag @@ -0,0 +1,24 @@ +#version 440 core + +in vec2 TexCoords; +in vec4 Color; +in float Diffuse; +in vec3 BoxCoord; + +out vec4 fragColor; + +layout(binding=0) uniform sampler2D BlockAtlas; +layout(binding=1) uniform sampler2D LightMap; +layout(binding=4) uniform sampler3D LightVolume; + +vec4 light() { + vec2 lm = texture(LightVolume, BoxCoord).rg * 0.9375 + 0.03125; + return texture2D(LightMap, lm); +} + + +void main() { + vec4 tex = texture2D(BlockAtlas, TexCoords); + + fragColor = vec4(tex.rgb * light().rgb * Diffuse, tex.a); +} \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/contraption_static.vert b/src/main/resources/assets/create/shader/contraption.vert similarity index 91% rename from src/main/resources/assets/create/shader/contraption_static.vert rename to src/main/resources/assets/create/shader/contraption.vert index 310c82f25..44d4795c7 100644 --- a/src/main/resources/assets/create/shader/contraption_static.vert +++ b/src/main/resources/assets/create/shader/contraption.vert @@ -8,12 +8,11 @@ layout (location = 3) in vec4 aColor; out float Diffuse; out vec2 TexCoords; -out vec2 Light; out vec4 Color; +out vec3 BoxCoord; -layout (binding = 2) uniform sampler3D lightVolume; - -uniform vec3 cSize; +uniform vec3 lightBoxSize; +uniform vec3 lightBoxMin; uniform vec3 cPos; uniform vec3 cRot; @@ -53,13 +52,13 @@ void main() { vec4 worldPos = rotatedPos + vec4(cPos + vec3(0.5), 0); - vec3 boxCoord = (worldPos.xyz - cPos - cSize * 0.5) / cSize; + vec3 boxCoord = (worldPos.xyz - lightBoxMin) / lightBoxSize; float df = diffuse(normalize(aNormal)); Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); Color = vec4(aColor.rgb / df, aColor.a); - Light = vec2(1.); + BoxCoord = boxCoord; TexCoords = aTexCoords; gl_Position = projection * view * worldPos; } diff --git a/src/main/resources/assets/create/shader/instanced.frag b/src/main/resources/assets/create/shader/instanced.frag index 9ef766648..8172975c0 100644 --- a/src/main/resources/assets/create/shader/instanced.frag +++ b/src/main/resources/assets/create/shader/instanced.frag @@ -2,7 +2,6 @@ in vec2 TexCoords; in vec2 Light; -in vec4 Color; in float Diffuse; out vec4 fragColor; @@ -15,11 +14,8 @@ vec4 light() { return texture2D(LightMap, lm); } - void main() { vec4 tex = texture2D(BlockAtlas, TexCoords); - tex *= vec4(light().rgb * Diffuse, 1); - - fragColor = tex; + fragColor = vec4(tex.rgb * light().rgb * Diffuse, tex.a); } \ No newline at end of file diff --git a/src/main/resources/assets/create/shader/rotating.vert b/src/main/resources/assets/create/shader/rotating.vert index c5ffa4aa2..b1e2a4ab1 100644 --- a/src/main/resources/assets/create/shader/rotating.vert +++ b/src/main/resources/assets/create/shader/rotating.vert @@ -12,7 +12,6 @@ layout (location = 7) in vec3 rotationAxis; out vec2 TexCoords; out vec2 Light; -out vec4 Color; out float Diffuse; uniform float time; @@ -48,7 +47,6 @@ void main() { renderPos += vec4(instancePos + vec3(0.5), 0); Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz)); - Color = vec4(1f); TexCoords = aTexCoords; gl_Position = projection * view * renderPos; Light = light;