mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-26 23:18:04 +01:00
Better draw call organization
- InstancingEngine takes over tracking individual draw calls - Many draw calls are associated with a single ShaderState - Each ShaderState will bind one shader program - Make Material a record - Inline Renderable and move InstancedModel.Layer to DrawCall
This commit is contained in:
parent
5dd72a4ba7
commit
cdfddba35a
9 changed files with 185 additions and 203 deletions
|
@ -4,26 +4,6 @@ import com.jozufozu.flywheel.core.source.FileResolution;
|
|||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class Material {
|
||||
protected final RenderType renderType;
|
||||
protected final FileResolution vertexShader;
|
||||
protected final FileResolution fragmentShader;
|
||||
public record Material(RenderType renderType, FileResolution vertexShader, FileResolution fragmentShader) {
|
||||
|
||||
public Material(RenderType renderType, FileResolution vertexShader, FileResolution fragmentShader) {
|
||||
this.renderType = renderType;
|
||||
this.vertexShader = vertexShader;
|
||||
this.fragmentShader = fragmentShader;
|
||||
}
|
||||
|
||||
public RenderType getRenderType() {
|
||||
return renderType;
|
||||
}
|
||||
|
||||
public FileResolution getVertexShader() {
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
public FileResolution getFragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
|
||||
public class DrawCall {
|
||||
|
||||
final Material material;
|
||||
private final GPUInstancer<?> instancer;
|
||||
MeshPool.BufferedMesh bufferedMesh;
|
||||
GlVertexArray vao;
|
||||
|
||||
DrawCall(GPUInstancer<?> instancer, Material material, Mesh mesh) {
|
||||
this.instancer = instancer;
|
||||
this.material = material;
|
||||
this.vao = new GlVertexArray();
|
||||
this.bufferedMesh = MeshPool.getInstance()
|
||||
.alloc(mesh);
|
||||
this.instancer.attributeBaseIndex = this.bufferedMesh.getAttributeCount();
|
||||
this.vao.enableArrays(this.bufferedMesh.getAttributeCount() + instancer.instanceFormat.getAttributeCount());
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public VertexType getVertexType() {
|
||||
return bufferedMesh.getVertexType();
|
||||
}
|
||||
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
||||
try (var ignored = GlStateTracker.getRestoreState()) {
|
||||
|
||||
this.instancer.renderSetup(vao);
|
||||
|
||||
if (this.instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(vao, this.instancer.glInstanceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean shouldRemove() {
|
||||
return invalid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only {@code true} if the InstancedModel has been destroyed.
|
||||
*/
|
||||
private boolean invalid() {
|
||||
return this.instancer.vbo == null || bufferedMesh == null || vao == null;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (invalid()) return;
|
||||
|
||||
vao.delete();
|
||||
bufferedMesh.delete();
|
||||
|
||||
vao = null;
|
||||
bufferedMesh = null;
|
||||
}
|
||||
}
|
|
@ -1,15 +1,9 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.Instancer;
|
||||
import com.jozufozu.flywheel.api.InstancerFactory;
|
||||
|
@ -26,13 +20,11 @@ public class GPUInstancerFactory<D extends InstancedPart> implements InstancerFa
|
|||
|
||||
protected final Map<ModelSupplier, InstancedModel<D>> models = new HashMap<>();
|
||||
protected final StructType<D> type;
|
||||
private final Consumer<InstancedModel<D>> creationListener;
|
||||
|
||||
protected final List<InstancedModel<D>> uninitialized = new ArrayList<>();
|
||||
|
||||
private final ListMultimap<RenderType, Renderable> renderLists = ArrayListMultimap.create();
|
||||
|
||||
public GPUInstancerFactory(StructType<D> type) {
|
||||
public GPUInstancerFactory(StructType<D> type, Consumer<InstancedModel<D>> creationListener) {
|
||||
this.type = type;
|
||||
this.creationListener = creationListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,7 +50,6 @@ public class GPUInstancerFactory<D extends InstancedPart> implements InstancerFa
|
|||
public void delete() {
|
||||
models.values().forEach(InstancedModel::delete);
|
||||
models.clear();
|
||||
renderLists.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,35 +62,9 @@ public class GPUInstancerFactory<D extends InstancedPart> implements InstancerFa
|
|||
.forEach(GPUInstancer::clear);
|
||||
}
|
||||
|
||||
public void init() {
|
||||
for (var instanced : uninitialized) {
|
||||
instanced.init();
|
||||
|
||||
for (Renderable renderable : instanced.getLayers()) {
|
||||
renderLists.put(renderable.getMaterial()
|
||||
.getRenderType(), renderable);
|
||||
}
|
||||
}
|
||||
uninitialized.clear();
|
||||
}
|
||||
|
||||
private InstancedModel<D> createInstancer(ModelSupplier model) {
|
||||
var instancer = new InstancedModel<>(type, model);
|
||||
uninitialized.add(instancer);
|
||||
this.creationListener.accept(instancer);
|
||||
return instancer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the RenderTypes that this InstancerFactory will render to the given set.
|
||||
* @param layersToProcess The set of RenderTypes that the InstancingEngine will process.
|
||||
*/
|
||||
public void gatherLayers(Set<RenderType> layersToProcess) {
|
||||
layersToProcess.addAll(renderLists.keySet());
|
||||
}
|
||||
|
||||
public List<Renderable> getRenderList(RenderType type) {
|
||||
var out = renderLists.get(type);
|
||||
out.removeIf(Renderable::shouldRemove);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,108 +1,35 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.model.MeshPool;
|
||||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
|
||||
public class InstancedModel<D extends InstancedPart> {
|
||||
|
||||
public final GPUInstancer<D> instancer;
|
||||
public final ModelSupplier model;
|
||||
private List<Layer> layers;
|
||||
private final StructType<D> type;
|
||||
private List<DrawCall> layers;
|
||||
|
||||
public InstancedModel(StructType<D> type, ModelSupplier model) {
|
||||
this.model = model;
|
||||
this.instancer = new GPUInstancer<>(this, type);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
public void init(RenderLists renderLists) {
|
||||
instancer.init();
|
||||
|
||||
buildLayers();
|
||||
}
|
||||
|
||||
public List<? extends Renderable> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
private void buildLayers() {
|
||||
layers = model.get()
|
||||
.entrySet()
|
||||
.stream()
|
||||
.map(entry -> new Layer(entry.getKey(), entry.getValue()))
|
||||
.map(entry -> new DrawCall(instancer, entry.getKey(), entry.getValue()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private class Layer implements Renderable {
|
||||
|
||||
final Material material;
|
||||
MeshPool.BufferedMesh bufferedMesh;
|
||||
GlVertexArray vao;
|
||||
|
||||
private Layer(Material material, Mesh mesh) {
|
||||
this.material = material;
|
||||
vao = new GlVertexArray();
|
||||
bufferedMesh = MeshPool.getInstance()
|
||||
.alloc(mesh);
|
||||
instancer.attributeBaseIndex = bufferedMesh.getAttributeCount();
|
||||
vao.enableArrays(bufferedMesh.getAttributeCount() + instancer.instanceFormat.getAttributeCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VertexType getVertexType() {
|
||||
return bufferedMesh.getVertexType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
if (invalid()) return;
|
||||
|
||||
try (var ignored = GlStateTracker.getRestoreState()) {
|
||||
|
||||
instancer.renderSetup(vao);
|
||||
|
||||
if (instancer.glInstanceCount > 0) {
|
||||
bufferedMesh.drawInstances(vao, instancer.glInstanceCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRemove() {
|
||||
return invalid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Only {@code true} if the InstancedModel has been destroyed.
|
||||
*/
|
||||
private boolean invalid() {
|
||||
return instancer.vbo == null || bufferedMesh == null || vao == null;
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (invalid()) return;
|
||||
|
||||
vao.delete();
|
||||
bufferedMesh.delete();
|
||||
|
||||
vao = null;
|
||||
bufferedMesh = null;
|
||||
for (DrawCall layer : layers) {
|
||||
renderLists.add(new ShaderState(layer.material, layer.getVertexType(), type), layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@ package com.jozufozu.flywheel.backend.instancing.instancing;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.jozufozu.flywheel.api.InstancedPart;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
|
@ -34,6 +34,7 @@ import com.jozufozu.flywheel.core.crumbling.CrumblingProgram;
|
|||
import com.jozufozu.flywheel.core.model.Mesh;
|
||||
import com.jozufozu.flywheel.core.model.ModelSupplier;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.core.source.FileResolution;
|
||||
import com.jozufozu.flywheel.core.vertex.Formats;
|
||||
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
|
@ -65,7 +66,8 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
|
||||
protected final Map<StructType<? extends InstancedPart>, GPUInstancerFactory<?>> factories = new HashMap<>();
|
||||
|
||||
protected final Set<RenderType> layersToProcess = new HashSet<>();
|
||||
protected final List<InstancedModel<?>> uninitializedModels = new ArrayList<>();
|
||||
protected final RenderLists renderLists = new RenderLists();
|
||||
|
||||
private final WeakHashSet<OriginShiftListener> listeners;
|
||||
private int vertexCount;
|
||||
|
@ -81,7 +83,12 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
@NotNull
|
||||
@Override
|
||||
public <D extends InstancedPart> GPUInstancerFactory<D> factory(StructType<D> type) {
|
||||
return (GPUInstancerFactory<D>) factories.computeIfAbsent(type, GPUInstancerFactory::new);
|
||||
return (GPUInstancerFactory<D>) factories.computeIfAbsent(type, this::createFactory);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <D extends InstancedPart> GPUInstancerFactory<D> createFactory(StructType<D> type) {
|
||||
return new GPUInstancerFactory<>(type, uninitializedModels::add);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,15 +101,14 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
var vp = context.viewProjection().copy();
|
||||
vp.multiplyWithTranslation((float) -camX, (float) -camY, (float) -camZ);
|
||||
|
||||
for (RenderType renderType : layersToProcess) {
|
||||
for (RenderType renderType : renderLists.drainLayers()) {
|
||||
render(renderType, camX, camY, camZ, vp, context.level());
|
||||
}
|
||||
layersToProcess.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderSpecificType(TaskEngine taskEngine, RenderContext context, RenderType type) {
|
||||
if (!layersToProcess.remove(type)) {
|
||||
if (!renderLists.process(type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -121,37 +127,50 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
vertexCount = 0;
|
||||
instanceCount = 0;
|
||||
|
||||
var multimap = renderLists.get(type);
|
||||
|
||||
if (multimap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
render(type, multimap, camX, camY, camZ, viewProjection, level);
|
||||
}
|
||||
|
||||
protected void render(RenderType type, ListMultimap<ShaderState, DrawCall> multimap, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
|
||||
type.setupRenderState();
|
||||
Textures.bindActiveTextures();
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
|
||||
for (var entry : factories.entrySet()) {
|
||||
var instanceType = entry.getKey();
|
||||
var factory = entry.getValue();
|
||||
for (var entry : Multimaps.asMap(multimap).entrySet()) {
|
||||
var shader = entry.getKey();
|
||||
var drawCalls = entry.getValue();
|
||||
|
||||
var toRender = factory.getRenderList(type);
|
||||
drawCalls.removeIf(DrawCall::shouldRemove);
|
||||
|
||||
if (toRender.isEmpty()) {
|
||||
if (drawCalls.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Renderable renderable : toRender) {
|
||||
setup(instanceType, renderable.getMaterial(), coreShaderInfo, camX, camY, camZ, viewProjection, level, renderable.getVertexType());
|
||||
setup(shader, coreShaderInfo, camX, camY, camZ, viewProjection, level);
|
||||
|
||||
renderable.render();
|
||||
for (var drawCall : drawCalls) {
|
||||
drawCall.render();
|
||||
}
|
||||
|
||||
instanceCount += factory.getInstanceCount();
|
||||
vertexCount += factory.getVertexCount();
|
||||
}
|
||||
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
protected P setup(StructType<?> instanceType, Material material, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level, VertexType vertexType) {
|
||||
protected P setup(ShaderState desc, CoreShaderInfo coreShaderInfo, double camX, double camY, double camZ, Matrix4f viewProjection, ClientLevel level) {
|
||||
|
||||
P program = context.getProgram(new ProgramCompiler.Context(vertexType, instanceType.getInstanceShader(),
|
||||
material.getVertexShader(), material.getFragmentShader(), coreShaderInfo.getAdjustedAlphaDiscard(),
|
||||
VertexType vertexType = desc.vertex();
|
||||
FileResolution instanceShader = desc.instance()
|
||||
.getInstanceShader();
|
||||
Material material = desc.material();
|
||||
|
||||
P program = context.getProgram(new ProgramCompiler.Context(vertexType, instanceShader,
|
||||
material.vertexShader(), material.fragmentShader(), coreShaderInfo.getAdjustedAlphaDiscard(),
|
||||
coreShaderInfo.fogType(), GameStateRegistry.takeSnapshot()));
|
||||
|
||||
program.bind();
|
||||
|
@ -190,12 +209,12 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
public void beginFrame(Camera info) {
|
||||
checkOriginDistance(info);
|
||||
|
||||
|
||||
for (GPUInstancerFactory<?> factory : factories.values()) {
|
||||
factory.init();
|
||||
|
||||
factory.gatherLayers(layersToProcess);
|
||||
for (var factory : uninitializedModels) {
|
||||
factory.init(renderLists);
|
||||
}
|
||||
uninitializedModels.clear();
|
||||
|
||||
renderLists.prepare();
|
||||
|
||||
MeshPool.getInstance()
|
||||
.flush();
|
||||
|
@ -279,13 +298,13 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
continue;
|
||||
}
|
||||
|
||||
material.getRenderType().setupRenderState();
|
||||
material.renderType().setupRenderState();
|
||||
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
|
||||
|
||||
CrumblingProgram program = Contexts.CRUMBLING.getProgram(new ProgramCompiler.Context(Formats.POS_TEX_NORMAL,
|
||||
structType.getInstanceShader(), material.getVertexShader(), material.getFragmentShader(),
|
||||
structType.getInstanceShader(), material.vertexShader(), material.fragmentShader(),
|
||||
coreShaderInfo.getAdjustedAlphaDiscard(), coreShaderInfo.fogType(),
|
||||
GameStateRegistry.takeSnapshot()));
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class RenderLists {
|
||||
|
||||
private Map<RenderType, ListMultimap<ShaderState, DrawCall>> renderLists = new HashMap<>();
|
||||
public final Set<RenderType> layersToProcess = new HashSet<>();
|
||||
|
||||
public ListMultimap<ShaderState, DrawCall> get(RenderType type) {
|
||||
return renderLists.computeIfAbsent(type, k -> ArrayListMultimap.create());
|
||||
}
|
||||
|
||||
public void add(ShaderState shaderState, DrawCall layer) {
|
||||
RenderType renderType = shaderState.material()
|
||||
.renderType();
|
||||
|
||||
get(renderType).put(shaderState, layer);
|
||||
}
|
||||
|
||||
public void prepare() {
|
||||
layersToProcess.clear();
|
||||
|
||||
layersToProcess.addAll(renderLists.keySet());
|
||||
}
|
||||
|
||||
public Iterable<? extends RenderType> drainLayers() {
|
||||
var out = new HashSet<>(layersToProcess);
|
||||
layersToProcess.clear();
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and mark a layer as processed.
|
||||
* @param type The layer to check.
|
||||
* @return {@code true} if the layer should be processed.
|
||||
*/
|
||||
public boolean process(RenderType type) {
|
||||
return layersToProcess.remove(type);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,8 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
|
||||
public interface Renderable {
|
||||
|
||||
void render();
|
||||
|
||||
boolean shouldRemove();
|
||||
|
||||
Material getMaterial();
|
||||
|
||||
VertexType getVertexType();
|
||||
public record ShaderState(Material material, VertexType vertex, StructType<?> instance) {
|
||||
}
|
|
@ -9,14 +9,11 @@ import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
|||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.Renderable;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.CoreShaderInfoMap.CoreShaderInfo;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
|
@ -168,30 +165,13 @@ public class CrumblingRenderer {
|
|||
return;
|
||||
}
|
||||
|
||||
currentLayer.setupRenderState();
|
||||
Textures.bindActiveTextures();
|
||||
CoreShaderInfo coreShaderInfo = CoreShaderInfo.get();
|
||||
var multimap = renderLists.get(type);
|
||||
|
||||
for (var entry : factories.entrySet()) {
|
||||
var instanceType = entry.getKey();
|
||||
var factory = entry.getValue();
|
||||
|
||||
var toRender = factory.getRenderList(type);
|
||||
|
||||
if (toRender.isEmpty()) {
|
||||
continue;
|
||||
if (multimap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var renderable : toRender) {
|
||||
|
||||
setup(instanceType, renderable.getMaterial(), coreShaderInfo, camX, camY, camZ, viewProjection, level, renderable.getVertexType());
|
||||
|
||||
renderable.render();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
currentLayer.clearRenderState();
|
||||
render(currentLayer, multimap, camX, camY, camZ, viewProjection, level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,8 +37,9 @@ import net.minecraft.world.level.block.state.properties.ChestType;
|
|||
|
||||
public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends BlockEntityInstance<T> implements DynamicInstance {
|
||||
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> LID = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createLidModel(type, mat.sprite()), new com.jozufozu.flywheel.api.material.Material(Sheets.chestSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT)));
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> BASE = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createBaseModel(type, mat.sprite()), new com.jozufozu.flywheel.api.material.Material(Sheets.chestSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT)));
|
||||
private static final com.jozufozu.flywheel.api.material.Material CHEST_MATERIAL = new com.jozufozu.flywheel.api.material.Material(Sheets.chestSheet(), MaterialShaders.SHADED_VERTEX, MaterialShaders.DEFAULT_FRAGMENT);
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> LID = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createLidModel(type, mat.sprite()), CHEST_MATERIAL));
|
||||
private static final BiFunction<ChestType, Material, BasicModelSupplier> BASE = Util.memoize((type, mat) -> new BasicModelSupplier(() -> createBaseModel(type, mat.sprite()), CHEST_MATERIAL));
|
||||
|
||||
private final OrientedPart body;
|
||||
private final TransformedPart lid;
|
||||
|
|
Loading…
Reference in a new issue