package main import ( // "fmt" "log" "math/rand" "os" "time" "flag" gui "github.com/gen2brain/raylib-go/raygui" rl "github.com/gen2brain/raylib-go/raylib" //"github.com/ojrac/opensimplex-go" ) var snapshotsPath string func main() { log := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) flag.StringVar(&snapshotsPath, "path", "snapshots", "Path to snapshots and db") flag.Parse() var sourceWidth int32 = 8000 var sourceHeight int32 = 6400 var targetWidth int32 = int32(1600) var targetHeight int32 = int32(1000) log.Printf("Storing snapshots at '%s'\n", snapshotsPath) os.MkdirAll(snapshotsPath, 0755) storage, err := NewStorage(snapshotsPath) 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") // layout_name: controls initialization var ControlScrollPaneScrollView rl.Rectangle var ControlScrollPaneScrollOffset rl.Vector2 BlendModeToggleGroupActive := int32(0) rl.SetTargetFPS(60) t0 := time.Now() rng := rand.New(rand.NewSource(0)) imageField := NewImageField("/home/d/Dropbox/art/data/david.png") //imageField := NewImageField("/home/d/Dropbox/art/data/moses_statue.jpg") field := &TranslateField { x: -float32(sourceWidth / 2.0), y: -float32(sourceHeight / 2.0), field: &ScaleField{ scale: 4.0, field: imageField, }, } sierpinskiLayer := &SierpinskiArrow { dirty: true } sketch := NewSketch(sourceWidth, sourceHeight) sketch.AddColorLayer("background-magenta", rl.Magenta) sketch.AddColorLayer("background-black", rl.Black) sketch.AddLayer("field", &FieldLayer{field: field, loColor: rl.NewColor(0, 0, 0, 0), hiColor: rl.Yellow, dirty: true}) contourLayer := NewContourLayer(&sketch, rng, field) sketch.AddLayer("contours", contourLayer) sketch.AddLayer("sierpinski-arrowhead", sierpinskiLayer) // aurora := NewImageLayer("/home/d/Dropbox/photos/Events/2025/Aurora/Photo Nov 11 2025, 9 52 03 PM.jpg") // sketch.AddLayer("aurora", aurora) // cave := NewImageLayer("/home/d/Dropbox/photos/Events/2025/ Chelsea and James visit Lindell/Photo Nov 29 2025, 5 26 40 PM (29).jpg") // sketch.AddLayer("cave", cave) ports := MakePorts() ports["sierpinskiArrowAngle"] = Sine { Amp: 5, Freq: 0.1, Bias: 60, } ports["sierpinskiArrowDepth"] = Const { V: 6, } ports["sierpinskiArrowLength"] = Const { V: 8000, } for !rl.WindowShouldClose() { // begin drawing t := time.Since(t0).Seconds() targetBounds := rl.Rectangle { X: float32(targetWidth) / 4.0, Y: 0, Width: float32(targetWidth) * 3.0 / 4.0, Height: float32(targetHeight), } // set up RenderCtx renderCtx := &RenderCtx{ TargetBounds: targetBounds, SourceWidth: int32(sourceWidth), SourceHeight: int32(sourceHeight), Time: t, Ports: ports.Eval(t), } sketch.Update(renderCtx) /** * MAIN DRAWING */ rl.BeginDrawing() rl.ClearBackground(rl.GetColor(uint(gui.GetStyle(gui.DEFAULT, gui.BACKGROUND_COLOR)))) sketch.Draw(renderCtx) gui.SetStyle(gui.DEFAULT, gui.BACKGROUND_COLOR, 0x181818FF) gui.SetStyle(gui.DEFAULT, gui.BASE_COLOR_NORMAL, 0x2A2A2AFF) gui.SetStyle(gui.DEFAULT, gui.BASE_COLOR_FOCUSED, 0x3A3A3AFF) gui.SetStyle(gui.DEFAULT, gui.BASE_COLOR_PRESSED, 0x4A4A4AFF) gui.SetStyle(gui.DEFAULT, gui.TEXT_COLOR_NORMAL, 0xE0E0E0FF) gui.SetStyle(gui.DEFAULT, gui.TEXT_COLOR_FOCUSED, 0xFFFFFFFF) gui.SetStyle(gui.DEFAULT, gui.BORDER_COLOR_NORMAL, 0x404040FF) controlPanelWidth := float32(targetWidth) / 4.0 controlPanelHeight := float32(targetHeight) // add gui layout controls // raygui: controls drawing gui.ScrollPanel( rl.Rectangle{ X: 10, Y: 10, Width: controlPanelWidth - 20, Height: controlPanelHeight - 20, }, "", rl.Rectangle{X: 10, Y: 10, Width: controlPanelWidth, Height: controlPanelHeight }, &ControlScrollPaneScrollOffset, &ControlScrollPaneScrollView, ) gui.GroupBox(rl.Rectangle{X: 20, Y: 20, Width: controlPanelWidth - 50, Height: 60 }, "Blending") BlendModeToggleGroupActive = gui.ToggleGroup(rl.Rectangle{X: 30, Y: 40, Width: (controlPanelWidth - 70) / 3.0, Height: 24}, "ONE;TWO;THREE", BlendModeToggleGroupActive) y := float32(90) for _, layerTools := range sketch.layerToolsOrdered { config := layerTools.config gui.Label(rl.Rectangle{X: 20, Y: y, Width: 120, Height: 24}, layerTools.name) y += 30 config.visible = gui.Toggle(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "A", config.visible) config.a = uint8(gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", float32(config.a), 0, 255)) y += 24 config.rVisible = gui.Toggle(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "R", config.rVisible) config.r = uint8(gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", float32(config.r), 0, 255)) y += 24 config.gVisible = gui.Toggle(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "G", config.gVisible) config.g = uint8(gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", float32(config.g), 0, 255)) y += 24 config.bVisible = gui.Toggle(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "B", config.bVisible) config.b = uint8(gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", float32(config.b), 0, 255)) y += 24 config.desaturate = !gui.Toggle(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "S", !config.desaturate) config.saturation = gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", config.saturation, 0, 100) y += 24 gui.Label(rl.Rectangle{X: 30, Y: y, Width: 16, Height: 16}, "K") config.kValue = gui.Slider(rl.Rectangle{X: 50, Y: y, Width: 264, Height: 16}, "", "", config.kValue, 0, 2) y += 30 } 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' { sketch.ResetCamera() } else if c >= '1' && c <= '9' { zoom := 1 << int(ch-'0') sketch.cam.Zoom = float32(zoom) } } //rl.EndMode2D() // HUD } rl.CloseWindow() } type FieldLayer struct { field Field loColor rl.Color hiColor rl.Color dirty bool } func (fl *FieldLayer) Update(ctx *RenderCtx) { ; } func (fl *FieldLayer) Draw(ctx *RenderCtx) { rl.ClearBackground(rl.Blank) rl.BeginBlendMode(rl.BlendAlphaPremultiply) for x := range ctx.SourceWidth { for y := range ctx.SourceHeight { v := fl.field.Get(float32(x), float32(y)) clr := LerpCurve(v, 1.0, fl.loColor, fl.hiColor) rl.DrawPixel(x, y, clr) } } rl.EndBlendMode() fl.dirty = false } func (fl *FieldLayer) IsDirty() bool { return fl.dirty }