Created Event_Queue and moved to a more correct windows architecture.
This commit is contained in:
33
window.odin
33
window.odin
@@ -1,13 +1,19 @@
|
||||
package window
|
||||
|
||||
import "core:container/queue"
|
||||
import "core:fmt"
|
||||
|
||||
Window :: struct {
|
||||
title: string,
|
||||
width, height: u16,
|
||||
|
||||
backend: Backend_Info,
|
||||
|
||||
event_queue: Event_Queue,
|
||||
}
|
||||
|
||||
Event_Queue :: queue.Queue(Event)
|
||||
|
||||
Event :: union {
|
||||
Event_Quit,
|
||||
Event_Input,
|
||||
@@ -54,7 +60,6 @@ Event_Input :: union {
|
||||
}
|
||||
|
||||
Event_Resize :: struct {
|
||||
old_width, old_height: u16,
|
||||
new_width, new_height: u16,
|
||||
}
|
||||
|
||||
@@ -64,6 +69,7 @@ create :: proc(width, height: u16) -> (^Window, bool) {
|
||||
w := new(Window)
|
||||
w.width = width
|
||||
w.height = height
|
||||
queue.init(&w.event_queue, 1024)
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
if !init_window_windows(w) {
|
||||
@@ -95,7 +101,7 @@ set_title :: proc(window: ^Window, title: string) {
|
||||
|
||||
get_pointer_to_surface :: proc(window: ^Window) -> rawptr {
|
||||
when ODIN_OS == .Windows {
|
||||
// fmt.printfln("HWND: %v.", window.backend.hwnd)
|
||||
fmt.printfln("HWND: %v.", window.backend.hwnd)
|
||||
return window.backend.hwnd
|
||||
}
|
||||
else {
|
||||
@@ -105,29 +111,38 @@ get_pointer_to_surface :: proc(window: ^Window) -> rawptr {
|
||||
|
||||
update :: proc(window: ^Window, out_event: ^Event) -> bool {
|
||||
assert(window != nil)
|
||||
assert(out_event != nil)
|
||||
|
||||
event: Event
|
||||
when ODIN_OS == .Windows {
|
||||
event = update_windows(window)
|
||||
update_windows(window)
|
||||
}
|
||||
else {
|
||||
#assert(false, "Missing implementation for 'set_title'.")
|
||||
}
|
||||
|
||||
out_event^ = event
|
||||
out_event^ = nil
|
||||
|
||||
if out_event^ == nil {
|
||||
event, ok := queue.pop_front_safe(&window.event_queue)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
assert(event != nil)
|
||||
out_event^ = event
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
destroy :: proc(window: ^Window) {
|
||||
assert(window != nil)
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
destroy_windows(window)
|
||||
|
||||
free(window)
|
||||
window^ = {}
|
||||
}
|
||||
else {
|
||||
#assert(false, "Missing implementation for 'destroy'.")
|
||||
}
|
||||
|
||||
queue.destroy(&window.event_queue)
|
||||
free(window)
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
package window
|
||||
|
||||
import "core:container/queue"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "base:runtime"
|
||||
import win "core:sys/windows"
|
||||
|
||||
Backend_Info :: struct {
|
||||
@@ -8,22 +11,120 @@ Backend_Info :: struct {
|
||||
hwnd: win.HWND,
|
||||
}
|
||||
|
||||
init_window_windows :: proc(window: ^Window) -> bool {
|
||||
assert(window != nil)
|
||||
@(private="file") set_event_queue :: #force_inline proc(hwnd: win.HWND, event_queue: ^Event_Queue) {
|
||||
win.SetWindowLongPtrW(hwnd, win.GWLP_USERDATA, win.LONG_PTR(uintptr(event_queue)))
|
||||
}
|
||||
@(private="file") get_event_queue :: #force_inline proc(hwnd: win.HWND) -> ^Event_Queue {
|
||||
return (^Event_Queue)(rawptr(uintptr(win.GetWindowLongPtrW(hwnd, win.GWLP_USERDATA))))
|
||||
}
|
||||
|
||||
instance := win.HINSTANCE(win.GetModuleHandleW(nil))
|
||||
assert(instance != nil, "Failed to fetch current instance")
|
||||
@(private="file") wm_create :: proc(hwnd: win.HWND, lparam: win.LPARAM) -> win.LRESULT {
|
||||
pcs := (^win.CREATESTRUCTW)(rawptr(uintptr(lparam)))
|
||||
assert(pcs != nil)
|
||||
|
||||
CLASS_NAME :: "ENSENN_WINDOW"
|
||||
event_queue := (^Event_Queue)(pcs.lpCreateParams)
|
||||
assert(event_queue != nil)
|
||||
|
||||
cls := win.WNDCLASSW {
|
||||
lpfnWndProc = proc "stdcall" (hwnd: win.HWND, msg: win.UINT, wparam: win.WPARAM, lparam: win.LPARAM) -> win.LRESULT {
|
||||
fmt.printfln("Event queue (%v): %v ", &event_queue, event_queue)
|
||||
|
||||
set_event_queue(hwnd, event_queue)
|
||||
|
||||
fmt.printfln("CREATE")
|
||||
return 0
|
||||
}
|
||||
|
||||
@(private="file") wnd_proc :: proc "system" (hwnd: win.HWND, msg: win.UINT, wparam: win.WPARAM, lparam: win.LPARAM) -> win.LRESULT {
|
||||
context = runtime.default_context()
|
||||
|
||||
event_queue := get_event_queue(hwnd)
|
||||
switch(msg) {
|
||||
case win.WM_CREATE: return wm_create(hwnd, lparam)
|
||||
case win.WM_KEYDOWN, win.WM_SYSKEYDOWN: {
|
||||
input_event: Event_Input = Event_Keyboard {
|
||||
virtual_key = get_virtual_key_windows(i32(wparam)),
|
||||
state = .Down
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, input_event)
|
||||
return 0
|
||||
}
|
||||
case win.WM_KEYUP, win.WM_SYSKEYUP: {
|
||||
input_event: Event_Input = Event_Keyboard {
|
||||
virtual_key = get_virtual_key_windows(i32(wparam)),
|
||||
state = .Up
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, input_event)
|
||||
return 0
|
||||
}
|
||||
// Mouse.
|
||||
case win.WM_MOUSEMOVE: {
|
||||
x := win.GET_X_LPARAM(lparam)
|
||||
y := win.GET_Y_LPARAM(lparam)
|
||||
|
||||
assert(x >= 0)
|
||||
assert(y >= 0)
|
||||
|
||||
mouse_event: Event_Mouse = Event_Mouse_Move {
|
||||
x = u16(x),
|
||||
y = u16(y),
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Input(mouse_event))
|
||||
return 0
|
||||
}
|
||||
case win.WM_LBUTTONDOWN, win.WM_LBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Left,
|
||||
state = msg == win.WM_LBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Input(mouse_event))
|
||||
return 0
|
||||
}
|
||||
case win.WM_MBUTTONDOWN, win.WM_MBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Middle,
|
||||
state = msg == win.WM_MBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Input(mouse_event))
|
||||
return 0
|
||||
}
|
||||
case win.WM_RBUTTONDOWN, win.WM_RBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Right,
|
||||
state = msg == win.WM_RBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Input(mouse_event))
|
||||
return 0
|
||||
}
|
||||
case win.WM_SIZE: {
|
||||
new_width := u16(win.LOWORD(lparam))
|
||||
new_height := u16(win.HIWORD(lparam))
|
||||
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Resize { new_width, new_height, })
|
||||
return 0;
|
||||
}
|
||||
case win.WM_CLOSE: {
|
||||
assert(event_queue != nil)
|
||||
queue.push_back(event_queue, Event_Quit {})
|
||||
win.DestroyWindow(hwnd)
|
||||
}
|
||||
case win.WM_DESTROY: {
|
||||
win.PostQuitMessage(0)
|
||||
return 0
|
||||
}
|
||||
case win.WM_ERASEBKGND: {
|
||||
return 1 // paint should fill out the client area so no need to erase the background
|
||||
}
|
||||
case: {
|
||||
return win.DefWindowProcW(hwnd, msg, wparam, lparam)
|
||||
@@ -31,8 +132,21 @@ init_window_windows :: proc(window: ^Window) -> bool {
|
||||
}
|
||||
|
||||
return 0
|
||||
},
|
||||
lpszClassName = win.utf8_to_wstring(CLASS_NAME),
|
||||
}
|
||||
|
||||
WINDOW_CLASS_NAME :: "ENSENN_WINDOW"
|
||||
|
||||
init_window_windows :: proc(window: ^Window) -> bool {
|
||||
assert(window != nil)
|
||||
|
||||
instance := win.HINSTANCE(win.GetModuleHandleW(nil))
|
||||
assert(instance != nil, "Failed to fetch current instance")
|
||||
|
||||
class_name_w := win.utf8_to_wstring(WINDOW_CLASS_NAME)
|
||||
|
||||
cls := win.WNDCLASSW {
|
||||
lpfnWndProc = wnd_proc,
|
||||
lpszClassName = class_name_w,
|
||||
hInstance = instance,
|
||||
hCursor = win.LoadCursorA(nil, win.IDC_ARROW),
|
||||
}
|
||||
@@ -52,8 +166,8 @@ init_window_windows :: proc(window: ^Window) -> bool {
|
||||
actual_window_height := rect.bottom - rect.top
|
||||
|
||||
hwnd := win.CreateWindowW(
|
||||
lpClassName = win.L(CLASS_NAME),
|
||||
lpWindowName = win.L(CLASS_NAME),
|
||||
lpClassName = win.L(WINDOW_CLASS_NAME),
|
||||
lpWindowName = win.L(WINDOW_CLASS_NAME),
|
||||
dwStyle = window_style,
|
||||
X = (screen_width - i32(window.width)) / 2,
|
||||
Y = (screen_height - i32(window.height)) / 2,
|
||||
@@ -62,7 +176,7 @@ init_window_windows :: proc(window: ^Window) -> bool {
|
||||
hWndParent = nil,
|
||||
hMenu = nil,
|
||||
hInstance = instance,
|
||||
lpParam = nil
|
||||
lpParam = &window.event_queue
|
||||
)
|
||||
assert(hwnd != nil, "Window creation failed")
|
||||
|
||||
@@ -81,124 +195,30 @@ set_title_windows :: proc(window: ^Window) {
|
||||
win.SetWindowTextW(window.backend.hwnd, win.utf8_to_wstring(window.title))
|
||||
}
|
||||
|
||||
update_windows :: proc(window: ^Window) -> Event {
|
||||
update_windows :: proc(window: ^Window) {
|
||||
assert(window != nil)
|
||||
|
||||
{ // Message loop.
|
||||
msg: win.MSG
|
||||
|
||||
{ // Resizing.
|
||||
rect: win.RECT
|
||||
win.GetClientRect(window.backend.hwnd, &rect)
|
||||
|
||||
new_width := u16(rect.right - rect.left)
|
||||
new_height := u16(rect.bottom - rect.top)
|
||||
|
||||
if new_width != window.width || new_height != window.height {
|
||||
old_width := window.width
|
||||
old_height := window.height
|
||||
|
||||
window.width = new_width
|
||||
window.height = new_height
|
||||
|
||||
if new_width > 0 && new_height > 0 {
|
||||
return Event_Resize {
|
||||
old_width, old_height,
|
||||
window.width, window.height,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
win.CoInitializeEx(nil)
|
||||
|
||||
ok := win.PeekMessageW(
|
||||
lpMsg = &msg,
|
||||
hWnd = nil, // NOTE: SS - Don't like that this needs to be nil but apparently it does for this window to receive the WM_CLOSE and WM_QUIT messages.
|
||||
// If wMsgFilterMin and wMsgFilterMax are both zero,
|
||||
// PeekMessage returns all available messages (that is, no range filtering is performed).
|
||||
wMsgFilterMin = 0, wMsgFilterMax = 0,
|
||||
wRemoveMsg = win.PM_REMOVE // If 'PM_REMOVE', messages are removed from the queue after processing by PeekMessage.
|
||||
)
|
||||
if !ok {
|
||||
// No messages.
|
||||
return nil
|
||||
}
|
||||
|
||||
for win.PeekMessageW(lpMsg = &msg, hWnd = nil, wMsgFilterMin = 0, wMsgFilterMax = 0, wRemoveMsg = win.PM_REMOVE) == win.TRUE {
|
||||
win.TranslateMessage(&msg)
|
||||
win.DispatchMessageW(&msg)
|
||||
|
||||
// fmt.printfln("Message type: %x", msg.message)
|
||||
|
||||
switch msg.message {
|
||||
// Keyboard.
|
||||
case win.WM_KEYDOWN, win.WM_SYSKEYDOWN: {
|
||||
input_event: Event_Input = Event_Keyboard {
|
||||
virtual_key = get_virtual_key_windows(i32(msg.wParam)),
|
||||
state = .Down
|
||||
}
|
||||
|
||||
return input_event
|
||||
}
|
||||
case win.WM_KEYUP, win.WM_SYSKEYUP: {
|
||||
input_event: Event_Input = Event_Keyboard {
|
||||
virtual_key = get_virtual_key_windows(i32(msg.wParam)),
|
||||
state = .Up
|
||||
}
|
||||
|
||||
return input_event
|
||||
}
|
||||
// Mouse.
|
||||
case win.WM_MOUSEMOVE: {
|
||||
x := win.GET_X_LPARAM(msg.lParam)
|
||||
y := win.GET_Y_LPARAM(msg.lParam)
|
||||
|
||||
assert(x >= 0)
|
||||
assert(y >= 0)
|
||||
|
||||
mouse_event: Event_Mouse = Event_Mouse_Move{
|
||||
x = u16(x),
|
||||
y = u16(y),
|
||||
}
|
||||
|
||||
return Event_Input(mouse_event)
|
||||
}
|
||||
case win.WM_LBUTTONDOWN, win.WM_LBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Left,
|
||||
state = msg.message == win.WM_LBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
return Event_Input(mouse_event)
|
||||
}
|
||||
case win.WM_MBUTTONDOWN, win.WM_MBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Middle,
|
||||
state = msg.message == win.WM_MBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
return Event_Input(mouse_event)
|
||||
}
|
||||
case win.WM_RBUTTONDOWN, win.WM_RBUTTONUP: {
|
||||
mouse_event: Event_Mouse = Event_Mouse_Button {
|
||||
button = .Right,
|
||||
state = msg.message == win.WM_RBUTTONDOWN ? .Down : .Up
|
||||
}
|
||||
|
||||
return Event_Input(mouse_event)
|
||||
}
|
||||
|
||||
case win.WM_QUIT: {
|
||||
return Event_Quit {}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
destroy_windows :: proc(window: ^Window) {
|
||||
assert(window != nil)
|
||||
assert(window.backend.hwnd != nil)
|
||||
|
||||
win.SetWindowLongPtrW(window.backend.hwnd, win.GWLP_USERDATA, 0)
|
||||
|
||||
win.DestroyWindow(window.backend.hwnd)
|
||||
window.backend.hwnd = nil
|
||||
|
||||
class_name_w := win.utf8_to_wstring(WINDOW_CLASS_NAME)
|
||||
win.UnregisterClassW(class_name_w, window.backend.instance)
|
||||
|
||||
}
|
||||
|
||||
@(private) get_virtual_key_windows :: proc(vk: i32) -> Virtual_Key {
|
||||
|
||||
Reference in New Issue
Block a user