mirror of
https://gitlab.com/cc-ru/ocelot/ocelot-desktop.git
synced 2025-12-20 02:59:19 +01:00
Run scalafmt
This commit is contained in:
parent
fbfd788d3f
commit
bc42954c30
@ -4,8 +4,7 @@ import ocelot.desktop.color_v2.repr.PackedInt
|
|||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
/**
|
/** Linear-RGB with 8 bits for alpha and 16 bits per color channel, packed into a [[Long]].
|
||||||
* Linear-RGB with 8 bits for alpha and 16 bits per color channel, packed into a [[Long]].
|
|
||||||
*
|
*
|
||||||
* Has the following layout: A_RR_GG_BB.
|
* Has the following layout: A_RR_GG_BB.
|
||||||
*
|
*
|
||||||
@ -22,37 +21,38 @@ import java.nio.ByteBuffer
|
|||||||
* would be lost anyway.
|
* would be lost anyway.
|
||||||
*/
|
*/
|
||||||
case class Color(inner: Long) extends AnyVal {
|
case class Color(inner: Long) extends AnyVal {
|
||||||
|
|
||||||
/** Red channel (0-65535). */
|
/** Red channel (0-65535). */
|
||||||
def r16: Short = ((inner >> 32) & 0xFFFF).toShort
|
def r16: Short = ((inner >> 32) & 0xffff).toShort
|
||||||
|
|
||||||
/** Green channel (0-65535). */
|
/** Green channel (0-65535). */
|
||||||
def g16: Short = ((inner >> 16) & 0xFFFF).toShort
|
def g16: Short = ((inner >> 16) & 0xffff).toShort
|
||||||
|
|
||||||
/** Blue channel (0-65535). */
|
/** Blue channel (0-65535). */
|
||||||
def b16: Short = (inner & 0xFFFF).toShort
|
def b16: Short = (inner & 0xffff).toShort
|
||||||
|
|
||||||
/** Alpha channel (0-65535). */
|
/** Alpha channel (0-65535). */
|
||||||
def a8: Byte = ((inner >> 48) & 0xFF).toByte
|
def a8: Byte = ((inner >> 48) & 0xff).toByte
|
||||||
|
|
||||||
/** Checks whether two colors are close enough. */
|
/** Checks whether two colors are close enough. */
|
||||||
def closeTo(other: Color, colorEps: Int = 10, alphaEps: Int = 1): Boolean = {
|
def closeTo(other: Color, colorEps: Int = 10, alphaEps: Int = 1): Boolean = {
|
||||||
((r16.toInt & 0xFFFF) - (other.r16.toInt & 0xFFFF)).abs <= colorEps &&
|
((r16.toInt & 0xffff) - (other.r16.toInt & 0xffff)).abs <= colorEps &&
|
||||||
((g16.toInt & 0xFFFF) - (other.g16.toInt & 0xFFFF)).abs <= colorEps &&
|
((g16.toInt & 0xffff) - (other.g16.toInt & 0xffff)).abs <= colorEps &&
|
||||||
((b16.toInt & 0xFFFF) - (other.b16.toInt & 0xFFFF)).abs <= colorEps &&
|
((b16.toInt & 0xffff) - (other.b16.toInt & 0xffff)).abs <= colorEps &&
|
||||||
((a8.toInt & 0xFF) - (other.a8.toInt & 0xFF)).abs <= alphaEps
|
((a8.toInt & 0xff) - (other.a8.toInt & 0xff)).abs <= alphaEps
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Performs alpha blending against a background. */
|
/** Performs alpha blending against a background. */
|
||||||
def blendOver(bg: Color): Color = {
|
def blendOver(bg: Color): Color = {
|
||||||
val fgR = r16.toInt & 0xFFFF
|
val fgR = r16.toInt & 0xffff
|
||||||
val fgG = g16.toInt & 0xFFFF
|
val fgG = g16.toInt & 0xffff
|
||||||
val fgB = b16.toInt & 0xFFFF
|
val fgB = b16.toInt & 0xffff
|
||||||
val fgA = a8.toInt & 0xFF
|
val fgA = a8.toInt & 0xff
|
||||||
|
|
||||||
val bgR = bg.r16.toInt & 0xFFFF
|
val bgR = bg.r16.toInt & 0xffff
|
||||||
val bgG = bg.g16.toInt & 0xFFFF
|
val bgG = bg.g16.toInt & 0xffff
|
||||||
val bgB = bg.b16.toInt & 0xFFFF
|
val bgB = bg.b16.toInt & 0xffff
|
||||||
val bgA = bg.a8.toInt & 0xFF
|
val bgA = bg.a8.toInt & 0xff
|
||||||
|
|
||||||
def alphaMul(r: Int, a: Int): Int = {
|
def alphaMul(r: Int, a: Int): Int = {
|
||||||
// we want to compute: round((r / 0xFFFF) * (a / 0xFF) * 0xFFFF)
|
// we want to compute: round((r / 0xFFFF) * (a / 0xFF) * 0xFFFF)
|
||||||
@ -76,39 +76,39 @@ case class Color(inner: Long) extends AnyVal {
|
|||||||
// (ra * 2^8 + ra + ra / 2^8 + 0x8000) / 2^16
|
// (ra * 2^8 + ra + ra / 2^8 + 0x8000) / 2^16
|
||||||
|
|
||||||
val ra = r * a
|
val ra = r * a
|
||||||
(((ra << 8) + ra + (ra >> 8) + 0x8000) >> 16) & 0xFFFF
|
(((ra << 8) + ra + (ra >> 8) + 0x8000) >> 16) & 0xffff
|
||||||
}
|
}
|
||||||
|
|
||||||
val resR = fgR + alphaMul(bgR, 0xFF - fgA)
|
val resR = fgR + alphaMul(bgR, 0xff - fgA)
|
||||||
val resG = fgG + alphaMul(bgG, 0xFF - fgA)
|
val resG = fgG + alphaMul(bgG, 0xff - fgA)
|
||||||
val resB = fgB + alphaMul(bgB, 0xFF - fgA)
|
val resB = fgB + alphaMul(bgB, 0xff - fgA)
|
||||||
val resA = fgA + alphaMul(bgA, 0xFF - fgA)
|
val resA = fgA + alphaMul(bgA, 0xff - fgA)
|
||||||
|
|
||||||
Color.pack(resR.toShort, resG.toShort, resB.toShort, resA.toByte)
|
Color.pack(resR.toShort, resG.toShort, resB.toShort, resA.toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Color {
|
object Color {
|
||||||
val White: Color = PackedInt(0xFFFFFF).toColor
|
val White: Color = PackedInt(0xffffff).toColor
|
||||||
val Grey: Color = PackedInt(0x808080).toColor
|
val Grey: Color = PackedInt(0x808080).toColor
|
||||||
val Black: Color = PackedInt(0x000000).toColor
|
val Black: Color = PackedInt(0x000000).toColor
|
||||||
|
|
||||||
val Red: Color = PackedInt(0xFF0000).toColor
|
val Red: Color = PackedInt(0xff0000).toColor
|
||||||
val Green: Color = PackedInt(0x00FF00).toColor
|
val Green: Color = PackedInt(0x00ff00).toColor
|
||||||
val Blue: Color = PackedInt(0x0000FF).toColor
|
val Blue: Color = PackedInt(0x0000ff).toColor
|
||||||
|
|
||||||
val Cyan: Color = PackedInt(0x00FFF).toColor
|
val Cyan: Color = PackedInt(0x00fff).toColor
|
||||||
val Magenta: Color = PackedInt(0xFF00FF).toColor
|
val Magenta: Color = PackedInt(0xff00ff).toColor
|
||||||
val Yellow: Color = PackedInt(0xFFFF00).toColor
|
val Yellow: Color = PackedInt(0xffff00).toColor
|
||||||
|
|
||||||
val Transparent: Color = Color(0)
|
val Transparent: Color = Color(0)
|
||||||
|
|
||||||
def pack(r16: Short, g16: Short, b16: Short, a8: Byte): Color = {
|
def pack(r16: Short, g16: Short, b16: Short, a8: Byte): Color = {
|
||||||
Color(
|
Color(
|
||||||
((a8.toLong & 0xFF) << 48)
|
((a8.toLong & 0xff) << 48)
|
||||||
| ((r16.toLong & 0xFFFF) << 32)
|
| ((r16.toLong & 0xffff) << 32)
|
||||||
| ((g16.toLong & 0xFFFF) << 16)
|
| ((g16.toLong & 0xffff) << 16)
|
||||||
| (b16.toLong & 0xFFFF)
|
| (b16.toLong & 0xffff)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,6 +136,7 @@ object Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Encoding {
|
object Encoding {
|
||||||
|
|
||||||
/** Linear encoding with a single 8-bit red channel. */
|
/** Linear encoding with a single 8-bit red channel. */
|
||||||
case object LinearR8 extends Encoding {
|
case object LinearR8 extends Encoding {
|
||||||
override val size: Int = 1
|
override val size: Int = 1
|
||||||
@ -146,7 +147,7 @@ object Color {
|
|||||||
|
|
||||||
override def decode(src: ByteBuffer): Color = {
|
override def decode(src: ByteBuffer): Color = {
|
||||||
val r = extend8To16Bits(src.get())
|
val r = extend8To16Bits(src.get())
|
||||||
pack(r, r, r, 0xFF.toByte)
|
pack(r, r, r, 0xff.toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,7 +165,7 @@ object Color {
|
|||||||
val r = extend8To16Bits(src.get())
|
val r = extend8To16Bits(src.get())
|
||||||
val g = extend8To16Bits(src.get())
|
val g = extend8To16Bits(src.get())
|
||||||
val b = extend8To16Bits(src.get())
|
val b = extend8To16Bits(src.get())
|
||||||
pack(r, g, b, 0xFF.toByte)
|
pack(r, g, b, 0xff.toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +203,7 @@ object Color {
|
|||||||
val r = srgb8ToLinear16(src.get())
|
val r = srgb8ToLinear16(src.get())
|
||||||
val g = srgb8ToLinear16(src.get())
|
val g = srgb8ToLinear16(src.get())
|
||||||
val b = srgb8ToLinear16(src.get())
|
val b = srgb8ToLinear16(src.get())
|
||||||
pack(r, g, b, 0xFF.toByte)
|
pack(r, g, b, 0xff.toByte)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,17 +230,17 @@ object Color {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Repeats a byte twice */
|
/** Repeats a byte twice */
|
||||||
private[color_v2] def extend8To16Bits(v: Byte): Short = (((v.toShort & 0xFF) << 8) | (v.toShort & 0xFF)).toShort
|
private[color_v2] def extend8To16Bits(v: Byte): Short = (((v.toShort & 0xff) << 8) | (v.toShort & 0xff)).toShort
|
||||||
|
|
||||||
/** Returns high byte from 16-bit word */
|
/** Returns high byte from 16-bit word */
|
||||||
private[color_v2] def shrink16To8Bits(v: Short): Byte = (v >> 8).toByte
|
private[color_v2] def shrink16To8Bits(v: Short): Byte = (v >> 8).toByte
|
||||||
|
|
||||||
/** Converts non-linear sRGB color component (0-255) to linear color space (0-65535). */
|
/** Converts non-linear sRGB color component (0-255) to linear color space (0-65535). */
|
||||||
private[color_v2] def srgb8ToLinear16(v: Byte): Short = Srgb8ToLinear16Lut(v.toInt & 0xFF)
|
private[color_v2] def srgb8ToLinear16(v: Byte): Short = Srgb8ToLinear16Lut(v.toInt & 0xff)
|
||||||
|
|
||||||
private lazy val Srgb8ToLinear16Lut: Array[Short] = {
|
private lazy val Srgb8ToLinear16Lut: Array[Short] = {
|
||||||
Array.tabulate(0x100) { i =>
|
Array.tabulate(0x100) { i =>
|
||||||
val srgb = i.toFloat / 0xFF.toFloat
|
val srgb = i.toFloat / 0xff.toFloat
|
||||||
|
|
||||||
val linear = if (srgb <= 0.04045) {
|
val linear = if (srgb <= 0.04045) {
|
||||||
srgb / 12.92
|
srgb / 12.92
|
||||||
@ -247,16 +248,16 @@ object Color {
|
|||||||
math.pow((srgb + 0.055) / 1.055, 2.4)
|
math.pow((srgb + 0.055) / 1.055, 2.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
(linear * 0xFFFF.toFloat).toShort
|
(linear * 0xffff.toFloat).toShort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Converts linear color component (0-65535) to non-linear sRGB color space (0-255). */
|
/** Converts linear color component (0-65535) to non-linear sRGB color space (0-255). */
|
||||||
private[color_v2] def linear16ToSrgb8(v: Short): Byte = Linear16ToSrgb8Lut(v.toInt & 0xFFFF)
|
private[color_v2] def linear16ToSrgb8(v: Short): Byte = Linear16ToSrgb8Lut(v.toInt & 0xffff)
|
||||||
|
|
||||||
private lazy val Linear16ToSrgb8Lut: Array[Byte] = {
|
private lazy val Linear16ToSrgb8Lut: Array[Byte] = {
|
||||||
Array.tabulate(0x10000) { i =>
|
Array.tabulate(0x10000) { i =>
|
||||||
val linear = i.toFloat / 0xFFFF.toFloat
|
val linear = i.toFloat / 0xffff.toFloat
|
||||||
|
|
||||||
val srgb = if (linear <= 0.0031308) {
|
val srgb = if (linear <= 0.0031308) {
|
||||||
linear * 12.92
|
linear * 12.92
|
||||||
@ -264,7 +265,7 @@ object Color {
|
|||||||
1.055 * math.pow(linear, 1.0 / 2.4) - 0.055
|
1.055 * math.pow(linear, 1.0 / 2.4) - 0.055
|
||||||
}
|
}
|
||||||
|
|
||||||
math.min((srgb * 0xFF.toFloat).round, 255.0).toInt.toByte
|
math.min((srgb * 0xff.toFloat).round, 255.0).toInt.toByte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,7 +6,7 @@ import ocelot.desktop.color_v2.Color._
|
|||||||
/** Linear RGBA color with double components (0-1) with premultiplied alpha. */
|
/** Linear RGBA color with double components (0-1) with premultiplied alpha. */
|
||||||
case class LinearRgba(r: Double, g: Double, b: Double, a: Double) extends ReprInstance {
|
case class LinearRgba(r: Double, g: Double, b: Double, a: Double) extends ReprInstance {
|
||||||
override def toColor: Color = {
|
override def toColor: Color = {
|
||||||
pack((r * 0xFFFF).toShort, (g * 0xFFFF).toShort, (b * 0xFFFF).toShort, (a * 0XFF).toByte)
|
pack((r * 0xffff).toShort, (g * 0xffff).toShort, (b * 0xffff).toShort, (a * 0xff).toByte)
|
||||||
}
|
}
|
||||||
|
|
||||||
def closeTo(other: LinearRgba, eps: Double = 1e-3): Boolean = {
|
def closeTo(other: LinearRgba, eps: Double = 1e-3): Boolean = {
|
||||||
@ -19,10 +19,10 @@ case object LinearRgba extends ReprObject {
|
|||||||
|
|
||||||
override def fromColor(color: Color): LinearRgba = {
|
override def fromColor(color: Color): LinearRgba = {
|
||||||
LinearRgba(
|
LinearRgba(
|
||||||
(color.r16.toInt & 0xFFFF).toDouble / 0xFFFF,
|
(color.r16.toInt & 0xffff).toDouble / 0xffff,
|
||||||
(color.g16.toInt & 0xFFFF).toDouble / 0xFFFF,
|
(color.g16.toInt & 0xffff).toDouble / 0xffff,
|
||||||
(color.b16.toInt & 0xFFFF).toDouble / 0xFFFF,
|
(color.b16.toInt & 0xffff).toDouble / 0xffff,
|
||||||
(color.a8.toInt & 0xFF).toDouble / 0xFF
|
(color.a8.toInt & 0xff).toDouble / 0xff,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -66,7 +66,7 @@ case object Okhsv extends ReprObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private def computeMaxSaturation(a: Double, b: Double): Double = {
|
private def computeMaxSaturation(a: Double, b: Double): Double = {
|
||||||
val (k0, k1, k2, k3, k4, wl, wm, ws) =
|
val (k0, k1, k2, k3, k4, wl, wm, ws) = {
|
||||||
if (-1.88170328 * a - 0.80936493 * b > 1) {
|
if (-1.88170328 * a - 0.80936493 * b > 1) {
|
||||||
// Red component
|
// Red component
|
||||||
(1.19086277, 1.76576728, 0.59662641, 0.75515197, 0.56771245,
|
(1.19086277, 1.76576728, 0.59662641, 0.75515197, 0.56771245,
|
||||||
@ -80,6 +80,7 @@ case object Okhsv extends ReprObject {
|
|||||||
(1.35733652, -0.00915799, -1.15130210, -0.50559606, 0.00692167,
|
(1.35733652, -0.00915799, -1.15130210, -0.50559606, 0.00692167,
|
||||||
-0.0041960863, -0.7034186147, 1.7076147010)
|
-0.0041960863, -0.7034186147, 1.7076147010)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b
|
var S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,7 @@ case class Oklab(lightness: Double, colorA: Double, colorB: Double, alpha: Doubl
|
|||||||
r = +0.2309699292 * s + 4.0767416621 * l - 3.3077115913 * m,
|
r = +0.2309699292 * s + 4.0767416621 * l - 3.3077115913 * m,
|
||||||
g = -0.3413193965 * s + -1.2684380046 * l + 2.6097574011 * m,
|
g = -0.3413193965 * s + -1.2684380046 * l + 2.6097574011 * m,
|
||||||
b = +1.7076147010 * s + -0.0041960863 * l - 0.7034186147 * m,
|
b = +1.7076147010 * s + -0.0041960863 * l - 0.7034186147 * m,
|
||||||
a = alpha
|
a = alpha,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ case object Oklab extends ReprObject {
|
|||||||
lightness = -0.0040720468 * s + 0.2104542553 * l + 0.7936177850 * m,
|
lightness = -0.0040720468 * s + 0.2104542553 * l + 0.7936177850 * m,
|
||||||
colorA = +0.4505937099 * s + 1.9779984951 * l - 2.4285922050 * m,
|
colorA = +0.4505937099 * s + 1.9779984951 * l - 2.4285922050 * m,
|
||||||
colorB = -0.8086757660 * s + 0.0259040371 * l + 0.7827717662 * m,
|
colorB = -0.8086757660 * s + 0.0259040371 * l + 0.7827717662 * m,
|
||||||
alpha = c.a
|
alpha = c.a,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,17 +5,18 @@ import ocelot.desktop.color_v2.Color._
|
|||||||
|
|
||||||
/** sRGB color packed into an [[Int]] (0xRRGGBB). No alpha. Very common in OpenComputers world. */
|
/** sRGB color packed into an [[Int]] (0xRRGGBB). No alpha. Very common in OpenComputers world. */
|
||||||
case class PackedInt(inner: Int) extends AnyVal with ReprInstance {
|
case class PackedInt(inner: Int) extends AnyVal with ReprInstance {
|
||||||
|
|
||||||
/** Red channel (0-255). */
|
/** Red channel (0-255). */
|
||||||
def r: Byte = ((inner >> 16) & 0xFF).toByte
|
def r: Byte = ((inner >> 16) & 0xff).toByte
|
||||||
|
|
||||||
/** Green channel (0-255). */
|
/** Green channel (0-255). */
|
||||||
def g: Byte = ((inner >> 8) & 0xFF).toByte
|
def g: Byte = ((inner >> 8) & 0xff).toByte
|
||||||
|
|
||||||
/** Blue channel (0-255). */
|
/** Blue channel (0-255). */
|
||||||
def b: Byte = (inner & 0xFF).toByte
|
def b: Byte = (inner & 0xff).toByte
|
||||||
|
|
||||||
override def toColor: Color = {
|
override def toColor: Color = {
|
||||||
pack(srgb8ToLinear16(r), srgb8ToLinear16(g), srgb8ToLinear16(b), 0xFF.toByte)
|
pack(srgb8ToLinear16(r), srgb8ToLinear16(g), srgb8ToLinear16(b), 0xff.toByte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,9 +24,9 @@ case object PackedInt extends ReprObject {
|
|||||||
override type Instance = PackedInt
|
override type Instance = PackedInt
|
||||||
|
|
||||||
override def fromColor(color: Color): PackedInt = {
|
override def fromColor(color: Color): PackedInt = {
|
||||||
val r = linear16ToSrgb8(color.r16).toInt & 0xFF
|
val r = linear16ToSrgb8(color.r16).toInt & 0xff
|
||||||
val g = linear16ToSrgb8(color.g16).toInt & 0xFF
|
val g = linear16ToSrgb8(color.g16).toInt & 0xff
|
||||||
val b = linear16ToSrgb8(color.b16).toInt & 0xFF
|
val b = linear16ToSrgb8(color.b16).toInt & 0xff
|
||||||
PackedInt((r << 16) | (g << 8) | b)
|
PackedInt((r << 16) | (g << 8) | b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,8 +1,10 @@
|
|||||||
package ocelot.desktop.color_v2
|
package ocelot.desktop.color_v2
|
||||||
|
|
||||||
package object repr {
|
package object repr {
|
||||||
|
|
||||||
/** Provides encoding and decoding of various alternative color representations to [[Color]]. */
|
/** Provides encoding and decoding of various alternative color representations to [[Color]]. */
|
||||||
trait ReprObject {
|
trait ReprObject {
|
||||||
|
|
||||||
/** Type of the alternative representation */
|
/** Type of the alternative representation */
|
||||||
type Instance <: ReprInstance;
|
type Instance <: ReprInstance;
|
||||||
|
|
||||||
@ -12,6 +14,7 @@ package object repr {
|
|||||||
|
|
||||||
/** Provides encoding and decoding of various alternative color representations to [[Color]]. */
|
/** Provides encoding and decoding of various alternative color representations to [[Color]]. */
|
||||||
trait ReprInstance extends Any {
|
trait ReprInstance extends Any {
|
||||||
|
|
||||||
/** Converts this representation to a [[Color]]. */
|
/** Converts this representation to a [[Color]]. */
|
||||||
def toColor: Color
|
def toColor: Color
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,8 @@ import ocelot.desktop.color.Color
|
|||||||
import ocelot.desktop.geometry.{Rect2D, Transform2D}
|
import ocelot.desktop.geometry.{Rect2D, Transform2D}
|
||||||
|
|
||||||
trait Encoder2D {
|
trait Encoder2D {
|
||||||
/**
|
|
||||||
* Draws a rectangle with a specified image and color.
|
/** Draws a rectangle with a specified image and color.
|
||||||
*
|
*
|
||||||
* @param rect Rectangle to draw (its position and size).
|
* @param rect Rectangle to draw (its position and size).
|
||||||
* @param image Fill image.
|
* @param image Fill image.
|
||||||
@ -15,8 +15,7 @@ trait Encoder2D {
|
|||||||
*/
|
*/
|
||||||
def rect(rect: Rect2D, image: Image = Image.None, color: Color = Color.White): Unit
|
def rect(rect: Rect2D, image: Image = Image.None, color: Color = Color.White): Unit
|
||||||
|
|
||||||
/**
|
/** Draws a group of objects with various optional effects. Takes a callback with a sub-encoder.
|
||||||
* Draws a group of objects with various optional effects. Takes a callback with a sub-encoder.
|
|
||||||
*
|
*
|
||||||
* @param scissor Apply a scissor rectangle (specified in the coordinate system of this encoder,
|
* @param scissor Apply a scissor rectangle (specified in the coordinate system of this encoder,
|
||||||
* not local coordinates of the inner encoder).
|
* not local coordinates of the inner encoder).
|
||||||
@ -27,6 +26,5 @@ trait Encoder2D {
|
|||||||
*/
|
*/
|
||||||
def group(scissor: Option[Rect2D] = None,
|
def group(scissor: Option[Rect2D] = None,
|
||||||
transform: Transform2D = Transform2D.identity,
|
transform: Transform2D = Transform2D.identity,
|
||||||
color: Color = Color.White)
|
color: Color = Color.White)(callback: Encoder2D => Unit): Unit
|
||||||
(callback: Encoder2D => Unit): Unit
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,15 +5,14 @@ import ocelot.desktop.color.Color
|
|||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
trait Graphics {
|
trait Graphics {
|
||||||
/**
|
|
||||||
* Type of [[Image.Static]] used by this graphics backend.
|
/** Type of [[Image.Static]] used by this graphics backend.
|
||||||
*
|
*
|
||||||
* Created with [[createStaticImage()]] and must be destroyed with [[destroyStaticImage()]]
|
* Created with [[createStaticImage()]] and must be destroyed with [[destroyStaticImage()]]
|
||||||
*/
|
*/
|
||||||
type StaticImage <: Image.Static
|
type StaticImage <: Image.Static
|
||||||
|
|
||||||
/**
|
/** Type of [[Image.Surface]] used by this graphics backend.
|
||||||
* Type of [[Image.Surface]] used by this graphics backend.
|
|
||||||
*
|
*
|
||||||
* This is used for off-screen rendering and for rendering to the window. Though the latter requires you to obtain
|
* This is used for off-screen rendering and for rendering to the window. Though the latter requires you to obtain
|
||||||
* a window-bound surface using implementation-specific methods defined outside of this trait.
|
* a window-bound surface using implementation-specific methods defined outside of this trait.
|
||||||
@ -26,6 +25,7 @@ trait Graphics {
|
|||||||
sealed class Pass
|
sealed class Pass
|
||||||
|
|
||||||
object Pass {
|
object Pass {
|
||||||
|
|
||||||
/** Clears the surface with a solid color. */
|
/** Clears the surface with a solid color. */
|
||||||
case class Clear(surface: Surface, color: Color) extends Pass
|
case class Clear(surface: Surface, color: Color) extends Pass
|
||||||
|
|
||||||
@ -36,16 +36,14 @@ trait Graphics {
|
|||||||
case class Download(surface: Surface, callback: ByteBuffer => Unit) extends Pass
|
case class Download(surface: Surface, callback: ByteBuffer => Unit) extends Pass
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates a static image with given dimensions, format, and data (row-major, packed without alignment or padding).
|
||||||
* Creates a static image with given dimensions, format, and data (row-major, packed without alignment or padding).
|
|
||||||
*
|
*
|
||||||
* @throws IllegalArgumentException if width or height is zero or negative,
|
* @throws IllegalArgumentException if width or height is zero or negative,
|
||||||
* if data is too short or too long for given format and dimensions
|
* if data is too short or too long for given format and dimensions
|
||||||
*/
|
*/
|
||||||
def createStaticImage(width: Int, height: Int, format: Image.Format, packedData: ByteBuffer): StaticImage
|
def createStaticImage(width: Int, height: Int, format: Image.Format, packedData: ByteBuffer): StaticImage
|
||||||
|
|
||||||
/**
|
/** Destroys a static image.
|
||||||
* Destroys a static image.
|
|
||||||
* @throws IllegalArgumentException if the image does not belong to this [[Graphics]] instance or is already destroyed.
|
* @throws IllegalArgumentException if the image does not belong to this [[Graphics]] instance or is already destroyed.
|
||||||
*/
|
*/
|
||||||
def destroyStaticImage(image: StaticImage): Unit
|
def destroyStaticImage(image: StaticImage): Unit
|
||||||
@ -53,8 +51,7 @@ trait Graphics {
|
|||||||
/** Creates a drawable off-screen surface with given dimensions. */
|
/** Creates a drawable off-screen surface with given dimensions. */
|
||||||
def createSurface(width: Int, height: Int, format: Image.Format): Surface
|
def createSurface(width: Int, height: Int, format: Image.Format): Surface
|
||||||
|
|
||||||
/**
|
/** Destroys a surface.
|
||||||
* Destroys a surface.
|
|
||||||
* @throws IllegalArgumentException if the surface does not belong to this [[Graphics]] instance or is already destroyed.
|
* @throws IllegalArgumentException if the surface does not belong to this [[Graphics]] instance or is already destroyed.
|
||||||
*/
|
*/
|
||||||
def destroySurface(surface: Surface): Unit
|
def destroySurface(surface: Surface): Unit
|
||||||
|
|||||||
@ -2,12 +2,10 @@ package ocelot.desktop.graphics_v2
|
|||||||
|
|
||||||
import ocelot.desktop.geometry.{Rect2D, Size2D}
|
import ocelot.desktop.geometry.{Rect2D, Size2D}
|
||||||
|
|
||||||
/**
|
/** Image used to fill geometry with color. */
|
||||||
* Image used to fill geometry with color.
|
sealed abstract class Image {
|
||||||
*/
|
|
||||||
abstract sealed class Image {
|
/** Size of the image in pixels.
|
||||||
/**
|
|
||||||
* Size of the image in pixels.
|
|
||||||
*
|
*
|
||||||
* Can be fractional. For instance, using [[Image.SubImage]] you can actually draw an image with a half-cropped pixel
|
* Can be fractional. For instance, using [[Image.SubImage]] you can actually draw an image with a half-cropped pixel
|
||||||
* given enough zoom.
|
* given enough zoom.
|
||||||
@ -16,25 +14,19 @@ abstract sealed class Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Image {
|
object Image {
|
||||||
/**
|
|
||||||
* Just a white image (all channels are 1.0). Use this to fill something with solid color.
|
/** Just a white image (all channels are 1.0). Use this to fill something with solid color. */
|
||||||
*/
|
|
||||||
object None extends Image {
|
object None extends Image {
|
||||||
override def size: Size2D = Size2D(1, 1)
|
override def size: Size2D = Size2D(1, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** A static image (loaded from a PNG resource or generated at runtime). */
|
||||||
* A static image (loaded from a PNG resource or generated at runtime).
|
|
||||||
*/
|
|
||||||
abstract class Static extends Image
|
abstract class Static extends Image
|
||||||
|
|
||||||
/**
|
/** Image contents of a drawable surface (useful for screens, holographs). */
|
||||||
* Image contents of a drawable surface (useful for screens, holographs).
|
|
||||||
*/
|
|
||||||
abstract class Surface extends Image
|
abstract class Surface extends Image
|
||||||
|
|
||||||
/**
|
/** Rectangular portion of an image.
|
||||||
* Rectangular portion of an image.
|
|
||||||
*
|
*
|
||||||
* @param srcImage Source image
|
* @param srcImage Source image
|
||||||
* @param rect Normalized rectangle, where (0,0) is top-left and (1,1) is bottom-right.
|
* @param rect Normalized rectangle, where (0,0) is top-left and (1,1) is bottom-right.
|
||||||
@ -44,7 +36,8 @@ object Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Image formats */
|
/** Image formats */
|
||||||
abstract sealed class Format {
|
sealed abstract class Format {
|
||||||
|
|
||||||
/** Returns true if the format is linear (has no gamma-correction). */
|
/** Returns true if the format is linear (has no gamma-correction). */
|
||||||
def isLinear: Boolean
|
def isLinear: Boolean
|
||||||
|
|
||||||
@ -53,6 +46,7 @@ object Image {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object Format {
|
object Format {
|
||||||
|
|
||||||
/** Linear format with one R 8-bit channel */
|
/** Linear format with one R 8-bit channel */
|
||||||
case object LinearR8 extends Format {
|
case object LinearR8 extends Format {
|
||||||
override val isLinear = true
|
override val isLinear = true
|
||||||
@ -67,8 +61,7 @@ object Image {
|
|||||||
override def bytesPerPixel: Int = 3
|
override def bytesPerPixel: Int = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Linear format with four RGBA 8-bit channels.
|
||||||
* Linear format with four RGBA 8-bit channels.
|
|
||||||
*
|
*
|
||||||
* Color is NOT premultiplied by alpha.
|
* Color is NOT premultiplied by alpha.
|
||||||
*/
|
*/
|
||||||
@ -85,8 +78,7 @@ object Image {
|
|||||||
override def bytesPerPixel: Int = 3
|
override def bytesPerPixel: Int = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Gamma-corrected (nonlinear sRGB) format with four RGBA 8-bit channels.
|
||||||
* Gamma-corrected (nonlinear sRGB) format with four RGBA 8-bit channels.
|
|
||||||
*
|
*
|
||||||
* Alpha is still linear. Color is NOT premultiplied by alpha.
|
* Alpha is still linear. Color is NOT premultiplied by alpha.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -33,13 +33,15 @@ class GraphicsImpl extends Graphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object GraphicsImpl {
|
object GraphicsImpl {
|
||||||
class StaticImageImpl private[reference_impl](val owner: GraphicsImpl, val imageBuffer: ImageBuffer) extends Image.Static {
|
class StaticImageImpl private[reference_impl] (val owner: GraphicsImpl, val imageBuffer: ImageBuffer)
|
||||||
|
extends Image.Static {
|
||||||
private[reference_impl] var isDestroyed = false
|
private[reference_impl] var isDestroyed = false
|
||||||
|
|
||||||
override def size: Size2D = imageBuffer.size
|
override def size: Size2D = imageBuffer.size
|
||||||
}
|
}
|
||||||
|
|
||||||
class SurfaceImpl private[reference_impl](val owner: GraphicsImpl, val imageBuffer: ImageBuffer) extends Image.Surface {
|
class SurfaceImpl private[reference_impl] (val owner: GraphicsImpl, val imageBuffer: ImageBuffer)
|
||||||
|
extends Image.Surface {
|
||||||
private[reference_impl] var isDestroyed = false
|
private[reference_impl] var isDestroyed = false
|
||||||
|
|
||||||
override def size: Size2D = imageBuffer.size
|
override def size: Size2D = imageBuffer.size
|
||||||
|
|||||||
@ -5,7 +5,8 @@ import ocelot.desktop.graphics_v2.Image
|
|||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
private[reference_impl] class ImageBuffer(val width: Int, val height: Int, val format: Image.Format, val data: ByteBuffer) {
|
private[reference_impl] class ImageBuffer(val width: Int, val height: Int, val format: Image.Format,
|
||||||
|
val data: ByteBuffer) {
|
||||||
require(width * height * format.bytesPerPixel == data.limit(), "Wrong ImageBuffer data size");
|
require(width * height * format.bytesPerPixel == data.limit(), "Wrong ImageBuffer data size");
|
||||||
|
|
||||||
def this(width: Int, height: Int, format: Image.Format) {
|
def this(width: Int, height: Int, format: Image.Format) {
|
||||||
|
|||||||
@ -5,8 +5,7 @@ import ocelot.desktop.graphics_v2.Image.Format
|
|||||||
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
/**
|
/** Packed linear color with premultiplied color with 8 bits for alpha and 16 bits per color channel.
|
||||||
* Packed linear color with premultiplied color with 8 bits for alpha and 16 bits per color channel.
|
|
||||||
*
|
*
|
||||||
* Has the following layout: A_RR_GG_BB.
|
* Has the following layout: A_RR_GG_BB.
|
||||||
*
|
*
|
||||||
@ -16,13 +15,13 @@ import java.nio.ByteBuffer
|
|||||||
* assuming we only store 8 bits per channel in our images.
|
* assuming we only store 8 bits per channel in our images.
|
||||||
*/
|
*/
|
||||||
private[reference_impl] case class PackedColor(packed: Long) extends AnyVal {
|
private[reference_impl] case class PackedColor(packed: Long) extends AnyVal {
|
||||||
def r16: Short = ((packed >> 32) & 0xFFFF).toShort
|
def r16: Short = ((packed >> 32) & 0xffff).toShort
|
||||||
|
|
||||||
def g16: Short = ((packed >> 16) & 0xFFFF).toShort
|
def g16: Short = ((packed >> 16) & 0xffff).toShort
|
||||||
|
|
||||||
def b16: Short = (packed & 0xFFFF).toShort
|
def b16: Short = (packed & 0xffff).toShort
|
||||||
|
|
||||||
def a8: Byte = ((packed >> 48) & 0xFF).toByte
|
def a8: Byte = ((packed >> 48) & 0xff).toByte
|
||||||
|
|
||||||
def encode(format: Image.Format, offset: Int, data: ByteBuffer): Unit = {
|
def encode(format: Image.Format, offset: Int, data: ByteBuffer): Unit = {
|
||||||
PackedColor.encode(format, offset, data, this)
|
PackedColor.encode(format, offset, data, this)
|
||||||
@ -31,20 +30,20 @@ private[reference_impl] case class PackedColor(packed: Long) extends AnyVal {
|
|||||||
|
|
||||||
private[reference_impl] object PackedColor {
|
private[reference_impl] object PackedColor {
|
||||||
private def pack(r: Short, g: Short, b: Short, a: Short): PackedColor = {
|
private def pack(r: Short, g: Short, b: Short, a: Short): PackedColor = {
|
||||||
PackedColor(((a & 0xFF) << 40) | ((r & 0xFFFF) << 32) | ((g & 0xFFFF) << 16) | (b & 0xFFFF))
|
PackedColor(((a & 0xff) << 40) | ((r & 0xffff) << 32) | ((g & 0xffff) << 16) | (b & 0xffff))
|
||||||
}
|
}
|
||||||
|
|
||||||
private def extend8To16Bits(v: Byte): Short = ((v << 8) | v).toShort
|
private def extend8To16Bits(v: Byte): Short = ((v << 8) | v).toShort
|
||||||
|
|
||||||
private def shrink16To8Bits(v: Short): Byte = (v / 0xFF).toByte
|
private def shrink16To8Bits(v: Short): Byte = (v / 0xff).toByte
|
||||||
|
|
||||||
private def preMultiply(col: Short, alpha: Byte): Short = (col * alpha / 0xFF).toShort
|
private def preMultiply(col: Short, alpha: Byte): Short = (col * alpha / 0xff).toShort
|
||||||
|
|
||||||
private def unPreMultiply(col: Short, alpha: Byte): Short = if (alpha == 0) 0 else (col * 0xFF / alpha).toShort
|
private def unPreMultiply(col: Short, alpha: Byte): Short = if (alpha == 0) 0 else (col * 0xff / alpha).toShort
|
||||||
|
|
||||||
private val Srgb8ToLinear16Lut: Array[Short] = {
|
private val Srgb8ToLinear16Lut: Array[Short] = {
|
||||||
(0 to 0xFF).map { i =>
|
(0 to 0xff).map { i =>
|
||||||
val srgb = i.toFloat / 0xFF.toFloat
|
val srgb = i.toFloat / 0xff.toFloat
|
||||||
|
|
||||||
val linear = if (srgb <= 0.04045) {
|
val linear = if (srgb <= 0.04045) {
|
||||||
srgb / 12.92
|
srgb / 12.92
|
||||||
@ -52,15 +51,15 @@ private[reference_impl] object PackedColor {
|
|||||||
math.pow((srgb + 0.055) / 1.055, 2.4)
|
math.pow((srgb + 0.055) / 1.055, 2.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
(linear * 0xFFFF.toFloat).toShort
|
(linear * 0xffff.toFloat).toShort
|
||||||
}.toArray
|
}.toArray
|
||||||
}
|
}
|
||||||
|
|
||||||
private def srgb8ToLinear16(v: Byte): Short = Srgb8ToLinear16Lut(v)
|
private def srgb8ToLinear16(v: Byte): Short = Srgb8ToLinear16Lut(v)
|
||||||
|
|
||||||
private val Linear16ToSrgb8Lut: Array[Byte] = {
|
private val Linear16ToSrgb8Lut: Array[Byte] = {
|
||||||
(0 to 0xFFFF).map { i =>
|
(0 to 0xffff).map { i =>
|
||||||
val linear = i.toFloat / 0xFFFF.toFloat
|
val linear = i.toFloat / 0xffff.toFloat
|
||||||
|
|
||||||
val srgb = if (linear <= 0.0031308) {
|
val srgb = if (linear <= 0.0031308) {
|
||||||
linear * 12.92
|
linear * 12.92
|
||||||
@ -68,7 +67,7 @@ private[reference_impl] object PackedColor {
|
|||||||
1.055 * math.pow(linear, 1.0 / 2.4) - 0.055
|
1.055 * math.pow(linear, 1.0 / 2.4) - 0.055
|
||||||
}
|
}
|
||||||
|
|
||||||
(srgb * 0xFF.toFloat).toByte
|
(srgb * 0xff.toFloat).toByte
|
||||||
}.toArray
|
}.toArray
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +77,13 @@ private[reference_impl] object PackedColor {
|
|||||||
format match {
|
format match {
|
||||||
case Format.LinearR8 =>
|
case Format.LinearR8 =>
|
||||||
val r = extend8To16Bits(data.get(offset))
|
val r = extend8To16Bits(data.get(offset))
|
||||||
pack(r, r, r, 0xFF)
|
pack(r, r, r, 0xff)
|
||||||
|
|
||||||
case Format.LinearRgb8 =>
|
case Format.LinearRgb8 =>
|
||||||
val r = extend8To16Bits(data.get(offset + 0))
|
val r = extend8To16Bits(data.get(offset + 0))
|
||||||
val g = extend8To16Bits(data.get(offset + 1))
|
val g = extend8To16Bits(data.get(offset + 1))
|
||||||
val b = extend8To16Bits(data.get(offset + 2))
|
val b = extend8To16Bits(data.get(offset + 2))
|
||||||
pack(r, g, b, 0xFF)
|
pack(r, g, b, 0xff)
|
||||||
|
|
||||||
case Format.LinearRgba8 =>
|
case Format.LinearRgba8 =>
|
||||||
val r = extend8To16Bits(data.get(offset + 0))
|
val r = extend8To16Bits(data.get(offset + 0))
|
||||||
@ -97,7 +96,7 @@ private[reference_impl] object PackedColor {
|
|||||||
val r = srgb8ToLinear16(data.get(offset + 0))
|
val r = srgb8ToLinear16(data.get(offset + 0))
|
||||||
val g = srgb8ToLinear16(data.get(offset + 1))
|
val g = srgb8ToLinear16(data.get(offset + 1))
|
||||||
val b = srgb8ToLinear16(data.get(offset + 2))
|
val b = srgb8ToLinear16(data.get(offset + 2))
|
||||||
pack(r, g, b, 0xFF)
|
pack(r, g, b, 0xff)
|
||||||
|
|
||||||
case Format.SrgbRgba8 =>
|
case Format.SrgbRgba8 =>
|
||||||
val a = data.get(offset + 3)
|
val a = data.get(offset + 3)
|
||||||
|
|||||||
@ -27,9 +27,9 @@ class ColorTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("LinearR8 encoding examples") {
|
test("LinearR8 encoding examples") {
|
||||||
checkEncoding(Encoding.LinearR8, Array(0x00.toByte), 0xFF_0000_0000_0000L)
|
checkEncoding(Encoding.LinearR8, Array(0x00.toByte), 0xff_0000_0000_0000L)
|
||||||
checkEncoding(Encoding.LinearR8, Array(0x13.toByte), 0xFF_1313_1313_1313L)
|
checkEncoding(Encoding.LinearR8, Array(0x13.toByte), 0xff_1313_1313_1313L)
|
||||||
checkEncoding(Encoding.LinearR8, Array(0xFF.toByte), 0xFF_FFFF_FFFF_FFFFL)
|
checkEncoding(Encoding.LinearR8, Array(0xff.toByte), 0xff_ffff_ffff_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("LinearR8 encoding round-trip") {
|
test("LinearR8 encoding round-trip") {
|
||||||
@ -39,9 +39,9 @@ class ColorTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("LinearRgb8 encoding examples") {
|
test("LinearRgb8 encoding examples") {
|
||||||
checkEncoding(Encoding.LinearRgb8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte), 0xFF_0000_0000_0000L)
|
checkEncoding(Encoding.LinearRgb8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte), 0xff_0000_0000_0000L)
|
||||||
checkEncoding(Encoding.LinearRgb8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte), 0xFF_1212_3434_5656L)
|
checkEncoding(Encoding.LinearRgb8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte), 0xff_1212_3434_5656L)
|
||||||
checkEncoding(Encoding.LinearRgb8, Array(0xFF.toByte, 0xFF.toByte, 0xFF.toByte), 0xFF_FFFF_FFFF_FFFFL)
|
checkEncoding(Encoding.LinearRgb8, Array(0xff.toByte, 0xff.toByte, 0xff.toByte), 0xff_ffff_ffff_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("LinearRgb8 encoding round-trip") {
|
test("LinearRgb8 encoding round-trip") {
|
||||||
@ -51,9 +51,9 @@ class ColorTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("SrgbRgb8 encoding examples") {
|
test("SrgbRgb8 encoding examples") {
|
||||||
checkEncoding(Encoding.SrgbRgb8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte), 0xFF_0000_0000_0000L)
|
checkEncoding(Encoding.SrgbRgb8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte), 0xff_0000_0000_0000L)
|
||||||
checkEncoding(Encoding.SrgbRgb8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte), 0xFF_018C_08Ca_17D2L)
|
checkEncoding(Encoding.SrgbRgb8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte), 0xff_018c_08ca_17d2L)
|
||||||
checkEncoding(Encoding.SrgbRgb8, Array(0xFF.toByte, 0xFF.toByte, 0xFF.toByte), 0xFF_FFFF_FFFF_FFFFL)
|
checkEncoding(Encoding.SrgbRgb8, Array(0xff.toByte, 0xff.toByte, 0xff.toByte), 0xff_ffff_ffff_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("SrgbRgb8 round-trip") {
|
test("SrgbRgb8 round-trip") {
|
||||||
@ -65,7 +65,7 @@ class ColorTest extends UnitTest {
|
|||||||
test("LinearRgba8 encoding examples") {
|
test("LinearRgba8 encoding examples") {
|
||||||
checkEncoding(Encoding.LinearRgba8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte, 0x00.toByte), 0x00_0000_0000_0000L)
|
checkEncoding(Encoding.LinearRgba8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte, 0x00.toByte), 0x00_0000_0000_0000L)
|
||||||
checkEncoding(Encoding.LinearRgba8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte, 0x42.toByte), 0x42_1212_3434_5656L)
|
checkEncoding(Encoding.LinearRgba8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte, 0x42.toByte), 0x42_1212_3434_5656L)
|
||||||
checkEncoding(Encoding.LinearRgba8, Array(0xFF.toByte, 0xFF.toByte, 0xFF.toByte, 0xFF.toByte), 0xFF_FFFF_FFFF_FFFFL)
|
checkEncoding(Encoding.LinearRgba8, Array(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte), 0xff_ffff_ffff_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("LinearRgba8 encoding round-trip") {
|
test("LinearRgba8 encoding round-trip") {
|
||||||
@ -76,8 +76,8 @@ class ColorTest extends UnitTest {
|
|||||||
|
|
||||||
test("SrgbRgba8 encoding examples") {
|
test("SrgbRgba8 encoding examples") {
|
||||||
checkEncoding(Encoding.SrgbRgba8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte, 0x00.toByte), 0x00_0000_0000_0000L)
|
checkEncoding(Encoding.SrgbRgba8, Array(0x00.toByte, 0x00.toByte, 0x00.toByte, 0x00.toByte), 0x00_0000_0000_0000L)
|
||||||
checkEncoding(Encoding.SrgbRgba8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte, 0x42.toByte), 0x42_018C_08Ca_17D2L)
|
checkEncoding(Encoding.SrgbRgba8, Array(0x12.toByte, 0x34.toByte, 0x56.toByte, 0x42.toByte), 0x42_018c_08ca_17d2L)
|
||||||
checkEncoding(Encoding.SrgbRgba8, Array(0xFF.toByte, 0xFF.toByte, 0xFF.toByte, 0xFF.toByte), 0xFF_FFFF_FFFF_FFFFL)
|
checkEncoding(Encoding.SrgbRgba8, Array(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte), 0xff_ffff_ffff_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("SrgbRgba8 encoding round-trip") {
|
test("SrgbRgba8 encoding round-trip") {
|
||||||
@ -92,18 +92,18 @@ class ColorTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("Alpha blending (opaque foreground)") {
|
test("Alpha blending (opaque foreground)") {
|
||||||
checkAlphaBlending(0xFF_1234_5678_9ABCL, 0xFF_CBA9_8765_4321L, 0xFF_CBA9_8765_4321L);
|
checkAlphaBlending(0xff_1234_5678_9abcL, 0xff_cba9_8765_4321L, 0xff_cba9_8765_4321L);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Alpha blending (white bg + 33% black fg)") {
|
test("Alpha blending (white bg + 33% black fg)") {
|
||||||
checkAlphaBlending(0xFF_FFFF_FFFF_FFFFL, 0x55_0000_0000_0000L, 0xFF_AAAA_AAAA_AAAAL);
|
checkAlphaBlending(0xff_ffff_ffff_ffffL, 0x55_0000_0000_0000L, 0xff_aaaa_aaaa_aaaaL);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Alpha blending (white bg, 50% black fg)") {
|
test("Alpha blending (white bg, 50% black fg)") {
|
||||||
checkAlphaBlending(0xFF_FFFF_FFFF_FFFFL, 0x80_0000_0000_0000L, 0xFF_7F7F_7F7F_7F7FL);
|
checkAlphaBlending(0xff_ffff_ffff_ffffL, 0x80_0000_0000_0000L, 0xff_7f7f_7f7f_7f7fL);
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Alpha blending (33% red bg, 66% cyan fg)") {
|
test("Alpha blending (33% red bg, 66% cyan fg)") {
|
||||||
checkAlphaBlending(0x55_5555_0000_0000L, 0xAA_0000_AAAA_AAAAL, 0xC6_1C72_AAAA_AAAAL);
|
checkAlphaBlending(0x55_5555_0000_0000L, 0xaa_0000_aaaa_aaaaL, 0xc6_1c72_aaaa_aaaaL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,18 +10,18 @@ class LinearRgbaTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("Pure red") {
|
test("Pure red") {
|
||||||
checkConversion(LinearRgba(1.0, 0.0, 0.0, 1.0), 0xFF_FFFF_0000_0000L)
|
checkConversion(LinearRgba(1.0, 0.0, 0.0, 1.0), 0xff_ffff_0000_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure green") {
|
test("Pure green") {
|
||||||
checkConversion(LinearRgba(0.0, 1.0, 0.0, 1.0), 0xFF_0000_FFFF_0000L)
|
checkConversion(LinearRgba(0.0, 1.0, 0.0, 1.0), 0xff_0000_ffff_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure blue") {
|
test("Pure blue") {
|
||||||
checkConversion(LinearRgba(0.0, 0.0, 1.0, 1.0), 0xFF_0000_0000_FFFFL)
|
checkConversion(LinearRgba(0.0, 0.0, 1.0, 1.0), 0xff_0000_0000_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("33% red, 66% blue, 33% alpha") {
|
test("33% red, 66% blue, 33% alpha") {
|
||||||
checkConversion(LinearRgba(1.0 / 3.0, 0.0, 2.0 / 3.0, 1.0 / 3.0), 0x55_5555_0000_AAAAL)
|
checkConversion(LinearRgba(1.0 / 3.0, 0.0, 2.0 / 3.0, 1.0 / 3.0), 0x55_5555_0000_aaaaL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,18 +10,18 @@ class OkhsvTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("Pure red") {
|
test("Pure red") {
|
||||||
checkConversion(Okhsv(29.23388519234263, 0.9995219692256989, 1.0000000001685625, 1), 0xFF_FFFF_0000_0000L)
|
checkConversion(Okhsv(29.23388519234263, 0.9995219692256989, 1.0000000001685625, 1), 0xff_ffff_0000_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure green") {
|
test("Pure green") {
|
||||||
checkConversion(Okhsv(142.49533888780996, 0.9999997210415695, 0.9999999884428648, 1.0), 0xFF_0000_FFFF_0000L)
|
checkConversion(Okhsv(142.49533888780996, 0.9999997210415695, 0.9999999884428648, 1.0), 0xff_0000_ffff_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure blue") {
|
test("Pure blue") {
|
||||||
checkConversion(Okhsv(264.052020638055, 0.9999910912349018, 0.9999999646150918, 1), 0xFF_0000_0000_FFFFL)
|
checkConversion(Okhsv(264.052020638055, 0.9999910912349018, 0.9999999646150918, 1), 0xff_0000_0000_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("33% red, 66% blue, 33% alpha") {
|
test("33% red, 66% blue, 33% alpha") {
|
||||||
checkConversion(Okhsv(311.9937528323292, 1.0005489476783134, 0.8409729279819962, 1.0 / 3.0), 0x55_5555_0000_AAAAL)
|
checkConversion(Okhsv(311.9937528323292, 1.0005489476783134, 0.8409729279819962, 1.0 / 3.0), 0x55_5555_0000_aaaaL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,18 +10,18 @@ class OklabTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("Pure red") {
|
test("Pure red") {
|
||||||
checkConversion(Oklab(0.6279553606145516, 0.22486306106597398, 0.1258462985307351, 1), 0xFF_FFFF_0000_0000L)
|
checkConversion(Oklab(0.6279553606145516, 0.22486306106597398, 0.1258462985307351, 1), 0xff_ffff_0000_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure green") {
|
test("Pure green") {
|
||||||
checkConversion(Oklab(0.8664396115356694, -0.23388757418790818, 0.17949847989672985, 1.0), 0xFF_0000_FFFF_0000L)
|
checkConversion(Oklab(0.8664396115356694, -0.23388757418790818, 0.17949847989672985, 1.0), 0xff_0000_ffff_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure blue") {
|
test("Pure blue") {
|
||||||
checkConversion(Oklab(0.4520137183853429, -0.03245698416876397, -0.3115281476783751, 1), 0xFF_0000_0000_FFFFL)
|
checkConversion(Oklab(0.4520137183853429, -0.03245698416876397, -0.3115281476783751, 1), 0xff_0000_0000_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("33% red, 66% blue, 33% alpha") {
|
test("33% red, 66% blue, 33% alpha") {
|
||||||
checkConversion(Oklab(0.5281181319927706, 0.176826580031683, -0.19642887916863233, 1f / 3f), 0x55_5555_0000_AAAAL)
|
checkConversion(Oklab(0.5281181319927706, 0.176826580031683, -0.19642887916863233, 1f / 3f), 0x55_5555_0000_aaaaL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,18 +10,18 @@ class PackedIntTest extends UnitTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test("Pure red") {
|
test("Pure red") {
|
||||||
checkConversion(PackedInt(0xFF0000), 0xFF_FFFF_0000_0000L)
|
checkConversion(PackedInt(0xff0000), 0xff_ffff_0000_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure green") {
|
test("Pure green") {
|
||||||
checkConversion(PackedInt(0x00FF00), 0xFF_0000_FFFF_0000L)
|
checkConversion(PackedInt(0x00ff00), 0xff_0000_ffff_0000L)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("Pure blue") {
|
test("Pure blue") {
|
||||||
checkConversion(PackedInt(0x0000FF), 0xFF_0000_0000_FFFFL)
|
checkConversion(PackedInt(0x0000ff), 0xff_0000_0000_ffffL)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("33% red, 66% blue") {
|
test("33% red, 66% blue") {
|
||||||
checkConversion(PackedInt(0x5500AA), 0xFF_1741_0000_66E7L)
|
checkConversion(PackedInt(0x5500aa), 0xff_1741_0000_66e7L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user