mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-28 22:04:57 +01:00
Batching Engine
- Implement alternate backend using SBBs
This commit is contained in:
parent
26c35e31b6
commit
f1e63106fc
47 changed files with 1215 additions and 356 deletions
|
@ -1,10 +1,8 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public interface Batched<S> extends StructType<S> {
|
||||
|
||||
BatchingTransformer<S> getTransformer(Model model);
|
||||
BatchingTransformer<S> getTransformer();
|
||||
|
||||
@Override
|
||||
default Batched<S> asBatched() {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
package com.jozufozu.flywheel.api.struct;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.jozufozu.flywheel.core.model.SuperByteBuffer;
|
||||
|
||||
public abstract class BatchingTransformer<S> {
|
||||
@FunctionalInterface
|
||||
public interface BatchingTransformer<S> {
|
||||
|
||||
public void draw(S s, PoseStack stack, VertexConsumer consumer) {
|
||||
|
||||
}
|
||||
void transform(S s, SuperByteBuffer b);
|
||||
}
|
||||
|
|
|
@ -17,10 +17,13 @@ import com.jozufozu.flywheel.api.FlywheelWorld;
|
|||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher;
|
||||
import com.jozufozu.flywheel.config.FlwConfig;
|
||||
import com.jozufozu.flywheel.config.FlwEngine;
|
||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
@ -29,6 +32,7 @@ public class Backend {
|
|||
public static final Logger log = LogManager.getLogger(Backend.class);
|
||||
|
||||
protected static final Backend INSTANCE = new Backend();
|
||||
private FlwEngine engine;
|
||||
|
||||
public static Backend getInstance() {
|
||||
return INSTANCE;
|
||||
|
@ -57,12 +61,13 @@ public class Backend {
|
|||
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
||||
*/
|
||||
public String getBackendDescriptor() {
|
||||
if (canUseInstancing()) {
|
||||
return "GL33 Instanced Arrays";
|
||||
}
|
||||
if (enabled) {
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
|
||||
if (canUseVBOs()) {
|
||||
return "VBOs";
|
||||
if (level == null) {
|
||||
return "Invalid";
|
||||
}
|
||||
return InstancedRenderDispatcher.getEngineName(level);
|
||||
}
|
||||
|
||||
return "Disabled";
|
||||
|
@ -134,8 +139,9 @@ public class Backend {
|
|||
|
||||
instancedArrays = compat.instancedArraysSupported();
|
||||
|
||||
enabled = FlwConfig.get()
|
||||
.enabled() && !OptifineHandler.usingShaders();
|
||||
FlwConfig config = FlwConfig.get();
|
||||
enabled = config.enabled() && !OptifineHandler.usingShaders();
|
||||
engine = config.client.engine.get();
|
||||
}
|
||||
|
||||
public boolean canUseInstancing(@Nullable Level world) {
|
||||
|
@ -188,4 +194,8 @@ public class Backend {
|
|||
|
||||
public static void init() {
|
||||
}
|
||||
|
||||
public FlwEngine getEngine() {
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,14 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
anyToRemove = true;
|
||||
}
|
||||
|
||||
public int getModelVertexCount() {
|
||||
return modelData.vertexCount();
|
||||
}
|
||||
|
||||
public int numInstances() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
protected BitSet getDirtyBitSet() {
|
||||
final int size = data.size();
|
||||
final BitSet dirtySet = new BitSet(size);
|
||||
|
|
|
@ -3,4 +3,5 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
|
||||
public interface Engine extends RenderDispatcher, MaterialManager {
|
||||
String getName();
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package com.jozufozu.flywheel.backend.instancing;
|
|||
|
||||
import com.jozufozu.flywheel.api.instance.IDynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.instancing.batching.BatchingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
||||
import com.jozufozu.flywheel.config.FlwEngine;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
|
@ -29,12 +31,11 @@ public class InstanceWorld {
|
|||
|
||||
public InstanceWorld() {
|
||||
|
||||
// TODO: finish impl
|
||||
if (false) {
|
||||
engine = new BatchingEngine();
|
||||
entityInstanceManager = new EntityInstanceManager(engine);
|
||||
tileEntityInstanceManager = new TileInstanceManager(engine);
|
||||
} else {
|
||||
FlwEngine engine = Backend.getInstance()
|
||||
.getEngine();
|
||||
|
||||
switch (engine) {
|
||||
case GL33 -> {
|
||||
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
||||
.build();
|
||||
|
||||
|
@ -43,7 +44,14 @@ public class InstanceWorld {
|
|||
|
||||
manager.addListener(entityInstanceManager);
|
||||
manager.addListener(tileEntityInstanceManager);
|
||||
engine = manager;
|
||||
this.engine = manager;
|
||||
}
|
||||
case BATCHING -> {
|
||||
this.engine = new BatchingEngine();
|
||||
entityInstanceManager = new EntityInstanceManager(this.engine);
|
||||
tileEntityInstanceManager = new TileInstanceManager(this.engine);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unknown engine type");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,10 @@ public class InstancedRenderDispatcher {
|
|||
getEntities(entity.level).queueUpdate(entity);
|
||||
}
|
||||
|
||||
public static String getEngineName(LevelAccessor world) {
|
||||
return instanceWorlds.get(world).engine.getName();
|
||||
}
|
||||
|
||||
public static InstanceManager<BlockEntity> getTiles(LevelAccessor world) {
|
||||
return instanceWorlds.get(world)
|
||||
.getTileEntityInstanceManager();
|
||||
|
|
|
@ -28,9 +28,9 @@ public class BatchedMaterial<D extends InstanceData> implements Material<D> {
|
|||
return models.computeIfAbsent(key, $ -> new CPUInstancer<>(type, modelSupplier.get()));
|
||||
}
|
||||
|
||||
public void render(PoseStack stack, VertexConsumer buffer) {
|
||||
public void render(PoseStack stack, VertexConsumer buffer, FormatContext context) {
|
||||
for (CPUInstancer<D> instancer : models.values()) {
|
||||
instancer.drawAll(stack, buffer);
|
||||
instancer.drawAll(stack, buffer, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ import java.util.Map;
|
|||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
|
||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
|
@ -31,8 +33,31 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
|||
public void render(PoseStack stack, MultiBufferSource source) {
|
||||
VertexConsumer buffer = source.getBuffer(state);
|
||||
|
||||
if (buffer instanceof DirectBufferBuilder direct) {
|
||||
DirectVertexConsumer consumer = direct.intoDirectConsumer(calculateNeededVertices());
|
||||
|
||||
renderInto(stack, consumer, new FormatContext(consumer.hasOverlay()));
|
||||
|
||||
direct.updateAfterWriting(consumer);
|
||||
} else {
|
||||
renderInto(stack, buffer, FormatContext.defaultContext());
|
||||
}
|
||||
}
|
||||
|
||||
private int calculateNeededVertices() {
|
||||
int total = 0;
|
||||
for (BatchedMaterial<?> material : materials.values()) {
|
||||
for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
total += instancer.getModelVertexCount() * instancer.numInstances();
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
private void renderInto(PoseStack stack, VertexConsumer consumer, FormatContext context) {
|
||||
for (BatchedMaterial<?> value : materials.values()) {
|
||||
value.render(stack, buffer);
|
||||
value.render(stack, consumer, context);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.jozufozu.flywheel.api.MaterialGroup;
|
|||
import com.jozufozu.flywheel.backend.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
|
@ -40,15 +41,28 @@ public class BatchingEngine implements Engine {
|
|||
|
||||
@Override
|
||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
||||
PoseStack stack = event.stack;
|
||||
|
||||
stack.pushPose();
|
||||
|
||||
stack.translate(-event.camX, -event.camY, -event.camZ);
|
||||
|
||||
for (Map.Entry<RenderType, BatchedMaterialGroup> entry : layers.get(event.getLayer()).entrySet()) {
|
||||
BatchedMaterialGroup group = entry.getValue();
|
||||
|
||||
group.render(event.stack, buffers);
|
||||
group.render(stack, buffers);
|
||||
}
|
||||
|
||||
stack.popPose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(Camera info) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Batching";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,18 +5,23 @@ import com.jozufozu.flywheel.api.struct.BatchingTransformer;
|
|||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.SuperByteBuffer;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
|
||||
public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
|
||||
private final BatchingTransformer<D> renderer;
|
||||
private final BatchingTransformer<D> transform;
|
||||
|
||||
private final SuperByteBuffer sbb;
|
||||
|
||||
public CPUInstancer(StructType<D> type, Model modelData) {
|
||||
super(type, modelData);
|
||||
|
||||
renderer = type.asBatched()
|
||||
.getTransformer(modelData);
|
||||
sbb = new SuperByteBuffer(modelData);
|
||||
transform = type.asBatched()
|
||||
.getTransformer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,15 +29,19 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
// noop
|
||||
}
|
||||
|
||||
public void drawAll(PoseStack stack, VertexConsumer buffer) {
|
||||
if (renderer == null) {
|
||||
public void drawAll(PoseStack stack, VertexConsumer buffer, FormatContext context) {
|
||||
if (transform == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderSetup();
|
||||
|
||||
for (D d : data) {
|
||||
renderer.draw(d, stack, buffer);
|
||||
if (context.usesOverlay()) sbb.entityMode();
|
||||
|
||||
transform.transform(d, sbb);
|
||||
|
||||
sbb.renderInto(stack, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
public record FormatContext(boolean usesOverlay) {
|
||||
|
||||
public static FormatContext defaultContext() {
|
||||
return new FormatContext(false);
|
||||
}
|
||||
}
|
|
@ -165,6 +165,11 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "GL33 Instanced Arrays";
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface OriginShiftListener {
|
||||
void onOriginShift();
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
public interface DirectBufferBuilder {
|
||||
|
||||
DirectVertexConsumer intoDirectConsumer(int neededVerts);
|
||||
|
||||
void updateAfterWriting(DirectVertexConsumer complete);
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
||||
|
||||
public class DirectVertexConsumer implements VertexConsumer {
|
||||
|
||||
public final VertexFormat format;
|
||||
private final int stride;
|
||||
public final int startPos;
|
||||
|
||||
private int position = -1;
|
||||
private int normal = -1;
|
||||
private int color = -1;
|
||||
private int uv = -1;
|
||||
private int uv1 = -1;
|
||||
private int uv2 = -1;
|
||||
|
||||
private long vertexBase;
|
||||
private int vertexCount;
|
||||
|
||||
public DirectVertexConsumer(ByteBuffer buffer, VertexFormat format) {
|
||||
this.format = format;
|
||||
startPos = buffer.position();
|
||||
stride = format.getVertexSize();
|
||||
|
||||
int offset = 0;
|
||||
|
||||
for (VertexFormatElement element : format.getElements()) {
|
||||
switch (element.getUsage()) {
|
||||
case POSITION -> this.position = offset;
|
||||
case NORMAL -> this.normal = offset;
|
||||
case COLOR -> this.color = offset;
|
||||
case UV -> {
|
||||
switch (element.getIndex()) {
|
||||
case 0 -> this.uv = offset;
|
||||
case 1 -> this.uv1 = offset;
|
||||
case 2 -> this.uv2 = offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
offset += element.getByteSize();
|
||||
}
|
||||
|
||||
this.vertexBase = MemoryUtil.memAddress(buffer);
|
||||
}
|
||||
|
||||
public boolean hasOverlay() {
|
||||
return uv1 >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer vertex(double x, double y, double z) {
|
||||
if (position < 0) return this;
|
||||
long base = vertexBase + position;
|
||||
MemoryUtil.memPutFloat(base, (float) x);
|
||||
MemoryUtil.memPutFloat(base + 4, (float) y);
|
||||
MemoryUtil.memPutFloat(base + 8, (float) z);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer color(int r, int g, int b, int a) {
|
||||
if (color < 0) return this;
|
||||
long base = vertexBase + color;
|
||||
MemoryUtil.memPutByte(base, (byte) r);
|
||||
MemoryUtil.memPutByte(base + 1, (byte) g);
|
||||
MemoryUtil.memPutByte(base + 2, (byte) b);
|
||||
MemoryUtil.memPutByte(base + 3, (byte) a);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv(float u, float v) {
|
||||
if (uv < 0) return this;
|
||||
long base = vertexBase + uv;
|
||||
MemoryUtil.memPutFloat(base, u);
|
||||
MemoryUtil.memPutFloat(base + 4, v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer overlayCoords(int u, int v) {
|
||||
if (uv1 < 0) return this;
|
||||
long base = vertexBase + uv1;
|
||||
MemoryUtil.memPutShort(base, (short) u);
|
||||
MemoryUtil.memPutShort(base + 2, (short) v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv2(int u, int v) {
|
||||
if (uv2 < 0) return this;
|
||||
long base = vertexBase + uv2;
|
||||
MemoryUtil.memPutShort(base, (short) u);
|
||||
MemoryUtil.memPutShort(base + 2, (short) v);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer normal(float x, float y, float z) {
|
||||
if (normal < 0) return this;
|
||||
long base = vertexBase + normal;
|
||||
MemoryUtil.memPutByte(base, RenderMath.nb(x));
|
||||
MemoryUtil.memPutByte(base + 1, RenderMath.nb(y));
|
||||
MemoryUtil.memPutByte(base + 2, RenderMath.nb(z));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVertex() {
|
||||
vertexBase += stride;
|
||||
vertexCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultColor(int r, int g, int b, int a) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetDefaultColor() {
|
||||
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -18,14 +18,22 @@ public abstract class BufferWriter<S> implements StructWriter<S> {
|
|||
this.stride = this.format.getStride();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the write pointer forward by the stride of one vertex. This should always be called after a
|
||||
* vertex is written. Implementations which override this should always call invoke the super implementation.
|
||||
*/
|
||||
protected void advance() {
|
||||
|
||||
@Override
|
||||
public final void write(S struct) {
|
||||
writeInternal(struct);
|
||||
advance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the write pointer forward by the stride of one vertex.
|
||||
* This will always be called after a struct is written, implementors need not call it themselves.
|
||||
*
|
||||
* @see #write
|
||||
*/
|
||||
protected abstract void advance();
|
||||
|
||||
protected abstract void writeInternal(S s);
|
||||
|
||||
@Override
|
||||
public void seek(int pos) {
|
||||
backingBuffer.position(pos * stride);
|
||||
|
|
|
@ -15,7 +15,7 @@ import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
|||
*/
|
||||
public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
||||
/**
|
||||
* The write pointer into the buffer storage. This is advanced by the vertex stride every time
|
||||
* The write pointer into the buffer storage. This is advanced by the stride every time
|
||||
* {@link UnsafeBufferWriter#advance()} is called.
|
||||
*/
|
||||
protected long writePointer;
|
||||
|
@ -35,8 +35,6 @@ public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
|||
@Override
|
||||
protected void advance() {
|
||||
this.writePointer += this.stride;
|
||||
|
||||
super.advance();
|
||||
}
|
||||
|
||||
private void acquireWritePointer() {
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package com.jozufozu.flywheel.config;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import net.minecraftforge.server.command.EnumArgument;
|
||||
|
||||
public class EngineConfigCommand {
|
||||
public ArgumentBuilder<CommandSourceStack, ?> register() {
|
||||
return Commands.literal("engine")
|
||||
.executes(context -> {
|
||||
ServerPlayer player = context.getSource()
|
||||
.getPlayerOrException();
|
||||
FlwPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SConfigureEnginePacket());
|
||||
return Command.SINGLE_SUCCESS;
|
||||
})
|
||||
.then(Commands.argument("type", EnumArgument.enumArgument(FlwEngine.class))
|
||||
.executes(context -> {
|
||||
FlwEngine type = context.getArgument("type", FlwEngine.class);
|
||||
|
||||
ServerPlayer player = context.getSource()
|
||||
.getPlayerOrException();
|
||||
FlwPackets.channel.send(PacketDistributor.PLAYER.with(() -> player), new SConfigureEnginePacket(type));
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ public class FlwCommands {
|
|||
dispatcher.register(Commands.literal("flywheel")
|
||||
.then(new BooleanConfigCommand("backend", BooleanConfig.ENGINE).register())
|
||||
.then(new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).register())
|
||||
.then(new EngineConfigCommand().register())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public class FlwConfig {
|
|||
|
||||
public static class ClientConfig {
|
||||
public final BooleanValue enabled;
|
||||
public final ForgeConfigSpec.EnumValue<FlwEngine> engine;
|
||||
public final BooleanValue debugNormals;
|
||||
|
||||
public ClientConfig(ForgeConfigSpec.Builder builder) {
|
||||
|
@ -46,6 +47,9 @@ public class FlwConfig {
|
|||
enabled = builder.comment("Enable or disable the entire engine")
|
||||
.define("enabled", true);
|
||||
|
||||
engine = builder.comment("Enable or disable the entire engine")
|
||||
.defineEnum("backend", FlwEngine.GL33);
|
||||
|
||||
debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal")
|
||||
.define("debugNormals", false);
|
||||
}
|
||||
|
|
57
src/main/java/com/jozufozu/flywheel/config/FlwEngine.java
Normal file
57
src/main/java/com/jozufozu/flywheel/config/FlwEngine.java
Normal file
|
@ -0,0 +1,57 @@
|
|||
package com.jozufozu.flywheel.config;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.OptifineHandler;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
|
||||
public enum FlwEngine {
|
||||
BATCHING(new TextComponent("Batching").withStyle(ChatFormatting.BLUE)),
|
||||
GL33(new TextComponent("GL 3.3 Instanced Arrays").withStyle(ChatFormatting.GREEN)),
|
||||
|
||||
;
|
||||
|
||||
private final Component name;
|
||||
|
||||
FlwEngine(Component name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static FlwEngine decode(FriendlyByteBuf buffer) {
|
||||
byte b = buffer.readByte();
|
||||
|
||||
if (b == -1) return null;
|
||||
|
||||
return values()[b];
|
||||
}
|
||||
|
||||
public void encode(FriendlyByteBuf buffer) {
|
||||
buffer.writeByte(this.ordinal());
|
||||
}
|
||||
|
||||
public void switchTo() {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (player == null) return;
|
||||
|
||||
// if (state == BooleanDirective.DISPLAY) {
|
||||
// Component text = new TextComponent("Flywheel renderer is currently: ").append(boolToText(FlwConfig.get().enabled()));
|
||||
// player.displayClientMessage(text, false);
|
||||
// return;
|
||||
// }
|
||||
|
||||
FlwConfig.get().client.engine.set(this);
|
||||
|
||||
Component text = new TextComponent("Using ").withStyle(ChatFormatting.WHITE).append(name);
|
||||
|
||||
player.displayClientMessage(text, false);
|
||||
Backend.reloadWorldRenderers();
|
||||
}
|
||||
}
|
|
@ -24,5 +24,11 @@ public class FlwPackets {
|
|||
.encoder(SConfigureBooleanPacket::encode)
|
||||
.consumer(SConfigureBooleanPacket::execute)
|
||||
.add();
|
||||
|
||||
channel.messageBuilder(SConfigureEnginePacket.class, 1, NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(SConfigureEnginePacket::new)
|
||||
.encoder(SConfigureEnginePacket::encode)
|
||||
.consumer(SConfigureEnginePacket::execute)
|
||||
.add();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package com.jozufozu.flywheel.config;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
public class SConfigureEnginePacket {
|
||||
|
||||
private final FlwEngine type;
|
||||
|
||||
public SConfigureEnginePacket() {
|
||||
type = null;
|
||||
}
|
||||
|
||||
public SConfigureEnginePacket(FlwEngine type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public SConfigureEnginePacket(FriendlyByteBuf buffer) {
|
||||
type = FlwEngine.decode(buffer);
|
||||
}
|
||||
|
||||
public void encode(FriendlyByteBuf buffer) {
|
||||
if (type != null)
|
||||
type.encode(buffer);
|
||||
else
|
||||
buffer.writeByte(-1);
|
||||
}
|
||||
|
||||
public void execute(Supplier<NetworkEvent.Context> ctx) {
|
||||
if (type != null) {
|
||||
type.switchTo();
|
||||
}
|
||||
ctx.get()
|
||||
.setPacketHandled(true);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package com.jozufozu.flywheel.core.materials;
|
|||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
|
||||
public abstract class BasicData extends InstanceData implements FlatLit<BasicData> {
|
||||
|
||||
public byte blockLight;
|
||||
|
@ -14,18 +16,23 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
|||
|
||||
@Override
|
||||
public BasicData setBlockLight(int blockLight) {
|
||||
this.blockLight = (byte) (blockLight << 4);
|
||||
this.blockLight = (byte) blockLight;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicData setSkyLight(int skyLight) {
|
||||
this.skyLight = (byte) (skyLight << 4);
|
||||
this.skyLight = (byte) skyLight;
|
||||
markDirty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPackedLight() {
|
||||
return LightTexture.pack(this.blockLight, this.skyLight);
|
||||
}
|
||||
|
||||
public BasicData setColor(int color) {
|
||||
return setColor(color, false);
|
||||
}
|
||||
|
|
|
@ -24,4 +24,6 @@ public interface FlatLit<D extends InstanceData & FlatLit<D>> {
|
|||
* @return <code>this</code>
|
||||
*/
|
||||
D setSkyLight(int skyLight);
|
||||
|
||||
int getPackedLight();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package com.jozufozu.flywheel.core.materials;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
||||
|
||||
public abstract class UnsafeBasicWriter<D extends BasicData> extends UnsafeBufferWriter<D> {
|
||||
|
||||
public UnsafeBasicWriter(VecBuffer backingBuffer, StructType<D> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(D d) {
|
||||
long addr = writePointer;
|
||||
MemoryUtil.memPutByte(addr, (byte) (d.blockLight << 4));
|
||||
MemoryUtil.memPutByte(addr + 1, (byte) (d.skyLight << 4));
|
||||
MemoryUtil.memPutByte(addr + 2, d.r);
|
||||
MemoryUtil.memPutByte(addr + 3, d.g);
|
||||
MemoryUtil.memPutByte(addr + 4, d.b);
|
||||
MemoryUtil.memPutByte(addr + 5, d.a);
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.materials.model;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.BatchingTransformer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public class ModelTransformer extends BatchingTransformer<ModelData> {
|
||||
public ModelTransformer(Model model) {
|
||||
|
||||
|
||||
//model.buffer();
|
||||
}
|
||||
}
|
|
@ -8,8 +8,6 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.Programs;
|
||||
import com.jozufozu.flywheel.core.materials.model.writer.UnsafeModelWriter;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -36,7 +34,11 @@ public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BatchingTransformer<ModelData> getTransformer(Model model) {
|
||||
return null;
|
||||
public BatchingTransformer<ModelData> getTransformer() {
|
||||
return (d, b) -> {
|
||||
b.transform(d.model, d.normal)
|
||||
.color(d.r, d.g, d.b, d.a)
|
||||
.light(d.getPackedLight());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package com.jozufozu.flywheel.core.materials.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.materials.UnsafeBasicWriter;
|
||||
import com.jozufozu.flywheel.util.WriteUnsafe;
|
||||
|
||||
public class UnsafeModelWriter extends UnsafeBasicWriter<ModelData> {
|
||||
|
||||
public UnsafeModelWriter(VecBuffer backingBuffer, StructType<ModelData> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(ModelData d) {
|
||||
super.writeInternal(d);
|
||||
long addr = writePointer + 6;
|
||||
|
||||
((WriteUnsafe) (Object) d.model).writeUnsafe(addr);
|
||||
addr += 4 * 16;
|
||||
((WriteUnsafe) (Object) d.normal).writeUnsafe(addr);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.materials.model.writer;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.util.WriteUnsafe;
|
||||
|
||||
public class UnsafeModelWriter extends UnsafeBufferWriter<ModelData> {
|
||||
|
||||
public UnsafeModelWriter(VecBuffer backingBuffer, StructType<ModelData> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ModelData d) {
|
||||
long addr = writePointer;
|
||||
MemoryUtil.memPutByte(addr, d.blockLight);
|
||||
MemoryUtil.memPutByte(addr + 1, d.skyLight);
|
||||
MemoryUtil.memPutByte(addr + 2, d.r);
|
||||
MemoryUtil.memPutByte(addr + 3, d.g);
|
||||
MemoryUtil.memPutByte(addr + 4, d.b);
|
||||
MemoryUtil.memPutByte(addr + 5, d.a);
|
||||
|
||||
addr += 6;
|
||||
|
||||
((WriteUnsafe) (Object) d.model).writeUnsafe(addr);
|
||||
addr += 4 * 16;
|
||||
((WriteUnsafe) (Object) d.normal).writeUnsafe(addr);
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
|
@ -8,8 +8,7 @@ import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.Programs;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.writer.UnsafeOrientedWriter;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.mojang.math.Quaternion;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
|
@ -36,7 +35,13 @@ public class OrientedType implements Instanced<OrientedData>, Batched<OrientedDa
|
|||
}
|
||||
|
||||
@Override
|
||||
public BatchingTransformer<OrientedData> getTransformer(Model model) {
|
||||
return null;
|
||||
public BatchingTransformer<OrientedData> getTransformer() {
|
||||
return (d, sbb) -> {
|
||||
sbb.light(d.getPackedLight())
|
||||
.color(d.r, d.g, d.b, d.a)
|
||||
.translate(d.posX + d.pivotX, d.posY + d.pivotY, d.posZ + d.pivotZ)
|
||||
.multiply(new Quaternion(d.qX, d.qY, d.qZ, d.qW))
|
||||
.translate(-d.pivotX, -d.pivotY, -d.pivotZ);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +1,20 @@
|
|||
package com.jozufozu.flywheel.core.materials.oriented.writer;
|
||||
package com.jozufozu.flywheel.core.materials.oriented;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.core.materials.UnsafeBasicWriter;
|
||||
|
||||
public class UnsafeOrientedWriter extends UnsafeBufferWriter<OrientedData> {
|
||||
public class UnsafeOrientedWriter extends UnsafeBasicWriter<OrientedData> {
|
||||
public UnsafeOrientedWriter(VecBuffer backingBuffer, StructType<OrientedData> vertexType) {
|
||||
super(backingBuffer, vertexType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OrientedData d) {
|
||||
protected void writeInternal(OrientedData d) {
|
||||
long addr = writePointer;
|
||||
MemoryUtil.memPutByte(addr, d.blockLight);
|
||||
MemoryUtil.memPutByte(addr + 1, d.skyLight);
|
||||
MemoryUtil.memPutByte(addr + 2, d.r);
|
||||
MemoryUtil.memPutByte(addr + 3, d.g);
|
||||
MemoryUtil.memPutByte(addr + 4, d.b);
|
||||
MemoryUtil.memPutByte(addr + 5, d.a);
|
||||
super.writeInternal(d);
|
||||
|
||||
MemoryUtil.memPutFloat(addr + 6, d.posX);
|
||||
MemoryUtil.memPutFloat(addr + 10, d.posY);
|
||||
|
@ -32,7 +26,5 @@ public class UnsafeOrientedWriter extends UnsafeBufferWriter<OrientedData> {
|
|||
MemoryUtil.memPutFloat(addr + 34, d.qY);
|
||||
MemoryUtil.memPutFloat(addr + 38, d.qZ);
|
||||
MemoryUtil.memPutFloat(addr + 42, d.qW);
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
|
||||
package com.jozufozu.flywheel.core.materials;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
|
@ -1,138 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.lwjgl.system.MemoryStack;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemColors;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
public class BakedModelModel implements Model {
|
||||
// DOWN, UP, NORTH, SOUTH, WEST, EAST, null
|
||||
private static final Direction[] dirs;
|
||||
|
||||
static {
|
||||
Direction[] directions = Direction.values();
|
||||
|
||||
dirs = Arrays.copyOf(directions, directions.length + 1);
|
||||
}
|
||||
|
||||
|
||||
public final BakedModel model;
|
||||
private final int numQuads;
|
||||
|
||||
public BakedModelModel(BakedModel model) {
|
||||
this.model = model;
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
int numQuads = 0;
|
||||
|
||||
for (Direction dir : dirs) {
|
||||
random.setSeed(42);
|
||||
List<BakedQuad> quads = model.getQuads(null, dir, random, VirtualEmptyModelData.INSTANCE);
|
||||
|
||||
numQuads += quads.size();
|
||||
}
|
||||
|
||||
this.numQuads = numQuads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return model.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buffer(VertexConsumer buffer) {
|
||||
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
ItemColors itemColors = mc.getItemColors();
|
||||
|
||||
Random random = new Random();
|
||||
|
||||
for (Direction dir : dirs) {
|
||||
random.setSeed(42);
|
||||
List<BakedQuad> quads = model.getQuads(null, dir, random, VirtualEmptyModelData.INSTANCE);
|
||||
|
||||
for (BakedQuad bakedQuad : quads) {
|
||||
// int i = -1;
|
||||
// if (!itemStack.isEmpty() && bakedQuad.isTinted()) {
|
||||
// i = itemColors.getColor(itemStack, bakedQuad.getTintIndex());
|
||||
// }
|
||||
//
|
||||
// byte red = (byte)(i >> 16 & 255);
|
||||
// byte green = (byte)(i >> 8 & 255);
|
||||
// byte blue = (byte)(i & 255);
|
||||
|
||||
int[] aint = bakedQuad.getVertices();
|
||||
Vec3i faceNormal = bakedQuad.getDirection().getNormal();
|
||||
Vector3f normal = new Vector3f((float)faceNormal.getX(), (float)faceNormal.getY(), (float)faceNormal.getZ());
|
||||
int intSize = DefaultVertexFormat.BLOCK.getIntegerSize();
|
||||
int vertexCount = aint.length / intSize;
|
||||
|
||||
try (MemoryStack memorystack = MemoryStack.stackPush()) {
|
||||
ByteBuffer bytebuffer = memorystack.malloc(DefaultVertexFormat.BLOCK.getVertexSize());
|
||||
IntBuffer intbuffer = bytebuffer.asIntBuffer();
|
||||
|
||||
for(int j = 0; j < vertexCount; ++j) {
|
||||
((Buffer)intbuffer).clear();
|
||||
intbuffer.put(aint, j * 8, 8);
|
||||
float f = bytebuffer.getFloat(0);
|
||||
float f1 = bytebuffer.getFloat(4);
|
||||
float f2 = bytebuffer.getFloat(8);
|
||||
// float cr;
|
||||
// float cg;
|
||||
// float cb;
|
||||
// float ca;
|
||||
// {
|
||||
// float r = (float)(bytebuffer.get(12) & 255) / 255.0F;
|
||||
// float g = (float)(bytebuffer.get(13) & 255) / 255.0F;
|
||||
// float b = (float)(bytebuffer.get(14) & 255) / 255.0F;
|
||||
// float a = (float)(bytebuffer.get(15) & 255) / 255.0F;
|
||||
// cr = r * red;
|
||||
// cg = g * green;
|
||||
// cb = b * blue;
|
||||
// ca = a;
|
||||
// }
|
||||
|
||||
float u = bytebuffer.getFloat(16);
|
||||
float v = bytebuffer.getFloat(20);
|
||||
|
||||
buffer.vertex(f, f1, f2);
|
||||
buffer.normal(normal.x(), normal.y(), normal.z());
|
||||
buffer.uv(u, v);
|
||||
buffer.endVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vertexCount() {
|
||||
return numQuads * 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexFormat format() {
|
||||
return Formats.UNLIT_MODEL;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import java.util.Arrays;
|
|||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
||||
import com.jozufozu.flywheel.util.ModelReader;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
|
@ -27,7 +28,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
public class BlockModel implements Model {
|
||||
private static final PoseStack IDENTITY = new PoseStack();
|
||||
|
||||
private final BufferBuilderReader reader;
|
||||
private final ModelReader reader;
|
||||
|
||||
private final String name;
|
||||
|
||||
|
@ -69,7 +70,7 @@ public class BlockModel implements Model {
|
|||
for (int i = 0; i < vertexCount; i++) {
|
||||
buffer.vertex(reader.getX(i), reader.getY(i), reader.getZ(i));
|
||||
|
||||
buffer.normal(RenderMath.f(reader.getNX(i)), RenderMath.f(reader.getNY(i)), RenderMath.f(reader.getNZ(i)));
|
||||
buffer.normal(reader.getNX(i), reader.getNY(i), reader.getNZ(i));
|
||||
|
||||
buffer.uv(reader.getU(i), reader.getV(i));
|
||||
|
||||
|
@ -77,6 +78,11 @@ public class BlockModel implements Model {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelReader getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
public static BufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
BlockRenderDispatcher dispatcher = mc.getBlockRenderer();
|
||||
|
@ -96,12 +102,4 @@ public class BlockModel implements Model {
|
|||
return builder;
|
||||
}
|
||||
|
||||
// DOWN, UP, NORTH, SOUTH, WEST, EAST, null
|
||||
private static final Direction[] dirs;
|
||||
|
||||
static {
|
||||
Direction[] directions = Direction.values();
|
||||
|
||||
dirs = Arrays.copyOf(directions, directions.length + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.core.model;
|
|||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
import com.jozufozu.flywheel.util.ModelReader;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
/**
|
||||
|
@ -76,4 +77,6 @@ public interface Model {
|
|||
default boolean empty() {
|
||||
return vertexCount() == 0;
|
||||
}
|
||||
|
||||
ModelReader getReader();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.ModelReader;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
public class ModelPart implements Model {
|
||||
|
||||
|
@ -48,4 +53,95 @@ public class ModelPart implements Model {
|
|||
public VertexFormat format() {
|
||||
return Formats.UNLIT_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelReader getReader() {
|
||||
return new PartReader(this);
|
||||
}
|
||||
|
||||
private class PartReader implements ModelReader {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
private PartReader(ModelPart part) {
|
||||
this.buffer = ByteBuffer.allocate(part.size());
|
||||
VecBufferWriter writer = new VecBufferWriter(this.buffer);
|
||||
|
||||
buffer(writer);
|
||||
}
|
||||
|
||||
private int vertIdx(int vertexIndex) {
|
||||
return vertexIndex * format().getStride();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX(int index) {
|
||||
return buffer.getFloat(vertIdx(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getY(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getZ(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getR(int index) {
|
||||
return (byte) 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getG(int index) {
|
||||
return (byte) 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getB(int index) {
|
||||
return (byte) 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getA(int index) {
|
||||
return (byte) 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getU(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getV(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 19);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLight(int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getNX(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 12));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getNY(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 13));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getNZ(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 14));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return vertices;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class RecordingVertexConsumer implements VertexConsumer {
|
||||
|
||||
List<Consumer<VertexConsumer>> replay = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public VertexConsumer vertex(double x, double y, double z) {
|
||||
replay.add(v -> v.vertex(x, y, z));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer color(int r, int g, int b, int a) {
|
||||
replay.add(v -> v.color(r, g, b, a));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv(float u, float v) {
|
||||
replay.add(vc -> vc.uv(u, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer overlayCoords(int u, int v) {
|
||||
replay.add(vc -> vc.overlayCoords(u, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer uv2(int u, int v) {
|
||||
replay.add(vc -> vc.uv2(u, v));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexConsumer normal(float x, float y, float z) {
|
||||
replay.add(v -> v.normal(x, y, z));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endVertex() {
|
||||
replay.add(VertexConsumer::endVertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void defaultColor(int r, int g, int b, int a) {
|
||||
replay.add(vc -> vc.defaultColor(r, g, b, a));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetDefaultColor() {
|
||||
replay.add(VertexConsumer::unsetDefaultColor);
|
||||
}
|
||||
|
||||
public VertexRecording saveRecording() {
|
||||
VertexRecording out = new VertexRecording(ImmutableList.copyOf(replay));
|
||||
replay.clear();
|
||||
return out;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,468 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import com.jozufozu.flywheel.util.ModelReader;
|
||||
import com.jozufozu.flywheel.util.transform.Rotate;
|
||||
import com.jozufozu.flywheel.util.transform.Scale;
|
||||
import com.jozufozu.flywheel.util.transform.TStack;
|
||||
import com.jozufozu.flywheel.util.transform.Translate;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.math.*;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.client.model.pipeline.LightUtil;
|
||||
|
||||
public class SuperByteBuffer implements Scale<SuperByteBuffer>, Translate<SuperByteBuffer>, Rotate<SuperByteBuffer>, TStack<SuperByteBuffer> {
|
||||
|
||||
private final Model model;
|
||||
private final ModelReader template;
|
||||
|
||||
// Vertex Position
|
||||
private final PoseStack transforms;
|
||||
|
||||
private final Params defaultParams = Params.defaultParams();
|
||||
private final Params params = defaultParams.copy();
|
||||
|
||||
// Temporary
|
||||
private static final Long2IntMap WORLD_LIGHT_CACHE = new Long2IntOpenHashMap();
|
||||
private final Vector4f pos = new Vector4f();
|
||||
private final Vector3f normal = new Vector3f();
|
||||
private final Vector4f lightPos = new Vector4f();
|
||||
|
||||
public SuperByteBuffer(Model model) {
|
||||
this.model = model;
|
||||
template = model.getReader();
|
||||
|
||||
transforms = new PoseStack();
|
||||
transforms.pushPose();
|
||||
}
|
||||
|
||||
public void renderInto(PoseStack input, VertexConsumer builder) {
|
||||
if (isEmpty())
|
||||
return;
|
||||
|
||||
Matrix4f modelMat = input.last()
|
||||
.pose()
|
||||
.copy();
|
||||
Matrix4f localTransforms = transforms.last()
|
||||
.pose();
|
||||
modelMat.multiply(localTransforms);
|
||||
|
||||
Matrix3f normalMat;
|
||||
|
||||
if (params.fullNormalTransform) {
|
||||
normalMat = input.last().normal().copy();
|
||||
normalMat.mul(transforms.last().normal());
|
||||
} else {
|
||||
normalMat = transforms.last().normal().copy();
|
||||
}
|
||||
|
||||
if (params.useWorldLight) {
|
||||
WORLD_LIGHT_CACHE.clear();
|
||||
}
|
||||
|
||||
float f = .5f;
|
||||
int vertexCount = template.getVertexCount();
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float x = template.getX(i);
|
||||
float y = template.getY(i);
|
||||
float z = template.getZ(i);
|
||||
pos.set(x, y, z, 1F);
|
||||
pos.transform(modelMat);
|
||||
builder.vertex(pos.x(), pos.y(), pos.z());
|
||||
|
||||
float normalX = template.getNX(i);
|
||||
float normalY = template.getNY(i);
|
||||
float normalZ = template.getNZ(i);
|
||||
|
||||
normal.set(normalX, normalY, normalZ);
|
||||
normal.transform(normalMat);
|
||||
normal.normalize();
|
||||
float nx = normal.x();
|
||||
float ny = normal.y();
|
||||
float nz = normal.z();
|
||||
|
||||
float instanceDiffuse = LightUtil.diffuseLight(nx, ny, nz);
|
||||
|
||||
switch (params.colorMode) {
|
||||
case MODEL_ONLY -> builder.color(template.getR(i), template.getG(i), template.getB(i), template.getA(i));
|
||||
case DIFFUSE_ONLY -> builder.color(instanceDiffuse, instanceDiffuse, instanceDiffuse, 1f);
|
||||
case MODEL_DIFFUSE -> {
|
||||
int r = Byte.toUnsignedInt(template.getR(i));
|
||||
int g = Byte.toUnsignedInt(template.getG(i));
|
||||
int b = Byte.toUnsignedInt(template.getB(i));
|
||||
int a = Byte.toUnsignedInt(template.getA(i));
|
||||
|
||||
float diffuse = switch (params.diffuseMode) {
|
||||
case NONE -> 1f;
|
||||
case INSTANCE -> instanceDiffuse;
|
||||
case ONE_OVER_STATIC -> 1 / LightUtil.diffuseLight(normalX, normalY, normalZ);
|
||||
case INSTANCE_OVER_STATIC -> instanceDiffuse / LightUtil.diffuseLight(normalX, normalY, normalZ);
|
||||
};
|
||||
|
||||
if (diffuse != 1) {
|
||||
r = transformColor(r, diffuse);
|
||||
g = transformColor(g, diffuse);
|
||||
b = transformColor(b, diffuse);
|
||||
}
|
||||
|
||||
builder.color(r, g, b, a);
|
||||
}
|
||||
case RECOLOR -> {
|
||||
if (params.diffuseMode == DiffuseMode.NONE) {
|
||||
builder.color(params.r, params.g, params.b, params.a);
|
||||
} else {
|
||||
int colorR = transformColor(params.r, instanceDiffuse);
|
||||
int colorG = transformColor(params.g, instanceDiffuse);
|
||||
int colorB = transformColor(params.b, instanceDiffuse);
|
||||
builder.color(colorR, colorG, colorB, params.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//builder.color(Math.max(0, (int) (nx * 255)), Math.max(0, (int) (ny * 255)), Math.max(0, (int) (nz * 255)), 0xFF);
|
||||
//builder.color(Math.max(0, (int) (normalX * 255)), Math.max(0, (int) (normalY * 255)), Math.max(0, (int) (normalZ * 255)), 0xFF);
|
||||
|
||||
float u = template.getU(i);
|
||||
float v = template.getV(i);
|
||||
if (params.spriteShiftFunc != null) {
|
||||
params.spriteShiftFunc.shift(builder, u, v);
|
||||
} else {
|
||||
builder.uv(u, v);
|
||||
}
|
||||
|
||||
if (params.hasOverlay) {
|
||||
builder.overlayCoords(params.overlay);
|
||||
}
|
||||
|
||||
int light;
|
||||
if (params.useWorldLight) {
|
||||
lightPos.set(((x - f) * 15 / 16f) + f, (y - f) * 15 / 16f + f, (z - f) * 15 / 16f + f, 1F);
|
||||
lightPos.transform(localTransforms);
|
||||
if (params.lightTransform != null) {
|
||||
lightPos.transform(params.lightTransform);
|
||||
}
|
||||
|
||||
light = getLight(Minecraft.getInstance().level, lightPos);
|
||||
if (params.hasCustomLight) {
|
||||
light = maxLight(light, params.packedLightCoords);
|
||||
}
|
||||
} else if (params.hasCustomLight) {
|
||||
light = params.packedLightCoords;
|
||||
} else {
|
||||
light = template.getLight(i);
|
||||
}
|
||||
|
||||
if (params.hybridLight) {
|
||||
builder.uv2(maxLight(light, template.getLight(i)));
|
||||
} else {
|
||||
builder.uv2(light);
|
||||
}
|
||||
|
||||
builder.normal(nx, ny, nz);
|
||||
|
||||
builder.endVertex();
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
public SuperByteBuffer reset() {
|
||||
while (!transforms.clear())
|
||||
transforms.popPose();
|
||||
transforms.pushPose();
|
||||
|
||||
params.load(defaultParams);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer translate(double x, double y, double z) {
|
||||
transforms.translate(x, y, z);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer multiply(Quaternion quaternion) {
|
||||
transforms.mulPose(quaternion);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer transform(PoseStack stack) {
|
||||
PoseStack.Pose last = stack.last();
|
||||
return transform(last.pose(), last.normal());
|
||||
}
|
||||
|
||||
public SuperByteBuffer transform(Matrix4f pose, Matrix3f normal) {
|
||||
transforms.last()
|
||||
.pose()
|
||||
.multiply(pose);
|
||||
transforms.last()
|
||||
.normal()
|
||||
.mul(normal);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer rotateCentered(Direction axis, float radians) {
|
||||
translate(.5f, .5f, .5f).rotate(axis, radians)
|
||||
.translate(-.5f, -.5f, -.5f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer rotateCentered(Quaternion q) {
|
||||
translate(.5f, .5f, .5f).multiply(q)
|
||||
.translate(-.5f, -.5f, -.5f);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer color(int r, int g, int b, int a) {
|
||||
params.colorMode = ColorMode.RECOLOR;
|
||||
params.r = r;
|
||||
params.g = g;
|
||||
params.b = b;
|
||||
params.a = a;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer color(byte r, byte g, byte b, byte a) {
|
||||
params.colorMode = ColorMode.RECOLOR;
|
||||
params.r = Byte.toUnsignedInt(r);
|
||||
params.g = Byte.toUnsignedInt(g);
|
||||
params.b = Byte.toUnsignedInt(b);
|
||||
params.a = Byte.toUnsignedInt(a);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer color(int color) {
|
||||
params.colorMode = ColorMode.RECOLOR;
|
||||
params.r = ((color >> 16) & 0xFF);
|
||||
params.g = ((color >> 8) & 0xFF);
|
||||
params.b = (color & 0xFF);
|
||||
params.a = 255;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer shiftUV(SpriteShiftFunc entry) {
|
||||
params.spriteShiftFunc = entry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer overlay() {
|
||||
params.hasOverlay = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer overlay(int overlay) {
|
||||
params.hasOverlay = true;
|
||||
params.overlay = overlay;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms normals not only by the local matrix stack, but also by the passed matrix stack.
|
||||
*/
|
||||
public SuperByteBuffer entityMode() {
|
||||
params.hasOverlay = true;
|
||||
params.fullNormalTransform = true;
|
||||
params.diffuseMode = DiffuseMode.NONE;
|
||||
params.colorMode = ColorMode.RECOLOR;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer light() {
|
||||
params.useWorldLight = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer light(Matrix4f lightTransform) {
|
||||
params.useWorldLight = true;
|
||||
params.lightTransform = lightTransform;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer light(int packedLightCoords) {
|
||||
params.hasCustomLight = true;
|
||||
params.packedLightCoords = packedLightCoords;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperByteBuffer light(Matrix4f lightTransform, int packedLightCoords) {
|
||||
light(lightTransform);
|
||||
light(packedLightCoords);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses max light from calculated light (world light or custom light) and vertex light for the final light value.
|
||||
* Ineffective if any other light method was not called.
|
||||
*/
|
||||
public SuperByteBuffer hybridLight() {
|
||||
params.hybridLight = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return template.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer scale(float factorX, float factorY, float factorZ) {
|
||||
transforms.scale(factorX, factorY, factorZ);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer pushPose() {
|
||||
transforms.pushPose();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuperByteBuffer popPose() {
|
||||
transforms.popPose();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SuperByteBuffer[" + model + ']';
|
||||
}
|
||||
|
||||
public static int transformColor(int component, float scale) {
|
||||
return Mth.clamp((int) (component * scale), 0, 255);
|
||||
}
|
||||
|
||||
public static int maxLight(int packedLight1, int packedLight2) {
|
||||
int blockLight1 = LightTexture.block(packedLight1);
|
||||
int skyLight1 = LightTexture.sky(packedLight1);
|
||||
int blockLight2 = LightTexture.block(packedLight2);
|
||||
int skyLight2 = LightTexture.sky(packedLight2);
|
||||
return LightTexture.pack(Math.max(blockLight1, blockLight2), Math.max(skyLight1, skyLight2));
|
||||
}
|
||||
|
||||
private static int getLight(Level world, Vector4f lightPos) {
|
||||
BlockPos pos = new BlockPos(lightPos.x(), lightPos.y(), lightPos.z());
|
||||
return WORLD_LIGHT_CACHE.computeIfAbsent(pos.asLong(), $ -> LevelRenderer.getLightColor(world, pos));
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SpriteShiftFunc {
|
||||
void shift(VertexConsumer builder, float u, float v);
|
||||
}
|
||||
|
||||
public enum ColorMode {
|
||||
MODEL_ONLY,
|
||||
MODEL_DIFFUSE,
|
||||
DIFFUSE_ONLY,
|
||||
RECOLOR
|
||||
}
|
||||
|
||||
public enum DiffuseMode {
|
||||
NONE,
|
||||
INSTANCE,
|
||||
ONE_OVER_STATIC,
|
||||
INSTANCE_OVER_STATIC,
|
||||
}
|
||||
|
||||
public static class Params {
|
||||
// Vertex Coloring
|
||||
public ColorMode colorMode = ColorMode.DIFFUSE_ONLY;
|
||||
public DiffuseMode diffuseMode = DiffuseMode.INSTANCE;
|
||||
public int r;
|
||||
public int g;
|
||||
public int b;
|
||||
public int a;
|
||||
|
||||
// Vertex Texture Coords
|
||||
public SpriteShiftFunc spriteShiftFunc;
|
||||
|
||||
// Vertex Overlay Color
|
||||
public boolean hasOverlay;
|
||||
public int overlay = OverlayTexture.NO_OVERLAY;
|
||||
|
||||
// Vertex Lighting
|
||||
public boolean useWorldLight;
|
||||
public Matrix4f lightTransform;
|
||||
public boolean hasCustomLight;
|
||||
public int packedLightCoords;
|
||||
public boolean hybridLight;
|
||||
|
||||
// Vertex Normals
|
||||
public boolean fullNormalTransform;
|
||||
|
||||
public void load(Params from) {
|
||||
colorMode = from.colorMode;
|
||||
diffuseMode = from.diffuseMode;
|
||||
r = from.r;
|
||||
g = from.g;
|
||||
b = from.b;
|
||||
a = from.a;
|
||||
spriteShiftFunc = from.spriteShiftFunc;
|
||||
hasOverlay = from.hasOverlay;
|
||||
overlay = from.overlay;
|
||||
useWorldLight = from.useWorldLight;
|
||||
lightTransform = from.lightTransform;
|
||||
hasCustomLight = from.hasCustomLight;
|
||||
packedLightCoords = from.packedLightCoords;
|
||||
hybridLight = from.hybridLight;
|
||||
fullNormalTransform = from.fullNormalTransform;
|
||||
}
|
||||
|
||||
public Params copy() {
|
||||
Params params = new Params();
|
||||
params.load(this);
|
||||
return params;
|
||||
}
|
||||
|
||||
public static Params defaultParams() {
|
||||
Params out = new Params();
|
||||
out.colorMode = ColorMode.DIFFUSE_ONLY;
|
||||
out.diffuseMode = DiffuseMode.INSTANCE;
|
||||
out.r = 0xFF;
|
||||
out.g = 0xFF;
|
||||
out.b = 0xFF;
|
||||
out.a = 0xFF;
|
||||
out.spriteShiftFunc = null;
|
||||
out.hasOverlay = false;
|
||||
out.overlay = OverlayTexture.NO_OVERLAY;
|
||||
out.useWorldLight = false;
|
||||
out.lightTransform = null;
|
||||
out.hasCustomLight = false;
|
||||
out.packedLightCoords = 0;
|
||||
out.hybridLight = false;
|
||||
out.fullNormalTransform = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
public static Params newEntityParams() {
|
||||
Params out = new Params();
|
||||
out.colorMode = ColorMode.RECOLOR;
|
||||
out.diffuseMode = DiffuseMode.NONE;
|
||||
out.r = 0xFF;
|
||||
out.g = 0xFF;
|
||||
out.b = 0xFF;
|
||||
out.a = 0xFF;
|
||||
out.spriteShiftFunc = null;
|
||||
out.hasOverlay = true;
|
||||
out.overlay = OverlayTexture.NO_OVERLAY;
|
||||
out.useWorldLight = false;
|
||||
out.lightTransform = null;
|
||||
out.hasCustomLight = false;
|
||||
out.packedLightCoords = 0;
|
||||
out.hybridLight = false;
|
||||
out.fullNormalTransform = true;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@ package com.jozufozu.flywheel.core.model;
|
|||
|
||||
import static com.jozufozu.flywheel.util.RenderMath.nb;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
|
@ -9,6 +11,10 @@ public class VecBufferWriter implements VertexConsumer {
|
|||
|
||||
private final VecBuffer buffer;
|
||||
|
||||
public VecBufferWriter(ByteBuffer buffer) {
|
||||
this.buffer = new VecBuffer(buffer);
|
||||
}
|
||||
|
||||
public VecBufferWriter(VecBuffer buffer) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public record VertexRecording(ImmutableList<Consumer<VertexConsumer>> recording) {
|
||||
|
||||
public void replay(VertexConsumer vc) {
|
||||
for (Consumer<VertexConsumer> consumer : recording) {
|
||||
consumer.accept(vc);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import java.util.Collection;
|
|||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
||||
import com.jozufozu.flywheel.util.ModelReader;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
|
@ -15,7 +16,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
|
|||
|
||||
public class WorldModel implements Model {
|
||||
|
||||
private final BufferBuilderReader reader;
|
||||
private final ModelReader reader;
|
||||
private final String name;
|
||||
|
||||
public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, String name) {
|
||||
|
@ -33,7 +34,7 @@ public class WorldModel implements Model {
|
|||
for (int i = 0; i < vertexCount(); i++) {
|
||||
vertices.vertex(reader.getX(i), reader.getY(i), reader.getZ(i));
|
||||
|
||||
vertices.normal(RenderMath.f(reader.getNX(i)), RenderMath.f(reader.getNY(i)), RenderMath.f(reader.getNZ(i)));
|
||||
vertices.normal(reader.getNX(i), reader.getNY(i), reader.getNZ(i));
|
||||
|
||||
vertices.uv(reader.getU(i), reader.getV(i));
|
||||
|
||||
|
@ -60,4 +61,8 @@ public class WorldModel implements Model {
|
|||
return Formats.COLORED_LIT_MODEL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelReader getReader() {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package com.jozufozu.flywheel.mixin;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||
import com.jozufozu.flywheel.backend.model.DirectBufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.mojang.blaze3d.vertex.VertexFormatElement;
|
||||
|
||||
@Mixin(BufferBuilder.class)
|
||||
public abstract class BufferBuilderMixin implements DirectBufferBuilder {
|
||||
@Shadow
|
||||
private ByteBuffer buffer;
|
||||
|
||||
@Shadow
|
||||
private VertexFormat format;
|
||||
|
||||
@Shadow
|
||||
protected abstract void ensureCapacity(int p_85723_);
|
||||
|
||||
@Shadow
|
||||
private int vertices;
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
private VertexFormatElement currentElement;
|
||||
|
||||
@Shadow
|
||||
private int elementIndex;
|
||||
|
||||
@Shadow
|
||||
private int nextElementByte;
|
||||
|
||||
@Override
|
||||
public DirectVertexConsumer intoDirectConsumer(int neededVerts) {
|
||||
ensureCapacity(neededVerts * this.format.getVertexSize());
|
||||
return new DirectVertexConsumer(this.buffer, this.format);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateAfterWriting(DirectVertexConsumer complete) {
|
||||
int vertexCount = complete.getVertexCount();
|
||||
int totalWrittenBytes = vertexCount * format.getVertexSize();
|
||||
|
||||
this.vertices += vertexCount;
|
||||
this.currentElement = format.getElements()
|
||||
.get(0);
|
||||
this.elementIndex = 0;
|
||||
this.nextElementByte += totalWrittenBytes;
|
||||
this.buffer.position(complete.startPos + totalWrittenBytes);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import com.mojang.blaze3d.vertex.BufferBuilder;
|
|||
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
|
||||
public class BufferBuilderReader {
|
||||
public class BufferBuilderReader implements ModelReader {
|
||||
|
||||
private final ByteBuffer buffer;
|
||||
private final int vertexCount;
|
||||
|
@ -35,66 +35,81 @@ public class BufferBuilderReader {
|
|||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return vertexCount == 0;
|
||||
}
|
||||
|
||||
public int vertIdx(int vertexIndex) {
|
||||
private int vertIdx(int vertexIndex) {
|
||||
return vertexIndex * formatSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX(int index) {
|
||||
return buffer.getFloat(vertIdx(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getY(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getZ(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getR(int index) {
|
||||
return buffer.get(vertIdx(index) + 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getG(int index) {
|
||||
return buffer.get(vertIdx(index) + 13);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getB(int index) {
|
||||
return buffer.get(vertIdx(index) + 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getA(int index) {
|
||||
return buffer.get(vertIdx(index) + 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getU(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 16);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getV(int index) {
|
||||
return buffer.getFloat(vertIdx(index) + 20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLight(int index) {
|
||||
return buffer.getInt(vertIdx(index) + 24);
|
||||
}
|
||||
|
||||
public byte getNX(int index) {
|
||||
return buffer.get(vertIdx(index) + 28);
|
||||
@Override
|
||||
public float getNX(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 28));
|
||||
}
|
||||
|
||||
public byte getNY(int index) {
|
||||
return buffer.get(vertIdx(index) + 29);
|
||||
@Override
|
||||
public float getNY(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 29));
|
||||
}
|
||||
|
||||
public byte getNZ(int index) {
|
||||
return buffer.get(vertIdx(index) + 30);
|
||||
@Override
|
||||
public float getNZ(int index) {
|
||||
return RenderMath.f(buffer.get(vertIdx(index) + 30));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
|
35
src/main/java/com/jozufozu/flywheel/util/ModelReader.java
Normal file
35
src/main/java/com/jozufozu/flywheel/util/ModelReader.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
public interface ModelReader {
|
||||
float getX(int index);
|
||||
|
||||
float getY(int index);
|
||||
|
||||
float getZ(int index);
|
||||
|
||||
byte getR(int index);
|
||||
|
||||
byte getG(int index);
|
||||
|
||||
byte getB(int index);
|
||||
|
||||
byte getA(int index);
|
||||
|
||||
float getU(int index);
|
||||
|
||||
float getV(int index);
|
||||
|
||||
int getLight(int index);
|
||||
|
||||
float getNX(int index);
|
||||
|
||||
float getNY(int index);
|
||||
|
||||
float getNZ(int index);
|
||||
|
||||
int getVertexCount();
|
||||
|
||||
default boolean isEmpty() {
|
||||
return getVertexCount() == 0;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
"compatibilityLevel": "JAVA_17",
|
||||
"refmap": "flywheel.refmap.json",
|
||||
"client": [
|
||||
"BufferBuilderMixin",
|
||||
"CancelEntityRenderMixin",
|
||||
"ChunkRebuildHooksMixin",
|
||||
"FixFabulousDepthMixin",
|
||||
|
|
Loading…
Reference in a new issue