pistons are lit and bearings are better lit in the corners
stop sampling light in places that don't matter
This commit is contained in:
parent
22a90c8e5d
commit
398a848791
13 changed files with 150 additions and 221 deletions
|
@ -190,7 +190,7 @@ public abstract class Contraption {
|
|||
// Create subcontraptions
|
||||
for (BlockFace blockFace : pendingSubContraptions) {
|
||||
Direction face = blockFace.getFace();
|
||||
StabilizedContraption subContraption = new StabilizedContraption(face);
|
||||
StabilizedContraption subContraption = new StabilizedContraption(this, face);
|
||||
World world = entity.world;
|
||||
BlockPos pos = blockFace.getPos();
|
||||
if (!subContraption.assemble(world, pos))
|
||||
|
|
|
@ -13,6 +13,7 @@ public class BearingLighter extends ContraptionLighter<BearingContraption> {
|
|||
@Override
|
||||
public GridAlignedBB getContraptionBounds() {
|
||||
GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds);
|
||||
localBounds.rotate45(contraption.getFacing().getAxis());
|
||||
localBounds.translate(contraption.anchor);
|
||||
return localBounds;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,14 @@ import net.minecraft.world.World;
|
|||
|
||||
public class StabilizedContraption extends Contraption {
|
||||
|
||||
public Contraption parent;
|
||||
|
||||
private Direction facing;
|
||||
|
||||
public StabilizedContraption() {}
|
||||
|
||||
public StabilizedContraption(Direction facing) {
|
||||
public StabilizedContraption(Contraption parent, Direction facing) {
|
||||
this.parent = parent;
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Blo
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.CarpetBlock;
|
||||
|
@ -18,6 +19,8 @@ import net.minecraft.util.math.BlockPos;
|
|||
import net.minecraft.world.IWorld;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -226,4 +229,9 @@ public class PistonContraption extends TranslatingContraption {
|
|||
return tag;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@Override
|
||||
public ContraptionLighter<?> makeLighter() {
|
||||
return new PistonLighter(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
package com.simibubi.create.content.contraptions.components.structureMovement.piston;
|
||||
|
||||
import com.simibubi.create.foundation.render.light.ContraptionLighter;
|
||||
import com.simibubi.create.foundation.render.light.GridAlignedBB;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
public class PistonLighter extends ContraptionLighter<PistonContraption> {
|
||||
public PistonLighter(PistonContraption contraption) {
|
||||
super(contraption);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GridAlignedBB getContraptionBounds() {
|
||||
GridAlignedBB bounds = GridAlignedBB.fromAABB(contraption.bounds);
|
||||
bounds.translate(contraption.anchor);
|
||||
|
||||
int length = contraption.extensionLength;
|
||||
Vec3i direction = contraption.orientation.getDirectionVec();
|
||||
|
||||
int shift = length / 2;
|
||||
int shiftX = direction.getX() * shift;
|
||||
int shiftY = direction.getY() * shift;
|
||||
int shiftZ = direction.getZ() * shift;
|
||||
bounds.translate(shiftX, shiftY, shiftZ);
|
||||
|
||||
int grow = (length + 1) / 2;
|
||||
int extendX = Math.abs(direction.getX() * grow);
|
||||
int extendY = Math.abs(direction.getY() * grow);
|
||||
int extendZ = Math.abs(direction.getZ() * grow);
|
||||
bounds.grow(extendX, extendY, extendZ);
|
||||
|
||||
return bounds;
|
||||
}
|
||||
}
|
|
@ -126,7 +126,7 @@ public class ClientEvents {
|
|||
CouplingRenderer.renderAll(ms, buffer);
|
||||
CreateClient.schematicHandler.render(ms, buffer);
|
||||
CreateClient.outliner.renderOutlines(ms, buffer);
|
||||
LightVolumeDebugger.render(ms, buffer);
|
||||
// LightVolumeDebugger.render(ms, buffer);
|
||||
// CollisionDebugger.render(ms, buffer);
|
||||
buffer.draw();
|
||||
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
package com.simibubi.create.foundation.render;
|
||||
|
||||
public class RenderMath {
|
||||
public static final float SQRT2 = 1.41421356237f;
|
||||
|
||||
public static int timesSqrt2(int i) {
|
||||
return (int) Math.floor((float) i * SQRT2 / 4f);
|
||||
}
|
||||
|
||||
public static int nextPowerOf2(int a) {
|
||||
int h = Integer.highestOneBit(a);
|
||||
return (h == a) ? h : (h << 1);
|
||||
|
|
|
@ -1,165 +0,0 @@
|
|||
package com.simibubi.create.foundation.render;
|
||||
|
||||
import net.minecraft.client.renderer.GLAllocation;
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
|
||||
import java.nio.*;
|
||||
|
||||
public class SafeDirectBuffer implements AutoCloseable {
|
||||
|
||||
private ByteBuffer wrapped;
|
||||
|
||||
public SafeDirectBuffer(int capacity) {
|
||||
this.wrapped = GLAllocation.createDirectByteBuffer(capacity);
|
||||
}
|
||||
|
||||
public void close() throws Exception {
|
||||
if (wrapped instanceof DirectBuffer) {
|
||||
((DirectBuffer) wrapped).cleaner().clean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only use this function to pass information to OpenGL.
|
||||
*/
|
||||
@Deprecated
|
||||
public ByteBuffer getBacking() {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
public void order(ByteOrder bo) {
|
||||
wrapped.order(bo);
|
||||
}
|
||||
|
||||
public void limit(int limit) {
|
||||
wrapped.limit(limit);
|
||||
}
|
||||
|
||||
public void rewind() {
|
||||
wrapped.rewind();
|
||||
}
|
||||
|
||||
public byte get() {
|
||||
return wrapped.get();
|
||||
}
|
||||
|
||||
public ByteBuffer put(byte b) {
|
||||
return wrapped.put(b);
|
||||
}
|
||||
|
||||
public byte get(int index) {
|
||||
return wrapped.get();
|
||||
}
|
||||
|
||||
public ByteBuffer put(int index, byte b) {
|
||||
return wrapped.put(index, b);
|
||||
}
|
||||
|
||||
public ByteBuffer compact() {
|
||||
return wrapped.compact();
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return wrapped.isReadOnly();
|
||||
}
|
||||
|
||||
public boolean isDirect() {
|
||||
return wrapped.isDirect();
|
||||
}
|
||||
|
||||
public char getChar() {
|
||||
return wrapped.getChar();
|
||||
}
|
||||
|
||||
public ByteBuffer putChar(char value) {
|
||||
return wrapped.putChar(value);
|
||||
}
|
||||
|
||||
public char getChar(int index) {
|
||||
return wrapped.getChar(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putChar(int index, char value) {
|
||||
return wrapped.putChar(index, value);
|
||||
}
|
||||
|
||||
public short getShort() {
|
||||
return wrapped.getShort();
|
||||
}
|
||||
|
||||
public ByteBuffer putShort(short value) {
|
||||
return wrapped.putShort(value);
|
||||
}
|
||||
|
||||
public short getShort(int index) {
|
||||
return wrapped.getShort(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putShort(int index, short value) {
|
||||
return wrapped.putShort(index, value);
|
||||
}
|
||||
|
||||
public int getInt() {
|
||||
return wrapped.getInt();
|
||||
}
|
||||
|
||||
public ByteBuffer putInt(int value) {
|
||||
return wrapped.putInt(value);
|
||||
}
|
||||
|
||||
public int getInt(int index) {
|
||||
return wrapped.getInt(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putInt(int index, int value) {
|
||||
return wrapped.putInt(index, value);
|
||||
}
|
||||
|
||||
public long getLong() {
|
||||
return wrapped.getLong();
|
||||
}
|
||||
|
||||
public ByteBuffer putLong(long value) {
|
||||
return wrapped.putLong(value);
|
||||
}
|
||||
|
||||
public long getLong(int index) {
|
||||
return wrapped.getLong(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putLong(int index, long value) {
|
||||
return wrapped.putLong(index, value);
|
||||
}
|
||||
|
||||
public float getFloat() {
|
||||
return wrapped.getFloat();
|
||||
}
|
||||
|
||||
public ByteBuffer putFloat(float value) {
|
||||
return wrapped.putFloat(value);
|
||||
}
|
||||
|
||||
public float getFloat(int index) {
|
||||
return wrapped.getFloat(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putFloat(int index, float value) {
|
||||
return wrapped.putFloat(index, value);
|
||||
}
|
||||
|
||||
public double getDouble() {
|
||||
return wrapped.getDouble();
|
||||
}
|
||||
|
||||
public ByteBuffer putDouble(double value) {
|
||||
return wrapped.putDouble(value);
|
||||
}
|
||||
|
||||
public double getDouble(int index) {
|
||||
return wrapped.getDouble(index);
|
||||
}
|
||||
|
||||
public ByteBuffer putDouble(int index, double value) {
|
||||
return wrapped.putDouble(index, value);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,6 @@ package com.simibubi.create.foundation.render.instancing;
|
|||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.simibubi.create.foundation.render.RenderMath;
|
||||
import com.simibubi.create.foundation.render.RenderWork;
|
||||
import com.simibubi.create.foundation.render.SafeDirectBuffer;
|
||||
import com.simibubi.create.foundation.render.TemplateBuffer;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import org.lwjgl.opengl.*;
|
||||
|
|
|
@ -16,9 +16,10 @@ public abstract class ContraptionLighter<C extends Contraption> {
|
|||
|
||||
GridAlignedBB bounds = getContraptionBounds();
|
||||
bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts
|
||||
GridAlignedBB importantArea = GridAlignedBB.copy(bounds);
|
||||
bounds.nextPowerOf2Centered();
|
||||
|
||||
lightVolume = new LightVolume(bounds);
|
||||
lightVolume = new LightVolume(bounds, importantArea);
|
||||
|
||||
lightVolume.initialize(contraption.entity.world);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.simibubi.create.foundation.render.light;
|
||||
|
||||
import com.simibubi.create.foundation.render.RenderMath;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.SectionPos;
|
||||
|
@ -79,12 +80,26 @@ public class GridAlignedBB {
|
|||
}
|
||||
|
||||
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();
|
||||
translate(by.getX(), by.getY(), by.getZ());
|
||||
}
|
||||
|
||||
public void translate(int x, int y, int z) {
|
||||
minX += x;
|
||||
maxX += x;
|
||||
minY += y;
|
||||
maxY += y;
|
||||
minZ += z;
|
||||
maxZ += z;
|
||||
}
|
||||
|
||||
public void rotate45(Direction.Axis axis) {
|
||||
if (axis == Direction.Axis.X) {
|
||||
this.grow(0, RenderMath.timesSqrt2(sizeY()), RenderMath.timesSqrt2(sizeZ()));
|
||||
} else if (axis == Direction.Axis.Y) {
|
||||
this.grow(RenderMath.timesSqrt2(sizeX()), 0, RenderMath.timesSqrt2(sizeZ()));
|
||||
} else if (axis == Direction.Axis.Z) {
|
||||
this.grow(RenderMath.timesSqrt2(sizeX()), RenderMath.timesSqrt2(sizeY()), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,12 +118,12 @@ public class GridAlignedBB {
|
|||
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;
|
||||
minX -= diffX / 2; // floor division for the minimums
|
||||
minY -= diffY / 2;
|
||||
minZ -= diffZ / 2;
|
||||
maxX += (diffX + 1) / 2; // ceiling divison for the maximums
|
||||
maxY += (diffY + 1) / 2;
|
||||
maxZ += (diffZ + 1) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,12 +149,12 @@ public class GridAlignedBB {
|
|||
}
|
||||
|
||||
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;
|
||||
minX -= x;
|
||||
minY -= y;
|
||||
minZ -= z;
|
||||
maxX += x;
|
||||
maxY += y;
|
||||
maxZ += z;
|
||||
}
|
||||
|
||||
public GridAlignedBB intersect(GridAlignedBB other) {
|
||||
|
|
|
@ -10,70 +10,80 @@ import org.lwjgl.system.MemoryUtil;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
// TODO: Don't immediately destroy light volumes.
|
||||
// There's a high chance that a contraption will stop and soon after start again.
|
||||
// By caching lightvolumes based on their volumes/locations, we can save having
|
||||
// to reread all the lighting data in those cases.
|
||||
public class LightVolume {
|
||||
|
||||
private final GridAlignedBB volume;
|
||||
private final GridAlignedBB sampleVolume;
|
||||
private final GridAlignedBB textureVolume;
|
||||
private ByteBuffer lightData;
|
||||
|
||||
private boolean bufferDirty;
|
||||
|
||||
private int glTexture;
|
||||
|
||||
public LightVolume(GridAlignedBB volume) {
|
||||
public LightVolume(GridAlignedBB textureVolume, GridAlignedBB sampleVolume) {
|
||||
// the gpu requires that all textures have power of 2 side lengths
|
||||
if (!volume.hasPowerOf2Sides())
|
||||
if (!textureVolume.hasPowerOf2Sides())
|
||||
throw new IllegalArgumentException("LightVolume must have power of 2 side lengths");
|
||||
|
||||
this.volume = volume;
|
||||
this.textureVolume = textureVolume;
|
||||
this.sampleVolume = sampleVolume;
|
||||
|
||||
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
|
||||
this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte
|
||||
}
|
||||
|
||||
public GridAlignedBB getBox() {
|
||||
return GridAlignedBB.copy(volume);
|
||||
public GridAlignedBB getTextureVolume() {
|
||||
return GridAlignedBB.copy(textureVolume);
|
||||
}
|
||||
|
||||
public GridAlignedBB getSampleVolume() {
|
||||
return GridAlignedBB.copy(sampleVolume);
|
||||
}
|
||||
|
||||
public int getMinX() {
|
||||
return volume.minX;
|
||||
return textureVolume.minX;
|
||||
}
|
||||
|
||||
public int getMinY() {
|
||||
return volume.minY;
|
||||
return textureVolume.minY;
|
||||
}
|
||||
|
||||
public int getMinZ() {
|
||||
return volume.minZ;
|
||||
return textureVolume.minZ;
|
||||
}
|
||||
|
||||
public int getMaxX() {
|
||||
return volume.maxX;
|
||||
return textureVolume.maxX;
|
||||
}
|
||||
|
||||
public int getMaxY() {
|
||||
return volume.maxY;
|
||||
return textureVolume.maxY;
|
||||
}
|
||||
|
||||
public int getMaxZ() {
|
||||
return volume.maxZ;
|
||||
return textureVolume.maxZ;
|
||||
}
|
||||
|
||||
public int getSizeX() {
|
||||
return volume.sizeX();
|
||||
return textureVolume.sizeX();
|
||||
}
|
||||
|
||||
public int getSizeY() {
|
||||
return volume.sizeY();
|
||||
return textureVolume.sizeY();
|
||||
}
|
||||
|
||||
public int getSizeZ() {
|
||||
return volume.sizeZ();
|
||||
return textureVolume.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.
|
||||
changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data.
|
||||
|
||||
if (!changedVolume.empty()) {
|
||||
if (type == LightType.BLOCK) copyBlock(world, changedVolume);
|
||||
|
@ -88,11 +98,11 @@ public class LightVolume {
|
|||
public void initialize(ILightReader world) {
|
||||
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||
|
||||
int shiftX = volume.minX;
|
||||
int shiftY = volume.minY;
|
||||
int shiftZ = volume.minZ;
|
||||
int shiftX = textureVolume.minX;
|
||||
int shiftY = textureVolume.minY;
|
||||
int shiftZ = textureVolume.minZ;
|
||||
|
||||
volume.forEachContained((x, y, z) -> {
|
||||
textureVolume.forEachContained((x, y, z) -> {
|
||||
pos.setPos(x, y, z);
|
||||
|
||||
int blockLight = world.getLightLevel(LightType.BLOCK, pos);
|
||||
|
@ -111,9 +121,9 @@ public class LightVolume {
|
|||
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;
|
||||
int xShift = textureVolume.minX;
|
||||
int yShift = textureVolume.minY;
|
||||
int zShift = textureVolume.minZ;
|
||||
|
||||
worldVolume.forEachContained((x, y, z) -> {
|
||||
pos.setPos(x, y, z);
|
||||
|
@ -133,9 +143,9 @@ public class LightVolume {
|
|||
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;
|
||||
int xShift = textureVolume.minX;
|
||||
int yShift = textureVolume.minY;
|
||||
int zShift = textureVolume.minZ;
|
||||
|
||||
worldVolume.forEachContained((x, y, z) -> {
|
||||
pos.setPos(x, y, z);
|
||||
|
@ -159,7 +169,7 @@ public class LightVolume {
|
|||
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);
|
||||
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, textureVolume.sizeX(), textureVolume.sizeY(), textureVolume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData);
|
||||
bufferDirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -199,6 +209,6 @@ public class LightVolume {
|
|||
}
|
||||
|
||||
private int index(int x, int y, int z) {
|
||||
return (x + volume.sizeX() * (y + z * volume.sizeY())) * 2;
|
||||
return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * 2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,33 @@ 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.Pair;
|
||||
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
|
||||
import com.simibubi.create.foundation.utility.outliner.Outline;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
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)))
|
||||
.flatMap(r -> {
|
||||
GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume();
|
||||
GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume();
|
||||
|
||||
ArrayList<Pair<GridAlignedBB, Integer>> pairs = new ArrayList<>(2);
|
||||
|
||||
pairs.add(Pair.of(texture, 0xFFFFFF));
|
||||
pairs.add(Pair.of(sample, 0xFFFF00));
|
||||
|
||||
return pairs.stream();
|
||||
})
|
||||
.map(pair -> {
|
||||
AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst()));
|
||||
|
||||
outline.getParams().colored(pair.getSecond());
|
||||
return outline;
|
||||
})
|
||||
.forEach(outline -> outline.render(ms, buffer));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue