circular (octagon actually) propagation of light

Former-commit-id: 1e67a3284ea298a0d8f27309d9d8ca800a8525c8
Former-commit-id: a5067df80d1053ceec6d78b6fda6cf0afa3c286c
This commit is contained in:
Song Minjae
2017-01-02 14:08:24 +09:00
parent 0c2cb48135
commit ae97310bf7
3 changed files with 43 additions and 55 deletions

View File

@@ -266,6 +266,8 @@ constructor() : BasicGameState() {
} }
private fun changePossession(refid: Int) { private fun changePossession(refid: Int) {
// TODO prevent possessing other player on multiplayer
if (!hasActor(refid)) { if (!hasActor(refid)) {
throw IllegalArgumentException("No such actor in actorContainer: $refid") throw IllegalArgumentException("No such actor in actorContainer: $refid")
} }
@@ -309,12 +311,19 @@ constructor() : BasicGameState() {
///////////////// /////////////////
// --> Change of blend mode <-- introduced by ActorWithBody // // --> Change of blend mode <-- introduced by ActorWithBody //
actorContainer.forEach { actor -> actorContainer.forEach { actor ->
if (actor is ActorWithBody && actor.inScreen() && actor !is Player) { if (actor is ActorWithBody && actor.inScreen() && actor !is Player && !actor.drawTopmost) {
actor.drawBody(gc, worldDrawFrameBuffer.graphics) actor.drawBody(gc, worldDrawFrameBuffer.graphics)
} }
} }
// --> Change of blend mode <-- introduced by ActorWithBody // // --> Change of blend mode <-- introduced by ActorWithBody //
player.drawBody(gc, worldDrawFrameBuffer.graphics) player.drawBody(gc, worldDrawFrameBuffer.graphics)
// --> Change of blend mode <-- introduced by ActorWithBody //
actorContainer.forEach { actor ->
if (actor is ActorWithBody && actor.inScreen() && actor !is Player && actor.drawTopmost) {
actor.drawBody(gc, worldDrawFrameBuffer.graphics)
}
}
// --> Change of blend mode <-- introduced by ActorWithBody //
///////////////////////////// /////////////////////////////

View File

@@ -26,13 +26,14 @@ open class ActorWithBody : Actor() {
/** !! ActorValue macros are on the very bottom of the source !! **/ /** !! ActorValue macros are on the very bottom of the source !! **/
override var actorValue: ActorValue = ActorValue() override var actorValue: ActorValue = ActorValue()
@Transient internal var sprite: SpriteAnimation? = null @Transient internal var sprite: SpriteAnimation? = null
@Transient internal var spriteGlow: SpriteAnimation? = null @Transient internal var spriteGlow: SpriteAnimation? = null
var drawMode = BLEND_NORMAL var drawMode = BLEND_NORMAL
/** for fake tiles. Draw on top of player(s) */
var drawTopmost = false
@Transient private val world: GameWorld = Terrarum.ingame.world @Transient private val world: GameWorld = Terrarum.ingame.world

View File

@@ -183,31 +183,33 @@ object LightmapRenderer {
// O(36n) == O(n) where n is a size of the map. // O(36n) == O(n) where n is a size of the map.
// Because of inevitable overlaps on the area, it only works with ADDITIVE blend (aka maxblend) // Because of inevitable overlaps on the area, it only works with ADDITIVE blend (aka maxblend)
// Round 1 // Round 1
for (y in for_y_start - overscan_open..for_y_end) { for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_start - overscan_open..for_x_end) { for (x in for_x_start - overscan_open..for_x_end) {
setLight(x, y, calculate(x, y)) setLight(x, y, calculate(x, y, 1))
} }
} }
// Round 2 // Round 2
for (y in for_y_end + overscan_open downTo for_y_start) { for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_start - overscan_open..for_x_end) { for (x in for_x_start - overscan_open..for_x_end) {
setLight(x, y, calculate(x, y)) setLight(x, y, calculate(x, y, 2))
} }
} }
// Round 3 // Round 3
for (y in for_y_end + overscan_open downTo for_y_start) { for (y in for_y_end + overscan_open downTo for_y_start) {
for (x in for_x_end + overscan_open downTo for_x_start) { for (x in for_x_end + overscan_open downTo for_x_start) {
setLight(x, y, calculate(x, y)) setLight(x, y, calculate(x, y, 3))
} }
} }
// Round 4 // Round 4
for (y in for_y_start - overscan_open..for_y_end) { for (y in for_y_start - overscan_open..for_y_end) {
for (x in for_x_end + overscan_open downTo for_x_start) { for (x in for_x_end + overscan_open downTo for_x_start) {
setLight(x, y, calculate(x, y)) setLight(x, y, calculate(x, y, 4))
} }
} }
} }
@@ -237,9 +239,9 @@ object LightmapRenderer {
} }
} }
private fun calculate(x: Int, y: Int): Int = calculate(x, y, false) private fun calculate(x: Int, y: Int, pass: Int): Int = calculate(x, y, pass, false)
private fun calculate(x: Int, y: Int, doNotCalculateAmbient: Boolean): Int { private fun calculate(x: Int, y: Int, pass: Int, doNotCalculateAmbient: Boolean): Int {
// O(9n) == O(n) where n is a size of the map // O(9n) == O(n) where n is a size of the map
// TODO devise multithreading on this // TODO devise multithreading on this
@@ -279,56 +281,24 @@ object LightmapRenderer {
if (!doNotCalculateAmbient) { if (!doNotCalculateAmbient) {
// calculate ambient // calculate ambient
var ambient: Int = 0 /* + * +
var nearby: Int * * @ *
for (yoff in -1..1) { * + * +
for (xoff in -1..1) { * sample ambient for eight points and apply attenuation for those
/** * maxblend eight values and use it
* filter for 'v's as: */
* +-+-+-+ var ambient = 0
* |a|v|a| ambient = ambient maxBlend darkenColoured(getLight(x - 1, y - 1) ?: 0, scaleColour(thisTileOpacity, 1.4142f))
* +-+-+-+ ambient = ambient maxBlend darkenColoured(getLight(x + 1, y - 1) ?: 0, scaleColour(thisTileOpacity, 1.4142f))
* |v| |v| ambient = ambient maxBlend darkenColoured(getLight(x - 1, y + 1) ?: 0, scaleColour(thisTileOpacity, 1.4142f))
* +-+-+-+ ambient = ambient maxBlend darkenColoured(getLight(x + 1, y + 1) ?: 0, scaleColour(thisTileOpacity, 1.4142f))
* |a|v|a| ambient = ambient maxBlend darkenColoured(getLight(x , y - 1) ?: 0, thisTileOpacity)
* +-+-+-+ ambient = ambient maxBlend darkenColoured(getLight(x , y - 1) ?: 0, thisTileOpacity)
*/ ambient = ambient maxBlend darkenColoured(getLight(x - 1, y ) ?: 0, thisTileOpacity)
if (xoff != yoff && -xoff != yoff) { ambient = ambient maxBlend darkenColoured(getLight(x + 1, y ) ?: 0, thisTileOpacity)
// 'v' tiles
nearby = getLight(x + xoff, y + yoff) ?: 0
}
else if (xoff != 0 && yoff != 0) {
// 'a' tiles
nearby = darkenUniformInt(getLight(x + xoff, y + yoff) ?: 0, 12)
// mix some to have more 'spreading'
// so that light spreads in a shape of an octagon instead of a diamond
}
else {
nearby = 0 // exclude 'me' tile
}
ambient = ambient maxBlend nearby // keep base value as brightest nearby
}
}
ambient = darkenColoured(ambient, thisTileOpacity) // get real ambient by appling opacity value
return lightLevelThis maxBlend ambient return lightLevelThis maxBlend ambient
// mix and return lightlevel and ambient
/*val retLevel = lightLevelThis maxBlend ambient
// hack: make sure (3,3,3) become 0
return if (retLevel.rawR() < 4 && retLevel.rawG() < 4 && retLevel.rawB() < 4)
0
else
retLevel*/
} }
else { else {
// hack: make sure (3,3,3) become 0
/*return if (lightLevelThis.rawR() < 4 && lightLevelThis.rawG() < 4 && lightLevelThis.rawB() < 4)
0
else
lightLevelThis*/
return lightLevelThis return lightLevelThis
} }
} }
@@ -482,6 +452,14 @@ object LightmapRenderer {
return constructRGBFromFloat(r.clampZero(), g.clampZero(), b.clampZero()) return constructRGBFromFloat(r.clampZero(), g.clampZero(), b.clampZero())
} }
fun scaleColour(data: Int, scale: Float): Int {
val r = data.r() * scale
val g = data.g() * scale
val b = data.b() * scale
return constructRGBFromFloat(r.clampOne(), g.clampOne(), b.clampOne())
}
/** /**
* Add each channel's RGB value. * Add each channel's RGB value.
* *