automated snapshot

This commit is contained in:
sumi
2025-12-16 17:45:21 -06:00
parent 73c0471d54
commit 5ad740b15f
5 changed files with 116 additions and 64 deletions

View File

@@ -97,6 +97,7 @@
# Helps CGO find headers/libs # Helps CGO find headers/libs
shellHook = '' shellHook = ''
export CGO_ENABLED=1 export CGO_ENABLED=1
export XDG_SESSION_TYPE=x11
''; '';
}; };
} }

138
main.go
View File

@@ -27,13 +27,14 @@ func GrayCurve(v, k float64) rl.Color {
return rl.Color{R: c, G: c, B: c, A: 255} return rl.Color{R: c, G: c, B: c, A: 255}
} }
func main() { const (
screenWidth = 1400
screenHeight = 700
displayScale = 2
snapshotsDir = "snapshots"
)
const ( func main() {
screenWidth = 1200
screenHeight = 700
snapshotsDir = "snapshots"
)
os.MkdirAll(snapshotsDir, 0755) os.MkdirAll(snapshotsDir, 0755)
@@ -45,15 +46,42 @@ func main() {
os.Exit(1) os.Exit(1)
} }
rl.SetConfigFlags(rl.FlagWindowHighdpi)
rl.InitWindow(screenWidth, screenHeight, "sumi sierpinski arrow") rl.InitWindow(screenWidth, screenHeight, "sumi sierpinski arrow")
sketches := []Sketch { log.Printf("screen=%dx%d render=%dx%d",
SierpinskiArrow{}, 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{ var camera = rl.Camera2D{
Target: rl.Vector2{X: 0, Y: 0}, 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, Rotation: 0,
Zoom: 1.0, Zoom: 1.0,
} }
@@ -63,13 +91,18 @@ func main() {
t0 := time.Now() t0 := time.Now()
ports := MakePorts() ports := MakePorts()
ports["sierpinskiArrowLength"] = Sine { ports["sierpinskiArrowLength"] = Const{
Amp: 1000.0, V: 1200,
Freq: 0.001,
} }
ports["sierpinskiArrowDepth"] = Saw { ports["sierpinskiArrowDepth"] = Const{
Min: 1, Max: 9, Period: 10, V: 7,
}
ports["sierpinskiArrowAngle"] = Sine{
Amp: 120,
Bias: 100,
Freq: 0.1,
} }
for !rl.WindowShouldClose() { for !rl.WindowShouldClose() {
@@ -79,23 +112,25 @@ func main() {
rl.BeginDrawing() rl.BeginDrawing()
rl.ClearBackground(rl.RayWhite) rl.ClearBackground(rl.RayWhite)
rl.BeginMode2D(camera) rl.BeginMode2D(camera)
rl.PushMatrix()
t := time.Since(t0).Seconds() t := time.Since(t0).Seconds()
// set up RenderCtx // set up RenderCtx
renderCtx := &RenderCtx { renderCtx := &RenderCtx{
Width: screenWidth, Width: int32(w),
Height: screenHeight, Height: int32(h),
Time: t, Time: t,
Ports: ports.Eval(t), Ports: ports.Eval(t),
} }
/** /**
MAIN DRAWING MAIN DRAWING
**/ **/
for _, s := range sketches { for _, s := range sketches {
rl.PushMatrix()
s.Draw(renderCtx) s.Draw(renderCtx)
rl.PopMatrix()
} }
if rl.IsKeyDown(rl.KeySpace) { if rl.IsKeyDown(rl.KeySpace) {
@@ -104,11 +139,12 @@ func main() {
} }
} }
rl.PopMatrix()
rl.EndMode2D() rl.EndMode2D()
rl.DrawLine(10, 10, int32(w-10), int32(h-10), rl.Black)
// HUD // 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() rl.EndDrawing()
} }
@@ -116,19 +152,23 @@ func main() {
} }
func updateCamera(camera *rl.Camera2D) { func updateCamera(camera *rl.Camera2D) {
// Get the world point that is under the mouse
mouseVec2 := rl.GetMousePosition()
if rl.IsMouseButtonDown(rl.MouseRightButton) { if rl.IsMouseButtonDown(rl.MouseRightButton) {
// get mouse delta from last frame
delta := rl.GetMouseDelta() delta := rl.GetMouseDelta()
// compute the amount to move scaled by the camera zoom
delta = rl.Vector2Scale(delta, -1.0/camera.Zoom) delta = rl.Vector2Scale(delta, -1.0/camera.Zoom)
camera.Target = rl.Vector2Add(camera.Target, delta) camera.Target = rl.Vector2Add(camera.Target, delta)
} }
// Zoom based on mouse wheel // Zoom based on mouse wheel
wheel := rl.GetMouseWheelMove() wheel := rl.GetMouseWheelMove()
if wheel != 0 { if wheel != 0 {
// Get the world point that is under the mouse mouseWorldPos := rl.GetScreenToWorld2D(mouseVec2, *camera)
mouseWorldPos := rl.GetScreenToWorld2D(rl.GetMousePosition(), *camera)
// Set the offset to where the mouse is // 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 // 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 // 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
}
func (w *Worm) Draw(ctx *RenderCtx) {
type SierpinskiArrow struct {}
func (s SierpinskiArrow) Draw(ctx *RenderCtx) {
rl.PushMatrix() 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() 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) { func sierpinskiArrow(ctx *RenderCtx, order int, length float64) {
if order == 0 { if order == 0 {
curve(ctx, order, length, 60) curve(ctx, order, length, ctx.Ports["sierpinskiArrowAngle"])
} else { } else {
rl.Rotatef(60, 0, 0, 1) rl.Rotatef(float32(ctx.Ports["sierpinskiArrowAngle"]), 0, 0, 1)
curve(ctx, order, length, -60) curve(ctx, order, length, -ctx.Ports["sierpinskiArrowAngle"])
} }
} }
@@ -167,7 +226,7 @@ func curve(ctx *RenderCtx, order int, length float64, angle float64) {
if order == 0 { if order == 0 {
len := int32(length) len := int32(length)
rl.DrawLine(0, 0, len, 0, rl.Black) rl.DrawLine(0, 0, len, 0, rl.Black)
rl.Translatef(float32(len), 0, 0) rl.Translatef(float32(length), 0, 0)
} else { } else {
curve(ctx, order-1, length/2, -angle) curve(ctx, order-1, length/2, -angle)
rl.Rotatef(float32(angle), 0, 0, 1) rl.Rotatef(float32(angle), 0, 0, 1)
@@ -183,25 +242,16 @@ func main2() {
for i := range len(angles) { for i := range len(angles) {
angles[i] = float32(noise.Eval2(float64(i)*0.05, 0.00))*0.1 - 0.05 angles[i] = float32(noise.Eval2(float64(i)*0.05, 0.00))*0.1 - 0.05
} }
frameNum := 0 frameNum := 0
for !rl.WindowShouldClose() { for !rl.WindowShouldClose() {
frameNum++ frameNum++
// initial transform by halfway again through angle array // initial transform by halfway again through angle array
angleIndex := (frameNum / 10) % len(angles)
angleIndex := (frameNum/10) % len(angles)
angle := angles[angleIndex] angle := angles[angleIndex]
initAngle := angles[(angleIndex+len(angles)/2)%len(angles)] initAngle := angles[(angleIndex+len(angles)/2)%len(angles)]
rl.Rotatef(2500*initAngle, 0, 0, 1) rl.Rotatef(2500*initAngle, 0, 0, 1)
rl.Translatef(100*initAngle, 100*initAngle, 0) rl.Translatef(100*initAngle, 100*initAngle, 0)
fmt.Printf("%.3f", angle) fmt.Printf("%.3f", angle)
rl.EndMode2D() rl.EndMode2D()
} }
} }

View File

@@ -9,11 +9,13 @@ type Signal interface {
} }
type Const struct{ V float64 } type Const struct{ V float64 }
func (s Const) Eval(t float64) float64 { return s.V } func (s Const) Eval(t float64) float64 { return s.V }
type Sine struct { type Sine struct {
Amp, Freq, Phase, Bias float64 Amp, Freq, Phase, Bias float64
} }
func (s Sine) Eval(t float64) float64 { func (s Sine) Eval(t float64) float64 {
return s.Bias + s.Amp*math.Sin(2*math.Pi*s.Freq*t+s.Phase) 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 { type Saw struct {
Min, Max, Period float64 Min, Max, Period float64
} }
func (s Saw) Eval(t float64) float64 { func (s Saw) Eval(t float64) float64 {
u := math.Mod(t, s.Period) / s.Period // 0..1 u := math.Mod(t, s.Period) / s.Period // 0..1
return s.Min + (s.Max-s.Min)*u return s.Min + (s.Max-s.Min)*u
} }

View File

@@ -21,7 +21,7 @@ func MakePorts() Ports {
**/ **/
func (p Ports) Eval(t float64) map[string]float64 { func (p Ports) Eval(t float64) map[string]float64 {
out := make(map[string]float64, len(p)) out := make(map[string]float64, len(p))
for name, sig := range(p) { for name, sig := range p {
out[name] = sig.Eval(t) out[name] = sig.Eval(t)
} }
return out return out
@@ -30,10 +30,9 @@ func (p Ports) Eval(t float64) map[string]float64 {
/** RenderCtx **/ /** RenderCtx **/
type RenderCtx struct { type RenderCtx struct {
Width int32 Width int32
Height int32 Height int32
Time float64 Time float64
Ports map[string]float64 Ports map[string]float64
Cam rl.Camera2D Cam rl.Camera2D
} }

View File

@@ -2,25 +2,25 @@ package main
import ( import (
"fmt" "fmt"
"log"
"github.com/d2fn/sumi/internal/ids" "github.com/d2fn/sumi/internal/ids"
"github.com/go-git/go-git/v6" "github.com/go-git/go-git/v6"
"log"
//"github.com/go-git/go-git/v5/plumbing" //"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/gen2brain/raylib-go/raylib"
"github.com/go-git/go-git/v6/plumbing/object"
_ "modernc.org/sqlite" // pure Go, Nix-friendly
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
"database/sql"
_ "modernc.org/sqlite" // pure Go, Nix-friendly
) )
type Storage struct { type Storage struct {
repoRoot string repoRoot string
snapshotsDir string snapshotsDir string
gen *ids.Generator gen *ids.Generator
db *sql.DB db *sql.DB
log *log.Logger log *log.Logger
} }
func NewStorage(snapshotsDir string) (*Storage, error) { func NewStorage(snapshotsDir string) (*Storage, error) {
@@ -30,12 +30,12 @@ func NewStorage(snapshotsDir string) (*Storage, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
s := Storage { s := Storage{
repoRoot: ".", repoRoot: ".",
snapshotsDir: snapshotsDir, snapshotsDir: snapshotsDir,
gen: gen, gen: gen,
db: db, db: db,
log: log, log: log,
} }
return &s, nil return &s, nil
} }