mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-01-22 10:57:55 +01:00
Refactor GPUInstancer to separate behavior
- Instancer VAO logic moved to InstancedModel - Refactor GlVertexArray for easier debugging - Sort of clean up BufferLayout - Padding items are broken, needs fix
This commit is contained in:
parent
a336abe4f4
commit
d5e9e044ec
43 changed files with 579 additions and 458 deletions
|
@ -1,6 +1,6 @@
|
|||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
public interface Material<D extends InstanceData> {
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ public interface VertexList {
|
|||
|
||||
int getVertexCount();
|
||||
|
||||
VertexType getVertexType();
|
||||
|
||||
default boolean isEmpty() {
|
||||
return getVertexCount() == 0;
|
||||
}
|
||||
|
|
|
@ -3,66 +3,123 @@ package com.jozufozu.flywheel.backend.gl;
|
|||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.LayoutItem;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
@SuppressWarnings("MismatchedReadAndWriteOfArray")
|
||||
public class GlVertexArray extends GlObject {
|
||||
|
||||
private final boolean[] arrays = new boolean[GL32.glGetInteger(GL32.GL_MAX_VERTEX_ATTRIBS)];
|
||||
private static final int MAX_ATTRIBS = GL32.glGetInteger(GL32.GL_MAX_VERTEX_ATTRIBS);
|
||||
|
||||
/**
|
||||
* Whether each attribute is enabled.
|
||||
*/
|
||||
private final boolean[] enabled = new boolean[MAX_ATTRIBS];
|
||||
/**
|
||||
* Each attribute's divisor.
|
||||
*/
|
||||
private final int[] divisors = new int[MAX_ATTRIBS];
|
||||
|
||||
/**
|
||||
* The VBO to which each attribute is bound.
|
||||
*/
|
||||
private final int[] targets = new int[MAX_ATTRIBS];
|
||||
|
||||
/**
|
||||
* Each attribute's data type.
|
||||
*/
|
||||
private final VertexAttribute[] attributes = new VertexAttribute[MAX_ATTRIBS];
|
||||
|
||||
/**
|
||||
* Each attribute's offset.
|
||||
*/
|
||||
private final int[] offsets = new int[MAX_ATTRIBS];
|
||||
|
||||
/**
|
||||
* Each attribute's stride.
|
||||
*/
|
||||
private final int[] strides = new int[MAX_ATTRIBS];
|
||||
|
||||
|
||||
public GlVertexArray() {
|
||||
setHandle(GlStateManager._glGenVertexArrays());
|
||||
}
|
||||
|
||||
public static void bind(int vao) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
public void bind() {
|
||||
if (!isBound()) {
|
||||
GlStateManager._glBindVertexArray(handle());
|
||||
}
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
bind(handle());
|
||||
public boolean isBound() {
|
||||
return handle() == GlStateTracker.getVertexArray();
|
||||
}
|
||||
|
||||
public static void unbind() {
|
||||
GlStateManager._glBindVertexArray(0);
|
||||
}
|
||||
|
||||
public void bindAttributes(int startIndex, BufferLayout type) {
|
||||
int boundBuffer = GlStateTracker.getBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
bind();
|
||||
int i = startIndex;
|
||||
int offset = 0;
|
||||
final int stride = type.getStride();
|
||||
|
||||
for (VertexAttribute attribute : type.getAttributes()) {
|
||||
targets[i] = boundBuffer;
|
||||
attributes[i] = attribute;
|
||||
offsets[i] = offset;
|
||||
strides[i] = stride;
|
||||
|
||||
GL20.glVertexAttribPointer(i++, attribute.size(), attribute.type().getGlEnum(), attribute.normalized(), stride, offset);
|
||||
|
||||
offset += attribute.getByteWidth();
|
||||
}
|
||||
}
|
||||
|
||||
public void enableArrays(int count) {
|
||||
bind();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
enable(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableArrays(int count) {
|
||||
bind();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
disable(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void enable(int i) {
|
||||
if (!arrays[i]) {
|
||||
if (!enabled[i]) {
|
||||
GL20.glEnableVertexAttribArray(i);
|
||||
arrays[i] = true;
|
||||
enabled[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void disable(int i) {
|
||||
if (arrays[i]) {
|
||||
if (enabled[i]) {
|
||||
GL20.glDisableVertexAttribArray(i);
|
||||
arrays[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void bindAttributes(int startIndex, BufferLayout type) {
|
||||
int offset = 0;
|
||||
for (LayoutItem spec : type.getLayoutItems()) {
|
||||
spec.vertexAttribPointer(type.getStride(), startIndex, offset);
|
||||
startIndex += spec.attributeCount();
|
||||
offset += spec.size();
|
||||
enabled[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void deleteInternal(int handle) {
|
||||
GlStateManager._glDeleteVertexArrays(handle);
|
||||
}
|
||||
|
||||
public void setAttributeDivisor(int index, int divisor) {
|
||||
if (divisors[index] != divisor) {
|
||||
bind();
|
||||
GlCompat.getInstance().instancedArrays.vertexAttribDivisor(index, divisor);
|
||||
divisors[index] = divisor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
/**
|
||||
* A bindable attribute in a vertex array.
|
||||
*
|
||||
* @param size The number of components in the attribute, e.g. 3 for a vec3.
|
||||
* @param type The type of the attribute, e.g. GL_FLOAT.
|
||||
* @param normalized Whether the data is normalized.
|
||||
*/
|
||||
public record VertexAttribute(int size, GlNumericType type, boolean normalized) {
|
||||
|
||||
public int getByteWidth() {
|
||||
return size * type.getByteWidth();
|
||||
}
|
||||
}
|
|
@ -6,19 +6,17 @@ import java.util.function.Supplier;
|
|||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
public abstract class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
|
||||
|
||||
protected final Supplier<D> factory;
|
||||
protected final ModelSupplier modelData;
|
||||
protected final ArrayList<D> data = new ArrayList<>();
|
||||
|
||||
protected boolean anyToRemove;
|
||||
|
||||
protected AbstractInstancer(Supplier<D> factory, ModelSupplier modelData) {
|
||||
protected AbstractInstancer(Supplier<D> factory) {
|
||||
this.factory = factory;
|
||||
this.modelData = modelData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,18 +56,10 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
anyToRemove = true;
|
||||
}
|
||||
|
||||
public int getModelVertexCount() {
|
||||
return modelData.getVertexCount();
|
||||
}
|
||||
|
||||
public int getInstanceCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return getModelVertexCount() * getInstanceCount();
|
||||
}
|
||||
|
||||
protected void removeDeletedInstances() {
|
||||
// Figure out which elements are to be removed.
|
||||
final int oldSize = this.data.size();
|
||||
|
@ -117,6 +107,6 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Instancer[" + modelData + ']';
|
||||
return "Instancer[" + getInstanceCount() + ']';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ import com.jozufozu.flywheel.api.InstanceData;
|
|||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.api.struct.Batched;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
|
@ -24,7 +25,7 @@ public class BatchedMaterial<D extends InstanceData> implements Material<D> {
|
|||
|
||||
@Override
|
||||
public Instancer<D> model(ModelSupplier modelKey) {
|
||||
return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type, k));
|
||||
return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type));
|
||||
}
|
||||
|
||||
public void setupAndRenderInto(PoseStack stack, VertexConsumer buffer) {
|
||||
|
|
|
@ -39,27 +39,27 @@ public class BatchedMaterialGroup implements MaterialGroup {
|
|||
|
||||
public void render(PoseStack stack, BatchDrawingTracker source, TaskEngine pool) {
|
||||
|
||||
vertexCount = 0;
|
||||
instanceCount = 0;
|
||||
for (BatchedMaterial<?> material : materials.values()) {
|
||||
for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
instancer.setup();
|
||||
vertexCount += instancer.getVertexCount();
|
||||
instanceCount += instancer.getInstanceCount();
|
||||
}
|
||||
}
|
||||
|
||||
DirectVertexConsumer consumer = source.getDirectConsumer(state, vertexCount);
|
||||
|
||||
// avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
|
||||
consumer.memSetZero();
|
||||
|
||||
for (BatchedMaterial<?> material : materials.values()) {
|
||||
for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
instancer.sbb.context.outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
|
||||
instancer.submitTasks(stack, pool, consumer);
|
||||
}
|
||||
}
|
||||
// vertexCount = 0;
|
||||
// instanceCount = 0;
|
||||
// for (BatchedMaterial<?> material : materials.values()) {
|
||||
// for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
// instancer.setup();
|
||||
// vertexCount += instancer.getVertexCount();
|
||||
// instanceCount += instancer.getInstanceCount();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// DirectVertexConsumer consumer = source.getDirectConsumer(state, vertexCount);
|
||||
//
|
||||
// // avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
|
||||
// consumer.memSetZero();
|
||||
//
|
||||
// for (BatchedMaterial<?> material : materials.values()) {
|
||||
// for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
// instancer.sbb.context.outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
|
||||
// instancer.submitTasks(stack, pool, consumer);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
|
|
@ -5,68 +5,67 @@ import com.jozufozu.flywheel.api.struct.Batched;
|
|||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
|
||||
public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
|
||||
private final Batched<D> batchingType;
|
||||
// private final Batched<D> batchingType;
|
||||
//
|
||||
// final ModelTransformer sbb;
|
||||
|
||||
final ModelTransformer sbb;
|
||||
|
||||
public CPUInstancer(Batched<D> type, ModelSupplier modelData) {
|
||||
super(type::create, modelData);
|
||||
batchingType = type;
|
||||
|
||||
sbb = new ModelTransformer(modelData.get());
|
||||
public CPUInstancer(Batched<D> type) {
|
||||
super(type::create);
|
||||
// batchingType = type;
|
||||
//
|
||||
// sbb = new ModelTransformer(modelData.get());
|
||||
}
|
||||
|
||||
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {
|
||||
int instances = getInstanceCount();
|
||||
|
||||
while (instances > 0) {
|
||||
int end = instances;
|
||||
instances -= 512;
|
||||
int start = Math.max(instances, 0);
|
||||
|
||||
int verts = getModelVertexCount() * (end - start);
|
||||
|
||||
DirectVertexConsumer sub = consumer.split(verts);
|
||||
|
||||
pool.submit(() -> drawRange(stack, sub, start, end));
|
||||
}
|
||||
// int instances = getInstanceCount();
|
||||
//
|
||||
// while (instances > 0) {
|
||||
// int end = instances;
|
||||
// instances -= 512;
|
||||
// int start = Math.max(instances, 0);
|
||||
//
|
||||
// int verts = getModelVertexCount() * (end - start);
|
||||
//
|
||||
// DirectVertexConsumer sub = consumer.split(verts);
|
||||
//
|
||||
// pool.submit(() -> drawRange(stack, sub, start, end));
|
||||
// }
|
||||
}
|
||||
|
||||
private void drawRange(PoseStack stack, VertexConsumer buffer, int from, int to) {
|
||||
ModelTransformer.Params params = new ModelTransformer.Params();
|
||||
|
||||
for (D d : data.subList(from, to)) {
|
||||
params.loadDefault();
|
||||
|
||||
batchingType.transform(d, params);
|
||||
|
||||
sbb.renderInto(params, stack, buffer);
|
||||
}
|
||||
// ModelTransformer.Params params = new ModelTransformer.Params();
|
||||
//
|
||||
// for (D d : data.subList(from, to)) {
|
||||
// params.loadDefault();
|
||||
//
|
||||
// batchingType.transform(d, params);
|
||||
//
|
||||
// sbb.renderInto(params, stack, buffer);
|
||||
// }
|
||||
}
|
||||
|
||||
void drawAll(PoseStack stack, VertexConsumer buffer) {
|
||||
ModelTransformer.Params params = new ModelTransformer.Params();
|
||||
for (D d : data) {
|
||||
params.loadDefault();
|
||||
|
||||
batchingType.transform(d, params);
|
||||
|
||||
sbb.renderInto(params, stack, buffer);
|
||||
}
|
||||
// ModelTransformer.Params params = new ModelTransformer.Params();
|
||||
// for (D d : data) {
|
||||
// params.loadDefault();
|
||||
//
|
||||
// batchingType.transform(d, params);
|
||||
//
|
||||
// sbb.renderInto(params, stack, buffer);
|
||||
// }
|
||||
}
|
||||
|
||||
void setup() {
|
||||
if (anyToRemove) {
|
||||
data.removeIf(InstanceData::isRemoved);
|
||||
anyToRemove = false;
|
||||
}
|
||||
// if (anyToRemove) {
|
||||
// data.removeIf(InstanceData::isRemoved);
|
||||
// anyToRemove = false;
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,45 +1,31 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.backend.model.BufferedModel;
|
||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
||||
|
||||
private final BufferLayout instanceFormat;
|
||||
private final Instanced<D> instancedType;
|
||||
final BufferLayout instanceFormat;
|
||||
final Instanced<D> instancedType;
|
||||
|
||||
private BufferedModel model;
|
||||
private GlVertexArray vao;
|
||||
private GlBuffer instanceVBO;
|
||||
private int glInstanceCount = 0;
|
||||
private boolean deleted;
|
||||
private boolean initialized;
|
||||
GlBuffer vbo;
|
||||
int attributeBaseIndex;
|
||||
int glInstanceCount = 0;
|
||||
|
||||
protected boolean anyToUpdate;
|
||||
boolean anyToUpdate;
|
||||
|
||||
public GPUInstancer(Instanced<D> type, ModelSupplier model) {
|
||||
super(type::create, model);
|
||||
public GPUInstancer(Instanced<D> type) {
|
||||
super(type::create);
|
||||
this.instanceFormat = type.getLayout();
|
||||
instancedType = type;
|
||||
}
|
||||
|
@ -49,72 +35,24 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
anyToUpdate = true;
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
public void init() {
|
||||
if (vbo != null) return;
|
||||
|
||||
vao.bind();
|
||||
|
||||
renderSetup();
|
||||
|
||||
if (glInstanceCount > 0) {
|
||||
model.drawInstances(glInstanceCount);
|
||||
}
|
||||
|
||||
// persistent mapping sync point
|
||||
instanceVBO.doneForThisFrame();
|
||||
}
|
||||
|
||||
private boolean invalid() {
|
||||
return deleted || model == null;
|
||||
}
|
||||
|
||||
public Map<RenderType, Renderable> init(ModelAllocator modelAllocator) {
|
||||
if (isInitialized()) return Collections.emptyMap();
|
||||
|
||||
initialized = true;
|
||||
|
||||
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
|
||||
instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16);
|
||||
|
||||
vao = new GlVertexArray();
|
||||
|
||||
model = modelAllocator.alloc(modelData.get(), vao);
|
||||
|
||||
vao.bind();
|
||||
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
|
||||
|
||||
return ImmutableMap.of(modelData.getRenderType(), this::render);
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
return initialized;
|
||||
vbo = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
|
||||
vbo.setGrowthMargin(instanceFormat.getStride() * 16);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return !anyToUpdate && !anyToRemove && glInstanceCount == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free acquired resources. All other Instancer methods are undefined behavior after calling delete.
|
||||
*/
|
||||
public void delete() {
|
||||
if (invalid()) return;
|
||||
|
||||
deleted = true;
|
||||
|
||||
model.delete();
|
||||
|
||||
instanceVBO.delete();
|
||||
vao.delete();
|
||||
}
|
||||
|
||||
protected void renderSetup() {
|
||||
void renderSetup(GlVertexArray vao) {
|
||||
if (anyToRemove) {
|
||||
removeDeletedInstances();
|
||||
}
|
||||
|
||||
instanceVBO.bind();
|
||||
if (!realloc()) {
|
||||
vbo.bind();
|
||||
if (!realloc(vao)) {
|
||||
|
||||
if (anyToRemove) {
|
||||
clearBufferTail();
|
||||
|
@ -127,7 +65,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
glInstanceCount = data.size();
|
||||
}
|
||||
|
||||
instanceVBO.unbind();
|
||||
vbo.unbind();
|
||||
|
||||
anyToRemove = anyToUpdate = false;
|
||||
}
|
||||
|
@ -135,9 +73,9 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
private void clearBufferTail() {
|
||||
int size = data.size();
|
||||
final int offset = size * instanceFormat.getStride();
|
||||
final long length = instanceVBO.getCapacity() - offset;
|
||||
final long length = vbo.getCapacity() - offset;
|
||||
if (length > 0) {
|
||||
try (MappedBuffer buf = instanceVBO.getBuffer(offset, length)) {
|
||||
try (MappedBuffer buf = vbo.getBuffer(offset, length)) {
|
||||
MemoryUtil.memSet(MemoryUtil.memAddress(buf.unwrap()), 0, length);
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error("Error clearing buffer tail:", e);
|
||||
|
@ -150,7 +88,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
if (size <= 0) return;
|
||||
|
||||
try (MappedBuffer mapped = instanceVBO.getBuffer()) {
|
||||
try (MappedBuffer mapped = vbo.getBuffer()) {
|
||||
|
||||
final StructWriter<D> writer = instancedType.getWriter(mapped);
|
||||
|
||||
|
@ -172,13 +110,13 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean realloc() {
|
||||
private boolean realloc(GlVertexArray vao) {
|
||||
int size = this.data.size();
|
||||
int stride = instanceFormat.getStride();
|
||||
int requiredSize = size * stride;
|
||||
if (instanceVBO.ensureCapacity(requiredSize)) {
|
||||
if (vbo.ensureCapacity(requiredSize)) {
|
||||
|
||||
try (MappedBuffer buffer = instanceVBO.getBuffer()) {
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
StructWriter<D> writer = instancedType.getWriter(buffer);
|
||||
for (D datum : data) {
|
||||
writer.write(datum);
|
||||
|
@ -189,19 +127,18 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
glInstanceCount = size;
|
||||
|
||||
bindInstanceAttributes();
|
||||
bindInstanceAttributes(vao);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void bindInstanceAttributes() {
|
||||
int attributeBaseIndex = model.getAttributeCount();
|
||||
private void bindInstanceAttributes(GlVertexArray vao) {
|
||||
vao.bindAttributes(attributeBaseIndex, instanceFormat);
|
||||
|
||||
for (int i = 0; i < instanceFormat.getAttributeCount(); i++) {
|
||||
GlCompat.getInstance().instancedArrays.vertexAttribDivisor(attributeBaseIndex + i, 1);
|
||||
vao.setAttributeDivisor(attributeBaseIndex + i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ import com.jozufozu.flywheel.api.InstanceData;
|
|||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.backend.model.MeshAllocator;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
|
@ -23,10 +23,10 @@ import net.minecraft.client.renderer.RenderType;
|
|||
*/
|
||||
public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
||||
|
||||
protected final Map<ModelSupplier, GPUInstancer<D>> models = new HashMap<>();
|
||||
protected final Map<ModelSupplier, InstancedModel<D>> models = new HashMap<>();
|
||||
protected final Instanced<D> type;
|
||||
|
||||
protected final List<GPUInstancer<D>> uninitialized = new ArrayList<>();
|
||||
protected final List<InstancedModel<D>> uninitialized = new ArrayList<>();
|
||||
|
||||
protected final Multimap<RenderType, Renderable> renderables = ArrayListMultimap.create();
|
||||
|
||||
|
@ -36,29 +36,32 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
|||
|
||||
@Override
|
||||
public Instancer<D> model(ModelSupplier modelKey) {
|
||||
return models.computeIfAbsent(modelKey, k -> {
|
||||
GPUInstancer<D> instancer = new GPUInstancer<>(type, modelKey);
|
||||
uninitialized.add(instancer);
|
||||
return instancer;
|
||||
});
|
||||
return models.computeIfAbsent(modelKey, this::createInstancer).instancer;
|
||||
}
|
||||
|
||||
public int getInstanceCount() {
|
||||
return models.values().stream().mapToInt(GPUInstancer::getInstanceCount).sum();
|
||||
return models.values()
|
||||
.stream()
|
||||
.map(InstancedModel::getInstancer)
|
||||
.mapToInt(GPUInstancer::getInstanceCount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return models.values().stream().mapToInt(GPUInstancer::getVertexCount).sum();
|
||||
return models.values()
|
||||
.stream()
|
||||
.mapToInt(InstancedModel::getVertexCount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
public boolean nothingToRender() {
|
||||
return models.size() > 0 && models.values()
|
||||
.stream()
|
||||
.allMatch(GPUInstancer::isEmpty);
|
||||
.allMatch(InstancedModel::isEmpty);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
models.values().forEach(GPUInstancer::delete);
|
||||
models.values().forEach(InstancedModel::delete);
|
||||
models.clear();
|
||||
renderables.clear();
|
||||
}
|
||||
|
@ -68,16 +71,15 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
|||
*/
|
||||
public void clear() {
|
||||
models.values()
|
||||
.stream()
|
||||
.map(InstancedModel::getInstancer)
|
||||
.forEach(GPUInstancer::clear);
|
||||
}
|
||||
|
||||
public Collection<GPUInstancer<D>> getAllInstancers() {
|
||||
return models.values();
|
||||
}
|
||||
public void init(MeshAllocator allocator) {
|
||||
for (var instanced : uninitialized) {
|
||||
|
||||
public void init(ModelAllocator allocator) {
|
||||
for (GPUInstancer<?> instancer : uninitialized) {
|
||||
var map = instancer.init(allocator);
|
||||
var map = instanced.init(allocator);
|
||||
|
||||
map.forEach((type, renderable) -> renderables.get(type).add(renderable));
|
||||
}
|
||||
|
@ -91,4 +93,10 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
|||
public boolean anythingToRender(RenderType type) {
|
||||
return renderables.get(type).size() > 0;
|
||||
}
|
||||
|
||||
private InstancedModel<D> createInstancer(ModelSupplier model) {
|
||||
var instancer = new InstancedModel<>(new GPUInstancer<>(type), model);
|
||||
uninitialized.add(instancer);
|
||||
return instancer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.model.BufferedModel;
|
||||
import com.jozufozu.flywheel.backend.model.MeshAllocator;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class InstancedModel<D extends InstanceData> {
|
||||
|
||||
GPUInstancer<D> instancer;
|
||||
ModelSupplier model;
|
||||
|
||||
@Nullable
|
||||
private BufferedModel bufferedMesh;
|
||||
@Nullable
|
||||
private GlVertexArray vao;
|
||||
|
||||
public InstancedModel(GPUInstancer<D> instancer, ModelSupplier model) {
|
||||
this.instancer = instancer;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
public Map<RenderType, Renderable> init(MeshAllocator allocator) {
|
||||
instancer.init();
|
||||
|
||||
vao = new GlVertexArray();
|
||||
|
||||
bufferedMesh = allocator.alloc(model.get(), vao);
|
||||
instancer.attributeBaseIndex = bufferedMesh.getAttributeCount();
|
||||
vao.enableArrays(bufferedMesh.getAttributeCount() + instancer.instanceFormat.getAttributeCount());
|
||||
|
||||
return ImmutableMap.of(RenderType.solid(), this::render);
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
||||
vao.bind();
|
||||
|
||||
instancer.renderSetup(vao);
|
||||
|
||||
if (instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(instancer.glInstanceCount);
|
||||
}
|
||||
|
||||
// persistent mapping sync point
|
||||
instancer.vbo.doneForThisFrame();
|
||||
}
|
||||
|
||||
private boolean invalid() {
|
||||
return instancer.vbo == null || bufferedMesh == null || vao == null;
|
||||
}
|
||||
|
||||
public GPUInstancer<D> getInstancer() {
|
||||
return instancer;
|
||||
}
|
||||
|
||||
public ModelSupplier getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return model.getVertexCount() * instancer.glInstanceCount;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return instancer.isEmpty();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (invalid()) return;
|
||||
|
||||
vao.delete();
|
||||
bufferedMesh.delete();
|
||||
instancer.vbo.delete();
|
||||
|
||||
vao = null;
|
||||
bufferedMesh = null;
|
||||
instancer.vbo = null;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -9,9 +8,6 @@ import java.util.Set;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -19,8 +15,8 @@ import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
|||
import com.jozufozu.flywheel.backend.instancing.Engine;
|
||||
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
|
||||
import com.jozufozu.flywheel.backend.model.FallbackAllocator;
|
||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.backend.model.ModelPool;
|
||||
import com.jozufozu.flywheel.backend.model.MeshAllocator;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.RenderTypeRegistry;
|
||||
|
@ -45,7 +41,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||
|
||||
protected final ProgramCompiler<P> context;
|
||||
private ModelAllocator allocator;
|
||||
private MeshAllocator allocator;
|
||||
|
||||
protected final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
|
||||
|
||||
|
@ -169,7 +165,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
public void beginFrame(Camera info) {
|
||||
checkOriginDistance(info);
|
||||
|
||||
ModelAllocator allocator = getModelAllocator();
|
||||
MeshAllocator allocator = getModelAllocator();
|
||||
|
||||
for (InstancedMaterial<?> material : materials.values()) {
|
||||
material.init(allocator);
|
||||
|
@ -177,7 +173,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
toRender.addAll(material.renderables.keySet());
|
||||
}
|
||||
|
||||
if (allocator instanceof ModelPool pool) {
|
||||
if (allocator instanceof MeshPool pool) {
|
||||
// ...and then flush the model arena in case anything was marked for upload
|
||||
pool.flush();
|
||||
}
|
||||
|
@ -215,19 +211,19 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ());
|
||||
}
|
||||
|
||||
private ModelAllocator getModelAllocator() {
|
||||
private MeshAllocator getModelAllocator() {
|
||||
if (allocator == null) {
|
||||
allocator = createAllocator();
|
||||
}
|
||||
return this.allocator;
|
||||
}
|
||||
|
||||
private static ModelAllocator createAllocator() {
|
||||
private static MeshAllocator createAllocator() {
|
||||
if (GlCompat.getInstance()
|
||||
.onAMDWindows()) {
|
||||
return FallbackAllocator.INSTANCE;
|
||||
} else {
|
||||
return new ModelPool(Formats.POS_TEX_NORMAL);
|
||||
return new MeshPool(Formats.POS_TEX_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public class ArrayModelRenderer {
|
||||
|
||||
private final Model model;
|
||||
private final Mesh mesh;
|
||||
protected GlVertexArray vao;
|
||||
protected BufferedModel vbo;
|
||||
protected boolean initialized;
|
||||
|
||||
public ArrayModelRenderer(Model model) {
|
||||
this.model = model;
|
||||
public ArrayModelRenderer(Mesh mesh) {
|
||||
this.mesh = mesh;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -29,14 +29,12 @@ public class ArrayModelRenderer {
|
|||
protected void init() {
|
||||
initialized = true;
|
||||
|
||||
if (model.empty()) return;
|
||||
if (mesh.empty()) return;
|
||||
|
||||
this.vbo = new IndexedModel(model);
|
||||
this.vbo = new IndexedModel(mesh);
|
||||
|
||||
vao = new GlVertexArray();
|
||||
|
||||
vao.bind();
|
||||
|
||||
// bind the model's vbo to our vao
|
||||
this.vbo.setupState(vao);
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public enum FallbackAllocator implements ModelAllocator {
|
||||
public enum FallbackAllocator implements MeshAllocator {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public BufferedModel alloc(Model model, GlVertexArray vao) {
|
||||
IndexedModel out = new IndexedModel(model);
|
||||
vao.bind();
|
||||
public BufferedModel alloc(Mesh mesh, GlVertexArray vao) {
|
||||
IndexedModel out = new IndexedModel(mesh);
|
||||
out.setupState(vao);
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
/**
|
||||
* An indexed triangle model. Just what the driver ordered.
|
||||
|
@ -20,32 +20,32 @@ import com.jozufozu.flywheel.core.model.Model;
|
|||
*/
|
||||
public class IndexedModel implements BufferedModel {
|
||||
|
||||
protected final Model model;
|
||||
protected final Mesh mesh;
|
||||
protected final GlPrimitive primitiveMode;
|
||||
protected ElementBuffer ebo;
|
||||
protected GlBuffer vbo;
|
||||
protected boolean deleted;
|
||||
|
||||
public IndexedModel(Model model) {
|
||||
this.model = model;
|
||||
public IndexedModel(Mesh mesh) {
|
||||
this.mesh = mesh;
|
||||
this.primitiveMode = GlPrimitive.TRIANGLES;
|
||||
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
vbo.bind();
|
||||
// allocate the buffer on the gpu
|
||||
vbo.ensureCapacity(model.size());
|
||||
vbo.ensureCapacity(mesh.size());
|
||||
|
||||
// mirror it in system memory, so we can write to it, and upload our model.
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
model.writeInto(buffer.unwrap());
|
||||
mesh.writeInto(buffer.unwrap());
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", model.name()), e);
|
||||
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", mesh.name()), e);
|
||||
}
|
||||
|
||||
vbo.unbind();
|
||||
|
||||
this.ebo = model.createEBO();
|
||||
this.ebo = mesh.createEBO();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -81,11 +81,11 @@ public class IndexedModel implements BufferedModel {
|
|||
|
||||
@Override
|
||||
public VertexType getType() {
|
||||
return model.getType();
|
||||
return mesh.getType();
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return model.vertexCount();
|
||||
return mesh.vertexCount();
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public interface ModelAllocator {
|
||||
public interface MeshAllocator {
|
||||
/**
|
||||
* Allocate a model.
|
||||
*
|
||||
* @param model The model to allocate.
|
||||
* @param mesh The model to allocate.
|
||||
* @param vao The vertex array object to attach the model to.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
BufferedModel alloc(Model model, GlVertexArray vao);
|
||||
BufferedModel alloc(Mesh mesh, GlVertexArray vao);
|
||||
|
||||
@FunctionalInterface
|
||||
interface Callback {
|
|
@ -14,9 +14,9 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public class ModelPool implements ModelAllocator {
|
||||
public class MeshPool implements MeshAllocator {
|
||||
|
||||
protected final VertexType vertexType;
|
||||
|
||||
|
@ -36,7 +36,7 @@ public class ModelPool implements ModelAllocator {
|
|||
*
|
||||
* @param vertexType The vertex type of the models that will be stored in the pool.
|
||||
*/
|
||||
public ModelPool(VertexType vertexType) {
|
||||
public MeshPool(VertexType vertexType) {
|
||||
this.vertexType = vertexType;
|
||||
int stride = vertexType.getStride();
|
||||
|
||||
|
@ -49,14 +49,14 @@ public class ModelPool implements ModelAllocator {
|
|||
/**
|
||||
* Allocate a model in the arena.
|
||||
*
|
||||
* @param model The model to allocate.
|
||||
* @param mesh The model to allocate.
|
||||
* @param vao The vertex array object to attach the model to.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
@Override
|
||||
public PooledModel alloc(Model model, GlVertexArray vao) {
|
||||
PooledModel bufferedModel = new PooledModel(vao, model, vertices);
|
||||
vertices += model.vertexCount();
|
||||
public PooledModel alloc(Mesh mesh, GlVertexArray vao) {
|
||||
PooledModel bufferedModel = new PooledModel(vao, mesh, vertices);
|
||||
vertices += mesh.vertexCount();
|
||||
models.add(bufferedModel);
|
||||
pendingUpload.add(bufferedModel);
|
||||
|
||||
|
@ -94,7 +94,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
model.first = vertices;
|
||||
|
||||
vertices += model.getVertexCount();
|
||||
vertices += model.mesh.vertexCount();
|
||||
}
|
||||
|
||||
this.vertices = vertices;
|
||||
|
@ -120,7 +120,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
model.buffer(writer);
|
||||
|
||||
vertices += model.getVertexCount();
|
||||
vertices += model.mesh.vertexCount();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
@ -153,31 +153,31 @@ public class ModelPool implements ModelAllocator {
|
|||
private final ElementBuffer ebo;
|
||||
private final GlVertexArray vao;
|
||||
|
||||
private final Model model;
|
||||
private final Mesh mesh;
|
||||
private int first;
|
||||
|
||||
private boolean deleted;
|
||||
|
||||
public PooledModel(GlVertexArray vao, Model model, int first) {
|
||||
public PooledModel(GlVertexArray vao, Mesh mesh, int first) {
|
||||
this.vao = vao;
|
||||
this.model = model;
|
||||
this.mesh = mesh;
|
||||
this.first = first;
|
||||
ebo = model.createEBO();
|
||||
ebo = mesh.createEBO();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getType() {
|
||||
return ModelPool.this.vertexType;
|
||||
return MeshPool.this.vertexType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVertexCount() {
|
||||
return model.vertexCount();
|
||||
return mesh.vertexCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupState(GlVertexArray vao) {
|
||||
vao.bind();
|
||||
vbo.bind();
|
||||
vao.enableArrays(getAttributeCount());
|
||||
vao.bindAttributes(0, vertexType.getLayout());
|
||||
}
|
||||
|
@ -212,9 +212,8 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
private void buffer(VertexWriter writer) {
|
||||
writer.seekToVertex(first);
|
||||
writer.writeVertexList(model.getReader());
|
||||
writer.writeVertexList(mesh.getReader());
|
||||
|
||||
vao.bind();
|
||||
setupState(vao);
|
||||
}
|
||||
}
|
|
@ -12,30 +12,30 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
|||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.MappedGlBuffer;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public class VBOModel implements BufferedModel {
|
||||
|
||||
protected final Model model;
|
||||
protected final Mesh mesh;
|
||||
protected final GlPrimitive primitiveMode;
|
||||
protected GlBuffer vbo;
|
||||
protected boolean deleted;
|
||||
|
||||
public VBOModel(GlPrimitive primitiveMode, Model model) {
|
||||
this.model = model;
|
||||
public VBOModel(GlPrimitive primitiveMode, Mesh mesh) {
|
||||
this.mesh = mesh;
|
||||
this.primitiveMode = primitiveMode;
|
||||
|
||||
vbo = new MappedGlBuffer(GlBufferType.ARRAY_BUFFER);
|
||||
|
||||
vbo.bind();
|
||||
// allocate the buffer on the gpu
|
||||
vbo.ensureCapacity(model.size());
|
||||
vbo.ensureCapacity(mesh.size());
|
||||
|
||||
// mirror it in system memory, so we can write to it, and upload our model.
|
||||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
model.writeInto(buffer.unwrap());
|
||||
mesh.writeInto(buffer.unwrap());
|
||||
} catch (Exception e) {
|
||||
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", model.name()), e);
|
||||
Flywheel.LOGGER.error(String.format("Error uploading model '%s':", mesh.name()), e);
|
||||
}
|
||||
|
||||
vbo.unbind();
|
||||
|
@ -47,11 +47,11 @@ public class VBOModel implements BufferedModel {
|
|||
|
||||
@Override
|
||||
public VertexType getType() {
|
||||
return model.getType();
|
||||
return mesh.getType();
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return model.vertexCount();
|
||||
return mesh.vertexCount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +64,7 @@ public class VBOModel implements BufferedModel {
|
|||
}
|
||||
|
||||
public void drawCall() {
|
||||
glDrawArrays(primitiveMode.glEnum, 0, getVertexCount());
|
||||
glDrawArrays(primitiveMode.glEnum, 0, mesh.vertexCount());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,7 +73,7 @@ public class VBOModel implements BufferedModel {
|
|||
public void drawInstances(int instanceCount) {
|
||||
if (!valid()) return;
|
||||
|
||||
GL31.glDrawArraysInstanced(primitiveMode.glEnum, 0, getVertexCount(), instanceCount);
|
||||
GL31.glDrawArraysInstanced(primitiveMode.glEnum, 0, mesh.vertexCount(), instanceCount);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.NonNullSupplier;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class BasicModelSupplier implements ModelSupplier {
|
||||
|
||||
private RenderType renderType;
|
||||
private final Lazy<Mesh> supplier;
|
||||
|
||||
public BasicModelSupplier(NonNullSupplier<Mesh> supplier) {
|
||||
this(supplier, RenderType.solid());
|
||||
}
|
||||
|
||||
public BasicModelSupplier(NonNullSupplier<Mesh> supplier, RenderType renderType) {
|
||||
this.supplier = Lazy.of(supplier);
|
||||
this.renderType = renderType;
|
||||
}
|
||||
|
||||
public BasicModelSupplier setCutout() {
|
||||
return setRenderType(RenderType.cutoutMipped());
|
||||
}
|
||||
|
||||
public BasicModelSupplier setRenderType(@Nonnull RenderType renderType) {
|
||||
this.renderType = renderType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mesh get() {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public RenderType getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return supplier.map(Mesh::vertexCount)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModelSupplier{" + supplier.map(Mesh::name)
|
||||
.orElse("Uninitialized") + '}';
|
||||
}
|
||||
}
|
|
@ -42,7 +42,7 @@ public class FullscreenQuad {
|
|||
vao = new GlVertexArray();
|
||||
vao.bind();
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
vao.enableArrays(1);
|
||||
|
||||
glVertexAttribPointer(0, 4, GlNumericType.FLOAT.getGlEnum(), false, 4 * 4, 0);
|
||||
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.NonNullSupplier;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class ModelSupplier extends Lazy<Model> {
|
||||
|
||||
private RenderType renderType;
|
||||
|
||||
public ModelSupplier(NonNullSupplier<Model> supplier) {
|
||||
this(supplier, RenderType.solid());
|
||||
}
|
||||
|
||||
public ModelSupplier(NonNullSupplier<Model> supplier, RenderType renderType) {
|
||||
super(supplier);
|
||||
this.renderType = renderType;
|
||||
}
|
||||
|
||||
public ModelSupplier setCutout() {
|
||||
return setRenderType(RenderType.cutoutMipped());
|
||||
}
|
||||
|
||||
public ModelSupplier setRenderType(@Nonnull RenderType renderType) {
|
||||
this.renderType = renderType;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public RenderType getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public int getVertexCount() {
|
||||
return map(Model::vertexCount).orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModelSupplier{" + map(Model::name).orElse("Uninitialized") + '}';
|
||||
}
|
||||
}
|
|
@ -2,36 +2,33 @@ package com.jozufozu.flywheel.core;
|
|||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.jozufozu.flywheel.core.model.BlockModel;
|
||||
import com.jozufozu.flywheel.core.model.BlockMesh;
|
||||
import com.jozufozu.flywheel.core.model.ModelUtil;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class Models {
|
||||
|
||||
public static ModelSupplier block(BlockState state) {
|
||||
return BLOCK_STATE.computeIfAbsent(state, it -> new ModelSupplier(() -> new BlockModel(it)));
|
||||
public static BasicModelSupplier block(BlockState state) {
|
||||
return BLOCK_STATE.computeIfAbsent(state, it -> new BasicModelSupplier(() -> new BlockMesh(it)));
|
||||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial) {
|
||||
return PARTIAL.computeIfAbsent(partial, it -> new ModelSupplier(() -> new BlockModel(it)));
|
||||
public static BasicModelSupplier partial(PartialModel partial) {
|
||||
return PARTIAL.computeIfAbsent(partial, it -> new BasicModelSupplier(() -> new BlockMesh(it)));
|
||||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial, Direction dir) {
|
||||
public static BasicModelSupplier partial(PartialModel partial, Direction dir) {
|
||||
return partial(partial, dir, () -> ModelUtil.rotateToFace(dir));
|
||||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial, Direction dir, Supplier<PoseStack> modelTransform) {
|
||||
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new ModelSupplier(() -> new BlockModel(partial, modelTransform.get())));
|
||||
public static BasicModelSupplier partial(PartialModel partial, Direction dir, Supplier<PoseStack> modelTransform) {
|
||||
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new BasicModelSupplier(() -> new BlockMesh(partial, modelTransform.get())));
|
||||
}
|
||||
|
||||
public static void onReload(ReloadRenderersEvent ignored) {
|
||||
|
@ -40,8 +37,8 @@ public class Models {
|
|||
PARTIAL_DIR.clear();
|
||||
}
|
||||
|
||||
private static final Map<BlockState, ModelSupplier> BLOCK_STATE = new HashMap<>();
|
||||
private static final Map<PartialModel, ModelSupplier> PARTIAL = new HashMap<>();
|
||||
private static final Map<Pair<Direction, PartialModel>, ModelSupplier> PARTIAL_DIR = new HashMap<>();
|
||||
private static final Map<BlockState, BasicModelSupplier> BLOCK_STATE = new HashMap<>();
|
||||
private static final Map<PartialModel, BasicModelSupplier> PARTIAL = new HashMap<>();
|
||||
private static final Map<Pair<Direction, PartialModel>, BasicModelSupplier> PARTIAL_DIR = new HashMap<>();
|
||||
|
||||
}
|
||||
|
|
|
@ -3,12 +3,14 @@ package com.jozufozu.flywheel.core.hardcoded;
|
|||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.vertex.PosTexNormalVertex;
|
||||
import com.jozufozu.flywheel.core.vertex.PosTexNormalWriterUnsafe;
|
||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||
|
||||
public class ModelPart implements Model {
|
||||
public class ModelPart implements Mesh {
|
||||
|
||||
private final int vertices;
|
||||
private final String name;
|
||||
|
@ -25,7 +27,7 @@ public class ModelPart implements Model {
|
|||
this.vertices = vertices;
|
||||
}
|
||||
|
||||
PosTexNormalWriterUnsafe writer = Formats.POS_TEX_NORMAL.createWriter(MemoryTracker.create(size()));
|
||||
PosTexNormalWriterUnsafe writer = getType().createWriter(MemoryTracker.create(size()));
|
||||
for (PartBuilder.CuboidBuilder cuboid : cuboids) {
|
||||
cuboid.buffer(writer);
|
||||
}
|
||||
|
@ -51,4 +53,9 @@ public class ModelPart implements Model {
|
|||
public VertexList getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PosTexNormalVertex getType() {
|
||||
return Formats.POS_TEX_NORMAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.VertexAttribute;
|
||||
|
||||
/**
|
||||
* Classic Vertex Format struct with a clever name.
|
||||
|
@ -17,29 +19,29 @@ import com.jozufozu.flywheel.api.vertex.VertexType;
|
|||
*/
|
||||
public class BufferLayout {
|
||||
|
||||
private final List<LayoutItem> allAttributes;
|
||||
private final List<VertexAttribute> attributes;
|
||||
|
||||
private final int numAttributes;
|
||||
private final int stride;
|
||||
|
||||
public BufferLayout(List<LayoutItem> allAttributes) {
|
||||
this.allAttributes = allAttributes;
|
||||
public BufferLayout(List<LayoutItem> layoutItems) {
|
||||
|
||||
int numAttributes = 0, stride = 0;
|
||||
for (LayoutItem spec : allAttributes) {
|
||||
numAttributes += spec.attributeCount();
|
||||
stride += spec.size();
|
||||
ImmutableList.Builder<VertexAttribute> attributes = ImmutableList.builder();
|
||||
|
||||
stride = calculateStride(layoutItems);
|
||||
|
||||
for (LayoutItem item : layoutItems) {
|
||||
item.provideAttributes(attributes::add);
|
||||
}
|
||||
this.numAttributes = numAttributes;
|
||||
this.stride = stride;
|
||||
|
||||
this.attributes = attributes.build();
|
||||
}
|
||||
|
||||
public List<LayoutItem> getLayoutItems() {
|
||||
return allAttributes;
|
||||
public Collection<VertexAttribute> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public int getAttributeCount() {
|
||||
return numAttributes;
|
||||
return attributes.size();
|
||||
}
|
||||
|
||||
public int getStride() {
|
||||
|
@ -50,6 +52,14 @@ public class BufferLayout {
|
|||
return new Builder();
|
||||
}
|
||||
|
||||
private static int calculateStride(List<LayoutItem> layoutItems) {
|
||||
int stride = 0;
|
||||
for (LayoutItem spec : layoutItems) {
|
||||
stride += spec.getByteWidth();
|
||||
}
|
||||
return stride;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final ImmutableList.Builder<LayoutItem> allItems;
|
||||
|
||||
|
@ -66,4 +76,5 @@ public class BufferLayout {
|
|||
return new BufferLayout(allItems.build());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,4 +21,6 @@ public class CommonItems {
|
|||
public static final PrimitiveItem NORMALIZED_BYTE = new PrimitiveItem(GlNumericType.BYTE, 1, true);
|
||||
public static final LayoutItem PADDING_BYTE = new Padding(1);
|
||||
|
||||
public static final MatrixItem MAT3 = new MatrixItem(3, 3);
|
||||
public static final MatrixItem MAT4 = new MatrixItem(4, 4);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.VertexAttribute;
|
||||
|
||||
public interface LayoutItem {
|
||||
|
||||
void vertexAttribPointer(int stride, int index, int offset);
|
||||
void provideAttributes(Consumer<VertexAttribute> consumer);
|
||||
|
||||
int size();
|
||||
int getByteWidth();
|
||||
|
||||
int attributeCount();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.VertexAttribute;
|
||||
|
||||
public record MatrixItem(int rows, int cols) implements LayoutItem {
|
||||
|
||||
@Override
|
||||
public void provideAttributes(Consumer<VertexAttribute> consumer) {
|
||||
for (int i = 0; i < rows; i++) {
|
||||
consumer.accept(new VertexAttribute(cols, GlNumericType.FLOAT, false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getByteWidth() {
|
||||
return GlNumericType.FLOAT.getByteWidth() * rows * cols;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
|
||||
public enum MatrixItems implements LayoutItem {
|
||||
MAT3(3, 3),
|
||||
MAT4(4, 4),
|
||||
;
|
||||
|
||||
private final int rows;
|
||||
private final int cols;
|
||||
|
||||
MatrixItems(int rows, int cols) {
|
||||
this.rows = rows;
|
||||
this.cols = cols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void vertexAttribPointer(int stride, int index, int offset) {
|
||||
for (int i = 0; i < rows; i++) {
|
||||
long attribPointer = offset + (long) i * cols * GlNumericType.FLOAT.getByteWidth();
|
||||
GL20.glVertexAttribPointer(index + i, cols, GlNumericType.FLOAT.getGlEnum(), false, stride, attribPointer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return GlNumericType.FLOAT.getByteWidth() * rows * cols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attributeCount() {
|
||||
return rows;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,20 +1,19 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.VertexAttribute;
|
||||
|
||||
record Padding(int bytes) implements LayoutItem {
|
||||
|
||||
@Override
|
||||
public void vertexAttribPointer(int stride, int index, int offset) {
|
||||
public void provideAttributes(Consumer<VertexAttribute> consumer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
public int getByteWidth() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attributeCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,42 +1,30 @@
|
|||
package com.jozufozu.flywheel.core.layout;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlNumericType;
|
||||
import com.jozufozu.flywheel.backend.gl.VertexAttribute;
|
||||
|
||||
public class PrimitiveItem implements LayoutItem {
|
||||
|
||||
private final GlNumericType type;
|
||||
private final int count;
|
||||
private final int size;
|
||||
private final int attributeCount;
|
||||
private final boolean normalized;
|
||||
private final VertexAttribute attribute;
|
||||
|
||||
public PrimitiveItem(GlNumericType type, int count) {
|
||||
this(type, count, false);
|
||||
}
|
||||
|
||||
public PrimitiveItem(GlNumericType type, int count, boolean normalized) {
|
||||
this.type = type;
|
||||
this.count = count;
|
||||
this.size = type.getByteWidth() * count;
|
||||
this.attributeCount = (this.size + 15) / 16; // ceiling division. GLSL vertex attributes can only be 16 bytes wide
|
||||
this.normalized = normalized;
|
||||
attribute = new VertexAttribute(count, type, normalized);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void vertexAttribPointer(int stride, int index, int offset) {
|
||||
GL20.glVertexAttribPointer(index, count, type.getGlEnum(), normalized, stride, offset);
|
||||
public void provideAttributes(Consumer<VertexAttribute> consumer) {
|
||||
consumer.accept(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attributeCount() {
|
||||
return attributeCount;
|
||||
public int getByteWidth() {
|
||||
return attribute.getByteWidth();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import com.jozufozu.flywheel.backend.gl.buffer.VecBuffer;
|
|||
import com.jozufozu.flywheel.core.Programs;
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.CommonItems;
|
||||
import com.jozufozu.flywheel.core.layout.MatrixItems;
|
||||
import com.jozufozu.flywheel.core.model.ModelTransformer;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
@ -16,7 +15,7 @@ public class ModelType implements Instanced<ModelData>, Batched<ModelData> {
|
|||
|
||||
public static final BufferLayout FORMAT = BufferLayout.builder()
|
||||
.addItems(CommonItems.LIGHT, CommonItems.RGBA)
|
||||
.addItems(MatrixItems.MAT4, MatrixItems.MAT3)
|
||||
.addItems(CommonItems.MAT4, CommonItems.MAT3)
|
||||
.build();
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,43 +12,43 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
/**
|
||||
* A model of a single block.
|
||||
*/
|
||||
public class BlockModel implements Model {
|
||||
public class BlockMesh implements Mesh {
|
||||
private static final PoseStack IDENTITY = new PoseStack();
|
||||
|
||||
private final VertexList reader;
|
||||
|
||||
private final String name;
|
||||
|
||||
public BlockModel(BlockState state) {
|
||||
public BlockMesh(BlockState state) {
|
||||
this(Minecraft.getInstance()
|
||||
.getBlockRenderer()
|
||||
.getBlockModel(state), state);
|
||||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState) {
|
||||
public BlockMesh(BakedModel model, BlockState referenceState) {
|
||||
this(model, referenceState, IDENTITY);
|
||||
}
|
||||
|
||||
public BlockModel(PartialModel model) {
|
||||
public BlockMesh(PartialModel model) {
|
||||
this(model, IDENTITY);
|
||||
}
|
||||
|
||||
public BlockModel(PartialModel model, PoseStack ms) {
|
||||
public BlockMesh(PartialModel model, PoseStack ms) {
|
||||
this(ModelUtil.bakedModel(model.get())
|
||||
.withPoseStack(ms), model.getName());
|
||||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
public BlockMesh(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
this(ModelUtil.bakedModel(model)
|
||||
.withReferenceState(referenceState)
|
||||
.withPoseStack(ms), referenceState.toString());
|
||||
}
|
||||
|
||||
public BlockModel(Bufferable builder, String name) {
|
||||
public BlockMesh(Bufferable builder, String name) {
|
||||
this(Formats.BLOCK.createReader(builder.build()), name);
|
||||
}
|
||||
|
||||
public BlockModel(VertexList reader, String name) {
|
||||
public BlockMesh(VertexList reader, String name) {
|
||||
this.reader = reader;
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -58,13 +58,13 @@ public class BlockModel implements Model {
|
|||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int vertexCount() {
|
||||
return reader.getVertexCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexList getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "BlockMesh{" + "name='" + name + "',type='" + reader.getVertexType() + "}";
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ import java.nio.ByteBuffer;
|
|||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.model.ElementBuffer;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.QuadConverter;
|
||||
|
||||
/**
|
||||
|
@ -28,7 +27,7 @@ import com.jozufozu.flywheel.core.QuadConverter;
|
|||
* assert model.size() == final - initial;
|
||||
* }</pre>
|
||||
*/
|
||||
public interface Model {
|
||||
public interface Mesh {
|
||||
|
||||
/**
|
||||
* A name uniquely identifying this model.
|
||||
|
@ -40,10 +39,12 @@ public interface Model {
|
|||
/**
|
||||
* @return The number of vertices the model has.
|
||||
*/
|
||||
int vertexCount();
|
||||
default int vertexCount() {
|
||||
return getReader().getVertexCount();
|
||||
}
|
||||
|
||||
default VertexType getType() {
|
||||
return Formats.POS_TEX_NORMAL;
|
||||
return getReader().getVertexType();
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,8 @@
|
|||
package com.jozufozu.flywheel.core.model;
|
||||
|
||||
public interface ModelSupplier {
|
||||
|
||||
Mesh get();
|
||||
|
||||
int getVertexCount();
|
||||
}
|
|
@ -20,15 +20,15 @@ import net.minecraft.util.Mth;
|
|||
|
||||
public class ModelTransformer {
|
||||
|
||||
private final Model model;
|
||||
private final Mesh mesh;
|
||||
private final VertexList reader;
|
||||
private final IntPredicate shadedPredicate;
|
||||
|
||||
public final Context context = new Context();
|
||||
|
||||
public ModelTransformer(Model model) {
|
||||
this.model = model;
|
||||
reader = model.getReader();
|
||||
public ModelTransformer(Mesh mesh) {
|
||||
this.mesh = mesh;
|
||||
reader = mesh.getReader();
|
||||
if (reader instanceof ShadedVertexList shaded) {
|
||||
shadedPredicate = shaded::isShaded;
|
||||
} else {
|
||||
|
@ -128,7 +128,7 @@ public class ModelTransformer {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ModelTransformer[" + model + ']';
|
||||
return "ModelTransformer[" + mesh + ']';
|
||||
}
|
||||
|
||||
public static int transformColor(byte component, float scale) {
|
||||
|
|
|
@ -76,4 +76,8 @@ public final class WorldModelBuilder implements Bufferable {
|
|||
this.poseStack = poseStack;
|
||||
return this;
|
||||
}
|
||||
|
||||
public BlockMesh finish() {
|
||||
return new BlockMesh(this, "name");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.model.ShadeSeparatedBufferBuilder;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
import com.mojang.blaze3d.vertex.BufferBuilder;
|
||||
|
@ -106,6 +108,11 @@ public class BlockVertexList implements VertexList {
|
|||
return vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return Formats.BLOCK;
|
||||
}
|
||||
|
||||
public static class Shaded extends BlockVertexList implements ShadedVertexList {
|
||||
|
||||
private final int unshadedStartVertex;
|
||||
|
|
|
@ -6,6 +6,8 @@ import org.lwjgl.system.MemoryUtil;
|
|||
|
||||
import com.jozufozu.flywheel.api.vertex.ShadedVertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
|
||||
public class BlockVertexListUnsafe implements VertexList {
|
||||
|
@ -99,6 +101,11 @@ public class BlockVertexListUnsafe implements VertexList {
|
|||
return vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return Formats.BLOCK;
|
||||
}
|
||||
|
||||
public static class Shaded extends BlockVertexListUnsafe implements ShadedVertexList {
|
||||
|
||||
private final int unshadedStartVertex;
|
||||
|
|
|
@ -5,6 +5,8 @@ import java.nio.ByteBuffer;
|
|||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.util.RenderMath;
|
||||
|
||||
public class PosTexNormalVertexListUnsafe implements VertexList {
|
||||
|
@ -92,4 +94,9 @@ public class PosTexNormalVertexListUnsafe implements VertexList {
|
|||
public int getVertexCount() {
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return Formats.POS_TEX_NORMAL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.api.MaterialManager;
|
|||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
|
@ -20,7 +20,7 @@ import net.minecraft.world.level.block.entity.BellBlockEntity;
|
|||
|
||||
public class BellInstance extends BlockEntityInstance<BellBlockEntity> implements DynamicInstance {
|
||||
|
||||
private static final ModelSupplier MODEL = new ModelSupplier(BellInstance::createBellModel, RenderType.cutoutMipped());
|
||||
private static final BasicModelSupplier MODEL = new BasicModelSupplier(BellInstance::createBellModel, RenderType.cutoutMipped());
|
||||
|
||||
private final OrientedData bell;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import com.jozufozu.flywheel.api.MaterialManager;
|
|||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
|
||||
|
@ -19,7 +19,6 @@ import com.mojang.math.Vector3f;
|
|||
|
||||
import it.unimi.dsi.fastutil.floats.Float2FloatFunction;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
|
@ -34,8 +33,8 @@ import net.minecraft.world.level.block.state.properties.ChestType;
|
|||
|
||||
public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends BlockEntityInstance<T> implements DynamicInstance {
|
||||
|
||||
private static final BiFunction<ChestType, Material, ModelSupplier> LID = Util.memoize((type, mat) -> new ModelSupplier(() -> createLidModel(type, mat.sprite()), Sheets.chestSheet()));
|
||||
private static final BiFunction<ChestType, Material, ModelSupplier> BASE = Util.memoize((type, mat) -> new ModelSupplier(() -> createBaseModel(type, mat.sprite()), Sheets.chestSheet()));
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> LID = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createLidModel(type, mat.sprite()), Sheets.chestSheet()));
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> BASE = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createBaseModel(type, mat.sprite()), Sheets.chestSheet()));
|
||||
|
||||
private final OrientedData body;
|
||||
private final ModelData lid;
|
||||
|
|
|
@ -2,17 +2,16 @@ package com.jozufozu.flywheel.vanilla;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.jozufozu.flywheel.api.Material;
|
||||
import com.jozufozu.flywheel.api.MaterialManager;
|
||||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.api.instance.TickableInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.jozufozu.flywheel.core.Models;
|
||||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
@ -30,7 +29,7 @@ import net.minecraft.world.phys.Vec3;
|
|||
public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance<T> implements DynamicInstance, TickableInstance {
|
||||
|
||||
private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png");
|
||||
private static final ModelSupplier MODEL = new ModelSupplier(MinecartInstance::getBodyModel, RenderType.entitySolid(MINECART_LOCATION));
|
||||
private static final BasicModelSupplier MODEL = new BasicModelSupplier(MinecartInstance::getBodyModel, RenderType.entitySolid(MINECART_LOCATION));
|
||||
|
||||
private final PoseStack stack = new PoseStack();
|
||||
|
||||
|
@ -160,7 +159,7 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
|
|||
}
|
||||
|
||||
@Nonnull
|
||||
private static Model getBodyModel() {
|
||||
private static Mesh getBodyModel() {
|
||||
int y = -3;
|
||||
return ModelPart.builder("minecart", 64, 32)
|
||||
.cuboid().invertYZ().start(-10, -8, -y).size(20, 16, 2).textureOffset(0, 10).rotateZ((float) Math.PI).rotateX(((float)Math.PI / 2F)).endCuboid()
|
||||
|
|
|
@ -6,7 +6,7 @@ import com.jozufozu.flywheel.api.MaterialManager;
|
|||
import com.jozufozu.flywheel.api.instance.DynamicInstance;
|
||||
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
|
||||
import com.jozufozu.flywheel.core.Materials;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.BasicModelSupplier;
|
||||
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
|
||||
import com.jozufozu.flywheel.core.materials.model.ModelData;
|
||||
import com.jozufozu.flywheel.util.AnimationTickHolder;
|
||||
|
@ -26,8 +26,8 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
|
|||
|
||||
public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntity> implements DynamicInstance {
|
||||
|
||||
private static final Function<TextureAtlasSprite, ModelSupplier> BASE = Util.memoize(it -> new ModelSupplier(() -> makeBaseModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
|
||||
private static final Function<TextureAtlasSprite, ModelSupplier> LID = Util.memoize(it -> new ModelSupplier(() -> makeLidModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
|
||||
private static final Function<TextureAtlasSprite, BasicModelSupplier> BASE = Util.memoize(it -> new BasicModelSupplier(() -> makeBaseModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
|
||||
private static final Function<TextureAtlasSprite, BasicModelSupplier> LID = Util.memoize(it -> new BasicModelSupplier(() -> makeLidModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
|
||||
|
||||
private final TextureAtlasSprite texture;
|
||||
|
||||
|
|
Loading…
Reference in a new issue