Basic model abstraction

- Stop providing a buffered model supplier
 - Instead, provide an IModel supplier
 - IModel exposes basic properties of models
 - IModel exposes a method to copy the model to a VecBuffer
This commit is contained in:
Jozufozu 2021-07-23 12:26:32 -07:00
parent 7ad7512e7e
commit 721b3b8633
11 changed files with 225 additions and 105 deletions

View file

@ -15,6 +15,8 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer; import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.material.MaterialSpec; import com.jozufozu.flywheel.backend.material.MaterialSpec;
import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.jozufozu.flywheel.util.AttribUtil; import com.jozufozu.flywheel.util.AttribUtil;
import net.minecraft.util.math.vector.Vector3i; import net.minecraft.util.math.vector.Vector3i;
@ -23,7 +25,7 @@ public class Instancer<D extends InstanceData> {
public final Supplier<Vector3i> originCoordinate; public final Supplier<Vector3i> originCoordinate;
protected final Supplier<BufferedModel> gen; protected final Supplier<IModel> gen;
protected BufferedModel model; protected BufferedModel model;
protected final VertexFormat instanceFormat; protected final VertexFormat instanceFormat;
@ -40,7 +42,7 @@ public class Instancer<D extends InstanceData> {
boolean anyToRemove; boolean anyToRemove;
boolean anyToUpdate; boolean anyToUpdate;
public Instancer(Supplier<BufferedModel> model, Supplier<Vector3i> originCoordinate, MaterialSpec<D> spec) { public Instancer(Supplier<IModel> model, Supplier<Vector3i> originCoordinate, MaterialSpec<D> spec) {
this.gen = model; this.gen = model;
this.factory = spec.getInstanceFactory(); this.factory = spec.getInstanceFactory();
this.instanceFormat = spec.getInstanceFormat(); this.instanceFormat = spec.getInstanceFormat();
@ -71,7 +73,7 @@ public class Instancer<D extends InstanceData> {
} }
private void init() { private void init() {
model = gen.get(); model = ModelUtil.getIndexedModel(gen.get());
initialized = true; initialized = true;
if (model.getVertexCount() <= 0) if (model.getVertexCount() <= 0)

View file

@ -3,38 +3,32 @@ package com.jozufozu.flywheel.backend.material;
import java.nio.Buffer; import java.nio.Buffer;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import com.google.common.cache.Cache; import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.RenderWork; import com.jozufozu.flywheel.backend.RenderWork;
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.backend.instancing.InstanceData; import com.jozufozu.flywheel.backend.instancing.InstanceData;
import com.jozufozu.flywheel.backend.instancing.Instancer; import com.jozufozu.flywheel.backend.instancing.Instancer;
import com.jozufozu.flywheel.backend.model.BufferedModel; import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.backend.model.IndexedModel; import com.jozufozu.flywheel.backend.model.IndexedModel;
import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.BufferBuilderReader; import com.jozufozu.flywheel.core.model.BlockModel;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.util.RenderUtil; import com.jozufozu.flywheel.util.RenderUtil;
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockRendererDispatcher; import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel; import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3i; import net.minecraft.util.math.vector.Vector3i;
public class InstanceMaterial<D extends InstanceData> { public class InstanceMaterial<D extends InstanceData> {
@ -100,7 +94,7 @@ public class InstanceMaterial<D extends InstanceData> {
return model(toRender, () -> buildModel(toRender)); return model(toRender, () -> buildModel(toRender));
} }
public Instancer<D> model(Object key, Supplier<BufferedModel> supplier) { public Instancer<D> model(Object key, Supplier<IModel> supplier) {
try { try {
return models.get(key, () -> new Instancer<>(supplier, originCoordinate, spec)); return models.get(key, () -> new Instancer<>(supplier, originCoordinate, spec));
} catch (ExecutionException e) { } catch (ExecutionException e) {
@ -109,70 +103,18 @@ public class InstanceMaterial<D extends InstanceData> {
} }
} }
private BufferedModel buildModel(BlockState renderedState) { private IModel buildModel(BlockState renderedState) {
BlockRendererDispatcher dispatcher = Minecraft.getInstance() BlockRendererDispatcher dispatcher = Minecraft.getInstance()
.getBlockRenderer(); .getBlockRenderer();
return buildModel(dispatcher.getBlockModel(renderedState), renderedState); return buildModel(dispatcher.getBlockModel(renderedState), renderedState);
} }
private BufferedModel buildModel(IBakedModel model, BlockState renderedState) { private IModel buildModel(IBakedModel model, BlockState renderedState) {
return buildModel(model, renderedState, new MatrixStack()); return buildModel(model, renderedState, new MatrixStack());
} }
private BufferedModel buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) { private IModel buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) {
BufferBuilderReader reader = new BufferBuilderReader(getBufferBuilder(model, referenceState, ms));
int vertexCount = reader.getVertexCount(); return new BlockModel(modelFormat, model, referenceState, ms);
ByteBuffer vertices = ByteBuffer.allocate(vertexCount * modelFormat.getStride());
vertices.order(ByteOrder.nativeOrder());
for (int i = 0; i < vertexCount; i++) {
vertices.putFloat(reader.getX(i));
vertices.putFloat(reader.getY(i));
vertices.putFloat(reader.getZ(i));
vertices.put(reader.getNX(i));
vertices.put(reader.getNY(i));
vertices.put(reader.getNZ(i));
vertices.putFloat(reader.getU(i));
vertices.putFloat(reader.getV(i));
}
((Buffer) vertices).rewind();
// return new BufferedModel(GlPrimitive.QUADS, format, vertices, vertexCount);
return IndexedModel.fromSequentialQuads(modelFormat, vertices, vertexCount);
} }
// 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 static BufferBuilder getBufferBuilder(IBakedModel model, BlockState referenceState, MatrixStack ms) {
Minecraft mc = Minecraft.getInstance();
BlockRendererDispatcher dispatcher = mc.getBlockRenderer();
BlockModelRenderer blockRenderer = dispatcher.getModelRenderer();
BufferBuilder builder = new BufferBuilder(512);
// BakedQuadWrapper quadReader = new BakedQuadWrapper();
//
// IModelData modelData = model.getModelData(mc.world, BlockPos.ZERO.up(255), referenceState, VirtualEmptyModelData.INSTANCE);
// List<BakedQuad> quads = Arrays.stream(dirs)
// .flatMap(dir -> model.getQuads(referenceState, dir, mc.world.rand, modelData).stream())
// .collect(Collectors.toList());
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
blockRenderer.renderModel(mc.level, model, referenceState, BlockPos.ZERO.above(255), ms, builder, true, mc.level.random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE);
builder.end();
return builder;
}
} }

View file

@ -0,0 +1,101 @@
package com.jozufozu.flywheel.core.model;
import java.util.Arrays;
import javax.annotation.Nullable;
import org.lwjgl.opengl.GL11;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.core.QuadConverter;
import com.jozufozu.flywheel.util.BufferBuilderReader;
import com.jozufozu.flywheel.util.VirtualEmptyModelData;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockModelRenderer;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
public class BlockModel implements IModel {
private static final MatrixStack IDENTITY = new MatrixStack();
private final BufferBuilderReader reader;
private final VertexFormat modelFormat;
public BlockModel(VertexFormat modelFormat, IBakedModel model, BlockState referenceState) {
this(modelFormat, model, referenceState, IDENTITY);
}
public BlockModel(VertexFormat modelFormat, IBakedModel model, BlockState referenceState, MatrixStack ms) {
this.modelFormat = modelFormat;
reader = new BufferBuilderReader(getBufferBuilder(model, referenceState, ms));
}
@Override
public VertexFormat format() {
return modelFormat;
}
@Override
public int vertexCount() {
return reader.getVertexCount();
}
@Override
public void buffer(VecBuffer buffer) {
int vertexCount = vertexCount();
for (int i = 0; i < vertexCount; i++) {
buffer.putVec3(reader.getX(i), reader.getY(i), reader.getZ(i));
buffer.putVec3(reader.getNX(i), reader.getNY(i), reader.getNZ(i));
buffer.putVec2(reader.getU(i), reader.getV(i));
}
}
@Override
public ElementBuffer createEBO() {
return QuadConverter.getInstance()
.quads2Tris(vertexCount() / 4);
}
public static BufferBuilder getBufferBuilder(IBakedModel model, BlockState referenceState, MatrixStack ms) {
Minecraft mc = Minecraft.getInstance();
BlockRendererDispatcher dispatcher = mc.getBlockRenderer();
BlockModelRenderer blockRenderer = dispatcher.getModelRenderer();
BufferBuilder builder = new BufferBuilder(512);
// BakedQuadWrapper quadReader = new BakedQuadWrapper();
//
// IModelData modelData = model.getModelData(mc.world, BlockPos.ZERO.up(255), referenceState, VirtualEmptyModelData.INSTANCE);
// List<BakedQuad> quads = Arrays.stream(dirs)
// .flatMap(dir -> model.getQuads(referenceState, dir, mc.world.rand, modelData).stream())
// .collect(Collectors.toList());
builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK);
blockRenderer.renderModel(mc.level, model, referenceState, BlockPos.ZERO.above(255), ms, builder, true, mc.level.random, 42, OverlayTexture.NO_OVERLAY, VirtualEmptyModelData.INSTANCE);
builder.end();
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);
}
}

