mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-15 10:25:06 -04:00
color tests, some fixes
This commit is contained in:
parent
59ddd7fe5e
commit
6fd062d19d
@ -100,7 +100,7 @@ open class TextComponent(
|
|||||||
override val legacy: String
|
override val legacy: String
|
||||||
get() {
|
get() {
|
||||||
val builder = StringBuilder()
|
val builder = StringBuilder()
|
||||||
ChatColors.getChar(color?.rgb())?.let { builder.append(ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX).append(it) }
|
ChatColors.getChar(color)?.let { builder.append(ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX).append(it) }
|
||||||
for (formattingCode in this.formatting) {
|
for (formattingCode in this.formatting) {
|
||||||
builder.append(ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX)
|
builder.append(ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX)
|
||||||
builder.append(formattingCode.char)
|
builder.append(formattingCode.char)
|
||||||
|
@ -49,10 +49,8 @@ object ChatColors {
|
|||||||
|
|
||||||
var index = 0
|
var index = 0
|
||||||
for (field in this::class.java.declaredFields) {
|
for (field in this::class.java.declaredFields) {
|
||||||
val color = field.get(null)
|
if (field.type != Int::class.java) continue // inlined datatype
|
||||||
if (color !is RGBAColor) {
|
val color = RGBAColor(field.getInt(null))
|
||||||
continue
|
|
||||||
}
|
|
||||||
VALUES[index] = color
|
VALUES[index] = color
|
||||||
CHAR_MAP[color] = index
|
CHAR_MAP[color] = index
|
||||||
nameMap[field.name.lowercase()] = color
|
nameMap[field.name.lowercase()] = color
|
||||||
@ -60,6 +58,7 @@ object ChatColors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NAME_MAP = nameMap
|
NAME_MAP = nameMap
|
||||||
|
if (NAME_MAP.size != 16) throw IllegalStateException("No colors found?")
|
||||||
|
|
||||||
CHAR_MAP.defaultReturnValue(-1)
|
CHAR_MAP.defaultReturnValue(-1)
|
||||||
}
|
}
|
||||||
@ -72,14 +71,12 @@ object ChatColors {
|
|||||||
return VALUES.getOrNull(id)
|
return VALUES.getOrNull(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(name: String): RGBAColor? {
|
operator fun get(name: String) = when (name) {
|
||||||
return when (name) {
|
|
||||||
"dark_grey" -> DARK_GRAY
|
"dark_grey" -> DARK_GRAY
|
||||||
else -> NAME_MAP[name]
|
else -> NAME_MAP[name]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun getChar(color: RGBColor?): String? {
|
fun getChar(color: RGBAColor?): String? {
|
||||||
if (color == null) return null
|
if (color == null) return null
|
||||||
val char = CHAR_MAP.getInt(color)
|
val char = CHAR_MAP.getInt(color)
|
||||||
if (char < 0) return null
|
if (char < 0) return null
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
package de.bixilon.minosoft.data.text.formatting.color
|
package de.bixilon.minosoft.data.text.formatting.color
|
||||||
|
|
||||||
|
import de.bixilon.kotlinglm.func.common.clamp
|
||||||
import de.bixilon.kutil.ansi.ANSI
|
import de.bixilon.kutil.ansi.ANSI
|
||||||
|
|
||||||
interface Color {
|
interface Color {
|
||||||
@ -40,6 +41,8 @@ interface Color {
|
|||||||
const val TIMES = VALUES * VALUES
|
const val TIMES = VALUES * VALUES
|
||||||
|
|
||||||
|
|
||||||
|
fun Int.clamp() = this.clamp(MIN, MAX)
|
||||||
|
|
||||||
fun toFloat(value: Int) = value * (1.0f / MAX)
|
fun toFloat(value: Int) = value * (1.0f / MAX)
|
||||||
fun fromFloat(value: Float) = (value * MAX).toInt()
|
fun fromFloat(value: Float) = (value * MAX).toInt()
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.text.formatting.color
|
|||||||
|
|
||||||
import de.bixilon.kotlinglm.vec3.Vec3
|
import de.bixilon.kotlinglm.vec3.Vec3
|
||||||
import de.bixilon.kotlinglm.vec4.Vec4
|
import de.bixilon.kotlinglm.vec4.Vec4
|
||||||
|
import de.bixilon.kutil.primitive.IntUtil.toHex
|
||||||
import de.bixilon.minosoft.data.text.ChatComponent
|
import de.bixilon.minosoft.data.text.ChatComponent
|
||||||
import de.bixilon.minosoft.data.text.TextComponent
|
import de.bixilon.minosoft.data.text.TextComponent
|
||||||
import de.bixilon.minosoft.data.text.formatting.TextFormattable
|
import de.bixilon.minosoft.data.text.formatting.TextFormattable
|
||||||
@ -22,13 +23,14 @@ import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.BITS
|
|||||||
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.MASK
|
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.MASK
|
||||||
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.MAX
|
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.MAX
|
||||||
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.TIMES
|
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.TIMES
|
||||||
|
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.clamp
|
||||||
|
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class RGBAColor(val argb: Int) : Color, TextFormattable {
|
value class RGBAColor(val argb: Int) : Color, TextFormattable {
|
||||||
|
|
||||||
constructor(red: Int, green: Int, blue: Int) : this(red, green, blue, MAX)
|
constructor(red: Int, green: Int, blue: Int) : this(red, green, blue, MAX)
|
||||||
constructor(red: Int, green: Int, blue: Int, alpha: Int) : this(((alpha and MASK) shl ALPHA_SHIFT) or ((red and MASK) shl RED_SHIFT) or ((green and MASK) shl GREEN_SHIFT) or ((blue and MASK) shl BLUE_SHIFT))
|
constructor(red: Int, green: Int, blue: Int, alpha: Int) : this(((alpha.clamp() and MASK) shl ALPHA_SHIFT) or ((red.clamp() and MASK) shl RED_SHIFT) or ((green.clamp() and MASK) shl GREEN_SHIFT) or ((blue.clamp() and MASK) shl BLUE_SHIFT))
|
||||||
|
|
||||||
constructor(red: Float, green: Float, blue: Float) : this(Color.fromFloat(red), Color.fromFloat(green), Color.fromFloat(blue))
|
constructor(red: Float, green: Float, blue: Float) : this(Color.fromFloat(red), Color.fromFloat(green), Color.fromFloat(blue))
|
||||||
constructor(red: Float, green: Float, blue: Float, alpha: Float) : this(Color.fromFloat(red), Color.fromFloat(green), Color.fromFloat(blue), Color.fromFloat(alpha))
|
constructor(red: Float, green: Float, blue: Float, alpha: Float) : this(Color.fromFloat(red), Color.fromFloat(green), Color.fromFloat(blue), Color.fromFloat(alpha))
|
||||||
@ -73,11 +75,15 @@ value class RGBAColor(val argb: Int) : Color, TextFormattable {
|
|||||||
fun toVec4() = Vec4(redf, greenf, bluef, alphaf)
|
fun toVec4() = Vec4(redf, greenf, bluef, alphaf)
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return if (alpha != MAX) {
|
val builder = StringBuilder(9)
|
||||||
String.format("#%08X", rgba)
|
builder.append('#')
|
||||||
} else {
|
builder.append(red.toHex(2))
|
||||||
String.format("#%06X", rgb)
|
builder.append(green.toHex(2))
|
||||||
|
builder.append(blue.toHex(2))
|
||||||
|
if (alpha != MAX) {
|
||||||
|
builder.append(alpha.toHex(2))
|
||||||
}
|
}
|
||||||
|
return builder.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toText(): ChatComponent {
|
override fun toText(): ChatComponent {
|
||||||
@ -93,7 +99,7 @@ value class RGBAColor(val argb: Int) : Color, TextFormattable {
|
|||||||
|
|
||||||
fun Vec4.color() = RGBAColor(r, g, b, a)
|
fun Vec4.color() = RGBAColor(r, g, b, a)
|
||||||
|
|
||||||
inline fun Int.rgba() = RGBAColor(this shl BITS or (this ushr (BITS * 3)))
|
inline fun Int.rgba() = RGBAColor(this shr BITS or (this and BITS shl (BITS * 3)))
|
||||||
inline fun Int.argb() = RGBColor(this)
|
inline fun Int.argb() = RGBColor(this)
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class RGB8Buffer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun setRGB(x: Int, y: Int, value: RGBColor) = setRGB(x, y, value.red, value.green, value.blue)
|
override fun setRGB(x: Int, y: Int, value: RGBColor) = setRGB(x, y, value.red, value.green, value.blue)
|
||||||
override fun setRGBA(x: Int, y: Int, value: RGBAColor) = setRGBA(x, y, value.red, value.green, value.blue, value.alpha)
|
override fun setRGBA(x: Int, y: Int, value: RGBAColor) = setRGB(x, y, value.red, value.green, value.blue)
|
||||||
|
|
||||||
override fun copy() = RGB8Buffer(Vec2i(size), data.duplicate())
|
override fun copy() = RGB8Buffer(Vec2i(size), data.duplicate())
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ class RGBA8Buffer(
|
|||||||
|
|
||||||
override fun getRGBA(x: Int, y: Int): RGBAColor {
|
override fun getRGBA(x: Int, y: Int): RGBAColor {
|
||||||
val stride = stride(x, y)
|
val stride = stride(x, y)
|
||||||
return RGBAColor(this[stride + 0], this[stride + 1], this[stride + 2], this[stride + 3] shl 0)
|
return RGBAColor(this[stride + 0], this[stride + 1], this[stride + 2], this[stride + 3])
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRGB(x: Int, y: Int): RGBColor {
|
override fun getRGB(x: Int, y: Int): RGBColor {
|
||||||
|
@ -111,7 +111,7 @@ object TextureUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdirParent()
|
file.mkdirParent()
|
||||||
|
|
||||||
ImageIO.write(bufferedImage, "png", file)
|
ImageIO.write(bufferedImage, "png", file)
|
||||||
}
|
}
|
||||||
|
@ -334,9 +334,9 @@ internal class ChatComponentTest {
|
|||||||
private fun assertEquals(expected: ChatComponent, actual: ChatComponent) {
|
private fun assertEquals(expected: ChatComponent, actual: ChatComponent) {
|
||||||
when (expected) {
|
when (expected) {
|
||||||
is BaseComponent -> {
|
is BaseComponent -> {
|
||||||
if (actual !is BaseComponent) throw AssertionFailedError("Type mismatch", "BaseComponent", actual::class.java.name)
|
if (actual !is BaseComponent) assert("Type mismatch", "BaseComponent", actual::class.java.name)
|
||||||
|
|
||||||
if (expected.parts.size != actual.parts.size) throw AssertionFailedError("Count of parts does not match", expected.parts, actual.parts)
|
if (expected.parts.size != actual.parts.size) assert("Count of parts does not match", expected.parts, actual.parts)
|
||||||
|
|
||||||
for (index in expected.parts.indices) {
|
for (index in expected.parts.indices) {
|
||||||
val first = expected.parts[index]
|
val first = expected.parts[index]
|
||||||
@ -347,20 +347,20 @@ internal class ChatComponentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is TextComponent -> {
|
is TextComponent -> {
|
||||||
if (actual !is TextComponent) throw AssertionFailedError("Type mismatch", "TextComponent", actual::class.java.name)
|
if (actual !is TextComponent) assert("Type mismatch", "TextComponent", actual::class.java.name)
|
||||||
if (expected.message != actual.message) {
|
if (expected.message != actual.message) assert("Message mismatch", expected.message, actual.message)
|
||||||
throw AssertionFailedError("Message mismatch", expected.message, actual.message)
|
if (expected.clickEvent != actual.clickEvent) assert("Click event mismatch: $expected", expected.clickEvent, actual.clickEvent)
|
||||||
}
|
if (expected.hoverEvent != actual.hoverEvent) assert("Click event mismatch: $expected", expected.hoverEvent, actual.hoverEvent)
|
||||||
if (expected.clickEvent != actual.clickEvent) {
|
if (expected.color != actual.color) assert("Color mismatch", expected.color, actual.color)
|
||||||
throw AssertionFailedError("Click event mismatch: $expected", expected.clickEvent, actual.clickEvent)
|
if (expected.font != actual.font) assert("Font mismatch: $expected", expected.font, actual.font)
|
||||||
}
|
if (expected.formatting != actual.formatting) assert("Formatting mismatch: $expected", expected.formatting, actual.formatting)
|
||||||
if (expected.hoverEvent != actual.hoverEvent) {
|
|
||||||
throw AssertionFailedError("Click event mismatch: $expected", expected.hoverEvent, actual.hoverEvent)
|
|
||||||
}
|
|
||||||
assertEquals(expected as Any, actual)
|
assertEquals(expected as Any, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> assertEquals(expected as Any, actual)
|
else -> assertEquals(expected as Any, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assert(message: String, expected: Any?, actual: Any?): Nothing = throw AssertionFailedError("$message: expected=$expected, actual=$actual", expected, actual)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.text.formatting.color
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class RGBAColorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color int components`() {
|
||||||
|
val color = RGBAColor(0x12, 0x34, 0x56, 0x78)
|
||||||
|
assertEquals(color.red, 0x12)
|
||||||
|
assertEquals(color.green, 0x34)
|
||||||
|
assertEquals(color.blue, 0x56)
|
||||||
|
assertEquals(color.alpha, 0x78)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color float components`() {
|
||||||
|
val color = RGBAColor(0x12, 0x34, 0x56, 0x78)
|
||||||
|
assertEquals(color.redf, 0x12 / 255.0f, 0.01f)
|
||||||
|
assertEquals(color.greenf, 0x34 / 255.0f, 0.01f)
|
||||||
|
assertEquals(color.bluef, 0x56 / 255.0f, 0.01f)
|
||||||
|
assertEquals(color.alphaf, 0x78 / 255.0f, 0.01f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color swizzles`() {
|
||||||
|
val color = RGBAColor(0x12, 0x34, 0x56, 0x78)
|
||||||
|
assertEquals(color.rgba, 0x12345678)
|
||||||
|
assertEquals(color.rgb, 0x123456)
|
||||||
|
assertEquals(color.argb, 0x78123456)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `default alpha`() {
|
||||||
|
val color = RGBAColor(0x12, 0x34, 0x56)
|
||||||
|
assertEquals(color.alpha, 0xFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `out of bounds clamping positive`() {
|
||||||
|
val color = RGBAColor(0x145, 0x145, 0x145, 0x145)
|
||||||
|
assertEquals(color.red, 0xFF)
|
||||||
|
assertEquals(color.green, 0xFF)
|
||||||
|
assertEquals(color.blue, 0xFF)
|
||||||
|
assertEquals(color.alpha, 0xFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `out of bounds clamping negative`() {
|
||||||
|
val color = RGBAColor(-123, -123, -123, -123)
|
||||||
|
assertEquals(color.red, 0)
|
||||||
|
assertEquals(color.green, 0)
|
||||||
|
assertEquals(color.blue, 0)
|
||||||
|
assertEquals(color.alpha, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `operations minus`() {
|
||||||
|
val a = RGBAColor(0x12, 0x34, 0x56, 0x78)
|
||||||
|
val b = RGBAColor(0x05, 0x06, 0x07, 0x08)
|
||||||
|
|
||||||
|
assertEquals(a - b, RGBAColor(0x0D, 0x2e, 0x4F, 0x70))
|
||||||
|
assertEquals(a - 3, RGBAColor(0x0F, 0x31, 0x53, 0x75))
|
||||||
|
assertEquals(a - 0.1f, RGBAColor(0x00, 0x1b, 0x3d, 0x5f))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `conversion rgb`() {
|
||||||
|
val color = RGBAColor(0x12, 0x34, 0x56, 0x78)
|
||||||
|
|
||||||
|
assertEquals(color.rgb(), RGBColor(0x12, 0x34, 0x56))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: operations (plus, times), conversion, toString, Int::rgb, Int::rgba, mix
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Minosoft
|
||||||
|
* Copyright (C) 2020-2025 Moritz Zwerger
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package de.bixilon.minosoft.data.text.formatting.color
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class RGBColorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color int components`() {
|
||||||
|
val color = RGBColor(0x12, 0x34, 0x56)
|
||||||
|
assertEquals(color.red, 0x12)
|
||||||
|
assertEquals(color.green, 0x34)
|
||||||
|
assertEquals(color.blue, 0x56)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color float components`() {
|
||||||
|
val color = RGBColor(0x12, 0x34, 0x56)
|
||||||
|
assertEquals(color.redf, 0x12 / 255.0f, 0.01f)
|
||||||
|
assertEquals(color.greenf, 0x34 / 255.0f, 0.01f)
|
||||||
|
assertEquals(color.bluef, 0x56 / 255.0f, 0.01f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `color swizzles`() {
|
||||||
|
val color = RGBColor(0x12, 0x34, 0x56)
|
||||||
|
assertEquals(color.rgb, 0x123456)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `out of bounds clamping positive`() {
|
||||||
|
val color = RGBColor(0x145, 0x145, 0x145)
|
||||||
|
assertEquals(color.red, 0xFF)
|
||||||
|
assertEquals(color.green, 0xFF)
|
||||||
|
assertEquals(color.blue, 0xFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `out of bounds clamping negative`() {
|
||||||
|
val color = RGBColor(-123, -123, -123)
|
||||||
|
assertEquals(color.red, 0)
|
||||||
|
assertEquals(color.green, 0)
|
||||||
|
assertEquals(color.blue, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `operations minus`() {
|
||||||
|
val a = RGBColor(0x12, 0x34, 0x56)
|
||||||
|
val b = RGBColor(0x05, 0x06, 0x07)
|
||||||
|
|
||||||
|
assertEquals(a - b, RGBColor(0x0D, 0x2e, 0x4F))
|
||||||
|
assertEquals(a - 3, RGBColor(0x0F, 0x31, 0x53))
|
||||||
|
assertEquals(a - 0.1f, RGBColor(0x00, 0x1b, 0x3d))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `conversion rgba`() {
|
||||||
|
val color = RGBColor(0x12, 0x34, 0x56)
|
||||||
|
|
||||||
|
assertEquals(color.rgba(), RGBAColor(0x12, 0x34, 0x56, 0xFF))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: operations (plus, times), conversion, toString, Int::rgb, Int::rgba, mix
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user