Merge remote-tracking branch 'origin/1.20/next' into 1.20/next

# Conflicts:
#	src/main/java/com/jozufozu/flywheel/backend/compile/PipelineCompiler.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectBuffers.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectCullingGroup.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectDrawManager.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectEngine.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectInstancer.java
#	src/main/java/com/jozufozu/flywheel/backend/engine/indirect/IndirectModel.java
#	src/main/resources/assets/flywheel/flywheel/internal/indirect/draw.vert
#	src/main/resources/assets/flywheel/flywheel/internal/instancing/main.vert
#	src/main/resources/assets/flywheel/flywheel/internal/layout.vert
This commit is contained in:
Jozufozu 2023-12-07 12:37:41 -08:00
commit ea4ec918a6
100 changed files with 830 additions and 884 deletions

View file

@ -7,22 +7,17 @@
/*const*/ vec2 flw_vertexLight; /*const*/ vec2 flw_vertexLight;
/*const*/ vec3 flw_vertexNormal; /*const*/ vec3 flw_vertexNormal;
/*const*/ float flw_distance;
/*const*/ vec4 flw_var0;
/*const*/ vec4 flw_var1;
/*const*/ vec4 flw_var2;
/*const*/ vec4 flw_var3;
/*const*/ FlwMaterial flw_material; /*const*/ FlwMaterial flw_material;
/*const*/ vec4 flw_sampleColor; /*const*/ vec4 flw_sampleColor;
/*const*/ float flw_distance;
vec4 flw_fragColor; vec4 flw_fragColor;
ivec2 flw_fragOverlay; ivec2 flw_fragOverlay;
vec2 flw_fragLight; vec2 flw_fragLight;
// To be implemented by material shaders. // To be implemented by the material fragment shader.
vec4 flw_fogFilter(vec4 color); vec4 flw_fogFilter(vec4 color);
bool flw_discardPredicate(vec4 finalColor); bool flw_discardPredicate(vec4 finalColor);
void flw_materialFragment(); void flw_materialFragment();

View file

@ -10,12 +10,12 @@ const uint FLW_MAT_DEPTH_TEST_ALWAYS = 8u;
const uint FLW_MAT_TRANSPARENCY_OPAQUE = 0u; const uint FLW_MAT_TRANSPARENCY_OPAQUE = 0u;
const uint FLW_MAT_TRANSPARENCY_ADDITIVE = 1u; const uint FLW_MAT_TRANSPARENCY_ADDITIVE = 1u;
const uint FLW_MAT_TRANSPARENCY_LIGHTING = 2u; const uint FLW_MAT_TRANSPARENCY_LIGHTNING = 2u;
const uint FLW_MAT_TRANSPARENCY_GLINT = 3u; const uint FLW_MAT_TRANSPARENCY_GLINT = 3u;
const uint FLW_MAT_TRANSPARENCY_CRUMBLING = 4u; const uint FLW_MAT_TRANSPARENCY_CRUMBLING = 4u;
const uint FLW_MAT_TRANSPARENCY_TRANSLUCENT = 5u; const uint FLW_MAT_TRANSPARENCY_TRANSLUCENT = 5u;
const uint FLW_MAT_WRITE_MASK_BOTH = 0u; const uint FLW_MAT_WRITE_MASK_COLOR_DEPTH = 0u;
const uint FLW_MAT_WRITE_MASK_COLOR = 1u; const uint FLW_MAT_WRITE_MASK_COLOR = 1u;
const uint FLW_MAT_WRITE_MASK_DEPTH = 2u; const uint FLW_MAT_WRITE_MASK_DEPTH = 2u;

View file

@ -7,20 +7,13 @@ ivec2 flw_vertexOverlay;
vec2 flw_vertexLight; vec2 flw_vertexLight;
vec3 flw_vertexNormal; vec3 flw_vertexNormal;
float flw_distance;
vec4 flw_var0;
vec4 flw_var1;
vec4 flw_var2;
vec4 flw_var3;
/*const*/ FlwMaterial flw_material; /*const*/ FlwMaterial flw_material;
// To be implemented by the instance shader. // To be implemented by the instance shader.
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius); void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
void flw_instanceVertex(FlwInstance i); void flw_instanceVertex(FlwInstance i);
// To be implemented by material shaders. // To be implemented by the material vertex shader.
void flw_materialVertex(); void flw_materialVertex();
// To be implemented by the context shader. // To be implemented by the context shader.

View file

@ -14,7 +14,7 @@ public interface Material {
CutoutShader cutout(); CutoutShader cutout();
ResourceLocation baseTexture(); ResourceLocation texture();
/** /**
* Should this material have linear filtering applied to the diffuse sampler? * Should this material have linear filtering applied to the diffuse sampler?

View file

@ -3,7 +3,7 @@ package com.jozufozu.flywheel.api.material;
public enum Transparency { public enum Transparency {
OPAQUE, OPAQUE,
ADDITIVE, ADDITIVE,
LIGHTING, LIGHTNING,
GLINT, GLINT,
CRUMBLING, CRUMBLING,
TRANSLUCENT, TRANSLUCENT,

View file

@ -4,7 +4,7 @@ public enum WriteMask {
/** /**
* Write to both the color and depth buffers. * Write to both the color and depth buffers.
*/ */
BOTH, COLOR_DEPTH,
/** /**
* Write to the color buffer only. * Write to the color buffer only.
*/ */
@ -15,11 +15,11 @@ public enum WriteMask {
DEPTH, DEPTH,
; ;
public boolean depth() { public boolean color() {
return this == BOTH || this == DEPTH; return this == COLOR_DEPTH || this == COLOR;
} }
public boolean color() { public boolean depth() {
return this == BOTH || this == COLOR; return this == COLOR_DEPTH || this == DEPTH;
} }
} }

View file

@ -2,18 +2,24 @@ package com.jozufozu.flywheel.api.model;
import java.util.Map; import java.util.Map;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
public interface Model { public interface Model {
Map<Material, Mesh> getMeshes(); Map<Material, Mesh> meshes();
/**
* Get a vec4 representing this model's bounding sphere in the format (x, y, z, radius).
* It should encompass all meshes' bounding spheres.
*
* @return A vec4 view.
*/
Vector4fc boundingSphere();
// TODO: unused. remove?
@Deprecated
int vertexCount();
void delete(); void delete();
default int getVertexCount() {
int size = 0;
for (Mesh mesh : getMeshes().values()) {
size += mesh.vertexCount();
}
return size;
}
} }

View file

@ -3,6 +3,9 @@ package com.jozufozu.flywheel.api.task;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.function.BooleanSupplier; import java.util.function.BooleanSupplier;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.NonExtendable
public interface TaskExecutor extends Executor { public interface TaskExecutor extends Executor {
/** /**
* Wait for <em>all</em> running tasks to finish. * Wait for <em>all</em> running tasks to finish.
@ -38,15 +41,6 @@ public interface TaskExecutor extends Executor {
*/ */
boolean syncWhile(BooleanSupplier cond); boolean syncWhile(BooleanSupplier cond);
/**
* Check for the number of threads this executor uses.
* <br>
* May be helpful when determining how many chunks to divide a task into.
*
* @return The number of threads this executor uses.
*/
int getThreadCount();
/** /**
* Schedule a task to be run on the main thread. * Schedule a task to be run on the main thread.
* <br> * <br>
@ -64,4 +58,13 @@ public interface TaskExecutor extends Executor {
* @return {@code true} if the current thread is the main thread. * @return {@code true} if the current thread is the main thread.
*/ */
boolean isMainThread(); boolean isMainThread();
/**
* Check for the number of threads this executor uses.
* <br>
* May be helpful when determining how many chunks to divide a task into.
*
* @return The number of threads this executor uses.
*/
int getThreadCount();
} }

View file

@ -1,5 +1,8 @@
package com.jozufozu.flywheel.api.visualization; package com.jozufozu.flywheel.api.visualization;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.NonExtendable
public interface VisualManager<T> { public interface VisualManager<T> {
/** /**
* Get the number of game objects that are currently being visualized. * Get the number of game objects that are currently being visualized.

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.api.visualization; package com.jozufozu.flywheel.api.visualization;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.api.visual.Effect; import com.jozufozu.flywheel.api.visual.Effect;
@ -12,6 +13,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ApiStatus.NonExtendable
public interface VisualizationManager { public interface VisualizationManager {
static boolean supportsVisualization(@Nullable LevelAccessor level) { static boolean supportsVisualization(@Nullable LevelAccessor level) {
return VisualizationManagerImpl.supportsVisualization(level); return VisualizationManagerImpl.supportsVisualization(level);

View file

@ -19,7 +19,7 @@ import com.jozufozu.flywheel.backend.compile.core.ShaderCompiler;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
@ -36,7 +36,7 @@ import net.minecraft.resources.ResourceLocation;
* @param <K> The type of the key used to compile shaders. * @param <K> The type of the key used to compile shaders.
*/ */
public class Compile<K> { public class Compile<K> {
public ShaderCompilerBuilder<K> shader(GLSLVersion glslVersion, ShaderType shaderType) { public ShaderCompilerBuilder<K> shader(GlslVersion glslVersion, ShaderType shaderType) {
return new ShaderCompilerBuilder<>(glslVersion, shaderType); return new ShaderCompilerBuilder<>(glslVersion, shaderType);
} }
@ -99,13 +99,13 @@ public class Compile<K> {
} }
public static class ShaderCompilerBuilder<K> { public static class ShaderCompilerBuilder<K> {
private final GLSLVersion glslVersion; private final GlslVersion glslVersion;
private final ShaderType shaderType; private final ShaderType shaderType;
private Consumer<Compilation> compilationCallbacks = $ -> { private Consumer<Compilation> compilationCallbacks = $ -> {
}; };
private final List<BiFunction<K, SourceLoader, SourceComponent>> fetchers = new ArrayList<>(); private final List<BiFunction<K, SourceLoader, SourceComponent>> fetchers = new ArrayList<>();
public ShaderCompilerBuilder(GLSLVersion glslVersion, ShaderType shaderType) { public ShaderCompilerBuilder(GlslVersion glslVersion, ShaderType shaderType) {
this.glslVersion = glslVersion; this.glslVersion = glslVersion;
this.shaderType = shaderType; this.shaderType = shaderType;
} }

View file

@ -24,8 +24,7 @@ public class FlwPrograms {
} }
public static void reload(ResourceManager resourceManager) { public static void reload(ResourceManager resourceManager) {
var empty = List.of(Flywheel.rl("api/fragment.glsl"), Flywheel.rl("api/vertex.glsl")); var sources = new ShaderSources(resourceManager);
var sources = new ShaderSources(resourceManager, empty);
var preLoadStats = new CompilerStats(); var preLoadStats = new CompilerStats();
var loadChecker = new SourceLoader(sources, preLoadStats); var loadChecker = new SourceLoader(sources, preLoadStats);
@ -43,12 +42,31 @@ public class FlwPrograms {
} }
} }
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
for (Context context : Context.REGISTRY) {
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(new PipelineProgramKey(instanceType, context));
}
}
return builder.build();
}
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_material_vertex"))
.materialSources(ShaderIndices.materialVertex()
.all())
.adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("_flw_uberMaterialVertexIndex"))
.build(loadChecker);
}
private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) { private static UberShaderComponent createFragmentMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("uber_fragment_material")) return UberShaderComponent.builder(Flywheel.rl("uber_material_fragment"))
.materialSources(ShaderIndices.materialFragment() .materialSources(ShaderIndices.materialFragment()
.all()) .all())
.adapt(FnSignature.ofVoid("flw_materialFragment")) .adapt(FnSignature.ofVoid("flw_materialFragment"))
.switchOn(GlslExpr.variable("_flw_materialFragmentID")) .switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
.build(loadChecker); .build(loadChecker);
} }
@ -61,7 +79,7 @@ public class FlwPrograms {
.name("flw_fogFilter") .name("flw_fogFilter")
.arg("vec4", "color") .arg("vec4", "color")
.build(), GlslExpr.variable("color")) .build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_fogID")) .switchOn(GlslExpr.variable("_flw_uberFogIndex"))
.build(loadChecker); .build(loadChecker);
} }
@ -74,16 +92,7 @@ public class FlwPrograms {
.name("flw_discardPredicate") .name("flw_discardPredicate")
.arg("vec4", "color") .arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false)) .build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_cutoutID")) .switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
.build(loadChecker);
}
private static UberShaderComponent createVertexMaterialComponent(SourceLoader loadChecker) {
return UberShaderComponent.builder(Flywheel.rl("vertex_material_adapter"))
.materialSources(ShaderIndices.materialVertex()
.all())
.adapt(FnSignature.ofVoid("flw_materialVertex"))
.switchOn(GlslExpr.variable("_flw_materialVertexID"))
.build(loadChecker); .build(loadChecker);
} }
@ -96,16 +105,6 @@ public class FlwPrograms {
.build(loadChecker); .build(loadChecker);
} }
private static ImmutableList<PipelineProgramKey> createPipelineKeys() {
ImmutableList.Builder<PipelineProgramKey> builder = ImmutableList.builder();
for (Context context : Context.REGISTRY) {
for (InstanceType<?> instanceType : InstanceType.REGISTRY) {
builder.add(new PipelineProgramKey(instanceType, context));
}
}
return builder.build();
}
public static class ResourceReloadListener implements ResourceManagerReloadListener { public static class ResourceReloadListener implements ResourceManagerReloadListener {
public static final ResourceReloadListener INSTANCE = new ResourceReloadListener(); public static final ResourceReloadListener INSTANCE = new ResourceReloadListener();

View file

@ -14,7 +14,7 @@ import com.jozufozu.flywheel.backend.compile.component.UniformComponent;
import com.jozufozu.flywheel.gl.GlCompat; import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.ShaderSources; import com.jozufozu.flywheel.glsl.ShaderSources;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.lib.util.Unit; import com.jozufozu.flywheel.lib.util.Unit;
@ -39,21 +39,22 @@ public class IndirectPrograms {
_delete(); _delete();
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents); var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
var cullingCompiler = createCullingCompiler(uniformComponent, sources); var cullingCompiler = createCullingCompiler(uniformComponent, sources);
var stage2Compiler = createStage2Compiler(sources); var applyCompiler = createApplyCompiler(sources);
try { try {
var pipelineResult = pipelineCompiler.compileAndReportErrors(); var pipelineResult = pipelineCompiler.compileAndReportErrors();
var cullingResult = cullingCompiler.compileAndReportErrors(); var cullingResult = cullingCompiler.compileAndReportErrors();
var stage2Result = stage2Compiler.compileAndReportErrors(); var applyResult = applyCompiler.compileAndReportErrors();
if (pipelineResult != null && cullingResult != null && stage2Result != null) { if (pipelineResult != null && cullingResult != null && applyResult != null) {
instance = new IndirectPrograms(pipelineResult, cullingResult, stage2Result.get(Unit.INSTANCE)); instance = new IndirectPrograms(pipelineResult, cullingResult, applyResult.get(Unit.INSTANCE));
} }
} catch (Throwable e) { } catch (Throwable e) {
Flywheel.LOGGER.error("Failed to compile indirect programs", e); Flywheel.LOGGER.error("Failed to compile indirect programs", e);
} }
pipelineCompiler.delete(); pipelineCompiler.delete();
cullingCompiler.delete(); cullingCompiler.delete();
applyCompiler.delete();
} }
private static ImmutableList<InstanceType<?>> createCullingKeys() { private static ImmutableList<InstanceType<?>> createCullingKeys() {
@ -84,22 +85,22 @@ public class IndirectPrograms {
return CULL.harness(sources) return CULL.harness(sources)
.keys(createCullingKeys()) .keys(createCullingKeys())
.compiler(CULL.program() .compiler(CULL.program()
.link(CULL.shader(GLSLVersion.V460, ShaderType.COMPUTE) .link(CULL.shader(GlslVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE) .define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withComponent(uniformComponent) .withComponent(uniformComponent)
.withComponent(IndirectComponent::create) .withComponent(IndirectComponent::create)
.withResource(Files.INDIRECT_CULL) .withResource(Files.INDIRECT_CULL)
.withResource(InstanceType::instanceShader)) .withResource(InstanceType::instanceShader))
.then((key, program) -> program.setUniformBlockBinding("FLWUniforms", 0))) .then((key, program) -> program.setUniformBlockBinding("FlwUniforms", 0)))
.build(); .build();
} }
private static CompilationHarness<Unit> createStage2Compiler(ShaderSources sources) { private static CompilationHarness<Unit> createApplyCompiler(ShaderSources sources) {
return APPLY.harness(sources) return APPLY.harness(sources)
.keys(ImmutableList.of(Unit.INSTANCE)) .keys(ImmutableList.of(Unit.INSTANCE))
.compiler(APPLY.program() .compiler(APPLY.program()
.link(APPLY.shader(GLSLVersion.V460, ShaderType.COMPUTE) .link(APPLY.shader(GlslVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE) .define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withResource(Files.INDIRECT_APPLY))) .withResource(Files.INDIRECT_APPLY)))
.build(); .build();
} }

View file

@ -3,13 +3,13 @@ package com.jozufozu.flywheel.backend.compile;
import java.util.Objects; import java.util.Objects;
import com.jozufozu.flywheel.api.instance.InstanceType; import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, ResourceLocation fragmentShader, public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, ResourceLocation fragmentMain,
ResourceLocation vertexAPI, ResourceLocation fragmentAPI, InstanceAssembler assembler) { ResourceLocation vertexApiImpl, ResourceLocation fragmentApiImpl, InstanceAssembler assembler) {
@FunctionalInterface @FunctionalInterface
public interface InstanceAssembler { public interface InstanceAssembler {
/** /**
@ -28,35 +28,35 @@ public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, R
} }
public static class Builder { public static class Builder {
private GLSLVersion glslVersion; private GlslVersion glslVersion;
private ResourceLocation vertex; private ResourceLocation vertexMain;
private ResourceLocation fragment; private ResourceLocation fragmentMain;
private ResourceLocation vertexAPI; private ResourceLocation vertexApiImpl;
private ResourceLocation fragmentAPI; private ResourceLocation fragmentApiImpl;
private InstanceAssembler assembler; private InstanceAssembler assembler;
public Builder glslVersion(GLSLVersion glslVersion) { public Builder glslVersion(GlslVersion glslVersion) {
this.glslVersion = glslVersion; this.glslVersion = glslVersion;
return this; return this;
} }
public Builder vertex(ResourceLocation vertex) { public Builder vertexMain(ResourceLocation shader) {
this.vertex = vertex; this.vertexMain = shader;
return this; return this;
} }
public Builder fragment(ResourceLocation fragment) { public Builder fragmentMain(ResourceLocation shader) {
this.fragment = fragment; this.fragmentMain = shader;
return this; return this;
} }
public Builder vertexAPI(ResourceLocation vertex) { public Builder vertexApiImpl(ResourceLocation shader) {
this.vertexAPI = vertex; this.vertexApiImpl = shader;
return this; return this;
} }
public Builder fragmentAPI(ResourceLocation fragment) { public Builder fragmentApiImpl(ResourceLocation shader) {
this.fragmentAPI = fragment; this.fragmentApiImpl = shader;
return this; return this;
} }
@ -67,12 +67,12 @@ public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, R
public Pipeline build() { public Pipeline build() {
Objects.requireNonNull(glslVersion); Objects.requireNonNull(glslVersion);
Objects.requireNonNull(vertex); Objects.requireNonNull(vertexMain);
Objects.requireNonNull(fragment); Objects.requireNonNull(fragmentMain);
Objects.requireNonNull(vertexAPI); Objects.requireNonNull(vertexApiImpl);
Objects.requireNonNull(fragmentAPI); Objects.requireNonNull(fragmentApiImpl);
Objects.requireNonNull(assembler); Objects.requireNonNull(assembler);
return new Pipeline(glslVersion, vertex, fragment, vertexAPI, fragmentAPI, assembler); return new Pipeline(glslVersion, vertexMain, fragmentMain, vertexApiImpl, fragmentApiImpl, assembler);
} }
} }
} }

View file

@ -20,25 +20,25 @@ public class PipelineCompiler {
.withComponent(uniformComponent) .withComponent(uniformComponent)
.withComponent(key -> pipeline.assembler() .withComponent(key -> pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(InternalLayout.LAYOUT.getAttributeCount(), key.instanceType()))) .assemble(new Pipeline.InstanceAssemblerContext(InternalLayout.LAYOUT.getAttributeCount(), key.instanceType())))
.withResource(pipeline.vertexAPI()) .withResource(pipeline.vertexApiImpl())
.withComponents(vertexComponents) .withComponents(vertexComponents)
.withResource(key -> key.instanceType() .withResource(key -> key.instanceType()
.instanceShader()) .instanceShader())
.withResource(key -> key.contextShader() .withResource(key -> key.contextShader()
.vertexShader()) .vertexShader())
.withResource(pipeline.vertexShader())) .withResource(pipeline.vertexMain()))
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT) .link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
.enableExtension("GL_ARB_conservative_depth") .enableExtension("GL_ARB_conservative_depth")
.withComponent(uniformComponent) .withComponent(uniformComponent)
.withResource(pipeline.fragmentAPI()) .withResource(pipeline.fragmentApiImpl())
.withComponents(fragmentComponents) .withComponents(fragmentComponents)
.withResource(key -> key.contextShader() .withResource(key -> key.contextShader()
.fragmentShader()) .fragmentShader())
.withResource(pipeline.fragmentShader())) .withResource(pipeline.fragmentMain()))
.then((key, program) -> { .then((key, program) -> {
key.contextShader() key.contextShader()
.onProgramLink(program); .onProgramLink(program);
program.setUniformBlockBinding("FLWUniforms", 0); program.setUniformBlockBinding("FlwUniforms", 0);
})) }))
.build(); .build();
} }

View file

@ -3,23 +3,23 @@ package com.jozufozu.flywheel.backend.compile;
import com.jozufozu.flywheel.Flywheel; import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.backend.compile.component.IndirectComponent; import com.jozufozu.flywheel.backend.compile.component.IndirectComponent;
import com.jozufozu.flywheel.backend.compile.component.InstancedArraysComponent; import com.jozufozu.flywheel.backend.compile.component.InstancedArraysComponent;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
public final class Pipelines { public final class Pipelines {
public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder() public static final Pipeline INSTANCED_ARRAYS = Pipeline.builder()
.glslVersion(GLSLVersion.V330) .glslVersion(GlslVersion.V330)
.vertex(Flywheel.rl("internal/instancing/draw.vert")) .vertexMain(Flywheel.rl("internal/instancing/main.vert"))
.fragment(Flywheel.rl("internal/instancing/draw.frag")) .fragmentMain(Flywheel.rl("internal/instancing/main.frag"))
.vertexAPI(Flywheel.rl("internal/instancing/api/vertex.glsl")) .vertexApiImpl(Flywheel.rl("internal/instancing/api_impl.vert"))
.fragmentAPI(Flywheel.rl("internal/instancing/api/fragment.glsl")) .fragmentApiImpl(Flywheel.rl("internal/instancing/api_impl.frag"))
.assembler(InstancedArraysComponent::new) .assembler(InstancedArraysComponent::new)
.build(); .build();
public static final Pipeline INDIRECT = Pipeline.builder() public static final Pipeline INDIRECT = Pipeline.builder()
.glslVersion(GLSLVersion.V460) .glslVersion(GlslVersion.V460)
.vertex(Flywheel.rl("internal/indirect/draw.vert")) .vertexMain(Flywheel.rl("internal/indirect/main.vert"))
.fragment(Flywheel.rl("internal/indirect/draw.frag")) .fragmentMain(Flywheel.rl("internal/indirect/main.frag"))
.vertexAPI(Flywheel.rl("internal/indirect/api/vertex.glsl")) .vertexApiImpl(Flywheel.rl("internal/indirect/api_impl.vert"))
.fragmentAPI(Flywheel.rl("internal/indirect/api/fragment.glsl")) .fragmentApiImpl(Flywheel.rl("internal/indirect/api_impl.frag"))
.assembler(IndirectComponent::create) .assembler(IndirectComponent::create)
.build(); .build();
} }

View file

@ -36,8 +36,8 @@ public class UniformComponent implements SourceComponent {
builder.uniformBlock() builder.uniformBlock()
.layout("std140") .layout("std140")
.name("FLWUniforms") .name("FlwUniforms")
.member("flywheel_uniforms", "flywheel"); .member("FlywheelUniforms", "flywheel");
builder.blankLine(); builder.blankLine();

View file

@ -12,7 +12,7 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.gl.GlCompat; import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
import com.jozufozu.flywheel.glsl.SourceFile; import com.jozufozu.flywheel.glsl.SourceFile;
import com.jozufozu.flywheel.lib.util.StringUtil; import com.jozufozu.flywheel.lib.util.StringUtil;
@ -31,11 +31,11 @@ public class Compilation {
private final List<SourceFile> files = new ArrayList<>(); private final List<SourceFile> files = new ArrayList<>();
private final StringBuilder generatedSource; private final StringBuilder generatedSource;
private final StringBuilder fullSource; private final StringBuilder fullSource;
private final GLSLVersion glslVersion; private final GlslVersion glslVersion;
private final ShaderType shaderType; private final ShaderType shaderType;
private int generatedLines = 0; private int generatedLines = 0;
public Compilation(GLSLVersion glslVersion, ShaderType shaderType) { public Compilation(GlslVersion glslVersion, ShaderType shaderType) {
this.glslVersion = glslVersion; this.glslVersion = glslVersion;
this.shaderType = shaderType; this.shaderType = shaderType;
@ -88,12 +88,12 @@ public class Compilation {
private void appendHeader(SourceComponent component, String source) { private void appendHeader(SourceComponent component, String source) {
if (component instanceof SourceFile file) { if (component instanceof SourceFile file) {
int fileID = files.size() + 1; int fileId = files.size() + 1;
files.add(file); files.add(file);
fullSource.append("\n#line 0 ") fullSource.append("\n#line 0 ")
.append(fileID) .append(fileId)
.append(" // ") .append(" // ")
.append(file.name) .append(file.name)
.append('\n'); .append('\n');

View file

@ -12,7 +12,7 @@ import org.jetbrains.annotations.Nullable;
import com.jozufozu.flywheel.gl.shader.GlShader; import com.jozufozu.flywheel.gl.shader.GlShader;
import com.jozufozu.flywheel.gl.shader.ShaderType; import com.jozufozu.flywheel.gl.shader.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion; import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.SourceComponent; import com.jozufozu.flywheel.glsl.SourceComponent;
public class ShaderCompiler { public class ShaderCompiler {
@ -24,7 +24,7 @@ public class ShaderCompiler {
} }
@Nullable @Nullable
public GlShader compile(GLSLVersion glslVersion, ShaderType shaderType, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) { public GlShader compile(GlslVersion glslVersion, ShaderType shaderType, Consumer<Compilation> callback, List<SourceComponent> sourceComponents) {
var key = new ShaderKey(glslVersion, shaderType, sourceComponents); var key = new ShaderKey(glslVersion, shaderType, sourceComponents);
var cached = shaderCache.get(key); var cached = shaderCache.get(key);
if (cached != null) { if (cached != null) {
@ -67,6 +67,6 @@ public class ShaderCompiler {
included.addAll(component.included()); included.addAll(component.included());
} }
private record ShaderKey(GLSLVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) { private record ShaderKey(GlslVersion glslVersion, ShaderType shaderType, List<SourceComponent> sourceComponents) {
} }
} }

View file

@ -1,9 +1,10 @@
package com.jozufozu.flywheel.backend; package com.jozufozu.flywheel.backend.engine;
import com.jozufozu.flywheel.api.material.DepthTest; import com.jozufozu.flywheel.api.material.DepthTest;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.material.Transparency; import com.jozufozu.flywheel.api.material.Transparency;
import com.jozufozu.flywheel.api.material.WriteMask; import com.jozufozu.flywheel.api.material.WriteMask;
import com.jozufozu.flywheel.backend.ShaderIndices;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;

View file

@ -1,4 +1,4 @@
package com.jozufozu.flywheel.backend; package com.jozufozu.flywheel.backend.engine;
import java.util.Comparator; import java.util.Comparator;
@ -16,7 +16,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AbstractTexture; import net.minecraft.client.renderer.texture.AbstractTexture;
public final class MaterialRenderState { public final class MaterialRenderState {
public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::baseTexture) public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::texture)
.thenComparing(Material::blur) .thenComparing(Material::blur)
.thenComparing(Material::mipmap) .thenComparing(Material::mipmap)
.thenComparing(Material::backfaceCulling) .thenComparing(Material::backfaceCulling)
@ -41,7 +41,7 @@ public final class MaterialRenderState {
GlTextureUnit.T0.makeActive(); GlTextureUnit.T0.makeActive();
AbstractTexture texture = Minecraft.getInstance() AbstractTexture texture = Minecraft.getInstance()
.getTextureManager() .getTextureManager()
.getTexture(material.baseTexture()); .getTexture(material.texture());
texture.setFilter(material.blur(), material.mipmap()); texture.setFilter(material.blur(), material.mipmap());
var textureId = texture.getId(); var textureId = texture.getId();
RenderSystem.setShaderTexture(0, textureId); RenderSystem.setShaderTexture(0, textureId);
@ -62,7 +62,7 @@ public final class MaterialRenderState {
RenderSystem.enablePolygonOffset(); RenderSystem.enablePolygonOffset();
} else { } else {
RenderSystem.polygonOffset(0.0F, 0.0F); RenderSystem.polygonOffset(0.0F, 0.0F);
RenderSystem.enablePolygonOffset(); RenderSystem.disablePolygonOffset();
} }
} }
@ -115,7 +115,7 @@ public final class MaterialRenderState {
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE);
} }
case LIGHTING -> { case LIGHTNING -> {
RenderSystem.enableBlend(); RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE); RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE);
} }

View file

@ -9,39 +9,30 @@ import com.google.common.collect.ImmutableList;
import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent; import com.jozufozu.flywheel.api.event.ReloadLevelRendererEvent;
import com.jozufozu.flywheel.api.uniform.ShaderUniforms; import com.jozufozu.flywheel.api.uniform.ShaderUniforms;
import com.jozufozu.flywheel.gl.buffer.GlBuffer; import com.jozufozu.flywheel.gl.buffer.GlBuffer;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.math.MoreMath; import com.jozufozu.flywheel.lib.math.MoreMath;
import com.jozufozu.flywheel.lib.memory.MemoryBlock; import com.jozufozu.flywheel.lib.memory.MemoryBlock;
import net.minecraft.util.Mth;
public class UniformBuffer { public class UniformBuffer {
// private static final int OFFSET_ALIGNMENT = GL32.glGetInteger(GL32.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT);
private static final int OFFSET_ALIGNMENT = GL32.glGetInteger(GL32.GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); // private static final int MAX_SIZE = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BLOCK_SIZE);
private static final int MAX_SIZE = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BLOCK_SIZE); // private static final int MAX_BINDINGS = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BUFFER_BINDINGS);
private static final int MAX_BINDINGS = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BUFFER_BINDINGS); // private static final boolean PO2_ALIGNMENT = Mth.isPowerOfTwo(OFFSET_ALIGNMENT);
private static final boolean PO2_ALIGNMENT = Mth.isPowerOfTwo(OFFSET_ALIGNMENT);
private static UniformBuffer instance; private static UniformBuffer instance;
private final ProviderSet providerSet;
public static UniformBuffer getInstance() {
if (instance == null) {
instance = new UniformBuffer();
}
return instance;
}
private final GlBuffer buffer; private final GlBuffer buffer;
private final ProviderSet providerSet;
private UniformBuffer() { private UniformBuffer() {
buffer = new GlBuffer(); buffer = new GlBuffer();
providerSet = new ProviderSet(ShaderUniforms.REGISTRY.getAll()); providerSet = new ProviderSet(ShaderUniforms.REGISTRY.getAll());
} }
public static void syncAndBind(GlProgram program) { public static UniformBuffer get() {
getInstance().sync(); if (instance == null) {
program.bind(); instance = new UniformBuffer();
}
return instance;
} }
public void sync() { public void sync() {
@ -52,15 +43,6 @@ public class UniformBuffer {
GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, 0, buffer.handle(), 0, providerSet.data.size()); GL32.glBindBufferRange(GL32.GL_UNIFORM_BUFFER, 0, buffer.handle(), 0, providerSet.data.size());
} }
// https://stackoverflow.com/questions/3407012/rounding-up-to-the-nearest-multiple-of-a-number
private static int alignUniformBuffer(int numToRound) {
if (PO2_ALIGNMENT) {
return (numToRound + OFFSET_ALIGNMENT - 1) & -OFFSET_ALIGNMENT;
} else {
return ((numToRound + OFFSET_ALIGNMENT - 1) / OFFSET_ALIGNMENT) * OFFSET_ALIGNMENT;
}
}
private void delete() { private void delete() {
providerSet.delete(); providerSet.delete();
buffer.delete(); buffer.delete();
@ -73,6 +55,15 @@ public class UniformBuffer {
} }
} }
// // https://stackoverflow.com/questions/3407012/rounding-up-to-the-nearest-multiple-of-a-number
// private static int alignUniformBuffer(int numToRound) {
// if (PO2_ALIGNMENT) {
// return (numToRound + OFFSET_ALIGNMENT - 1) & -OFFSET_ALIGNMENT;
// } else {
// return ((numToRound + OFFSET_ALIGNMENT - 1) / OFFSET_ALIGNMENT) * OFFSET_ALIGNMENT;
// }
// }
private static class LiveProvider { private static class LiveProvider {
private final ShaderUniforms shaderUniforms; private final ShaderUniforms shaderUniforms;
private final int offset; private final int offset;

View file

@ -48,7 +48,7 @@ class BatchedDrawManager extends InstancerStorage<BatchedInstancer<?>> {
@Override @Override
protected <I extends Instance> void add(InstancerKey<I> key, BatchedInstancer<?> instancer, Model model, RenderStage stage) { protected <I extends Instance> void add(InstancerKey<I> key, BatchedInstancer<?> instancer, Model model, RenderStage stage) {
var stagePlan = stagePlans.computeIfAbsent(stage, renderStage -> new BatchedStagePlan(renderStage, drawTracker)); var stagePlan = stagePlans.computeIfAbsent(stage, renderStage -> new BatchedStagePlan(renderStage, drawTracker));
var meshes = model.getMeshes(); var meshes = model.meshes();
for (var entry : meshes.entrySet()) { for (var entry : meshes.entrySet()) {
var material = entry.getKey(); var material = entry.getKey();
RenderType renderType = material.getFallbackRenderType(); RenderType renderType = material.getFallbackRenderType();

View file

@ -16,12 +16,12 @@ public class IndirectBuffers {
public static final long INT_SIZE = Integer.BYTES; public static final long INT_SIZE = Integer.BYTES;
public static final long PTR_SIZE = Pointer.POINTER_SIZE; public static final long PTR_SIZE = Pointer.POINTER_SIZE;
public static final long MODEL_STRIDE = 24;
// Byte size of a draw command, plus our added mesh data. // Byte size of a draw command, plus our added mesh data.
public static final long DRAW_COMMAND_STRIDE = 40; public static final long DRAW_COMMAND_STRIDE = 40;
public static final long DRAW_COMMAND_OFFSET = 0; public static final long DRAW_COMMAND_OFFSET = 0;
public static final long MODEL_STRIDE = 24;
// Offsets to the 3 segments // Offsets to the 3 segments
private static final long HANDLE_OFFSET = 0; private static final long HANDLE_OFFSET = 0;
private static final long OFFSET_OFFSET = BUFFER_COUNT * INT_SIZE; private static final long OFFSET_OFFSET = BUFFER_COUNT * INT_SIZE;
@ -41,6 +41,9 @@ public class IndirectBuffers {
private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2; private static final long MODEL_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 2;
private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3; private static final long DRAW_SIZE_OFFSET = SIZE_OFFSET + PTR_SIZE * 3;
private static final float OBJECT_GROWTH_FACTOR = 1.25f;
private static final float MODEL_GROWTH_FACTOR = 2f;
private static final float DRAW_GROWTH_FACTOR = 2f;
/** /**
* A small block of memory divided into 3 contiguous segments: * A small block of memory divided into 3 contiguous segments:
@ -65,13 +68,13 @@ public class IndirectBuffers {
this.objectStride = objectStride; this.objectStride = objectStride;
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1); this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
object = new ResizableStorageArray(objectStride, 1.75); object = new ResizableStorageArray(objectStride, OBJECT_GROWTH_FACTOR);
target = new ResizableStorageArray(INT_SIZE, 1.75); target = new ResizableStorageArray(INT_SIZE, OBJECT_GROWTH_FACTOR);
model = new ResizableStorageArray(MODEL_STRIDE, 2); model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, 2); draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, DRAW_GROWTH_FACTOR);
} }
void updateCounts(int objectCount, int drawCount, int modelCount) { void updateCounts(int objectCount, int modelCount, int drawCount) {
object.ensureCapacity(objectCount); object.ensureCapacity(objectCount);
target.ensureCapacity(objectCount); target.ensureCapacity(objectCount);
model.ensureCapacity(modelCount); model.ensureCapacity(modelCount);

View file

@ -21,67 +21,114 @@ import com.jozufozu.flywheel.api.instance.InstanceType;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
import com.jozufozu.flywheel.backend.MaterialRenderState;
import com.jozufozu.flywheel.backend.compile.IndirectPrograms; import com.jozufozu.flywheel.backend.compile.IndirectPrograms;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlCompat; import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlProgram; import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.model.ModelUtil;
public class IndirectCullingGroup<I extends Instance> { public class IndirectCullingGroup<I extends Instance> {
private static final Comparator<IndirectDraw> DRAW_COMPARATOR = Comparator.comparing(IndirectDraw::stage)
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR);
private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT; private static final int DRAW_BARRIER_BITS = GL_SHADER_STORAGE_BARRIER_BIT | GL_COMMAND_BARRIER_BIT;
private final GlProgram cull; private final GlProgram cullProgram;
private final GlProgram draw; private final GlProgram applyProgram;
private final GlProgram drawProgram;
private final long objectStride; private final long objectStride;
private final IndirectBuffers buffers; private final IndirectBuffers buffers;
public final IndirectMeshPool meshPool; private final IndirectMeshPool meshPool;
private final List<IndirectModel> indirectModels = new ArrayList<>(); private final List<IndirectModel> indirectModels = new ArrayList<>();
private final List<IndirectDraw> indirectDraws = new ArrayList<>(); private final List<IndirectDraw> indirectDraws = new ArrayList<>();
private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class); private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class);
private boolean needsDrawBarrier; private boolean needsDrawBarrier;
private boolean needsSortDraws; private boolean needsSortDraws;
private int instanceCountThisFrame; private int instanceCountThisFrame;
private final GlProgram apply;
IndirectCullingGroup(InstanceType<I> instanceType) { IndirectCullingGroup(InstanceType<I> instanceType) {
var programs = IndirectPrograms.get();
cullProgram = programs.getCullingProgram(instanceType);
applyProgram = programs.getApplyProgram();
drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT);
objectStride = instanceType.getLayout() objectStride = instanceType.getLayout()
.getStride() + IndirectBuffers.INT_SIZE; .getStride() + IndirectBuffers.INT_SIZE;
buffers = new IndirectBuffers(objectStride); buffers = new IndirectBuffers(objectStride);
meshPool = new IndirectMeshPool(); meshPool = new IndirectMeshPool();
var indirectPrograms = IndirectPrograms.get();
cull = indirectPrograms.getCullingProgram(instanceType);
apply = indirectPrograms.getApplyProgram();
draw = indirectPrograms.getIndirectProgram(instanceType, Contexts.WORLD);
} }
public void add(IndirectInstancer<I> instancer, RenderStage stage, Model model) { public void flush(StagingBuffer stagingBuffer) {
var meshes = model.getMeshes(); needsDrawBarrier = true;
instanceCountThisFrame = prepareModels();
var boundingSphere = ModelUtil.computeBoundingSphere(meshes.values()); if (nothingToDo()) {
return;
int modelId = indirectModels.size();
instancer.setModelId(modelId);
var indirectModel = new IndirectModel(instancer, modelId, boundingSphere);
indirectModels.add(indirectModel);
for (Map.Entry<Material, Mesh> materialMeshEntry : meshes.entrySet()) {
IndirectMeshPool.BufferedMesh bufferedMesh = meshPool.alloc(materialMeshEntry.getValue());
indirectDraws.add(new IndirectDraw(indirectModel, materialMeshEntry.getKey(), bufferedMesh, stage));
} }
needsSortDraws = true; buffers.updateCounts(instanceCountThisFrame, indirectModels.size(), indirectDraws.size());
if (needsSortDraws) {
sortDraws();
needsSortDraws = false;
}
meshPool.flush(stagingBuffer);
uploadObjects(stagingBuffer);
uploadModels(stagingBuffer);
uploadDraws(stagingBuffer);
}
public void dispatchCull() {
if (nothingToDo()) {
return;
}
UniformBuffer.get().sync();
cullProgram.bind();
buffers.bindForCompute();
glDispatchCompute(GlCompat.getComputeGroupCount(instanceCountThisFrame), 1, 1);
}
public void dispatchApply() {
if (nothingToDo()) {
return;
}
applyProgram.bind();
buffers.bindForCompute();
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glDispatchCompute(GlCompat.getComputeGroupCount(indirectDraws.size()), 1, 1);
}
private boolean nothingToDo() {
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
}
private boolean nothingToDo(RenderStage stage) {
return nothingToDo() || !multiDraws.containsKey(stage);
}
/**
* @return the total instance count
*/
private int prepareModels() {
int baseInstance = 0;
for (var model : indirectModels) {
model.prepare(baseInstance);
baseInstance += model.instancer.getInstanceCount();
}
return baseInstance;
} }
private void sortDraws() { private void sortDraws() {
multiDraws.clear(); multiDraws.clear();
// sort by stage, then material // sort by stage, then material
indirectDraws.sort(Comparator.comparing(IndirectDraw::stage) indirectDraws.sort(DRAW_COMPARATOR);
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR));
for (int start = 0, i = 0; i < indirectDraws.size(); i++) { for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
var draw1 = indirectDraws.get(i); var draw1 = indirectDraws.get(i);
@ -99,52 +146,22 @@ public class IndirectCullingGroup<I extends Instance> {
} }
} }
public void flush(StagingBuffer stagingBuffer) { public boolean hasStage(RenderStage stage) {
needsDrawBarrier = true; return multiDraws.containsKey(stage);
instanceCountThisFrame = calculateTotalInstanceCountAndPrepareBatches();
if (nothingToDo()) {
return;
}
buffers.updateCounts(instanceCountThisFrame, indirectDraws.size(), indirectModels.size());
if (needsSortDraws) {
sortDraws();
needsSortDraws = false;
}
meshPool.flush(stagingBuffer);
uploadInstances(stagingBuffer);
uploadModels(stagingBuffer);
uploadIndirectCommands(stagingBuffer);
} }
public void dispatchCull() { public void add(IndirectInstancer<I> instancer, Model model, RenderStage stage) {
if (nothingToDo()) { int modelIndex = indirectModels.size();
return; instancer.setModelIndex(modelIndex);
var indirectModel = new IndirectModel(instancer, modelIndex, model.boundingSphere());
indirectModels.add(indirectModel);
for (Map.Entry<Material, Mesh> entry : model.meshes().entrySet()) {
IndirectMeshPool.BufferedMesh bufferedMesh = meshPool.alloc(entry.getValue());
indirectDraws.add(new IndirectDraw(indirectModel, entry.getKey(), bufferedMesh, stage));
} }
UniformBuffer.syncAndBind(cull);
buffers.bindForCompute();
glDispatchCompute(getGroupCount(instanceCountThisFrame), 1, 1);
}
public void dispatchApply() { needsSortDraws = true;
if (nothingToDo()) {
return;
}
apply.bind();
buffers.bindForCompute();
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
glDispatchCompute(getGroupCount(indirectDraws.size()), 1, 1);
}
private boolean nothingToDo() {
return indirectDraws.isEmpty() || instanceCountThisFrame == 0;
}
private boolean nothingToDo(RenderStage stage) {
return nothingToDo() || !multiDraws.containsKey(stage);
} }
public void submit(RenderStage stage) { public void submit(RenderStage stage) {
@ -152,13 +169,14 @@ public class IndirectCullingGroup<I extends Instance> {
return; return;
} }
UniformBuffer.syncAndBind(draw); UniformBuffer.get().sync();
drawProgram.bind();
meshPool.bindForDraw(); meshPool.bindForDraw();
buffers.bindForDraw(); buffers.bindForDraw();
drawBarrier(); drawBarrier();
var flwBaseDraw = draw.getUniformLocation("_flw_baseDraw"); var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
for (var multiDraw : multiDraws.get(stage)) { for (var multiDraw : multiDraws.get(stage)) {
glUniform1ui(flwBaseDraw, multiDraw.start); glUniform1ui(flwBaseDraw, multiDraw.start);
@ -173,7 +191,7 @@ public class IndirectCullingGroup<I extends Instance> {
} }
} }
private void uploadInstances(StagingBuffer stagingBuffer) { private void uploadObjects(StagingBuffer stagingBuffer) {
long pos = 0; long pos = 0;
for (IndirectModel batch : indirectModels) { for (IndirectModel batch : indirectModels) {
var instanceCount = batch.instancer.getInstanceCount(); var instanceCount = batch.instancer.getInstanceCount();
@ -190,7 +208,7 @@ public class IndirectCullingGroup<I extends Instance> {
stagingBuffer.enqueueCopy(totalSize, handle, 0, this::writeModels); stagingBuffer.enqueueCopy(totalSize, handle, 0, this::writeModels);
} }
private void uploadIndirectCommands(StagingBuffer stagingBuffer) { private void uploadDraws(StagingBuffer stagingBuffer) {
var totalSize = indirectDraws.size() * IndirectBuffers.DRAW_COMMAND_STRIDE; var totalSize = indirectDraws.size() * IndirectBuffers.DRAW_COMMAND_STRIDE;
var handle = buffers.draw.handle(); var handle = buffers.draw.handle();
@ -199,44 +217,23 @@ public class IndirectCullingGroup<I extends Instance> {
private void writeModels(long writePtr) { private void writeModels(long writePtr) {
for (var batch : indirectModels) { for (var batch : indirectModels) {
batch.writeModel(writePtr); batch.write(writePtr);
writePtr += IndirectBuffers.MODEL_STRIDE; writePtr += IndirectBuffers.MODEL_STRIDE;
} }
} }
private void writeCommands(long writePtr) { private void writeCommands(long writePtr) {
for (var batch : indirectDraws) { for (var batch : indirectDraws) {
batch.writeIndirectCommand(writePtr); batch.write(writePtr);
writePtr += IndirectBuffers.DRAW_COMMAND_STRIDE; writePtr += IndirectBuffers.DRAW_COMMAND_STRIDE;
} }
} }
private int calculateTotalInstanceCountAndPrepareBatches() {
int baseInstance = 0;
for (var batch : indirectModels) {
batch.prepare(baseInstance);
baseInstance += batch.instancer.getInstanceCount();
}
return baseInstance;
}
public void delete() { public void delete() {
buffers.delete(); buffers.delete();
meshPool.delete(); meshPool.delete();
} }
public boolean hasStage(RenderStage stage) {
return multiDraws.containsKey(stage);
}
private static int getGroupCount(int threadCount) {
if (GlCompat.amd) {
return (threadCount + 63) >> 6; // ceil(threadCount / 64)
} else {
return (threadCount + 31) >> 5; // ceil(threadCount / 32)
}
}
private record MultiDraw(Material material, int start, int end) { private record MultiDraw(Material material, int start, int end) {
void submit() { void submit() {
MaterialRenderState.setup(material); MaterialRenderState.setup(material);

View file

@ -4,17 +4,17 @@ import org.lwjgl.system.MemoryUtil;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.backend.MaterialEncoder;
import com.jozufozu.flywheel.backend.ShaderIndices; import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.engine.MaterialEncoder;
public class IndirectDraw { public class IndirectDraw {
private final IndirectModel model; private final IndirectModel model;
private final IndirectMeshPool.BufferedMesh mesh;
private final Material material; private final Material material;
private final IndirectMeshPool.BufferedMesh mesh;
private final RenderStage stage; private final RenderStage stage;
private final int vertexMaterialID; private final int materialVertexIndex;
private final int fragmentMaterialID; private final int materialFragmentIndex;
private final int packedFogAndCutout; private final int packedFogAndCutout;
private final int packedMaterialProperties; private final int packedMaterialProperties;
@ -24,8 +24,8 @@ public class IndirectDraw {
this.mesh = mesh; this.mesh = mesh;
this.stage = stage; this.stage = stage;
this.vertexMaterialID = ShaderIndices.getVertexShaderIndex(material.shaders()); this.materialVertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
this.fragmentMaterialID = ShaderIndices.getFragmentShaderIndex(material.shaders()); this.materialFragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material); this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
this.packedMaterialProperties = MaterialEncoder.packProperties(material); this.packedMaterialProperties = MaterialEncoder.packProperties(material);
} }
@ -42,16 +42,17 @@ public class IndirectDraw {
return stage; return stage;
} }
public void writeIndirectCommand(long ptr) { public void write(long ptr) {
MemoryUtil.memPutInt(ptr, mesh.indexCount()); // count MemoryUtil.memPutInt(ptr, mesh.indexCount()); // count
MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be set by the apply shader
MemoryUtil.memPutInt(ptr + 8, mesh.firstIndex); // firstIndex MemoryUtil.memPutInt(ptr + 8, mesh.firstIndex()); // firstIndex
MemoryUtil.memPutInt(ptr + 12, mesh.baseVertex); // baseVertex MemoryUtil.memPutInt(ptr + 12, mesh.baseVertex()); // baseVertex
MemoryUtil.memPutInt(ptr + 16, model.baseInstance); // baseInstance MemoryUtil.memPutInt(ptr + 16, model.baseInstance()); // baseInstance
MemoryUtil.memPutInt(ptr + 20, model.id); // modelID MemoryUtil.memPutInt(ptr + 20, model.index); // modelIndex
MemoryUtil.memPutInt(ptr + 24, vertexMaterialID); // vertexMaterialID
MemoryUtil.memPutInt(ptr + 28, fragmentMaterialID); // fragmentMaterialID MemoryUtil.memPutInt(ptr + 24, materialVertexIndex); // materialVertexIndex
MemoryUtil.memPutInt(ptr + 28, materialFragmentIndex); // materialFragmentIndex
MemoryUtil.memPutInt(ptr + 32, packedFogAndCutout); // packedFogAndCutout MemoryUtil.memPutInt(ptr + 32, packedFogAndCutout); // packedFogAndCutout
MemoryUtil.memPutInt(ptr + 36, packedMaterialProperties); // packedMaterialProperties MemoryUtil.memPutInt(ptr + 36, packedMaterialProperties); // packedMaterialProperties
} }

View file

@ -12,29 +12,35 @@ import com.jozufozu.flywheel.backend.engine.InstancerStorage;
public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>> { public class IndirectDrawManager extends InstancerStorage<IndirectInstancer<?>> {
private final StagingBuffer stagingBuffer = new StagingBuffer(); private final StagingBuffer stagingBuffer = new StagingBuffer();
public final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>(); private final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
@Override @Override
protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) { protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) {
return new IndirectInstancer<>(type); return new IndirectInstancer<>(type);
} }
@SuppressWarnings("unchecked")
@Override @Override
protected <I extends Instance> void add(InstancerKey<I> key, IndirectInstancer<?> instancer, Model model, RenderStage stage) { protected <I extends Instance> void add(InstancerKey<I> key, IndirectInstancer<?> instancer, Model model, RenderStage stage) {
var indirectList = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), IndirectCullingGroup::new); var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), IndirectCullingGroup::new);
group.add((IndirectInstancer<I>) instancer, model, stage);
indirectList.add((IndirectInstancer<I>) instancer, stage, model);
} }
public boolean hasStage(RenderStage stage) { public boolean hasStage(RenderStage stage) {
for (var list : cullingGroups.values()) { for (var group : cullingGroups.values()) {
if (list.hasStage(stage)) { if (group.hasStage(stage)) {
return true; return true;
} }
} }
return false; return false;
} }
public void renderStage(RenderStage stage) {
for (var group : cullingGroups.values()) {
group.submit(stage);
}
}
@Override @Override
public void flush() { public void flush() {
super.flush(); super.flush();

View file

@ -6,10 +6,10 @@ import com.jozufozu.flywheel.api.event.RenderContext;
import com.jozufozu.flywheel.api.event.RenderStage; import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.AbstractEngine; import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
import com.jozufozu.flywheel.backend.engine.InstancerStorage; import com.jozufozu.flywheel.backend.engine.InstancerStorage;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.lib.task.Flag; import com.jozufozu.flywheel.lib.task.Flag;
@ -61,9 +61,7 @@ public class IndirectEngine extends AbstractEngine {
GlTextureUnit.T2.makeActive(); GlTextureUnit.T2.makeActive();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2)); RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
for (var list : drawManager.cullingGroups.values()) { drawManager.renderStage(stage);
list.submit(stage);
}
MaterialRenderState.reset(); MaterialRenderState.reset();

View file

@ -10,7 +10,7 @@ import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I> { public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I> {
private final long objectStride; private final long objectStride;
private final InstanceWriter<I> writer; private final InstanceWriter<I> writer;
private int modelId; private int modelIndex;
public IndirectInstancer(InstanceType<I> type) { public IndirectInstancer(InstanceType<I> type) {
super(type); super(type);
@ -24,7 +24,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
removeDeletedInstances(); removeDeletedInstances();
} }
public void writeSparse(StagingBuffer stagingBuffer, long start, int dstVbo) { public void writeChanged(StagingBuffer stagingBuffer, long start, int dstVbo) {
int count = instances.size(); int count = instances.size();
for (int i = changed.nextSetBit(0); i >= 0 && i < count; i = changed.nextSetBit(i + 1)) { for (int i = changed.nextSetBit(0); i >= 0 && i < count; i = changed.nextSetBit(i + 1)) {
var instance = instances.get(i); var instance = instances.get(i);
@ -33,7 +33,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
changed.clear(); changed.clear();
} }
public void writeFull(StagingBuffer stagingBuffer, long start, int dstVbo) { public void writeAll(StagingBuffer stagingBuffer, long start, int dstVbo) {
long totalSize = objectStride * instances.size(); long totalSize = objectStride * instances.size();
stagingBuffer.enqueueCopy(totalSize, dstVbo, start, this::writeAll); stagingBuffer.enqueueCopy(totalSize, dstVbo, start, this::writeAll);
@ -50,12 +50,12 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
private void writeOne(long ptr, I instance) { private void writeOne(long ptr, I instance) {
// write modelID // write modelID
MemoryUtil.memPutInt(ptr, modelId); MemoryUtil.memPutInt(ptr, modelIndex);
// write object // write object
writer.write(ptr + IndirectBuffers.INT_SIZE, instance); writer.write(ptr + IndirectBuffers.INT_SIZE, instance);
} }
public void setModelId(int modelId) { public void setModelIndex(int modelIndex) {
this.modelId = modelId; this.modelIndex = modelIndex;
} }
} }

View file

@ -6,7 +6,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.backend.InternalLayout; import com.jozufozu.flywheel.backend.InternalLayout;
@ -20,9 +19,9 @@ public class IndirectMeshPool {
private final Map<Mesh, BufferedMesh> meshes = new HashMap<>(); private final Map<Mesh, BufferedMesh> meshes = new HashMap<>();
private final List<BufferedMesh> meshList = new ArrayList<>(); private final List<BufferedMesh> meshList = new ArrayList<>();
final GlVertexArray vertexArray; private final GlVertexArray vertexArray;
final GlBuffer vbo; private final GlBuffer vbo;
final GlBuffer ebo; private final GlBuffer ebo;
private boolean dirty; private boolean dirty;
@ -142,9 +141,9 @@ public class IndirectMeshPool {
public static class BufferedMesh { public static class BufferedMesh {
private final Mesh mesh; private final Mesh mesh;
public long byteIndex; private long byteIndex;
public int firstIndex; private int baseVertex;
public int baseVertex; private int firstIndex;
private BufferedMesh(Mesh mesh) { private BufferedMesh(Mesh mesh) {
this.mesh = mesh; this.mesh = mesh;
@ -158,8 +157,12 @@ public class IndirectMeshPool {
return mesh.indexCount(); return mesh.indexCount();
} }
public Vector4fc boundingSphere() { public int baseVertex() {
return mesh.boundingSphere(); return baseVertex;
}
public int firstIndex() {
return firstIndex;
} }
} }
} }

View file

@ -1,28 +1,24 @@
package com.jozufozu.flywheel.backend.engine.indirect; package com.jozufozu.flywheel.backend.engine.indirect;
import org.joml.Vector4f;
import org.joml.Vector4fc; import org.joml.Vector4fc;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
public class IndirectModel { public class IndirectModel {
public final IndirectInstancer<?> instancer; public final IndirectInstancer<?> instancer;
public final int id; public final int index;
public int baseInstance = -1;
private boolean needsFullWrite = true;
private final Vector4fc boundingSphere; private final Vector4fc boundingSphere;
public IndirectModel(IndirectInstancer<?> instancer, int id, Vector4f boundingSphere) { private int baseInstance = -1;
private boolean needsFullWrite = true;
public IndirectModel(IndirectInstancer<?> instancer, int index, Vector4fc boundingSphere) {
this.instancer = instancer; this.instancer = instancer;
this.id = id; this.index = index;
this.boundingSphere = boundingSphere; this.boundingSphere = boundingSphere;
} }
public void writeModel(long ptr) { public int baseInstance() {
MemoryUtil.memPutInt(ptr, 0); // instanceCount - to be incremented by the compute shader return baseInstance;
MemoryUtil.memPutInt(ptr + 4, baseInstance); // baseInstance
boundingSphere.getToAddress(ptr + 8); // boundingSphere
} }
public void prepare(int baseInstance) { public void prepare(int baseInstance) {
@ -37,9 +33,15 @@ public class IndirectModel {
public void writeObjects(StagingBuffer stagingBuffer, long start, int dstVbo) { public void writeObjects(StagingBuffer stagingBuffer, long start, int dstVbo) {
if (needsFullWrite) { if (needsFullWrite) {
instancer.writeFull(stagingBuffer, start, dstVbo); instancer.writeAll(stagingBuffer, start, dstVbo);
} else { } else {
instancer.writeSparse(stagingBuffer, start, dstVbo); instancer.writeChanged(stagingBuffer, start, dstVbo);
} }
} }
public void write(long ptr) {
MemoryUtil.memPutInt(ptr, 0); // instanceCount - to be incremented by the cull shader
MemoryUtil.memPutInt(ptr + 4, baseInstance); // baseInstance
boundingSphere.getToAddress(ptr + 8); // boundingSphere
}
} }

View file

@ -17,7 +17,7 @@ import com.mojang.blaze3d.platform.GlStateManager;
import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; import it.unimi.dsi.fastutil.objects.Object2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
public class EBOCache { public class EboCache {
private final List<Entry> quads = new ArrayList<>(); private final List<Entry> quads = new ArrayList<>();
private final Object2ReferenceMap<Key, Entry> others = new Object2ReferenceOpenHashMap<>(); private final Object2ReferenceMap<Key, Entry> others = new Object2ReferenceOpenHashMap<>();
@ -37,9 +37,9 @@ public class EBOCache {
private int getQuads(int indexCount) { private int getQuads(int indexCount) {
// Use an existing quad EBO if there's one big enough. // Use an existing quad EBO if there's one big enough.
for (Entry quadEBO : quads) { for (Entry quadEbo : quads) {
if (quadEBO.gpuSize >= indexCount * GlNumericType.UINT.byteWidth()) { if (quadEbo.gpuSize >= indexCount * GlNumericType.UINT.byteWidth()) {
return quadEBO.ebo; return quadEbo.ebo;
} }
} }
// If not, create a new one. // If not, create a new one.
@ -55,7 +55,6 @@ public class EBOCache {
} }
private record Entry(int ebo, int gpuSize) { private record Entry(int ebo, int gpuSize) {
@NotNull @NotNull
private static Entry create(IndexSequence provider, int indexCount) { private static Entry create(IndexSequence provider, int indexCount) {
int byteSize = indexCount * GlNumericType.UINT.byteWidth(); int byteSize = indexCount * GlNumericType.UINT.byteWidth();

View file

@ -12,14 +12,15 @@ import com.jozufozu.flywheel.api.instance.Instance;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.material.Transparency; import com.jozufozu.flywheel.api.material.Transparency;
import com.jozufozu.flywheel.api.material.WriteMask; import com.jozufozu.flywheel.api.material.WriteMask;
import com.jozufozu.flywheel.backend.MaterialRenderState;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms; import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl; import com.jozufozu.flywheel.backend.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.lib.context.Contexts; import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.material.CutoutShaders; import com.jozufozu.flywheel.lib.material.CutoutShaders;
import com.jozufozu.flywheel.lib.material.FogShaders;
import com.jozufozu.flywheel.lib.material.SimpleMaterial; import com.jozufozu.flywheel.lib.material.SimpleMaterial;
import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.systems.RenderSystem;
@ -37,6 +38,8 @@ public class InstancedCrumbling {
return; return;
} }
var crumblingMaterial = SimpleMaterial.builder();
try (var state = GlStateTracker.getRestoreState()) { try (var state = GlStateTracker.getRestoreState()) {
for (var shaderStateEntry : byShaderState.entrySet()) { for (var shaderStateEntry : byShaderState.entrySet()) {
var byProgress = shaderStateEntry.getValue(); var byProgress = shaderStateEntry.getValue();
@ -50,8 +53,9 @@ public class InstancedCrumbling {
var baseMaterial = shader.material(); var baseMaterial = shader.material();
int diffuseTexture = getDiffuseTexture(baseMaterial); int diffuseTexture = getDiffuseTexture(baseMaterial);
var crumblingMaterial = SimpleMaterial.builderOf(baseMaterial) crumblingMaterial.copyFrom(baseMaterial)
.cutout(CutoutShaders.OFF) .fog(FogShaders.NONE)
.cutout(CutoutShaders.ONE_TENTH)
.polygonOffset(true) .polygonOffset(true)
.transparency(Transparency.CRUMBLING) .transparency(Transparency.CRUMBLING)
.writeMask(WriteMask.COLOR) .writeMask(WriteMask.COLOR)
@ -60,8 +64,9 @@ public class InstancedCrumbling {
var program = InstancingPrograms.get() var program = InstancingPrograms.get()
.get(shader.instanceType(), Contexts.CRUMBLING); .get(shader.instanceType(), Contexts.CRUMBLING);
UniformBuffer.syncAndBind(program); program.bind();
UniformBuffer.get().sync();
InstancingEngine.uploadMaterialUniform(program, crumblingMaterial); InstancingEngine.uploadMaterialUniform(program, crumblingMaterial);
for (Int2ObjectMap.Entry<List<Runnable>> progressEntry : byProgress.int2ObjectEntrySet()) { for (Int2ObjectMap.Entry<List<Runnable>> progressEntry : byProgress.int2ObjectEntrySet()) {
@ -71,7 +76,7 @@ public class InstancedCrumbling {
continue; continue;
} }
crumblingMaterial.baseTexture(ModelBakery.BREAKING_LOCATIONS.get(progressEntry.getIntKey())); crumblingMaterial.texture(ModelBakery.BREAKING_LOCATIONS.get(progressEntry.getIntKey()));
MaterialRenderState.setup(crumblingMaterial); MaterialRenderState.setup(crumblingMaterial);
@ -126,7 +131,7 @@ public class InstancedCrumbling {
private static int getDiffuseTexture(Material material) { private static int getDiffuseTexture(Material material) {
return Minecraft.getInstance() return Minecraft.getInstance()
.getTextureManager() .getTextureManager()
.getTexture(material.baseTexture()) .getTexture(material.texture())
.getId(); .getId();
} }
} }

View file

@ -27,7 +27,7 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
* A map of vertex types to their mesh pools. * A map of vertex types to their mesh pools.
*/ */
private final InstancedMeshPool meshPool = new InstancedMeshPool(); private final InstancedMeshPool meshPool = new InstancedMeshPool();
private final EBOCache eboCache = new EBOCache(); private final EboCache eboCache = new EboCache();
public DrawSet get(RenderStage stage) { public DrawSet get(RenderStage stage) {
return drawSets.getOrDefault(stage, DrawSet.EMPTY); return drawSets.getOrDefault(stage, DrawSet.EMPTY);
@ -66,7 +66,7 @@ public class InstancedDrawManager extends InstancerStorage<InstancedInstancer<?>
DrawSet drawSet = drawSets.computeIfAbsent(stage, DrawSet::new); DrawSet drawSet = drawSets.computeIfAbsent(stage, DrawSet::new);
var meshes = model.getMeshes(); var meshes = model.meshes();
for (var entry : meshes.entrySet()) { for (var entry : meshes.entrySet()) {
var mesh = alloc(entry.getValue()); var mesh = alloc(entry.getValue());

View file

@ -45,7 +45,7 @@ public class InstancedMeshPool {
* @param eboCache The EBO cache to use. * @param eboCache The EBO cache to use.
* @return A handle to the allocated mesh. * @return A handle to the allocated mesh.
*/ */
public BufferedMesh alloc(Mesh mesh, EBOCache eboCache) { public BufferedMesh alloc(Mesh mesh, EboCache eboCache) {
return meshes.computeIfAbsent(mesh, m -> { return meshes.computeIfAbsent(mesh, m -> {
BufferedMesh bufferedMesh = new BufferedMesh(m, byteSize, eboCache); BufferedMesh bufferedMesh = new BufferedMesh(m, byteSize, eboCache);
byteSize += bufferedMesh.size(); byteSize += bufferedMesh.size();
@ -143,7 +143,7 @@ public class InstancedMeshPool {
private final Set<GlVertexArray> boundTo = new HashSet<>(); private final Set<GlVertexArray> boundTo = new HashSet<>();
private BufferedMesh(Mesh mesh, long byteIndex, EBOCache eboCache) { private BufferedMesh(Mesh mesh, long byteIndex, EboCache eboCache) {
this.mesh = mesh; this.mesh = mesh;
this.byteIndex = byteIndex; this.byteIndex = byteIndex;
this.ebo = eboCache.get(mesh.indexSequence(), mesh.indexCount()); this.ebo = eboCache.get(mesh.indexSequence(), mesh.indexCount());

View file

@ -9,13 +9,13 @@ import com.jozufozu.flywheel.api.event.RenderStage;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.task.Plan; import com.jozufozu.flywheel.api.task.Plan;
import com.jozufozu.flywheel.api.task.TaskExecutor; import com.jozufozu.flywheel.api.task.TaskExecutor;
import com.jozufozu.flywheel.backend.MaterialEncoder;
import com.jozufozu.flywheel.backend.MaterialRenderState;
import com.jozufozu.flywheel.backend.ShaderIndices; import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.compile.InstancingPrograms; import com.jozufozu.flywheel.backend.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.AbstractEngine; import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer; import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
import com.jozufozu.flywheel.backend.engine.InstancerStorage; 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.UniformBuffer; import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlStateTracker; import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit; import com.jozufozu.flywheel.gl.GlTextureUnit;
@ -111,9 +111,10 @@ public class InstancingEngine extends AbstractEngine {
} }
var program = InstancingPrograms.get() var program = InstancingPrograms.get()
.get(shader.instanceType(), Contexts.WORLD); .get(shader.instanceType(), Contexts.DEFAULT);
UniformBuffer.syncAndBind(program); program.bind();
UniformBuffer.get().sync();
uploadMaterialUniform(program, shader.material()); uploadMaterialUniform(program, shader.material());
MaterialRenderState.setup(shader.material()); MaterialRenderState.setup(shader.material());

View file

@ -135,18 +135,18 @@ public class FlwCommands {
command.then(Commands.literal("debugFrustum") command.then(Commands.literal("debugFrustum")
.then(Commands.literal("pause") .then(Commands.literal("pause")
.executes(context -> { .executes(context -> {
FlwShaderUniforms.FRUSTUM_PAUSED = true; FlwShaderUniforms.frustumPaused = true;
return 1; return 1;
})) }))
.then(Commands.literal("unpause") .then(Commands.literal("unpause")
.executes(context -> { .executes(context -> {
FlwShaderUniforms.FRUSTUM_PAUSED = false; FlwShaderUniforms.frustumPaused = false;
return 1; return 1;
})) }))
.then(Commands.literal("capture") .then(Commands.literal("capture")
.executes(context -> { .executes(context -> {
FlwShaderUniforms.FRUSTUM_PAUSED = true; FlwShaderUniforms.frustumPaused = true;
FlwShaderUniforms.FRUSTUM_CAPTURE = true; FlwShaderUniforms.frustumCapture = true;
return 1; return 1;
}))); })));

View file

@ -10,6 +10,8 @@ import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.KHRShaderSubgroup; import org.lwjgl.opengl.KHRShaderSubgroup;
import org.lwjgl.system.MemoryStack; import org.lwjgl.system.MemoryStack;
import com.jozufozu.flywheel.lib.math.MoreMath;
import net.minecraft.Util; import net.minecraft.Util;
/** /**
@ -18,19 +20,19 @@ import net.minecraft.Util;
* Each field stores an enum variant that provides access to the most appropriate version of a feature for the current * Each field stores an enum variant that provides access to the most appropriate version of a feature for the current
* system. * system.
*/ */
public class GlCompat { public final class GlCompat {
public static final boolean ALLOW_DSA = true;
public static final GLCapabilities CAPABILITIES = GL.createCapabilities(); public static final GLCapabilities CAPABILITIES = GL.createCapabilities();
public static final boolean amd = _decideIfWeAreAMD(); public static final boolean AMD = _decideIfWeAreAMD();
public static final boolean windows = _decideIfWeAreWindows(); public static final boolean WINDOWS = _decideIfWeAreWindows();
public static final boolean supportsIndirect = _decideIfWeSupportIndirect(); public static final boolean ALLOW_DSA = true;
public static final boolean SUPPORTS_INDIRECT = _decideIfWeSupportIndirect();
public static final int SUBGROUP_SIZE = _subgroupSize(); public static final int SUBGROUP_SIZE = _subgroupSize();
private GlCompat() { private GlCompat() {
} }
public static boolean onAMDWindows() { public static boolean onAMDWindows() {
return amd && windows; return AMD && WINDOWS;
} }
public static boolean supportsInstancing() { public static boolean supportsInstancing() {
@ -38,7 +40,22 @@ public class GlCompat {
} }
public static boolean supportsIndirect() { public static boolean supportsIndirect() {
return supportsIndirect; return SUPPORTS_INDIRECT;
}
private static boolean _decideIfWeAreAMD() {
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
if (vendor == null) {
return false;
}
// vendor string I got was "ATI Technologies Inc."
return vendor.contains("ATI") || vendor.contains("AMD");
}
private static boolean _decideIfWeAreWindows() {
return Util.getPlatform() == Util.OS.WINDOWS;
} }
private static boolean _decideIfWeSupportIndirect() { private static boolean _decideIfWeSupportIndirect() {
@ -50,7 +67,11 @@ public class GlCompat {
return GL31C.glGetInteger(KHRShaderSubgroup.GL_SUBGROUP_SIZE_KHR); return GL31C.glGetInteger(KHRShaderSubgroup.GL_SUBGROUP_SIZE_KHR);
} }
// try to guess // try to guess
return amd ? 64 : 32; return AMD ? 64 : 32;
}
public static int getComputeGroupCount(int invocations) {
return MoreMath.ceilingDiv(invocations, SUBGROUP_SIZE);
} }
/** /**
@ -73,20 +94,5 @@ public class GlCompat {
GL20C.nglShaderSource(glId, 1, pointers.address0(), 0); GL20C.nglShaderSource(glId, 1, pointers.address0(), 0);
} }
} }
private static boolean _decideIfWeAreWindows() {
return Util.getPlatform() == Util.OS.WINDOWS;
}
private static boolean _decideIfWeAreAMD() {
String vendor = GL20C.glGetString(GL20C.GL_VENDOR);
if (vendor == null) {
return false;
}
// vendor string I got was "ATI Technologies Inc."
return vendor.contains("ATI") || vendor.contains("AMD");
}
} }

View file

@ -1,6 +1,6 @@
package com.jozufozu.flywheel.glsl; package com.jozufozu.flywheel.glsl;
public enum GLSLVersion { public enum GlslVersion {
V110(110), V110(110),
V120(120), V120(120),
V130(130), V130(130),
@ -18,7 +18,7 @@ public enum GLSLVersion {
public final int version; public final int version;
GLSLVersion(int version) { GlslVersion(int version) {
this.version = version; this.version = version;
} }

View file

@ -40,13 +40,6 @@ public class ShaderSources {
cache.putAll(preloadCache); cache.putAll(preloadCache);
} }
public ShaderSources(ResourceManager manager, List<ResourceLocation> preloadEmpty) {
this.manager = manager;
for (ResourceLocation rl : preloadEmpty) {
cache.put(rl, SourceFile.empty(rl));
}
}
@NotNull @NotNull
public LoadResult find(ResourceLocation location) { public LoadResult find(ResourceLocation location) {
if (findStack.contains(location)) { if (findStack.contains(location)) {

View file

@ -39,9 +39,9 @@ public class GlslSwitch implements GlslStmt {
@Override @Override
public String prettyPrint() { public String prettyPrint() {
return """ return """
switch (%s) { switch (%s) {
%s %s
}""".formatted(on.prettyPrint(), formatCases()); }""".formatted(on.prettyPrint(), formatCases());
} }
@NotNull @NotNull

View file

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.gl.shader.GlProgram;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
public final class Contexts { public final class Contexts {
public static final SimpleContext WORLD = Context.REGISTRY.registerAndGet(new SimpleContext(Files.WORLD_VERTEX, Files.WORLD_FRAGMENT, program -> { public static final SimpleContext DEFAULT = Context.REGISTRY.registerAndGet(new SimpleContext(Files.DEFAULT_VERTEX, Files.DEFAULT_FRAGMENT, program -> {
program.bind(); program.bind();
program.setSamplerBinding("_flw_diffuseTex", 0); program.setSamplerBinding("_flw_diffuseTex", 0);
program.setSamplerBinding("_flw_overlayTex", 1); program.setSamplerBinding("_flw_overlayTex", 1);
@ -32,14 +32,14 @@ public final class Contexts {
} }
public static final class Files { public static final class Files {
public static final ResourceLocation WORLD_VERTEX = Names.WORLD.withSuffix(".vert"); public static final ResourceLocation DEFAULT_VERTEX = Names.DEFAULT.withSuffix(".vert");
public static final ResourceLocation WORLD_FRAGMENT = Names.WORLD.withSuffix(".frag"); public static final ResourceLocation DEFAULT_FRAGMENT = Names.DEFAULT.withSuffix(".frag");
public static final ResourceLocation CRUMBLING_VERTEX = Names.CRUMBLING.withSuffix(".vert"); public static final ResourceLocation CRUMBLING_VERTEX = Names.CRUMBLING.withSuffix(".vert");
public static final ResourceLocation CRUMBLING_FRAGMENT = Names.CRUMBLING.withSuffix(".frag"); public static final ResourceLocation CRUMBLING_FRAGMENT = Names.CRUMBLING.withSuffix(".frag");
} }
public static final class Names { public static final class Names {
public static final ResourceLocation WORLD = Flywheel.rl("context/world"); public static final ResourceLocation DEFAULT = Flywheel.rl("context/default");
public static final ResourceLocation CRUMBLING = Flywheel.rl("context/crumbling"); public static final ResourceLocation CRUMBLING = Flywheel.rl("context/crumbling");
} }
} }

View file

@ -14,12 +14,12 @@ public abstract class AbstractInstance implements Instance {
} }
@Override @Override
public InstanceType<?> type() { public final InstanceType<?> type() {
return type; return type;
} }
@Override @Override
public InstanceHandle handle() { public final InstanceHandle handle() {
return handle; return handle;
} }

View file

@ -14,6 +14,10 @@ public class CutoutShaders {
* Discard fragments with alpha close to or equal to zero. * Discard fragments with alpha close to or equal to zero.
*/ */
public static final CutoutShader EPSILON = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/epsilon.glsl"))); public static final CutoutShader EPSILON = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/epsilon.glsl")));
/**
* Discard fragments with alpha less than to 0.1.
*/
public static final CutoutShader ONE_TENTH = CutoutShader.REGISTRY.registerAndGet(new SimpleCutoutShader(Flywheel.rl("cutout/one_tenth.glsl")));
/** /**
* Discard fragments with alpha less than to 0.5. * Discard fragments with alpha less than to 0.5.
*/ */

View file

@ -39,27 +39,27 @@ public final class Materials {
.build(); .build();
public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder() public static final Material CHUNK_CUTOUT_MIPPED_SHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.HALF)
.useOverlay(false) .useOverlay(false)
.fallbackRenderType(RenderType.cutoutMipped()) .fallbackRenderType(RenderType.cutoutMipped())
.vertexTransformer(SHADING_TRANSFORMER) .vertexTransformer(SHADING_TRANSFORMER)
.build(); .build();
public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder() public static final Material CHUNK_CUTOUT_MIPPED_UNSHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.HALF)
.useOverlay(false) .useOverlay(false)
.diffuse(false) .diffuse(false)
.fallbackRenderType(RenderType.cutoutMipped()) .fallbackRenderType(RenderType.cutoutMipped())
.build(); .build();
public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder() public static final Material CHUNK_CUTOUT_SHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.ONE_TENTH)
.mipmap(false) .mipmap(false)
.useOverlay(false) .useOverlay(false)
.fallbackRenderType(RenderType.cutout()) .fallbackRenderType(RenderType.cutout())
.vertexTransformer(SHADING_TRANSFORMER) .vertexTransformer(SHADING_TRANSFORMER)
.build(); .build();
public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder() public static final Material CHUNK_CUTOUT_UNSHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.ONE_TENTH)
.mipmap(false) .mipmap(false)
.useOverlay(false) .useOverlay(false)
.diffuse(false) .diffuse(false)
@ -80,14 +80,14 @@ public final class Materials {
.build(); .build();
public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder() public static final Material CHUNK_TRIPWIRE_SHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.ONE_TENTH)
.transparency(Transparency.TRANSLUCENT) .transparency(Transparency.TRANSLUCENT)
.useOverlay(false) .useOverlay(false)
.fallbackRenderType(RenderType.tripwire()) .fallbackRenderType(RenderType.tripwire())
.vertexTransformer(SHADING_TRANSFORMER) .vertexTransformer(SHADING_TRANSFORMER)
.build(); .build();
public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder() public static final Material CHUNK_TRIPWIRE_UNSHADED = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.ONE_TENTH)
.transparency(Transparency.TRANSLUCENT) .transparency(Transparency.TRANSLUCENT)
.useOverlay(false) .useOverlay(false)
.diffuse(false) .diffuse(false)
@ -95,13 +95,14 @@ public final class Materials {
.build(); .build();
public static final Material CHEST = SimpleMaterial.builder() public static final Material CHEST = SimpleMaterial.builder()
.baseTexture(Sheets.CHEST_SHEET) .cutout(CutoutShaders.ONE_TENTH)
.texture(Sheets.CHEST_SHEET)
.mipmap(false) .mipmap(false)
.fallbackRenderType(Sheets.chestSheet()) .fallbackRenderType(Sheets.chestSheet())
.build(); .build();
public static final Material SHULKER = SimpleMaterial.builder() public static final Material SHULKER = SimpleMaterial.builder()
.cutout(CutoutShaders.EPSILON) .cutout(CutoutShaders.ONE_TENTH)
.baseTexture(Sheets.SHULKER_SHEET) .texture(Sheets.SHULKER_SHEET)
.mipmap(false) .mipmap(false)
.backfaceCulling(false) .backfaceCulling(false)
.fallbackRenderType(Sheets.shulkerBoxSheet()) .fallbackRenderType(Sheets.shulkerBoxSheet())
@ -111,7 +112,7 @@ public final class Materials {
.fallbackRenderType(Sheets.solidBlockSheet()) .fallbackRenderType(Sheets.solidBlockSheet())
.build(); .build();
public static final Material MINECART = SimpleMaterial.builder() public static final Material MINECART = SimpleMaterial.builder()
.baseTexture(MINECART_LOCATION) .texture(MINECART_LOCATION)
.mipmap(false) .mipmap(false)
.fallbackRenderType(RenderType.entitySolid(MINECART_LOCATION)) .fallbackRenderType(RenderType.entitySolid(MINECART_LOCATION))
.build(); .build();

View file

@ -21,7 +21,7 @@ public class SimpleMaterial implements Material {
protected final FogShader fog; protected final FogShader fog;
protected final CutoutShader cutout; protected final CutoutShader cutout;
protected final ResourceLocation baseTexture; protected final ResourceLocation texture;
protected final boolean blur; protected final boolean blur;
protected final boolean mipmap; protected final boolean mipmap;
@ -41,7 +41,7 @@ public class SimpleMaterial implements Material {
shaders = builder.shaders(); shaders = builder.shaders();
fog = builder.fog(); fog = builder.fog();
cutout = builder.cutout(); cutout = builder.cutout();
baseTexture = builder.baseTexture(); texture = builder.texture();
blur = builder.blur(); blur = builder.blur();
mipmap = builder.mipmap(); mipmap = builder.mipmap();
backfaceCulling = builder.backfaceCulling(); backfaceCulling = builder.backfaceCulling();
@ -88,8 +88,8 @@ public class SimpleMaterial implements Material {
} }
@Override @Override
public ResourceLocation baseTexture() { public ResourceLocation texture() {
return baseTexture; return texture;
} }
@Override @Override
@ -150,7 +150,7 @@ public class SimpleMaterial implements Material {
protected FogShader fog; protected FogShader fog;
protected CutoutShader cutout; protected CutoutShader cutout;
protected ResourceLocation baseTexture; protected ResourceLocation texture;
protected boolean blur; protected boolean blur;
protected boolean mipmap; protected boolean mipmap;
@ -171,14 +171,14 @@ public class SimpleMaterial implements Material {
shaders = StandardMaterialShaders.DEFAULT; shaders = StandardMaterialShaders.DEFAULT;
fog = FogShaders.LINEAR; fog = FogShaders.LINEAR;
cutout = CutoutShaders.OFF; cutout = CutoutShaders.OFF;
baseTexture = InventoryMenu.BLOCK_ATLAS; texture = InventoryMenu.BLOCK_ATLAS;
blur = false; blur = false;
mipmap = true; mipmap = true;
backfaceCulling = true; backfaceCulling = true;
polygonOffset = false; polygonOffset = false;
depthTest = DepthTest.LEQUAL; depthTest = DepthTest.LEQUAL;
transparency = Transparency.OPAQUE; transparency = Transparency.OPAQUE;
writeMask = WriteMask.BOTH; writeMask = WriteMask.COLOR_DEPTH;
useOverlay = true; useOverlay = true;
useLight = true; useLight = true;
diffuse = true; diffuse = true;
@ -194,7 +194,7 @@ public class SimpleMaterial implements Material {
shaders = material.shaders(); shaders = material.shaders();
fog = material.fog(); fog = material.fog();
cutout = material.cutout(); cutout = material.cutout();
baseTexture = material.baseTexture(); texture = material.texture();
blur = material.blur(); blur = material.blur();
mipmap = material.mipmap(); mipmap = material.mipmap();
backfaceCulling = material.backfaceCulling(); backfaceCulling = material.backfaceCulling();
@ -233,8 +233,8 @@ public class SimpleMaterial implements Material {
return this; return this;
} }
public Builder baseTexture(ResourceLocation value) { public Builder texture(ResourceLocation value) {
this.baseTexture = value; this.texture = value;
return this; return this;
} }
@ -314,8 +314,8 @@ public class SimpleMaterial implements Material {
} }
@Override @Override
public ResourceLocation baseTexture() { public ResourceLocation texture() {
return baseTexture; return texture;
} }
@Override @Override

View file

@ -2,7 +2,6 @@ package com.jozufozu.flywheel.lib.model;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Collection;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.joml.Vector4f; import org.joml.Vector4f;
@ -101,29 +100,33 @@ public final class ModelUtil {
return null; return null;
} }
public static Vector4f computeBoundingSphere(Collection<Mesh> values) { public static int computeTotalVertexCount(Iterable<Mesh> meshes) {
int totalVertices = 0; int vertexCount = 0;
for (Mesh value : values) { for (Mesh mesh : meshes) {
totalVertices += value.vertexCount(); vertexCount += mesh.vertexCount();
} }
var block = MemoryBlock.malloc((long) totalVertices * PositionOnlyVertexList.STRIDE); return vertexCount;
}
public static Vector4f computeBoundingSphere(Iterable<Mesh> meshes) {
int vertexCount = computeTotalVertexCount(meshes);
var block = MemoryBlock.malloc((long) vertexCount * PositionOnlyVertexList.STRIDE);
var vertexList = new PositionOnlyVertexList(); var vertexList = new PositionOnlyVertexList();
int baseVertex = 0; int baseVertex = 0;
for (Mesh value : values) { for (Mesh mesh : meshes) {
vertexList.ptr(block.ptr() + (long) baseVertex * PositionOnlyVertexList.STRIDE); vertexList.ptr(block.ptr() + (long) baseVertex * PositionOnlyVertexList.STRIDE);
value.write(vertexList); mesh.write(vertexList);
baseVertex += value.vertexCount(); baseVertex += mesh.vertexCount();
} }
vertexList.ptr(block.ptr()); vertexList.ptr(block.ptr());
vertexList.vertexCount(totalVertices); vertexList.vertexCount(vertexCount);
var sphere = computeBoundingSphere(vertexList);
var out = computeBoundingSphere(vertexList);
block.free(); block.free();
return out;
return sphere;
} }
public static Vector4f computeBoundingSphere(VertexList vertexList) { public static Vector4f computeBoundingSphere(VertexList vertexList) {

View file

@ -2,27 +2,42 @@ package com.jozufozu.flywheel.lib.model;
import java.util.Map; import java.util.Map;
import org.joml.Vector4fc;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.api.model.Model;
public class SimpleModel implements Model { public class SimpleModel implements Model {
private final Mesh mesh; private final ImmutableMap<Material, Mesh> meshes;
private final Map<Material, Mesh> meshMap; private final Vector4fc boundingSphere;
private final int vertexCount;
public SimpleModel(Mesh mesh, Material material) { public SimpleModel(ImmutableMap<Material, Mesh> meshes) {
this.mesh = mesh; this.meshes = meshes;
meshMap = ImmutableMap.of(material, mesh); this.boundingSphere = ModelUtil.computeBoundingSphere(meshes.values());
this.vertexCount = ModelUtil.computeTotalVertexCount(meshes.values());
} }
@Override @Override
public Map<Material, Mesh> getMeshes() { public Map<Material, Mesh> meshes() {
return meshMap; return meshes;
}
@Override
public Vector4fc boundingSphere() {
return boundingSphere;
}
@Override
public int vertexCount() {
return vertexCount;
} }
@Override @Override
public void delete() { public void delete() {
mesh.delete(); meshes.values()
.forEach(Mesh::delete);
} }
} }

View file

@ -0,0 +1,40 @@
package com.jozufozu.flywheel.lib.model;
import java.util.Map;
import org.joml.Vector4fc;
import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model;
public class SingleMeshModel implements Model {
private final Mesh mesh;
private final Map<Material, Mesh> meshMap;
public SingleMeshModel(Mesh mesh, Material material) {
this.mesh = mesh;
meshMap = ImmutableMap.of(material, mesh);
}
@Override
public Map<Material, Mesh> meshes() {
return meshMap;
}
@Override
public Vector4fc boundingSphere() {
return mesh.boundingSphere();
}
@Override
public int vertexCount() {
return mesh.vertexCount();
}
@Override
public void delete() {
mesh.delete();
}
}

View file

@ -1,32 +1,18 @@
package com.jozufozu.flywheel.lib.model.baked; package com.jozufozu.flywheel.lib.model.baked;
import java.util.Map;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.jozufozu.flywheel.api.material.Material; import com.jozufozu.flywheel.api.material.Material;
import com.jozufozu.flywheel.api.model.Mesh; import com.jozufozu.flywheel.api.model.Mesh;
import com.jozufozu.flywheel.api.model.Model; import com.jozufozu.flywheel.lib.model.SimpleModel;
public class TessellatedModel implements Model { public class TessellatedModel extends SimpleModel {
private final ImmutableMap<Material, Mesh> meshes;
private final boolean shadeSeparated; private final boolean shadeSeparated;
public TessellatedModel(ImmutableMap<Material, Mesh> meshes, boolean shadeSeparated) { public TessellatedModel(ImmutableMap<Material, Mesh> meshes, boolean shadeSeparated) {
this.meshes = meshes; super(meshes);
this.shadeSeparated = shadeSeparated; this.shadeSeparated = shadeSeparated;
} }
@Override
public Map<Material, Mesh> getMeshes() {
return meshes;
}
@Override
public void delete() {
meshes.values()
.forEach(Mesh::delete);
}
public boolean isShadeSeparated() { public boolean isShadeSeparated() {
return shadeSeparated; return shadeSeparated;
} }

View file

@ -24,9 +24,9 @@ public class FlwShaderUniforms implements ShaderUniforms {
public static final ResourceLocation FILE = Flywheel.rl("uniform/flywheel.glsl"); public static final ResourceLocation FILE = Flywheel.rl("uniform/flywheel.glsl");
public static final int SIZE = 224; public static final int SIZE = 224;
public static boolean FRUSTUM_PAUSED = false; public static boolean frustumPaused = false;
public static boolean FRUSTUM_CAPTURE = false; public static boolean frustumCapture = false;
public static boolean FOG_UPDATE = true; public static boolean fogUpdate = true;
@Override @Override
public int byteSize() { public int byteSize() {
@ -94,9 +94,9 @@ public class FlwShaderUniforms implements ShaderUniforms {
MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment
MemoryUtil.memPutInt(ptr + 112, getConstantAmbientLightFlag(context)); MemoryUtil.memPutInt(ptr + 112, getConstantAmbientLightFlag(context));
if (!FRUSTUM_PAUSED || FRUSTUM_CAPTURE) { if (!frustumPaused || frustumCapture) {
MatrixMath.writePackedFrustumPlanes(ptr + 128, viewProjection); MatrixMath.writePackedFrustumPlanes(ptr + 128, viewProjection);
FRUSTUM_CAPTURE = false; frustumCapture = false;
} }
dirty = true; dirty = true;
@ -110,7 +110,7 @@ public class FlwShaderUniforms implements ShaderUniforms {
} }
private boolean maybeUpdateFog() { private boolean maybeUpdateFog() {
if (!FOG_UPDATE || ptr == MemoryUtil.NULL) { if (!fogUpdate || ptr == MemoryUtil.NULL) {
return false; return false;
} }
@ -125,7 +125,7 @@ public class FlwShaderUniforms implements ShaderUniforms {
MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape() MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape()
.getIndex()); .getIndex());
FOG_UPDATE = false; fogUpdate = false;
return true; return true;
} }

View file

@ -14,7 +14,7 @@ import net.minecraft.client.renderer.FogRenderer;
abstract class FogUpdateMixin { abstract class FogUpdateMixin {
@Unique @Unique
private static void flywheel$updateFog() { private static void flywheel$updateFog() {
FlwShaderUniforms.FOG_UPDATE = true; FlwShaderUniforms.fogUpdate = true;
} }
@Inject(method = "setupNoFog()V", at = @At("RETURN")) @Inject(method = "setupNoFog()V", at = @At("RETURN"))

View file

@ -15,7 +15,7 @@ import com.jozufozu.flywheel.lib.instance.InstanceTypes;
import com.jozufozu.flywheel.lib.instance.OrientedInstance; import com.jozufozu.flywheel.lib.instance.OrientedInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.ModelHolder; import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.model.SimpleModel; import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
@ -26,7 +26,7 @@ import net.minecraft.world.level.block.entity.BellBlockEntity;
public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> implements DynamicVisual { public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> implements DynamicVisual {
private static final ModelHolder BELL_MODEL = new ModelHolder(() -> { private static final ModelHolder BELL_MODEL = new ModelHolder(() -> {
return new SimpleModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL); return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.BELL, BellRenderer.BELL_RESOURCE_LOCATION.sprite(), "bell_body"), Materials.BELL);
}); });
private OrientedInstance bell; private OrientedInstance bell;

View file

@ -17,7 +17,7 @@ import com.jozufozu.flywheel.lib.instance.OrientedInstance;
import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.ModelCache; import com.jozufozu.flywheel.lib.model.ModelCache;
import com.jozufozu.flywheel.lib.model.SimpleModel; import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.util.Pair; import com.jozufozu.flywheel.lib.util.Pair;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
@ -45,13 +45,13 @@ public class ChestVisual<T extends BlockEntity & LidBlockEntity> extends Abstrac
} }
private static final ModelCache<Pair<ChestType, Material>> BOTTOM_MODELS = new ModelCache<>(key -> { private static final ModelCache<Pair<ChestType, Material>> BOTTOM_MODELS = new ModelCache<>(key -> {
return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "bottom"), Materials.CHEST); return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "bottom"), Materials.CHEST);
}); });
private static final ModelCache<Pair<ChestType, Material>> LID_MODELS = new ModelCache<>(key -> { private static final ModelCache<Pair<ChestType, Material>> LID_MODELS = new ModelCache<>(key -> {
return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lid"), Materials.CHEST); return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lid"), Materials.CHEST);
}); });
private static final ModelCache<Pair<ChestType, Material>> LOCK_MODELS = new ModelCache<>(key -> { private static final ModelCache<Pair<ChestType, Material>> LOCK_MODELS = new ModelCache<>(key -> {
return new SimpleModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST); return new SingleMeshModel(ModelPartConverter.convert(LAYER_LOCATIONS.get(key.first()), key.second().sprite(), "lock"), Materials.CHEST);
}); });
private OrientedInstance bottom; private OrientedInstance bottom;

View file

@ -11,7 +11,7 @@ import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.ModelHolder; import com.jozufozu.flywheel.lib.model.ModelHolder;
import com.jozufozu.flywheel.lib.model.Models; import com.jozufozu.flywheel.lib.model.Models;
import com.jozufozu.flywheel.lib.model.SimpleModel; import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.visual.AbstractEntityVisual; import com.jozufozu.flywheel.lib.visual.AbstractEntityVisual;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
@ -26,7 +26,7 @@ import net.minecraft.world.phys.Vec3;
public class MinecartVisual<T extends AbstractMinecart> extends AbstractEntityVisual<T> implements TickableVisual, DynamicVisual { public class MinecartVisual<T extends AbstractMinecart> extends AbstractEntityVisual<T> implements TickableVisual, DynamicVisual {
private static final ModelHolder BODY_MODEL = new ModelHolder(() -> { private static final ModelHolder BODY_MODEL = new ModelHolder(() -> {
return new SimpleModel(ModelPartConverter.convert(ModelLayers.MINECART), Materials.MINECART); return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.MINECART), Materials.MINECART);
}); });
private TransformedInstance body; private TransformedInstance body;

View file

@ -13,7 +13,7 @@ import com.jozufozu.flywheel.lib.instance.InstanceTypes;
import com.jozufozu.flywheel.lib.instance.TransformedInstance; import com.jozufozu.flywheel.lib.instance.TransformedInstance;
import com.jozufozu.flywheel.lib.material.Materials; import com.jozufozu.flywheel.lib.material.Materials;
import com.jozufozu.flywheel.lib.model.ModelCache; import com.jozufozu.flywheel.lib.model.ModelCache;
import com.jozufozu.flywheel.lib.model.SimpleModel; import com.jozufozu.flywheel.lib.model.SingleMeshModel;
import com.jozufozu.flywheel.lib.model.part.ModelPartConverter; import com.jozufozu.flywheel.lib.model.part.ModelPartConverter;
import com.jozufozu.flywheel.lib.transform.TransformStack; import com.jozufozu.flywheel.lib.transform.TransformStack;
import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual; import com.jozufozu.flywheel.lib.visual.AbstractBlockEntityVisual;
@ -30,10 +30,10 @@ import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements DynamicVisual { public class ShulkerBoxVisual extends AbstractBlockEntityVisual<ShulkerBoxBlockEntity> implements DynamicVisual {
private static final ModelCache<Material> BASE_MODELS = new ModelCache<>(texture -> { private static final ModelCache<Material> BASE_MODELS = new ModelCache<>(texture -> {
return new SimpleModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "base"), Materials.SHULKER); return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "base"), Materials.SHULKER);
}); });
private static final ModelCache<Material> LID_MODELS = new ModelCache<>(texture -> { private static final ModelCache<Material> LID_MODELS = new ModelCache<>(texture -> {
return new SimpleModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER); return new SingleMeshModel(ModelPartConverter.convert(ModelLayers.SHULKER, texture.sprite(), "lid"), Materials.SHULKER);
}); });
private TransformedInstance base; private TransformedInstance base;

View file

@ -1,5 +1,3 @@
#include "flywheel:api/fragment.glsl"
uniform sampler2D _flw_crumblingTex; uniform sampler2D _flw_crumblingTex;
in vec2 crumblingTexCoord; in vec2 crumblingTexCoord;
@ -7,16 +5,12 @@ in vec2 crumblingTexCoord;
vec4 crumblingSampleColor; vec4 crumblingSampleColor;
void flw_beginFragment() { void flw_beginFragment() {
crumblingSampleColor = texture(_flw_crumblingTex, crumblingTexCoord);
// Make the crumbling overlay transparent when the diffuse layer is transparent.
crumblingSampleColor.a *= flw_fragColor.a;
if (crumblingSampleColor.a < 0.01) {
discard;
}
} }
void flw_endFragment() { void flw_endFragment() {
flw_fragColor = crumblingSampleColor; crumblingSampleColor = texture(_flw_crumblingTex, crumblingTexCoord);
// Make the crumbling overlay transparent when the fragment color after the material shader is transparent.
flw_fragColor.rgb = crumblingSampleColor.rgb;
flw_fragColor.a *= crumblingSampleColor.a;
} }

View file

@ -1,6 +1,3 @@
#include "flywheel:api/vertex.glsl"
#include "flywheel:util/fog.glsl"
out vec2 crumblingTexCoord; out vec2 crumblingTexCoord;
const int DOWN = 0; const int DOWN = 0;

View file

@ -1,5 +1,3 @@
#include "flywheel:api/fragment.glsl"
void flw_beginFragment() { void flw_beginFragment() {
} }

View file

@ -0,0 +1,5 @@
void flw_beginVertex() {
}
void flw_endVertex() {
}

View file

@ -1,8 +0,0 @@
#include "flywheel:api/vertex.glsl"
#include "flywheel:util/fog.glsl"
void flw_beginVertex() {
}
void flw_endVertex() {
}

View file

@ -1,3 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) { bool flw_discardPredicate(vec4 color) {
return finalColor.a < 0.01; return color.a < 0.01;
} }

View file

@ -1,3 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) { bool flw_discardPredicate(vec4 color) {
return finalColor.a < 0.5; return color.a < 0.5;
} }

View file

@ -1,3 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) { bool flw_discardPredicate(vec4 color) {
return false; return false;
} }

View file

@ -0,0 +1,3 @@
bool flw_discardPredicate(vec4 color) {
return color.a < 0.1;
}

View file

@ -1,5 +1,12 @@
#include "flywheel:util/fog.glsl" vec4 linearFog(vec4 color, float distance, float fogStart, float fogEnd, vec4 fogColor) {
if (distance <= fogStart) {
return color;
}
float fogValue = distance < fogEnd ? smoothstep(fogStart, fogEnd, distance) : 1.0;
return vec4(mix(color.rgb, fogColor.rgb, fogValue * fogColor.a), color.a);
}
vec4 flw_fogFilter(vec4 color) { vec4 flw_fogFilter(vec4 color) {
return linear_fog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor); return linearFog(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y, flywheel.fogColor);
} }

View file

@ -1,5 +1,13 @@
#include "flywheel:util/fog.glsl" vec4 linearFogFade(vec4 color, float distance, float fogStart, float fogEnd) {
if (distance <= fogStart) {
return color;
} else if (distance >= fogEnd) {
return vec4(0.0);
}
return color * smoothstep(fogEnd, fogStart, distance);
}
vec4 flw_fogFilter(vec4 color) { vec4 flw_fogFilter(vec4 color) {
return linear_fog_fade(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y); return linearFogFade(color, flw_distance, flywheel.fogRange.x, flywheel.fogRange.y);
} }

View file

@ -1,4 +1,3 @@
#include "flywheel:api/vertex.glsl"
#include "flywheel:util/quaternion.glsl" #include "flywheel:util/quaternion.glsl"
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) { void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) {

View file

@ -1,5 +1,3 @@
#include "flywheel:api/vertex.glsl"
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) { void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius) {
mat4 pose = i.pose; mat4 pose = i.pose;
center = (pose * vec4(center, 1.0)).xyz; center = (pose * vec4(center, 1.0)).xyz;

View file

@ -0,0 +1,18 @@
#include "flywheel:internal/material.glsl"
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
flat in ivec2 flw_vertexOverlay;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
in float flw_distance;
vec4 flw_sampleColor;
FlwMaterial flw_material;
vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;

View file

@ -0,0 +1,12 @@
#include "flywheel:internal/material.glsl"
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
FlwMaterial flw_material;

View file

@ -0,0 +1,21 @@
float sphericalDistance(vec3 relativePos) {
return length(relativePos);
}
float cylindricalDistance(vec3 relativePos) {
float distXZ = length(relativePos.xz);
float distY = abs(relativePos.y);
return max(distXZ, distY);
}
float fogDistance(vec3 relativePos, int fogShape) {
if (fogShape == 0) {
return sphericalDistance(relativePos);
} else {
return cylindricalDistance(relativePos);
}
}
float fogDistance(vec3 worldPos, vec3 cameraPos, int fogShape) {
return fogDistance(worldPos - cameraPos, fogShape);
}

View file

@ -1,44 +0,0 @@
// API
// ------------------------------------------
#include "flywheel:api/material.glsl"
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
flat in ivec2 flw_vertexOverlay;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
in float flw_distance;
in vec4 flw_var0;
in vec4 flw_var1;
in vec4 flw_var2;
in vec4 flw_var3;
FlwMaterial flw_material;
vec4 flw_sampleColor;
vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;
vec4 flw_fogFilter(vec4 color);
bool flw_discardPredicate(vec4 finalColor);
void flw_beginFragment();
void flw_materialFragment();
void flw_endFragment();
// ------------------------------------------
// INTERNAL
// ------------------------------------------
uint _flw_materialFragmentID;
uint _flw_fogID;
uint _flw_cutoutID;
// ------------------------------------------

View file

@ -1,36 +0,0 @@
// API
// ------------------------------------------
#include "flywheel:api/material.glsl"
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
out vec4 flw_var0;
out vec4 flw_var1;
out vec4 flw_var2;
out vec4 flw_var3;
FlwMaterial flw_material;
void flw_layoutVertex();
void flw_beginVertex();
void flw_instanceVertex(FlwInstance i);
void flw_materialVertex();
void flw_endVertex();
// ------------------------------------------
// INTERNAL
// ------------------------------------------
uint _flw_materialVertexID;
FlwInstance _flw_unpackInstance(FlwPackedInstance i);
// ------------------------------------------

View file

@ -0,0 +1,5 @@
#include "flywheel:internal/common_api_impl.frag"
uint _flw_uberMaterialFragmentIndex;
uint _flw_uberFogIndex;
uint _flw_uberCutoutIndex;

View file

@ -0,0 +1,3 @@
#include "flywheel:internal/common_api_impl.vert"
uint _flw_uberMaterialVertexIndex;

View file

@ -2,27 +2,25 @@
#include "flywheel:internal/indirect/model_descriptor.glsl" #include "flywheel:internal/indirect/model_descriptor.glsl"
#include "flywheel:internal/indirect/draw_command.glsl" #include "flywheel:internal/indirect/draw_command.glsl"
layout(local_size_x = FLW_SUBGROUP_SIZE) in; layout(local_size_x = _FLW_SUBGROUP_SIZE) in;
layout(std430, binding = MODEL_BINDING) restrict readonly buffer ModelDescriptors { layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict readonly buffer ModelBuffer {
ModelDescriptor models[]; ModelDescriptor models[];
}; };
layout(std430, binding = DRAW_BINDING) restrict buffer MeshDrawCommands { layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict buffer DrawBuffer {
MeshDrawCommand drawCommands[]; MeshDrawCommand drawCommands[];
}; };
// Apply the results of culling to the draw commands. // Apply the results of culling to the draw commands.
void main() { void main() {
uint drawID = gl_GlobalInvocationID.x; uint drawIndex = gl_GlobalInvocationID.x;
if (drawID >= drawCommands.length()) { if (drawIndex >= drawCommands.length()) {
return; return;
} }
uint modelID = drawCommands[drawID].modelID; uint modelIndex = drawCommands[drawIndex].modelIndex;
uint instanceCount = models[modelIndex].instanceCount;
uint instanceCount = models[modelID].instanceCount; drawCommands[drawIndex].instanceCount = instanceCount;
drawCommands[drawID].instanceCount = instanceCount;
} }

View file

@ -1,4 +1,4 @@
#define OBJECT_BINDING 0 #define _FLW_OBJECT_BUFFER_BINDING 0
#define TARGET_BINDING 1 #define _FLW_TARGET_BUFFER_BINDING 1
#define MODEL_BINDING 2 #define _FLW_MODEL_BUFFER_BINDING 2
#define DRAW_BINDING 3 #define _FLW_DRAW_BUFFER_BINDING 3

View file

@ -2,7 +2,7 @@
#include "flywheel:internal/indirect/model_descriptor.glsl" #include "flywheel:internal/indirect/model_descriptor.glsl"
#include "flywheel:internal/indirect/object.glsl" #include "flywheel:internal/indirect/object.glsl"
layout(local_size_x = FLW_SUBGROUP_SIZE) in; layout(local_size_x = _FLW_SUBGROUP_SIZE) in;
// need to add stubs so the instance shader compiles. // need to add stubs so the instance shader compiles.
vec4 flw_vertexPos; vec4 flw_vertexPos;
@ -19,15 +19,15 @@ vec4 flw_var3;
void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius); void flw_transformBoundingSphere(in FlwInstance i, inout vec3 center, inout float radius);
layout(std430, binding = OBJECT_BINDING) restrict readonly buffer ObjectBuffer { layout(std430, binding = _FLW_OBJECT_BUFFER_BINDING) restrict readonly buffer ObjectBuffer {
Object objects[]; Object objects[];
}; };
layout(std430, binding = TARGET_BINDING) restrict writeonly buffer TargetBuffer { layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict writeonly buffer TargetBuffer {
uint objectIDs[]; uint objectIndices[];
}; };
layout(std430, binding = MODEL_BINDING) restrict buffer ModelDescriptors { layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict buffer ModelBuffer {
ModelDescriptor models[]; ModelDescriptor models[];
}; };
@ -44,14 +44,14 @@ bool testSphere(vec3 center, float radius) {
return all(xyInside) && all(zInside); return all(xyInside) && all(zInside);
} }
bool isVisible(uint objectID, uint modelID) { bool isVisible(uint objectIndex, uint modelIndex) {
BoundingSphere sphere = models[modelID].boundingSphere; BoundingSphere sphere = models[modelIndex].boundingSphere;
vec3 center; vec3 center;
float radius; float radius;
unpackBoundingSphere(sphere, center, radius); _flw_unpackBoundingSphere(sphere, center, radius);
FlwInstance instance = _flw_unpackInstance(objects[objectID].instance); FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
flw_transformBoundingSphere(instance, center, radius); flw_transformBoundingSphere(instance, center, radius);
@ -59,18 +59,17 @@ bool isVisible(uint objectID, uint modelID) {
} }
void main() { void main() {
uint objectID = gl_GlobalInvocationID.x; uint objectIndex = gl_GlobalInvocationID.x;
if (objectID >= objects.length()) { if (objectIndex >= objects.length()) {
return; return;
} }
uint modelID = objects[objectID].modelID; uint modelIndex = objects[objectIndex].modelIndex;
if (isVisible(objectID, modelID)) { if (isVisible(objectIndex, modelIndex)) {
uint batchIndex = atomicAdd(models[modelID].instanceCount, 1); uint localIndex = atomicAdd(models[modelIndex].instanceCount, 1);
uint globalIndex = models[modelID].baseInstance + batchIndex; uint targetIndex = models[modelIndex].baseInstance + localIndex;
objectIndices[targetIndex] = objectIndex;
objectIDs[globalIndex] = objectID;
} }
} }

View file

@ -1,56 +0,0 @@
#include "flywheel:internal/indirect/api/vertex.glsl"
#include "flywheel:internal/indirect/buffers.glsl"
#include "flywheel:internal/indirect/draw_command.glsl"
#include "flywheel:internal/indirect/object.glsl"
#include "flywheel:internal/material.glsl"
#include "flywheel:internal/vertex_input.glsl"
#include "flywheel:util/diffuse.glsl"
flat out uvec3 _flw_material;
layout(std430, binding = OBJECT_BINDING) restrict readonly buffer ObjectBuffer {
Object objects[];
};
layout(std430, binding = TARGET_BINDING) restrict readonly buffer TargetBuffer {
uint objectIDs[];
};
layout(std430, binding = DRAW_BINDING) restrict readonly buffer DrawCommands {
MeshDrawCommand drawCommands[];
};
uniform uint _flw_baseDraw;
void main() {
uint instanceIndex = objectIDs[gl_BaseInstance + gl_InstanceID];
uint batchID = gl_DrawID + _flw_baseDraw;
FlwInstance i = _flw_unpackInstance(objects[instanceIndex].instance);
_flw_materialVertexID = drawCommands[batchID].vertexMaterialID;
uint p = drawCommands[batchID].packedMaterialProperties;
_flw_unpackMaterialProperties(p, flw_material);
_flw_material = uvec3(drawCommands[batchID].fragmentMaterialID, drawCommands[batchID].packedFogAndCutout, p);
_flw_layoutVertex();
flw_beginVertex();
flw_instanceVertex(i);
flw_materialVertex();
flw_endVertex();
flw_vertexNormal = normalize(flw_vertexNormal);
if (flw_material.diffuse) {
float diffuseFactor;
if (flywheel.constantAmbientLight == 1) {
diffuseFactor = diffuseNether(flw_vertexNormal);
} else {
diffuseFactor = diffuse(flw_vertexNormal);
}
flw_vertexColor = vec4(flw_vertexColor.rgb * diffuseFactor, flw_vertexColor.a);
}
flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape);
gl_Position = flywheel.viewProjection * flw_vertexPos;
}

View file

@ -5,9 +5,10 @@ struct MeshDrawCommand {
uint vertexOffset; uint vertexOffset;
uint baseInstance; uint baseInstance;
uint modelID; uint modelIndex;
uint vertexMaterialID;
uint fragmentMaterialID; uint materialVertexIndex;
uint materialFragmentIndex;
uint packedFogAndCutout; uint packedFogAndCutout;
uint packedMaterialProperties; uint packedMaterialProperties;
}; };

View file

@ -1,5 +1,4 @@
#include "flywheel:internal/indirect/api/fragment.glsl" #include "flywheel:internal/packed_material.glsl"
#include "flywheel:internal/material.glsl"
// optimize discard usage // optimize discard usage
#ifdef GL_ARB_conservative_depth #ifdef GL_ARB_conservative_depth
@ -10,15 +9,14 @@ uniform sampler2D _flw_diffuseTex;
uniform sampler2D _flw_overlayTex; uniform sampler2D _flw_overlayTex;
uniform sampler2D _flw_lightTex; uniform sampler2D _flw_lightTex;
flat in uvec3 _flw_material; flat in uvec3 _flw_packedMaterial;
out vec4 _flw_fragColor; out vec4 _flw_outputColor;
void main() { void main() {
_flw_materialFragmentID = _flw_material.x; _flw_uberMaterialFragmentIndex = _flw_packedMaterial.x;
_flw_unpackUint2x16(_flw_packedMaterial.y, _flw_uberCutoutIndex, _flw_uberFogIndex);
_flw_unpackUint2x16(_flw_material.y, _flw_cutoutID, _flw_fogID); _flw_unpackMaterialProperties(_flw_packedMaterial.z, flw_material);
_flw_unpackMaterialProperties(_flw_material.z, flw_material);
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord); flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor; flw_fragColor = flw_vertexColor * flw_sampleColor;
@ -45,5 +43,5 @@ void main() {
discard; discard;
} }
_flw_fragColor = flw_fogFilter(color); _flw_outputColor = flw_fogFilter(color);
} }

View file

@ -0,0 +1,57 @@
#include "flywheel:internal/diffuse.glsl"
#include "flywheel:internal/fog_distance.glsl"
#include "flywheel:internal/vertex_input.glsl"
#include "flywheel:internal/packed_material.glsl"
#include "flywheel:internal/indirect/buffers.glsl"
#include "flywheel:internal/indirect/draw_command.glsl"
#include "flywheel:internal/indirect/object.glsl"
layout(std430, binding = _FLW_OBJECT_BUFFER_BINDING) restrict readonly buffer ObjectBuffer {
Object objects[];
};
layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict readonly buffer TargetBuffer {
uint objectIndices[];
};
layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict readonly buffer DrawBuffer {
MeshDrawCommand drawCommands[];
};
uniform uint _flw_baseDraw;
flat out uvec3 _flw_packedMaterial;
void main() {
uint drawIndex = gl_DrawID + _flw_baseDraw;
MeshDrawCommand draw = drawCommands[drawIndex];
_flw_uberMaterialVertexIndex = draw.materialVertexIndex;
uint packedMaterialProperties = draw.packedMaterialProperties;
_flw_unpackMaterialProperties(packedMaterialProperties, flw_material);
_flw_packedMaterial = uvec3(draw.materialFragmentIndex, draw.packedFogAndCutout, packedMaterialProperties);
uint objectIndex = objectIndices[gl_BaseInstance + gl_InstanceID];
FlwInstance instance = _flw_unpackInstance(objects[objectIndex].instance);
_flw_layoutVertex();
flw_beginVertex();
flw_instanceVertex(instance);
flw_materialVertex();
flw_endVertex();
flw_vertexNormal = normalize(flw_vertexNormal);
if (flw_material.diffuse) {
float diffuseFactor;
if (flywheel.constantAmbientLight == 1) {
diffuseFactor = diffuseNether(flw_vertexNormal);
} else {
diffuseFactor = diffuse(flw_vertexNormal);
}
flw_vertexColor = vec4(flw_vertexColor.rgb * diffuseFactor, flw_vertexColor.a);
}
flw_distance = fogDistance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape);
gl_Position = flywheel.viewProjection * flw_vertexPos;
}

View file

@ -5,13 +5,13 @@ struct BoundingSphere {
float radius; float radius;
}; };
void unpackBoundingSphere(in BoundingSphere sphere, out vec3 center, out float radius) {
center = vec3(sphere.x, sphere.y, sphere.z);
radius = sphere.radius;
}
struct ModelDescriptor { struct ModelDescriptor {
uint instanceCount; uint instanceCount;
uint baseInstance; uint baseInstance;
BoundingSphere boundingSphere; BoundingSphere boundingSphere;
}; };
void _flw_unpackBoundingSphere(in BoundingSphere sphere, out vec3 center, out float radius) {
center = vec3(sphere.x, sphere.y, sphere.z);
radius = sphere.radius;
}

View file

@ -1,4 +1,4 @@
struct Object { struct Object {
uint modelID; uint modelIndex;
FlwPackedInstance instance; FlwPackedInstance instance;
}; };

View file

@ -1,43 +0,0 @@
// API
// -----------------------------------------
#include "flywheel:api/material.glsl"
in vec4 flw_vertexPos;
in vec4 flw_vertexColor;
in vec2 flw_vertexTexCoord;
flat in ivec2 flw_vertexOverlay;
in vec2 flw_vertexLight;
in vec3 flw_vertexNormal;
in float flw_distance;
in vec4 flw_var0;
in vec4 flw_var1;
in vec4 flw_var2;
in vec4 flw_var3;
vec4 flw_sampleColor;
vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;
FlwMaterial flw_material;
vec4 flw_fogFilter(vec4 color);
bool flw_discardPredicate(vec4 finalColor);
void flw_beginFragment();
void flw_materialFragment();
void flw_endFragment();
// -----------------------------------------
// INTERNAL
// -----------------------------------------
uint _flw_materialFragmentID;
uint _flw_fogID;
uint _flw_cutoutID;
// -----------------------------------------

View file

@ -1,35 +0,0 @@
// API
// ------------------------------------
#include "flywheel:api/material.glsl"
out vec4 flw_vertexPos;
out vec4 flw_vertexColor;
out vec2 flw_vertexTexCoord;
flat out ivec2 flw_vertexOverlay;
out vec2 flw_vertexLight;
out vec3 flw_vertexNormal;
out float flw_distance;
out vec4 flw_var0;
out vec4 flw_var1;
out vec4 flw_var2;
out vec4 flw_var3;
FlwMaterial flw_material;
void flw_layoutVertex();
void flw_beginVertex();
void flw_instanceVertex(FlwInstance i);
void flw_materialVertex();
void flw_endVertex();
// ------------------------------------
// INTERNAL
// ------------------------------------
uint _flw_materialVertexID;
FlwInstance _flw_unpackInstance();
// ------------------------------------

View file

@ -0,0 +1,5 @@
#include "flywheel:internal/common_api_impl.frag"
uint _flw_uberMaterialFragmentIndex;
uint _flw_uberFogIndex;
uint _flw_uberCutoutIndex;

View file

@ -0,0 +1,3 @@
#include "flywheel:internal/common_api_impl.vert"
uint _flw_uberMaterialVertexIndex;

View file

@ -1,5 +1,4 @@
#include "flywheel:internal/instancing/api/fragment.glsl" #include "flywheel:internal/packed_material.glsl"
#include "flywheel:internal/material.glsl"
// optimize discard usage // optimize discard usage
#ifdef GL_ARB_conservative_depth #ifdef GL_ARB_conservative_depth
@ -12,12 +11,11 @@ uniform sampler2D _flw_lightTex;
uniform uvec4 _flw_packedMaterial; uniform uvec4 _flw_packedMaterial;
out vec4 _flw_fragColor; out vec4 _flw_outputColor;
void main() { void main() {
_flw_materialFragmentID = _flw_packedMaterial.y; _flw_uberMaterialFragmentIndex = _flw_packedMaterial.y;
_flw_unpackUint2x16(_flw_packedMaterial.z, _flw_uberCutoutIndex, _flw_uberFogIndex);
_flw_unpackUint2x16(_flw_packedMaterial.z, _flw_cutoutID, _flw_fogID);
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material); _flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord); flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
@ -45,5 +43,5 @@ void main() {
discard; discard;
} }
_flw_fragColor = flw_fogFilter(color); _flw_outputColor = flw_fogFilter(color);
} }

View file

@ -1,20 +1,19 @@
#include "flywheel:internal/instancing/api/vertex.glsl" #include "flywheel:internal/diffuse.glsl"
#include "flywheel:internal/material.glsl" #include "flywheel:internal/fog_distance.glsl"
#include "flywheel:internal/vertex_input.glsl" #include "flywheel:internal/vertex_input.glsl"
#include "flywheel:util/diffuse.glsl" #include "flywheel:internal/packed_material.glsl"
uniform uvec4 _flw_packedMaterial; uniform uvec4 _flw_packedMaterial;
void main() { void main() {
_flw_materialVertexID = _flw_packedMaterial.x; _flw_uberMaterialVertexIndex = _flw_packedMaterial.x;
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material); _flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
FlwInstance i = _flw_unpackInstance(); FlwInstance instance = _flw_unpackInstance();
_flw_layoutVertex(); _flw_layoutVertex();
flw_beginVertex(); flw_beginVertex();
flw_instanceVertex(i); flw_instanceVertex(instance);
flw_materialVertex(); flw_materialVertex();
flw_endVertex(); flw_endVertex();
@ -30,6 +29,6 @@ void main() {
flw_vertexColor = vec4(flw_vertexColor.rgb * diffuseFactor, flw_vertexColor.a); flw_vertexColor = vec4(flw_vertexColor.rgb * diffuseFactor, flw_vertexColor.a);
} }
flw_distance = fog_distance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape); flw_distance = fogDistance(flw_vertexPos.xyz, flywheel.cameraPos.xyz, flywheel.fogShape);
gl_Position = flywheel.viewProjection * flw_vertexPos; gl_Position = flywheel.viewProjection * flw_vertexPos;
} }

View file

@ -1,57 +1,33 @@
#include "flywheel:api/material.glsl" const uint FLW_MAT_DEPTH_TEST_OFF = 0u;
const uint FLW_MAT_DEPTH_TEST_NEVER = 1u;
const uint FLW_MAT_DEPTH_TEST_LESS = 2u;
const uint FLW_MAT_DEPTH_TEST_EQUAL = 3u;
const uint FLW_MAT_DEPTH_TEST_LEQUAL = 4u;
const uint FLW_MAT_DEPTH_TEST_GREATER = 5u;
const uint FLW_MAT_DEPTH_TEST_NOTEQUAL = 6u;
const uint FLW_MAT_DEPTH_TEST_GEQUAL = 7u;
const uint FLW_MAT_DEPTH_TEST_ALWAYS = 8u;
// The number of bits each property takes up const uint FLW_MAT_TRANSPARENCY_OPAQUE = 0u;
const uint _FLW_BLUR_LENGTH = 1u; const uint FLW_MAT_TRANSPARENCY_ADDITIVE = 1u;
const uint _FLW_MIPMAP_LENGTH = 1u; const uint FLW_MAT_TRANSPARENCY_LIGHTNING = 2u;
const uint _FLW_BACKFACE_CULLING_LENGTH = 1u; const uint FLW_MAT_TRANSPARENCY_GLINT = 3u;
const uint _FLW_POLYGON_OFFSET_LENGTH = 1u; const uint FLW_MAT_TRANSPARENCY_CRUMBLING = 4u;
const uint _FLW_DEPTH_TEST_LENGTH = 4u; const uint FLW_MAT_TRANSPARENCY_TRANSLUCENT = 5u;
const uint _FLW_TRANSPARENCY_LENGTH = 3u;
const uint _FLW_WRITE_MASK_LENGTH = 2u;
const uint _FLW_USE_OVERLAY_LENGTH = 1u;
const uint _FLW_USE_LIGHT_LENGTH = 1u;
const uint _FLW_DIFFUSE_LENGTH = 1u;
// The bit offset of each property const uint FLW_MAT_WRITE_MASK_COLOR_DEPTH = 0u;
const uint _FLW_BLUR_OFFSET = 0u; const uint FLW_MAT_WRITE_MASK_COLOR = 1u;
const uint _FLW_MIPMAP_OFFSET = _FLW_BLUR_OFFSET + _FLW_BLUR_LENGTH; const uint FLW_MAT_WRITE_MASK_DEPTH = 2u;
const uint _FLW_BACKFACE_CULLING_OFFSET = _FLW_MIPMAP_OFFSET + _FLW_MIPMAP_LENGTH;
const uint _FLW_POLYGON_OFFSET_OFFSET = _FLW_BACKFACE_CULLING_OFFSET + _FLW_BACKFACE_CULLING_LENGTH;
const uint _FLW_DEPTH_TEST_OFFSET = _FLW_POLYGON_OFFSET_OFFSET + _FLW_POLYGON_OFFSET_LENGTH;
const uint _FLW_TRANSPARENCY_OFFSET = _FLW_DEPTH_TEST_OFFSET + _FLW_DEPTH_TEST_LENGTH;
const uint _FLW_WRITE_MASK_OFFSET = _FLW_TRANSPARENCY_OFFSET + _FLW_TRANSPARENCY_LENGTH;
const uint _FLW_USE_OVERLAY_OFFSET = _FLW_WRITE_MASK_OFFSET + _FLW_WRITE_MASK_LENGTH;
const uint _FLW_USE_LIGHT_OFFSET = _FLW_USE_OVERLAY_OFFSET + _FLW_USE_OVERLAY_LENGTH;
const uint _FLW_DIFFUSE_OFFSET = _FLW_USE_LIGHT_OFFSET + _FLW_USE_LIGHT_LENGTH;
// The bit mask for each property struct FlwMaterial {
const uint _FLW_BLUR_MASK = ((1u << _FLW_BLUR_LENGTH) - 1u) << _FLW_BLUR_OFFSET; bool blur;
const uint _FLW_MIPMAP_MASK = ((1u << _FLW_MIPMAP_LENGTH) - 1u) << _FLW_MIPMAP_OFFSET; bool mipmap;
const uint _FLW_BACKFACE_CULLING_MASK = ((1u << _FLW_BACKFACE_CULLING_LENGTH) - 1u) << _FLW_BACKFACE_CULLING_OFFSET; bool backfaceCulling;
const uint _FLW_POLYGON_OFFSET_MASK = ((1u << _FLW_POLYGON_OFFSET_LENGTH) - 1u) << _FLW_POLYGON_OFFSET_OFFSET; bool polygonOffset;
const uint _FLW_DEPTH_TEST_MASK = ((1u << _FLW_DEPTH_TEST_LENGTH) - 1u) << _FLW_DEPTH_TEST_OFFSET; uint depthTest;
const uint _FLW_TRANSPARENCY_MASK = ((1u << _FLW_TRANSPARENCY_LENGTH) - 1u) << _FLW_TRANSPARENCY_OFFSET; uint transparency;
const uint _FLW_WRITE_MASK_MASK = ((1u << _FLW_WRITE_MASK_LENGTH) - 1u) << _FLW_WRITE_MASK_OFFSET; uint writeMask;
const uint _FLW_USE_OVERLAY_MASK = ((1u << _FLW_USE_OVERLAY_LENGTH) - 1u) << _FLW_USE_OVERLAY_OFFSET; bool useOverlay;
const uint _FLW_USE_LIGHT_MASK = ((1u << _FLW_USE_LIGHT_LENGTH) - 1u) << _FLW_USE_LIGHT_OFFSET; bool useLight;
const uint _FLW_DIFFUSE_MASK = ((1u << _FLW_DIFFUSE_LENGTH) - 1u) << _FLW_DIFFUSE_OFFSET; bool diffuse;
};
// Packed format:
// diffuse[1] | useOverlay[1] | useLight[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
m.blur = (p & _FLW_BLUR_MASK) != 0u;
m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u;
m.backfaceCulling = (p & _FLW_BACKFACE_CULLING_MASK) != 0u;
m.polygonOffset = (p & _FLW_POLYGON_OFFSET_MASK) != 0u;
m.depthTest = (p & _FLW_DEPTH_TEST_MASK) >> _FLW_DEPTH_TEST_OFFSET;
m.transparency = (p & _FLW_TRANSPARENCY_MASK) >> _FLW_TRANSPARENCY_OFFSET;
m.writeMask = (p & _FLW_WRITE_MASK_MASK) >> _FLW_WRITE_MASK_OFFSET;
m.useOverlay = (p & _FLW_USE_OVERLAY_MASK) != 0u;
m.useLight = (p & _FLW_USE_LIGHT_MASK) != 0u;
m.diffuse = (p & _FLW_DIFFUSE_MASK) != 0u;
}
void _flw_unpackUint2x16(uint s, out uint hi, out uint lo) {
hi = (s >> 16) & 0xFFFFu;
lo = s & 0xFFFFu;
}

View file

@ -0,0 +1,55 @@
// The number of bits each property takes up
const uint _FLW_BLUR_LENGTH = 1u;
const uint _FLW_MIPMAP_LENGTH = 1u;
const uint _FLW_BACKFACE_CULLING_LENGTH = 1u;
const uint _FLW_POLYGON_OFFSET_LENGTH = 1u;
const uint _FLW_DEPTH_TEST_LENGTH = 4u;
const uint _FLW_TRANSPARENCY_LENGTH = 3u;
const uint _FLW_WRITE_MASK_LENGTH = 2u;
const uint _FLW_USE_OVERLAY_LENGTH = 1u;
const uint _FLW_USE_LIGHT_LENGTH = 1u;
const uint _FLW_DIFFUSE_LENGTH = 1u;
// The bit offset of each property
const uint _FLW_BLUR_OFFSET = 0u;
const uint _FLW_MIPMAP_OFFSET = _FLW_BLUR_OFFSET + _FLW_BLUR_LENGTH;
const uint _FLW_BACKFACE_CULLING_OFFSET = _FLW_MIPMAP_OFFSET + _FLW_MIPMAP_LENGTH;
const uint _FLW_POLYGON_OFFSET_OFFSET = _FLW_BACKFACE_CULLING_OFFSET + _FLW_BACKFACE_CULLING_LENGTH;
const uint _FLW_DEPTH_TEST_OFFSET = _FLW_POLYGON_OFFSET_OFFSET + _FLW_POLYGON_OFFSET_LENGTH;
const uint _FLW_TRANSPARENCY_OFFSET = _FLW_DEPTH_TEST_OFFSET + _FLW_DEPTH_TEST_LENGTH;
const uint _FLW_WRITE_MASK_OFFSET = _FLW_TRANSPARENCY_OFFSET + _FLW_TRANSPARENCY_LENGTH;
const uint _FLW_USE_OVERLAY_OFFSET = _FLW_WRITE_MASK_OFFSET + _FLW_WRITE_MASK_LENGTH;
const uint _FLW_USE_LIGHT_OFFSET = _FLW_USE_OVERLAY_OFFSET + _FLW_USE_OVERLAY_LENGTH;
const uint _FLW_DIFFUSE_OFFSET = _FLW_USE_LIGHT_OFFSET + _FLW_USE_LIGHT_LENGTH;
// The bit mask for each property
const uint _FLW_BLUR_MASK = ((1u << _FLW_BLUR_LENGTH) - 1u) << _FLW_BLUR_OFFSET;
const uint _FLW_MIPMAP_MASK = ((1u << _FLW_MIPMAP_LENGTH) - 1u) << _FLW_MIPMAP_OFFSET;
const uint _FLW_BACKFACE_CULLING_MASK = ((1u << _FLW_BACKFACE_CULLING_LENGTH) - 1u) << _FLW_BACKFACE_CULLING_OFFSET;
const uint _FLW_POLYGON_OFFSET_MASK = ((1u << _FLW_POLYGON_OFFSET_LENGTH) - 1u) << _FLW_POLYGON_OFFSET_OFFSET;
const uint _FLW_DEPTH_TEST_MASK = ((1u << _FLW_DEPTH_TEST_LENGTH) - 1u) << _FLW_DEPTH_TEST_OFFSET;
const uint _FLW_TRANSPARENCY_MASK = ((1u << _FLW_TRANSPARENCY_LENGTH) - 1u) << _FLW_TRANSPARENCY_OFFSET;
const uint _FLW_WRITE_MASK_MASK = ((1u << _FLW_WRITE_MASK_LENGTH) - 1u) << _FLW_WRITE_MASK_OFFSET;
const uint _FLW_USE_OVERLAY_MASK = ((1u << _FLW_USE_OVERLAY_LENGTH) - 1u) << _FLW_USE_OVERLAY_OFFSET;
const uint _FLW_USE_LIGHT_MASK = ((1u << _FLW_USE_LIGHT_LENGTH) - 1u) << _FLW_USE_LIGHT_OFFSET;
const uint _FLW_DIFFUSE_MASK = ((1u << _FLW_DIFFUSE_LENGTH) - 1u) << _FLW_DIFFUSE_OFFSET;
// Packed format:
// diffuse[1] | useOverlay[1] | useLight[1] | writeMask[2] | transparency[3] | depthTest[4] | polygonOffset[1] | backfaceCulling[1] | mipmap[1] | blur[1]
void _flw_unpackMaterialProperties(uint p, out FlwMaterial m) {
m.blur = (p & _FLW_BLUR_MASK) != 0u;
m.mipmap = (p & _FLW_MIPMAP_MASK) != 0u;
m.backfaceCulling = (p & _FLW_BACKFACE_CULLING_MASK) != 0u;
m.polygonOffset = (p & _FLW_POLYGON_OFFSET_MASK) != 0u;
m.depthTest = (p & _FLW_DEPTH_TEST_MASK) >> _FLW_DEPTH_TEST_OFFSET;
m.transparency = (p & _FLW_TRANSPARENCY_MASK) >> _FLW_TRANSPARENCY_OFFSET;
m.writeMask = (p & _FLW_WRITE_MASK_MASK) >> _FLW_WRITE_MASK_OFFSET;
m.useOverlay = (p & _FLW_USE_OVERLAY_MASK) != 0u;
m.useLight = (p & _FLW_USE_LIGHT_MASK) != 0u;
m.diffuse = (p & _FLW_DIFFUSE_MASK) != 0u;
}
void _flw_unpackUint2x16(uint s, out uint hi, out uint lo) {
hi = (s >> 16) & 0xFFFFu;
lo = s & 0xFFFFu;
}

View file

@ -1,5 +1,3 @@
#include "flywheel:api/vertex.glsl"
layout(location = 0) in vec3 _flw_pos; layout(location = 0) in vec3 _flw_pos;
layout(location = 1) in vec4 _flw_color; layout(location = 1) in vec4 _flw_color;
layout(location = 2) in vec2 _flw_texCoord; layout(location = 2) in vec2 _flw_texCoord;

View file

@ -1,4 +1,2 @@
#include "flywheel:api/fragment.glsl"
void flw_materialFragment() { void flw_materialFragment() {
} }

View file

@ -1,4 +1,2 @@
#include "flywheel:api/vertex.glsl"
void flw_materialVertex() { void flw_materialVertex() {
} }

View file

@ -1,4 +1,4 @@
struct FLWPackedPlanes { struct FrustumPlanes {
vec4 xyX; // <nx.x, px.x, ny.x, py.x> vec4 xyX; // <nx.x, px.x, ny.x, py.x>
vec4 xyY; // <nx.y, px.y, ny.y, py.y> vec4 xyY; // <nx.y, px.y, ny.y, py.y>
vec4 xyZ; // <nx.z, px.z, ny.z, py.z> vec4 xyZ; // <nx.z, px.z, ny.z, py.z>
@ -9,12 +9,12 @@ struct FLWPackedPlanes {
vec2 zW; // <nz.w, pz.w> vec2 zW; // <nz.w, pz.w>
}; };
struct flywheel_uniforms { struct FlywheelUniforms {
vec4 fogColor; vec4 fogColor;
vec2 fogRange; vec2 fogRange;
int fogShape; int fogShape;
mat4 viewProjection; mat4 viewProjection;
vec4 cameraPos; vec4 cameraPos;
int constantAmbientLight; int constantAmbientLight;
FLWPackedPlanes planes; FrustumPlanes planes;
}; };

View file

@ -1,40 +0,0 @@
float spherical_distance(vec3 relativePos) {
return length(relativePos);
}
float cylindrical_distance(vec3 relativePos) {
float distXZ = length(relativePos.xz);
float distY = abs(relativePos.y);
return max(distXZ, distY);
}
float fog_distance(vec3 relativePos, int fogShape) {
if (fogShape == 0) {
return spherical_distance(relativePos);
} else {
return cylindrical_distance(relativePos);
}
}
float fog_distance(vec3 worldPos, vec3 cameraPos, int fogShape) {
return fog_distance(worldPos - cameraPos, fogShape);
}
vec4 linear_fog(vec4 color, float distance, float fogStart, float fogEnd, vec4 fogColor) {
if (distance <= fogStart) {
return color;
}
float fogValue = distance < fogEnd ? smoothstep(fogStart, fogEnd, distance) : 1.0;
return vec4(mix(color.rgb, fogColor.rgb, fogValue * fogColor.a), color.a);
}
vec4 linear_fog_fade(vec4 color, float distance, float fogStart, float fogEnd) {
if (distance <= fogStart) {
return color;
} else if (distance >= fogEnd) {
return vec4(0.0);
}
return color * smoothstep(fogEnd, fogStart, distance);
}

View file

@ -1,8 +1,8 @@
#define PIOVER2 1.5707963268 #define PI_OVER_2 1.5707963268
vec4 quat(vec3 axis, float angle) { vec4 quat(vec3 axis, float angle) {
float halfAngle = angle * PIOVER2 / 180.0; float halfAngle = angle * PI_OVER_2 / 180.0;
vec2 cs = sin(vec2(PIOVER2 - halfAngle, halfAngle)); // compute sin and cos in one instruction vec2 cs = sin(vec2(PI_OVER_2 - halfAngle, halfAngle)); // compute sin and cos in one instruction
return vec4(axis.xyz * cs.y, cs.x); return vec4(axis.xyz * cs.y, cs.x);
} }