diff --git a/cmd/fyne_demo/main.go b/cmd/fyne_demo/main.go index 1956818830..dbf17b1dc7 100644 --- a/cmd/fyne_demo/main.go +++ b/cmd/fyne_demo/main.go @@ -6,6 +6,7 @@ import "fmt" import "github.com/fyne-io/fyne" import "github.com/fyne-io/fyne/app" +import "github.com/fyne-io/fyne/canvas" import "github.com/fyne-io/fyne/layout" import "github.com/fyne-io/fyne/theme" import "github.com/fyne-io/fyne/dialog" @@ -43,6 +44,9 @@ func main() { entry := widget.NewEntry() entry.Text = "Entry" + cv := canvas.NewImageFromResource(theme.FyneLogo()) + cv.SetMinSize(fyne.NewSize(64, 64)) + w.SetContent(widget.NewVBox( widget.NewToolbar(widget.NewToolbarAction(theme.MailComposeIcon(), func() { fmt.Println("New") }), widget.NewToolbarSeparator(), @@ -64,6 +68,8 @@ func main() { widget.NewButton("Form", func() { formApp(app) }), ), + widget.NewHBox(layout.NewSpacer(), cv, layout.NewSpacer()), + widget.NewGroup("Dialogs", widget.NewButton("Info", func() { dialog.ShowInformation("Information", "You should know this thing...", w) diff --git a/driver/gl/draw.go b/driver/gl/draw.go index e8c8e60e35..be0b3be264 100644 --- a/driver/gl/draw.go +++ b/driver/gl/draw.go @@ -6,8 +6,16 @@ import ( "fmt" "github.com/fyne-io/fyne" "github.com/fyne-io/fyne/canvas" + "github.com/fyne-io/fyne/theme" "github.com/go-gl/gl/v3.3-core/gl" + "image/draw" + "log" + "os" + "path/filepath" + + "image" "image/color" + _ "image/png" "strings" ) @@ -66,46 +74,32 @@ const ( vertexShaderSource = ` #version 130 in vec3 vp; - uniform vec4 obj_fill_color; - out vec4 fill_color; + in vec2 vertTexCoord; + out vec2 fragTexCoord; + void main() { - fill_color = obj_fill_color; + fragTexCoord = vertTexCoord; + gl_Position = vec4(vp, 1.0); } ` + "\x00" fragmentShaderSource = ` #version 130 - in vec4 fill_color; + in vec2 fragTexCoord; out vec4 frag_colour; + uniform sampler2D tex; + void main() { - frag_colour = fill_color; + vec4 color = texture(tex, fragTexCoord); + if(color.a < 0.01) + discard; + + frag_colour = color; } ` + "\x00" ) -func square(size fyne.Size, pos fyne.Position, full fyne.Size) []float32 { - xPos := float32(pos.X) / float32(full.Width) - x1 := -1 + xPos*2 - x2Pos := float32(pos.X+size.Width) / float32(full.Width) - x2 := -1 + x2Pos*2 - - yPos := float32(pos.Y) / float32(full.Height) - y1 := 1 - yPos*2 - y2Pos := float32(pos.Y+size.Height) / float32(full.Height) - y2 := 1 - y2Pos*2 - - return []float32{ - x1, y1, 0, - x1, y2, 0, - x2, y2, 0, - - x1, y1, 0, - x2, y1, 0, - x2, y2, 0, - } -} - func (d *gLDriver) initOpenGL() { vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER) if err != nil { @@ -124,38 +118,110 @@ func (d *gLDriver) initOpenGL() { d.program = prog } -// makeVao initializes and returns a vertex array from the points provided. -func (c *glCanvas) makeVao(points []float32, fill color.Color) uint32 { +// rectCoords calculates the openGL coordinate space of a rectangle +func (c *glCanvas) rectCoords(size fyne.Size, pos fyne.Position) []float32 { + xPos := float32(pos.X) / float32(c.Size().Width) + x1 := -1 + xPos*2 + x2Pos := float32(pos.X+size.Width) / float32(c.Size().Width) + x2 := -1 + x2Pos*2 + + yPos := float32(pos.Y) / float32(c.Size().Height) + y1 := 1 - yPos*2 + y2Pos := float32(pos.Y+size.Height) / float32(c.Size().Height) + y2 := 1 - y2Pos*2 + + return []float32{ + // coord x, y, x texture x, y + x1, y2, 0, 0.0, 1.0, // top left + x1, y1, 0, 0.0, 0.0, // bottom left + x2, y2, 0, 1.0, 1.0, // top right + x2, y1, 0, 1.0, 0.0, // bottom right + } +} + +// textureForPoints initializes a vertex array and prepares a texture to draw on it +func (c *glCanvas) textureForPoints(points []float32) { var vbo uint32 gl.GenBuffers(1, &vbo) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW) - r, g, b, a := fill.RGBA() - loc := gl.GetUniformLocation(c.program, gl.Str("obj_fill_color\x00")) - gl.Uniform4f(loc, float32(uint8(r))/255, - float32(uint8(g))/255, float32(uint8(b))/255, float32(uint8(a))/255) - var vao uint32 gl.GenVertexArrays(1, &vao) gl.BindVertexArray(vao) gl.EnableVertexAttribArray(0) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) - gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil) + gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 5*4, nil) - return vao -} + textureUniform := gl.GetUniformLocation(c.program, gl.Str("tex\x00")) + gl.Uniform1i(textureUniform, 0) + + texCoordAttrib := uint32(gl.GetAttribLocation(c.program, gl.Str("vertTexCoord\x00"))) + gl.EnableVertexAttribArray(texCoordAttrib) + gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4)) -func draw(vao uint32, len int) { gl.BindVertexArray(vao) - gl.DrawArrays(gl.TRIANGLES, 0, int32(len/3)) + + var texture uint32 + gl.GenTextures(1, &texture) + gl.ActiveTexture(gl.TEXTURE0) + gl.BindTexture(gl.TEXTURE_2D, texture) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) + gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) } func (c *glCanvas) drawRectangle(rect *canvas.Rectangle, pos fyne.Position) { - // Add the padding so that our calculations fit in a smaller area - points := square(rect.Size, pos, c.Size()) - square := c.makeVao(points, rect.FillColor) - draw(square, len(points)) + points := c.rectCoords(rect.Size, pos) + c.textureForPoints(points) + + r, g, b, a := rect.FillColor.RGBA() + data := []uint8{uint8(r), uint8(g), uint8(b), uint8(a)} + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, + gl.UNSIGNED_BYTE, gl.Ptr(data)) + + gl.DrawArrays(gl.TRIANGLE_STRIP, 0, int32(len(points)/5)) +} + +func (c *glCanvas) drawRawImage(img *image.RGBA, size fyne.Size, pos fyne.Position) { + points := c.rectCoords(size, pos) + c.textureForPoints(points) + + gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(img.Rect.Size().X), int32(img.Rect.Size().Y), + 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix)) + + gl.DrawArrays(gl.TRIANGLE_STRIP, 0, int32(len(points)/5)) +} + +func (c *glCanvas) drawImage(img *canvas.Image, pos fyne.Position) { + raw := image.NewRGBA(image.Rect(0, 0, img.Size.Width, img.Size.Height)) + + if img.File != "" { + if strings.ToLower(filepath.Ext(img.File)) == ".svg" { + placeholderColor := &image.Uniform{color.RGBA{0, 0, 255, 255}} + draw.Draw(raw, raw.Bounds(), placeholderColor, image.ZP, draw.Src) + } else { + file, _ := os.Open(img.File) + pixels, _, err := image.Decode(file) + + if err != nil { + log.Println("image err", err) + + errColor := &image.Uniform{color.RGBA{255, 0, 0, 255}} + draw.Draw(raw, raw.Bounds(), errColor, image.ZP, draw.Src) + } else { + raw = image.NewRGBA(pixels.Bounds()) + + draw.Draw(raw, raw.Bounds(), pixels, image.ZP, draw.Src) + } + } + } else if img.PixelColor != nil { + pixels := NewPixelImage(img) + draw.Draw(raw, raw.Bounds(), pixels, image.ZP, draw.Src) + } + + c.drawRawImage(raw, img.Size, pos) } func (c *glCanvas) drawObject(o fyne.CanvasObject, offset fyne.Position) { @@ -163,5 +229,7 @@ func (c *glCanvas) drawObject(o fyne.CanvasObject, offset fyne.Position) { switch obj := o.(type) { case *canvas.Rectangle: c.drawRectangle(obj, pos) + case *canvas.Image: + c.drawImage(obj, pos) } } diff --git a/driver/gl/image.go b/driver/gl/image.go new file mode 100644 index 0000000000..eb2967f937 --- /dev/null +++ b/driver/gl/image.go @@ -0,0 +1,33 @@ +// +build !ci,gl + +package gl + +import ( + "github.com/fyne-io/fyne/canvas" + "image" + "image/color" +) + +type pixelImage struct { + source *canvas.Image +} + +func (i *pixelImage) ColorModel() color.Model { + return color.RGBAModel +} + +func (i *pixelImage) Bounds() image.Rectangle { + return image.Rect(0, 0, i.source.Size.Width, i.source.Size.Height) +} + +func (i *pixelImage) At(x, y int) color.Color { + if i.source.PixelColor == nil { + return color.Transparent + } + + return i.source.PixelColor(x, y, i.source.Size.Width, i.source.Size.Height) +} + +func NewPixelImage(source *canvas.Image) image.Image { + return &pixelImage{source: source} +} diff --git a/driver/gl/window.go b/driver/gl/window.go index fd4da1e9f7..de7a34de5c 100644 --- a/driver/gl/window.go +++ b/driver/gl/window.go @@ -66,7 +66,7 @@ func (w *window) SetFixedSize(fixed bool) { if fixed { w.viewport.SetSizeLimits(winWidth, winHeight, winWidth, winHeight) } else { - w.viewport.SetSizeLimits(winWidth, winHeight, 10000, 10000) + w.viewport.SetSizeLimits(winWidth, winHeight, glfw.DontCare, glfw.DontCare) } } diff --git a/widget/label.go b/widget/label.go index fbf66e63c1..21bbf6a50d 100644 --- a/widget/label.go +++ b/widget/label.go @@ -156,7 +156,7 @@ func (l *Label) RowLength(row int) int { func (l *Label) createRenderer() fyne.WidgetRenderer { render := &labelRenderer{label: l} - render.background = canvas.NewRectangle(theme.ButtonColor()) + render.background = canvas.NewRectangle(theme.BackgroundColor()) render.texts = []*canvas.Text{} render.objects = []fyne.CanvasObject{render.background} render.updateTexts(render.parseText(l.Text))