apgbpal/apgbpal.go
2023-12-09 20:50:15 -08:00

143 lines
2.6 KiB
Go

package main
import (
"fmt"
"strings"
"log"
)
type RGBA struct {
R byte
G byte
B byte
A byte
}
func (c RGBA) Bytes() [4]byte {
return [4]byte {c.R, c.G, cB, c.A}
}
func HexByteAt(str string, index int) (byte, error) {
if len(string) < index + 2 {
return 0, fmt.Errorf("no hex byte at %d in too short string %q", index, str)
}
big, err := strconv.ParseUint(str[index:index+1], 16, 8)
if err != nil {
return 0, fmt.Errorf("can't parse hex byte at %d in string %q: %w", index, str, err)
}
return byte(big), nil
}
func MustParseRGBA(str string) RGBA {
s := strings.TrimSpace(str)
s = strings.ToLower(s)
s, _ = strings.CutPrefix(s, "#")
var ret RGBA
switch len(s) {
case 6:
ret.A = 0xFF
case 8:
var err error
ret.A, err = HexByteAt(s, 6)
if err != nil {
log.Fatalf("can't parse alpha channel: %v", err)
}
default:
log.Fatalf("%q is not an RGBA value: wrong length after trimming", str)
}
if ret.R, err := HexByteAt(s, 0); err != nil {
log.Fatalf("can't parse red channel: %v", err)
}
if ret.G, err := HexByteAt(s, 2); err != nil {
log.Fatalf("can't parse green channel: %v", err)
}
if ret.B, err := HexByteAt(s, 4); err != nil {
log.Fatalf("can't parse blue channel: %v", err)
}
}
type BGPal [4]RGBA
func (b BGPal) Bytes() [20]byte {
var ret [20]byte
ret[0] = 'b'
ret[1] = 'g'
ret[2] = ':'
for c := 0; c < 4; c++ {
bb := b[c].Bytes()
for i := 0; i < 4; i++ {
ret[3+i+4*c]=bb[i]
}
}
ret[19] = '\n'
return ret
}
func MustParseBGPal(strs []string) BGPal {
if len(strs) != 4 {
log.Fatalf("MustParseBGPal requires length 4, got %d", len(strs))
}
var ret BGPal
for i := 0; i < 4; i++ {
ret[i], err := MustParseRGBA(strs[i])
if err != nil {
log.Fatalf("MustParseBGPal can't parse at %d: %v", i, err)
}
}
return ret
}
type OBJPal [3]RGBA
func (o OBJPal) Bytes(indexchar byte) [18]byte {
var ret [18]byte
ret[0] = 'o'
ret[1] = 'b'
ret[2] = 'j'
ret[3] = indexchar
ret[4] = ':'
for c := 0; c < 3; c++ {
oo := o[c].Bytes()
for i := 0; i < 4; i++ {
ret[5+i+4*c]=oo[i]
}
}
ret[17] = '\n'
return ret
}
func MustParseOBJPal {
if len(strs) != 3 {
log.Fatalf("MustParseObjPal requires length 3, got %d", len(strs))
}
var ret OBJPal
for i := 0; i < 3; i++ {
ret[i], err := MustParseRGBA(strs[i])
if err != nil {
log.Fatalf("MustParseOBJPal can't parse at %d: %v", i, err)
}
}
return ret
}
type APGBPal struct {
BG BGPal
OBJ0 OBJPal
OBJ1 OBJPal
}
func (a APGBPal) Bytes() [56]byte {
var ret [56]byte
for i, b := range a.BG.Bytes() {
ret[i] = b
}
for i, b := range a.OBJ0.Bytes('0') {
ret[i+20] = b
}
for i, b := range a.OBJ1.Bytes('1') {
ret[i+38] = b
}
return ret
}