View file

@ -0,0 +1,26 @@
package com.jozufozu.flywheel.core.model;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
/**
* A model that can be rendered by flywheel.
*/
public interface IModel {
/**
* Copy this model into the given buffer.
*/
void buffer(VecBuffer buffer);
int vertexCount();
VertexFormat format();
ElementBuffer createEBO();
default int size() {
return vertexCount() * format().getStride();
}
}

View file

@ -1,8 +1,53 @@
package com.jozufozu.flywheel.core.model; package com.jozufozu.flywheel.core.model;
public class ModelPart { import java.util.ArrayList;
import java.util.List;
import com.jozufozu.flywheel.backend.gl.attrib.VertexFormat;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.ElementBuffer;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.QuadConverter;
public class ModelPart implements IModel {
private final List<PartBuilder.CuboidBuilder> cuboids;
private int vertices;
public ModelPart(List<PartBuilder.CuboidBuilder> cuboids) {
this.cuboids = cuboids;
vertices = 0;
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
vertices += cuboid.vertices();
}
}
public static PartBuilder builder(int sizeU, int sizeV) { public static PartBuilder builder(int sizeU, int sizeV) {
return new PartBuilder(sizeU, sizeV); return new PartBuilder(sizeU, sizeV);
} }
@Override
public void buffer(VecBuffer buffer) {
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
cuboid.buffer(buffer);
}
}
@Override
public int vertexCount() {
return vertices;
}
@Override
public VertexFormat format() {
return Formats.UNLIT_MODEL;
}
@Override
public ElementBuffer createEBO() {
return QuadConverter.getInstance()
.quads2Tris(vertices / 4);
}
} }

