mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 01:54:04 +09:00
wip2
This commit is contained in:
@@ -93,6 +93,13 @@ public class Color {
|
|||||||
this.a = a;
|
this.a = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Color (float c) {
|
||||||
|
this.r = c;
|
||||||
|
this.g = c;
|
||||||
|
this.b = c;
|
||||||
|
this.a = c;
|
||||||
|
}
|
||||||
|
|
||||||
/** Constructs a new color using the given color
|
/** Constructs a new color using the given color
|
||||||
*
|
*
|
||||||
* @param color the color */
|
* @param color the color */
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import net.torvald.terrarum.realestate.LandUtil
|
|||||||
*/
|
*/
|
||||||
object LightmapRenderer {
|
object LightmapRenderer {
|
||||||
private const val TILE_SIZE = CreateTileAtlas.TILE_SIZE
|
private const val TILE_SIZE = CreateTileAtlas.TILE_SIZE
|
||||||
|
private const val SQRT2 = 1.41421356f
|
||||||
|
|
||||||
private var world: GameWorld = GameWorld.makeNullWorld()
|
private var world: GameWorld = GameWorld.makeNullWorld()
|
||||||
private lateinit var lightCalcShader: ShaderProgram
|
private lateinit var lightCalcShader: ShaderProgram
|
||||||
@@ -88,7 +89,10 @@ object LightmapRenderer {
|
|||||||
* Sstores both the block light sources and actor light sources.
|
* Sstores both the block light sources and actor light sources.
|
||||||
*/
|
*/
|
||||||
private val lightSourcesMap = HashMap<BlockAddress, Color>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
private val lightSourcesMap = HashMap<BlockAddress, Color>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||||
private val shadesMap = HashMap<BlockAddress, Color>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
/**
|
||||||
|
* Pair of: Regular shade, the former shade times 1.4142
|
||||||
|
*/
|
||||||
|
private val shadesMap = HashMap<BlockAddress, Pair<Color, Color>>((Terrarum.ingame?.ACTORCONTAINER_INITIAL_SIZE ?: 2) * 4)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
|
printdbg(this, "Overscan open: $overscan_open; opaque: $overscan_opaque")
|
||||||
@@ -206,13 +210,15 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
//println("$for_x_start..$for_x_end, $for_x\t$for_y_start..$for_y_end, $for_y")
|
//println("$for_x_start..$for_x_end, $for_x\t$for_y_start..$for_y_end, $for_y")
|
||||||
|
|
||||||
|
// set sunlight
|
||||||
|
sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT)
|
||||||
|
|
||||||
AppLoader.measureDebugTime("Renderer.Preload") {
|
AppLoader.measureDebugTime("Renderer.Preload") {
|
||||||
// this is to recycle pre-calculated lights and shades for all 4 rounds.
|
// this is to recycle pre-calculated lights and shades for all 4 rounds.
|
||||||
// the old code always re-calculates them (calls 'getLightsAndShades()') for every blocks for every round.
|
// the old code always re-calculates them (calls 'getLightsAndShades()') for every blocks for every round.
|
||||||
// the light source information can also be used to create no-op mask? I'm sceptical about that, there must
|
// the light source information can also be used to create no-op mask? I'm sceptical about that, there must
|
||||||
// exist some edge cases like the other time...
|
// exist some edge cases like the other time...
|
||||||
buildLightSourcesMap(actorContainers)
|
buildLightSourcesMap(actorContainers)
|
||||||
buildShadesMap()
|
|
||||||
} // usually takes 3000 ns
|
} // usually takes 3000 ns
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -229,9 +235,6 @@ object LightmapRenderer {
|
|||||||
* If you run only 4 sets, orthogonal/diagonal artefacts are bound to occur,
|
* If you run only 4 sets, orthogonal/diagonal artefacts are bound to occur,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// set sunlight
|
|
||||||
sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT)
|
|
||||||
|
|
||||||
// set no-op mask from solidity of the block
|
// set no-op mask from solidity of the block
|
||||||
AppLoader.measureDebugTime("Renderer.LightNoOpMask") {
|
AppLoader.measureDebugTime("Renderer.LightNoOpMask") {
|
||||||
noopMask.clear()
|
noopMask.clear()
|
||||||
@@ -342,8 +345,20 @@ object LightmapRenderer {
|
|||||||
internal data class ThreadedLightmapUpdateMessage(val x: Int, val y: Int)
|
internal data class ThreadedLightmapUpdateMessage(val x: Int, val y: Int)
|
||||||
|
|
||||||
|
|
||||||
|
private var _block = BlockCodex[0]
|
||||||
|
private var _wall = 0
|
||||||
|
private var _blockLum = Color(0)
|
||||||
|
private var _fluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
||||||
|
private var _fluidProp = BlockCodex[_fluid.type]
|
||||||
|
private var _tileAddr = 0L
|
||||||
|
private var _fluidAmountToCol = Color(0)
|
||||||
|
|
||||||
private fun buildLightSourcesMap(actorContainers: Array<out List<ActorWithBody>?>) {
|
private fun buildLightSourcesMap(actorContainers: Array<out List<ActorWithBody>?>) {
|
||||||
lightSourcesMap.clear()
|
lightSourcesMap.clear()
|
||||||
|
shadesMap.clear()
|
||||||
|
|
||||||
|
// TODO make all local vars class-level global
|
||||||
|
|
||||||
// lanterns from actors
|
// lanterns from actors
|
||||||
actorContainers.forEach { actorContainer ->
|
actorContainers.forEach { actorContainer ->
|
||||||
actorContainer?.forEach {
|
actorContainer?.forEach {
|
||||||
@@ -373,36 +388,50 @@ object LightmapRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// light sources from blocks
|
// light sources and shades from a block
|
||||||
for (x in for_x_start - overscan_open..for_x_end + overscan_open) {
|
for (x in for_x_start - overscan_open..for_x_end + overscan_open) {
|
||||||
for (y in for_y_start - overscan_open..for_y_end + overscan_open) {
|
for (y in for_y_start - overscan_open..for_y_end + overscan_open) {
|
||||||
val block = BlockCodex[world.getTileFromTerrain(x, y)]
|
_block = BlockCodex[world.getTileFromTerrain(x, y)]
|
||||||
val wall = world.getTileFromWall(x, y)
|
_wall = world.getTileFromWall(x, y) ?: Block.STONE
|
||||||
val blockLum = block.internalLumCol
|
_blockLum = _block.luminosity
|
||||||
val fluid = world.getFluid(x, y)
|
_fluid = world.getFluid(x, y)
|
||||||
val tileAddr = LandUtil.getBlockAddr(world, x, y)
|
_fluidProp = BlockCodex[_fluid.type]
|
||||||
|
_tileAddr = LandUtil.getBlockAddr(world, x, y)
|
||||||
|
_fluidAmountToCol = Color(_fluid.amount.coerceIn(0f, 1f))
|
||||||
|
|
||||||
|
// light sources from blocks //
|
||||||
|
|
||||||
// mix with the existing value
|
// mix with the existing value
|
||||||
lightSourcesMap[tileAddr]?.maxAndAssign(blockLum)
|
if (lightSourcesMap[_tileAddr] == null)
|
||||||
|
lightSourcesMap[_tileAddr] = _blockLum
|
||||||
|
else
|
||||||
|
lightSourcesMap[_tileAddr]!!.maxAndAssign(_blockLum)
|
||||||
|
|
||||||
// see if sunlight is applicable. If it does, mix with the existing value
|
// see if sunlight is applicable. If it does, mix with the existing value
|
||||||
if (!block.isSolid && wall == Block.AIR) {
|
if (!_block.isSolid && _wall == Block.AIR) {
|
||||||
lightSourcesMap[tileAddr]?.maxAndAssign(sunLight)
|
lightSourcesMap[_tileAddr]!!.maxAndAssign(sunLight)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mix the lava light
|
// mix the lava light
|
||||||
if (fluid.type != Fluid.NULL) {
|
if (_fluid.type != Fluid.NULL) {
|
||||||
TODO("getLightsAndShades()")
|
lightSourcesMap[_tileAddr]!!.maxAndAssign(
|
||||||
|
_fluidProp.luminosity mul _fluidAmountToCol
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// deal with the shades //
|
||||||
|
|
||||||
|
// shade from the block
|
||||||
|
val shade = _block.opacity
|
||||||
|
// shade from the fluid
|
||||||
|
shade.maxAndAssign(_fluidProp.opacity mul _fluidAmountToCol)
|
||||||
|
|
||||||
|
// actually store the shade value
|
||||||
|
shadesMap[_tileAddr] = shade to shade.cpy().mul(SQRT2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildShadesMap() {
|
|
||||||
shadesMap.clear()
|
|
||||||
TODO("getLightsAndShades()")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildNoopMask() {
|
private fun buildNoopMask() {
|
||||||
fun isShaded(x: Int, y: Int) = BlockCodex[world.getTileFromTerrain(x, y) ?: Block.STONE].isSolid
|
fun isShaded(x: Int, y: Int) = BlockCodex[world.getTileFromTerrain(x, y) ?: Block.STONE].isSolid
|
||||||
|
|
||||||
@@ -435,14 +464,14 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
//private val ambientAccumulator = Color(0f,0f,0f,0f)
|
//private val ambientAccumulator = Color(0f,0f,0f,0f)
|
||||||
private val lightLevelThis = Color(0)
|
//private val lightLevelThis = Color(0)
|
||||||
private var thisTerrain = 0
|
//private var thisTerrain = 0
|
||||||
private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
//private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
||||||
private val fluidAmountToCol = Color(0)
|
//private val fluidAmountToCol = Color(0)
|
||||||
private var thisWall = 0
|
//private var thisWall = 0
|
||||||
private val thisTileLuminosity = Color(0)
|
//private val thisTileLuminosity = Color(0)
|
||||||
private val thisTileOpacity = Color(0)
|
//private val thisTileOpacity = Color(0)
|
||||||
private val thisTileOpacity2 = Color(0) // thisTileOpacity * sqrt(2)
|
//private val thisTileOpacity2 = Color(0) // thisTileOpacity * sqrt(2)
|
||||||
private val sunLight = Color(0)
|
private val sunLight = Color(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -456,7 +485,7 @@ object LightmapRenderer {
|
|||||||
* - thisTileOpacity2
|
* - thisTileOpacity2
|
||||||
* - sunlight
|
* - sunlight
|
||||||
*/
|
*/
|
||||||
private fun getLightsAndShades(x: Int, y: Int) {
|
/*private fun getLightsAndShades(x: Int, y: Int) {
|
||||||
// TODO lanternmap now also holds light sources (incl. sunlight)
|
// TODO lanternmap now also holds light sources (incl. sunlight)
|
||||||
|
|
||||||
|
|
||||||
@@ -490,7 +519,7 @@ object LightmapRenderer {
|
|||||||
// blend lantern
|
// blend lantern
|
||||||
lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lightSourcesMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lightSourcesMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
||||||
|
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private val inNoopMaskp = Point2i(0,0)
|
private val inNoopMaskp = Point2i(0,0)
|
||||||
|
|
||||||
@@ -549,7 +578,10 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
// O(9n) == O(n) where n is a size of the map
|
// O(9n) == O(n) where n is a size of the map
|
||||||
|
|
||||||
getLightsAndShades(x, y)
|
//getLightsAndShades(x, y)
|
||||||
|
val tileAddr = LandUtil.getBlockAddr(world, x, y)
|
||||||
|
val lightLevelThis = lightSourcesMap[tileAddr]!!.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance
|
||||||
|
val (thisTileOpacity, thisTileOpacity2) = shadesMap[tileAddr]!!
|
||||||
|
|
||||||
// calculate ambient
|
// calculate ambient
|
||||||
/* + * + 0 4 1
|
/* + * + 0 4 1
|
||||||
@@ -573,7 +605,7 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
//return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance
|
//return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance
|
||||||
setLightOf(lightmap, x, y, lightLevelThis.cpy())
|
setLightOf(lightmap, x, y, lightLevelThis)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getLightForOpaque(x: Int, y: Int): Color? { // ...so that they wouldn't appear too dark
|
private fun getLightForOpaque(x: Int, y: Int): Color? { // ...so that they wouldn't appear too dark
|
||||||
@@ -932,4 +964,4 @@ object LightmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Color.toRGBA() = (255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt()
|
fun Color.toRGBA() = (255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt()
|
||||||
|
//fun Color(c: Float) = Color(c, c, c, c)
|
||||||
|
|||||||
Reference in New Issue
Block a user