adopt github.com/faiface/mainthread package + frame prototype

This commit is contained in:
faiface 2017-01-20 17:45:19 +01:00
parent de21a40184
commit 7a7b2f2588
11 changed files with 141 additions and 148 deletions

View File

@ -1,7 +1,7 @@
package pixel package pixel
import ( import (
"github.com/faiface/pixel/pixelgl" "github.com/faiface/mainthread"
"github.com/go-gl/glfw/v3.2/glfw" "github.com/go-gl/glfw/v3.2/glfw"
) )
@ -23,7 +23,7 @@ func (w *Window) JustReleased(button Button) bool {
// MousePosition returns the current mouse position relative to the window. // MousePosition returns the current mouse position relative to the window.
func (w *Window) MousePosition() Vec { func (w *Window) MousePosition() Vec {
var x, y, width, height float64 var x, y, width, height float64
pixelgl.Do(func() { mainthread.Call(func() {
x, y = w.window.GetCursorPos() x, y = w.window.GetCursorPos()
wi, hi := w.window.GetSize() wi, hi := w.window.GetSize()
width, height = float64(wi), float64(hi) width, height = float64(wi), float64(hi)
@ -187,7 +187,7 @@ const (
) )
func (w *Window) initInput() { func (w *Window) initInput() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
switch action { switch action {
case glfw.Press: case glfw.Press:
@ -220,7 +220,7 @@ func (w *Window) updateInput() {
w.currInp.scroll -= w.tempInp.scroll w.currInp.scroll -= w.tempInp.scroll
// get events (usually calls callbacks, but callbacks can be called outside too) // get events (usually calls callbacks, but callbacks can be called outside too)
pixelgl.Do(func() { mainthread.Call(func() {
glfw.PollEvents() glfw.PollEvents()
}) })

View File

@ -1,7 +1,7 @@
package pixel package pixel
import ( import (
"github.com/faiface/pixel/pixelgl" "github.com/faiface/mainthread"
"github.com/go-gl/glfw/v3.2/glfw" "github.com/go-gl/glfw/v3.2/glfw"
) )
@ -12,7 +12,7 @@ type Monitor struct {
// PrimaryMonitor returns the main monitor (usually the one with the taskbar and stuff). // PrimaryMonitor returns the main monitor (usually the one with the taskbar and stuff).
func PrimaryMonitor() *Monitor { func PrimaryMonitor() *Monitor {
monitor := pixelgl.DoVal(func() interface{} { monitor := mainthread.CallVal(func() interface{} {
return glfw.GetPrimaryMonitor() return glfw.GetPrimaryMonitor()
}).(*glfw.Monitor) }).(*glfw.Monitor)
return &Monitor{ return &Monitor{
@ -23,7 +23,7 @@ func PrimaryMonitor() *Monitor {
// Monitors returns a slice of all currently available monitors. // Monitors returns a slice of all currently available monitors.
func Monitors() []*Monitor { func Monitors() []*Monitor {
var monitors []*Monitor var monitors []*Monitor
pixelgl.Do(func() { mainthread.Call(func() {
for _, monitor := range glfw.GetMonitors() { for _, monitor := range glfw.GetMonitors() {
monitors = append(monitors, &Monitor{monitor: monitor}) monitors = append(monitors, &Monitor{monitor: monitor})
} }
@ -33,7 +33,7 @@ func Monitors() []*Monitor {
// Name returns a human-readable name of a monitor. // Name returns a human-readable name of a monitor.
func (m *Monitor) Name() string { func (m *Monitor) Name() string {
name := pixelgl.DoVal(func() interface{} { name := mainthread.CallVal(func() interface{} {
return m.monitor.GetName() return m.monitor.GetName()
}).(string) }).(string)
return name return name
@ -42,7 +42,7 @@ func (m *Monitor) Name() string {
// PhysicalSize returns the size of the display area of a monitor in millimeters. // PhysicalSize returns the size of the display area of a monitor in millimeters.
func (m *Monitor) PhysicalSize() (width, height float64) { func (m *Monitor) PhysicalSize() (width, height float64) {
var wi, hi int var wi, hi int
pixelgl.Do(func() { mainthread.Call(func() {
wi, hi = m.monitor.GetPhysicalSize() wi, hi = m.monitor.GetPhysicalSize()
}) })
width = float64(wi) width = float64(wi)
@ -53,7 +53,7 @@ func (m *Monitor) PhysicalSize() (width, height float64) {
// Position returns the position of the upper-left corner of a monitor in screen coordinates. // Position returns the position of the upper-left corner of a monitor in screen coordinates.
func (m *Monitor) Position() (x, y float64) { func (m *Monitor) Position() (x, y float64) {
var xi, yi int var xi, yi int
pixelgl.Do(func() { mainthread.Call(func() {
xi, yi = m.monitor.GetPos() xi, yi = m.monitor.GetPos()
}) })
x = float64(xi) x = float64(xi)
@ -63,7 +63,7 @@ func (m *Monitor) Position() (x, y float64) {
// Size returns the resolution of a monitor in pixels. // Size returns the resolution of a monitor in pixels.
func (m *Monitor) Size() (width, height float64) { func (m *Monitor) Size() (width, height float64) {
mode := pixelgl.DoVal(func() interface{} { mode := mainthread.CallVal(func() interface{} {
return m.monitor.GetVideoMode() return m.monitor.GetVideoMode()
}).(*glfw.VidMode) }).(*glfw.VidMode)
width = float64(mode.Width) width = float64(mode.Width)
@ -73,7 +73,7 @@ func (m *Monitor) Size() (width, height float64) {
// BitDepth returns the number of bits per color of a monitor. // BitDepth returns the number of bits per color of a monitor.
func (m *Monitor) BitDepth() (red, green, blue int) { func (m *Monitor) BitDepth() (red, green, blue int) {
mode := pixelgl.DoVal(func() interface{} { mode := mainthread.CallVal(func() interface{} {
return m.monitor.GetVideoMode() return m.monitor.GetVideoMode()
}).(*glfw.VidMode) }).(*glfw.VidMode)
red = mode.RedBits red = mode.RedBits
@ -84,7 +84,7 @@ func (m *Monitor) BitDepth() (red, green, blue int) {
// RefreshRate returns the refresh frequency of a monitor in Hz (refreshes/second). // RefreshRate returns the refresh frequency of a monitor in Hz (refreshes/second).
func (m *Monitor) RefreshRate() (rate float64) { func (m *Monitor) RefreshRate() (rate float64) {
mode := pixelgl.DoVal(func() interface{} { mode := mainthread.CallVal(func() interface{} {
return m.monitor.GetVideoMode() return m.monitor.GetVideoMode()
}).(*glfw.VidMode) }).(*glfw.VidMode)
rate = float64(mode.RefreshRate) rate = float64(mode.RefreshRate)

View File

@ -4,6 +4,7 @@ import (
"image" "image"
"image/draw" "image/draw"
"github.com/faiface/mainthread"
"github.com/faiface/pixel/pixelgl" "github.com/faiface/pixel/pixelgl"
) )
@ -29,7 +30,7 @@ func NewPicture(img image.Image, smooth bool) *Picture {
} }
var texture *pixelgl.Texture var texture *pixelgl.Texture
pixelgl.Do(func() { mainthread.Call(func() {
texture = pixelgl.NewTexture( texture = pixelgl.NewTexture(
img.Bounds().Dx(), img.Bounds().Dx(),
img.Bounds().Dy(), img.Bounds().Dy(),

67
pixelgl/frame.go Normal file
View File

@ -0,0 +1,67 @@
package pixelgl
import (
"fmt"
"runtime"
"github.com/faiface/mainthread"
"github.com/go-gl/gl/v3.3-core/gl"
)
type Frame struct {
fb binder
tex *Texture
width, height int
}
func NewFrame(width, height int, smooth bool) *Frame {
f := &Frame{
fb: binder{
restoreLoc: gl.FRAMEBUFFER_BINDING,
bindFunc: func(obj uint32) {
gl.BindFramebuffer(gl.FRAMEBUFFER, obj)
},
},
width: width,
height: height,
}
gl.GenFramebuffers(1, &f.fb.obj)
fmt.Println(f.fb.obj)
f.tex = NewTexture(width, height, smooth, make([]uint8, width*height*4))
f.fb.bind()
gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, f.tex.tex.obj, 0)
f.fb.restore()
runtime.SetFinalizer(f, (*Frame).delete)
return f
}
func (f *Frame) delete() {
mainthread.CallNonBlock(func() {
gl.DeleteFramebuffers(1, &f.fb.obj)
})
}
func (f *Frame) Width() int {
return f.width
}
func (f *Frame) Height() int {
return f.height
}
func (f *Frame) Begin() {
f.fb.bind()
}
func (f *Frame) End() {
f.fb.restore()
}
func (f *Frame) Texture() *Texture {
return f.tex
}

View File

@ -2,6 +2,20 @@ package pixelgl
import "github.com/go-gl/gl/v3.3-core/gl" import "github.com/go-gl/gl/v3.3-core/gl"
// Init initializes OpenGL by loading the function pointers from the active OpenGL context.
// This function must be manually run inside the main thread (Do, DoErr, DoVal, etc.).
//
// It must be called under the presence of an active OpenGL context, e.g., always after calling
// window.MakeContextCurrent(). Also, always call this function when switching contexts.
func Init() {
err := gl.Init()
if err != nil {
panic(err)
}
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
}
// Clear clears the current framebuffer or window with the given color. // Clear clears the current framebuffer or window with the given color.
func Clear(r, g, b, a float32) { func Clear(r, g, b, a float32) {
gl.ClearColor(r, g, b, a) gl.ClearColor(r, g, b, a)

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"github.com/faiface/mainthread"
"github.com/go-gl/gl/v3.3-core/gl" "github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/mathgl/mgl32" "github.com/go-gl/mathgl/mgl32"
) )
@ -110,7 +111,7 @@ func NewShader(vertexFmt, uniformFmt AttrFormat, vertexShader, fragmentShader st
} }
func (s *Shader) delete() { func (s *Shader) delete() {
DoNoBlock(func() { mainthread.CallNonBlock(func() {
gl.DeleteProgram(s.program.obj) gl.DeleteProgram(s.program.obj)
}) })
} }

View File

@ -3,6 +3,7 @@ package pixelgl
import ( import (
"runtime" "runtime"
"github.com/faiface/mainthread"
"github.com/go-gl/gl/v3.3-core/gl" "github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/mathgl/mgl32" "github.com/go-gl/mathgl/mgl32"
) )
@ -67,7 +68,7 @@ func NewTexture(width, height int, smooth bool, pixels []uint8) *Texture {
} }
func (t *Texture) delete() { func (t *Texture) delete() {
DoNoBlock(func() { mainthread.CallNonBlock(func() {
gl.DeleteTextures(1, &t.tex.obj) gl.DeleteTextures(1, &t.tex.obj)
}) })
} }

View File

@ -1,102 +0,0 @@
package pixelgl
import (
"runtime"
"github.com/go-gl/gl/v3.3-core/gl"
)
// Due to the limitations of OpenGL and operating systems, all OpenGL related calls must be
// done from the main thread.
var (
callQueue = make(chan func(), 8)
respChan = make(chan interface{}, 4)
)
func init() {
runtime.LockOSThread()
}
// Run is essentialy the "main" function of the pixelgl package. Run this function from the
// main function (because that's guaranteed to run in the main thread).
//
// This function reserves the main thread for the OpenGL stuff and runs a supplied run function
// in a separate goroutine.
//
// Run returns when the provided run function finishes.
func Run(run func()) {
done := make(chan struct{})
go func() {
run()
close(done)
}()
loop:
for {
select {
case f := <-callQueue:
f()
case <-done:
break loop
}
}
}
// Init initializes OpenGL by loading the function pointers from the active OpenGL context.
// This function must be manually run inside the main thread (Do, DoErr, DoVal, etc.).
//
// It must be called under the presence of an active OpenGL context, e.g., always after calling
// window.MakeContextCurrent(). Also, always call this function when switching contexts.
func Init() {
err := gl.Init()
if err != nil {
panic(err)
}
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
}
// DoNoBlock executes a function inside the main OpenGL thread. DoNoBlock does not wait until
// the function finishes.
func DoNoBlock(f func()) {
callQueue <- f
}
// Do executes a function inside the main OpenGL thread. Do blocks until the function finishes.
//
// All OpenGL calls must be done in the dedicated thread.
func Do(f func()) {
callQueue <- func() {
f()
respChan <- struct{}{}
}
<-respChan
}
// DoErr executes a function inside the main OpenGL thread and returns an error to the called.
// DoErr blocks until the function finishes.
//
// All OpenGL calls must be done in the dedicated thread.
func DoErr(f func() error) error {
callQueue <- func() {
respChan <- f()
}
err := <-respChan
if err != nil {
return err.(error)
}
return nil
}
// DoVal executes a function inside the main OpenGL thread and returns a value to the caller.
// DoVal blocks until the function finishes.
//
// All OpenGL calls must be done in the main thread.
func DoVal(f func() interface{}) interface{} {
callQueue <- func() {
respChan <- f()
}
return <-respChan
}

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"runtime" "runtime"
"github.com/faiface/mainthread"
"github.com/go-gl/gl/v3.3-core/gl" "github.com/go-gl/gl/v3.3-core/gl"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -252,7 +253,7 @@ func newVertexArray(shader *Shader, cap int) *vertexArray {
} }
func (va *vertexArray) delete() { func (va *vertexArray) delete() {
DoNoBlock(func() { mainthread.CallNonBlock(func() {
gl.DeleteVertexArrays(1, &va.vao.obj) gl.DeleteVertexArrays(1, &va.vao.obj)
gl.DeleteBuffers(1, &va.vbo.obj) gl.DeleteBuffers(1, &va.vbo.obj)
}) })

4
run.go
View File

@ -1,7 +1,7 @@
package pixel package pixel
import ( import (
"github.com/faiface/pixel/pixelgl" "github.com/faiface/mainthread"
"github.com/go-gl/glfw/v3.2/glfw" "github.com/go-gl/glfw/v3.2/glfw"
) )
@ -28,5 +28,5 @@ import (
// function. // function.
func Run(run func()) { func Run(run func()) {
defer glfw.Terminate() defer glfw.Terminate()
pixelgl.Run(run) mainthread.Run(run)
} }

View File

@ -5,6 +5,7 @@ import (
"runtime" "runtime"
"github.com/faiface/mainthread"
"github.com/faiface/pixel/pixelgl" "github.com/faiface/pixel/pixelgl"
"github.com/go-gl/glfw/v3.2/glfw" "github.com/go-gl/glfw/v3.2/glfw"
"github.com/go-gl/mathgl/mgl32" "github.com/go-gl/mathgl/mgl32"
@ -79,6 +80,9 @@ type Window struct {
buttons [KeyLast + 1]bool buttons [KeyLast + 1]bool
scroll Vec scroll Vec
} }
//DEBUG
Frame *pixelgl.Frame
} }
var currentWindow *Window var currentWindow *Window
@ -94,7 +98,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
w := &Window{config: config} w := &Window{config: config}
err := pixelgl.DoErr(func() error { err := mainthread.CallErr(func() error {
err := glfw.Init() err := glfw.Init()
if err != nil { if err != nil {
return err return err
@ -127,7 +131,7 @@ func NewWindow(config WindowConfig) (*Window, error) {
return nil, errors.Wrap(err, "creating window failed") return nil, errors.Wrap(err, "creating window failed")
} }
pixelgl.Do(func() { mainthread.Call(func() {
w.begin() w.begin()
w.end() w.end()
@ -160,25 +164,24 @@ func NewWindow(config WindowConfig) (*Window, error) {
// Destroy destroys a window. The window can't be used any further. // Destroy destroys a window. The window can't be used any further.
func (w *Window) Destroy() { func (w *Window) Destroy() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Destroy() w.window.Destroy()
}) })
} }
// Clear clears the window with a color. // Clear clears the window with a color.
func (w *Window) Clear(c color.Color) { func (w *Window) Clear(c color.Color) {
pixelgl.DoNoBlock(func() { mainthread.CallNonBlock(func() {
w.begin() w.begin()
defer w.end()
c := NRGBAModel.Convert(c).(NRGBA) c := NRGBAModel.Convert(c).(NRGBA)
pixelgl.Clear(float32(c.R), float32(c.G), float32(c.B), float32(c.A)) pixelgl.Clear(float32(c.R), float32(c.G), float32(c.B), float32(c.A))
w.end()
}) })
} }
// Update swaps buffers and polls events. // Update swaps buffers and polls events.
func (w *Window) Update() { func (w *Window) Update() {
pixelgl.Do(func() { mainthread.Call(func() {
w.begin() w.begin()
if w.config.VSync { if w.config.VSync {
glfw.SwapInterval(1) glfw.SwapInterval(1)
@ -197,7 +200,7 @@ func (w *Window) Update() {
// This is usefull when overriding the user's attempt to close a window, or just to close a // This is usefull when overriding the user's attempt to close a window, or just to close a
// window from within a program. // window from within a program.
func (w *Window) SetClosed(closed bool) { func (w *Window) SetClosed(closed bool) {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.SetShouldClose(closed) w.window.SetShouldClose(closed)
}) })
} }
@ -206,14 +209,14 @@ func (w *Window) SetClosed(closed bool) {
// //
// The closed flag is automatically set when a user attempts to close a window. // The closed flag is automatically set when a user attempts to close a window.
func (w *Window) Closed() bool { func (w *Window) Closed() bool {
return pixelgl.DoVal(func() interface{} { return mainthread.CallVal(func() interface{} {
return w.window.ShouldClose() return w.window.ShouldClose()
}).(bool) }).(bool)
} }
// SetTitle changes the title of a window. // SetTitle changes the title of a window.
func (w *Window) SetTitle(title string) { func (w *Window) SetTitle(title string) {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.SetTitle(title) w.window.SetTitle(title)
}) })
} }
@ -221,14 +224,14 @@ func (w *Window) SetTitle(title string) {
// SetSize resizes a window to the specified size in pixels. In case of a fullscreen window, // SetSize resizes a window to the specified size in pixels. In case of a fullscreen window,
// it changes the resolution of that window. // it changes the resolution of that window.
func (w *Window) SetSize(width, height float64) { func (w *Window) SetSize(width, height float64) {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.SetSize(int(width), int(height)) w.window.SetSize(int(width), int(height))
}) })
} }
// Size returns the size of the client area of a window (the part you can draw on). // Size returns the size of the client area of a window (the part you can draw on).
func (w *Window) Size() (width, height float64) { func (w *Window) Size() (width, height float64) {
pixelgl.Do(func() { mainthread.Call(func() {
wi, hi := w.window.GetSize() wi, hi := w.window.GetSize()
width = float64(wi) width = float64(wi)
height = float64(hi) height = float64(hi)
@ -238,14 +241,14 @@ func (w *Window) Size() (width, height float64) {
// Show makes a window visible if it was hidden. // Show makes a window visible if it was hidden.
func (w *Window) Show() { func (w *Window) Show() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Show() w.window.Show()
}) })
} }
// Hide hides a window if it was visible. // Hide hides a window if it was visible.
func (w *Window) Hide() { func (w *Window) Hide() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Hide() w.window.Hide()
}) })
} }
@ -259,7 +262,7 @@ func (w *Window) Hide() {
func (w *Window) SetFullscreen(monitor *Monitor) { func (w *Window) SetFullscreen(monitor *Monitor) {
if w.Monitor() != monitor { if w.Monitor() != monitor {
if monitor == nil { if monitor == nil {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.SetMonitor( w.window.SetMonitor(
nil, nil,
w.restore.xpos, w.restore.xpos,
@ -270,7 +273,7 @@ func (w *Window) SetFullscreen(monitor *Monitor) {
) )
}) })
} else { } else {
pixelgl.Do(func() { mainthread.Call(func() {
w.restore.xpos, w.restore.ypos = w.window.GetPos() w.restore.xpos, w.restore.ypos = w.window.GetPos()
w.restore.width, w.restore.height = w.window.GetSize() w.restore.width, w.restore.height = w.window.GetSize()
@ -297,7 +300,7 @@ func (w *Window) IsFullscreen() bool {
// Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this // Monitor returns a monitor a fullscreen window is on. If the window is not fullscreen, this
// function returns nil. // function returns nil.
func (w *Window) Monitor() *Monitor { func (w *Window) Monitor() *Monitor {
monitor := pixelgl.DoVal(func() interface{} { monitor := mainthread.CallVal(func() interface{} {
return w.window.GetMonitor() return w.window.GetMonitor()
}).(*glfw.Monitor) }).(*glfw.Monitor)
if monitor == nil { if monitor == nil {
@ -310,28 +313,28 @@ func (w *Window) Monitor() *Monitor {
// Focus brings a window to the front and sets input focus. // Focus brings a window to the front and sets input focus.
func (w *Window) Focus() { func (w *Window) Focus() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Focus() w.window.Focus()
}) })
} }
// Focused returns true if a window has input focus. // Focused returns true if a window has input focus.
func (w *Window) Focused() bool { func (w *Window) Focused() bool {
return pixelgl.DoVal(func() interface{} { return mainthread.CallVal(func() interface{} {
return w.window.GetAttrib(glfw.Focused) == glfw.True return w.window.GetAttrib(glfw.Focused) == glfw.True
}).(bool) }).(bool)
} }
// Maximize puts a windowed window to a maximized state. // Maximize puts a windowed window to a maximized state.
func (w *Window) Maximize() { func (w *Window) Maximize() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Maximize() w.window.Maximize()
}) })
} }
// Restore restores a windowed window from a maximized state. // Restore restores a windowed window from a maximized state.
func (w *Window) Restore() { func (w *Window) Restore() {
pixelgl.Do(func() { mainthread.Call(func() {
w.window.Restore() w.window.Restore()
}) })
} }
@ -346,11 +349,19 @@ func (w *Window) begin() {
if w.shader != nil { if w.shader != nil {
w.shader.Begin() w.shader.Begin()
} }
pixelgl.Viewport(0, 0, int32(w.width), int32(w.height)) if w.Frame != nil {
w.Frame.Begin()
pixelgl.Viewport(0, 0, int32(w.Frame.Width()), int32(w.Frame.Height()))
} else {
pixelgl.Viewport(0, 0, int32(w.width), int32(w.height))
}
} }
// Note: must be called inside the main thread. // Note: must be called inside the main thread.
func (w *Window) end() { func (w *Window) end() {
if w.Frame != nil {
w.Frame.End()
}
if w.shader != nil { if w.shader != nil {
w.shader.End() w.shader.End()
} }
@ -373,7 +384,7 @@ func (wt *windowTriangles) Draw() {
col := wt.w.col col := wt.w.col
bnd := wt.w.bnd bnd := wt.w.bnd
pixelgl.DoNoBlock(func() { mainthread.CallNonBlock(func() {
wt.w.begin() wt.w.begin()
wt.w.shader.SetUniformAttr(transformMat3, mat) wt.w.shader.SetUniformAttr(transformMat3, mat)
@ -438,7 +449,7 @@ func (wt *windowTriangles) updateData(offset int, t Triangles) {
func (wt *windowTriangles) submitData() { func (wt *windowTriangles) submitData() {
data := wt.data // avoid race condition data := wt.data // avoid race condition
pixelgl.DoNoBlock(func() { mainthread.CallNonBlock(func() {
wt.vs.Begin() wt.vs.Begin()
dataLen := len(data) / wt.vs.Stride() dataLen := len(data) / wt.vs.Stride()
if dataLen > wt.vs.Len() { if dataLen > wt.vs.Len() {
@ -603,12 +614,11 @@ void main() {
vec2 boundsMin = bounds.xy; vec2 boundsMin = bounds.xy;
vec2 boundsMax = bounds.zw; vec2 boundsMax = bounds.zw;
float tx = boundsMin.x * (1 - Texture.x) + boundsMax.x * Texture.x;
float ty = boundsMin.y * (1 - Texture.y) + boundsMax.y * Texture.y;
if (Texture == vec2(-1, -1)) { if (Texture == vec2(-1, -1)) {
color = maskColor * Color; color = maskColor * Color;
} else { } else {
float tx = boundsMin.x * (1 - Texture.x) + boundsMax.x * Texture.x;
float ty = boundsMin.y * (1 - Texture.y) + boundsMax.y * Texture.y;
color = maskColor * Color * texture(tex, vec2(tx, 1 - ty)); color = maskColor * Color * texture(tex, vec2(tx, 1 - ty));
} }
} }