diff --git a/apgbpal.go b/apgbpal.go index d3e9e28..d469ab3 100644 --- a/apgbpal.go +++ b/apgbpal.go @@ -1,5 +1,11 @@ package main +import ( + "fmt" + "strings" + "log" +) + type RGBA struct { R byte G byte @@ -11,6 +17,45 @@ 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 { @@ -28,6 +73,20 @@ func (b BGPal) Bytes() [20]byte { 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 { @@ -47,12 +106,37 @@ func (o OBJPal) Bytes(indexchar byte) [18]byte { 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 - OBJ2 OBJPal } func (a APGBPal) Bytes() [56]byte { - -} \ No newline at end of file + 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 +} +