adam-gui/vendor/fyne.io/fyne/v2/internal/painter/gl/texture.go

187 lines
4.9 KiB
Go
Raw Permalink Normal View History

2024-04-29 19:13:50 +02:00
package gl
import (
"fmt"
"image"
"image/draw"
"math"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/internal/cache"
paint "fyne.io/fyne/v2/internal/painter"
"fyne.io/fyne/v2/theme"
)
var noTexture = Texture(cache.NoTexture)
// Texture represents an uploaded GL texture
type Texture cache.TextureType
func (p *painter) freeTexture(obj fyne.CanvasObject) {
texture, ok := cache.GetTexture(obj)
if !ok {
return
}
p.ctx.DeleteTexture(Texture(texture))
p.logError()
cache.DeleteTexture(obj)
}
func (p *painter) getTexture(object fyne.CanvasObject, creator func(canvasObject fyne.CanvasObject) Texture) (Texture, error) {
texture, ok := cache.GetTexture(object)
if !ok {
texture = cache.TextureType(creator(object))
cache.SetTexture(object, texture, p.canvas)
}
if !cache.IsValid(texture) {
return noTexture, fmt.Errorf("no texture available")
}
return Texture(texture), nil
}
func (p *painter) imgToTexture(img image.Image, textureFilter canvas.ImageScale) Texture {
switch i := img.(type) {
case *image.Uniform:
texture := p.newTexture(textureFilter)
r, g, b, a := i.RGBA()
r8, g8, b8, a8 := uint8(r>>8), uint8(g>>8), uint8(b>>8), uint8(a>>8)
data := []uint8{r8, g8, b8, a8}
p.ctx.TexImage2D(
texture2D,
0,
1,
1,
colorFormatRGBA,
unsignedByte,
data,
)
p.logError()
return texture
case *image.RGBA:
if len(i.Pix) == 0 { // image is empty
return noTexture
}
texture := p.newTexture(textureFilter)
p.ctx.TexImage2D(
texture2D,
0,
i.Rect.Size().X,
i.Rect.Size().Y,
colorFormatRGBA,
unsignedByte,
i.Pix,
)
p.logError()
return texture
default:
rgba := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy()))
draw.Draw(rgba, rgba.Rect, img, image.Point{}, draw.Over)
return p.imgToTexture(rgba, textureFilter)
}
}
func (p *painter) newGlCircleTexture(obj fyne.CanvasObject) Texture {
circle := obj.(*canvas.Circle)
raw := paint.DrawCircle(circle, paint.VectorPad(circle), p.textureScale)
return p.imgToTexture(raw, canvas.ImageScaleSmooth)
}
func (p *painter) newGlImageTexture(obj fyne.CanvasObject) Texture {
img := obj.(*canvas.Image)
width := p.textureScale(img.Size().Width)
height := p.textureScale(img.Size().Height)
tex := paint.PaintImage(img, p.canvas, int(width), int(height))
if tex == nil {
return noTexture
}
return p.imgToTexture(tex, img.ScaleMode)
}
func (p *painter) newGlLinearGradientTexture(obj fyne.CanvasObject) Texture {
gradient := obj.(*canvas.LinearGradient)
w := gradient.Size().Width
h := gradient.Size().Height
switch gradient.Angle {
case 90, 270:
h = 1
case 0, 180:
w = 1
}
width := p.textureScale(w)
height := p.textureScale(h)
return p.imgToTexture(gradient.Generate(int(width), int(height)), canvas.ImageScaleSmooth)
}
func (p *painter) newGlRadialGradientTexture(obj fyne.CanvasObject) Texture {
gradient := obj.(*canvas.RadialGradient)
width := p.textureScale(gradient.Size().Width)
height := p.textureScale(gradient.Size().Height)
return p.imgToTexture(gradient.Generate(int(width), int(height)), canvas.ImageScaleSmooth)
}
func (p *painter) newGlRasterTexture(obj fyne.CanvasObject) Texture {
rast := obj.(*canvas.Raster)
width := p.textureScale(rast.Size().Width)
height := p.textureScale(rast.Size().Height)
return p.imgToTexture(rast.Generator(int(width), int(height)), rast.ScaleMode)
}
func (p *painter) newGlTextTexture(obj fyne.CanvasObject) Texture {
text := obj.(*canvas.Text)
color := text.Color
if color == nil {
color = theme.ForegroundColor()
}
bounds := text.MinSize()
width := int(math.Ceil(float64(p.textureScale(bounds.Width) + paint.VectorPad(text)))) // potentially italic overspill
height := int(math.Ceil(float64(p.textureScale(bounds.Height))))
img := image.NewNRGBA(image.Rect(0, 0, width, height))
face := paint.CachedFontFace(text.TextStyle, text.TextSize*p.canvas.Scale(), p.texScale)
paint.DrawString(img, text.Text, color, face.Fonts, text.TextSize, p.pixScale, text.TextStyle.TabWidth)
return p.imgToTexture(img, canvas.ImageScaleSmooth)
}
func (p *painter) newTexture(textureFilter canvas.ImageScale) Texture {
if int(textureFilter) >= len(textureFilterToGL) {
fyne.LogError(fmt.Sprintf("Invalid canvas.ImageScale value (%d), using canvas.ImageScaleSmooth as default value", textureFilter), nil)
textureFilter = canvas.ImageScaleSmooth
}
texture := p.ctx.CreateTexture()
p.logError()
p.ctx.ActiveTexture(texture0)
p.ctx.BindTexture(texture2D, texture)
p.logError()
p.ctx.TexParameteri(texture2D, textureMinFilter, textureFilterToGL[textureFilter])
p.ctx.TexParameteri(texture2D, textureMagFilter, textureFilterToGL[textureFilter])
p.ctx.TexParameteri(texture2D, textureWrapS, clampToEdge)
p.ctx.TexParameteri(texture2D, textureWrapT, clampToEdge)
p.logError()
return texture
}
func (p *painter) textureScale(v float32) float32 {
if p.pixScale == 1.0 {
return float32(math.Round(float64(v)))
}
return float32(math.Round(float64(v * p.pixScale)))
}