some more color tests and fixes

This commit is contained in:
Moritz Zwerger 2025-03-31 19:33:03 +02:00
parent 83c3337f38
commit a17f75c201
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
14 changed files with 109 additions and 41 deletions

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2024 Moritz Zwerger
* 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.
*
@ -70,6 +70,7 @@ class SignBlockEntityTest {
assertEquals(entity.back.color, ChatColors.BLUE)
assertEquals(entity.back.text, arrayOf(ChatComponent.of("This is the back"), ChatComponent.of("text"), ChatComponent.of("of"), ChatComponent.of("this sign.")))
}
fun `nbt 1_20_4`() {
val nbt = mapOf(
"is_waxed" to 1.toByte(),

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2024 Moritz Zwerger
* 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.
*
@ -16,6 +16,7 @@ package de.bixilon.minosoft.gui.rendering.textures
import de.bixilon.kotlinglm.vec2.Vec2i
import de.bixilon.kutil.stream.InputStreamUtil.readAll
import de.bixilon.kutil.unsafe.UnsafeUtil.setUnsafeAccessible
import de.bixilon.minosoft.data.text.formatting.color.RGBAColor
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.RGB8Buffer
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.RGBA8Buffer
import de.bixilon.minosoft.gui.rendering.system.base.texture.data.buffer.TextureBuffer
@ -69,10 +70,9 @@ class TextureReadingTest {
}
private fun TextureBuffer.assertSand() {
assertEquals(getRGBA(0, 0), 0xE7E4BBFF.toInt())
assertEquals(getRGBA(1, 0), 0xDACFA3FF.toInt())
assertEquals(getRGBA(0, 1), 0xD5C496FF.toInt())
assertEquals(getRGBA(0, 0), RGBAColor(0xE7, 0xE4, 0xBB))
assertEquals(getRGBA(1, 0), RGBAColor(0xDA, 0xCF, 0xA3))
assertEquals(getRGBA(0, 1), RGBAColor(0xD5, 0xC4, 0x96))
}
fun `read1 sand rgba`() {

View File

@ -24,7 +24,7 @@ import de.bixilon.minosoft.data.registries.identified.ResourceLocation
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.data.text.EmptyComponent
import de.bixilon.minosoft.data.text.formatting.color.ChatColors
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
import de.bixilon.minosoft.data.text.formatting.color.RGBAColor
import de.bixilon.minosoft.protocol.network.session.play.PlaySession
class SignBlockEntity(session: PlaySession) : BlockEntity(session) {
@ -56,7 +56,7 @@ class SignBlockEntity(session: PlaySession) : BlockEntity(session) {
class SignTextProperties(
var glowing: Boolean = false,
var color: RGBColor? = null,
var color: RGBAColor? = null,
val text: Array<ChatComponent> = Array(LINES) { EmptyComponent },
) {
@ -78,7 +78,7 @@ class SignBlockEntity(session: PlaySession) : BlockEntity(session) {
}
fun update(color: Any?, glowing: Any?) {
this.color = color?.toString()?.lowercase()?.let { ChatColors.NAME_MAP[it]?.rgb() }
this.color = color?.toString()?.lowercase()?.let { ChatColors.NAME_MAP[it] }
this.glowing = glowing?.toBoolean() ?: false
}
}

View File

@ -130,12 +130,12 @@ open class TextComponent(
}
fun copy(message: Any? = this.message, color: RGBAColor? = this.color, formatting: BitEnumSet<FormattingCodes> = this.formatting, clickEvent: ClickEvent? = this.clickEvent, hoverEvent: HoverEvent? = this.hoverEvent) = TextComponent(
message = message,
color = color,
formatting = formatting,
clickEvent = clickEvent,
hoverEvent = hoverEvent,
)
message = message,
color = color,
formatting = formatting,
clickEvent = clickEvent,
hoverEvent = hoverEvent,
)
override val length: Int
get() = message.length

View File

@ -17,12 +17,12 @@ package de.bixilon.minosoft.data.text.formatting.color
value class RGBAArray(val array: IntArray) {
constructor(size: Int) : this(IntArray(size))
constructor(size: Int, init: (Int) -> RGBAColor) : this(IntArray(size) { init.invoke(it).argb })
constructor(size: Int, init: (Int) -> RGBAColor) : this(IntArray(size) { init.invoke(it).rgba })
operator fun get(index: Int) = RGBAColor(array[index])
inline fun getOrNull(index: Int) = array.getOrNull(index)?.let { RGBAColor(it) }
operator fun set(index: Int, value: RGBAColor) {
array[index] = value.rgb
array[index] = value.rgba
}
}

View File

@ -27,7 +27,7 @@ import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.clamp
@JvmInline
value class RGBAColor(val argb: Int) : Color, TextFormattable {
value class RGBAColor(val rgba: Int) : Color, TextFormattable {
constructor(red: Int, green: Int, blue: Int) : this(red, green, blue, MAX)
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))
@ -35,10 +35,10 @@ value class RGBAColor(val argb: Int) : Color, TextFormattable {
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))
override inline val red: Int get() = (argb ushr RED_SHIFT) and MASK
override inline val green: Int get() = (argb ushr GREEN_SHIFT) and MASK
override inline val blue: Int get() = (argb ushr BLUE_SHIFT) and MASK
inline val alpha: Int get() = (argb ushr ALPHA_SHIFT) and MASK
override inline val red: Int get() = (rgba ushr RED_SHIFT) and MASK
override inline val green: Int get() = (rgba ushr GREEN_SHIFT) and MASK
override inline val blue: Int get() = (rgba ushr BLUE_SHIFT) and MASK
inline val alpha: Int get() = (rgba ushr ALPHA_SHIFT) and MASK
override inline val redf get() = Color.toFloat(red)
@ -46,8 +46,8 @@ value class RGBAColor(val argb: Int) : Color, TextFormattable {
override inline val bluef get() = Color.toFloat(blue)
inline val alphaf get() = Color.toFloat(alpha)
override inline val rgb get() = argb and ((MASK shl RED_SHIFT) or (MASK shl GREEN_SHIFT) or (MASK shl BLUE_SHIFT))
inline val rgba get() = (argb shl BITS) or alpha
override inline val rgb get() = rgba ushr BITS
inline val argb get() = (rgba ushr BITS) or (rgba shl 3 * BITS)
inline operator fun plus(value: Int) = plus(RGBAColor(value, value, value, value))
@ -93,22 +93,21 @@ value class RGBAColor(val argb: Int) : Color, TextFormattable {
companion object {
const val ALPHA_SHIFT = 3 * BITS
const val RED_SHIFT = 2 * BITS
const val GREEN_SHIFT = 1 * BITS
const val BLUE_SHIFT = 0 * BITS
const val RED_SHIFT = 3 * BITS
const val GREEN_SHIFT = 2 * BITS
const val BLUE_SHIFT = 1 * BITS
const val ALPHA_SHIFT = 0 * BITS
fun Vec4.color() = RGBAColor(r, g, b, a)
inline fun Int.rgba() = RGBAColor(this shr BITS or (this and BITS shl (BITS * 3)))
inline fun Int.argb() = RGBColor(this)
inline fun Int.rgba() = RGBAColor(this)
fun String.rgba(): RGBAColor {
val string = this.removePrefix("#")
val int = Integer.parseUnsignedInt(string, 16)
return when (string.length) {
6 -> RGBAColor(int or (MASK shl ALPHA_SHIFT))
6 -> ((int shl BITS) or (MASK shl ALPHA_SHIFT)).rgba()
8 -> int.rgba()
else -> throw IllegalArgumentException("Invalid color string: $this")
}

View File

@ -13,6 +13,8 @@
package de.bixilon.minosoft.data.text.formatting.color
import de.bixilon.minosoft.data.text.formatting.color.RGBColor.Companion.rgb
@JvmInline
value class RGBArray(val array: IntArray) {
@ -21,8 +23,8 @@ value class RGBArray(val array: IntArray) {
inline val size get() = array.size
inline operator fun get(index: Int) = RGBColor(array[index])
inline fun getOrNull(index: Int) = array.getOrNull(index)?.let { RGBColor(it) }
inline operator fun get(index: Int) = array[index].rgb()
inline fun getOrNull(index: Int) = array.getOrNull(index)?.rgb()
inline operator fun set(index: Int, value: RGBColor) {
array[index] = value.rgb
}

View File

@ -20,11 +20,12 @@ 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.MAX
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.TIMES
import de.bixilon.minosoft.data.text.formatting.color.Color.Companion.clamp
@JvmInline
value class RGBColor(override val rgb: Int) : Color, TextFormattable {
constructor(red: Int, green: Int, blue: Int) : this(((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) : this(((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(rgb: Vec3) : this(rgb.r, rgb.g, rgb.b)
@ -87,7 +88,7 @@ value class RGBColor(override val rgb: Int) : Color, TextFormattable {
val int = Integer.parseUnsignedInt(string, 16)
val rgb = when (string.length) {
6 -> int
8 -> int ushr BITS // rgba
8 -> int ushr BITS
else -> throw IllegalArgumentException("Invalid color string: $this")
}
return RGBColor(rgb)

View File

@ -76,6 +76,7 @@ interface NativeShader {
is Vec3 -> setVec3(uniformName, data)
is Vec2 -> setVec2(uniformName, data)
is RGBColor -> setRGBColor(uniformName, data)
is RGBAColor -> setRGBAColor(uniformName, data)
is UniformBuffer -> setUniformBuffer(uniformName, data)
// ToDo: PNGTexture
is Boolean -> setBoolean(uniformName, data)

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2024 Moritz Zwerger
* 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.
*
@ -105,7 +105,7 @@ class SkinManager(private val textures: TextureManager) {
}
private fun TextureBuffer.isReallyWide(): Boolean {
// check if pixel at arm (wide, not slim) is black. If not, its a wide skinn
// check if pixel at arm (wide, not slim) is black. If not, its a wide skin
if (!this[50, 16].isBlack()) return true // left arm slim
if (!this[42, 48].isBlack()) return true // right arm slim

View File

@ -75,9 +75,9 @@ object TextureUtil {
var rgba = RGBAColor(image.raster.getSample(x, y, samples[0]), image.raster.getSample(x, y, samples[1]), image.raster.getSample(x, y, samples[2]))
if (samples.size > 3) {
rgba = rgba.with(image.raster.getSample(x, y, samples[3]))
rgba = rgba.with(alpha = image.raster.getSample(x, y, samples[3]))
} else {
rgba = rgba.with(image.alphaRaster?.getSample(x, y, 0) ?: 0xFF)
rgba = rgba.with(alpha = image.alphaRaster?.getSample(x, y, 0) ?: 0xFF)
}
buffer.setRGBA(x, y, rgba)
}

View File

@ -0,0 +1,40 @@
/*
* 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.Test
import kotlin.test.assertEquals
class ChatColorsTest {
@Test
fun `get yellow`() {
assertEquals(ChatColors["yellow"], RGBAColor(255, 255, 85))
}
@Test
fun `get name of gold`() {
assertEquals(ChatColors.NAME_MAP.getKey(RGBAColor(255, 170, 0)), "gold")
}
@Test
fun `get a`() {
assertEquals(ChatColors.VALUES.getOrNull(Character.digit('a', 16)), RGBAColor(85, 255, 85))
}
@Test
fun `get char of red`() {
assertEquals(ChatColors.getChar(RGBAColor(170, 0, 0)), "4")
}
}

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.text.formatting.color
import de.bixilon.minosoft.data.text.formatting.color.RGBAColor.Companion.rgba
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
@ -85,5 +86,16 @@ class RGBAColorTest {
assertEquals(color.rgb(), RGBColor(0x12, 0x34, 0x56))
}
// TODO: operations (plus, times), conversion, toString, Int::rgb, Int::rgba, mix
@Test
fun `int to rgba`() {
assertEquals(0x12345678.rgba(), RGBAColor(0x12, 0x34, 0x56, 0x78))
}
@Test
fun `string to rgba`() {
assertEquals("#123456".rgba(), RGBAColor(0x12, 0x34, 0x56))
assertEquals("#12345678".rgba(), RGBAColor(0x12, 0x34, 0x56, 0x78))
}
// TODO: operations (plus, times), toString, mix
}

View File

@ -13,6 +13,7 @@
package de.bixilon.minosoft.data.text.formatting.color
import de.bixilon.minosoft.data.text.formatting.color.RGBColor.Companion.rgb
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
@ -73,5 +74,16 @@ class RGBColorTest {
assertEquals(color.rgba(), RGBAColor(0x12, 0x34, 0x56, 0xFF))
}
// TODO: operations (plus, times), conversion, toString, Int::rgb, Int::rgba, mix
@Test
fun `int to rgb`() {
assertEquals(0x123456.rgb(), RGBColor(0x12, 0x34, 0x56))
}
@Test
fun `string to rgb`() {
assertEquals("#123456".rgb(), RGBColor(0x12, 0x34, 0x56))
assertEquals("#12345678".rgb(), RGBColor(0x12, 0x34, 0x56))
}
// TODO: operations (plus, times), toString, Int::rgb, Int::rgba, mix
}