diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/BackendConfig.java b/common/src/backend/java/dev/engine_room/flywheel/backend/BackendConfig.java index b61b3bef5..c7632298e 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/BackendConfig.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/BackendConfig.java @@ -11,4 +11,6 @@ public interface BackendConfig { * @return The current light smoothness setting. */ LightSmoothness lightSmoothness(); + + boolean useLightDirections(); } diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/LevelUniforms.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/LevelUniforms.java index 978d9ed04..977fdd6f9 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/LevelUniforms.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/LevelUniforms.java @@ -1,15 +1,21 @@ package dev.engine_room.flywheel.backend.engine.uniform; +import org.joml.Vector3f; + import dev.engine_room.flywheel.api.RenderContext; +import dev.engine_room.flywheel.backend.BackendConfig; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; public final class LevelUniforms extends UniformWriter { - private static final int SIZE = 16 * 2 + 4 * 13; + private static final int SIZE = 16 * 4 + 4 * 13; static final UniformBuffer BUFFER = new UniformBuffer(Uniforms.LEVEL_INDEX, SIZE); + public static final Vector3f LIGHT0_DIRECTION = new Vector3f(); + public static final Vector3f LIGHT1_DIRECTION = new Vector3f(); + private LevelUniforms() { } @@ -24,6 +30,9 @@ public static void update(RenderContext context) { ptr = writeVec4(ptr, (float) skyColor.x, (float) skyColor.y, (float) skyColor.z, 1f); ptr = writeVec4(ptr, (float) cloudColor.x, (float) cloudColor.y, (float) cloudColor.z, 1f); + ptr = writeVec3(ptr, LIGHT0_DIRECTION); + ptr = writeVec3(ptr, LIGHT1_DIRECTION); + long dayTime = level.getDayTime(); long levelDay = dayTime / 24000L; float timeOfDay = (float) (dayTime - levelDay * 24000L) / 24000f; @@ -46,6 +55,8 @@ public static void update(RenderContext context) { ptr = writeInt(ptr, level.effects().constantAmbientLight() ? 1 : 0); + ptr = writeInt(ptr, BackendConfig.INSTANCE.useLightDirections() ? 1 : 0); + // TODO: use defines for custom dimension ids int dimensionId; ResourceKey dimension = level.dimension(); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/UniformWriter.java b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/UniformWriter.java index 7c3bd709f..81b2ba6b1 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/UniformWriter.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/engine/uniform/UniformWriter.java @@ -1,6 +1,7 @@ package dev.engine_room.flywheel.backend.engine.uniform; import org.joml.Matrix4f; +import org.joml.Vector3fc; import org.lwjgl.system.MemoryUtil; import dev.engine_room.flywheel.lib.util.ExtraMemoryOps; @@ -37,6 +38,10 @@ static long writeVec3(long ptr, float x, float y, float z) { return ptr + 16; } + static long writeVec3(long ptr, Vector3fc vec) { + return writeVec3(ptr, vec.x(), vec.y(), vec.z()); + } + static long writeVec4(long ptr, float x, float y, float z, float w) { MemoryUtil.memPutFloat(ptr, x); MemoryUtil.memPutFloat(ptr + 4, y); diff --git a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/GlStateManagerMixin.java b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/GlStateManagerMixin.java index e2aeffe91..d1369f934 100644 --- a/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/GlStateManagerMixin.java +++ b/common/src/backend/java/dev/engine_room/flywheel/backend/mixin/GlStateManagerMixin.java @@ -1,5 +1,7 @@ package dev.engine_room.flywheel.backend.mixin; +import org.joml.Matrix4f; +import org.joml.Vector3f; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -7,6 +9,7 @@ import com.mojang.blaze3d.platform.GlStateManager; +import dev.engine_room.flywheel.backend.engine.uniform.LevelUniforms; import dev.engine_room.flywheel.backend.gl.GlStateTracker; import dev.engine_room.flywheel.backend.gl.buffer.GlBufferType; @@ -26,4 +29,12 @@ abstract class GlStateManagerMixin { private static void flywheel$onUseProgram(int program, CallbackInfo ci) { GlStateTracker._setProgram(program); } + + @Inject(method = "setupLevelDiffuseLighting", at = @At("HEAD")) + private static void flywheel$onSetupLevelDiffuseLighting(Vector3f vector3f, Vector3f vector3f2, Matrix4f matrix4f, CallbackInfo ci) { + // Capture the light directions before they're transformed into screen space + // Basically all usages of assigning light direction go through here so I think this is safe + LevelUniforms.LIGHT0_DIRECTION.set(vector3f); + LevelUniforms.LIGHT1_DIRECTION.set(vector3f2); + } } diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag index 677e141ca..1037ec635 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/common.frag @@ -21,10 +21,14 @@ out vec4 _flw_outputColor; float _flw_diffuseFactor() { if (flw_material.diffuse) { - if (flw_constantAmbientLight == 1u) { - return diffuseNether(flw_vertexNormal); + if (flw_useLightDirections == 1u) { + return diffuseFromLightDirections(flw_vertexNormal); } else { - return diffuse(flw_vertexNormal); + if (flw_constantAmbientLight == 1u) { + return diffuseNether(flw_vertexNormal); + } else { + return diffuse(flw_vertexNormal); + } } } else { return 1.; diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/diffuse.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/diffuse.glsl index 53fbdc010..f2774b01b 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/diffuse.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/diffuse.glsl @@ -7,3 +7,11 @@ float diffuseNether(vec3 normal) { vec3 n2 = normal * normal * vec3(.6, .9, .8); return min(n2.x + n2.y + n2.z, 1.); } + +float diffuseFromLightDirections(vec3 normal) { + // We assume the directions are normalized before upload. + float light0 = max(0.0, dot(flw_light0Direction, normal)); + float light1 = max(0.0, dot(flw_light1Direction, normal)); + return min(1.0, (light0 + light1) * 0.6 + 0.4); +} + diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/level.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/level.glsl index 267f4b46a..f7f53f847 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/level.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/uniforms/level.glsl @@ -2,6 +2,9 @@ layout(std140) uniform _FlwLevelUniforms { vec4 flw_skyColor; vec4 flw_cloudColor; + vec4 _flw_light0Direction; + vec4 _flw_light1Direction; + /** The current day number of the level. */ uint flw_levelDay; /** The current fraction of the current day that has elapsed. */ @@ -23,11 +26,15 @@ layout(std140) uniform _FlwLevelUniforms { float flw_skyDarken; uint flw_constantAmbientLight; + uint flw_useLightDirections; /** Use FLW_DIMENSION_* ids to determine the dimension. May eventually be implemented for custom dimensions. */ uint flw_dimension; }; +#define flw_light0Direction (_flw_light0Direction.xyz) +#define flw_light1Direction (_flw_light1Direction.xyz) + #define FLW_DIMENSION_OVERWORLD 0 #define FLW_DIMENSION_NETHER 1 #define FLW_DIMENSION_END 2 diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelUtil.java b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelUtil.java index 17a93e383..c559f66d0 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelUtil.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/model/ModelUtil.java @@ -50,15 +50,15 @@ public static Material getMaterial(RenderType chunkRenderType, boolean shaded) { } @Nullable - public static Material getItemMaterial(RenderType renderType, boolean shaded) { - var chunkMaterial = getMaterial(renderType, shaded); + public static Material getItemMaterial(RenderType renderType) { + var chunkMaterial = getMaterial(renderType, true); if (chunkMaterial != null) { return chunkMaterial; } if (renderType == Sheets.translucentCullBlockSheet() || renderType == Sheets.translucentItemSheet()) { - return shaded ? Materials.CUTOUT_BLOCK : Materials.CUTOUT_UNSHADED_BLOCK; + return Materials.CUTOUT_BLOCK; } if (renderType == RenderType.glint() || renderType == RenderType.glintDirect()) { return Materials.GLINT; diff --git a/common/src/main/resources/assets/flywheel/lang/en_us.json b/common/src/main/resources/assets/flywheel/lang/en_us.json index 88d3081c4..a8d0d041c 100644 --- a/common/src/main/resources/assets/flywheel/lang/en_us.json +++ b/common/src/main/resources/assets/flywheel/lang/en_us.json @@ -6,5 +6,9 @@ "command.flywheel.limit_updates.get.off": "Update limiting is currently disabled", "command.flywheel.limit_updates.get.on": "Update limiting is currently enabled", "command.flywheel.limit_updates.set.off": "Update limiting is now disabled", - "command.flywheel.limit_updates.set.on": "Update limiting is now enabled" + "command.flywheel.limit_updates.set.on" : "Update limiting is now enabled", + "command.flywheel.use_light_directions.get.off" : "Not using light directions", + "command.flywheel.use_light_directions.get.on" : "Using light directions", + "command.flywheel.use_light_directions.set.off" : "Set light directions to off", + "command.flywheel.use_light_directions.set.on" : "Set light directions to on" } diff --git a/fabric/src/main/java/dev/engine_room/flywheel/impl/FabricFlwConfig.java b/fabric/src/main/java/dev/engine_room/flywheel/impl/FabricFlwConfig.java index cf51ddf48..061371a35 100644 --- a/fabric/src/main/java/dev/engine_room/flywheel/impl/FabricFlwConfig.java +++ b/fabric/src/main/java/dev/engine_room/flywheel/impl/FabricFlwConfig.java @@ -185,16 +185,24 @@ public JsonObject toJson() { public static class FabricBackendConfig implements BackendConfig { public static final LightSmoothness LIGHT_SMOOTHNESS_DEFAULT = LightSmoothness.SMOOTH; + public static final boolean USE_LIGHT_DIRECTIONS_DEFAULT = true; public LightSmoothness lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT; + public boolean useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT; @Override public LightSmoothness lightSmoothness() { return lightSmoothness; } + @Override + public boolean useLightDirections() { + return useLightDirections; + } + public void fromJson(JsonObject object) { readLightSmoothness(object); + readUseLightDirections(object); } private void readLightSmoothness(JsonObject object) { @@ -224,9 +232,23 @@ private void readLightSmoothness(JsonObject object) { lightSmoothness = LIGHT_SMOOTHNESS_DEFAULT; } + private void readUseLightDirections(JsonObject object) { + var useLightDirectionsJson = object.get("useLightDirections"); + + if (useLightDirectionsJson instanceof JsonPrimitive primitive && primitive.isBoolean()) { + useLightDirections = primitive.getAsBoolean(); + return; + } else if (useLightDirectionsJson != null) { + FlwBackend.LOGGER.warn("'useLightDirections' value must be a boolean"); + } + + useLightDirections = USE_LIGHT_DIRECTIONS_DEFAULT; + } + public JsonObject toJson() { JsonObject object = new JsonObject(); object.addProperty("lightSmoothness", lightSmoothness.getSerializedName()); + object.addProperty("useLightDirections", useLightDirections); return object; } } diff --git a/fabric/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java b/fabric/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java index 72ff04be9..46817bcaf 100644 --- a/fabric/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java +++ b/fabric/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java @@ -9,6 +9,7 @@ import dev.engine_room.flywheel.api.backend.Backend; import dev.engine_room.flywheel.api.backend.BackendManager; import dev.engine_room.flywheel.backend.compile.LightSmoothness; +import dev.engine_room.flywheel.backend.compile.PipelineCompiler; import dev.engine_room.flywheel.backend.engine.uniform.DebugMode; import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; @@ -133,12 +134,39 @@ public static void registerClientCommands(CommandDispatcher { + if (FabricFlwConfig.INSTANCE.backendConfig.useLightDirections) { + context.getSource() + .sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.on")); + } else { + context.getSource() + .sendFeedback(Component.translatable("command.flywheel.use_light_directions.get.off")); + } + return Command.SINGLE_SUCCESS; + }) + .then(ClientCommandManager.literal("on") + .executes(context -> { + FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = true; + FabricFlwConfig.INSTANCE.save(); + context.getSource() + .sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.on")); + return Command.SINGLE_SUCCESS; + })) + .then(ClientCommandManager.literal("off") + .executes(context -> { + FabricFlwConfig.INSTANCE.backendConfig.useLightDirections = false; + FabricFlwConfig.INSTANCE.save(); + context.getSource() + .sendFeedback(Component.translatable("command.flywheel.use_light_directions.set.off")); + return Command.SINGLE_SUCCESS; + }))); + dispatcher.register(command); } diff --git a/forge/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java b/forge/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java index ee46048d5..87a80c76f 100644 --- a/forge/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java +++ b/forge/src/main/java/dev/engine_room/flywheel/impl/FlwCommands.java @@ -7,6 +7,7 @@ import dev.engine_room.flywheel.api.backend.Backend; import dev.engine_room.flywheel.api.backend.BackendManager; import dev.engine_room.flywheel.backend.compile.LightSmoothness; +import dev.engine_room.flywheel.backend.compile.PipelineCompiler; import dev.engine_room.flywheel.backend.engine.uniform.DebugMode; import dev.engine_room.flywheel.backend.engine.uniform.FrameUniforms; import net.minecraft.client.Minecraft; @@ -131,12 +132,34 @@ public static void registerClientCommands(RegisterClientCommandsEvent event) { if (oldValue != newValue) { lightSmoothnessValue.set(newValue); - Minecraft.getInstance() - .reloadResourcePacks(); + PipelineCompiler.deleteAll(); } return Command.SINGLE_SUCCESS; }))); + var useLightDirectionsValue = ForgeFlwConfig.INSTANCE.client.backendConfig.useLightDirections; + command.then(Commands.literal("useLightDirections") + .executes(context -> { + if (useLightDirectionsValue.get()) { + sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.on")); + } else { + sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.get.off")); + } + return Command.SINGLE_SUCCESS; + }) + .then(Commands.literal("on") + .executes(context -> { + useLightDirectionsValue.set(true); + sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.on")); + return Command.SINGLE_SUCCESS; + })) + .then(Commands.literal("off") + .executes(context -> { + useLightDirectionsValue.set(false); + sendMessage(context.getSource(), Component.translatable("command.flywheel.use_light_directions.set.off")); + return Command.SINGLE_SUCCESS; + }))); + event.getDispatcher().register(command); } diff --git a/forge/src/main/java/dev/engine_room/flywheel/impl/ForgeFlwConfig.java b/forge/src/main/java/dev/engine_room/flywheel/impl/ForgeFlwConfig.java index dbf03d087..cd1994453 100644 --- a/forge/src/main/java/dev/engine_room/flywheel/impl/ForgeFlwConfig.java +++ b/forge/src/main/java/dev/engine_room/flywheel/impl/ForgeFlwConfig.java @@ -101,15 +101,24 @@ private ClientConfig(ForgeConfigSpec.Builder builder) { public static class ForgeBackendConfig implements BackendConfig { public final ForgeConfigSpec.EnumValue lightSmoothness; + public final ForgeConfigSpec.BooleanValue useLightDirections; public ForgeBackendConfig(ForgeConfigSpec.Builder builder) { lightSmoothness = builder.comment("How smooth flywheel's shader-based lighting should be. May have a large performance impact.") .defineEnum("lightSmoothness", LightSmoothness.SMOOTH); + + useLightDirections = builder.comment("If true, diffuse lighting is accurate to vanilla entities and block entities. If false, diffuse lighting is accurate to vanilla chunks. Zero performance impact, just a matter of visual preference.") + .define("useLightDirections", true); } @Override public LightSmoothness lightSmoothness() { return lightSmoothness.get(); } + + @Override + public boolean useLightDirections() { + return useLightDirections.get(); + } } }