mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-04 04:27:34 +00:00
214 lines
4.9 KiB
Go
214 lines
4.9 KiB
Go
// Copyright (c) 2022 Sam Blenny
|
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
//
|
|
package lib
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// Holds a matrix of pixel values
|
|
type Matrix [][]int
|
|
|
|
// Holds one row of pixel values from a matrix
|
|
type MatrixRow []int
|
|
|
|
// Return pixel matrix as 16*16px sprite pattern packed into a [u32] array.
|
|
// pat[0:7]: 1-bit pixels packed into u32 words
|
|
//
|
|
// Pixel bit values are intended as a background/foreground mask for use with
|
|
// XOR blit. Color palette is not set. Rather, palette depends on contents of
|
|
// whatever bitmap the blit pattern gets XOR'ed with.
|
|
//
|
|
// Meaning of pixel bit values in blit pattern:
|
|
// - bit=0: keep color of pixel from background bitmap
|
|
// - bit=1: invert color of pixel from background bitmap
|
|
//
|
|
// Pixel packing happens in row-major order (first left to right, then top to
|
|
// bottom) with the glyph's top-left pixel placed in the least significant bit
|
|
// of the first pixel word.
|
|
func (m Matrix) convertToPattern() []uint32 {
|
|
// Pack trimmed pattern into a byte array
|
|
wide := len(m[0])
|
|
high := len(m)
|
|
pattern := []uint32{}
|
|
bufWord := uint32(0)
|
|
bits := 0
|
|
for y := 0; y < high; y++ {
|
|
for x := 0; x < wide; x++ {
|
|
shift := ((y % 2) * 16) + x
|
|
bufWord |= uint32(m[y][x]) << shift
|
|
bits += 1
|
|
if bits == 32 {
|
|
pattern = append(pattern, bufWord)
|
|
bufWord = 0
|
|
bits = 0
|
|
}
|
|
}
|
|
}
|
|
if bits > 0 {
|
|
finalShift := 32 - bits
|
|
bufWord <<= finalShift
|
|
pattern = append(pattern, bufWord)
|
|
}
|
|
return pattern
|
|
}
|
|
|
|
func (m Matrix) convertToPattern32() []uint32 {
|
|
// Pack trimmed pattern into a byte array
|
|
wide := len(m[0])
|
|
high := len(m)
|
|
pattern := []uint32{}
|
|
bufWord := uint32(0)
|
|
bits := 0
|
|
for y := 0; y < high; y++ {
|
|
for x := 0; x < wide; x++ {
|
|
bufWord |= uint32(m[y][x]) << x
|
|
bits += 1
|
|
if bits == 32 {
|
|
pattern = append(pattern, bufWord)
|
|
bufWord = 0
|
|
bits = 0
|
|
}
|
|
}
|
|
}
|
|
if bits > 0 {
|
|
finalShift := 32 - bits
|
|
bufWord <<= finalShift
|
|
pattern = append(pattern, bufWord)
|
|
}
|
|
return pattern
|
|
}
|
|
|
|
// Trim pixel matrix to remove whitespace around the glyph. Return the trimmed
|
|
// matrix and the y-offset (pixels of top whitespace that were trimmed).
|
|
func (m Matrix) Trim(font FontSpec, row int, col int) Matrix {
|
|
// Trim left whitespace
|
|
trblTrimLimit := font.TrimLimits(row, col)
|
|
m = m.transpose()
|
|
m = m.trimLeadingEmptyRows(trblTrimLimit[3])
|
|
// Trim right whitespace
|
|
m = m.reverseRows()
|
|
m = m.trimLeadingEmptyRows(trblTrimLimit[1])
|
|
m = m.reverseRows()
|
|
m = m.transpose()
|
|
// Don't trim top whitespace
|
|
// Don't trim bottom whitespace
|
|
return m
|
|
}
|
|
|
|
// Pad a matrix to 16x16, adding padding to the right and bottom
|
|
func (m Matrix) padTo16x16() Matrix {
|
|
// Make an empty 16x16 destination matrix
|
|
dest := Matrix{}
|
|
for y := 0; y < 16; y++ {
|
|
row := MatrixRow{}
|
|
for x := 0; x < 16; x++ {
|
|
row = append(row, 0)
|
|
}
|
|
dest = append(dest, row)
|
|
}
|
|
// Copy pixels from source matrix to top-left of destination matrix
|
|
wide := len(m[0])
|
|
high := len(m)
|
|
for y := 0; y < high; y++ {
|
|
for x := 0; x < wide; x++ {
|
|
dest[y][x] = m[y][x]
|
|
}
|
|
}
|
|
return dest
|
|
}
|
|
|
|
// Pad a matrix to 32x32, adding padding to the right and bottom
|
|
func (m Matrix) padTo32x32() Matrix {
|
|
// Make an empty 32x32 destination matrix
|
|
dest := Matrix{}
|
|
for y := 0; y < 32; y++ {
|
|
row := MatrixRow{}
|
|
for x := 0; x < 32; x++ {
|
|
row = append(row, 0)
|
|
}
|
|
dest = append(dest, row)
|
|
}
|
|
// Copy pixels from source matrix to top-left of destination matrix
|
|
wide := len(m[0])
|
|
high := len(m)
|
|
for y := 0; y < high; y++ {
|
|
for x := 0; x < wide; x++ {
|
|
dest[y][x] = m[y][x]
|
|
}
|
|
}
|
|
return dest
|
|
}
|
|
|
|
// Transpose a matrix (flip around diagonal)
|
|
func (m Matrix) transpose() Matrix {
|
|
if len(m) < 1 {
|
|
return m
|
|
}
|
|
w := len(m[0])
|
|
h := len(m)
|
|
var transposed Matrix
|
|
for col := 0; col < w; col++ {
|
|
var trRow []int
|
|
for row := 0; row < h; row++ {
|
|
trRow = append(trRow, m[row][col])
|
|
}
|
|
transposed = append(transposed, trRow)
|
|
}
|
|
return transposed
|
|
}
|
|
|
|
// Reverse the order of rows in a matrix
|
|
func (m Matrix) reverseRows() Matrix {
|
|
var reversed Matrix
|
|
for i := len(m) - 1; i >= 0; i-- {
|
|
reversed = append(reversed, m[i])
|
|
}
|
|
return reversed
|
|
}
|
|
|
|
// Trim whitespace rows from top of matrix
|
|
func (m Matrix) trimLeadingEmptyRows(limit int) Matrix {
|
|
if len(m) < 1 {
|
|
return m
|
|
}
|
|
for i := 0; i < limit; i++ {
|
|
sum := 0
|
|
for _, n := range m[0] {
|
|
sum += n
|
|
}
|
|
if len(m) > 0 && sum == 0 {
|
|
m = m[1:]
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
// Dump an ASCII art approximation of the blit pattern to stdout. This can help
|
|
// with troubleshooting character map setup when adding a new font.
|
|
func (m Matrix) Debug(cs CharSpec, enable bool) {
|
|
if enable {
|
|
cp := cs.Hex
|
|
fmt.Printf("%X:\n", cp)
|
|
fmt.Println(m.convertToText())
|
|
}
|
|
}
|
|
|
|
// Return glyph as text with one ASCII char per pixel
|
|
func (m Matrix) convertToText() string {
|
|
var ascii string
|
|
for _, row := range m {
|
|
for _, px := range row {
|
|
if px == 1 {
|
|
ascii += "█" // "\u2588"
|
|
} else {
|
|
ascii += "."
|
|
}
|
|
}
|
|
ascii += "\n"
|
|
}
|
|
return ascii
|
|
}
|