Last active
August 26, 2023 13:36
-
-
Save kinjalkishor/b7b9d78f4fdd2f003f2cdd7f0aeb3082 to your computer and use it in GitHub Desktop.
Simple WinApi window class version
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#if defined(_MSC_VER) | |
#pragma comment(lib, "user32.lib") | |
#pragma comment(lib, "gdi32.lib") | |
#endif | |
#define WIN32_LEAN_AND_MEAN | |
#include <Windows.h> | |
//#include <wtypes.h> | |
#include <stdio.h> | |
#include "base_types.h" | |
#include "base_io.h" | |
#include "base_console.h" | |
#include "base_def.h" | |
inline const wchar_t* APP_CLASS_NAME = L"SAMPLE_APP_CLASS"; | |
//===================================================== | |
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); | |
class app_vars { | |
public: | |
bool app_quit = false; | |
bool app_active = true; | |
bool app_minimized = false; | |
void sys_quit() { app_quit = true; } | |
}; | |
//extern app_vars g_av; | |
app_vars g_av; | |
#include <thread> | |
#include <chrono> | |
inline void sys_sleep(u32 dwMilliseconds) { | |
//Sleep(dwMilliseconds); | |
std::this_thread::sleep_for(std::chrono::milliseconds(dwMilliseconds)); | |
} | |
class game_timer_qpc { | |
public: | |
float period() { | |
i64 cnts_per_sec = 0; | |
QueryPerformanceFrequency((LARGE_INTEGER*)&cnts_per_sec); | |
// secs_per_cnt_qpc is 0.0000001f, 1e-07; | |
float secs_per_cnt_qpc = 1.0f / scast<float>(cnts_per_sec); | |
//println("{}", secs_per_cnt_qpc); | |
return secs_per_cnt_qpc; | |
} | |
i64 get_time() { | |
// Retrieves the current value of the performance counter, | |
// which is a high resolution (<1 micro second) time stamp. | |
i64 prev_time_qpc = 0; | |
QueryPerformanceCounter((LARGE_INTEGER*)&prev_time_qpc); | |
return prev_time_qpc; | |
} | |
}; | |
class game_timer_ch { | |
public: | |
float period() { | |
//using high_resolution_clock = steady_clock; | |
// secs_per_cnt_ch or period is 0.000000001f, 1e-09; | |
float secs_per_cnt_ch = scast<float>(std::chrono::high_resolution_clock::period::num) | |
/ scast<float>(std::chrono::high_resolution_clock::period::den); | |
//println("{}", secs_per_cnt_ch); | |
return secs_per_cnt_ch; | |
} | |
i64 get_time() { | |
std::chrono::high_resolution_clock::time_point prev_time_ch = std::chrono::high_resolution_clock::now(); | |
std::chrono::high_resolution_clock::duration duration = prev_time_ch.time_since_epoch(); | |
//i64 time_unit = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); | |
i64 time_unit = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count(); | |
return time_unit; | |
} | |
//using high_resolution_clock = steady_clock; | |
//// secs_per_cnt_ch or period is 0.000000001f, 1e-09; | |
//float secs_per_cnt_ch = scast<float>(std::chrono::high_resolution_clock::period::num) / scast<float>(std::chrono::high_resolution_clock::period::den); | |
//println("{}", secs_per_cnt_ch); | |
//std::chrono::high_resolution_clock::time_point prev_time_ch = std::chrono::high_resolution_clock::now(); | |
// | |
//std::chrono::high_resolution_clock::time_point curr_time_ch = std::chrono::high_resolution_clock::now(); | |
//std::chrono::duration<i64, std::nano> time_span = curr_time_ch - prev_time_ch; | |
//float delta_time_ch = scast<float>(time_span.count())*secs_per_cnt_ch; | |
}; | |
class win_app { | |
public: | |
HWND m_hwnd = nullptr; | |
HINSTANCE m_app_instance = nullptr; | |
WNDPROC m_wnd_proc = nullptr; | |
u32 m_win_bg_color = RGB(25, 25, 112); | |
wchar_t m_app_class_name[64] = {}; | |
MSG m_msg = {}; | |
win_app() { | |
m_msg.message = WM_NULL; | |
} | |
~win_app() {} | |
bool register_class(HINSTANCE hInstance, WNDPROC wnd_proc) { | |
m_app_instance = hInstance; | |
m_wnd_proc = wnd_proc; | |
wcsncpy(m_app_class_name, APP_CLASS_NAME, 64); | |
// register window class | |
WNDCLASSEX wcex = {}; | |
wcex.cbSize = sizeof(wcex); | |
wcex.style = CS_OWNDC; //must for opengl | |
//wcex.style = CS_HREDRAW|CS_VREDRAW; | |
wcex.lpfnWndProc = m_wnd_proc; | |
wcex.cbClsExtra = 0; | |
wcex.cbWndExtra = 0; | |
wcex.hInstance = m_app_instance; | |
wcex.hIcon = LoadIconW(nullptr, IDI_APPLICATION); | |
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); | |
//wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); | |
wcex.hbrBackground = CreateSolidBrush(m_win_bg_color); | |
wcex.lpszMenuName = nullptr; | |
wcex.lpszClassName = m_app_class_name; | |
wcex.hIconSm = LoadIconW(nullptr, IDI_APPLICATION); | |
if (!RegisterClassExW(&wcex)) { | |
println("Cannot Register WinApi Class."); | |
return false; | |
} | |
return true; | |
} | |
bool create_window(const char* wnd_title, i32 xpos, i32 ypos, i32 width, i32 height) { | |
u32 dwStyle = 0; | |
u32 dwExStyle = 0; | |
//dwStyle = WS_POPUP|WS_VISIBLE| WS_CLIPSIBLINGS|WS_CLIPCHILDREN; //borderless | |
dwStyle = WS_OVERLAPPEDWINDOW|WS_VISIBLE| WS_CLIPSIBLINGS|WS_CLIPCHILDREN; | |
//dwExStyle = WS_EX_APPWINDOW|WS_EX_TOPMOST; //fullscreen | |
dwExStyle = WS_EX_APPWINDOW|WS_EX_WINDOWEDGE; | |
wchar_t wstr_wnd_title[256] = {}; | |
sdf::multi_byte_to_wide_char(wstr_wnd_title, sdf::ssize(wstr_wnd_title), wnd_title, sdf::strz_length(wnd_title)); | |
i32 x, y, w, h; | |
RECT window_rect = {0, 0, width, height}; | |
AdjustWindowRectEx(&window_rect, dwStyle, false, dwExStyle); | |
x = xpos + window_rect.left; | |
y = ypos + window_rect.top; | |
w = window_rect.right - window_rect.left; | |
h = window_rect.bottom - window_rect.top; | |
HWND handle_wnd = CreateWindowExW(dwExStyle, | |
m_app_class_name, | |
wstr_wnd_title, | |
dwStyle, | |
x, y, w, h, | |
nullptr, nullptr, m_app_instance, nullptr); | |
if (!handle_wnd) { | |
println("Cannot Create Window."); | |
//return false; | |
} | |
ShowWindow(handle_wnd, SW_SHOW); | |
UpdateWindow(handle_wnd); | |
SetForegroundWindow(handle_wnd); | |
SetFocus(handle_wnd); | |
m_hwnd = handle_wnd; | |
return true; | |
} | |
void poll_events() { | |
if(PeekMessageW(&m_msg, nullptr, 0, 0, PM_REMOVE)) { | |
TranslateMessage(&m_msg); | |
DispatchMessageW(&m_msg); | |
} | |
} | |
bool is_quit_msg() { | |
return (m_msg.message == WM_QUIT); | |
} | |
int msg_return() { | |
return scast<int>(m_msg.wParam); | |
} | |
void deinit() { | |
DestroyWindow(m_hwnd); | |
UnregisterClassW(m_app_class_name, m_app_instance); | |
} | |
}; | |
//====================================== | |
// WinMain | |
//====================================== | |
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { | |
std_console gconstd; | |
gconstd.create_window("NexWars Std Console", 864, 0, 640, 640); | |
printf("SysConsole Initialized.\n"); | |
println("Sample app"); | |
//------------------ | |
// config | |
i32 xpos = 10; | |
i32 ypos = 50; | |
i32 width = 800; | |
i32 height = 450; | |
bool fullscreen = false; | |
bool borderless = false; | |
const char* wnd_title = "Sample window"; | |
//------------------ | |
win_app nw_app; | |
nw_app.register_class(hInstance, MainWndProc); | |
nw_app.create_window(wnd_title, xpos, ypos, width, height); | |
//---------------------------- | |
game_timer_qpc nw_timer; | |
i64 prev_time_qpc = nw_timer.get_time(); | |
//game_timer_ch nw_timer2; | |
//i64 prev_time_ch = nw_timer2.get_time(); | |
// program main loop | |
while (!g_av.app_quit) { | |
//poll events | |
nw_app.poll_events(); | |
if (nw_app.is_quit_msg()) { g_av.sys_quit(); } | |
if (g_av.app_active) { | |
i64 curr_time_qpc = nw_timer.get_time(); | |
float delta_time_qpc = (curr_time_qpc - prev_time_qpc)*nw_timer.period(); | |
//i64 curr_time_ch = nw_timer2.get_time(); | |
//float delta_time_ch = (curr_time_ch - prev_time_ch)*nw_timer2.period()*0.001f; | |
//println("{:6f}, {:6f}, {:6f}", curr_time_qpc*nw_timer.period(), prev_time_qpc*nw_timer.period(), delta_time_qpc); | |
//println("{:6f}, {:6f}, {:6f}", curr_time_ch*nw_timer2.period(), prev_time_ch*nw_timer2.period(), delta_time_ch); | |
//process_input(); | |
//rn->render(delta_time); | |
//rn->swap_buffers(); | |
prev_time_qpc = curr_time_qpc; | |
} else { | |
sys_sleep(1); | |
continue; | |
} | |
} // while: not app_quit | |
nw_app.deinit(); | |
return nw_app.msg_return(); | |
} | |
//====================================== | |
// Window Procedure | |
//====================================== | |
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { | |
switch (uMsg) { | |
case WM_ACTIVATE: | |
g_av.app_active = scast<bool>(LOWORD(wParam) != WA_INACTIVE); | |
g_av.app_minimized = scast<bool>(HIWORD(wParam)); | |
return 0; | |
case WM_CREATE: | |
return 0; | |
case WM_DESTROY: | |
PostQuitMessage(0); | |
return 0; | |
case WM_CLOSE: | |
//DestroyWindow(hWnd); | |
PostQuitMessage(0); | |
return 0; | |
case WM_QUIT: | |
PostQuitMessage(0); | |
return 0; | |
case WM_KEYDOWN: | |
switch (wParam) { | |
case VK_ESCAPE: | |
PostQuitMessage(0); | |
return 0; | |
} | |
return 0; | |
default: break; | |
} | |
return DefWindowProcW(hWnd, uMsg, wParam, lParam); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment