gx: implement C1.over(C2), add gx.cyan and gx.magenta, fix + and - ops, add more tests
parent
a4fb5d2cfd
commit
afd3ca8273
114
vlib/gx/color.v
114
vlib/gx/color.v
|
@ -1,9 +1,19 @@
|
||||||
module gx
|
module gx
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
blue = Color{
|
black = Color{
|
||||||
r: 0
|
r: 0
|
||||||
g: 0
|
g: 0
|
||||||
|
b: 0
|
||||||
|
}
|
||||||
|
gray = Color{
|
||||||
|
r: 128
|
||||||
|
g: 128
|
||||||
|
b: 128
|
||||||
|
}
|
||||||
|
white = Color{
|
||||||
|
r: 255
|
||||||
|
g: 255
|
||||||
b: 255
|
b: 255
|
||||||
}
|
}
|
||||||
red = Color{
|
red = Color{
|
||||||
|
@ -16,11 +26,26 @@ pub const (
|
||||||
g: 255
|
g: 255
|
||||||
b: 0
|
b: 0
|
||||||
}
|
}
|
||||||
|
blue = Color{
|
||||||
|
r: 0
|
||||||
|
g: 0
|
||||||
|
b: 255
|
||||||
|
}
|
||||||
yellow = Color{
|
yellow = Color{
|
||||||
r: 255
|
r: 255
|
||||||
g: 255
|
g: 255
|
||||||
b: 0
|
b: 0
|
||||||
}
|
}
|
||||||
|
magenta = Color{
|
||||||
|
r: 255
|
||||||
|
g: 0
|
||||||
|
b: 255
|
||||||
|
}
|
||||||
|
cyan = Color{
|
||||||
|
r: 0
|
||||||
|
g: 255
|
||||||
|
b: 255
|
||||||
|
}
|
||||||
orange = Color{
|
orange = Color{
|
||||||
r: 255
|
r: 255
|
||||||
g: 165
|
g: 165
|
||||||
|
@ -31,16 +56,6 @@ pub const (
|
||||||
g: 0
|
g: 0
|
||||||
b: 128
|
b: 128
|
||||||
}
|
}
|
||||||
black = Color{
|
|
||||||
r: 0
|
|
||||||
g: 0
|
|
||||||
b: 0
|
|
||||||
}
|
|
||||||
gray = Color{
|
|
||||||
r: 128
|
|
||||||
g: 128
|
|
||||||
b: 128
|
|
||||||
}
|
|
||||||
indigo = Color{
|
indigo = Color{
|
||||||
r: 75
|
r: 75
|
||||||
g: 0
|
g: 0
|
||||||
|
@ -56,11 +71,6 @@ pub const (
|
||||||
g: 130
|
g: 130
|
||||||
b: 238
|
b: 238
|
||||||
}
|
}
|
||||||
white = Color{
|
|
||||||
r: 255
|
|
||||||
g: 255
|
|
||||||
b: 255
|
|
||||||
}
|
|
||||||
dark_blue = Color{
|
dark_blue = Color{
|
||||||
r: 0
|
r: 0
|
||||||
g: 0
|
g: 0
|
||||||
|
@ -139,21 +149,55 @@ pub fn rgba(r byte, g byte, b byte, a byte) Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c Color) + (c2 Color) Color {
|
// + adds `b` to `a`, with a maximum value of 255 for each channel
|
||||||
|
pub fn (a Color) + (b Color) Color {
|
||||||
|
mut na := int(a.a) + b.a
|
||||||
|
mut nr := int(a.r) + b.r
|
||||||
|
mut ng := int(a.g) + b.g
|
||||||
|
mut nb := int(a.b) + b.b
|
||||||
|
if na > 255 {
|
||||||
|
na = 255
|
||||||
|
}
|
||||||
|
if nr > 255 {
|
||||||
|
nr = 255
|
||||||
|
}
|
||||||
|
if ng > 255 {
|
||||||
|
ng = 255
|
||||||
|
}
|
||||||
|
if nb > 255 {
|
||||||
|
nb = 255
|
||||||
|
}
|
||||||
return Color{
|
return Color{
|
||||||
r: c.r + c2.r
|
r: byte(nr)
|
||||||
g: c.g + c2.g
|
g: byte(ng)
|
||||||
b: c.b + c2.b
|
b: byte(nb)
|
||||||
a: c.a + c2.a
|
a: byte(na)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (c Color) - (c2 Color) Color {
|
// - subtracts `b` from `a`, with a minimum value of 0 for each channel
|
||||||
|
pub fn (a Color) - (b Color) Color {
|
||||||
|
mut na := if a.a > b.a { a.a } else { b.a }
|
||||||
|
mut nr := int(a.r) - b.r
|
||||||
|
mut ng := int(a.g) - b.g
|
||||||
|
mut nb := int(a.b) - b.b
|
||||||
|
if na < 0 {
|
||||||
|
na = 0
|
||||||
|
}
|
||||||
|
if nr < 0 {
|
||||||
|
nr = 0
|
||||||
|
}
|
||||||
|
if ng < 0 {
|
||||||
|
ng = 0
|
||||||
|
}
|
||||||
|
if nb < 0 {
|
||||||
|
nb = 0
|
||||||
|
}
|
||||||
return Color{
|
return Color{
|
||||||
r: c.r - c2.r
|
r: byte(nr)
|
||||||
g: c.g - c2.g
|
g: byte(ng)
|
||||||
b: c.b - c2.b
|
b: byte(nb)
|
||||||
a: c.a - c2.a
|
a: byte(na)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,6 +219,24 @@ pub fn (c Color) / (c2 Color) Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// over - implements an `a` over `b` operation.
|
||||||
|
// see https://keithp.com/~keithp/porterduff/p253-porter.pdf
|
||||||
|
pub fn (a Color) over(b Color) Color {
|
||||||
|
aa := f32(a.a) / 255
|
||||||
|
ab := f32(b.a) / 255
|
||||||
|
ar := aa + ab * (1 - aa)
|
||||||
|
//
|
||||||
|
rr := (f32(a.r) * aa + f32(b.r) * ab * (1 - aa)) / ar
|
||||||
|
gr := (f32(a.g) * aa + f32(b.g) * ab * (1 - aa)) / ar
|
||||||
|
br := (f32(a.b) * aa + f32(b.b) * ab * (1 - aa)) / ar
|
||||||
|
return Color{
|
||||||
|
r: byte(rr)
|
||||||
|
g: byte(gr)
|
||||||
|
b: byte(br)
|
||||||
|
a: byte(ar * 255)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (c Color) eq(c2 Color) bool {
|
pub fn (c Color) eq(c2 Color) bool {
|
||||||
return c.r == c2.r && c.g == c2.g && c.b == c2.b && c.a == c2.a
|
return c.r == c2.r && c.g == c2.g && c.b == c2.b && c.a == c2.a
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,38 +4,47 @@ fn test_hex() {
|
||||||
// valid colors
|
// valid colors
|
||||||
a := gx.hex(0x6c5ce7ff)
|
a := gx.hex(0x6c5ce7ff)
|
||||||
b := gx.rgba(108, 92, 231, 255)
|
b := gx.rgba(108, 92, 231, 255)
|
||||||
assert a.eq(b)
|
assert a == b
|
||||||
// doesn't give right value with short hex value
|
// doesn't give right value with short hex value
|
||||||
short := gx.hex(0xfff)
|
short := gx.hex(0xfff)
|
||||||
assert !short.eq(gx.white)
|
assert short != gx.white
|
||||||
|
assert short == gx.Color{0, 0, 15, 255}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_add() {
|
fn test_add() {
|
||||||
a := gx.rgba(100, 100, 100, 100)
|
a := gx.rgba(100, 100, 100, 100)
|
||||||
b := gx.rgba(100, 100, 100, 100)
|
b := gx.rgba(100, 100, 100, 100)
|
||||||
r := gx.rgba(200, 200, 200, 200)
|
r := gx.rgba(200, 200, 200, 200)
|
||||||
assert (a + b).eq(r)
|
assert (a + b) == r
|
||||||
|
//
|
||||||
|
assert gx.red + gx.green == gx.yellow
|
||||||
|
assert gx.red + gx.blue == gx.magenta
|
||||||
|
assert gx.green + gx.blue == gx.cyan
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_sub() {
|
fn test_sub() {
|
||||||
a := gx.rgba(100, 100, 100, 100)
|
a := gx.rgba(100, 100, 100, 50)
|
||||||
b := gx.rgba(100, 100, 100, 100)
|
b := gx.rgba(100, 100, 100, 100)
|
||||||
r := gx.rgba(0, 0, 0, 0)
|
r := gx.rgba(0, 0, 0, 100)
|
||||||
assert (a - b).eq(r)
|
assert (a - b) == r
|
||||||
|
//
|
||||||
|
assert gx.white - gx.green == gx.magenta
|
||||||
|
assert gx.white - gx.blue == gx.yellow
|
||||||
|
assert gx.white - gx.red == gx.cyan
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_mult() {
|
fn test_mult() {
|
||||||
a := gx.rgba(10, 10, 10, 10)
|
a := gx.rgba(10, 10, 10, 10)
|
||||||
b := gx.rgba(10, 10, 10, 10)
|
b := gx.rgba(10, 10, 10, 10)
|
||||||
r := gx.rgba(100, 100, 100, 100)
|
r := gx.rgba(100, 100, 100, 100)
|
||||||
assert (a * b).eq(r)
|
assert (a * b) == r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_div() {
|
fn test_div() {
|
||||||
a := gx.rgba(100, 100, 100, 100)
|
a := gx.rgba(100, 100, 100, 100)
|
||||||
b := gx.rgba(10, 10, 10, 10)
|
b := gx.rgba(10, 10, 10, 10)
|
||||||
r := gx.rgba(10, 10, 10, 10)
|
r := gx.rgba(10, 10, 10, 10)
|
||||||
assert (a / b).eq(r)
|
assert (a / b) == r
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_rgba8() {
|
fn test_rgba8() {
|
||||||
|
@ -61,3 +70,32 @@ fn test_abgr8() {
|
||||||
assert gx.green.abgr8() == -16711936
|
assert gx.green.abgr8() == -16711936
|
||||||
assert gx.blue.abgr8() == -65536
|
assert gx.blue.abgr8() == -65536
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_over() {
|
||||||
|
// shorten names:
|
||||||
|
r := gx.red
|
||||||
|
g := gx.green
|
||||||
|
b := gx.blue
|
||||||
|
y := gx.yellow
|
||||||
|
semi_r := gx.Color{255, 0, 0, 128}
|
||||||
|
semi_g := gx.Color{0, 255, 0, 128}
|
||||||
|
semi_b := gx.Color{0, 0, 255, 128}
|
||||||
|
// fully opaque colors, should be preserved when layed *over* any others:
|
||||||
|
assert b.over(g) == b
|
||||||
|
assert r.over(g) == r
|
||||||
|
assert y.over(r) == y
|
||||||
|
assert g.over(r) == g
|
||||||
|
|
||||||
|
// half transparent pure colors, *over* pure colors, should preserve them correspondingly:
|
||||||
|
assert semi_r.over(r) == gx.Color{255, 0, 0, 255} // preserve pure red
|
||||||
|
assert semi_r.over(g) == gx.Color{128, 126, 0, 255}
|
||||||
|
assert semi_r.over(b) == gx.Color{128, 0, 126, 255}
|
||||||
|
|
||||||
|
assert semi_g.over(r) == gx.Color{126, 128, 0, 255}
|
||||||
|
assert semi_g.over(g) == gx.Color{0, 255, 0, 255} // preserve pure green
|
||||||
|
assert semi_g.over(b) == gx.Color{0, 128, 126, 255}
|
||||||
|
|
||||||
|
assert semi_b.over(r) == gx.Color{126, 0, 128, 255}
|
||||||
|
assert semi_b.over(g) == gx.Color{0, 126, 128, 255}
|
||||||
|
assert semi_b.over(b) == gx.Color{0, 0, 255, 255} // preserve pure blue
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue