Material refactor pt 2

- Inline all the things
 - Now MaterialManager -> Material -> Instancer
 - ModelSuppliers store RenderType
 - Currently broken, it only renders chunk layers so vanilla instances are invisible
This commit is contained in:
Jozufozu 2022-04-11 15:11:39 -07:00
parent ec92fef445
commit ccbce86a69
25 changed files with 264 additions and 311 deletions

View file

@ -9,6 +9,7 @@ import com.jozufozu.flywheel.config.BackendTypeArgument;
import com.jozufozu.flywheel.config.FlwCommands;
import com.jozufozu.flywheel.config.FlwConfig;
import com.jozufozu.flywheel.core.Contexts;
import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.StitchedSprite;
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
@ -70,6 +71,7 @@ public class Flywheel {
forgeEventBus.addListener(FlwCommands::registerClientCommands);
forgeEventBus.<ReloadRenderersEvent>addListener(ProgramCompiler::invalidateAll);
forgeEventBus.addListener(Models::onReload);
modEventBus.addListener(Contexts::flwInit);
modEventBus.addListener(PartialModel::onModelRegistry);

View file

@ -1,14 +1,6 @@
package com.jozufozu.flywheel.api;
import java.util.function.Supplier;
import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import com.jozufozu.flywheel.core.ModelSupplier;
public interface Material<D extends InstanceData> {
@ -20,19 +12,4 @@ public interface Material<D extends InstanceData> {
*/
Instancer<D> model(ModelSupplier modelKey);
default Instancer<D> getModel(PartialModel partial) {
return model(Models.partial(partial));
}
default Instancer<D> getModel(PartialModel partial, Direction dir) {
return model(Models.partial(partial, dir, () -> ModelUtil.rotateToFace(dir)));
}
default Instancer<D> getModel(PartialModel partial, Direction dir, Supplier<PoseStack> modelTransform) {
return model(Models.partial(partial, dir, modelTransform));
}
default Instancer<D> getModel(BlockState toRender) {
return model(Models.block(toRender));
}
}

View file

@ -1,42 +1,15 @@
package com.jozufozu.flywheel.api;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Vec3i;
public interface MaterialManager {
/**
* Get a material group that will render in the given layer with the given state.
*
* @param layer The {@link RenderLayer} you want to draw in.
* @param type The {@link RenderType} you need to draw with.
* @return A material group whose children will
*/
MaterialGroup state(RenderLayer layer, RenderType type);
<D extends InstanceData> InstancedMaterial<D> material(StructType<D> type);
Vec3i getOriginCoordinate();
default MaterialGroup solid(RenderType state) {
return state(RenderLayer.SOLID, state);
}
default MaterialGroup cutout(RenderType state) {
return state(RenderLayer.CUTOUT, state);
}
default MaterialGroup transparent(RenderType state) {
return state(RenderLayer.TRANSPARENT, state);
}
default MaterialGroup defaultSolid() {
return solid(RenderType.solid());
}
default MaterialGroup defaultCutout() {
return cutout(RenderType.cutout());
}
default MaterialGroup defaultTransparent() {
return transparent(RenderType.translucent());
}
}

View file

@ -1,11 +0,0 @@
package com.jozufozu.flywheel.api;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.core.model.Model;
public interface ModelSupplier {
@Nonnull
Model get();
}

View file

@ -6,17 +6,17 @@ import java.util.function.Supplier;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.core.ModelSupplier;
public abstract class AbstractInstancer<D extends InstanceData> implements Instancer<D> {
protected final Supplier<D> factory;
protected final Model modelData;
protected final ModelSupplier modelData;
protected final ArrayList<D> data = new ArrayList<>();
protected boolean anyToRemove;
protected AbstractInstancer(Supplier<D> factory, Model modelData) {
protected AbstractInstancer(Supplier<D> factory, ModelSupplier modelData) {
this.factory = factory;
this.modelData = modelData;
}
@ -59,7 +59,7 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
}
public int getModelVertexCount() {
return modelData.vertexCount();
return 0;
}
public int getInstanceCount() {

View file

@ -0,0 +1,6 @@
package com.jozufozu.flywheel.backend.instancing;
@FunctionalInterface
public interface Renderable {
void draw();
}

View file

@ -2,14 +2,12 @@ package com.jozufozu.flywheel.backend.instancing.batching;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
@ -26,7 +24,7 @@ public class BatchedMaterial<D extends InstanceData> implements Material<D> {
@Override
public Instancer<D> model(ModelSupplier modelKey) {
return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type, k.get()));
return models.computeIfAbsent(modelKey, k -> new CPUInstancer<>(type, k));
}
public void setupAndRenderInto(PoseStack stack, VertexConsumer buffer) {

View file

@ -5,11 +5,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.RenderLayer;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.instancing.BatchDrawingTracker;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.FlwUtil;
import com.mojang.blaze3d.platform.Lighting;
@ -33,8 +35,8 @@ public class BatchingEngine implements Engine {
}
@Override
public MaterialGroup state(RenderLayer layer, RenderType type) {
return layers.get(layer).computeIfAbsent(type, BatchedMaterialGroup::new);
public <D extends InstanceData> InstancedMaterial<D> material(StructType<D> type) {
return null;
}
@Override

View file

@ -5,7 +5,7 @@ import com.jozufozu.flywheel.api.struct.Batched;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.model.DirectVertexConsumer;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.jozufozu.flywheel.core.model.ModelTransformer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
@ -16,11 +16,11 @@ public class CPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
final ModelTransformer sbb;
public CPUInstancer(Batched<D> type, Model modelData) {
public CPUInstancer(Batched<D> type, ModelSupplier modelData) {
super(type::create, modelData);
batchingType = type;
sbb = new ModelTransformer(modelData);
sbb = new ModelTransformer(modelData.get());
}
void submitTasks(PoseStack stack, TaskEngine pool, DirectVertexConsumer consumer) {

View file

@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.instancing.blockentity;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.RenderLayer;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.AbstractInstance;
@ -11,6 +12,7 @@ import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.util.box.GridAlignedBB;
import com.jozufozu.flywheel.util.box.ImmutableBox;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
@ -77,11 +79,11 @@ public abstract class BlockEntityInstance<T extends BlockEntity> extends Abstrac
}
protected Material<ModelData> getTransformMaterial() {
return materialManager.defaultCutout().material(Materials.TRANSFORMED);
return materialManager.material(Materials.TRANSFORMED);
}
protected Material<OrientedData> getOrientedMaterial() {
return materialManager.defaultCutout().material(Materials.ORIENTED);
return materialManager.material(Materials.ORIENTED);
}
@Override

View file

@ -1,7 +1,10 @@
package com.jozufozu.flywheel.backend.instancing.instancing;
import java.util.Map;
import org.lwjgl.system.MemoryUtil;
import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Instanced;
@ -12,10 +15,13 @@ import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
import com.jozufozu.flywheel.backend.gl.buffer.MappedBuffer;
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.backend.instancing.AbstractInstancer;
import com.jozufozu.flywheel.backend.instancing.Renderable;
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.model.Model;
import net.minecraft.client.renderer.RenderType;
public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
@ -31,7 +37,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
protected boolean anyToUpdate;
public GPUInstancer(Instanced<D> type, Model model) {
public GPUInstancer(Instanced<D> type, ModelSupplier model) {
super(type::create, model);
this.instanceFormat = type.getLayout();
instancedType = type;
@ -61,14 +67,17 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
return deleted || model == null;
}
public void init(ModelAllocator modelAllocator) {
if (isInitialized()) return;
public Map<RenderType, Renderable> init(ModelAllocator modelAllocator) {
if (isInitialized()) return ImmutableMap.of();
initialized = true;
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16);
vao = new GlVertexArray();
model = modelAllocator.alloc(modelData, arenaModel -> {
model = modelAllocator.alloc(modelData.get(), arenaModel -> {
vao.bind();
arenaModel.setupState(vao);
@ -77,8 +86,7 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
vao.bind();
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
instanceVBO = GlBuffer.requestPersistent(GlBufferType.ARRAY_BUFFER);
instanceVBO.setGrowthMargin(instanceFormat.getStride() * 16);
return ImmutableMap.of(modelData.getRenderType(), this::render);
}
public boolean isInitialized() {

View file

@ -5,14 +5,18 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.Instancer;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.backend.instancing.Renderable;
import com.jozufozu.flywheel.backend.model.ModelAllocator;
import com.jozufozu.flywheel.core.ModelSupplier;
import net.minecraft.client.renderer.RenderType;
/**
* A collection of Instancers that all have the same format.
@ -22,16 +26,24 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
protected final Map<ModelSupplier, GPUInstancer<D>> models = new HashMap<>();
protected final Instanced<D> type;
public final Map<RenderType, List<Renderable>> renderables = new HashMap<>();
protected final List<GPUInstancer<D>> uninitialized = new ArrayList<>();
public InstancedMaterial(Instanced<D> type) {
this.type = type;
}
@Nullable
public List<Renderable> getRenderables(RenderType type) {
return renderables.get(type);
}
@Override
public Instancer<D> model(ModelSupplier modelKey) {
return models.computeIfAbsent(modelKey, k -> {
GPUInstancer<D> instancer = new GPUInstancer<>(type, k.get());
GPUInstancer<D> instancer = new GPUInstancer<>(type, modelKey);
uninitialized.add(instancer);
return instancer;
});
@ -67,4 +79,18 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
public Collection<GPUInstancer<D>> getAllInstancers() {
return models.values();
}
void init(ModelAllocator allocator) {
for (GPUInstancer<?> instancer : uninitialized) {
instancer.init(allocator)
.forEach(this::addRenderable);
}
uninitialized.clear();
}
private void addRenderable(RenderType type, Renderable renderable) {
this.renderables.computeIfAbsent(type, k -> new ArrayList<>())
.add(renderable);
}
}

View file

@ -26,127 +26,24 @@ import net.minecraft.client.renderer.RenderType;
* The children of a material group will all be rendered at the same time.
* No guarantees are made about the order of draw calls.
*/
public class InstancedMaterialGroup<P extends WorldProgram> implements MaterialGroup {
public class InstancedMaterialGroup<P extends WorldProgram> {
protected final InstancingEngine<P> owner;
protected final RenderType type;
private final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
private ModelAllocator allocator;
private int vertexCount;
private int instanceCount;
public InstancedMaterialGroup(InstancingEngine<P> owner, RenderType type) {
this.owner = owner;
this.type = type;
}
@SuppressWarnings("unchecked")
@Override
public <D extends InstanceData> InstancedMaterial<D> material(StructType<D> type) {
if (type instanceof Instanced<D> instanced) {
return (InstancedMaterial<D>) materials.computeIfAbsent(instanced, InstancedMaterial::new);
} else {
throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing.");
}
}
/**
* Get the number of instances drawn last frame.
* @return The instance count.
*/
public int getInstanceCount() {
return instanceCount;
}
/**
* Get the number of vertices drawn last frame.
* @return The vertex count.
*/
public int getVertexCount() {
return vertexCount;
}
public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
type.setupRenderState();
Textures.bindActiveTextures();
renderAll(viewProjection, camX, camY, camZ, layer);
//renderAll(viewProjection, camX, camY, camZ, layer);
type.clearRenderState();
}
protected void renderAll(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
initializeInstancers();
vertexCount = 0;
instanceCount = 0;
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
InstancedMaterial<?> material = entry.getValue();
if (material.nothingToRender()) continue;
P program = owner.context.getProgram(ProgramContext.create(entry.getKey()
.getProgramSpec(), Formats.POS_TEX_NORMAL, layer));
program.bind();
program.uploadViewProjection(viewProjection);
program.uploadCameraPos(camX, camY, camZ);
setup(program);
for (GPUInstancer<?> instancer : material.getAllInstancers()) {
instancer.render();
vertexCount += instancer.getVertexCount();
instanceCount += instancer.getInstanceCount();
}
}
}
private void initializeInstancers() {
ModelAllocator allocator = getModelAllocator();
// initialize all uninitialized instancers...
for (InstancedMaterial<?> material : materials.values()) {
for (GPUInstancer<?> instancer : material.uninitialized) {
instancer.init(allocator);
}
material.uninitialized.clear();
}
if (allocator instanceof ModelPool pool) {
// ...and then flush the model arena in case anything was marked for upload
pool.flush();
}
}
protected void setup(P program) {
}
public void clear() {
materials.values().forEach(InstancedMaterial::clear);
}
public void delete() {
materials.values()
.forEach(InstancedMaterial::delete);
materials.clear();
}
private ModelAllocator getModelAllocator() {
if (allocator == null) {
allocator = createAllocator();
}
return this.allocator;
}
private static ModelAllocator createAllocator() {
if (GlCompat.getInstance()
.onAMDWindows()) {
return FallbackAllocator.INSTANCE;
} else {
return new ModelPool(Formats.POS_TEX_NORMAL);
}
}
}

View file

@ -1,21 +1,27 @@
package com.jozufozu.flywheel.backend.instancing.instancing;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import javax.annotation.Nullable;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.api.MaterialGroup;
import com.jozufozu.flywheel.api.RenderLayer;
import com.jozufozu.flywheel.api.InstanceData;
import com.jozufozu.flywheel.api.struct.Instanced;
import com.jozufozu.flywheel.api.struct.StructType;
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
import com.jozufozu.flywheel.backend.instancing.Engine;
import com.jozufozu.flywheel.backend.instancing.Renderable;
import com.jozufozu.flywheel.backend.instancing.TaskEngine;
import com.jozufozu.flywheel.backend.model.FallbackAllocator;
import com.jozufozu.flywheel.backend.model.ModelAllocator;
import com.jozufozu.flywheel.backend.model.ModelPool;
import com.jozufozu.flywheel.core.Formats;
import com.jozufozu.flywheel.core.compile.ProgramCompiler;
import com.jozufozu.flywheel.core.compile.ProgramContext;
import com.jozufozu.flywheel.core.shader.WorldProgram;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.jozufozu.flywheel.util.FlwUtil;
import com.jozufozu.flywheel.util.Textures;
import com.jozufozu.flywheel.util.WeakHashSet;
import com.mojang.math.Matrix4f;
@ -34,10 +40,13 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
protected final ProgramCompiler<P> context;
protected final GroupFactory<P> groupFactory;
protected final boolean ignoreOriginCoordinate;
private ModelAllocator allocator;
protected final Map<RenderLayer, Map<RenderType, InstancedMaterialGroup<P>>> layers;
private final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
private final WeakHashSet<OriginShiftListener> listeners;
private int vertexCount;
private int instanceCount;
public static <P extends WorldProgram> Builder<P> builder(ProgramCompiler<P> context) {
return new Builder<>(context);
@ -49,30 +58,24 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
this.listeners = new WeakHashSet<>();
this.groupFactory = groupFactory;
}
this.layers = new EnumMap<>(RenderLayer.class);
for (RenderLayer value : RenderLayer.values()) {
layers.put(value, new HashMap<>());
@SuppressWarnings("unchecked")
@Nonnull
@Override
public <D extends InstanceData> InstancedMaterial<D> material(StructType<D> type) {
if (type instanceof Instanced<D> instanced) {
return (InstancedMaterial<D>) materials.computeIfAbsent(instanced, InstancedMaterial::new);
} else {
throw new ClassCastException("Cannot use type '" + type + "' with GPU instancing.");
}
}
/**
* Get a material group that will render in the given layer with the given type.
*
* @param layer
* @param type The {@link RenderType} you need to draw with.
* @return A material group whose children will
*/
@Override
public MaterialGroup state(RenderLayer layer, RenderType type) {
return layers.get(layer).computeIfAbsent(type, t -> groupFactory.create(this, t));
}
/**
* Render every model for every material.
*/
@Override
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
RenderType type = event.getType();
double camX;
double camY;
double camZ;
@ -91,28 +94,46 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
viewProjection = event.viewProjection;
}
getGroupsToRender(event.getLayer()).forEach(group -> group.render(viewProjection, camX, camY, camZ, event.getLayer()));
vertexCount = 0;
instanceCount = 0;
type.setupRenderState();
Textures.bindActiveTextures();
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
List<Renderable> renderables = entry.getValue()
.getRenderables(type);
if (renderables == null || renderables.isEmpty()) {
continue;
}
P program = context.getProgram(ProgramContext.create(entry.getKey()
.getProgramSpec(), Formats.POS_TEX_NORMAL, event.layer));
program.bind();
program.uploadViewProjection(viewProjection);
program.uploadCameraPos(camX, camY, camZ);
//setup(program);
for (Renderable renderable : renderables) {
renderable.draw();
}
}
type.clearRenderState();
}
private Stream<InstancedMaterialGroup<P>> getGroupsToRender(@Nullable RenderLayer layer) {
// layer is null when this is called from CrumblingRenderer
if (layer != null) {
return layers.get(layer)
.values()
.stream();
} else {
return layers.values()
.stream()
.flatMap(FlwUtil::mapValues);
}
public void clearAll() {
materials.values().forEach(InstancedMaterial::clear);
}
@Override
public void delete() {
for (Map<RenderType, InstancedMaterialGroup<P>> groups : layers.values()) {
materials.values()
.forEach(InstancedMaterial::delete);
groups.values().forEach(InstancedMaterialGroup::delete);
}
materials.clear();
}
@Override
@ -143,22 +164,48 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
originCoordinate = new BlockPos(cX, cY, cZ);
for (Map<RenderType, InstancedMaterialGroup<P>> groups : layers.values()) {
groups.values().forEach(InstancedMaterialGroup::clear);
}
materials.values().forEach(InstancedMaterial::clear);
listeners.forEach(OriginShiftListener::onOriginShift);
}
ModelAllocator allocator = getModelAllocator();
for (InstancedMaterial<?> material : materials.values()) {
material.init(allocator);
}
if (allocator instanceof ModelPool pool) {
// ...and then flush the model arena in case anything was marked for upload
pool.flush();
}
}
@Override
public void addDebugInfo(List<String> info) {
info.add("GL33 Instanced Arrays");
info.add("Instances: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getInstanceCount).sum());
info.add("Vertices: " + getGroupsToRender(null).mapToInt(InstancedMaterialGroup::getVertexCount).sum());
info.add("Instances: " + instanceCount);
info.add("Vertices: " + vertexCount);
info.add("Origin: " + originCoordinate.getX() + ", " + originCoordinate.getY() + ", " + originCoordinate.getZ());
}
private ModelAllocator getModelAllocator() {
if (allocator == null) {
allocator = createAllocator();
}
return this.allocator;
}
private static ModelAllocator createAllocator() {
if (GlCompat.getInstance()
.onAMDWindows()) {
return FallbackAllocator.INSTANCE;
} else {
return new ModelPool(Formats.POS_TEX_NORMAL);
}
}
@FunctionalInterface
public interface OriginShiftListener {
void onOriginShift();

View file

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL43;
import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.api.vertex.VertexType;

View file

@ -0,0 +1,44 @@
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 {
private final Lazy<Model> supplier;
private RenderType renderType;
public ModelSupplier(NonNullSupplier<Model> supplier) {
this(supplier, RenderType.solid());
}
public ModelSupplier(NonNullSupplier<Model> supplier, RenderType renderType) {
this.supplier = Lazy.of(supplier);
this.renderType = renderType;
}
public ModelSupplier setCutout() {
return setRenderType(RenderType.cutoutMipped());
}
public ModelSupplier setRenderType(@Nonnull RenderType renderType) {
this.renderType = renderType;
return this;
}
@Nonnull
public Model get() {
return supplier.get();
}
@Nonnull
public RenderType getRenderType() {
return renderType;
}
}

View file

@ -2,12 +2,12 @@ package com.jozufozu.flywheel.core;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.core.model.BlockModel;
import com.jozufozu.flywheel.core.model.ModelUtil;
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
import com.jozufozu.flywheel.util.Pair;
import com.mojang.blaze3d.vertex.PoseStack;
@ -19,19 +19,29 @@ import net.minecraft.world.level.block.state.BlockState;
public class Models {
public static ModelSupplier block(BlockState state) {
return BLOCK_STATE.apply(state);
return BLOCK_STATE.computeIfAbsent(state, it -> new ModelSupplier(() -> new BlockModel(it)));
}
public static ModelSupplier partial(PartialModel partial) {
return PARTIAL.apply(partial);
return PARTIAL.computeIfAbsent(partial, it -> new ModelSupplier(() -> new BlockModel(it.get(), Blocks.AIR.defaultBlockState())));
}
public static ModelSupplier partial(PartialModel partial, Direction dir) {
return partial(partial, dir, () -> ModelUtil.rotateToFace(dir));
}
public static ModelSupplier partial(PartialModel partial, Direction dir, Supplier<PoseStack> modelTransform) {
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new SimpleModelSupplier(() -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState(), modelTransform.get())));
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new ModelSupplier(() -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState(), modelTransform.get())));
}
private static final Function<BlockState, ModelSupplier> BLOCK_STATE = Util.memoize(it -> new SimpleModelSupplier(() -> new BlockModel(it)));
private static final Function<PartialModel, ModelSupplier> PARTIAL = Util.memoize(it -> new SimpleModelSupplier(() -> new BlockModel(it.get(), Blocks.AIR.defaultBlockState())));
public static void onReload(ReloadRenderersEvent ignored) {
BLOCK_STATE.clear();
PARTIAL.clear();
PARTIAL_DIR.clear();
}
private static final Map<BlockState, ModelSupplier> BLOCK_STATE = new HashMap<>();
private static final Map<PartialModel, ModelSupplier> PARTIAL = new HashMap<>();
private static final Map<Pair<Direction, PartialModel>, ModelSupplier> PARTIAL_DIR = new HashMap<>();
}

View file

@ -1,25 +0,0 @@
package com.jozufozu.flywheel.core;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.core.model.Model;
import com.jozufozu.flywheel.util.Lazy;
import com.jozufozu.flywheel.util.NonNullSupplier;
public class SimpleModelSupplier implements ModelSupplier {
private final Lazy<Model> supplier;
public SimpleModelSupplier(NonNullSupplier<Model> supplier) {
this.supplier = Lazy.of(supplier);
}
@Nonnull
@Override
public Model get() {
return supplier.get();
}
}

View file

@ -75,7 +75,7 @@ public class ProgramCompiler<P extends GlProgram> extends Memoizer<ProgramContex
value.delete();
}
public static void invalidateAll(ReloadRenderersEvent event) {
public static void invalidateAll(ReloadRenderersEvent ignored) {
ALL_COMPILERS.forEach(ProgramCompiler::invalidate);
}
}

View file

@ -36,7 +36,7 @@ public class CrumblingGroup<P extends CrumblingProgram> extends InstancedMateria
RenderSystem.setShaderTexture(4, breakingTex);
Textures.bindActiveTextures();
renderAll(viewProjection, camX, camY, camZ, layer);
//renderAll(viewProjection, camX, camY, camZ, layer);
CrumblingRenderer._currentLayer.clearRenderState();
}

View file

@ -1,6 +1,7 @@
package com.jozufozu.flywheel.util;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
@ -24,6 +25,10 @@ public class Lazy<T> implements Supplier<T> {
return value;
}
public <Q> Lazy<Q> map(Function<T, Q> func) {
return new Lazy<>(() -> func.apply(get()));
}
public static <T> Lazy<T> of(NonNullSupplier<T> factory) {
return new Lazy<>(factory);
}

View file

@ -3,24 +3,24 @@ package com.jozufozu.flywheel.vanilla;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.SimpleModelSupplier;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
import com.jozufozu.flywheel.util.AnimationTickHolder;
import com.mojang.math.Quaternion;
import com.mojang.math.Vector3f;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BellRenderer;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.entity.BellBlockEntity;
public class BellInstance extends BlockEntityInstance<BellBlockEntity> implements DynamicInstance {
private static final ModelSupplier MODEL = new SimpleModelSupplier(BellInstance::createBellModel);
private static final ModelSupplier MODEL = new ModelSupplier(BellInstance::createBellModel, RenderType.cutoutMipped());
private final OrientedData bell;
@ -63,8 +63,7 @@ public class BellInstance extends BlockEntityInstance<BellBlockEntity> implement
}
private OrientedData createBellInstance() {
return materialManager.defaultCutout()
.material(Materials.ORIENTED)
return materialManager.material(Materials.ORIENTED)
.model(MODEL)
.createInstance();
}

View file

@ -6,11 +6,10 @@ import java.util.function.BiFunction;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.SimpleModelSupplier;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.materials.oriented.OrientedData;
@ -35,8 +34,8 @@ import net.minecraft.world.level.block.state.properties.ChestType;
public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends BlockEntityInstance<T> implements DynamicInstance {
private static final BiFunction<ChestType, TextureAtlasSprite, ModelSupplier> LID = Util.memoize((type, sprite) -> new SimpleModelSupplier(() -> createLidModel(type, sprite)));
private static final BiFunction<ChestType, TextureAtlasSprite, ModelSupplier> BASE = Util.memoize((type, sprite) -> new SimpleModelSupplier(() -> createBaseModel(type, sprite)));
private static final BiFunction<ChestType, Material, ModelSupplier> LID = Util.memoize((type, mat) -> new ModelSupplier(() -> createLidModel(type, mat.sprite()), RenderType.entitySolid(mat.atlasLocation())));
private static final BiFunction<ChestType, Material, ModelSupplier> BASE = Util.memoize((type, mat) -> new ModelSupplier(() -> createBaseModel(type, mat.sprite()), RenderType.entitySolid(mat.atlasLocation())));
private final OrientedData body;
private final ModelData lid;
@ -117,17 +116,15 @@ public class ChestInstance<T extends BlockEntity & LidBlockEntity> extends Block
private OrientedData baseInstance() {
return materialManager.solid(RenderType.entitySolid(renderMaterial.atlasLocation()))
.material(Materials.ORIENTED)
.model(BASE.apply(chestType, renderMaterial.sprite()))
return materialManager.material(Materials.ORIENTED)
.model(BASE.apply(chestType, renderMaterial))
.createInstance();
}
private ModelData lidInstance() {
return materialManager.solid(RenderType.entitySolid(renderMaterial.atlasLocation()))
.material(Materials.TRANSFORMED)
.model(LID.apply(chestType, renderMaterial.sprite()))
return materialManager.material(Materials.TRANSFORMED)
.model(LID.apply(chestType, renderMaterial))
.createInstance();
}

View file

@ -2,13 +2,14 @@ package com.jozufozu.flywheel.vanilla;
import javax.annotation.Nonnull;
import com.jozufozu.flywheel.api.Material;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.api.instance.TickableInstance;
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.SimpleModelSupplier;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.jozufozu.flywheel.core.Models;
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.core.model.Model;
@ -29,7 +30,7 @@ import net.minecraft.world.phys.Vec3;
public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance<T> implements DynamicInstance, TickableInstance {
private static final ResourceLocation MINECART_LOCATION = new ResourceLocation("textures/entity/minecart.png");
private static final ModelSupplier MODEL = new SimpleModelSupplier(MinecartInstance::getBodyModel);
private static final ModelSupplier MODEL = new ModelSupplier(MinecartInstance::getBodyModel, RenderType.entitySolid(MINECART_LOCATION));
private final PoseStack stack = new PoseStack();
@ -147,15 +148,13 @@ public class MinecartInstance<T extends AbstractMinecart> extends EntityInstance
if (blockstate.getRenderShape() == RenderShape.INVISIBLE)
return null;
return materialManager.defaultSolid()
.material(Materials.TRANSFORMED)
.getModel(blockstate)
return materialManager.material(Materials.TRANSFORMED)
.model(Models.block(blockstate))
.createInstance();
}
private ModelData getBody() {
return materialManager.solid(RenderType.entitySolid(MINECART_LOCATION))
.material(Materials.TRANSFORMED)
return materialManager.material(Materials.TRANSFORMED)
.model(MODEL)
.createInstance();
}

View file

@ -3,11 +3,10 @@ package com.jozufozu.flywheel.vanilla;
import java.util.function.Function;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.ModelSupplier;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance;
import com.jozufozu.flywheel.core.Materials;
import com.jozufozu.flywheel.core.SimpleModelSupplier;
import com.jozufozu.flywheel.core.ModelSupplier;
import com.jozufozu.flywheel.core.hardcoded.ModelPart;
import com.jozufozu.flywheel.core.materials.model.ModelData;
import com.jozufozu.flywheel.util.AnimationTickHolder;
@ -27,8 +26,8 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntity> implements DynamicInstance {
private static final Function<TextureAtlasSprite, ModelSupplier> BASE = Util.memoize(it -> new SimpleModelSupplier(() -> makeBaseModel(it)));
private static final Function<TextureAtlasSprite, ModelSupplier> LID = Util.memoize(it -> new SimpleModelSupplier(() -> makeLidModel(it)));
private static final Function<TextureAtlasSprite, ModelSupplier> BASE = Util.memoize(it -> new ModelSupplier(() -> makeBaseModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
private static final Function<TextureAtlasSprite, ModelSupplier> LID = Util.memoize(it -> new ModelSupplier(() -> makeLidModel(it), RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET)));
private final TextureAtlasSprite texture;
@ -74,9 +73,8 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
Quaternion spin = Vector3f.YP.rotationDegrees(270.0F * progress);
TransformStack tstack = TransformStack.cast(stack);
tstack.pushPose()
TransformStack.cast(stack)
.pushPose()
.centre()
.multiply(spin)
.unCentre()
@ -99,15 +97,13 @@ public class ShulkerBoxInstance extends BlockEntityInstance<ShulkerBoxBlockEntit
}
private ModelData makeBaseInstance() {
return materialManager.cutout(RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET))
.material(Materials.TRANSFORMED)
return materialManager.material(Materials.TRANSFORMED)
.model(BASE.apply(texture))
.createInstance();
}
private ModelData makeLidInstance() {
return materialManager.cutout(RenderType.entityCutoutNoCull(Sheets.SHULKER_SHEET))
.material(Materials.TRANSFORMED)
return materialManager.material(Materials.TRANSFORMED)
.model(LID.apply(texture))
.createInstance();
}