alpha patterns
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPackAlphaBlock(t *testing.T) {
|
||||
var dst [4]byte
|
||||
packAlphaBlock(dst[:], [3]uint32{64, 512, 940})
|
||||
|
||||
word := binary.LittleEndian.Uint32(dst[:])
|
||||
|
||||
if got := word & 0x3ff; got != 64 {
|
||||
t.Errorf("sample 0 = %d, want 64", got)
|
||||
}
|
||||
if got := (word >> 10) & 0x3ff; got != 512 {
|
||||
t.Errorf("sample 1 = %d, want 512", got)
|
||||
}
|
||||
if got := (word >> 20) & 0x3ff; got != 940 {
|
||||
t.Errorf("sample 2 = %d, want 940", got)
|
||||
}
|
||||
if got := word >> 30; got != 0 {
|
||||
t.Errorf("unused bits = %d, want 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackAlphaBlockMasksSamples(t *testing.T) {
|
||||
var dst [4]byte
|
||||
packAlphaBlock(dst[:], [3]uint32{0x401, 0x802, 0xc03})
|
||||
|
||||
word := binary.LittleEndian.Uint32(dst[:])
|
||||
|
||||
if got := word & 0x3ff; got != 1 {
|
||||
t.Errorf("sample 0 = %d, want 1", got)
|
||||
}
|
||||
if got := (word >> 10) & 0x3ff; got != 2 {
|
||||
t.Errorf("sample 1 = %d, want 2", got)
|
||||
}
|
||||
if got := (word >> 20) & 0x3ff; got != 3 {
|
||||
t.Errorf("sample 2 = %d, want 3", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillAlphaPlaneCompleteBlocks(t *testing.T) {
|
||||
const width, height = 6, 2
|
||||
dst := make([]byte, AlphaFrameSize(width, height))
|
||||
if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil {
|
||||
t.Fatalf("fillAlphaPlane: %v", err)
|
||||
}
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
if got := sampleAlpha(dst, width, x, y); got != alphaOpaque {
|
||||
t.Errorf("sample (%d,%d) = %d, want %d", x, y, got, alphaOpaque)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillAlphaPlaneZerosPartialBlockPadding(t *testing.T) {
|
||||
const width, height = 4, 2
|
||||
dst := make([]byte, AlphaFrameSize(width, height))
|
||||
if err := fillAlphaPlane(dst, width, height, alphaTransparent); err != nil {
|
||||
t.Fatalf("fillAlphaPlane: %v", err)
|
||||
}
|
||||
|
||||
stride := AlphaLineSize(width)
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
if got := sampleAlpha(dst, width, x, y); got != alphaTransparent {
|
||||
t.Errorf("sample (%d,%d) = %d, want %d", x, y, got, alphaTransparent)
|
||||
}
|
||||
}
|
||||
lastWord := binary.LittleEndian.Uint32(dst[y*stride+4:])
|
||||
if got := (lastWord >> 10) & 0x3ff; got != 0 {
|
||||
t.Errorf("row %d padding sample 1 = %d, want 0", y, got)
|
||||
}
|
||||
if got := (lastWord >> 20) & 0x3ff; got != 0 {
|
||||
t.Errorf("row %d padding sample 2 = %d, want 0", y, got)
|
||||
}
|
||||
if got := lastWord >> 30; got != 0 {
|
||||
t.Errorf("row %d unused bits = %d, want 0", y, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFillAlphaPlaneRejectsSmallDestination(t *testing.T) {
|
||||
const width, height = 6, 2
|
||||
dst := make([]byte, AlphaFrameSize(width, height)-1)
|
||||
err := fillAlphaPlane(dst, width, height, alphaOpaque)
|
||||
if err == nil || !strings.Contains(err.Error(), "destination is too small") {
|
||||
t.Fatalf("error = %v, want destination size error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchAlphaMovingSquare(t *testing.T) {
|
||||
const width, height = 304, 200
|
||||
dst := make([]byte, AlphaFrameSize(width, height))
|
||||
if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil {
|
||||
t.Fatalf("fillAlphaPlane: %v", err)
|
||||
}
|
||||
if err := patchAlphaMovingSquare(dst, width, height, 0); err != nil {
|
||||
t.Fatalf("patchAlphaMovingSquare: %v", err)
|
||||
}
|
||||
|
||||
if got := sampleAlpha(dst, width, width/2, height/2); got != alphaTransparent {
|
||||
t.Errorf("square center = %d, want transparent %d", got, alphaTransparent)
|
||||
}
|
||||
if got := sampleAlpha(dst, width, 10, height/2); got != alphaOpaque {
|
||||
t.Errorf("outside square = %d, want opaque %d", got, alphaOpaque)
|
||||
}
|
||||
|
||||
// At frame zero the square begins at x=77. Its first three-sample word
|
||||
// therefore contains two opaque samples followed by one transparent sample.
|
||||
for x, want := range []uint32{alphaOpaque, alphaOpaque, alphaTransparent} {
|
||||
if got := sampleAlpha(dst, width, 75+x, height/2); got != want {
|
||||
t.Errorf("boundary sample x=%d = %d, want %d", 75+x, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchAlphaMovingSquarePreservesPartialBlockPadding(t *testing.T) {
|
||||
const width, height = 100, 200
|
||||
dst := make([]byte, AlphaFrameSize(width, height))
|
||||
if err := fillAlphaPlane(dst, width, height, alphaOpaque); err != nil {
|
||||
t.Fatalf("fillAlphaPlane: %v", err)
|
||||
}
|
||||
if err := patchAlphaMovingSquare(dst, width, height, 0); err != nil {
|
||||
t.Fatalf("patchAlphaMovingSquare: %v", err)
|
||||
}
|
||||
|
||||
lastWordOffset := height/2*AlphaLineSize(width) + (width/3)*4
|
||||
lastWord := binary.LittleEndian.Uint32(dst[lastWordOffset:])
|
||||
if got := lastWord & 0x3ff; got != alphaTransparent {
|
||||
t.Errorf("last visible sample = %d, want %d", got, alphaTransparent)
|
||||
}
|
||||
if got := lastWord >> 10; got != 0 {
|
||||
t.Errorf("partial-block padding bits = %#x, want 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatchAlphaMovingSquareRejectsSmallDestination(t *testing.T) {
|
||||
const width, height = 100, 200
|
||||
err := patchAlphaMovingSquare(
|
||||
make([]byte, AlphaFrameSize(width, height)-1),
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
)
|
||||
if err == nil || !strings.Contains(err.Error(), "destination is too small") {
|
||||
t.Fatalf("error = %v, want destination size error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func sampleAlpha(buf []byte, width, x, y int) uint32 {
|
||||
offset := y*AlphaLineSize(width) + x/3*4
|
||||
word := binary.LittleEndian.Uint32(buf[offset:])
|
||||
return (word >> uint(x%3*10)) & 0x3ff
|
||||
}
|
||||
Reference in New Issue
Block a user