mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-11-10 12:34:11 +01:00
Putting everything in context
- Begin context refactor. - Rename (old) Context -> ContextShader and remove gl program method. - Add (new) Context which does not need to be registered. - Contexts are responsible for binding textures given a material. - Instancers are created in a specific context. - Add Shader interface for attaching textures. - Add Textures interface for fetching textures to pass to a Shader. - Remove texture related code from MaterialRenderState. - Key culling groups by context. - Key DrawSets by context.
This commit is contained in:
parent
e7d7602941
commit
bab0448724
@ -19,7 +19,7 @@ import com.jozufozu.flywheel.impl.BackendManagerImpl;
|
||||
import com.jozufozu.flywheel.impl.registry.IdRegistryImpl;
|
||||
import com.jozufozu.flywheel.impl.registry.RegistryImpl;
|
||||
import com.jozufozu.flywheel.impl.visualization.VisualizationEventHandler;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
import com.jozufozu.flywheel.lib.context.ContextShaders;
|
||||
import com.jozufozu.flywheel.lib.instance.InstanceTypes;
|
||||
import com.jozufozu.flywheel.lib.material.CutoutShaders;
|
||||
import com.jozufozu.flywheel.lib.material.FogShaders;
|
||||
@ -128,7 +128,7 @@ public class Flywheel {
|
||||
CutoutShaders.init();
|
||||
FogShaders.init();
|
||||
StandardMaterialShaders.init();
|
||||
Contexts.init();
|
||||
ContextShaders.init();
|
||||
|
||||
ShaderIndices.init();
|
||||
|
||||
|
@ -3,6 +3,7 @@ package com.jozufozu.flywheel.api.backend;
|
||||
import java.util.List;
|
||||
|
||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderContext;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
@ -31,7 +32,7 @@ public interface Engine {
|
||||
* @return An instancer for the given instance type, model, and render stage.
|
||||
* @see InstancerProvider
|
||||
*/
|
||||
<I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model, RenderStage stage);
|
||||
<I extends Instance> Instancer<I> instancer(InstanceType<I> type, Context context, Model model, RenderStage stage);
|
||||
|
||||
/**
|
||||
* Create a plan that will be executed every frame.
|
||||
|
@ -1,17 +1,16 @@
|
||||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.internal.InternalFlywheelApi;
|
||||
import com.jozufozu.flywheel.api.registry.Registry;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
||||
public interface Context {
|
||||
static Registry<Context> REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry();
|
||||
ContextShader contextShader();
|
||||
|
||||
void onProgramLink(GlProgram program);
|
||||
|
||||
ResourceLocation vertexShader();
|
||||
|
||||
ResourceLocation fragmentShader();
|
||||
/**
|
||||
* Prepare the shader for rendering with the given material and textures.
|
||||
*
|
||||
* @param material The material about to be rendered.
|
||||
* @param shader The shader to prepare.
|
||||
* @param textures Source of the textures to use.
|
||||
*/
|
||||
void prepare(Material material, Shader shader, Textures textures);
|
||||
}
|
||||
|
@ -0,0 +1,14 @@
|
||||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.internal.InternalFlywheelApi;
|
||||
import com.jozufozu.flywheel.api.registry.Registry;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public interface ContextShader {
|
||||
static Registry<ContextShader> REGISTRY = InternalFlywheelApi.INSTANCE.createRegistry();
|
||||
|
||||
ResourceLocation vertexShader();
|
||||
|
||||
ResourceLocation fragmentShader();
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||
|
||||
@BackendImplemented
|
||||
public interface Shader {
|
||||
void setTexture(String glslName, Texture texture);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||
|
||||
@BackendImplemented
|
||||
public interface Texture {
|
||||
void filter(boolean blur, boolean mipmap);
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.jozufozu.flywheel.api.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.BackendImplemented;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
@BackendImplemented
|
||||
public interface Textures {
|
||||
/**
|
||||
* Get a built-in texture by its resource location.
|
||||
*
|
||||
* @param texture The texture's resource location.
|
||||
* @return The texture.
|
||||
*/
|
||||
Texture byName(ResourceLocation texture);
|
||||
|
||||
/**
|
||||
* Get the overlay texture.
|
||||
*
|
||||
* @return The overlay texture.
|
||||
*/
|
||||
Texture overlay();
|
||||
|
||||
/**
|
||||
* Get the light texture.
|
||||
*
|
||||
* @return The light texture.
|
||||
*/
|
||||
Texture light();
|
||||
|
||||
// TODO: Allow creating dynamic textures.
|
||||
}
|
@ -7,7 +7,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.ShaderIndices;
|
||||
import com.jozufozu.flywheel.backend.compile.component.UberShaderComponent;
|
||||
@ -46,9 +46,9 @@ public final class FlwPrograms {
|
||||
|
||||
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
|
||||
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
|
||||
for (Context context : Context.REGISTRY) {
|
||||
for (ContextShader contextShader : ContextShader.REGISTRY) {
|
||||
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
|
||||
builder.add(new PipelineProgramKey(instanceType, context));
|
||||
builder.add(new PipelineProgramKey(instanceType, contextShader));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
|
@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
|
||||
import com.jozufozu.flywheel.backend.compile.core.CompilationHarness;
|
||||
@ -121,7 +121,7 @@ public class IndirectPrograms extends AbstractPrograms {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
public GlProgram getIndirectProgram(InstanceType<?> instanceType, Context contextShader) {
|
||||
public GlProgram getIndirectProgram(InstanceType<?> instanceType, ContextShader contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(instanceType, contextShader));
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import java.util.Map;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.backend.glsl.ShaderSources;
|
||||
@ -61,7 +61,7 @@ public class InstancingPrograms extends AbstractPrograms {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
public GlProgram get(InstanceType<?> instanceType, Context contextShader) {
|
||||
public GlProgram get(InstanceType<?> instanceType, ContextShader contextShader) {
|
||||
return pipeline.get(new PipelineProgramKey(instanceType, contextShader));
|
||||
}
|
||||
|
||||
|
@ -50,8 +50,6 @@ public class PipelineCompiler {
|
||||
.fragmentShader())
|
||||
.withResource(pipeline.fragmentMain()))
|
||||
.then((key, program) -> {
|
||||
key.contextShader()
|
||||
.onProgramLink(program);
|
||||
program.setUniformBlockBinding("_FlwFrameUniforms", 0);
|
||||
program.setUniformBlockBinding("_FlwFogUniforms", 1);
|
||||
})
|
||||
|
@ -1,6 +1,6 @@
|
||||
package com.jozufozu.flywheel.backend.compile;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
|
||||
/**
|
||||
@ -9,5 +9,5 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
* @param instanceType The instance shader to use.
|
||||
* @param contextShader The context shader to use.
|
||||
*/
|
||||
public record PipelineProgramKey(InstanceType<?> instanceType, Context contextShader) {
|
||||
public record PipelineProgramKey(InstanceType<?> instanceType, ContextShader contextShader) {
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.jozufozu.flywheel.backend.engine;
|
||||
|
||||
import com.jozufozu.flywheel.api.backend.Engine;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
@ -21,8 +22,8 @@ public abstract class AbstractEngine implements Engine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model, RenderStage stage) {
|
||||
return getStorage().getInstancer(type, model, stage);
|
||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Context context, Model model, RenderStage stage) {
|
||||
return getStorage().getInstancer(type, context, model, stage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2,6 +2,7 @@ package com.jozufozu.flywheel.backend.engine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.instance.Instancer;
|
||||
@ -9,6 +10,7 @@ import com.jozufozu.flywheel.lib.util.AtomicBitset;
|
||||
|
||||
public abstract class AbstractInstancer<I extends Instance> implements Instancer<I> {
|
||||
public final InstanceType<I> type;
|
||||
public final Context context;
|
||||
|
||||
// Lock for all instances, only needs to be used in methods that may run on the TaskExecutor.
|
||||
protected final Object lock = new Object();
|
||||
@ -18,8 +20,9 @@ public abstract class AbstractInstancer<I extends Instance> implements Instancer
|
||||
protected final AtomicBitset changed = new AtomicBitset();
|
||||
protected final AtomicBitset deleted = new AtomicBitset();
|
||||
|
||||
protected AbstractInstancer(InstanceType<I> type) {
|
||||
protected AbstractInstancer(InstanceType<I> type, Context context) {
|
||||
this.type = type;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,9 +1,10 @@
|
||||
package com.jozufozu.flywheel.backend.engine;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
|
||||
public record InstancerKey<I extends Instance>(InstanceType<I> type, Model model, RenderStage stage) {
|
||||
public record InstancerKey<I extends Instance>(InstanceType<I> type, Context context, Model model, RenderStage stage) {
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
@ -27,8 +28,8 @@ public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||
protected final List<UninitializedInstancer<N, ?>> initializationQueue = new ArrayList<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <I extends Instance> Instancer<I> getInstancer(InstanceType<I> type, Model model, RenderStage stage) {
|
||||
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(type, model, stage), this::createAndDeferInit);
|
||||
public <I extends Instance> Instancer<I> getInstancer(InstanceType<I> type, Context context, Model model, RenderStage stage) {
|
||||
return (Instancer<I>) instancers.computeIfAbsent(new InstancerKey<>(type, context, model, stage), this::createAndDeferInit);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
@ -50,12 +51,12 @@ public abstract class InstancerStorage<N extends AbstractInstancer<?>> {
|
||||
.forEach(AbstractInstancer::clear);
|
||||
}
|
||||
|
||||
protected abstract <I extends Instance> N create(InstanceType<I> type);
|
||||
protected abstract <I extends Instance> N create(InstancerKey<I> type);
|
||||
|
||||
protected abstract <I extends Instance> void initialize(InstancerKey<I> key, N instancer);
|
||||
|
||||
private N createAndDeferInit(InstancerKey<?> key) {
|
||||
var out = create(key.type());
|
||||
var out = create(key);
|
||||
|
||||
// Only queue the instancer for initialization if it has anything to render.
|
||||
if (key.model()
|
||||
|
@ -8,13 +8,9 @@ import com.jozufozu.flywheel.api.material.DepthTest;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
import com.jozufozu.flywheel.api.material.Transparency;
|
||||
import com.jozufozu.flywheel.api.material.WriteMask;
|
||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
|
||||
public final class MaterialRenderState {
|
||||
public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::texture)
|
||||
.thenComparing(Material::blur)
|
||||
@ -29,7 +25,6 @@ public final class MaterialRenderState {
|
||||
}
|
||||
|
||||
public static void setup(Material material) {
|
||||
setupTexture(material);
|
||||
setupBackfaceCulling(material.backfaceCulling());
|
||||
setupPolygonOffset(material.polygonOffset());
|
||||
setupDepthTest(material.depthTest());
|
||||
@ -37,17 +32,6 @@ public final class MaterialRenderState {
|
||||
setupWriteMask(material.writeMask());
|
||||
}
|
||||
|
||||
private static void setupTexture(Material material) {
|
||||
GlTextureUnit.T0.makeActive();
|
||||
AbstractTexture texture = Minecraft.getInstance()
|
||||
.getTextureManager()
|
||||
.getTexture(material.texture());
|
||||
texture.setFilter(material.blur(), material.mipmap());
|
||||
var textureId = texture.getId();
|
||||
RenderSystem.setShaderTexture(0, textureId);
|
||||
RenderSystem.bindTexture(textureId);
|
||||
}
|
||||
|
||||
private static void setupBackfaceCulling(boolean backfaceCulling) {
|
||||
if (backfaceCulling) {
|
||||
RenderSystem.enableCull();
|
||||
@ -141,7 +125,6 @@ public final class MaterialRenderState {
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
resetTexture();
|
||||
resetBackfaceCulling();
|
||||
resetPolygonOffset();
|
||||
resetDepthTest();
|
||||
@ -149,11 +132,6 @@ public final class MaterialRenderState {
|
||||
resetWriteMask();
|
||||
}
|
||||
|
||||
private static void resetTexture() {
|
||||
GlTextureUnit.T0.makeActive();
|
||||
RenderSystem.setShaderTexture(0, 0);
|
||||
}
|
||||
|
||||
private static void resetBackfaceCulling() {
|
||||
RenderSystem.enableCull();
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
@ -24,11 +25,13 @@ import com.jozufozu.flywheel.api.model.Mesh;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TextureBinder;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TexturesImpl;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
import com.jozufozu.flywheel.backend.gl.Driver;
|
||||
import com.jozufozu.flywheel.backend.gl.GlCompat;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
import com.jozufozu.flywheel.lib.context.SimpleContextShader;
|
||||
|
||||
public class IndirectCullingGroup<I extends Instance> {
|
||||
private static final Comparator<IndirectDraw> DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::stage)
|
||||
@ -37,6 +40,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
|
||||
|
||||
private final InstanceType<I> instanceType;
|
||||
private final Context context;
|
||||
private final long objectStride;
|
||||
private final IndirectBuffers buffers;
|
||||
private final IndirectMeshPool meshPool;
|
||||
@ -53,17 +57,19 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
private boolean hasNewDraws;
|
||||
private int instanceCountThisFrame;
|
||||
|
||||
IndirectCullingGroup(InstanceType<I> instanceType, IndirectPrograms programs) {
|
||||
IndirectCullingGroup(InstanceType<I> instanceType, Context context, IndirectPrograms programs) {
|
||||
this.instanceType = instanceType;
|
||||
this.context = context;
|
||||
objectStride = instanceType.layout()
|
||||
.byteSize() + IndirectBuffers.INT_SIZE;
|
||||
buffers = new IndirectBuffers(objectStride);
|
||||
meshPool = new IndirectMeshPool();
|
||||
|
||||
this.programs = programs;
|
||||
// TODO: Culling programs need to be context aware.
|
||||
cullProgram = programs.getCullingProgram(instanceType);
|
||||
applyProgram = programs.getApplyProgram();
|
||||
drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT);
|
||||
drawProgram = programs.getIndirectProgram(instanceType, context.contextShader());
|
||||
}
|
||||
|
||||
public void flush(StagingBuffer stagingBuffer) {
|
||||
@ -179,7 +185,7 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
hasNewDraws = true;
|
||||
}
|
||||
|
||||
public void submit(RenderStage stage) {
|
||||
public void submit(RenderStage stage, TexturesImpl textures) {
|
||||
if (nothingToDo(stage)) {
|
||||
return;
|
||||
}
|
||||
@ -195,12 +201,17 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
|
||||
for (var multiDraw : multiDraws.get(stage)) {
|
||||
glUniform1ui(flwBaseDraw, multiDraw.start);
|
||||
|
||||
context.prepare(multiDraw.material, drawProgram, textures);
|
||||
MaterialRenderState.setup(multiDraw.material);
|
||||
|
||||
multiDraw.submit();
|
||||
TextureBinder.resetTextureBindings();
|
||||
}
|
||||
}
|
||||
|
||||
public void bindForCrumbling() {
|
||||
var program = programs.getIndirectProgram(instanceType, Contexts.CRUMBLING);
|
||||
public void bindWithContextShader(SimpleContextShader override) {
|
||||
var program = programs.getIndirectProgram(instanceType, override);
|
||||
|
||||
program.bind();
|
||||
|
||||
@ -265,16 +276,14 @@ public class IndirectCullingGroup<I extends Instance> {
|
||||
}
|
||||
|
||||
private record MultiDraw(Material material, int start, int end) {
|
||||
void submit() {
|
||||
MaterialRenderState.setup(material);
|
||||
|
||||
private void submit() {
|
||||
if (GlCompat.DRIVER == Driver.INTEL) {
|
||||
// Intel renders garbage with MDI, but Consecutive Normal Draws works fine.
|
||||
for (int i = start; i < end; i++) {
|
||||
for (int i = this.start; i < this.end; i++) {
|
||||
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, i * IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
}
|
||||
} else {
|
||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, start * IndirectBuffers.DRAW_COMMAND_STRIDE, end - start, (int) IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, this.start * IndirectBuffers.DRAW_COMMAND_STRIDE, this.end - this.start, (int) IndirectBuffers.DRAW_COMMAND_STRIDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.backend.Engine;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
@ -21,8 +22,10 @@ import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
||||
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
||||
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TexturesImpl;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBuffer;
|
||||
import com.jozufozu.flywheel.backend.gl.buffer.GlBufferType;
|
||||
import com.jozufozu.flywheel.lib.context.ContextShaders;
|
||||
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
|
||||
import com.jozufozu.flywheel.lib.memory.MemoryBlock;
|
||||
import com.jozufozu.flywheel.lib.util.Pair;
|
||||
@ -34,7 +37,8 @@ import net.minecraft.client.resources.model.ModelBakery;
|
||||
public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>> {
|
||||
private final IndirectPrograms programs;
|
||||
private final StagingBuffer stagingBuffer;
|
||||
private final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
|
||||
private final TexturesImpl textures = new TexturesImpl();
|
||||
private final Map<GroupKey<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
|
||||
private final GlBuffer crumblingDrawBuffer = new GlBuffer();
|
||||
|
||||
public IndirectDrawManager(IndirectPrograms programs) {
|
||||
@ -43,14 +47,15 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) {
|
||||
return new IndirectInstancer<>(type);
|
||||
protected <I extends Instance> IndirectInstancer<?> create(InstancerKey<I> key) {
|
||||
return new IndirectInstancer<>(key.type(), key.context());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected <I extends Instance> void initialize(InstancerKey<I> key, IndirectInstancer<?> instancer) {
|
||||
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), t -> new IndirectCullingGroup<>(t, programs));
|
||||
var groupKey = new GroupKey<>(key.type(), key.context());
|
||||
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(groupKey, t -> new IndirectCullingGroup<>(t.type, t.context, programs));
|
||||
group.add((IndirectInstancer<I>) instancer, key.model(), key.stage());
|
||||
}
|
||||
|
||||
@ -65,7 +70,7 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||
|
||||
public void renderStage(RenderStage stage) {
|
||||
for (var group : cullingGroups.values()) {
|
||||
group.submit(stage);
|
||||
group.submit(stage, textures);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +128,7 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||
|
||||
// Set up the crumbling program buffers. Nothing changes here between draws.
|
||||
cullingGroups.get(instanceTypeEntry.getKey())
|
||||
.bindForCrumbling();
|
||||
.bindWithContextShader(ContextShaders.CRUMBLING);
|
||||
|
||||
for (var progressEntry : byProgress.int2ObjectEntrySet()) {
|
||||
for (var instanceHandlePair : progressEntry.getValue()) {
|
||||
@ -156,8 +161,8 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||
block.free();
|
||||
}
|
||||
|
||||
private static Map<InstanceType<?>, Int2ObjectMap<List<Pair<IndirectInstancer<?>, InstanceHandleImpl>>>> doCrumblingSort(List<Engine.CrumblingBlock> crumblingBlocks) {
|
||||
Map<InstanceType<?>, Int2ObjectMap<List<Pair<IndirectInstancer<?>, InstanceHandleImpl>>>> byType = new HashMap<>();
|
||||
private static Map<GroupKey<?>, Int2ObjectMap<List<Pair<IndirectInstancer<?>, InstanceHandleImpl>>>> doCrumblingSort(List<Engine.CrumblingBlock> crumblingBlocks) {
|
||||
Map<GroupKey<?>, Int2ObjectMap<List<Pair<IndirectInstancer<?>, InstanceHandleImpl>>>> byType = new HashMap<>();
|
||||
for (Engine.CrumblingBlock block : crumblingBlocks) {
|
||||
int progress = block.progress();
|
||||
|
||||
@ -176,11 +181,14 @@ public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>>
|
||||
continue;
|
||||
}
|
||||
|
||||
byType.computeIfAbsent(instancer.type, $ -> new Int2ObjectArrayMap<>())
|
||||
byType.computeIfAbsent(new GroupKey<>(instancer.type, instancer.context), $ -> new Int2ObjectArrayMap<>())
|
||||
.computeIfAbsent(progress, $ -> new ArrayList<>())
|
||||
.add(Pair.of(instancer, impl));
|
||||
}
|
||||
}
|
||||
return byType;
|
||||
}
|
||||
|
||||
public record GroupKey<I extends Instance>(InstanceType<I> type, Context context) {
|
||||
}
|
||||
}
|
||||
|
@ -13,15 +13,9 @@ import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.jozufozu.flywheel.lib.task.Flag;
|
||||
import com.jozufozu.flywheel.lib.task.NamedFlag;
|
||||
import com.jozufozu.flywheel.lib.task.SyncedPlan;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
|
||||
public class IndirectEngine extends AbstractEngine {
|
||||
private final IndirectPrograms programs;
|
||||
@ -60,23 +54,9 @@ public class IndirectEngine extends AbstractEngine {
|
||||
}
|
||||
|
||||
try (var restoreState = GlStateTracker.getRestoreState()) {
|
||||
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
|
||||
int prevActiveTexture = GlStateManager._getActiveTexture();
|
||||
gameRenderer.overlayTexture().setupOverlayColor();
|
||||
gameRenderer.lightTexture().turnOnLightLayer();
|
||||
|
||||
GlTextureUnit.T1.makeActive();
|
||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
|
||||
GlTextureUnit.T2.makeActive();
|
||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
|
||||
|
||||
drawManager.renderStage(stage);
|
||||
|
||||
MaterialRenderState.reset();
|
||||
|
||||
gameRenderer.overlayTexture().teardownOverlayColor();
|
||||
gameRenderer.lightTexture().turnOffLightLayer();
|
||||
GlStateManager._activeTexture(prevActiveTexture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
||||
@ -18,8 +19,8 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
|
||||
private long lastStartPos = -1;
|
||||
|
||||
public IndirectInstancer(InstanceType<I> type) {
|
||||
super(type);
|
||||
public IndirectInstancer(InstanceType<I> type, Context context) {
|
||||
super(type, context);
|
||||
this.objectStride = type.layout()
|
||||
.byteSize() + IndirectBuffers.INT_SIZE;
|
||||
writer = this.type.writer();
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.jozufozu.flywheel.backend.engine.instancing;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.backend.InternalVertex;
|
||||
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
||||
import com.jozufozu.flywheel.backend.gl.array.GlVertexArray;
|
||||
@ -9,7 +11,9 @@ public class DrawCall {
|
||||
private final InstancedInstancer<?> instancer;
|
||||
private final InstancedMeshPool.BufferedMesh mesh;
|
||||
|
||||
@Nullable
|
||||
private GlVertexArray vao;
|
||||
@Nullable
|
||||
private GlVertexArray vaoScratch;
|
||||
|
||||
public DrawCall(InstancedInstancer<?> instancer, InstancedMeshPool.BufferedMesh mesh, ShaderState shaderState) {
|
||||
|
@ -13,7 +13,7 @@ import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
import com.jozufozu.flywheel.lib.context.ContextShaders;
|
||||
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
|
||||
@ -46,7 +46,7 @@ public class InstancedCrumbling {
|
||||
|
||||
CommonCrumbling.applyCrumblingProperties(crumblingMaterial, baseMaterial);
|
||||
|
||||
var program = programs.get(shader.instanceType(), Contexts.CRUMBLING);
|
||||
var program = programs.get(shader.instanceType(), ContextShaders.CRUMBLING);
|
||||
program.bind();
|
||||
|
||||
Uniforms.bindForDraw();
|
||||
|
@ -10,7 +10,6 @@ import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.jozufozu.flywheel.api.event.RenderStage;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.model.Mesh;
|
||||
import com.jozufozu.flywheel.backend.engine.InstancerKey;
|
||||
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
||||
@ -56,8 +55,8 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <I extends Instance> InstancedInstancer<I> create(InstanceType<I> type) {
|
||||
return new InstancedInstancer<>(type);
|
||||
protected <I extends Instance> InstancedInstancer<I> create(InstancerKey<I> key) {
|
||||
return new InstancedInstancer<>(key.type(), key.context());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,7 +70,7 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
|
||||
for (var entry : meshes.entrySet()) {
|
||||
var mesh = alloc(entry.getValue());
|
||||
|
||||
ShaderState shaderState = new ShaderState(entry.getKey(), instancer.type);
|
||||
ShaderState shaderState = new ShaderState(entry.getKey(), key.type(), key.context());
|
||||
DrawCall drawCall = new DrawCall(instancer, mesh, shaderState);
|
||||
|
||||
drawSet.put(shaderState, drawCall);
|
||||
|
@ -5,7 +5,10 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.Instance;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceWriter;
|
||||
@ -23,12 +26,13 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
|
||||
private final Set<GlVertexArray> boundTo = new HashSet<>();
|
||||
private final InstanceWriter<I> writer;
|
||||
@Nullable
|
||||
private GlBuffer vbo;
|
||||
|
||||
private final List<DrawCall> drawCalls = new ArrayList<>();
|
||||
|
||||
public InstancedInstancer(InstanceType<I> type) {
|
||||
super(type);
|
||||
public InstancedInstancer(InstanceType<I> type, Context context) {
|
||||
super(type, context);
|
||||
var layout = type.layout();
|
||||
instanceAttributes = LayoutAttributes.attributes(layout);
|
||||
instanceStride = layout.byteSize();
|
||||
@ -68,7 +72,7 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
}
|
||||
|
||||
private void updateBuffer() {
|
||||
if (changed.isEmpty()) {
|
||||
if (changed.isEmpty() || vbo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -120,6 +124,9 @@ public class InstancedInstancer<I extends Instance> extends AbstractInstancer<I>
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
if (vbo == null) {
|
||||
return;
|
||||
}
|
||||
vbo.delete();
|
||||
vbo = null;
|
||||
}
|
||||
|
@ -16,22 +16,18 @@ import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
|
||||
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialEncoder;
|
||||
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TextureBinder;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TexturesImpl;
|
||||
import com.jozufozu.flywheel.backend.engine.uniform.Uniforms;
|
||||
import com.jozufozu.flywheel.backend.gl.GlStateTracker;
|
||||
import com.jozufozu.flywheel.backend.gl.GlTextureUnit;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
import com.jozufozu.flywheel.lib.task.Flag;
|
||||
import com.jozufozu.flywheel.lib.task.NamedFlag;
|
||||
import com.jozufozu.flywheel.lib.task.SyncedPlan;
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
|
||||
public class InstancingEngine extends AbstractEngine {
|
||||
private final InstancingPrograms programs;
|
||||
private final TexturesImpl textures = new TexturesImpl();
|
||||
private final InstancedDrawManager drawManager = new InstancedDrawManager();
|
||||
private final Flag flushFlag = new NamedFlag("flushed");
|
||||
|
||||
@ -68,21 +64,7 @@ public class InstancingEngine extends AbstractEngine {
|
||||
}
|
||||
|
||||
try (var state = GlStateTracker.getRestoreState()) {
|
||||
GameRenderer gameRenderer = Minecraft.getInstance().gameRenderer;
|
||||
int prevActiveTexture = GlStateManager._getActiveTexture();
|
||||
gameRenderer.overlayTexture().setupOverlayColor();
|
||||
gameRenderer.lightTexture().turnOnLightLayer();
|
||||
|
||||
GlTextureUnit.T1.makeActive();
|
||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(1));
|
||||
GlTextureUnit.T2.makeActive();
|
||||
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
|
||||
|
||||
render(drawSet);
|
||||
|
||||
gameRenderer.overlayTexture().teardownOverlayColor();
|
||||
gameRenderer.lightTexture().turnOffLightLayer();
|
||||
GlStateManager._activeTexture(prevActiveTexture);
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,17 +98,21 @@ public class InstancingEngine extends AbstractEngine {
|
||||
continue;
|
||||
}
|
||||
|
||||
var program = programs.get(shader.instanceType(), Contexts.DEFAULT);
|
||||
var program = programs.get(shader.instanceType(), shader.context()
|
||||
.contextShader());
|
||||
program.bind();
|
||||
|
||||
Uniforms.bindForDraw();
|
||||
uploadMaterialUniform(program, shader.material());
|
||||
|
||||
shader.context()
|
||||
.prepare(shader.material(), program, textures);
|
||||
MaterialRenderState.setup(shader.material());
|
||||
|
||||
for (var drawCall : drawCalls) {
|
||||
drawCall.render();
|
||||
}
|
||||
TextureBinder.resetTextureBindings();
|
||||
}
|
||||
|
||||
MaterialRenderState.reset();
|
||||
|
@ -1,7 +1,8 @@
|
||||
package com.jozufozu.flywheel.backend.engine.instancing;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.api.instance.InstanceType;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
||||
public record ShaderState(Material material, InstanceType<?> instanceType) {
|
||||
public record ShaderState(Material material, InstanceType<?> instanceType, Context context) {
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.jozufozu.flywheel.backend.engine.textures;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Texture;
|
||||
|
||||
/**
|
||||
* Internal base interface that {@link com.jozufozu.flywheel.backend.gl.shader.GlProgram GlProgram} expects.
|
||||
*/
|
||||
public interface IdentifiedTexture extends Texture {
|
||||
/**
|
||||
* @return The GL texture id of this texture.
|
||||
*/
|
||||
int id();
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.jozufozu.flywheel.backend.engine.textures;
|
||||
|
||||
import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntArrayMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
|
||||
public class TextureBinder {
|
||||
// TODO: some kind of cache eviction when the program changes
|
||||
// so we don't always reset and bind the light and overlay textures?
|
||||
private static final Int2IntMap texturesToSamplerUnits = new Int2IntArrayMap();
|
||||
private static int nextSamplerUnit = 0;
|
||||
|
||||
/**
|
||||
* Binds the given texture to the next available texture unit, returning the unit it was bound to.
|
||||
*
|
||||
* @param id The id of the texture to bind.
|
||||
* @return The texture unit the texture was bound to.
|
||||
*/
|
||||
public static int bindTexture(int id) {
|
||||
return texturesToSamplerUnits.computeIfAbsent(id, i -> {
|
||||
int unit = nextSamplerUnit++;
|
||||
RenderSystem.activeTexture(GL_TEXTURE0 + unit);
|
||||
RenderSystem.bindTexture(i);
|
||||
return unit;
|
||||
});
|
||||
}
|
||||
|
||||
public static void resetTextureBindings() {
|
||||
nextSamplerUnit = 0;
|
||||
|
||||
for (Int2IntMap.Entry entry : texturesToSamplerUnits.int2IntEntrySet()) {
|
||||
RenderSystem.activeTexture(GL_TEXTURE0 + entry.getIntValue());
|
||||
RenderSystem.bindTexture(0);
|
||||
}
|
||||
|
||||
texturesToSamplerUnits.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.jozufozu.flywheel.backend.engine.textures;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Texture;
|
||||
import com.jozufozu.flywheel.api.context.Textures;
|
||||
import com.jozufozu.flywheel.backend.mixin.LightTextureAccessor;
|
||||
import com.jozufozu.flywheel.backend.mixin.OverlayTextureAccessor;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class TexturesImpl implements Textures {
|
||||
|
||||
private final DirectTexture lightTexture;
|
||||
private final DirectTexture overlayTexture;
|
||||
private final Map<ResourceLocation, WrappedTexture> wrappers = new HashMap<>();
|
||||
|
||||
public TexturesImpl() {
|
||||
var gameRenderer = Minecraft.getInstance().gameRenderer;
|
||||
|
||||
this.lightTexture = new DirectTexture(((LightTextureAccessor) gameRenderer.lightTexture()).flywheel$texture()
|
||||
.getId());
|
||||
this.overlayTexture = new DirectTexture(((OverlayTextureAccessor) gameRenderer.overlayTexture()).flywheel$texture()
|
||||
.getId());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Texture byName(ResourceLocation texture) {
|
||||
return wrappers.computeIfAbsent(texture, key -> new WrappedTexture(Minecraft.getInstance()
|
||||
.getTextureManager()
|
||||
.getTexture(key)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture overlay() {
|
||||
return overlayTexture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Texture light() {
|
||||
return lightTexture;
|
||||
}
|
||||
|
||||
public record WrappedTexture(AbstractTexture texture) implements IdentifiedTexture {
|
||||
@Override
|
||||
public void filter(boolean blur, boolean mipmap) {
|
||||
texture.setFilter(blur, mipmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int id() {
|
||||
return texture.getId();
|
||||
}
|
||||
}
|
||||
|
||||
public record DirectTexture(int id) implements IdentifiedTexture {
|
||||
@Override
|
||||
public void filter(boolean blur, boolean mipmap) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ public class GlStateTracker {
|
||||
}
|
||||
|
||||
public static State getRestoreState() {
|
||||
return new State(BUFFERS.clone(), vao, program);
|
||||
return new State(BUFFERS.clone(), vao, program, GlStateManager._getActiveTexture());
|
||||
}
|
||||
|
||||
public static void bindVao(int vao) {
|
||||
@ -51,7 +51,7 @@ public class GlStateTracker {
|
||||
}
|
||||
}
|
||||
|
||||
public record State(int[] buffers, int vao, int program) implements AutoCloseable {
|
||||
public record State(int[] buffers, int vao, int program, int activeTexture) implements AutoCloseable {
|
||||
public void restore() {
|
||||
if (vao != GlStateTracker.vao) {
|
||||
GlStateManager._glBindVertexArray(vao);
|
||||
@ -68,6 +68,8 @@ public class GlStateTracker {
|
||||
if (program != GlStateTracker.program) {
|
||||
GlStateManager._glUseProgram(program);
|
||||
}
|
||||
|
||||
GlStateManager._activeTexture(activeTexture);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,6 +9,10 @@ import static org.lwjgl.opengl.GL31.glUniformBlockBinding;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Shader;
|
||||
import com.jozufozu.flywheel.api.context.Texture;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.IdentifiedTexture;
|
||||
import com.jozufozu.flywheel.backend.engine.textures.TextureBinder;
|
||||
import com.jozufozu.flywheel.backend.gl.GlObject;
|
||||
import com.mojang.blaze3d.shaders.ProgramManager;
|
||||
import com.mojang.logging.LogUtils;
|
||||
@ -16,7 +20,7 @@ import com.mojang.logging.LogUtils;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
|
||||
public class GlProgram extends GlObject {
|
||||
public class GlProgram extends GlObject implements Shader {
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
private final Object2IntMap<String> uniformLocationCache = new Object2IntOpenHashMap<>();
|
||||
@ -33,6 +37,24 @@ public class GlProgram extends GlObject {
|
||||
ProgramManager.glUseProgram(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTexture(String glslName, Texture texture) {
|
||||
if (!(texture instanceof IdentifiedTexture identified)) {
|
||||
return;
|
||||
}
|
||||
int uniform = getUniformLocation(glslName);
|
||||
|
||||
if (uniform < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int id = identified.id();
|
||||
|
||||
int binding = TextureBinder.bindTexture(id);
|
||||
|
||||
glUniform1i(uniform, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the index of the uniform with the given name.
|
||||
*
|
||||
|
@ -0,0 +1,13 @@
|
||||
package com.jozufozu.flywheel.backend.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
|
||||
@Mixin(LightTexture.class)
|
||||
public interface LightTextureAccessor {
|
||||
@Accessor("lightTexture")
|
||||
DynamicTexture flywheel$texture();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package com.jozufozu.flywheel.backend.mixin;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
|
||||
@Mixin(OverlayTexture.class)
|
||||
public interface OverlayTextureAccessor {
|
||||
@Accessor("texture")
|
||||
DynamicTexture flywheel$texture();
|
||||
}
|
@ -10,12 +10,13 @@ import com.jozufozu.flywheel.api.instance.Instancer;
|
||||
import com.jozufozu.flywheel.api.instance.InstancerProvider;
|
||||
import com.jozufozu.flywheel.api.model.Model;
|
||||
import com.jozufozu.flywheel.api.visualization.VisualizationContext;
|
||||
import com.jozufozu.flywheel.lib.context.Contexts;
|
||||
|
||||
public record InstancerProviderImpl(Engine engine,
|
||||
RenderStage renderStage) implements InstancerProvider, Supplier<VisualizationContext> {
|
||||
@Override
|
||||
public <I extends Instance> Instancer<I> instancer(InstanceType<I> type, Model model) {
|
||||
return engine.instancer(type, model, renderStage);
|
||||
return engine.instancer(type, Contexts.DEFAULT, model, renderStage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,18 @@
|
||||
package com.jozufozu.flywheel.lib.context;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
|
||||
public class ContextShaders {
|
||||
public static final SimpleContextShader DEFAULT = ContextShader.REGISTRY.registerAndGet(new SimpleContextShader(Flywheel.rl("context/default.vert"), Flywheel.rl("context/default.frag")));
|
||||
public static final SimpleContextShader CRUMBLING = ContextShader.REGISTRY.registerAndGet(new SimpleContextShader(Flywheel.rl("context/crumbling.vert"), Flywheel.rl("context/crumbling.frag")));
|
||||
|
||||
private ContextShaders() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
@ -1,37 +1,48 @@
|
||||
package com.jozufozu.flywheel.lib.context;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import com.jozufozu.flywheel.Flywheel;
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
import com.jozufozu.flywheel.api.context.Shader;
|
||||
import com.jozufozu.flywheel.api.context.Textures;
|
||||
import com.jozufozu.flywheel.api.material.Material;
|
||||
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
|
||||
public final class Contexts {
|
||||
public static final SimpleContext DEFAULT = Context.REGISTRY.registerAndGet(new SimpleContext(
|
||||
Flywheel.rl("context/default.vert"),
|
||||
Flywheel.rl("context/default.frag"),
|
||||
program -> {
|
||||
program.bind();
|
||||
program.setSamplerBinding("_flw_diffuseTex", 0);
|
||||
program.setSamplerBinding("_flw_overlayTex", 1);
|
||||
program.setSamplerBinding("_flw_lightTex", 2);
|
||||
GlProgram.unbind();
|
||||
}));
|
||||
public static final Context DEFAULT = new Context() {
|
||||
@Override
|
||||
public ContextShader contextShader() {
|
||||
return ContextShaders.DEFAULT;
|
||||
}
|
||||
|
||||
public static final SimpleContext CRUMBLING = Context.REGISTRY.registerAndGet(new SimpleContext(
|
||||
Flywheel.rl("context/crumbling.vert"),
|
||||
Flywheel.rl("context/crumbling.frag"),
|
||||
program -> {
|
||||
program.bind();
|
||||
program.setSamplerBinding("_flw_crumblingTex", 0);
|
||||
program.setSamplerBinding("_flw_diffuseTex", 1);
|
||||
GlProgram.unbind();
|
||||
}));
|
||||
@Override
|
||||
public void prepare(Material material, Shader shader, Textures textures) {
|
||||
var texture = textures.byName(material.texture());
|
||||
texture.filter(material.blur(), material.mipmap());
|
||||
shader.setTexture("_flw_diffuseTex", texture);
|
||||
|
||||
shader.setTexture("_flw_overlayTex", textures.overlay());
|
||||
shader.setTexture("_flw_lightTex", textures.light());
|
||||
}
|
||||
};
|
||||
|
||||
public static final Context CRUMBLING = new Context() {
|
||||
@Override
|
||||
public ContextShader contextShader() {
|
||||
return ContextShaders.CRUMBLING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prepare(Material material, Shader shader, Textures textures) {
|
||||
var texture = textures.byName(material.texture());
|
||||
texture.filter(material.blur(), material.mipmap());
|
||||
shader.setTexture("_flw_diffuseTex", texture);
|
||||
|
||||
var crumblingTexture = textures.byName(ModelBakery.BREAKING_LOCATIONS.get(0));
|
||||
shader.setTexture("_flw_crumblingTex", crumblingTexture);
|
||||
}
|
||||
};
|
||||
|
||||
private Contexts() {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static void init() {
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
package com.jozufozu.flywheel.lib.context;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.Context;
|
||||
import com.jozufozu.flywheel.backend.gl.shader.GlProgram;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public record SimpleContext(ResourceLocation vertexShader, ResourceLocation fragmentShader, Consumer<GlProgram> onLink) implements Context {
|
||||
@Override
|
||||
public void onProgramLink(GlProgram program) {
|
||||
onLink.accept(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation vertexShader() {
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation fragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.jozufozu.flywheel.lib.context;
|
||||
|
||||
import com.jozufozu.flywheel.api.context.ContextShader;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public record SimpleContextShader(ResourceLocation vertexShader,
|
||||
ResourceLocation fragmentShader) implements ContextShader {
|
||||
@Override
|
||||
public ResourceLocation vertexShader() {
|
||||
return vertexShader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation fragmentShader() {
|
||||
return fragmentShader;
|
||||
}
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
"refmap": "flywheel.refmap.json",
|
||||
"client": [
|
||||
"GlStateManagerMixin",
|
||||
"LightTextureAccessor",
|
||||
"OverlayTextureAccessor",
|
||||
"RenderSystemMixin"
|
||||
],
|
||||
"injectors": {
|
||||
|
Loading…
Reference in New Issue
Block a user