world refactor

This commit is contained in:
Ilia Denisov
2026-03-17 11:48:05 +02:00
committed by GitHub
parent 9208ef1065
commit 5029857fe4
82 changed files with 9838 additions and 9715 deletions
+360 -7
View File
@@ -12,12 +12,17 @@ var (
errIDExhausted = errors.New("primitive id exhausted")
)
// indexState stores the viewport-dependent parameters required to rebuild the
// spatial grid after object or style-affecting mutations.
type indexState struct {
initialized bool
viewportW int
viewportH int
zoomFp int
}
// derivedStyleKey identifies one cached derived style by its base style and
// stable override fingerprint.
type derivedStyleKey struct {
base StyleID
fp uint64
@@ -163,7 +168,7 @@ func (w *World) SetTheme(theme StyleTheme) {
w.themeDefaultCircleStyleID = w.styles.AddStyle(theme.CircleStyle())
w.themeDefaultPointStyleID = w.styles.AddStyle(theme.PointStyle())
w.reresolveThemeManagedStyles()
w.refreshThemeManagedStyles()
// Full redraw to apply new background and base styles.
w.renderState.Reset()
@@ -183,7 +188,9 @@ func (w *World) themeBaseStyleID(base styleBase) StyleID {
}
}
func (w *World) reresolveThemeManagedStyles() {
// refreshThemeManagedStyles recomputes resolved StyleID values for primitives
// that track the active theme rather than a fixed explicit style.
func (w *World) refreshThemeManagedStyles() {
th := w.Theme()
for id, it := range w.objects {
@@ -243,13 +250,15 @@ func (w *World) reresolveThemeManagedStyles() {
w.objects[id] = v
default:
panic("reresolveThemeManagedStyles: unknown item type")
panic("refreshThemeManagedStyles: unknown item type")
}
}
w.ForceFullRedrawNext()
}
// derivedStyleID resolves a derived style, reusing the per-world cache when an
// identical base style and override combination has already been materialized.
func (w *World) derivedStyleID(base StyleID, ov StyleOverride) StyleID {
if ov.IsZero() {
return base
@@ -297,7 +306,7 @@ func (w *World) rebuildIndexFromLastState() {
return
}
w.indexOnViewportChangeZoomFp(w.index.viewportW, w.index.viewportH, w.index.zoomFp)
w.rebuildIndexForViewportZoomFp(w.index.viewportW, w.index.viewportH, w.index.zoomFp)
w.indexDirty = false
}
@@ -598,12 +607,16 @@ func (w *World) IndexOnViewportChange(viewportWidthPx, viewportHeightPx int, cam
w.index.viewportH = viewportHeightPx
w.index.zoomFp = zoomFp
w.indexOnViewportChangeZoomFp(viewportWidthPx, viewportHeightPx, zoomFp)
w.rebuildIndexForViewportZoomFp(viewportWidthPx, viewportHeightPx, zoomFp)
w.indexDirty = false
}
// indexOnViewportChangeZoomFp performs indexing logic using fixed-point zoom.
func (w *World) indexOnViewportChangeZoomFp(viewportWidthPx, viewportHeightPx int, zoomFp int) {
// rebuildIndexForViewportZoomFp rebuilds the spatial grid for a particular
// viewport size and fixed-point zoom.
//
// The chosen cell size is derived from the currently visible world span and
// then clamped into the package-wide cell-size bounds.
func (w *World) rebuildIndexForViewportZoomFp(viewportWidthPx, viewportHeightPx int, zoomFp int) {
worldWidth, worldHeight := viewportPxToWorldFixed(viewportWidthPx, viewportHeightPx, zoomFp)
cellsAcrossMin := 8
@@ -659,3 +672,343 @@ func circleRadiusEffFp(rawRadiusFp, circleRadiusScaleFp int) int {
}
return int(v)
}
// PointClassID classifies Point primitives for theme-level style overrides.
//
// Themes may use the class to derive a final style from the point base style
// without changing the primitive geometry itself.
type PointClassID uint8
const (
// PointClassDefault selects the theme's default point styling.
PointClassDefault PointClassID = iota
// PointClassTrackUnknown marks a point as an unknown track marker.
PointClassTrackUnknown
// PointClassTrackIncoming marks a point as an incoming track marker.
PointClassTrackIncoming
// PointClassTrackOutgoing marks a point as an outgoing track marker.
PointClassTrackOutgoing
)
// LineClassID classifies Line primitives for theme-level style overrides.
type LineClassID uint8
const (
// LineClassDefault selects the theme's default line styling.
LineClassDefault LineClassID = iota
// LineClassTrackIncoming marks a line as an incoming track.
LineClassTrackIncoming
// LineCLassTrackOutgoing marks a line as an outgoing track.
// The unusual spelling is preserved for backward compatibility.
LineCLassTrackOutgoing
// LineClassMeasurement marks a line as a measurement helper.
LineClassMeasurement
)
// CircleClassID classifies Circle primitives for theme-level style overrides.
type CircleClassID uint8
const (
// CircleClassDefault selects the theme's default circle styling.
CircleClassDefault CircleClassID = iota
// CircleClassHome marks a circle as a home-world area.
CircleClassHome
// CircleClassAcquired marks a circle as an acquired world area.
CircleClassAcquired
// CircleClassOccupied marks a circle as an occupied world area.
CircleClassOccupied
// CircleClassFree marks a circle as a free world area.
CircleClassFree
)
// PrimitiveID is a compact stable identifier for primitives stored in the World.
// It is allocated by the World and may be reused after deletion (free-list).
type PrimitiveID uint32
// MapItem is the common interface implemented by all world primitives.
type MapItem interface {
ID() PrimitiveID
}
// styleBase describes how a primitive resolves its base style across theme changes.
type styleBase uint8
const (
styleBaseFixed styleBase = iota
styleBaseThemeLine
styleBaseThemeCircle
styleBaseThemePoint
)
// Point is a point primitive in fixed-point world coordinates.
type Point struct {
Id PrimitiveID
X, Y int
// Priority controls per-object draw ordering. Smaller draws earlier.
Priority int
// StyleID references a resolved style in the world's style table.
StyleID StyleID
// Theme style binding. If Base==styleBaseFixed => StyleID stays as-is across theme changes.
Base styleBase
// Override is applied relative to current theme base style (only when Base is theme* and Override is non-zero).
Override StyleOverride
Class PointClassID
// HitSlopPx expands hit-test radius in screen pixels (per-object override).
// 0 means "use primitive default".
HitSlopPx int
}
// Line is a line segment primitive in fixed-point world coordinates.
type Line struct {
Id PrimitiveID
X1, Y1 int
X2, Y2 int
// Priority controls per-object draw ordering. Smaller draws earlier.
Priority int
// StyleID references a resolved style in the world's style table.
StyleID StyleID
// Theme style binding. If Base==styleBaseFixed => StyleID stays as-is across theme changes.
Base styleBase
// Override is applied relative to current theme base style (only when Base is theme* and Override is non-zero).
Override StyleOverride
Class LineClassID
// HitSlopPx expands hit-test radius in screen pixels (per-object override).
// 0 means "use primitive default".
HitSlopPx int
}
// Circle is a circle primitive in fixed-point world coordinates.
type Circle struct {
Id PrimitiveID
X, Y int
Radius int
// Priority controls per-object draw ordering. Smaller draws earlier.
Priority int
// StyleID references a resolved style in the world's style table.
StyleID StyleID
// Theme style binding. If Base==styleBaseFixed => StyleID stays as-is across theme changes.
Base styleBase
// Override is applied relative to current theme base style (only when Base is theme* and Override is non-zero).
Override StyleOverride
Class CircleClassID
// HitSlopPx expands hit-test radius in screen pixels (per-object override).
// 0 means "use primitive default".
HitSlopPx int
}
// ID returns the point identifier.
func (p Point) ID() PrimitiveID { return p.Id }
// ID returns the line identifier.
func (l Line) ID() PrimitiveID { return l.Id }
// ID returns the circle identifier.
func (c Circle) ID() PrimitiveID { return c.Id }
// MinX returns the minimum X endpoint coordinate of the line.
func (l Line) MinX() int { return min(l.X1, l.X2) }
// MaxX returns the maximum X endpoint coordinate of the line.
func (l Line) MaxX() int { return max(l.X1, l.X2) }
// MinY returns the minimum Y endpoint coordinate of the line.
func (l Line) MinY() int { return min(l.Y1, l.Y2) }
// MaxY returns the maximum Y endpoint coordinate of the line.
func (l Line) MaxY() int { return max(l.Y1, l.Y2) }
// MinX returns the minimum X coordinate of the circle bbox.
func (c Circle) MinX() int { return c.X - c.Radius }
// MaxX returns the maximum X coordinate of the circle bbox.
func (c Circle) MaxX() int { return c.X + c.Radius }
// MinY returns the minimum Y coordinate of the circle bbox.
func (c Circle) MinY() int { return c.Y - c.Radius }
// MaxY returns the maximum Y coordinate of the circle bbox.
func (c Circle) MaxY() int { return c.Y + c.Radius }
// PointOpt applies optional point-construction parameters to PointOptions.
type PointOpt func(*PointOptions)
// PointOptions stores optional arguments accepted by World.AddPoint.
//
// Defaults are resolved before applying user-provided PointOpt values.
type PointOptions struct {
Priority int
StyleID StyleID
Override StyleOverride
Class PointClassID
HitSlopPx int
hasStyleID bool
}
// defaultPointOptions returns the default option set used by World.AddPoint.
func defaultPointOptions() PointOptions {
return PointOptions{
Priority: DefaultPriorityPoint,
StyleID: StyleIDDefaultPoint,
Class: PointClassDefault,
}
}
// PointWithPriority sets point draw priority.
//
// Lower priorities render earlier within the same tile.
func PointWithPriority(p int) PointOpt {
return func(o *PointOptions) {
o.Priority = p
}
}
// PointWithStyleID forces the point to use a pre-registered style.
func PointWithStyleID(id StyleID) PointOpt {
return func(o *PointOptions) {
o.StyleID = id
o.hasStyleID = true
// Explicit style ID wins over overrides.
o.Override = StyleOverride{}
}
}
// PointWithClass selects the theme class used for point style resolution.
func PointWithClass(c PointClassID) PointOpt {
return func(o *PointOptions) { o.Class = c }
}
// PointWithStyleOverride applies a user override on top of the resolved point base style.
//
// If PointWithStyleID is also supplied, the explicit style ID wins.
func PointWithStyleOverride(ov StyleOverride) PointOpt {
return func(o *PointOptions) {
o.Override = ov
}
}
// PointWithHitSlopPx overrides the default point hit slop in screen pixels.
func PointWithHitSlopPx(px int) PointOpt {
return func(o *PointOptions) { o.HitSlopPx = px }
}
// CircleOpt applies optional circle-construction parameters to CircleOptions.
type CircleOpt func(*CircleOptions)
// CircleOptions stores optional arguments accepted by World.AddCircle.
type CircleOptions struct {
Priority int
StyleID StyleID
Override StyleOverride
Class CircleClassID
HitSlopPx int
hasStyleID bool
}
// defaultCircleOptions returns the default option set used by World.AddCircle.
func defaultCircleOptions() CircleOptions {
return CircleOptions{
Priority: DefaultPriorityCircle,
StyleID: StyleIDDefaultCircle,
Class: CircleClassDefault,
}
}
// CircleWithPriority sets circle draw priority.
func CircleWithPriority(p int) CircleOpt {
return func(o *CircleOptions) {
o.Priority = p
}
}
// CircleWithStyleID forces the circle to use a pre-registered style.
func CircleWithStyleID(id StyleID) CircleOpt {
return func(o *CircleOptions) {
o.StyleID = id
o.hasStyleID = true
o.Override = StyleOverride{}
}
}
// CircleWithClass selects the theme class used for circle style resolution.
func CircleWithClass(c CircleClassID) CircleOpt {
return func(o *CircleOptions) { o.Class = c }
}
// CircleWithStyleOverride applies a user override on top of the resolved circle base style.
func CircleWithStyleOverride(ov StyleOverride) CircleOpt {
return func(o *CircleOptions) {
o.Override = ov
}
}
// CircleWithHitSlopPx overrides the default circle hit slop in screen pixels.
func CircleWithHitSlopPx(px int) CircleOpt {
return func(o *CircleOptions) { o.HitSlopPx = px }
}
// LineOpt applies optional line-construction parameters to LineOptions.
type LineOpt func(*LineOptions)
// LineOptions stores optional arguments accepted by World.AddLine.
type LineOptions struct {
Priority int
StyleID StyleID
Override StyleOverride
Class LineClassID
HitSlopPx int
hasStyleID bool
}
// defaultLineOptions returns the default option set used by World.AddLine.
func defaultLineOptions() LineOptions {
return LineOptions{
Priority: DefaultPriorityLine,
StyleID: StyleIDDefaultLine,
Class: LineClassDefault,
}
}
// LineWithPriority sets line draw priority.
func LineWithPriority(p int) LineOpt {
return func(o *LineOptions) {
o.Priority = p
}
}
// LineWithStyleID forces the line to use a pre-registered style.
func LineWithStyleID(id StyleID) LineOpt {
return func(o *LineOptions) {
o.StyleID = id
o.hasStyleID = true
o.Override = StyleOverride{}
}
}
// LineWithClass selects the theme class used for line style resolution.
func LineWithClass(c LineClassID) LineOpt {
return func(o *LineOptions) { o.Class = c }
}
// LineWithStyleOverride applies a user override on top of the resolved line base style.
func LineWithStyleOverride(ov StyleOverride) LineOpt {
return func(o *LineOptions) {
o.Override = ov
}
}
// LineWithHitSlopPx overrides the default line hit slop in screen pixels.
func LineWithHitSlopPx(px int) LineOpt {
return func(o *LineOptions) { o.HitSlopPx = px }
}