From 7bbe7dc9618949f2fe023efcb896a70150966e44 Mon Sep 17 00:00:00 2001 From: faiface Date: Thu, 2 May 2019 01:01:02 +0200 Subject: revamp the whole thing for a fresh new start --- env.go | 11 +++++++ event.go | 49 ++++++++++++++++++++++++++++++ layout/interface.go | 23 -------------- mux.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ win/win.go | 78 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 200 insertions(+), 47 deletions(-) create mode 100644 env.go create mode 100644 event.go delete mode 100644 layout/interface.go create mode 100644 mux.go diff --git a/env.go b/env.go new file mode 100644 index 0000000..cd71b5b --- /dev/null +++ b/env.go @@ -0,0 +1,11 @@ +package gui + +import ( + "image" + "image/draw" +) + +type Env struct { + Events <-chan Event + Draw chan<- func(draw.Image) image.Rectangle +} diff --git a/event.go b/event.go new file mode 100644 index 0000000..3440926 --- /dev/null +++ b/event.go @@ -0,0 +1,49 @@ +package gui + +import "fmt" + +type Event string + +func Eventf(format string, a ...interface{}) Event { + return Event(fmt.Sprintf(format, a...)) +} + +func (e Event) Matches(format string, a ...interface{}) bool { + _, err := fmt.Sscanf(string(e), format, a...) + return err == nil +} + +func MakeEventsChan() (<-chan Event, chan<- Event) { + out, in := make(chan Event), make(chan Event) + + go func() { + var queue []Event + + for { + x, ok := <-in + if !ok { + close(out) + return + } + queue = append(queue, x) + + for len(queue) > 0 { + select { + case out <- queue[0]: + queue = queue[1:] + case x, ok := <-in: + if !ok { + for _, x := range queue { + out <- x + } + close(out) + return + } + queue = append(queue, x) + } + } + } + }() + + return out, in +} diff --git a/layout/interface.go b/layout/interface.go deleted file mode 100644 index 28b6a01..0000000 --- a/layout/interface.go +++ /dev/null @@ -1,23 +0,0 @@ -package layout - -import ( - "fmt" - "image" - "image/draw" -) - -type EventDrawer interface { - Event() <-chan Event - Draw() chan<- func(draw.Image) image.Rectangle -} - -type Event string - -func Eventf(format string, a ...interface{}) Event { - return Event(fmt.Sprintf(format, a...)) -} - -func (e Event) Matches(format string, a ...interface{}) bool { - _, err := fmt.Sscanf(string(e), format, a...) - return err == nil -} diff --git a/mux.go b/mux.go new file mode 100644 index 0000000..cbe3488 --- /dev/null +++ b/mux.go @@ -0,0 +1,86 @@ +package gui + +import ( + "image" + "image/draw" + "sync" +) + +type Mux struct { + mu sync.Mutex + eventsIns []chan<- Event + draw chan<- func(draw.Image) image.Rectangle +} + +func NewMux(env Env) (mux *Mux, master Env) { + drawChan := make(chan func(draw.Image) image.Rectangle) + mux = &Mux{draw: drawChan} + master = mux.makeEnv(true) + + go func() { + for d := range drawChan { + env.Draw <- d + } + close(env.Draw) + }() + + go func() { + for e := range env.Events { + mux.mu.Lock() + for _, eventsIn := range mux.eventsIns { + eventsIn <- e + } + mux.mu.Unlock() + } + mux.mu.Lock() + for _, eventsIn := range mux.eventsIns { + close(eventsIn) + } + mux.mu.Unlock() + }() + + return mux, master +} + +func (mux *Mux) MakeEnv() Env { + return mux.makeEnv(false) +} + +func (mux *Mux) makeEnv(master bool) Env { + eventsOut, eventsIn := MakeEventsChan() + drawChan := make(chan func(draw.Image) image.Rectangle) + env := Env{eventsOut, drawChan} + + mux.mu.Lock() + mux.eventsIns = append(mux.eventsIns, eventsIn) + mux.mu.Unlock() + + go func() { + for d := range drawChan { + mux.draw <- d + } + if master { + mux.mu.Lock() + for _, eventsIn := range mux.eventsIns { + close(eventsIn) + } + mux.eventsIns = nil + close(mux.draw) + mux.mu.Unlock() + } else { + mux.mu.Lock() + i := -1 + for i = range mux.eventsIns { + if mux.eventsIns[i] == eventsIn { + break + } + } + if i != -1 { + mux.eventsIns = append(mux.eventsIns[:i], mux.eventsIns[i+1:]...) + } + mux.mu.Unlock() + } + }() + + return env +} diff --git a/win/win.go b/win/win.go index 10ce5b0..552f58d 100644 --- a/win/win.go +++ b/win/win.go @@ -4,8 +4,10 @@ import ( "image" "image/draw" "runtime" + "time" + "unsafe" - "github.com/faiface/gui/layout" + "github.com/faiface/gui" "github.com/faiface/mainthread" "github.com/go-gl/gl/v2.1/gl" "github.com/go-gl/glfw/v3.2/glfw" @@ -49,11 +51,14 @@ func New(opts ...Option) (*Win, error) { opt(&o) } + eventsOut, eventsIn := gui.MakeEventsChan() + w := &Win{ - event: make(chan layout.Event), - draw: make(chan func(draw.Image) image.Rectangle), - newSize: make(chan image.Rectangle), - finish: make(chan struct{}), + eventsOut: eventsOut, + eventsIn: eventsIn, + draw: make(chan func(draw.Image) image.Rectangle), + newSize: make(chan image.Rectangle), + finish: make(chan struct{}), } var err error @@ -96,8 +101,9 @@ func makeGLFWWin(o *options) (*glfw.Window, error) { } type Win struct { - event chan layout.Event - draw chan func(draw.Image) image.Rectangle + eventsOut <-chan gui.Event + eventsIn chan<- gui.Event + draw chan func(draw.Image) image.Rectangle newSize chan image.Rectangle finish chan struct{} @@ -106,12 +112,8 @@ type Win struct { img *image.RGBA } -func (w *Win) Event() <-chan layout.Event { - return w.event -} - -func (w *Win) Draw() chan<- func(draw.Image) image.Rectangle { - return w.draw +func (w *Win) Env() gui.Env { + return gui.Env{Events: w.eventsOut, Draw: w.draw} } func (w *Win) eventThread() { @@ -120,38 +122,38 @@ func (w *Win) eventThread() { w.w.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { switch action { case glfw.Press: - w.event <- layout.Eventf("mo/down/%d/%d", moX, moY) + w.eventsIn <- gui.Eventf("mo/down/%d/%d", moX, moY) case glfw.Release: - w.event <- layout.Eventf("mo/up/%d/%d", moX, moY) + w.eventsIn <- gui.Eventf("mo/up/%d/%d", moX, moY) } }) w.w.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { moX, moY = int(x), int(y) - w.event <- layout.Eventf("mo/move/%d/%d", moX, moY) + w.eventsIn <- gui.Eventf("mo/move/%d/%d", moX, moY) }) w.w.SetCharCallback(func(_ *glfw.Window, r rune) { - w.event <- layout.Eventf("kb/type/%d", r) + w.eventsIn <- gui.Eventf("kb/type/%d", r) }) w.w.SetSizeCallback(func(_ *glfw.Window, width, height int) { r := image.Rect(0, 0, width, height) w.newSize <- r - w.event <- layout.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y) + w.eventsIn <- gui.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y) }) w.w.SetCloseCallback(func(_ *glfw.Window) { - w.event <- layout.Eventf("wi/close") + w.eventsIn <- gui.Eventf("wi/close") }) r := w.img.Bounds() - w.event <- layout.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y) + w.eventsIn <- gui.Eventf("resize/%d/%d/%d/%d", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y) for { select { case <-w.finish: - close(w.event) + close(w.eventsIn) w.w.Destroy() return default: @@ -164,13 +166,18 @@ func (w *Win) openGLThread() { w.w.MakeContextCurrent() gl.Init() + w.openGLFlush(w.img.Bounds()) + +loop: for { + var totalR image.Rectangle + select { case r := <-w.newSize: img := image.NewRGBA(r) draw.Draw(img, w.img.Bounds(), w.img, w.img.Bounds().Min, draw.Src) w.img = img - w.openGLFlush(r) + totalR = totalR.Union(r) case d, ok := <-w.draw: if !ok { @@ -178,7 +185,30 @@ func (w *Win) openGLThread() { return } r := d(w.img) - w.openGLFlush(r) + totalR = totalR.Union(r) + } + + for { + select { + case <-time.After(time.Second / 960): + w.openGLFlush(totalR) + totalR = image.ZR + continue loop + + case r := <-w.newSize: + img := image.NewRGBA(r) + draw.Draw(img, w.img.Bounds(), w.img, w.img.Bounds().Min, draw.Src) + w.img = img + totalR = totalR.Union(r) + + case d, ok := <-w.draw: + if !ok { + close(w.finish) + return + } + r := d(w.img) + totalR = totalR.Union(r) + } } } } @@ -210,7 +240,7 @@ func (w *Win) openGLFlush(r image.Rectangle) { int32(r.Dy()), gl.RGBA, gl.UNSIGNED_BYTE, - gl.Ptr(tmp.Pix), + unsafe.Pointer(&tmp.Pix[0]), ) gl.Flush() } -- cgit v1.2.3