View file

@ -0,0 +1,21 @@
package com.jozufozu.flywheel.core.model;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.IndexedModel;
public class ModelUtil {
public static IndexedModel getIndexedModel(IModel blockModel) {
ByteBuffer vertices = ByteBuffer.allocate(blockModel.size());
vertices.order(ByteOrder.nativeOrder());
blockModel.buffer(new VecBuffer(vertices));
((Buffer) vertices).rewind();
return new IndexedModel(blockModel.format(), vertices, blockModel.vertexCount(), blockModel.createEBO());
}
}

View file

@ -6,11 +6,9 @@ import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer; import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.backend.model.IndexedModel;
import com.jozufozu.flywheel.core.Formats;
import net.minecraft.client.renderer.texture.TextureAtlasSprite; import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
@ -18,23 +16,16 @@ import net.minecraft.util.math.vector.Vector3f;
public class PartBuilder { public class PartBuilder {
private float sizeU = 64.0F; private final float sizeU;
private float sizeV = 32.0F; private final float sizeV;
private TextureAtlasSprite sprite; private TextureAtlasSprite sprite;
private final List<CuboidBuilder> cuboids = new ArrayList<>(); private final List<CuboidBuilder> cuboids = new ArrayList<>();
public PartBuilder() { }
public PartBuilder(int sizeU, int sizeV) { public PartBuilder(int sizeU, int sizeV) {
this.setTextureSize(sizeU, sizeV); this.sizeU = (float) sizeU;
} this.sizeV = (float) sizeV;
public PartBuilder setTextureSize(int textureWidth, int textureHeight) {
this.sizeU = (float)textureWidth;
this.sizeV = (float)textureHeight;
return this;
} }
public PartBuilder sprite(TextureAtlasSprite sprite) { public PartBuilder sprite(TextureAtlasSprite sprite) {
@ -46,22 +37,8 @@ public class PartBuilder {
return new CuboidBuilder(this); return new CuboidBuilder(this);
} }
public BufferedModel build() { public ModelPart build() {
int vertices = 0; return new ModelPart(cuboids);
for (CuboidBuilder cuboid : cuboids) {
vertices += cuboid.vertices();
}
VecBuffer buffer = VecBuffer.allocate(vertices * Formats.UNLIT_MODEL.getStride());
for (CuboidBuilder cuboid : cuboids) {
cuboid.buffer(buffer);
}
buffer.rewind();
return IndexedModel.fromSequentialQuads(Formats.UNLIT_MODEL, buffer.unwrap(), vertices);
} }
private PartBuilder addCuboid(CuboidBuilder builder) { private PartBuilder addCuboid(CuboidBuilder builder) {

View file

@ -0,0 +1,6 @@
@ParametersAreNonnullByDefault @MethodsReturnNonnullByDefault
package com.jozufozu.flywheel.core.model;
import javax.annotation.ParametersAreNonnullByDefault;
import mcp.MethodsReturnNonnullByDefault;

View file

@ -64,7 +64,7 @@ public class BellInstance extends TileEntityInstance<BellTileEntity> implements
.createInstance(); .createInstance();
} }
private static BufferedModel createBellModel() { private static ModelPart createBellModel() {
return ModelPart.builder(32, 32) return ModelPart.builder(32, 32)
.sprite(BellTileEntityRenderer.BELL_RESOURCE_LOCATION.sprite()) .sprite(BellTileEntityRenderer.BELL_RESOURCE_LOCATION.sprite())
.cuboid() .cuboid()

View file

@ -134,7 +134,7 @@ public class ChestInstance<T extends TileEntity & IChestLid> extends TileEntityI
.createInstance(); .createInstance();
} }
private BufferedModel getBaseModel() { private ModelPart getBaseModel() {
switch (chestType) { switch (chestType) {
case LEFT: case LEFT:
@ -167,7 +167,7 @@ public class ChestInstance<T extends TileEntity & IChestLid> extends TileEntityI
.build(); .build();
} }
private BufferedModel getLidModel() { private ModelPart getLidModel() {
switch (chestType) { switch (chestType) {
case LEFT: case LEFT:

View file

@ -101,7 +101,7 @@ public class ShulkerBoxInstance extends TileEntityInstance<ShulkerBoxTileEntity>
.createInstance(); .createInstance();
} }
private BufferedModel makeBaseModel() { private ModelPart makeBaseModel() {
return ModelPart.builder(64, 64) return ModelPart.builder(64, 64)
.sprite(texture) .sprite(texture)
.cuboid() .cuboid()
@ -112,7 +112,7 @@ public class ShulkerBoxInstance extends TileEntityInstance<ShulkerBoxTileEntity>
.build(); .build();
} }
private BufferedModel makeLidModel() { private ModelPart makeLidModel() {
return ModelPart.builder(64, 64) return ModelPart.builder(64, 64)
.sprite(texture) .sprite(texture)
.cuboid() .cuboid()