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 allocation_granularity;
|
||||
string machine_name;
|
||||
|
||||
// Monitor stuff:
|
||||
b32 monitors_enumerated;
|
||||
Array<Monitor> monitors; // Back with GPAllocator
|
||||
};
|
||||
|
||||
struct OS_Process_Info {
|
||||
@ -44,6 +48,10 @@ struct OS_Process_Info {
|
||||
string user_program_data_path;
|
||||
Array<string> module_load_paths;
|
||||
Array<string> environment_paths;
|
||||
|
||||
b32 window_class_initialized;
|
||||
Arena* event_arena;
|
||||
Array<Window_Info> windows;
|
||||
};
|
||||
|
||||
struct OS_State_Win32 {
|
||||
@ -53,11 +61,11 @@ struct OS_State_Win32 {
|
||||
OS_Process_Info process_info;
|
||||
};
|
||||
|
||||
global OS_State_Win32 os_state_w32;
|
||||
internal b32 win32_g_is_quiet = 0; // No console output
|
||||
global OS_State_Win32 global_win32_state;
|
||||
internal b32 global_win32_is_quiet = 0; // No console output
|
||||
|
||||
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;
|
||||
if(InterlockedCompareExchange(&first, 1, 0) != 0)
|
||||
@ -69,6 +77,8 @@ internal LONG WINAPI Win32_Exception_Filter (EXCEPTION_POINTERS* exception_ptrs)
|
||||
|
||||
// #Exception handling code (TODO)
|
||||
|
||||
ExitProcess(1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -102,18 +112,18 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
||||
|
||||
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->page_size = sysinfo.dwPageSize;
|
||||
info->large_page_size = GetLargePageMinimum();
|
||||
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->process_id = GetCurrentProcessId();
|
||||
}
|
||||
// #cpuid
|
||||
/*{ OS_System_Info* info = &os_state_w32.system_info;
|
||||
/*{ OS_System_Info* info = &global_win32_state.system_info;
|
||||
// [ ] Extract input args
|
||||
u32 length;
|
||||
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
||||
@ -154,7 +164,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
||||
}
|
||||
// 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};
|
||||
DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
|
||||
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);
|
||||
// This can be freed later when we call temp_reset();
|
||||
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));
|
||||
}
|
||||
|
||||
// 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)
|
||||
// [ ] GetEnvironmentStringsW
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
// void initialize_window_class(float background_color[3]) {}
|
||||
Window_Type create_window (string new_window_name, bool center_window) {
|
||||
return 0;
|
||||
// Instead of returning WindowType, return the handle + other information.
|
||||
bool os_create_window (string new_window_name, Window_Type parent, bool center_window, bool open_on_largest_monitor, bool display_window) {
|
||||
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
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
#pragma comment(lib, "user32")
|
||||
|
||||
f64 GetUnixTimestamp ();
|
||||
s64 GetUnixTimestampNanoseconds ();
|
||||
|
||||
// struct File_Contents {
|
||||
// File file = {};
|
||||
// ArrayView<u8> file_data = {};
|
||||
// bool read_success = false;
|
||||
// };
|
||||
|
||||
enum class Wait_For_Result : s32 {
|
||||
SUCCESS = 0,
|
||||
TIMEOUT = 1,
|
||||
@ -51,3 +47,41 @@ internal bool write_entire_file (string file_path, ArrayView<u8> file_data);
|
||||
|
||||
// #window_creation
|
||||
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
|
||||
# include "lib/OS/OS_Win32.h"
|
||||
#endif
|
||||
#include "lib/UI/Layout.h"
|
||||
#include "lib/Base/Logger.h"
|
||||
#include "lib/Base/String.cpp"
|
||||
|
||||
|
||||
@ -35,11 +35,25 @@ internal void Main_Entry_Point (int argc, WCHAR **argv) {
|
||||
run_post_setup_tests();
|
||||
#endif
|
||||
|
||||
// 2. Setup Window
|
||||
// 3. Initialize Graphics Backend (DX11 or OpenGL3)
|
||||
// 2. Create Window
|
||||
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`
|
||||
// [ ] 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