diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index 10845eb61..ff204b1de 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -56,6 +56,8 @@ import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; +import java.time.LocalDate; +import java.time.LocalTime; import java.util.ArrayList; import javax.inject.Inject; import javax.swing.SwingUtilities; @@ -124,6 +126,7 @@ import rs117.hd.config.FogDepthMode; import rs117.hd.config.UIScalingMode; import rs117.hd.config.WaterEffects; +import rs117.hd.environments.DayLight; import rs117.hd.environments.EnvironmentManager; import rs117.hd.lighting.LightManager; import rs117.hd.materials.Material; @@ -158,6 +161,7 @@ public class HdPlugin extends Plugin implements DrawCallbacks private static final int MATERIAL_PROPERTIES_COUNT = 12; private static final int LIGHT_PROPERTIES_COUNT = 8; private static final int SCALAR_BYTES = 4; + private static final LocalDate CURRENT_DATE = LocalDate.now(); @Inject private Client client; @@ -402,6 +406,8 @@ enum ComputeMode public boolean configNpcLights = true; public boolean configShadowsEnabled = false; public boolean configExpandShadowDraw = false; + public boolean configDayNightEnabled = false; + public boolean configDayOnly = false; // Reduces drawing a buggy mess when toggling HD private boolean startUpCompleted = false; @@ -423,6 +429,8 @@ protected void startUp() configNpcLights = config.npcLights(); configShadowsEnabled = config.shadowsEnabled(); configExpandShadowDraw = config.expandShadowDraw(); + configDayNightEnabled = config.dayNight(); + configDayOnly = config.dayOnly(); clientThread.invoke(() -> { @@ -1594,8 +1602,15 @@ private void drawFrame(int overlayColor) Matrix4 lightProjectionMatrix = new Matrix4(); float lightPitch = -128; float lightYaw = 55; + boolean shadowsAvailable = true; + if(configDayNightEnabled) { + DayLight timeOfDay = environmentManager.currentTimeOfDay; + lightPitch = timeOfDay.getCurrentPitch(LocalTime.now()); + lightYaw = timeOfDay.getCurrentYaw(CURRENT_DATE); + shadowsAvailable = timeOfDay.isShadowsEnabled(); + } - if (client.getGameState() == GameState.LOGGED_IN && configShadowsEnabled && fboShadowMap != -1 && environmentManager.currentDirectionalStrength > 0.0f) + if (client.getGameState() == GameState.LOGGED_IN && configShadowsEnabled && shadowsAvailable && fboShadowMap != -1 && environmentManager.currentDirectionalStrength > 0.0f) { // render shadow depth map gl.glViewport(0, 0, config.shadowResolution().getValue(), config.shadowResolution().getValue()); @@ -1791,9 +1806,9 @@ else if (config.fogDepthMode() == FogDepthMode.NONE) double lightX = Math.cos(lightPitchRadians) * Math.sin(lightYawRadians); double lightY = Math.sin(lightPitchRadians); double lightZ = Math.cos(lightPitchRadians) * Math.cos(lightYawRadians); - gl.glUniform1f(uniLightX, (float)lightX); - gl.glUniform1f(uniLightY, (float)lightY); - gl.glUniform1f(uniLightZ, (float)lightZ); + gl.glUniform1f(uniLightX, (float) lightX); + gl.glUniform1f(uniLightY, (float) lightY); + gl.glUniform1f(uniLightZ, (float) lightZ); // use a curve to calculate max bias value based on the density of the shadow map float shadowPixelsPerTile = (float)config.shadowResolution().getValue() / (float)config.shadowDistance().getValue(); @@ -2157,6 +2172,16 @@ public void onConfigChanged(ConfigChanged event) case "expandShadowDraw": configExpandShadowDraw = config.expandShadowDraw(); break; + case "dayNight": + configDayNightEnabled = config.dayNight(); + reloadScene(); + environmentManager.update(); + break; + case "dayOnly": + configDayOnly = config.dayOnly(); + reloadScene(); + environmentManager.update(); + break; } } diff --git a/src/main/java/rs117/hd/HdPluginConfig.java b/src/main/java/rs117/hd/HdPluginConfig.java index 82cb581f7..551706760 100644 --- a/src/main/java/rs117/hd/HdPluginConfig.java +++ b/src/main/java/rs117/hd/HdPluginConfig.java @@ -295,7 +295,6 @@ default boolean expandShadowDraw() } - /*====== Environment settings ======*/ @ConfigSection( @@ -415,4 +414,28 @@ default boolean tzhaarHD() { return true; } + + @ConfigItem( + keyName = "dayNight", + name = "Day/Night Cycle", + description = "Environmental lighting will be based on your local PC's time of day.", + position = 209, + section = environmentSettings + ) + default boolean dayNight() + { + return false; + } + + @ConfigItem( + keyName = "dayOnly", + name = "Day Only", + description = "Only show day lighting for you local PC time of day.", + position = 210, + section = environmentSettings + ) + default boolean dayOnly() + { + return false; + } } diff --git a/src/main/java/rs117/hd/environments/DayLight.java b/src/main/java/rs117/hd/environments/DayLight.java new file mode 100644 index 000000000..3df9825af --- /dev/null +++ b/src/main/java/rs117/hd/environments/DayLight.java @@ -0,0 +1,68 @@ +package rs117.hd.environments; + +import lombok.extern.slf4j.Slf4j; + +import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; + +@Slf4j +public enum DayLight { + + DAY(LocalTime.of(7, 0), true), + NIGHT(LocalTime.of(17, 0), false); + + private LocalTime startTime; + private boolean shadowsEnabled; + + /** + * This is a day(12-hour) based change. + */ + private static final int START_PITCH = 175; + private static final int END_PITCH = 360; + + /** + * This is a season(month) based changed. + * December/June = -90 degrees + * March/September = -45/-135 degrees + */ + private static final int START_YAW = -45; + private static final int END_YAW = -135; + + /** + * TODO: Calculate this value based on distance between sunrise/sunset. + */ + private static final float CYCLE_LENGTH = 12; + + DayLight(LocalTime startTime, boolean shadowsEnabled) { + this.startTime = startTime; + this.shadowsEnabled = shadowsEnabled; + } + + public boolean isShadowsEnabled() { + return shadowsEnabled; + } + + public static DayLight getTimeOfDay(LocalTime currentTime) { + return currentTime.isAfter(DAY.startTime) && currentTime.isBefore(NIGHT.startTime) ? DAY : NIGHT; + } + + private float percentageOfDaylight(LocalTime currentTime) { + return Math.abs(Duration.between(currentTime, startTime).toMillis()) / (CYCLE_LENGTH * 60 * 60 * 1000); + } + + private float percentageOfSeason(LocalDate currentDate) { + float month = currentDate.getMonthValue() + (currentDate.getDayOfMonth() / currentDate.lengthOfMonth()); + float normalizedMonth = month <= 6 ? month : month - 7; + return normalizedMonth / 6; + } + + public float getCurrentPitch(LocalTime currentTime) { + return percentageOfDaylight(currentTime) * (END_PITCH - START_PITCH) + START_PITCH; + } + + public float getCurrentYaw(LocalDate currentDate) { + return percentageOfSeason(currentDate) * (END_YAW - START_YAW) + START_YAW; + } + +} diff --git a/src/main/java/rs117/hd/environments/Environment.java b/src/main/java/rs117/hd/environments/Environment.java index a27d3611d..13c5f1150 100644 --- a/src/main/java/rs117/hd/environments/Environment.java +++ b/src/main/java/rs117/hd/environments/Environment.java @@ -757,7 +757,14 @@ public enum Environment UNKNOWN_OVERWORLD(Area.UNKNOWN_OVERWORLD, new Properties()), // overrides 'ALL' to provide default daylight conditions for the overworld area - OVERWORLD(Area.OVERWORLD, new Properties()), + OVERWORLD(Area.OVERWORLD, new Properties(), DayLight.DAY), + OVERWORLD_NIGHT(Area.OVERWORLD, new Properties() + .setFogColor(15, 14, 13) + .setFogDepth(40) + .setAmbientColor("#292828") + .setAmbientStrength(0.4f) + .setDirectionalStrength(0.7f) + .setDirectionalColor("#FFFFFF"), DayLight.NIGHT), // used for underground, instances, etc. ALL(Area.ALL, new Properties() .setFogColor("#31271A") @@ -788,6 +795,7 @@ public enum Environment private final int groundFogStart; private final int groundFogEnd; private final float groundFogOpacity; + private final DayLight timeOfDay; private static class Properties { @@ -935,6 +943,11 @@ public Properties enableLightning() } Environment(Area area, Properties properties) + { + this(area, properties, DayLight.DAY); + } + + Environment(Area area, Properties properties, DayLight timeOfDay) { this.area = area; this.fogDepth = properties.fogDepth; @@ -955,5 +968,7 @@ public Properties enableLightning() this.groundFogStart = properties.groundFogStart; this.groundFogEnd = properties.groundFogEnd; this.groundFogOpacity = properties.groundFogOpacity; + this.timeOfDay = timeOfDay; } + } diff --git a/src/main/java/rs117/hd/environments/EnvironmentManager.java b/src/main/java/rs117/hd/environments/EnvironmentManager.java index 7ef198556..7cac0962d 100644 --- a/src/main/java/rs117/hd/environments/EnvironmentManager.java +++ b/src/main/java/rs117/hd/environments/EnvironmentManager.java @@ -25,9 +25,13 @@ package rs117.hd.environments; import com.google.common.primitives.Floats; + +import java.time.LocalTime; import java.util.ArrayList; import javax.inject.Inject; import javax.inject.Singleton; + +import jdk.vm.ci.meta.Local; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.Constants; @@ -128,6 +132,8 @@ public class EnvironmentManager public boolean lightningEnabled = false; + public DayLight currentTimeOfDay = DayLight.getTimeOfDay(LocalTime.now()); + public void update() { WorldPoint camPosition = localPointToWorldTile(hdPlugin.camTarget[0], hdPlugin.camTarget[1]); @@ -135,9 +141,11 @@ public void update() int camTargetY = camPosition.getY(); int camTargetZ = camPosition.getPlane(); + currentTimeOfDay = hdPlugin.configDayOnly ? DayLight.DAY : DayLight.getTimeOfDay(LocalTime.now()); + for (Environment environment : sceneEnvironments) { - if (environment.getArea().containsPoint(camTargetX, camTargetY, camTargetZ)) + if (environment.getArea().containsPoint(camTargetX, camTargetY, camTargetZ) && environment.getTimeOfDay() == currentTimeOfDay) { if (environment != currentEnvironment) {