From 6d611d9fab7fdb712420ac562bedb7bcef0726c4 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 17 May 2022 18:47:06 +0200 Subject: [PATCH] Merging with new base, dumping obj files to raw binary and loading --- .gitignore | 3 +- base_string.cpp | 454 ++++++++++++ build.bat | 4 + kpl_multimedia.cpp | 899 ++++++++++++++++++++++++ kpl_multimedia.h | 230 +++++++ main.cpp | 337 +++++---- math.h | 1642 +++++++++++++++++++++++++++++++++++++++++++- obj_parser.cpp | 494 ++++++++----- profile.cpp | 55 +- project.4c | 9 + stb_image.cpp | 2 - ui.cpp | 72 +- 12 files changed, 3760 insertions(+), 441 deletions(-) create mode 100644 base_string.cpp create mode 100644 build.bat create mode 100644 kpl_multimedia.cpp create mode 100644 kpl_multimedia.h create mode 100644 project.4c delete mode 100644 stb_image.cpp diff --git a/.gitignore b/.gitignore index 87f553a..87bd62c 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ data.txt *.sln *.vcxproj* *.rdbg -*.sublime* \ No newline at end of file +*.sublime* +*.bin \ No newline at end of file diff --git a/base_string.cpp b/base_string.cpp new file mode 100644 index 0000000..660c8d0 --- /dev/null +++ b/base_string.cpp @@ -0,0 +1,454 @@ + +function U8 +to_lower_case(U8 a) { + if (a >= 'A' && a <= 'Z') + a += 32; + return a; +} + +function U8 +to_upper_case(U8 a) { + if (a >= 'a' && a <= 'z') + a -= 32; + return a; +} + +function U8 +char_to_lower(U8 c){ + if(c >= 'A' && c <= 'Z') + c += 32; + return c; +} + +function U8 +char_to_upper(U8 c){ + if(c >= 'a' && c <= 'z') + c -= 32; + return c; +} + +function B32 +is_whitespace(U8 w) { + bool result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r'; + return result; +} + +function B32 +is_alphabetic(U8 a) { + if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) { + return true; + } + return false; +} + +function B32 +is_number(U8 a) { + B32 result = a >= '0' && a <= '9'; + return result; +} + +function B32 +is_alphanumeric(U8 a) { + B32 result = is_number(a) || is_alphabetic(a); + return result; +} + +function B32 +string_compare(String a, String b, B32 ignore_case = false) { + if (a.len != b.len) + return false; + for (S64 i = 0; i < a.len; i++) { + U8 A = a.str[i]; + U8 B = b.str[i]; + if (ignore_case) { + A = to_lower_case(A); + B = to_lower_case(B); + } + if (A != B) + return false; + } + return true; +} + +function B32 +operator==(String a, String b){ + return string_compare(a,b); +} + +function String +string_copy(Allocator *a, String string){ + U8 *copy = exp_alloc_array(a, U8, string.len+1); + memory_copy(copy, string.str, string.len); + copy[string.len] = 0; + return (String){copy, string.len}; +} + +function String +string_fmtv(Allocator *a, const char *str, va_list args1) { + va_list args2; + va_copy(args2, args1); + S64 len = stbsp_vsnprintf(0, 0, str, args2); + va_end(args2); + + char *result = exp_alloc_array(a, char, len + 1); + stbsp_vsnprintf(result, len + 1, str, args1); + + String res = {(U8 *)result, len}; + return res; +} + +#define STRING_FMT(alloc, str, result) \ +va_list args1; \ +va_start(args1, str); \ +String result = string_fmtv(alloc, str, args1); \ +va_end(args1) + +function String +string_fmt(Allocator *a, const char *str, ...) { + STRING_FMT(a, str, result); + return result; +} + +//----------------------------------------------------------------------------- +// String builder +//----------------------------------------------------------------------------- +struct String_Builder_Block{ + String_Builder_Block *next; + S64 cap; + S64 len; + U8 data[0]; +}; + +struct String_Builder{ + Allocator *allocator; + String_Builder_Block *first; + String_Builder_Block *last; + + void push_block(SizeU size){ + auto *block = (String_Builder_Block *)exp_alloc(allocator, sizeof(String_Builder_Block) + size); + memory_zero(block, sizeof(String_Builder_Block)+1); // Also clear first byte of character data + block->cap = size; + SLLQueuePush(first, last, block); + } + + void init(S64 size = 4096){ + assert(allocator); + push_block(size); + } + + void append_data(void *data, S64 size){ + if(first == 0){ + init(); + } + + S64 remaining_cap = last->cap - last->len; + if(size > remaining_cap){ + S64 new_block_size = max(last->cap*2, size*2); + push_block(new_block_size); + } + + U8 *write_address = last->data + last->len; + last->len += size; + memory_copy(write_address, data, size); + } +}; + +function String_Builder +string_builder_make(Allocator *a, S64 first_block_size = 4096){ + String_Builder sb = {a}; + sb.init(first_block_size); + return sb; +} + +function void +appendf(String_Builder *b, const char *str, ...){ + if(b->first == 0){ + b->init(); + } + va_list args, args2; + va_start(args, str); + retry:{ + String_Builder_Block *block = b->last; + int block_size = block->cap - block->len; + char *write_address = (char *)block->data + block->len; + + va_copy(args2, args); + int written = vsnprintf(write_address, block_size, str, args2); + va_end(args2); + + if(written > block_size){ + int new_block_size = max(4096, (written+1)*2); + b->push_block(new_block_size); + goto retry; + } + block->len += written; + } + va_end(args); +} + +enum String_Builder_Flag{ + String_Builder_Flag_None = 0, + String_Builder_Flag_AddSize = 0, +}; + +function String +string_flatten(String_Builder *b, String_Builder_Flag flags = String_Builder_Flag_None){ + // @Note(Krzosa): Only single block, no need to flatten, vsnprintf null terminates too + if(b->first == b->last){ + String result = {b->first->data, b->first->len}; + return result; + } + + // @Note(Krzosa): Compute size to allocate + S64 size = 1; + if(is_flag_set(flags, String_Builder_Flag_AddSize)) size += sizeof(SizeU); + IterList(b){ + size += it->len; + } + + String result = {}; + result.str = (U8 *)exp_alloc(b->allocator, size); + if(is_flag_set(flags, String_Builder_Flag_AddSize)) { + memory_copy(result.str + result.len, &size, sizeof(S64)); + result.len += sizeof(S64); + } + + // @Note(Krzosa): Copy the content of each block into the string + IterList(b){ + memory_copy(result.str + result.len, it->data, it->len); + result.len += it->len; + } + + result.str[result.len] = 0; + return result; +} + +function void +test_string_builder(){ + Scratch scratch; + String_Builder sb = string_builder_make(scratch, 4); + appendf(&sb, "Thing, %d", 242252); + String f = string_flatten(&sb); + assert(string_compare(f, "Thing, 242252"_s)); + appendf(&sb, "-%f %f %f", 23.0, 42.29, 2925.2); + f = string_flatten(&sb); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +function void +string_path_normalize(String s) { + for (S64 i = 0; i < s.len; i++) { + if (s.str[i] == '\\') + s.str[i] = '/'; + } +} + +function String +string_make(char *str, S64 len) { + String result; + result.str = (U8 *)str; + result.len = len; + return result; +} + +function String +string_make(U8 *str, S64 len) { + return string_make((char*)str, len); +} + +function String +string_chop(String string, S64 len) { + len = clamp_top(len, string.len); + String result = string_make(string.str, string.len - len); + return result; +} + +function String +string_skip(String string, S64 len) { + len = clamp_top(len, string.len); + S64 remain = string.len - len; + String result = string_make(string.str + len, remain); + return result; +} + +function String +string_get_postfix(String string, S64 len) { + len = clamp_top(len, string.len); + S64 remain_len = string.len - len; + String result = string_make(string.str + remain_len, len); + return result; +} + +function String +string_get_prefix(String string, S64 len) { + len = clamp_top(len, string.len); + String result = string_make(string.str, len); + return result; +} + +function String +string_slice(String string, S64 first_index, S64 one_past_last_index) { + assert_msg(first_index < one_past_last_index, "string_slice, first_index is bigger then one_past_last_index"); + assert_msg(string.len > 0, "Slicing string of length 0! Might be an error!"); + String result = string; + if (string.len > 0) { + if (one_past_last_index > first_index) { + first_index = clamp_top(first_index, string.len - 1); + one_past_last_index = clamp_top(one_past_last_index, string.len); + result.str += first_index; + result.len = one_past_last_index - first_index; + } + else { + result.len = 0; + } + } + return result; +} + +function String +string_trim(String string) { + if (string.len == 0) return string; + + + S64 whitespace_begin = 0; + for (; whitespace_begin < string.len; whitespace_begin++) { + if (!is_whitespace(string.str[whitespace_begin])) { + break; + } + } + + S64 whitespace_end = string.len; + for (; whitespace_end != whitespace_begin; whitespace_end--) { + if (!is_whitespace(string.str[whitespace_end - 1])) { + break; + } + } + + if (whitespace_begin == whitespace_end) { + string.len = 0; + } + else { + string = string_slice(string, whitespace_begin, whitespace_end); + } + + return string; +} + +function String +string_trim_end(String string) { + S64 whitespace_end = string.len; + for (; whitespace_end != 0; whitespace_end--) { + if (!is_whitespace(string.str[whitespace_end - 1])) { + break; + } + } + + String result = string_get_prefix(string, whitespace_end); + return result; +} + +function String +string_to_lower_case(Allocator *arena, String s) { + String copy = string_copy(arena, s); + for (U64 i = 0; i < copy.len; i++) { + copy.str[i] = to_lower_case(copy.str[i]); + } + return copy; +} + +function String +string_to_upper_case(Allocator *arena, String s) { + String copy = string_copy(arena, s); + for (U64 i = 0; i < copy.len; i++) { + copy.str[i] = to_upper_case(copy.str[i]); + } + return copy; +} + +typedef U64 MatchFlag; +enum { + MatchFlag_None=0, + MatchFlag_FindLast=1, + MatchFlag_IgnoreCase=2, +}; + +function B32 +string_find(String string, String find, MatchFlag flags, S64 *index_out) { + B32 result = false; + if (flags & MatchFlag_FindLast) { + for (S64 i = string.len; i != 0; i--) { + S64 index = i - 1; + String substring = string_slice(string, index, index + find.len); + if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { + if (index_out) + *index_out = index; + result = true; + break; + } + } + } + else { + for (S64 i = 0; i < string.len; i++) { + String substring = string_slice(string, i, i + find.len); + if (string_compare(substring, find, flags & MatchFlag_IgnoreCase)) { + if (index_out) + *index_out = i; + result = true; + break; + } + } + } + + return result; +} + +function String +string_chop_last_slash(String s) { + String result = s; + string_find(s, "/"_s, MatchFlag_FindLast, &result.len); + return result; +} + +function String +string_chop_last_period(String s) { + String result = s; + string_find(s, "."_s, MatchFlag_FindLast, &result.len); + return result; +} + +function String +string_skip_to_last_slash(String s) { + S64 pos; + String result = s; + if (string_find(s, "/"_s, MatchFlag_FindLast, &pos)) { + result = string_skip(result, pos + 1); + } + return result; +} + +function String +string_skip_to_last_period(String s) { + S64 pos; + String result = s; + if (string_find(s, "."_s, MatchFlag_FindLast, &pos)) { + result = string_skip(result, pos + 1); + } + return result; +} + +#if 0 +function void +test_stb_sprintf(){ + char buff[1024]; + const char *asd = "adfag"; + int len = snprintf(buff, 1024, "Thing %s", asd); + assert(string_make(buff,len) == "Thing adfag"_s); + + String thing = "Thing12312412412412412"_s; + thing.len = 5; + len = snprintf(buff, 1024, "%Q %Q", thing, string_make(thing.str + 5, 5)); + __debugbreak(); +} +#endif \ No newline at end of file diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..8ae189f --- /dev/null +++ b/build.bat @@ -0,0 +1,4 @@ +@echo off + + +clang main.cpp -Wall -Wno-unused-function -Wno-missing-braces -fno-exceptions -fdiagnostics-absolute-paths -g -I"C:/base" -I".." -o main.exe -Wl,user32.lib \ No newline at end of file diff --git a/kpl_multimedia.cpp b/kpl_multimedia.cpp new file mode 100644 index 0000000..5e7b366 --- /dev/null +++ b/kpl_multimedia.cpp @@ -0,0 +1,899 @@ +#include +#include +#include +#include + +#pragma comment(linker, "/subsystem:windows") +#pragma comment(lib, "gdi32.lib") +#pragma comment(lib, "Shcore.lib") +#pragma comment(lib, "opengl32.lib") + +// Symbols taken from GLFW +// +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on Nvidia Optimus systems +// with up-to-date drivers +// +__declspec(dllexport) DWORD NvOptimusEnablement = 1; + +// Executables (but not DLLs) exporting this symbol with this value will be +// automatically directed to the high-performance GPU on AMD PowerXpress systems +// with up-to-date drivers +// +__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + + + +OS os; +#include "math.h" + +typedef HRESULT tSetProcessDpiAwareness(PROCESS_DPI_AWARENESS); +typedef MMRESULT TimeBeginPeriod(MMRESULT); +constexpr DWORD window_style_simplified = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU; +constexpr DWORD window_style_resizable = WS_OVERLAPPEDWINDOW; +constexpr DWORD window_style_borderless = WS_POPUP; + +struct Win32Bitmap { + Bitmap bitmap; + HDC dc; + HBITMAP dib; +}; + +struct Win32FontCtx { + HFONT font; + Win32Bitmap bitmap; + TEXTMETRIC text_metric; + Font result; +}; + +struct OS_Win32 { + HWND window; + HDC window_dc; + Win32Bitmap screen; + HINSTANCE instance; + int show_cmd; + char *cmd_line; + bool good_scheduling; + void *main_fiber; + void *msg_fiber; + U8 text_buff[32]; + Vec2I prev_window_size; + Vec2I prev_mouse_pos; +}; +static_assert(sizeof(OS_Win32) < 256, "Too big"); +#define w32(a) (*(OS_Win32 *)(a).platform) + +api Bitmap bitmap(U32 *pixels, Vec2I size, Vec2 align_in_pixels = {}) { + Bitmap result; + result.pixels = pixels; + result.size = size; + result.align = align_in_pixels; + return result; +} + +function Win32Bitmap win32_create_bitmap(Vec2I size) { + Win32Bitmap result; + result.bitmap.size = size; + if (result.bitmap.size.y < 0) + result.bitmap.size.y = -result.bitmap.size.y; + + HDC hdc = GetDC(0); + BITMAPINFO bminfo = {}; + bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader); + bminfo.bmiHeader.biWidth = (LONG)size.x; + bminfo.bmiHeader.biHeight = (LONG)-size.y; + bminfo.bmiHeader.biPlanes = 1; + bminfo.bmiHeader.biBitCount = 32; + bminfo.bmiHeader.biCompression = BI_RGB; // AA RR GG BB + bminfo.bmiHeader.biXPelsPerMeter = 1; + bminfo.bmiHeader.biYPelsPerMeter = 1; + + void *mem = 0; + result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (void **)&mem, 0, 0); + assert_msg(mem != 0, "Failed to create win32 bitmap"); + result.dc = CreateCompatibleDC(hdc); + result.bitmap.pixels = (U32 *)mem; + return result; +} + +function void win32_destroy_bitmap(Win32Bitmap *b) { + if (b->bitmap.pixels) { + b->bitmap.pixels = 0; + DeleteDC(b->dc); + DeleteObject(b->dib); + } +} + +function LRESULT +CALLBACK win32_window_proc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) { + EventKind kind = EventKind_None; + Key key = Key_None; + LRESULT result = 0; + switch (uMsg) { + case WM_CLOSE: + DestroyWindow(window); + os.quit = 1; + break; + case WM_DESTROY: + PostQuitMessage(0); + os.quit = 1; + break; + case WM_SYSKEYDOWN: + case WM_KEYDOWN: { + kind = EventKind_KeyDown; + switch (wParam) { + +#define X(button, win) \ +case win: \ +key = Key_##button; \ +break; + + KEY_MAPPING + } + } break; + case WM_SYSKEYUP: + case WM_KEYUP: { + kind = EventKind_KeyUp; + switch (wParam) { + KEY_MAPPING +#undef X + } + } break; + case WM_TIMER: { + SwitchToFiber(w32(os).main_fiber); + } break; + case WM_ENTERMENULOOP: + case WM_ENTERSIZEMOVE: { + SetTimer(w32(os).window, 0, 1, 0); + } break; + case WM_EXITMENULOOP: + case WM_EXITSIZEMOVE: { + KillTimer(w32(os).window, 0); + } break; + case WM_MOUSEMOVE: { + POINT p; + GetCursorPos(&p); + ScreenToClient(w32(os).window, &p); + os.mouse_pos = vec2i(p.x, p.y); + os.mouse_pos.y = os.window_size.y - os.mouse_pos.y; + kind = EventKind_MouseMove; + } break; + case WM_LBUTTONDOWN: { + kind = EventKind_KeyDown; + key = Key_MouseLeft; + } break; + case WM_LBUTTONUP: { + kind = EventKind_KeyUp; + key = Key_MouseLeft; + } break; + case WM_RBUTTONDOWN: { + kind = EventKind_KeyDown; + key = Key_MouseRight; + } break; + case WM_RBUTTONUP: { + kind = EventKind_KeyUp; + key = Key_MouseRight; + } break; + case WM_MBUTTONDOWN: { + kind = EventKind_KeyDown; + key = Key_MouseMiddle; + } break; + case WM_MBUTTONUP: { + kind = EventKind_KeyUp; + key = Key_MouseMiddle; + } break; + case WM_MOUSEWHEEL: { + if ((int)wParam > 0) + os.mouse_wheel = 1; + else + os.mouse_wheel = -1; + kind = EventKind_MouseWheel; + } break; + case WM_CHAR: { + // @Todo: Can this overflow? + //kind = EventKind_KeyboardText; + //U32 codepoint = '?'; + //utf16_to_utf32((U16 *)&wParam, &codepoint); + //os.text.len += utf32_to_utf8(codepoint, w32(os).text_buff + os.text.len); + } break; + default: + result = DefWindowProcW(window, uMsg, wParam, lParam); + break; + } + + if (kind) { + if (kind == EventKind_KeyDown) { + if (os.key[key].down == 0) + os.key[key].pressed = 1; + os.key[key].down = 1; + } else if (kind == EventKind_KeyUp) { + os.key[key].released = 1; + os.key[key].down = 0; + } + } + + return result; +} + +function void +CALLBACK _os_fiber_event_proc(void *data) { + unused(data); + for (;;) { + MSG msg; + while (PeekMessageW(&msg, w32(os).window, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + SwitchToFiber(w32(os).main_fiber); + } +} + +function Vec2I +get_window_size(HWND window) { + Vec2I result; + RECT window_rect; + GetClientRect(window, &window_rect); + result.x = window_rect.right - window_rect.left; + result.y = window_rect.bottom - window_rect.top; + return result; +} + +function Vec2I +get_window_size_with_border(HWND window) { + RECT ClientRect; + GetWindowRect(window, &ClientRect); + Vec2I draw_area; + draw_area.x = (ClientRect.right - ClientRect.left); + draw_area.y = (ClientRect.bottom - ClientRect.top); + return draw_area; +} + +function Vec2I +get_border_size(HWND window) { + Vec2I client = get_window_size(window); + Vec2I wind_size = get_window_size_with_border(window); + Vec2I result = vec2i(wind_size.x - client.x, wind_size.y - client.y); + return result; +} + +api void os_quit() { os.quit = 1; } +api void os_set_fps(F64 fps) { os.ms_per_frame = 1 / fps; } +api void os_set_ms_per_frame(F64 ms) { os.ms_per_frame = ms; } + +api void os_show_cursor(B32 status) { + ShowCursor(status); + os.cursor_visible = status; +} + +api void os_set_window_title(String title) { + Scratch scratch; + BOOL result = SetWindowTextA(w32(os).window, (char *)title.str); + assert_msg(result != 0, "Failed to set window title"); + os.window_title = title; +} + +api void os_set_window_size(S32 x, S32 y) { + Vec2I border = get_border_size(w32(os).window); + int actual_width = (int)(x + border.x); + int actual_height = (int)(y + border.y); + bool result = + SetWindowPos(w32(os).window, 0, 0, 0, actual_width, actual_height, SWP_NOMOVE | SWP_NOOWNERZORDER); + assert_msg(result, "SetWindowPos returned invalid value"); + os.window_size = get_window_size(w32(os).window); +} + +api void os_pull_state() { + os.window_was_resized = false; + os.window_size = get_window_size(w32(os).window); + if (os.window_size != w32(os).prev_window_size) { + os.window_was_resized = true; + w32(os).prev_window_size = os.window_size; + } + os.monitor_size = vec2i(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); + + // @Note: Client relative + POINT point = {0, 0}; + ClientToScreen(w32(os).window, &point); + os.window_pos.x = point.x; + os.window_pos.y = point.y; + + // @Note: Get DPI scale + UINT dpi = GetDpiForWindow(w32(os).window); + assert_msg(dpi != 0, "Failed to get dpi for window"); + os.dpi_scale = (F32)dpi / 96.f; + + // @Note: Reset text + os.text.len = 0; + // @Note: Reset keys + for (int i = 0; i < Key_Count; i++) { + os.key[i].released = 0; + os.key[i].pressed = 0; + } + os.mouse_wheel = 0; + SwitchToFiber(w32(os).msg_fiber); + if (!os.quit) { + os.delta_mouse_pos = w32(os).prev_mouse_pos - os.mouse_pos; + w32(os).prev_mouse_pos = os.mouse_pos; + + // @Note: Resize + if (os.render_backend == RenderBackend_Software) { + if (os.window_size != w32(os).screen.bitmap.size && os.window_size.x != 0 && os.window_size.y != 0) { + win32_destroy_bitmap(&w32(os).screen); + w32(os).screen = win32_create_bitmap(vec2i(os.window_size.x, -(os.window_size.y))); + os.screen = &w32(os).screen.bitmap; + } + } + } +} + +api void os_init_software_render() { os.render_backend = RenderBackend_Software; } + +api B32 os_init_opengl() { + PIXELFORMATDESCRIPTOR p = {}; + p.nSize = sizeof(p); + p.nVersion = 1; + p.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + p.iPixelType = PFD_TYPE_RGBA; + p.cColorBits = 32; + p.cDepthBits = 24; + p.cStencilBits = 8; + p.iLayerType = PFD_MAIN_PLANE; + + S32 pixel_format = ChoosePixelFormat(w32(os).window_dc, &p); + if (pixel_format != 0) { + if (SetPixelFormat(w32(os).window_dc, pixel_format, &p)) { + HGLRC gl_ctx = wglCreateContext(w32(os).window_dc); + if (gl_ctx != NULL) { + if (wglMakeCurrent(w32(os).window_dc, gl_ctx)) { + // Success + } + else { + log_error("Failed on wglMakeCurrent!"); + return false; + } + } + else { + log_error("Failed on wglCreateContext!"); + return false; + } + } + else { + log_error("Failed on SetPixelFormat!"); + return false; + } + } + else { + log_error("Failed on ChoosePixelFormat!"); + return false; + } + + os.opengl.vendor = (char *)glGetString(GL_VENDOR); + os.opengl.renderer = (char *)glGetString(GL_RENDERER); + os.opengl.version = (char *)glGetString(GL_VERSION); + os.opengl.extensions = (char *)glGetString(GL_EXTENSIONS); + os.render_backend = RenderBackend_OpenGL1; + + return true; +} + +global S64 Global_counts_per_second; +api F64 os_time() { + if (Global_counts_per_second == 0) { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + Global_counts_per_second = freq.QuadPart; + } + + LARGE_INTEGER time; + QueryPerformanceCounter(&time); + F64 result = (F64)time.QuadPart / (F64)Global_counts_per_second; + return result; +} + +api B32 os_init() { + HMODULE shcore = LoadLibraryA("Shcore.dll"); + if (shcore) { + tSetProcessDpiAwareness *set_dpi_awr = + (tSetProcessDpiAwareness *)GetProcAddress(shcore, "SetProcessDpiAwareness"); + if (set_dpi_awr) { + HRESULT hr = set_dpi_awr(PROCESS_PER_MONITOR_DPI_AWARE); + assert_msg(SUCCEEDED(hr), "Failed to set dpi awareness"); + } + } + + HMODULE winmm = LoadLibraryA("winmm.dll"); + if (winmm) { + TimeBeginPeriod *timeBeginPeriod = (TimeBeginPeriod *)GetProcAddress(winmm, "timeBeginPeriod"); + if (timeBeginPeriod) { + if (timeBeginPeriod(1) == TIMERR_NOERROR) { + w32(os).good_scheduling = true; + } + } + } + + DWORD window_style_chosen = window_style_resizable; + if (!os.window_resizable) + window_style_chosen = window_style_simplified; + + os.app_start_time = os_time(); + os.frame_start_time = os.app_start_time; + os.update_begin_cycles = __rdtsc(); + + WNDCLASSW wc = {}; // @Todo(Krzosa): UTF + wc.lpfnWndProc = win32_window_proc; + wc.hInstance = w32(os).instance; + // @Todo(Krzosa): UTF conversions + wc.lpszClassName = L"Have a good day"; // @Todo(Krzosa): Cant set window title + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; + if (!RegisterClassW(&wc)) { // @Todo(Krzosa): UTF + log_error("Failed to create window class!"); + return false; + } + + RECT window_rect; + window_rect.left = (LONG)os.window_pos.x; + window_rect.top = (LONG)os.window_pos.y; + window_rect.right = (LONG)os.window_size.x + window_rect.left; + window_rect.bottom = (LONG)os.window_size.y + window_rect.top; + AdjustWindowRectEx(&window_rect, window_style_chosen, false, 0); + + // @Todo(Krzosa): UTF + w32(os).window = CreateWindowW(wc.lpszClassName, wc.lpszClassName, window_style_chosen, window_rect.left, window_rect.top, window_rect.right - window_rect.left,window_rect.bottom - window_rect.top, NULL, NULL, w32(os).instance, NULL); + if (w32(os).window == 0) { + log_error("Failed to create window!"); + return false; + } + + ShowWindow(w32(os).window, w32(os).show_cmd); + UpdateWindow(w32(os).window); + w32(os).window_dc = GetDC(w32(os).window); + + w32(os).main_fiber = ConvertThreadToFiber(0); + assert_msg(w32(os).main_fiber, "Failed to create main fiber"); + w32(os).msg_fiber = CreateFiber(0, _os_fiber_event_proc, 0); + assert_msg(w32(os).msg_fiber, "Failed to create message fiber"); + + if (os.cursor_visible == false) + os_show_cursor(false); + + switch (os.render_backend) { + case RenderBackend_Software: { + os_init_software_render(); + } break; + case RenderBackend_OpenGL1: { + os_init_opengl(); + } break; + default: assert_msg(0, "Invalid value for render backend"); + break; + } + + os_pull_state(); + os.initialized = true; + return true; +} + +api bool os_game_loop() { + assert_msg(os.initialized, "Platform is not initialized! Please call os_init"); + switch (os.render_backend) { + case RenderBackend_Software: { + if (os.screen) { // @Note: Draw screen + U32 *p = os.screen->pixels; + for (int y = 0; y < os.screen->y; y++) { + for (int x = 0; x < os.screen->x; x++) { + *p = ((*p & 0xff000000)) | ((*p & 0x00ff0000) >> 16) | ((*p & 0x0000ff00)) | + ((*p & 0x000000ff) << 16); + p += 1; + } + } + + HDC hdc = w32(os).window_dc; + SelectObject(w32(os).screen.dc, w32(os).screen.dib); + BitBlt(hdc, 0, 0, (LONG)os.screen->size.x, (LONG)os.screen->size.y, w32(os).screen.dc, 0, 0, SRCCOPY); + } + } break; + case RenderBackend_OpenGL1: { + SwapBuffers(w32(os).window_dc); + } break; + default: + assert_msg(0, "Please select a rendering backend!"); + break; + } + arena_clear(os.frame_arena); + os.update_time = os_time() - os.frame_start_time; + os.update_end_cycles = __rdtsc(); + F64 frame_time = os.update_time; + F64 ms_per_frame = os.ms_per_frame; + if (frame_time < ms_per_frame) { + if (w32(os).good_scheduling) { + // @Todo: I have no idea if letting over sleep is bad or not + // Busy waiting is chugging cpu alot more, not sure what to do + F64 time_to_sleep = (ms_per_frame - frame_time) * 1000; + if (time_to_sleep > 0) { + Sleep((DWORD)time_to_sleep); + } + } + + do { + frame_time = os_time() - os.frame_start_time; + } while (frame_time < ms_per_frame); + } + os.frame++; + os.delta_time = frame_time; + os.fps = 1 / os.delta_time; + os.time += os.delta_time; + os.frame_start_time = os_time(); + os.update_begin_cycles = __rdtsc(); + os_pull_state(); + return !os.quit; +} + +int main(int argc, char **argv); +int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmd_line, int show_cmd) { + thread_ctx_init(); + w32(os).instance = instance; + w32(os).show_cmd = show_cmd; + w32(os).cmd_line = cmd_line; + + Arena frame_arena = {}; + arena_init(&frame_arena, "Frame arena"_s); + os.perm_arena = &pernament_arena; + os.frame_arena = &frame_arena; + + os.dpi_scale = 1; + os.text.str = w32(os).text_buff; + os.window_title = "Have a good day!"_s; + os.window_pos.x = 0; + os.window_pos.y = 50; + os.window_size.x = 1280; + os.window_size.y = 720; + os.ms_per_frame = 1.f / 60.f; + os.cursor_visible = true; + + if(AttachConsole(-1)) { + freopen("CONIN$", "r",stdin); + freopen("CONOUT$", "w",stdout); + freopen("CONOUT$", "w",stderr); + } + + return main(__argc, __argv); +} + +////////////// +// @Note: Font API +function FontGlyph extract_glyph(Allocator *arena, Win32FontCtx *ctx, wchar_t glyph) { + SIZE size; + GetTextExtentPoint32W(ctx->bitmap.dc, &glyph, 1, &size); + TextOutW(ctx->bitmap.dc, 0, 0, &glyph, 1); + + // @Note: Find bitmap edges + int minx = 100000; + int miny = 100000; + int maxx = -100000; + int maxy = -100000; + for (int y = 499; y >= 500 - size.cy; y--) { + for (int x = 0; x < size.cx; x++) { + if (ctx->bitmap.bitmap.pixels[x + y * (int)ctx->bitmap.bitmap.size.x] != 0) { + if (minx > x) + minx = x; + if (miny > y) + miny = y; + if (maxx < x) + maxx = x; + if (maxy < y) + maxy = y; + } + } + } + + assert(minx >= 0 && miny >= 0); + int bwidth = maxx - minx + 1; + int bheight = maxy - miny + 1; + U32 *cropped = + (U32 *)exp_alloc(arena, sizeof(U32) * (U32)(bwidth) * (U32)(bheight)); + for (int y = miny; y <= maxy; y++) { + for (int x = minx; x <= maxx; x++) { + U32 value = ctx->bitmap.bitmap.pixels[x + y * (int)ctx->bitmap.bitmap.size.x]; + U32 *dst = cropped + ((size_t)(x - minx) + (size_t)(y - miny) * bwidth); +#if 1 // Premultiplied alpha + F32 alpha = (F32)((value & 0x000000ff) >> 0); + F32 rgb = (F32)0xff*(alpha/255.f); + U8 val = (U8)(rgb + 0.5f); + *dst = (((U32)(alpha+0.5f) << 24) | val << 16 | val << 8 | val); +#else + U8 grey = (value & 0x000000ff); + *dst = (grey << 24 | 0xff << 16 | 0xff << 8 | 0xff); +#endif + } + } + exp_alloc(arena, sizeof(U32) * (U32)bwidth); + + // @Note: Calculate char metrics + int glyph_descent = (499 - size.cy) - miny; + + FontGlyph result; + INT width; + GetCharWidth32W(ctx->bitmap.dc, glyph, glyph, &width); + result.xadvance = (F32)width; + result.bitmap = bitmap(cropped, vec2i(bwidth, bheight), + vec2((F32)-minx, (F32)ctx->text_metric.tmDescent + (F32)glyph_descent)); + return result; +} + +function Win32FontCtx begin_font_extraction(char *filename, char *font_name, S64 height) { + assert_msg(height < 500, "Height of font over 500"); + Win32FontCtx ctx = {}; + if (filename) { + int fonts_added = AddFontResourceExA(filename, FR_PRIVATE, 0); + assert_msg(fonts_added != 0, "AddFontResourceEx added 0 fonts"); + } + + ctx.bitmap = win32_create_bitmap(vec2i(500, -500)); + ctx.font = + CreateFontA((S32)height, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE, font_name); + assert_msg(ctx.font != NULL, "CreateFont returned a 0 pointer"); + SelectObject(ctx.bitmap.dc, ctx.bitmap.dib); + SelectObject(ctx.bitmap.dc, ctx.font); + GetTextMetrics(ctx.bitmap.dc, &ctx.text_metric); + ctx.result.height = (F32)height; + ctx.result.descent = (F32)ctx.text_metric.tmDescent; + ctx.result.ascent = (F32)ctx.text_metric.tmAscent; + ctx.result.line_advance = (F32)(height + ctx.text_metric.tmExternalLeading); + SetBkColor(ctx.bitmap.dc, RGB(0, 0, 0)); + SetTextColor(ctx.bitmap.dc, RGB(255, 255, 255)); + return ctx; +} + +function Font end_font_extraction(Win32FontCtx *ctx) { + win32_destroy_bitmap(&ctx->bitmap); + DeleteObject(ctx->font); + return ctx->result; +} + +api Font os_load_font(Allocator *arena, S32 height, const char *font_name, const char *filename) { + FontGlyph *glyphs = exp_alloc_array(arena, FontGlyph, 96, AF_ZeroMemory); + Win32FontCtx font_ctx = begin_font_extraction((char *)filename, (char *)font_name, height); + for (U32 i = '!'; i <= '~'; i++) { + glyphs[i - '!'] = extract_glyph(arena, &font_ctx, (wchar_t)i); + } + Font font = end_font_extraction(&font_ctx); + font.glyphs = glyphs; + font.glyphs_len = '~' - '!'; + return font; +} + +function void set_window_style(HWND window, DWORD style) { + // @Todo: Need to readup on this + SetWindowLongPtrW(window, GWL_STYLE, style); + SetWindowPos(window, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); + ShowWindow(window, SW_SHOW); +} + +#undef w32 +/////////////////////////////////////// +// @Section Audio +#include +#include +#include +#include + +const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator); +const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator); +const IID IID_IAudioClient = __uuidof(IAudioClient); +const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient); + +// NOTE: typedefines for the functions which are goint to be loaded +typedef HRESULT CoCreateInstanceFunction(REFCLSID rclsid, LPUNKNOWN *pUnkOuter, DWORD dwClsContext, + REFIID riid, LPVOID *ppv); +typedef HRESULT CoInitializeExFunction(LPVOID pvReserved, DWORD dwCoInit); + +// NOTE: empty functions(stubs) which are used when library fails to load +HRESULT CoCreateInstanceStub(REFCLSID rclsid, LPUNKNOWN *pUnkOuter, DWORD dwClsContext, REFIID riid, + LPVOID *ppv) { + unused(rclsid); + unused(pUnkOuter); + unused(dwClsContext); + unused(riid); + unused(ppv); + return S_FALSE; +} + +HRESULT CoInitializeExStub(LPVOID pvReserved, DWORD dwCoInit) { + unused(pvReserved); + unused(dwCoInit); + return S_FALSE; +} + +// NOTE: pointers to the functions from the dll +CoCreateInstanceFunction *CoCreateInstanceFunctionPointer = CoCreateInstanceStub; +CoInitializeExFunction *CoInitializeExFunctionPointer = CoInitializeExStub; + +// NOTE: Number of REFERENCE_TIME units per second +// One unit is equal to 100 nano seconds +#define REF_TIMES_PER_SECOND 10000000 +#define REF_TIMES_PER_MSECOND 10000 +#define w32(a) (*(Audio_Win32 *)(a)->platform) + +struct Audio_Win32 { + IMMDevice *device; + IAudioClient *audio_client; + + IMMDeviceEnumerator *device_enum; + IAudioRenderClient *audio_render_client; + IAudioCaptureClient *audio_capture_client; +}; +static_assert(sizeof(Audio::platform) > sizeof(Audio_Win32), + "Audio::platform is too small to hold Audio_Win32 struct"); + +// Load COM Library functions dynamically, +// this way sound is not necessary to run the game +function B32 win32_load_com() { + B32 result = true; + HMODULE ole32Library = LoadLibraryA("ole32.dll"); + if (ole32Library) { + CoCreateInstanceFunctionPointer = + (CoCreateInstanceFunction *)GetProcAddress(ole32Library, "CoCreateInstance"); + if (!CoCreateInstanceFunctionPointer) { + CoCreateInstanceFunctionPointer = CoCreateInstanceStub; + log_error("CoCreateInstance failed to load"); + result = false; + } + CoInitializeExFunctionPointer = (CoInitializeExFunction *)GetProcAddress(ole32Library, "CoInitializeEx"); + if (!CoInitializeExFunctionPointer) { + CoInitializeExFunctionPointer = CoInitializeExStub; + log_error("CoInitializeEx failed to load"); + result = false; + } + } else { + CoCreateInstanceFunctionPointer = CoCreateInstanceStub; + CoInitializeExFunctionPointer = CoInitializeExStub; + log_error("Failed to load OLE32.dll"); + result = false; + } + return result; +} + +api void os_clean_audio(Audio *audio) { + if (w32(audio).audio_client) + w32(audio).audio_client->Stop(); + if (w32(audio).device_enum) + w32(audio).device_enum->Release(); + if (w32(audio).device) + w32(audio).device->Release(); + if (w32(audio).audio_client) + w32(audio).audio_client->Release(); + if (w32(audio).audio_render_client) + w32(audio).audio_render_client->Release(); + audio->initialized = false; +} + +function DWORD win32_audio_thread(void *parameter) { + Audio *audio = (Audio *)parameter; + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + HANDLE buffer_ready_event = CreateEvent(0, 0, 0, 0); + if (!buffer_ready_event) { + return -1; + } + if (FAILED(w32(audio).audio_client->SetEventHandle(buffer_ready_event))) { + return -1; + } + U32 buffer_frame_count; + if (FAILED(w32(audio).audio_client->GetBufferSize(&buffer_frame_count))) { + return -1; + } + // U32 buffer_sample_count = buffer_frame_count * audio->number_of_channels; + if (FAILED(w32(audio).audio_client->Start())) { + w32(audio).audio_client->Stop(); + return -1; + } + for (;;) { + if (WaitForSingleObject(buffer_ready_event, INFINITE) != WAIT_OBJECT_0) { + w32(audio).audio_client->Stop(); + return -1; + } + U32 padding_frame_count; + if (FAILED(w32(audio).audio_client->GetCurrentPadding(&padding_frame_count))) { + w32(audio).audio_client->Stop(); + return -1; + } + U32 *samples; + U32 fill_frame_count = buffer_frame_count - padding_frame_count; + if (FAILED(w32(audio).audio_render_client->GetBuffer(fill_frame_count, (BYTE **)&samples))) { + w32(audio).audio_client->Stop(); + return -1; + } + audio->callback(audio, samples, fill_frame_count); + if (FAILED(w32(audio).audio_render_client->ReleaseBuffer(fill_frame_count, 0))) { + w32(audio).audio_client->Stop(); + return -1; + } + } + return 0; +} + +function AUDIO_CALLBACK(default_audio_callback) { + memory_zero(buffer, (U64)frames_to_fill * (U64)audio->samples_per_second); +} + +api B32 os_init_audio(Audio *audio) { + audio->bits_per_sample = 16; + if (audio->number_of_channels == 0) + audio->number_of_channels = 2; + if (audio->samples_per_second == 0) + audio->samples_per_second = 44100; + if (audio->callback == 0) + audio->callback = default_audio_callback; + + B32 success = win32_load_com(); + if (!success) { + return false; + } + if (FAILED(CoInitializeExFunctionPointer(0, COINITBASE_MULTITHREADED))) { + log_error("Failed to initialize COM, CoInitializeEx"); + return false; + } + if (FAILED(CoCreateInstanceFunctionPointer(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, + IID_IMMDeviceEnumerator, (LPVOID *)&w32(audio).device_enum))) { + log_error("Failed to initialize COM, CoCreateInstance"); + return false; + } + if (FAILED(w32(audio).device_enum->GetDefaultAudioEndpoint(eRender, eConsole, &w32(audio).device))) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, GetDefaultAudioEndpoint"); + return false; + } + if (FAILED( + w32(audio).device->Activate(IID_IAudioClient, CLSCTX_ALL, 0, (void **)&w32(audio).audio_client))) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, " + "w32(audio).device->Activate(IID_IAudioClient,"); + return false; + } + + WAVEFORMATEX waveFormat = {}; + waveFormat.wFormatTag = WAVE_FORMAT_PCM; + waveFormat.nChannels = audio->number_of_channels; + waveFormat.nSamplesPerSec = audio->samples_per_second; + waveFormat.wBitsPerSample = audio->bits_per_sample; + waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; + waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; + REFERENCE_TIME requestedBufferDuration = REF_TIMES_PER_MSECOND * 40; + if (FAILED(w32(audio).audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, + AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_RATEADJUST | + AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY, + requestedBufferDuration, 0, &waveFormat, 0))) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, w32(audio).audio_client->Initialize"); + return false; + } + if (FAILED(w32(audio).audio_client->GetService(IID_IAudioRenderClient, + (void **)&w32(audio).audio_render_client))) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, " + "w32(audio).audio_client->GetService(IID_IAudioRenderClient"); + return false; + } + if (FAILED(w32(audio).audio_client->GetBufferSize(&audio->buffer_frame_count))) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, w32(audio).audio_client->GetBufferSize"); + return false; + } + HANDLE thread_handle = CreateThread(0, 0, win32_audio_thread, audio, 0, 0); + if (!thread_handle) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, CreateThread returned 0 in handle"); + return false; + } + if (thread_handle == INVALID_HANDLE_VALUE) { + os_clean_audio(audio); + log_error("Failed to initialize WASAPI, CreateThread for " + "audio failed with INVALID HANDLE VALUE"); + return false; + } + CloseHandle(thread_handle); + audio->initialized = true; +#undef w32 + return true; +} + diff --git a/kpl_multimedia.h b/kpl_multimedia.h new file mode 100644 index 0000000..8871774 --- /dev/null +++ b/kpl_multimedia.h @@ -0,0 +1,230 @@ +#pragma once + +struct Bitmap { + union { + U32 *pixels; + U64 id; + }; + union { + Vec2I size; + struct { + S32 x, y; + }; + }; + Vec2 align; +}; + +enum EventKind { + EventKind_None, + EventKind_KeyDown, + EventKind_KeyUp, + EventKind_MouseMove, + EventKind_MouseWheel, + EventKind_KeyboardText, +}; + +enum Key { + Key_None, + Key_Up, + Key_Down, + Key_Left, + Key_Right, + Key_Escape, + Key_F1, + Key_F2, + Key_F3, + Key_F4, + Key_F5, + Key_F6, + Key_F7, + Key_F8, + Key_F9, + Key_F10, + Key_F11, + Key_F12, + Key_MouseLeft, + Key_MouseRight, + Key_MouseMiddle, + Key_0 = '0', + Key_1, + Key_2, + Key_3, + Key_4, + Key_5, + Key_6, + Key_7, + Key_8, + Key_9 = '9', + Key_A = 'a', + Key_B, + Key_C, + Key_D, + Key_E, + Key_F, + Key_G, + Key_H, + Key_I, + Key_J, + Key_K, + Key_L, + Key_M, + Key_N, + Key_O, + Key_P, + Key_Q, + Key_R, + Key_S, + Key_T, + Key_U, + Key_V, + Key_W, + Key_X, + Key_Y, + Key_Z = 'z', + Key_Count = 256, +}; + +#define KEY_MAPPING \ +X(Up, VK_UP) \ +X(Down, VK_DOWN) \ +X(Left, VK_LEFT) \ +X(Right, VK_RIGHT) \ +X(Escape, VK_ESCAPE) \ +X(F1, VK_F1) \ +X(F2, VK_F2) \ +X(F3, VK_F3) \ +X(F4, VK_F4) \ +X(F5, VK_F5) \ +X(F6, VK_F6) \ +X(F7, VK_F7) \ +X(F8, VK_F8) \ +X(F9, VK_F9) \ +X(F10, VK_F10) \ +X(F11, VK_F11) \ +X(F12, VK_F12) \ +X(A, 65) \ +X(B, 66) \ +X(C, 67) \ +X(D, 68) \ +X(E, 69) \ +X(F, 70) \ +X(G, 71) \ +X(H, 72) \ +X(I, 73) \ +X(J, 74) \ +X(K, 75) \ +X(L, 76) \ +X(M, 77) \ +X(N, 78) \ +X(O, 79) \ +X(P, 80) \ +X(Q, 81) \ +X(R, 82) \ +X(S, 83) \ +X(T, 84) \ +X(U, 85) \ +X(V, 86) \ +X(W, 87) \ +X(X, 88) \ +X(Y, 89) \ +X(Z, 90) \ +X(0, 48) \ +X(1, 49) \ +X(2, 50) \ +X(3, 51) \ +X(4, 52) \ +X(5, 53) \ +X(6, 54) \ +X(7, 55) \ +X(8, 56) \ +X(9, 57) + +struct DigitalKey { + bool pressed; + bool down; + bool released; +}; + +enum RenderBackend { + RenderBackend_Software, + RenderBackend_OpenGL1, +}; + +struct OS { + bool quit; + bool initialized; + Arena *frame_arena; + Arena *perm_arena; + + F64 ms_per_frame; + bool window_resizable; + bool window_was_resized; + String window_title; + Vec2I window_size; + Vec2I window_pos; + RenderBackend render_backend; + + Bitmap *screen; + Vec2I monitor_size; + F32 dpi_scale; + + F64 fps; + F64 delta_time; + F64 time; + U64 frame; + F64 update_time; + U64 update_begin_cycles; + U64 update_end_cycles; + F64 frame_start_time; + F64 app_start_time; + + B32 cursor_visible; + DigitalKey key[Key_Count]; + F32 mouse_wheel; + Vec2I mouse_pos; + Vec2I delta_mouse_pos; + + String text; + + char platform[256]; + struct { + char *vendor; + char *version; + char *renderer; + char *extensions; + } opengl; +}; + +struct FontGlyph { + F32 xadvance; + U32 codepoint; + Bitmap bitmap; +}; + +struct Font { + F32 line_advance; + F32 ascent; + F32 descent; + F32 height; + FontGlyph *glyphs; + U32 glyphs_len; +}; + +struct Audio; +#define AUDIO_CALLBACK(name) void name(Audio *audio, U32* buffer, U32 frames_to_fill) +typedef AUDIO_CALLBACK(AudioCallback); + +struct Audio { + AudioCallback *callback; + B32 initialized; + U32 samples_per_second; + U32 number_of_channels; + + // NOTE: one frame is 2 samples (left, right) 32 bits if + // one sample is equal 16 bit + U32 buffer_frame_count; + U32 latency_frame_count; + S32 bits_per_sample; + + char platform[128]; +}; diff --git a/main.cpp b/main.cpp index b3d0c01..4d89cc0 100644 --- a/main.cpp +++ b/main.cpp @@ -25,6 +25,8 @@ /// - [x] FPS Camera /// - [ ] Quarternions for rotations /// - [x] Reading OBJ models +/// - [x] Dumping raw obj files +/// - [x] Loading raw obj files, big startup speedup! /// - [ ] Reading more OBJ formats /// - [x] Reading OBJ .mtl files /// - [x] Loading materials @@ -77,13 +79,10 @@ /// /// - - -#define _CRT_SECURE_NO_WARNINGS - #define PREMULTIPLIED_ALPHA_BLENDING 1 - -#define PLATFORM -#include "kpl.h" +#define PREMULTIPLIED_ALPHA_BLENDING 1 +#include "base.cpp" +#include "kpl_multimedia.h" +#include "kpl_multimedia.cpp" #include "profile.cpp" #include "math.h" @@ -110,9 +109,9 @@ struct R_Render { F32 *depth320; }; +#define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include "obj_parser.cpp" -#include enum Scene { Scene_F22, @@ -120,24 +119,22 @@ enum Scene { Scene_Count, }; +global F32 light_rotation = 0; +global F32 zfar_value = 100000.f; -GLOBAL F32 light_rotation = 0; -GLOBAL F32 zfar_value = 100000.f; - - -FUNCTION +function Vec4 srgb_to_almost_linear(Vec4 a) { Vec4 result = {a.r*a.r, a.g*a.g, a.b*a.b, a.a}; return result; // @Note: Linear would be to power of 2.2 } -FUNCTION +function Vec4 almost_linear_to_srgb(Vec4 a) { Vec4 result = { sqrtf(a.r), sqrtf(a.g), sqrtf(a.b), a.a }; return result; } -FUNCTION +function Vec4 premultiplied_alpha(Vec4 dst, Vec4 src) { Vec4 result; result.r = src.r + ((1-src.a) * dst.r); @@ -147,13 +144,13 @@ Vec4 premultiplied_alpha(Vec4 dst, Vec4 src) { return result; } -FUNCTION +function void r_draw_rect(Bitmap* dst, F32 X, F32 Y, F32 w, F32 h, Vec4 color) { - int max_x = (int)(MIN(X + w, dst->x) + 0.5f); - int max_y = (int)(MIN(Y + h, dst->y) + 0.5f); - int min_x = (int)(MAX(0, X) + 0.5f); - int min_y = (int)(MAX(0, Y) + 0.5f); - + int max_x = (int)(min(X + w, (F32)dst->x) + 0.5f); + int max_y = (int)(min(Y + h, (F32)dst->y) + 0.5f); + int min_x = (int)(max(0.f, X) + 0.5f); + int min_y = (int)(max(0.f, Y) + 0.5f); + color.rgb *= color.a; color = srgb_to_almost_linear(color); for (int y = min_y; y < max_y; y++) { @@ -167,17 +164,17 @@ void r_draw_rect(Bitmap* dst, F32 X, F32 Y, F32 w, F32 h, Vec4 color) { } } -FUNCTION +function void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F32MAX)) { - I64 minx = (I64)(pos.x + 0.5); - I64 miny = (I64)(pos.y + 0.5); + S64 minx = (S64)(pos.x + 0.5); + S64 miny = (S64)(pos.y + 0.5); if (size.x == F32MAX || size.y == F32MAX) { - I64 maxx = minx + src->x; - I64 maxy = miny + src->y; - I64 offsetx = 0; - I64 offsety = 0; - + S64 maxx = minx + src->x; + S64 maxy = miny + src->y; + S64 offsetx = 0; + S64 offsety = 0; + if (maxx > dst->x) { maxx = dst->x; } @@ -192,10 +189,10 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F3 offsety = -miny; miny = 0; } - for (I64 y = miny; y < maxy; y++) { - for (I64 x = minx; x < maxx; x++) { - I64 tx = x - minx + offsetx; - I64 ty = y - miny + offsety; + for (S64 y = miny; y < maxy; y++) { + for (S64 x = minx; x < maxx; x++) { + S64 tx = x - minx + offsetx; + S64 ty = y - miny + offsety; U32 *dst_pixel = dst->pixels + (x + y * dst->x); U32 *pixel = src->pixels + (tx + ty * src->x); Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel)); @@ -208,11 +205,11 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F3 } } else { - I64 maxx = minx + (I64)(size.x + 0.5f); - I64 maxy = miny + (I64)(size.y + 0.5f); - I64 offsetx = 0; - I64 offsety = 0; - + S64 maxx = minx + (S64)(size.x + 0.5f); + S64 maxy = miny + (S64)(size.y + 0.5f); + S64 offsetx = 0; + S64 offsety = 0; + if (maxx > dst->x) { maxx = dst->x; } @@ -229,12 +226,12 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F3 } F32 distx = (F32)(maxx - minx); F32 disty = (F32)(maxy - miny); - for (I64 y = miny; y < maxy; y++) { - for (I64 x = minx; x < maxx; x++) { + for (S64 y = miny; y < maxy; y++) { + for (S64 x = minx; x < maxx; x++) { F32 u = (F32)(x - minx) / distx; F32 v = (F32)(y - miny) / disty; - I64 tx = (I64)(u * src->x + 0.5f); - I64 ty = (I64)(v * src->y + 0.5f); + S64 tx = (S64)(u * src->x + 0.5f); + S64 ty = (S64)(v * src->y + 0.5f); U32 *dst_pixel = dst->pixels + (x + y * dst->x); U32 *pixel = src->pixels + (tx + ty * src->x); Vec4 result_color = srgb_to_almost_linear(vec4abgr(*pixel)); @@ -249,8 +246,8 @@ void r_draw_bitmap(Bitmap* dst, Bitmap* src, Vec2 pos, Vec2 size=vec2(F32MAX, F3 } -FUNCTION -Vec4 r_base_string(Bitmap *dst, Font *font, S8 word, Vec2 pos, B32 draw) { +function +Vec4 r_base_string(Bitmap *dst, Font *font, String word, Vec2 pos, B32 draw) { Vec2 og_position = pos; F32 max_x = pos.x; for (U64 i = 0; i < word.len; i++) { @@ -274,65 +271,65 @@ Vec4 r_base_string(Bitmap *dst, Font *font, S8 word, Vec2 pos, B32 draw) { return rect; } -FUNCTION -Vec4 r_draw_string(Bitmap *dst, Font *font, S8 word, Vec2 pos) { +function +Vec4 r_draw_string(Bitmap *dst, Font *font, String word, Vec2 pos) { return r_base_string(dst, font, word, pos, true); } -FUNCTION -Vec4 r_get_string_rect(Font *font, S8 word, Vec2 pos) { +function +Vec4 r_get_string_rect(Font *font, String word, Vec2 pos) { return r_base_string(0, font, word, pos, false); } -FUNCTION +function F32 edge_function(Vec4 vecp0, Vec4 vecp1, Vec4 p) { F32 result = (vecp1.y - vecp0.y) * (p.x - vecp0.x) - (vecp1.x - vecp0.x) * (p.y - vecp0.y); return result; } -FUNCTION +function void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 light_direction, - Vec4 p0, Vec4 p1, Vec4 p2, - Vec2 tex0, Vec2 tex1, Vec2 tex2, - Vec3 norm0, Vec3 norm1, Vec3 norm2) { + Vec4 p0, Vec4 p1, Vec4 p2, + Vec2 tex0, Vec2 tex1, Vec2 tex2, + Vec3 norm0, Vec3 norm1, Vec3 norm2) { if(os.frame > 60) PROFILE_BEGIN(draw_triangle); - F32 min_x1 = (F32)(MIN(p0.x, MIN(p1.x, p2.x))); - F32 min_y1 = (F32)(MIN(p0.y, MIN(p1.y, p2.y))); - F32 max_x1 = (F32)(MAX(p0.x, MAX(p1.x, p2.x))); - F32 max_y1 = (F32)(MAX(p0.y, MAX(p1.y, p2.y))); - I64 min_x = (I64)MAX(0, floor(min_x1)); - I64 min_y = (I64)MAX(0, floor(min_y1)); - I64 max_x = (I64)MIN(dst->x, ceil(max_x1)); - I64 max_y = (I64)MIN(dst->y, ceil(max_y1)); - + F32 min_x1 = (F32)(min(p0.x, min(p1.x, p2.x))); + F32 min_y1 = (F32)(min(p0.y, min(p1.y, p2.y))); + F32 max_x1 = (F32)(max(p0.x, max(p1.x, p2.x))); + F32 max_y1 = (F32)(max(p0.y, max(p1.y, p2.y))); + S64 min_x = (S64)max(0.f, floor(min_x1)); + S64 min_y = (S64)max(0.f, floor(min_y1)); + S64 max_x = (S64)min((F32)dst->x, ceil(max_x1)); + S64 max_y = (S64)min((F32)dst->y, ceil(max_y1)); + F32 dy10 = (p1.y - p0.y); F32 dy21 = (p2.y - p1.y); F32 dy02 = (p0.y - p2.y); - + F32 dx10 = (p1.x - p0.x); F32 dx21 = (p2.x - p1.x); F32 dx02 = (p0.x - p2.x); - + F32 C0 = dy10 * (p0.x) - dx10 * (p0.y); F32 C1 = dy21 * (p1.x) - dx21 * (p1.y); F32 C2 = dy02 * (p2.x) - dx02 * (p2.y); - + F32 Cy0 = dy10 * min_x - dx10 * min_y - C0; F32 Cy1 = dy21 * min_x - dx21 * min_y - C1; F32 Cy2 = dy02 * min_x - dx02 * min_y - C2; - + U32 *destination = dst->pixels + dst->x*min_y; F32 area = (p1.y - p0.y) * (p2.x - p0.x) - (p1.x - p0.x) * (p2.y - p0.y); - for (I64 y = min_y; y < max_y; y++) { + for (S64 y = min_y; y < max_y; y++) { F32 Cx0 = Cy0; F32 Cx1 = Cy1; F32 Cx2 = Cy2; - for (I64 x = min_x; x < max_x; x++) { + for (S64 x = min_x; x < max_x; x++) { if (Cx0 >= 0 && Cx1 >= 0 && Cx2 >= 0) { F32 w1 = Cx1 / area; F32 w2 = Cx2 / area; F32 w3 = Cx0 / area; - + // @Note: We could do: interpolated_w = 1.f / interpolated_w to get proper depth // but why waste an instruction, the smaller the depth value the farther the object F32 interpolated_w = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3; @@ -342,7 +339,7 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig F32 invw0 = (w1 / p0.w); F32 invw1 = (w2 / p1.w); F32 invw2 = (w3 / p2.w); - + Vec3 norm = (norm0 * invw0 + norm1 * invw1 + norm2 * invw2) / interpolated_w; F32 u = tex0.x * invw0 + tex1.x * invw1 + tex2.x * invw2; F32 v = tex0.y * invw0 + tex1.y * invw1 + tex2.y * invw2; @@ -356,14 +353,14 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig u = u * (src->x - 1); v = v * (src->y - 1); } - I64 ui = (I64)(u); - I64 vi = (I64)(v); - F32 udiff = u - (F32)ui; - F32 vdiff = v - (F32)vi; + S64 ui = (S64)(u); + S64 vi = (S64)(v); + //F32 udiff = u - (F32)ui; + //F32 vdiff = v - (F32)vi; // Origin UV (0,0) is in bottom left U32 *dst_pixel = destination + x; U32 *pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x); - + #if PREMULTIPLIED_ALPHA_BLENDING Vec4 result_color; { U32 c = *pixel; @@ -386,24 +383,24 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig r*=r; g*=g; b*=b; dst_color = { r,g,b,a }; } - + Vec3 light_color = vec3(0.8,0.8,1); constexpr F32 ambient_strength = 0.1f; { Vec3 ambient = ambient_strength * light_color; - Vec3 diffuse = CLAMP_BOT(0, -dot(norm, light_direction)) * light_color; + Vec3 diffuse = clamp_bot(0.f, -dot(norm, light_direction)) * light_color; result_color.rgb *= (ambient+diffuse); } - + result_color = premultiplied_alpha(dst_color, result_color); result_color = almost_linear_to_srgb(result_color); U32 color32 = vec4_to_u32abgr(result_color); #else U32 color32 = *pixel; #endif - + *dst_pixel = color32; } } @@ -420,33 +417,33 @@ void draw_triangle_nearest(Bitmap* dst, F32 *depth_buffer, Bitmap *src, Vec3 lig if(os.frame > 60) PROFILE_END(draw_triangle); } -FUNCTION +function void draw_triangle_bilinear(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 light, - Vec4 p0, Vec4 p1, Vec4 p2, - Vec2 tex0, Vec2 tex1, Vec2 tex2) { - F32 min_x1 = (F32)(MIN(p0.x, MIN(p1.x, p2.x))); - F32 min_y1 = (F32)(MIN(p0.y, MIN(p1.y, p2.y))); - F32 max_x1 = (F32)(MAX(p0.x, MAX(p1.x, p2.x))); - F32 max_y1 = (F32)(MAX(p0.y, MAX(p1.y, p2.y))); - I64 min_x = (I64)MAX(0, floor(min_x1)); - I64 min_y = (I64)MAX(0, floor(min_y1)); - I64 max_x = (I64)MIN(dst->x, ceil(max_x1)); - I64 max_y = (I64)MIN(dst->y, ceil(max_y1)); - + Vec4 p0, Vec4 p1, Vec4 p2, + Vec2 tex0, Vec2 tex1, Vec2 tex2) { + F32 min_x1 = (F32)(min(p0.x, min(p1.x, p2.x))); + F32 min_y1 = (F32)(min(p0.y, min(p1.y, p2.y))); + F32 max_x1 = (F32)(max(p0.x, max(p1.x, p2.x))); + F32 max_y1 = (F32)(max(p0.y, max(p1.y, p2.y))); + S64 min_x = (S64)max(0.f, floor(min_x1)); + S64 min_y = (S64)max(0.f, floor(min_y1)); + S64 max_x = (S64)min((F32)dst->x, ceil(max_x1)); + S64 max_y = (S64)min((F32)dst->y, ceil(max_y1)); + F32 area = edge_function(p0, p1, p2); - for (I64 y = min_y; y < max_y; y++) { - for (I64 x = min_x; x < max_x; x++) { + for (S64 y = min_y; y < max_y; y++) { + for (S64 x = min_x; x < max_x; x++) { F32 edge0 = edge_function(p0, p1, { (F32)x,(F32)y }); F32 edge1 = edge_function(p1, p2, { (F32)x,(F32)y }); F32 edge2 = edge_function(p2, p0, { (F32)x,(F32)y }); - - + + if (edge0 >= 0 && edge1 >= 0 && edge2 >= 0) { F32 w1 = edge1 / area; F32 w2 = edge2 / area; F32 w3 = edge0 / area; F32 interpolated_w = (1.f / p0.w) * w1 + (1.f / p1.w) * w2 + (1.f / p2.w) * w3; - + F32 u = tex0.x * (w1 / p0.w) + tex1.x * (w2 / p1.w) + tex2.x * (w3 / p2.w); F32 v = tex0.y * (w1 / p0.w) + tex1.y * (w2 / p1.w) + tex2.y * (w3 / p2.w); u /= interpolated_w; @@ -458,14 +455,14 @@ void draw_triangle_bilinear(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 lig *depth = interpolated_w; u = u * (src->x - 2); v = v * (src->y - 2); - I64 ui = (I64)(u); - I64 vi = (I64)(v); + S64 ui = (S64)(u); + S64 vi = (S64)(v); F32 udiff = u - (F32)ui; F32 vdiff = v - (F32)vi; // Origin UV (0,0) is in bottom left U32 *pixel = src->pixels + (ui + (src->y - 1ll - vi) * src->x); U32 *dst_pixel = dst->pixels + (x + y * dst->x); - + Vec4 pixelx1y1 = vec4abgr(*pixel); Vec4 pixelx2y1 = vec4abgr(*(pixel + 1)); Vec4 pixelx1y2 = vec4abgr(*(pixel - src->x)); @@ -487,7 +484,7 @@ void draw_triangle_bilinear(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 lig #endif // PREMULTIPLIED_ALPHA_BLENDING result_color = almost_linear_to_srgb(result_color); U32 color32 = vec4_to_u32abgr(result_color); - + *dst_pixel = color32; } } @@ -495,10 +492,10 @@ void draw_triangle_bilinear(Bitmap* dst, F32 *depth_buffer, Bitmap *src, F32 lig } } -FUNCTION -void r_scatter_plot(Bitmap *dst, F64 *data, I64 data_len) { +function +void r_scatter_plot(Bitmap *dst, F64 *data, S64 data_len) { F64 min = F32MAX; - F64 max = FLT_MIN; + F64 max = F32MIN; F64 step = dst->x / (F64)data_len; for (U32 i = 0; i < data_len; i++) { if (min > data[i]) min = data[i]; @@ -516,13 +513,13 @@ void r_scatter_plot(Bitmap *dst, F64 *data, I64 data_len) { } } -FUNCTION -void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *mesh, Vec3 *vertices, Vec2 *tex_coords, Vec3 *normals) { +function +void r_draw_mesh(R_Render *r, String scene_name, Obj_Material *materials, Obj_Mesh *mesh, Vec3 *vertices, Vec2 *tex_coords, Vec3 *normals) { for (int i = 0; i < mesh->indices.len; i++) { - ObjIndex *index = mesh->indices.e + i; + Obj_Index *index = mesh->indices.data + i; Bitmap *image = &r->img; if(index->material_id != -1) { - OBJMaterial *material = materials + index->material_id; + Obj_Material *material = materials + index->material_id; // @Todo: No size info from OBJ things, this stuff needs a bit of refactor // Need to figure out how to accomodate multiple possible formats of input etc. if(material->texture_ambient.pixels) { @@ -547,13 +544,13 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me normals[index->normal[2] - 1], }, }; - + //@Note: Transform for (int j = 0; j < 3; j++) { vert[j].pos = r->transform * vert[j].pos; } - - + + Vec3 p0_to_camera = r->camera_pos - vert[0].pos; Vec3 p0_to_p1 = vert[1].pos - vert[0].pos; Vec3 p0_to_p2 = vert[2].pos - vert[0].pos; @@ -584,7 +581,7 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me B32 vertex_is_outside = false; Vec3 zfar_normal = vec3(0, 0, -1); Vec3 zfar_pos = vec3(0, 0, zfar_value); - for (I32 j = 0; j < 3; j++) { + for (S32 j = 0; j < 3; j++) { // @Note: Camera vert[j].pos = r->camera * vert[j].pos; // @Note: Skip triangle if even one vertex gets outside the clipping plane @@ -593,22 +590,22 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me break; } } - + if (vertex_is_outside) { continue; } - + // @Note: Znear, clip triangles to the near clipping plane Vec3 znear_normal = vec3(0, 0, 1); Vec3 znear_pos = vec3(0, 0, 1.f); - + struct _R_Vertex { Vec4 pos; Vec2 tex; Vec3 norm; } in[4]; - I32 in_count = 0; - + S32 in_count = 0; + R_Vertex *prev = vert + 2; R_Vertex *curr = vert; F32 prev_dot = dot(znear_normal, prev->pos - znear_pos); @@ -629,12 +626,12 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me prev = curr++; prev_dot = curr_dot; } - + if (in_count == 0) { continue; } - - for(I64 j = 0; j < in_count; j++) { + + for(S64 j = 0; j < in_count; j++) { //@Note: Perspective in[j].pos = r->projection * in[j].pos; in[j].pos.x = in[j].pos.x / in[j].pos.w; @@ -651,9 +648,9 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me if (in_count > 3) { draw_triangle_nearest(&r->screen320, r->depth320, image, light_direction, in[0].pos, in[2].pos, in[3].pos, in[0].tex, in[2].tex, in[3].tex, in[0].norm, in[2].norm, in[3].norm); } - - -#if 1 + + +#if 0 ProfileScope *scope = profile_scopes + ProfileScopeName_draw_triangle; LOCAL_PERSIST B32 profile_flag; if (!profile_flag && scope->i > 2000) { @@ -661,19 +658,21 @@ void r_draw_mesh(R_Render *r, S8 scene_name, OBJMaterial *materials, ObjMesh *me save_profile_data(scope, scene_name, LIT("draw_triangle")); } #endif - + } } } -#include "ui.cpp" -F32 speed = 100.f; -F32 rotation = 0; -Obj f22; -Obj sponza; -Obj *obj; -R_Render r = {}; -GLOBAL Scene scene = Scene_Sponza; +#include "ui.cpp" +global F32 speed = 100.f; +global F32 rotation = 0; +global Obj f22; +global Obj *sponza; +global Obj *obj; +global R_Render r = {}; +global Scene scene = Scene_Sponza; + +function UI_SIGNAL_CALLBACK(scene_callback) { switch(scene) { case Scene_F22: { @@ -684,57 +683,45 @@ UI_SIGNAL_CALLBACK(scene_callback) { case Scene_Sponza: { speed = 100; r.camera_pos = vec3(0,0,-2); - obj = &sponza; + obj = sponza; } break; case Scene_Count: - INVALID_DEFAULT_CASE; + invalid_default_case; } scene = (Scene)(((int)scene + 1) % Scene_Count); } -int main() { +int main(int argc, char **argv) { os.window_size.x = 320*2; os.window_size.y = 180*2; os.window_resizable = 1; - os_init().error_is_fatal(); - S8List list = {}; - string_push(os.frame_arena, &list, LIT("main.cpp")); - generate_documentation(list, LIT("README.md")); - Font font = os_load_font(os.perm_arena, 24, "Arial"); - for (U32 i = 0; i < font.glyphs_len; i++) { - FontGlyph *g = font.glyphs + i; - U32 *pointer = g->bitmap.pixels; - for (I32 y = 0; y < g->bitmap.y; y++) { - for (I32 x = 0; x < g->bitmap.x; x++) { - Vec4 color = vec4abgr(*pointer); - color.rgb *= color.a; - *pointer++ = vec4_to_u32abgr(color); - } - } - - } - + assert(os_init()); + Font font = os_load_font(os.perm_arena, 24, "Arial", 0); + + f22 = load_obj(&os_process_heap, "assets/f22.obj"_s); + //Obj sponza_obj = load_obj(&os_process_heap, "assets/sponza/sponza.obj"_s); + //sponza = &sponza_obj; + //dump_obj_to_file(sponza); + sponza = load_obj_dump(os.perm_arena, "sponza.bin"_s); - f22 = load_obj(os.perm_arena, LIT("assets/f22.obj")); - sponza = load_obj(os.perm_arena, LIT("assets/sponza/sponza.obj")); scene_callback(); - + int screen_x = 1280/2; int screen_y = 720/2; r.camera_pos = {0,0,-2}; - r.screen320 = {(U32 *)PUSH_SIZE(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y}; - r.plot = {(U32 *)PUSH_SIZE(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720}; - r.depth320 = (F32 *)PUSH_SIZE(os.perm_arena, sizeof(F32) * screen_x * screen_y); - r.img = load_image("assets/bricksx64.png"); - + r.screen320 = {(U32 *)arena_push_size(os.perm_arena, screen_x*screen_y*sizeof(U32)), screen_x, screen_y}; + r.plot = {(U32 *)arena_push_size(os.perm_arena, 1280*720*sizeof(U32)), 1280, 720}; + r.depth320 = (F32 *)arena_push_size(os.perm_arena, sizeof(F32) * screen_x * screen_y); + r.img = load_image("assets/bricksx64.png"_s); + /* @Note: Transparent texture */ { #if 0 Vec4 testc = vec4(1, 1, 1, 0.5f); testc.rgb *= testc.a; U32 testc32 = vec4_to_u32abgr(testc); U32 a[] = { d - testc32, testc32, testc32, testc32, + testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, testc32, @@ -745,17 +732,17 @@ int main() { #endif } - - - S8 frame_data = {}; + + + String frame_data = {}; UISetup setup[] = { - UI_SIGNAL(LIT("Change scene"), scene_callback), + UI_SIGNAL("Change scene"_s, scene_callback), UI_IMAGE(&r.plot), UI_LABEL(&frame_data), }; - UI ui = ui_make(os.perm_arena, setup, ARRAY_CAP(setup)); + UI ui = ui_make(setup, buff_cap(setup)); B32 ui_mouse_lock = true; - + while (os_game_loop()) { @@ -794,7 +781,7 @@ int main() { *dp++ = -F32MAX; } } - + Mat4 camera_rotation = mat4_rotation_y(r.camera_yaw.x) * mat4_rotation_x(r.camera_yaw.y); r.camera_direction = (camera_rotation * vec4(0,0,1,1)).xyz; @@ -804,14 +791,14 @@ int main() { r.transform = mat4_rotation_z(rotation); r.transform = r.transform * mat4_rotation_y(rotation); for (int i = 0; i < obj->mesh.len; i++) { - Vec2* tex_coords = (Vec2*)obj->texture_coordinates.e; - Vec3 *normals = (Vec3 *)obj->normals.e; - ObjMesh *mesh = obj->mesh.e; - Vec3* vertices = (Vec3 *)obj->vertices.e; - r_draw_mesh(&r, obj->name, obj->materials.e, mesh+i, vertices, tex_coords, normals); + Vec2* tex_coords = (Vec2*)obj->texture_coordinates.data; + Vec3 *normals = (Vec3 *)obj->normals.data; + Obj_Mesh *mesh = obj->mesh.data; + Vec3* vertices = (Vec3 *)obj->vertices.data; + r_draw_mesh(&r, obj->name, obj->materials.data, mesh+i, vertices, tex_coords, normals); } - + // @Note: Draw 320screen to OS screen U32* ptr = os.screen->pixels; for (int y = 0; y < os.screen->y; y++) { @@ -824,7 +811,7 @@ int main() { } } ui_end_frame(os.screen, &ui, &font); - frame_data = string_format(os.frame_arena, "FPS:%f dt:%f frame:%u", os.fps, os.delta_time, os.frame); + frame_data = string_fmt(os.frame_arena, "FPS:%f dt:%f frame:%u", os.fps, os.delta_time, os.frame); } } diff --git a/math.h b/math.h index b8c0599..b9d57fb 100644 --- a/math.h +++ b/math.h @@ -1,24 +1,1620 @@ -FUNCTION +#pragma once + +/////////////////////////////////////// +// @Section Math +#include +constexpr F32 PI32 = 3.14159265359f; + +api F32 power(S64 pow, F32 value) { + F32 result = value; + if (pow == 0) { + result = 1; + } else { + for (S64 i = 1; i < pow; i++) { + result *= result; + } + } + return result; +} + +api F32 to_radians(F32 degrees) { + F32 result = degrees * (PI32 / 180.f); + return result; +} + +api F32 to_degrees(F32 radians) { + F32 result = radians * (180.f / PI32); + return result; +} + +api F32 fraction(F32 value) { + F32 result = value - floorf(value); + return result; +} + +api F32 absolute(F32 value) { + if (value < 0) + value = -value; + return value; +} + +api S32 square(S32 val) { return val * val; } + +api S32 clamp01(S32 val) { + S32 result = clamp(0, val, 1); + return result; +} + +api S32 sign(S32 val) { + if (val > 0) + return 1; + else if (val < 0) + return -1; + return 0; +} + +api F32 square(F32 val) { return val * val; } + +api F32 clamp01(F32 val) { + F32 result = clamp(0.f, val, 1.f); + return result; +} + +api F32 sign(F32 val) { + if (val > 0) + return 1; + else if (val < 0) + return -1; + return 0; +} + +api F32 floor(F32 val) { return floorf(val); } + +api F32 ceil(F32 val) { return ceilf(val); } + +api F32 round(F32 val) { return roundf(val); } + +api F32 sine(F32 val) { return sinf(val); } + +api F32 sine01(F32 val) { + F32 result = sine(val); + result += 1; + result /= 2; + return result; +} + +api F32 cosine(F32 val) { return cosf(val); } + +api F32 square_root(F32 val) { return sqrtf(val); } + +api Vec2 vec2(F32 x, F32 y) { + Vec2 result; + result.x = x; + result.y = y; + return result; +} +api Vec2 vec2() { return vec2(0, 0); } +api Vec2 operator+(Vec2 a, Vec2 b) { + Vec2 result = vec2(a.x + b.x, a.y + b.y); + return result; +} +api Vec2 operator+(Vec2 a, F32 b) { + Vec2 result = vec2(a.x + b, a.y + b); + return result; +} +api Vec2 operator+(F32 a, Vec2 b) { + Vec2 result = vec2(a + b.x, a + b.y); + return result; +} +api Vec2 &operator+=(Vec2 &a, Vec2 b) { + a = a + b; + return a; +} +api Vec2 &operator+=(Vec2 &a, F32 b) { + a = a + b; + return a; +} +api Vec2 operator-(Vec2 a, Vec2 b) { + Vec2 result = vec2(a.x - b.x, a.y - b.y); + return result; +} +api Vec2 operator-(Vec2 a, F32 b) { + Vec2 result = vec2(a.x - b, a.y - b); + return result; +} +api Vec2 operator-(F32 a, Vec2 b) { + Vec2 result = vec2(a - b.x, a - b.y); + return result; +} +api Vec2 &operator-=(Vec2 &a, Vec2 b) { + a = a - b; + return a; +} +api Vec2 &operator-=(Vec2 &a, F32 b) { + a = a - b; + return a; +} +api Vec2 operator*(Vec2 a, Vec2 b) { + Vec2 result = vec2(a.x * b.x, a.y * b.y); + return result; +} +api Vec2 operator*(Vec2 a, F32 b) { + Vec2 result = vec2(a.x * b, a.y * b); + return result; +} +api Vec2 operator*(F32 a, Vec2 b) { + Vec2 result = vec2(a * b.x, a * b.y); + return result; +} +api Vec2 &operator*=(Vec2 &a, Vec2 b) { + a = a * b; + return a; +} +api Vec2 &operator*=(Vec2 &a, F32 b) { + a = a * b; + return a; +} +api Vec2 operator/(Vec2 a, Vec2 b) { + Vec2 result = vec2(a.x / b.x, a.y / b.y); + return result; +} +api Vec2 operator/(Vec2 a, F32 b) { + Vec2 result = vec2(a.x / b, a.y / b); + return result; +} +api Vec2 operator/(F32 a, Vec2 b) { + Vec2 result = vec2(a / b.x, a / b.y); + return result; +} +api Vec2 &operator/=(Vec2 &a, Vec2 b) { + a = a / b; + return a; +} +api Vec2 &operator/=(Vec2 &a, F32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec2 a, Vec2 b) { + B32 result = (a.x != b.x) || (a.y != b.y); + return result; +} +api B32 operator==(Vec2 a, Vec2 b) { + B32 result = (a.x == b.x) && (a.y == b.y); + return result; +} +api Vec2 operator-(Vec2 a) { + Vec2 result = vec2(-a.x, -a.y); + return result; +} +api Vec2 clamp(Vec2 min, Vec2 val, Vec2 max) { + Vec2 result = vec2(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y)); + return result; +} +api Vec2 clamp(F32 min, Vec2 val, F32 max) { + Vec2 result = vec2(clamp(min, val.x, max), clamp(min, val.y, max)); + return result; +} +api Vec2 clamp01(Vec2 val) { + Vec2 result = vec2(clamp01(val.x), clamp01(val.y)); + return result; +} +api Vec2 ceil(Vec2 a) { + Vec2 result = vec2(ceil(a.x), ceil(a.y)); + return result; +} +api Vec2 floor(Vec2 a) { + Vec2 result = vec2(floor(a.x), floor(a.y)); + return result; +} +api Vec2 round(Vec2 a) { + Vec2 result = vec2(round(a.x), round(a.y)); + return result; +} +api Vec2 absolute(Vec2 a) { + Vec2 result = vec2(absolute(a.x), absolute(a.y)); + return result; +} +api Vec2 sign(Vec2 a) { + Vec2 result = vec2(sign(a.x), sign(a.y)); + return result; +} +api Vec2 fraction(Vec2 a) { + Vec2 result = vec2(fraction(a.x), fraction(a.y)); + return result; +} +api Vec2 square(Vec2 a) { + Vec2 result = vec2(square(a.x), square(a.y)); + return result; +} +api Vec2 square_root(Vec2 a) { + Vec2 result = vec2(square_root(a.x), square_root(a.y)); + return result; +} +api F32 dot(Vec2 a, Vec2 b) { + F32 result = a.x * b.x + a.y * b.y; + return result; +} +api F32 length_squared(Vec2 a) { + F32 result = dot(a, a); + return result; +} +api F32 length(Vec2 a) { + F32 result = square_root(length_squared(a)); + return result; +} +api Vec2 lerp(Vec2 from, Vec2 to, F32 t) { + Vec2 result = (1 - t) * from + to * t; + return result; +} +api Vec3 vec3(F32 x, F32 y, F32 z) { + Vec3 result; + result.x = x; + result.y = y; + result.z = z; + return result; +} +api Vec3 vec3() { return vec3(0, 0, 0); } +api Vec3 operator+(Vec3 a, Vec3 b) { + Vec3 result = vec3(a.x + b.x, a.y + b.y, a.z + b.z); + return result; +} +api Vec3 operator+(Vec3 a, F32 b) { + Vec3 result = vec3(a.x + b, a.y + b, a.z + b); + return result; +} +api Vec3 operator+(F32 a, Vec3 b) { + Vec3 result = vec3(a + b.x, a + b.y, a + b.z); + return result; +} +api Vec3 &operator+=(Vec3 &a, Vec3 b) { + a = a + b; + return a; +} +api Vec3 &operator+=(Vec3 &a, F32 b) { + a = a + b; + return a; +} +api Vec3 operator-(Vec3 a, Vec3 b) { + Vec3 result = vec3(a.x - b.x, a.y - b.y, a.z - b.z); + return result; +} +api Vec3 operator-(Vec3 a, F32 b) { + Vec3 result = vec3(a.x - b, a.y - b, a.z - b); + return result; +} +api Vec3 operator-(F32 a, Vec3 b) { + Vec3 result = vec3(a - b.x, a - b.y, a - b.z); + return result; +} +api Vec3 &operator-=(Vec3 &a, Vec3 b) { + a = a - b; + return a; +} +api Vec3 &operator-=(Vec3 &a, F32 b) { + a = a - b; + return a; +} +api Vec3 operator*(Vec3 a, Vec3 b) { + Vec3 result = vec3(a.x * b.x, a.y * b.y, a.z * b.z); + return result; +} +api Vec3 operator*(Vec3 a, F32 b) { + Vec3 result = vec3(a.x * b, a.y * b, a.z * b); + return result; +} +api Vec3 operator*(F32 a, Vec3 b) { + Vec3 result = vec3(a * b.x, a * b.y, a * b.z); + return result; +} +api Vec3 &operator*=(Vec3 &a, Vec3 b) { + a = a * b; + return a; +} +api Vec3 &operator*=(Vec3 &a, F32 b) { + a = a * b; + return a; +} +api Vec3 operator/(Vec3 a, Vec3 b) { + Vec3 result = vec3(a.x / b.x, a.y / b.y, a.z / b.z); + return result; +} +api Vec3 operator/(Vec3 a, F32 b) { + Vec3 result = vec3(a.x / b, a.y / b, a.z / b); + return result; +} +api Vec3 operator/(F32 a, Vec3 b) { + Vec3 result = vec3(a / b.x, a / b.y, a / b.z); + return result; +} +api Vec3 &operator/=(Vec3 &a, Vec3 b) { + a = a / b; + return a; +} +api Vec3 &operator/=(Vec3 &a, F32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec3 a, Vec3 b) { + B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z); + return result; +} +api B32 operator==(Vec3 a, Vec3 b) { + B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z); + return result; +} +api Vec3 operator-(Vec3 a) { + Vec3 result = vec3(-a.x, -a.y, -a.z); + return result; +} +api Vec3 clamp(Vec3 min, Vec3 val, Vec3 max) { + Vec3 result = vec3(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z)); + return result; +} +api Vec3 clamp(F32 min, Vec3 val, F32 max) { + Vec3 result = vec3(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max)); + return result; +} +api Vec3 clamp01(Vec3 val) { + Vec3 result = vec3(clamp01(val.x), clamp01(val.y), clamp01(val.z)); + return result; +} +api Vec3 ceil(Vec3 a) { + Vec3 result = vec3(ceil(a.x), ceil(a.y), ceil(a.z)); + return result; +} +api Vec3 floor(Vec3 a) { + Vec3 result = vec3(floor(a.x), floor(a.y), floor(a.z)); + return result; +} +api Vec3 round(Vec3 a) { + Vec3 result = vec3(round(a.x), round(a.y), round(a.z)); + return result; +} +api Vec3 absolute(Vec3 a) { + Vec3 result = vec3(absolute(a.x), absolute(a.y), absolute(a.z)); + return result; +} +api Vec3 sign(Vec3 a) { + Vec3 result = vec3(sign(a.x), sign(a.y), sign(a.z)); + return result; +} +api Vec3 fraction(Vec3 a) { + Vec3 result = vec3(fraction(a.x), fraction(a.y), fraction(a.z)); + return result; +} +api Vec3 square(Vec3 a) { + Vec3 result = vec3(square(a.x), square(a.y), square(a.z)); + return result; +} +api Vec3 square_root(Vec3 a) { + Vec3 result = vec3(square_root(a.x), square_root(a.y), square_root(a.z)); + return result; +} +api F32 dot(Vec3 a, Vec3 b) { + F32 result = a.x * b.x + a.y * b.y + a.z * b.z; + return result; +} +api F32 length_squared(Vec3 a) { + F32 result = dot(a, a); + return result; +} +api F32 length(Vec3 a) { + F32 result = square_root(length_squared(a)); + return result; +} +api Vec3 lerp(Vec3 from, Vec3 to, F32 t) { + Vec3 result = (1 - t) * from + to * t; + return result; +} +api Vec4 vec4(F32 x, F32 y, F32 z, F32 w) { + Vec4 result; + result.x = x; + result.y = y; + result.z = z; + result.w = w; + return result; +} +api Vec4 vec4() { return vec4(0, 0, 0, 0); } +api Vec4 operator+(Vec4 a, Vec4 b) { + Vec4 result = vec4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + return result; +} +api Vec4 operator+(Vec4 a, F32 b) { + Vec4 result = vec4(a.x + b, a.y + b, a.z + b, a.w + b); + return result; +} +api Vec4 operator+(F32 a, Vec4 b) { + Vec4 result = vec4(a + b.x, a + b.y, a + b.z, a + b.w); + return result; +} +api Vec4 &operator+=(Vec4 &a, Vec4 b) { + a = a + b; + return a; +} +api Vec4 &operator+=(Vec4 &a, F32 b) { + a = a + b; + return a; +} +api Vec4 operator-(Vec4 a, Vec4 b) { + Vec4 result = vec4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + return result; +} +api Vec4 operator-(Vec4 a, F32 b) { + Vec4 result = vec4(a.x - b, a.y - b, a.z - b, a.w - b); + return result; +} +api Vec4 operator-(F32 a, Vec4 b) { + Vec4 result = vec4(a - b.x, a - b.y, a - b.z, a - b.w); + return result; +} +api Vec4 &operator-=(Vec4 &a, Vec4 b) { + a = a - b; + return a; +} +api Vec4 &operator-=(Vec4 &a, F32 b) { + a = a - b; + return a; +} +api Vec4 operator*(Vec4 a, Vec4 b) { + Vec4 result = vec4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + return result; +} +api Vec4 operator*(Vec4 a, F32 b) { + Vec4 result = vec4(a.x * b, a.y * b, a.z * b, a.w * b); + return result; +} +api Vec4 operator*(F32 a, Vec4 b) { + Vec4 result = vec4(a * b.x, a * b.y, a * b.z, a * b.w); + return result; +} +api Vec4 &operator*=(Vec4 &a, Vec4 b) { + a = a * b; + return a; +} +api Vec4 &operator*=(Vec4 &a, F32 b) { + a = a * b; + return a; +} +api Vec4 operator/(Vec4 a, Vec4 b) { + Vec4 result = vec4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + return result; +} +api Vec4 operator/(Vec4 a, F32 b) { + Vec4 result = vec4(a.x / b, a.y / b, a.z / b, a.w / b); + return result; +} +api Vec4 operator/(F32 a, Vec4 b) { + Vec4 result = vec4(a / b.x, a / b.y, a / b.z, a / b.w); + return result; +} +api Vec4 &operator/=(Vec4 &a, Vec4 b) { + a = a / b; + return a; +} +api Vec4 &operator/=(Vec4 &a, F32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec4 a, Vec4 b) { + B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); + return result; +} +api B32 operator==(Vec4 a, Vec4 b) { + B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); + return result; +} +api Vec4 operator-(Vec4 a) { + Vec4 result = vec4(-a.x, -a.y, -a.z, -a.w); + return result; +} +api Vec4 clamp(Vec4 min, Vec4 val, Vec4 max) { + Vec4 result = vec4(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z), + clamp(min.w, val.w, max.w)); + return result; +} +api Vec4 clamp(F32 min, Vec4 val, F32 max) { + Vec4 result = + vec4(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max), clamp(min, val.w, max)); + return result; +} +api Vec4 clamp01(Vec4 val) { + Vec4 result = vec4(clamp01(val.x), clamp01(val.y), clamp01(val.z), clamp01(val.w)); + return result; +} +api Vec4 ceil(Vec4 a) { + Vec4 result = vec4(ceil(a.x), ceil(a.y), ceil(a.z), ceil(a.w)); + return result; +} +api Vec4 floor(Vec4 a) { + Vec4 result = vec4(floor(a.x), floor(a.y), floor(a.z), floor(a.w)); + return result; +} +api Vec4 round(Vec4 a) { + Vec4 result = vec4(round(a.x), round(a.y), round(a.z), round(a.w)); + return result; +} +api Vec4 absolute(Vec4 a) { + Vec4 result = vec4(absolute(a.x), absolute(a.y), absolute(a.z), absolute(a.w)); + return result; +} +api Vec4 sign(Vec4 a) { + Vec4 result = vec4(sign(a.x), sign(a.y), sign(a.z), sign(a.w)); + return result; +} +api Vec4 fraction(Vec4 a) { + Vec4 result = vec4(fraction(a.x), fraction(a.y), fraction(a.z), fraction(a.w)); + return result; +} +api Vec4 square(Vec4 a) { + Vec4 result = vec4(square(a.x), square(a.y), square(a.z), square(a.w)); + return result; +} +api Vec4 square_root(Vec4 a) { + Vec4 result = vec4(square_root(a.x), square_root(a.y), square_root(a.z), square_root(a.w)); + return result; +} +api F32 dot(Vec4 a, Vec4 b) { + F32 result = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + return result; +} +api F32 length_squared(Vec4 a) { + F32 result = dot(a, a); + return result; +} +api F32 length(Vec4 a) { + F32 result = square_root(length_squared(a)); + return result; +} +api Vec4 lerp(Vec4 from, Vec4 to, F32 t) { + Vec4 result = (1 - t) * from + to * t; + return result; +} +api Vec2I vec2i(S32 x, S32 y) { + Vec2I result; + result.x = x; + result.y = y; + return result; +} +api Vec2I vec2i() { return vec2i(0, 0); } +api Vec2I operator+(Vec2I a, Vec2I b) { + Vec2I result = vec2i(a.x + b.x, a.y + b.y); + return result; +} +api Vec2I operator+(Vec2I a, S32 b) { + Vec2I result = vec2i(a.x + b, a.y + b); + return result; +} +api Vec2I operator+(S32 a, Vec2I b) { + Vec2I result = vec2i(a + b.x, a + b.y); + return result; +} +api Vec2I &operator+=(Vec2I &a, Vec2I b) { + a = a + b; + return a; +} +api Vec2I &operator+=(Vec2I &a, S32 b) { + a = a + b; + return a; +} +api Vec2I operator-(Vec2I a, Vec2I b) { + Vec2I result = vec2i(a.x - b.x, a.y - b.y); + return result; +} +api Vec2I operator-(Vec2I a, S32 b) { + Vec2I result = vec2i(a.x - b, a.y - b); + return result; +} +api Vec2I operator-(S32 a, Vec2I b) { + Vec2I result = vec2i(a - b.x, a - b.y); + return result; +} +api Vec2I &operator-=(Vec2I &a, Vec2I b) { + a = a - b; + return a; +} +api Vec2I &operator-=(Vec2I &a, S32 b) { + a = a - b; + return a; +} +api Vec2I operator*(Vec2I a, Vec2I b) { + Vec2I result = vec2i(a.x * b.x, a.y * b.y); + return result; +} +api Vec2I operator*(Vec2I a, S32 b) { + Vec2I result = vec2i(a.x * b, a.y * b); + return result; +} +api Vec2I operator*(S32 a, Vec2I b) { + Vec2I result = vec2i(a * b.x, a * b.y); + return result; +} +api Vec2I &operator*=(Vec2I &a, Vec2I b) { + a = a * b; + return a; +} +api Vec2I &operator*=(Vec2I &a, S32 b) { + a = a * b; + return a; +} +api Vec2I operator/(Vec2I a, Vec2I b) { + Vec2I result = vec2i(a.x / b.x, a.y / b.y); + return result; +} +api Vec2I operator/(Vec2I a, S32 b) { + Vec2I result = vec2i(a.x / b, a.y / b); + return result; +} +api Vec2I operator/(S32 a, Vec2I b) { + Vec2I result = vec2i(a / b.x, a / b.y); + return result; +} +api Vec2I &operator/=(Vec2I &a, Vec2I b) { + a = a / b; + return a; +} +api Vec2I &operator/=(Vec2I &a, S32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec2I a, Vec2I b) { + B32 result = (a.x != b.x) || (a.y != b.y); + return result; +} +api B32 operator==(Vec2I a, Vec2I b) { + B32 result = (a.x == b.x) && (a.y == b.y); + return result; +} +api Vec2I operator-(Vec2I a) { + Vec2I result = vec2i(-a.x, -a.y); + return result; +} +api Vec2I clamp(Vec2I min, Vec2I val, Vec2I max) { + Vec2I result = vec2i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y)); + return result; +} +api Vec2I clamp(S32 min, Vec2I val, S32 max) { + Vec2I result = vec2i(clamp(min, val.x, max), clamp(min, val.y, max)); + return result; +} +api Vec2I clamp01(Vec2I val) { + Vec2I result = vec2i(clamp01(val.x), clamp01(val.y)); + return result; +} +api Vec3I vec3i(S32 x, S32 y, S32 z) { + Vec3I result; + result.x = x; + result.y = y; + result.z = z; + return result; +} +api Vec3I vec3i() { return vec3i(0, 0, 0); } +api Vec3I operator+(Vec3I a, Vec3I b) { + Vec3I result = vec3i(a.x + b.x, a.y + b.y, a.z + b.z); + return result; +} +api Vec3I operator+(Vec3I a, S32 b) { + Vec3I result = vec3i(a.x + b, a.y + b, a.z + b); + return result; +} +api Vec3I operator+(S32 a, Vec3I b) { + Vec3I result = vec3i(a + b.x, a + b.y, a + b.z); + return result; +} +api Vec3I &operator+=(Vec3I &a, Vec3I b) { + a = a + b; + return a; +} +api Vec3I &operator+=(Vec3I &a, S32 b) { + a = a + b; + return a; +} +api Vec3I operator-(Vec3I a, Vec3I b) { + Vec3I result = vec3i(a.x - b.x, a.y - b.y, a.z - b.z); + return result; +} +api Vec3I operator-(Vec3I a, S32 b) { + Vec3I result = vec3i(a.x - b, a.y - b, a.z - b); + return result; +} +api Vec3I operator-(S32 a, Vec3I b) { + Vec3I result = vec3i(a - b.x, a - b.y, a - b.z); + return result; +} +api Vec3I &operator-=(Vec3I &a, Vec3I b) { + a = a - b; + return a; +} +api Vec3I &operator-=(Vec3I &a, S32 b) { + a = a - b; + return a; +} +api Vec3I operator*(Vec3I a, Vec3I b) { + Vec3I result = vec3i(a.x * b.x, a.y * b.y, a.z * b.z); + return result; +} +api Vec3I operator*(Vec3I a, S32 b) { + Vec3I result = vec3i(a.x * b, a.y * b, a.z * b); + return result; +} +api Vec3I operator*(S32 a, Vec3I b) { + Vec3I result = vec3i(a * b.x, a * b.y, a * b.z); + return result; +} +api Vec3I &operator*=(Vec3I &a, Vec3I b) { + a = a * b; + return a; +} +api Vec3I &operator*=(Vec3I &a, S32 b) { + a = a * b; + return a; +} +api Vec3I operator/(Vec3I a, Vec3I b) { + Vec3I result = vec3i(a.x / b.x, a.y / b.y, a.z / b.z); + return result; +} +api Vec3I operator/(Vec3I a, S32 b) { + Vec3I result = vec3i(a.x / b, a.y / b, a.z / b); + return result; +} +api Vec3I operator/(S32 a, Vec3I b) { + Vec3I result = vec3i(a / b.x, a / b.y, a / b.z); + return result; +} +api Vec3I &operator/=(Vec3I &a, Vec3I b) { + a = a / b; + return a; +} +api Vec3I &operator/=(Vec3I &a, S32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec3I a, Vec3I b) { + B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z); + return result; +} +api B32 operator==(Vec3I a, Vec3I b) { + B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z); + return result; +} +api Vec3I operator-(Vec3I a) { + Vec3I result = vec3i(-a.x, -a.y, -a.z); + return result; +} +api Vec3I clamp(Vec3I min, Vec3I val, Vec3I max) { + Vec3I result = vec3i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z)); + return result; +} +api Vec3I clamp(S32 min, Vec3I val, S32 max) { + Vec3I result = vec3i(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max)); + return result; +} +api Vec3I clamp01(Vec3I val) { + Vec3I result = vec3i(clamp01(val.x), clamp01(val.y), clamp01(val.z)); + return result; +} +api Vec4I v4i(S32 x, S32 y, S32 z, S32 w) { + Vec4I result; + result.x = x; + result.y = y; + result.z = z; + result.w = w; + return result; +} +api Vec4I v4i() { return v4i(0, 0, 0, 0); } +api Vec4I operator+(Vec4I a, Vec4I b) { + Vec4I result = v4i(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + return result; +} +api Vec4I operator+(Vec4I a, S32 b) { + Vec4I result = v4i(a.x + b, a.y + b, a.z + b, a.w + b); + return result; +} +api Vec4I operator+(S32 a, Vec4I b) { + Vec4I result = v4i(a + b.x, a + b.y, a + b.z, a + b.w); + return result; +} +api Vec4I &operator+=(Vec4I &a, Vec4I b) { + a = a + b; + return a; +} +api Vec4I &operator+=(Vec4I &a, S32 b) { + a = a + b; + return a; +} +api Vec4I operator-(Vec4I a, Vec4I b) { + Vec4I result = v4i(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + return result; +} +api Vec4I operator-(Vec4I a, S32 b) { + Vec4I result = v4i(a.x - b, a.y - b, a.z - b, a.w - b); + return result; +} +api Vec4I operator-(S32 a, Vec4I b) { + Vec4I result = v4i(a - b.x, a - b.y, a - b.z, a - b.w); + return result; +} +api Vec4I &operator-=(Vec4I &a, Vec4I b) { + a = a - b; + return a; +} +api Vec4I &operator-=(Vec4I &a, S32 b) { + a = a - b; + return a; +} +api Vec4I operator*(Vec4I a, Vec4I b) { + Vec4I result = v4i(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + return result; +} +api Vec4I operator*(Vec4I a, S32 b) { + Vec4I result = v4i(a.x * b, a.y * b, a.z * b, a.w * b); + return result; +} +api Vec4I operator*(S32 a, Vec4I b) { + Vec4I result = v4i(a * b.x, a * b.y, a * b.z, a * b.w); + return result; +} +api Vec4I &operator*=(Vec4I &a, Vec4I b) { + a = a * b; + return a; +} +api Vec4I &operator*=(Vec4I &a, S32 b) { + a = a * b; + return a; +} +api Vec4I operator/(Vec4I a, Vec4I b) { + Vec4I result = v4i(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + return result; +} +api Vec4I operator/(Vec4I a, S32 b) { + Vec4I result = v4i(a.x / b, a.y / b, a.z / b, a.w / b); + return result; +} +api Vec4I operator/(S32 a, Vec4I b) { + Vec4I result = v4i(a / b.x, a / b.y, a / b.z, a / b.w); + return result; +} +api Vec4I &operator/=(Vec4I &a, Vec4I b) { + a = a / b; + return a; +} +api Vec4I &operator/=(Vec4I &a, S32 b) { + a = a / b; + return a; +} +api B32 operator!=(Vec4I a, Vec4I b) { + B32 result = (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); + return result; +} +api B32 operator==(Vec4I a, Vec4I b) { + B32 result = (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); + return result; +} +api Vec4I operator-(Vec4I a) { + Vec4I result = v4i(-a.x, -a.y, -a.z, -a.w); + return result; +} +api Vec4I clamp(Vec4I min, Vec4I val, Vec4I max) { + Vec4I result = v4i(clamp(min.x, val.x, max.x), clamp(min.y, val.y, max.y), clamp(min.z, val.z, max.z), + clamp(min.w, val.w, max.w)); + return result; +} +api Vec4I clamp(S32 min, Vec4I val, S32 max) { + Vec4I result = + v4i(clamp(min, val.x, max), clamp(min, val.y, max), clamp(min, val.z, max), clamp(min, val.w, max)); + return result; +} +api Vec4I clamp01(Vec4I val) { + Vec4I result = v4i(clamp01(val.x), clamp01(val.y), clamp01(val.z), clamp01(val.w)); + return result; +} +api Rect2 rect2(F32 min_x, F32 min_y, F32 max_x, F32 max_y) { + Rect2 result; + result.min_x = min_x; + result.min_y = min_y; + result.max_x = max_x; + result.max_y = max_y; + return result; +} +api Rect2 rect2() { return rect2(0, 0, 0, 0); } +api Rect2 operator+(Rect2 a, Rect2 b) { + Rect2 result = rect2(a.min_x + b.min_x, a.min_y + b.min_y, a.max_x + b.max_x, a.max_y + b.max_y); + return result; +} +api Rect2 operator+(Rect2 a, F32 b) { + Rect2 result = rect2(a.min_x + b, a.min_y + b, a.max_x + b, a.max_y + b); + return result; +} +api Rect2 operator+(F32 a, Rect2 b) { + Rect2 result = rect2(a + b.min_x, a + b.min_y, a + b.max_x, a + b.max_y); + return result; +} +api Rect2 &operator+=(Rect2 &a, Rect2 b) { + a = a + b; + return a; +} +api Rect2 &operator+=(Rect2 &a, F32 b) { + a = a + b; + return a; +} +api Rect2 operator-(Rect2 a, Rect2 b) { + Rect2 result = rect2(a.min_x - b.min_x, a.min_y - b.min_y, a.max_x - b.max_x, a.max_y - b.max_y); + return result; +} +api Rect2 operator-(Rect2 a, F32 b) { + Rect2 result = rect2(a.min_x - b, a.min_y - b, a.max_x - b, a.max_y - b); + return result; +} +api Rect2 operator-(F32 a, Rect2 b) { + Rect2 result = rect2(a - b.min_x, a - b.min_y, a - b.max_x, a - b.max_y); + return result; +} +api Rect2 &operator-=(Rect2 &a, Rect2 b) { + a = a - b; + return a; +} +api Rect2 &operator-=(Rect2 &a, F32 b) { + a = a - b; + return a; +} +api Rect2 operator*(Rect2 a, Rect2 b) { + Rect2 result = rect2(a.min_x * b.min_x, a.min_y * b.min_y, a.max_x * b.max_x, a.max_y * b.max_y); + return result; +} +api Rect2 operator*(Rect2 a, F32 b) { + Rect2 result = rect2(a.min_x * b, a.min_y * b, a.max_x * b, a.max_y * b); + return result; +} +api Rect2 operator*(F32 a, Rect2 b) { + Rect2 result = rect2(a * b.min_x, a * b.min_y, a * b.max_x, a * b.max_y); + return result; +} +api Rect2 &operator*=(Rect2 &a, Rect2 b) { + a = a * b; + return a; +} +api Rect2 &operator*=(Rect2 &a, F32 b) { + a = a * b; + return a; +} +api Rect2 operator/(Rect2 a, Rect2 b) { + Rect2 result = rect2(a.min_x / b.min_x, a.min_y / b.min_y, a.max_x / b.max_x, a.max_y / b.max_y); + return result; +} +api Rect2 operator/(Rect2 a, F32 b) { + Rect2 result = rect2(a.min_x / b, a.min_y / b, a.max_x / b, a.max_y / b); + return result; +} +api Rect2 operator/(F32 a, Rect2 b) { + Rect2 result = rect2(a / b.min_x, a / b.min_y, a / b.max_x, a / b.max_y); + return result; +} +api Rect2 &operator/=(Rect2 &a, Rect2 b) { + a = a / b; + return a; +} +api Rect2 &operator/=(Rect2 &a, F32 b) { + a = a / b; + return a; +} +api B32 operator!=(Rect2 a, Rect2 b) { + B32 result = (a.min_x != b.min_x) || (a.min_y != b.min_y) || (a.max_x != b.max_x) || (a.max_y != b.max_y); + return result; +} +api B32 operator==(Rect2 a, Rect2 b) { + B32 result = (a.min_x == b.min_x) && (a.min_y == b.min_y) && (a.max_x == b.max_x) && (a.max_y == b.max_y); + return result; +} +api Rect2 operator-(Rect2 a) { + Rect2 result = rect2(-a.min_x, -a.min_y, -a.max_x, -a.max_y); + return result; +} +api Rect2 clamp(Rect2 min, Rect2 val, Rect2 max) { + Rect2 result = rect2(clamp(min.min_x, val.min_x, max.min_x), clamp(min.min_y, val.min_y, max.min_y), + clamp(min.max_x, val.max_x, max.max_x), clamp(min.max_y, val.max_y, max.max_y)); + return result; +} +api Rect2 clamp(F32 min, Rect2 val, F32 max) { + Rect2 result = rect2(clamp(min, val.min_x, max), clamp(min, val.min_y, max), clamp(min, val.max_x, max), + clamp(min, val.max_y, max)); + return result; +} +api Rect2 clamp01(Rect2 val) { + Rect2 result = rect2(clamp01(val.min_x), clamp01(val.min_y), clamp01(val.max_x), clamp01(val.max_y)); + return result; +} +api Rect2I rect2i(S32 min_x, S32 min_y, S32 max_x, S32 max_y) { + Rect2I result; + result.min_x = min_x; + result.min_y = min_y; + result.max_x = max_x; + result.max_y = max_y; + return result; +} +api Rect2I rect2i() { return rect2i(0, 0, 0, 0); } +api Rect2I operator+(Rect2I a, Rect2I b) { + Rect2I result = rect2i(a.min_x + b.min_x, a.min_y + b.min_y, a.max_x + b.max_x, a.max_y + b.max_y); + return result; +} +api Rect2I operator+(Rect2I a, S32 b) { + Rect2I result = rect2i(a.min_x + b, a.min_y + b, a.max_x + b, a.max_y + b); + return result; +} +api Rect2I operator+(S32 a, Rect2I b) { + Rect2I result = rect2i(a + b.min_x, a + b.min_y, a + b.max_x, a + b.max_y); + return result; +} +api Rect2I &operator+=(Rect2I &a, Rect2I b) { + a = a + b; + return a; +} +api Rect2I &operator+=(Rect2I &a, S32 b) { + a = a + b; + return a; +} +api Rect2I operator-(Rect2I a, Rect2I b) { + Rect2I result = rect2i(a.min_x - b.min_x, a.min_y - b.min_y, a.max_x - b.max_x, a.max_y - b.max_y); + return result; +} +api Rect2I operator-(Rect2I a, S32 b) { + Rect2I result = rect2i(a.min_x - b, a.min_y - b, a.max_x - b, a.max_y - b); + return result; +} +api Rect2I operator-(S32 a, Rect2I b) { + Rect2I result = rect2i(a - b.min_x, a - b.min_y, a - b.max_x, a - b.max_y); + return result; +} +api Rect2I &operator-=(Rect2I &a, Rect2I b) { + a = a - b; + return a; +} +api Rect2I &operator-=(Rect2I &a, S32 b) { + a = a - b; + return a; +} +api Rect2I operator*(Rect2I a, Rect2I b) { + Rect2I result = rect2i(a.min_x * b.min_x, a.min_y * b.min_y, a.max_x * b.max_x, a.max_y * b.max_y); + return result; +} +api Rect2I operator*(Rect2I a, S32 b) { + Rect2I result = rect2i(a.min_x * b, a.min_y * b, a.max_x * b, a.max_y * b); + return result; +} +api Rect2I operator*(S32 a, Rect2I b) { + Rect2I result = rect2i(a * b.min_x, a * b.min_y, a * b.max_x, a * b.max_y); + return result; +} +api Rect2I &operator*=(Rect2I &a, Rect2I b) { + a = a * b; + return a; +} +api Rect2I &operator*=(Rect2I &a, S32 b) { + a = a * b; + return a; +} +api Rect2I operator/(Rect2I a, Rect2I b) { + Rect2I result = rect2i(a.min_x / b.min_x, a.min_y / b.min_y, a.max_x / b.max_x, a.max_y / b.max_y); + return result; +} +api Rect2I operator/(Rect2I a, S32 b) { + Rect2I result = rect2i(a.min_x / b, a.min_y / b, a.max_x / b, a.max_y / b); + return result; +} +api Rect2I operator/(S32 a, Rect2I b) { + Rect2I result = rect2i(a / b.min_x, a / b.min_y, a / b.max_x, a / b.max_y); + return result; +} +api Rect2I &operator/=(Rect2I &a, Rect2I b) { + a = a / b; + return a; +} +api Rect2I &operator/=(Rect2I &a, S32 b) { + a = a / b; + return a; +} +api B32 operator!=(Rect2I a, Rect2I b) { + B32 result = (a.min_x != b.min_x) || (a.min_y != b.min_y) || (a.max_x != b.max_x) || (a.max_y != b.max_y); + return result; +} +api B32 operator==(Rect2I a, Rect2I b) { + B32 result = (a.min_x == b.min_x) && (a.min_y == b.min_y) && (a.max_x == b.max_x) && (a.max_y == b.max_y); + return result; +} +api Rect2I operator-(Rect2I a) { + Rect2I result = rect2i(-a.min_x, -a.min_y, -a.max_x, -a.max_y); + return result; +} +api Rect2I clamp(Rect2I min, Rect2I val, Rect2I max) { + Rect2I result = rect2i(clamp(min.min_x, val.min_x, max.min_x), clamp(min.min_y, val.min_y, max.min_y), + clamp(min.max_x, val.max_x, max.max_x), clamp(min.max_y, val.max_y, max.max_y)); + return result; +} +api Rect2I clamp(S32 min, Rect2I val, S32 max) { + Rect2I result = rect2i(clamp(min, val.min_x, max), clamp(min, val.min_y, max), clamp(min, val.max_x, max), + clamp(min, val.max_y, max)); + return result; +} +api Rect2I clamp01(Rect2I val) { + Rect2I result = rect2i(clamp01(val.min_x), clamp01(val.min_y), clamp01(val.max_x), clamp01(val.max_y)); + return result; +} +api Vec2 cast_v2(Vec2I a) { + Vec2 result = vec2((F32)(a.x), (F32)(a.y)); + return result; +} +api Vec2I cast_v2i(Vec2 a) { + Vec2I result = vec2i((S32)(a.x), (S32)(a.y)); + return result; +} +api Vec2I round_cast_v2i(Vec2 a) { + Vec2I result = vec2i((S32)round(a.x), (S32)round(a.y)); + return result; +} +api Vec2I ceil_cast_v2i(Vec2 a) { + Vec2I result = vec2i((S32)ceil(a.x), (S32)ceil(a.y)); + return result; +} +api Vec2I floor_cast_v2i(Vec2 a) { + Vec2I result = vec2i((S32)floor(a.x), (S32)floor(a.y)); + return result; +} +api Vec3 cast_v3(Vec3I a) { + Vec3 result = vec3((F32)(a.x), (F32)(a.y), (F32)(a.z)); + return result; +} +api Vec3I cast_v3i(Vec3 a) { + Vec3I result = vec3i((S32)(a.x), (S32)(a.y), (S32)(a.z)); + return result; +} +api Vec3I round_cast_v3i(Vec3 a) { + Vec3I result = vec3i((S32)round(a.x), (S32)round(a.y), (S32)round(a.z)); + return result; +} +api Vec3I ceil_cast_v3i(Vec3 a) { + Vec3I result = vec3i((S32)ceil(a.x), (S32)ceil(a.y), (S32)ceil(a.z)); + return result; +} +api Vec3I floor_cast_v3i(Vec3 a) { + Vec3I result = vec3i((S32)floor(a.x), (S32)floor(a.y), (S32)floor(a.z)); + return result; +} +api Vec4 cast_v4(Vec4I a) { + Vec4 result = vec4((F32)(a.x), (F32)(a.y), (F32)(a.z), (F32)(a.w)); + return result; +} +api Vec4I cast_v4i(Vec4 a) { + Vec4I result = v4i((S32)(a.x), (S32)(a.y), (S32)(a.z), (S32)(a.w)); + return result; +} +api Vec4I round_cast_v4i(Vec4 a) { + Vec4I result = v4i((S32)round(a.x), (S32)round(a.y), (S32)round(a.z), (S32)round(a.w)); + return result; +} +api Vec4I ceil_cast_v4i(Vec4 a) { + Vec4I result = v4i((S32)ceil(a.x), (S32)ceil(a.y), (S32)ceil(a.z), (S32)ceil(a.w)); + return result; +} +api Vec4I floor_cast_v4i(Vec4 a) { + Vec4I result = v4i((S32)floor(a.x), (S32)floor(a.y), (S32)floor(a.z), (S32)floor(a.w)); + return result; +} +api Rect2 cast_rect2(Rect2I a) { + Rect2 result = rect2((F32)(a.min_x), (F32)(a.min_y), (F32)(a.max_x), (F32)(a.max_y)); + return result; +} +api Rect2I cast_rect2i(Rect2 a) { + Rect2I result = rect2i((S32)(a.min_x), (S32)(a.min_y), (S32)(a.max_x), (S32)(a.max_y)); + return result; +} +api Rect2I round_cast_rect2i(Rect2 a) { + Rect2I result = rect2i((S32)round(a.min_x), (S32)round(a.min_y), (S32)round(a.max_x), (S32)round(a.max_y)); + return result; +} +api Rect2I ceil_cast_rect2i(Rect2 a) { + Rect2I result = rect2i((S32)ceil(a.min_x), (S32)ceil(a.min_y), (S32)ceil(a.max_x), (S32)ceil(a.max_y)); + return result; +} +api Rect2I floor_cast_rect2i(Rect2 a) { + Rect2I result = rect2i((S32)floor(a.min_x), (S32)floor(a.min_y), (S32)floor(a.max_x), (S32)floor(a.max_y)); + return result; +} +api Rect2I rect2i(Vec2I a, Vec2I b) { + Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); + return result; +} +api Rect2I rect2i(S32 a, Vec3I b) { + Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); + return result; +} +api Rect2I rect2i(Vec3I a, S32 b) { + Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); + return result; +} +api Rect2I rect2i(Vec2I a, S32 b, S32 c) { + Rect2I result = rect2i(a.p[0], a.p[1], b, c); + return result; +} +api Rect2I rect2i(S32 a, S32 b, Vec2I c) { + Rect2I result = rect2i(a, b, c.p[0], c.p[1]); + return result; +} +api Vec4I v4i(Vec2I a, Vec2I b) { + Vec4I result = v4i(a.p[0], a.p[1], b.p[0], b.p[1]); + return result; +} +api Vec4I v4i(S32 a, Vec3I b) { + Vec4I result = v4i(a, b.p[0], b.p[1], b.p[2]); + return result; +} +api Vec4I v4i(Vec3I a, S32 b) { + Vec4I result = v4i(a.p[0], a.p[1], a.p[2], b); + return result; +} +api Vec4I v4i(Vec2I a, S32 b, S32 c) { + Vec4I result = v4i(a.p[0], a.p[1], b, c); + return result; +} +api Vec4I v4i(S32 a, S32 b, Vec2I c) { + Vec4I result = v4i(a, b, c.p[0], c.p[1]); + return result; +} +api Rect2 rect2(Vec2 a, Vec2 b) { + Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); + return result; +} +api Rect2 rect2(F32 a, Vec3 b) { + Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); + return result; +} +api Rect2 rect2(Vec3 a, F32 b) { + Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); + return result; +} +api Rect2 rect2(Vec2 a, F32 b, F32 c) { + Rect2 result = rect2(a.p[0], a.p[1], b, c); + return result; +} +api Rect2 rect2(F32 a, F32 b, Vec2 c) { + Rect2 result = rect2(a, b, c.p[0], c.p[1]); + return result; +} +api Vec4 vec4(Vec2 a, Vec2 b) { + Vec4 result = vec4(a.p[0], a.p[1], b.p[0], b.p[1]); + return result; +} +api Vec4 vec4(F32 a, Vec3 b) { + Vec4 result = vec4(a, b.p[0], b.p[1], b.p[2]); + return result; +} +api Vec4 vec4(Vec3 a, F32 b) { + Vec4 result = vec4(a.p[0], a.p[1], a.p[2], b); + return result; +} +api Vec4 vec4(Vec2 a, F32 b, F32 c) { + Vec4 result = vec4(a.p[0], a.p[1], b, c); + return result; +} +api Vec4 vec4(F32 a, F32 b, Vec2 c) { + Vec4 result = vec4(a, b, c.p[0], c.p[1]); + return result; +} +api Rect2 rect2_min_size(Vec2 a, Vec2 b) { + Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); + result.max += result.min; + return result; +} +api Rect2 rect2_min_size(F32 a, Vec3 b) { + Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); + result.max += result.min; + return result; +} +api Rect2 rect2_min_size(Vec3 a, F32 b) { + Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); + result.max += result.min; + return result; +} +api Rect2 rect2_min_size(Vec2 a, F32 b, F32 c) { + Rect2 result = rect2(a.p[0], a.p[1], b, c); + result.max += result.min; + return result; +} +api Rect2 rect2_min_size(F32 a, F32 b, Vec2 c) { + Rect2 result = rect2(a, b, c.p[0], c.p[1]); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(Vec2I a, Vec2I b) { + Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(S32 a, Vec3I b) { + Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(Vec3I a, S32 b) { + Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(Vec2I a, S32 b, S32 c) { + Rect2I result = rect2i(a.p[0], a.p[1], b, c); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(S32 a, S32 b, Vec2I c) { + Rect2I result = rect2i(a, b, c.p[0], c.p[1]); + result.max += result.min; + return result; +} +api Rect2 rect2_center_half_dim(Vec2 a, Vec2 b) { + Rect2 result = rect2(a.p[0], a.p[1], b.p[0], b.p[1]); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2 rect2_center_half_dim(F32 a, Vec3 b) { + Rect2 result = rect2(a, b.p[0], b.p[1], b.p[2]); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2 rect2_center_half_dim(Vec3 a, F32 b) { + Rect2 result = rect2(a.p[0], a.p[1], a.p[2], b); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2 rect2_center_half_dim(Vec2 a, F32 b, F32 c) { + Rect2 result = rect2(a.p[0], a.p[1], b, c); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2 rect2_center_half_dim(F32 a, F32 b, Vec2 c) { + Rect2 result = rect2(a, b, c.p[0], c.p[1]); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(Vec2I a, Vec2I b) { + Rect2I result = rect2i(a.p[0], a.p[1], b.p[0], b.p[1]); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(S32 a, Vec3I b) { + Rect2I result = rect2i(a, b.p[0], b.p[1], b.p[2]); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(Vec3I a, S32 b) { + Rect2I result = rect2i(a.p[0], a.p[1], a.p[2], b); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(Vec2I a, S32 b, S32 c) { + Rect2I result = rect2i(a.p[0], a.p[1], b, c); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(S32 a, S32 b, Vec2I c) { + Rect2I result = rect2i(a, b, c.p[0], c.p[1]); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2 rect2_min_size(F32 a, F32 b, F32 c, F32 d) { + Rect2 result = rect2(a, b, c, d); + result.max += result.min; + return result; +} +api Rect2I rect2i_min_size(S32 a, S32 b, S32 c, S32 d) { + Rect2I result = rect2i(a, b, c, d); + result.max += result.min; + return result; +} +api Rect2 rect2_center_half_dim(F32 a, F32 b, F32 c, F32 d) { + Rect2 result = rect2(a, b, c, d); + Vec2 center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Rect2I rect2i_center_half_dim(S32 a, S32 b, S32 c, S32 d) { + Rect2I result = rect2i(a, b, c, d); + Vec2I center = result.min; + result.min -= result.max; + result.max += center; + return result; +} +api Vec3 vec3(F32 a, Vec2 b) { + Vec3 result = vec3(a, b.p[0], b.p[1]); + return result; +} +api Vec3 vec3(Vec2 a, F32 b) { + Vec3 result = vec3(a.p[0], a.p[1], b); + return result; +} +api Vec3I vec3i(S32 a, Vec2I b) { + Vec3I result = vec3i(a, b.p[0], b.p[1]); + return result; +} +api Vec3I vec3i(Vec2I a, S32 b) { + Vec3I result = vec3i(a.p[0], a.p[1], b); + return result; +} + +api Rect2I intersect(Rect2I a, Rect2I clip) { + Rect2I result; + result.min.x = max(a.min.x, clip.min.x); + result.min.y = max(a.min.y, clip.min.y); + result.max.x = min(a.max.x, clip.max.x); + result.max.y = min(a.max.y, clip.max.y); + return result; +} + +api B32 has_area(Rect2I a) { + B32 result = (a.max_x - a.min_x > 0) && (a.max_y - a.min_y > 0); + return result; +} + +api Rect2 intersect(Rect2 a, Rect2 clip) { + Rect2 result; + result.min.x = max(a.min.x, clip.min.x); + result.min.y = max(a.min.y, clip.min.y); + result.max.x = min(a.max.x, clip.max.x); + result.max.y = min(a.max.y, clip.max.y); + return result; +} + +api B32 has_area(Rect2 a) { + B32 result = (a.max_x - a.min_x > 0) && (a.max_y - a.min_y > 0); + return result; +} + +api Vec2 perp(Vec2 a) { + Vec2 result = vec2(-a.y, a.x); + return result; +} + +api Vec4 vec4argb(U32 v) { + U8 a = (v >> 24) & 0x000000ff; + U8 r = (v >> 16) & 0x000000ff; + U8 g = (v >> 8) & 0x000000ff; + U8 b = (v >> 0) & 0x000000ff; + Vec4 result = vec4((F32)r / 255.f, (F32)g / 255.f, (F32)b / 255.f, (F32)a / 255.f); + return result; +} + +api Vec4 vec4abgr(U32 c) { + float a = ((c & 0xff000000) >> 24) / 255.f; + float b = ((c & 0x00ff0000) >> 16) / 255.f; + float g = ((c & 0x0000ff00) >> 8) / 255.f; + float r = ((c & 0x000000ff) >> 0) / 255.f; + Vec4 result = vec4(r, g, b, a); + return result; +} + +api U32 vec4_to_u32argb(Vec4 c) { + U32 result = (U32)((U8)(c.a * 255.f) << 24u | (U8)(c.r * 255.f) << 16u | (U8)(c.g * 255.f) << 8u | + (U8)(c.b * 255.f) << 0u); + return result; +} + +api U32 vec4_to_u32abgr(Vec4 color) { + U8 red = (U8)(color.r * 255); + U8 green = (U8)(color.g * 255); + U8 blue = (U8)(color.b * 255); + U8 alpha = (U8)(color.a * 255); + U32 result = (U32)(alpha << 24 | blue << 16 | green << 8 | red << 0); + return result; +} + +api Mat4 operator*(Mat4 a, Mat4 b) { + Mat4 result; + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + result.p[y][x] = + a.p[y][0] * b.p[0][x] + a.p[y][1] * b.p[1][x] + a.p[y][2] * b.p[2][x] + a.p[y][3] * b.p[3][x]; + } + } + return result; +} + +api Vec4 operator*(Mat4 a, Vec4 b) { + Vec4 result; + for (int y = 0; y < 4; y++) { + result.p[y] = a.p[y][0] * b.p[0] + a.p[y][1] * b.p[1] + a.p[y][2] * b.p[2] + a.p[y][3] * b.p[3]; + } + return result; +} + +api Vec3 operator*(Mat4 a, Vec3 b) { + Vec4 result; + for (int y = 0; y < 4; y++) + result.p[y] = a.p[y][0] * b.p[0] + a.p[y][1] * b.p[1] + a.p[y][2] * b.p[2] + a.p[y][3] * 1; + return result.xyz; +} + +api Vec3 cross(Vec3 a, Vec3 b) { + Vec3 result; + result.x = a.y * b.z - a.z * b.y; + result.y = a.z * b.x - a.x * b.z; + result.z = a.x * b.y - a.y * b.x; + return result; +} + +api Vec2 normalize(Vec2 a) { + Vec2 result = {}; + F32 len = length(a); + if (len != 0.f) { + F32 inv_len = 1.0f / len; + result.x = a.x * inv_len; + result.y = a.y * inv_len; + } + return result; +} + +api Vec3 normalize(Vec3 a) { + Vec3 result = {}; + F32 len = length(a); + if (len != 0.f) { + F32 inv_len = 1.0f / len; + result.x = a.x * inv_len; + result.y = a.y * inv_len; + result.z = a.z * inv_len; + } + return result; +} + +api Vec4 normalize(Vec4 a) { + Vec4 result = {}; + F32 len = length(a); + if (len != 0.f) { + F32 inv_len = 1.0f / len; + result.x = a.x * inv_len; + result.y = a.y * inv_len; + result.z = a.z * inv_len; + result.w = a.w * inv_len; + } + return result; +} + +function Mat4 mat4_identity() { - return { - 1,0,0,0, - 0,1,0,0, - 0,0,1,0, - 0,0,0,1, - }; + Mat4 result = {}; + result.p[0][0] = 1; + result.p[1][1] = 1; + result.p[2][2] = 1; + result.p[3][3] = 1; + return result; } -FUNCTION +function Mat4 mat4_scale(Vec3 a) { - return { - a.x, 0, 0, 0, - 0, a.y, 0, 0, - 0, 0, a.z, 0, - 0, 0, 0, 1 - }; + Mat4 result = {}; + result.p[0][0] = a.x; + result.p[1][1] = a.y; + result.p[2][2] = a.z; + result.p[3][3] = 1; + return result; } -FUNCTION +function Mat4 mat4_translation(Vec3 a) { return { 1, 0, 0, a.x, @@ -28,7 +1624,7 @@ Mat4 mat4_translation(Vec3 a) { }; } -FUNCTION +function Mat4 mat4_rotation_z(float rotation) { float s = sinf(rotation); float c = cosf(rotation); @@ -41,7 +1637,7 @@ Mat4 mat4_rotation_z(float rotation) { return result; } -FUNCTION +function Mat4 mat4_rotation_y(float rotation) { float s = sinf(rotation); float c = cosf(rotation); @@ -54,7 +1650,7 @@ Mat4 mat4_rotation_y(float rotation) { return result; } -FUNCTION +function Mat4 mat4_rotation_x(float rotation) { float s = sinf(rotation); float c = cosf(rotation); @@ -67,7 +1663,9 @@ Mat4 mat4_rotation_x(float rotation) { return result; } -FUNCTION +constexpr F32 deg2rad = (PI32 / 180.f); // @Usage: degree * deg2rad = radians; +constexpr F32 rad2deg = (180.f / PI32); +function Mat4 mat4_perspective(float fov, float window_x, float window_y, float znear, float zfar) { float aspect_ratio = window_y / window_x; float f = (1.f / tanf((fov/2.f)*deg2rad)); @@ -80,7 +1678,7 @@ Mat4 mat4_perspective(float fov, float window_x, float window_y, float znear, fl return result; } -FN Mat4 mat4_look_at(Vec3 pos, Vec3 target, Vec3 up) { +function Mat4 mat4_look_at(Vec3 pos, Vec3 target, Vec3 up) { Vec3 z = normalize(target - pos); Vec3 x = normalize(cross(up, z)); Vec3 y = cross(z, x); @@ -93,7 +1691,7 @@ FN Mat4 mat4_look_at(Vec3 pos, Vec3 target, Vec3 up) { return result; } -FUNCTION +function Mat4 mat4_transpose(Mat4 a) { Mat4 result = a; result.p[0][1] = result.p[1][0]; @@ -105,7 +1703,7 @@ Mat4 mat4_transpose(Mat4 a) { return result; } -FUNCTION +function Mat4 mat4_translate(Mat4 a, Vec3 translation) { a.p[0][0] += translation.x; a.p[0][1] += translation.y; diff --git a/obj_parser.cpp b/obj_parser.cpp index 653eba2..6cfbe17 100644 --- a/obj_parser.cpp +++ b/obj_parser.cpp @@ -1,73 +1,66 @@ -template -struct DynamicArray { - T *e; - U64 cap, len; - T *push_empty(int element_count = 1) { - if (cap == 0) { - cap = 8; - e = (T*)malloc(sizeof(T)*cap); - } - else if (len + element_count > cap) { - U64 new_size = (len + element_count) * 2; - void *ptr = realloc(e, new_size*sizeof(T)); - if (!ptr) FATAL_ERROR("Ran out of memory! Cant allocate more."); - e = (T *)ptr; - cap = new_size; - } - T *result = e + len; - len += element_count; - return result; - } - void push(T element) { - T *result = push_empty(); - *result = element; - } -}; - -struct ObjIndex { +struct Obj_Index { int vertex[3]; int tex[3]; int normal[3]; - I32 material_id; - I32 smoothing_group_id; + S32 material_id; + S32 smoothing_group_id; }; -struct ObjMesh { +struct Obj_Mesh { char name[64]; - DynamicArray indices; + Array indices; }; -struct OBJMaterial { +struct Obj_Material { char name[64]; U32 name_len; Bitmap texture_ambient; // map_Ka Bitmap texture_diffuse; // map_Kd Bitmap texture_dissolve; // map_d - Bitmap texture_displacment; // map_Disp + Bitmap texture_displacement; // map_Disp F32 non_transparency; // d F32 transparency; // Tr F32 optical_density; // Ni F32 shininess; // Ns - I32 illumination_model; // illum + S32 illumination_model; // illum Vec3 ambient_color; // Ka Vec3 diffuse_color; // Kd Vec3 specular_color; // Ks }; struct Obj { - S8 name; - DynamicArray vertices; - DynamicArray texture_coordinates; - DynamicArray normals; - DynamicArray mesh; - DynamicArray materials; + String name; + Array vertices; + Array texture_coordinates; + Array normals; + Array mesh; + Array materials; }; -FUNCTION -Bitmap load_image(const char* path) { +enum class Obj_Token_Type { + none, word, number, whitespace, end +}; + +struct Obj_Token { + Obj_Token_Type type; + double number; + union { + struct { + char* s; + int len; + }; + String s8; + }; +}; + +function Bitmap +load_image(String path) { + Scratch scratch; + String file = os_read_file(scratch, path); + int x, y, n; - unsigned char* data = stbi_load(path, &x, &y, &n, 4); + unsigned char* data = stbi_load_from_memory(file.str, file.len, &x, &y, &n, 4); Bitmap result = { (U32*)data, x, y }; #if PREMULTIPLIED_ALPHA_BLENDING if(data) { @@ -86,36 +79,20 @@ Bitmap load_image(const char* path) { return result; } -enum class OBJTokenType { - none, word, number, whitespace, end -}; - -struct OBJToken { - OBJTokenType type; - double number; - union { - struct { - char* s; - int len; - }; - S8 s8; - }; -}; - -FUNCTION OBJToken next_token_raw(char** data) { - OBJToken result = {}; +function Obj_Token next_token_raw(char** data) { + Obj_Token result = {}; result.s = *data; *data += 1; - + if (is_alphabetic(*result.s)) { - result.type = OBJTokenType::word; + result.type = Obj_Token_Type::word; while (!is_whitespace(**data)) { *data += 1; } result.len = (int)(*data - result.s); } else if (is_number(*result.s) || *result.s == '-') { - result.type = OBJTokenType::number; + result.type = Obj_Token_Type::number; while (is_number(**data) || **data == '.' || **data == 'e' || **data == '-') { *data += 1; } @@ -127,198 +104,206 @@ FUNCTION OBJToken next_token_raw(char** data) { result = next_token_raw(data); } else if (is_whitespace(*result.s)) { - result.type = OBJTokenType::whitespace; + result.type = Obj_Token_Type::whitespace; while (is_whitespace(**data)) *data += 1; result.len = (int)(*data - result.s); } else if (*result.s == 0) { - result.type = OBJTokenType::end; + result.type = Obj_Token_Type::end; } else if (*result.s >= '!') { - result.type = (OBJTokenType)*result.s; + result.type = (Obj_Token_Type)*result.s; } - + return result; } -FUNCTION OBJToken next_token(char** data) { - OBJToken result; +function Obj_Token next_token(char** data) { + Obj_Token result; do { result = next_token_raw(data); - } while (result.type == OBJTokenType::whitespace); + } while (result.type == Obj_Token_Type::whitespace); return result; } -FUNCTION double expect_number(char** data) { - OBJToken t = next_token(data); - TASSERT(t.type == OBJTokenType::number); // @Todo: Error handling, error flag +function double expect_number(char** data) { + Obj_Token t = next_token(data); + assert(t.type == Obj_Token_Type::number); // @Todo: Error handling, error flag return t.number; } -FUNCTION void expect_token(char** data, char token) { - OBJToken t = next_token(data); - TASSERT(t.type == (OBJTokenType)token); // @Todo: Error handling, error flag +function void expect_token(char** data, char token) { + Obj_Token t = next_token(data); + assert(t.type == (Obj_Token_Type)token); // @Todo: Error handling, error flag } -FUNCTION void debug_expect_raw(char** data, OBJTokenType type) { +function void debug_expect_raw(char** data, Obj_Token_Type type) { char* data_temp = *data; - OBJToken t = next_token_raw(&data_temp); - TASSERT(t.type == type); + Obj_Token t = next_token_raw(&data_temp); + assert(t.type == type); } -FUNCTION void parse_mtl(Arena *arena, Obj* obj, S8 path_obj_folder, S8 mtl_file) { +function void +parse_mtl(Obj* obj, String path_obj_folder, String mtl_file) { Scratch scratch; char *data = (char *)mtl_file.str; - OBJMaterial *m = 0; + Obj_Material *m = 0; + for (;;) { - OBJToken token = next_token(&data); - if (token.type == OBJTokenType::end) break; - else if (token.type == OBJTokenType::word) { - if (string_compare(token.s8, LIT("newmtl"))) { + Obj_Token token = next_token(&data); + if (token.type == Obj_Token_Type::end) break; + else if (token.type == Obj_Token_Type::word) { + if (string_compare(token.s8, "newmtl"_s)) { token = next_token(&data); - m = obj->materials.push_empty(); - ZERO_STRUCT(m); - m->name_len = CLAMP_TOP(token.len, 64); - memory_copy(token.s8.str, m->name, m->name_len); + m = obj->materials.push_empty_zero(); + m->name_len = clamp_top(token.len, 64); + memory_copy(m->name, token.s8.str, m->name_len); } - else if (string_compare(token.s8, LIT("Ns"))) { + else if (string_compare(token.s8, "Ns"_s)) { m->shininess = expect_number(&data); } - else if (string_compare(token.s8, LIT("Ka"))) { + else if (string_compare(token.s8, "Ka"_s)) { m->ambient_color.x = expect_number(&data); m->ambient_color.y = expect_number(&data); m->ambient_color.z = expect_number(&data); } - else if (string_compare(token.s8, LIT("Kd"))) { + else if (string_compare(token.s8, "Kd"_s)) { m->diffuse_color.x = expect_number(&data); m->diffuse_color.y = expect_number(&data); m->diffuse_color.z = expect_number(&data); } - else if (string_compare(token.s8, LIT("Ks"))) { + else if (string_compare(token.s8, "Ks"_s)) { m->specular_color.x = expect_number(&data); m->specular_color.y = expect_number(&data); m->specular_color.z = expect_number(&data); } - else if (string_compare(token.s8, LIT("Ni"))) { + else if (string_compare(token.s8, "Ni"_s)) { m->optical_density = expect_number(&data); } - else if (string_compare(token.s8, LIT("d"))) { + else if (string_compare(token.s8, "d"_s)) { m->non_transparency = expect_number(&data); } - else if (string_compare(token.s8, LIT("illum"))) { - m->illumination_model = (I32)expect_number(&data); + else if (string_compare(token.s8, "illum"_s)) { + m->illumination_model = (S32)expect_number(&data); } - else if (string_compare(token.s8, LIT("map_Kd"))) { - OBJToken t = next_token(&data); - S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8); - m->texture_diffuse = load_image((const char *)path.str); + else if (string_compare(token.s8, "map_Kd"_s)) { + Obj_Token t = next_token(&data); + String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8); + m->texture_diffuse = load_image(path); } - else if (string_compare(token.s8, LIT("map_Ka"))) { - OBJToken t = next_token(&data); - S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8); - m->texture_ambient = load_image((const char *)path.str); + else if (string_compare(token.s8, "map_Ka"_s)) { + Obj_Token t = next_token(&data); + String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8); + m->texture_ambient = load_image(path); } - else if (string_compare(token.s8, LIT("map_d"))) { - OBJToken t = next_token(&data); - S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8); - m->texture_dissolve = load_image((const char *)path.str); + else if (string_compare(token.s8, "map_d"_s)) { + Obj_Token t = next_token(&data); + String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8); + m->texture_dissolve = load_image(path); } - else if (string_compare(token.s8, LIT("map_Disp"))) { - OBJToken t = next_token(&data); - S8 path = string_format(scratch, "%s/%s\0", path_obj_folder, t.s8); - m->texture_displacment = load_image((const char *)path.str); + else if (string_compare(token.s8, "map_Disp"_s)) { + Obj_Token t = next_token(&data); + String path = string_fmt(scratch, "%Q/%Q\0", path_obj_folder, t.s8); + m->texture_displacement = load_image(path); } } } } -FUNCTION Obj parse(Arena *arena, char* data, S8 path_obj_folder) { +function Obj +parse(Allocator *allocator, char* data, String path_obj_folder) { Scratch mtl_scratch; Obj result = {}; + result.vertices.init(allocator, 160000); + result.texture_coordinates.init(allocator, 160000); + result.normals.init(allocator, 160000); + result.mesh.init(allocator, 64); + result.materials.init(allocator, 64); int smoothing = 0; - ObjMesh *mesh = result.mesh.push_empty(); - ZERO_STRUCT(mesh); + + Obj_Mesh *mesh = result.mesh.push_empty_zero(); + mesh->indices.init(allocator); int material_id = -1; - - for (;; ) { - OBJToken token = next_token(&data); - if (token.type == OBJTokenType::end) break; - else if (token.type == OBJTokenType::word) { - if (string_compare(token.s8, LIT("v"))) { - Vec3 *vertex = result.vertices.push_empty(); + + S64 debug_i = 0; + for (;;debug_i++){ + Obj_Token token = next_token(&data); + if (token.type == Obj_Token_Type::end) break; + else if (token.type == Obj_Token_Type::word) { + if (string_compare(token.s8, "v"_s)) { + Vec3 *vertex = result.vertices.push_empty_zero(); vertex->x = (float)expect_number(&data); vertex->y = (float)expect_number(&data); vertex->z = (float)expect_number(&data); - debug_expect_raw(&data, OBJTokenType::whitespace); + debug_expect_raw(&data, Obj_Token_Type::whitespace); } - else if (string_compare(token.s8, LIT("vt"))) { - Vec2 *tex = result.texture_coordinates.push_empty(); + else if (string_compare(token.s8, "vt"_s)) { + Vec2 *tex = result.texture_coordinates.push_empty_zero(); tex->x = (float)expect_number(&data); tex->y = (float)expect_number(&data); - debug_expect_raw(&data, OBJTokenType::whitespace); + debug_expect_raw(&data, Obj_Token_Type::whitespace); } - else if (string_compare(token.s8, LIT("vn"))) { - Vec3 *norm = result.normals.push_empty(); + else if (string_compare(token.s8, "vn"_s)) { + Vec3 *norm = result.normals.push_empty_zero(); norm->x = (float)expect_number(&data); norm->y = (float)expect_number(&data); norm->z = (float)expect_number(&data); - debug_expect_raw(&data, OBJTokenType::whitespace); + debug_expect_raw(&data, Obj_Token_Type::whitespace); } - else if (string_compare(token.s8, LIT("mtllib"))) { - OBJToken t = next_token(&data); - S8 path = string_format(mtl_scratch, "%s/%s", path_obj_folder, t.s8); - Result mtl_file = os_read_file(mtl_scratch, path); - if(mtl_file.no_error()) { - PUSH_SIZE(mtl_scratch, 1); - parse_mtl(arena, &result, path_obj_folder, mtl_file.result); + else if (string_compare(token.s8, "mtllib"_s)) { + Obj_Token t = next_token(&data); + String path = string_fmt(mtl_scratch, "%Q/%Q", path_obj_folder, t.s8); + String mtl_file = os_read_file(mtl_scratch, path); + if(mtl_file.str) { + parse_mtl(&result, path_obj_folder, mtl_file); } } - else if (string_compare(token.s8, LIT("usemtl"))) { - OBJToken t = next_token(&data); - TASSERT(t.type == OBJTokenType::word); + else if (string_compare(token.s8, "usemtl"_s)) { + Obj_Token t = next_token(&data); + assert(t.type == Obj_Token_Type::word); for(U64 i = 0; i < result.materials.len; i++) { - OBJMaterial *m = result.materials.e + i; - if(string_compare(string_make((U8 *)m->name, m->name_len), t.s8)) { + Obj_Material *m = result.materials.data + i; + if(string_compare({(U8 *)m->name, m->name_len}, t.s8)) { material_id = i; break; } } } - else if (string_compare(token.s8, LIT("o"))) { - OBJToken t = next_token(&data); - TASSERT(t.type == OBJTokenType::word); + else if (string_compare(token.s8, "o"_s)) { + Obj_Token t = next_token(&data); + assert(t.type == Obj_Token_Type::word); if (mesh->indices.len != 0) { - mesh = result.mesh.push_empty(); - ZERO_STRUCT(mesh); + mesh = result.mesh.push_empty_zero(); + mesh->indices.init(allocator); } else { - U64 len = CLAMP_TOP(t.len, 64); - memory_copy(t.s, mesh->name, len); + U64 len = clamp_top(t.len, 64); + memory_copy(mesh->name, t.s, len); } } - else if (string_compare(token.s8, LIT("s"))) { - OBJToken t = next_token(&data); - if (t.type == OBJTokenType::number) { + else if (string_compare(token.s8, "s"_s)) { + Obj_Token t = next_token(&data); + if (t.type == Obj_Token_Type::number) { smoothing = (int)t.number; } else { - TASSERT(t.type == OBJTokenType::word); - if (string_compare(t.s8, LIT("on"))) { + assert(t.type == Obj_Token_Type::word); + if (string_compare(t.s8, "on"_s)) { smoothing = 1; } - else if (string_compare(t.s8, LIT("off"))) { + else if (string_compare(t.s8, "off"_s)) { smoothing = 0; } - else INVALID_CODEPATH; + else invalid_codepath; } } - else if (string_compare(token.s8, LIT("g"))) { - OBJToken t = next_token(&data); - TASSERT(t.type == OBJTokenType::word); + else if (string_compare(token.s8, "g"_s)) { + Obj_Token t = next_token(&data); + assert(t.type == Obj_Token_Type::word); } - else if (string_compare(token.s8, LIT("f"))) { - ObjIndex *i = mesh->indices.push_empty(); + else if (string_compare(token.s8, "f"_s)) { + Obj_Index *i = mesh->indices.push_empty_zero(); i->smoothing_group_id = smoothing; i->material_id = material_id; i->vertex[0] = (int)expect_number(&data); @@ -326,53 +311,206 @@ FUNCTION Obj parse(Arena *arena, char* data, S8 path_obj_folder) { i->tex[0] = (int)expect_number(&data); expect_token(&data, '/'); i->normal[0] = (int)expect_number(&data); - + i->vertex[1] = (int)expect_number(&data); expect_token(&data, '/'); i->tex[1] = (int)expect_number(&data); expect_token(&data, '/'); i->normal[1] = (int)expect_number(&data); - + i->vertex[2] = (int)expect_number(&data); expect_token(&data, '/'); i->tex[2] = (int)expect_number(&data); expect_token(&data, '/'); i->normal[2] = (int)expect_number(&data); - //debug_expect_raw(&data, OBJTokenType::whitespace); + //debug_expect_raw(&data, Obj_Token_Type::whitespace); } } } return result; } -FUNCTION void test_lex() { +function void +test_lex() { const char* d = "v 0.885739 0.001910 -0.380334"; char* dd = (char *)d; - TASSERT(next_token(&dd).type == OBJTokenType::word); - OBJToken t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number > 0.8857); - t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number > 0.0019); - t = next_token(&dd); TASSERT(t.type == OBJTokenType::number && t.number < -0.38); + assert(next_token(&dd).type == Obj_Token_Type::word); + Obj_Token t = next_token(&dd); assert(t.type == Obj_Token_Type::number && t.number > 0.8857); + t = next_token(&dd); assert(t.type == Obj_Token_Type::number && t.number > 0.0019); + t = next_token(&dd); assert(t.type == Obj_Token_Type::number && t.number < -0.38); d = "# Blender v2.79 (sub 0) OBJ File: 'fighters_0.blend'\n" "# www.blender.org\n" "mtllib f-22.mtl\n" "o F-22\n"; dd = (char *)d; - t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("mtllib"))); - t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("f-22.mtl"))); - t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("o"))); - t = next_token(&dd); TASSERT(t.type == OBJTokenType::word && string_compare(t.s8, LIT("F-22"))); + t = next_token(&dd); assert(t.type == Obj_Token_Type::word && string_compare(t.s8, "mtllib"_s)); + t = next_token(&dd); assert(t.type == Obj_Token_Type::word && string_compare(t.s8, "f-22.mtl"_s)); + t = next_token(&dd); assert(t.type == Obj_Token_Type::word && string_compare(t.s8, "o"_s)); + t = next_token(&dd); assert(t.type == Obj_Token_Type::word && string_compare(t.s8, "F-22"_s)); } void test() { test_lex(); } -FUNCTION Obj load_obj(Arena *arena, S8 file) { +function Obj +load_obj(Allocator *arena, String file) { Scratch scratch; - S8 data = os_read_file(scratch, file).error_is_fatal(); - PUSH_SIZE(scratch, 1); - S8 path = string_chop_last_slash(file); + String data = os_read_file(scratch, file); + assert(data.str); + + String path = string_chop_last_slash(file); Obj result = parse(arena, (char *)data.str, path); result.name = file; return result; } + +template void +dump_array(String_Builder *sb, Array *arr){ + sb->append_data(arr, sizeof(*arr)); + sb->append_data(arr->data, sizeof(T)*arr->len); +} + +function void +dump_bitmap_image(String_Builder *sb, Bitmap *bm){ + sb->append_data(bm->pixels, sizeof(U32)*bm->x*bm->y); +} + +function B32 +_os_write_file(String file, String data, B32 append = false) { + B32 result = false; + DWORD access = GENERIC_WRITE; + DWORD creation_disposition = CREATE_ALWAYS; + if (append) { + access = FILE_APPEND_DATA; + creation_disposition = OPEN_ALWAYS; + } + + Scratch scratch; // @Todo(Krzosa): Unicode + HANDLE handle = CreateFileA((const char *)file.str, access, 0, NULL, creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle != INVALID_HANDLE_VALUE) { + DWORD bytes_written = 0; + // @Todo: can only read 32 byte size files? + assert_msg(data.len == (U32)data.len, + "Max data size os_write can handle is 32 bytes, data to write is " + "larger then 32 bytes!"); + B32 error = WriteFile(handle, data.str, (U32)data.len, &bytes_written, NULL); + if (error == false) { + log_error("Failed to write to file: %Q", file); + } + else { + if (bytes_written != data.len) { + log_error("Failed to write to file: %Q, mismatch between length requested to write and length written", file); + } + else{ + result = true; + } + } + CloseHandle(handle); + } + else { + log_error("File not found when trying to write: %Q", file); + } + + return result; +} + +function B32 +os_write_file(String file, String data) { + return _os_write_file(file, data, false); +} +function B32 +os_append_file(String file, String data) { + return _os_write_file(file, data, true); +} + +struct Stream{ + U8 *cursor; + U8 *end; +}; + +#define stream_read_array(s,T,c) (T *)stream_read(s,sizeof(T)*(c)) +#define stream_read_struct(s,T) stream_read_array(s,T,1) +function void * +stream_read(Stream *s, SizeU size){ + U8 *result = s->cursor; + s->cursor += size; + assert(s->end >= s->cursor); + return result; +} + +function void +dump_obj_to_file(Obj *obj){ + obj->vertices.allocator = 0; + obj->vertices.cap = obj->vertices.len; + + obj->texture_coordinates.allocator = 0; + obj->texture_coordinates.cap = obj->texture_coordinates.len; + + obj->normals.allocator = 0; + obj->normals.cap = obj->normals.len; + + obj->mesh.allocator = 0; + obj->mesh.cap = obj->mesh.len; + + obj->materials.allocator = 0; + obj->materials.cap = obj->materials.len; + + Iter(obj->mesh){ + it->indices.allocator = 0; + it->indices.cap = it->indices.len; + } + + Scratch arena; + String_Builder sb = string_builder_make(arena, mib(4)); + sb.append_data(obj, sizeof(Obj)); + sb.append_data(obj->name.str, obj->name.len); + sb.append_data(obj->vertices.data, obj->vertices.len*sizeof(Vec3)); + sb.append_data(obj->texture_coordinates.data, obj->texture_coordinates.len*sizeof(Vec2)); + sb.append_data(obj->normals.data, obj->normals.len*sizeof(Vec3)); + sb.append_data(obj->mesh.data, obj->mesh.len*sizeof(Obj_Mesh)); + sb.append_data(obj->materials.data, obj->materials.len*sizeof(Obj_Material)); + + Iter(obj->mesh){ + sb.append_data(it->indices.data, sizeof(Obj_Index)*it->indices.len); + } + + Iter(obj->materials){ + sb.append_data(it, sizeof(Obj_Material)); + dump_bitmap_image(&sb, &it->texture_ambient); + dump_bitmap_image(&sb, &it->texture_diffuse); + dump_bitmap_image(&sb, &it->texture_dissolve); + dump_bitmap_image(&sb, &it->texture_displacement); + } + + String result = string_flatten(&sb); + os_write_file("sponza.bin"_s, result); +} + +function Obj * +load_obj_dump(Allocator *allocator, String filename){ + String string = os_read_file(allocator, filename); + + Obj *obj = (Obj *)string.str; + Stream stream = {(U8 *)(obj+1), string.str + string.len}; + obj->name.str = stream_read_array(&stream, U8, obj->name.len); + obj->vertices.data = stream_read_array(&stream, Vec3, obj->vertices.len); + obj->texture_coordinates.data = stream_read_array(&stream, Vec2, obj->texture_coordinates.len); + obj->normals.data = stream_read_array(&stream, Vec3, obj->normals.len); + obj->mesh.data = stream_read_array(&stream, Obj_Mesh, obj->mesh.len); + obj->materials.data = stream_read_array(&stream, Obj_Material, obj->materials.len); + + Iter(obj->mesh){ + it->indices.data = stream_read_array(&stream, Obj_Index, it->indices.len); + } + + Iter(obj->materials){ + it->texture_ambient.pixels = stream_read_array(&stream, U32, it->texture_ambient.x*it->texture_ambient.y); + it->texture_diffuse.pixels = stream_read_array(&stream, U32, it->texture_diffuse.x*it->texture_diffuse.y); + it->texture_dissolve.pixels = stream_read_array(&stream, U32, it->texture_dissolve.x*it->texture_dissolve.y); + it->texture_displacement.pixels = stream_read_array(&stream, U32, it->texture_displacement.x*it->texture_displacement.y); + } + + return obj; +} + diff --git a/profile.cpp b/profile.cpp index dc671dd..32b153d 100644 --- a/profile.cpp +++ b/profile.cpp @@ -5,26 +5,26 @@ enum ProfileScopeName { struct ProfileScope { U64 samples[5096]; - I64 i; + S64 i; }; -GLOBAL ProfileScope profile_scopes[ProfileScopeName_Count]; +global ProfileScope profile_scopes[ProfileScopeName_Count]; #define PROFILE_BEGIN(name) do { \ - ProfileScope *__profile_scope = profile_scopes + ProfileScopeName_##name; \ - __profile_scope->samples[__profile_scope->i] = __rdtsc(); \ +ProfileScope *__profile_scope = profile_scopes + ProfileScopeName_##name; \ +__profile_scope->samples[__profile_scope->i] = __rdtsc(); \ } while (0) #define PROFILE_END(name) do { \ - ProfileScope *_profile_scope = profile_scopes + ProfileScopeName_##name; \ - _profile_scope->samples[_profile_scope->i] = __rdtsc() - _profile_scope->samples[_profile_scope->i]; \ - _profile_scope->i = (_profile_scope->i + 1) % 5096; \ +ProfileScope *_profile_scope = profile_scopes + ProfileScopeName_##name; \ +_profile_scope->samples[_profile_scope->i] = __rdtsc() - _profile_scope->samples[_profile_scope->i]; \ +_profile_scope->i = (_profile_scope->i + 1) % 5096; \ }while (0) -FN void save_profile_data(ProfileScope *scope, S8 scenario_name, S8 scope_name) { - /*for (I64 si = 1; si < scope->i; si++) { - for (I64 sj = 1; sj < scope->i; sj++) { +function void save_profile_data(ProfileScope *scope, S8 scenario_name, S8 scope_name) { + /*for (S64 si = 1; si < scope->i; si++) { + for (S64 sj = 1; sj < scope->i; sj++) { if (scope->samples[sj] < scope->samples[sj - 1]) { F64 temp = scope->samples[sj]; scope->samples[sj] = scope->samples[sj-1]; @@ -32,21 +32,22 @@ FN void save_profile_data(ProfileScope *scope, S8 scenario_name, S8 scope_name) } } }*/ - - Scratch scratch; - scenario_name = string_chop_last_period(scenario_name); - scenario_name = string_skip_to_last_slash(scenario_name); - U8 *string_pointer = string_begin(scratch); - S8 build_name = BUILD_NAME; - string_format(scratch, "%s %s\n", build_name, scenario_name); - I64 one_past_last = scope->i; - for (I64 si = 0; si < one_past_last; si++) { - string_format(scratch, "%u\n", scope->samples[si]); - } - - S8 data = string_end(scratch, string_pointer); - Date date = os_date(); - os_make_dir(LIT("stats")); - S8 name = string_format(scratch, "stats/%s_%s_%s_%u_%u_%u_%u_%u_%u.txt", scope_name, build_name, scenario_name, date.year, date.month, date.day, date.hour, date.minute, date.second); - os_append_file(name, data); + + /* + Scratch scratch; + scenario_name = string_chop_last_period(scenario_name); + scenario_name = string_skip_to_last_slash(scenario_name); + U8 *string_pointer = string_begin(scratch); + string_fmt(scratch, "%s %s\n", build_name, scenario_name); + S64 one_past_last = scope->i; + for (S64 si = 0; si < one_past_last; si++) { + string_fmt(scratch, "%u\n", scope->samples[si]); + } + + S8 data = string_end(scratch, string_pointer); + Date date = os_date(); + os_make_dir(LIT("stats")); + S8 name = string_fmt(scratch, "stats/%s_%s_%s_%u_%u_%u_%u_%u_%u.txt", scope_name, build_name, scenario_name, date.year, date.month, date.day, date.hour, date.minute, date.second); + os_append_file(name, data); + */ } \ No newline at end of file diff --git a/project.4c b/project.4c new file mode 100644 index 0000000..2497131 --- /dev/null +++ b/project.4c @@ -0,0 +1,9 @@ +project_name='software_render' +whitelist=['*.cpp' '*.c' '*.h' '*.4c'] +blacklist=[] +F1='build.bat' +F5='build.bat && remedybg start-debugging' +F10='build.bat && remedybg run-to-cursor {file} {line}' +F11='remedybg main.exe' +include=['{project}'] +// includes_recursive='false' diff --git a/stb_image.cpp b/stb_image.cpp deleted file mode 100644 index 8ddfd1f..0000000 --- a/stb_image.cpp +++ /dev/null @@ -1,2 +0,0 @@ -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" diff --git a/ui.cpp b/ui.cpp index e5b7b5a..0fe8b54 100644 --- a/ui.cpp +++ b/ui.cpp @@ -12,20 +12,20 @@ enum UIWidgetKind { typedef UI_SIGNAL_CALLBACK(UISignalCallback); struct UISetup { UIWidgetKind kind; - S8 text; + String text; union { void *v; Bitmap *image; B32 *b32; - S8 *label; - I32 *option; + String *label; + S32 *option; UISignalCallback *signal_callback; }; - I32 option_max; + S32 option_max; }; #define UI_BOOL(text, x) {UIWidgetKind_Boolean,text,(void*)(x)} -#define UI_IMAGE(x) {UIWidgetKind_Image,string_null,(void*)(x)} -#define UI_LABEL(x) {UIWidgetKind_Label,string_null,(void*)(x)} +#define UI_IMAGE(x) {UIWidgetKind_Image,{},(void*)(x)} +#define UI_LABEL(x) {UIWidgetKind_Label,{},(void*)(x)} #define UI_OPTION(text,x,option_max){UIWidgetKind_Option,text,(void*)(x),(option_max)} #define UI_SIGNAL(text,x){UIWidgetKind_Signal,text,(void*)(x)} @@ -35,66 +35,66 @@ struct UIWidget { UIWidget *prev; UIWidget *first_child; UIWidget *last_child; - - S8 text; + + String text; Vec2 size; - I32 option_max; + S32 option_max; union { Bitmap *image; B32 *b32; - S8 *label; - I32 *option; + String *label; + S32 *option; UISignalCallback *signal_callback; } ptr; }; struct UI : UIWidget { Arena arena; - + UIWidget *hot; UIWidget *active; }; -FUNCTION UIWidget *ui_new_widget(Arena *arena, UIWidgetKind kind) { - UIWidget *result = PUSH_STRUCT(arena, UIWidget); +function UIWidget *ui_new_widget(Allocator *arena, UIWidgetKind kind) { + UIWidget *result = exp_alloc_type(arena, UIWidget); result->kind = kind; return result; } -FUNCTION void ui_push_child(UIWidget *widget, UIWidget *child) { - DLL_QUEUE_PUSH(widget->first_child, widget->last_child, child); +function void ui_push_child(UIWidget *widget, UIWidget *child) { + //DLL_QUEUE_PUSH(widget->first_child, widget->last_child, child); } -FUNCTION UIWidget *ui_push_child(Arena *arena, UIWidget *widget, UIWidgetKind kind) { +function UIWidget *ui_push_child(Arena *arena, UIWidget *widget, UIWidgetKind kind) { UIWidget *result = ui_new_widget(arena, kind); ui_push_child(widget, result); return result; } -FUNCTION UIWidget *ui_push_image(Arena *arena, UIWidget *widget, Bitmap *img) { +function UIWidget *ui_push_image(Arena *arena, UIWidget *widget, Bitmap *img) { UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Image); result->ptr.image = img; - + F32 ratio = (F32)result->ptr.image->x / (F32)result->ptr.image->y; result->size.y = 64; result->size.x = 64 * ratio; return result; } -FUNCTION UIWidget *ui_push_bool(Arena *arena, UIWidget *widget, S8 string, B32 *b32) { +function UIWidget *ui_push_bool(Arena *arena, UIWidget *widget, String string, B32 *b32) { UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Boolean); result->text = string; result->ptr.b32 = b32; return result; } -FUNCTION UIWidget *ui_push_string(Arena *arena, UIWidget *widget, S8 *string) { +function UIWidget *ui_push_string(Arena *arena, UIWidget *widget, String *string) { UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Label); result->ptr.label = string; return result; } -FUNCTION UIWidget *ui_push_option(Arena *arena, UIWidget *widget, S8 string, I32 *option, I32 option_max) { +function UIWidget *ui_push_option(Arena *arena, UIWidget *widget, String string, S32 *option, S32 option_max) { UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Option); result->text = string; result->ptr.option = option; @@ -102,16 +102,16 @@ FUNCTION UIWidget *ui_push_option(Arena *arena, UIWidget *widget, S8 string, I32 return result; } -FUNCTION UIWidget *ui_push_signal(Arena *arena, UIWidget *widget, S8 string, UISignalCallback *callback) { +function UIWidget *ui_push_signal(Arena *arena, UIWidget *widget, String string, UISignalCallback *callback) { UIWidget *result = ui_push_child(arena, widget, UIWidgetKind_Signal); result->text = string; result->ptr.signal_callback = callback; return result; } -FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) { +function UI ui_make(UISetup *setup, U64 len) { UI result = {}; - result.arena = arena_sub(arena, MiB(16)); + arena_init(&result.arena, "UI_Arena"_s); UIWidget *parent = &result; for (UISetup *s = setup; s != (setup+len); s++) { switch (s->kind) { @@ -130,16 +130,16 @@ FUNCTION UI ui_make(Arena *arena, UISetup *setup, U64 len) { case UIWidgetKind_Signal: { ui_push_signal(&result.arena, parent, s->text, s->signal_callback); } break; - INVALID_DEFAULT_CASE; + invalid_default_case; } } return result; } -FUNCTION B32 ui_mouse_test(UI *ui, UIWidget *w, Vec4 rect) { +function B32 ui_mouse_test(UI *ui, UIWidget *w, Vec4 rect) { B32 result = false; if (os.mouse_pos.x > rect.x && os.mouse_pos.x < rect.x + rect.width && - os.mouse_pos.y > rect.y && os.mouse_pos.y < rect.y + rect.height) { + os.mouse_pos.y > rect.y && os.mouse_pos.y < rect.y + rect.height) { ui->hot = w; if (os.key[Key_MouseLeft].down) { ui->active = w; @@ -148,7 +148,7 @@ FUNCTION B32 ui_mouse_test(UI *ui, UIWidget *w, Vec4 rect) { else if (w == ui->hot) { ui->hot = 0; } - + if (os.key[Key_MouseLeft].released) { if (ui->active == w) { if (ui->hot == w) @@ -156,11 +156,11 @@ FUNCTION B32 ui_mouse_test(UI *ui, UIWidget *w, Vec4 rect) { ui->active = 0; } } - + return result; } -FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { +function void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { Scratch scratch; Vec2 pos = vec2(0, (F32)dst->y); for (UIWidget *w = ui->first_child; w; w = w->next) { @@ -170,7 +170,7 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { pos.y -= w->size.y; rect = vec4(pos, w->size); ui_mouse_test(ui, w, rect); - S8 string = string_format(scratch, "%d %d", w->ptr.image->x, w->ptr.image->y); + String string = string_fmt(scratch, "%d %d", w->ptr.image->x, w->ptr.image->y); r_draw_string(dst, font, string, pos); r_draw_bitmap(dst, w->ptr.image, pos, w->size); if (ui->active == w) { @@ -185,7 +185,7 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { case UIWidgetKind_Boolean: { pos.y -= font->height; Vec4 color = vec4(0, 0, 0, 1); - S8 string = string_format(scratch, "%s %d", w->text, *w->ptr.b32); + String string = string_fmt(scratch, "%s %d", w->text, *w->ptr.b32); rect = r_get_string_rect(font, string, pos); B32 clicked = ui_mouse_test(ui, w, rect); if (clicked) *w->ptr.b32 = !*w->ptr.b32; @@ -205,7 +205,7 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { case UIWidgetKind_Option: { pos.y -= font->height; Vec4 color = vec4(0, 0, 0, 1); - S8 string = string_format(scratch, "%s %d", w->text, *w->ptr.option); + String string = string_fmt(scratch, "%s %d", w->text, *w->ptr.option); rect = r_get_string_rect(font, string, pos); B32 clicked = ui_mouse_test(ui, w, rect); if (clicked) { @@ -222,7 +222,7 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { case UIWidgetKind_Signal: { pos.y -= font->height; Vec4 color = vec4(0, 0, 0, 1); - S8 string = string_format(scratch, "%s", w->text); + String string = string_fmt(scratch, "%s", w->text); rect = r_get_string_rect(font, string, pos); B32 clicked = ui_mouse_test(ui, w, rect); if (clicked) { @@ -236,7 +236,7 @@ FUNCTION void ui_end_frame(Bitmap *dst, UI *ui, Font *font) { rect = r_draw_string(dst, font, string, pos); pos.y -= rect.height - font->height; } break; - INVALID_DEFAULT_CASE; + invalid_default_case; } } } \ No newline at end of file