From 8489421dbfa6c3f3c8e9c3200c3bb8543306fd7c Mon Sep 17 00:00:00 2001 From: Charlie <66182434+asbott@users.noreply.github.com> Date: Sat, 29 Jun 2024 01:18:22 +0200 Subject: [PATCH] Got a window going --- build.c | 2 +- build_clang.bat | 2 +- build_release_clang.bat | 2 +- entry.c | 33 +++++++ main.c | 57 ----------- oogabooga/drawing.c | 24 +++++ oogabooga/input.c | 0 oogabooga/linmath.c | 61 ++++++++++++ oogabooga/oogabooga.c | 25 +++-- oogabooga/os_impl_windows.c | 184 ++++++++++++++++++++++++++++++++++++ oogabooga/os_interface.c | 43 ++++++++- oogabooga/string.c | 2 + 12 files changed, 364 insertions(+), 71 deletions(-) create mode 100644 entry.c delete mode 100644 main.c create mode 100644 oogabooga/drawing.c create mode 100644 oogabooga/input.c create mode 100644 oogabooga/linmath.c diff --git a/build.c b/build.c index f0fc461..60f215b 100644 --- a/build.c +++ b/build.c @@ -17,4 +17,4 @@ typedef struct Context_Extra { // Includes for game goes here // ... -#include "main.c" \ No newline at end of file +#include "entry.c" \ No newline at end of file diff --git a/build_clang.bat b/build_clang.bat index fa742b7..fb669b4 100644 --- a/build_clang.bat +++ b/build_clang.bat @@ -4,6 +4,6 @@ mkdir build pushd build -clang -g -o cgame.exe ../build.c -O0 -DDEBUG -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter +clang -g -o cgame.exe ../build.c -O0 -DDEBUG -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter -lgdi32 -luser32 -lopengl32 popd \ No newline at end of file diff --git a/build_release_clang.bat b/build_release_clang.bat index f4a9ec1..2fd580d 100644 --- a/build_release_clang.bat +++ b/build_release_clang.bat @@ -7,7 +7,7 @@ pushd build mkdir release pushd release -clang -o cgame.exe ../../build.c -O3 -DRELEASE -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter +clang -o cgame.exe ../../build.c -Ofast -DRELEASE -std=c11 -Wextra -Wno-incompatible-library-redeclaration -Wno-sign-compare -Wno-unused-parameter popd popd \ No newline at end of file diff --git a/entry.c b/entry.c new file mode 100644 index 0000000..d5ff688 --- /dev/null +++ b/entry.c @@ -0,0 +1,33 @@ + + +int entry(int argc, char **argv) { + + window.title = fixed_string("My epic game"); + //window.width = 400; + //window.height = 400; + //window.x = 200; + //window.y = 200; + + window.x = 0; + window.y = 0; + + while (!window.should_close) { + reset_temporary_storage(); + context.allocator = temp; + + print("%d, %d, %d, %d\n", window.x, window.y, window.width, window.height); + + glBegin(GL_QUADS); + glColor3f(1.0f, 0.0f, 0.0f); + glVertex2f(-0.5f, -0.5f); + glVertex2f(0.5f, -0.5f); + glVertex2f(0.5f, 0.5f); + glVertex2f(-0.5f, 0.5f); + glEnd(); + + os_update(); + } + + return 0; +} + diff --git a/main.c b/main.c deleted file mode 100644 index 580dcc3..0000000 --- a/main.c +++ /dev/null @@ -1,57 +0,0 @@ - -int oogabooga_main(int argc, char **argv) { - - print(cstr("This is our print! %i\n"), 5); - - // alloc calls to context.allocator.proc which by default is set to the - // heap allocator in memory.c - int *a = (int*)alloc(sizeof(int)); - dealloc(a); - - // We can do an old school memory dump to save our game with the global variables - // (void*) program_memory and (u64) program_memory_size - // program_memory will ALWAYS have the same virtual memory base address, so all - // pointers will remain valid when read back from disk. - - // We can push allocator like jai - push_allocator(temp); - // all calls to alloc() here will be with the temporary allocator - pop_allocator(); // But this is C so we have to pop it manually! - - // or we can just do this for temporary allocation - int *b = talloc(sizeof(int)); - (void)b; - - // Call each frame - reset_temporary_storage(); - - Context c = context; - // ... modify c - push_context(c); - // ... do stuff in modified context - pop_context(); - - // For now, context only has the allocator and CONTEXT_EXTRA which can be defined - // to add some custom stuff to context - // But it needs to be in build.c before including oogabooga.c. - // #define CONTEXT_EXTRA struct { int monkee; } - context.extra.monkee = 69; - - - int hello; - hello = 5; - (void)hello; - -#ifdef DEBUG - print("Hello, balls! (debug)\n"); -#endif - -#ifdef RELEASE - print("Hello, balls! (release)\n"); -#endif - - print("Program exit as expected\n"); - - return 0; -} - diff --git a/oogabooga/drawing.c b/oogabooga/drawing.c new file mode 100644 index 0000000..7d89815 --- /dev/null +++ b/oogabooga/drawing.c @@ -0,0 +1,24 @@ + +#define QUADS_PER_BLOCK 1024 + +typedef struct Draw_Quad { + float left; + float right; + float bottom; + float top; + + Vector4 color; + +} Draw_Quad; + +typedef struct Draw_Quad_Block { + Draw_Quad quad_buffer[QUADS_PER_BLOCK]; + u64 num_quads; + + struct Draw_Quad_Block *next; +} Draw_Quad_Block; + +typedef struct Draw_Frame { + Draw_Quad_Block first_quad_block; +} Draw_Frame; + diff --git a/oogabooga/input.c b/oogabooga/input.c new file mode 100644 index 0000000..e69de29 diff --git a/oogabooga/linmath.c b/oogabooga/linmath.c new file mode 100644 index 0000000..57b3896 --- /dev/null +++ b/oogabooga/linmath.c @@ -0,0 +1,61 @@ + + +typedef struct Vector2 { + union {float x, r;}; + union {float y, g;}; +} Vector2; +typedef Vector2 v2; + +typedef struct Vector3 { + union {float x, r;}; + union {float y, g;}; + union {float z, b;}; +} Vector3; +typedef Vector3 v3; + +typedef struct Vector4 { + union {float x, r;}; + union {float y, g;}; + union {float z, b;}; + union {float w, a;}; +} Vector4; +typedef Vector4 v4; + +// #Simd #Speed + +Vector2 v2_add(Vector2 a, Vector2 b) { + return (v2){a.x + b.x, a.y + b.y}; +} +Vector3 v3_add(Vector3 a, Vector3 b) { + return (v3){a.x + b.x, a.y + b.y, a.z + b.z}; +} +Vector4 v4_add(Vector4 a, Vector4 b) { + return (v4){a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w}; +} +Vector2 v2_sub(Vector2 a, Vector2 b) { + return (v2){a.x - b.x, a.y - b.y}; +} +Vector3 v3_sub(Vector3 a, Vector3 b) { + return (v3){a.x - b.x, a.y - b.y, a.z - b.z}; +} +Vector4 v4_sub(Vector4 a, Vector4 b) { + return (v4){a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w}; +} +Vector2 v2_mul(Vector2 a, Vector2 b) { + return (v2){a.x * b.x, a.y * b.y}; +} +Vector3 v3_mul(Vector3 a, Vector3 b) { + return (v3){a.x * b.x, a.y * b.y, a.z * b.z}; +} +Vector4 v4_mul(Vector4 a, Vector4 b) { + return (v4){a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w}; +} +Vector2 v2_div(Vector2 a, Vector2 b) { + return (v2){a.x / b.x, a.y / b.y}; +} +Vector3 v3_div(Vector3 a, Vector3 b) { + return (v3){a.x / b.x, a.y / b.y, a.z / b.z}; +} +Vector4 v4_div(Vector4 a, Vector4 b) { + return (v4){a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w}; +} \ No newline at end of file diff --git a/oogabooga/oogabooga.c b/oogabooga/oogabooga.c index f660ed7..50adad4 100644 --- a/oogabooga/oogabooga.c +++ b/oogabooga/oogabooga.c @@ -1,12 +1,16 @@ #if !defined(DEBUG) && !defined(RELEASE) -#ifdef _DEBUG -#define DEBUG -#elif defined(NDEBUG) -#define RELEASE + #ifdef _DEBUG + #define DEBUG + #elif defined(NDEBUG) + #define RELEASE + #endif + #endif +#ifndef ENTRY_PROC + #define ENTRY_PROC entry #endif #ifdef _WIN32 @@ -25,16 +29,17 @@ #endif #include "base.c" - #include "string.c" #include "string_format.c" #include "os_interface.c" +#include "linmath.c" + #include "memory.c" +#include "input.c" - - +#include "drawing.c" #ifdef OS_WINDOWS #include "os_impl_windows.c" @@ -49,7 +54,7 @@ void oogabooga_init(u64 program_memory_size) { os_init(program_memory_size); - heap_init(); + heap_init(); temporary_storage_init(); } @@ -61,7 +66,7 @@ void oogabooga_init(u64 program_memory_size) { #endif -int oogabooga_main(int argc, char **argv); +int ENTRY_PROC(int argc, char **argv); int main(int argc, char **argv) { context.allocator.proc = initialization_allocator_proc; @@ -73,7 +78,7 @@ int main(int argc, char **argv) { oogabooga_run_tests(); #endif - int code = oogabooga_main(argc, argv); + int code = ENTRY_PROC(argc, argv); printf("Ooga booga program exit with code %i\n", code); diff --git a/oogabooga/os_impl_windows.c b/oogabooga/os_impl_windows.c index d6bb9d1..c8c1fec 100644 --- a/oogabooga/os_impl_windows.c +++ b/oogabooga/os_impl_windows.c @@ -19,6 +19,35 @@ void* heap_allocator_proc(u64 size, void *p, Allocator_Message message) { return 0; } +LRESULT CALLBACK win32_window_proc(HWND passed_window, UINT message, WPARAM wparam, LPARAM lparam) { + + if (window._initialized) { + assert(passed_window == window._os_handle, "Event from another window?? wut (%d)", message); + } + + switch (message) { + case WM_CLOSE: + DestroyWindow(window._os_handle); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + case WM_SIZE: + break; + case WM_MOVE: + break; + default: + return DefWindowProc(passed_window, message, wparam, lparam); + } + return 0; +} + +// #Temporary #Cleanup +// #Temporary #Cleanup +// #Temporary #Cleanup +// #Temporary #Cleanup +#include "GL/gl.h" +HDC hdc; void os_init(u64 program_memory_size) { SYSTEM_INFO si; @@ -69,6 +98,89 @@ void os_init(u64 program_memory_size) { assert(os.crt_memcmp, "Missing crt_memcmp in crt"); os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memset")); assert(os.crt_memset, "Missing memset in crt"); + + window.title = fixed_string("Unnamed Window"); + window.width = 1280; + window.height = 720; + window.x = 0; + window.y = 0; + window.should_close = false; + window._initialized = false; + window.clear_color.r = 0.392f; + window.clear_color.g = 0.584f; + window.clear_color.b = 0.929f; + window.clear_color.a = 1.0f; + + WNDCLASSEX wc = (WNDCLASSEX){0}; + MSG msg; + HINSTANCE instance = GetModuleHandle(NULL); + assert(instance != INVALID_HANDLE_VALUE, "Failed getting current HINSTANCE"); + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_OWNDC; + wc.lpfnWndProc = win32_window_proc; + wc.hInstance = instance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = "sigma balls"; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + BOOL ok = RegisterClassEx(&wc); + assert(ok, "Failed registering window class (error code %lu)", GetLastError()); + + RECT rect = {0, 0, window.width, window.height}; + DWORD style = WS_OVERLAPPEDWINDOW; + DWORD ex_style = WS_EX_CLIENTEDGE; + ok = AdjustWindowRectEx(&rect, style, FALSE, ex_style); + assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError()); + + u32 actual_window_width = rect.right - rect.left; + u32 actual_window_height = rect.bottom - rect.top; + // Create the window + window._os_handle = CreateWindowEx( + ex_style, + "sigma balls", + temp_convert_to_null_terminated_string(window.title), + style, + CW_USEDEFAULT, CW_USEDEFAULT, actual_window_width, actual_window_height, + NULL, NULL, instance, NULL); + assert(window._os_handle != NULL, "Window creation failed, error: %lu", GetLastError()); + window._initialized = true; + ShowWindow(window._os_handle, SW_SHOWDEFAULT); + UpdateWindow(window._os_handle); + + + + + // #Temporary #Cleanup + // #Temporary #Cleanup + // #Temporary #Cleanup + // #Temporary #Cleanup + + PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + 32, + 0, 0, 0, 0, 0, 0, + 0, 0, + 0, 0, 0, 0, 0, + 24, + 8, + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + hdc = GetDC(window._os_handle); + int pixelFormat = ChoosePixelFormat(hdc, &pfd); + SetPixelFormat(hdc, pixelFormat, &pfd); + + HGLRC hglrc = wglCreateContext(hdc); + wglMakeCurrent(hdc, hglrc); } bool os_grow_program_memory(u64 new_size) { @@ -277,4 +389,76 @@ bool os_compare_and_swap_64(u64 *a, u64 b, u64 old) { bool os_compare_and_swap_bool(bool *a, bool b, bool old) { return os_compare_and_swap_8(cast(u8*)a, cast(u8)b, cast(u8)old); +} + + +void os_update() { + + static Os_Window last_window; + + if (!strings_match(last_window.title, window.title)) { + SetWindowText(window._os_handle, temp_convert_to_null_terminated_string(window.title)); + } + + BOOL ok; + int screen_height = GetSystemMetrics(SM_CYSCREEN); + DWORD style = (DWORD)GetWindowLong(window._os_handle, GWL_STYLE); + DWORD ex_style = (DWORD)GetWindowLong(window._os_handle, GWL_EXSTYLE); + if (last_window.x != window.x || last_window.y != window.y || last_window.width != window.width || last_window.y != window.y) { + RECT update_rect; + update_rect.left = window.x; + update_rect.right = window.x + window.width; + update_rect.bottom = screen_height-(window.y); + update_rect.top = screen_height-(window.y+window.height); + ok = AdjustWindowRectEx(&update_rect, style, FALSE, ex_style); + assert(ok != 0, "AdjustWindowRectEx failed with error code %lu", GetLastError()); + + u32 actual_x = update_rect.left; + u32 actual_y = update_rect.top; + u32 actual_width = update_rect.right-update_rect.left; + u32 actual_height = update_rect.bottom-update_rect.top; + + SetWindowPos(window._os_handle, 0, actual_x, actual_y, actual_width, actual_height, 0); + } + + RECT client_rect; + ok = GetClientRect(window._os_handle, &client_rect); + assert(ok, "GetClientRect failed with error code %lu", GetLastError()); + + // Convert the client area rectangle top-left corner to screen coordinates + POINT top_left; + top_left.x = client_rect.left; + top_left.y = client_rect.top; + ok = ClientToScreen(window._os_handle, &top_left); + assert(ok, "ClientToScreen failed with error code %lu", GetLastError()); + + // Convert the client area rectangle bottom-right corner to screen coordinates + POINT bottom_right; + bottom_right.x = client_rect.right; + bottom_right.y = client_rect.bottom; + ok = ClientToScreen(window._os_handle, &bottom_right); + assert(ok, "ClientToScreen failed with error code %lu", GetLastError()); + + + window.x = (u32)top_left.x; + window.y = (u32)(screen_height-bottom_right.y); + window.width = (u32)(client_rect.right - client_rect.left); + window.height = (u32)(client_rect.bottom - client_rect.top); + + last_window = window; + + SwapBuffers(hdc); + glClearColor(window.clear_color.r, window.clear_color.g, window.clear_color.b, window.clear_color.a); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, window.width, window.height); + + MSG msg; + while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + if (msg.message == WM_QUIT) { + window.should_close = true; + break; + } + TranslateMessage(&msg); + DispatchMessage(&msg); + } } \ No newline at end of file diff --git a/oogabooga/os_interface.c b/oogabooga/os_interface.c index 3d33f09..dc8fc4a 100644 --- a/oogabooga/os_interface.c +++ b/oogabooga/os_interface.c @@ -4,17 +4,19 @@ typedef HANDLE Mutex_Handle; typedef HANDLE Thread_Handle; typedef HMODULE Dynamic_Library_Handle; + typedef HWND Window_Handle; #elif defined(__linux__) typedef SOMETHING Mutex_Handle; typedef SOMETHING Thread_Handle; typedef SOMETHING Dynamic_Library_Handle; - + typedef SOMETHING Window_Handle; #error "Linux is not supported yet"; #elif defined(__APPLE__) && defined(__MACH__) typedef SOMETHING Mutex_Handle; typedef SOMETHING Thread_Handle; typedef SOMETHING Dynamic_Library_Handle; + typedef SOMETHING Window_Handle; #error "Mac is not supported yet"; #else #error "Current OS not supported!"; @@ -189,3 +191,42 @@ void os_write_string_to_stdout(string s); /// void* os_get_stack_base(); void* os_get_stack_limit(); + + + +/// +/// +// Window management +/// +typedef struct Os_Window { + + // Keep in mind that setting these in runtime is potentially slow! + string title; + u32 width; + u32 height; + u32 x; + u32 y; + struct { + float32 r, g, b, a; + } clear_color; + + bool should_close; + + // readonly + bool _initialized; + Window_Handle _os_handle; + +} Os_Window; +Os_Window window; + + + + +/// +/// +// Window input +/// + + + +void os_update(); \ No newline at end of file diff --git a/oogabooga/string.c b/oogabooga/string.c index b298228..818efa3 100644 --- a/oogabooga/string.c +++ b/oogabooga/string.c @@ -50,6 +50,8 @@ typedef struct string { void push_temp_allocator(); +// Not sure what to call this lol +#define fixed_string const_string #define cstr const_string #define const_string(s) ((string){ length_of_null_terminated_string(s), (u8*)s })