mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-12 19:44:05 +09:00
more depth to the distant clouds
This commit is contained in:
@@ -2,18 +2,20 @@
|
|||||||
"skyboxGradColourMap": "generic_skybox.tga",
|
"skyboxGradColourMap": "generic_skybox.tga",
|
||||||
"daylightClut": "clut_daylight.tga",
|
"daylightClut": "clut_daylight.tga",
|
||||||
"classification": "generic",
|
"classification": "generic",
|
||||||
"cloudChance": 20,
|
"cloudChance": 33,
|
||||||
"cloudGamma": [0.48, 1.8],
|
"cloudGamma": [0.48, 1.8],
|
||||||
"cloudGammaVariance": [0.1, 0.1],
|
"cloudGammaVariance": [0.1, 0.1],
|
||||||
"cloudDriftSpeed": 0.08,
|
"cloudDriftSpeed": 0.08,
|
||||||
"clouds": {
|
"clouds": {
|
||||||
"large": {
|
"cumulonimbus": {
|
||||||
"filename": "cloud_large.png",
|
"filename": "cloud_large.png", "tw": 2048, "th": 1024, "probability": 0.25,
|
||||||
"tw": 2048, "th": 1024, "probability": 0.2, "baseScale": 0.666, "scaleVariance": 0.7
|
"baseScale": 1.0, "scaleVariance": 0.8,
|
||||||
|
"altLow": 80, "altHigh": 600
|
||||||
},
|
},
|
||||||
"normal": {
|
"cumulus": {
|
||||||
"filename": "cloud_normal.png",
|
"filename": "cloud_normal.png", "tw": 1024, "th": 512, "probability": 1.0,
|
||||||
"tw": 1024, "th": 512, "probability": 1.0, "baseScale": 0.75, "scaleVariance": 0.8
|
"baseScale": 1.0, "scaleVariance": 0.6,
|
||||||
|
"altLow": 80, "altHigh": 800
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
val soldeg = WeatherMixer.forceSolarElev ?: world?.worldTime?.solarElevationDeg
|
val soldeg = WeatherMixer.forceSolarElev ?: world?.worldTime?.solarElevationDeg
|
||||||
val soldegStr = (soldeg ?: 0.0).toIntAndFrac(3,2)
|
val soldegStr = (soldeg ?: 0.0).toIntAndFrac(3,2)
|
||||||
val soldegNeg = ((soldeg ?: 0.0) >= 0.0).toInt()
|
val soldegNeg = ((soldeg ?: 0.0) >= 0.0).toInt()
|
||||||
val turbidity = WeatherMixer.forceTurbidity ?: WeatherMixer.turbidity
|
val turbidity = (WeatherMixer.forceTurbidity ?: WeatherMixer.turbidity).toIntAndFrac(1, 4)
|
||||||
|
|
||||||
val soldegCol = if (WeatherMixer.forceSolarElev != null) ccO else ccG
|
val soldegCol = if (WeatherMixer.forceSolarElev != null) ccO else ccG
|
||||||
val turbCol = if (WeatherMixer.forceTurbidity != null) ccO else ccG
|
val turbCol = if (WeatherMixer.forceTurbidity != null) ccO else ccG
|
||||||
@@ -300,6 +300,9 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
if (ingame is TerrarumIngame) {
|
if (ingame is TerrarumIngame) {
|
||||||
App.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as TerrarumIngame).particlesActive}",
|
App.fontSmallNumbers.draw(batch, "${ccM}Particles $ccG${(ingame as TerrarumIngame).particlesActive}",
|
||||||
(TinyAlphNum.W * 2 + 41 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
(TinyAlphNum.W * 2 + 41 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
||||||
|
App.fontSmallNumbers.draw(batch, "${ccM}Clouds $ccG${WeatherMixer.cloudsSpawned}",
|
||||||
|
(TinyAlphNum.W * 2 + 53 * 8).toFloat(), App.scr.height - TinyAlphNum.H * 2f)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,8 @@ data class CloudProps(
|
|||||||
val spriteSheet: TextureRegionPack,
|
val spriteSheet: TextureRegionPack,
|
||||||
val probability: Float,
|
val probability: Float,
|
||||||
val baseScale: Float,
|
val baseScale: Float,
|
||||||
val scaleVariance: Float
|
val scaleVariance: Float,
|
||||||
)
|
val altLow: Float,
|
||||||
|
val altHigh: Float,
|
||||||
|
) {
|
||||||
|
}
|
||||||
@@ -24,8 +24,10 @@ import net.torvald.terrarum.gameactors.Hitbox
|
|||||||
import net.torvald.terrarum.spriteassembler.ADPropertyObject
|
import net.torvald.terrarum.spriteassembler.ADPropertyObject
|
||||||
import net.torvald.terrarum.utils.JsonFetcher
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
import net.torvald.terrarum.utils.forEachSiblings
|
import net.torvald.terrarum.utils.forEachSiblings
|
||||||
|
import net.torvald.terrarum.weather.WeatherObjectCloud.Companion.ALPHA_ROLLOFF_Z
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import net.torvald.util.SortedArrayList
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileFilter
|
import java.io.FileFilter
|
||||||
import java.lang.Double.doubleToLongBits
|
import java.lang.Double.doubleToLongBits
|
||||||
@@ -89,10 +91,11 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
private var astrumOffX = 0f
|
private var astrumOffX = 0f
|
||||||
private var astrumOffY = 0f
|
private var astrumOffY = 0f
|
||||||
|
|
||||||
private val clouds = Array<WeatherObjectCloud?>(4096) { null }
|
private val clouds = SortedArrayList<WeatherObjectCloud>()
|
||||||
private var cloudsSpawned = 0
|
var cloudsSpawned = 0; private set
|
||||||
private var cloudDriftVector = Vector3(-1f, 0f, 1f) // this is a direction vector
|
private var cloudDriftVector = Vector3(-1f, 0f, 0.1f) // this is a direction vector
|
||||||
|
private val cloudSpawnMax: Int
|
||||||
|
get() = App.getConfigInt("maxparticles") * 2
|
||||||
|
|
||||||
override fun loadFromSave(s0: Long, s1: Long) {
|
override fun loadFromSave(s0: Long, s1: Long) {
|
||||||
super.loadFromSave(s0, s1)
|
super.loadFromSave(s0, s1)
|
||||||
@@ -111,9 +114,9 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
astrumOffX = s0.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionWidth
|
astrumOffX = s0.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionWidth
|
||||||
astrumOffY = s1.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionHeight
|
astrumOffY = s1.and(0xFFFFL).toFloat() / 65535f * starmapTex.regionHeight
|
||||||
|
|
||||||
Arrays.fill(clouds, null)
|
clouds.clear()
|
||||||
cloudsSpawned = 0
|
cloudsSpawned = 0
|
||||||
cloudDriftVector = Vector3(1f, 0f, 0f).rotate(Vector3(0f,1f,0f), 192f)
|
cloudDriftVector = Vector3(-0.98f, -0.02f, 0.21f)
|
||||||
|
|
||||||
oldCamPos.set(WorldCamera.camVector)
|
oldCamPos.set(WorldCamera.camVector)
|
||||||
}
|
}
|
||||||
@@ -193,6 +196,10 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
private val oldCamPos = Vector2(0f, 0f)
|
private val oldCamPos = Vector2(0f, 0f)
|
||||||
private val camDelta = Vector2(0f, 0f)
|
private val camDelta = Vector2(0f, 0f)
|
||||||
|
|
||||||
|
val oobMarginR = 1.5f * App.scr.wf
|
||||||
|
val oobMarginL = -0.5f * App.scr.wf
|
||||||
|
private val oobMarginY = -0.5f * App.scr.hf
|
||||||
|
|
||||||
private fun updateClouds(delta: Float, world: GameWorld) {
|
private fun updateClouds(delta: Float, world: GameWorld) {
|
||||||
val camvec = WorldCamera.camVector
|
val camvec = WorldCamera.camVector
|
||||||
val camvec2 = camvec.cpy()
|
val camvec2 = camvec.cpy()
|
||||||
@@ -218,29 +225,30 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clouds.forEach {
|
clouds.forEach {
|
||||||
it?.let {
|
// do parallax scrolling
|
||||||
// do parallax scrolling
|
it.posX += camDelta.x * cloudParallaxMultX
|
||||||
it.posX += camDelta.x * cloudParallaxMultX
|
it.posY += camDelta.y * cloudParallaxMultY
|
||||||
it.posY += camDelta.y * cloudParallaxMultY
|
|
||||||
|
|
||||||
it.update(cloudDriftVector, currentWeather.cloudDriftSpeed)
|
|
||||||
|
|
||||||
val pjx = it.posX / it.posZ
|
it.update(cloudDriftVector, currentWeather.cloudDriftSpeed)
|
||||||
|
|
||||||
if (pjx !in -1500f..App.scr.wf + 1500f || it.scale < 1f / 2048f || it.posZ !in 0.001f..100f) {
|
|
||||||
it.flagToDespawn = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clouds.indices.forEach { i ->
|
|
||||||
if (clouds[i]?.flagToDespawn == true) {
|
// remove clouds that are marked to be despawn
|
||||||
clouds[i]?.dispose()
|
var i = 0
|
||||||
clouds[i] = null
|
while (true) {
|
||||||
|
if (i >= clouds.size) break
|
||||||
|
|
||||||
|
if (clouds[i].flagToDespawn) {
|
||||||
|
clouds.removeAt(i)
|
||||||
|
i -= 1
|
||||||
cloudsSpawned -= 1
|
cloudsSpawned -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
cloudUpdateAkku += delta
|
cloudUpdateAkku += delta
|
||||||
|
|
||||||
|
|
||||||
@@ -256,17 +264,25 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
private fun randomPosWithin(range: ClosedFloatingPointRange<Float>, random: Float) =
|
private fun randomPosWithin(range: ClosedFloatingPointRange<Float>, random: Float) =
|
||||||
((range.start + range.endInclusive) / 2f) + random * (range.endInclusive - range.start) / 2f
|
((range.start + range.endInclusive) / 2f) + random * (range.endInclusive - range.start) / 2f
|
||||||
|
|
||||||
private fun tryToSpawnCloud(currentWeather: BaseModularWeather, initX: Float? = null) {
|
private fun takeUniformRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
printdbg(this, "Trying to spawn a cloud... (${cloudsSpawned} / ${clouds.size})")
|
FastMath.interpolateLinear(Math.random().toFloat(), range.start, range.endInclusive)
|
||||||
|
private fun takeTriangularRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
|
FastMath.interpolateLinear((Math.random() + Math.random()).div(2f).toFloat(), range.start, range.endInclusive)
|
||||||
|
private fun takeGaussianRand(range: ClosedFloatingPointRange<Float>) =
|
||||||
|
FastMath.interpolateLinear((Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random() + Math.random()).div(8f).toFloat(), range.start, range.endInclusive)
|
||||||
|
|
||||||
if (cloudsSpawned < clouds.size) {
|
|
||||||
|
private fun tryToSpawnCloud(currentWeather: BaseModularWeather, initX: Float? = null) {
|
||||||
|
// printdbg(this, "Trying to spawn a cloud... (${cloudsSpawned} / ${cloudSpawnMax})")
|
||||||
|
|
||||||
|
if (cloudsSpawned < cloudSpawnMax) {
|
||||||
val flip = Math.random() < 0.5
|
val flip = Math.random() < 0.5
|
||||||
val rC = Math.random().toFloat()
|
val rC = takeUniformRand(0f..1f)
|
||||||
val rZ = (Math.random() * 9 + 1.0).toFloat() // 1..10 uniformly
|
val rZ = takeUniformRand(1f..ALPHA_ROLLOFF_Z)
|
||||||
val rY = ((Math.random() + Math.random()) - 1.0).toFloat() // -1..1
|
val rY = takeUniformRand(-1f..1f)
|
||||||
val r1 = (Math.random() * 2.0 - 1.0).toFloat() // -1..1
|
val r1 = takeUniformRand(-1f..1f)
|
||||||
val r2 = (Math.random() * 2.0 - 1.0).toFloat() // -1..1
|
val r2 = takeUniformRand(-1f..1f)
|
||||||
val rT1 = ((Math.random() + Math.random()) - 1.0).toFloat() // -1..1
|
val rT1 = takeTriangularRand(-1f..1f)
|
||||||
val (rA, rB) = doubleToLongBits(Math.random()).let {
|
val (rA, rB) = doubleToLongBits(Math.random()).let {
|
||||||
it.ushr(20).and(0xFFFF).toInt() to it.ushr(36).and(0xFFFF).toInt()
|
it.ushr(20).and(0xFFFF).toInt() to it.ushr(36).and(0xFFFF).toInt()
|
||||||
}
|
}
|
||||||
@@ -285,11 +301,9 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
val scaleVariance = 1f + rT1.absoluteValue * cloud.scaleVariance
|
val scaleVariance = 1f + rT1.absoluteValue * cloud.scaleVariance
|
||||||
val cloudScale = cloud.baseScale * (if (rT1 < 0) 1f / scaleVariance else scaleVariance)
|
val cloudScale = cloud.baseScale * (if (rT1 < 0) 1f / scaleVariance else scaleVariance)
|
||||||
val hCloudSize = (cloud.spriteSheet.tileW * cloudScale) / 2f + 1f
|
val hCloudSize = (cloud.spriteSheet.tileW * cloudScale) / 2f + 1f
|
||||||
val posX = if (initX != null) initX * rZ else if (cloudDriftVector.x < 0) (App.scr.width + hCloudSize) * rZ else -hCloudSize * rZ
|
val posXscr = initX ?: if (cloudDriftVector.x < 0) (App.scr.width + hCloudSize) else -hCloudSize
|
||||||
val posY = when (cloud.category) {
|
val posX = WeatherObjectCloud.screenXtoWorldX(posXscr, rZ)
|
||||||
"large" -> randomPosWithin(-120f..120f, rY) * scrHscaler * (rZ * 0.5f)
|
val posY = randomPosWithin(-cloud.altHigh..-cloud.altLow, rY) * scrHscaler
|
||||||
else -> randomPosWithin(-150f..150f, rY) * scrHscaler * (rZ * 0.5f)
|
|
||||||
}
|
|
||||||
val sheetX = rA % cloud.spriteSheet.horizontalCount
|
val sheetX = rA % cloud.spriteSheet.horizontalCount
|
||||||
val sheetY = rB % cloud.spriteSheet.verticalCount
|
val sheetY = rB % cloud.spriteSheet.verticalCount
|
||||||
WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also {
|
WeatherObjectCloud(cloud.spriteSheet.get(sheetX, sheetY), flip).also {
|
||||||
@@ -308,11 +322,11 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
it.posY = posY
|
it.posY = posY
|
||||||
it.posZ = rZ
|
it.posZ = rZ
|
||||||
|
|
||||||
clouds.addAtFreeSpot(it)
|
clouds.add(it)
|
||||||
cloudsSpawned += 1
|
cloudsSpawned += 1
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "... Spawning ${cloud.category}($sheetX, $sheetY) cloud at pos ${it.pos}, scale ${it.scale}, invGamma ${it.darkness}")
|
// printdbg(this, "... Spawning ${cloud.category}($sheetX, $sheetY) cloud at pos ${it.pos}, scale ${it.scale}, invGamma ${it.darkness}")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -320,8 +334,9 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun initClouds() {
|
private fun initClouds() {
|
||||||
repeat((currentWeather.cloudChance * 6.8f).ceilToInt()) { // multiplier is an empirical value that depends on the 'rZ'
|
val hCloudSize = 1024f
|
||||||
tryToSpawnCloud(currentWeather, ((Math.random() * 2.0 - 1.0) * App.scr.wf).toFloat())
|
repeat((currentWeather.cloudChance * 3.3f).ceilToInt()) { // multiplier is an empirical value that depends on the 'rZ'
|
||||||
|
tryToSpawnCloud(currentWeather, takeUniformRand(-hCloudSize..App.scr.width + hCloudSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -353,14 +368,14 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun drawClouds(batch: SpriteBatch) {
|
private fun drawClouds(batch: SpriteBatch) {
|
||||||
batch.color = globalLightNow.toGdxColor().also {
|
|
||||||
it.a = 1f
|
|
||||||
} // TODO add cloud-only colour strip on the CLUT
|
|
||||||
batch.shader = shaderClouds
|
batch.shader = shaderClouds
|
||||||
clouds.filterNotNull().sortedByDescending { it.posZ }.forEach {
|
clouds.forEach {
|
||||||
batch.inUse { _ ->
|
batch.inUse { _ ->
|
||||||
|
batch.color = globalLightNow.toGdxColor().also { col ->
|
||||||
|
col.a = it.alpha
|
||||||
|
} // TODO add cloud-only colour strip on the CLUT
|
||||||
batch.shader.setUniformf("gamma", it.darkness)
|
batch.shader.setUniformf("gamma", it.darkness)
|
||||||
it.render(batch, 0f, 0f) // TODO parallax
|
it.render(batch, 0f, 0f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -579,7 +594,9 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
TextureRegionPack(ModMgr.getGdxFile(modname, "$pathToImage/${json.getString("filename")}"), json.getInt("tw"), json.getInt("th")),
|
TextureRegionPack(ModMgr.getGdxFile(modname, "$pathToImage/${json.getString("filename")}"), json.getInt("tw"), json.getInt("th")),
|
||||||
json.getFloat("probability"),
|
json.getFloat("probability"),
|
||||||
json.getFloat("baseScale"),
|
json.getFloat("baseScale"),
|
||||||
json.getFloat("scaleVariance")
|
json.getFloat("scaleVariance"),
|
||||||
|
json.getFloat("altLow"),
|
||||||
|
json.getFloat("altHigh"),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
cloudsMap.sortBy { it.probability }
|
cloudsMap.sortBy { it.probability }
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ abstract class WeatherObject : Disposable {
|
|||||||
set(value) { pos.z = value }
|
set(value) { pos.z = value }
|
||||||
var scale: Float = 1f
|
var scale: Float = 1f
|
||||||
|
|
||||||
|
var alpha: Float = 1f
|
||||||
|
|
||||||
var flagToDespawn = false
|
var flagToDespawn = false
|
||||||
|
|
||||||
abstract fun update()
|
abstract fun update()
|
||||||
|
|||||||
@@ -5,12 +5,13 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.badlogic.gdx.math.Vector3
|
import com.badlogic.gdx.math.Vector3
|
||||||
import net.torvald.terrarum.App
|
import net.torvald.terrarum.App
|
||||||
|
import kotlin.math.pow
|
||||||
import kotlin.math.sign
|
import kotlin.math.sign
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-08-21.
|
* Created by minjaesong on 2023-08-21.
|
||||||
*/
|
*/
|
||||||
class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: Boolean) : WeatherObject() {
|
class WeatherObjectCloud(private val texture: TextureRegion, private val flipW: Boolean) : WeatherObject(), Comparable<WeatherObjectCloud> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To actually utilise this value, your render code must begin the spritebatch per-object, like so:
|
* To actually utilise this value, your render code must begin the spritebatch per-object, like so:
|
||||||
@@ -26,6 +27,7 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW:
|
|||||||
var darkness: Vector2 = Vector2(0.5f, 2.0f) // the "gamma" value fed into the clouds shader
|
var darkness: Vector2 = Vector2(0.5f, 2.0f) // the "gamma" value fed into the clouds shader
|
||||||
|
|
||||||
override fun update() {
|
override fun update() {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,30 +35,71 @@ class WeatherObjectCloud(private val texture: TextureRegion, private val flipW:
|
|||||||
* Resulting vector: (x + dX, y + dY, scale * dScale)
|
* Resulting vector: (x + dX, y + dY, scale * dScale)
|
||||||
*/
|
*/
|
||||||
fun update(flowVector: Vector3, gait: Float) {
|
fun update(flowVector: Vector3, gait: Float) {
|
||||||
val vecMult = Vector3(1f, 1f, 1f / (2f * App.scr.hf * 0.35f))
|
|
||||||
pos.add(flowVector.cpy().scl(vecMult).scl(gait))
|
pos.add(flowVector.cpy().scl(vecMult).scl(gait))
|
||||||
|
|
||||||
|
alpha = -(posZ / ALPHA_ROLLOFF_Z).pow(1.703f) + 1f
|
||||||
|
|
||||||
|
val lrCoord = screenCoordBottomLR
|
||||||
|
if (lrCoord.x > WeatherMixer.oobMarginR || lrCoord.z < WeatherMixer.oobMarginL || posZ !in 0.05f..ALPHA_ROLLOFF_Z || alpha < 1f / 255f) {
|
||||||
|
flagToDespawn = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val w = App.scr.halfwf
|
||||||
|
private val h = App.scr.hf * 0.5f
|
||||||
|
private val vecMult = Vector3(1f, 1f, 1f / (2f * h))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* X/Y position is a bottom-centre point of the image
|
* X/Y position is a bottom-centre point of the image
|
||||||
* Shader must be prepared prior to the render() call
|
* Shader must be prepared prior to the render() call
|
||||||
*/
|
*/
|
||||||
override fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float) {
|
override fun render(batch: SpriteBatch, offsetX: Float, offsetY: Float) {
|
||||||
val x = posX + offsetX - texture.regionWidth * scale * 0.5f
|
val sc = screenCoord
|
||||||
val y = posY + offsetY - texture.regionHeight * scale
|
|
||||||
val z = posZ // must be at least 1.0
|
|
||||||
val w = App.scr.halfwf
|
|
||||||
val h = App.scr.hf * 0.35f
|
|
||||||
|
|
||||||
val drawX = (x + w * (z-1)) / z
|
|
||||||
val drawY = (y + h * (z-1)) / z
|
|
||||||
val drawScale = scale / z
|
|
||||||
|
|
||||||
if (flipW)
|
if (flipW)
|
||||||
batch.draw(texture, drawX + texture.regionWidth / z, drawY, -texture.regionWidth * drawScale, texture.regionHeight * drawScale)
|
batch.draw(texture, sc.x + texture.regionWidth / posZ, sc.y, -texture.regionWidth * sc.z, texture.regionHeight * sc.z)
|
||||||
else
|
else
|
||||||
batch.draw(texture, drawX, drawY, texture.regionWidth * drawScale, texture.regionHeight * drawScale)
|
batch.draw(texture, sc.x, sc.y, texture.regionWidth * sc.z, texture.regionHeight * sc.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vec3(screen X, screenY, draw scale)
|
||||||
|
*/
|
||||||
|
val screenCoord: Vector3
|
||||||
|
get() {
|
||||||
|
val x = posX - texture.regionWidth * scale * 0.5f
|
||||||
|
val y = posY - texture.regionHeight * scale
|
||||||
|
val z = posZ // must be at least 1.0
|
||||||
|
|
||||||
|
val drawX = (x + w * (z-1)) / z
|
||||||
|
val drawY = (y + h * (z-1)) / z
|
||||||
|
val drawScale = scale / z
|
||||||
|
|
||||||
|
return Vector3(drawX, drawY, drawScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* vec3(screen-X of bottom-left point, screen-Y, screen-X of bottom-right point)
|
||||||
|
*/
|
||||||
|
val screenCoordBottomLR: Vector3
|
||||||
|
get() {
|
||||||
|
val xL = posX - texture.regionWidth * scale * 0.5f
|
||||||
|
val xR = posX + texture.regionWidth * scale * 0.5f
|
||||||
|
val y = posY - texture.regionHeight * scale
|
||||||
|
val z = posZ // must be at least 1.0
|
||||||
|
|
||||||
|
val drawXL = (xL + w * (z-1)) / z
|
||||||
|
val drawXR = (xR + w * (z-1)) / z
|
||||||
|
val drawY = (y + h * (z-1)) / z
|
||||||
|
|
||||||
|
return Vector3(drawXL, drawY, drawXR)
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispose() { /* cloud texture will be disposed of by the WeatherMixer */ }
|
override fun dispose() { /* cloud texture will be disposed of by the WeatherMixer */ }
|
||||||
|
override fun compareTo(other: WeatherObjectCloud): Int = (other.posZ - this.posZ).sign.toInt()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun screenXtoWorldX(screenX: Float, z: Float) = screenX * z - App.scr.halfwf * (z - 1f)
|
||||||
|
const val ALPHA_ROLLOFF_Z = 16f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user