Add basic window creation (Win32)
This commit is contained in:
parent
56dec1cf93
commit
15cf7e68fd
@ -34,6 +34,10 @@ struct OS_System_Info {
|
|||||||
u64 large_page_size;
|
u64 large_page_size;
|
||||||
u64 allocation_granularity;
|
u64 allocation_granularity;
|
||||||
string machine_name;
|
string machine_name;
|
||||||
|
|
||||||
|
// Monitor stuff:
|
||||||
|
b32 monitors_enumerated;
|
||||||
|
Array<Monitor> monitors; // Back with GPAllocator
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OS_Process_Info {
|
struct OS_Process_Info {
|
||||||
@ -44,6 +48,10 @@ struct OS_Process_Info {
|
|||||||
string user_program_data_path;
|
string user_program_data_path;
|
||||||
Array<string> module_load_paths;
|
Array<string> module_load_paths;
|
||||||
Array<string> environment_paths;
|
Array<string> environment_paths;
|
||||||
|
|
||||||
|
b32 window_class_initialized;
|
||||||
|
Arena* event_arena;
|
||||||
|
Array<Window_Info> windows;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OS_State_Win32 {
|
struct OS_State_Win32 {
|
||||||
@ -53,11 +61,11 @@ struct OS_State_Win32 {
|
|||||||
OS_Process_Info process_info;
|
OS_Process_Info process_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
global OS_State_Win32 os_state_w32;
|
global OS_State_Win32 global_win32_state;
|
||||||
internal b32 win32_g_is_quiet = 0; // No console output
|
internal b32 global_win32_is_quiet = 0; // No console output
|
||||||
|
|
||||||
internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs) {
|
internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs) {
|
||||||
if (win32_g_is_quiet) { ExitProcess(1); }
|
if (global_win32_is_quiet) { ExitProcess(1); }
|
||||||
|
|
||||||
local_persist volatile LONG first = 0;
|
local_persist volatile LONG first = 0;
|
||||||
if(InterlockedCompareExchange(&first, 1, 0) != 0)
|
if(InterlockedCompareExchange(&first, 1, 0) != 0)
|
||||||
@ -69,6 +77,8 @@ internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs)
|
|||||||
|
|
||||||
// #Exception handling code (TODO)
|
// #Exception handling code (TODO)
|
||||||
|
|
||||||
|
ExitProcess(1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,18 +112,18 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
|
|
||||||
push_arena(thread_context()->arena);
|
push_arena(thread_context()->arena);
|
||||||
|
|
||||||
{ OS_System_Info* info = &os_state_w32.system_info;
|
{ OS_System_Info* info = &global_win32_state.system_info;
|
||||||
info->logical_processor_count = (s32)sysinfo.dwNumberOfProcessors;
|
info->logical_processor_count = (s32)sysinfo.dwNumberOfProcessors;
|
||||||
info->page_size = sysinfo.dwPageSize;
|
info->page_size = sysinfo.dwPageSize;
|
||||||
info->large_page_size = GetLargePageMinimum();
|
info->large_page_size = GetLargePageMinimum();
|
||||||
info->allocation_granularity = sysinfo.dwAllocationGranularity;
|
info->allocation_granularity = sysinfo.dwAllocationGranularity;
|
||||||
}
|
}
|
||||||
{ OS_Process_Info* info = &os_state_w32.process_info;
|
{ OS_Process_Info* info = &global_win32_state.process_info;
|
||||||
info->large_pages_allowed = false;
|
info->large_pages_allowed = false;
|
||||||
info->process_id = GetCurrentProcessId();
|
info->process_id = GetCurrentProcessId();
|
||||||
}
|
}
|
||||||
// #cpuid
|
// #cpuid
|
||||||
/*{ OS_System_Info* info = &os_state_w32.system_info;
|
/*{ OS_System_Info* info = &global_win32_state.system_info;
|
||||||
// [ ] Extract input args
|
// [ ] Extract input args
|
||||||
u32 length;
|
u32 length;
|
||||||
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
||||||
@ -154,7 +164,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
}
|
}
|
||||||
// info->secondary_core_count = ;
|
// info->secondary_core_count = ;
|
||||||
*/
|
*/
|
||||||
{ OS_System_Info* info = &os_state_w32.system_info;
|
{ OS_System_Info* info = &global_win32_state.system_info;
|
||||||
|
info->monitors.allocator = GPAllocator();
|
||||||
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||||
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
|
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
|
||||||
if(GetComputerNameA((char*)buffer, &size)) {
|
if(GetComputerNameA((char*)buffer, &size)) {
|
||||||
@ -163,7 +174,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{ OS_Process_Info* info = &os_state_w32.process_info;
|
{ OS_Process_Info* info = &global_win32_state.process_info;
|
||||||
|
info->windows.allocator = GPAllocator();
|
||||||
DWORD length = GetCurrentDirectoryW(0, 0);
|
DWORD length = GetCurrentDirectoryW(0, 0);
|
||||||
// This can be freed later when we call temp_reset();
|
// This can be freed later when we call temp_reset();
|
||||||
u16* memory = NewArray<u16>(temp(), length + 1);
|
u16* memory = NewArray<u16>(temp(), length + 1);
|
||||||
@ -172,6 +184,11 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
Assert(is_valid(info->working_path));
|
Assert(is_valid(info->working_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup event arena, allocators for Array<> types.
|
||||||
|
if (!global_win32_state.process_info.event_arena) {
|
||||||
|
global_win32_state.process_info.event_arena = next_arena(Arena_Reserve::Size_64K);
|
||||||
|
}
|
||||||
|
|
||||||
// [ ] Get Working directory (info->working_path)
|
// [ ] Get Working directory (info->working_path)
|
||||||
// [ ] GetEnvironmentStringsW
|
// [ ] GetEnvironmentStringsW
|
||||||
temp_reset();
|
temp_reset();
|
||||||
@ -504,10 +521,211 @@ internal bool write_entire_file (string file_path, ArrayView<u8> file_data) {
|
|||||||
return write_entire_file(file_path, file_data.data, file_data.count);
|
return write_entire_file(file_path, file_data.data, file_data.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal LRESULT // see os_w32_wnd_proc from raddebugger.
|
||||||
|
win32_wnd_proc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
LRESULT result = 0;
|
||||||
|
bool good = true;
|
||||||
|
|
||||||
|
Arena* event_arena = global_win32_state.process_info.event_arena;
|
||||||
|
Assert(event_arena != nullptr);
|
||||||
|
|
||||||
|
switch (uMsg) {
|
||||||
|
default: {
|
||||||
|
result = DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||||
|
} break;
|
||||||
|
case WM_CLOSE: {
|
||||||
|
ExitProcess(0); // #temp.
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal BOOL
|
||||||
|
monitor_enum_proc (HMONITOR hMonitor, HDC hdc, RECT* rect, LPARAM data) {
|
||||||
|
Monitor monitor = {};
|
||||||
|
monitor.left = rect->left;
|
||||||
|
monitor.top = rect->top;
|
||||||
|
monitor.right = rect->right;
|
||||||
|
monitor.bottom = rect->bottom;
|
||||||
|
|
||||||
|
monitor.monitor_info.cbSize = sizeof(MONITORINFO);
|
||||||
|
|
||||||
|
GetMonitorInfoW(hMonitor, &monitor.monitor_info);
|
||||||
|
monitor.primary = !!(monitor.monitor_info.dwFlags & 0x1);
|
||||||
|
monitor.present = true;
|
||||||
|
|
||||||
|
array_add(global_win32_state.system_info.monitors, monitor);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #TODO: how do I setup a callback if monitors configuration is changed?
|
||||||
|
// we handle WM_DISPLAYCHANGE or WM_DEVICECHANGE and call EnumDisplayMonitors
|
||||||
|
internal void os_enumerate_monitors () {
|
||||||
|
if (!global_win32_state.system_info.monitors_enumerated) {
|
||||||
|
// should reset array?
|
||||||
|
if (!EnumDisplayMonitors(nullptr, nullptr, monitor_enum_proc, 0)) {
|
||||||
|
log_error("Failed to enumerate monitors\n");
|
||||||
|
Assert(false); // Failed to enumerate monitors
|
||||||
|
ExitProcess(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
global_win32_state.system_info.monitors_enumerated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window_Dimensions platform_get_centered_window_dimensions (bool open_on_largest_monitor=false) {
|
||||||
|
os_enumerate_monitors();
|
||||||
|
|
||||||
|
Assert(global_win32_state.system_info.monitors.count > 0); // must have at least 1 monitor!
|
||||||
|
|
||||||
|
Array<Monitor> monitors = global_win32_state.system_info.monitors;
|
||||||
|
Monitor monitor = monitors[0];
|
||||||
|
|
||||||
|
if (open_on_largest_monitor) {
|
||||||
|
s64 max_area = 0;
|
||||||
|
for (s64 i = 0; i < monitors.count; i += 1) {
|
||||||
|
s64 width = monitors[i].right - monitors[i].left;
|
||||||
|
s64 height = monitors[i].bottom - monitors[i].top;
|
||||||
|
s64 area = width * height;
|
||||||
|
|
||||||
|
if (max_area < area) {
|
||||||
|
monitor = monitors[i];
|
||||||
|
max_area = area;
|
||||||
|
} else if (max_area == area && monitors[i].primary) {
|
||||||
|
// if monitors are the same dimension, then just use primary monitor
|
||||||
|
monitor = monitors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Opens on whatever monitor is marked as "primary."
|
||||||
|
for (s64 i = 0; i < monitors.count; i += 1) {
|
||||||
|
if (monitors[i].primary) {
|
||||||
|
monitor = monitors[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 monitor_width = monitor.right - monitor.left;
|
||||||
|
s64 monitor_height = monitor.bottom - monitor.top;
|
||||||
|
|
||||||
|
s64 window_width = (s64)((f64)monitor_width / 1.125);
|
||||||
|
s64 window_height = (s64)((f64)monitor_height / 1.25);
|
||||||
|
s64 window_x = (monitor.left + (monitor_width / 2) - (window_width / 2));
|
||||||
|
s64 window_y = (monitor.top + (monitor_height / 2) - (window_height / 2));
|
||||||
|
|
||||||
|
Window_Dimensions dimensions = {
|
||||||
|
(s32)window_x,
|
||||||
|
(s32)window_y,
|
||||||
|
(s32)window_width,
|
||||||
|
(s32)window_height,
|
||||||
|
};
|
||||||
|
|
||||||
|
return dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
// #window_creation -> put API in OS_Win32.h
|
// #window_creation -> put API in OS_Win32.h
|
||||||
// void initialize_window_class(float background_color[3]) {}
|
// Instead of returning WindowType, return the handle + other information.
|
||||||
Window_Type create_window (string new_window_name, bool center_window) {
|
bool os_create_window (string new_window_name, Window_Type parent, bool center_window, bool open_on_largest_monitor, bool display_window) {
|
||||||
return 0;
|
const ArrayView<f32> background_color = array_view_from_values<f32>(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
local_persist string class_name = "Win32_Window_Class";
|
||||||
|
|
||||||
|
if (!global_win32_state.process_info.window_class_initialized) {
|
||||||
|
global_win32_state.process_info.window_class_initialized = true;
|
||||||
|
|
||||||
|
WNDCLASSEXW wc = {};
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||||
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||||
|
wc.lpfnWndProc = win32_wnd_proc;
|
||||||
|
wc.cbClsExtra = 0;
|
||||||
|
wc.cbWndExtra = 0;
|
||||||
|
wc.hInstance = nullptr;
|
||||||
|
wc.hIcon = (HICON)LoadImageW(nullptr, (LPCWSTR)utf8_to_wide("tmp.ico").data, IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
|
||||||
|
wc.hCursor = LoadCursorW(nullptr, (LPCWSTR)IDC_ARROW);
|
||||||
|
wc.hbrBackground = nullptr;
|
||||||
|
wc.lpszMenuName = nullptr;
|
||||||
|
wc.lpszClassName = (LPCWSTR)utf8_to_wide(class_name).data;
|
||||||
|
|
||||||
|
if (RegisterClassExW(&wc) == 0) {
|
||||||
|
log_error("RegisterClassExW Failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Window_Dimensions wd = { 100, 100, 640, 480 };
|
||||||
|
|
||||||
|
if (center_window) {
|
||||||
|
wd = platform_get_centered_window_dimensions(open_on_largest_monitor);
|
||||||
|
log("[Window_Dimensions] location: (%d, %d); size: %dx%d px",
|
||||||
|
wd.window_x, wd.window_y, wd.window_width, wd.window_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND hwnd = CreateWindowExW(
|
||||||
|
WS_EX_APPWINDOW,
|
||||||
|
(LPCWSTR)utf8_to_wide(class_name).data,
|
||||||
|
(LPCWSTR)utf8_to_wide(new_window_name).data,
|
||||||
|
WS_OVERLAPPEDWINDOW,
|
||||||
|
wd.window_x, wd.window_y, wd.window_width, wd.window_height,
|
||||||
|
nullptr, nullptr, nullptr, nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!hwnd) {
|
||||||
|
Assert(false);
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the window:
|
||||||
|
if (display_window) {
|
||||||
|
UpdateWindow(hwnd);
|
||||||
|
ShowWindow(hwnd, SW_SHOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save window to stack
|
||||||
|
Window_Info info = {};
|
||||||
|
info.window = hwnd;
|
||||||
|
info.initial_dimensions = wd;
|
||||||
|
info.is_main_window = (parent == nullptr);
|
||||||
|
|
||||||
|
// Should we mutex this? Seems very unlikely we'll ever need to call this
|
||||||
|
// from multiple threads at the same time.
|
||||||
|
array_add(global_win32_state.process_info.windows, info);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window_Info get_main_window() {
|
||||||
|
Array<Window_Info> windows = global_win32_state.process_info.windows;
|
||||||
|
Assert(windows.count > 0);
|
||||||
|
|
||||||
|
for (s64 i = 0; i < windows.count; i += 1) {
|
||||||
|
if (windows[i].is_main_window) {
|
||||||
|
return windows[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_window_dimensions(Window_Info* info, s32* width, s32* height) {
|
||||||
|
if (info == nullptr || width == nullptr || height == nullptr) return false;
|
||||||
|
Assert(width && height);
|
||||||
|
|
||||||
|
RECT c = {};
|
||||||
|
bool success = GetClientRect(info->window, &c);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
(*width) = 0;
|
||||||
|
(*height) = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*width) = (s32)(c.right - c.left);
|
||||||
|
(*height) = (s32)(c.bottom - c.top);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// #TODO: #window_creation
|
// #TODO: #window_creation
|
||||||
|
|||||||
@ -1,12 +1,8 @@
|
|||||||
|
#pragma comment(lib, "user32")
|
||||||
|
|
||||||
f64 GetUnixTimestamp ();
|
f64 GetUnixTimestamp ();
|
||||||
s64 GetUnixTimestampNanoseconds ();
|
s64 GetUnixTimestampNanoseconds ();
|
||||||
|
|
||||||
// struct File_Contents {
|
|
||||||
// File file = {};
|
|
||||||
// ArrayView<u8> file_data = {};
|
|
||||||
// bool read_success = false;
|
|
||||||
// };
|
|
||||||
|
|
||||||
enum class Wait_For_Result : s32 {
|
enum class Wait_For_Result : s32 {
|
||||||
SUCCESS = 0,
|
SUCCESS = 0,
|
||||||
TIMEOUT = 1,
|
TIMEOUT = 1,
|
||||||
@ -51,3 +47,41 @@ internal bool write_entire_file (string file_path, ArrayView<u8> file_data);
|
|||||||
|
|
||||||
// #window_creation
|
// #window_creation
|
||||||
typedef HWND Window_Type;
|
typedef HWND Window_Type;
|
||||||
|
|
||||||
|
struct Window_Dimensions {
|
||||||
|
s32 window_x;
|
||||||
|
s32 window_y;
|
||||||
|
s32 window_width;
|
||||||
|
s32 window_height;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Window_Info {
|
||||||
|
Window_Type window;
|
||||||
|
Window_Dimensions initial_dimensions;
|
||||||
|
|
||||||
|
b32 is_main_window;
|
||||||
|
};
|
||||||
|
|
||||||
|
// #move: Monitor - platform-independent hardware monitor information:
|
||||||
|
struct Monitor {
|
||||||
|
s64 left;
|
||||||
|
s64 top;
|
||||||
|
s64 right;
|
||||||
|
s64 bottom;
|
||||||
|
bool primary;
|
||||||
|
bool present;
|
||||||
|
#if OS_WINDOWS
|
||||||
|
MONITORINFO monitor_info;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool os_create_window (string new_window_name, Window_Type parent=nullptr, bool center_window=true, bool open_on_largest_monitor=true, bool display_window=true);
|
||||||
|
|
||||||
|
Window_Info get_main_window();
|
||||||
|
|
||||||
|
// struct File_Contents {
|
||||||
|
// File file = {};
|
||||||
|
// ArrayView<u8> file_data = {};
|
||||||
|
// bool read_success = false;
|
||||||
|
// };
|
||||||
|
|||||||
15
lib/UI/Layout.h
Normal file
15
lib/UI/Layout.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
struct Rect {
|
||||||
|
f32 x; f32 y; f32 w; f32 h;
|
||||||
|
};
|
||||||
|
|
||||||
|
force_inline bool operator==(const Rect& a, const Rect& b) {
|
||||||
|
return a.x == b.x && a.y == b.y && a.w == b.w && a.h == b.h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect make_rect_int (s64 x, s64 y, s64 w, s64 h) {
|
||||||
|
return {(f32)x, (f32)y, (f32)w, (f32)h};
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect make_rect (f32 x, f32 y, f32 w, f32 h) {
|
||||||
|
return {x, y, w, h};
|
||||||
|
}
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
# include "lib/OS/OS_Win32.h"
|
# include "lib/OS/OS_Win32.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "lib/UI/Layout.h"
|
||||||
#include "lib/Base/Logger.h"
|
#include "lib/Base/Logger.h"
|
||||||
#include "lib/Base/String.cpp"
|
#include "lib/Base/String.cpp"
|
||||||
|
|
||||||
|
|||||||
@ -35,11 +35,25 @@ internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
run_post_setup_tests();
|
run_post_setup_tests();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// 2. Setup Window
|
// 2. Create Window
|
||||||
// 3. Initialize Graphics Backend (DX11 or OpenGL3)
|
bool success = os_create_window("App Main Window", nullptr, true, true);
|
||||||
|
Assert(success);
|
||||||
|
|
||||||
|
Window_Info main_window = get_main_window();
|
||||||
|
s32 window_width; s32 window_height;
|
||||||
|
success = get_window_dimensions(&main_window, &window_width, &window_height);
|
||||||
|
Assert(success);
|
||||||
|
// #TODO: Set in global state for convenience:
|
||||||
|
Rect main_screen = make_rect_int(0, 0, window_width, window_height);
|
||||||
|
// renderer.//set_render_target(main_window.window, main_screen);
|
||||||
|
|
||||||
|
// get_render_dimensions
|
||||||
|
|
||||||
|
// 3. Init Graphics (DX11 or OpenGL3)
|
||||||
|
// Maybe start with OpenGL3
|
||||||
// #TODO: #Main - `Main_Entry_Point`
|
// #TODO: #Main - `Main_Entry_Point`
|
||||||
// [ ] Setup Mouse and Keyboard Inputs
|
|
||||||
// [ ] Launch second thread
|
// 4. [ ] Setup Mouse and Keyboard Inputs
|
||||||
|
// 5. [ ] Launch second thread; thread groups
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user