140 lines
3.4 KiB
Go
140 lines
3.4 KiB
Go
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)
|
|
}
|