From a107a268f72ae75ac9031a9574ffca18cefe91f7 Mon Sep 17 00:00:00 2001 From: Dietrich Featherston Date: Mon, 5 Jan 2026 14:41:26 -0600 Subject: [PATCH] dynamic sizing --- main.go | 121 ++++++++++++++++++++++++++++++++---------------------- sketch.go | 18 ++++---- 2 files changed, 82 insertions(+), 57 deletions(-) diff --git a/main.go b/main.go index 6678b49..85be04d 100644 --- a/main.go +++ b/main.go @@ -20,37 +20,56 @@ import ( var ( snapshotsPath string storage *Storage - sourceWidth, sourceHeight int - targetWidth, targetHeight int ) -func bootstrap() { +type Layout struct { + monitor rl.RectangleInt32 + window rl.RectangleInt32 + controls rl.RectangleInt32 + viewport rl.RectangleInt32 + graphics rl.RectangleInt32 +} + +func bootstrap() Layout { rl.InitWindow(800, 600, "bootstrap") monitor := rl.GetCurrentMonitor() fmt.Printf("Using monitor %d\n", monitor) + // derive defaults from the monitor size monitorWidth := rl.GetMonitorWidth(monitor) monitorHeight := rl.GetMonitorHeight(monitor) - defaultTargetWidth := int(float32(monitorWidth) * 0.95) - defaultTargetHeight := int(float32(monitorHeight) * 0.9) - defaultSourceWidth := 5*defaultTargetWidth - defaultSourceHeight := 5*defaultTargetHeight + // use a large portion of the available space, but not all of it! + defaultWindowWidth := int(float32(monitorWidth) * 0.95) + defaultWindowHeight := int(float32(monitorHeight) * 0.9) + windowWidth := defaultWindowWidth + windowHeight := defaultWindowHeight + + // set controls to use 1/6th of the width + controlsRelWidth := 1.0 / 12.0 + + defaultGraphicsWidth := 5*int((float64(defaultWindowWidth)*(1.0-controlsRelWidth))) + defaultGraphicsHeight := 5*defaultWindowHeight + graphicsWidth := defaultGraphicsWidth + graphicsHeight := defaultGraphicsHeight fmt.Printf("monitor : %d x %d / window : %d x %d / buffer : %d x %d", monitorWidth, monitorHeight, - defaultTargetWidth, defaultTargetHeight, - defaultSourceWidth, defaultSourceHeight) + defaultWindowWidth, defaultWindowHeight, + defaultGraphicsWidth, defaultWindowHeight) flag.StringVar(&snapshotsPath, "path", "snapshots", "Path to snapshots and db") - flag.IntVar(&sourceWidth, "bw", defaultSourceWidth, "Width of the internal graphics source") - flag.IntVar(&sourceHeight, "bh", defaultSourceHeight, "Height of the internal graphics source") - flag.IntVar(&targetWidth, "w", defaultTargetWidth, "Width of the display window") - flag.IntVar(&targetHeight, "h", defaultTargetHeight, "Height of the display window") + flag.IntVar(&graphicsWidth, "gw", defaultGraphicsWidth, "Width of the internal graphics buffer. Can be much larger than the screen.") + flag.IntVar(&graphicsHeight, "gh", defaultGraphicsHeight, "Height of the internal graphics buffer. Can be much larger than the screen.") + flag.IntVar(&windowWidth, "w", defaultWindowWidth, "Width of the display window") + flag.IntVar(&windowHeight, "h", defaultWindowHeight, "Height of the display window") flag.Parse() + controlsWidth := int(float64(windowWidth) * controlsRelWidth) + viewportWidth := windowWidth - controlsWidth + rl.CloseWindow() log.Printf("Storing snapshots at '%s'\n", snapshotsPath) @@ -62,16 +81,24 @@ func bootstrap() { log.Printf("Error loading storage: %v\n", err) os.Exit(1) } + + return Layout { + monitor: rl.RectangleInt32{ X: 0, Y: 0, Width: int32(monitorWidth), Height: int32(monitorHeight) }, + window: rl.RectangleInt32{ X: 0, Y: 0, Width: int32(windowWidth), Height: int32(windowHeight) }, + controls: rl.RectangleInt32{ X: 0, Y: 0, Width: int32(controlsWidth), Height: int32(windowHeight) }, + viewport: rl.RectangleInt32{ X: int32(controlsWidth), Y: 0, Width: int32(viewportWidth), Height: int32(windowHeight) }, + graphics: rl.RectangleInt32{ X: 0, Y: 0, Width: int32(graphicsWidth), Height: int32(graphicsHeight) }, + } } func main() { log := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) - bootstrap() + layout := bootstrap() //rl.SetConfigFlags(rl.FlagMsaa4xHint) - rl.InitWindow(int32(targetWidth), int32(targetHeight), "sumi sierpinski arrow") + rl.InitWindow(layout.window.Width, layout.window.Height, "sumi sierpinski arrow") // reproducable flourescent color cycle colorCycle := g.NewFixedColorCycle(g.FlourescentColors).Shuffle(0) @@ -89,8 +116,8 @@ func main() { //imageField := NewImageField("/home/d/Dropbox/art/data/moses_statue.jpg") field := &TranslateField { - x: -float32(sourceWidth / 2.0), - y: -float32(sourceHeight / 2.0), + x: -float32(layout.graphics.Width / 2.0), + y: -float32(layout.graphics.Height / 2.0), field: &ScaleField{ scale: 100.0, field: &AdderField { @@ -104,7 +131,7 @@ func main() { //sierpinskiLayer := &SierpinskiArrow { dirty: true } - sketch := NewSketch(int32(sourceWidth), int32(sourceHeight)) + sketch := NewSketch(layout.graphics.Width, layout.graphics.Height) fieldColor := colorCycle.Next() fmt.Printf("field color = %v\n", fieldColor) @@ -157,18 +184,11 @@ func main() { // 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), + TargetBounds: layout.viewport, + SourceWidth: layout.graphics.Width, + SourceHeight: layout.graphics.Height, Time: t, Ports: ports.Eval(t), } @@ -192,43 +212,48 @@ func main() { gui.SetStyle(gui.DEFAULT, gui.BORDER_COLOR_NORMAL, 0x404040FF) y := float32(10) + + minX := float32(20) + maxX := float32(layout.controls.X + layout.controls.Width - 20) + sliderWidth := maxX - minX - 20 + controlRowHeight := 20 for _, layerTools := range sketch.layerToolsOrdered { config := layerTools.config - gui.Label(rl.Rectangle{X: 20, Y: y, Width: 120, Height: 24}, layerTools.name) + gui.Label(rl.Rectangle{X: minX, Y: y, Width: 120, Height: 24}, layerTools.name) - y += 30 + y += float32(controlRowHeight + 10) - 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)) + config.visible = gui.Toggle(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "A", config.visible) + config.a = uint8(gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", float32(config.a), 0, 255)) - y += 24 + y += float32(controlRowHeight) - 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)) + config.rVisible = gui.Toggle(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "R", config.rVisible) + config.r = uint8(gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", float32(config.r), 0, 255)) - y += 24 + y += float32(controlRowHeight) - 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)) + config.gVisible = gui.Toggle(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "G", config.gVisible) + config.g = uint8(gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", float32(config.g), 0, 255)) - y += 24 + y += float32(controlRowHeight) - 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)) + config.bVisible = gui.Toggle(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "B", config.bVisible) + config.b = uint8(gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", float32(config.b), 0, 255)) - y += 24 + y += float32(controlRowHeight) - 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) + config.desaturate = !gui.Toggle(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "S", !config.desaturate) + config.saturation = gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", config.saturation, 0, 100) - y += 24 + y += float32(controlRowHeight) - 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) + gui.Label(rl.Rectangle{X: minX, Y: y, Width: 16, Height: 16}, "K") + config.kValue = gui.Slider(rl.Rectangle{X: minX + 20, Y: y, Width: sliderWidth, Height: 16}, "", "", config.kValue, 0, 2) - y += 30 + y += float32(controlRowHeight + 10) } rl.EndDrawing() diff --git a/sketch.go b/sketch.go index 83989cc..40a8273 100644 --- a/sketch.go +++ b/sketch.go @@ -21,7 +21,7 @@ type TextureCam struct { /** RenderCtx **/ type RenderCtx struct { - TargetBounds rl.Rectangle + TargetBounds rl.RectangleInt32 SourceWidth int32 SourceHeight int32 Time float64 @@ -200,7 +200,7 @@ func (s *Sketch) Draw(ctx *RenderCtx) { func (s *Sketch) calcOutputRectKeepingAspectRatio(ctx *RenderCtx) rl.Rectangle { sourceAspect := float32(ctx.SourceWidth) / float32(ctx.SourceHeight) - targetAspect := ctx.TargetBounds.Width / ctx.TargetBounds.Height + targetAspect := float32(ctx.TargetBounds.Width) / float32(ctx.TargetBounds.Height) outputWidth := ctx.TargetBounds.Width outputHeight := ctx.TargetBounds.Height @@ -209,22 +209,22 @@ func (s *Sketch) calcOutputRectKeepingAspectRatio(ctx *RenderCtx) rl.Rectangle { // source is relatively taller than the target // so we set the output height to the target height // and calculate the width based on source aspect and center - outputWidth = outputHeight * sourceAspect + outputWidth = int32(float32(outputHeight) * sourceAspect) } else { // source is relatively wider than the target // so we set the output width to the target width // and calculate the height based on source aspect and center - outputHeight = outputWidth / sourceAspect + outputHeight = int32(float32(outputWidth) / sourceAspect) } // output width and height are correct -- center within TargetBounds x := ctx.TargetBounds.X + ctx.TargetBounds.Width / 2.0 - outputWidth / 2.0 y := ctx.TargetBounds.Y + ctx.TargetBounds.Height / 2.0 - outputHeight / 2.0 - return rl.Rectangle { - X: x, Y: y, - Width: outputWidth, - Height: outputHeight, + return rl.Rectangle{ + X: float32(x), Y: float32(y), + Width: float32(outputWidth), + Height: float32(outputHeight), } } @@ -244,7 +244,7 @@ func (s *Sketch) Update(ctx *RenderCtx) { if rl.IsMouseButtonDown(rl.MouseRightButton) { // get mouse delta from last frame delta := rl.GetMouseDelta() - sourceScale := float32(ctx.SourceWidth) / ctx.TargetBounds.Width + sourceScale := float32(ctx.SourceWidth) / float32(ctx.TargetBounds.Width) // compute the amount to move scaled by the camera zoom delta = rl.Vector2Scale(delta, -sourceScale/s.cam.Zoom) delta.Y = -delta.Y