diff --git a/src/common.h b/src/common.h index a06518d2..4845f096 100644 --- a/src/common.h +++ b/src/common.h @@ -514,15 +514,6 @@ INLINE i64 clamp_i64(i64 v, i64 min, i64 max) { return v < min ? min : v > max ? INLINE f32 clamp_f32(f32 v, f32 min, f32 max) { return v < min ? min : v > max ? max : v; } INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; } -INLINE u64 cstr_len(char *cstr) -{ - u64 len = 0; - for (char *c = cstr; *c != 0; ++c) { - ++len; - } - return len; -} - /* ========================== * * Profiling * ========================== */ diff --git a/src/font.c b/src/font.c index 8968062b..b815536a 100644 --- a/src/font.c +++ b/src/font.c @@ -186,7 +186,7 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 help) STR("Font path \"%F\" too long!"), FMT_STR(path))); } - string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr)); + cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path); params->path_len = path.len; params->asset = asset; params->point_size = point_size; diff --git a/src/resource.h b/src/resource.h index 599cdaf8..6ef34aa9 100644 --- a/src/resource.h +++ b/src/resource.h @@ -8,6 +8,7 @@ struct resource { struct buffer bytes; + /* Internal */ #if !RESOURCES_EMBEDDED struct sys_file file; struct sys_file_map file_map; diff --git a/src/sheet.c b/src/sheet.c index 3603b4e3..8b880a4b 100644 --- a/src/sheet.c +++ b/src/sheet.c @@ -236,7 +236,7 @@ struct asset *sheet_load_asset(struct string path, b32 help) STR("Sheet path \"%F\" too long!"), FMT_STR(path))); } - string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr)); + cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path); params->path_len = path.len; params->asset = asset; diff --git a/src/sound.c b/src/sound.c index de6728a7..f97624fd 100644 --- a/src/sound.c +++ b/src/sound.c @@ -191,7 +191,7 @@ struct asset *sound_load_asset(struct string path, u32 flags, b32 help) STR("Sound path \"%F\" too long!"), FMT_STR(path))); } - string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr)); + cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path); params->path_len = path.len; params->asset = asset; params->flags = flags; diff --git a/src/string.c b/src/string.c index e964f06f..d7b5ac91 100644 --- a/src/string.c +++ b/src/string.c @@ -160,54 +160,17 @@ struct string string_copy(struct arena *arena, struct string src) return str; } -struct string string_copy_buff(struct buffer buff, struct string src) +struct string string_copy_buff(struct buffer dest_buff, struct string src) { - u64 len = min_u64(buff.size, src.len); + u64 len = min_u64(dest_buff.size, src.len); struct string str = { .len = len, - .text = buff.data + .text = dest_buff.data }; MEMCPY(str.text, src.text, src.len); return str; } -/* TODO: Benchmark performance of appending each character while calculating size here */ -// //struct string string_copy_cstr(struct arena *arena, char *cstr) -// //{ -// // u8 *final_text = arena_next(arena); -// // char *c = cstr; -// // for (; *c != 0; ++c) { -// // u8 *new_char = arena_push(arena, 1); -// // *new_char = *c; -// // } -// // return (struct string) { -// // .len = c - cstr, -// // .text = final_text -// // }; -// //} - -struct string string_from_cstr(char *cstr) -{ - struct string str = { 0 }; - if (cstr) { - char *c = cstr; - while (*c != 0) { - ++c; - } - str.len = c - cstr; - str.text = (u8 *)cstr; - } - return str; -} - -struct string string_from_cstr_len(char *cstr, u64 len) -{ - return (struct string) { - .text = (u8 *)cstr, - .len = len - }; -} - struct string string_repeat(struct arena *arena, struct string src, u64 count) { u64 final_len = src.len * count; @@ -365,54 +328,6 @@ b32 string_ends_with(struct string str, struct string substring) return false; } -#if 0 -/* NOTE: This is a LOSSY conversion. - * `wstr` must be null-terminated. - */ -struct string string_from_wstr(struct arena *arena, u16 *wstr) -{ - u8 *final_text = arena_next(arena); - u16 *wchar = wstr; - for (; *wchar != 0; ++wchar) { - u8 *c = arena_push(arena, 1); - *c = (u8)(*wchar & 0xFF); - } - return (struct string) { - .len = wchar - wstr, - .text = final_text - }; -} -#endif - -char *string_to_cstr(struct arena *arena, struct string str) -{ - u8 *text = arena_push_array(arena, u8, str.len + 1); - MEMCPY(text, str.text, str.len); - text[str.len] = '\0'; - return (char *)text; -} - -char *string_to_cstr_buff(struct string str, struct buffer buff) -{ - if (buff.size > 0) { - u64 len = min_u64(str.len, buff.size - 1); - MEMCPY(buff.data, str.text, len); - buff.data[len] = '\0'; - } - return (char *)buff.data; -} - -wchar_t *string_to_wstr(struct arena *arena, struct string str) -{ - /* FIXME: Do proper encoding. */ - u16 *text = arena_push_array(arena, u16, str.len + 1); - for (u64 i = 0; i < str.len; ++i) { - text[i] = (u16)str.text[i]; - } - text[str.len] = '\0'; - return (wchar_t *)text; -} - /* ========================== * * Format * ========================== */ @@ -549,7 +464,7 @@ struct string _string_format(struct arena *arena, struct string fmt, ...) } /* ========================== * - * Unicode transformation + * Unicode * ========================== */ /* utf8 <- utf16 */ @@ -576,6 +491,30 @@ struct string string_from_string16(struct arena *arena, struct string16 str16) return res; } +/* utf8 <- utf32 */ +struct string string_from_string32(struct arena *arena, struct string32 str32) +{ + struct string res = { + .len = 0, + .text = arena_dry_push(arena, u8) + }; + + u64 pos32 = 0; + while (pos32 < str32.len) { + struct string32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 }; + struct utf32_decode_result decoded = utf32_decode(str32_remaining); + struct utf8_encode_result encoded = utf8_encode(decoded.codepoint); + + u8 *dest = arena_push_array(arena, u8, encoded.count8); + MEMCPY(dest, &encoded.chars8, encoded.count8); + + pos32 += 1; + res.len += encoded.count8; + } + + return res; +} + /* utf16 <- utf8 */ struct string16 string16_from_string(struct arena *arena, struct string str8) { @@ -600,30 +539,6 @@ struct string16 string16_from_string(struct arena *arena, struct string str8) return res; } -/* utf8 <- utf32 */ -struct string string_from_string32(struct arena *arena, struct string32 str32) -{ - struct string res = { - .len = 0, - .text = arena_dry_push(arena, u8) - }; - - u64 pos32 = 0; - while (pos32 < str32.len) { - struct string32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 }; - struct utf32_decode_result decoded = utf32_decode(str32_remaining); - struct utf8_encode_result encoded = utf8_encode(decoded.codepoint); - - u8 *dest = arena_push_array(arena, u8, encoded.count8); - MEMCPY(dest, &encoded.chars8, encoded.count8); - - pos32 += 1; - res.len += encoded.count8; - } - - return res; -} - /* utf32 <- utf8 */ struct string32 string32_from_string(struct arena *arena, struct string str8) { @@ -647,3 +562,93 @@ struct string32 string32_from_string(struct arena *arena, struct string str8) return res; } + +/* ========================== * + * Legacy strings + * ========================== */ + +/* C narrow strings */ + +u64 cstr_len(char *cstr) +{ + char *end = cstr; + while (*end) { + ++end; + } + return end - cstr; +} + +char *cstr_from_string(struct arena *arena, struct string src) +{ + u8 *text = arena_push_array(arena, u8, src.len + 1); + MEMCPY(text, src.text, src.len); + text[src.len] = 0; + return (char *)text; +} + +char *cstr_buff_from_string(struct buffer dest_buff, struct string src) +{ + if (dest_buff.size > 0) { + u64 len = min_u64(src.len, dest_buff.size - 1); + MEMCPY(dest_buff.data, src.text, len); + dest_buff.data[len] = 0; + } + return (char *)dest_buff.data; +} + +struct string string_from_cstr(char *cstr) +{ + u64 len = cstr_len(cstr); + return (struct string) { + .len = len, + .text = (u8 *)cstr + }; +} + +struct string string_from_cstr_len(char *cstr, u64 len) +{ + return (struct string) { + .text = (u8 *)cstr, + .len = len + }; +} + +/* C wide strings */ + +u64 wstr_len(wchar_t *wstr) +{ + wchar_t *end = wstr; + while (*end) { + ++end; + } + return end - wstr; +} + +wchar_t *wstr_from_string(struct arena *arena, struct string src) +{ + struct string16 str16 = string16_from_string(arena, src); + *arena_push(arena, u16) = 0; + return (wchar_t *)str16.text; +} + +wchar_t *wstr_from_string16(struct arena *arena, struct string16 src) +{ + u16 *text = arena_push_array(arena, u16, src.len + 1); + text[src.len] = 0; + return (wchar_t *)text; +} + +struct string string_from_wstr(struct arena *arena, wchar_t *wstr) +{ + struct string16 str16 = string16_from_wstr(wstr); + return string_from_string16(arena, str16); +} + +struct string16 string16_from_wstr(wchar_t *wstr) +{ + u64 len = wstr_len(wstr); + return (struct string16) { + .len = len, + .text = (u16 *)wstr + }; +} diff --git a/src/string.h b/src/string.h index c5f3d10e..f31b25b3 100644 --- a/src/string.h +++ b/src/string.h @@ -21,9 +21,7 @@ struct string string_from_float(struct arena *arena, f64 f, u32 precision); * ========================== */ struct string string_copy(struct arena *arena, struct string src); -struct string string_copy_buff(struct buffer buff, struct string src); -struct string string_from_cstr(char *cstr); -struct string string_from_cstr_len(char *cstr, u64 len); +struct string string_copy_buff(struct buffer dest_buff, struct string src); struct string string_repeat(struct arena *arena, struct string src, u64 count); struct string string_cat(struct arena *arena, struct string str1, struct string str2); struct string_array string_split(struct arena *arena, struct string str, struct string delim); @@ -32,9 +30,6 @@ b32 string_eq(struct string str1, struct string str2); b32 string_contains(struct string str, struct string substring); b32 string_starts_with(struct string str, struct string substring); b32 string_ends_with(struct string str, struct string substring); -char *string_to_cstr(struct arena *arena, struct string str); -char *string_to_cstr_buff(struct string str, struct buffer buff); -wchar_t *string_to_wstr(struct arena *arena, struct string str); /* ========================== * * Format @@ -86,12 +81,28 @@ struct string _string_format(struct arena *arena, struct string fmt, ...); struct string string_formatv(struct arena *arena, struct string fmt, va_list args); /* ========================== * - * Unicode transformation + * Unicode * ========================== */ struct string string_from_string16(struct arena *arena, struct string16 str16); -struct string16 string16_from_string(struct arena *arena, struct string str8); struct string string_from_string32(struct arena *arena, struct string32 str32); +struct string16 string16_from_string(struct arena *arena, struct string str8); struct string32 string32_from_string(struct arena *arena, struct string str8); +/* ========================== * + * Legacy strings + * ========================== */ + +u64 cstr_len(char *cstr); +char *cstr_from_string(struct arena *arena, struct string src); +char *cstr_buff_from_string(struct buffer dest_buff, struct string src); +struct string string_from_cstr(char *cstr); +struct string string_from_cstr_len(char *cstr, u64 len); + +u64 wstr_len(wchar_t *wstr); +wchar_t *wstr_from_string(struct arena *arena, struct string src); +wchar_t *wstr_from_string16(struct arena *arena, struct string16 src); +struct string string_from_wstr(struct arena *arena, wchar_t *wstr); +struct string16 string16_from_wstr(wchar_t *wstr); + #endif diff --git a/src/sys.h b/src/sys.h index bf42aa10..c8c5b56c 100644 --- a/src/sys.h +++ b/src/sys.h @@ -195,8 +195,8 @@ u64 sys_file_size(struct sys_file file); * ========================== */ struct sys_file_map { - u64 handle; struct buffer mapped_memory; + u64 handle; }; struct sys_file_map sys_file_map_open_read(struct sys_file file); @@ -207,18 +207,20 @@ struct buffer sys_file_map_data(struct sys_file_map map); * Dir iter * ========================== */ -/* Opaque */ -struct sys_dir_iter; - -struct sys_dir_iter_info { - struct string file_name; +struct sys_file_filter_result { + struct string filename; b32 is_dir; }; +struct sys_file_filter { + struct sys_file_filter_result info; + u64 handle; +}; + /* Iterate all files in a directory */ -struct sys_dir_iter *sys_dir_iter_begin(struct arena *arena, struct string dir_name); -struct sys_dir_iter_info *sys_dir_iter_next(struct arena *arena, struct sys_dir_iter *iter); -void sys_dir_iter_end(struct sys_dir_iter *iter); +struct sys_file_filter sys_file_filter_begin(struct arena *arena, struct string pattern); +b32 sys_file_filter_next(struct arena *arena, struct sys_file_filter *iter); +void sys_file_filter_end(struct sys_file_filter *iter); /* ========================== * * Window diff --git a/src/sys_win32.c b/src/sys_win32.c index 3bb82a86..8ac11c14 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -10,6 +10,7 @@ #include "math.h" #include "util.h" #include "tls.h" +#include "utf.h" #include #include @@ -27,6 +28,7 @@ #pragma comment(lib, "dwmapi") #define SYS_WINDOW_EVENT_LISTENERS_MAX 512 +#define WINDOW_CLASS_NAME L"power_play_window_class" struct win32_thread_params { sys_thread_func *thread_func; @@ -107,7 +109,7 @@ GLOBAL struct { struct win32_thread_params *first_free_thread_params; /* Windows */ - WNDCLASSEX window_class; + WNDCLASSEXW window_class; struct sys_mutex windows_mutex; struct arena windows_arena; struct win32_window *first_free_window; @@ -187,39 +189,39 @@ void sys_memory_decommit(void *address, u64 size) VirtualFree(address, size, MEM_DECOMMIT); } -/* ========================== * - * Wchar - * - * TODO: Move wide char ops to string.c and actually do proper decoding - * ========================== */ - -INTERNAL struct string wchar_path_to_string(struct arena *arena, wchar_t *src) -{ - struct string str = { 0, arena_dry_push(arena, u8) }; - while (1) { - wchar_t wchar = src[str.len]; - if (wchar != 0) { - if (wchar == '\\') { - wchar = '/'; - } - u8 *c = arena_push(arena, u8); - /* FIXME: We're ignoring the high byte here */ - *c = (u8)(wchar & 0xFF); - ++str.len; - } else { - break; - } - } - return str; -} - /* ========================== * * File system * ========================== */ +INTERNAL struct string string_from_win32_path(struct arena *arena, wchar_t *src) +{ + struct string res = { + .len = 0, + .text = arena_dry_push(arena, u8) + }; + + while (*src) { + struct string16 decode_str = { .len = *(src + 1) ? 2 : 1, .text = src }; + struct utf16_decode_result decoded = utf16_decode(decode_str); + struct utf8_encode_result encoded = utf8_encode(decoded.codepoint); + u8 *dest = arena_push_array(arena, u8, encoded.count8); + for (u32 i = 0; i < encoded.count8; ++i) { + u8 byte = encoded.chars8[i]; + if (byte == '\\') { + byte = '/'; + } + dest[i] = byte; + } + res.len += encoded.count8; + src += decoded.advance16; + } + + return res; +} + struct string sys_get_write_path(struct arena *arena) { - wchar_t *p = NULL; + u16 *p = NULL; /* TODO: cache this? */ HRESULT res = SHGetKnownFolderPath( &FOLDERID_LocalAppData, @@ -229,7 +231,7 @@ struct string sys_get_write_path(struct arena *arena) ); struct string path = { 0 }; if (res == S_OK) { - path = wchar_path_to_string(arena, p); + path = string_from_win32_path(arena, p); } CoTaskMemFree(p); return path; @@ -239,8 +241,8 @@ b32 sys_is_file(struct string path) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); - DWORD attributes = GetFileAttributes(path_cstr); + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); scratch_end(scratch); return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY); } @@ -248,8 +250,8 @@ b32 sys_is_file(struct string path) b32 sys_is_dir(struct string path) { struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); - DWORD attributes = GetFileAttributes(path_cstr); + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); + DWORD attributes = GetFileAttributesW(path_wstr); scratch_end(scratch); return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); } @@ -258,10 +260,35 @@ void sys_mkdir(struct string path) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); - b32 success = SHCreateDirectoryExA(NULL, path_cstr, NULL) == ERROR_SUCCESS; - (UNUSED)success; - ASSERT(success); + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); + int err_code = SHCreateDirectory(NULL, path_wstr); + struct string err = { 0 }; + switch (err_code) { + case ERROR_BAD_PATHNAME: { + err = STR("Bad path name"); + } break; + + case ERROR_FILENAME_EXCED_RANGE: { + err = STR("Path name too long"); + } break; + + case ERROR_FILE_EXISTS: { + err = STR("A file already exists at this location"); + } break; + + case ERROR_CANCELLED: { + err = STR("User canceled the operation"); + } break; + + default: break; + } + if (err.len > 0) { + struct string msg = string_format(scratch.arena, + STR("Failed to create directory \"%F\": %F"), + FMT_STR(path), + FMT_STR(err)); + sys_panic(msg); + } scratch_end(scratch); } @@ -269,11 +296,11 @@ struct sys_file sys_file_open_read(struct string path) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); /* TODO: Handle errors / non-existing file (handle == INVALID_HANDLE_VALUE) */ - HANDLE handle = CreateFileA( - path_cstr, + HANDLE handle = CreateFileW( + path_wstr, GENERIC_READ, FILE_SHARE_READ, NULL, @@ -290,9 +317,9 @@ struct sys_file sys_file_open_write(struct string path) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); - HANDLE handle = CreateFileA( - path_cstr, + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); + HANDLE handle = CreateFileW( + path_wstr, GENERIC_WRITE, 0, NULL, @@ -310,9 +337,9 @@ struct sys_file sys_file_open_append(struct string path) { __prof; struct temp_arena scratch = scratch_begin_no_conflict(); - const char *path_cstr = string_to_cstr(scratch.arena, path); - HANDLE handle = CreateFileA( - path_cstr, + wchar_t *path_wstr = wstr_from_string(scratch.arena, path); + HANDLE handle = CreateFileW( + path_wstr, FILE_APPEND_DATA, FILE_SHARE_READ, NULL, @@ -395,7 +422,7 @@ u64 sys_file_size(struct sys_file file) struct sys_file_map sys_file_map_open_read(struct sys_file file) { - HANDLE map_handle = CreateFileMappingA( + HANDLE map_handle = CreateFileMappingW( (HANDLE)file.handle, NULL, PAGE_READONLY, @@ -451,60 +478,57 @@ struct buffer sys_file_map_data(struct sys_file_map map) } /* ========================== * - * Dir iter + * File iter * ========================== */ -struct sys_dir_iter { - HANDLE handle; - char *dir_path_cstr; +struct win32_file_filter { + HANDLE find_handle; + wchar_t *filter_wstr; }; -struct sys_dir_iter *sys_dir_iter_begin(struct arena *arena, struct string dir_name) +struct sys_file_filter sys_file_filter_begin(struct arena *arena, struct string pattern) { - struct temp_arena scratch = scratch_begin(arena); - struct sys_dir_iter *iter = arena_push_zero(arena, struct sys_dir_iter); - if (dir_name.len >= 1 && dir_name.text[dir_name.len - 1] == '/') { - struct string dir_path_w_asterisk = string_cat(scratch.arena, dir_name, STR("*")); - iter->dir_path_cstr = string_to_cstr(arena, dir_path_w_asterisk); - } else { - /* Invalid directory path supplied */ - ASSERT(false); - } - scratch_end(scratch); - return iter; + struct sys_file_filter filter = { 0 }; + struct win32_file_filter *filter_internal = arena_push_zero(arena, struct win32_file_filter); + filter_internal->filter_wstr = wstr_from_string(arena, pattern); + filter.handle = (u64)filter_internal; + return filter; } -struct sys_dir_iter_info *sys_dir_iter_next(struct arena *arena, struct sys_dir_iter *iter) +b32 sys_file_filter_next(struct arena *arena, struct sys_file_filter *filter) { - WIN32_FIND_DATA find_file_data = { 0 }; + struct win32_file_filter *filter_internal = (struct win32_file_filter *)filter->handle; + + WIN32_FIND_DATAW find_file_data = { 0 }; b32 found = false; - if (iter->handle) { - found = FindNextFileA(iter->handle, &find_file_data); - } else if (iter->dir_path_cstr) { - iter->handle = FindFirstFileExA(iter->dir_path_cstr, FindExInfoStandard, &find_file_data, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH); - found = iter->handle != INVALID_HANDLE_VALUE; + if (filter_internal->find_handle) { + found = FindNextFileW(filter_internal->find_handle, &find_file_data); + } else { + filter_internal->find_handle = FindFirstFileExW(filter_internal->filter_wstr, FindExInfoStandard, &find_file_data, FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH); + found = filter_internal->find_handle != INVALID_HANDLE_VALUE; } - struct sys_dir_iter_info *info = NULL; if (found) { - struct string file_name = string_from_cstr(find_file_data.cFileName); + struct string file_name = string_from_wstr(arena, find_file_data.cFileName); if (string_eq(file_name, STR(".")) || string_eq(file_name, STR(".."))) { /* Skip initial '.' and '..' matches */ - info = sys_dir_iter_next(arena, iter); + found = sys_file_filter_next(arena, filter); } else { - info = arena_push_zero(arena, struct sys_dir_iter_info); - info->is_dir = find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; - info->file_name = string_copy(arena, file_name); + filter->info.is_dir = find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; + filter->info.filename = string_copy(arena, file_name); } } - return info; + return found; } -void sys_dir_iter_end(struct sys_dir_iter *iter) +void sys_file_filter_end(struct sys_file_filter *filter) { - FindClose(iter->handle); + struct win32_file_filter *filter_internal = (struct win32_file_filter *)filter->handle; + if (filter_internal->find_handle) { + FindClose(filter_internal->find_handle); + } } /* ========================== * @@ -536,10 +560,10 @@ INTERNAL HWND win32_create_window(struct win32_window *window) DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP; /* TODO: Check for hwnd success */ - HWND hwnd = CreateWindowExA( + HWND hwnd = CreateWindowExW( exstyle, L.window_class.lpszClassName, - "", + L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, @@ -556,7 +580,7 @@ INTERNAL HWND win32_create_window(struct win32_window *window) DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode)); /* Set window as userdata */ - SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)window); + SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window); return hwnd; } @@ -779,7 +803,7 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str if (fullscreen) { if (!old_fullscreen) { /* Entering fullscreen */ - SetWindowLongPtrA(hwnd, GWL_STYLE, WS_POPUP); + SetWindowLongPtrW(hwnd, GWL_STYLE, WS_POPUP); } rect = (RECT) { .left = 0, @@ -790,7 +814,7 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str } else { if (old_fullscreen) { /* Leaving fullscreen */ - SetWindowLongPtrA(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + SetWindowLongPtrW(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); } rect = (RECT) { .left = settings->floating_x, @@ -808,21 +832,26 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str }; SetWindowPlacement(hwnd, &wp); - SetWindowTextA(hwnd, settings->title); + { + struct temp_arena scratch = scratch_begin_no_conflict(); + wchar_t *title_wstr = wstr_from_string(scratch.arena, string_from_cstr(settings->title)); + SetWindowTextW(hwnd, title_wstr); + scratch_end(scratch); + } } INTERNAL void win32_window_wake(struct win32_window *window) { /* Post a blank message to the window's thread message queue to wake it. */ - PostMessageA(window->hwnd, WM_NULL, 0, 0); + PostMessageW(window->hwnd, WM_NULL, 0, 0); } INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { - struct win32_window *window = (struct win32_window *)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + struct win32_window *window = (struct win32_window *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); if (!window) { - return DefWindowProcA(hwnd, msg, wparam, lparam); + return DefWindowProcW(hwnd, msg, wparam, lparam); } LRESULT result = 0; @@ -834,7 +863,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, } break; case WM_PAINT: { - result = DefWindowProcA(hwnd, msg, wparam, lparam); + result = DefWindowProcW(hwnd, msg, wparam, lparam); } break; case WM_MOVE: @@ -842,13 +871,13 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, case WM_SIZE: case WM_SIZING: { win32_update_window_from_system(window); - result = DefWindowProcA(hwnd, msg, wparam, lparam); + result = DefWindowProcW(hwnd, msg, wparam, lparam); } break; /* Keyboard buttons */ case WM_SYSKEYUP: case WM_SYSKEYDOWN: { - result = DefWindowProcA(hwnd, msg, wparam, lparam); + result = DefWindowProcW(hwnd, msg, wparam, lparam); } FALLTHROUGH; case WM_KEYUP: case WM_KEYDOWN: { @@ -997,7 +1026,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, default: { - result = DefWindowProcA(hwnd, msg, wparam, lparam); + result = DefWindowProcW(hwnd, msg, wparam, lparam); } break; } @@ -1476,7 +1505,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID params) struct string thread_name = string_from_cstr(thread_params.thread_name_cstr); if (thread_name.len > 0) { struct temp_arena scratch = scratch_begin_no_conflict(); - wchar_t *wc_thread_name = string_to_wstr(scratch.arena, thread_name); + wchar_t *wc_thread_name = wstr_from_string(scratch.arena, thread_name); SetThreadDescription(GetCurrentThread(), wc_thread_name); scratch_end(scratch); } @@ -1509,7 +1538,7 @@ struct sys_thread sys_thread_init(sys_thread_func *thread_func, void *thread_dat tp->thread_data = thread_data; /* Copy thread name to params */ - string_to_cstr_buff(thread_name, BUFFER_FROM_ARRAY(tp->thread_name_cstr)); + cstr_buff_from_string(BUFFER_FROM_ARRAY(tp->thread_name_cstr), thread_name); HANDLE handle = CreateThread( NULL, @@ -1558,10 +1587,10 @@ void sys_thread_assert(u32 tid) void sys_message_box(enum sys_message_box_kind kind, struct string message) { - char message_buff[4096] = { 0 }; - char *message_cstr = string_to_cstr_buff(message, BUFFER_FROM_ARRAY(message_buff)); + struct temp_arena scratch = scratch_begin_no_conflict(); + wchar_t *message_wstr = wstr_from_string(scratch.arena, message); - const char *title = ""; + const wchar_t *title = L""; UINT mbox_type = 0; switch (kind) { @@ -1570,22 +1599,24 @@ void sys_message_box(enum sys_message_box_kind kind, struct string message) } break; case SYS_MESSAGE_BOX_KIND_WARNING: { - title = "Warning"; + title = L"Warning"; mbox_type = MB_ICONWARNING; } break; case SYS_MESSAGE_BOX_KIND_ERROR: { - title = "Error"; + title = L"Error"; mbox_type = MB_ICONERROR; } break; case SYS_MESSAGE_BOX_KIND_FATAL: { - title = "Fatal error"; + title = L"Fatal error"; mbox_type = MB_ICONSTOP; } break; } - MessageBoxExA(NULL, message_cstr, title, mbox_type, 0); + MessageBoxExW(NULL, message_wstr, title, mbox_type, 0); + + scratch_end(scratch); } /* ========================== * @@ -1650,21 +1681,30 @@ u32 sys_rand_u32(void) return v; } -void sys_panic_raw(char *msg_cstr) +INTERNAL void panic_exit(void) { - /* FIXME: Exit other threads before showing message box */ - MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0); ASSERT(false); sys_exit(); } +void sys_panic_raw(char *msg_cstr) +{ + /* FIXME: Exit other threads before showing message box */ + MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0); + panic_exit(); +} + void sys_panic(struct string msg) { - struct temp_arena scratch = scratch_begin_no_conflict(); + /* FIXME: Exit other threads before showing message box */ logf_critical("Panicking: %F", FMT_STR(msg)); - struct string prepend = STR("A fatal error has occured and the application needs to exit:\n\n"); - msg = string_cat(scratch.arena, prepend, msg); - sys_panic_raw(string_to_cstr(scratch.arena, msg)); + struct temp_arena scratch = scratch_begin_no_conflict(); + msg = string_cat(scratch.arena, + STR("A fatal error has occured and the application needs to exit:\n\n"), + msg); + wchar_t *msg_wstr = wstr_from_string(scratch.arena, msg); + MessageBoxExW(NULL, msg_wstr, L"Fatal error", MB_ICONSTOP, 0); + panic_exit(); scratch_end(scratch); } @@ -1782,14 +1822,14 @@ INTERNAL SYS_THREAD_FUNC_DEF(app_thread_entry_point, arg) app_entry_point(); } -int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPSTR command_line, _In_ int show_code) +int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR command_line, _In_ int show_code) { (UNUSED)instance; (UNUSED)prev_instance; (UNUSED)command_line; (UNUSED)show_code; - const char *error_msg = NULL; + const wchar_t *error_msg = NULL; SetThreadDescription(GetCurrentThread(), L"Main thread"); @@ -1816,7 +1856,7 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, L.thread_tls_index = TlsAlloc(); if (L.thread_tls_index == TLS_OUT_OF_INDEXES) { /* TODO: GetLastError */ - error_msg = "Platform initialization error: TLS_OUT_OF_INDEXES"; + error_msg = L"Platform initialization error: TLS_OUT_OF_INDEXES"; goto error; } @@ -1840,9 +1880,9 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, /* Create window class */ { /* Register the window class */ - WNDCLASSEX *wc = &L.window_class; + WNDCLASSEXW *wc = &L.window_class; wc->cbSize = sizeof(WNDCLASSEX); - wc->lpszClassName = "power_play_window_class"; + wc->lpszClassName = WINDOW_CLASS_NAME; wc->hCursor = LoadCursor(NULL, IDC_ARROW); wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); @@ -1854,9 +1894,9 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, GetModuleFileName(instance, path, MAX_PATH); ExtractIconEx(path, 0, &wc->hIcon, &wc->hIconSm, 1); - if (!RegisterClassExA(wc)) { + if (!RegisterClassExW(wc)) { /* TODO: GetLastError */ - error_msg = "Failed to register window class"; + error_msg = L"Failed to register window class"; goto error; } } @@ -1871,14 +1911,14 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) { /* TODO: GetLastError */ - error_msg = "Failed to register raw input device"; + error_msg = L"Failed to register raw input device"; goto error; } } error: if (error_msg) { - MessageBoxExA(NULL, error_msg, "Fatal initialization error", MB_ICONSTOP, 0); + MessageBoxExW(NULL, error_msg, L"Fatal initialization error", MB_ICONSTOP, 0); ASSERT(false); return 1; } @@ -1910,9 +1950,9 @@ __attribute((used)) int _fltused; __attribute((used)) -void __stdcall WinMainCRTStartup(void) +void __stdcall wWinMainCRTStartup(void) { - int result = WinMain(GetModuleHandle(0), 0, GetCommandLineA(), 0); + int result = wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), 0); ExitProcess(result); } diff --git a/src/texture.c b/src/texture.c index 3d004504..ba96da21 100644 --- a/src/texture.c +++ b/src/texture.c @@ -247,7 +247,7 @@ struct asset *texture_load_asset(struct string path, b32 help) STR("Texture path \"%F\" too long!"), FMT_STR(path))); } - string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr)); + cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path); params->path_len = path.len; params->asset = asset;