From eac0b4b31a1ae323222076dcb31dc7cd4d9402d5 Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Sat, 24 Aug 2024 14:49:13 -0400 Subject: move win to gui package --- win/events.go | 89 --------------- win/win.go | 358 ---------------------------------------------------------- 2 files changed, 447 deletions(-) delete mode 100644 win/events.go delete mode 100644 win/win.go (limited to 'win') diff --git a/win/events.go b/win/events.go deleted file mode 100644 index 90fab52..0000000 --- a/win/events.go +++ /dev/null @@ -1,89 +0,0 @@ -package win - -import ( - "fmt" - "image" -) - -// Button indicates a mouse button in an event. -type Button string - -// List of all mouse buttons. -const ( - ButtonLeft Button = "left" - ButtonRight Button = "right" - ButtonMiddle Button = "middle" -) - -// Key indicates a keyboard key in an event. -type Key string - -// List of all keyboard keys. -const ( - KeyLeft Key = "left" - KeyRight Key = "right" - KeyUp Key = "up" - KeyDown Key = "down" - KeyEscape Key = "escape" - KeySpace Key = "space" - KeyBackspace Key = "backspace" - KeyDelete Key = "delete" - KeyEnter Key = "enter" - KeyTab Key = "tab" - KeyHome Key = "home" - KeyEnd Key = "end" - KeyPageUp Key = "pageup" - KeyPageDown Key = "pagedown" - KeyShift Key = "shift" - KeyCtrl Key = "ctrl" - KeyAlt Key = "alt" -) - -type ( - // WiClose is an event that happens when the user presses the close button on the window. - WiClose struct{} - - // MoMove is an event that happens when the mouse gets moved across the window. - MoMove struct{ image.Point } - - // MoDown is an event that happens when a mouse button gets pressed. - MoDown struct { - image.Point - Button Button - } - - // MoUp is an event that happens when a mouse button gets released. - MoUp struct { - image.Point - Button Button - } - - // MoScroll is an event that happens on scrolling the mouse. - // - // The Point field tells the amount scrolled in each direction. - MoScroll struct{ image.Point } - - // KbType is an event that happens when a Unicode character gets typed on the keyboard. - KbType struct{ Rune rune } - - // KbDown is an event that happens when a key on the keyboard gets pressed. - KbDown struct{ Key Key } - - // KbUp is an event that happens when a key on the keyboard gets released. - KbUp struct{ Key Key } - - // KbRepeat is an event that happens when a key on the keyboard gets repeated. - // - // This happens when its held down for some time. - KbRepeat struct{ Key Key } -) - -func (wc WiClose) String() string { return "wi/close" } -func (mm MoMove) String() string { return fmt.Sprintf("mo/move/%d/%d", mm.X, mm.Y) } -func (md MoDown) String() string { return fmt.Sprintf("mo/down/%d/%d/%s", md.X, md.Y, md.Button) } -func (mu MoUp) String() string { return fmt.Sprintf("mo/up/%d/%d/%s", mu.X, mu.Y, mu.Button) } -func (ms MoScroll) String() string { return fmt.Sprintf("mo/scroll/%d/%d", ms.X, ms.Y) } -func (kt KbType) String() string { return fmt.Sprintf("kb/type/%d", kt.Rune) } -func (kd KbDown) String() string { return fmt.Sprintf("kb/down/%s", kd.Key) } -func (ku KbUp) String() string { return fmt.Sprintf("kb/up/%s", ku.Key) } -func (kr KbRepeat) String() string { return fmt.Sprintf("kb/repeat/%s", kr.Key) } diff --git a/win/win.go b/win/win.go deleted file mode 100644 index 1741549..0000000 --- a/win/win.go +++ /dev/null @@ -1,358 +0,0 @@ -package win - -import ( - "image" - "image/draw" - "runtime" - "time" - "unsafe" - - "github.com/faiface/gui" - "github.com/faiface/mainthread" - "github.com/go-gl/gl/v2.1/gl" - "github.com/go-gl/glfw/v3.2/glfw" -) - -// Option is a functional option to the window constructor New. -type Option func(*options) - -type options struct { - title string - width, height int - resizable bool - borderless bool - maximized bool -} - -// Title option sets the title (caption) of the window. -func Title(title string) Option { - return func(o *options) { - o.title = title - } -} - -// Size option sets the width and height of the window. -func Size(width, height int) Option { - return func(o *options) { - o.width = width - o.height = height - } -} - -// Resizable option makes the window resizable by the user. -func Resizable() Option { - return func(o *options) { - o.resizable = true - } -} - -// Borderless option makes the window borderless. -func Borderless() Option { - return func(o *options) { - o.borderless = true - } -} - -// Maximized option makes the window start maximized. -func Maximized() Option { - return func(o *options) { - o.maximized = true - } -} - -// New creates a new window with all the supplied options. -// -// The default title is empty and the default size is 640x480. -func New(opts ...Option) (*Win, error) { - o := options{ - title: "", - width: 640, - height: 480, - resizable: false, - borderless: false, - maximized: false, - } - for _, opt := range opts { - opt(&o) - } - - eventsOut, eventsIn := gui.MakeEventsChan() - - w := &Win{ - eventsOut: eventsOut, - eventsIn: eventsIn, - draw: make(chan func(draw.Image) image.Rectangle), - newSize: make(chan image.Rectangle), - finish: make(chan struct{}), - } - - var err error - mainthread.Call(func() { - w.w, err = makeGLFWWin(&o) - }) - if err != nil { - return nil, err - } - - mainthread.Call(func() { - // hiDPI hack - width, _ := w.w.GetFramebufferSize() - w.ratio = width / o.width - if w.ratio < 1 { - w.ratio = 1 - } - if w.ratio != 1 { - o.width /= w.ratio - o.height /= w.ratio - } - w.w.Destroy() - w.w, err = makeGLFWWin(&o) - }) - if err != nil { - return nil, err - } - - bounds := image.Rect(0, 0, o.width*w.ratio, o.height*w.ratio) - w.img = image.NewRGBA(bounds) - - go func() { - runtime.LockOSThread() - w.openGLThread() - }() - - mainthread.CallNonBlock(w.eventThread) - - return w, nil -} - -func makeGLFWWin(o *options) (*glfw.Window, error) { - err := glfw.Init() - if err != nil { - return nil, err - } - glfw.WindowHint(glfw.DoubleBuffer, glfw.False) - if o.resizable { - glfw.WindowHint(glfw.Resizable, glfw.True) - } else { - glfw.WindowHint(glfw.Resizable, glfw.False) - } - if o.borderless { - glfw.WindowHint(glfw.Decorated, glfw.False) - } - if o.maximized { - glfw.WindowHint(glfw.Maximized, glfw.True) - } - w, err := glfw.CreateWindow(o.width, o.height, o.title, nil, nil) - if err != nil { - return nil, err - } - if o.maximized { - o.width, o.height = w.GetFramebufferSize() // set o.width and o.height to the window size due to the window being maximized - } - return w, nil -} - -// Win is an Env that handles an actual graphical window. -// -// It receives its events from the OS and it draws to the surface of the window. -// -// Warning: only one window can be open at a time. This will be fixed. -type Win struct { - eventsOut <-chan gui.Event - eventsIn chan<- gui.Event - draw chan func(draw.Image) image.Rectangle - - newSize chan image.Rectangle - finish chan struct{} - - w *glfw.Window - img *image.RGBA - ratio int -} - -// Events returns the events channel of the window. -func (w *Win) Events() <-chan gui.Event { return w.eventsOut } - -// Draw returns the draw channel of the window. -func (w *Win) Draw() chan<- func(draw.Image) image.Rectangle { return w.draw } - -var buttons = map[glfw.MouseButton]Button{ - glfw.MouseButtonLeft: ButtonLeft, - glfw.MouseButtonRight: ButtonRight, - glfw.MouseButtonMiddle: ButtonMiddle, -} - -var keys = map[glfw.Key]Key{ - glfw.KeyLeft: KeyLeft, - glfw.KeyRight: KeyRight, - glfw.KeyUp: KeyUp, - glfw.KeyDown: KeyDown, - glfw.KeyEscape: KeyEscape, - glfw.KeySpace: KeySpace, - glfw.KeyBackspace: KeyBackspace, - glfw.KeyDelete: KeyDelete, - glfw.KeyEnter: KeyEnter, - glfw.KeyTab: KeyTab, - glfw.KeyHome: KeyHome, - glfw.KeyEnd: KeyEnd, - glfw.KeyPageUp: KeyPageUp, - glfw.KeyPageDown: KeyPageDown, - glfw.KeyLeftShift: KeyShift, - glfw.KeyRightShift: KeyShift, - glfw.KeyLeftControl: KeyCtrl, - glfw.KeyRightControl: KeyCtrl, - glfw.KeyLeftAlt: KeyAlt, - glfw.KeyRightAlt: KeyAlt, -} - -func (w *Win) eventThread() { - var moX, moY int - - w.w.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { - moX, moY = int(x), int(y) - w.eventsIn <- MoMove{image.Pt(moX*w.ratio, moY*w.ratio)} - }) - - w.w.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) { - b, ok := buttons[button] - if !ok { - return - } - switch action { - case glfw.Press: - w.eventsIn <- MoDown{image.Pt(moX*w.ratio, moY*w.ratio), b} - case glfw.Release: - w.eventsIn <- MoUp{image.Pt(moX*w.ratio, moY*w.ratio), b} - } - }) - - w.w.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) { - w.eventsIn <- MoScroll{image.Pt(int(xoff), int(yoff))} - }) - - w.w.SetCharCallback(func(_ *glfw.Window, r rune) { - w.eventsIn <- KbType{r} - }) - - w.w.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, _ int, action glfw.Action, _ glfw.ModifierKey) { - k, ok := keys[key] - if !ok { - return - } - switch action { - case glfw.Press: - w.eventsIn <- KbDown{k} - case glfw.Release: - w.eventsIn <- KbUp{k} - case glfw.Repeat: - w.eventsIn <- KbRepeat{k} - } - }) - - w.w.SetFramebufferSizeCallback(func(_ *glfw.Window, width, height int) { - r := image.Rect(0, 0, width, height) - w.newSize <- r - w.eventsIn <- gui.Resize{Rectangle: r} - }) - - w.w.SetCloseCallback(func(_ *glfw.Window) { - w.eventsIn <- WiClose{} - }) - - r := w.img.Bounds() - w.eventsIn <- gui.Resize{Rectangle: r} - - for { - select { - case <-w.finish: - close(w.eventsIn) - w.w.Destroy() - return - default: - glfw.WaitEventsTimeout(1.0 / 30) - } - } -} - -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 - totalR = totalR.Union(r) - - case d, ok := <-w.draw: - if !ok { - close(w.finish) - return - } - r := d(w.img) - 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) - } - } - } -} - -func (w *Win) openGLFlush(r image.Rectangle) { - bounds := w.img.Bounds() - r = r.Intersect(bounds) - if r.Empty() { - return - } - - tmp := image.NewRGBA(r) - draw.Draw(tmp, r, w.img, r.Min, draw.Src) - - gl.DrawBuffer(gl.FRONT) - gl.Viewport( - int32(bounds.Min.X), - int32(bounds.Min.Y), - int32(bounds.Dx()), - int32(bounds.Dy()), - ) - gl.RasterPos2d( - -1+2*float64(r.Min.X)/float64(bounds.Dx()), - +1-2*float64(r.Min.Y)/float64(bounds.Dy()), - ) - gl.PixelZoom(1, -1) - gl.DrawPixels( - int32(r.Dx()), - int32(r.Dy()), - gl.RGBA, - gl.UNSIGNED_BYTE, - unsafe.Pointer(&tmp.Pix[0]), - ) - gl.Flush() -} -- cgit v1.2.3