336 lines
7.9 KiB
Go
336 lines
7.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"math"
|
|
"math/rand"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/gen2brain/raylib-go/raylib"
|
|
"github.com/ojrac/opensimplex-go"
|
|
)
|
|
|
|
const (
|
|
targetWidth = 1000
|
|
targetHeight = 1000
|
|
sourceScale = 2
|
|
snapshotsDir = "snapshots"
|
|
)
|
|
|
|
type TextureCam struct {
|
|
SourceWidth int32
|
|
SourceHeight int32
|
|
LookAt rl.Vector2
|
|
Zoom float32
|
|
}
|
|
|
|
func main() {
|
|
|
|
sourceWidth := int32(sourceScale * targetWidth)
|
|
sourceHeight := int32(sourceScale * targetHeight)
|
|
|
|
os.MkdirAll(snapshotsDir, 0755)
|
|
log := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile)
|
|
storage, err := NewStorage(snapshotsDir)
|
|
if err != nil {
|
|
log.Printf("Error loading storage: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
rl.SetConfigFlags(rl.FlagMsaa4xHint)
|
|
rl.InitWindow(targetWidth, targetHeight, "sumi sierpinski arrow")
|
|
|
|
// point at source center
|
|
// put source center at center of screen
|
|
var camera = TextureCam{
|
|
LookAt: rl.Vector2{X: float32(sourceWidth) / 2.0, Y: float32(sourceHeight) / 2.0},
|
|
Zoom: 1.0,
|
|
SourceWidth: sourceWidth,
|
|
SourceHeight: sourceHeight,
|
|
}
|
|
|
|
rl.SetTargetFPS(60)
|
|
t0 := time.Now()
|
|
|
|
/*
|
|
*/
|
|
|
|
imageField := NewImageField("/home/d/Dropbox/art/passage/data/david.png")
|
|
|
|
field :=
|
|
TranslateField{
|
|
x: -float32(sourceWidth / 2.0),
|
|
y: -float32(sourceHeight / 2.0),
|
|
field: &ScaleField{
|
|
scale: 1.0,
|
|
field: &imageField,
|
|
},
|
|
}
|
|
rng := rand.New(rand.NewSource(0))
|
|
|
|
contourLayer := NewContourLayer(rng, &field, sourceWidth, sourceHeight)
|
|
|
|
sketch := NewSketch(sourceWidth, sourceHeight)
|
|
//sketch.CreateLayer("testPattern", &TestPattern{}, int32(sourceWidth), int32(sourceHeight))
|
|
//sketch.CreateLayer("actors", &contourLayer, int32(sourceWidth), int32(sourceHeight))
|
|
//sketch.CreateLayer("field", &FieldLayer{field: &field, dirty: true}, int32(sourceWidth), int32(sourceHeight))
|
|
sketch.CreateLayer("contours", &contourLayer, int32(sourceWidth), int32(sourceHeight))
|
|
|
|
ports := MakePorts()
|
|
ports["sierpinskiArrowAngle"] = Sine{
|
|
Amp: 120,
|
|
Bias: 100,
|
|
Freq: 0.1,
|
|
}
|
|
|
|
for !rl.WindowShouldClose() {
|
|
|
|
// begin drawing
|
|
t := time.Since(t0).Seconds()
|
|
|
|
// set up RenderCtx
|
|
renderCtx := &RenderCtx{
|
|
TargetWidth: int32(targetWidth),
|
|
TargetHeight: int32(targetHeight),
|
|
SourceWidth: int32(sourceWidth),
|
|
SourceHeight: int32(sourceHeight),
|
|
Time: t,
|
|
Ports: ports.Eval(t),
|
|
Cam: &camera,
|
|
}
|
|
|
|
sketch.Update(renderCtx)
|
|
|
|
/**
|
|
* MAIN DRAWING
|
|
*/
|
|
rl.BeginDrawing()
|
|
rl.ClearBackground(rl.Blank)
|
|
|
|
sketch.Draw(renderCtx)
|
|
|
|
rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.White)
|
|
|
|
rl.EndDrawing()
|
|
|
|
if rl.IsKeyDown(rl.KeySpace) {
|
|
capture := sketch.Capture()
|
|
if _, err := storage.Save(capture); err != nil {
|
|
log.Printf("Error saving snapshot: %v\n", err)
|
|
}
|
|
}
|
|
|
|
for ch := rl.GetCharPressed(); ch != 0; ch = rl.GetCharPressed() {
|
|
c := rune(ch)
|
|
if c == 'c' {
|
|
resetCamera(&camera)
|
|
} else if c >= '1' && c <= '9' {
|
|
zoom := 1 << int(ch-'0')
|
|
camera.Zoom = float32(zoom)
|
|
}
|
|
}
|
|
|
|
//rl.EndMode2D()
|
|
|
|
// HUD
|
|
}
|
|
|
|
rl.CloseWindow()
|
|
}
|
|
|
|
func resetCamera(cam *TextureCam) {
|
|
cam.LookAt = rl.Vector2{X: float32(cam.SourceWidth) / 2.0, Y: float32(cam.SourceHeight) / 2.0}
|
|
cam.Zoom = 1.0
|
|
}
|
|
|
|
type FieldLayer struct {
|
|
field Field
|
|
dirty bool
|
|
}
|
|
|
|
func (s *FieldLayer) Update(ctx *RenderCtx) {
|
|
;
|
|
}
|
|
|
|
func (s *FieldLayer) Draw(ctx *RenderCtx) {
|
|
for x := range ctx.SourceWidth {
|
|
for y := range ctx.SourceHeight {
|
|
v := s.field.Get(float32(x), float32(y))
|
|
clr := GrayCurve(v, 1.0)
|
|
rl.DrawPixel(x, y, clr)
|
|
}
|
|
}
|
|
s.dirty = false
|
|
}
|
|
|
|
func (s *FieldLayer) IsDirty() bool {
|
|
return s.dirty
|
|
}
|
|
|
|
type ContourLayer struct {
|
|
field Field
|
|
actors []*Actor
|
|
rng *rand.Rand
|
|
sourceWidth int32
|
|
sourceHeight int32
|
|
}
|
|
|
|
func NewContourLayer(rng *rand.Rand, field Field, sourceWidth int32, sourceHeight int32) ContourLayer {
|
|
|
|
actors := make([]*Actor, 0)
|
|
|
|
layer := ContourLayer {
|
|
rng: rng,
|
|
field: field,
|
|
actors: actors,
|
|
sourceWidth: sourceWidth,
|
|
sourceHeight: sourceHeight,
|
|
}
|
|
|
|
layer.AddActors(1)
|
|
|
|
return layer
|
|
}
|
|
|
|
func (s *ContourLayer) AddActors(n int) {
|
|
for range n {
|
|
x := s.rng.Int31() % s.sourceWidth
|
|
y := s.rng.Int31() % s.sourceHeight
|
|
newActor :=
|
|
&Actor {
|
|
position: rl.Vector2{X: float32(x), Y: float32(y)},
|
|
field: s.field,
|
|
stepSize: 1,
|
|
color: rl.NewColor(11, 35, 176, 20),
|
|
}
|
|
s.actors = append(s.actors, newActor)
|
|
}
|
|
}
|
|
|
|
func (s *ContourLayer) Update(ctx *RenderCtx) {
|
|
s.AddActors(100) // parameterize
|
|
}
|
|
|
|
func (s *ContourLayer) Draw(ctx *RenderCtx) {
|
|
rl.BeginBlendMode(rl.BlendAdditive)
|
|
for _, actor := range s.actors {
|
|
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, 3*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)
|
|
//fmt.Printf("position %v -> nextPosition %v \n", a.position, nextPosition)
|
|
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)
|
|
}
|
|
|
|
type SierpinskiArrow struct{}
|
|
|
|
func (s *SierpinskiArrow) Draw(ctx *RenderCtx) {
|
|
sierpinskiArrow(ctx, int(ctx.Ports["sierpinskiArrowDepth"]), ctx.Ports["sierpinskiArrowLength"])
|
|
}
|
|
|
|
func sierpinskiArrow(ctx *RenderCtx, order int, length float64) {
|
|
if order == 0 {
|
|
curve(ctx, order, length, ctx.Ports["sierpinskiArrowAngle"])
|
|
} else {
|
|
rl.Rotatef(float32(ctx.Ports["sierpinskiArrowAngle"]), 0, 0, 1)
|
|
curve(ctx, order, length, -ctx.Ports["sierpinskiArrowAngle"])
|
|
}
|
|
}
|
|
|
|
func curve(ctx *RenderCtx, order int, length float64, angle float64) {
|
|
if order == 0 {
|
|
len := int32(length)
|
|
rl.DrawLine(0, 0, len, 0, rl.Black)
|
|
rl.Translatef(float32(length), 0, 0)
|
|
} else {
|
|
curve(ctx, order-1, length/2, -angle)
|
|
rl.Rotatef(float32(angle), 0, 0, 1)
|
|
curve(ctx, order-1, length/2, angle)
|
|
rl.Rotatef(float32(angle), 0, 0, 1)
|
|
curve(ctx, order-1, length/2, -angle)
|
|
}
|
|
}
|
|
|
|
func main2() {
|
|
angles := make([]float32, 1000)
|
|
noise := opensimplex.NewNormalized(0)
|
|
for i := range len(angles) {
|
|
angles[i] = float32(noise.Eval2(float64(i)*0.05, 0.00))*0.1 - 0.05
|
|
}
|
|
frameNum := 0
|
|
for !rl.WindowShouldClose() {
|
|
frameNum++
|
|
// initial transform by halfway again through angle array
|
|
angleIndex := (frameNum / 10) % len(angles)
|
|
angle := angles[angleIndex]
|
|
initAngle := angles[(angleIndex+len(angles)/2)%len(angles)]
|
|
rl.Rotatef(2500*initAngle, 0, 0, 1)
|
|
rl.Translatef(100*initAngle, 100*initAngle, 0)
|
|
fmt.Printf("%.3f", angle)
|
|
rl.EndMode2D()
|
|
}
|
|
}
|