mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-16 12:13:42 +01:00
on our way to super fancy contraption lighting
This commit is contained in:
parent
0cb18c532d
commit
22a90c8e5d
24 changed files with 810 additions and 394 deletions
|
@ -16,7 +16,8 @@ import com.simibubi.create.foundation.block.render.CustomBlockModels;
|
||||||
import com.simibubi.create.foundation.block.render.SpriteShifter;
|
import com.simibubi.create.foundation.block.render.SpriteShifter;
|
||||||
import com.simibubi.create.foundation.item.CustomItemModels;
|
import com.simibubi.create.foundation.item.CustomItemModels;
|
||||||
import com.simibubi.create.foundation.item.CustomRenderedItems;
|
import com.simibubi.create.foundation.item.CustomRenderedItems;
|
||||||
import com.simibubi.create.foundation.render.FastContraptionRenderer;
|
import com.simibubi.create.foundation.render.ContraptionRenderDispatcher;
|
||||||
|
import com.simibubi.create.foundation.render.RenderedContraption;
|
||||||
import com.simibubi.create.foundation.render.FastKineticRenderer;
|
import com.simibubi.create.foundation.render.FastKineticRenderer;
|
||||||
import com.simibubi.create.foundation.render.SuperByteBufferCache;
|
import com.simibubi.create.foundation.render.SuperByteBufferCache;
|
||||||
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
import com.simibubi.create.foundation.utility.outliner.Outliner;
|
||||||
|
@ -182,6 +183,6 @@ public class CreateClient {
|
||||||
public static void invalidateRenderers() {
|
public static void invalidateRenderers() {
|
||||||
CreateClient.bufferCache.invalidate();
|
CreateClient.bufferCache.invalidate();
|
||||||
CreateClient.kineticRenderer.invalidate();
|
CreateClient.kineticRenderer.invalidate();
|
||||||
FastContraptionRenderer.invalidateAll();
|
ContraptionRenderDispatcher.invalidateAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
|
||||||
import com.simibubi.create.foundation.render.FastContraptionRenderer;
|
import com.simibubi.create.foundation.render.ContraptionRenderDispatcher;
|
||||||
|
import com.simibubi.create.foundation.render.RenderedContraption;
|
||||||
|
import net.java.games.input.Controller;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||||
import net.minecraft.client.renderer.culling.ClippingHelperImpl;
|
import net.minecraft.client.renderer.culling.ClippingHelperImpl;
|
||||||
|
@ -50,7 +52,7 @@ public abstract class AbstractContraptionEntityRenderer<C extends AbstractContra
|
||||||
Contraption contraption = entity.getContraption();
|
Contraption contraption = entity.getContraption();
|
||||||
if (contraption != null) {
|
if (contraption != null) {
|
||||||
ContraptionRenderer.renderDynamic(entity.world, contraption, ms, msLocal, buffers);
|
ContraptionRenderer.renderDynamic(entity.world, contraption, ms, msLocal, buffers);
|
||||||
FastContraptionRenderer.markForRendering(entity.world, contraption, msLocal);
|
ContraptionRenderDispatcher.markForRendering(entity.world, contraption, msLocal);
|
||||||
}
|
}
|
||||||
ms.pop();
|
ms.pop();
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,10 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||||
|
import com.simibubi.create.foundation.render.light.EmptyLighter;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import org.apache.commons.lang3.tuple.MutablePair;
|
import org.apache.commons.lang3.tuple.MutablePair;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
@ -956,4 +960,9 @@ public abstract class Contraption {
|
||||||
mountedFluidStorage.updateFluid(containedFluid);
|
mountedFluidStorage.updateFluid(containedFluid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public ContraptionLighter<?> makeLighter() {
|
||||||
|
return new EmptyLighter(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -84,7 +84,7 @@ public class ContraptionRenderer {
|
||||||
return new SuperByteBuffer(builder);
|
return new SuperByteBuffer(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static BufferBuilder buildStructure(Contraption c, RenderType layer) {
|
public static BufferBuilder buildStructure(Contraption c, RenderType layer) {
|
||||||
if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world)
|
if (renderWorld == null || renderWorld.getWorld() != Minecraft.getInstance().world)
|
||||||
renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world);
|
renderWorld = new PlacementSimulationWorld(Minecraft.getInstance().world);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
|
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.simibubi.create.AllTags.AllBlockTags;
|
import com.simibubi.create.AllTags.AllBlockTags;
|
||||||
|
@ -88,4 +91,9 @@ public class BearingContraption extends Contraption {
|
||||||
return axis == facing.getAxis();
|
return axis == facing.getAxis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
@Override
|
||||||
|
public ContraptionLighter<?> makeLighter() {
|
||||||
|
return new BearingLighter(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.simibubi.create.content.contraptions.components.structureMovement.bearing;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||||
|
import com.simibubi.create.foundation.render.light.GridAlignedBB;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
|
||||||
|
public class BearingLighter extends ContraptionLighter<BearingContraption> {
|
||||||
|
|
||||||
|
public BearingLighter(BearingContraption contraption) {
|
||||||
|
super(contraption);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GridAlignedBB getContraptionBounds() {
|
||||||
|
GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds);
|
||||||
|
localBounds.translate(contraption.anchor);
|
||||||
|
return localBounds;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import com.simibubi.create.foundation.networking.AllPackets;
|
||||||
import com.simibubi.create.foundation.networking.LeftClickPacket;
|
import com.simibubi.create.foundation.networking.LeftClickPacket;
|
||||||
import com.simibubi.create.foundation.render.FastRenderDispatcher;
|
import com.simibubi.create.foundation.render.FastRenderDispatcher;
|
||||||
import com.simibubi.create.foundation.render.RenderWork;
|
import com.simibubi.create.foundation.render.RenderWork;
|
||||||
|
import com.simibubi.create.foundation.render.light.LightVolumeDebugger;
|
||||||
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
|
import com.simibubi.create.foundation.tileEntity.behaviour.edgeInteraction.EdgeInteractionRenderer;
|
||||||
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
|
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringRenderer;
|
||||||
|
@ -118,7 +119,6 @@ public class ClientEvents {
|
||||||
Vec3d cameraPos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
|
Vec3d cameraPos = Minecraft.getInstance().gameRenderer.getActiveRenderInfo().getProjectedView();
|
||||||
|
|
||||||
MatrixStack ms = event.getMatrixStack();
|
MatrixStack ms = event.getMatrixStack();
|
||||||
ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
|
|
||||||
ms.push();
|
ms.push();
|
||||||
ms.translate(-cameraPos.getX(), -cameraPos.getY(), -cameraPos.getZ());
|
ms.translate(-cameraPos.getX(), -cameraPos.getY(), -cameraPos.getZ());
|
||||||
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
|
||||||
|
@ -126,6 +126,7 @@ public class ClientEvents {
|
||||||
CouplingRenderer.renderAll(ms, buffer);
|
CouplingRenderer.renderAll(ms, buffer);
|
||||||
CreateClient.schematicHandler.render(ms, buffer);
|
CreateClient.schematicHandler.render(ms, buffer);
|
||||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||||
|
LightVolumeDebugger.render(ms, buffer);
|
||||||
// CollisionDebugger.render(ms, buffer);
|
// CollisionDebugger.render(ms, buffer);
|
||||||
buffer.draw();
|
buffer.draw();
|
||||||
|
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
package com.simibubi.create.foundation.render;
|
|
||||||
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
import net.minecraft.world.LightType;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import org.lwjgl.opengl.*;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import static com.simibubi.create.foundation.render.RenderMath.nextPowerOf2;
|
|
||||||
|
|
||||||
public class ContraptionLighter {
|
|
||||||
|
|
||||||
private int minX;
|
|
||||||
private int minY;
|
|
||||||
private int minZ;
|
|
||||||
|
|
||||||
private final int sizeX;
|
|
||||||
private final int sizeY;
|
|
||||||
private final int sizeZ;
|
|
||||||
|
|
||||||
private SafeDirectBuffer lightVolume;
|
|
||||||
|
|
||||||
private boolean dirty;
|
|
||||||
|
|
||||||
private int texture;
|
|
||||||
|
|
||||||
public ContraptionLighter(Contraption contraption) {
|
|
||||||
texture = GL11.glGenTextures();
|
|
||||||
|
|
||||||
AxisAlignedBB bounds = contraption.bounds;
|
|
||||||
|
|
||||||
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 = nextPowerOf2(maxX - minX);
|
|
||||||
sizeY = nextPowerOf2(maxY - minY);
|
|
||||||
sizeZ = nextPowerOf2(maxZ - minZ);
|
|
||||||
|
|
||||||
lightVolume = new SafeDirectBuffer(sizeX * sizeY * sizeZ * 2);
|
|
||||||
|
|
||||||
update(contraption);
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
|
||||||
RenderWork.enqueue(() -> {
|
|
||||||
GL15.glDeleteTextures(texture);
|
|
||||||
texture = 0;
|
|
||||||
try {
|
|
||||||
lightVolume.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
lightVolume = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupPosition(Contraption c) {
|
|
||||||
Vec3d positionVec = c.entity.getPositionVec();
|
|
||||||
minX = (int) (Math.floor(positionVec.x) - sizeX / 2);
|
|
||||||
minY = (int) (Math.floor(positionVec.y) - 1);
|
|
||||||
minZ = (int) (Math.floor(positionVec.z) - sizeZ / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(Contraption c) {
|
|
||||||
if (lightVolume == null) return;
|
|
||||||
|
|
||||||
setupPosition(c);
|
|
||||||
|
|
||||||
World world = c.entity.world;
|
|
||||||
|
|
||||||
BlockPos.Mutable pos = new BlockPos.Mutable();
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
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 + sizeX * (y + z * sizeY)) * 2;
|
|
||||||
|
|
||||||
byte b = (byte) ((block & 0xF) << 4);
|
|
||||||
byte s = (byte) ((sky & 0xF) << 4);
|
|
||||||
|
|
||||||
lightVolume.put(i, b);
|
|
||||||
lightVolume.put(i + 1, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void use() {
|
|
||||||
if (texture == 0 || lightVolume == null) return;
|
|
||||||
|
|
||||||
GL12.glBindTexture(GL12.GL_TEXTURE_3D, texture);
|
|
||||||
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
|
|
||||||
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
|
|
||||||
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL13.GL_CLAMP);
|
|
||||||
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL13.GL_CLAMP);
|
|
||||||
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL13.GL_CLAMP);
|
|
||||||
if (dirty) {
|
|
||||||
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, sizeX, sizeY, sizeZ, 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightVolume.getBacking());
|
|
||||||
dirty = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void release() {
|
|
||||||
GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package com.simibubi.create.foundation.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||||
|
import com.simibubi.create.foundation.render.light.LightVolume;
|
||||||
|
import com.simibubi.create.foundation.render.shader.Shader;
|
||||||
|
import com.simibubi.create.foundation.render.shader.ShaderCallback;
|
||||||
|
import com.simibubi.create.foundation.render.shader.ShaderHelper;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.Matrix4f;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
|
import net.minecraft.world.LightType;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL13;
|
||||||
|
import org.lwjgl.opengl.GL40;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ContraptionRenderDispatcher {
|
||||||
|
public static final HashMap<Integer, RenderedContraption> renderers = new HashMap<>();
|
||||||
|
|
||||||
|
public static void markForRendering(World world, Contraption c, MatrixStack model) {
|
||||||
|
getRenderer(world, c).setRenderSettings(model.peek().getModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void notifyLightUpdate(ILightReader world, LightType type, SectionPos pos) {
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
renderer.getLighter().lightVolume.notifyLightUpdate(world, type, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RenderedContraption getRenderer(World world, Contraption c) {
|
||||||
|
RenderedContraption renderer;
|
||||||
|
int entityId = c.entity.getEntityId();
|
||||||
|
if (renderers.containsKey(entityId)) {
|
||||||
|
renderer = renderers.get(entityId);
|
||||||
|
} else {
|
||||||
|
renderer = new RenderedContraption(world, c);
|
||||||
|
renderers.put(entityId, renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void renderLayer(RenderType renderType, Matrix4f projectionMat, Matrix4f viewMat) {
|
||||||
|
removeDeadContraptions();
|
||||||
|
|
||||||
|
if (renderers.isEmpty()) return;
|
||||||
|
|
||||||
|
FastKineticRenderer.setup(Minecraft.getInstance().gameRenderer);
|
||||||
|
GL11.glEnable(GL13.GL_TEXTURE_3D);
|
||||||
|
GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4
|
||||||
|
|
||||||
|
ShaderCallback callback = ShaderHelper.getViewProjectionCallback(projectionMat, viewMat);
|
||||||
|
|
||||||
|
int structureShader = ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, callback);
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
renderer.doRenderLayer(renderType, structureShader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderType == FastKineticRenderer.getKineticRenderLayer()) {
|
||||||
|
int rotatingShader = ShaderHelper.useShader(Shader.CONTRAPTION_ROTATING, callback);
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
renderer.setup(rotatingShader);
|
||||||
|
renderer.kinetics.renderRotating();
|
||||||
|
renderer.teardown();
|
||||||
|
}
|
||||||
|
|
||||||
|
int beltShader = ShaderHelper.useShader(Shader.CONTRAPTION_BELT, callback);
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
renderer.setup(beltShader);
|
||||||
|
renderer.kinetics.renderBelts();
|
||||||
|
renderer.teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderHelper.releaseShader();
|
||||||
|
|
||||||
|
GL11.glDisable(GL13.GL_TEXTURE_3D);
|
||||||
|
FastKineticRenderer.teardown();
|
||||||
|
GL13.glActiveTexture(GL40.GL_TEXTURE0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeDeadContraptions() {
|
||||||
|
ArrayList<Integer> toRemove = new ArrayList<>();
|
||||||
|
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
if (renderer.isDead()) {
|
||||||
|
toRemove.add(renderer.getEntityId());
|
||||||
|
renderer.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer id : toRemove) {
|
||||||
|
renderers.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void invalidateAll() {
|
||||||
|
for (RenderedContraption renderer : renderers.values()) {
|
||||||
|
renderer.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderers.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,226 +0,0 @@
|
||||||
package com.simibubi.create.foundation.render;
|
|
||||||
|
|
||||||
import com.mojang.blaze3d.matrix.MatrixStack;
|
|
||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
|
||||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
|
|
||||||
import com.simibubi.create.foundation.render.instancing.IInstanceRendered;
|
|
||||||
import com.simibubi.create.foundation.render.instancing.IInstancedTileEntityRenderer;
|
|
||||||
import com.simibubi.create.foundation.render.shader.Shader;
|
|
||||||
import com.simibubi.create.foundation.render.shader.ShaderCallback;
|
|
||||||
import com.simibubi.create.foundation.render.shader.ShaderHelper;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
|
||||||
import net.minecraft.client.renderer.Matrix4f;
|
|
||||||
import net.minecraft.client.renderer.RenderType;
|
|
||||||
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
|
||||||
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
|
||||||
import net.minecraft.tileentity.TileEntity;
|
|
||||||
import net.minecraft.world.World;
|
|
||||||
import org.lwjgl.opengl.GL11;
|
|
||||||
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;
|
|
||||||
|
|
||||||
public class FastContraptionRenderer extends ContraptionRenderer {
|
|
||||||
|
|
||||||
private static final HashMap<Integer, FastContraptionRenderer> renderers = new HashMap<>();
|
|
||||||
|
|
||||||
private HashMap<RenderType, ContraptionBuffer> renderLayers = new HashMap<>();
|
|
||||||
|
|
||||||
private ContraptionLighter lighter;
|
|
||||||
|
|
||||||
public final FastKineticRenderer kinetics;
|
|
||||||
|
|
||||||
private Contraption c;
|
|
||||||
|
|
||||||
private Matrix4f model;
|
|
||||||
|
|
||||||
public FastContraptionRenderer(World world, Contraption c) {
|
|
||||||
this.c = c;
|
|
||||||
this.lighter = new ContraptionLighter(c);
|
|
||||||
this.kinetics = new FastKineticRenderer();
|
|
||||||
|
|
||||||
buildLayers(c);
|
|
||||||
buildInstancedTiles(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildLayers(Contraption c) {
|
|
||||||
for (ContraptionBuffer buffer : renderLayers.values()) {
|
|
||||||
buffer.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
renderLayers.clear();
|
|
||||||
|
|
||||||
List<RenderType> blockLayers = RenderType.getBlockLayers();
|
|
||||||
|
|
||||||
for (RenderType layer : blockLayers) {
|
|
||||||
renderLayers.put(layer, buildStructureBuffer(c, layer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildInstancedTiles(Contraption c) {
|
|
||||||
List<TileEntity> tileEntities = c.renderedTileEntities;
|
|
||||||
if (!tileEntities.isEmpty()) {
|
|
||||||
for (TileEntity te : tileEntities) {
|
|
||||||
if (te instanceof IInstanceRendered) {
|
|
||||||
TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(te);
|
|
||||||
|
|
||||||
if (renderer instanceof IInstancedTileEntityRenderer) {
|
|
||||||
kinetics.addInstancedData(this, te, (IInstancedTileEntityRenderer<? super TileEntity>) renderer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kinetics.markAllDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void tick() {
|
|
||||||
if (Minecraft.getInstance().isGamePaused()) return;
|
|
||||||
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
renderer.lighter.update(renderer.c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setRenderSettings(Matrix4f model) {
|
|
||||||
this.model = model;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setup(int shader) {
|
|
||||||
setupShaderUniforms(shader);
|
|
||||||
lighter.use();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void teardown() {
|
|
||||||
lighter.release();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupShaderUniforms(int shader) {
|
|
||||||
FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
|
|
||||||
|
|
||||||
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(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 model = GlStateManager.getUniformLocation(shader, "model");
|
|
||||||
this.model.write(ShaderHelper.MATRIX_BUFFER);
|
|
||||||
ShaderHelper.MATRIX_BUFFER.rewind();
|
|
||||||
GlStateManager.uniformMatrix4(model, false, ShaderHelper.MATRIX_BUFFER);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void invalidate() {
|
|
||||||
for (ContraptionBuffer buffer : renderLayers.values()) {
|
|
||||||
buffer.delete();
|
|
||||||
}
|
|
||||||
renderLayers.clear();
|
|
||||||
|
|
||||||
lighter.delete();
|
|
||||||
|
|
||||||
kinetics.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void markForRendering(World world, Contraption c, MatrixStack model) {
|
|
||||||
getRenderer(world, c).setRenderSettings(model.peek().getModel());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FastContraptionRenderer getRenderer(World world, Contraption c) {
|
|
||||||
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 renderLayer(RenderType renderType, Matrix4f projectionMat, Matrix4f viewMat) {
|
|
||||||
removeDeadContraptions();
|
|
||||||
|
|
||||||
if (renderers.isEmpty()) return;
|
|
||||||
|
|
||||||
FastKineticRenderer.setup(Minecraft.getInstance().gameRenderer);
|
|
||||||
GL11.glEnable(GL13.GL_TEXTURE_3D);
|
|
||||||
GL13.glActiveTexture(GL40.GL_TEXTURE4); // the shaders expect light volumes to be in texture 4
|
|
||||||
|
|
||||||
ShaderCallback callback = ShaderHelper.getViewProjectionCallback(projectionMat, viewMat);
|
|
||||||
|
|
||||||
int structureShader = ShaderHelper.useShader(Shader.CONTRAPTION_STRUCTURE, callback);
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
ContraptionBuffer buffer = renderer.renderLayers.get(renderType);
|
|
||||||
if (buffer != null) {
|
|
||||||
renderer.setup(structureShader);
|
|
||||||
buffer.render();
|
|
||||||
renderer.teardown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderType == FastKineticRenderer.getKineticRenderLayer()) {
|
|
||||||
int rotatingShader = ShaderHelper.useShader(Shader.CONTRAPTION_ROTATING, callback);
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
renderer.setup(rotatingShader);
|
|
||||||
renderer.kinetics.renderRotating();
|
|
||||||
renderer.teardown();
|
|
||||||
}
|
|
||||||
|
|
||||||
int beltShader = ShaderHelper.useShader(Shader.CONTRAPTION_BELT, callback);
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
renderer.setup(beltShader);
|
|
||||||
renderer.kinetics.renderBelts();
|
|
||||||
renderer.teardown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShaderHelper.releaseShader();
|
|
||||||
|
|
||||||
GL11.glDisable(GL13.GL_TEXTURE_3D);
|
|
||||||
FastKineticRenderer.teardown();
|
|
||||||
GL13.glActiveTexture(GL40.GL_TEXTURE0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeDeadContraptions() {
|
|
||||||
ArrayList<Integer> toRemove = new ArrayList<>();
|
|
||||||
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
if (!renderer.c.entity.isAlive()) {
|
|
||||||
toRemove.add(renderer.c.entity.getEntityId());
|
|
||||||
renderer.invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Integer id : toRemove) {
|
|
||||||
renderers.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void invalidateAll() {
|
|
||||||
for (FastContraptionRenderer renderer : renderers.values()) {
|
|
||||||
renderer.invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
renderers.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ContraptionBuffer buildStructureBuffer(Contraption c, RenderType layer) {
|
|
||||||
BufferBuilder builder = buildStructure(c, layer);
|
|
||||||
return new ContraptionBuffer(builder);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -70,7 +70,7 @@ public class FastKineticRenderer {
|
||||||
renderer.addInstanceData(new InstanceContext.World<>(te));
|
renderer.addInstanceData(new InstanceContext.World<>(te));
|
||||||
}
|
}
|
||||||
|
|
||||||
<T extends TileEntity> void addInstancedData(FastContraptionRenderer c, T te, IInstancedTileEntityRenderer<T> renderer) {
|
<T extends TileEntity> void addInstancedData(RenderedContraption c, T te, IInstancedTileEntityRenderer<T> renderer) {
|
||||||
renderer.addInstanceData(new InstanceContext.Contraption<>(te, c));
|
renderer.addInstanceData(new InstanceContext.Contraption<>(te, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ public class FastKineticRenderer {
|
||||||
runOnAll(InstanceBuffer::delete);
|
runOnAll(InstanceBuffer::delete);
|
||||||
belts.values().forEach(Cache::invalidateAll);
|
belts.values().forEach(Cache::invalidateAll);
|
||||||
rotating.values().forEach(Cache::invalidateAll);
|
rotating.values().forEach(Cache::invalidateAll);
|
||||||
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runOnAll(Consumer<InstanceBuffer<?>> f) {
|
private void runOnAll(Consumer<InstanceBuffer<?>> f) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import net.minecraft.potion.Effects;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.SectionPos;
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
import net.minecraft.world.LightType;
|
import net.minecraft.world.LightType;
|
||||||
import net.minecraft.world.chunk.Chunk;
|
import net.minecraft.world.chunk.Chunk;
|
||||||
|
|
||||||
|
@ -42,11 +43,11 @@ public class FastRenderDispatcher {
|
||||||
CreateClient.kineticRenderer.renderInstancesAsWorld(type, projection, view);
|
CreateClient.kineticRenderer.renderInstancesAsWorld(type, projection, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
FastContraptionRenderer.renderLayer(type, projection, view);
|
ContraptionRenderDispatcher.renderLayer(type, projection, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void notifyLightUpdate(ClientChunkProvider world, LightType type, SectionPos pos) {
|
public static void notifyLightUpdate(ClientChunkProvider world, LightType type, SectionPos pos) {
|
||||||
FastContraptionRenderer.tick();
|
ContraptionRenderDispatcher.notifyLightUpdate((ILightReader) world.getWorld(), type, pos);
|
||||||
|
|
||||||
Chunk chunk = world.getChunk(pos.getSectionX(), pos.getSectionZ(), false);
|
Chunk chunk = world.getChunk(pos.getSectionX(), pos.getSectionZ(), false);
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,9 @@ public class RenderMath {
|
||||||
int h = Integer.highestOneBit(a);
|
int h = Integer.highestOneBit(a);
|
||||||
return (h == a) ? h : (h << 1);
|
return (h == a) ? h : (h << 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPowerOf2(int n) {
|
||||||
|
int b = n & (n - 1);
|
||||||
|
return b == 0 && n != 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
package com.simibubi.create.foundation.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRenderer;
|
||||||
|
import com.simibubi.create.foundation.render.instancing.IInstanceRendered;
|
||||||
|
import com.simibubi.create.foundation.render.instancing.IInstancedTileEntityRenderer;
|
||||||
|
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||||
|
import com.simibubi.create.foundation.render.light.LightVolume;
|
||||||
|
import com.simibubi.create.foundation.render.shader.ShaderHelper;
|
||||||
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
|
import net.minecraft.client.renderer.Matrix4f;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.tileentity.TileEntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
|
import net.minecraft.world.LightType;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RenderedContraption {
|
||||||
|
private HashMap<RenderType, ContraptionBuffer> renderLayers = new HashMap<>();
|
||||||
|
|
||||||
|
private final ContraptionLighter<?> lighter;
|
||||||
|
|
||||||
|
public final FastKineticRenderer kinetics;
|
||||||
|
|
||||||
|
private Contraption contraption;
|
||||||
|
|
||||||
|
private Matrix4f model;
|
||||||
|
|
||||||
|
public RenderedContraption(World world, Contraption contraption) {
|
||||||
|
this.contraption = contraption;
|
||||||
|
this.lighter = contraption.makeLighter();
|
||||||
|
this.kinetics = new FastKineticRenderer();
|
||||||
|
|
||||||
|
buildLayers(contraption);
|
||||||
|
buildInstancedTiles(contraption);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEntityId() {
|
||||||
|
return contraption.entity.getEntityId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDead() {
|
||||||
|
return !contraption.entity.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContraptionLighter<?> getLighter() {
|
||||||
|
return lighter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doRenderLayer(RenderType layer, int shader) {
|
||||||
|
ContraptionBuffer buffer = renderLayers.get(layer);
|
||||||
|
if (buffer != null) {
|
||||||
|
setup(shader);
|
||||||
|
buffer.render();
|
||||||
|
teardown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildLayers(Contraption c) {
|
||||||
|
for (ContraptionBuffer buffer : renderLayers.values()) {
|
||||||
|
buffer.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
renderLayers.clear();
|
||||||
|
|
||||||
|
List<RenderType> blockLayers = RenderType.getBlockLayers();
|
||||||
|
|
||||||
|
for (RenderType layer : blockLayers) {
|
||||||
|
renderLayers.put(layer, buildStructureBuffer(c, layer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildInstancedTiles(Contraption c) {
|
||||||
|
List<TileEntity> tileEntities = c.renderedTileEntities;
|
||||||
|
if (!tileEntities.isEmpty()) {
|
||||||
|
for (TileEntity te : tileEntities) {
|
||||||
|
if (te instanceof IInstanceRendered) {
|
||||||
|
TileEntityRenderer<TileEntity> renderer = TileEntityRendererDispatcher.instance.getRenderer(te);
|
||||||
|
|
||||||
|
if (renderer instanceof IInstancedTileEntityRenderer) {
|
||||||
|
kinetics.addInstancedData(this, te, (IInstancedTileEntityRenderer<? super TileEntity>) renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kinetics.markAllDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRenderSettings(Matrix4f model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup(int shader) {
|
||||||
|
setupShaderUniforms(shader);
|
||||||
|
lighter.lightVolume.use();
|
||||||
|
}
|
||||||
|
|
||||||
|
void teardown() {
|
||||||
|
lighter.lightVolume.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupShaderUniforms(int shader) {
|
||||||
|
FloatBuffer buf = ShaderHelper.VEC3_BUFFER;
|
||||||
|
|
||||||
|
int lightBoxSize = GlStateManager.getUniformLocation(shader, "lightBoxSize");
|
||||||
|
buf.put(0, (float) lighter.lightVolume.getSizeX());
|
||||||
|
buf.put(1, (float) lighter.lightVolume.getSizeY());
|
||||||
|
buf.put(2, (float) lighter.lightVolume.getSizeZ());
|
||||||
|
buf.rewind();
|
||||||
|
GlStateManager.uniform3(lightBoxSize, buf);
|
||||||
|
|
||||||
|
int lightBoxMin = GlStateManager.getUniformLocation(shader, "lightBoxMin");
|
||||||
|
buf.put(0, (float) lighter.lightVolume.getMinX());
|
||||||
|
buf.put(1, (float) lighter.lightVolume.getMinY());
|
||||||
|
buf.put(2, (float) lighter.lightVolume.getMinZ());
|
||||||
|
buf.rewind();
|
||||||
|
GlStateManager.uniform3(lightBoxMin, buf);
|
||||||
|
|
||||||
|
int model = GlStateManager.getUniformLocation(shader, "model");
|
||||||
|
this.model.write(ShaderHelper.MATRIX_BUFFER);
|
||||||
|
ShaderHelper.MATRIX_BUFFER.rewind();
|
||||||
|
GlStateManager.uniformMatrix4(model, false, ShaderHelper.MATRIX_BUFFER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void invalidate() {
|
||||||
|
for (ContraptionBuffer buffer : renderLayers.values()) {
|
||||||
|
buffer.delete();
|
||||||
|
}
|
||||||
|
renderLayers.clear();
|
||||||
|
|
||||||
|
lighter.lightVolume.delete();
|
||||||
|
|
||||||
|
kinetics.invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ContraptionBuffer buildStructureBuffer(Contraption c, RenderType layer) {
|
||||||
|
BufferBuilder builder = ContraptionRenderer.buildStructure(c, layer);
|
||||||
|
return new ContraptionBuffer(builder);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package com.simibubi.create.foundation.render.instancing;
|
package com.simibubi.create.foundation.render.instancing;
|
||||||
|
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
import com.simibubi.create.foundation.render.FastContraptionRenderer;
|
import com.simibubi.create.foundation.render.RenderedContraption;
|
||||||
import com.simibubi.create.foundation.render.FastKineticRenderer;
|
import com.simibubi.create.foundation.render.FastKineticRenderer;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
|
||||||
|
@ -19,9 +19,9 @@ public abstract class InstanceContext<T extends TileEntity> {
|
||||||
|
|
||||||
public static class Contraption<T extends TileEntity> extends InstanceContext<T> {
|
public static class Contraption<T extends TileEntity> extends InstanceContext<T> {
|
||||||
|
|
||||||
public final FastContraptionRenderer c;
|
public final RenderedContraption c;
|
||||||
|
|
||||||
public Contraption(T te, FastContraptionRenderer c) {
|
public Contraption(T te, RenderedContraption c) {
|
||||||
super(te);
|
super(te);
|
||||||
this.c = c;
|
this.c = c;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||||
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
|
import net.minecraft.world.LightType;
|
||||||
|
|
||||||
|
import static com.simibubi.create.foundation.render.RenderMath.nextPowerOf2;
|
||||||
|
|
||||||
|
public abstract class ContraptionLighter<C extends Contraption> {
|
||||||
|
protected final C contraption;
|
||||||
|
public final LightVolume lightVolume;
|
||||||
|
|
||||||
|
protected ContraptionLighter(C contraption) {
|
||||||
|
this.contraption = contraption;
|
||||||
|
|
||||||
|
GridAlignedBB bounds = getContraptionBounds();
|
||||||
|
bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts
|
||||||
|
bounds.nextPowerOf2Centered();
|
||||||
|
|
||||||
|
lightVolume = new LightVolume(bounds);
|
||||||
|
|
||||||
|
lightVolume.initialize(contraption.entity.world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract GridAlignedBB getContraptionBounds();
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface CoordinateConsumer {
|
||||||
|
void consume(int x, int y, int z);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||||
|
|
||||||
|
// so other contraptions don't crash before they have a lighter
|
||||||
|
public class EmptyLighter extends ContraptionLighter<Contraption> {
|
||||||
|
public EmptyLighter(Contraption contraption) {
|
||||||
|
super(contraption);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GridAlignedBB getContraptionBounds() {
|
||||||
|
return new GridAlignedBB(0, 0, 0, 1, 1, 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.RenderMath;
|
||||||
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
import net.minecraft.world.LightType;
|
||||||
|
|
||||||
|
import java.util.function.IntFunction;
|
||||||
|
|
||||||
|
import static com.simibubi.create.foundation.render.RenderMath.isPowerOf2;
|
||||||
|
|
||||||
|
public class GridAlignedBB {
|
||||||
|
public int minX;
|
||||||
|
public int minY;
|
||||||
|
public int minZ;
|
||||||
|
public int maxX;
|
||||||
|
public int maxY;
|
||||||
|
public int maxZ;
|
||||||
|
|
||||||
|
public GridAlignedBB(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
|
||||||
|
this.minX = minX;
|
||||||
|
this.minY = minY;
|
||||||
|
this.minZ = minZ;
|
||||||
|
this.maxX = maxX;
|
||||||
|
this.maxY = maxY;
|
||||||
|
this.maxZ = maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GridAlignedBB copy(GridAlignedBB bb) {
|
||||||
|
return new GridAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GridAlignedBB fromAABB(AxisAlignedBB aabb) {
|
||||||
|
int minX = (int) Math.floor(aabb.minX);
|
||||||
|
int minY = (int) Math.floor(aabb.minY);
|
||||||
|
int minZ = (int) Math.floor(aabb.minZ);
|
||||||
|
int maxX = (int) Math.ceil(aabb.maxX);
|
||||||
|
int maxY = (int) Math.ceil(aabb.maxY);
|
||||||
|
int maxZ = (int) Math.ceil(aabb.maxZ);
|
||||||
|
return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GridAlignedBB fromSection(SectionPos pos) {
|
||||||
|
return new GridAlignedBB(pos.getWorldStartX(),
|
||||||
|
pos.getWorldStartY(),
|
||||||
|
pos.getWorldStartZ(),
|
||||||
|
pos.getWorldEndX() + 1,
|
||||||
|
pos.getWorldEndY() + 1,
|
||||||
|
pos.getWorldEndZ() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AxisAlignedBB toAABB(GridAlignedBB bb) {
|
||||||
|
return new AxisAlignedBB(bb.minX, bb.minY, bb.minZ, bb.maxX, bb.maxY, bb.maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sizeX() {
|
||||||
|
return maxX - minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sizeY() {
|
||||||
|
return maxY - minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sizeZ() {
|
||||||
|
return maxZ - minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int volume() {
|
||||||
|
return sizeX() * sizeY() * sizeZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean empty() {
|
||||||
|
// if any dimension has side length 0 this box contains no volume
|
||||||
|
return minX == maxX ||
|
||||||
|
minY == maxY ||
|
||||||
|
minZ == maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void translate(Vec3i by) {
|
||||||
|
this.minX += by.getX();
|
||||||
|
this.minY += by.getY();
|
||||||
|
this.minZ += by.getZ();
|
||||||
|
this.maxX += by.getX();
|
||||||
|
this.maxY += by.getY();
|
||||||
|
this.maxZ += by.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow this bounding box to have power of 2 side length, scaling from the center.
|
||||||
|
*/
|
||||||
|
public void nextPowerOf2Centered() {
|
||||||
|
int sizeX = sizeX();
|
||||||
|
int sizeY = sizeY();
|
||||||
|
int sizeZ = sizeZ();
|
||||||
|
|
||||||
|
int newSizeX = RenderMath.nextPowerOf2(sizeX);
|
||||||
|
int newSizeY = RenderMath.nextPowerOf2(sizeY);
|
||||||
|
int newSizeZ = RenderMath.nextPowerOf2(sizeZ);
|
||||||
|
|
||||||
|
int diffX = newSizeX - sizeX;
|
||||||
|
int diffY = newSizeY - sizeY;
|
||||||
|
int diffZ = newSizeZ - sizeZ;
|
||||||
|
|
||||||
|
this.minX -= diffX / 2; // floor division for the minimums
|
||||||
|
this.minY -= diffY / 2;
|
||||||
|
this.minZ -= diffZ / 2;
|
||||||
|
this.maxX += (diffX + 1) / 2; // ceiling divison for the maximums
|
||||||
|
this.maxY += (diffY + 1) / 2;
|
||||||
|
this.maxZ += (diffZ + 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grow this bounding box to have power of 2 side lengths, scaling from the minimum coords.
|
||||||
|
*/
|
||||||
|
public void nextPowerOf2() {
|
||||||
|
int sizeX = RenderMath.nextPowerOf2(sizeX());
|
||||||
|
int sizeY = RenderMath.nextPowerOf2(sizeY());
|
||||||
|
int sizeZ = RenderMath.nextPowerOf2(sizeZ());
|
||||||
|
|
||||||
|
this.maxX = this.minX + sizeX;
|
||||||
|
this.maxY = this.minY + sizeY;
|
||||||
|
this.maxZ = this.minZ + sizeZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPowerOf2Sides() {
|
||||||
|
// this is only true if all individual side lengths are powers of 2
|
||||||
|
return isPowerOf2(volume());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void grow(int s) {
|
||||||
|
this.grow(s, s, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void grow(int x, int y, int z) {
|
||||||
|
this.minX -= x;
|
||||||
|
this.minY -= y;
|
||||||
|
this.minZ -= z;
|
||||||
|
this.maxX += x;
|
||||||
|
this.maxY += y;
|
||||||
|
this.maxZ += z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GridAlignedBB intersect(GridAlignedBB other) {
|
||||||
|
int minX = Math.max(this.minX, other.minX);
|
||||||
|
int minY = Math.max(this.minY, other.minY);
|
||||||
|
int minZ = Math.max(this.minZ, other.minZ);
|
||||||
|
int maxX = Math.min(this.maxX, other.maxX);
|
||||||
|
int maxY = Math.min(this.maxY, other.maxY);
|
||||||
|
int maxZ = Math.min(this.maxZ, other.maxZ);
|
||||||
|
return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void intersectAssign(GridAlignedBB other) {
|
||||||
|
this.minX = Math.max(this.minX, other.minX);
|
||||||
|
this.minY = Math.max(this.minY, other.minY);
|
||||||
|
this.minZ = Math.max(this.minZ, other.minZ);
|
||||||
|
this.maxX = Math.min(this.maxX, other.maxX);
|
||||||
|
this.maxY = Math.min(this.maxY, other.maxY);
|
||||||
|
this.maxZ = Math.min(this.maxZ, other.maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GridAlignedBB union(GridAlignedBB other) {
|
||||||
|
int minX = Math.min(this.minX, other.minX);
|
||||||
|
int minY = Math.min(this.minY, other.minY);
|
||||||
|
int minZ = Math.min(this.minZ, other.minZ);
|
||||||
|
int maxX = Math.max(this.maxX, other.maxX);
|
||||||
|
int maxY = Math.max(this.maxY, other.maxY);
|
||||||
|
int maxZ = Math.max(this.maxZ, other.maxZ);
|
||||||
|
return new GridAlignedBB(minX, minY, minZ, maxX, maxY, maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unionAssign(GridAlignedBB other) {
|
||||||
|
this.minX = Math.min(this.minX, other.minX);
|
||||||
|
this.minY = Math.min(this.minY, other.minY);
|
||||||
|
this.minZ = Math.min(this.minZ, other.minZ);
|
||||||
|
this.maxX = Math.max(this.maxX, other.maxX);
|
||||||
|
this.maxY = Math.max(this.maxY, other.maxY);
|
||||||
|
this.maxZ = Math.max(this.maxZ, other.maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersects(GridAlignedBB other) {
|
||||||
|
return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean intersects(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
|
||||||
|
return this.minX < maxX && this.maxX > minX && this.minY < maxY && this.maxY > minY && this.minZ < maxZ && this.maxZ > minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEachContained(CoordinateConsumer func) {
|
||||||
|
if (empty()) return;
|
||||||
|
|
||||||
|
for (int x = minX; x < maxX; x++) {
|
||||||
|
for (int y = Math.max(minY, 0); y < Math.min(maxY, 255); y++) { // clamp to world height limits
|
||||||
|
for (int z = minZ; z < maxZ; z++) {
|
||||||
|
func.consume(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,204 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.RenderWork;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.SectionPos;
|
||||||
|
import net.minecraft.world.ILightReader;
|
||||||
|
import net.minecraft.world.LightType;
|
||||||
|
import org.lwjgl.opengl.*;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class LightVolume {
|
||||||
|
|
||||||
|
private final GridAlignedBB volume;
|
||||||
|
private ByteBuffer lightData;
|
||||||
|
|
||||||
|
private boolean bufferDirty;
|
||||||
|
|
||||||
|
private int glTexture;
|
||||||
|
|
||||||
|
public LightVolume(GridAlignedBB volume) {
|
||||||
|
// the gpu requires that all textures have power of 2 side lengths
|
||||||
|
if (!volume.hasPowerOf2Sides())
|
||||||
|
throw new IllegalArgumentException("LightVolume must have power of 2 side lengths");
|
||||||
|
|
||||||
|
this.volume = volume;
|
||||||
|
|
||||||
|
this.glTexture = GL11.glGenTextures();
|
||||||
|
this.lightData = MemoryUtil.memAlloc(this.volume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte
|
||||||
|
}
|
||||||
|
|
||||||
|
public GridAlignedBB getBox() {
|
||||||
|
return GridAlignedBB.copy(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinX() {
|
||||||
|
return volume.minX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinY() {
|
||||||
|
return volume.minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinZ() {
|
||||||
|
return volume.minZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxX() {
|
||||||
|
return volume.maxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxY() {
|
||||||
|
return volume.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxZ() {
|
||||||
|
return volume.maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSizeX() {
|
||||||
|
return volume.sizeX();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSizeY() {
|
||||||
|
return volume.sizeY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSizeZ() {
|
||||||
|
return volume.sizeZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) {
|
||||||
|
GridAlignedBB changedVolume = GridAlignedBB.fromSection(location);
|
||||||
|
changedVolume.intersectAssign(volume); // compute the region contained by us that has dirty lighting data.
|
||||||
|
|
||||||
|
if (!changedVolume.empty()) {
|
||||||
|
if (type == LightType.BLOCK) copyBlock(world, changedVolume);
|
||||||
|
else if (type == LightType.SKY) copySky(world, changedVolume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completely (re)populate this volume with block and sky lighting data.
|
||||||
|
* This is expensive and should be avoided.
|
||||||
|
*/
|
||||||
|
public void initialize(ILightReader world) {
|
||||||
|
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||||
|
|
||||||
|
int shiftX = volume.minX;
|
||||||
|
int shiftY = volume.minY;
|
||||||
|
int shiftZ = volume.minZ;
|
||||||
|
|
||||||
|
volume.forEachContained((x, y, z) -> {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
|
||||||
|
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
|
||||||
|
int skyLight = world.getLightLevel(LightType.SKY, pos);
|
||||||
|
|
||||||
|
writeLight(x - shiftX, y - shiftY, z - shiftZ, blockLight, skyLight);
|
||||||
|
});
|
||||||
|
|
||||||
|
bufferDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy block light from the world into this volume.
|
||||||
|
* @param worldVolume the region in the world to copy data from.
|
||||||
|
*/
|
||||||
|
public void copyBlock(ILightReader world, GridAlignedBB worldVolume) {
|
||||||
|
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||||
|
|
||||||
|
int xShift = volume.minX;
|
||||||
|
int yShift = volume.minY;
|
||||||
|
int zShift = volume.minZ;
|
||||||
|
|
||||||
|
worldVolume.forEachContained((x, y, z) -> {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
|
||||||
|
int light = world.getLightLevel(LightType.BLOCK, pos);
|
||||||
|
|
||||||
|
writeBlock(x - xShift, y - yShift, z - zShift, light);
|
||||||
|
});
|
||||||
|
|
||||||
|
bufferDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy sky light from the world into this volume.
|
||||||
|
* @param worldVolume the region in the world to copy data from.
|
||||||
|
*/
|
||||||
|
public void copySky(ILightReader world, GridAlignedBB worldVolume) {
|
||||||
|
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||||
|
|
||||||
|
int xShift = volume.minX;
|
||||||
|
int yShift = volume.minY;
|
||||||
|
int zShift = volume.minZ;
|
||||||
|
|
||||||
|
worldVolume.forEachContained((x, y, z) -> {
|
||||||
|
pos.setPos(x, y, z);
|
||||||
|
|
||||||
|
int light = world.getLightLevel(LightType.SKY, pos);
|
||||||
|
|
||||||
|
writeSky(x - xShift, y - yShift, z - zShift, light);
|
||||||
|
});
|
||||||
|
|
||||||
|
bufferDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void use() {
|
||||||
|
// just in case something goes wrong or we accidentally call this before this volume is properly disposed of.
|
||||||
|
if (glTexture == 0 || lightData == null) return;
|
||||||
|
|
||||||
|
GL12.glBindTexture(GL12.GL_TEXTURE_3D, glTexture);
|
||||||
|
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MIN_FILTER, GL13.GL_LINEAR);
|
||||||
|
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_MAG_FILTER, GL13.GL_LINEAR);
|
||||||
|
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_S, GL20.GL_MIRRORED_REPEAT);
|
||||||
|
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT);
|
||||||
|
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT);
|
||||||
|
if (bufferDirty) {
|
||||||
|
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, volume.sizeX(), volume.sizeY(), volume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData);
|
||||||
|
bufferDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void release() {
|
||||||
|
GL12.glBindTexture(GL12.GL_TEXTURE_3D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() {
|
||||||
|
RenderWork.enqueue(() -> {
|
||||||
|
GL15.glDeleteTextures(glTexture);
|
||||||
|
glTexture = 0;
|
||||||
|
MemoryUtil.memFree(lightData);
|
||||||
|
lightData = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLight(int x, int y, int z, int block, int sky) {
|
||||||
|
byte b = (byte) ((block & 0xF) << 4);
|
||||||
|
byte s = (byte) ((sky & 0xF) << 4);
|
||||||
|
|
||||||
|
int i = index(x, y, z);
|
||||||
|
lightData.put(i, b);
|
||||||
|
lightData.put(i + 1, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeBlock(int x, int y, int z, int block) {
|
||||||
|
byte b = (byte) ((block & 0xF) << 4);
|
||||||
|
|
||||||
|
lightData.put(index(x, y, z), b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeSky(int x, int y, int z, int sky) {
|
||||||
|
byte b = (byte) ((sky & 0xF) << 4);
|
||||||
|
|
||||||
|
lightData.put(index(x, y, z) + 1, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int index(int x, int y, int z) {
|
||||||
|
return (x + volume.sizeX() * (y + z * volume.sizeY())) * 2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package com.simibubi.create.foundation.render.light;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
|
import com.simibubi.create.foundation.render.ContraptionRenderDispatcher;
|
||||||
|
import com.simibubi.create.foundation.render.RenderedContraption;
|
||||||
|
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||||
|
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
|
||||||
|
import com.simibubi.create.foundation.utility.outliner.Outline;
|
||||||
|
|
||||||
|
public class LightVolumeDebugger {
|
||||||
|
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
|
||||||
|
ContraptionRenderDispatcher.renderers.values()
|
||||||
|
.stream()
|
||||||
|
.map(r -> r.getLighter().lightVolume.getBox())
|
||||||
|
.map(volume -> new AABBOutline(GridAlignedBB.toAABB(volume)))
|
||||||
|
.forEach(outline -> outline.render(ms, buffer));
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ import net.minecraft.resources.IReloadableResourceManager;
|
||||||
import net.minecraft.resources.IResourceManager;
|
import net.minecraft.resources.IResourceManager;
|
||||||
import net.minecraft.resources.IResourceManagerReloadListener;
|
import net.minecraft.resources.IResourceManagerReloadListener;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.resource.ISelectiveResourceReloadListener;
|
||||||
|
import net.minecraftforge.resource.VanillaResourceType;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
@ -41,11 +43,13 @@ public class ShaderHelper {
|
||||||
if (Minecraft.getInstance() != null
|
if (Minecraft.getInstance() != null
|
||||||
&& Minecraft.getInstance().getResourceManager() instanceof IReloadableResourceManager) {
|
&& Minecraft.getInstance().getResourceManager() instanceof IReloadableResourceManager) {
|
||||||
((IReloadableResourceManager) Minecraft.getInstance().getResourceManager()).addReloadListener(
|
((IReloadableResourceManager) Minecraft.getInstance().getResourceManager()).addReloadListener(
|
||||||
(IResourceManagerReloadListener) manager -> {
|
(ISelectiveResourceReloadListener) (manager, predicate) -> {
|
||||||
PROGRAMS.values().forEach(ShaderLinkHelper::deleteShader);
|
if (predicate.test(VanillaResourceType.SHADERS)) {
|
||||||
PROGRAMS.clear();
|
PROGRAMS.values().forEach(ShaderLinkHelper::deleteShader);
|
||||||
for (Shader shader : Shader.values()) {
|
PROGRAMS.clear();
|
||||||
createProgram(manager, shader);
|
for (Shader shader : Shader.values()) {
|
||||||
|
createProgram(manager, shader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ Technology that empowers the player.'''
|
||||||
[[dependencies.create]]
|
[[dependencies.create]]
|
||||||
modId="forge"
|
modId="forge"
|
||||||
mandatory=true
|
mandatory=true
|
||||||
versionRange="[31.2.0,)"
|
versionRange="[31.2.44,)"
|
||||||
ordering="NONE"
|
ordering="NONE"
|
||||||
side="BOTH"
|
side="BOTH"
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,17 @@ void main() {
|
||||||
|
|
||||||
float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult;
|
float scroll = fract(speed * time / (36 * 16.)) * scrollSize * scrollMult;
|
||||||
|
|
||||||
Diffuse = diffuse(normalize((rotation * vec4(aNormal, 0.)).xyz));
|
vec3 norm = (rotation * vec4(aNormal, 0.)).xyz;
|
||||||
|
|
||||||
|
Diffuse = diffuse(norm);
|
||||||
Light = light;
|
Light = light;
|
||||||
TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll);
|
TexCoords = aTexCoords - sourceUV + scrollTexture.xy + vec2(0., scroll);
|
||||||
gl_Position = projection * view * renderPos;
|
gl_Position = projection * view * renderPos;
|
||||||
|
|
||||||
if (debug == 1) {
|
if (debug == 1) {
|
||||||
Color = vec4(networkTint, 1);
|
Color = vec4(networkTint, 1);
|
||||||
|
} else if (debug == 2) {
|
||||||
|
Color = vec4(norm, 1);
|
||||||
} else {
|
} else {
|
||||||
Color = vec4(1);
|
Color = vec4(1);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue