Newer
Older
"github.com/faiface/mainthread"
"github.com/faiface/pixel"
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/pkg/errors"
)
// WindowConfig is a structure for specifying all possible properties of a Window. Properties are
// chosen in such a way, that you usually only need to set a few of them - defaults (zeros) should
// usually be sensible.
// Note that you always need to set the Bounds of a Window.
// Bounds specify the bounds of the Window in pixels.
Bounds pixel.Rect
// If set to nil, a Window will be windowed. Otherwise it will be fullscreen on the
// specified Monitor.
// Undecorated Window ommits the borders and decorations (close button, etc.).
// If set to true, a Window will not get focused upon showing up.
// VSync (vertical synchronization) synchronizes Window's framerate with the framerate of
// Window is a window handler. Use this type to manipulate a window (input, drawing, etc.).
bounds pixel.Rect
canvas *Canvas
vsync bool
// need to save these to correctly restore a fullscreen window
restore struct {
xpos, ypos, width, height int
}
prevInp, tempInp, currInp struct {
// NewWindow creates a new Window with it's properties specified in the provided config.
// If Window creation fails, an error is returned (e.g. due to unavailable graphics device).
func NewWindow(cfg WindowConfig) (*Window, error) {
bool2int := map[bool]int{
true: glfw.True,
false: glfw.False,
}
err := mainthread.CallErr(func() error {
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 3)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
glfw.WindowHint(glfw.Resizable, bool2int[cfg.Resizable])
glfw.WindowHint(glfw.Visible, bool2int[!cfg.Hidden])
glfw.WindowHint(glfw.Decorated, bool2int[!cfg.Undecorated])
glfw.WindowHint(glfw.Focused, bool2int[!cfg.Unfocused])
glfw.WindowHint(glfw.Maximized, bool2int[cfg.Maximized])
w.window, err = glfw.CreateWindow(
// enter the OpenGL context
if err != nil {
return nil, errors.Wrap(err, "creating window failed")
}
runtime.SetFinalizer(w, (*Window).Destroy)
// Destroy destroys the Window. The Window can't be used any further.
mainthread.Call(func() {
// Update swaps buffers and polls events. Call this method at the end of each frame.
_, _, oldW, oldH := intBounds(w.bounds)
newW, newH := w.window.GetSize()
w.bounds = w.bounds.ResizedMin(w.bounds.Size() + pixel.V(
float64(newW-oldW),
float64(newH-oldH),
))
mainthread.Call(func() {
glhf.Bounds(0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height())
w.canvas.f.Begin()
w.canvas.f.Blit(
nil,
0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height(),
0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height(),
)
w.canvas.f.End()
if w.vsync {
// This is usefull when overriding the user's attempt to close the Window, or just to close the
// Window from within the program.
func (w *Window) SetClosed(closed bool) {
mainthread.Call(func() {
w.window.SetShouldClose(closed)
})
}
// Closed returns the closed flag of the Window, which reports whether the Window should be closed.
// The closed flag is automatically set when a user attempts to close the Window.
var closed bool
mainthread.Call(func() {
closed = w.window.ShouldClose()
})
return closed
mainthread.Call(func() {
// SetBounds sets the bounds of the Window in pixels. Bounds can be fractional, but the actual size
// of the window will be rounded to integers.
func (w *Window) SetBounds(bounds pixel.Rect) {
w.bounds = bounds
mainthread.Call(func() {
// Bounds returns the current bounds of the Window.
func (w *Window) Bounds() pixel.Rect {
return w.bounds
mainthread.Call(func() {
mainthread.Call(func() {
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
func (w *Window) setFullscreen(monitor *Monitor) {
mainthread.Call(func() {
w.restore.xpos, w.restore.ypos = w.window.GetPos()
w.restore.width, w.restore.height = w.window.GetSize()
mode := monitor.monitor.GetVideoMode()
w.window.SetMonitor(
monitor.monitor,
0,
0,
mode.Width,
mode.Height,
mode.RefreshRate,
)
})
}
func (w *Window) setWindowed() {
mainthread.Call(func() {
w.window.SetMonitor(
nil,
w.restore.xpos,
w.restore.ypos,
w.restore.width,
w.restore.height,
0,
)
})
}
// SetMonitor sets the Window fullscreen on the given Monitor. If the Monitor is nil, the Window
// The Window will be automatically set to the Monitor's resolution. If you want a different
// resolution, you will need to set it manually with SetBounds method.
func (w *Window) SetMonitor(monitor *Monitor) {
if monitor != nil {
w.setFullscreen(monitor)
// IsFullscreen returns true if the Window is in fullscreen mode.
func (w *Window) IsFullscreen() bool {
return w.Monitor() != nil
}
// Monitor returns a monitor the Window is fullscreen on. If the Window is not fullscreen, this
var monitor *glfw.Monitor
mainthread.Call(func() {
monitor = w.window.GetMonitor()
})
if monitor == nil {
return nil
}
return &Monitor{
monitor: monitor,
}
// Focus brings the Window to the front and sets input focus.
func (w *Window) Focus() {
mainthread.Call(func() {
var focused bool
mainthread.Call(func() {
focused = w.window.GetAttrib(glfw.Focused) == glfw.True
})
return focused
// Maximize puts the Window to the maximized state.
mainthread.Call(func() {
// Restore restores the Window from the maximized state.
mainthread.Call(func() {
// SetVSync sets whether the Window's Update should synchronize with the monitor refresh rate.
func (w *Window) SetVSync(vsync bool) {
w.vsync = vsync
}
// VSync returns whether the Window is set to synchronize with the monitor refresh rate.
func (w *Window) VSync() bool {
return w.vsync
}
// Note: must be called inside the main thread.
func (w *Window) begin() {
// Note: must be called inside the main thread.
func (w *Window) end() {
// MakeTriangles generates a specialized copy of the supplied Triangles that will draw onto this
// Window.
//
// Window supports TrianglesPosition, TrianglesColor and TrianglesPicture.
func (w *Window) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
return w.canvas.MakeTriangles(t)
// MakePicture generates a specialized copy of the supplied Picture that will draw onto this Window.
//
// Window support PictureColor.
func (w *Window) MakePicture(p pixel.Picture) pixel.TargetPicture {
return w.canvas.MakePicture(p)
// SetMatrix sets a Matrix that every point will be projected by.
func (w *Window) SetMatrix(m pixel.Matrix) {
w.canvas.SetMatrix(m)
// SetColorMask sets a global color mask for the Window.
func (w *Window) SetColorMask(c color.Color) {
w.canvas.SetColorMask(c)
// SetSmooth sets whether the stretched Pictures drawn onto this Window should be drawn smooth or
// pixely.
func (w *Window) SetSmooth(smooth bool) {
w.canvas.SetSmooth(smooth)
// Smooth returns whether the stretched Pictures drawn onto this Window are set to be drawn smooth
// or pixely.
func (w *Window) Smooth() bool {
return w.canvas.Smooth()
func (w *Window) Clear(c color.Color) {
w.canvas.Clear(c)