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