93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
package generator
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
const (
|
|
alphaTransparent uint32 = 64
|
|
alphaOpaque uint32 = 940
|
|
)
|
|
|
|
func packAlphaBlock(dst []byte, samples [3]uint32) {
|
|
const mask uint32 = 0x3ff
|
|
|
|
word := samples[0]&mask |
|
|
(samples[1]&mask)<<10 |
|
|
(samples[2]&mask)<<20
|
|
|
|
binary.LittleEndian.PutUint32(dst, word)
|
|
}
|
|
|
|
func fillAlphaPlane(
|
|
dst []byte,
|
|
width, height int,
|
|
value uint32,
|
|
) error {
|
|
need := AlphaFrameSize(width, height)
|
|
if len(dst) < need {
|
|
return fmt.Errorf(
|
|
"alpha: destination is too small: got %d bytes, need %d",
|
|
len(dst),
|
|
need,
|
|
)
|
|
}
|
|
|
|
stride := AlphaLineSize(width)
|
|
for y := 0; y < height; y++ {
|
|
row := dst[y*stride : (y+1)*stride]
|
|
for x := 0; x < width; x += 3 {
|
|
var samples [3]uint32
|
|
for i := range samples {
|
|
if x+i < width {
|
|
samples[i] = value
|
|
}
|
|
}
|
|
packAlphaBlock(row[x/3*4:], samples)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func patchAlphaMovingSquare(dst []byte, width, height, frameIndex int) error {
|
|
need := AlphaFrameSize(width, height)
|
|
if len(dst) < need {
|
|
return fmt.Errorf(
|
|
"alpha: destination is too small: got %d bytes, need %d",
|
|
len(dst),
|
|
need,
|
|
)
|
|
}
|
|
|
|
bounds := movingSquareBounds(width, height, frameIndex)
|
|
firstPixelX := max(0, int(math.Floor(bounds.minX)))
|
|
lastPixelX := min(width, int(math.Ceil(bounds.maxX)))
|
|
firstBlockX := firstPixelX / 3 * 3
|
|
lastBlockX := min(width, (lastPixelX+2)/3*3)
|
|
firstY := max(0, int(math.Floor(bounds.minY)))
|
|
lastY := min(height, int(math.Ceil(bounds.maxY)))
|
|
stride := AlphaLineSize(width)
|
|
|
|
for y := firstY; y < lastY; y++ {
|
|
for blockX := firstBlockX; blockX < lastBlockX; blockX += 3 {
|
|
var samples [3]uint32
|
|
for i := range samples {
|
|
x := blockX + i
|
|
switch {
|
|
case x >= width:
|
|
samples[i] = 0
|
|
case bounds.contains(x, y):
|
|
samples[i] = alphaTransparent
|
|
default:
|
|
samples[i] = alphaOpaque
|
|
}
|
|
}
|
|
offset := y*stride + blockX/3*4
|
|
packAlphaBlock(dst[offset:], samples)
|
|
}
|
|
}
|
|
return nil
|
|
}
|