mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2025-02-04 17:24:59 +01:00
Material refactor pt 3
- Slight simplification to model allocation - RenderLayers are no more - Add basically empty RenderTypeRegistry, to be filled out as I go - Move content of RenderLayerEvent into RenderContext - BlockModels have PartialModel names now - Futz around with InstancingEngine's render logic - Fix invisibility bug caused by not unbinding vaos
This commit is contained in:
parent
ccbce86a69
commit
671ac33dda
29 changed files with 415 additions and 464 deletions
|
@ -8,7 +8,7 @@ import net.minecraft.core.Vec3i;
|
|||
|
||||
public interface MaterialManager {
|
||||
|
||||
<D extends InstanceData> InstancedMaterial<D> material(StructType<D> type);
|
||||
<D extends InstanceData> Material<D> material(StructType<D> type);
|
||||
|
||||
Vec3i getOriginCoordinate();
|
||||
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
package com.jozufozu.flywheel.api;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* The 3 discrete stages the world is rendered in.
|
||||
*/
|
||||
public enum RenderLayer {
|
||||
/**
|
||||
* Solid layer:<br>
|
||||
*
|
||||
* All polygons will entirely occlude everything behind them.
|
||||
*
|
||||
* <br><br>
|
||||
* e.g. stone, dirt, solid blocks
|
||||
*/
|
||||
SOLID,
|
||||
/**
|
||||
* Cutout layer:<br>
|
||||
*
|
||||
* <em>Fragments</em> will either occlude or not occlude depending on the texture/material.
|
||||
*
|
||||
* <br><br>
|
||||
* e.g. leaves, cobwebs, tall grass, saplings, glass
|
||||
*/
|
||||
CUTOUT,
|
||||
/**
|
||||
* Transparent layer:<br>
|
||||
*
|
||||
* Nothing is guaranteed to occlude and fragments blend their color with what's behind them.
|
||||
*
|
||||
* <br><br>
|
||||
* e.g. stained glass, water
|
||||
*/
|
||||
TRANSPARENT,
|
||||
;
|
||||
|
||||
@Nullable
|
||||
public static RenderLayer getPrimaryLayer(RenderType type) {
|
||||
if (type == RenderType.solid()) {
|
||||
return SOLID;
|
||||
} else if (type == RenderType.cutoutMipped()) {
|
||||
return CUTOUT;
|
||||
} else if (type == RenderType.translucent()) {
|
||||
return TRANSPARENT;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static RenderLayer getLayer(RenderType type) {
|
||||
if (type == RenderType.solid()) {
|
||||
return SOLID;
|
||||
} else if (type == RenderType.cutoutMipped() || type == RenderType.cutout()) {
|
||||
return CUTOUT;
|
||||
} else if (type == RenderType.translucent()) {
|
||||
return TRANSPARENT;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
package com.jozufozu.flywheel.backend.gl;
|
||||
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import com.jozufozu.flywheel.core.layout.BufferLayout;
|
||||
import com.jozufozu.flywheel.core.layout.LayoutItem;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
|
||||
public class GlVertexArray extends GlObject {
|
||||
|
||||
private final boolean[] arrays = new boolean[GL32.glGetInteger(GL32.GL_MAX_VERTEX_ATTRIBS)];
|
||||
|
||||
public GlVertexArray() {
|
||||
setHandle(GlStateManager._glGenVertexArrays());
|
||||
}
|
||||
|
@ -25,13 +29,27 @@ public class GlVertexArray extends GlObject {
|
|||
|
||||
public void enableArrays(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
GL20.glEnableVertexAttribArray(i);
|
||||
enable(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void disableArrays(int count) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
disable(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void enable(int i) {
|
||||
if (!arrays[i]) {
|
||||
GL20.glEnableVertexAttribArray(i);
|
||||
arrays[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void disable(int i) {
|
||||
if (arrays[i]) {
|
||||
GL20.glDisableVertexAttribArray(i);
|
||||
arrays[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ public abstract class AbstractInstancer<D extends InstanceData> implements Insta
|
|||
}
|
||||
|
||||
public int getModelVertexCount() {
|
||||
return 0;
|
||||
return modelData.getVertexCount();
|
||||
}
|
||||
|
||||
public int getInstanceCount() {
|
||||
|
|
|
@ -8,13 +8,16 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstanceM
|
|||
import com.jozufozu.flywheel.backend.instancing.entity.EntityInstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.util.ClientLevelExtension;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
@ -35,8 +38,7 @@ public class InstanceWorld {
|
|||
public static InstanceWorld create(LevelAccessor level) {
|
||||
return switch (Backend.getBackendType()) {
|
||||
case INSTANCING -> {
|
||||
InstancingEngine<WorldProgram> manager = InstancingEngine.builder(Contexts.WORLD)
|
||||
.build();
|
||||
InstancingEngine<WorldProgram> manager = new InstancingEngine<>(Contexts.WORLD);
|
||||
|
||||
var entityInstanceManager = new EntityInstanceManager(manager);
|
||||
var blockEntityInstanceManager = new BlockEntityInstanceManager(manager);
|
||||
|
@ -116,12 +118,12 @@ public class InstanceWorld {
|
|||
/**
|
||||
* Draw the given layer.
|
||||
*/
|
||||
public void renderLayer(RenderLayerEvent event) {
|
||||
public void renderLayer(RenderContext context) {
|
||||
taskEngine.syncPoint();
|
||||
event.stack.pushPose();
|
||||
event.stack.translate(-event.camX, -event.camY, -event.camZ);
|
||||
engine.render(taskEngine, event);
|
||||
event.stack.popPose();
|
||||
context.pushPose();
|
||||
context.translateBack(context.camX(), context.camY(), context.camZ());
|
||||
engine.render(taskEngine, context);
|
||||
context.popPose();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -98,12 +98,10 @@ public class InstancedRenderDispatcher {
|
|||
|
||||
@SubscribeEvent
|
||||
public static void renderLayer(RenderLayerEvent event) {
|
||||
if (event.layer == null) return;
|
||||
|
||||
ClientLevel world = event.getWorld();
|
||||
if (!Backend.canUseInstancing(world)) return;
|
||||
|
||||
instanceWorlds.get(world).renderLayer(event);
|
||||
instanceWorlds.get(world).renderLayer(event.context);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package com.jozufozu.flywheel.backend.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public interface RenderDispatcher {
|
||||
/**
|
||||
* Render every model for every material.
|
||||
*
|
||||
* @param taskEngine
|
||||
* @param event Context for rendering.
|
||||
*/
|
||||
void render(TaskEngine taskEngine, RenderLayerEvent event);
|
||||
void render(TaskEngine taskEngine, RenderContext context);
|
||||
|
||||
/**
|
||||
* Maintain the integer origin coordinate to be within a certain distance from the camera in all directions.
|
||||
|
|
|
@ -1,42 +1,36 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.batching;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.RenderLayer;
|
||||
import com.jozufozu.flywheel.api.struct.Batched;
|
||||
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.jozufozu.flywheel.core.RenderContext;
|
||||
import com.mojang.blaze3d.platform.Lighting;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
|
||||
public class BatchingEngine implements Engine {
|
||||
|
||||
private final Map<RenderLayer, Map<RenderType, BatchedMaterialGroup>> layers;
|
||||
private final Map<Batched<? extends InstanceData>, BatchedMaterial<?>> materials = new HashMap<>();
|
||||
private final BatchDrawingTracker batchTracker = new BatchDrawingTracker();
|
||||
|
||||
public BatchingEngine() {
|
||||
this.layers = new EnumMap<>(RenderLayer.class);
|
||||
for (RenderLayer value : RenderLayer.values()) {
|
||||
layers.put(value, new HashMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <D extends InstanceData> InstancedMaterial<D> material(StructType<D> type) {
|
||||
return null;
|
||||
public <D extends InstanceData> BatchedMaterial<D> material(StructType<D> type) {
|
||||
if (type instanceof Batched<D> batched) {
|
||||
return (BatchedMaterial<D>) materials.computeIfAbsent(batched, BatchedMaterial::new);
|
||||
} else {
|
||||
throw new ClassCastException("Cannot use type '" + type + "' with batching.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,16 +39,34 @@ public class BatchingEngine implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
|
||||
Map<RenderType, BatchedMaterialGroup> groups = layers.get(event.getLayer());
|
||||
for (BatchedMaterialGroup group : groups.values()) {
|
||||
group.render(event.stack, batchTracker, taskEngine);
|
||||
}
|
||||
public void render(TaskEngine taskEngine, RenderContext context) {
|
||||
|
||||
// vertexCount = 0;
|
||||
// instanceCount = 0;
|
||||
// for (BatchedMaterial<?> material : materials.values()) {
|
||||
// for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
// instancer.setup();
|
||||
// vertexCount += instancer.getVertexCount();
|
||||
// instanceCount += instancer.getInstanceCount();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// DirectVertexConsumer consumer = batchTracker.getDirectConsumer(state, vertexCount);
|
||||
//
|
||||
// // avoids rendering garbage, but doesn't fix the issue of some instances not being buffered
|
||||
// consumer.memSetZero();
|
||||
//
|
||||
// for (BatchedMaterial<?> material : materials.values()) {
|
||||
// for (CPUInstancer<?> instancer : material.models.values()) {
|
||||
// instancer.sbb.context.outputColorDiffuse = !consumer.hasOverlay() && !OptifineHandler.isUsingShaders();
|
||||
// instancer.submitTasks(stack, pool, consumer);
|
||||
// }
|
||||
// }
|
||||
|
||||
// FIXME: this probably breaks some vanilla stuff but it works much better for flywheel
|
||||
Matrix4f mat = new Matrix4f();
|
||||
mat.setIdentity();
|
||||
if (event.getWorld().effects().constantAmbientLight()) {
|
||||
if (context.level().effects().constantAmbientLight()) {
|
||||
Lighting.setupNetherLevel(mat);
|
||||
} else {
|
||||
Lighting.setupLevel(mat);
|
||||
|
@ -76,15 +88,7 @@ public class BatchingEngine implements Engine {
|
|||
@Override
|
||||
public void addDebugInfo(List<String> info) {
|
||||
info.add("Batching");
|
||||
info.add("Instances: " + layers.values()
|
||||
.stream()
|
||||
.flatMap(FlwUtil::mapValues)
|
||||
.mapToInt(BatchedMaterialGroup::getInstanceCount)
|
||||
.sum());
|
||||
info.add("Vertices: " + layers.values()
|
||||
.stream()
|
||||
.flatMap(FlwUtil::mapValues)
|
||||
.mapToInt(BatchedMaterialGroup::getVertexCount)
|
||||
.sum());
|
||||
info.add("Instances: " + 0);
|
||||
info.add("Vertices: " + 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ 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;
|
||||
|
@ -12,7 +11,6 @@ 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;
|
||||
|
|
|
@ -9,6 +9,7 @@ import com.jozufozu.flywheel.Flywheel;
|
|||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.api.struct.StructWriter;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
|
@ -67,8 +68,16 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
return deleted || model == null;
|
||||
}
|
||||
|
||||
public Map<RenderType, Renderable> init(ModelAllocator modelAllocator) {
|
||||
if (isInitialized()) return ImmutableMap.of();
|
||||
public boolean shouldRenderIn(RenderType renderType) {
|
||||
return modelData.getRenderType() == renderType;
|
||||
}
|
||||
|
||||
public void renderIn(RenderType renderType) {
|
||||
render();
|
||||
}
|
||||
|
||||
public void init(ModelAllocator modelAllocator) {
|
||||
if (isInitialized()) return;
|
||||
|
||||
initialized = true;
|
||||
|
||||
|
@ -77,16 +86,10 @@ public class GPUInstancer<D extends InstanceData> extends AbstractInstancer<D> {
|
|||
|
||||
vao = new GlVertexArray();
|
||||
|
||||
model = modelAllocator.alloc(modelData.get(), arenaModel -> {
|
||||
vao.bind();
|
||||
|
||||
arenaModel.setupState(vao);
|
||||
});
|
||||
model = modelAllocator.alloc(modelData.get(), vao);
|
||||
|
||||
vao.bind();
|
||||
vao.enableArrays(model.getAttributeCount() + instanceFormat.getAttributeCount());
|
||||
|
||||
return ImmutableMap.of(modelData.getRenderType(), this::render);
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
|
|
|
@ -6,13 +6,10 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
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.struct.Instanced;
|
||||
import com.jozufozu.flywheel.backend.instancing.Renderable;
|
||||
import com.jozufozu.flywheel.backend.model.ModelAllocator;
|
||||
import com.jozufozu.flywheel.core.ModelSupplier;
|
||||
|
||||
|
@ -27,19 +24,12 @@ 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 -> {
|
||||
|
@ -80,17 +70,18 @@ public class InstancedMaterial<D extends InstanceData> implements Material<D> {
|
|||
return models.values();
|
||||
}
|
||||
|
||||
void init(ModelAllocator allocator) {
|
||||
public void init(ModelAllocator allocator) {
|
||||
for (GPUInstancer<?> instancer : uninitialized) {
|
||||
|
||||
instancer.init(allocator)
|
||||
.forEach(this::addRenderable);
|
||||
instancer.init(allocator);
|
||||
}
|
||||
uninitialized.clear();
|
||||
}
|
||||
|
||||
private void addRenderable(RenderType type, Renderable renderable) {
|
||||
this.renderables.computeIfAbsent(type, k -> new ArrayList<>())
|
||||
.add(renderable);
|
||||
public void renderIn(RenderType layer) {
|
||||
for (GPUInstancer<?> instancer : models.values()) {
|
||||
if (instancer.shouldRenderIn(layer)) {
|
||||
instancer.renderIn(layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package com.jozufozu.flywheel.backend.instancing.instancing;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.MaterialGroup;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.api.struct.StructType;
|
||||
import com.jozufozu.flywheel.api.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.gl.versioned.GlCompat;
|
||||
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.ProgramContext;
|
||||
import com.jozufozu.flywheel.core.shader.WorldProgram;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
/**
|
||||
* A group of materials all rendered with the same GL state.
|
||||
*
|
||||
* 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> {
|
||||
|
||||
protected final InstancingEngine<P> owner;
|
||||
protected final RenderType type;
|
||||
|
||||
public InstancedMaterialGroup(InstancingEngine<P> owner, RenderType type) {
|
||||
this.owner = owner;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
|
||||
type.setupRenderState();
|
||||
Textures.bindActiveTextures();
|
||||
//renderAll(viewProjection, camX, camY, camZ, layer);
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
protected void setup(P program) {
|
||||
|
||||
}
|
||||
}
|
|
@ -11,16 +11,16 @@ 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.RenderContext;
|
||||
import com.jozufozu.flywheel.core.RenderTypeRegistry;
|
||||
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.Textures;
|
||||
import com.jozufozu.flywheel.util.WeakHashSet;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -29,6 +29,7 @@ import net.minecraft.client.Camera;
|
|||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
|
||||
public class InstancingEngine<P extends WorldProgram> implements Engine {
|
||||
|
@ -38,26 +39,18 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
protected BlockPos originCoordinate = BlockPos.ZERO;
|
||||
|
||||
protected final ProgramCompiler<P> context;
|
||||
protected final GroupFactory<P> groupFactory;
|
||||
protected final boolean ignoreOriginCoordinate;
|
||||
private ModelAllocator allocator;
|
||||
|
||||
private final Map<Instanced<? extends InstanceData>, InstancedMaterial<?>> materials = new HashMap<>();
|
||||
protected 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);
|
||||
}
|
||||
|
||||
public InstancingEngine(ProgramCompiler<P> context, GroupFactory<P> groupFactory, boolean ignoreOriginCoordinate) {
|
||||
public InstancingEngine(ProgramCompiler<P> context) {
|
||||
this.context = context;
|
||||
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
||||
|
||||
this.listeners = new WeakHashSet<>();
|
||||
this.groupFactory = groupFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -72,28 +65,20 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void render(TaskEngine taskEngine, RenderLayerEvent event) {
|
||||
public void render(TaskEngine taskEngine, RenderContext context) {
|
||||
|
||||
RenderType type = event.getType();
|
||||
var camX = context.camX() - originCoordinate.getX();
|
||||
var camY = context.camY() - originCoordinate.getY();
|
||||
var camZ = context.camZ() - originCoordinate.getZ();
|
||||
|
||||
double camX;
|
||||
double camY;
|
||||
double camZ;
|
||||
Matrix4f viewProjection;
|
||||
if (!ignoreOriginCoordinate) {
|
||||
camX = event.camX - originCoordinate.getX();
|
||||
camY = event.camY - originCoordinate.getY();
|
||||
camZ = event.camZ - originCoordinate.getZ();
|
||||
// don't want to mutate viewProjection
|
||||
var vp = context.viewProjection().copy();
|
||||
vp.multiply(Matrix4f.createTranslateMatrix((float) -camX, (float) -camY, (float) -camZ));
|
||||
|
||||
viewProjection = Matrix4f.createTranslateMatrix((float) -camX, (float) -camY, (float) -camZ);
|
||||
viewProjection.multiplyBackward(event.viewProjection);
|
||||
} else {
|
||||
camX = event.camX;
|
||||
camY = event.camY;
|
||||
camZ = event.camZ;
|
||||
viewProjection = event.viewProjection;
|
||||
}
|
||||
render(context.type(), camX, camY, camZ, vp);
|
||||
}
|
||||
|
||||
protected void render(RenderType type, double camX, double camY, double camZ, Matrix4f viewProjection) {
|
||||
vertexCount = 0;
|
||||
instanceCount = 0;
|
||||
|
||||
|
@ -101,29 +86,30 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
Textures.bindActiveTextures();
|
||||
|
||||
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
|
||||
List<Renderable> renderables = entry.getValue()
|
||||
.getRenderables(type);
|
||||
InstancedMaterial<?> material = entry.getValue();
|
||||
Instanced<? extends InstanceData> instanceType = entry.getKey();
|
||||
|
||||
if (renderables == null || renderables.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
setup(type, camX, camY, camZ, viewProjection, instanceType.getProgramSpec());
|
||||
|
||||
P program = context.getProgram(ProgramContext.create(entry.getKey()
|
||||
.getProgramSpec(), Formats.POS_TEX_NORMAL, event.layer));
|
||||
instanceCount += material.getInstanceCount();
|
||||
vertexCount += material.getVertexCount();
|
||||
|
||||
program.bind();
|
||||
program.uploadViewProjection(viewProjection);
|
||||
program.uploadCameraPos(camX, camY, camZ);
|
||||
|
||||
//setup(program);
|
||||
for (Renderable renderable : renderables) {
|
||||
renderable.draw();
|
||||
}
|
||||
material.renderIn(type);
|
||||
}
|
||||
|
||||
type.clearRenderState();
|
||||
}
|
||||
|
||||
protected P setup(RenderType layer, double camX, double camY, double camZ, Matrix4f viewProjection, ResourceLocation programSpec) {
|
||||
P program = context.getProgram(ProgramContext.create(programSpec, Formats.POS_TEX_NORMAL, RenderTypeRegistry.getAlphaDiscard(layer)));
|
||||
|
||||
program.bind();
|
||||
program.uploadViewProjection(viewProjection);
|
||||
program.uploadCameraPos(camX, camY, camZ);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
materials.values().forEach(InstancedMaterial::clear);
|
||||
}
|
||||
|
@ -152,22 +138,7 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
*/
|
||||
@Override
|
||||
public void beginFrame(Camera info) {
|
||||
int cX = Mth.floor(info.getPosition().x);
|
||||
int cY = Mth.floor(info.getPosition().y);
|
||||
int cZ = Mth.floor(info.getPosition().z);
|
||||
|
||||
int dX = cX - originCoordinate.getX();
|
||||
int dY = cY - originCoordinate.getY();
|
||||
int dZ = cZ - originCoordinate.getZ();
|
||||
|
||||
if (Math.abs(dX) > MAX_ORIGIN_DISTANCE || Math.abs(dY) > MAX_ORIGIN_DISTANCE || Math.abs(dZ) > MAX_ORIGIN_DISTANCE) {
|
||||
|
||||
originCoordinate = new BlockPos(cX, cY, cZ);
|
||||
|
||||
materials.values().forEach(InstancedMaterial::clear);
|
||||
|
||||
listeners.forEach(OriginShiftListener::onOriginShift);
|
||||
}
|
||||
checkOriginDistance(info);
|
||||
|
||||
ModelAllocator allocator = getModelAllocator();
|
||||
|
||||
|
@ -182,6 +153,29 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
|
||||
}
|
||||
|
||||
private void checkOriginDistance(Camera info) {
|
||||
int cX = Mth.floor(info.getPosition().x);
|
||||
int cY = Mth.floor(info.getPosition().y);
|
||||
int cZ = Mth.floor(info.getPosition().z);
|
||||
|
||||
int dX = cX - originCoordinate.getX();
|
||||
int dY = cY - originCoordinate.getY();
|
||||
int dZ = cZ - originCoordinate.getZ();
|
||||
|
||||
if (Math.abs(dX) > MAX_ORIGIN_DISTANCE || Math.abs(dY) > MAX_ORIGIN_DISTANCE || Math.abs(dZ) > MAX_ORIGIN_DISTANCE) {
|
||||
|
||||
shiftListeners(cX, cY, cZ);
|
||||
}
|
||||
}
|
||||
|
||||
private void shiftListeners(int cX, int cY, int cZ) {
|
||||
originCoordinate = new BlockPos(cX, cY, cZ);
|
||||
|
||||
materials.values().forEach(InstancedMaterial::clear);
|
||||
|
||||
listeners.forEach(OriginShiftListener::onOriginShift);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDebugInfo(List<String> info) {
|
||||
info.add("GL33 Instanced Arrays");
|
||||
|
@ -210,33 +204,4 @@ public class InstancingEngine<P extends WorldProgram> implements Engine {
|
|||
public interface OriginShiftListener {
|
||||
void onOriginShift();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface GroupFactory<P extends WorldProgram> {
|
||||
InstancedMaterialGroup<P> create(InstancingEngine<P> engine, RenderType type);
|
||||
}
|
||||
|
||||
public static class Builder<P extends WorldProgram> {
|
||||
protected final ProgramCompiler<P> context;
|
||||
protected GroupFactory<P> groupFactory = InstancedMaterialGroup::new;
|
||||
protected boolean ignoreOriginCoordinate;
|
||||
|
||||
public Builder(ProgramCompiler<P> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Builder<P> setGroupFactory(GroupFactory<P> groupFactory) {
|
||||
this.groupFactory = groupFactory;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<P> setIgnoreOriginCoordinate(boolean ignoreOriginCoordinate) {
|
||||
this.ignoreOriginCoordinate = ignoreOriginCoordinate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InstancingEngine<P> build() {
|
||||
return new InstancingEngine<>(context, groupFactory, ignoreOriginCoordinate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public enum FallbackAllocator implements ModelAllocator {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public BufferedModel alloc(Model model, Callback allocationCallback) {
|
||||
public BufferedModel alloc(Model model, GlVertexArray vao) {
|
||||
IndexedModel out = new IndexedModel(model);
|
||||
allocationCallback.onAlloc(out);
|
||||
vao.bind();
|
||||
out.setupState(vao);
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,8 @@ public class IndexedModel implements BufferedModel {
|
|||
}
|
||||
|
||||
/**
|
||||
* Draws many instances of this model, assuming the appropriate state is already bound.
|
||||
*/
|
||||
* Draws many instances of this model, assuming the appropriate state is already bound.
|
||||
*/
|
||||
@Override
|
||||
public void drawInstances(int instanceCount) {
|
||||
if (!valid()) return;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.backend.model;
|
||||
|
||||
import com.jozufozu.flywheel.backend.gl.GlVertexArray;
|
||||
import com.jozufozu.flywheel.core.model.Model;
|
||||
|
||||
public interface ModelAllocator {
|
||||
|
@ -7,9 +8,10 @@ public interface ModelAllocator {
|
|||
* Allocate a model.
|
||||
*
|
||||
* @param model The model to allocate.
|
||||
* @param vao The vertex array object to attach the model to.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
BufferedModel alloc(Model model, Callback allocationCallback);
|
||||
BufferedModel alloc(Model model, GlVertexArray vao);
|
||||
|
||||
@FunctionalInterface
|
||||
interface Callback {
|
||||
|
|
|
@ -4,7 +4,6 @@ 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;
|
||||
|
@ -51,12 +50,12 @@ public class ModelPool implements ModelAllocator {
|
|||
* Allocate a model in the arena.
|
||||
*
|
||||
* @param model The model to allocate.
|
||||
* @param vao The vertex array object to attach the model to.
|
||||
* @return A handle to the allocated model.
|
||||
*/
|
||||
@Override
|
||||
public PooledModel alloc(Model model, Callback callback) {
|
||||
PooledModel bufferedModel = new PooledModel(model, vertices);
|
||||
bufferedModel.callback = callback;
|
||||
public PooledModel alloc(Model model, GlVertexArray vao) {
|
||||
PooledModel bufferedModel = new PooledModel(vao, model, vertices);
|
||||
vertices += model.vertexCount();
|
||||
models.add(bufferedModel);
|
||||
pendingUpload.add(bufferedModel);
|
||||
|
@ -119,7 +118,7 @@ public class ModelPool implements ModelAllocator {
|
|||
for (PooledModel model : models) {
|
||||
model.first = vertices;
|
||||
|
||||
buffer(writer, model);
|
||||
model.buffer(writer);
|
||||
|
||||
vertices += model.getVertexCount();
|
||||
}
|
||||
|
@ -133,7 +132,7 @@ public class ModelPool implements ModelAllocator {
|
|||
try (MappedBuffer buffer = vbo.getBuffer()) {
|
||||
VertexWriter writer = vertexType.createWriter(buffer.unwrap());
|
||||
for (PooledModel model : pendingUpload) {
|
||||
buffer(writer, model);
|
||||
model.buffer(writer);
|
||||
}
|
||||
pendingUpload.clear();
|
||||
} catch (Exception e) {
|
||||
|
@ -141,12 +140,6 @@ public class ModelPool implements ModelAllocator {
|
|||
}
|
||||
}
|
||||
|
||||
private void buffer(VertexWriter writer, PooledModel model) {
|
||||
writer.seekToVertex(model.first);
|
||||
writer.writeVertexList(model.model.getReader());
|
||||
if (model.callback != null) model.callback.onAlloc(model);
|
||||
}
|
||||
|
||||
private void setDirty() {
|
||||
dirty = true;
|
||||
}
|
||||
|
@ -158,14 +151,15 @@ public class ModelPool implements ModelAllocator {
|
|||
public class PooledModel implements BufferedModel {
|
||||
|
||||
private final ElementBuffer ebo;
|
||||
private Callback callback;
|
||||
private final GlVertexArray vao;
|
||||
|
||||
private final Model model;
|
||||
private int first;
|
||||
|
||||
private boolean remove;
|
||||
private boolean deleted;
|
||||
|
||||
public PooledModel(Model model, int first) {
|
||||
public PooledModel(GlVertexArray vao, Model model, int first) {
|
||||
this.vao = vao;
|
||||
this.model = model;
|
||||
this.first = first;
|
||||
ebo = model.createEBO();
|
||||
|
@ -183,7 +177,7 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
@Override
|
||||
public void setupState(GlVertexArray vao) {
|
||||
vbo.bind();
|
||||
vao.bind();
|
||||
vao.enableArrays(getAttributeCount());
|
||||
vao.bindAttributes(0, vertexType.getLayout());
|
||||
}
|
||||
|
@ -206,14 +200,22 @@ public class ModelPool implements ModelAllocator {
|
|||
|
||||
@Override
|
||||
public boolean isDeleted() {
|
||||
return false;
|
||||
return deleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
setDirty();
|
||||
anyToRemove = true;
|
||||
remove = true;
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
private void buffer(VertexWriter writer) {
|
||||
writer.seekToVertex(first);
|
||||
writer.writeVertexList(model.getReader());
|
||||
|
||||
vao.bind();
|
||||
setupState(vao);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,7 @@ import com.jozufozu.flywheel.util.NonNullSupplier;
|
|||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class ModelSupplier {
|
||||
|
||||
private final Lazy<Model> supplier;
|
||||
public class ModelSupplier extends Lazy<Model> {
|
||||
|
||||
private RenderType renderType;
|
||||
|
||||
|
@ -19,7 +17,7 @@ public class ModelSupplier {
|
|||
}
|
||||
|
||||
public ModelSupplier(NonNullSupplier<Model> supplier, RenderType renderType) {
|
||||
this.supplier = Lazy.of(supplier);
|
||||
super(supplier);
|
||||
this.renderType = renderType;
|
||||
}
|
||||
|
||||
|
@ -32,13 +30,17 @@ public class ModelSupplier {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public Model get() {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
@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") + '}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public class Models {
|
|||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial) {
|
||||
return PARTIAL.computeIfAbsent(partial, it -> new ModelSupplier(() -> new BlockModel(it.get(), Blocks.AIR.defaultBlockState())));
|
||||
return PARTIAL.computeIfAbsent(partial, it -> new ModelSupplier(() -> new BlockModel(it)));
|
||||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial, Direction dir) {
|
||||
|
@ -31,7 +31,7 @@ public class Models {
|
|||
}
|
||||
|
||||
public static ModelSupplier partial(PartialModel partial, Direction dir, Supplier<PoseStack> modelTransform) {
|
||||
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new ModelSupplier(() -> new BlockModel(partial.get(), Blocks.AIR.defaultBlockState(), modelTransform.get())));
|
||||
return PARTIAL_DIR.computeIfAbsent(Pair.of(dir, partial), $ -> new ModelSupplier(() -> new BlockModel(partial, modelTransform.get())));
|
||||
}
|
||||
|
||||
public static void onReload(ReloadRenderersEvent ignored) {
|
||||
|
|
52
src/main/java/com/jozufozu/flywheel/core/RenderContext.java
Normal file
52
src/main/java/com/jozufozu/flywheel/core/RenderContext.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import com.jozufozu.flywheel.util.transform.TransformStack;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix3f;
|
||||
import com.mojang.math.Matrix4f;
|
||||
import com.mojang.math.Quaternion;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.RenderBuffers;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public record RenderContext(ClientLevel level, RenderType type, PoseStack stack, Matrix4f viewProjection, RenderBuffers buffers,
|
||||
double camX, double camY, double camZ) implements TransformStack {
|
||||
|
||||
@Override
|
||||
public TransformStack multiply(Quaternion quaternion) {
|
||||
return TransformStack.cast(stack).multiply(quaternion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack scale(float factorX, float factorY, float factorZ) {
|
||||
return TransformStack.cast(stack).scale(factorX, factorY, factorZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack pushPose() {
|
||||
stack.pushPose();
|
||||
return TransformStack.cast(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack popPose() {
|
||||
stack.popPose();
|
||||
return TransformStack.cast(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack mulPose(Matrix4f pose) {
|
||||
return TransformStack.cast(stack).mulPose(pose);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack mulNormal(Matrix3f normal) {
|
||||
return TransformStack.cast(stack).mulNormal(normal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransformStack translate(double x, double y, double z) {
|
||||
return TransformStack.cast(stack).translate(x, y, z);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.jozufozu.flywheel.core;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class RenderTypeRegistry {
|
||||
|
||||
|
||||
/**
|
||||
* Gets the alpha discard threshold for the given render layer.
|
||||
*
|
||||
* @param layer The render layer to get the alpha discard threshold for.
|
||||
* @return The alpha discard threshold.
|
||||
*/
|
||||
public static float getAlphaDiscard(@Nullable RenderType layer) {
|
||||
return layer == RenderType.cutoutMipped() ? 0.1f : 0f;
|
||||
}
|
||||
}
|
|
@ -2,11 +2,8 @@ package com.jozufozu.flywheel.core.compile;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexType;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.api.RenderLayer;
|
||||
import com.jozufozu.flywheel.core.GameStateRegistry;
|
||||
import com.jozufozu.flywheel.core.shader.ProgramSpec;
|
||||
import com.jozufozu.flywheel.core.shader.StateSnapshot;
|
||||
|
@ -20,29 +17,19 @@ public final class ProgramContext {
|
|||
/**
|
||||
* Creates a compilation context for the given program, vertex type and render layer.
|
||||
*
|
||||
* @param programName The name of the program to use.
|
||||
* @param vertexType The vertex type to use.
|
||||
* @param layer If cutout, the alpha discard threshold is 0.1, otherwise 0.
|
||||
* @param programName The name of the program to use.
|
||||
* @param vertexType The vertex type to use.
|
||||
* @param alphaDiscard The alpha threshold below which pixels are discarded.
|
||||
* @return A compilation context.
|
||||
*/
|
||||
public static ProgramContext create(ResourceLocation programName, VertexType vertexType, @Nullable RenderLayer layer) {
|
||||
public static ProgramContext create(ResourceLocation programName, VertexType vertexType, float alphaDiscard) {
|
||||
ProgramSpec spec = Backend.getSpec(programName);
|
||||
|
||||
if (spec == null) {
|
||||
throw new NullPointerException("Cannot compile shader because '" + programName + "' is not recognized.");
|
||||
}
|
||||
|
||||
return new ProgramContext(spec, getAlphaDiscard(layer), vertexType, GameStateRegistry.takeSnapshot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alpha discard threshold for the given render layer.
|
||||
*
|
||||
* @param layer The render layer to get the alpha discard threshold for.
|
||||
* @return The alpha discard threshold.
|
||||
*/
|
||||
public static float getAlphaDiscard(@Nullable RenderLayer layer) {
|
||||
return layer == RenderLayer.CUTOUT ? 0.1f : 0f;
|
||||
return new ProgramContext(spec, alphaDiscard, vertexType, GameStateRegistry.takeSnapshot());
|
||||
}
|
||||
|
||||
public final ProgramSpec spec;
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
package com.jozufozu.flywheel.core.crumbling;
|
||||
|
||||
import com.jozufozu.flywheel.api.RenderLayer;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterialGroup;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
|
||||
public class CrumblingGroup<P extends CrumblingProgram> extends InstancedMaterialGroup<P> {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public CrumblingGroup(InstancingEngine<P> owner, RenderType type) {
|
||||
super(owner, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Matrix4f viewProjection, double camX, double camY, double camZ, RenderLayer layer) {
|
||||
type.setupRenderState();
|
||||
|
||||
int renderTex = RenderSystem.getShaderTexture(0);
|
||||
|
||||
updateAtlasSize();
|
||||
|
||||
type.clearRenderState();
|
||||
|
||||
CrumblingRenderer._currentLayer.setupRenderState();
|
||||
|
||||
int breakingTex = RenderSystem.getShaderTexture(0);
|
||||
|
||||
RenderSystem.setShaderTexture(0, renderTex);
|
||||
RenderSystem.setShaderTexture(4, breakingTex);
|
||||
|
||||
Textures.bindActiveTextures();
|
||||
//renderAll(viewProjection, camX, camY, camZ, layer);
|
||||
|
||||
CrumblingRenderer._currentLayer.clearRenderState();
|
||||
}
|
||||
|
||||
private void updateAtlasSize() {
|
||||
|
||||
AtlasInfo.SheetSize sheetSize = AtlasInfo.getSheetSize(Textures.getShaderTexture(0));
|
||||
|
||||
if (sheetSize != null) {
|
||||
width = sheetSize.width();
|
||||
height = sheetSize.height();
|
||||
} else {
|
||||
width = height = 256;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setup(P p) {
|
||||
p.setAtlasSize(width, height);
|
||||
}
|
||||
}
|
|
@ -2,20 +2,26 @@ package com.jozufozu.flywheel.core.crumbling;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
|
||||
import com.jozufozu.flywheel.api.InstanceData;
|
||||
import com.jozufozu.flywheel.api.struct.Instanced;
|
||||
import com.jozufozu.flywheel.backend.Backend;
|
||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.jozufozu.flywheel.backend.instancing.InstanceManager;
|
||||
import com.jozufozu.flywheel.backend.instancing.SerialTaskEngine;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancedMaterial;
|
||||
import com.jozufozu.flywheel.backend.instancing.instancing.InstancingEngine;
|
||||
import com.jozufozu.flywheel.core.Contexts;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.jozufozu.flywheel.mixin.LevelRendererAccessor;
|
||||
import com.jozufozu.flywheel.util.Lazy;
|
||||
import com.jozufozu.flywheel.util.Pair;
|
||||
import com.jozufozu.flywheel.util.Textures;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
|
@ -50,16 +56,17 @@ public class CrumblingRenderer {
|
|||
_init();
|
||||
}
|
||||
|
||||
public static void renderBreaking(RenderLayerEvent event) {
|
||||
if (!Backend.canUseInstancing(event.getWorld())) return;
|
||||
public static void renderBreaking(ClientLevel level, PoseStack stack, double x, double y, double z, Matrix4f viewProjection) {
|
||||
|
||||
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(event.getWorld());
|
||||
if (!Backend.canUseInstancing(level)) return;
|
||||
|
||||
Int2ObjectMap<List<BlockEntity>> activeStages = getActiveStageBlockEntities(level);
|
||||
|
||||
if (activeStages.isEmpty()) return;
|
||||
|
||||
State state = STATE.get();
|
||||
InstanceManager<BlockEntity> instanceManager = state.instanceManager;
|
||||
InstancingEngine<CrumblingProgram> materials = state.materialManager;
|
||||
var instanceManager = state.instanceManager;
|
||||
var materials = state.materialManager;
|
||||
|
||||
TextureManager textureManager = Minecraft.getInstance().getTextureManager();
|
||||
Camera info = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
|
@ -72,8 +79,11 @@ public class CrumblingRenderer {
|
|||
stage.getValue().forEach(instanceManager::add);
|
||||
|
||||
instanceManager.beginFrame(SerialTaskEngine.INSTANCE, info);
|
||||
materials.beginFrame(info);
|
||||
|
||||
materials.render(SerialTaskEngine.INSTANCE, event);
|
||||
var ctx = new RenderContext(level, _currentLayer, stack, viewProjection, null, x, y, z);
|
||||
|
||||
materials.render(SerialTaskEngine.INSTANCE, ctx);
|
||||
|
||||
instanceManager.invalidate();
|
||||
}
|
||||
|
@ -131,13 +141,11 @@ public class CrumblingRenderer {
|
|||
}
|
||||
|
||||
private static class State {
|
||||
private final InstancingEngine<CrumblingProgram> materialManager;
|
||||
private final CrumblingEngine materialManager;
|
||||
private final InstanceManager<BlockEntity> instanceManager;
|
||||
|
||||
private State() {
|
||||
materialManager = InstancingEngine.builder(Contexts.CRUMBLING)
|
||||
.setGroupFactory(CrumblingGroup::new)
|
||||
.build();
|
||||
materialManager = new CrumblingEngine();
|
||||
instanceManager = new CrumblingInstanceManager(materialManager);
|
||||
materialManager.addListener(instanceManager);
|
||||
}
|
||||
|
@ -147,4 +155,51 @@ public class CrumblingRenderer {
|
|||
instanceManager.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
private static class CrumblingEngine extends InstancingEngine<CrumblingProgram> {
|
||||
|
||||
public CrumblingEngine() {
|
||||
super(Contexts.CRUMBLING);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void render(RenderType type, double camX, double camY, double camZ, Matrix4f viewProjection) {
|
||||
type.setupRenderState();
|
||||
|
||||
int renderTex = RenderSystem.getShaderTexture(0);
|
||||
|
||||
AtlasInfo.SheetSize sheetSize = AtlasInfo.getSheetSize(Textures.getShaderTexture(0));
|
||||
|
||||
int width;
|
||||
int height;
|
||||
if (sheetSize != null) {
|
||||
width = sheetSize.width();
|
||||
height = sheetSize.height();
|
||||
} else {
|
||||
width = height = 256;
|
||||
}
|
||||
|
||||
type.clearRenderState();
|
||||
|
||||
CrumblingRenderer._currentLayer.setupRenderState();
|
||||
|
||||
int breakingTex = RenderSystem.getShaderTexture(0);
|
||||
|
||||
RenderSystem.setShaderTexture(0, renderTex);
|
||||
RenderSystem.setShaderTexture(4, breakingTex);
|
||||
|
||||
Textures.bindActiveTextures();
|
||||
|
||||
for (Map.Entry<Instanced<? extends InstanceData>, InstancedMaterial<?>> entry : materials.entrySet()) {
|
||||
CrumblingProgram program = setup(type, camX, camY, camZ, viewProjection, entry.getKey()
|
||||
.getProgramSpec());
|
||||
|
||||
program.setAtlasSize(width, height);
|
||||
|
||||
//entry.getValue().getAllRenderables().forEach(Renderable::draw);
|
||||
}
|
||||
|
||||
CrumblingRenderer._currentLayer.clearRenderState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package com.jozufozu.flywheel.core.model;
|
|||
|
||||
import com.jozufozu.flywheel.api.vertex.VertexList;
|
||||
import com.jozufozu.flywheel.core.Formats;
|
||||
import com.jozufozu.flywheel.core.PartialModel;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
|
@ -28,9 +30,21 @@ public class BlockModel implements Model {
|
|||
this(model, referenceState, IDENTITY);
|
||||
}
|
||||
|
||||
public BlockModel(PartialModel model) {
|
||||
this(model, IDENTITY);
|
||||
}
|
||||
|
||||
public BlockModel(PartialModel model, PoseStack ms) {
|
||||
this(Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model.get(), Blocks.AIR.defaultBlockState(), ms)), model.getLocation().toString());
|
||||
}
|
||||
|
||||
public BlockModel(BakedModel model, BlockState referenceState, PoseStack ms) {
|
||||
reader = Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model, referenceState, ms));
|
||||
name = referenceState.toString();
|
||||
this(Formats.BLOCK.createReader(ModelUtil.getBufferBuilder(model, referenceState, ms)), referenceState.toString());
|
||||
}
|
||||
|
||||
public BlockModel(VertexList reader, String name) {
|
||||
this.reader = reader;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package com.jozufozu.flywheel.event;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.api.RenderLayer;
|
||||
import com.jozufozu.flywheel.core.RenderContext;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -13,65 +11,51 @@ import net.minecraft.client.renderer.RenderType;
|
|||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
public class RenderLayerEvent extends Event {
|
||||
private final ClientLevel world;
|
||||
public final RenderType type;
|
||||
public final PoseStack stack;
|
||||
public final Matrix4f viewProjection;
|
||||
public final RenderBuffers buffers;
|
||||
public final double camX;
|
||||
public final double camY;
|
||||
public final double camZ;
|
||||
public final RenderLayer layer;
|
||||
public final RenderContext context;
|
||||
|
||||
public RenderLayerEvent(ClientLevel world, RenderType type, PoseStack stack, RenderBuffers buffers, double camX, double camY, double camZ) {
|
||||
this.world = world;
|
||||
this.type = type;
|
||||
this.stack = stack;
|
||||
|
||||
viewProjection = stack.last()
|
||||
var viewProjection = stack.last()
|
||||
.pose()
|
||||
.copy();
|
||||
viewProjection.multiplyBackward(RenderSystem.getProjectionMatrix());
|
||||
|
||||
this.buffers = buffers;
|
||||
this.camX = camX;
|
||||
this.camY = camY;
|
||||
this.camZ = camZ;
|
||||
|
||||
this.layer = RenderLayer.getPrimaryLayer(type);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RenderLayer getLayer() {
|
||||
return layer;
|
||||
}
|
||||
|
||||
public ClientLevel getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public RenderType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Matrix4f getViewProjection() {
|
||||
return viewProjection;
|
||||
}
|
||||
|
||||
public double getCamX() {
|
||||
return camX;
|
||||
}
|
||||
|
||||
public double getCamY() {
|
||||
return camY;
|
||||
}
|
||||
|
||||
public double getCamZ() {
|
||||
return camZ;
|
||||
context = new RenderContext(world, type, stack, viewProjection, buffers, camX, camY, camZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RenderLayerEvent[" + layer + "][" + "world=" + world + ", type=" + type + ", stack=" + stack + ", viewProjection=" + viewProjection + ", buffers=" + buffers + ", camX=" + camX + ", camY=" + camY + ", camZ=" + camZ + ']';
|
||||
return "RenderLayerEvent{" + context + "}";
|
||||
}
|
||||
|
||||
public ClientLevel getWorld() {
|
||||
return context.level();
|
||||
}
|
||||
|
||||
public RenderType getType() {
|
||||
return context.type();
|
||||
}
|
||||
|
||||
public PoseStack getStack() {
|
||||
return context.stack();
|
||||
}
|
||||
|
||||
public Matrix4f getViewProjection() {
|
||||
return context.viewProjection();
|
||||
}
|
||||
|
||||
public RenderBuffers getBuffers() {
|
||||
return context.buffers();
|
||||
}
|
||||
|
||||
public double getCamX() {
|
||||
return context.camX();
|
||||
}
|
||||
|
||||
public double getCamY() {
|
||||
return context.camY();
|
||||
}
|
||||
|
||||
public double getCamZ() {
|
||||
return context.camZ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import com.jozufozu.flywheel.backend.OptifineHandler;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.core.LastActiveCamera;
|
||||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
|
||||
|
@ -19,7 +20,9 @@ public class FrustumMixin {
|
|||
@Inject(method = "prepare", at = @At("TAIL"))
|
||||
private void onPrepare(double x, double y, double z, CallbackInfo ci) {
|
||||
if (OptifineHandler.isShadowPass()) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(Minecraft.getInstance().level, LastActiveCamera.getActiveCamera(), (Frustum) (Object) this));
|
||||
restoreState.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.jozufozu.flywheel.core.crumbling.CrumblingRenderer;
|
|||
import com.jozufozu.flywheel.event.BeginFrameEvent;
|
||||
import com.jozufozu.flywheel.event.ReloadRenderersEvent;
|
||||
import com.jozufozu.flywheel.event.RenderLayerEvent;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.BufferUploader;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Matrix4f;
|
||||
|
@ -48,7 +49,9 @@ public class LevelRendererMixin {
|
|||
|
||||
@Inject(at = @At("HEAD"), method = "setupRender")
|
||||
private void setupRender(Camera camera, Frustum frustum, boolean queue, boolean isSpectator, CallbackInfo ci) {
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
MinecraftForge.EVENT_BUS.post(new BeginFrameEvent(level, camera, frustum));
|
||||
restoreState.restore();
|
||||
}
|
||||
|
||||
@Unique
|
||||
|
@ -103,8 +106,13 @@ public class LevelRendererMixin {
|
|||
|
||||
Vec3 cameraPos = info.getPosition();
|
||||
|
||||
Matrix4f viewProjection = stack.last()
|
||||
.pose()
|
||||
.copy();
|
||||
viewProjection.multiplyBackward(RenderSystem.getProjectionMatrix());
|
||||
|
||||
GlStateTracker.State restoreState = GlStateTracker.getRestoreState();
|
||||
CrumblingRenderer.renderBreaking(new RenderLayerEvent(level, null, stack, null, cameraPos.x, cameraPos.y, cameraPos.z));
|
||||
CrumblingRenderer.renderBreaking(level, stack, cameraPos.x, cameraPos.y, cameraPos.z, viewProjection);
|
||||
restoreState.restore();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.jozufozu.flywheel.util;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
@ -25,7 +26,7 @@ public class Lazy<T> implements Supplier<T> {
|
|||
return value;
|
||||
}
|
||||
|
||||
public <Q> Lazy<Q> map(Function<T, Q> func) {
|
||||
public <Q> Lazy<Q> lazyMap(Function<T, Q> func) {
|
||||
return new Lazy<>(() -> func.apply(get()));
|
||||
}
|
||||
|
||||
|
@ -38,4 +39,18 @@ public class Lazy<T> implements Supplier<T> {
|
|||
func.accept(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If initialized, maps the stored value based on the function, otherwise returns the None.
|
||||
* @param func The function to map the value with.
|
||||
* @param <Q> The type of the mapped value.
|
||||
* @return The mapped value, or None if not initialized.
|
||||
*/
|
||||
public <Q> Optional<Q> map(Function<T, Q> func) {
|
||||
if (value != null) {
|
||||
return Optional.of(func.apply(value));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue