mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +09:00
initial test, ~40% of the performance was achieved
This commit is contained in:
@@ -16,487 +16,80 @@
|
||||
|
||||
package net.torvald.gdx.graphics
|
||||
|
||||
import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.utils.NumberUtils
|
||||
import jdk.incubator.vector.FloatVector
|
||||
import jdk.incubator.vector.VectorOperators
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* A Cvec is kind of a Vector4f made compatible with LibGdx's Color class, with the intention of actually utilising
|
||||
* the JEP 338 VectorInstrinsics later, when the damned thing finally releases.
|
||||
*
|
||||
* -XX:+UseVectorApiIntrinsics --add-modules=jdk.incubator.vector
|
||||
*
|
||||
* Before then, the code will be identical to LibGdx's.
|
||||
*/
|
||||
inline class Cvec constructor(val vec: FloatVector) {
|
||||
|
||||
/** A color class, holding the r, g, b and alpha component as floats in the range [0,1]. All methods perform clamping on the
|
||||
* internal values after execution.
|
||||
*
|
||||
* @author mzechner
|
||||
*/
|
||||
class Cvec {
|
||||
constructor(floatArray: FloatArray) : this(FloatVector.fromArray(SPECIES, floatArray, 0))
|
||||
constructor(r: Float, g: Float, b: Float, a: Float) : this(FloatVector.fromValues(SPECIES, r, g, b, a))
|
||||
constructor(scalar: Float) : this(FloatVector.fromValues(SPECIES, scalar, scalar, scalar, scalar))
|
||||
constructor() : this(FloatVector.zero(SPECIES))
|
||||
constructor(rgba8888: Int) : this(FloatVector.fromValues(SPECIES,
|
||||
((rgba8888 ushr 24) and 0xff) / 255f,
|
||||
((rgba8888 ushr 16) and 0xff) / 255f,
|
||||
((rgba8888 ushr 8) and 0xff) / 255f,
|
||||
(rgba8888 and 0xff) / 255f
|
||||
))
|
||||
|
||||
/** the red, green, blue and alpha components */
|
||||
var r: Float = 0.toFloat()
|
||||
var g: Float = 0.toFloat()
|
||||
var b: Float = 0.toFloat()
|
||||
var a: Float = 0.toFloat()
|
||||
|
||||
/** Constructs a new Cvec with all components set to 0. */
|
||||
constructor() {}
|
||||
|
||||
/** @see .rgba8888ToCvec
|
||||
*/
|
||||
constructor(rgba8888: Int) {
|
||||
rgba8888ToCvec(this, rgba8888)
|
||||
companion object {
|
||||
private val EPSILON = 1f / 1024f
|
||||
private val SPECIES = FloatVector.SPECIES_128
|
||||
}
|
||||
|
||||
constructor(color: Color) {
|
||||
this.r = color.r
|
||||
this.g = color.g
|
||||
this.b = color.b
|
||||
this.a = color.a
|
||||
}
|
||||
//fun cpy(): Cvec = Cvec(this.vec)
|
||||
|
||||
/** Constructor, sets the components of the color
|
||||
*
|
||||
* @param r the red component
|
||||
* @param g the green component
|
||||
* @param b the blue component
|
||||
* @param a the alpha component
|
||||
*/
|
||||
constructor(r: Float, g: Float, b: Float, a: Float) {
|
||||
this.r = r
|
||||
this.g = g
|
||||
this.b = b
|
||||
this.a = a
|
||||
}
|
||||
// not using shorthand names to prevent confusion with builtin functions
|
||||
|
||||
/** Constructs a new color using the given color
|
||||
*
|
||||
* @param color the color
|
||||
*/
|
||||
constructor(color: Cvec) {
|
||||
set(color)
|
||||
fun multiply(other: FloatVector) = Cvec(vec.mul(other))
|
||||
infix operator fun times(other: Cvec) = multiply(other.vec)
|
||||
//infix operator fun times(scalar: Float) = Cvec(vec.mul(scalar))
|
||||
|
||||
fun subtract(other: FloatVector) = Cvec(vec.sub(other))
|
||||
infix operator fun minus(other: Cvec) = subtract(other.vec)
|
||||
//infix operator fun minus(scalar: Float) = Cvec(vec.sub(scalar))
|
||||
|
||||
fun addition(other: FloatVector) = Cvec(vec.add(other))
|
||||
infix operator fun plus(other: Cvec) = addition(other.vec)
|
||||
//infix operator fun plus(scalar: Float) = Cvec(vec.add(scalar))
|
||||
|
||||
fun maximum(other: FloatVector): Cvec = Cvec(vec.max(other))
|
||||
infix fun max(other: Cvec): Cvec = maximum(other.vec)
|
||||
|
||||
fun lerp(target: Cvec, t: Float): Cvec {
|
||||
return Cvec(t) * (target - this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get RGBA Element using index, of which:
|
||||
* - 0: R
|
||||
* - 1: G
|
||||
* - 2: B
|
||||
* - 3: A
|
||||
* true if at least one element in the vector is not zero.
|
||||
*/
|
||||
fun getElem(index: Int) = when(index) {
|
||||
0 -> r
|
||||
1 -> g
|
||||
2 -> b
|
||||
3 -> a
|
||||
else -> throw IndexOutOfBoundsException("Invalid index $index")
|
||||
fun nonZero(): Boolean = vec.reduceLanes(VectorOperators.MUL) != 0f //vec.toArray().fold(false) { acc, fl -> acc or (fl.absoluteValue >= EPSILON) }
|
||||
|
||||
fun toRGBA8888(): Int {
|
||||
var acc = 0
|
||||
for (i in 0..3)
|
||||
acc += vec.lane(i).coerceIn(0f, 1f).times(255f).roundToInt().shl(8 * (3 - i))
|
||||
|
||||
return acc
|
||||
}
|
||||
|
||||
/** Sets this color to the given color.
|
||||
*
|
||||
* @param color the Cvec
|
||||
*/
|
||||
fun set(color: Cvec): Cvec {
|
||||
this.r = color.r
|
||||
this.g = color.g
|
||||
this.b = color.b
|
||||
this.a = color.a
|
||||
return this
|
||||
}
|
||||
/*override fun equals(other: Any?): Boolean {
|
||||
return this.vec.equal((other as Cvec).vec).allTrue()
|
||||
}*/
|
||||
|
||||
/** Multiplies the this color and the given color
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color.
|
||||
*/
|
||||
fun mul(color: Cvec): Cvec {
|
||||
this.r *= color.r
|
||||
this.g *= color.g
|
||||
this.b *= color.b
|
||||
this.a *= color.a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Multiplies all components of this Cvec with the given value.
|
||||
*
|
||||
* @param value the value
|
||||
* @return this color
|
||||
*/
|
||||
fun mul(value: Float): Cvec {
|
||||
this.r *= value
|
||||
this.g *= value
|
||||
this.b *= value
|
||||
this.a *= value
|
||||
return this
|
||||
}
|
||||
|
||||
/** Adds the given color to this color.
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color
|
||||
*/
|
||||
fun add(color: Cvec): Cvec {
|
||||
this.r += color.r
|
||||
this.g += color.g
|
||||
this.b += color.b
|
||||
this.a += color.a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Subtracts the given color from this color
|
||||
*
|
||||
* @param color the color
|
||||
* @return this color
|
||||
*/
|
||||
fun sub(color: Cvec): Cvec {
|
||||
this.r -= color.r
|
||||
this.g -= color.g
|
||||
this.b -= color.b
|
||||
this.a -= color.a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Sets this Cvec's component values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
*/
|
||||
operator fun set(r: Float, g: Float, b: Float, a: Float): Cvec {
|
||||
this.r = r
|
||||
this.g = g
|
||||
this.b = b
|
||||
this.a = a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Sets this color's component values through an integer representation.
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
* @see .rgba8888ToCvec
|
||||
*/
|
||||
fun set(rgba: Int): Cvec {
|
||||
rgba8888ToCvec(this, rgba)
|
||||
return this
|
||||
}
|
||||
|
||||
/** Adds the given color component values to this Cvec's values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
*/
|
||||
fun add(r: Float, g: Float, b: Float, a: Float): Cvec {
|
||||
this.r += r
|
||||
this.g += g
|
||||
this.b += b
|
||||
this.a += a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Subtracts the given values from this Cvec's component values.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
*/
|
||||
fun sub(r: Float, g: Float, b: Float, a: Float): Cvec {
|
||||
this.r -= r
|
||||
this.g -= g
|
||||
this.b -= b
|
||||
this.a -= a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Multiplies this Cvec's color components by the given ones.
|
||||
*
|
||||
* @param r Red component
|
||||
* @param g Green component
|
||||
* @param b Blue component
|
||||
* @param a Alpha component
|
||||
*
|
||||
* @return this Cvec for chaining
|
||||
*/
|
||||
fun mul(r: Float, g: Float, b: Float, a: Float): Cvec {
|
||||
this.r *= r
|
||||
this.g *= g
|
||||
this.b *= b
|
||||
this.a *= a
|
||||
return this
|
||||
}
|
||||
|
||||
/** Linearly interpolates between this color and the target color by t which is in the range [0,1]. The result is stored in
|
||||
* this color.
|
||||
* @param target The target color
|
||||
* @param t The interpolation coefficient
|
||||
* @return This color for chaining.
|
||||
*/
|
||||
fun lerp(target: Cvec, t: Float): Cvec {
|
||||
this.r += t * (target.r - this.r)
|
||||
this.g += t * (target.g - this.g)
|
||||
this.b += t * (target.b - this.b)
|
||||
this.a += t * (target.a - this.a)
|
||||
return this
|
||||
}
|
||||
|
||||
/** Linearly interpolates between this color and the target color by t which is in the range [0,1]. The result is stored in
|
||||
* this color.
|
||||
* @param r The red component of the target color
|
||||
* @param g The green component of the target color
|
||||
* @param b The blue component of the target color
|
||||
* @param a The alpha component of the target color
|
||||
* @param t The interpolation coefficient
|
||||
* @return This color for chaining.
|
||||
*/
|
||||
fun lerp(r: Float, g: Float, b: Float, a: Float, t: Float): Cvec {
|
||||
this.r += t * (r - this.r)
|
||||
this.g += t * (g - this.g)
|
||||
this.b += t * (b - this.b)
|
||||
this.a += t * (a - this.a)
|
||||
return this
|
||||
}
|
||||
|
||||
/** Multiplies the RGB values by the alpha. */
|
||||
fun premultiplyAlpha(): Cvec {
|
||||
r *= a
|
||||
g *= a
|
||||
b *= a
|
||||
return this
|
||||
}
|
||||
|
||||
override fun equals(o: Any?): Boolean {
|
||||
if (this === o) return true
|
||||
if (o == null || javaClass != o.javaClass) return false
|
||||
val color = o as Cvec?
|
||||
return toIntBits() == color!!.toIntBits()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = if (r != +0.0f) NumberUtils.floatToIntBits(r) else 0
|
||||
result = 31 * result + if (g != +0.0f) NumberUtils.floatToIntBits(g) else 0
|
||||
result = 31 * result + if (b != +0.0f) NumberUtils.floatToIntBits(b) else 0
|
||||
result = 31 * result + if (a != +0.0f) NumberUtils.floatToIntBits(a) else 0
|
||||
return result
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR and then converts it to a float. Alpha is compressed
|
||||
* from 0-255 to 0-254 to avoid using float bits in the NaN range (see [NumberUtils.intToFloatColor]).
|
||||
* @return the packed color as a 32-bit float
|
||||
*/
|
||||
fun toFloatBits(): Float {
|
||||
val color = (255 * a).toInt() shl 24 or ((255 * b).toInt() shl 16) or ((255 * g).toInt() shl 8) or (255 * r).toInt()
|
||||
return NumberUtils.intToFloatColor(color)
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR.
|
||||
* @return the packed color as a 32-bit int.
|
||||
*/
|
||||
fun toIntBits(): Int {
|
||||
return (255 * a).toInt() shl 24 or ((255 * b).toInt() shl 16) or ((255 * g).toInt() shl 8) or (255 * r).toInt()
|
||||
}
|
||||
|
||||
/** Returns the color encoded as hex string with the format RRGGBBAA. */
|
||||
override fun toString(): String {
|
||||
var value = Integer
|
||||
.toHexString((255 * r).toInt() shl 24 or ((255 * g).toInt() shl 16) or ((255 * b).toInt() shl 8) or (255 * a).toInt())
|
||||
while (value.length < 8)
|
||||
value = "0$value"
|
||||
return value
|
||||
}
|
||||
|
||||
/** Sets the RGB Cvec components using the specified Hue-Saturation-Value. Note that HSV components are voluntary not clamped
|
||||
* to preserve high range color and can range beyond typical values.
|
||||
* @param h The Hue in degree from 0 to 360
|
||||
* @param s The Saturation from 0 to 1
|
||||
* @param v The Value (brightness) from 0 to 1
|
||||
* @return The modified Cvec for chaining.
|
||||
*/
|
||||
fun fromHsv(h: Float, s: Float, v: Float): Cvec {
|
||||
val x = (h / 60f + 6) % 6
|
||||
val i = x.toInt()
|
||||
val f = x - i
|
||||
val p = v * (1 - s)
|
||||
val q = v * (1 - s * f)
|
||||
val t = v * (1 - s * (1 - f))
|
||||
when (i) {
|
||||
0 -> {
|
||||
r = v
|
||||
g = t
|
||||
b = p
|
||||
}
|
||||
1 -> {
|
||||
r = q
|
||||
g = v
|
||||
b = p
|
||||
}
|
||||
2 -> {
|
||||
r = p
|
||||
g = v
|
||||
b = t
|
||||
}
|
||||
3 -> {
|
||||
r = p
|
||||
g = q
|
||||
b = v
|
||||
}
|
||||
4 -> {
|
||||
r = t
|
||||
g = p
|
||||
b = v
|
||||
}
|
||||
else -> {
|
||||
r = v
|
||||
g = p
|
||||
b = q
|
||||
}
|
||||
}
|
||||
|
||||
//return clamp();
|
||||
return this
|
||||
}
|
||||
|
||||
/** Sets RGB components using the specified Hue-Saturation-Value. This is a convenient method for
|
||||
* [.fromHsv]. This is the inverse of [.toHsv].
|
||||
* @param hsv The Hue, Saturation and Value components in that order.
|
||||
* @return The modified Cvec for chaining.
|
||||
*/
|
||||
fun fromHsv(hsv: FloatArray): Cvec {
|
||||
return fromHsv(hsv[0], hsv[1], hsv[2])
|
||||
}
|
||||
|
||||
fun toGdxColor() = Color(r, g, b, a)
|
||||
|
||||
/** Extract Hue-Saturation-Value. This is the inverse of [.fromHsv].
|
||||
* @param hsv The HSV array to be modified.
|
||||
* @return HSV components for chaining.
|
||||
*/
|
||||
fun toHsv(hsv: FloatArray): FloatArray {
|
||||
val max = Math.max(Math.max(r, g), b)
|
||||
val min = Math.min(Math.min(r, g), b)
|
||||
val range = max - min
|
||||
if (range == 0f) {
|
||||
hsv[0] = 0f
|
||||
}
|
||||
else if (max == r) {
|
||||
hsv[0] = (60 * (g - b) / range + 360) % 360
|
||||
}
|
||||
else if (max == g) {
|
||||
hsv[0] = 60 * (b - r) / range + 120
|
||||
}
|
||||
else {
|
||||
hsv[0] = 60 * (r - g) / range + 240
|
||||
}
|
||||
|
||||
if (max > 0) {
|
||||
hsv[1] = 1 - min / max
|
||||
}
|
||||
else {
|
||||
hsv[1] = 0f
|
||||
}
|
||||
|
||||
hsv[2] = max
|
||||
|
||||
return hsv
|
||||
}
|
||||
|
||||
/** @return a copy of this color
|
||||
*/
|
||||
fun cpy(): Cvec {
|
||||
return Cvec(this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val WHITE = Cvec(1f, 1f, 1f, 1f)
|
||||
|
||||
/** Returns a new color from a hex string with the format RRGGBBAA.
|
||||
* @see .toString
|
||||
*/
|
||||
fun valueOf(hex: String): Cvec {
|
||||
var hex = hex
|
||||
hex = if (hex[0] == '#') hex.substring(1) else hex
|
||||
val r = Integer.valueOf(hex.substring(0, 2), 16)
|
||||
val g = Integer.valueOf(hex.substring(2, 4), 16)
|
||||
val b = Integer.valueOf(hex.substring(4, 6), 16)
|
||||
val a = if (hex.length != 8) 255 else Integer.valueOf(hex.substring(6, 8), 16)
|
||||
return Cvec(r / 255f, g / 255f, b / 255f, a / 255f)
|
||||
}
|
||||
|
||||
/** Packs the color components into a 32-bit integer with the format ABGR. Note that no range checking is performed for higher
|
||||
* performance.
|
||||
* @param r the red component, 0 - 255
|
||||
* @param g the green component, 0 - 255
|
||||
* @param b the blue component, 0 - 255
|
||||
* @param a the alpha component, 0 - 255
|
||||
* @return the packed color as a 32-bit int
|
||||
*/
|
||||
fun toIntBits(r: Int, g: Int, b: Int, a: Int): Int {
|
||||
return a shl 24 or (b shl 16) or (g shl 8) or r
|
||||
}
|
||||
|
||||
fun alpha(alpha: Float): Int {
|
||||
return (alpha * 255.0f).toInt()
|
||||
}
|
||||
|
||||
fun rgba8888(r: Float, g: Float, b: Float, a: Float): Int {
|
||||
return (r * 255).toInt() shl 24 or ((g * 255).toInt() shl 16) or ((b * 255).toInt() shl 8) or (a * 255).toInt()
|
||||
}
|
||||
|
||||
fun argb8888(a: Float, r: Float, g: Float, b: Float): Int {
|
||||
return (a * 255).toInt() shl 24 or ((r * 255).toInt() shl 16) or ((g * 255).toInt() shl 8) or (b * 255).toInt()
|
||||
}
|
||||
|
||||
fun rgba8888(color: Cvec): Int {
|
||||
return (color.r * 255).toInt() shl 24 or ((color.g * 255).toInt() shl 16) or ((color.b * 255).toInt() shl 8) or (color.a * 255).toInt()
|
||||
}
|
||||
|
||||
fun argb8888(color: Cvec): Int {
|
||||
return (color.a * 255).toInt() shl 24 or ((color.r * 255).toInt() shl 16) or ((color.g * 255).toInt() shl 8) or (color.b * 255).toInt()
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified integer value in the format RGBA8888. This is inverse to the rgba8888(r, g,
|
||||
* b, a) method.
|
||||
*
|
||||
* @param color The Cvec to be modified.
|
||||
* @param value An integer color value in RGBA8888 format.
|
||||
*/
|
||||
fun rgba8888ToCvec(color: Cvec, value: Int) {
|
||||
color.r = (value and -0x1000000).ushr(24) / 255f
|
||||
color.g = (value and 0x00ff0000).ushr(16) / 255f
|
||||
color.b = (value and 0x0000ff00).ushr(8) / 255f
|
||||
color.a = (value and 0x000000ff) / 255f
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified integer value in the format ARGB8888. This is the inverse to the argb8888(a,
|
||||
* r, g, b) method
|
||||
*
|
||||
* @param color The Cvec to be modified.
|
||||
* @param value An integer color value in ARGB8888 format.
|
||||
*/
|
||||
fun argb8888ToCvec(color: Cvec, value: Int) {
|
||||
color.a = (value and -0x1000000).ushr(24) / 255f
|
||||
color.r = (value and 0x00ff0000).ushr(16) / 255f
|
||||
color.g = (value and 0x0000ff00).ushr(8) / 255f
|
||||
color.b = (value and 0x000000ff) / 255f
|
||||
}
|
||||
|
||||
/** Sets the Cvec components using the specified float value in the format ABGB8888.
|
||||
* @param color The Cvec to be modified.
|
||||
*/
|
||||
fun abgr8888ToCvec(color: Cvec, value: Float) {
|
||||
val c = NumberUtils.floatToIntColor(value)
|
||||
color.a = (c and -0x1000000).ushr(24) / 255f
|
||||
color.b = (c and 0x00ff0000).ushr(16) / 255f
|
||||
color.g = (c and 0x0000ff00).ushr(8) / 255f
|
||||
color.r = (c and 0x000000ff) / 255f
|
||||
}
|
||||
}
|
||||
fun toGdxColor() = com.badlogic.gdx.graphics.Color(
|
||||
vec.lane(0),
|
||||
vec.lane(1),
|
||||
vec.lane(2),
|
||||
vec.lane(3)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,11 +12,13 @@ import net.torvald.UnsafeHelper
|
||||
*/
|
||||
internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
||||
|
||||
val TOTAL_SIZE_IN_BYTES = 16L * width * height
|
||||
val sizeof = 16L
|
||||
|
||||
val TOTAL_SIZE_IN_BYTES = sizeof * width * height
|
||||
|
||||
val array = UnsafeHelper.allocate(TOTAL_SIZE_IN_BYTES)
|
||||
|
||||
private inline fun toAddr(x: Int, y: Int) = 16L * (y * width + x)
|
||||
private inline fun toAddr(x: Int, y: Int) = sizeof * (y * width + x)
|
||||
|
||||
fun zerofill() = array.fillWith(0)
|
||||
|
||||
@@ -24,35 +26,21 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
||||
zerofill()
|
||||
}
|
||||
|
||||
fun getR(x: Int, y: Int) = array.getFloat(toAddr(x, y))
|
||||
fun getG(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 4)
|
||||
fun getB(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 8)
|
||||
fun getA(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 12)
|
||||
|
||||
fun setR(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y), value) }
|
||||
fun setG(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 4, value) }
|
||||
fun setB(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 8, value) }
|
||||
fun setA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 12, value) }
|
||||
|
||||
fun addA(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 12, getA(x, y) + value) }
|
||||
|
||||
/**
|
||||
* @param channel 0 for R, 1 for G, 2 for B, 3 for A
|
||||
*/
|
||||
inline fun channelSet(x: Int, y: Int, channel: Int, value: Float) {
|
||||
array.setFloat(toAddr(x, y) + 4L * channel, value)
|
||||
fun getVec(x: Int, y: Int): Cvec {
|
||||
val addr = toAddr(x, y)
|
||||
return Cvec(
|
||||
array.getFloat(addr),
|
||||
array.getFloat(addr + 4),
|
||||
array.getFloat(addr + 8),
|
||||
array.getFloat(addr + 12)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param channel 0 for R, 1 for G, 2 for B, 3 for A
|
||||
*/
|
||||
inline fun channelGet(x: Int, y: Int, channel: Int) = array.getFloat(toAddr(x, y) + 4L * channel)
|
||||
|
||||
fun max(x: Int, y: Int, other: Cvec) {
|
||||
setR(x, y, maxOf(getR(x, y), other.r))
|
||||
setG(x, y, maxOf(getG(x, y), other.g))
|
||||
setB(x, y, maxOf(getB(x, y), other.b))
|
||||
setA(x, y, maxOf(getA(x, y), other.a))
|
||||
fun setVec(x: Int, y: Int, value: Cvec) {
|
||||
val addr = toAddr(x, y)
|
||||
array.setFloat(addr, value.vec.lane(0))
|
||||
array.setFloat(addr + 4, value.vec.lane(1))
|
||||
array.setFloat(addr + 8, value.vec.lane(2))
|
||||
array.setFloat(addr + 12, value.vec.lane(3))
|
||||
}
|
||||
|
||||
fun destroy() = this.array.destroy()
|
||||
|
||||
@@ -75,7 +75,7 @@ class GdxColorMap {
|
||||
fun getRaw(x: Int, y: Int): RGBA8888 = dataRaw[y * width + x]
|
||||
fun getRaw(x: Int): RGBA8888 = if (is2D) throw UnsupportedOperationException("This is 2D color map") else dataRaw[x]
|
||||
|
||||
//fun getAsCvec(x: Int, y: Int): Cvec = dataCvec[y * width + x]
|
||||
//fun getAsCvec(x: Int, y: Int): Cvec = dataCvec[y * width + x] // for some reason it just returns zero
|
||||
|
||||
override fun toString(): String {
|
||||
val sb = StringBuilder()
|
||||
|
||||
@@ -147,7 +147,7 @@ object BlockCodex {
|
||||
prop.baseLumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
||||
prop.baseLumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
||||
prop.baseLumColA = floatVal(record, "lumuv") / LightmapRenderer.MUL_FLOAT
|
||||
prop.baseLumCol.set(prop.baseLumColR, prop.baseLumColG, prop.baseLumColB, prop.baseLumColA)
|
||||
prop.baseLumCol = Cvec(prop.baseLumColR, prop.baseLumColG, prop.baseLumColB, prop.baseLumColA)
|
||||
|
||||
prop.friction = intVal(record, "fr")
|
||||
prop.viscosity = intVal(record, "vscs")
|
||||
|
||||
@@ -20,7 +20,7 @@ class BlockProp {
|
||||
var shadeColB = 0f
|
||||
var shadeColA = 0f
|
||||
|
||||
lateinit var opacity: Cvec
|
||||
var opacity: Cvec = Cvec(0f)
|
||||
|
||||
fun getOpacity(channel: Int) = when (channel) {
|
||||
0 -> shadeColR
|
||||
@@ -51,12 +51,12 @@ class BlockProp {
|
||||
internal var baseLumColG = 0f // base value used to calculate dynamic luminosity
|
||||
internal var baseLumColB = 0f // base value used to calculate dynamic luminosity
|
||||
internal var baseLumColA = 0f // base value used to calculate dynamic luminosity
|
||||
internal val baseLumCol = Cvec(0)
|
||||
internal var baseLumCol = Cvec(0f)
|
||||
//var lumColR = 0f // memoised value of dynamic luminosity
|
||||
//var lumColG = 0f // memoised value of dynamic luminosity
|
||||
//var lumColB = 0f // memoised value of dynamic luminosity
|
||||
//var lumColA = 0f // memoised value of dynamic luminosity
|
||||
internal val _lumCol = Cvec(0)
|
||||
internal var _lumCol = Cvec(0f)
|
||||
// X- and Y-value must be treated properly beforehand! (use GameWorld.coerceXY())
|
||||
fun getLumCol(x: Int, y: Int) = if (dynamicLuminosityFunction == 0) {
|
||||
baseLumCol
|
||||
@@ -65,12 +65,6 @@ class BlockProp {
|
||||
BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol
|
||||
}
|
||||
|
||||
fun getLumCol(x: Int, y: Int, channel: Int): Float = if (dynamicLuminosityFunction == 0) {
|
||||
baseLumCol.getElem(channel)
|
||||
} else {
|
||||
val offset = XXHash32.hash(((x and 0xFFFF).shl(16) or (y and 0xFFFF)).toLittle(), 10000).fmod(BlockCodex.DYNAMIC_RANDOM_CASES)
|
||||
BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol.getElem(channel)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param luminosity
|
||||
|
||||
@@ -95,7 +95,7 @@ object BlockPropUtil {
|
||||
prop.rngBase2 = getNewRandom()
|
||||
}
|
||||
|
||||
prop._lumCol.set(getDynamicLumFunc(prop))
|
||||
prop._lumCol = getDynamicLumFunc(prop)
|
||||
//prop.lumColR = prop.lumCol.r
|
||||
//prop.lumColG = prop.lumCol.g
|
||||
//prop.lumColB = prop.lumCol.b
|
||||
@@ -111,8 +111,8 @@ object BlockPropUtil {
|
||||
private fun getDynamicLumFunc(prop: BlockProp): Cvec {
|
||||
return when (prop.dynamicLuminosityFunction) {
|
||||
1 -> getTorchFlicker(prop)
|
||||
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light
|
||||
3 -> WeatherMixer.getGlobalLightOfTime(Terrarum.ingame!!.world, WorldTime.DAY_LENGTH / 2).cpy().mul(LightmapRenderer.DIV_FLOAT) // daylight at noon
|
||||
2 -> (Terrarum.ingame!!.world).globalLight * LightmapRenderer.DIV_FLOAT_VEC // current global light
|
||||
3 -> WeatherMixer.getGlobalLightOfTime(Terrarum.ingame!!.world, WorldTime.DAY_LENGTH / 2) * LightmapRenderer.DIV_FLOAT_VEC // daylight at noon
|
||||
4 -> getSlowBreath(prop)
|
||||
5 -> getPulsate(prop)
|
||||
else -> prop.baseLumCol
|
||||
@@ -141,11 +141,6 @@ object BlockPropUtil {
|
||||
* @return processed colour
|
||||
*/
|
||||
private fun alterBrightnessUniform(data: Cvec, brighten: Float): Cvec {
|
||||
return Cvec(
|
||||
data.r + brighten,
|
||||
data.g + brighten,
|
||||
data.b + brighten,
|
||||
data.a + brighten
|
||||
)
|
||||
return data + Cvec(brighten)
|
||||
}
|
||||
}
|
||||
@@ -74,10 +74,10 @@ open class ActorHumanoid(
|
||||
(actorValue.getAsFloat(AVKey.LUMA) ?: 0f) / LightmapRenderer.MUL_FLOAT
|
||||
)
|
||||
set(value) {
|
||||
actorValue[AVKey.LUMR] = value.r * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMG] = value.g * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMB] = value.b * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMA] = value.a * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMR] = value.vec.lane(0) * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMG] = value.vec.lane(1) * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMB] = value.vec.lane(2) * LightmapRenderer.MUL_FLOAT
|
||||
actorValue[AVKey.LUMA] = value.vec.lane(3) * LightmapRenderer.MUL_FLOAT
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@ open class ProjectileSimple(
|
||||
|
||||
|
||||
override var color: Cvec
|
||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Cvec).cpy()
|
||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Cvec)
|
||||
set(value) {
|
||||
}
|
||||
/**
|
||||
|
||||
@@ -48,7 +48,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
lateinit var mixedWeather: BaseModularWeather
|
||||
|
||||
val globalLightNow = Cvec(0)
|
||||
var globalLightNow = Cvec(0f)
|
||||
|
||||
// Weather indices
|
||||
const val WEATHER_GENERIC = "generic"
|
||||
@@ -133,7 +133,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
|
||||
// calculate global light
|
||||
val globalLight = getGradientColour(world, skyboxColourMap, 2, timeNow)
|
||||
globalLightNow.set(globalLight)
|
||||
globalLightNow = globalLight
|
||||
|
||||
|
||||
/* (copied from the shader source)
|
||||
@@ -250,7 +250,7 @@ internal object WeatherMixer : RNGConsumer {
|
||||
" | ${colourThis.toStringRGB()} -[${scale.times(100).toInt()}%]-> ${colourNext.toStringRGB()}" +
|
||||
" | * `$r`$g`$b`")*/
|
||||
|
||||
return Cvec(newCol)
|
||||
return Cvec(newCol.r, newCol.g, newCol.b, newCol.a)
|
||||
}
|
||||
|
||||
fun getWeatherList(classification: String) = weatherList[classification]!!
|
||||
|
||||
@@ -146,10 +146,10 @@ class BasicDebugInfoWindow : UICanvas() {
|
||||
val mtX = mouseTileX.toString()
|
||||
val mtY = mouseTileY.toString()
|
||||
val valRaw = LightmapRenderer.getLight(mouseTileX, mouseTileY)
|
||||
val rawR = valRaw?.r?.times(100f)?.round()?.div(100f)
|
||||
val rawG = valRaw?.g?.times(100f)?.round()?.div(100f)
|
||||
val rawB = valRaw?.b?.times(100f)?.round()?.div(100f)
|
||||
val rawA = valRaw?.a?.times(100f)?.round()?.div(100f)
|
||||
val rawR = valRaw?.vec?.lane(0)?.times(100f)?.round()?.div(100f)
|
||||
val rawG = valRaw?.vec?.lane(1)?.times(100f)?.round()?.div(100f)
|
||||
val rawB = valRaw?.vec?.lane(2)?.times(100f)?.round()?.div(100f)
|
||||
val rawA = valRaw?.vec?.lane(3)?.times(100f)?.round()?.div(100f)
|
||||
|
||||
lightVal = if (valRaw == null) "$EMDASH"
|
||||
else "$rawR $rawG $rawB $rawA"
|
||||
|
||||
@@ -122,7 +122,9 @@ object LightmapRenderer {
|
||||
const val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat()
|
||||
const val COLOUR_RANGE_SIZE = MUL * MUL_2
|
||||
const val MUL_FLOAT = MUL / 256f
|
||||
val MUL_FLOAT_VEC = Cvec(MUL_FLOAT)
|
||||
const val DIV_FLOAT = 256f / MUL
|
||||
val DIV_FLOAT_VEC = Cvec(DIV_FLOAT)
|
||||
|
||||
internal var for_x_start = 0
|
||||
internal var for_y_start = 0
|
||||
@@ -159,12 +161,7 @@ object LightmapRenderer {
|
||||
val x = x.convX()
|
||||
val y = y.convY()
|
||||
|
||||
return Cvec(
|
||||
lightmap.getR(x, y) * MUL_FLOAT,
|
||||
lightmap.getG(x, y) * MUL_FLOAT,
|
||||
lightmap.getB(x, y) * MUL_FLOAT,
|
||||
lightmap.getA(x, y) * MUL_FLOAT
|
||||
)
|
||||
return lightmap.getVec(x, y) * MUL_FLOAT_VEC
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +218,7 @@ object LightmapRenderer {
|
||||
*/
|
||||
|
||||
// set sunlight
|
||||
sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT)
|
||||
sunLight = world.globalLight * DIV_FLOAT_VEC
|
||||
|
||||
// set no-op mask from solidity of the block
|
||||
AppLoader.measureDebugTime("Renderer.LightNoOpMask") {
|
||||
@@ -506,7 +503,7 @@ object LightmapRenderer {
|
||||
*
|
||||
* @return true if skip
|
||||
*/
|
||||
private fun radiate(channel: Int, wx: Int, wy: Int, lightsource: Cvec, distSqr: Int): Boolean {
|
||||
/*private fun radiate(channel: Int, wx: Int, wy: Int, lightsource: Cvec, distSqr: Int): Boolean {
|
||||
val lx = wx.convX(); val ly = wy.convY()
|
||||
|
||||
if (lx !in 0 until LIGHTMAP_WIDTH || ly !in 0 until LIGHTMAP_HEIGHT)
|
||||
@@ -537,28 +534,25 @@ object LightmapRenderer {
|
||||
if (inNoopMask(worldX, worldY)) return false
|
||||
|
||||
// just quick snippets to make test work
|
||||
lightLevelThis.set(colourNull)
|
||||
thisTileOpacity.set(BlockCodex[world.getTileFromTerrain(worldX, worldY)].opacity)
|
||||
thisTileOpacity = BlockCodex[world.getTileFromTerrain(worldX, worldY)].opacity
|
||||
|
||||
val x = worldX.convX()
|
||||
val y = worldY.convY()
|
||||
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
|
||||
lightLevelThis = lightLevelThis max
|
||||
/* + *///darkenColoured(x - 1, y - 1, thisTileOpacity2) max
|
||||
/* + *///darkenColoured(x + 1, y - 1, thisTileOpacity2) max
|
||||
/* + *///darkenColoured(x - 1, y + 1, thisTileOpacity2) max
|
||||
/* + *///darkenColoured(x + 1, y + 1, thisTileOpacity2) max
|
||||
/* * */darkenColoured(x, y - 1, thisTileOpacity) max
|
||||
/* * */darkenColoured(x, y + 1, thisTileOpacity) max
|
||||
/* * */darkenColoured(x - 1, y, thisTileOpacity) max
|
||||
/* * */darkenColoured(x + 1, y, thisTileOpacity)
|
||||
|
||||
lightmap.setR(x, y, lightLevelThis.r)
|
||||
lightmap.setG(x, y, lightLevelThis.g)
|
||||
lightmap.setB(x, y, lightLevelThis.b)
|
||||
lightmap.setA(x, y, lightLevelThis.a)
|
||||
lightmap.setVec(x, y, lightLevelThis)
|
||||
|
||||
return false
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// TODO re-init at every resize
|
||||
@@ -677,12 +671,12 @@ object LightmapRenderer {
|
||||
|
||||
|
||||
private val ambientAccumulator = Cvec(0f,0f,0f,0f)
|
||||
private val lightLevelThis = Cvec(0)
|
||||
private val fluidAmountToCol = Cvec(0)
|
||||
private val thisTileLuminosity = Cvec(0)
|
||||
private val thisTileOpacity = Cvec(0)
|
||||
private val thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2)
|
||||
private val sunLight = Cvec(0)
|
||||
private var lightLevelThis = Cvec(0f)
|
||||
private var fluidAmountToCol = Cvec(0f)
|
||||
private var thisTileLuminosity = Cvec(0f)
|
||||
private var thisTileOpacity = Cvec(0f)
|
||||
private var thisTileOpacity2 = Cvec(0f) // thisTileOpacity * sqrt(2)
|
||||
private var sunLight = Cvec(0f)
|
||||
private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
||||
private var thisTerrain = 0
|
||||
private var thisWall = 0
|
||||
@@ -694,6 +688,8 @@ object LightmapRenderer {
|
||||
private var thisTileOpacityCh = 0f
|
||||
private var thisTileOpacity2Ch = 0f
|
||||
|
||||
private val SQRT2_VEC = Cvec(1.41421356f)
|
||||
|
||||
/**
|
||||
* This function will alter following variables:
|
||||
* - lightLevelThis
|
||||
@@ -708,7 +704,7 @@ object LightmapRenderer {
|
||||
private fun getLightsAndShades(x: Int, y: Int) {
|
||||
val (x, y) = world.coerceXY(x, y)
|
||||
|
||||
lightLevelThis.set(colourNull)
|
||||
lightLevelThis = colourNull
|
||||
thisTerrain = world.getTileFromTerrainRaw(x, y)
|
||||
thisFluid = world.getFluid(x, y)
|
||||
thisWall = world.getTileFromWallRaw(x, y)
|
||||
@@ -736,84 +732,29 @@ object LightmapRenderer {
|
||||
}
|
||||
|
||||
if (thisFluid.type != Fluid.NULL) {
|
||||
fluidAmountToCol.set(thisFluid.amount, thisFluid.amount, thisFluid.amount, thisFluid.amount)
|
||||
fluidAmountToCol = Cvec(thisFluid.amount)
|
||||
|
||||
thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y))
|
||||
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].getLumCol(x, y).mul(fluidAmountToCol)) // already been div by four
|
||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
||||
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four
|
||||
thisTileLuminosity = BlockCodex[thisTerrain].getLumCol(x, y) max
|
||||
(BlockCodex[thisFluid.type].getLumCol(x, y) * fluidAmountToCol) // already been div by four
|
||||
thisTileOpacity = BlockCodex[thisTerrain].opacity max
|
||||
(BlockCodex[thisFluid.type].opacity * fluidAmountToCol) // already been div by four
|
||||
}
|
||||
else {
|
||||
thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y))
|
||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
||||
thisTileLuminosity = BlockCodex[thisTerrain].getLumCol(x, y)
|
||||
thisTileOpacity = BlockCodex[thisTerrain].opacity
|
||||
}
|
||||
|
||||
thisTileOpacity2.set(thisTileOpacity); thisTileOpacity2.mul(1.41421356f)
|
||||
thisTileOpacity2 = thisTileOpacity * SQRT2_VEC
|
||||
//sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent()
|
||||
|
||||
|
||||
// open air || luminous tile backed by sunlight
|
||||
if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosity.nonZero() && thisWall == AIR)) {
|
||||
lightLevelThis.set(sunLight)
|
||||
lightLevelThis = sunLight
|
||||
}
|
||||
|
||||
// blend lantern
|
||||
lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
||||
}
|
||||
|
||||
private fun getLightsAndShadesCh(x: Int, y: Int, channel: Int) {
|
||||
lightLevelThisCh = 0f
|
||||
thisTerrain = world.getTileFromTerrain(x, y) ?: Block.STONE
|
||||
thisFluid = world.getFluid(x, y)
|
||||
thisWall = world.getTileFromWall(x, y) ?: Block.STONE
|
||||
|
||||
// regarding the issue #26
|
||||
try {
|
||||
val fuck = BlockCodex[thisTerrain].getLumCol(x, y)
|
||||
}
|
||||
catch (e: NullPointerException) {
|
||||
System.err.println("## NPE -- x: $x, y: $y, value: $thisTerrain")
|
||||
e.printStackTrace()
|
||||
// create shitty minidump
|
||||
System.err.println("MINIMINIDUMP START")
|
||||
for (xx in x - 16 until x + 16) {
|
||||
val raw = world.getTileFromTerrain(xx, y)
|
||||
val lsb = raw.and(0xff).toString(16).padStart(2, '0')
|
||||
val msb = raw.ushr(8).and(0xff).toString(16).padStart(2, '0')
|
||||
System.err.print(lsb)
|
||||
System.err.print(msb)
|
||||
System.err.print(" ")
|
||||
}
|
||||
System.err.println("\nMINIMINIDUMP END")
|
||||
|
||||
exitProcess(1)
|
||||
}
|
||||
|
||||
if (thisFluid.type != Fluid.NULL) {
|
||||
fluidAmountToColCh = thisFluid.amount
|
||||
|
||||
thisTileLuminosityCh = BlockCodex[thisTerrain].getLumCol(x, y, channel)
|
||||
thisTileLuminosityCh = maxOf(BlockCodex[thisFluid.type].getLumCol(x, y, channel) * fluidAmountToColCh, thisTileLuminosityCh) // already been div by four
|
||||
thisTileOpacityCh = BlockCodex[thisTerrain].getOpacity(channel)
|
||||
thisTileOpacityCh = maxOf(BlockCodex[thisFluid.type].getOpacity(channel) * fluidAmountToColCh, thisTileOpacityCh) // already been div by four
|
||||
}
|
||||
else {
|
||||
thisTileLuminosityCh = BlockCodex[thisTerrain].getLumCol(x, y, channel)
|
||||
thisTileOpacityCh = BlockCodex[thisTerrain].getOpacity(channel)
|
||||
}
|
||||
|
||||
thisTileOpacity2Ch = thisTileOpacityCh * 1.41421356f
|
||||
//sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent()
|
||||
|
||||
|
||||
// open air || luminous tile backed by sunlight
|
||||
if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosityCh > epsilon && thisWall == AIR)) {
|
||||
lightLevelThisCh = sunLight.getElem(channel)
|
||||
}
|
||||
|
||||
// blend lantern
|
||||
lightLevelThisCh = maxOf(thisTileLuminosityCh, lightLevelThisCh)
|
||||
lightLevelThisCh = maxOf(lanternMap[LandUtil.getBlockAddr(world, x, y)]?.getElem(channel) ?: 0f, lightLevelThisCh)
|
||||
lightLevelThis = lightLevelThis max thisTileLuminosity max (lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
||||
}
|
||||
|
||||
private val inNoopMaskp = Point2i(0,0)
|
||||
@@ -888,70 +829,35 @@ object LightmapRenderer {
|
||||
|
||||
// will "overwrite" what's there in the lightmap if it's the first pass
|
||||
// takes about 2 ms on 6700K
|
||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
|
||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
|
||||
lightLevelThis = lightLevelThis max
|
||||
/* + */darkenColoured(x - 1, y - 1, thisTileOpacity2) max
|
||||
/* + */darkenColoured(x + 1, y - 1, thisTileOpacity2) max
|
||||
/* + */darkenColoured(x - 1, y + 1, thisTileOpacity2) max
|
||||
/* + */darkenColoured(x + 1, y + 1, thisTileOpacity2) max
|
||||
/* * */darkenColoured(x, y - 1, thisTileOpacity) max
|
||||
/* * */darkenColoured(x, y + 1, thisTileOpacity) max
|
||||
/* * */darkenColoured(x - 1, y, thisTileOpacity) max
|
||||
/* * */darkenColoured(x + 1, y, thisTileOpacity)
|
||||
|
||||
|
||||
//return lightLevelThis.cpy() // it HAS to be a cpy(), otherwise all cells gets the same instance
|
||||
//setLightOf(lightmap, x, y, lightLevelThis.cpy())
|
||||
|
||||
lightmap.setR(x, y, lightLevelThis.r)
|
||||
lightmap.setG(x, y, lightLevelThis.g)
|
||||
lightmap.setB(x, y, lightLevelThis.b)
|
||||
lightmap.setA(x, y, lightLevelThis.a)
|
||||
lightmap.setVec(x, y, lightLevelThis)
|
||||
}
|
||||
|
||||
// per-channel version is slower...
|
||||
private fun calculateAndAssignCh(lightmap: UnsafeCvecArray, worldX: Int, worldY: Int, channel: Int) {
|
||||
|
||||
if (inNoopMask(worldX, worldY)) return
|
||||
|
||||
// O(9n) == O(n) where n is a size of the map
|
||||
|
||||
getLightsAndShadesCh(worldX, worldY, channel)
|
||||
|
||||
val x = worldX.convX()
|
||||
val y = worldY.convY()
|
||||
|
||||
// calculate ambient
|
||||
/* + * + 0 4 1
|
||||
* * @ * 6 @ 7
|
||||
* + * + 2 5 3
|
||||
* sample ambient for eight points and apply attenuation for those
|
||||
* maxblend eight values and use it
|
||||
*/
|
||||
|
||||
// will "overwrite" what's there in the lightmap if it's the first pass
|
||||
// takes about 2 ms on 6700K
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
||||
|
||||
lightLevelThisCh = maxOf(darken(x, y - 1, thisTileOpacityCh, channel), lightLevelThisCh)
|
||||
lightLevelThisCh = maxOf(darken(x, y + 1, thisTileOpacityCh, channel), lightLevelThisCh)
|
||||
lightLevelThisCh = maxOf(darken(x - 1, y, thisTileOpacityCh, channel), lightLevelThisCh)
|
||||
lightLevelThisCh = maxOf(darken(x + 1, y, thisTileOpacityCh, channel), lightLevelThisCh)
|
||||
|
||||
lightmap.channelSet(x, y, channel, lightLevelThisCh)
|
||||
}
|
||||
|
||||
private fun isSolid(x: Int, y: Int): Float? { // ...so that they wouldn't appear too dark
|
||||
private val SOLIDMULTMAGIC_FALSE = Cvec(1f)
|
||||
private val SOLIDMULTMAGIC_TRUE = Cvec(1.2f)
|
||||
private fun isSolid(x: Int, y: Int): Cvec? { // ...so that they wouldn't appear too dark
|
||||
if (!inBounds(x, y)) return null
|
||||
|
||||
// brighten if solid
|
||||
return if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) 1.2f else 1f
|
||||
return if (BlockCodex[world.getTileFromTerrain(x, y)].isSolid) SOLIDMULTMAGIC_TRUE else SOLIDMULTMAGIC_FALSE
|
||||
}
|
||||
|
||||
var lightBuffer: Pixmap = Pixmap(1, 1, Pixmap.Format.RGBA8888)
|
||||
|
||||
private val colourNull = Cvec(0)
|
||||
private val colourNull = Cvec(0f)
|
||||
private val gdxColorNull = Color(0)
|
||||
private const val epsilon = 1f/1024f
|
||||
|
||||
@@ -990,12 +896,7 @@ object LightmapRenderer {
|
||||
val color = if (solidMultMagic == null)
|
||||
gdxColorNull
|
||||
else
|
||||
Color(
|
||||
lightmap.getR(arrayX, arrayY) * solidMultMagic,
|
||||
lightmap.getG(arrayX, arrayY) * solidMultMagic,
|
||||
lightmap.getB(arrayX, arrayY) * solidMultMagic,
|
||||
lightmap.getA(arrayX, arrayY) * solidMultMagic
|
||||
).normaliseToHDR()
|
||||
lightmap.getVec(arrayX, arrayY).times(solidMultMagic).toGdxColor().normaliseToHDR()
|
||||
|
||||
lightBuffer.setColor(color)
|
||||
|
||||
@@ -1028,7 +929,8 @@ object LightmapRenderer {
|
||||
lightmap.destroy()
|
||||
}
|
||||
|
||||
private const val lightScalingMagic = 8f
|
||||
private val lightScalingMagic = Cvec(8f)
|
||||
private val CVEC_ONE = Cvec(1f)
|
||||
|
||||
/**
|
||||
* Subtract each channel's RGB value.
|
||||
@@ -1050,30 +952,7 @@ object LightmapRenderer {
|
||||
|
||||
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull
|
||||
|
||||
return Cvec(
|
||||
lightmap.getR(x, y) * (1f - darken.r * lightScalingMagic),
|
||||
lightmap.getG(x, y) * (1f - darken.g * lightScalingMagic),
|
||||
lightmap.getB(x, y) * (1f - darken.b * lightScalingMagic),
|
||||
lightmap.getA(x, y) * (1f - darken.a * lightScalingMagic)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private fun darken(x: Int, y: Int, darken: Float, channel: Int): Float {
|
||||
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return 0f
|
||||
return lightmap.channelGet(x, y, channel) * (1f - darken * lightScalingMagic)
|
||||
}
|
||||
|
||||
/** infix is removed to clarify the association direction */
|
||||
private fun Cvec.maxAndAssign(other: Cvec): Cvec {
|
||||
// TODO investigate: if I use assignment instead of set(), it blackens like the vector branch. --Torvald, 2019-06-07
|
||||
// that was because you forgot 'this.r/g/b/a = ' part, bitch. --Torvald, 2019-06-07
|
||||
this.r = if (this.r > other.r) this.r else other.r
|
||||
this.g = if (this.g > other.g) this.g else other.g
|
||||
this.b = if (this.b > other.b) this.b else other.b
|
||||
this.a = if (this.a > other.a) this.a else other.a
|
||||
|
||||
return this
|
||||
return lightmap.getVec(x, y) * (CVEC_ONE - darken * lightScalingMagic)
|
||||
}
|
||||
|
||||
private fun Float.inv() = 1f / this
|
||||
@@ -1142,11 +1021,6 @@ object LightmapRenderer {
|
||||
hdr(this.a.coerceIn(0f, 1f))
|
||||
)
|
||||
|
||||
private fun Cvec.nonZero() = this.r.abs() > epsilon ||
|
||||
this.g.abs() > epsilon ||
|
||||
this.b.abs() > epsilon ||
|
||||
this.a.abs() > epsilon
|
||||
|
||||
val histogram: Histogram
|
||||
get() {
|
||||
val reds = IntArray(MUL) // reds[intensity] ← counts
|
||||
@@ -1226,6 +1100,5 @@ object LightmapRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
fun Cvec.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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user