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.material.MaterialSpec;
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 net.minecraft.util.math.vector.Vector3i;
@ -23,7 +25,7 @@ public class Instancer<D extends InstanceData> {
public final Supplier<Vector3i> originCoordinate;
protected final Supplier<BufferedModel> gen;
protected final Supplier<IModel> gen;
protected BufferedModel model;
protected final VertexFormat instanceFormat;
@ -40,7 +42,7 @@ public class Instancer<D extends InstanceData> {
boolean anyToRemove;
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.factory = spec.getInstanceFactory();
this.instanceFormat = spec.getInstanceFormat();
@ -71,7 +73,7 @@ public class Instancer<D extends InstanceData> {
}
private void init() {
model = gen.get();
model = ModelUtil.getIndexedModel(gen.get());
initialized = true;
if (model.getVertexCount() <= 0)

View file

@ -3,38 +3,32 @@ package com.jozufozu.flywheel.backend.material;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.commons.lang3.tuple.Pair;
import org.lwjgl.opengl.GL11;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.jozufozu.flywheel.backend.RenderWork;
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.Instancer;
import com.jozufozu.flywheel.backend.model.BufferedModel;
import com.jozufozu.flywheel.backend.model.IndexedModel;
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.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;
import net.minecraft.util.math.vector.Vector3i;
public class InstanceMaterial<D extends InstanceData> {
@ -100,7 +94,7 @@ public class InstanceMaterial<D extends InstanceData> {
return model(toRender, () -> buildModel(toRender));
}
public Instancer<D> model(Object key, Supplier<BufferedModel> supplier) {
public Instancer<D> model(Object key, Supplier<IModel> supplier) {
try {
return models.get(key, () -> new Instancer<>(supplier, originCoordinate, spec));
} 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()
.getBlockRenderer();
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());
}
private BufferedModel buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) {
BufferBuilderReader reader = new BufferBuilderReader(getBufferBuilder(model, referenceState, ms));
private IModel buildModel(IBakedModel model, BlockState referenceState, MatrixStack ms) {
int vertexCount = reader.getVertexCount();
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);
return new BlockModel(modelFormat, model, referenceState, ms);
}
// 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;
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) {
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.List;
import java.util.Set;
import java.util.function.Supplier;
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.util.Direction;
@ -18,23 +16,16 @@ import net.minecraft.util.math.vector.Vector3f;
public class PartBuilder {
private float sizeU = 64.0F;
private float sizeV = 32.0F;
private final float sizeU;
private final float sizeV;
private TextureAtlasSprite sprite;
private final List<CuboidBuilder> cuboids = new ArrayList<>();
public PartBuilder() { }
public PartBuilder(int sizeU, int sizeV) {
this.setTextureSize(sizeU, sizeV);
}
public PartBuilder setTextureSize(int textureWidth, int textureHeight) {
this.sizeU = (float)textureWidth;
this.sizeV = (float)textureHeight;
return this;
this.sizeU = (float) sizeU;
this.sizeV = (float) sizeV;
}
public PartBuilder sprite(TextureAtlasSprite sprite) {
@ -46,22 +37,8 @@ public class PartBuilder {
return new CuboidBuilder(this);
}
public BufferedModel build() {
int vertices = 0;
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);
public ModelPart build() {
return new ModelPart(cuboids);
}
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();
}
private static BufferedModel createBellModel() {
private static ModelPart createBellModel() {
return ModelPart.builder(32, 32)
.sprite(BellTileEntityRenderer.BELL_RESOURCE_LOCATION.sprite())
.cuboid()

View file

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

View file

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