Got a window going
This commit is contained in:
parent
09553f1e3b
commit
8489421dbf
12 changed files with 364 additions and 71 deletions
2
build.c
2
build.c
|
@ -17,4 +17,4 @@ typedef struct Context_Extra {
|
|||
// Includes for game goes here
|
||||
// ...
|
||||
|
||||
#include "main.c"
|
||||
#include "entry.c"
|
|
@ -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
|
|
@ -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
|
33
entry.c
Normal file
33
entry.c
Normal 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
57
main.c
|
@ -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
24
oogabooga/drawing.c
Normal 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
0
oogabooga/input.c
Normal file
61
oogabooga/linmath.c
Normal file
61
oogabooga/linmath.c
Normal 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};
|
||||
}
|
|
@ -9,6 +9,10 @@
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef ENTRY_PROC
|
||||
#define ENTRY_PROC entry
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#define OS_WINDOWS
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
@ -278,3 +390,75 @@ 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
|
@ -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 })
|
||||
|
||||
|
|
Reference in a new issue