152 lines
4.0 KiB
Go
152 lines
4.0 KiB
Go
package world
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type bgOffsetScaleTheme struct {
|
|
img image.Image
|
|
anchor BackgroundAnchorMode
|
|
}
|
|
|
|
func (t bgOffsetScaleTheme) ID() string { return "bgoffset" }
|
|
func (t bgOffsetScaleTheme) Name() string { return "bgoffset" }
|
|
|
|
func (t bgOffsetScaleTheme) BackgroundColor() color.Color { return color.RGBA{A: 255} }
|
|
func (t bgOffsetScaleTheme) BackgroundImage() image.Image { return t.img }
|
|
|
|
func (t bgOffsetScaleTheme) BackgroundTileMode() BackgroundTileMode { return BackgroundTileRepeat }
|
|
func (t bgOffsetScaleTheme) BackgroundScaleMode() BackgroundScaleMode { return BackgroundScaleNone }
|
|
func (t bgOffsetScaleTheme) BackgroundAnchorMode() BackgroundAnchorMode { return t.anchor }
|
|
|
|
func (t bgOffsetScaleTheme) PointStyle() Style {
|
|
return Style{FillColor: color.RGBA{A: 255}, PointRadiusPx: 2}
|
|
}
|
|
func (t bgOffsetScaleTheme) LineStyle() Style {
|
|
return Style{StrokeColor: color.RGBA{A: 255}, StrokeWidthPx: 1}
|
|
}
|
|
func (t bgOffsetScaleTheme) CircleStyle() Style {
|
|
return Style{FillColor: color.RGBA{A: 255}, StrokeColor: color.RGBA{A: 255}, StrokeWidthPx: 1}
|
|
}
|
|
|
|
func (t bgOffsetScaleTheme) PointClassOverride(PointClassID) (StyleOverride, bool) {
|
|
return StyleOverride{}, false
|
|
}
|
|
func (t bgOffsetScaleTheme) LineClassOverride(LineClassID) (StyleOverride, bool) {
|
|
return StyleOverride{}, false
|
|
}
|
|
func (t bgOffsetScaleTheme) CircleClassOverride(CircleClassID) (StyleOverride, bool) {
|
|
return StyleOverride{}, false
|
|
}
|
|
|
|
func TestRender_BackgroundTileRepeat_WorldAnchored_ShiftsWithPan(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
w := NewWorld(20, 20)
|
|
w.resetGrid(2 * SCALE)
|
|
|
|
img := image.NewRGBA(image.Rect(0, 0, 4, 4)) // tile 4x4
|
|
w.SetTheme(bgOffsetScaleTheme{img: img, anchor: BackgroundAnchorWorld})
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 8,
|
|
ViewportHeightPx: 8,
|
|
MarginXPx: 0,
|
|
MarginYPx: 0,
|
|
CameraXWorldFp: 5 * SCALE,
|
|
CameraYWorldFp: 5 * SCALE,
|
|
CameraZoom: 1.0,
|
|
}
|
|
|
|
// First render.
|
|
d1 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d1, params))
|
|
|
|
minX1, minY1 := minDrawImageXY(t, d1)
|
|
require.Equal(t, -1, minX1)
|
|
require.Equal(t, -1, minY1)
|
|
|
|
// Pan camera by +1 world unit along both axes (zoom=1 => 1px).
|
|
params2 := params
|
|
params2.CameraXWorldFp += 1 * SCALE
|
|
params2.CameraYWorldFp += 1 * SCALE
|
|
|
|
// Force full redraw to make this test independent of incremental pipeline.
|
|
w.ForceFullRedrawNext()
|
|
|
|
d2 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d2, params2))
|
|
|
|
minX2, minY2 := minDrawImageXY(t, d2)
|
|
|
|
// With world anchoring, moving camera +1 shifts the tiling origin by -1 (mod tile size).
|
|
require.Equal(t, -2, minX2)
|
|
require.Equal(t, -2, minY2)
|
|
}
|
|
|
|
func TestRender_BackgroundTileRepeat_ViewportAnchored_DoesNotShiftWithPan(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
w := NewWorld(20, 20)
|
|
w.resetGrid(2 * SCALE)
|
|
|
|
img := image.NewRGBA(image.Rect(0, 0, 4, 4))
|
|
w.SetTheme(bgOffsetScaleTheme{img: img, anchor: BackgroundAnchorViewport})
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 8,
|
|
ViewportHeightPx: 8,
|
|
MarginXPx: 0,
|
|
MarginYPx: 0,
|
|
CameraXWorldFp: 5 * SCALE,
|
|
CameraYWorldFp: 5 * SCALE,
|
|
CameraZoom: 1.0,
|
|
}
|
|
|
|
d1 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d1, params))
|
|
|
|
minX1, minY1 := minDrawImageXY(t, d1)
|
|
|
|
params2 := params
|
|
params2.CameraXWorldFp += 1 * SCALE
|
|
params2.CameraYWorldFp += 1 * SCALE
|
|
|
|
w.ForceFullRedrawNext()
|
|
|
|
d2 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d2, params2))
|
|
|
|
minX2, minY2 := minDrawImageXY(t, d2)
|
|
|
|
// With viewport anchoring, tiling origin is fixed (no camera dependency).
|
|
require.Equal(t, minX1, minX2)
|
|
require.Equal(t, minY1, minY2)
|
|
}
|
|
|
|
func minDrawImageXY(t *testing.T, d *fakePrimitiveDrawer) (int, int) {
|
|
t.Helper()
|
|
|
|
cmds := d.CommandsByName("DrawImage")
|
|
require.NotEmpty(t, cmds, "expected DrawImage calls from background tiling")
|
|
|
|
minX := int(cmds[0].Args[0])
|
|
minY := int(cmds[0].Args[1])
|
|
|
|
for _, c := range cmds[1:] {
|
|
x := int(c.Args[0])
|
|
y := int(c.Args[1])
|
|
if x < minX {
|
|
minX = x
|
|
}
|
|
if y < minY {
|
|
minY = y
|
|
}
|
|
}
|
|
return minX, minY
|
|
}
|