diff --git a/contour_layer.go b/contour_layer.go index e4ae411..0f45398 100644 --- a/contour_layer.go +++ b/contour_layer.go @@ -4,6 +4,7 @@ import ( "github.com/gen2brain/raylib-go/raylib" "math" "math/rand" + sg "github.com/d2fn/sumi/internal/graphics" ) type ContourLayer struct { @@ -12,12 +13,12 @@ type ContourLayer struct { maxActors uint32 actors []*Actor actorIndex uint32 - actorColor rl.Color + actorColor sg.Color loActorAngle float32 hiActorAngle float32 } -func NewContourLayer(sketch *Sketch, rng *rand.Rand, field Field, color rl.Color, loActorAngle float32, hiActorAngle float32) *ContourLayer { +func NewContourLayer(sketch *Sketch, rng *rand.Rand, field Field, color sg.Color, loActorAngle float32, hiActorAngle float32) *ContourLayer { maxActors := 200000 @@ -37,13 +38,13 @@ func NewContourLayer(sketch *Sketch, rng *rand.Rand, field Field, color rl.Color return &layer } -func (s *ContourLayer) AddActors(color rl.Color, n, sourceWidth, sourceHeight int32) { +func (s *ContourLayer) AddActors(color sg.Color, n, sourceWidth, sourceHeight int32) { for range n { x := s.rng.Int31() % sourceWidth y := s.rng.Int31() % sourceHeight newActor := &Actor{ - position: rl.Vector2{X: float32(x), Y: float32(y)}, + position: sg.Point { X: float32(x), Y: float32(y) }, field: s.field, stepSize: 1, color: s.actorColor, @@ -55,18 +56,19 @@ func (s *ContourLayer) AddActors(color rl.Color, n, sourceWidth, sourceHeight in } } -func (s *ContourLayer) Update(ctx *RenderCtx) { - s.AddActors(s.actorColor, 100, ctx.SourceWidth, ctx.SourceHeight) +func (s *ContourLayer) Update(ctx *Env) { + s.AddActors(s.actorColor, 100, int32(ctx.Graphics.Layout.Graphics.Width), int32(ctx.Graphics.Layout.Graphics.Height)) } -func (s *ContourLayer) Draw(ctx *RenderCtx) { - rl.BeginBlendMode(rl.BlendAdditive) +func (s *ContourLayer) Draw(ctx *Env) { + g := ctx.Graphics + g.BeginAdditiveBlend() for _, actor := range s.actors { if actor != nil { - actor.Draw() + actor.Draw(ctx) } } - rl.EndBlendMode() + g.EndBlend() } func (s *ContourLayer) IsDirty() bool { @@ -74,40 +76,43 @@ func (s *ContourLayer) IsDirty() bool { } type Actor struct { - position rl.Vector2 + position sg.Point field Field stepSize float32 - color rl.Color + color sg.Color loAngle float32 hiAngle float32 } -func (a *Actor) Draw() { +func (a *Actor) Draw(ctx *Env) { v := a.field.Get(a.position.X, a.position.Y) rad := rl.Remap(v, 0, 1, a.loAngle, a.hiAngle) - nextPosition := rl.Vector2{X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))} - rl.DrawLineV(a.position, nextPosition, a.color) + nextPosition := sg.Point {X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))} + //nextPosition := rl.Vector2{X: a.position.X + a.stepSize*float32(math.Cos(float64(rad))), Y: a.position.Y + a.stepSize*float32(math.Sin(float64(rad)))} + + g := ctx.Graphics + g.SetStrokeWeight(1.0) + g.SetStroke(true) + g.SetStrokeColor(a.color) + g.DrawLine(a.position, nextPosition) + //rl.DrawLineV(a.position, nextPosition, a.color) a.position = nextPosition } -func RandRadialVec(rng *rand.Rand, minRadius float32, maxRadius float32, loAngle float32, hiAngle float32) rl.Vector2 { - r := float64(rl.Remap(rng.Float32(), 0, 1, minRadius, maxRadius)) - deg := float64(rl.Remap(rng.Float32(), 0, 1, loAngle, hiAngle)) - rad := rl.Deg2rad * deg - return rl.Vector2{X: float32(r * math.Cos(rad)), Y: float32(r * math.Sin(rad))} -} - type Worm struct { - position rl.Vector2 + position sg.Point angles []float32 angleIndex int stepSize int renderPct float32 } -func (w *Worm) Draw(ctx *RenderCtx) { - rl.PushMatrix() - rl.Translatef(w.position.X, w.position.Y, 0) +func (w *Worm) Draw(ctx *Env) { + g := ctx.Graphics + g.PushMatrix() + g.Translate(w.position) + //rl.PushMatrix() + //rl.Translatef(w.position.X, w.position.Y, 0) lastAngle := float32(0.0) stepCount := 0 nudged := false @@ -117,8 +122,8 @@ func (w *Worm) Draw(ctx *RenderCtx) { deltaAngle := angle - lastAngle if !nudged { rad := float64(deltaAngle * math.Pi / 180.0) - nudge := rl.Vector2{X: float32(w.stepSize) * float32(math.Cos(rad)), Y: float32(w.stepSize) * float32(math.Sin(rad))} - w.position = rl.Vector2Add(w.position, nudge) + nudge := sg.Vec {X: float32(w.stepSize) * float32(math.Cos(rad)), Y: float32(w.stepSize) * float32(math.Sin(rad))} + w.position = w.position.Add(nudge)//rl.Vector2Add(w.position, nudge) nudged = true } rl.Rotatef(deltaAngle, 0, 0, 1) @@ -130,6 +135,6 @@ func (w *Worm) Draw(ctx *RenderCtx) { break } } - rl.PopMatrix() + g.PopMatrix() w.angleIndex = (w.angleIndex + 1) % len(w.angles) } diff --git a/env.go b/env.go new file mode 100644 index 0000000..79c799f --- /dev/null +++ b/env.go @@ -0,0 +1,37 @@ +package main + +import ( + sg "github.com/d2fn/sumi/internal/graphics" +) + +/** Env **/ +type Env struct { + Layout Layout + Time float64 + Ports map[string]float64 + Graphics sg.Graphics +} + +type Layout struct { + // total monitor bounds + Monitor sg.Rect + // bounds of the application window + Window sg.Rect + // bounds of the ui controls area + Controls sg.Rect + // bounds of the region of the app window reserved for rendering the graphics buffer + Viewport sg.Rect + // bounds of the off screen graphics buffer where rendering happens + Graphics sg.Rect +} + + +func (ctx *Env) GetGraphicsWidth() float32 { + return ctx.Graphics.Bounds.Width +} + +func (ctx *Env) GetGraphicsHeight() float32 { + return ctx.Graphics.Bounds.Height +} + + diff --git a/field.go b/field.go index e1117db..c6e6d46 100644 --- a/field.go +++ b/field.go @@ -101,15 +101,15 @@ type FieldLayer struct { dirty bool } -func (fl *FieldLayer) Update(ctx *RenderCtx) { +func (fl *FieldLayer) Update(env *Env) { } -func (fl *FieldLayer) Draw(ctx *RenderCtx) { +func (fl *FieldLayer) Draw(env *Env) { rl.ClearBackground(rl.Blank) rl.BeginBlendMode(rl.BlendAlphaPremultiply) - for x := range ctx.SourceWidth { - for y := range ctx.SourceHeight { + for x := range int32(env.GetGraphicsHeight()) { + for y := range int32(env.GetGraphicsHeight()) { v := fl.field.Get(float32(x), float32(y)) clr := LerpCurve(v, 1.3, fl.loColor, fl.hiColor) rl.DrawPixel(x, y, clr) diff --git a/internal/graphics/graphics.go b/internal/graphics/graphics.go index d2a12d9..853d6db 100644 --- a/internal/graphics/graphics.go +++ b/internal/graphics/graphics.go @@ -8,45 +8,152 @@ import ( ) type Graphics struct { - layout Layout - style Style + Style Style + Bounds Rect } -type Layout struct { - // total monitor bounds - Monitor Rect - // bounds of the application window - Window Rect - // bounds of the ui controls area - Controls Rect - // bounds of the region of the app window reserved for rendering the graphics buffer - Viewport Rect - // bounds of the off screen graphics buffer where rendering happens - Graphics Rect +type Style struct { + StrokeColor, FillColor color.RGBA + StrokeWeight float32 + Stroke, Fill bool +} + +func (g *Graphics) GetGraphicsWidth() int32 { + return int32(g.Bounds.Width) +} + +func (g *Graphics) GetGraphicsHeight() int32 { + return int32(g.Bounds.Height) +} + + +func (g *Graphics) PushStyle() { +} + +func (g *Graphics) PopStyle() { +} + +func (g *Graphics) SetStrokeColor(c Color) { + g.Style.StrokeColor = color.RGBA { R: c.R, G: c.G, B: c.B, A: c.A } +} + +func (g *Graphics) SetFillColor(c Color) { + g.Style.FillColor = color.RGBA { R: c.R, G: c.G, B: c.B, A: c.A } +} + +func (g *Graphics) SetStrokeWeight(w float32) { + g.Style.StrokeWeight = w +} + +func (g *Graphics) SetStroke(b bool) { + g.Style.Stroke = b +} + +func (g *Graphics) SetFill(b bool) { + g.Style.Fill = b +} + +func (g *Graphics) PushMatrix() { + rl.PushMatrix() +} + +func (g *Graphics) Translate(p Point) { + rl.Translatef(p.X, p.Y, 0) +} + +func (g *Graphics) PopMatrix() { + rl.PopMatrix() +} + +func (g *Graphics) BeginClip(r Rect) { + rlRect := r.ToRL() + rint := (&rlRect).ToInt32() + rl.BeginScissorMode(rint.X, rint.Y, rint.Width, rint.Height) +} + +func (g *Graphics) EndClip() { + rl.EndScissorMode() +} + +func (g *Graphics) BeginAdditiveBlend() { + rl.BeginBlendMode(rl.BlendAdditive) +} + +func (g *Graphics) EndBlend() { + rl.EndBlendMode() +} + +func (g *Graphics) BeginTexture(t rl.RenderTexture2D) { + rl.BeginTextureMode(t) +} + +func (g *Graphics) EndTexture() { + rl.EndTextureMode() +} + +func (g *Graphics) DrawRect(r Rect) { + if g.Style.Fill { + rl.DrawRectangleRec(r.ToRL(), g.Style.FillColor) + } + if g.Style.Stroke { + saveLineWidth := rl.GetLineWidth() + rl.SetLineWidth(g.Style.StrokeWeight) + rl.DrawRectangleLines( + int32(r.X), int32(r.Y), + int32(r.Width), int32(r.Height), + g.Style.StrokeColor, + ) + rl.SetLineWidth(saveLineWidth) + } +} + +func (g *Graphics) DrawLine(a, b Point) { + saveLineWidth := rl.GetLineWidth() + rl.SetLineWidth(g.Style.StrokeWeight) + rl.DrawLineV(a.ToRL(), b.ToRL(), g.Style.StrokeColor) + rl.SetLineWidth(saveLineWidth) } type Color color.RGBA +func RGBA(r, g, b, a uint8) Color { + return Color { R: r, G: g, B: b, A: a } +} + type HSBA struct { H uint S, B float32 A uint8 } -type Style struct { - StrokeColor Color - StrokeWeight float32 - FillColor Color +type Point rl.Vector3 +type Vec rl.Vector3 +type Rect rl.Rectangle + +func (p *Point) Add(v Vec) Point { + return Point { X: p.X + v.X, Y: p.Y + v.Y, Z: p.Z + v.Z } } -type Rect rl.Rectangle +func (p Point) ToRL() rl.Vector2 { + return rl.Vector2 { X: p.X, Y: p.Y } +} + +func (p Point) ToRL3() rl.Vector3 { + return rl.Vector3 { X: p.X, Y: p.Y, Z: p.Z } +} /** * scale the given rect down to the target rect * maintaining the aspect ratio of the original rect */ -func (r Rect) ToRL() *rl.Rectangle { - return &rl.Rectangle { X: r.X, Y: r.Y, Width: r.Width, Height: r.Height } + +func (r Rect) UL() Point { + return Point { X: r.X, Y: r.Y } +} + + +func (r Rect) ToRL() rl.Rectangle { + return rl.Rectangle { X: r.X, Y: r.Y, Width: r.Width, Height: r.Height } } func (r Rect) ScaleTo(tgt Rect) Rect { diff --git a/main.go b/main.go index c26d6ad..ffa875f 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "os" "time" - g "github.com/d2fn/sumi/internal/graphics" + sg "github.com/d2fn/sumi/internal/graphics" "github.com/ojrac/opensimplex-go" gui "github.com/gen2brain/raylib-go/raygui" @@ -17,13 +17,14 @@ import ( //"github.com/ojrac/opensimplex-go" ) + +func Bootstrap() sg.Graphics { + var ( snapshotsPath string storage *Storage ) -func Bootstrap() g.Layout { - rl.InitWindow(800, 600, "bootstrap") monitor := rl.GetCurrentMonitor() @@ -74,12 +75,27 @@ func Bootstrap() g.Layout { os.Exit(1) } - return g.Layout { - Monitor: g.Rect{X: 0, Y: 0, Width: float32(monitorWidth), Height: float32(monitorHeight)}, - Window: g.Rect{X: 0, Y: 0, Width: float32(windowWidth), Height: float32(windowHeight)}, - Controls: g.Rect{X: 0, Y: 0, Width: float32(controlsWidth), Height: float32(windowHeight)}, - Viewport: g.Rect{X: float32(controlsWidth), Y: 0, Width: float32(viewportWidth), Height: float32(windowHeight)}, - Graphics: g.Rect{X: 0, Y: 0, Width: float32(graphicsWidth), Height: float32(graphicsHeight)}, + layout := sg.Layout { + Monitor: sg.Rect{X: 0, Y: 0, Width: float32(monitorWidth), Height: float32(monitorHeight)}, + Window: sg.Rect{X: 0, Y: 0, Width: float32(windowWidth), Height: float32(windowHeight)}, + Controls: sg.Rect{X: 0, Y: 0, Width: float32(controlsWidth), Height: float32(windowHeight)}, + Viewport: sg.Rect{X: float32(controlsWidth), Y: 0, Width: float32(viewportWidth), Height: float32(windowHeight)}, + Graphics: sg.Rect{X: 0, Y: 0, Width: float32(graphicsWidth), Height: float32(graphicsHeight)}, + } + + //rl.SetConfigFlags(rl.FlagMsaa4xHint) + rl.InitWindow(int32(layout.Window.Width), int32(layout.Window.Height), "sumi sierpinski arrow") + rl.SetTargetFPS(60) + + return sg.Graphics { + Layout: layout, + Style: sg.Style { + Fill: false, + FillColor: rl.RayWhite, + Stroke: true, + StrokeColor: rl.Black, + StrokeWeight: 1.0, + }, } } @@ -87,15 +103,11 @@ func main() { log := log.New(os.Stdout, "", log.Ldate|log.Ltime|log.Lshortfile) - layout := Bootstrap() - - //rl.SetConfigFlags(rl.FlagMsaa4xHint) - rl.InitWindow(int32(layout.Window.Width), int32(layout.Window.Height), "sumi sierpinski arrow") + g := Bootstrap() // reproducable flourescent color cycle - colorCycle := g.NewFixedColorCycle(g.FlourescentColors).Shuffle(0) + colorCycle := sg.NewFixedColorCycle(sg.FlourescentColors).Shuffle(0) - rl.SetTargetFPS(60) t0 := time.Now() rng := rand.New(rand.NewSource(0)) @@ -108,8 +120,8 @@ func main() { //imageField := NewImageField("/home/d/Dropbox/art/data/moses_statue.jpg") field := &TranslateField{ - x: -float32(layout.Graphics.Width / 2.0), - y: -float32(layout.Graphics.Height / 2.0), + x: -float32(g.Layout.Graphics.Width / 2.0), + y: -float32(g.Layout.Graphics.Height / 2.0), field: &ScaleField{ scale: 100.0, field: &AdderField{ @@ -123,7 +135,7 @@ func main() { //sierpinskiLayer := &SierpinskiArrow { dirty: true } - sketch := NewSketch(int32(layout.Graphics.Width), int32(layout.Graphics.Height)) + sketch := NewSketch(&g) fieldColor := colorCycle.Next() fmt.Printf("field color = %v\n", fieldColor) @@ -138,12 +150,14 @@ func main() { hsv := rl.ColorToHSV(actorColor) hsv.Z *= 0.7 actorColor = rl.ColorFromHSV(hsv.X, hsv.Y, hsv.Z) - actorColor = g.Clamp(actorColor, 10, 255) + actorColor = sg.Clamp(actorColor, 10, 255) actorColor.A = 10 + + actorSGColor := sg.Color { R: actorColor.R, G: actorColor.G, B: actorColor.B, A: actorColor.A } //NewColor(11, 35, 176, 50), //r - contourLayer := NewContourLayer(&sketch, rng, field, actorColor, -25*math.Pi, 25*math.Pi) + contourLayer := NewContourLayer(&sketch, rng, field, actorSGColor, -25*math.Pi, 25*math.Pi) 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") @@ -175,15 +189,13 @@ func main() { t := time.Since(t0).Seconds() // set up RenderCtx - renderCtx := &RenderCtx { - TargetBounds: layout.Viewport, - SourceWidth: int32(layout.Graphics.Width), - SourceHeight: int32(layout.Graphics.Height), + env := &Env { + Graphics: g, Time: t, Ports: ports.Eval(t), } - sketch.Update(renderCtx) + sketch.Update(env) /** * MAIN DRAWING @@ -191,7 +203,7 @@ func main() { rl.BeginDrawing() rl.ClearBackground(rl.GetColor(uint(gui.GetStyle(gui.DEFAULT, gui.BACKGROUND_COLOR)))) - sketch.Draw(renderCtx) + sketch.Draw(env) gui.SetStyle(gui.DEFAULT, gui.BACKGROUND_COLOR, 0x181818FF) gui.SetStyle(gui.DEFAULT, gui.BASE_COLOR_NORMAL, 0x2A2A2AFF) @@ -204,7 +216,7 @@ func main() { y := float32(10) minX := float32(60) - maxX := float32(layout.Controls.X + layout.Controls.Width - 20) + maxX := float32(g.Layout.Controls.X + g.Layout.Controls.Width - 20) sliderWidth := maxX - minX - 20 controlRowHeight := 20 for _, layerTools := range sketch.layerToolsOrdered { @@ -246,7 +258,6 @@ func main() { */ y += float32(controlRowHeight + 10) - } rl.EndDrawing() diff --git a/sierpinski.go b/sierpinski.go index 8568425..71b0165 100644 --- a/sierpinski.go +++ b/sierpinski.go @@ -8,13 +8,13 @@ type SierpinskiArrow struct { dirty bool } -func (s *SierpinskiArrow) Draw(ctx *RenderCtx) { - rl.Translatef(float32(ctx.SourceWidth)/2.0, float32(ctx.SourceHeight)/2.0, 0) +func (s *SierpinskiArrow) Draw(env *Env) { + rl.Translatef(float32(env.GetGraphicsWidth())/2.0, float32(env.GetGraphicsHeight())/2.0, 0) rl.ClearBackground(rl.NewColor(0, 0, 0, 0)) - sierpinskiArrow(ctx, int(ctx.Ports["sierpinskiArrowDepth"]), ctx.Ports["sierpinskiArrowLength"]) + sierpinskiArrow(env, int(env.Ports["sierpinskiArrowDepth"]), env.Ports["sierpinskiArrowLength"]) } -func (s *SierpinskiArrow) Update(ctx *RenderCtx) { +func (s *SierpinskiArrow) Update(_ *Env) { s.dirty = true } @@ -22,26 +22,26 @@ func (s *SierpinskiArrow) IsDirty() bool { return s.dirty } -func sierpinskiArrow(ctx *RenderCtx, order int, length float64) { +func sierpinskiArrow(env *Env, order int, length float64) { if order == 0 { - curve(ctx, order, length, ctx.Ports["sierpinskiArrowAngle"]) + curve(env, order, length, env.Ports["sierpinskiArrowAngle"]) } else { - rl.Rotatef(float32(ctx.Ports["sierpinskiArrowAngle"]), 0, 0, 1) - curve(ctx, order, length, -ctx.Ports["sierpinskiArrowAngle"]) + rl.Rotatef(float32(env.Ports["sierpinskiArrowAngle"]), 0, 0, 1) + curve(env, order, length, -env.Ports["sierpinskiArrowAngle"]) } } -func curve(ctx *RenderCtx, order int, length float64, angle float64) { +func curve(env *Env, order int, length float64, angle float64) { if order == 0 { len := int32(length) rl.SetLineWidth(4) rl.DrawLine(0, 0, len, 0, rl.RayWhite) rl.Translatef(float32(length), 0, 0) } else { - curve(ctx, order-1, length/2, -angle) + curve(env, order-1, length/2, -angle) rl.Rotatef(float32(angle), 0, 0, 1) - curve(ctx, order-1, length/2, angle) + curve(env, order-1, length/2, angle) rl.Rotatef(float32(angle), 0, 0, 1) - curve(ctx, order-1, length/2, -angle) + curve(env, order-1, length/2, -angle) } } diff --git a/sketch.go b/sketch.go index e86b9a0..870447a 100644 --- a/sketch.go +++ b/sketch.go @@ -2,14 +2,13 @@ package main import ( "fmt" - g "github.com/d2fn/sumi/internal/graphics" + sg "github.com/d2fn/sumi/internal/graphics" "github.com/gen2brain/raylib-go/raylib" "math" ) type Sketch struct { - sourceWidth int32 - sourceHeight int32 + graphics *sg.Graphics cam *TextureCam composite rl.RenderTexture2D layerTools map[string]*LayerTools @@ -21,15 +20,6 @@ type TextureCam struct { Zoom float32 } -/** RenderCtx **/ -type RenderCtx struct { - TargetBounds g.Rect - SourceWidth int32 - SourceHeight int32 - Time float64 - Ports map[string]float64 -} - type LayerTools struct { name string layer Layer @@ -52,27 +42,26 @@ type LayerConfig struct { kValue float32 } -func NewSketch(sourceWidth, sourceHeight int32) Sketch { +func NewSketch(g *sg.Graphics) Sketch { // point at source center // put source center at center of screen var camera = TextureCam{ - LookAt: rl.Vector2{X: float32(sourceWidth) / 2.0, Y: float32(sourceHeight) / 2.0}, + LookAt: rl.Vector2{X: float32(g.Layout.Graphics.Width) / 2.0, Y: float32(g.Layout.Graphics.Height) / 2.0}, Zoom: 1.0, } return Sketch{ - sourceWidth: sourceWidth, - sourceHeight: sourceHeight, + graphics: g, layerTools: make(map[string]*LayerTools), layerToolsOrdered: []*LayerTools{}, - composite: rl.LoadRenderTexture(sourceWidth, sourceHeight), + composite: rl.LoadRenderTexture(int32(g.Layout.Graphics.Width), int32(g.Layout.Graphics.Height)), cam: &camera, } } func (s *Sketch) AddLayer(name string, layer Layer) { - texture := rl.LoadRenderTexture(s.sourceWidth, s.sourceHeight) + texture := rl.LoadRenderTexture(int32(s.graphics.Layout.Graphics.Width), int32(s.graphics.Layout.Graphics.Height)) config := NewLayerConfig() layerTools := LayerTools{ @@ -93,7 +82,8 @@ func (s *Sketch) AddColorLayer(name string, c rl.Color) { s.AddLayer(name, colorLayer) } -func (s *Sketch) Redraw(ctx *RenderCtx) { +func (s *Sketch) Redraw(ctx *Env) { + g := ctx.Graphics // render onto all layer textures for _, instance := range s.layerToolsOrdered { layer := instance.layer @@ -102,46 +92,51 @@ func (s *Sketch) Redraw(ctx *RenderCtx) { layer.Update(ctx) // re-render to texture if dirty if instance.layer.IsDirty() { - rl.BeginTextureMode(instance.texture) - rl.PushMatrix() + g.PushMatrix() + g.BeginTexture(instance.texture) layer.Draw(ctx) - rl.PopMatrix() - rl.EndTextureMode() + g.PopMatrix() + g.EndTexture() } } } } -func (s *Sketch) Draw(ctx *RenderCtx) { +func (s *Sketch) Draw(ctx *Env) { + g := ctx.Graphics s.Redraw(ctx) // copy from full texture for compositing, with vertical flipping + src := g.Layout.Graphics + src.Height = -src.Height + dst := g.Layout.Graphics + + /* src := g.Rect { X: 0, Y: 0, Width: float32(ctx.SourceWidth), Height: -float32(ctx.SourceHeight), } - dst := g.Rect { + dst := g.Rect{ X: 0, Y: 0, Width: float32(ctx.SourceWidth), Height: float32(ctx.SourceHeight), } + */ viewport := s.CalcViewport(ctx) - sourceRect := g.Rect{X: 0, Y: 0, Width: float32(ctx.SourceWidth), Height: float32(ctx.SourceHeight)} - targetRect := g.Rect{X: float32(ctx.TargetBounds.X), Y: float32(ctx.TargetBounds.Y), Width: float32(ctx.TargetBounds.Width), Height: float32(ctx.TargetBounds.Height)} - outputRect := sourceRect.ScaleTo(targetRect) + outputRect := g.Layout.Graphics.ScaleTo(g.Layout.Viewport) fmt.Printf("outputRect = %v\n", outputRect) x := float32(0) y := float32(0) w := outputRect.Width h := outputRect.Height - rl.PushMatrix() - rl.Translatef(outputRect.X, outputRect.Y, 0) - rl.BeginScissorMode(int32(outputRect.X), int32(outputRect.Y), int32(outputRect.Width), int32(outputRect.Height)) + g.PushMatrix() + g.Translate(outputRect.UL()) + g.BeginClip(outputRect) checkSize := float32(25.0) grey := rl.NewColor(220, 220, 220, 255) cellX := 0 @@ -161,8 +156,8 @@ func (s *Sketch) Draw(ctx *RenderCtx) { y += checkSize cellY++ } - rl.EndScissorMode() - rl.PopMatrix() + g.EndClip() + g.PopMatrix() rl.BeginBlendMode(rl.BlendAlphaPremultiply) //rl.BeginBlendMode(rl.BlendAlpha) @@ -188,7 +183,7 @@ func (s *Sketch) Draw(ctx *RenderCtx) { g = uint8(float32(g) * (float32(config.a) / 255.0)) b = uint8(float32(b) * (float32(config.a) / 255.0)) tint := rl.NewColor(r, g, b, config.a) - rl.DrawTexturePro(instance.texture.Texture, src, dst, rl.Vector2{}, 0, tint) + rl.DrawTexturePro(instance.texture.Texture, src.ToRL(), dst.ToRL(), rl.Vector2{}, 0, tint) } } rl.EndTextureMode() @@ -197,29 +192,30 @@ func (s *Sketch) Draw(ctx *RenderCtx) { rl.GenTextureMipmaps(&s.composite.Texture) rl.SetTextureFilter(s.composite.Texture, rl.FilterTrilinear) - rl.DrawTexturePro(s.composite.Texture, viewport, *outputRect.ToRL(), rl.Vector2{}, 0, rl.White) + rl.DrawTexturePro(s.composite.Texture, viewport.ToRL(), outputRect.ToRL(), rl.Vector2{}, 0, rl.White) - outlineRect := outputRect.ToRL().ToInt32() + outputRectRL := outputRect.ToRL() + outlineRect := (&outputRectRL).ToInt32() rl.DrawRectangleLines(outlineRect.X, outlineRect.Y, outlineRect.Width, outlineRect.Height, rl.Gray) } -func (s *Sketch) CalcViewport(ctx *RenderCtx) g.Rect { - viewportWidth := rl.Clamp(float32(ctx.SourceWidth)/s.cam.Zoom, 0, float32(ctx.SourceWidth)) - viewportHeight := rl.Clamp(float32(ctx.SourceHeight)/s.cam.Zoom, 0, float32(ctx.SourceHeight)) - return g.Rect { - X: rl.Clamp(s.cam.LookAt.X-viewportWidth/2.0, 0, float32(ctx.SourceWidth)-viewportWidth), - Y: rl.Clamp(s.cam.LookAt.Y-viewportHeight/2.0, 0, float32(ctx.SourceHeight)-viewportHeight), +func (s *Sketch) CalcViewport(ctx *Env) sg.Rect { + viewportWidth := rl.Clamp(float32(ctx.Graphics.Layout.Graphics.Width)/s.cam.Zoom, 0, float32(ctx.Graphics.Layout.Graphics.Width)) + viewportHeight := rl.Clamp(float32(ctx.Graphics.Layout.Graphics.Height)/s.cam.Zoom, 0, float32(ctx.Graphics.Layout.Graphics.Height)) + return sg.Rect{ + X: rl.Clamp(s.cam.LookAt.X-viewportWidth/2.0, 0, float32(ctx.Graphics.Layout.Graphics.Width)-viewportWidth), + Y: rl.Clamp(s.cam.LookAt.Y-viewportHeight/2.0, 0, float32(ctx.Graphics.Layout.Graphics.Height)-viewportHeight), Width: float32(viewportWidth), Height: -float32(viewportHeight), } } -func (s *Sketch) Update(ctx *RenderCtx) { +func (s *Sketch) Update(ctx *Env) { if rl.IsMouseButtonDown(rl.MouseRightButton) { // get mouse delta from last frame delta := rl.GetMouseDelta() - sourceScale := float32(ctx.SourceWidth) / float32(ctx.TargetBounds.Width) + sourceScale := float32(ctx.Graphics.Layout.Graphics.Width) / float32(ctx.Graphics.Layout.Viewport.Width) // compute the amount to move scaled by the camera zoom delta = rl.Vector2Scale(delta, -sourceScale/s.cam.Zoom) delta.Y = -delta.Y @@ -227,8 +223,8 @@ func (s *Sketch) Update(ctx *RenderCtx) { } // clamp LookAt to be somewhere on the texture - s.cam.LookAt.X = rl.Clamp(s.cam.LookAt.X, 0, float32(ctx.SourceWidth-1)) - s.cam.LookAt.Y = rl.Clamp(s.cam.LookAt.Y, 0, float32(ctx.SourceHeight-1)) + s.cam.LookAt.X = rl.Clamp(s.cam.LookAt.X, 0, float32(ctx.Graphics.Layout.Graphics.Width)) + s.cam.LookAt.Y = rl.Clamp(s.cam.LookAt.Y, 0, float32(ctx.Graphics.Layout.Graphics.Height)) // Zoom based on mouse wheel wheel := rl.GetMouseWheelMove() @@ -246,12 +242,12 @@ func (s *Sketch) Update(ctx *RenderCtx) { } func (s *Sketch) ResetCamera() { - s.cam.LookAt = rl.Vector2{X: float32(s.sourceWidth) / 2.0, Y: float32(s.sourceHeight) / 2.0} + s.cam.LookAt = rl.Vector2{X: float32(s.graphics.Layout.Graphics.Width) / 2.0, Y: float32(s.graphics.Layout.Graphics.Height) / 2.0} s.cam.Zoom = 1.0 } type SketchCapture struct { - width, height uint32 + width, height int32 compositeImage *rl.Image layerTools map[string]*LayerTools layerToolsOrdered []*LayerTools @@ -265,7 +261,8 @@ func (s *Sketch) Capture() *SketchCapture { rl.ImageFlipVertical(layerTool.capture) } return &SketchCapture{ - width: uint32(s.sourceWidth), height: uint32(s.sourceHeight), + width: s.graphics.GetGraphicsWidth(), + height: s.graphics.GetGraphicsHeight(), compositeImage: composite, layerTools: s.layerTools, layerToolsOrdered: s.layerToolsOrdered, @@ -290,8 +287,8 @@ func NewLayerConfig() LayerConfig { /** Layer **/ type Layer interface { - Update(ctx *RenderCtx) - Draw(ctx *RenderCtx) + Update(ctx *Env) + Draw(ctx *Env) IsDirty() bool } @@ -300,11 +297,11 @@ type ColorLayer struct { dirty bool } -func (cl *ColorLayer) Update(ctx *RenderCtx) { +func (cl *ColorLayer) Update(ctx *Env) { } -func (cl *ColorLayer) Draw(ctx *RenderCtx) { +func (cl *ColorLayer) Draw(ctx *Env) { rl.ClearBackground(cl.color) cl.dirty = false } @@ -327,12 +324,12 @@ func NewImageLayer(path string) *ImageLayer { } } -func (il *ImageLayer) Update(ctx *RenderCtx) { +func (il *ImageLayer) Update(ctx *Env) { } -func (il *ImageLayer) Draw(ctx *RenderCtx) { - rl.Translatef(float32(ctx.SourceWidth)/2.0-float32(il.texture.Width)/2.0, float32(ctx.SourceHeight)/2.0-float32(il.texture.Height)/2.0, 0) +func (il *ImageLayer) Draw(ctx *Env) { + rl.Translatef(float32(ctx.GetGraphicsWidth())/2.0-float32(il.texture.Width)/2.0, float32(ctx.GetGraphicsHeight())/2.0-float32(il.texture.Height)/2.0, 0) rl.DrawTexture(il.texture, 0, 0, rl.White) } @@ -344,22 +341,22 @@ type TestPattern struct { dirty bool } -func (tp *TestPattern) Update(ctx *RenderCtx) { +func (tp *TestPattern) Update(ctx *Env) { } -func (tp *TestPattern) Draw(ctx *RenderCtx) { +func (tp *TestPattern) Draw(ctx *Env) { rl.ClearBackground(rl.Black) - centerX := float32(ctx.SourceWidth) / 2 - centerY := float32(ctx.SourceHeight) / 2 + centerX := float32(ctx.GetGraphicsWidth()) / 2 + centerY := float32(ctx.GetGraphicsHeight()) / 2 - rl.DrawRectangleRec(*g.Rect{X: 0, Y: 0, Width: centerX, Height: centerY}.ToRL(), rl.Red) + rl.DrawRectangleRec(rl.Rectangle{X: 0, Y: 0, Width: centerX, Height: centerY}, rl.Red) rl.DrawRectangleRec(rl.Rectangle{X: centerX, Y: 0, Width: centerX, Height: centerY}, rl.Green) rl.DrawRectangleRec(rl.Rectangle{X: 0, Y: centerY, Width: centerX, Height: centerY}, rl.Blue) rl.DrawRectangleRec(rl.Rectangle{X: centerX, Y: centerY, Width: centerX, Height: centerY}, rl.White) - rl.DrawLine(0, 0, ctx.SourceWidth, ctx.SourceHeight, rl.Black) + rl.DrawLine(0, 0, ctx.Graphics.GetGraphicsWidth(), ctx.Graphics.GetGraphicsHeight(), rl.Black) rl.PushMatrix() rl.Translatef(centerX, centerY, 0)