Got a window going

This commit is contained in:
Charlie 2024-06-29 01:18:22 +02:00
parent 09553f1e3b
commit 8489421dbf
12 changed files with 364 additions and 71 deletions

View file

@ -17,4 +17,4 @@ typedef struct Context_Extra {
// Includes for game goes here // Includes for game goes here
// ... // ...
#include "main.c" #include "entry.c"

View file

@ -4,6 +4,6 @@ mkdir build
pushd 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 popd

View file

@ -7,7 +7,7 @@ pushd build
mkdir release mkdir release
pushd 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
popd popd

33
entry.c Normal file
View file

@ -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;
}

57
main.c
View file

@ -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;
}

24
oogabooga/drawing.c Normal file
View file

@ -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;

0
oogabooga/input.c Normal file
View file

61
oogabooga/linmath.c Normal file
View file

@ -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};
}

View file

@ -1,12 +1,16 @@
#if !defined(DEBUG) && !defined(RELEASE) #if !defined(DEBUG) && !defined(RELEASE)
#ifdef _DEBUG #ifdef _DEBUG
#define DEBUG #define DEBUG
#elif defined(NDEBUG) #elif defined(NDEBUG)
#define RELEASE #define RELEASE
#endif
#endif #endif
#ifndef ENTRY_PROC
#define ENTRY_PROC entry
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
@ -25,16 +29,17 @@
#endif #endif
#include "base.c" #include "base.c"
#include "string.c" #include "string.c"
#include "string_format.c" #include "string_format.c"
#include "os_interface.c" #include "os_interface.c"
#include "linmath.c"
#include "memory.c" #include "memory.c"
#include "input.c"
#include "drawing.c"
#ifdef OS_WINDOWS #ifdef OS_WINDOWS
#include "os_impl_windows.c" #include "os_impl_windows.c"
@ -49,7 +54,7 @@
void oogabooga_init(u64 program_memory_size) { void oogabooga_init(u64 program_memory_size) {
os_init(program_memory_size); os_init(program_memory_size);
heap_init(); heap_init();
temporary_storage_init(); temporary_storage_init();
} }
@ -61,7 +66,7 @@ void oogabooga_init(u64 program_memory_size) {
#endif #endif
int oogabooga_main(int argc, char **argv); int ENTRY_PROC(int argc, char **argv);
int main(int argc, char **argv) { int main(int argc, char **argv) {
context.allocator.proc = initialization_allocator_proc; context.allocator.proc = initialization_allocator_proc;
@ -73,7 +78,7 @@ int main(int argc, char **argv) {
oogabooga_run_tests(); oogabooga_run_tests();
#endif #endif
int code = oogabooga_main(argc, argv); int code = ENTRY_PROC(argc, argv);
printf("Ooga booga program exit with code %i\n", code); printf("Ooga booga program exit with code %i\n", code);

View file

@ -19,6 +19,35 @@ void* heap_allocator_proc(u64 size, void *p, Allocator_Message message) {
return 0; 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) { void os_init(u64 program_memory_size) {
SYSTEM_INFO si; SYSTEM_INFO si;
@ -69,6 +98,89 @@ void os_init(u64 program_memory_size) {
assert(os.crt_memcmp, "Missing crt_memcmp in crt"); 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")); os.crt_memset = (Crt_Memset_Proc)os_dynamic_library_load_symbol(os.crt, const_string("memset"));
assert(os.crt_memset, "Missing memset in crt"); 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) { 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) { 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); 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);
}
} }

View file

@ -4,17 +4,19 @@
typedef HANDLE Mutex_Handle; typedef HANDLE Mutex_Handle;
typedef HANDLE Thread_Handle; typedef HANDLE Thread_Handle;
typedef HMODULE Dynamic_Library_Handle; typedef HMODULE Dynamic_Library_Handle;
typedef HWND Window_Handle;
#elif defined(__linux__) #elif defined(__linux__)
typedef SOMETHING Mutex_Handle; typedef SOMETHING Mutex_Handle;
typedef SOMETHING Thread_Handle; typedef SOMETHING Thread_Handle;
typedef SOMETHING Dynamic_Library_Handle; typedef SOMETHING Dynamic_Library_Handle;
typedef SOMETHING Window_Handle;
#error "Linux is not supported yet"; #error "Linux is not supported yet";
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
typedef SOMETHING Mutex_Handle; typedef SOMETHING Mutex_Handle;
typedef SOMETHING Thread_Handle; typedef SOMETHING Thread_Handle;
typedef SOMETHING Dynamic_Library_Handle; typedef SOMETHING Dynamic_Library_Handle;
typedef SOMETHING Window_Handle;
#error "Mac is not supported yet"; #error "Mac is not supported yet";
#else #else
#error "Current OS not supported!"; #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_base();
void* os_get_stack_limit(); 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();

View file

@ -50,6 +50,8 @@ typedef struct string {
void push_temp_allocator(); void push_temp_allocator();
// Not sure what to call this lol
#define fixed_string const_string
#define cstr const_string #define cstr const_string
#define const_string(s) ((string){ length_of_null_terminated_string(s), (u8*)s }) #define const_string(s) ((string){ length_of_null_terminated_string(s), (u8*)s })