feat: primitive styling
This commit is contained in:
+99
-9
@@ -21,6 +21,7 @@ type World struct {
|
||||
rows, cols int
|
||||
objects map[uuid.UUID]MapItem
|
||||
renderState rendererIncrementalState
|
||||
styles *StyleTable
|
||||
}
|
||||
|
||||
// NewWorld constructs a new world with the given real dimensions.
|
||||
@@ -34,6 +35,7 @@ func NewWorld(width, height int) *World {
|
||||
H: height * SCALE,
|
||||
cellSize: 1,
|
||||
objects: make(map[uuid.UUID]MapItem),
|
||||
styles: NewStyleTable(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,46 +48,88 @@ func (g *World) checkCoordinate(xf, yf int) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// AddStyleLine creates a new line style derived from the default line style.
|
||||
func (g *World) AddStyleLine(override StyleOverride) StyleID {
|
||||
return g.styles.AddDerived(StyleIDDefaultLine, override)
|
||||
}
|
||||
|
||||
// AddStyleCircle creates a new circle style derived from the default circle style.
|
||||
func (g *World) AddStyleCircle(override StyleOverride) StyleID {
|
||||
return g.styles.AddDerived(StyleIDDefaultCircle, override)
|
||||
}
|
||||
|
||||
// AddStylePoint creates a new point style derived from the default point style.
|
||||
func (g *World) AddStylePoint(override StyleOverride) StyleID {
|
||||
return g.styles.AddDerived(StyleIDDefaultPoint, override)
|
||||
}
|
||||
|
||||
// AddPoint validates and stores a point primitive in the world.
|
||||
// The input coordinates are given in real world units and are converted
|
||||
// to fixed-point before validation.
|
||||
func (g *World) AddPoint(x, y float64) (uuid.UUID, error) {
|
||||
func (g *World) AddPoint(x, y float64, opts ...PointOpt) (uuid.UUID, error) {
|
||||
xf := fixedPoint(x)
|
||||
yf := fixedPoint(y)
|
||||
|
||||
if ok := g.checkCoordinate(xf, yf); !ok {
|
||||
return uuid.Nil, errBadCoordinate
|
||||
}
|
||||
|
||||
o := defaultPointOptions()
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(&o)
|
||||
}
|
||||
}
|
||||
styleID := g.resolvePointStyleID(o)
|
||||
|
||||
id := uuid.New()
|
||||
g.objects[id] = Point{Id: id, X: xf, Y: yf}
|
||||
g.objects[id] = Point{
|
||||
Id: id,
|
||||
X: xf,
|
||||
Y: yf,
|
||||
Priority: o.Priority,
|
||||
StyleID: styleID,
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// AddCircle validates and stores a circle primitive in the world.
|
||||
// The center and radius are given in real world units and are converted
|
||||
// to fixed-point before validation. A zero radius is allowed.
|
||||
func (g *World) AddCircle(x, y, r float64) (uuid.UUID, error) {
|
||||
func (g *World) AddCircle(x, y, r float64, opts ...CircleOpt) (uuid.UUID, error) {
|
||||
xf := fixedPoint(x)
|
||||
yf := fixedPoint(y)
|
||||
rf := fixedPoint(r)
|
||||
|
||||
if ok := g.checkCoordinate(xf, yf); !ok {
|
||||
return uuid.Nil, errBadCoordinate
|
||||
}
|
||||
if rf < 0 {
|
||||
if r < 0 {
|
||||
return uuid.Nil, errBadRadius
|
||||
}
|
||||
|
||||
o := defaultCircleOptions()
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(&o)
|
||||
}
|
||||
}
|
||||
styleID := g.resolveCircleStyleID(o)
|
||||
|
||||
id := uuid.New()
|
||||
g.objects[id] = Circle{Id: id, X: xf, Y: yf, Radius: rf}
|
||||
g.objects[id] = Circle{
|
||||
Id: id,
|
||||
X: xf,
|
||||
Y: yf,
|
||||
Radius: fixedPoint(r),
|
||||
Priority: o.Priority,
|
||||
StyleID: styleID,
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
// AddLine validates and stores a line primitive in the world.
|
||||
// The endpoints are given in real world units and are converted
|
||||
// to fixed-point before validation.
|
||||
func (g *World) AddLine(x1, y1, x2, y2 float64) (uuid.UUID, error) {
|
||||
func (g *World) AddLine(x1, y1, x2, y2 float64, opts ...LineOpt) (uuid.UUID, error) {
|
||||
x1f := fixedPoint(x1)
|
||||
y1f := fixedPoint(y1)
|
||||
x2f := fixedPoint(x2)
|
||||
@@ -98,11 +142,57 @@ func (g *World) AddLine(x1, y1, x2, y2 float64) (uuid.UUID, error) {
|
||||
return uuid.Nil, errBadCoordinate
|
||||
}
|
||||
|
||||
o := defaultLineOptions()
|
||||
for _, opt := range opts {
|
||||
if opt != nil {
|
||||
opt(&o)
|
||||
}
|
||||
}
|
||||
styleID := g.resolveLineStyleID(o)
|
||||
|
||||
id := uuid.New()
|
||||
g.objects[id] = Line{Id: id, X1: x1f, Y1: y1f, X2: x2f, Y2: y2f}
|
||||
g.objects[id] = Line{
|
||||
Id: id,
|
||||
X1: x1f,
|
||||
Y1: y1f,
|
||||
X2: x2f,
|
||||
Y2: y2f,
|
||||
Priority: o.Priority,
|
||||
StyleID: styleID,
|
||||
}
|
||||
return id, nil
|
||||
}
|
||||
|
||||
func (g *World) resolvePointStyleID(o PointOptions) StyleID {
|
||||
if o.hasStyleID {
|
||||
return o.StyleID
|
||||
}
|
||||
if o.Override.IsZero() {
|
||||
return StyleIDDefaultPoint
|
||||
}
|
||||
return g.styles.AddDerived(StyleIDDefaultPoint, o.Override)
|
||||
}
|
||||
|
||||
func (g *World) resolveCircleStyleID(o CircleOptions) StyleID {
|
||||
if o.hasStyleID {
|
||||
return o.StyleID
|
||||
}
|
||||
if o.Override.IsZero() {
|
||||
return StyleIDDefaultCircle
|
||||
}
|
||||
return g.styles.AddDerived(StyleIDDefaultCircle, o.Override)
|
||||
}
|
||||
|
||||
func (g *World) resolveLineStyleID(o LineOptions) StyleID {
|
||||
if o.hasStyleID {
|
||||
return o.StyleID
|
||||
}
|
||||
if o.Override.IsZero() {
|
||||
return StyleIDDefaultLine
|
||||
}
|
||||
return g.styles.AddDerived(StyleIDDefaultLine, o.Override)
|
||||
}
|
||||
|
||||
// worldToCellX converts a fixed-point X coordinate to a grid column index.
|
||||
func (g *World) worldToCellX(x int) int {
|
||||
return worldToCell(x, g.W, g.cols, g.cellSize)
|
||||
|
||||
Reference in New Issue
Block a user