diff --git a/assets/mods/basegame/weathers/WeatherGeneric.json b/assets/mods/basegame/weathers/WeatherGeneric.json index 4ca2b1233..b260fc714 100644 --- a/assets/mods/basegame/weathers/WeatherGeneric.json +++ b/assets/mods/basegame/weathers/WeatherGeneric.json @@ -21,5 +21,6 @@ "altLow": 1080, "altHigh": 1800 } }, - "atmoTurbidity": 3.5 + "atmoTurbidity": 3.5, + "shaderVibrancy": [1.0, 1.0] } \ No newline at end of file diff --git a/assets/mods/basegame/weathers/WeatherGeneric2.json b/assets/mods/basegame/weathers/WeatherGeneric2.json index 3bf0f5e48..f24ab2526 100644 --- a/assets/mods/basegame/weathers/WeatherGeneric2.json +++ b/assets/mods/basegame/weathers/WeatherGeneric2.json @@ -27,5 +27,6 @@ } }, "atmoTurbidity": 3.5, + "shaderVibrancy": [1.0, 1.0], "__comment__": "Make a texture for altocumulus so that this weather can be realised with less than 1000 sprites" } \ No newline at end of file diff --git a/assets/mods/basegame/weathers/WeatherOvercast.json b/assets/mods/basegame/weathers/WeatherOvercast.json index 03a77944b..a0e079bc8 100644 --- a/assets/mods/basegame/weathers/WeatherOvercast.json +++ b/assets/mods/basegame/weathers/WeatherOvercast.json @@ -8,7 +8,7 @@ "cloudGammaVariance": [0.0, 0.0], "windSpeed": 10.45, "windSpeedVariance": 0.5, - "windSpeedDamping": 0.0, + "windSpeedDamping": 0.5, "clouds": { "cumulus": { "filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 0.1, @@ -26,5 +26,6 @@ "altLow": 1100, "altHigh": 1500 } }, - "atmoTurbidity": 9.5 + "atmoTurbidity": 9.5, + "shaderVibrancy": [0.93, 0.9] } \ No newline at end of file diff --git a/assets/mods/basegame/weathers/cloud_wide.kra b/assets/mods/basegame/weathers/cloud_wide.kra index e3c279bb7..d3d6102bd 100644 --- a/assets/mods/basegame/weathers/cloud_wide.kra +++ b/assets/mods/basegame/weathers/cloud_wide.kra @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:550dc244b939526569a2cc938009dda52b2cf8946ea7375c2ec45ff2f06889a1 -size 24791822 +oid sha256:937e2ac01fe4441a80864af3512d069ace20acb15ac26a72bb2acf325d0f3a28 +size 34099954 diff --git a/src/net/torvald/terrarum/TerrarumPostProcessor.kt b/src/net/torvald/terrarum/TerrarumPostProcessor.kt index a7e0760d0..f34cbe299 100644 --- a/src/net/torvald/terrarum/TerrarumPostProcessor.kt +++ b/src/net/torvald/terrarum/TerrarumPostProcessor.kt @@ -13,6 +13,7 @@ import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.ui.BasicDebugInfoWindow import net.torvald.terrarum.ui.Toolkit +import net.torvald.terrarum.weather.WeatherMixer /** * Must be called by the App Loader @@ -236,6 +237,13 @@ object TerrarumPostProcessor : Disposable { else shaderPostNoDither + val (vo, vg) = INGAME.world.weatherbox.let { + if (it.currentWeather.identifier == "titlescreen") + 1f to 1f + else + it.currentVibrancy.x to it.currentVibrancy.y + } + App.getCurrentDitherTex().bind(1) fbo.colorBufferTexture.bind(0) @@ -245,6 +253,7 @@ object TerrarumPostProcessor : Disposable { shader.setUniformi("rnd", rng.nextInt(8192), rng.nextInt(8192)) shader.setUniformi("u_pattern", 1) shader.setUniformf("quant", shaderQuant[App.getConfigInt("displaycolourdepth")] ?: 255f) + shader.setUniformf("vibrancy", 1f, vo, vg, 1f) shader.setUniformMatrix4fv("swizzler", swizzler, rng.nextInt(24), 16*4) App.fullscreenQuad.render(shader, GL20.GL_TRIANGLES) diff --git a/src/net/torvald/terrarum/gameworld/GameWorld.kt b/src/net/torvald/terrarum/gameworld/GameWorld.kt index d2537c269..eefbab08c 100644 --- a/src/net/torvald/terrarum/gameworld/GameWorld.kt +++ b/src/net/torvald/terrarum/gameworld/GameWorld.kt @@ -153,7 +153,7 @@ open class GameWorld( var weatherbox = Weatherbox() init { - weatherbox.initWith(WeatherMixer.weatherDict["generic01"]!!, 7200L) + weatherbox.initWith(WeatherMixer.weatherDict["generic01"]!!, 3600L) val currentWeather = weatherbox.currentWeather // TEST FILL WITH RANDOM VALUES (0..6).map { WeatherMixer.takeUniformRand(0f..1f) }.let { @@ -165,12 +165,13 @@ open class GameWorld( weatherbox.windDir.p3 = it[6] } (0..6).map { WeatherMixer.takeUniformRand(-1f..1f) }.let { - weatherbox.windSpeed.pM2 = currentWeather.getRandomWindSpeed(it[0], it[1]) - weatherbox.windSpeed.pM1 = currentWeather.getRandomWindSpeed(it[1], it[2]) - weatherbox.windSpeed.p0 = currentWeather.getRandomWindSpeed(it[2], it[3]) - weatherbox.windSpeed.p1 = currentWeather.getRandomWindSpeed(it[3], it[4]) - weatherbox.windSpeed.p2 = currentWeather.getRandomWindSpeed(it[4], it[5]) - weatherbox.windSpeed.p3 = currentWeather.getRandomWindSpeed(it[5], it[6]) + val pM3 = currentWeather.getRandomWindSpeed(it[1]) + weatherbox.windSpeed.pM2 = currentWeather.getRandomWindSpeed(pM3, it[1]) + weatherbox.windSpeed.pM1 = currentWeather.getRandomWindSpeed(weatherbox.windSpeed.pM2, it[2]) + weatherbox.windSpeed.p0 = currentWeather.getRandomWindSpeed(weatherbox.windSpeed.pM1, it[3]) + weatherbox.windSpeed.p1 = currentWeather.getRandomWindSpeed(weatherbox.windSpeed.p0, it[4]) + weatherbox.windSpeed.p2 = currentWeather.getRandomWindSpeed(weatherbox.windSpeed.p1, it[5]) + weatherbox.windSpeed.p3 = currentWeather.getRandomWindSpeed(weatherbox.windSpeed.p2, it[6]) } // the savegame loader will overwrite whatever the initial value we have here diff --git a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt index b5e60dc67..3051c22c0 100644 --- a/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt +++ b/src/net/torvald/terrarum/modulebasegame/TitleScreen.kt @@ -177,6 +177,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) { printdbg(this, "Demo world not found, using empty world") } + this.world = demoWorld // set initial time to summer demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32) @@ -213,7 +214,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) { IngameRenderer.setRenderedWorld(demoWorld) WeatherMixer.internalReset(this) - WeatherMixer.titleScreenInitWeather(this.world.weatherbox) + WeatherMixer.titleScreenInitWeather(demoWorld.weatherbox) // load a half-gradient texture that would be used throughout the titlescreen and its sub UIs diff --git a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt index ae3df48e9..87ea483c3 100644 --- a/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt +++ b/src/net/torvald/terrarum/ui/BasicDebugInfoWindow.kt @@ -359,8 +359,10 @@ class BasicDebugInfoWindow : UICanvas() { val schedYstart = App.scr.height - 140 - 120 - 13f * (weatherbox.weatherSchedule.size + 3) App.fontSmallNumbers.draw(batch, "$ccY== WeatherSched [${weatherbox.weatherSchedule.size}] ==", drawXf, schedYstart) weatherbox.weatherSchedule.forEachIndexed { index, weather -> - val sek = if (index == 0) weatherbox.updateAkku else 0 - App.fontSmallNumbers.draw(batch, "$ccY${weather.weather.identifier} $ccG${weather.duration - sek}", drawXf, schedYstart + 13 * (index + 1)) + val sek = if (index == 1) weatherbox.updateAkku else 0 + val cc1 = if (index == 0) ccK else ccY + val cc2 = if (index == 0) ccK else ccG + App.fontSmallNumbers.draw(batch, "$cc1${weather.weather.identifier} $cc2${weather.duration - sek}", drawXf, schedYstart + 13 * (index + 1)) } } diff --git a/src/net/torvald/terrarum/weather/BaseModularWeather.kt b/src/net/torvald/terrarum/weather/BaseModularWeather.kt index d126937b3..90d80d759 100644 --- a/src/net/torvald/terrarum/weather/BaseModularWeather.kt +++ b/src/net/torvald/terrarum/weather/BaseModularWeather.kt @@ -29,18 +29,26 @@ data class BaseModularWeather( val cloudGamma: Vector2, val cloudGammaVariance: Vector2, var clouds: List, // sorted by CloudProps.probability + val shaderVibrancy: FloatArray, val mixFrom: String? = null, val mixPercentage: Double? = null, ) { + /** * @param rnd random number between -1 and +1 */ fun getRandomWindSpeed(old: Float, rnd: Float): Float { val v = 1f + rnd.absoluteValue * windSpeedVariance val r = if (rnd < 0) windSpeed / v else windSpeed * v - return FastMath.interpolateLinear(windSpeedDamping, old, r) + return FastMath.interpolateLinear(1f - windSpeedDamping, old, r) + } + + fun getRandomWindSpeed(rnd: Float): Float { + val v = 1f + rnd.absoluteValue * windSpeedVariance + val r = if (rnd < 0) windSpeed / v else windSpeed * v + return r } fun getRandomCloudGamma(rnd1: Float, rnd2: Float): Vector2 { diff --git a/src/net/torvald/terrarum/weather/WeatherMixer.kt b/src/net/torvald/terrarum/weather/WeatherMixer.kt index bb0506a82..30836deff 100644 --- a/src/net/torvald/terrarum/weather/WeatherMixer.kt +++ b/src/net/torvald/terrarum/weather/WeatherMixer.kt @@ -64,7 +64,8 @@ internal object WeatherMixer : RNGConsumer { 0f, Vector2(1f, 1f), Vector2(0f, 0f), - listOf() + listOf(), + floatArrayOf(1f, 1f) ) override val RNG = HQRNG() @@ -169,7 +170,7 @@ internal object WeatherMixer : RNGConsumer { weatherDB[weather.classification]!!.add(weather) } - weatherDict["titlescreen"] = weatherDB[WEATHER_GENERIC]!![0].copy(windSpeed = 1f) + weatherDict["titlescreen"] = weatherDB[WEATHER_GENERIC]!![0].copy(identifier = "titlescreen", windSpeed = 1f) } /** @@ -459,7 +460,8 @@ internal object WeatherMixer : RNGConsumer { } private fun initClouds(currentWeather: BaseModularWeather) { - val hCloudSize = 1024f + clouds.clear() + cloudsSpawned = 0 // multiplier is an empirical value that depends on the 'rZ' // it does converge at ~6, but having it as an initial state does not make it stay converged repeat((currentWeather.cloudChance * 1.333f).ceilToInt()) { @@ -731,13 +733,6 @@ internal object WeatherMixer : RNGConsumer { val skyboxInJson = JSON.getString("skyboxGradColourMap") val lightbox = JSON.getString("daylightClut") - val skybox = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}")) - val daylight = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}")) - - val identifier = JSON.getString("identifier") - val classification = JSON.getString("classification") - - val cloudsMap = ArrayList() val clouds = JSON["clouds"] clouds.forEachSiblings { name, json -> @@ -755,13 +750,12 @@ internal object WeatherMixer : RNGConsumer { - return BaseModularWeather( - identifier = identifier, + identifier = JSON.getString("identifier"), json = JSON, - skyboxGradColourMap = skybox, - daylightClut = daylight, - classification = classification, + skyboxGradColourMap = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${skyboxInJson}")), + daylightClut = GdxColorMap(ModMgr.getGdxFile(modname, "$pathToImage/${lightbox}")), + classification = JSON.getString("classification"), cloudChance = JSON.getFloat("cloudChance"), windSpeed = JSON.getFloat("windSpeed"), windSpeedVariance = JSON.getFloat("windSpeedVariance"), @@ -769,6 +763,7 @@ internal object WeatherMixer : RNGConsumer { cloudGamma = JSON["cloudGamma"].asFloatArray().let { Vector2(it[0], it[1]) }, cloudGammaVariance = JSON["cloudGammaVariance"].asFloatArray().let { Vector2(it[0], it[1]) }, clouds = cloudsMap, + shaderVibrancy = JSON["shaderVibrancy"].asFloatArray() ) } diff --git a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt index 2f02799fa..73f249ea8 100644 --- a/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt +++ b/src/net/torvald/terrarum/weather/WeatherObjectCloud.kt @@ -5,12 +5,11 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.math.Vector3 import com.jme3.math.FastMath +import com.jme3.math.FastMath.PI +import com.jme3.math.FastMath.sin import net.torvald.terrarum.App import net.torvald.terrarum.gameworld.GameWorld -import kotlin.math.absoluteValue -import kotlin.math.pow -import kotlin.math.roundToInt -import kotlin.math.sign +import kotlin.math.* /** * Created by minjaesong on 2023-08-21. @@ -47,7 +46,7 @@ class WeatherObjectCloud( scl(world.worldTime.timeDelta.toFloat()) ) - eigenAlpha = if (posZ < 1f) posZ.pow(0.5f) else -((posZ - 1f) / ALPHA_ROLLOFF_Z) + 1f + eigenAlpha = if (posZ < 1f) posZ.pow(0.5f) else cosh((posZ - CLOUD_STAGE_DEPTH) / (0.75636f * CLOUD_STAGE_DEPTH)) - 1f //-((posZ - 1f) / CLOUD_STAGE_DEPTH) + 1f val alphaMult = if (life < NEWBORN_GROWTH_TIME) life / NEWBORN_GROWTH_TIME @@ -60,13 +59,13 @@ class WeatherObjectCloud( val lrCoord = screenCoordBottomLRforDespawnCalculation - if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..ALPHA_ROLLOFF_Z + 1f || alpha < 0f) { + if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.0001f..CLOUD_STAGE_DEPTH + 1f || alpha < 0f) { flagToDespawn = true despawnCode = if (lrCoord.x > WeatherMixer.oobMarginR) "OUT_OF_SCREEN_RIGHT" else if (lrCoord.z < WeatherMixer.oobMarginL) "OUT_OF_SCREEN_LEFT" else if (posZ < 0.0001f) "OUT_OF_SCREEN_TOO_CLOSE" - else if (posZ > ALPHA_ROLLOFF_Z + 1f) "OUT_OF_SCREEN_TOO_FAR" + else if (posZ > CLOUD_STAGE_DEPTH + 1f) "OUT_OF_SCREEN_TOO_FAR" else if (life >= lifespan + OLD_AGE_DECAY) "OLD_AGE" else if (alpha < 0f) "ALPHA_BELOW_ZERO" else "UNKNOWN" @@ -180,6 +179,7 @@ class WeatherObjectCloud( fun worldYtoWorldZforScreenYof0(y: Float) = 1f - (y / H) // rearrange screenCoord equations to derive this eq :p const val ALPHA_ROLLOFF_Z = 64f + const val CLOUD_STAGE_DEPTH = 256f const val OLD_AGE_DECAY = 5000f const val NEWBORN_GROWTH_TIME = 1000f diff --git a/src/net/torvald/terrarum/weather/Weatherbox.kt b/src/net/torvald/terrarum/weather/Weatherbox.kt index cf387d200..8b157e969 100644 --- a/src/net/torvald/terrarum/weather/Weatherbox.kt +++ b/src/net/torvald/terrarum/weather/Weatherbox.kt @@ -1,12 +1,11 @@ package net.torvald.terrarum.weather +import com.badlogic.gdx.math.Vector2 import com.jme3.math.FastMath +import net.torvald.terrarum.App.printdbg import net.torvald.terrarum.floorToInt import net.torvald.terrarum.gameworld.GameWorld import net.torvald.terrarum.gameworld.fmod -import org.apache.commons.math3.analysis.UnivariateFunction -import org.apache.commons.math3.analysis.interpolation.NevilleInterpolator -import org.apache.commons.math3.analysis.interpolation.SplineInterpolator import java.util.* data class WeatherSchedule(val weather: BaseModularWeather = WeatherMixer.DEFAULT_WEATHER, val duration: Long = 3600) @@ -37,25 +36,37 @@ class Weatherbox { val windDir = WeatherDirBox() // 0 .. 1.0 val windSpeed = WeatherStateBox() // 0 .. arbitrarily large number - val weatherSchedule: MutableList = mutableListOf() - val currentWeather: BaseModularWeather + val weatherSchedule = ArrayList() + val oldWeather: BaseModularWeather get() = weatherSchedule[0].weather - val currentWeatherDuration: Long + val currentWeather: BaseModularWeather + get() = weatherSchedule[1].weather +// val nextWeather: BaseModularWeather +// get() = weatherSchedule[2].weather + val oldWeatherDuration: Long get() = weatherSchedule[0].duration + val currentWeatherDuration: Long + get() = weatherSchedule[1].duration + + @Transient val currentVibrancy = Vector2(1f, 1f) + val weatherBlend: Float + get() = updateAkku.toFloat() / currentWeatherDuration fun initWith(initWeather: BaseModularWeather, duration: Long) { weatherSchedule.clear() weatherSchedule.add(WeatherSchedule(initWeather, duration)) + weatherSchedule.add(WeatherSchedule(initWeather, duration)) } var updateAkku = 0L; private set fun update(world: GameWorld) { + updateShaderParams() updateWind(world) if (updateAkku >= currentWeatherDuration) { // TODO add more random weathers - if (weatherSchedule.size == 1) { + while (weatherSchedule.size < 3) { val newName = if (currentWeather.identifier == "generic01") "overcast01" else "generic01" val newDuration = 7200L weatherSchedule.add(WeatherSchedule(WeatherMixer.weatherDict[newName]!!, newDuration)) @@ -64,7 +75,10 @@ class Weatherbox { } // subtract akku by old currentWeatherDuration - updateAkku -= weatherSchedule.removeAt(0).duration +// printdbg(this, "Dequeueing a weather") + + weatherSchedule.removeAt(0) + updateAkku -= oldWeatherDuration } updateAkku += world.worldTime.timeDelta @@ -76,6 +90,15 @@ class Weatherbox { } windDir.update( world.worldTime.timeDelta / WIND_DIR_TIME_UNIT) { RNG.nextFloat() * 4f } } + + private fun updateShaderParams() { + val (co, cg) = oldWeather.shaderVibrancy + val (no, ng) = currentWeather.shaderVibrancy + currentVibrancy.set( + FastMath.interpolateLinear(weatherBlend * 2, co, no), + FastMath.interpolateLinear(weatherBlend * 2, cg, ng), + ) + } } diff --git a/src/shaders/postproc_dither.frag b/src/shaders/postproc_dither.frag index 436b123d1..f9b73b208 100644 --- a/src/shaders/postproc_dither.frag +++ b/src/shaders/postproc_dither.frag @@ -31,6 +31,9 @@ const mat4 swizzler = mat4( ); uniform float quant = 255.0; // 64 steps -> 63.0; 256 steps -> 255.0 +vec4 quantVec = vec4(quant); +vec4 invQuant = vec4(1.0 / quant); + out vec4 fragColor; const vec2 boolean = vec2(0.0, 1.0); @@ -54,12 +57,12 @@ const mat4 ycocg_to_rgb = mat4( vec4 nearestColour(vec4 inColor) { - return floor(vec4(quant) * inColor) * vec4(1.0 / quant); + return floor(quantVec * inColor) * invQuant; } vec4 getDitherredDot(vec4 inColor) { vec4 bayerThreshold = swizzler * vec4(matrixNormaliser + texture(u_pattern, (gl_FragCoord.xy + rnd) * patternsize)); - return nearestColour(bayerThreshold * vec4(1.0 / quant) + inColor); + return nearestColour(fma(bayerThreshold, invQuant, inColor)); }