mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-06 02:05:00 +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;
|
package com.jozufozu.flywheel.api.struct;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
|
||||||
|
|
||||||
public interface Batched<S> extends StructType<S> {
|
public interface Batched<S> extends StructType<S> {
|
||||||
|
|
||||||
BatchingTransformer<S> getTransformer(Model model);
|
BatchingTransformer<S> getTransformer();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Batched<S> asBatched() {
|
default Batched<S> asBatched() {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package com.jozufozu.flywheel.api.struct;
|
package com.jozufozu.flywheel.api.struct;
|
||||||
|
|
||||||
import com.mojang.blaze3d.vertex.PoseStack;
|
import com.jozufozu.flywheel.core.model.SuperByteBuffer;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
||||||
|
|
||||||
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.InstanceData;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
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.FlwConfig;
|
||||||
|
import com.jozufozu.flywheel.config.FlwEngine;
|
||||||
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
import com.jozufozu.flywheel.core.shader.spec.ProgramSpec;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
@ -29,6 +32,7 @@ public class Backend {
|
||||||
public static final Logger log = LogManager.getLogger(Backend.class);
|
public static final Logger log = LogManager.getLogger(Backend.class);
|
||||||
|
|
||||||
protected static final Backend INSTANCE = new Backend();
|
protected static final Backend INSTANCE = new Backend();
|
||||||
|
private FlwEngine engine;
|
||||||
|
|
||||||
public static Backend getInstance() {
|
public static Backend getInstance() {
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
|
@ -57,12 +61,13 @@ public class Backend {
|
||||||
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
* (Meshlet, MDI, GL31 Draw Instanced are planned), this will name which one is in use.
|
||||||
*/
|
*/
|
||||||
public String getBackendDescriptor() {
|
public String getBackendDescriptor() {
|
||||||
if (canUseInstancing()) {
|
if (enabled) {
|
||||||
return "GL33 Instanced Arrays";
|
ClientLevel level = Minecraft.getInstance().level;
|
||||||
}
|
|
||||||
|
|
||||||
if (canUseVBOs()) {
|
if (level == null) {
|
||||||
return "VBOs";
|
return "Invalid";
|
||||||
|
}
|
||||||
|
return InstancedRenderDispatcher.getEngineName(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Disabled";
|
return "Disabled";
|
||||||
|
@ -134,8 +139,9 @@ public class Backend {
|
||||||
|
|
||||||
instancedArrays = compat.instancedArraysSupported();
|
instancedArrays = compat.instancedArraysSupported();
|
||||||
|
|
||||||
enabled = FlwConfig.get()
|
FlwConfig config = FlwConfig.get();
|
||||||
.enabled() && !OptifineHandler.usingShaders();
|
enabled = config.enabled() && !OptifineHandler.usingShaders();
|
||||||
|
engine = config.client.engine.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canUseInstancing(@Nullable Level world) {
|
public boolean canUseInstancing(@Nullable Level world) {
|
||||||
|
@ -188,4 +194,8 @@ public class Backend {
|
||||||
|
|
||||||
public static void init() {
|
public static void init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FlwEngine getEngine() {
|
||||||
|
return engine;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,14 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
||||||
anyToRemove = true;
|
anyToRemove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getModelVertexCount() {
|
||||||
|
return modelData.vertexCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int numInstances() {
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
protected BitSet getDirtyBitSet() {
|
protected BitSet getDirtyBitSet() {
|
||||||
final int size = data.size();
|
final int size = data.size();
|
||||||
final BitSet dirtySet = new BitSet(size);
|
final BitSet dirtySet = new BitSet(size);
|
||||||
|
|
|
@ -3,4 +3,5 @@ package com.jozufozu.flywheel.backend.instancing;
|
||||||
import com.jozufozu.flywheel.api.MaterialManager;
|
import com.jozufozu.flywheel.api.MaterialManager;
|
||||||
|
|
||||||
public interface Engine extends RenderDispatcher, 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.IDynamicInstance;
|
||||||
import com.jozufozu.flywheel.api.instance.ITickableInstance;
|
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.batching.BatchingEngine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
|
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
|
||||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||||
import com.jozufozu.flywheel.backend.instancing.tile.TileInstanceManager;
|
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.Contexts;
|
||||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||||
|
@ -29,12 +31,11 @@ public class InstanceWorld {
|
||||||
|
|
||||||
public InstanceWorld() {
|
public InstanceWorld() {
|
||||||
|
|
||||||
// TODO: finish impl
|
FlwEngine engine = Backend.getInstance()
|
||||||
if (false) {
|
.getEngine();
|
||||||
engine = new BatchingEngine();
|
|
||||||
entityInstanceManager = new EntityInstanceManager(engine);
|
switch (engine) {
|
||||||
tileEntityInstanceManager = new TileInstanceManager(engine);
|
case GL33 -> {
|
||||||
} else {
|
|
||||||
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -43,7 +44,14 @@ public class InstanceWorld {
|
||||||
|
|
||||||
manager.addListener(entityInstanceManager);
|
manager.addListener(entityInstanceManager);
|
||||||
manager.addListener(tileEntityInstanceManager);
|
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);
|
getEntities(entity.level).queueUpdate(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getEngineName(LevelAccessor world) {
|
||||||
|
return instanceWorlds.get(world).engine.getName();
|
||||||
|
}
|
||||||
|
|
||||||
public static InstanceManager<BlockEntity> getTiles(LevelAccessor world) {
|
public static InstanceManager<BlockEntity> getTiles(LevelAccessor world) {
|
||||||
return instanceWorlds.get(world)
|
return instanceWorlds.get(world)
|
||||||
.getTileEntityInstanceManager();
|
.getTileEntityInstanceManager();
|
||||||
|
|
|
@ -28,9 +28,9 @@ public class BatchedMaterial<D extends InstanceData> implements Material<D> {
|
||||||
return models.computeIfAbsent(key, $ -> new CPUInstancer<>(type, modelSupplier.get()));
|
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()) {
|
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.InstanceData;
|
||||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
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.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
|
@ -31,8 +33,31 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
||||||
public void render(PoseStack stack, MultiBufferSource source) {
|
public void render(PoseStack stack, MultiBufferSource source) {
|
||||||
VertexConsumer buffer = source.getBuffer(state);
|
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()) {
|
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.RenderLayer;
|
||||||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
|
||||||
import net.minecraft.client.Camera;
|
import net.minecraft.client.Camera;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
@ -40,15 +41,28 @@ public class BatchingEngine implements Engine {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(RenderLayerEvent event, MultiBufferSource buffers) {
|
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()) {
|
for (Map.Entry<RenderType, BatchedMaterialGroup> entry : layers.get(event.getLayer()).entrySet()) {
|
||||||
BatchedMaterialGroup group = entry.getValue();
|
BatchedMaterialGroup group = entry.getValue();
|
||||||
|
|
||||||
group.render(event.stack, buffers);
|
group.render(stack, buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stack.popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void beginFrame(Camera info) {
|
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.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
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.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
|
|
||||||
public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
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) {
|
public CPUInstancer(StructType<D> type, Model modelData) {
|
||||||
super(type, modelData);
|
super(type, modelData);
|
||||||
|
|
||||||
renderer = type.asBatched()
|
sbb = new SuperByteBuffer(modelData);
|
||||||
.getTransformer(modelData);
|
transform = type.asBatched()
|
||||||
|
.getTransformer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -24,15 +29,19 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||||
// noop
|
// noop
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawAll(PoseStack stack, VertexConsumer buffer) {
|
public void drawAll(PoseStack stack, VertexConsumer buffer, FormatContext context) {
|
||||||
if (renderer == null) {
|
if (transform == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSetup();
|
renderSetup();
|
||||||
|
|
||||||
for (D d : data) {
|
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
|
@FunctionalInterface
|
||||||
public interface OriginShiftListener {
|
public interface OriginShiftListener {
|
||||||
void onOriginShift();
|
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();
|
this.stride = this.format.getStride();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Advances the write pointer forward by the stride of one vertex. This should always be called after a
|
public final void write(S struct) {
|
||||||
* vertex is written. Implementations which override this should always call invoke the super implementation.
|
writeInternal(struct);
|
||||||
*/
|
advance();
|
||||||
protected void 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
|
@Override
|
||||||
public void seek(int pos) {
|
public void seek(int pos) {
|
||||||
backingBuffer.position(pos * stride);
|
backingBuffer.position(pos * stride);
|
||||||
|
|
|
@ -15,7 +15,7 @@ import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||||
*/
|
*/
|
||||||
public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
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.
|
* {@link UnsafeBufferWriter#advance()} is called.
|
||||||
*/
|
*/
|
||||||
protected long writePointer;
|
protected long writePointer;
|
||||||
|
@ -35,8 +35,6 @@ public abstract class UnsafeBufferWriter<S> extends BufferWriter<S> {
|
||||||
@Override
|
@Override
|
||||||
protected void advance() {
|
protected void advance() {
|
||||||
this.writePointer += this.stride;
|
this.writePointer += this.stride;
|
||||||
|
|
||||||
super.advance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void acquireWritePointer() {
|
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")
|
dispatcher.register(Commands.literal("flywheel")
|
||||||
.then(new BooleanConfigCommand("backend", BooleanConfig.ENGINE).register())
|
.then(new BooleanConfigCommand("backend", BooleanConfig.ENGINE).register())
|
||||||
.then(new BooleanConfigCommand("debugNormals", BooleanConfig.NORMAL_OVERLAY).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 static class ClientConfig {
|
||||||
public final BooleanValue enabled;
|
public final BooleanValue enabled;
|
||||||
|
public final ForgeConfigSpec.EnumValue<FlwEngine> engine;
|
||||||
public final BooleanValue debugNormals;
|
public final BooleanValue debugNormals;
|
||||||
|
|
||||||
public ClientConfig(ForgeConfigSpec.Builder builder) {
|
public ClientConfig(ForgeConfigSpec.Builder builder) {
|
||||||
|
@ -46,6 +47,9 @@ public class FlwConfig {
|
||||||
enabled = builder.comment("Enable or disable the entire engine")
|
enabled = builder.comment("Enable or disable the entire engine")
|
||||||
.define("enabled", true);
|
.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")
|
debugNormals = builder.comment("Enable or disable a debug overlay that colors pixels by their normal")
|
||||||
.define("debugNormals", false);
|
.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)
|
.encoder(SConfigureBooleanPacket::encode)
|
||||||
.consumer(SConfigureBooleanPacket::execute)
|
.consumer(SConfigureBooleanPacket::execute)
|
||||||
.add();
|
.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 com.jozufozu.flywheel.api.InstanceData;
|
||||||
|
|
||||||
|
import net.minecraft.client.renderer.LightTexture;
|
||||||
|
|
||||||
public abstract class BasicData extends InstanceData implements FlatLit<BasicData> {
|
public abstract class BasicData extends InstanceData implements FlatLit<BasicData> {
|
||||||
|
|
||||||
public byte blockLight;
|
public byte blockLight;
|
||||||
|
@ -14,18 +16,23 @@ public abstract class BasicData extends InstanceData implements FlatLit<BasicDat
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BasicData setBlockLight(int blockLight) {
|
public BasicData setBlockLight(int blockLight) {
|
||||||
this.blockLight = (byte) (blockLight << 4);
|
this.blockLight = (byte) blockLight;
|
||||||
markDirty();
|
markDirty();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BasicData setSkyLight(int skyLight) {
|
public BasicData setSkyLight(int skyLight) {
|
||||||
this.skyLight = (byte) (skyLight << 4);
|
this.skyLight = (byte) skyLight;
|
||||||
markDirty();
|
markDirty();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPackedLight() {
|
||||||
|
return LightTexture.pack(this.blockLight, this.skyLight);
|
||||||
|
}
|
||||||
|
|
||||||
public BasicData setColor(int color) {
|
public BasicData setColor(int color) {
|
||||||
return setColor(color, false);
|
return setColor(color, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,6 @@ public interface FlatLit<D extends InstanceData & FlatLit<D>> {
|
||||||
* @return <code>this</code>
|
* @return <code>this</code>
|
||||||
*/
|
*/
|
||||||
D setSkyLight(int skyLight);
|
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.backend.gl.buffer.VecBuffer;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
import com.jozufozu.flywheel.core.Programs;
|
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;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
@ -36,7 +34,11 @@ public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BatchingTransformer<ModelData> getTransformer(Model model) {
|
public BatchingTransformer<ModelData> getTransformer() {
|
||||||
return null;
|
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.backend.gl.buffer.VecBuffer;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
import com.jozufozu.flywheel.core.Programs;
|
import com.jozufozu.flywheel.core.Programs;
|
||||||
import com.jozufozu.flywheel.core.materials.oriented.writer.UnsafeOrientedWriter;
|
import com.mojang.math.Quaternion;
|
||||||
import com.jozufozu.flywheel.core.model.Model;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
@ -36,7 +35,13 @@ public class OrientedType implements Instanced<OrientedData>, Batched<OrientedDa
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BatchingTransformer<OrientedData> getTransformer(Model model) {
|
public BatchingTransformer<OrientedData> getTransformer() {
|
||||||
return null;
|
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 org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.api.struct.StructType;
|
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||||
import com.jozufozu.flywheel.backend.struct.UnsafeBufferWriter;
|
import com.jozufozu.flywheel.api.struct.StructType;
|
||||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
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) {
|
public UnsafeOrientedWriter(VecBuffer backingBuffer, StructType<OrientedData> vertexType) {
|
||||||
super(backingBuffer, vertexType);
|
super(backingBuffer, vertexType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(OrientedData d) {
|
protected void writeInternal(OrientedData d) {
|
||||||
long addr = writePointer;
|
long addr = writePointer;
|
||||||
MemoryUtil.memPutByte(addr, d.blockLight);
|
super.writeInternal(d);
|
||||||
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);
|
|
||||||
|
|
||||||
MemoryUtil.memPutFloat(addr + 6, d.posX);
|
MemoryUtil.memPutFloat(addr + 6, d.posX);
|
||||||
MemoryUtil.memPutFloat(addr + 10, d.posY);
|
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 + 34, d.qY);
|
||||||
MemoryUtil.memPutFloat(addr + 38, d.qZ);
|
MemoryUtil.memPutFloat(addr + 38, d.qZ);
|
||||||
MemoryUtil.memPutFloat(addr + 42, d.qW);
|
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.backend.gl.attrib.VertexFormat;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.jozufozu.flywheel.util.RenderMath;
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
|
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
|
||||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||||
|
@ -27,7 +28,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||||
public class BlockModel implements Model {
|
public class BlockModel implements Model {
|
||||||
private static final PoseStack IDENTITY = new PoseStack();
|
private static final PoseStack IDENTITY = new PoseStack();
|
||||||
|
|
||||||
private final BufferBuilderReader reader;
|
private final ModelReader reader;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ public class BlockModel implements Model {
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
for (int i = 0; i < vertexCount; i++) {
|
||||||
buffer.vertex(reader.getX(i), reader.getY(i), reader.getZ(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));
|
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) {
|
public static BufferBuilder getBufferBuilder(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||||
Minecraft mc = Minecraft.getInstance();
|
Minecraft mc = Minecraft.getInstance();
|
||||||
BlockRenderDispatcher dispatcher = mc.getBlockRenderer();
|
BlockRenderDispatcher dispatcher = mc.getBlockRenderer();
|
||||||
|
@ -96,12 +102,4 @@ public class BlockModel implements Model {
|
||||||
return builder;
|
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.gl.attrib.VertexFormat;
|
||||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||||
import com.jozufozu.flywheel.core.QuadConverter;
|
import com.jozufozu.flywheel.core.QuadConverter;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,4 +77,6 @@ public interface Model {
|
||||||
default boolean empty() {
|
default boolean empty() {
|
||||||
return vertexCount() == 0;
|
return vertexCount() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelReader getReader();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
package com.jozufozu.flywheel.core.model;
|
package com.jozufozu.flywheel.core.model;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
|
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.Formats;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import com.mojang.math.Vector3f;
|
||||||
|
|
||||||
public class ModelPart implements Model {
|
public class ModelPart implements Model {
|
||||||
|
|
||||||
|
@ -48,4 +53,95 @@ public class ModelPart implements Model {
|
||||||
public VertexFormat format() {
|
public VertexFormat format() {
|
||||||
return Formats.UNLIT_MODEL;
|
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 static com.jozufozu.flywheel.util.RenderMath.nb;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
|
@ -9,6 +11,10 @@ public class VecBufferWriter implements VertexConsumer {
|
||||||
|
|
||||||
private final VecBuffer buffer;
|
private final VecBuffer buffer;
|
||||||
|
|
||||||
|
public VecBufferWriter(ByteBuffer buffer) {
|
||||||
|
this.buffer = new VecBuffer(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
public VecBufferWriter(VecBuffer buffer) {
|
public VecBufferWriter(VecBuffer buffer) {
|
||||||
this.buffer = 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.backend.gl.attrib.VertexFormat;
|
||||||
import com.jozufozu.flywheel.core.Formats;
|
import com.jozufozu.flywheel.core.Formats;
|
||||||
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
import com.jozufozu.flywheel.util.BufferBuilderReader;
|
||||||
|
import com.jozufozu.flywheel.util.ModelReader;
|
||||||
import com.jozufozu.flywheel.util.RenderMath;
|
import com.jozufozu.flywheel.util.RenderMath;
|
||||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
|
||||||
|
|
||||||
public class WorldModel implements Model {
|
public class WorldModel implements Model {
|
||||||
|
|
||||||
private final BufferBuilderReader reader;
|
private final ModelReader reader;
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public WorldModel(BlockAndTintGetter renderWorld, RenderType layer, Collection<StructureTemplate.StructureBlockInfo> blocks, 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++) {
|
for (int i = 0; i < vertexCount(); i++) {
|
||||||
vertices.vertex(reader.getX(i), reader.getY(i), reader.getZ(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));
|
vertices.uv(reader.getU(i), reader.getV(i));
|
||||||
|
|
||||||
|
@ -60,4 +61,8 @@ public class WorldModel implements Model {
|
||||||
return Formats.COLORED_LIT_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.blaze3d.vertex.VertexFormat;
|
||||||
import com.mojang.datafixers.util.Pair;
|
import com.mojang.datafixers.util.Pair;
|
||||||
|
|
||||||
public class BufferBuilderReader {
|
public class BufferBuilderReader implements ModelReader {
|
||||||
|
|
||||||
private final ByteBuffer buffer;
|
private final ByteBuffer buffer;
|
||||||
private final int vertexCount;
|
private final int vertexCount;
|
||||||
|
@ -35,66 +35,81 @@ public class BufferBuilderReader {
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return vertexCount == 0;
|
return vertexCount == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int vertIdx(int vertexIndex) {
|
private int vertIdx(int vertexIndex) {
|
||||||
return vertexIndex * formatSize;
|
return vertexIndex * formatSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getX(int index) {
|
public float getX(int index) {
|
||||||
return buffer.getFloat(vertIdx(index));
|
return buffer.getFloat(vertIdx(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getY(int index) {
|
public float getY(int index) {
|
||||||
return buffer.getFloat(vertIdx(index) + 4);
|
return buffer.getFloat(vertIdx(index) + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getZ(int index) {
|
public float getZ(int index) {
|
||||||
return buffer.getFloat(vertIdx(index) + 8);
|
return buffer.getFloat(vertIdx(index) + 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte getR(int index) {
|
public byte getR(int index) {
|
||||||
return buffer.get(vertIdx(index) + 12);
|
return buffer.get(vertIdx(index) + 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte getG(int index) {
|
public byte getG(int index) {
|
||||||
return buffer.get(vertIdx(index) + 13);
|
return buffer.get(vertIdx(index) + 13);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte getB(int index) {
|
public byte getB(int index) {
|
||||||
return buffer.get(vertIdx(index) + 14);
|
return buffer.get(vertIdx(index) + 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public byte getA(int index) {
|
public byte getA(int index) {
|
||||||
return buffer.get(vertIdx(index) + 15);
|
return buffer.get(vertIdx(index) + 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getU(int index) {
|
public float getU(int index) {
|
||||||
return buffer.getFloat(vertIdx(index) + 16);
|
return buffer.getFloat(vertIdx(index) + 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getV(int index) {
|
public float getV(int index) {
|
||||||
return buffer.getFloat(vertIdx(index) + 20);
|
return buffer.getFloat(vertIdx(index) + 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getLight(int index) {
|
public int getLight(int index) {
|
||||||
return buffer.getInt(vertIdx(index) + 24);
|
return buffer.getInt(vertIdx(index) + 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getNX(int index) {
|
@Override
|
||||||
return buffer.get(vertIdx(index) + 28);
|
public float getNX(int index) {
|
||||||
|
return RenderMath.f(buffer.get(vertIdx(index) + 28));
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getNY(int index) {
|
@Override
|
||||||
return buffer.get(vertIdx(index) + 29);
|
public float getNY(int index) {
|
||||||
|
return RenderMath.f(buffer.get(vertIdx(index) + 29));
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getNZ(int index) {
|
@Override
|
||||||
return buffer.get(vertIdx(index) + 30);
|
public float getNZ(int index) {
|
||||||
|
return RenderMath.f(buffer.get(vertIdx(index) + 30));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getVertexCount() {
|
public int getVertexCount() {
|
||||||
return vertexCount;
|
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",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"refmap": "flywheel.refmap.json",
|
"refmap": "flywheel.refmap.json",
|
||||||
"client": [
|
"client": [
|
||||||
|
"BufferBuilderMixin",
|
||||||
"CancelEntityRenderMixin",
|
"CancelEntityRenderMixin",
|
||||||
"ChunkRebuildHooksMixin",
|
"ChunkRebuildHooksMixin",
|
||||||
"FixFabulousDepthMixin",
|
"FixFabulousDepthMixin",
|
||||||
|
|
Loading…
Reference in a new issue