package main import ( sg "github.com/d2fn/sumi/internal/graphics" "github.com/gen2brain/raylib-go/raylib" "image/color" "math" "math/rand" ) type ContourLayer struct { field Field rng *rand.Rand maxActors uint32 actors []*Actor actorIndex uint32 actorColor color.RGBA loActorAngle float32 hiActorAngle float32 } func NewContourLayer(sketch *Sketch, rng *rand.Rand, field Field, color color.RGBA, loActorAngle float32, hiActorAngle float32) *ContourLayer { maxActors := 200000 actors := make([]*Actor, maxActors) layer := ContourLayer{ rng: rng, field: field, actors: actors, maxActors: uint32(maxActors), actorColor: color, actorIndex: 0, loActorAngle: loActorAngle, hiActorAngle: hiActorAngle, } return &layer } func (s *ContourLayer) AddActors(color color.RGBA, n, sourceWidth, sourceHeight int32) { for range n { x := s.rng.Int31() % sourceWidth y := s.rng.Int31() % sourceHeight newActor := &Actor{ position: sg.Point{X: float32(x), Y: float32(y)}, field: s.field, stepSize: 1, color: s.actorColor, loAngle: s.loActorAngle, hiAngle: s.hiActorAngle, } s.actors[s.actorIndex] = newActor s.actorIndex = (s.actorIndex + 1) % s.maxActors } } func (s *ContourLayer) Update(env *Env, g *sg.Graphics) { s.AddActors(s.actorColor, 100, g.WidthInt32(), g.HeightInt32()) } func (s *ContourLayer) Draw(env *Env, g *sg.Graphics) { g.BeginAdditiveBlend() for _, actor := range s.actors { if actor != nil { actor.Draw(env, g) } } g.EndBlend() } func (s *ContourLayer) IsDirty() bool { return true } type Actor struct { position sg.Point field Field stepSize float32 color color.RGBA loAngle float32 hiAngle float32 } func (a *Actor) Draw(env *Env, g *sg.Graphics) { v := a.field.Get(a.position.X, a.position.Y) rad := rl.Remap(v, 0, 1, a.loAngle, a.hiAngle) nextPosition := sg.Point{X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))} //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)))} g.SetStrokeWeight(1.0) g.SetStroke(true) c := a.color c.A = 255 g.DrawLine(a.position, nextPosition) //rl.DrawLineV(a.position, nextPosition, a.color) a.position = nextPosition } type Worm struct { position sg.Point angles []float32 angleIndex int stepSize int renderPct float32 } func (w *Worm) Draw(env *Env, g *sg.Graphics) { g.PushMatrix() g.Translate(w.position) //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 := sg.Vec{X: float32(w.stepSize) * float32(math.Cos(rad)), Y: float32(w.stepSize) * float32(math.Sin(rad))} w.position = w.position.Add(nudge) //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 } } g.PopMatrix() w.angleIndex = (w.angleIndex + 1) % len(w.angles) }