From 6e8d97f29b18652d234a30eb39911c9443b59c83 Mon Sep 17 00:00:00 2001 From: Caleb Gardner Date: Sat, 11 Jan 2025 13:16:58 -0600 Subject: [PATCH] MORE MESSING AROUND --- .gitignore | 1 + internal/ui/round_rect.go | 226 ++++++++++++++++++++++++++++++-------- internal/ui/stuff.go | 13 ++- internal/ui/tween.go | 40 ++++++- 4 files changed, 227 insertions(+), 53 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3364861 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +testing/ diff --git a/internal/ui/round_rect.go b/internal/ui/round_rect.go index 9b4a227..041c2b7 100644 --- a/internal/ui/round_rect.go +++ b/internal/ui/round_rect.go @@ -1,8 +1,10 @@ package ui import ( + "fmt" "image" "image/color" + "time" rl "github.com/gen2brain/raylib-go/raylib" ) @@ -10,21 +12,25 @@ import ( // A rectangle with borders. // Default only has black borders. type Rect struct { - x int32 - y int32 - h int32 - w int32 - radius int32 + x int32 + y int32 + h int32 + w int32 + radius int32 + reload bool + shown bool + rendering bool borderWidth int32 borderColor color.RGBA fillColor color.RGBA - tex *rl.Texture2D + curTweens map[string]*Tween + tex rl.RenderTexture2D } func NewRect(x, y, height, width int32) *Rect { - return &Rect{ + r := &Rect{ x: x, y: y, h: height, @@ -33,93 +39,221 @@ func NewRect(x, y, height, width int32) *Rect { borderWidth: 2, borderColor: rl.Black, fillColor: rl.Blank, + reload: true, + curTweens: make(map[string]*Tween), } + r.tex = rl.LoadRenderTexture(width, height) + rl.SetTextureFilter(r.tex.Texture, rl.FilterAnisotropic8x|rl.FilterBilinear) + return r +} + +func (r *Rect) Copy() *Rect { + return &Rect{ + x: r.x, + y: r.y, + h: r.h, + w: r.w, + radius: r.radius, + borderWidth: r.borderWidth, + borderColor: r.borderColor, + fillColor: r.fillColor, + } +} + +func (r *Rect) addTween(key string, old, new int32) { + r.curTweens[key] = NewTween(old, new, 1000*time.Millisecond) } func (r *Rect) SetPosition(x, y int32) { - r.x, r.y = x, y + if !r.shown { + r.x, r.y = x, y + return + } + if r.x != x { + r.addTween("x", r.x, x) + } + if r.y != y { + r.addTween("y", r.y, y) + } } func (r *Rect) SetSize(h, w int32) { - r.h, r.w = h, w - r.Unload() + if !r.shown { + r.h, r.w = h, w + return + } + if r.h != h { + r.addTween("h", r.h, h) + r.reload = true + } + if r.w != w { + r.addTween("w", r.w, w) + r.reload = true + } } func (r *Rect) SetBorderRadius(radius int32) { - r.radius = radius - r.Unload() + if !r.shown { + r.radius = radius + return + } + if r.radius != radius { + r.addTween("radius", r.radius, radius) + r.reload = true + } } func (r *Rect) SetBorderWidth(w int32) { - r.borderWidth = w - r.Unload() + if !r.shown { + r.borderWidth = w + return + } + if r.borderWidth != w { + r.addTween("borderWidth", r.borderWidth, w) + r.reload = true + } } func (r *Rect) SetBorderColor(c color.RGBA) { + if r.borderColor != c { + r.reload = true + } r.borderColor = c - r.Unload() } func (r *Rect) SetFillColor(c color.RGBA) { - r.fillColor = c - r.Unload() -} - -func (r *Rect) Unload() { - if r.tex != nil { - rl.UnloadTexture(*r.tex) - r.tex = nil + if r.fillColor != c { + r.reload = true } + r.fillColor = c } func (r *Rect) Draw() { - if r.tex != nil { - rl.DrawTextureEx(*r.tex, rl.NewVector2(float32(r.x), float32(r.y)), 0, 1, rl.White) + r.shown = true + if !r.reload && len(r.curTweens) == 0 { + rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(r.x), float32(r.y)), 0, 1, rl.White) return } - // Create image at 16x resolution then resize down so it looks better - img := rl.NewImageFromImage(image.NewAlpha(image.Rect(0, 0, int(r.w*4), int(r.h*4)))) + var curRect *Rect + updateTex := false + if len(r.curTweens) != 0 { + curRect = r.Copy() + tween, ok := r.curTweens["x"] + if ok { + curRect.x = tween.CurVal() + if tween.Ended() { + r.x = curRect.x + delete(r.curTweens, "x") + } + } + tween, ok = r.curTweens["y"] + if ok { + curRect.y = tween.CurVal() + if tween.Ended() { + r.y = curRect.y + delete(r.curTweens, "y") + } + } + tween, ok = r.curTweens["h"] + if ok { + curRect.h = tween.CurVal() + if curRect.h != r.h { + updateTex = true + } + fmt.Println("h", curRect.h, r.h) + if tween.Ended() { + r.h = curRect.h + delete(r.curTweens, "h") + } + } + tween, ok = r.curTweens["w"] + if ok { + curRect.w = tween.CurVal() + if curRect.w != r.w { + updateTex = true + } + fmt.Println("w", curRect.w, r.w) + if tween.Ended() { + r.w = curRect.w + delete(r.curTweens, "w") + } + } + tween, ok = r.curTweens["radius"] + if ok { + curRect.radius = tween.CurVal() + if curRect.radius != r.radius { + updateTex = true + } + if tween.Ended() { + r.radius = curRect.radius + delete(r.curTweens, "radius") + } + } + tween, ok = r.curTweens["borderWidth"] + if ok { + curRect.borderWidth = tween.CurVal() + if curRect.borderWidth != r.borderWidth { + updateTex = true + } + if tween.Ended() { + r.borderWidth = curRect.borderWidth + delete(r.curTweens, "borderWidth") + } + } + } else { + curRect = r + } + if r.reload || updateTex { + // rl.UnloadTexture(r.tex) + // r.tex = rl.LoadTextureFromImage(curRect.buildImage()) + // rl.UpdateTexture(r.tex, rl.LoadImageColors(curRect.buildImage())) + rl.BeginTextureMode(r.tex) + rl.UpdateTextureRec(r.tex.Texture, rl.NewRectangle(0, 0, float32(curRect.w), float32(curRect.h)), rl.LoadImageColors(curRect.buildImage())) + rl.EndTextureMode() + } + rl.DrawTextureEx(r.tex.Texture, rl.NewVector2(float32(curRect.x), float32(curRect.y)), 0, 1, rl.White) + r.reload = false +} +func (r Rect) buildImage() *rl.Image { + // Create image at 16x resolution then resize down so it looks better + img := rl.NewImageFromImage(image.NewAlpha(image.Rect(0, 0, int(r.w), int(r.h)))) // Filled areas if r.fillColor != rl.Blank { - rl.ImageDrawRectangle(img, 4*r.radius, 0, 4*(r.w-(2*r.radius)), 4*r.h, r.fillColor) + rl.ImageDrawRectangle(img, r.radius, 0, (r.w - (2 * r.radius)), r.h, r.fillColor) if r.radius > 0 { - rl.ImageDrawRectangle(img, 4*(r.w-r.radius), 4*r.radius, 4*r.radius, 4*(r.h-(2*r.radius)), r.fillColor) - rl.ImageDrawRectangle(img, 0, 4*r.radius, 4*r.radius, 4*(r.h-(2*r.radius)), r.fillColor) + rl.ImageDrawRectangle(img, (r.w - r.radius), r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor) + rl.ImageDrawRectangle(img, 0, r.radius, r.radius, (r.h - (2 * r.radius)), r.fillColor) } } if r.borderColor != rl.Blank { // Horizontal lines - rl.ImageDrawRectangle(img, 4*r.radius, 0, 4*(r.w-(2*r.radius)), r.borderWidth*4, r.borderColor) - rl.ImageDrawRectangle(img, 4*r.radius, (4*r.h)-(r.borderWidth*4), 4*(r.w-(2*r.radius)), r.borderWidth*4, r.borderColor) + rl.ImageDrawRectangle(img, r.radius, 0, (r.w - (2 * r.radius)), r.borderWidth, r.borderColor) + rl.ImageDrawRectangle(img, r.radius, (r.h)-(r.borderWidth), (r.w - (2 * r.radius)), r.borderWidth, r.borderColor) // Vertical lines - rl.ImageDrawRectangle(img, 0, 4*r.radius, r.borderWidth*4, 4*(r.h-(2*r.radius)), r.borderColor) - rl.ImageDrawRectangle(img, (4*r.w)-(4*r.borderWidth), 4*r.radius, r.borderWidth*4, 4*(r.h-(2*r.radius)), r.borderColor) + rl.ImageDrawRectangle(img, 0, r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor) + rl.ImageDrawRectangle(img, (r.w)-(r.borderWidth), r.radius, r.borderWidth, (r.h - (2 * r.radius)), r.borderColor) } if r.radius > 0 { r.placeCorners(r.radius, img) } - - rl.ImageResize(img, r.w, r.h) - tmp := rl.LoadTextureFromImage(img) - r.tex = &tmp - rl.DrawTextureEx(*r.tex, rl.NewVector2(float32(r.x), float32(r.y)), 0, 1, r.borderColor) + return img } -func (r Rect) placeCorners(radius float32, img *rl.Image) { +func (r Rect) placeCorners(radius int32, img *rl.Image) { // Setup corner - corner := rl.NewImageFromImage(image.NewAlpha(image.Rect(0, 0, int(radius*4), int(radius*4)))) + corner := rl.NewImageFromImage(image.NewAlpha(image.Rect(0, 0, int(radius), int(radius)))) if r.borderWidth > 0 { - rl.ImageDrawCircleV(corner, 4*radius, 4*radius, 4*radius, r.borderColor) + rl.ImageDrawCircle(corner, radius, radius, radius, r.borderColor) } - rl.ImageDrawCircle(corner, 4*radius, 4*radius, (4*radius)-(4*r.borderWidth), r.fillColor) + rl.ImageDrawCircle(corner, radius, radius, (radius)-(r.borderWidth), r.fillColor) // Add corners to actual image rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.White) rl.ImageRotateCW(corner) - rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(float32(4*(r.w-radius)), 0, float32(corner.Width), float32(corner.Height)), rl.White) + rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(float32((r.w-radius)), 0, float32(corner.Width), float32(corner.Height)), rl.White) rl.ImageRotateCW(corner) - rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(float32(4*(r.w-radius)), float32(4*(r.h-radius)), float32(corner.Width), float32(corner.Height)), rl.White) + rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(float32((r.w-radius)), float32((r.h-radius)), float32(corner.Width), float32(corner.Height)), rl.White) rl.ImageRotateCW(corner) - rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(0, float32(4*(r.h-radius)), float32(corner.Width), float32(corner.Height)), rl.White) + rl.ImageDraw(img, corner, rl.NewRectangle(0, 0, float32(corner.Width), float32(corner.Height)), rl.NewRectangle(0, float32((r.h-radius)), float32(corner.Width), float32(corner.Height)), rl.White) } diff --git a/internal/ui/stuff.go b/internal/ui/stuff.go index d93d892..741588a 100644 --- a/internal/ui/stuff.go +++ b/internal/ui/stuff.go @@ -1,6 +1,8 @@ package ui import ( + "time" + rl "github.com/gen2brain/raylib-go/raylib" ) @@ -8,7 +10,7 @@ type Window struct{} func Test() { rl.InitWindow(800, 450, "raylib [core] example - basic window") - rl.SetWindowState(rl.FlagWindowResizable | rl.FlagWindowHighdpi) + rl.SetWindowState(rl.FlagWindowResizable | rl.FlagWindowHighdpi | rl.FlagVsyncHint) rl.SetConfigFlags(rl.FlagMsaa4xHint) defer rl.CloseWindow() rl.Scalef(2, 2, 2) @@ -20,9 +22,18 @@ func Test() { tmpRect := NewRect(10, 10, 250, 500) tmpRect.SetBorderRadius(25) + go func() { + for { + time.Sleep(5 * time.Second) + tmpRect.SetSize(200, 400) + time.Sleep(5 * time.Second) + tmpRect.SetSize(250, 500) + } + }() // tmpRect.SetFillColor(rl.Green) for !rl.WindowShouldClose() { rl.BeginDrawing() + rl.DrawFPS(0, 0) rl.ClearBackground(rl.DarkGray) // rl.DrawText("Congrats! You created your first window!", 190, 100, 20, rl.LightGray) diff --git a/internal/ui/tween.go b/internal/ui/tween.go index 6678eea..3ccb1cf 100644 --- a/internal/ui/tween.go +++ b/internal/ui/tween.go @@ -1,11 +1,39 @@ package ui -type num interface { - int32 | float32 +import ( + "math" + "time" +) + +type Tween struct { + startVal int32 + startTime time.Time + dif int32 + dur time.Duration } -type Tween[T num] struct { - start T - nextMult float32 - end T +func NewTween(startVal, endVal int32, duration time.Duration) *Tween { + return &Tween{ + startVal: startVal, + dif: endVal - startVal, + dur: duration, + startTime: time.Now().Round(time.Millisecond), + } +} + +func (t *Tween) CurVal() int32 { + since := time.Now().Round(time.Millisecond).Sub(t.startTime) + if since <= 0 { + return t.startVal + } + if since >= t.dur { + return t.startVal + t.dif + } + m := float32(since.Milliseconds()) / float32(t.dur.Milliseconds()) + m = -1 * float32(math.Log10(-.9*float64(m)+1)) + return t.startVal + int32(math.Round(float64(float32(t.dif)*m))) +} + +func (t *Tween) Ended() bool { + return time.Now().Round(time.Millisecond).Sub(t.startTime) >= t.dur }