Skip to content

Commit 5baef4d

Browse files
committed
feat: Use nearest-neighbor scaling in pi.Stretch
Because it is more accurate than the current algorithm and the performance is similar.
1 parent 610a13e commit 5baef4d

File tree

12 files changed

+105
-14
lines changed

12 files changed

+105
-14
lines changed
223 Bytes
Loading
223 Bytes
Loading
223 Bytes
Loading
223 Bytes
Loading
226 Bytes
Loading
229 Bytes
Loading
234 Bytes
Loading
232 Bytes
Loading

internal/test/stretch/sprite.png

224 Bytes
Loading

sprite.go

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package pi
55

66
import (
77
"fmt"
8+
"github.com/elgopher/pi/pimath"
89
)
910

1011
// DrawSprite draws the given sprite at (dx, dy) on the current draw target.
@@ -72,31 +73,45 @@ func Stretch(sprite Sprite, dx, dy, dw, dh int) {
7273
targetStride := drawTarget.width - int(dst.W)
7374
srcSource := sprite.Source
7475

75-
if sprite.FlipY {
76-
src.Y += float64(dh-1) * stepY
77-
stepY *= -1
78-
}
76+
stepXAbs := src.W / dst.W
77+
stepYAbs := src.H / dst.H
7978

79+
// start sampling from half-step offsets
8080
if sprite.FlipX {
81-
src.X += float64(dw-1) * stepX
82-
stepX *= -1
81+
src.X += src.W - stepXAbs/2
82+
stepXAbs = -stepXAbs
83+
} else {
84+
src.X += stepXAbs / 2
8385
}
8486

85-
srcX, srcY := src.X, src.Y
87+
if sprite.FlipY {
88+
src.Y += src.H - stepYAbs/2
89+
stepYAbs = -stepYAbs
90+
} else {
91+
src.Y += stepYAbs / 2
92+
}
93+
94+
srcY := src.Y
95+
96+
srcMaxX := int(src.X + src.W)
97+
srcMaxY := int(src.Y + src.H)
8698

8799
for line := 0.0; line < dst.H; line++ {
88-
srcLineIdx := int(srcY) * srcSource.width // multiplication, but only once per line, so it's not a performance problem
100+
syIndex := pimath.Clamp(int(srcY), 0, srcMaxY-1)
101+
srcLineIdx := syIndex * srcSource.width
102+
103+
srcX := src.X
104+
for cell := 0; cell < int(dst.W); cell++ {
105+
sxIndex := pimath.Clamp(int(srcX), 0, srcMaxX-1)
89106

90-
for cell := 0.0; cell < dst.W; cell++ {
91-
sourceColor := srcSource.data[srcLineIdx+int(srcX)] & ReadMask
107+
sourceColor := srcSource.data[srcLineIdx+sxIndex] & ReadMask
92108
targetColor := drawTarget.data[targetIdx] & TargetMask
93109
drawTarget.data[targetIdx] =
94110
ColorTables[(sourceColor|targetColor)>>6][sourceColor&(MaxColors-1)][targetColor&(MaxColors-1)]
95-
srcX += stepX
111+
srcX += stepXAbs
96112
targetIdx++
97113
}
98-
srcX = src.X
99-
srcY += stepY
114+
srcY += stepYAbs
100115
targetIdx += targetStride
101116
}
102117
}

0 commit comments

Comments
 (0)