Files
Terrarum/src/net/torvald/terrarum/weather/WeatherMixer.kt
Song Minjae d8b70887a9 new item type, "Dynamic Item"; working text terminal
Former-commit-id: 81e6d836f5f1e6490027d38146a32d404cf9ce3e
Former-commit-id: af6557340f9cd0ea0b67eb7a8825aeffe75f9d82
2016-09-10 16:45:04 +09:00

206 lines
7.6 KiB
Kotlin

package net.torvald.terrarum.weather
import com.jme3.math.FastMath
import net.torvald.JsonFetcher
import net.torvald.colourutil.CIELChUtil
import net.torvald.colourutil.ColourUtil
import net.torvald.random.HQRNG
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameworld.WorldTime
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
import org.newdawn.slick.fills.GradientFill
import org.newdawn.slick.geom.Rectangle
import java.io.File
import java.util.*
/**
* Current, next are there for cross-fading two weathers
*
* Created by minjaesong on 16-07-11.
*/
object WeatherMixer {
lateinit var weatherList: HashMap<String, ArrayList<BaseModularWeather>>
lateinit var currentWeather: BaseModularWeather
lateinit var nextWeather: BaseModularWeather
lateinit var mixedWeather: BaseModularWeather
private var skyBoxCurrent = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
private var skyBoxNext = Rectangle(0f, 0f, Terrarum.WIDTH.toFloat(), Terrarum.HEIGHT.toFloat())
val globalLightNow = Color(0)
// Weather indices
const val WEATHER_GENERIC = "generic"
const val WEATHER_GENERIC_RAIN = "genericrain"
// TODO add weather classification indices manually
const val RAW_DIR = "./assets/raw/weathers"
init {
weatherList = HashMap<String, ArrayList<BaseModularWeather>>()
// read weather descriptions from assets/weather (modular weather)
val weatherRawValidList = ArrayList<File>()
val weatherRaws = File(RAW_DIR).listFiles()
weatherRaws.forEach {
if (!it.isDirectory && it.name.endsWith(".json"))
weatherRawValidList.add(it)
}
// --> read from directory and store file that looks like RAW
for (raw in weatherRawValidList) {
val weather = readFromJson(raw)
// if List for the classification does not exist, make one
if (!weatherList.containsKey(weather.classification))
weatherList.put(weather.classification, ArrayList())
weatherList[weather.classification]!!.add(weather)
}
// initialise
currentWeather = weatherList[WEATHER_GENERIC]!![0]
nextWeather = getRandomWeather(WEATHER_GENERIC)
}
fun update(gc: GameContainer, delta: Int) {
currentWeather = weatherList[WEATHER_GENERIC]!![0]
}
fun render(g: Graphics) {
// we will not care for nextSkybox for now
val timeNow = Terrarum.ingame.world.time.elapsedSeconds()
val skyboxColourMap = currentWeather.skyboxGradColourMap
val lightColourMap = currentWeather.globalLightColourMap
// draw skybox to provided (should be main) graphics instance
val skyColourFill = GradientFill(
0f, 0f,
getGradientColour(skyboxColourMap, 0, timeNow),
0f, Terrarum.HEIGHT.toFloat(),
getGradientColour(skyboxColourMap, 1, timeNow)
)
g.fill(skyBoxCurrent, skyColourFill)
// calculate global light
val gradCol = getGradientColour(lightColourMap, 0, timeNow)
globalLightNow.r = gradCol.r
globalLightNow.g = gradCol.g
globalLightNow.b = gradCol.b
}
/**
* Get a GL of specific time
*/
fun getGlobalLightOfTime(timeInSec: Int): Color =
getGradientColour(currentWeather.globalLightColourMap, 0, timeInSec)
fun getGradientColour(image: Image, row: Int, timeInSec: Int): Color {
val dataPointDistance = WorldTime.DAY_LENGTH / image.width
val phaseThis: Int = timeInSec / dataPointDistance // x-coord in gradmap
val phaseNext: Int = (phaseThis + 1) % image.width
val colourThis = image.getColor(phaseThis, row)
val colourNext = image.getColor(phaseNext, row)
// interpolate R, G and B
val scale = (timeInSec % dataPointDistance).toFloat() / dataPointDistance // [0.0, 1.0]
//val newCol = ColourUtil.getGradient(scale, colourThis, colourNext)
val newCol = CIELChUtil.getGradient(scale, colourThis, colourNext)
/* // very nice monitor code
// 65 -> 66 | 300 | 19623 | RGB8(255, 0, 255) -[41%]-> RGB8(193, 97, 23) | * `230`40`160`
// ^ step |width| time | colour from scale colour to | output
if (dataPointDistance == 300)
println("$phaseThis -> $phaseNext | $dataPointDistance | $timeInSec" +
" | ${colourThis.toStringRGB()} -[${scale.times(100).toInt()}%]-> ${colourNext.toStringRGB()}" +
" | * `$r`$g`$b`")*/
return newCol
}
fun Color.toStringRGB() = "RGB8(${this.red}, ${this.green}, ${this.blue})"
fun getWeatherList(classification: String) = weatherList[classification]!!
fun getRandomWeather(classification: String) =
getWeatherList(classification)[HQRNG().nextInt(getWeatherList(classification).size)]
fun readFromJson(file: File): BaseModularWeather = readFromJson(file.path)
fun readFromJson(path: String): BaseModularWeather {
/* JSON structure:
{
"globalLight": "colourmap/sky_colour.png", // integer for static, string (path to image) for dynamic
"skyboxGradColourMap": "colourmap/sky_colour.png", // integer for static, string (path to image) for dynamic
"extraImages": [
// if any, it will be like:
sun01.png,
clouds01.png,
clouds02.png,
auroraBlueViolet.png
]
}
*/
val pathToImage = "./assets/graphics/weathers"
val JSON = JsonFetcher(path)
val globalLightInJson = JSON.get("globalLight").asJsonPrimitive
val skyboxInJson = JSON.get("skyboxGradColourMap").asJsonPrimitive
val extraImagesPath = JSON.getAsJsonArray("extraImages")
val globalLight: Image
val skybox: Image
val extraImages = ArrayList<Image>()
val classification = JSON.get("classification").asJsonPrimitive.asString
val mixFrom: String?
try { mixFrom = JSON.get("mixFrom").asJsonPrimitive.asString }
catch (e: NullPointerException) { mixFrom = null }
val mixPercentage: Double?
try { mixPercentage = JSON.get("mixPercentage").asJsonPrimitive.asDouble }
catch (e: NullPointerException) { mixPercentage = null }
// parse globalLight
if (globalLightInJson.isString)
globalLight = Image("$pathToImage/${globalLightInJson.asString}")
else if (globalLightInJson.isNumber) {
// make 1x1 image with specified colour
globalLight = Image(1, 1)
globalLight.graphics.color = Color(globalLightInJson.asNumber.toInt())
globalLight.graphics.fillRect(0f, 0f, 1f, 1f)
}
else
throw IllegalStateException("In weather descriptor $path -- globalLight seems malformed.")
// parse skyboxGradColourMap
if (skyboxInJson.isString)
skybox = Image("$pathToImage/${skyboxInJson.asString}")
else if (globalLightInJson.isNumber) {
// make 1x2 image with specified colour
skybox = Image(1, 2)
skybox.graphics.color = Color(skyboxInJson.asNumber.toInt())
skybox.graphics.fillRect(0f, 0f, 1f, 2f)
}
else
throw IllegalStateException("In weather descriptor $path -- skyboxGradColourMap seems malformed.")
// get extra images
for (i in extraImagesPath)
extraImages.add(Image("$pathToImage/${i.asString}"))
// get mix from
return BaseModularWeather(globalLight, skybox, classification, extraImages)
}
}