mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-07 17:14:06 +09:00
Compare commits
1 Commits
newlight2
...
test-vecto
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
083ff2b466 |
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -38,7 +38,7 @@
|
|||||||
<property name="caretWidth" class="java.lang.Integer" />
|
<property name="caretWidth" class="java.lang.Integer" />
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8.0_242" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="false" project-jdk-name="15-ea" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -16,487 +16,80 @@
|
|||||||
|
|
||||||
package net.torvald.gdx.graphics
|
package net.torvald.gdx.graphics
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import jdk.incubator.vector.FloatVector
|
||||||
import com.badlogic.gdx.utils.NumberUtils
|
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
|
* 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.
|
* 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.
|
* 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
|
constructor(floatArray: FloatArray) : this(FloatVector.fromArray(SPECIES, floatArray, 0))
|
||||||
* internal values after execution.
|
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))
|
||||||
* @author mzechner
|
constructor() : this(FloatVector.zero(SPECIES))
|
||||||
*/
|
constructor(rgba8888: Int) : this(FloatVector.fromValues(SPECIES,
|
||||||
class Cvec {
|
((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 */
|
companion object {
|
||||||
var r: Float = 0.toFloat()
|
private val EPSILON = 1f / 1024f
|
||||||
var g: Float = 0.toFloat()
|
private val SPECIES = FloatVector.SPECIES_128
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(color: Color) {
|
//fun cpy(): Cvec = Cvec(this.vec)
|
||||||
this.r = color.r
|
|
||||||
this.g = color.g
|
|
||||||
this.b = color.b
|
|
||||||
this.a = color.a
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Constructor, sets the components of the color
|
// not using shorthand names to prevent confusion with builtin functions
|
||||||
*
|
|
||||||
* @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
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Constructs a new color using the given color
|
fun multiply(other: FloatVector) = Cvec(vec.mul(other))
|
||||||
*
|
infix operator fun times(other: Cvec) = multiply(other.vec)
|
||||||
* @param color the color
|
//infix operator fun times(scalar: Float) = Cvec(vec.mul(scalar))
|
||||||
*/
|
|
||||||
constructor(color: Cvec) {
|
fun subtract(other: FloatVector) = Cvec(vec.sub(other))
|
||||||
set(color)
|
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:
|
* true if at least one element in the vector is not zero.
|
||||||
* - 0: R
|
|
||||||
* - 1: G
|
|
||||||
* - 2: B
|
|
||||||
* - 3: A
|
|
||||||
*/
|
*/
|
||||||
fun getElem(index: Int) = when(index) {
|
fun nonZero(): Boolean = vec.reduceLanes(VectorOperators.MUL) != 0f //vec.toArray().fold(false) { acc, fl -> acc or (fl.absoluteValue >= EPSILON) }
|
||||||
0 -> r
|
|
||||||
1 -> g
|
fun toRGBA8888(): Int {
|
||||||
2 -> b
|
var acc = 0
|
||||||
3 -> a
|
for (i in 0..3)
|
||||||
else -> throw IndexOutOfBoundsException("Invalid index $index")
|
acc += vec.lane(i).coerceIn(0f, 1f).times(255f).roundToInt().shl(8 * (3 - i))
|
||||||
|
|
||||||
|
return acc
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets this color to the given color.
|
/*override fun equals(other: Any?): Boolean {
|
||||||
*
|
return this.vec.equal((other as Cvec).vec).allTrue()
|
||||||
* @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
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Multiplies the this color and the given color
|
fun toGdxColor() = com.badlogic.gdx.graphics.Color(
|
||||||
*
|
vec.lane(0),
|
||||||
* @param color the color
|
vec.lane(1),
|
||||||
* @return this color.
|
vec.lane(2),
|
||||||
*/
|
vec.lane(3)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,13 @@ import net.torvald.UnsafeHelper
|
|||||||
*/
|
*/
|
||||||
internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
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)
|
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)
|
fun zerofill() = array.fillWith(0)
|
||||||
|
|
||||||
@@ -24,35 +26,21 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
|||||||
zerofill()
|
zerofill()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getR(x: Int, y: Int) = array.getFloat(toAddr(x, y))
|
fun getVec(x: Int, y: Int): Cvec {
|
||||||
fun getG(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 4)
|
val addr = toAddr(x, y)
|
||||||
fun getB(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 8)
|
return Cvec(
|
||||||
fun getA(x: Int, y: Int) = array.getFloat(toAddr(x, y) + 12)
|
array.getFloat(addr),
|
||||||
|
array.getFloat(addr + 4),
|
||||||
fun setR(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y), value) }
|
array.getFloat(addr + 8),
|
||||||
fun setG(x: Int, y: Int, value: Float) { array.setFloat(toAddr(x, y) + 4, value) }
|
array.getFloat(addr + 12)
|
||||||
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 setVec(x: Int, y: Int, value: Cvec) {
|
||||||
/**
|
val addr = toAddr(x, y)
|
||||||
* @param channel 0 for R, 1 for G, 2 for B, 3 for A
|
array.setFloat(addr, value.vec.lane(0))
|
||||||
*/
|
array.setFloat(addr + 4, value.vec.lane(1))
|
||||||
inline fun channelGet(x: Int, y: Int, channel: Int) = array.getFloat(toAddr(x, y) + 4L * channel)
|
array.setFloat(addr + 8, value.vec.lane(2))
|
||||||
|
array.setFloat(addr + 12, value.vec.lane(3))
|
||||||
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 destroy() = this.array.destroy()
|
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, 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 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 {
|
override fun toString(): String {
|
||||||
val sb = StringBuilder()
|
val sb = StringBuilder()
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ object BlockCodex {
|
|||||||
prop.baseLumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColG = floatVal(record, "lumg") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.baseLumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
prop.baseLumColB = floatVal(record, "lumb") / LightmapRenderer.MUL_FLOAT
|
||||||
prop.baseLumColA = floatVal(record, "lumuv") / 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.friction = intVal(record, "fr")
|
||||||
prop.viscosity = intVal(record, "vscs")
|
prop.viscosity = intVal(record, "vscs")
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class BlockProp {
|
|||||||
var shadeColB = 0f
|
var shadeColB = 0f
|
||||||
var shadeColA = 0f
|
var shadeColA = 0f
|
||||||
|
|
||||||
lateinit var opacity: Cvec
|
var opacity: Cvec = Cvec(0f)
|
||||||
|
|
||||||
fun getOpacity(channel: Int) = when (channel) {
|
fun getOpacity(channel: Int) = when (channel) {
|
||||||
0 -> shadeColR
|
0 -> shadeColR
|
||||||
@@ -51,12 +51,12 @@ class BlockProp {
|
|||||||
internal var baseLumColG = 0f // base value used to calculate dynamic luminosity
|
internal var baseLumColG = 0f // base value used to calculate dynamic luminosity
|
||||||
internal var baseLumColB = 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 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 lumColR = 0f // memoised value of dynamic luminosity
|
||||||
//var lumColG = 0f // memoised value of dynamic luminosity
|
//var lumColG = 0f // memoised value of dynamic luminosity
|
||||||
//var lumColB = 0f // memoised value of dynamic luminosity
|
//var lumColB = 0f // memoised value of dynamic luminosity
|
||||||
//var lumColA = 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())
|
// X- and Y-value must be treated properly beforehand! (use GameWorld.coerceXY())
|
||||||
fun getLumCol(x: Int, y: Int) = if (dynamicLuminosityFunction == 0) {
|
fun getLumCol(x: Int, y: Int) = if (dynamicLuminosityFunction == 0) {
|
||||||
baseLumCol
|
baseLumCol
|
||||||
@@ -65,12 +65,6 @@ class BlockProp {
|
|||||||
BlockCodex[BlockCodex.dynamicToVirtualMap[id]!! - offset]._lumCol
|
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
|
* @param luminosity
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ object BlockPropUtil {
|
|||||||
prop.rngBase2 = getNewRandom()
|
prop.rngBase2 = getNewRandom()
|
||||||
}
|
}
|
||||||
|
|
||||||
prop._lumCol.set(getDynamicLumFunc(prop))
|
prop._lumCol = getDynamicLumFunc(prop)
|
||||||
//prop.lumColR = prop.lumCol.r
|
//prop.lumColR = prop.lumCol.r
|
||||||
//prop.lumColG = prop.lumCol.g
|
//prop.lumColG = prop.lumCol.g
|
||||||
//prop.lumColB = prop.lumCol.b
|
//prop.lumColB = prop.lumCol.b
|
||||||
@@ -111,8 +111,8 @@ object BlockPropUtil {
|
|||||||
private fun getDynamicLumFunc(prop: BlockProp): Cvec {
|
private fun getDynamicLumFunc(prop: BlockProp): Cvec {
|
||||||
return when (prop.dynamicLuminosityFunction) {
|
return when (prop.dynamicLuminosityFunction) {
|
||||||
1 -> getTorchFlicker(prop)
|
1 -> getTorchFlicker(prop)
|
||||||
2 -> (Terrarum.ingame!!.world).globalLight.cpy().mul(LightmapRenderer.DIV_FLOAT) // current global light
|
2 -> (Terrarum.ingame!!.world).globalLight * LightmapRenderer.DIV_FLOAT_VEC // current global light
|
||||||
3 -> WeatherMixer.getGlobalLightOfTime(Terrarum.ingame!!.world, WorldTime.DAY_LENGTH / 2).cpy().mul(LightmapRenderer.DIV_FLOAT) // daylight at noon
|
3 -> WeatherMixer.getGlobalLightOfTime(Terrarum.ingame!!.world, WorldTime.DAY_LENGTH / 2) * LightmapRenderer.DIV_FLOAT_VEC // daylight at noon
|
||||||
4 -> getSlowBreath(prop)
|
4 -> getSlowBreath(prop)
|
||||||
5 -> getPulsate(prop)
|
5 -> getPulsate(prop)
|
||||||
else -> prop.baseLumCol
|
else -> prop.baseLumCol
|
||||||
@@ -141,11 +141,6 @@ object BlockPropUtil {
|
|||||||
* @return processed colour
|
* @return processed colour
|
||||||
*/
|
*/
|
||||||
private fun alterBrightnessUniform(data: Cvec, brighten: Float): Cvec {
|
private fun alterBrightnessUniform(data: Cvec, brighten: Float): Cvec {
|
||||||
return Cvec(
|
return data + Cvec(brighten)
|
||||||
data.r + brighten,
|
|
||||||
data.g + brighten,
|
|
||||||
data.b + brighten,
|
|
||||||
data.a + brighten
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,10 +74,10 @@ open class ActorHumanoid(
|
|||||||
(actorValue.getAsFloat(AVKey.LUMA) ?: 0f) / LightmapRenderer.MUL_FLOAT
|
(actorValue.getAsFloat(AVKey.LUMA) ?: 0f) / LightmapRenderer.MUL_FLOAT
|
||||||
)
|
)
|
||||||
set(value) {
|
set(value) {
|
||||||
actorValue[AVKey.LUMR] = value.r * LightmapRenderer.MUL_FLOAT
|
actorValue[AVKey.LUMR] = value.vec.lane(0) * LightmapRenderer.MUL_FLOAT
|
||||||
actorValue[AVKey.LUMG] = value.g * LightmapRenderer.MUL_FLOAT
|
actorValue[AVKey.LUMG] = value.vec.lane(1) * LightmapRenderer.MUL_FLOAT
|
||||||
actorValue[AVKey.LUMB] = value.b * LightmapRenderer.MUL_FLOAT
|
actorValue[AVKey.LUMB] = value.vec.lane(2) * LightmapRenderer.MUL_FLOAT
|
||||||
actorValue[AVKey.LUMA] = value.a * LightmapRenderer.MUL_FLOAT
|
actorValue[AVKey.LUMA] = value.vec.lane(3) * LightmapRenderer.MUL_FLOAT
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ open class ProjectileSimple(
|
|||||||
|
|
||||||
|
|
||||||
override var color: Cvec
|
override var color: Cvec
|
||||||
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Cvec).cpy()
|
get() = (bulletDatabase[type][OFFSET_LUMINOSITY] as Cvec)
|
||||||
set(value) {
|
set(value) {
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
lateinit var mixedWeather: BaseModularWeather
|
lateinit var mixedWeather: BaseModularWeather
|
||||||
|
|
||||||
val globalLightNow = Cvec(0)
|
var globalLightNow = Cvec(0f)
|
||||||
|
|
||||||
// Weather indices
|
// Weather indices
|
||||||
const val WEATHER_GENERIC = "generic"
|
const val WEATHER_GENERIC = "generic"
|
||||||
@@ -133,7 +133,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
|
|
||||||
// calculate global light
|
// calculate global light
|
||||||
val globalLight = getGradientColour(world, skyboxColourMap, 2, timeNow)
|
val globalLight = getGradientColour(world, skyboxColourMap, 2, timeNow)
|
||||||
globalLightNow.set(globalLight)
|
globalLightNow = globalLight
|
||||||
|
|
||||||
|
|
||||||
/* (copied from the shader source)
|
/* (copied from the shader source)
|
||||||
@@ -250,7 +250,7 @@ internal object WeatherMixer : RNGConsumer {
|
|||||||
" | ${colourThis.toStringRGB()} -[${scale.times(100).toInt()}%]-> ${colourNext.toStringRGB()}" +
|
" | ${colourThis.toStringRGB()} -[${scale.times(100).toInt()}%]-> ${colourNext.toStringRGB()}" +
|
||||||
" | * `$r`$g`$b`")*/
|
" | * `$r`$g`$b`")*/
|
||||||
|
|
||||||
return Cvec(newCol)
|
return Cvec(newCol.r, newCol.g, newCol.b, newCol.a)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getWeatherList(classification: String) = weatherList[classification]!!
|
fun getWeatherList(classification: String) = weatherList[classification]!!
|
||||||
|
|||||||
@@ -146,10 +146,10 @@ class BasicDebugInfoWindow : UICanvas() {
|
|||||||
val mtX = mouseTileX.toString()
|
val mtX = mouseTileX.toString()
|
||||||
val mtY = mouseTileY.toString()
|
val mtY = mouseTileY.toString()
|
||||||
val valRaw = LightmapRenderer.getLight(mouseTileX, mouseTileY)
|
val valRaw = LightmapRenderer.getLight(mouseTileX, mouseTileY)
|
||||||
val rawR = valRaw?.r?.times(100f)?.round()?.div(100f)
|
val rawR = valRaw?.vec?.lane(0)?.times(100f)?.round()?.div(100f)
|
||||||
val rawG = valRaw?.g?.times(100f)?.round()?.div(100f)
|
val rawG = valRaw?.vec?.lane(1)?.times(100f)?.round()?.div(100f)
|
||||||
val rawB = valRaw?.b?.times(100f)?.round()?.div(100f)
|
val rawB = valRaw?.vec?.lane(2)?.times(100f)?.round()?.div(100f)
|
||||||
val rawA = valRaw?.a?.times(100f)?.round()?.div(100f)
|
val rawA = valRaw?.vec?.lane(3)?.times(100f)?.round()?.div(100f)
|
||||||
|
|
||||||
lightVal = if (valRaw == null) "$EMDASH"
|
lightVal = if (valRaw == null) "$EMDASH"
|
||||||
else "$rawR $rawG $rawB $rawA"
|
else "$rawR $rawG $rawB $rawA"
|
||||||
|
|||||||
@@ -122,7 +122,9 @@ object LightmapRenderer {
|
|||||||
const val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat()
|
const val CHANNEL_MAX_FLOAT = CHANNEL_MAX.toFloat()
|
||||||
const val COLOUR_RANGE_SIZE = MUL * MUL_2
|
const val COLOUR_RANGE_SIZE = MUL * MUL_2
|
||||||
const val MUL_FLOAT = MUL / 256f
|
const val MUL_FLOAT = MUL / 256f
|
||||||
|
val MUL_FLOAT_VEC = Cvec(MUL_FLOAT)
|
||||||
const val DIV_FLOAT = 256f / MUL
|
const val DIV_FLOAT = 256f / MUL
|
||||||
|
val DIV_FLOAT_VEC = Cvec(DIV_FLOAT)
|
||||||
|
|
||||||
internal var for_x_start = 0
|
internal var for_x_start = 0
|
||||||
internal var for_y_start = 0
|
internal var for_y_start = 0
|
||||||
@@ -159,12 +161,7 @@ object LightmapRenderer {
|
|||||||
val x = x.convX()
|
val x = x.convX()
|
||||||
val y = y.convY()
|
val y = y.convY()
|
||||||
|
|
||||||
return Cvec(
|
return lightmap.getVec(x, y) * MUL_FLOAT_VEC
|
||||||
lightmap.getR(x, y) * MUL_FLOAT,
|
|
||||||
lightmap.getG(x, y) * MUL_FLOAT,
|
|
||||||
lightmap.getB(x, y) * MUL_FLOAT,
|
|
||||||
lightmap.getA(x, y) * MUL_FLOAT
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +218,7 @@ object LightmapRenderer {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// set sunlight
|
// 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
|
// set no-op mask from solidity of the block
|
||||||
AppLoader.measureDebugTime("Renderer.LightNoOpMask") {
|
AppLoader.measureDebugTime("Renderer.LightNoOpMask") {
|
||||||
@@ -506,7 +503,7 @@ object LightmapRenderer {
|
|||||||
*
|
*
|
||||||
* @return true if skip
|
* @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()
|
val lx = wx.convX(); val ly = wy.convY()
|
||||||
|
|
||||||
if (lx !in 0 until LIGHTMAP_WIDTH || ly !in 0 until LIGHTMAP_HEIGHT)
|
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
|
if (inNoopMask(worldX, worldY)) return false
|
||||||
|
|
||||||
// just quick snippets to make test work
|
// just quick snippets to make test work
|
||||||
lightLevelThis.set(colourNull)
|
thisTileOpacity = BlockCodex[world.getTileFromTerrain(worldX, worldY)].opacity
|
||||||
thisTileOpacity.set(BlockCodex[world.getTileFromTerrain(worldX, worldY)].opacity)
|
|
||||||
|
|
||||||
val x = worldX.convX()
|
val x = worldX.convX()
|
||||||
val y = worldY.convY()
|
val y = worldY.convY()
|
||||||
|
|
||||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
lightLevelThis = lightLevelThis max
|
||||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
/* + *///darkenColoured(x - 1, y - 1, thisTileOpacity2) max
|
||||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
/* + *///darkenColoured(x + 1, y - 1, thisTileOpacity2) max
|
||||||
/* + *///lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
/* + *///darkenColoured(x - 1, y + 1, thisTileOpacity2) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
|
/* + *///darkenColoured(x + 1, y + 1, thisTileOpacity2) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
|
/* * */darkenColoured(x, y - 1, thisTileOpacity) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
|
/* * */darkenColoured(x, y + 1, thisTileOpacity) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
|
/* * */darkenColoured(x - 1, y, thisTileOpacity) max
|
||||||
|
/* * */darkenColoured(x + 1, y, thisTileOpacity)
|
||||||
|
|
||||||
lightmap.setR(x, y, lightLevelThis.r)
|
lightmap.setVec(x, y, lightLevelThis)
|
||||||
lightmap.setG(x, y, lightLevelThis.g)
|
|
||||||
lightmap.setB(x, y, lightLevelThis.b)
|
|
||||||
lightmap.setA(x, y, lightLevelThis.a)
|
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
// TODO re-init at every resize
|
// TODO re-init at every resize
|
||||||
@@ -677,12 +671,12 @@ object LightmapRenderer {
|
|||||||
|
|
||||||
|
|
||||||
private val ambientAccumulator = Cvec(0f,0f,0f,0f)
|
private val ambientAccumulator = Cvec(0f,0f,0f,0f)
|
||||||
private val lightLevelThis = Cvec(0)
|
private var lightLevelThis = Cvec(0f)
|
||||||
private val fluidAmountToCol = Cvec(0)
|
private var fluidAmountToCol = Cvec(0f)
|
||||||
private val thisTileLuminosity = Cvec(0)
|
private var thisTileLuminosity = Cvec(0f)
|
||||||
private val thisTileOpacity = Cvec(0)
|
private var thisTileOpacity = Cvec(0f)
|
||||||
private val thisTileOpacity2 = Cvec(0) // thisTileOpacity * sqrt(2)
|
private var thisTileOpacity2 = Cvec(0f) // thisTileOpacity * sqrt(2)
|
||||||
private val sunLight = Cvec(0)
|
private var sunLight = Cvec(0f)
|
||||||
private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
private var thisFluid = GameWorld.FluidInfo(Fluid.NULL, 0f)
|
||||||
private var thisTerrain = 0
|
private var thisTerrain = 0
|
||||||
private var thisWall = 0
|
private var thisWall = 0
|
||||||
@@ -694,6 +688,8 @@ object LightmapRenderer {
|
|||||||
private var thisTileOpacityCh = 0f
|
private var thisTileOpacityCh = 0f
|
||||||
private var thisTileOpacity2Ch = 0f
|
private var thisTileOpacity2Ch = 0f
|
||||||
|
|
||||||
|
private val SQRT2_VEC = Cvec(1.41421356f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function will alter following variables:
|
* This function will alter following variables:
|
||||||
* - lightLevelThis
|
* - lightLevelThis
|
||||||
@@ -708,7 +704,7 @@ object LightmapRenderer {
|
|||||||
private fun getLightsAndShades(x: Int, y: Int) {
|
private fun getLightsAndShades(x: Int, y: Int) {
|
||||||
val (x, y) = world.coerceXY(x, y)
|
val (x, y) = world.coerceXY(x, y)
|
||||||
|
|
||||||
lightLevelThis.set(colourNull)
|
lightLevelThis = colourNull
|
||||||
thisTerrain = world.getTileFromTerrainRaw(x, y)
|
thisTerrain = world.getTileFromTerrainRaw(x, y)
|
||||||
thisFluid = world.getFluid(x, y)
|
thisFluid = world.getFluid(x, y)
|
||||||
thisWall = world.getTileFromWallRaw(x, y)
|
thisWall = world.getTileFromWallRaw(x, y)
|
||||||
@@ -736,84 +732,29 @@ object LightmapRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (thisFluid.type != Fluid.NULL) {
|
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 = BlockCodex[thisTerrain].getLumCol(x, y) max
|
||||||
thisTileLuminosity.maxAndAssign(BlockCodex[thisFluid.type].getLumCol(x, y).mul(fluidAmountToCol)) // already been div by four
|
(BlockCodex[thisFluid.type].getLumCol(x, y) * fluidAmountToCol) // already been div by four
|
||||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
thisTileOpacity = BlockCodex[thisTerrain].opacity max
|
||||||
thisTileOpacity.maxAndAssign(BlockCodex[thisFluid.type].opacity.mul(fluidAmountToCol)) // already been div by four
|
(BlockCodex[thisFluid.type].opacity * fluidAmountToCol) // already been div by four
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
thisTileLuminosity.set(BlockCodex[thisTerrain].getLumCol(x, y))
|
thisTileLuminosity = BlockCodex[thisTerrain].getLumCol(x, y)
|
||||||
thisTileOpacity.set(BlockCodex[thisTerrain].opacity)
|
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()
|
//sunLight.set(world.globalLight); sunLight.mul(DIV_FLOAT) // moved to fireRecalculateEvent()
|
||||||
|
|
||||||
|
|
||||||
// open air || luminous tile backed by sunlight
|
// open air || luminous tile backed by sunlight
|
||||||
if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosity.nonZero() && thisWall == AIR)) {
|
if ((thisTerrain == AIR && thisWall == AIR) || (thisTileLuminosity.nonZero() && thisWall == AIR)) {
|
||||||
lightLevelThis.set(sunLight)
|
lightLevelThis = sunLight
|
||||||
}
|
}
|
||||||
|
|
||||||
// blend lantern
|
// blend lantern
|
||||||
lightLevelThis.maxAndAssign(thisTileLuminosity).maxAndAssign(lanternMap[LandUtil.getBlockAddr(world, x, y)] ?: colourNull)
|
lightLevelThis = lightLevelThis max thisTileLuminosity max (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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val inNoopMaskp = Point2i(0,0)
|
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
|
// will "overwrite" what's there in the lightmap if it's the first pass
|
||||||
// takes about 2 ms on 6700K
|
// takes about 2 ms on 6700K
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y - 1, thisTileOpacity2))
|
lightLevelThis = lightLevelThis max
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y - 1, thisTileOpacity2))
|
/* + */darkenColoured(x - 1, y - 1, thisTileOpacity2) max
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y + 1, thisTileOpacity2))
|
/* + */darkenColoured(x + 1, y - 1, thisTileOpacity2) max
|
||||||
/* + */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y + 1, thisTileOpacity2))
|
/* + */darkenColoured(x - 1, y + 1, thisTileOpacity2) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y - 1, thisTileOpacity))
|
/* + */darkenColoured(x + 1, y + 1, thisTileOpacity2) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x, y + 1, thisTileOpacity))
|
/* * */darkenColoured(x, y - 1, thisTileOpacity) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x - 1, y, thisTileOpacity))
|
/* * */darkenColoured(x, y + 1, thisTileOpacity) max
|
||||||
/* * */lightLevelThis.maxAndAssign(darkenColoured(x + 1, y, thisTileOpacity))
|
/* * */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
|
//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.cpy())
|
||||||
|
|
||||||
lightmap.setR(x, y, lightLevelThis.r)
|
lightmap.setVec(x, y, lightLevelThis)
|
||||||
lightmap.setG(x, y, lightLevelThis.g)
|
|
||||||
lightmap.setB(x, y, lightLevelThis.b)
|
|
||||||
lightmap.setA(x, y, lightLevelThis.a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// per-channel version is slower...
|
private val SOLIDMULTMAGIC_FALSE = Cvec(1f)
|
||||||
private fun calculateAndAssignCh(lightmap: UnsafeCvecArray, worldX: Int, worldY: Int, channel: Int) {
|
private val SOLIDMULTMAGIC_TRUE = Cvec(1.2f)
|
||||||
|
private fun isSolid(x: Int, y: Int): Cvec? { // ...so that they wouldn't appear too dark
|
||||||
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
|
|
||||||
if (!inBounds(x, y)) return null
|
if (!inBounds(x, y)) return null
|
||||||
|
|
||||||
// brighten if solid
|
// 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)
|
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 val gdxColorNull = Color(0)
|
||||||
private const val epsilon = 1f/1024f
|
private const val epsilon = 1f/1024f
|
||||||
|
|
||||||
@@ -990,12 +896,7 @@ object LightmapRenderer {
|
|||||||
val color = if (solidMultMagic == null)
|
val color = if (solidMultMagic == null)
|
||||||
gdxColorNull
|
gdxColorNull
|
||||||
else
|
else
|
||||||
Color(
|
lightmap.getVec(arrayX, arrayY).times(solidMultMagic).toGdxColor().normaliseToHDR()
|
||||||
lightmap.getR(arrayX, arrayY) * solidMultMagic,
|
|
||||||
lightmap.getG(arrayX, arrayY) * solidMultMagic,
|
|
||||||
lightmap.getB(arrayX, arrayY) * solidMultMagic,
|
|
||||||
lightmap.getA(arrayX, arrayY) * solidMultMagic
|
|
||||||
).normaliseToHDR()
|
|
||||||
|
|
||||||
lightBuffer.setColor(color)
|
lightBuffer.setColor(color)
|
||||||
|
|
||||||
@@ -1028,7 +929,8 @@ object LightmapRenderer {
|
|||||||
lightmap.destroy()
|
lightmap.destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val lightScalingMagic = 8f
|
private val lightScalingMagic = Cvec(8f)
|
||||||
|
private val CVEC_ONE = Cvec(1f)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtract each channel's RGB value.
|
* 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
|
if (x !in 0 until LIGHTMAP_WIDTH || y !in 0 until LIGHTMAP_HEIGHT) return colourNull
|
||||||
|
|
||||||
return Cvec(
|
return lightmap.getVec(x, y) * (CVEC_ONE - darken * lightScalingMagic)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Float.inv() = 1f / this
|
private fun Float.inv() = 1f / this
|
||||||
@@ -1142,11 +1021,6 @@ object LightmapRenderer {
|
|||||||
hdr(this.a.coerceIn(0f, 1f))
|
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
|
val histogram: Histogram
|
||||||
get() {
|
get() {
|
||||||
val reds = IntArray(MUL) // reds[intensity] ← counts
|
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()
|
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