97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
package world
|
|
|
|
import (
|
|
"hash"
|
|
"hash/fnv"
|
|
"image/color"
|
|
"math"
|
|
)
|
|
|
|
// hashU64 writes v to the hash in little-endian form.
|
|
// We keep it manual to avoid extra allocations and dependencies.
|
|
func hashU64(h hash.Hash64, v uint64) {
|
|
var b [8]byte
|
|
b[0] = byte(v)
|
|
b[1] = byte(v >> 8)
|
|
b[2] = byte(v >> 16)
|
|
b[3] = byte(v >> 24)
|
|
b[4] = byte(v >> 32)
|
|
b[5] = byte(v >> 40)
|
|
b[6] = byte(v >> 48)
|
|
b[7] = byte(v >> 56)
|
|
_, _ = h.Write(b[:])
|
|
}
|
|
|
|
func hashBool(h hash.Hash64, v bool) {
|
|
if v {
|
|
hashU64(h, 1)
|
|
} else {
|
|
hashU64(h, 0)
|
|
}
|
|
}
|
|
|
|
func hashColor(h hash.Hash64, c color.Color) {
|
|
if c == nil {
|
|
hashU64(h, 0)
|
|
return
|
|
}
|
|
r, g, b, a := c.RGBA()
|
|
hashU64(h, uint64(r))
|
|
hashU64(h, uint64(g))
|
|
hashU64(h, uint64(b))
|
|
hashU64(h, uint64(a))
|
|
}
|
|
|
|
// fingerprint returns a stable hash of the override content.
|
|
//
|
|
// Notes on semantics:
|
|
// - FillColor / StrokeColor: nil means "unset" (do not override). Transparent override is represented
|
|
// by a non-nil color with alpha=0.
|
|
// - Pointer fields (*float64, *[]float64) encode presence via nil/non-nil.
|
|
// - StrokeDashes: nil pointer means "unset"; non-nil pointer to nil slice means "set to nil".
|
|
func (o StyleOverride) fingerprint() uint64 {
|
|
h := fnv.New64a() // returns hash.Hash64
|
|
|
|
// FillColor / StrokeColor
|
|
hashBool(h, o.FillColor != nil)
|
|
hashColor(h, o.FillColor)
|
|
|
|
hashBool(h, o.StrokeColor != nil)
|
|
hashColor(h, o.StrokeColor)
|
|
|
|
// StrokeWidthPx
|
|
hashBool(h, o.StrokeWidthPx != nil)
|
|
if o.StrokeWidthPx != nil {
|
|
hashU64(h, math.Float64bits(*o.StrokeWidthPx))
|
|
}
|
|
|
|
// StrokeDashes
|
|
hashBool(h, o.StrokeDashes != nil)
|
|
if o.StrokeDashes != nil {
|
|
ds := *o.StrokeDashes
|
|
if ds == nil {
|
|
// Explicitly set to nil slice
|
|
hashU64(h, 0xffffffffffffffff)
|
|
} else {
|
|
hashU64(h, uint64(len(ds)))
|
|
for _, v := range ds {
|
|
hashU64(h, math.Float64bits(v))
|
|
}
|
|
}
|
|
}
|
|
|
|
// StrokeDashOffset
|
|
hashBool(h, o.StrokeDashOffset != nil)
|
|
if o.StrokeDashOffset != nil {
|
|
hashU64(h, math.Float64bits(*o.StrokeDashOffset))
|
|
}
|
|
|
|
// PointRadiusPx
|
|
hashBool(h, o.PointRadiusPx != nil)
|
|
if o.PointRadiusPx != nil {
|
|
hashU64(h, math.Float64bits(*o.PointRadiusPx))
|
|
}
|
|
|
|
return h.Sum64()
|
|
}
|