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*/ 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*/ vec4 flw_sampleColor;
/*const*/ float flw_distance;
vec4 flw_fragColor;
ivec2 flw_fragOverlay;
vec2 flw_fragLight;
// To be implemented by material shaders.
// To be implemented by the material fragment shader.
vec4 flw_fogFilter(vec4 color);
bool flw_discardPredicate(vec4 finalColor);
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_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_CRUMBLING = 4u;
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_DEPTH = 2u;

View file

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

View file

@ -14,7 +14,7 @@ public interface Material {
CutoutShader cutout();
ResourceLocation baseTexture();
ResourceLocation texture();
/**
* 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 {
OPAQUE,
ADDITIVE,
LIGHTING,
LIGHTNING,
GLINT,
CRUMBLING,
TRANSLUCENT,

View file

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

View file

@ -2,18 +2,24 @@ package com.jozufozu.flywheel.api.model;
import java.util.Map;
import org.joml.Vector4fc;
import com.jozufozu.flywheel.api.material.Material;
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();
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.function.BooleanSupplier;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.NonExtendable
public interface TaskExecutor extends Executor {
/**
* Wait for <em>all</em> running tasks to finish.
@ -38,15 +41,6 @@ public interface TaskExecutor extends Executor {
*/
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.
* <br>
@ -64,4 +58,13 @@ public interface TaskExecutor extends Executor {
* @return {@code true} if the current thread is the main thread.
*/
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;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.NonExtendable
public interface VisualManager<T> {
/**
* Get the number of game objects that are currently being visualized.

View file

@ -1,5 +1,6 @@
package com.jozufozu.flywheel.api.visualization;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
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.block.entity.BlockEntity;
@ApiStatus.NonExtendable
public interface VisualizationManager {
static boolean supportsVisualization(@Nullable LevelAccessor 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.GlShader;
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.SourceComponent;
@ -36,7 +36,7 @@ import net.minecraft.resources.ResourceLocation;
* @param <K> The type of the key used to compile shaders.
*/
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);
}
@ -99,13 +99,13 @@ public class Compile<K> {
}
public static class ShaderCompilerBuilder<K> {
private final GLSLVersion glslVersion;
private final GlslVersion glslVersion;
private final ShaderType shaderType;
private Consumer<Compilation> compilationCallbacks = $ -> {
};
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.shaderType = shaderType;
}

View file

@ -24,8 +24,7 @@ public class FlwPrograms {
}
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, empty);
var sources = new ShaderSources(resourceManager);
var preLoadStats = new CompilerStats();
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) {
return UberShaderComponent.builder(Flywheel.rl("uber_fragment_material"))
return UberShaderComponent.builder(Flywheel.rl("uber_material_fragment"))
.materialSources(ShaderIndices.materialFragment()
.all())
.adapt(FnSignature.ofVoid("flw_materialFragment"))
.switchOn(GlslExpr.variable("_flw_materialFragmentID"))
.switchOn(GlslExpr.variable("_flw_uberMaterialFragmentIndex"))
.build(loadChecker);
}
@ -61,7 +79,7 @@ public class FlwPrograms {
.name("flw_fogFilter")
.arg("vec4", "color")
.build(), GlslExpr.variable("color"))
.switchOn(GlslExpr.variable("_flw_fogID"))
.switchOn(GlslExpr.variable("_flw_uberFogIndex"))
.build(loadChecker);
}
@ -74,16 +92,7 @@ public class FlwPrograms {
.name("flw_discardPredicate")
.arg("vec4", "color")
.build(), GlslExpr.boolLiteral(false))
.switchOn(GlslExpr.variable("_flw_cutoutID"))
.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"))
.switchOn(GlslExpr.variable("_flw_uberCutoutIndex"))
.build(loadChecker);
}
@ -96,16 +105,6 @@ public class FlwPrograms {
.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 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.shader.GlProgram;
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.SourceComponent;
import com.jozufozu.flywheel.lib.util.Unit;
@ -39,21 +39,22 @@ public class IndirectPrograms {
_delete();
var pipelineCompiler = PipelineCompiler.create(sources, Pipelines.INDIRECT, pipelineKeys, uniformComponent, vertexComponents, fragmentComponents);
var cullingCompiler = createCullingCompiler(uniformComponent, sources);
var stage2Compiler = createStage2Compiler(sources);
var applyCompiler = createApplyCompiler(sources);
try {
var pipelineResult = pipelineCompiler.compileAndReportErrors();
var cullingResult = cullingCompiler.compileAndReportErrors();
var stage2Result = stage2Compiler.compileAndReportErrors();
var applyResult = applyCompiler.compileAndReportErrors();
if (pipelineResult != null && cullingResult != null && stage2Result != null) {
instance = new IndirectPrograms(pipelineResult, cullingResult, stage2Result.get(Unit.INSTANCE));
if (pipelineResult != null && cullingResult != null && applyResult != null) {
instance = new IndirectPrograms(pipelineResult, cullingResult, applyResult.get(Unit.INSTANCE));
}
} catch (Throwable e) {
Flywheel.LOGGER.error("Failed to compile indirect programs", e);
}
pipelineCompiler.delete();
cullingCompiler.delete();
applyCompiler.delete();
}
private static ImmutableList<InstanceType<?>> createCullingKeys() {
@ -84,22 +85,22 @@ public class IndirectPrograms {
return CULL.harness(sources)
.keys(createCullingKeys())
.compiler(CULL.program()
.link(CULL.shader(GLSLVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.link(CULL.shader(GlslVersion.V460, ShaderType.COMPUTE)
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withComponent(uniformComponent)
.withComponent(IndirectComponent::create)
.withResource(Files.INDIRECT_CULL)
.withResource(InstanceType::instanceShader))
.then((key, program) -> program.setUniformBlockBinding("FLWUniforms", 0)))
.then((key, program) -> program.setUniformBlockBinding("FlwUniforms", 0)))
.build();
}
private static CompilationHarness<Unit> createStage2Compiler(ShaderSources sources) {
private static CompilationHarness<Unit> createApplyCompiler(ShaderSources sources) {
return APPLY.harness(sources)
.keys(ImmutableList.of(Unit.INSTANCE))
.compiler(APPLY.program()
.link(APPLY.shader(GLSLVersion.V460, ShaderType.COMPUTE)
.define("FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.link(APPLY.shader(GlslVersion.V460, ShaderType.COMPUTE)
.define("_FLW_SUBGROUP_SIZE", GlCompat.SUBGROUP_SIZE)
.withResource(Files.INDIRECT_APPLY)))
.build();
}

View file

@ -3,13 +3,13 @@ package com.jozufozu.flywheel.backend.compile;
import java.util.Objects;
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 net.minecraft.resources.ResourceLocation;
public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, ResourceLocation fragmentShader,
ResourceLocation vertexAPI, ResourceLocation fragmentAPI, InstanceAssembler assembler) {
public record Pipeline(GlslVersion glslVersion, ResourceLocation vertexMain, ResourceLocation fragmentMain,
ResourceLocation vertexApiImpl, ResourceLocation fragmentApiImpl, InstanceAssembler assembler) {
@FunctionalInterface
public interface InstanceAssembler {
/**
@ -28,35 +28,35 @@ public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, R
}
public static class Builder {
private GLSLVersion glslVersion;
private ResourceLocation vertex;
private ResourceLocation fragment;
private ResourceLocation vertexAPI;
private ResourceLocation fragmentAPI;
private GlslVersion glslVersion;
private ResourceLocation vertexMain;
private ResourceLocation fragmentMain;
private ResourceLocation vertexApiImpl;
private ResourceLocation fragmentApiImpl;
private InstanceAssembler assembler;
public Builder glslVersion(GLSLVersion glslVersion) {
public Builder glslVersion(GlslVersion glslVersion) {
this.glslVersion = glslVersion;
return this;
}
public Builder vertex(ResourceLocation vertex) {
this.vertex = vertex;
public Builder vertexMain(ResourceLocation shader) {
this.vertexMain = shader;
return this;
}
public Builder fragment(ResourceLocation fragment) {
this.fragment = fragment;
public Builder fragmentMain(ResourceLocation shader) {
this.fragmentMain = shader;
return this;
}
public Builder vertexAPI(ResourceLocation vertex) {
this.vertexAPI = vertex;
public Builder vertexApiImpl(ResourceLocation shader) {
this.vertexApiImpl = shader;
return this;
}
public Builder fragmentAPI(ResourceLocation fragment) {
this.fragmentAPI = fragment;
public Builder fragmentApiImpl(ResourceLocation shader) {
this.fragmentApiImpl = shader;
return this;
}
@ -67,12 +67,12 @@ public record Pipeline(GLSLVersion glslVersion, ResourceLocation vertexShader, R
public Pipeline build() {
Objects.requireNonNull(glslVersion);
Objects.requireNonNull(vertex);
Objects.requireNonNull(fragment);
Objects.requireNonNull(vertexAPI);
Objects.requireNonNull(fragmentAPI);
Objects.requireNonNull(vertexMain);
Objects.requireNonNull(fragmentMain);
Objects.requireNonNull(vertexApiImpl);
Objects.requireNonNull(fragmentApiImpl);
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(key -> pipeline.assembler()
.assemble(new Pipeline.InstanceAssemblerContext(InternalLayout.LAYOUT.getAttributeCount(), key.instanceType())))
.withResource(pipeline.vertexAPI())
.withResource(pipeline.vertexApiImpl())
.withComponents(vertexComponents)
.withResource(key -> key.instanceType()
.instanceShader())
.withResource(key -> key.contextShader()
.vertexShader())
.withResource(pipeline.vertexShader()))
.withResource(pipeline.vertexMain()))
.link(PIPELINE.shader(pipeline.glslVersion(), ShaderType.FRAGMENT)
.enableExtension("GL_ARB_conservative_depth")
.withComponent(uniformComponent)
.withResource(pipeline.fragmentAPI())
.withResource(pipeline.fragmentApiImpl())
.withComponents(fragmentComponents)
.withResource(key -> key.contextShader()
.fragmentShader())
.withResource(pipeline.fragmentShader()))
.withResource(pipeline.fragmentMain()))
.then((key, program) -> {
key.contextShader()
.onProgramLink(program);
program.setUniformBlockBinding("FLWUniforms", 0);
program.setUniformBlockBinding("FlwUniforms", 0);
}))
.build();
}

View file

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

View file

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

View file

@ -12,7 +12,7 @@ import com.jozufozu.flywheel.Flywheel;
import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlShader;
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.SourceFile;
import com.jozufozu.flywheel.lib.util.StringUtil;
@ -31,11 +31,11 @@ public class Compilation {
private final List<SourceFile> files = new ArrayList<>();
private final StringBuilder generatedSource;
private final StringBuilder fullSource;
private final GLSLVersion glslVersion;
private final GlslVersion glslVersion;
private final ShaderType shaderType;
private int generatedLines = 0;
public Compilation(GLSLVersion glslVersion, ShaderType shaderType) {
public Compilation(GlslVersion glslVersion, ShaderType shaderType) {
this.glslVersion = glslVersion;
this.shaderType = shaderType;
@ -88,12 +88,12 @@ public class Compilation {
private void appendHeader(SourceComponent component, String source) {
if (component instanceof SourceFile file) {
int fileID = files.size() + 1;
int fileId = files.size() + 1;
files.add(file);
fullSource.append("\n#line 0 ")
.append(fileID)
.append(fileId)
.append(" // ")
.append(file.name)
.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.ShaderType;
import com.jozufozu.flywheel.glsl.GLSLVersion;
import com.jozufozu.flywheel.glsl.GlslVersion;
import com.jozufozu.flywheel.glsl.SourceComponent;
public class ShaderCompiler {
@ -24,7 +24,7 @@ public class ShaderCompiler {
}
@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 cached = shaderCache.get(key);
if (cached != null) {
@ -67,6 +67,6 @@ public class ShaderCompiler {
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.Material;
import com.jozufozu.flywheel.api.material.Transparency;
import com.jozufozu.flywheel.api.material.WriteMask;
import com.jozufozu.flywheel.backend.ShaderIndices;
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;
@ -16,7 +16,7 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.AbstractTexture;
public final class MaterialRenderState {
public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::baseTexture)
public static final Comparator<Material> COMPARATOR = Comparator.comparing(Material::texture)
.thenComparing(Material::blur)
.thenComparing(Material::mipmap)
.thenComparing(Material::backfaceCulling)
@ -41,7 +41,7 @@ public final class MaterialRenderState {
GlTextureUnit.T0.makeActive();
AbstractTexture texture = Minecraft.getInstance()
.getTextureManager()
.getTexture(material.baseTexture());
.getTexture(material.texture());
texture.setFilter(material.blur(), material.mipmap());
var textureId = texture.getId();
RenderSystem.setShaderTexture(0, textureId);
@ -62,7 +62,7 @@ public final class MaterialRenderState {
RenderSystem.enablePolygonOffset();
} else {
RenderSystem.polygonOffset(0.0F, 0.0F);
RenderSystem.enablePolygonOffset();
RenderSystem.disablePolygonOffset();
}
}
@ -115,7 +115,7 @@ public final class MaterialRenderState {
RenderSystem.enableBlend();
RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE);
}
case LIGHTING -> {
case LIGHTNING -> {
RenderSystem.enableBlend();
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.uniform.ShaderUniforms;
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.memory.MemoryBlock;
import net.minecraft.util.Mth;
public class UniformBuffer {
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_BINDINGS = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BUFFER_BINDINGS);
private static final boolean PO2_ALIGNMENT = Mth.isPowerOfTwo(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_BINDINGS = GL32.glGetInteger(GL32.GL_MAX_UNIFORM_BUFFER_BINDINGS);
// private static final boolean PO2_ALIGNMENT = Mth.isPowerOfTwo(OFFSET_ALIGNMENT);
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 ProviderSet providerSet;
private UniformBuffer() {
buffer = new GlBuffer();
providerSet = new ProviderSet(ShaderUniforms.REGISTRY.getAll());
}
public static void syncAndBind(GlProgram program) {
getInstance().sync();
program.bind();
public static UniformBuffer get() {
if (instance == null) {
instance = new UniformBuffer();
}
return instance;
}
public void sync() {
@ -52,15 +43,6 @@ public class UniformBuffer {
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() {
providerSet.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 final ShaderUniforms shaderUniforms;
private final int offset;

View file

@ -48,7 +48,7 @@ class BatchedDrawManager extends InstancerStorage<BatchedInstancer<?>> {
@Override
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 meshes = model.getMeshes();
var meshes = model.meshes();
for (var entry : meshes.entrySet()) {
var material = entry.getKey();
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 PTR_SIZE = Pointer.POINTER_SIZE;
public static final long MODEL_STRIDE = 24;
// 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_OFFSET = 0;
public static final long MODEL_STRIDE = 24;
// Offsets to the 3 segments
private static final long HANDLE_OFFSET = 0;
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 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:
@ -65,13 +68,13 @@ public class IndirectBuffers {
this.objectStride = objectStride;
this.multiBindBlock = MemoryBlock.calloc(BUFFERS_SIZE_BYTES, 1);
object = new ResizableStorageArray(objectStride, 1.75);
target = new ResizableStorageArray(INT_SIZE, 1.75);
model = new ResizableStorageArray(MODEL_STRIDE, 2);
draw = new ResizableStorageArray(DRAW_COMMAND_STRIDE, 2);
object = new ResizableStorageArray(objectStride, OBJECT_GROWTH_FACTOR);
target = new ResizableStorageArray(INT_SIZE, OBJECT_GROWTH_FACTOR);
model = new ResizableStorageArray(MODEL_STRIDE, MODEL_GROWTH_FACTOR);
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);
target.ensureCapacity(objectCount);
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.model.Mesh;
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.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlCompat;
import com.jozufozu.flywheel.gl.shader.GlProgram;
import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.model.ModelUtil;
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 final GlProgram cull;
private final GlProgram draw;
private final GlProgram cullProgram;
private final GlProgram applyProgram;
private final GlProgram drawProgram;
private final long objectStride;
private final IndirectBuffers buffers;
public final IndirectMeshPool meshPool;
private final IndirectMeshPool meshPool;
private final List<IndirectModel> indirectModels = new ArrayList<>();
private final List<IndirectDraw> indirectDraws = new ArrayList<>();
private final Map<RenderStage, List<MultiDraw>> multiDraws = new EnumMap<>(RenderStage.class);
private boolean needsDrawBarrier;
private boolean needsSortDraws;
private int instanceCountThisFrame;
private final GlProgram apply;
IndirectCullingGroup(InstanceType<I> instanceType) {
var programs = IndirectPrograms.get();
cullProgram = programs.getCullingProgram(instanceType);
applyProgram = programs.getApplyProgram();
drawProgram = programs.getIndirectProgram(instanceType, Contexts.DEFAULT);
objectStride = instanceType.getLayout()
.getStride() + IndirectBuffers.INT_SIZE;
buffers = new IndirectBuffers(objectStride);
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) {
var meshes = model.getMeshes();
public void flush(StagingBuffer stagingBuffer) {
needsDrawBarrier = true;
instanceCountThisFrame = prepareModels();
var boundingSphere = ModelUtil.computeBoundingSphere(meshes.values());
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));
if (nothingToDo()) {
return;
}
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() {
multiDraws.clear();
// sort by stage, then material
indirectDraws.sort(Comparator.comparing(IndirectDraw::stage)
.thenComparing(IndirectDraw::material, MaterialRenderState.COMPARATOR));
indirectDraws.sort(DRAW_COMPARATOR);
for (int start = 0, i = 0; i < indirectDraws.size(); i++) {
var draw1 = indirectDraws.get(i);
@ -99,52 +146,22 @@ public class IndirectCullingGroup<I extends Instance> {
}
}
public void flush(StagingBuffer stagingBuffer) {
needsDrawBarrier = true;
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 boolean hasStage(RenderStage stage) {
return multiDraws.containsKey(stage);
}
public void dispatchCull() {
if (nothingToDo()) {
return;
public void add(IndirectInstancer<I> instancer, Model model, RenderStage stage) {
int modelIndex = indirectModels.size();
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() {
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);
needsSortDraws = true;
}
public void submit(RenderStage stage) {
@ -152,13 +169,14 @@ public class IndirectCullingGroup<I extends Instance> {
return;
}
UniformBuffer.syncAndBind(draw);
UniformBuffer.get().sync();
drawProgram.bind();
meshPool.bindForDraw();
buffers.bindForDraw();
drawBarrier();
var flwBaseDraw = draw.getUniformLocation("_flw_baseDraw");
var flwBaseDraw = drawProgram.getUniformLocation("_flw_baseDraw");
for (var multiDraw : multiDraws.get(stage)) {
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;
for (IndirectModel batch : indirectModels) {
var instanceCount = batch.instancer.getInstanceCount();
@ -190,7 +208,7 @@ public class IndirectCullingGroup<I extends Instance> {
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 handle = buffers.draw.handle();
@ -199,44 +217,23 @@ public class IndirectCullingGroup<I extends Instance> {
private void writeModels(long writePtr) {
for (var batch : indirectModels) {
batch.writeModel(writePtr);
batch.write(writePtr);
writePtr += IndirectBuffers.MODEL_STRIDE;
}
}
private void writeCommands(long writePtr) {
for (var batch : indirectDraws) {
batch.writeIndirectCommand(writePtr);
batch.write(writePtr);
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() {
buffers.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) {
void submit() {
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.material.Material;
import com.jozufozu.flywheel.backend.MaterialEncoder;
import com.jozufozu.flywheel.backend.ShaderIndices;
import com.jozufozu.flywheel.backend.engine.MaterialEncoder;
public class IndirectDraw {
private final IndirectModel model;
private final IndirectMeshPool.BufferedMesh mesh;
private final Material material;
private final IndirectMeshPool.BufferedMesh mesh;
private final RenderStage stage;
private final int vertexMaterialID;
private final int fragmentMaterialID;
private final int materialVertexIndex;
private final int materialFragmentIndex;
private final int packedFogAndCutout;
private final int packedMaterialProperties;
@ -24,8 +24,8 @@ public class IndirectDraw {
this.mesh = mesh;
this.stage = stage;
this.vertexMaterialID = ShaderIndices.getVertexShaderIndex(material.shaders());
this.fragmentMaterialID = ShaderIndices.getFragmentShaderIndex(material.shaders());
this.materialVertexIndex = ShaderIndices.getVertexShaderIndex(material.shaders());
this.materialFragmentIndex = ShaderIndices.getFragmentShaderIndex(material.shaders());
this.packedFogAndCutout = MaterialEncoder.packFogAndCutout(material);
this.packedMaterialProperties = MaterialEncoder.packProperties(material);
}
@ -42,16 +42,17 @@ public class IndirectDraw {
return stage;
}
public void writeIndirectCommand(long ptr) {
public void write(long ptr) {
MemoryUtil.memPutInt(ptr, mesh.indexCount()); // count
MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount
MemoryUtil.memPutInt(ptr + 8, mesh.firstIndex); // firstIndex
MemoryUtil.memPutInt(ptr + 12, mesh.baseVertex); // baseVertex
MemoryUtil.memPutInt(ptr + 16, model.baseInstance); // baseInstance
MemoryUtil.memPutInt(ptr + 4, 0); // instanceCount - to be set by the apply shader
MemoryUtil.memPutInt(ptr + 8, mesh.firstIndex()); // firstIndex
MemoryUtil.memPutInt(ptr + 12, mesh.baseVertex()); // baseVertex
MemoryUtil.memPutInt(ptr + 16, model.baseInstance()); // baseInstance
MemoryUtil.memPutInt(ptr + 20, model.id); // modelID
MemoryUtil.memPutInt(ptr + 24, vertexMaterialID); // vertexMaterialID
MemoryUtil.memPutInt(ptr + 28, fragmentMaterialID); // fragmentMaterialID
MemoryUtil.memPutInt(ptr + 20, model.index); // modelIndex
MemoryUtil.memPutInt(ptr + 24, materialVertexIndex); // materialVertexIndex
MemoryUtil.memPutInt(ptr + 28, materialFragmentIndex); // materialFragmentIndex
MemoryUtil.memPutInt(ptr + 32, packedFogAndCutout); // packedFogAndCutout
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<?>> {
private final StagingBuffer stagingBuffer = new StagingBuffer();
public final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
private final Map<InstanceType<?>, IndirectCullingGroup<?>> cullingGroups = new HashMap<>();
@Override
protected <I extends Instance> IndirectInstancer<?> create(InstanceType<I> type) {
return new IndirectInstancer<>(type);
}
@SuppressWarnings("unchecked")
@Override
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);
indirectList.add((IndirectInstancer<I>) instancer, stage, model);
var group = (IndirectCullingGroup<I>) cullingGroups.computeIfAbsent(key.type(), IndirectCullingGroup::new);
group.add((IndirectInstancer<I>) instancer, model, stage);
}
public boolean hasStage(RenderStage stage) {
for (var list : cullingGroups.values()) {
if (list.hasStage(stage)) {
for (var group : cullingGroups.values()) {
if (group.hasStage(stage)) {
return true;
}
}
return false;
}
public void renderStage(RenderStage stage) {
for (var group : cullingGroups.values()) {
group.submit(stage);
}
}
@Override
public void 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.task.Plan;
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.AbstractInstancer;
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.GlTextureUnit;
import com.jozufozu.flywheel.lib.task.Flag;
@ -61,9 +61,7 @@ public class IndirectEngine extends AbstractEngine {
GlTextureUnit.T2.makeActive();
RenderSystem.bindTexture(RenderSystem.getShaderTexture(2));
for (var list : drawManager.cullingGroups.values()) {
list.submit(stage);
}
drawManager.renderStage(stage);
MaterialRenderState.reset();

View file

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

View file

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

View file

@ -1,28 +1,24 @@
package com.jozufozu.flywheel.backend.engine.indirect;
import org.joml.Vector4f;
import org.joml.Vector4fc;
import org.lwjgl.system.MemoryUtil;
public class IndirectModel {
public final IndirectInstancer<?> instancer;
public final int id;
public int baseInstance = -1;
private boolean needsFullWrite = true;
public final int index;
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.id = id;
this.index = index;
this.boundingSphere = boundingSphere;
}
public void writeModel(long ptr) {
MemoryUtil.memPutInt(ptr, 0); // instanceCount - to be incremented by the compute shader
MemoryUtil.memPutInt(ptr + 4, baseInstance); // baseInstance
boundingSphere.getToAddress(ptr + 8); // boundingSphere
public int baseInstance() {
return baseInstance;
}
public void prepare(int baseInstance) {
@ -37,9 +33,15 @@ public class IndirectModel {
public void writeObjects(StagingBuffer stagingBuffer, long start, int dstVbo) {
if (needsFullWrite) {
instancer.writeFull(stagingBuffer, start, dstVbo);
instancer.writeAll(stagingBuffer, start, dstVbo);
} 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.Object2ReferenceOpenHashMap;
public class EBOCache {
public class EboCache {
private final List<Entry> quads = new ArrayList<>();
private final Object2ReferenceMap<Key, Entry> others = new Object2ReferenceOpenHashMap<>();
@ -37,9 +37,9 @@ public class EBOCache {
private int getQuads(int indexCount) {
// Use an existing quad EBO if there's one big enough.
for (Entry quadEBO : quads) {
if (quadEBO.gpuSize >= indexCount * GlNumericType.UINT.byteWidth()) {
return quadEBO.ebo;
for (Entry quadEbo : quads) {
if (quadEbo.gpuSize >= indexCount * GlNumericType.UINT.byteWidth()) {
return quadEbo.ebo;
}
}
// If not, create a new one.
@ -55,7 +55,6 @@ public class EBOCache {
}
private record Entry(int ebo, int gpuSize) {
@NotNull
private static Entry create(IndexSequence provider, int indexCount) {
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.Transparency;
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.engine.InstanceHandleImpl;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit;
import com.jozufozu.flywheel.lib.context.Contexts;
import com.jozufozu.flywheel.lib.material.CutoutShaders;
import com.jozufozu.flywheel.lib.material.FogShaders;
import com.jozufozu.flywheel.lib.material.SimpleMaterial;
import com.mojang.blaze3d.systems.RenderSystem;
@ -37,6 +38,8 @@ public class InstancedCrumbling {
return;
}
var crumblingMaterial = SimpleMaterial.builder();
try (var state = GlStateTracker.getRestoreState()) {
for (var shaderStateEntry : byShaderState.entrySet()) {
var byProgress = shaderStateEntry.getValue();
@ -50,8 +53,9 @@ public class InstancedCrumbling {
var baseMaterial = shader.material();
int diffuseTexture = getDiffuseTexture(baseMaterial);
var crumblingMaterial = SimpleMaterial.builderOf(baseMaterial)
.cutout(CutoutShaders.OFF)
crumblingMaterial.copyFrom(baseMaterial)
.fog(FogShaders.NONE)
.cutout(CutoutShaders.ONE_TENTH)
.polygonOffset(true)
.transparency(Transparency.CRUMBLING)
.writeMask(WriteMask.COLOR)
@ -60,8 +64,9 @@ public class InstancedCrumbling {
var program = InstancingPrograms.get()
.get(shader.instanceType(), Contexts.CRUMBLING);
UniformBuffer.syncAndBind(program);
program.bind();
UniformBuffer.get().sync();
InstancingEngine.uploadMaterialUniform(program, crumblingMaterial);
for (Int2ObjectMap.Entry<List<Runnable>> progressEntry : byProgress.int2ObjectEntrySet()) {
@ -71,7 +76,7 @@ public class InstancedCrumbling {
continue;
}
crumblingMaterial.baseTexture(ModelBakery.BREAKING_LOCATIONS.get(progressEntry.getIntKey()));
crumblingMaterial.texture(ModelBakery.BREAKING_LOCATIONS.get(progressEntry.getIntKey()));
MaterialRenderState.setup(crumblingMaterial);
@ -126,7 +131,7 @@ public class InstancedCrumbling {
private static int getDiffuseTexture(Material material) {
return Minecraft.getInstance()
.getTextureManager()
.getTexture(material.baseTexture())
.getTexture(material.texture())
.getId();
}
}

View file

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

View file

@ -45,7 +45,7 @@ public class InstancedMeshPool {
* @param eboCache The EBO cache to use.
* @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 -> {
BufferedMesh bufferedMesh = new BufferedMesh(m, byteSize, eboCache);
byteSize += bufferedMesh.size();
@ -143,7 +143,7 @@ public class InstancedMeshPool {
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.byteIndex = byteIndex;
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.task.Plan;
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.compile.InstancingPrograms;
import com.jozufozu.flywheel.backend.engine.AbstractEngine;
import com.jozufozu.flywheel.backend.engine.AbstractInstancer;
import com.jozufozu.flywheel.backend.engine.InstancerStorage;
import com.jozufozu.flywheel.backend.engine.MaterialEncoder;
import com.jozufozu.flywheel.backend.engine.MaterialRenderState;
import com.jozufozu.flywheel.backend.engine.UniformBuffer;
import com.jozufozu.flywheel.gl.GlStateTracker;
import com.jozufozu.flywheel.gl.GlTextureUnit;
@ -111,9 +111,10 @@ public class InstancingEngine extends AbstractEngine {
}
var program = InstancingPrograms.get()
.get(shader.instanceType(), Contexts.WORLD);
UniformBuffer.syncAndBind(program);
.get(shader.instanceType(), Contexts.DEFAULT);
program.bind();
UniformBuffer.get().sync();
uploadMaterialUniform(program, shader.material());
MaterialRenderState.setup(shader.material());

View file

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

View file

@ -10,6 +10,8 @@ import org.lwjgl.opengl.GLCapabilities;
import org.lwjgl.opengl.KHRShaderSubgroup;
import org.lwjgl.system.MemoryStack;
import com.jozufozu.flywheel.lib.math.MoreMath;
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
* system.
*/
public class GlCompat {
public static final boolean ALLOW_DSA = true;
public final class GlCompat {
public static final GLCapabilities CAPABILITIES = GL.createCapabilities();
public static final boolean amd = _decideIfWeAreAMD();
public static final boolean windows = _decideIfWeAreWindows();
public static final boolean supportsIndirect = _decideIfWeSupportIndirect();
public static final boolean AMD = _decideIfWeAreAMD();
public static final boolean WINDOWS = _decideIfWeAreWindows();
public static final boolean ALLOW_DSA = true;
public static final boolean SUPPORTS_INDIRECT = _decideIfWeSupportIndirect();
public static final int SUBGROUP_SIZE = _subgroupSize();
private GlCompat() {
}
public static boolean onAMDWindows() {
return amd && windows;
return AMD && WINDOWS;
}
public static boolean supportsInstancing() {
@ -38,7 +40,22 @@ public class GlCompat {
}
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() {
@ -50,7 +67,11 @@ public class GlCompat {
return GL31C.glGetInteger(KHRShaderSubgroup.GL_SUBGROUP_SIZE_KHR);
}
// 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);
}
}
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;
public enum GLSLVersion {
public enum GlslVersion {
V110(110),
V120(120),
V130(130),
@ -18,7 +18,7 @@ public enum GLSLVersion {
public final int version;
GLSLVersion(int version) {
GlslVersion(int version) {
this.version = version;
}

View file

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

View file

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

View file

@ -9,7 +9,7 @@ import com.jozufozu.flywheel.gl.shader.GlProgram;
import net.minecraft.resources.ResourceLocation;
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.setSamplerBinding("_flw_diffuseTex", 0);
program.setSamplerBinding("_flw_overlayTex", 1);
@ -32,14 +32,14 @@ public final class Contexts {
}
public static final class Files {
public static final ResourceLocation WORLD_VERTEX = Names.WORLD.withSuffix(".vert");
public static final ResourceLocation WORLD_FRAGMENT = Names.WORLD.withSuffix(".frag");
public static final ResourceLocation DEFAULT_VERTEX = Names.DEFAULT.withSuffix(".vert");
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_FRAGMENT = Names.CRUMBLING.withSuffix(".frag");
}
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");
}
}

View file

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

View file

@ -14,6 +14,10 @@ public class CutoutShaders {
* 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")));
/**
* 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.
*/

View file

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

View file

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

View file

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

View file

@ -2,27 +2,42 @@ 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 SimpleModel implements Model {
private final Mesh mesh;
private final Map<Material, Mesh> meshMap;
private final ImmutableMap<Material, Mesh> meshes;
private final Vector4fc boundingSphere;
private final int vertexCount;
public SimpleModel(Mesh mesh, Material material) {
this.mesh = mesh;
meshMap = ImmutableMap.of(material, mesh);
public SimpleModel(ImmutableMap<Material, Mesh> meshes) {
this.meshes = meshes;
this.boundingSphere = ModelUtil.computeBoundingSphere(meshes.values());
this.vertexCount = ModelUtil.computeTotalVertexCount(meshes.values());
}
@Override
public Map<Material, Mesh> getMeshes() {
return meshMap;
public Map<Material, Mesh> meshes() {
return meshes;
}
@Override
public Vector4fc boundingSphere() {
return boundingSphere;
}
@Override
public int vertexCount() {
return vertexCount;
}
@Override
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;
import java.util.Map;
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;
import com.jozufozu.flywheel.lib.model.SimpleModel;
public class TessellatedModel implements Model {
private final ImmutableMap<Material, Mesh> meshes;
public class TessellatedModel extends SimpleModel {
private final boolean shadeSeparated;
public TessellatedModel(ImmutableMap<Material, Mesh> meshes, boolean shadeSeparated) {
this.meshes = meshes;
super(meshes);
this.shadeSeparated = shadeSeparated;
}
@Override
public Map<Material, Mesh> getMeshes() {
return meshes;
}
@Override
public void delete() {
meshes.values()
.forEach(Mesh::delete);
}
public boolean isShadeSeparated() {
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 int SIZE = 224;
public static boolean FRUSTUM_PAUSED = false;
public static boolean FRUSTUM_CAPTURE = false;
public static boolean FOG_UPDATE = true;
public static boolean frustumPaused = false;
public static boolean frustumCapture = false;
public static boolean fogUpdate = true;
@Override
public int byteSize() {
@ -94,9 +94,9 @@ public class FlwShaderUniforms implements ShaderUniforms {
MemoryUtil.memPutFloat(ptr + 108, 0f); // vec4 alignment
MemoryUtil.memPutInt(ptr + 112, getConstantAmbientLightFlag(context));
if (!FRUSTUM_PAUSED || FRUSTUM_CAPTURE) {
if (!frustumPaused || frustumCapture) {
MatrixMath.writePackedFrustumPlanes(ptr + 128, viewProjection);
FRUSTUM_CAPTURE = false;
frustumCapture = false;
}
dirty = true;
@ -110,7 +110,7 @@ public class FlwShaderUniforms implements ShaderUniforms {
}
private boolean maybeUpdateFog() {
if (!FOG_UPDATE || ptr == MemoryUtil.NULL) {
if (!fogUpdate || ptr == MemoryUtil.NULL) {
return false;
}
@ -125,7 +125,7 @@ public class FlwShaderUniforms implements ShaderUniforms {
MemoryUtil.memPutInt(ptr + 24, RenderSystem.getShaderFogShape()
.getIndex());
FOG_UPDATE = false;
fogUpdate = false;
return true;
}

View file

@ -14,7 +14,7 @@ import net.minecraft.client.renderer.FogRenderer;
abstract class FogUpdateMixin {
@Unique
private static void flywheel$updateFog() {
FlwShaderUniforms.FOG_UPDATE = true;
FlwShaderUniforms.fogUpdate = true;
}
@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.material.Materials;
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.visual.AbstractBlockEntityVisual;
@ -26,7 +26,7 @@ import net.minecraft.world.level.block.entity.BellBlockEntity;
public class BellVisual extends AbstractBlockEntityVisual<BellBlockEntity> implements DynamicVisual {
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;

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.material.Materials;
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.util.Pair;
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 -> {
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 -> {
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 -> {
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;

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.model.ModelHolder;
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.visual.AbstractEntityVisual;
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 {
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;

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.material.Materials;
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.transform.TransformStack;
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 {
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 -> {
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;

View file

@ -1,5 +1,3 @@
#include "flywheel:api/fragment.glsl"
uniform sampler2D _flw_crumblingTex;
in vec2 crumblingTexCoord;
@ -7,16 +5,12 @@ in vec2 crumblingTexCoord;
vec4 crumblingSampleColor;
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() {
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;
const int DOWN = 0;

View file

@ -1,5 +1,3 @@
#include "flywheel:api/fragment.glsl"
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) {
return finalColor.a < 0.01;
bool flw_discardPredicate(vec4 color) {
return color.a < 0.01;
}

View file

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

View file

@ -1,3 +1,3 @@
bool flw_discardPredicate(vec4 finalColor) {
bool flw_discardPredicate(vec4 color) {
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) {
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) {
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"
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) {
mat4 pose = i.pose;
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/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[];
};
layout(std430, binding = DRAW_BINDING) restrict buffer MeshDrawCommands {
layout(std430, binding = _FLW_DRAW_BUFFER_BINDING) restrict buffer DrawBuffer {
MeshDrawCommand drawCommands[];
};
// Apply the results of culling to the draw commands.
void main() {
uint drawID = gl_GlobalInvocationID.x;
uint drawIndex = gl_GlobalInvocationID.x;
if (drawID >= drawCommands.length()) {
if (drawIndex >= drawCommands.length()) {
return;
}
uint modelID = drawCommands[drawID].modelID;
uint instanceCount = models[modelID].instanceCount;
drawCommands[drawID].instanceCount = instanceCount;
uint modelIndex = drawCommands[drawIndex].modelIndex;
uint instanceCount = models[modelIndex].instanceCount;
drawCommands[drawIndex].instanceCount = instanceCount;
}

View file

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

View file

@ -2,7 +2,7 @@
#include "flywheel:internal/indirect/model_descriptor.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.
vec4 flw_vertexPos;
@ -19,15 +19,15 @@ vec4 flw_var3;
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[];
};
layout(std430, binding = TARGET_BINDING) restrict writeonly buffer TargetBuffer {
uint objectIDs[];
layout(std430, binding = _FLW_TARGET_BUFFER_BINDING) restrict writeonly buffer TargetBuffer {
uint objectIndices[];
};
layout(std430, binding = MODEL_BINDING) restrict buffer ModelDescriptors {
layout(std430, binding = _FLW_MODEL_BUFFER_BINDING) restrict buffer ModelBuffer {
ModelDescriptor models[];
};
@ -44,14 +44,14 @@ bool testSphere(vec3 center, float radius) {
return all(xyInside) && all(zInside);
}
bool isVisible(uint objectID, uint modelID) {
BoundingSphere sphere = models[modelID].boundingSphere;
bool isVisible(uint objectIndex, uint modelIndex) {
BoundingSphere sphere = models[modelIndex].boundingSphere;
vec3 center;
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);
@ -59,18 +59,17 @@ bool isVisible(uint objectID, uint modelID) {
}
void main() {
uint objectID = gl_GlobalInvocationID.x;
uint objectIndex = gl_GlobalInvocationID.x;
if (objectID >= objects.length()) {
if (objectIndex >= objects.length()) {
return;
}
uint modelID = objects[objectID].modelID;
uint modelIndex = objects[objectIndex].modelIndex;
if (isVisible(objectID, modelID)) {
uint batchIndex = atomicAdd(models[modelID].instanceCount, 1);
uint globalIndex = models[modelID].baseInstance + batchIndex;
objectIDs[globalIndex] = objectID;
if (isVisible(objectIndex, modelIndex)) {
uint localIndex = atomicAdd(models[modelIndex].instanceCount, 1);
uint targetIndex = models[modelIndex].baseInstance + localIndex;
objectIndices[targetIndex] = objectIndex;
}
}

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 baseInstance;
uint modelID;
uint vertexMaterialID;
uint fragmentMaterialID;
uint modelIndex;
uint materialVertexIndex;
uint materialFragmentIndex;
uint packedFogAndCutout;
uint packedMaterialProperties;
};

View file

@ -1,5 +1,4 @@
#include "flywheel:internal/indirect/api/fragment.glsl"
#include "flywheel:internal/material.glsl"
#include "flywheel:internal/packed_material.glsl"
// optimize discard usage
#ifdef GL_ARB_conservative_depth
@ -10,15 +9,14 @@ uniform sampler2D _flw_diffuseTex;
uniform sampler2D _flw_overlayTex;
uniform sampler2D _flw_lightTex;
flat in uvec3 _flw_material;
flat in uvec3 _flw_packedMaterial;
out vec4 _flw_fragColor;
out vec4 _flw_outputColor;
void main() {
_flw_materialFragmentID = _flw_material.x;
_flw_unpackUint2x16(_flw_material.y, _flw_cutoutID, _flw_fogID);
_flw_unpackMaterialProperties(_flw_material.z, flw_material);
_flw_uberMaterialFragmentIndex = _flw_packedMaterial.x;
_flw_unpackUint2x16(_flw_packedMaterial.y, _flw_uberCutoutIndex, _flw_uberFogIndex);
_flw_unpackMaterialProperties(_flw_packedMaterial.z, flw_material);
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
flw_fragColor = flw_vertexColor * flw_sampleColor;
@ -45,5 +43,5 @@ void main() {
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;
};
void unpackBoundingSphere(in BoundingSphere sphere, out vec3 center, out float radius) {
center = vec3(sphere.x, sphere.y, sphere.z);
radius = sphere.radius;
}
struct ModelDescriptor {
uint instanceCount;
uint baseInstance;
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 {
uint modelID;
uint modelIndex;
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/material.glsl"
#include "flywheel:internal/packed_material.glsl"
// optimize discard usage
#ifdef GL_ARB_conservative_depth
@ -12,12 +11,11 @@ uniform sampler2D _flw_lightTex;
uniform uvec4 _flw_packedMaterial;
out vec4 _flw_fragColor;
out vec4 _flw_outputColor;
void main() {
_flw_materialFragmentID = _flw_packedMaterial.y;
_flw_unpackUint2x16(_flw_packedMaterial.z, _flw_cutoutID, _flw_fogID);
_flw_uberMaterialFragmentIndex = _flw_packedMaterial.y;
_flw_unpackUint2x16(_flw_packedMaterial.z, _flw_uberCutoutIndex, _flw_uberFogIndex);
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
flw_sampleColor = texture(_flw_diffuseTex, flw_vertexTexCoord);
@ -45,5 +43,5 @@ void main() {
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/material.glsl"
#include "flywheel:internal/diffuse.glsl"
#include "flywheel:internal/fog_distance.glsl"
#include "flywheel:internal/vertex_input.glsl"
#include "flywheel:util/diffuse.glsl"
#include "flywheel:internal/packed_material.glsl"
uniform uvec4 _flw_packedMaterial;
void main() {
_flw_materialVertexID = _flw_packedMaterial.x;
_flw_uberMaterialVertexIndex = _flw_packedMaterial.x;
_flw_unpackMaterialProperties(_flw_packedMaterial.w, flw_material);
FlwInstance i = _flw_unpackInstance();
FlwInstance instance = _flw_unpackInstance();
_flw_layoutVertex();
flw_beginVertex();
flw_instanceVertex(i);
flw_instanceVertex(instance);
flw_materialVertex();
flw_endVertex();
@ -30,6 +29,6 @@ void main() {
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;
}

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_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;
const uint FLW_MAT_TRANSPARENCY_OPAQUE = 0u;
const uint FLW_MAT_TRANSPARENCY_ADDITIVE = 1u;
const uint FLW_MAT_TRANSPARENCY_LIGHTNING = 2u;
const uint FLW_MAT_TRANSPARENCY_GLINT = 3u;
const uint FLW_MAT_TRANSPARENCY_CRUMBLING = 4u;
const uint FLW_MAT_TRANSPARENCY_TRANSLUCENT = 5u;
// 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;
const uint FLW_MAT_WRITE_MASK_COLOR_DEPTH = 0u;
const uint FLW_MAT_WRITE_MASK_COLOR = 1u;
const uint FLW_MAT_WRITE_MASK_DEPTH = 2u;
// 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;
}
struct FlwMaterial {
bool blur;
bool mipmap;
bool backfaceCulling;
bool polygonOffset;
uint depthTest;
uint transparency;
uint writeMask;
bool useOverlay;
bool useLight;
bool diffuse;
};

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 = 1) in vec4 _flw_color;
layout(location = 2) in vec2 _flw_texCoord;

View file

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

View file

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

View file

@ -1,4 +1,4 @@
struct FLWPackedPlanes {
struct FrustumPlanes {
vec4 xyX; // <nx.x, px.x, ny.x, py.x>
vec4 xyY; // <nx.y, px.y, ny.y, py.y>
vec4 xyZ; // <nx.z, px.z, ny.z, py.z>
@ -9,12 +9,12 @@ struct FLWPackedPlanes {
vec2 zW; // <nz.w, pz.w>
};
struct flywheel_uniforms {
struct FlywheelUniforms {
vec4 fogColor;
vec2 fogRange;
int fogShape;
mat4 viewProjection;
vec4 cameraPos;
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) {
float halfAngle = angle * PIOVER2 / 180.0;
vec2 cs = sin(vec2(PIOVER2 - halfAngle, halfAngle)); // compute sin and cos in one instruction
float halfAngle = angle * PI_OVER_2 / 180.0;
vec2 cs = sin(vec2(PI_OVER_2 - halfAngle, halfAngle)); // compute sin and cos in one instruction
return vec4(axis.xyz * cs.y, cs.x);
}