186 lines
4.5 KiB
Go
186 lines
4.5 KiB
Go
package vulkan
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"unsafe"
|
|
|
|
"zworld/engine/renderapi/command"
|
|
"zworld/engine/renderapi/image"
|
|
"zworld/engine/renderapi/swapchain"
|
|
"zworld/plugins/system/input"
|
|
"zworld/plugins/system/input/keys"
|
|
"zworld/plugins/system/input/mouse"
|
|
|
|
"github.com/go-gl/glfw/v3.3/glfw"
|
|
"github.com/vkngwrapper/core/v2/core1_0"
|
|
"github.com/vkngwrapper/core/v2/driver"
|
|
"github.com/vkngwrapper/extensions/v2/khr_surface"
|
|
khr_surface_driver "github.com/vkngwrapper/extensions/v2/khr_surface/driver"
|
|
)
|
|
|
|
type ResizeHandler func(width, height int)
|
|
|
|
type Window interface {
|
|
Target
|
|
|
|
Title() string
|
|
SetTitle(string)
|
|
|
|
Poll()
|
|
ShouldClose() bool
|
|
Destroy()
|
|
|
|
SetInputHandler(input.Handler)
|
|
|
|
Swapchain() swapchain.T
|
|
}
|
|
|
|
type WindowArgs struct {
|
|
Title string
|
|
Width int
|
|
Height int
|
|
Frames int
|
|
Vsync bool
|
|
Debug bool
|
|
InputHandler input.Handler
|
|
ResizeHandler ResizeHandler
|
|
}
|
|
|
|
type window struct {
|
|
wnd *glfw.Window
|
|
mouse mouse.MouseWrapper
|
|
|
|
title string
|
|
width, height int
|
|
frames int
|
|
scale float32
|
|
swap swapchain.T
|
|
surface khr_surface.Surface
|
|
}
|
|
|
|
func NewWindow(backend App, args WindowArgs) (Window, error) {
|
|
// window creation hints.
|
|
glfw.WindowHint(glfw.ClientAPI, glfw.NoAPI)
|
|
|
|
// create a new GLFW window
|
|
wnd, err := glfw.CreateWindow(args.Width, args.Height, args.Title, nil, nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create glfw window: %w", err)
|
|
}
|
|
|
|
// find the scaling of the current monitor
|
|
// what do we do if the user moves it to a different monitor with different scaling?
|
|
monitor := GetCurrentMonitor(wnd)
|
|
scale, _ := monitor.GetContentScale()
|
|
|
|
// retrieve window & framebuffer size
|
|
width, height := wnd.GetFramebufferSize()
|
|
log.Printf("Created window with size %dx%d and content scale %.0f%%\n",
|
|
width, height, scale*100)
|
|
|
|
// create window surface
|
|
surfPtr, err := wnd.CreateWindowSurface((*driver.VkInstance)(unsafe.Pointer(backend.Instance().Ptr().Handle())), nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
surfaceHandle := (*khr_surface_driver.VkSurfaceKHR)(unsafe.Pointer(surfPtr))
|
|
surfaceExt := khr_surface.CreateExtensionFromInstance(backend.Instance().Ptr())
|
|
surface, err := surfaceExt.CreateSurfaceFromHandle(*surfaceHandle)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
surfaceFormat, _, err := surface.PhysicalDeviceSurfaceFormats(backend.Device().Physical())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
// allocate swapchain
|
|
swap := swapchain.New(backend.Device(), args.Frames, width, height, surface, surfaceFormat[0])
|
|
|
|
window := &window{
|
|
wnd: wnd,
|
|
title: args.Title,
|
|
width: width,
|
|
height: height,
|
|
frames: args.Frames,
|
|
scale: scale,
|
|
swap: swap,
|
|
surface: surface,
|
|
}
|
|
|
|
// attach default input handler, if provided
|
|
if args.InputHandler != nil {
|
|
window.SetInputHandler(args.InputHandler)
|
|
}
|
|
|
|
// set resize callback
|
|
wnd.SetFramebufferSizeCallback(func(w *glfw.Window, width, height int) {
|
|
// update window scaling
|
|
monitor := GetCurrentMonitor(wnd)
|
|
window.scale, _ = monitor.GetContentScale()
|
|
|
|
window.width = width
|
|
window.height = height
|
|
window.swap.Resize(width, height)
|
|
})
|
|
|
|
return window, nil
|
|
}
|
|
|
|
func (w *window) Poll() {
|
|
glfw.PollEvents()
|
|
}
|
|
|
|
func (w *window) Size() TargetSize {
|
|
return TargetSize{
|
|
Width: w.width,
|
|
Height: w.height,
|
|
Frames: w.frames,
|
|
Scale: w.scale,
|
|
}
|
|
}
|
|
|
|
func (w *window) Width() int { return w.width }
|
|
func (w *window) Height() int { return w.height }
|
|
func (w *window) Frames() int { return w.frames }
|
|
func (w *window) Scale() float32 { return w.scale }
|
|
func (w *window) ShouldClose() bool { return w.wnd.ShouldClose() }
|
|
func (w *window) Title() string { return w.title }
|
|
|
|
func (w *window) Surfaces() []image.T { return w.swap.Images() }
|
|
func (w *window) SurfaceFormat() core1_0.Format { return w.swap.SurfaceFormat() }
|
|
func (w *window) Swapchain() swapchain.T { return w.swap }
|
|
|
|
func (w *window) SetInputHandler(handler input.Handler) {
|
|
// keyboard events
|
|
w.wnd.SetKeyCallback(keys.KeyCallbackWrapper(handler))
|
|
w.wnd.SetCharCallback(keys.CharCallbackWrapper(handler))
|
|
|
|
// mouse events
|
|
w.mouse = mouse.NewWrapper(handler)
|
|
w.wnd.SetMouseButtonCallback(w.mouse.Button)
|
|
w.wnd.SetCursorPosCallback(w.mouse.Move)
|
|
w.wnd.SetScrollCallback(w.mouse.Scroll)
|
|
}
|
|
|
|
func (w *window) SetTitle(title string) {
|
|
w.wnd.SetTitle(title)
|
|
w.title = title
|
|
}
|
|
|
|
func (w *window) Aquire() (*swapchain.Context, error) {
|
|
return w.swap.Aquire()
|
|
}
|
|
|
|
func (w *window) Present(worker command.Worker, ctx *swapchain.Context) {
|
|
w.swap.Present(worker, ctx)
|
|
}
|
|
|
|
func (w *window) Destroy() {
|
|
w.swap.Destroy()
|
|
w.surface.Destroy(nil)
|
|
}
|