Files
sumi/contour_layer.go
2025-12-26 13:16:33 -06:00

129 lines
3.0 KiB
Go

package main
import (
"math"
"math/rand"
"github.com/gen2brain/raylib-go/raylib"
)
type ContourLayer struct {
field Field
maxActors uint32
actors []*Actor
actorIndex uint32
actorColor rl.Color
rng *rand.Rand
}
func NewContourLayer(sketch *Sketch, rng *rand.Rand, field Field, color rl.Color) *ContourLayer {
maxActors := 200000
actors := make([]*Actor, maxActors)
layer := ContourLayer {
rng: rng,
field: field,
actors: actors,
maxActors: uint32(maxActors),
actorColor: color,
actorIndex: 0,
}
return &layer
}
func (s *ContourLayer) AddActors(color rl.Color, n, sourceWidth, sourceHeight int32) {
for range n {
x := s.rng.Int31() % sourceWidth
y := s.rng.Int31() % sourceHeight
newActor :=
&Actor {
position: rl.Vector2{X: float32(x), Y: float32(y)},
field: s.field,
stepSize: 1,
color: s.actorColor,
}
s.actors[s.actorIndex] = newActor
s.actorIndex = (s.actorIndex + 1) % s.maxActors
}
}
func (s *ContourLayer) Update(ctx *RenderCtx) {
s.AddActors(s.actorColor, 100, ctx.SourceWidth, ctx.SourceHeight)
}
func (s *ContourLayer) Draw(ctx *RenderCtx) {
rl.BeginBlendMode(rl.BlendAdditive)
for _, actor := range s.actors {
if actor != nil {
actor.Draw()
}
}
rl.EndBlendMode()
}
func (s *ContourLayer) IsDirty() bool {
return true
}
type Actor struct {
position rl.Vector2
field Field
stepSize float32
color rl.Color
}
func (a *Actor) Draw() {
v := a.field.Get(a.position.X, a.position.Y)
rad := rl.Remap(v, 0, 1, 0, 5*math.Pi)
nextPosition := rl.Vector2{X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))}
rl.DrawLineV(a.position, nextPosition, a.color)
a.position = nextPosition
}
func RandRadialVec(rng *rand.Rand, minRadius float32, maxRadius float32, loAngle float32, hiAngle float32) rl.Vector2 {
r := float64(rl.Remap(rng.Float32(), 0, 1, minRadius, maxRadius))
deg := float64(rl.Remap(rng.Float32(), 0, 1, loAngle, hiAngle))
rad := rl.Deg2rad * deg
return rl.Vector2{X: float32(r * math.Cos(rad)), Y: float32(r * math.Sin(rad))}
}
type Worm struct {
position rl.Vector2
angles []float32
angleIndex int
stepSize int
renderPct float32
}
func (w *Worm) Draw(ctx *RenderCtx) {
rl.PushMatrix()
rl.Translatef(w.position.X, w.position.Y, 0)
lastAngle := float32(0.0)
stepCount := 0
nudged := false
for i := range w.angles {
ii := (i + w.angleIndex) % len(w.angles)
angle := w.angles[ii]
deltaAngle := angle - lastAngle
if !nudged {
rad := float64(deltaAngle * math.Pi / 180.0)
nudge := rl.Vector2{X: float32(w.stepSize) * float32(math.Cos(rad)), Y: float32(w.stepSize) * float32(math.Sin(rad))}
w.position = rl.Vector2Add(w.position, nudge)
nudged = true
}
rl.Rotatef(deltaAngle, 0, 0, 1)
rl.DrawLine(0, 0, int32(w.stepSize), 0, rl.NewColor(184, 187, 38, 50))
rl.Translatef(float32(w.stepSize), 0, 0)
lastAngle = angle
stepCount++
if stepCount > int(float32(len(w.angles))*w.renderPct) {
break
}
}
rl.PopMatrix()
w.angleIndex = (w.angleIndex + 1) % len(w.angles)
}