ui: basic map scroller
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestDrawLinesFromPlan_WrapX_SplitsAndDrawsInThreeXTiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
w := NewWorld(10, 10)
|
||||
w.resetGrid(2 * SCALE)
|
||||
|
||||
// Horizontal line that wraps across X: 9 -> 1 at y=5.
|
||||
id, err := w.AddLine(9, 5, 1, 5)
|
||||
require.NoError(t, err)
|
||||
w.indexObject(w.objects[id])
|
||||
|
||||
params := RenderParams{
|
||||
ViewportWidthPx: 10,
|
||||
ViewportHeightPx: 10,
|
||||
MarginXPx: 2,
|
||||
MarginYPx: 2,
|
||||
CameraXWorldFp: 5 * SCALE,
|
||||
CameraYWorldFp: 5 * SCALE,
|
||||
CameraZoom: 1.0,
|
||||
}
|
||||
|
||||
plan, err := w.buildRenderPlanStageA(params)
|
||||
require.NoError(t, err)
|
||||
|
||||
d := &fakePrimitiveDrawer{}
|
||||
drawLinesFromPlan(d, plan, w.W, w.H)
|
||||
|
||||
// Expect drawing in 3 X tiles (left partial, middle full, right partial) for the central Y tile:
|
||||
// Each tile group: Save, ClipRect, AddLine(s), Stroke, Restore
|
||||
//
|
||||
// Left tile (offsetX=-10000): 1 line segment.
|
||||
// Middle tile (offsetX=0): 2 segments (wrapped split).
|
||||
// Right tile (offsetX=10000): 1 segment.
|
||||
wantNames := []string{
|
||||
"Save", "ClipRect", "AddLine", "Stroke", "Restore",
|
||||
"Save", "ClipRect", "AddLine", "AddLine", "Stroke", "Restore",
|
||||
"Save", "ClipRect", "AddLine", "Stroke", "Restore",
|
||||
}
|
||||
require.Equal(t, wantNames, d.CommandNames())
|
||||
|
||||
// Group 1: left strip clip (0,2,2,10), line at y=7 from x=1..2
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 1), 0, 2, 2, 10)
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 2), 1, 7, 2, 7)
|
||||
}
|
||||
|
||||
// Group 2: middle strip clip (2,2,10,10), two segments:
|
||||
// segment [9000..10000] => x 11..12, y 7
|
||||
// segment [0..1000] => x 2..3, y 7
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 6), 2, 2, 10, 10)
|
||||
|
||||
// The order of segments is stable with our splitting: first the one ending at boundary, then the remainder.
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 7), 11, 7, 12, 7)
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 8), 2, 7, 3, 7)
|
||||
}
|
||||
|
||||
// Group 3: right strip clip (12,2,2,10), line at y=7 from x=12..13
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 12), 12, 2, 2, 10) // ClipRect
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 13), 12, 7, 13, 7) // AddLine
|
||||
}
|
||||
}
|
||||
|
||||
func TestDrawLinesFromPlan_WrapY_SplitsAndDrawsInThreeYTiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
w := NewWorld(10, 10)
|
||||
w.resetGrid(2 * SCALE)
|
||||
|
||||
// Vertical line that wraps across Y: 9 -> 1 at x=5.
|
||||
id, err := w.AddLine(5, 9, 5, 1)
|
||||
require.NoError(t, err)
|
||||
w.indexObject(w.objects[id])
|
||||
|
||||
params := RenderParams{
|
||||
ViewportWidthPx: 10,
|
||||
ViewportHeightPx: 10,
|
||||
MarginXPx: 2,
|
||||
MarginYPx: 2,
|
||||
CameraXWorldFp: 5 * SCALE,
|
||||
CameraYWorldFp: 5 * SCALE,
|
||||
CameraZoom: 1.0,
|
||||
}
|
||||
|
||||
plan, err := w.buildRenderPlanStageA(params)
|
||||
require.NoError(t, err)
|
||||
|
||||
d := &fakePrimitiveDrawer{}
|
||||
drawLinesFromPlan(d, plan, w.W, w.H)
|
||||
|
||||
// Here we expect 3 Y tiles for the central X tile:
|
||||
// Top partial, middle full (two segments), bottom partial.
|
||||
//
|
||||
// The exact ordering of tiles is by tx then ty, so X=middle strips first.
|
||||
// For this geometry the line only intersects the middle X tiles (offsetX=0),
|
||||
// but spans Y across -1,0,1.
|
||||
wantNames := []string{
|
||||
"Save", "ClipRect", "AddLine", "Stroke", "Restore",
|
||||
"Save", "ClipRect", "AddLine", "AddLine", "Stroke", "Restore",
|
||||
"Save", "ClipRect", "AddLine", "Stroke", "Restore",
|
||||
}
|
||||
require.Equal(t, wantNames, d.CommandNames())
|
||||
|
||||
// Group 1: top strip clip (2,0,10,2), line at x=7 from y=1..2
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 1), 2, 0, 10, 2)
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 2), 7, 1, 7, 2)
|
||||
}
|
||||
|
||||
// Group 2: middle strip clip (2,2,10,10), two segments:
|
||||
// segment [9000..10000] => y 11..12 at x=7
|
||||
// segment [0..1000] => y 2..3 at x=7
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 6), 2, 2, 10, 10)
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 7), 7, 11, 7, 12)
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 8), 7, 2, 7, 3)
|
||||
}
|
||||
|
||||
// Group 3: bottom strip clip (2,12,10,2), line at x=7 from y=12..13
|
||||
{
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 12), 2, 12, 10, 2) // ClipRect
|
||||
requireCommandArgs(t, requireDrawerCommandAt(t, d, 13), 7, 12, 7, 13) // AddLine
|
||||
}
|
||||
}
|
||||
|
||||
func TestTorusShortestLineSegments_TieCaseIsDeterministicAndSplits(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// World 10 units => 10000 fixed.
|
||||
worldW := 10 * SCALE
|
||||
worldH := 10 * SCALE
|
||||
|
||||
// Tie-case along X: 1 -> 6 is exactly half world apart (dx = +5000).
|
||||
// Deterministic rule chooses negative delta representation (wrap is applied).
|
||||
l := Line{
|
||||
X1: 1 * SCALE, Y1: 5 * SCALE,
|
||||
X2: 6 * SCALE, Y2: 5 * SCALE,
|
||||
}
|
||||
|
||||
segs := torusShortestLineSegments(l, worldW, worldH)
|
||||
|
||||
// Expect two horizontal segments:
|
||||
// [6000..10000] and [0..1000] at y=5000.
|
||||
require.Len(t, segs, 2)
|
||||
|
||||
// Direction is deterministic and follows the chosen negative-delta representation.
|
||||
require.Equal(t, lineSeg{x1: 1000, y1: 5000, x2: 0, y2: 5000}, segs[0])
|
||||
require.Equal(t, lineSeg{x1: 10000, y1: 5000, x2: 6000, y2: 5000}, segs[1])
|
||||
}
|
||||
Reference in New Issue
Block a user