From 5ad740b15f3fa52afec10cd25dea28626fdf44a2 Mon Sep 17 00:00:00 2001 From: sumi Date: Tue, 16 Dec 2025 17:45:21 -0600 Subject: [PATCH] automated snapshot --- flake.nix | 1 + main.go | 138 ++++++++++++++++++++++++++++++++++++----------------- signals.go | 4 +- sketch.go | 11 ++--- storage.go | 26 +++++----- 5 files changed, 116 insertions(+), 64 deletions(-) diff --git a/flake.nix b/flake.nix index e215b6c..a776098 100644 --- a/flake.nix +++ b/flake.nix @@ -97,6 +97,7 @@ # Helps CGO find headers/libs shellHook = '' export CGO_ENABLED=1 + export XDG_SESSION_TYPE=x11 ''; }; } diff --git a/main.go b/main.go index ef5d93e..51bfd58 100644 --- a/main.go +++ b/main.go @@ -27,13 +27,14 @@ func GrayCurve(v, k float64) rl.Color { return rl.Color{R: c, G: c, B: c, A: 255} } -func main() { +const ( + screenWidth = 1400 + screenHeight = 700 + displayScale = 2 + snapshotsDir = "snapshots" +) - const ( - screenWidth = 1200 - screenHeight = 700 - snapshotsDir = "snapshots" - ) +func main() { os.MkdirAll(snapshotsDir, 0755) @@ -45,15 +46,42 @@ func main() { os.Exit(1) } + rl.SetConfigFlags(rl.FlagWindowHighdpi) rl.InitWindow(screenWidth, screenHeight, "sumi sierpinski arrow") - sketches := []Sketch { - SierpinskiArrow{}, + log.Printf("screen=%dx%d render=%dx%d", + rl.GetScreenWidth(), rl.GetScreenHeight(), + rl.GetRenderWidth(), rl.GetRenderHeight(), + ) + + + w := rl.GetRenderWidth() + h := rl.GetRenderHeight() + + angles := make([]float32, 1000) + noise := opensimplex.NewNormalized(0) + r := 0.75 + dtheta := 360.0/float64(len(angles)) + for i := range len(angles) { + rad := float64(i) * dtheta * math.Pi / 180.0 + x := r * math.Cos(rad) + y := r * math.Sin(rad) + angles[i] = float32(noise.Eval2(x, y) * 360.0) + } + + sketches := []Sketch{ + &SierpinskiArrow{}, + &Worm{ + position: rl.Vector2 { X: 50, Y: 50 }, + angles: angles, + angleIndex: 0, + stepSize: 2, + }, } var camera = rl.Camera2D{ Target: rl.Vector2{X: 0, Y: 0}, - Offset: rl.Vector2{X: float32(screenWidth) / 2, Y: float32(screenHeight) / 2}, + Offset: rl.Vector2{X: float32(w) / 2, Y: float32(h) / 2}, Rotation: 0, Zoom: 1.0, } @@ -63,13 +91,18 @@ func main() { t0 := time.Now() ports := MakePorts() - ports["sierpinskiArrowLength"] = Sine { - Amp: 1000.0, - Freq: 0.001, + ports["sierpinskiArrowLength"] = Const{ + V: 1200, } - ports["sierpinskiArrowDepth"] = Saw { - Min: 1, Max: 9, Period: 10, + ports["sierpinskiArrowDepth"] = Const{ + V: 7, + } + + ports["sierpinskiArrowAngle"] = Sine{ + Amp: 120, + Bias: 100, + Freq: 0.1, } for !rl.WindowShouldClose() { @@ -79,23 +112,25 @@ func main() { rl.BeginDrawing() rl.ClearBackground(rl.RayWhite) rl.BeginMode2D(camera) - rl.PushMatrix() t := time.Since(t0).Seconds() // set up RenderCtx - renderCtx := &RenderCtx { - Width: screenWidth, - Height: screenHeight, - Time: t, - Ports: ports.Eval(t), + renderCtx := &RenderCtx{ + Width: int32(w), + Height: int32(h), + Time: t, + Ports: ports.Eval(t), } /** MAIN DRAWING **/ + for _, s := range sketches { + rl.PushMatrix() s.Draw(renderCtx) + rl.PopMatrix() } if rl.IsKeyDown(rl.KeySpace) { @@ -104,11 +139,12 @@ func main() { } } - rl.PopMatrix() rl.EndMode2D() + rl.DrawLine(10, 10, int32(w-10), int32(h-10), rl.Black) + // HUD - rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.White) + rl.DrawText("Mouse right button drag to move, mouse wheel to zoom", 10, 10, 20, rl.Black) rl.EndDrawing() } @@ -116,19 +152,23 @@ func main() { } func updateCamera(camera *rl.Camera2D) { + // Get the world point that is under the mouse + mouseVec2 := rl.GetMousePosition() + if rl.IsMouseButtonDown(rl.MouseRightButton) { + // get mouse delta from last frame delta := rl.GetMouseDelta() + // compute the amount to move scaled by the camera zoom delta = rl.Vector2Scale(delta, -1.0/camera.Zoom) camera.Target = rl.Vector2Add(camera.Target, delta) } // Zoom based on mouse wheel wheel := rl.GetMouseWheelMove() if wheel != 0 { - // Get the world point that is under the mouse - mouseWorldPos := rl.GetScreenToWorld2D(rl.GetMousePosition(), *camera) + mouseWorldPos := rl.GetScreenToWorld2D(mouseVec2, *camera) // Set the offset to where the mouse is - camera.Offset = rl.GetMousePosition() + camera.Offset = mouseVec2 // Set the target to match, so that the camera maps the world space point // under the cursor to the screen space point under the cursor at any zoom @@ -144,22 +184,41 @@ func updateCamera(camera *rl.Camera2D) { } } +type Worm struct { + position rl.Vector2 + angles []float32 + angleIndex int + stepSize int +} - -type SierpinskiArrow struct {} - -func (s SierpinskiArrow) Draw(ctx *RenderCtx) { +func (w *Worm) Draw(ctx *RenderCtx) { rl.PushMatrix() - sierpinskiArrow(ctx, int(ctx.Ports["sierpinskiArrowDepth"]), ctx.Ports["sierpinskiArrowLength"]) + rl.Translatef(w.position.X, w.position.Y, 0) + lastAngle := float32(0.0) + for i := range w.angles { + ii := (i + w.angleIndex) % len(w.angles) + angle := w.angles[ii] + rl.Rotatef(angle - lastAngle, 0, 0, 1) + rl.DrawLine(0, 0, int32(w.stepSize), 0, rl.Black) + rl.Translatef(float32(w.stepSize), 0, 0) + lastAngle = angle + } 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, 60) + curve(ctx, order, length, ctx.Ports["sierpinskiArrowAngle"]) } else { - rl.Rotatef(60, 0, 0, 1) - curve(ctx, order, length, -60) + rl.Rotatef(float32(ctx.Ports["sierpinskiArrowAngle"]), 0, 0, 1) + curve(ctx, order, length, -ctx.Ports["sierpinskiArrowAngle"]) } } @@ -167,7 +226,7 @@ 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(len), 0, 0) + rl.Translatef(float32(length), 0, 0) } else { curve(ctx, order-1, length/2, -angle) rl.Rotatef(float32(angle), 0, 0, 1) @@ -183,25 +242,16 @@ func main2() { 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) + 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() } - } diff --git a/signals.go b/signals.go index 4a2cc7f..3c9ebae 100644 --- a/signals.go +++ b/signals.go @@ -9,11 +9,13 @@ type Signal interface { } type Const struct{ V float64 } + func (s Const) Eval(t float64) float64 { return s.V } type Sine struct { Amp, Freq, Phase, Bias float64 } + func (s Sine) Eval(t float64) float64 { return s.Bias + s.Amp*math.Sin(2*math.Pi*s.Freq*t+s.Phase) } @@ -21,8 +23,8 @@ func (s Sine) Eval(t float64) float64 { type Saw struct { Min, Max, Period float64 } + func (s Saw) Eval(t float64) float64 { u := math.Mod(t, s.Period) / s.Period // 0..1 return s.Min + (s.Max-s.Min)*u } - diff --git a/sketch.go b/sketch.go index e073e06..4d91ac1 100644 --- a/sketch.go +++ b/sketch.go @@ -21,7 +21,7 @@ func MakePorts() Ports { **/ func (p Ports) Eval(t float64) map[string]float64 { out := make(map[string]float64, len(p)) - for name, sig := range(p) { + for name, sig := range p { out[name] = sig.Eval(t) } return out @@ -30,10 +30,9 @@ func (p Ports) Eval(t float64) map[string]float64 { /** RenderCtx **/ type RenderCtx struct { - Width int32 + Width int32 Height int32 - Time float64 - Ports map[string]float64 - Cam rl.Camera2D + Time float64 + Ports map[string]float64 + Cam rl.Camera2D } - diff --git a/storage.go b/storage.go index a31d279..e069750 100644 --- a/storage.go +++ b/storage.go @@ -2,25 +2,25 @@ package main import ( "fmt" - "log" "github.com/d2fn/sumi/internal/ids" "github.com/go-git/go-git/v6" + "log" //"github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v6/plumbing/object" + "database/sql" "github.com/gen2brain/raylib-go/raylib" + "github.com/go-git/go-git/v6/plumbing/object" + _ "modernc.org/sqlite" // pure Go, Nix-friendly "os" "path/filepath" "time" - "database/sql" - _ "modernc.org/sqlite" // pure Go, Nix-friendly ) type Storage struct { - repoRoot string + repoRoot string snapshotsDir string - gen *ids.Generator - db *sql.DB - log *log.Logger + gen *ids.Generator + db *sql.DB + log *log.Logger } func NewStorage(snapshotsDir string) (*Storage, error) { @@ -30,12 +30,12 @@ func NewStorage(snapshotsDir string) (*Storage, error) { if err != nil { return nil, err } - s := Storage { - repoRoot: ".", + s := Storage{ + repoRoot: ".", snapshotsDir: snapshotsDir, - gen: gen, - db: db, - log: log, + gen: gen, + db: db, + log: log, } return &s, nil }