ui: basic map scroller
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
package world
|
||||
|
||||
// RenderPlan describes the full expanded-canvas redraw plan for one RenderParams.
|
||||
// It is a pure description: it does not execute any drawing.
|
||||
type RenderPlan struct {
|
||||
CanvasWidthPx int
|
||||
CanvasHeightPx int
|
||||
|
||||
ZoomFp int
|
||||
|
||||
// WorldRect is the unwrapped world-space rect covered by the expanded canvas.
|
||||
WorldRect Rect
|
||||
|
||||
// Tiles are ordered in the same order as produced by tileWorldRect:
|
||||
// increasing tile X index, then increasing tile Y index.
|
||||
Tiles []TileDrawPlan
|
||||
}
|
||||
|
||||
// TileDrawPlan describes how to draw one torus tile contribution.
|
||||
type TileDrawPlan struct {
|
||||
Tile WorldTile
|
||||
|
||||
// Clip rect on the expanded canvas in pixel coordinates.
|
||||
// It is half-open in spirit: [ClipX, ClipX+ClipW) x [ClipY, ClipY+ClipH).
|
||||
ClipX int
|
||||
ClipY int
|
||||
ClipW int
|
||||
ClipH int
|
||||
|
||||
// Candidates are unique per tile (deduped by ID).
|
||||
Candidates []MapItem
|
||||
}
|
||||
|
||||
// worldSpanFixedToCanvasPx converts a world fixed-point span into a canvas pixel span
|
||||
// for the given fixed-point zoom. The conversion is truncating (floor).
|
||||
func worldSpanFixedToCanvasPx(spanWorldFp, zoomFp int) int {
|
||||
// spanWorldFp can be negative in some internal cases, but for clip computations
|
||||
// we always pass non-negative spans.
|
||||
return (spanWorldFp * zoomFp) / (SCALE * SCALE)
|
||||
}
|
||||
|
||||
// buildRenderPlanStageA builds a full expanded-canvas redraw plan (Stage A).
|
||||
//
|
||||
// It assumes the world grid is already built (IndexOnViewportChange called).
|
||||
// The plan contains per-tile clip rectangles and per-tile candidate lists
|
||||
// from the spatial index.
|
||||
func (w *World) buildRenderPlanStageA(params RenderParams) (RenderPlan, error) {
|
||||
if err := params.Validate(); err != nil {
|
||||
return RenderPlan{}, err
|
||||
}
|
||||
|
||||
zoomFp, err := params.CameraZoomFp()
|
||||
if err != nil {
|
||||
return RenderPlan{}, err
|
||||
}
|
||||
|
||||
worldRect, err := params.ExpandedCanvasWorldRect()
|
||||
if err != nil {
|
||||
return RenderPlan{}, err
|
||||
}
|
||||
|
||||
tiles := tileWorldRect(worldRect, w.W, w.H)
|
||||
|
||||
// Query candidates per tile.
|
||||
batches, err := w.collectCandidatesForTiles(tiles)
|
||||
if err != nil {
|
||||
return RenderPlan{}, err
|
||||
}
|
||||
|
||||
planTiles := make([]TileDrawPlan, 0, len(batches))
|
||||
|
||||
for _, batch := range batches {
|
||||
tile := batch.Tile
|
||||
|
||||
// Convert the tile's canonical rect + offsets into the unwrapped segment.
|
||||
segMinX := tile.Rect.minX + tile.OffsetX
|
||||
segMaxX := tile.Rect.maxX + tile.OffsetX
|
||||
segMinY := tile.Rect.minY + tile.OffsetY
|
||||
segMaxY := tile.Rect.maxY + tile.OffsetY
|
||||
|
||||
// Map that segment into expanded canvas pixel coordinates relative to worldRect.minX/minY.
|
||||
clipX := worldSpanFixedToCanvasPx(segMinX-worldRect.minX, zoomFp)
|
||||
clipY := worldSpanFixedToCanvasPx(segMinY-worldRect.minY, zoomFp)
|
||||
clipX2 := worldSpanFixedToCanvasPx(segMaxX-worldRect.minX, zoomFp)
|
||||
clipY2 := worldSpanFixedToCanvasPx(segMaxY-worldRect.minY, zoomFp)
|
||||
|
||||
clipW := clipX2 - clipX
|
||||
clipH := clipY2 - clipY
|
||||
|
||||
planTiles = append(planTiles, TileDrawPlan{
|
||||
Tile: tile,
|
||||
ClipX: clipX,
|
||||
ClipY: clipY,
|
||||
ClipW: clipW,
|
||||
ClipH: clipH,
|
||||
Candidates: batch.Items,
|
||||
})
|
||||
}
|
||||
|
||||
return RenderPlan{
|
||||
CanvasWidthPx: params.CanvasWidthPx(),
|
||||
CanvasHeightPx: params.CanvasHeightPx(),
|
||||
ZoomFp: zoomFp,
|
||||
WorldRect: worldRect,
|
||||
Tiles: planTiles,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user