Renamed Image{,s} to Texture{,s}.
This commit is contained in:
parent
2c9007ce9b
commit
48aaf30182
@ -7,24 +7,24 @@ import (
|
||||
"opslag.de/schobers/zntg/ui"
|
||||
)
|
||||
|
||||
var _ ui.Image = &uiImage{}
|
||||
var _ ui.Texture = &texture{}
|
||||
|
||||
type uiImage struct {
|
||||
type texture struct {
|
||||
bmp *allg5.Bitmap
|
||||
}
|
||||
|
||||
func (i *uiImage) Destroy() {
|
||||
i.bmp.Destroy()
|
||||
func (t *texture) Destroy() {
|
||||
t.bmp.Destroy()
|
||||
}
|
||||
|
||||
func (i *uiImage) Height() float32 {
|
||||
return float32(i.bmp.Height())
|
||||
func (t *texture) Height() float32 {
|
||||
return float32(t.bmp.Height())
|
||||
}
|
||||
|
||||
func (i *uiImage) Image() image.Image {
|
||||
return i.bmp.Image()
|
||||
func (t *texture) Texture() image.Image {
|
||||
return t.bmp.Image()
|
||||
}
|
||||
|
||||
func (i *uiImage) Width() float32 {
|
||||
return float32(i.bmp.Width())
|
||||
func (t *texture) Width() float32 {
|
||||
return float32(t.bmp.Width())
|
||||
}
|
||||
|
@ -130,44 +130,44 @@ func (r *Renderer) Clear(c color.Color) {
|
||||
allg5.ClearToColor(newColor(c))
|
||||
}
|
||||
|
||||
func (r *Renderer) CreateImage(im image.Image) (ui.Image, error) {
|
||||
func (r *Renderer) CreateTexture(im image.Image) (ui.Texture, error) {
|
||||
bmp, err := allg5.NewBitmapFromImage(im, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &uiImage{bmp}, nil
|
||||
return &texture{bmp}, nil
|
||||
}
|
||||
|
||||
func (r *Renderer) CreateImagePath(path string) (ui.Image, error) {
|
||||
func (r *Renderer) CreateTexturePath(path string) (ui.Texture, error) {
|
||||
bmp, err := allg5.LoadBitmap(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &uiImage{bmp}, nil
|
||||
return &texture{bmp}, nil
|
||||
}
|
||||
|
||||
func (r *Renderer) CreateImageSize(w, h float32) (ui.Image, error) {
|
||||
func (r *Renderer) CreateTextureSize(w, h float32) (ui.Texture, error) {
|
||||
bmp, err := allg5.NewVideoBitmap(int(w), int(h))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &uiImage{bmp}, nil
|
||||
return &texture{bmp}, nil
|
||||
}
|
||||
|
||||
func (r *Renderer) DefaultTarget() ui.Image {
|
||||
return &uiImage{r.disp.Target()}
|
||||
func (r *Renderer) DefaultTarget() ui.Texture {
|
||||
return &texture{r.disp.Target()}
|
||||
}
|
||||
|
||||
func (r *Renderer) Display() *allg5.Display { return r.disp }
|
||||
|
||||
func (r *Renderer) DrawImage(im ui.Image, p geom.PointF32) {
|
||||
bmp := r.mustGetBitmap(im)
|
||||
func (r *Renderer) DrawTexture(texture ui.Texture, p geom.PointF32) {
|
||||
bmp := r.mustGetBitmap(texture)
|
||||
x, y := snap(p)
|
||||
bmp.Draw(x, y)
|
||||
}
|
||||
|
||||
func (r *Renderer) DrawImageOptions(im ui.Image, p geom.PointF32, opts ui.DrawOptions) {
|
||||
bmp := r.mustGetBitmap(im)
|
||||
func (r *Renderer) DrawTextureOptions(texture ui.Texture, p geom.PointF32, opts ui.DrawOptions) {
|
||||
bmp := r.mustGetBitmap(texture)
|
||||
var o allg5.DrawOptions
|
||||
if opts.Tint != nil {
|
||||
tint := newColor(opts.Tint)
|
||||
@ -188,12 +188,12 @@ func (r *Renderer) Font(name string) ui.Font {
|
||||
return r.ft[name]
|
||||
}
|
||||
|
||||
func (r *Renderer) mustGetBitmap(im ui.Image) *allg5.Bitmap {
|
||||
m, ok := im.(*uiImage)
|
||||
func (r *Renderer) mustGetBitmap(t ui.Texture) *allg5.Bitmap {
|
||||
texture, ok := t.(*texture)
|
||||
if !ok {
|
||||
panic("image must be created on same renderer")
|
||||
}
|
||||
return m.bmp
|
||||
return texture.bmp
|
||||
}
|
||||
|
||||
func (r *Renderer) Rectangle(rect geom.RectangleF32, c color.Color, thickness float32) {
|
||||
@ -225,8 +225,8 @@ func (r *Renderer) RegisterFonts(path string, fonts ...FontDefinition) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Renderer) RenderTo(im ui.Image) {
|
||||
bmp := r.mustGetBitmap(im)
|
||||
func (r *Renderer) RenderTo(texture ui.Texture) {
|
||||
bmp := r.mustGetBitmap(texture)
|
||||
bmp.SetAsTarget()
|
||||
}
|
||||
|
||||
@ -238,8 +238,8 @@ func (r *Renderer) Size() geom.PointF32 {
|
||||
return geom.PtF32(float32(r.disp.Width()), float32(r.disp.Height()))
|
||||
}
|
||||
|
||||
func (r *Renderer) SetIcon(im ui.Image) {
|
||||
bmp := r.mustGetBitmap(im)
|
||||
func (r *Renderer) SetIcon(texture ui.Texture) {
|
||||
bmp := r.mustGetBitmap(texture)
|
||||
r.disp.SetIcon(bmp)
|
||||
}
|
||||
|
||||
@ -255,8 +255,8 @@ func (r *Renderer) SetWindowTitle(t string) {
|
||||
r.disp.SetWindowTitle(t)
|
||||
}
|
||||
|
||||
func (r *Renderer) Target() ui.Image {
|
||||
return &uiImage{allg5.CurrentTarget()}
|
||||
func (r *Renderer) Target() ui.Texture {
|
||||
return &texture{allg5.CurrentTarget()}
|
||||
}
|
||||
|
||||
func (r *Renderer) text(p geom.PointF32, font string, c color.Color, t string, align allg5.HorizontalAlignment) {
|
||||
|
18
ui/buffer.go
18
ui/buffer.go
@ -5,38 +5,38 @@ import "opslag.de/schobers/geom"
|
||||
type RenderBufferFn func(ctx Context, size geom.PointF32)
|
||||
|
||||
type Buffer struct {
|
||||
im Image
|
||||
texture Texture
|
||||
size geom.PointF32
|
||||
}
|
||||
|
||||
func (b *Buffer) Update(ctx Context, size geom.PointF32) error {
|
||||
if b.im != nil {
|
||||
if b.texture != nil {
|
||||
if size == b.size {
|
||||
return nil
|
||||
}
|
||||
b.im.Destroy()
|
||||
b.im = nil
|
||||
b.texture.Destroy()
|
||||
b.texture = nil
|
||||
b.size = geom.ZeroPtF32
|
||||
}
|
||||
im, err := ctx.Renderer().CreateImageSize(size.X, size.Y)
|
||||
texture, err := ctx.Renderer().CreateTextureSize(size.X, size.Y)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.im = im
|
||||
b.texture = texture
|
||||
b.size = size
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Buffer) Render(ctx Context, pos geom.PointF32, fn RenderBufferFn) {
|
||||
if b.im == nil {
|
||||
if b.texture == nil {
|
||||
return
|
||||
}
|
||||
renderer := ctx.Renderer()
|
||||
currTarget := renderer.Target()
|
||||
renderer.RenderTo(b.im)
|
||||
renderer.RenderTo(b.texture)
|
||||
fn(ctx, b.size)
|
||||
renderer.RenderTo(currTarget)
|
||||
renderer.DrawImage(b.im, pos)
|
||||
renderer.DrawTexture(b.texture, pos)
|
||||
}
|
||||
|
||||
type BufferControl struct {
|
||||
|
10
ui/button.go
10
ui/button.go
@ -10,7 +10,7 @@ type Button struct {
|
||||
ControlBase
|
||||
|
||||
HoverColor color.Color
|
||||
Icon Image
|
||||
Icon Texture
|
||||
IconScale float32
|
||||
Text string
|
||||
Type ButtonType
|
||||
@ -27,8 +27,8 @@ const (
|
||||
|
||||
func BuildButton(text string, fn func(b *Button)) *Button { return BuildIconButton(nil, text, fn) }
|
||||
|
||||
func BuildIconButton(i Image, text string, fn func(b *Button)) *Button {
|
||||
var b = &Button{Text: text, Icon: i}
|
||||
func BuildIconButton(icon Texture, text string, fn func(b *Button)) *Button {
|
||||
var b = &Button{Text: text, Icon: icon}
|
||||
if fn != nil {
|
||||
fn(b)
|
||||
}
|
||||
@ -133,9 +133,9 @@ func (b *Button) Render(ctx Context) {
|
||||
bounds = bounds.Inset(pad)
|
||||
pos := bounds.Min
|
||||
if b.Icon != nil && b.Icon.Height() > 0 {
|
||||
icon, _ := ctx.Images().ScaledHeight(b.Icon, b.scale(bounds.Dy()))
|
||||
icon, _ := ctx.Textures().ScaledHeight(b.Icon, b.scale(bounds.Dy()))
|
||||
if icon != nil {
|
||||
ctx.Renderer().DrawImageOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: textColor})
|
||||
ctx.Renderer().DrawTextureOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: textColor})
|
||||
pos.X += icon.Width() + pad
|
||||
}
|
||||
}
|
||||
|
@ -30,12 +30,12 @@ func (c *Checkbox) desiredSize(ctx Context) geom.PointF32 {
|
||||
if len(c.Text) != 0 {
|
||||
w += pad + font.WidthOf(c.Text)
|
||||
}
|
||||
icon, _ := ctx.Images().ScaledHeight(c.getOrCreateNormalIcon(ctx), h)
|
||||
icon, _ := ctx.Textures().ScaledHeight(c.getOrCreateNormalIcon(ctx), h)
|
||||
w += pad + icon.Width()
|
||||
return geom.PtF32(w+pad, pad+h+pad)
|
||||
}
|
||||
|
||||
func (c *Checkbox) icon(ctx Context) Image {
|
||||
func (c *Checkbox) icon(ctx Context) Texture {
|
||||
if c.Selected {
|
||||
return GetOrCreateIcon(ctx, "ui-default-checkbox-selected", c.selectedIcon)
|
||||
} else if c.over {
|
||||
@ -44,7 +44,7 @@ func (c *Checkbox) icon(ctx Context) Image {
|
||||
return c.getOrCreateNormalIcon(ctx)
|
||||
}
|
||||
|
||||
func (c *Checkbox) getOrCreateNormalIcon(ctx Context) Image {
|
||||
func (c *Checkbox) getOrCreateNormalIcon(ctx Context) Texture {
|
||||
return GetOrCreateIcon(ctx, "ui-default-checkbox", c.normalIcon)
|
||||
}
|
||||
|
||||
@ -125,13 +125,13 @@ func (c *Checkbox) Render(ctx Context) {
|
||||
var pad = style.Dimensions.TextPadding
|
||||
bounds = bounds.Inset(pad)
|
||||
pos := bounds.Min
|
||||
icon, _ := ctx.Images().ScaledHeight(c.icon(ctx), bounds.Dy())
|
||||
icon, _ := ctx.Textures().ScaledHeight(c.icon(ctx), bounds.Dy())
|
||||
if icon != nil {
|
||||
iconColor := fore
|
||||
if c.Selected && c.Font.Color == nil {
|
||||
iconColor = palette.Primary
|
||||
}
|
||||
ctx.Renderer().DrawImageOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: iconColor})
|
||||
ctx.Renderer().DrawTextureOptions(icon, geom.PtF32(pos.X, pos.Y+.5*(bounds.Dy()-icon.Height())), DrawOptions{Tint: iconColor})
|
||||
pos.X += icon.Width() + pad
|
||||
}
|
||||
if len(c.Text) != 0 {
|
||||
|
@ -3,7 +3,7 @@ package ui
|
||||
type Context interface {
|
||||
Animate()
|
||||
HasQuit() bool
|
||||
Images() *Images
|
||||
Textures() *Textures
|
||||
Quit()
|
||||
Renderer() Renderer
|
||||
Style() *Style
|
||||
@ -17,7 +17,7 @@ type context struct {
|
||||
quit chan struct{}
|
||||
r Renderer
|
||||
view Control
|
||||
ims *Images
|
||||
textures *Textures
|
||||
style *Style
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ func (c *context) HasQuit() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *context) Images() *Images { return c.ims }
|
||||
func (c *context) Textures() *Textures { return c.textures }
|
||||
|
||||
func (c *context) Quit() {
|
||||
if !c.HasQuit() {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
type basic struct {
|
||||
ui.StackPanel
|
||||
|
||||
plus ui.Image
|
||||
plus ui.Texture
|
||||
}
|
||||
|
||||
func (b *basic) Init(ctx ui.Context) error {
|
||||
@ -73,7 +73,7 @@ func run() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plus, err := render.CreateImagePath("../resources/images/plus.png")
|
||||
plus, err := render.CreateTexturePath("../resources/images/plus.png")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
34
ui/icon.go
34
ui/icon.go
@ -10,27 +10,27 @@ import (
|
||||
type ImagePixelTestFn func(geom.PointF32) bool
|
||||
type ImageAlphaPixelTestFn func(geom.PointF32) uint8
|
||||
|
||||
func createImage(ctx Context, image image.Image) Image {
|
||||
im, err := ctx.Renderer().CreateImage(image)
|
||||
func createTexture(ctx Context, image image.Image) Texture {
|
||||
texture, err := ctx.Renderer().CreateTexture(image)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return im
|
||||
return texture
|
||||
}
|
||||
|
||||
func CreateIcon(ctx Context, test ImagePixelTestFn) Image {
|
||||
func CreateIcon(ctx Context, test ImagePixelTestFn) Texture {
|
||||
icon := DrawIcon(test)
|
||||
return createImage(ctx, icon)
|
||||
return createTexture(ctx, icon)
|
||||
}
|
||||
|
||||
func CreateImage(ctx Context, size geom.Point, test ImagePixelTestFn) Image {
|
||||
func CreateTexture(ctx Context, size geom.Point, test ImagePixelTestFn) Texture {
|
||||
image := DrawImage(size, test)
|
||||
return createImage(ctx, image)
|
||||
return createTexture(ctx, image)
|
||||
}
|
||||
|
||||
func CreateImageAlpha(ctx Context, size geom.Point, test ImageAlphaPixelTestFn) Image {
|
||||
func CreateTextureAlpha(ctx Context, size geom.Point, test ImageAlphaPixelTestFn) Texture {
|
||||
image := DrawImageAlpha(size, test)
|
||||
return createImage(ctx, image)
|
||||
return createTexture(ctx, image)
|
||||
}
|
||||
|
||||
func DrawIcon(test ImagePixelTestFn) image.Image {
|
||||
@ -66,18 +66,18 @@ func DrawImageAlpha(size geom.Point, test ImageAlphaPixelTestFn) image.Image {
|
||||
return icon
|
||||
}
|
||||
|
||||
func GetOrCreateIcon(ctx Context, name string, testFactory func() ImagePixelTestFn) Image {
|
||||
im := ctx.Images().Image(name)
|
||||
if im != nil {
|
||||
return im
|
||||
func GetOrCreateIcon(ctx Context, name string, testFactory func() ImagePixelTestFn) Texture {
|
||||
texture := ctx.Textures().Texture(name)
|
||||
if texture != nil {
|
||||
return texture
|
||||
}
|
||||
test := testFactory()
|
||||
im = CreateIcon(ctx, test)
|
||||
if im == nil {
|
||||
texture = CreateIcon(ctx, test)
|
||||
if texture == nil {
|
||||
return nil
|
||||
}
|
||||
ctx.Images().AddImage(name, im)
|
||||
return im
|
||||
ctx.Textures().AddTexture(name, texture)
|
||||
return texture
|
||||
}
|
||||
|
||||
func IconSize() geom.Point {
|
||||
|
123
ui/images.go
123
ui/images.go
@ -1,123 +0,0 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
"opslag.de/schobers/geom"
|
||||
)
|
||||
|
||||
type CreateImageFn func() (image.Image, error)
|
||||
|
||||
func ScaleImage(render Renderer, im Image, scale float32) Image {
|
||||
w := uint(im.Width() * scale)
|
||||
if w == 0 {
|
||||
return nil
|
||||
}
|
||||
scaled := resize.Resize(w, 0, im.Image(), resize.Bilinear)
|
||||
res, err := render.CreateImage(scaled)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type Images struct {
|
||||
render Renderer
|
||||
ims map[string]Image
|
||||
scaled map[Image]ScaledImages
|
||||
}
|
||||
|
||||
func NewImages(render Renderer) *Images {
|
||||
return &Images{render, map[string]Image{}, map[Image]ScaledImages{}}
|
||||
}
|
||||
|
||||
func (i *Images) AddImage(name string, im Image) {
|
||||
curr := i.ims[name]
|
||||
if curr != nil {
|
||||
curr.Destroy()
|
||||
}
|
||||
i.ims[name] = im
|
||||
}
|
||||
|
||||
func (i *Images) AddImageFn(name string, create CreateImageFn) error {
|
||||
im, err := create()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return i.AddImageNative(name, im)
|
||||
}
|
||||
|
||||
func (i *Images) AddImageNative(name string, im image.Image) error {
|
||||
m, err := i.render.CreateImage(im)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.AddImage(name, m)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Images) Destroy() {
|
||||
for _, im := range i.ims {
|
||||
im.Destroy()
|
||||
}
|
||||
i.ims = nil
|
||||
for _, ims := range i.scaled {
|
||||
ims.Destroy()
|
||||
}
|
||||
i.scaled = nil
|
||||
}
|
||||
|
||||
func (i *Images) Image(name string) Image {
|
||||
im, ok := i.ims[name]
|
||||
if ok {
|
||||
return im
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Images) Scaled(im Image, scale float32) Image {
|
||||
if scale <= 0 {
|
||||
return nil
|
||||
}
|
||||
if scale == 1 {
|
||||
return im
|
||||
}
|
||||
ims := i.scaled[im]
|
||||
if ims == nil {
|
||||
ims = make(ScaledImages)
|
||||
} else {
|
||||
scaled := ims[scale]
|
||||
if scaled != nil {
|
||||
return scaled
|
||||
}
|
||||
}
|
||||
scaled := ScaleImage(i.render, im, scale)
|
||||
ims[scale] = scaled
|
||||
i.scaled[im] = ims
|
||||
return scaled
|
||||
}
|
||||
|
||||
func (i *Images) ScaledHeight(im Image, height float32) (Image, float32) {
|
||||
scale := height / im.Height()
|
||||
if geom.IsNaN32(scale) {
|
||||
return nil, 0
|
||||
}
|
||||
return i.Scaled(im, scale), scale
|
||||
}
|
||||
|
||||
func (i *Images) ScaledByName(name string, scale float32) Image {
|
||||
im := i.Image(name)
|
||||
if im == nil {
|
||||
return nil
|
||||
}
|
||||
return i.Scaled(im, scale)
|
||||
}
|
||||
|
||||
type ScaledImages map[float32]Image
|
||||
|
||||
func (i ScaledImages) Destroy() {
|
||||
for _, im := range i {
|
||||
im.Destroy()
|
||||
}
|
||||
}
|
@ -17,21 +17,21 @@ type Renderer interface {
|
||||
|
||||
// Drawing
|
||||
Clear(c color.Color)
|
||||
CreateImage(m image.Image) (Image, error)
|
||||
CreateImagePath(path string) (Image, error)
|
||||
CreateImageSize(w, h float32) (Image, error)
|
||||
DefaultTarget() Image
|
||||
DrawImage(im Image, p geom.PointF32)
|
||||
DrawImageOptions(im Image, p geom.PointF32, opts DrawOptions)
|
||||
CreateTexture(m image.Image) (Texture, error)
|
||||
CreateTexturePath(path string) (Texture, error)
|
||||
CreateTextureSize(w, h float32) (Texture, error)
|
||||
DefaultTarget() Texture
|
||||
DrawTexture(t Texture, p geom.PointF32)
|
||||
DrawTextureOptions(t Texture, p geom.PointF32, opts DrawOptions)
|
||||
FillRectangle(r geom.RectangleF32, c color.Color)
|
||||
Font(name string) Font
|
||||
Rectangle(r geom.RectangleF32, c color.Color, thickness float32)
|
||||
RegisterFont(name, path string, size int) error
|
||||
RenderTo(Image)
|
||||
RenderTo(Texture)
|
||||
RenderToDisplay()
|
||||
SetMouseCursor(c MouseCursor)
|
||||
Size() geom.PointF32
|
||||
Target() Image
|
||||
Target() Texture
|
||||
Text(p geom.PointF32, font string, color color.Color, text string)
|
||||
TextAlign(p geom.PointF32, font string, color color.Color, text string, align HorizontalAlignment)
|
||||
}
|
||||
|
@ -134,17 +134,17 @@ func (s *Slider) OnValueChanged(fn func(float32)) {
|
||||
type sliderHandle struct {
|
||||
ControlBase
|
||||
|
||||
handle Image
|
||||
handle Texture
|
||||
}
|
||||
|
||||
func (h *sliderHandle) im(ctx Context) Image {
|
||||
func (h *sliderHandle) texture(ctx Context) Texture {
|
||||
if h.handle != nil {
|
||||
return h.handle
|
||||
}
|
||||
size := h.Bounds().Size()
|
||||
center := geom.PtF32(.5*size.X-.5, .5*size.Y-.5)
|
||||
radius := 0.5 * geom.Min32(size.X, size.Y)
|
||||
h.handle = CreateImageAlpha(ctx, geom.Pt(int(size.X), int(size.Y)), func(p geom.PointF32) uint8 {
|
||||
h.handle = CreateTextureAlpha(ctx, geom.Pt(int(size.X), int(size.Y)), func(p geom.PointF32) uint8 {
|
||||
dist := center.Distance(p)
|
||||
if dist < radius {
|
||||
if dist < (radius - 1) {
|
||||
@ -169,5 +169,5 @@ func (h *sliderHandle) Render(ctx Context) {
|
||||
if h.IsOver() {
|
||||
color = ctx.Style().Palette.PrimaryLight
|
||||
}
|
||||
ctx.Renderer().DrawImageOptions(h.im(ctx), h.Bounds().Min, DrawOptions{Tint: color})
|
||||
ctx.Renderer().DrawTextureOptions(h.texture(ctx), h.Bounds().Min, DrawOptions{Tint: color})
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ package ui
|
||||
|
||||
import "image"
|
||||
|
||||
type Image interface {
|
||||
type Texture interface {
|
||||
Destroy()
|
||||
Height() float32
|
||||
Image() image.Image
|
||||
Texture() image.Image
|
||||
Width() float32
|
||||
}
|
123
ui/textures.go
Normal file
123
ui/textures.go
Normal file
@ -0,0 +1,123 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
"opslag.de/schobers/geom"
|
||||
)
|
||||
|
||||
type CreateImageFn func() (image.Image, error)
|
||||
|
||||
func ScaleTexture(render Renderer, texture Texture, scale float32) Texture {
|
||||
w := uint(texture.Width() * scale)
|
||||
if w == 0 {
|
||||
return nil
|
||||
}
|
||||
scaled := resize.Resize(w, 0, texture.Texture(), resize.Bilinear)
|
||||
res, err := render.CreateTexture(scaled)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
type Textures struct {
|
||||
render Renderer
|
||||
textures map[string]Texture
|
||||
scaled map[Texture]ScaledTextures
|
||||
}
|
||||
|
||||
func NewTextures(render Renderer) *Textures {
|
||||
return &Textures{render, map[string]Texture{}, map[Texture]ScaledTextures{}}
|
||||
}
|
||||
|
||||
func (t *Textures) AddTexture(name string, texture Texture) {
|
||||
curr := t.textures[name]
|
||||
if curr != nil {
|
||||
curr.Destroy()
|
||||
}
|
||||
t.textures[name] = texture
|
||||
}
|
||||
|
||||
func (t *Textures) AddTextureFn(name string, create CreateImageFn) error {
|
||||
im, err := create()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.AddTextureNative(name, im)
|
||||
}
|
||||
|
||||
func (t *Textures) AddTextureNative(name string, im image.Image) error {
|
||||
texture, err := t.render.CreateTexture(im)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.AddTexture(name, texture)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Textures) Destroy() {
|
||||
for _, texture := range t.textures {
|
||||
texture.Destroy()
|
||||
}
|
||||
t.textures = nil
|
||||
for _, textures := range t.scaled {
|
||||
textures.Destroy()
|
||||
}
|
||||
t.scaled = nil
|
||||
}
|
||||
|
||||
func (t *Textures) Texture(name string) Texture {
|
||||
texture, ok := t.textures[name]
|
||||
if ok {
|
||||
return texture
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Textures) Scaled(texture Texture, scale float32) Texture {
|
||||
if scale <= 0 {
|
||||
return nil
|
||||
}
|
||||
if scale == 1 {
|
||||
return texture
|
||||
}
|
||||
textures := t.scaled[texture]
|
||||
if textures == nil {
|
||||
textures = make(ScaledTextures)
|
||||
} else {
|
||||
scaled := textures[scale]
|
||||
if scaled != nil {
|
||||
return scaled
|
||||
}
|
||||
}
|
||||
scaled := ScaleTexture(t.render, texture, scale)
|
||||
textures[scale] = scaled
|
||||
t.scaled[texture] = textures
|
||||
return scaled
|
||||
}
|
||||
|
||||
func (t *Textures) ScaledHeight(textures Texture, height float32) (Texture, float32) {
|
||||
scale := height / textures.Height()
|
||||
if geom.IsNaN32(scale) {
|
||||
return nil, 0
|
||||
}
|
||||
return t.Scaled(textures, scale), scale
|
||||
}
|
||||
|
||||
func (t *Textures) ScaledByName(name string, scale float32) Texture {
|
||||
textures := t.Texture(name)
|
||||
if textures == nil {
|
||||
return nil
|
||||
}
|
||||
return t.Scaled(textures, scale)
|
||||
}
|
||||
|
||||
type ScaledTextures map[float32]Texture
|
||||
|
||||
func (t ScaledTextures) Destroy() {
|
||||
for _, textures := range t {
|
||||
textures.Destroy()
|
||||
}
|
||||
}
|
2
ui/ui.go
2
ui/ui.go
@ -13,7 +13,7 @@ func Run(r Renderer, s *Style, view Control) error {
|
||||
|
||||
// RunWait runs the application loop and conditionally waits on events before rendering.
|
||||
func RunWait(r Renderer, s *Style, view Control, wait bool) error {
|
||||
ctx := &context{quit: make(chan struct{}), r: r, style: s, view: view, ims: NewImages(r)}
|
||||
ctx := &context{quit: make(chan struct{}), r: r, style: s, view: view, textures: NewTextures(r)}
|
||||
root, ok := view.(RootControl)
|
||||
if ok {
|
||||
err := root.Init(ctx)
|
||||
|
Loading…
Reference in New Issue
Block a user