mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-16 12:13:42 +01:00
probably fix the NPEs
start work on adaptive backend extra sanity stuff for the render manager massive speedup when rendering a lot of tile entities
This commit is contained in:
parent
04ccf6e738
commit
b63466774b
15 changed files with 176 additions and 106 deletions
|
@ -247,7 +247,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
|
||||||
effects.triggerOverStressedEffect();
|
effects.triggerOverStressedEffect();
|
||||||
|
|
||||||
if (clientPacket)
|
if (clientPacket)
|
||||||
CreateClient.kineticRenderer.update(this);
|
FastRenderDispatcher.enqueueUpdate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getGeneratedSpeed() {
|
public float getGeneratedSpeed() {
|
||||||
|
|
|
@ -27,8 +27,8 @@ public abstract class KineticTileInstance<T extends KineticTileEntity> extends T
|
||||||
|
|
||||||
protected final Consumer<RotatingData> setupFunc(float speed, Direction.Axis axis) {
|
protected final Consumer<RotatingData> setupFunc(float speed, Direction.Axis axis) {
|
||||||
return data -> {
|
return data -> {
|
||||||
data.setBlockLight(tile.getWorld().getLightLevel(LightType.BLOCK, pos))
|
data.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
|
||||||
.setSkyLight(tile.getWorld().getLightLevel(LightType.SKY, pos))
|
.setSkyLight(world.getLightLevel(LightType.SKY, pos))
|
||||||
.setTileEntity(tile)
|
.setTileEntity(tile)
|
||||||
.setRotationalSpeed(speed)
|
.setRotationalSpeed(speed)
|
||||||
.setRotationOffset(getRotationOffset(axis))
|
.setRotationOffset(getRotationOffset(axis))
|
||||||
|
|
|
@ -45,7 +45,6 @@ public class SingleRotatingInstance extends KineticTileInstance<KineticTileEntit
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
rotatingModelKey.delete();
|
rotatingModelKey.delete();
|
||||||
rotatingModelKey = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BlockState getRenderedBlockState() {
|
protected BlockState getRenderedBlockState() {
|
||||||
|
|
|
@ -112,6 +112,5 @@ public class FanInstance extends KineticTileInstance<EncasedFanTileEntity> {
|
||||||
public void remove() {
|
public void remove() {
|
||||||
shaft.delete();
|
shaft.delete();
|
||||||
fan.delete();
|
fan.delete();
|
||||||
shaft = fan = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,14 +44,13 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
BlockState blockState = tile.getBlockState();
|
if (!AllBlocks.BELT.has(lastState))
|
||||||
if (!AllBlocks.BELT.has(blockState))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
keys = new ArrayList<>(2);
|
keys = new ArrayList<>(2);
|
||||||
|
|
||||||
beltSlope = blockState.get(BeltBlock.SLOPE);
|
beltSlope = lastState.get(BeltBlock.SLOPE);
|
||||||
facing = blockState.get(BeltBlock.HORIZONTAL_FACING);
|
facing = lastState.get(BeltBlock.HORIZONTAL_FACING);
|
||||||
upward = beltSlope == BeltSlope.UPWARD;
|
upward = beltSlope == BeltSlope.UPWARD;
|
||||||
diagonal = beltSlope.isDiagonal();
|
diagonal = beltSlope.isDiagonal();
|
||||||
sideways = beltSlope == BeltSlope.SIDEWAYS;
|
sideways = beltSlope == BeltSlope.SIDEWAYS;
|
||||||
|
@ -59,7 +58,7 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
alongX = facing.getAxis() == Direction.Axis.X;
|
alongX = facing.getAxis() == Direction.Axis.X;
|
||||||
alongZ = facing.getAxis() == Direction.Axis.Z;
|
alongZ = facing.getAxis() == Direction.Axis.Z;
|
||||||
|
|
||||||
BeltPart part = blockState.get(BeltBlock.PART);
|
BeltPart part = lastState.get(BeltBlock.PART);
|
||||||
boolean start = part == BeltPart.START;
|
boolean start = part == BeltPart.START;
|
||||||
boolean end = part == BeltPart.END;
|
boolean end = part == BeltPart.END;
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
AllBlockPartials beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom);
|
AllBlockPartials beltPartial = BeltRenderer.getBeltPartial(diagonal, start, end, bottom);
|
||||||
SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(diagonal, bottom);
|
SpriteShiftEntry spriteShift = BeltRenderer.getSpriteShiftEntry(diagonal, bottom);
|
||||||
|
|
||||||
InstancedModel<BeltData> beltModel = beltPartial.renderOnBelt(modelManager, blockState);
|
InstancedModel<BeltData> beltModel = beltPartial.renderOnBelt(modelManager, lastState);
|
||||||
Consumer<BeltData> setupFunc = setupFunc(spriteShift);
|
Consumer<BeltData> setupFunc = setupFunc(spriteShift);
|
||||||
|
|
||||||
keys.add(beltModel.setupInstance(setupFunc));
|
keys.add(beltModel.setupInstance(setupFunc));
|
||||||
|
@ -76,7 +75,7 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tile.hasPulley()) {
|
if (tile.hasPulley()) {
|
||||||
InstancedModel<RotatingData> pulleyModel = getPulleyModel(blockState);
|
InstancedModel<RotatingData> pulleyModel = getPulleyModel();
|
||||||
|
|
||||||
pulleyKey = pulleyModel.setupInstance(setupFunc(tile.getSpeed(), getRotationAxis()));
|
pulleyKey = pulleyModel.setupInstance(setupFunc(tile.getSpeed(), getRotationAxis()));
|
||||||
}
|
}
|
||||||
|
@ -107,7 +106,6 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
keys.forEach(InstanceKey::delete);
|
keys.forEach(InstanceKey::delete);
|
||||||
keys.clear();
|
keys.clear();
|
||||||
if (pulleyKey != null) pulleyKey.delete();
|
if (pulleyKey != null) pulleyKey.delete();
|
||||||
pulleyKey = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getScrollSpeed() {
|
private float getScrollSpeed() {
|
||||||
|
@ -122,8 +120,8 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private InstancedModel<RotatingData> getPulleyModel(BlockState blockState) {
|
private InstancedModel<RotatingData> getPulleyModel() {
|
||||||
Direction dir = getOrientation(blockState);
|
Direction dir = getOrientation();
|
||||||
|
|
||||||
Direction.Axis axis = dir.getAxis();
|
Direction.Axis axis = dir.getAxis();
|
||||||
|
|
||||||
|
@ -141,11 +139,11 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
return modelTransform;
|
return modelTransform;
|
||||||
};
|
};
|
||||||
|
|
||||||
return rotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, blockState, dir, ms);
|
return rotatingMaterial().getModel(AllBlockPartials.BELT_PULLEY, lastState, dir, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Direction getOrientation(BlockState blockState) {
|
private Direction getOrientation() {
|
||||||
Direction dir = blockState.get(BeltBlock.HORIZONTAL_FACING)
|
Direction dir = lastState.get(BeltBlock.HORIZONTAL_FACING)
|
||||||
.rotateY();
|
.rotateY();
|
||||||
if (beltSlope == BeltSlope.SIDEWAYS)
|
if (beltSlope == BeltSlope.SIDEWAYS)
|
||||||
dir = Direction.UP;
|
dir = Direction.UP;
|
||||||
|
@ -161,8 +159,8 @@ public class BeltInstance extends KineticTileInstance<BeltTileEntity> {
|
||||||
|
|
||||||
BlockPos pos = tile.getPos();
|
BlockPos pos = tile.getPos();
|
||||||
data.setTileEntity(tile)
|
data.setTileEntity(tile)
|
||||||
.setBlockLight(tile.getWorld().getLightLevel(LightType.BLOCK, pos))
|
.setBlockLight(world.getLightLevel(LightType.BLOCK, pos))
|
||||||
.setSkyLight(tile.getWorld().getLightLevel(LightType.SKY, pos))
|
.setSkyLight(world.getLightLevel(LightType.SKY, pos))
|
||||||
.setRotation(rotX, rotY, rotZ)
|
.setRotation(rotX, rotY, rotZ)
|
||||||
.setRotationalSpeed(getScrollSpeed())
|
.setRotationalSpeed(getScrollSpeed())
|
||||||
.setRotationOffset(0)
|
.setRotationOffset(0)
|
||||||
|
|
|
@ -35,15 +35,14 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
|
||||||
protected void init() {
|
protected void init() {
|
||||||
keys = new ArrayList<>(2);
|
keys = new ArrayList<>(2);
|
||||||
|
|
||||||
BlockState state = tile.getBlockState();
|
Block block = lastState.getBlock();
|
||||||
Block block = state.getBlock();
|
final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(lastState);
|
||||||
final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(state);
|
|
||||||
|
|
||||||
float speed = tile.getSpeed();
|
float speed = tile.getSpeed();
|
||||||
|
|
||||||
for (Direction dir : Iterate.directionsInAxis(boxAxis)) {
|
for (Direction dir : Iterate.directionsInAxis(boxAxis)) {
|
||||||
|
|
||||||
InstancedModel<RotatingData> half = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, state, dir);
|
InstancedModel<RotatingData> half = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, dir);
|
||||||
|
|
||||||
float splitSpeed = speed * tile.getRotationSpeedModifier(dir);
|
float splitSpeed = speed * tile.getRotationSpeedModifier(dir);
|
||||||
|
|
||||||
|
@ -53,9 +52,8 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate() {
|
public void onUpdate() {
|
||||||
BlockState state = tile.getBlockState();
|
Block block = lastState.getBlock();
|
||||||
Block block = state.getBlock();
|
final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(lastState);
|
||||||
final Direction.Axis boxAxis = ((IRotate) block).getRotationAxis(state);
|
|
||||||
|
|
||||||
Direction[] directions = Iterate.directionsInAxis(boxAxis);
|
Direction[] directions = Iterate.directionsInAxis(boxAxis);
|
||||||
|
|
||||||
|
@ -80,7 +78,6 @@ public class SplitShaftInstance extends KineticTileInstance<SplitShaftTileEntity
|
||||||
protected void updateRotation(InstanceKey<RotatingData> key, Direction dir) {
|
protected void updateRotation(InstanceKey<RotatingData> key, Direction dir) {
|
||||||
key.modifyInstance(data -> {
|
key.modifyInstance(data -> {
|
||||||
Direction.Axis axis = dir.getAxis();
|
Direction.Axis axis = dir.getAxis();
|
||||||
final BlockPos pos = tile.getPos();
|
|
||||||
|
|
||||||
data.setRotationalSpeed(tile.getSpeed() * tile.getRotationSpeedModifier(dir))
|
data.setRotationalSpeed(tile.getSpeed() * tile.getRotationSpeedModifier(dir))
|
||||||
.setRotationOffset(getRotationOffset(axis))
|
.setRotationOffset(getRotationOffset(axis))
|
||||||
|
|
|
@ -37,13 +37,10 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
protected void init() {
|
protected void init() {
|
||||||
keys = new EnumMap<>(Direction.class);
|
keys = new EnumMap<>(Direction.class);
|
||||||
|
|
||||||
BlockState state = tile.getBlockState();
|
final Direction.Axis boxAxis = lastState.get(BlockStateProperties.AXIS);
|
||||||
|
|
||||||
final Direction.Axis boxAxis = state.get(BlockStateProperties.AXIS);
|
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
|
||||||
|
int skyLight = world.getLightLevel(LightType.SKY, pos);
|
||||||
BlockPos pos = tile.getPos();
|
|
||||||
int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos);
|
|
||||||
int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos);
|
|
||||||
updateSourceFacing();
|
updateSourceFacing();
|
||||||
|
|
||||||
for (Direction direction : Iterate.directions) {
|
for (Direction direction : Iterate.directions) {
|
||||||
|
@ -51,7 +48,7 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
if (boxAxis == axis)
|
if (boxAxis == axis)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
InstancedModel<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, state, direction);
|
InstancedModel<RotatingData> shaft = AllBlockPartials.SHAFT_HALF.renderOnDirectionalSouthRotating(modelManager, lastState, direction);
|
||||||
|
|
||||||
InstanceKey<RotatingData> key = shaft.setupInstance(data -> {
|
InstanceKey<RotatingData> key = shaft.setupInstance(data -> {
|
||||||
data.setBlockLight(blockLight)
|
data.setBlockLight(blockLight)
|
||||||
|
@ -79,7 +76,7 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
|
|
||||||
protected void updateSourceFacing() {
|
protected void updateSourceFacing() {
|
||||||
if (tile.hasSource()) {
|
if (tile.hasSource()) {
|
||||||
BlockPos source = tile.source.subtract(tile.getPos());
|
BlockPos source = tile.source.subtract(pos);
|
||||||
sourceFacing = Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
|
sourceFacing = Direction.getFacingFromVector(source.getX(), source.getY(), source.getZ());
|
||||||
} else {
|
} else {
|
||||||
sourceFacing = null;
|
sourceFacing = null;
|
||||||
|
@ -89,7 +86,6 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate() {
|
public void onUpdate() {
|
||||||
updateSourceFacing();
|
updateSourceFacing();
|
||||||
BlockPos pos = tile.getPos();
|
|
||||||
for (Map.Entry<Direction, InstanceKey<RotatingData>> key : keys.entrySet()) {
|
for (Map.Entry<Direction, InstanceKey<RotatingData>> key : keys.entrySet()) {
|
||||||
key.getValue().modifyInstance(data -> {
|
key.getValue().modifyInstance(data -> {
|
||||||
Direction direction = key.getKey();
|
Direction direction = key.getKey();
|
||||||
|
@ -104,7 +100,6 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLight() {
|
public void updateLight() {
|
||||||
BlockPos pos = tile.getPos();
|
|
||||||
int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos);
|
int blockLight = tile.getWorld().getLightLevel(LightType.BLOCK, pos);
|
||||||
int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos);
|
int skyLight = tile.getWorld().getLightLevel(LightType.SKY, pos);
|
||||||
|
|
||||||
|
@ -115,10 +110,7 @@ public class GearboxInstance extends KineticTileInstance<GearboxTileEntity> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove() {
|
public void remove() {
|
||||||
for (InstanceKey<RotatingData> key : keys.values()) {
|
keys.values().forEach(InstanceKey::delete);
|
||||||
key.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
keys.clear();
|
keys.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,18 +27,6 @@ public class CancelTileEntityRenderMixin {
|
||||||
private void noRenderInstancedTiles(CallbackInfoReturnable<List<TileEntity>> cir) {
|
private void noRenderInstancedTiles(CallbackInfoReturnable<List<TileEntity>> cir) {
|
||||||
List<TileEntity> tiles = cir.getReturnValue();
|
List<TileEntity> tiles = cir.getReturnValue();
|
||||||
|
|
||||||
List<TileEntity> out = new ArrayList<>(tiles.size());
|
tiles.removeIf(tile -> tile instanceof IInstanceRendered && !((IInstanceRendered) tile).shouldRenderAsTE());
|
||||||
|
|
||||||
for (TileEntity tile : tiles) {
|
|
||||||
if (tile instanceof IInstanceRendered) {
|
|
||||||
IInstanceRendered instanceRendered = (IInstanceRendered) tile;
|
|
||||||
|
|
||||||
if (!instanceRendered.shouldRenderAsTE()) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.add(tile);
|
|
||||||
}
|
|
||||||
|
|
||||||
cir.setReturnValue(out);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package com.simibubi.create.foundation.render;
|
package com.simibubi.create.foundation.render;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.gl.Backend;
|
||||||
import com.simibubi.create.foundation.render.gl.GlBuffer;
|
import com.simibubi.create.foundation.render.gl.GlBuffer;
|
||||||
import com.simibubi.create.foundation.render.gl.GlVertexArray;
|
import com.simibubi.create.foundation.render.gl.GlVertexArray;
|
||||||
import com.simibubi.create.foundation.render.instancing.VertexFormat;
|
import com.simibubi.create.foundation.render.instancing.VertexFormat;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import org.lwjgl.opengl.GL15;
|
import org.lwjgl.opengl.GL15;
|
||||||
import org.lwjgl.opengl.GL40;
|
import org.lwjgl.opengl.GL20;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ public abstract class BufferedModel extends TemplateBuffer {
|
||||||
|
|
||||||
int numAttributes = getTotalShaderAttributeCount();
|
int numAttributes = getTotalShaderAttributeCount();
|
||||||
for (int i = 0; i <= numAttributes; i++) {
|
for (int i = 0; i <= numAttributes; i++) {
|
||||||
GL40.glEnableVertexAttribArray(i);
|
GL20.glEnableVertexAttribArray(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
invariantVBO.bind(GL15.GL_ARRAY_BUFFER);
|
invariantVBO.bind(GL15.GL_ARRAY_BUFFER);
|
||||||
|
@ -44,13 +45,11 @@ public abstract class BufferedModel extends TemplateBuffer {
|
||||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW);
|
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, invariantSize, GL15.GL_STATIC_DRAW);
|
||||||
|
|
||||||
// mirror it in system memory so we can write to it
|
// mirror it in system memory so we can write to it
|
||||||
ByteBuffer constant = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
|
Backend.MAP_BUFFER.mapBuffer(GL15.GL_ARRAY_BUFFER, invariantSize, buffer -> {
|
||||||
|
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
copyVertex(constant, i);
|
copyVertex(buffer, i);
|
||||||
}
|
}
|
||||||
constant.rewind();
|
});
|
||||||
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
|
|
||||||
|
|
||||||
getModelFormat().informAttributes(0);
|
getModelFormat().informAttributes(0);
|
||||||
|
|
||||||
|
|
|
@ -27,16 +27,16 @@ import net.minecraft.world.chunk.Chunk;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Queue;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class FastRenderDispatcher {
|
public class FastRenderDispatcher {
|
||||||
|
|
||||||
public static WorldAttached<ConcurrentLinkedQueue<TileEntity>> queuedUpdates = new WorldAttached<>(ConcurrentLinkedQueue::new);
|
public static WorldAttached<ConcurrentHashMap.KeySetView<TileEntity, Boolean>> queuedUpdates = new WorldAttached<>(ConcurrentHashMap::newKeySet);
|
||||||
public static WorldAttached<ConcurrentLinkedQueue<TileEntity>> queuedRemovals = new WorldAttached<>(ConcurrentLinkedQueue::new);
|
public static WorldAttached<ConcurrentHashMap.KeySetView<TileEntity, Boolean>> queuedRemovals = new WorldAttached<>(ConcurrentHashMap::newKeySet);
|
||||||
public static WorldAttached<ConcurrentLinkedQueue<TileEntityInstance<?>>> addedLastTick = new WorldAttached<>(ConcurrentLinkedQueue::new);
|
public static WorldAttached<ConcurrentHashMap.KeySetView<TileEntityInstance<?>, Boolean>> addedLastTick = new WorldAttached<>(ConcurrentHashMap::newKeySet);
|
||||||
|
|
||||||
private static Matrix4f projectionMatrixThisFrame = null;
|
private static Matrix4f projectionMatrixThisFrame = null;
|
||||||
|
|
||||||
|
@ -56,18 +56,21 @@ public class FastRenderDispatcher {
|
||||||
ClientWorld world = Minecraft.getInstance().world;
|
ClientWorld world = Minecraft.getInstance().world;
|
||||||
|
|
||||||
runQueue(addedLastTick.get(world), TileEntityInstance::updateLight);
|
runQueue(addedLastTick.get(world), TileEntityInstance::updateLight);
|
||||||
runQueue(queuedUpdates.get(world), CreateClient.kineticRenderer::update);
|
|
||||||
runQueue(queuedRemovals.get(world), CreateClient.kineticRenderer::remove);
|
runQueue(queuedRemovals.get(world), CreateClient.kineticRenderer::remove);
|
||||||
|
CreateClient.kineticRenderer.clean();
|
||||||
|
|
||||||
|
runQueue(queuedUpdates.get(world), CreateClient.kineticRenderer::update);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void runQueue(@Nullable Queue<T> q, Consumer<T> action) {
|
private static <T> void runQueue(@Nullable ConcurrentHashMap.KeySetView<T, Boolean> changed, Consumer<T> action) {
|
||||||
if (q == null) return;
|
if (changed == null) return;
|
||||||
|
|
||||||
while (!q.isEmpty()) {
|
// because of potential concurrency issues, we make a copy of what's in the set at the time we get here
|
||||||
T t = q.poll();
|
ArrayList<T> tiles = new ArrayList<>(changed);
|
||||||
|
|
||||||
action.accept(t);
|
tiles.forEach(action);
|
||||||
}
|
|
||||||
|
changed.removeAll(tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void renderLayer(RenderType type, MatrixStack stack, double cameraX, double cameraY, double cameraZ) {
|
public static void renderLayer(RenderType type, MatrixStack stack, double cameraX, double cameraY, double cameraZ) {
|
||||||
|
|
|
@ -4,13 +4,16 @@ import com.simibubi.create.foundation.render.gl.shader.Shader;
|
||||||
import com.simibubi.create.foundation.render.gl.shader.ShaderCallback;
|
import com.simibubi.create.foundation.render.gl.shader.ShaderCallback;
|
||||||
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
|
import com.simibubi.create.foundation.render.gl.shader.ShaderHelper;
|
||||||
import com.simibubi.create.foundation.render.instancing.*;
|
import com.simibubi.create.foundation.render.instancing.*;
|
||||||
|
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||||
import net.minecraft.client.renderer.Matrix4f;
|
import net.minecraft.client.renderer.Matrix4f;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class InstancedTileRenderer {
|
public class InstancedTileRenderer {
|
||||||
protected Map<TileEntity, TileEntityInstance<?>> renderers = new HashMap<>();
|
protected Map<TileEntity, TileEntityInstance<?>> renderers = new HashMap<>();
|
||||||
|
@ -31,12 +34,17 @@ public class InstancedTileRenderer {
|
||||||
return (RenderMaterial<M>) materials.get(materialType);
|
return (RenderMaterial<M>) materials.get(materialType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public <T extends TileEntity> TileEntityInstance<? super T> getInstance(T tile) {
|
||||||
|
return getInstance(tile, true);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Nullable
|
@Nullable
|
||||||
public <T extends TileEntity> TileEntityInstance<? super T> getRenderer(T tile) {
|
public <T extends TileEntity> TileEntityInstance<? super T> getInstance(T tile, boolean create) {
|
||||||
if (renderers.containsKey(tile)) {
|
if (renderers.containsKey(tile)) {
|
||||||
return (TileEntityInstance<? super T>) renderers.get(tile);
|
return (TileEntityInstance<? super T>) renderers.get(tile);
|
||||||
} else {
|
} else if (create) {
|
||||||
TileEntityInstance<? super T> renderer = InstancedTileRenderRegistry.instance.create(this, tile);
|
TileEntityInstance<? super T> renderer = InstancedTileRenderRegistry.instance.create(this, tile);
|
||||||
|
|
||||||
if (renderer != null) {
|
if (renderer != null) {
|
||||||
|
@ -45,38 +53,49 @@ public class InstancedTileRenderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderer;
|
return renderer;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends TileEntity> void onLightUpdate(T tile) {
|
public <T extends TileEntity> void onLightUpdate(T tile) {
|
||||||
if (tile instanceof IInstanceRendered) {
|
if (tile instanceof IInstanceRendered) {
|
||||||
TileEntityInstance<? super T> renderer = getRenderer(tile);
|
TileEntityInstance<? super T> instance = getInstance(tile);
|
||||||
|
|
||||||
if (renderer != null)
|
if (instance != null)
|
||||||
renderer.updateLight();
|
instance.updateLight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends TileEntity> void update(T tile) {
|
public <T extends TileEntity> void update(T tile) {
|
||||||
if (tile instanceof IInstanceRendered) {
|
if (tile instanceof IInstanceRendered) {
|
||||||
TileEntityInstance<? super T> renderer = getRenderer(tile);
|
TileEntityInstance<? super T> instance = getInstance(tile);
|
||||||
|
|
||||||
if (renderer != null)
|
if (instance != null)
|
||||||
renderer.update();
|
instance.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends TileEntity> void remove(T tile) {
|
public <T extends TileEntity> void remove(T tile) {
|
||||||
if (tile instanceof IInstanceRendered) {
|
if (tile instanceof IInstanceRendered) {
|
||||||
TileEntityInstance<? super T> renderer = getRenderer(tile);
|
TileEntityInstance<? super T> instance = getInstance(tile, false);
|
||||||
|
|
||||||
if (renderer != null) {
|
if (instance != null) {
|
||||||
renderer.remove();
|
instance.remove();
|
||||||
renderers.remove(tile);
|
renderers.remove(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clean() {
|
||||||
|
// Clean up twice a second. This doesn't have to happen every tick,
|
||||||
|
// but this does need to be run to ensure we don't miss anything.
|
||||||
|
if (AnimationTickHolder.ticks % 10 == 0) {
|
||||||
|
List<TileEntity> removed = renderers.keySet().stream().filter(TileEntity::isRemoved).collect(Collectors.toList());
|
||||||
|
removed.forEach(renderers::remove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void invalidate() {
|
public void invalidate() {
|
||||||
for (RenderMaterial<?> material : materials.values()) {
|
for (RenderMaterial<?> material : materials.values()) {
|
||||||
material.delete();
|
material.delete();
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class RenderedContraption {
|
||||||
if (!tileEntities.isEmpty()) {
|
if (!tileEntities.isEmpty()) {
|
||||||
for (TileEntity te : tileEntities) {
|
for (TileEntity te : tileEntities) {
|
||||||
if (te instanceof IInstanceRendered) {
|
if (te instanceof IInstanceRendered) {
|
||||||
kinetics.getRenderer(te); // this is enough to instantiate the model instance
|
kinetics.getInstance(te); // this is enough to instantiate the model instance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.simibubi.create.foundation.render.gl;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.render.gl.backend.MapBuffer;
|
||||||
|
|
||||||
|
public class Backend {
|
||||||
|
public static final MapBuffer MAP_BUFFER = MapBuffer.GL30_RANGE;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.simibubi.create.foundation.render.gl.backend;
|
||||||
|
|
||||||
|
import org.lwjgl.opengl.ARBMapBufferRange;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL30;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public enum MapBuffer {
|
||||||
|
|
||||||
|
GL30_RANGE {
|
||||||
|
@Override
|
||||||
|
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
|
||||||
|
ByteBuffer buffer = GL30.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT);
|
||||||
|
|
||||||
|
upload.accept(buffer);
|
||||||
|
buffer.rewind();
|
||||||
|
|
||||||
|
GL30.glUnmapBuffer(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ARB_RANGE {
|
||||||
|
@Override
|
||||||
|
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
|
||||||
|
ByteBuffer buffer = ARBMapBufferRange.glMapBufferRange(target, offset, length, GL30.GL_MAP_WRITE_BIT | GL30.GL_MAP_INVALIDATE_RANGE_BIT);
|
||||||
|
|
||||||
|
upload.accept(buffer);
|
||||||
|
buffer.rewind();
|
||||||
|
|
||||||
|
GL30.glUnmapBuffer(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
GL15_MAP {
|
||||||
|
@Override
|
||||||
|
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
|
||||||
|
ByteBuffer buffer = GL15.glMapBuffer(target, GL15.GL_WRITE_ONLY);
|
||||||
|
|
||||||
|
buffer.position(offset);
|
||||||
|
upload.accept(buffer);
|
||||||
|
buffer.rewind();
|
||||||
|
GL15.glUnmapBuffer(target);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UNSUPPORTED {
|
||||||
|
@Override
|
||||||
|
public void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload) {
|
||||||
|
throw new UnsupportedOperationException("glMapBuffer not supported");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public abstract void mapBuffer(int target, int offset, int length, Consumer<ByteBuffer> upload);
|
||||||
|
|
||||||
|
public final void mapBuffer(int target, int size, Consumer<ByteBuffer> upload) {
|
||||||
|
mapBuffer(target, 0, size, upload);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,16 @@
|
||||||
package com.simibubi.create.foundation.render.instancing;
|
package com.simibubi.create.foundation.render.instancing;
|
||||||
|
|
||||||
|
|
||||||
|
import com.google.common.collect.Range;
|
||||||
import com.simibubi.create.foundation.render.BufferedModel;
|
import com.simibubi.create.foundation.render.BufferedModel;
|
||||||
import com.simibubi.create.foundation.render.RenderMath;
|
import com.simibubi.create.foundation.render.RenderMath;
|
||||||
|
import com.simibubi.create.foundation.render.gl.Backend;
|
||||||
import com.simibubi.create.foundation.render.gl.GlBuffer;
|
import com.simibubi.create.foundation.render.gl.GlBuffer;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import org.lwjgl.opengl.*;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
import org.lwjgl.opengl.GL15;
|
||||||
|
import org.lwjgl.opengl.GL31;
|
||||||
|
import org.lwjgl.opengl.GL33;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -23,6 +28,7 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
protected final ArrayList<InstanceKey<D>> keys = new ArrayList<>();
|
protected final ArrayList<InstanceKey<D>> keys = new ArrayList<>();
|
||||||
protected final ArrayList<D> data = new ArrayList<>();
|
protected final ArrayList<D> data = new ArrayList<>();
|
||||||
protected int minIndexChanged = -1;
|
protected int minIndexChanged = -1;
|
||||||
|
protected int maxIndexChanged = -1;
|
||||||
|
|
||||||
public InstancedModel(BufferBuilder buf) {
|
public InstancedModel(BufferBuilder buf) {
|
||||||
super(buf);
|
super(buf);
|
||||||
|
@ -67,10 +73,6 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markDirty() {
|
|
||||||
minIndexChanged = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void deleteInternal() {
|
protected void deleteInternal() {
|
||||||
super.deleteInternal();
|
super.deleteInternal();
|
||||||
instanceVBO.delete();
|
instanceVBO.delete();
|
||||||
|
@ -91,7 +93,8 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
keys.get(i).index--;
|
keys.get(i).index--;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMinIndexChanged(key.index);
|
markIndexChanged(index - 1);
|
||||||
|
maxIndexChanged = keys.size() - 1;
|
||||||
|
|
||||||
key.invalidate();
|
key.invalidate();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +106,7 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
|
|
||||||
edit.accept(data);
|
edit.accept(data);
|
||||||
|
|
||||||
setMinIndexChanged(key.index);
|
markIndexChanged(key.index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized InstanceKey<D> setupInstance(Consumer<D> setup) {
|
public synchronized InstanceKey<D> setupInstance(Consumer<D> setup) {
|
||||||
|
@ -114,16 +117,22 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
data.add(instanceData);
|
data.add(instanceData);
|
||||||
keys.add(key);
|
keys.add(key);
|
||||||
|
|
||||||
setMinIndexChanged(key.index);
|
markIndexChanged(key.index);
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setMinIndexChanged(int index) {
|
protected void markIndexChanged(int index) {
|
||||||
if (minIndexChanged < 0) {
|
if (minIndexChanged < 0) {
|
||||||
minIndexChanged = index;
|
minIndexChanged = index;
|
||||||
} else {
|
} else if (index < minIndexChanged) {
|
||||||
minIndexChanged = Math.min(minIndexChanged, index);
|
minIndexChanged = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxIndexChanged < 0) {
|
||||||
|
maxIndexChanged = index;
|
||||||
|
} else if (index > maxIndexChanged) {
|
||||||
|
maxIndexChanged = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,16 +170,17 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, instanceSize, GL15.GL_STATIC_DRAW);
|
GL15.glBufferData(GL15.GL_ARRAY_BUFFER, instanceSize, GL15.GL_STATIC_DRAW);
|
||||||
glBufferSize = instanceSize;
|
glBufferSize = instanceSize;
|
||||||
minIndexChanged = 0;
|
minIndexChanged = 0;
|
||||||
|
maxIndexChanged = data.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = GL15.glMapBuffer(GL15.GL_ARRAY_BUFFER, GL15.GL_WRITE_ONLY);
|
int offset = minIndexChanged * stride;
|
||||||
|
int length = (1 + maxIndexChanged - minIndexChanged) * stride;
|
||||||
|
|
||||||
buffer.position(stride * minIndexChanged);
|
Backend.MAP_BUFFER.mapBuffer(GL15.GL_ARRAY_BUFFER, offset, length, buffer -> {
|
||||||
for (int i = minIndexChanged; i < data.size(); i++) {
|
for (int i = minIndexChanged; i <= maxIndexChanged; i++) {
|
||||||
data.get(i).write(buffer);
|
data.get(i).write(buffer);
|
||||||
}
|
}
|
||||||
buffer.rewind();
|
});
|
||||||
GL15.glUnmapBuffer(GL15.GL_ARRAY_BUFFER);
|
|
||||||
|
|
||||||
glInstanceCount = data.size();
|
glInstanceCount = data.size();
|
||||||
|
|
||||||
|
@ -184,5 +194,6 @@ public abstract class InstancedModel<D extends InstanceData> extends BufferedMod
|
||||||
instanceVBO.unbind(GL15.GL_ARRAY_BUFFER);
|
instanceVBO.unbind(GL15.GL_ARRAY_BUFFER);
|
||||||
|
|
||||||
minIndexChanged = -1;
|
minIndexChanged = -1;
|
||||||
|
maxIndexChanged = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue