package main import ( // "fmt" "log" "math/rand" "os" "time" gui "github.com/gen2brain/raylib-go/raygui" rl "github.com/gen2brain/raylib-go/raylib" //"github.com/ojrac/opensimplex-go" ) const ( snapshotsDir = "snapshots" ) func main() { var sourceWidth int32 = 8000 var sourceHeight int32 = 6400 var targetWidth int32 = int32(2000) var targetHeight int32 = int32(1200) 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") // 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/passage/data/david.png") field := &TranslateField { x: -float32(sourceWidth / 2.0), y: -float32(sourceHeight / 2.0), field: &ScaleField{ scale: 4.0, field: imageField, }, } sketch := NewSketch(sourceWidth, sourceHeight) sierpinskiLayer := &SierpinskiArrow { dirty: true } imageLayer := NewImageLayer("/home/d/Dropbox/photos/Events/2025/Aurora/Photo Nov 11 2025, 9 52 03 PM.jpg") sketch.AddColorLayer("background-black", rl.Black) sketch.AddLayer("field", &FieldLayer{field: field, dirty: true}) contourLayer := NewContourLayer(&sketch, rng, field) sketch.AddLayer("contours", contourLayer) sketch.AddLayer("sierpinski", sierpinskiLayer) sketch.AddLayer("aurora", imageLayer) 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 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 }