From 9eabdcd222696b7ef1127920535ab97b373bfad7 Mon Sep 17 00:00:00 2001 From: jacob Date: Fri, 3 May 2024 02:35:25 -0500 Subject: [PATCH] msvc support in progress --- CMakeLists.txt | 183 ++++++++++++++++++++----------- build.bat | 66 ++++++++--- src/ase.c | 8 +- src/atomic.h | 2 +- src/common.h | 249 ++++++++++++++++++++++++++++-------------- src/entity.c | 6 +- src/game.c | 4 +- src/incbin.c | 91 +++++++++++++++ src/incbin.h | 61 +++++++++-- src/json.c | 6 +- src/log.h | 20 ++-- src/math.h | 3 +- src/mp3_mmf.c | 1 + src/playback_wasapi.c | 1 + src/renderer.h | 4 +- src/renderer_d3d11.c | 1 + src/scratch.h | 6 +- src/sprite.c | 8 +- src/tar.c | 4 +- src/thread_local.c | 6 +- src/thread_local.h | 9 +- src/ttf_dwrite.cpp | 18 +-- src/user.c | 30 ++--- src/util.h | 4 +- 24 files changed, 556 insertions(+), 235 deletions(-) create mode 100644 src/incbin.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 086aef3a..93446c77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,13 +3,14 @@ project(powerplay) # Options below are laid out so that running cmake with all "OFF" results in the "release" / "user" build -option(RTC "Should the build compile with runtime checks enabled (asserts, asan, etc.) - REQUIRES CRTLIB ON" OFF) -option(ASAN "Should the build compile with the address sanitizer enabled (asserts, asan, etc.) - REQUIRES CRTLIB ON" OFF) -option(CRTLIB "Should the build link with the CRTLIB" OFF) -option(DEBINFO "Should the build compile with debug info" OFF) -option(DEVELOPER "Should the build compile with developer mode enabled" OFF) -option(PROFILING "Should the build compile with profiling enabled - REQUIRES CRTLIB ON" OFF) -option(UNOPTIMIZED "Should the build compile with optimization disabled" OFF) +option(RTC "Should the build compile with runtime checks enabled (asserts, asan, etc.) - REQUIRES CRTLIB=ON" OFF) +option(ASAN "Should the build compile with the address sanitizer enabled (asserts, asan, etc.) - REQUIRES CRTLIB=ON" OFF) +option(CRTLIB "Should the build link with the CRTLIB" OFF) +option(DEBINFO "Should the build compile with debug info" OFF) +option(DEVELOPER "Should the build compile with developer mode enabled" OFF) +option(PROFILING "Should the build compile with profiling enabled - REQUIRES CRTLIB=ON, MSVC=OFF" OFF) +option(UNOPTIMIZED "Should the build compile with optimization disabled" OFF) +option(MSVC "Should the build compile using MSVC" OFF) ################################################################################ # Source files @@ -123,7 +124,7 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Add executable -add_executable(powerplay_exe ${sources}) +add_executable(powerplay_exe WIN32 ${sources}) set_target_properties( powerplay_exe PROPERTIES C_STANDARD 99 @@ -142,75 +143,127 @@ target_precompile_headers(powerplay_exe PRIVATE src/common.h) # -Wconversion \ # -Wno-sign-conversion \ -set(COMPILER_WARNINGS " \ --Weverything -Werror \ --Wframe-larger-than=65536 \ -\ --Wno-unused-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation \ --Wno-old-style-cast -Wno-conversion -Wno-sign-conversion \ --Wno-declaration-after-statement -Wno-extra-semi -Wno-extra-semi-stmt \ --Wno-bad-function-cast -Wno-class-varargs -Wno-unreachable-code-break \ --Wno-cast-align -Wno-float-equal -Wno-zero-as-null-pointer-constant \ --Wno-cast-qual -Wno-missing-noreturn -Wno-missing-field-initializers \ --Wno-missing-braces -Wno-initializer-overrides \ --Wno-c99-extensions -Wno-c++98-compat-pedantic -Wno-c++98-compat \ --Wno-switch-enum -Wno-switch-default \ --Wno-reserved-identifier -Wno-reserved-macro-identifier \ --Wno-unsafe-buffer-usage -Wno-writable-strings \ -") -# -Wno-unused-vfariable -Wno-unused-but-set-variable -Wno-unused-parameter +if (MSVC) + set(COMPILER_WARNINGS "") -set(COMPILER_FLAGS " --fuse-ld=lld-link \ --nostdlib \ --fno-strict-aliasing \ --fno-finite-loops \ --fwrapv \ --msse4.2 \ -") + set(COMPILER_AND_LINKER_FLAGS) -set(LINKER_FLAGS " \ -${rc_res_sources} \ --fno-strict-aliasing \ --fno-finite-loops \ --fwrapv \ --msse4.2 \ -") + set(COMPILER_FLAGS) + + set(LINKER_FLAGS "${rc_res_sources} /subsystem:windows") + + set(C_VERSION "/std:c11") + set(CPP_VERSION "/std:c++20") +else() + set(COMPILER_WARNINGS " \ + -Weverything -Werror \ + -Wframe-larger-than=65536 \ + \ + -Wno-unused-macros -Wno-gnu-zero-variadic-macro-arguments -Wno-documentation \ + -Wno-old-style-cast -Wno-conversion -Wno-sign-conversion \ + -Wno-declaration-after-statement -Wno-extra-semi -Wno-extra-semi-stmt \ + -Wno-bad-function-cast -Wno-class-varargs -Wno-unreachable-code-break \ + -Wno-cast-align -Wno-float-equal -Wno-zero-as-null-pointer-constant \ + -Wno-cast-qual -Wno-missing-noreturn -Wno-missing-field-initializers \ + -Wno-missing-braces -Wno-initializer-overrides \ + -Wno-c99-extensions -Wno-c++98-compat-pedantic -Wno-c++98-compat \ + -Wno-switch-enum -Wno-switch-default \ + -Wno-reserved-identifier -Wno-reserved-macro-identifier \ + -Wno-unsafe-buffer-usage -Wno-writable-strings \ + ") + # -Wno-unused-vfariable -Wno-unused-but-set-variable -Wno-unused-parameter + + set(COMPILER_AND_LINKER_FLAGS " + -fuse-ld=lld-link \ + -nostdlib \ + -fno-strict-aliasing \ + -fno-finite-loops \ + -fwrapv \ + -msse4.2 \ + ") + + set(COMPILER_FLAGS) + + set(LINKER_FLAGS " \ + ${rc_res_sources} \ + -fno-strict-aliasing \ + -fno-finite-loops \ + -fwrapv \ + -msse4.2 \ + ") + + set(C_VERSION "-std=c99") + set(CPP_VERSION "-std=c++20") +endif() # RTC (Runtime checks) if (RTC) if (NOT CRTLIB) message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)") endif() - # Enable UBSan - set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -fsanitize-trap=all -DRTC=1") - # set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -DRTC=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DRTC=1") + if (MSVC) + if (NOT ASAN) + # Enable RTC (not compatible with ASAN) + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /RTCcsu") + endif() + else() + # Enable UBSan + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=undefined -fsanitize-trap=all") + # set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=undefined -DRTC=1") + endif() endif() # CRTLIB (C runtime library) if (CRTLIB) - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DCRTLIB=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DCRTLIB=1") if (RTC) - set(COMPILER_FLAGS "${COMPILER_FLAGS} -D_DEBUG -D_MT -D_DLL") - set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrtd -lucrtd -lmsvcprtd -lvcruntimed") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -D_DEBUG -D_MT -D_DLL") + if (MSVC) + set(LINKER_FLAGS "${LINKER_FLAGS} msvcrtd.lib ucrtd.lib msvcprtd.lib vcruntime.lib") + else() + set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrtd -lucrtd -lmsvcprtd -lvcruntimed") + endif() else() - set(COMPILER_FLAGS "${COMPILER_FLAGS} -D_MT -D_DLL") - set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrt -lucrt -lmsvcprt -lvcruntime") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -D_MT -D_DLL") + if (MSVC) + set(LINKER_FLAGS "${LINKER_FLAGS} msvcrt.lib ucrt.lib msvcprt.lib vcruntime.lib ") + else() + set(LINKER_FLAGS "${LINKER_FLAGS} -lmsvcrt -lucrt -lmsvcprt -lvcruntime") + endif() endif() else() - set(COMPILER_FLAGS "${COMPILER_FLAGS} -mno-stack-arg-probe -fno-builtin") + if (MSVC) + message(FATAL_ERROR "TODO") + else() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -mno-stack-arg-probe -fno-builtin") + endif() endif() # Optimization if (UNOPTIMIZED) - set(COMPILER_FLAGS "${COMPILER_FLAGS} -O0 -DUNOPTIMIZED=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DUNOPTIMIZED=1") + if (MSVC) + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /Od") + else() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -O0") + endif() else() - set(COMPILER_FLAGS "${COMPILER_FLAGS} -O3 -flto") + if (MSVC) + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /O2 /LTCG") + else() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -O3 -flto") + endif() endif() # Debug info if (DEBINFO) - set(COMPILER_FLAGS "${COMPILER_FLAGS} -g -DDEBINFO=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DDEBINFO=1") + if (MSVC) + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /Zi") + else() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -g") + endif() endif() # ASAN @@ -218,12 +271,17 @@ if (ASAN) if (NOT CRTLIB) message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with ASAN") endif() - set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=address -shared-libasan -DASAN=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DASAN=1") + if (MSVC) + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} /fsanitize=address") + else() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -fsanitize=address -shared-libasan") + endif() endif() # Developer mode if(DEVELOPER) - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DDEVELOPER=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DDEVELOPER=1") endif() # Profiling @@ -231,16 +289,19 @@ if(PROFILING) if (NOT CRTLIB) message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with PROFILING") endif() - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DPROFILING=1") + if (MSVC) + message(FATAL_ERROR "MSVC not supported with PROFILING enabled (Profiling relies on Clang attributes)") + endif() + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DPROFILING=1") # Tracy flags - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DTRACY_ENABLE=1") - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DTRACY_CALLSTACK=5") - set(COMPILER_FLAGS "${COMPILER_FLAGS} -DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_ENABLE=1") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_CALLSTACK=5") + set(COMPILER_AND_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} -DTRACY_NO_SAMPLING -DTRACY_NO_SYSTEM_TRACING -DTRACY_NO_CALLSTACK") # Disable warnings when compiling tracy client set(COMPILER_WARNINGS "-Wno-everything") endif() -set(CMAKE_C_FLAGS "${COMPILER_FLAGS} ${COMPILER_WARNINGS} -std=c99") -set(CMAKE_CXX_FLAGS "${COMPILER_FLAGS} ${COMPILER_WARNINGS} -std=c++14") -set(CMAKE_EXE_LINKER_FLAGS "${COMPILER_FLAGS} ${LINKER_FLAGS}") +set(CMAKE_C_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${COMPILER_FLAGS} ${COMPILER_WARNINGS} ${C_VERSION}") +set(CMAKE_CXX_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${COMPILER_FLAGS} ${COMPILER_WARNINGS} ${CPP_VERSION}") +set(CMAKE_EXE_LINKER_FLAGS "${COMPILER_AND_LINKER_FLAGS} ${LINKER_FLAGS}") diff --git a/build.bat b/build.bat index 25f0d37a..89b538ea 100644 --- a/build.bat +++ b/build.bat @@ -6,6 +6,9 @@ setlocal :: "developer" The target will include all developer tooling :: "profiling" The target will be compiled with profiling markup :: "asan" The target will compile with address sanitizer enabled +:: "msvc" Compile with MSVC instead of Clang + +for %%a in (%*) do set "%%a=1" :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: :: Verify environment @@ -16,14 +19,21 @@ if "%Platform%" neq "x64" ( exit /b 1 ) -where /q clang.exe || ( - echo ERROR: "clang.exe" not found. - exit /b 1 -) +if "%msvc%" == "1" ( + where /q cl.exe || ( + echo ERROR: "cl.exe" not found. + exit /b 1 + ) +) else ( + where /q clang.exe || ( + echo ERROR: "clang.exe" not found. + exit /b 1 + ) -where /q lld-link || ( - echo ERROR: "lld-link.exe" not found. - exit /b 1 + where /q lld-link || ( + echo ERROR: "lld-link.exe" not found. + exit /b 1 + ) ) where /q ninja.exe || ( @@ -42,13 +52,18 @@ where /q cmake || ( :: Must explicitly pass disabled CMake options or else missing options are :: assumed to be equal to the value from the last build -set cmake_options_zero=-DRTC=0 -DASAN=0 -DCRTLIB=0 -DDEBINFO=0 -DDEVELOPER=0 -DPROFILING=0 -DUNOPTIMIZED=0 +set cmake_options_zero=-DRTC=0 -DASAN=0 -DCRTLIB=0 -DDEBINFO=0 -DDEVELOPER=0 -DPROFILING=0 -DUNOPTIMIZED=0 -DMSVC=0 set cmake_options_enabled= echo ======================================== -for %%a in (%*) do set "%%a=1" +if "%msvc%" == "1" ( + echo [Msvc] + set cmake_options_enabled=%cmake_options_enabled% -DMSVC=1 +) else ( + echo [Clang] +) if "%debug%" == "1" ( echo [Debug build] @@ -82,17 +97,32 @@ echo ======================================== if not exist "build" mkdir build -cmake -H. -G Ninja -B build %cmake_options_zero% %cmake_options_enabled%^ - -DCMAKE_C_COMPILER:PATH="clang.exe"^ - -DCMAKE_CXX_COMPILER:PATH="clang.exe"^ - -DCMAKE_C_COMPILER_ID="Clang"^ - -DCMAKE_CXX_COMPILER_ID="Clang"^ - -DCMAKE_SYSTEM_NAME="Generic"^ - -DPLATFORM_WIN32=1 +if "%msvc%" == "1" ( + cmake -H. -G Ninja -B build %cmake_options_zero% %cmake_options_enabled%^ + -DCMAKE_C_COMPILER:PATH="cl.exe"^ + -DCMAKE_CXX_COMPILER:PATH="cl.exe"^ + -DPLATFORM_WIN32=1 +) else ( + cmake -H. -G Ninja -B build %cmake_options_zero% %cmake_options_enabled%^ + -DCMAKE_C_COMPILER:PATH="clang.exe"^ + -DCMAKE_CXX_COMPILER:PATH="clang.exe"^ + -DCMAKE_C_COMPILER_ID="Clang"^ + -DCMAKE_CXX_COMPILER_ID="Clang"^ + -DCMAKE_SYSTEM_NAME="Generic"^ + -DPLATFORM_WIN32=1 +) -if NOT %errorlevel% == 0 exit /b 1 +if NOT %errorlevel% == 0 ( + echo. + echo ERROR: Configuration failed + exit /b 1 +) cmake --build build :: cmake --build build -v -exit /b %errorlevel% +if NOT %errorlevel% == 0 ( + echo. + echo ERROR: Build failed + exit /b 1 +) diff --git a/src/ase.c b/src/ase.c index df884d95..a51d42bd 100644 --- a/src/ase.c +++ b/src/ase.c @@ -408,7 +408,7 @@ enum cel_type { CEL_TYPE_COMPRESSED_TILEMAP = 3 }; -struct ase_header { +PACK(struct ase_header { u32 file_size; u16 magic; u16 frames; @@ -429,16 +429,16 @@ struct ase_header { u16 grid_width; u16 grid_height; u8 _4[84]; -} PACKED; +}); -struct frame_header { +PACK(struct frame_header { u32 bytes; u16 magic; u16 chunks_old; u16 frame_duration_ms; u8 _[2]; u32 chunks_new; -} PACKED; +}); INTERNAL void push_error_copy_msg(struct arena *arena, struct ase_error_list *list, struct string msg_src) { diff --git a/src/atomic.h b/src/atomic.h index ae468069..899358ab 100644 --- a/src/atomic.h +++ b/src/atomic.h @@ -1,7 +1,7 @@ #ifndef ATOMIC_H #define ATOMIC_H -#if OS_WINDOWS +#if PLATFORM_WINDOWS FORCE_INLINE i32 atomic_i32_eval(struct atomic_i32 *x) { return _InterlockedOr((volatile long *)&x->_v, 0); } FORCE_INLINE i32 atomic_i32_inc_eval(struct atomic_i32 *x) { return _InterlockedIncrement((volatile long *)&x->_v); } diff --git a/src/common.h b/src/common.h index 21ddfd38..1f9323d5 100644 --- a/src/common.h +++ b/src/common.h @@ -73,39 +73,39 @@ extern "C" { * ========================== */ /* Compiler */ -#if defined(_MSC_VER) && !defined(__clang__) -# define COMPILER_MSVC 1 -# define COMPILER_CLANG 0 -# define COMPILER_GCC 0 -#elif defined(__clang__) -# define COMPILER_MSVC 0 +#if defined(__clang__) # define COMPILER_CLANG 1 -# define COMPILER_GCC 0 -#elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_MSVC 0 +#elif defined(_MSC_VER) # define COMPILER_CLANG 0 -# define COMPILER_GCC 1 +# define COMPILER_MSVC 1 #else # error "Unknown compiler" #endif /* Operating system */ #if defined(_WIN32) -# define OS_WINDOWS 1 -# define OS_MAC 0 -# define OS_LINUX 0 +# define PLATFORM_WINDOWS 1 +# define PLATFORM_MAC 0 +# define PLATFORM_LINUX 0 #elif defined(__APPLE__) && defined(__MACH__) -# define OS_WINDOWS 0 -# define OS_MAC 1 -# define OS_LINUX 0 +# define PLATFORM_WINDOWS 0 +# define PLATFORM_MAC 1 +# define PLATFORM_LINUX 0 #elif defined(__gnu_linux__) -# define OS_WINDOWS 0 -# define OS_MAC 0 -# define OS_LINUX 1 +# define PLATFORM_WINDOWS 0 +# define PLATFORM_MAC 0 +# define PLATFORM_LINUX 1 #else # error "Unknown OS" #endif +#if defined(__cplusplus) +# define LANGUAGE_CPP 1 +#else +# define LANGUAGE_C 1 +#endif + /* ========================== * * Debug * ========================== */ @@ -115,22 +115,31 @@ extern "C" { #define CT_ASSERT2(cond, line) CT_ASSERT3(cond, line) #define CT_ASSERT(cond) CT_ASSERT2(cond, __LINE__) -#if DEBINFO -# define DEBUG_ALIAS(var, alias) __attribute((used)) *(alias) = &(var); +#if COMPILER_MSVC +# if DEBINFO +# define DEBUG_ALIAS(var, alias) *(alias) = &(var); +# else +# define DEBUG_ALIAS(var, alias) *(alias) = &(var); +# endif #else -# define DEBUG_ALIAS(var, alias) __attribute((unused)) *(alias) = &(var); +# if DEBINFO +# define DEBUG_ALIAS(var, alias) __attribute((used)) *(alias) = &(var); +# else +# define DEBUG_ALIAS(var, alias) __attribute((unused)) *(alias) = &(var); +# endif #endif #if RTC - -#define ASSERT(cond) ((cond) ? 1 : (__builtin_trap(), 0)) -#define DEBUGBREAK __builtin_debugtrap() -#define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; (UNUSED) __DEBUGBREAKABLE_VAR; } - +# if COMPILER_MSVC +# define ASSERT(cond) ((cond) ? 1 : ((*(volatile int *)0) = 0, 0)) +# define DEBUGBREAK __debugbreak +# else +# define ASSERT(cond) ((cond) ? 1 : (__builtin_trap(), 0)) +# define DEBUGBREAK __builtin_debugtrap() +# endif +# define DEBUGBREAKABLE { volatile i32 __DEBUGBREAKABLE_VAR = 0; (UNUSED) __DEBUGBREAKABLE_VAR; } #else - -#define ASSERT(cond) (void)(0) - +# define ASSERT(cond) (void)(0) #endif /* Address sanitization */ @@ -148,6 +157,12 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); * Common macros * ========================== */ +#if COMPILER_MSVC && LANGUAGE_CPP +# define CPPFRIENDLY_INITLIST_TYPE(type) type +# else +# define CPPFRIENDLY_INITLIST_TYPE(type) (type) +#endif + #if 1 # define INLINE static inline #else @@ -155,7 +170,11 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); # define INLINE static inline __attribute((always_inline)) #endif -#define FORCE_INLINE static inline __attribute((always_inline)) +#if COMPILER_MSVC +# define FORCE_INLINE static inline __forceinline +#else +# define FORCE_INLINE static inline __attribute((always_inline)) +#endif /* Separate `static` usage into different keywords for easier grepping */ #define LOCAL_PERSIST static @@ -163,9 +182,14 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define GLOBAL static /* Read-only */ -#if OS_WINDOWS -# define READONLY __declspec(allocate(".rdata")) -#elif OS_MAC +#if PLATFORM_WINDOWS +# if COMPILER_MSVC +# pragma section(".rdata$", read) +# define READONLY __declspec(allocate(".rdata$")) +# else +# define READONLY __declspec(allocate(".rdata")) +# endif +#elif PLATFORM_MAC #define READONLY __attribute((section("__TEXT,__const"))) #else #define READONLY __attribute((section(".rodata"))) @@ -173,7 +197,12 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); /* Markup */ #define UNUSED void + +#if COMPILER_CLANG #define FALLTHROUGH __attribute((fallthrough)) +#else +#define FALLTHROUGH +#endif /* Sizes */ #define KILOBYTE(n) (n*1024ULL) @@ -182,18 +211,25 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define TERABYTE(n) (n*GIGABYTE(1024ULL)) /* typeof */ -#if defined(__cplusplus) || (__STDC_VERSION__ < 202311L) -# define typeof(type) __typeof__(type) +#if LANGUAGE_CPP || (__STDC_VERSION__ < 202311L) +# if COMPILER_MSVC +/* Typeof not supported in MSVC */ +# define typeof(type) ASSERT(false) +# define TYPEOF_DEFINED 0 +# else +# define typeof(type) __typeof__(type) +# define TYPEOF_DEFINED 1 +# endif #endif /* alignof */ -#if !defined(__cplusplus) && (__STDC_VERSION__ < 202311L) -# define alignof(type) __alignof__(type) +#if LANGUAGE_C && (__STDC_VERSION__ < 202311L) +# define alignof(type) __alignof(type) #endif #define ARRAY_COUNT(a) (sizeof(a) / sizeof((a)[0])) -/* field macros */ +/* Field macros */ #define FIELD_SIZEOF(type, field) sizeof(((type *)0)->field) #if COMPILER_MSVC && !defined _CRT_USE_BUILTIN_OFFSETOF # define FIELD_OFFSETOF(type, field) ((u64)&(((type *)0)->field)) @@ -212,24 +248,31 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #define IS_ARRAY(a) (IS_INDEXABLE(a) && (((void *)&a) == ((void *)a))) /* Pack */ -#define PACKED __attribute((__packed__)) +#if COMPILER_MSVC +# define PACK(s) __pragma(pack(push, 1)) s __pragma(pack(pop)) +#else +# define PACK(s) s __attribute((__packed__)) +#endif /* Color */ -#define RGBA(r, g, b, a) (u32)((u32)(r) | ((u32)(g) << 8) | ((u32)(b) << 16) | ((u32)(a) << 24)) -#define RGB(r, g, b) RGBA(r, g, b, 0xFF) +#define RGBA_32(r, g, b, a) (u32)((u32)(r) | ((u32)(g) << 8) | ((u32)(b) << 16) | ((u32)(a) << 24)) +#define RGB_32(r, g, b) RGBA_32(r, g, b, 0xFF) #define _RGB_F_TO_U8(f) ((u8)((f * 255.0f) + 0.5f)) -#define RGBA_F(r, g, b, a) RGBA(_RGB_F_TO_U8(r), _RGB_F_TO_U8(g), _RGB_F_TO_U8(b), _RGB_F_TO_U8(a)) -#define RGB_F(r, g, b) RGBA_F(r, g, b, 1.f) +#define RGBA_32_F(r, g, b, a) RGBA_32(_RGB_F_TO_U8(r), _RGB_F_TO_U8(g), _RGB_F_TO_U8(b), _RGB_F_TO_U8(a)) +#define RGB_32_F(r, g, b) RGBA_32_F(r, g, b, 1.f) -#define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF) -#define COLOR_BLACK RGB(0, 0, 0 ) -#define COLOR_RED RGB(0xFF, 0, 0 ) -#define COLOR_GREEN RGB(0, 0xFF, 0 ) -#define COLOR_BLUE RGB(0, 0, 0xFF) +#define COLOR_WHITE RGB_32(0xFF, 0xFF, 0xFF) +#define COLOR_BLACK RGB_32(0, 0, 0 ) +#define COLOR_RED RGB_32(0xFF, 0, 0 ) +#define COLOR_GREEN RGB_32(0, 0xFF, 0 ) +#define COLOR_BLUE RGB_32(0, 0, 0xFF) /* Barrier */ -#if defined(__x86_64) || defined(__i386__) +#if COMPILER_MSVC +# define WRITE_BARRIER() _WriteBarrier() +# define READ_BARRIER() _ReadBarrier() +#elif defined(__x86_64) || defined(__i386__) # define WRITE_BARRIER() __asm__ volatile("" ::: "memory") # define READ_BARRIER() __asm__ volatile("" ::: "memory") #else @@ -258,24 +301,19 @@ typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; -typedef __int128_t i128; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; -typedef __uint128_t u128; typedef float f32; typedef double f64; typedef i8 b8; typedef i32 b32; -#define I128(hi64, lo64) (((i128)(hi64) << 64) | (lo64)) -#define U128(hi64, lo64) (((u128)(hi64) << 64) | (lo64)) - #define U8_MAX (0xFF) #define U16_MAX (0xFFFF) #define U32_MAX (0xFFFFFFFF) -#define U64_MAX (0xFFFFFFFFFFFFFFFFULG) +#define U64_MAX (0xFFFFFFFFFFFFFFFFULL) #define I8_MAX (0x7F) #define I16_MAX (0x7FFF) @@ -287,12 +325,74 @@ typedef i32 b32; #define I32_MIN ((i32)-0x80000000) #define I64_MIN ((i64)-0x8000000000000000LL) -#define F32_INFINITY (1.0 / 0.0f) -#define F64_INFINITY (1.0 / 0.0) +GLOBAL const u32 _f32_infinity_u32 = 0x7f800000; +GLOBAL const f32 *_f32_infinity = (f32 *)&_f32_infinity_u32; +GLOBAL const u64 _f64_infinity_u64 = 0x7ff0000000000000ULL; +GLOBAL const f64 *_f64_infinity = (f64 *)&_f64_infinity_u64; +#define F32_INFINITY (*_f32_infinity) +#define F64_INFINITY (*_f64_infinity) #define PI ((f32)3.14159265358979323846) #define TAU ((f32)6.28318530717958647693) +/* ========================== * + * Big int + * ========================== */ + +#if COMPILER_CLANG + +#define U128(hi64, lo64) (((u128)(hi64) << 64) | (lo64)) +#define U128_HI64(a) ((u64)((a) >> 64)) +#define U128_LO64(a) ((u64)(a)) + +typedef __uint128_t u128; + +INLINE b32 u128_eq(u128 a, u128 b) { return a == b; } +INLINE u128 u128_xor_u8(u128 a, u8 b) { return a ^ b; } +INLINE u128 u128_mul(u128 a, u128 b) { return a * b; } + +#elif COMPILER_MSVC + +#ifdef __cplusplus +# define U128(hi64, lo64) { (hi64), (lo64) } +#else +# define U128(hi64, lo64) ((u128) { .hi = (hi64), .lo = (lo64) }) +#endif +#define U128_HI64(a) ((a).hi) +#define U128_LO64(a) ((a).lo) + +typedef struct { u64 hi; u64 lo; } u128; + +INLINE b32 u128_eq(u128 a, u128 b) { return a.hi == b.hi && a.lo == b.lo; } +INLINE u128 u128_xor_u8(u128 a, u8 b) { return U128(a.hi, a.lo ^ b); } + +/* https://www.codeproject.com/Tips/784635/UInt-Bit-Operations */ + +u128 u128_mul(u128 a, u128 b) +{ + u64 a1 = (a.lo & 0xffffffff); + u64 b1 = (b.lo & 0xffffffff); + u64 t = (a1 * b1); + u64 w3 = (t & 0xffffffff); + u64 k = (t >> 32); + + a.lo >>= 32; + t = (a.lo * b1) + k; + k = (t & 0xffffffff); + u64 w1 = (t >> 32); + + b.lo >>= 32; + t = (a1 * b.lo) + k; + k = (t >> 32); + + u128 res = U128((a.lo * b.lo) + w1 + k, (t << 32) + w3); + res.hi += (a.hi * b.lo) + (a.lo * b.hi); + + return res; +} + +#endif + /* ========================== * * Atomics * ========================== */ @@ -380,7 +480,7 @@ struct sprite_tag { * ========================== */ /* Utility buffer constructor */ -#define BUFFER(size, data) (struct buffer) {size, data} +#define BUFFER(size, data) (CPPFRIENDLY_INITLIST_TYPE(struct buffer) { (size), (data) }) /* Utility buffer constructor from static array */ #define BUFFER_FROM_ARRAY(a) \ @@ -388,40 +488,27 @@ struct sprite_tag { /* Must be array */ \ ASSERT(IS_ARRAY(a)), \ /* Must be array of bytes */ \ - ASSERT(sizeof(a[0]) == sizeof(u8)), \ - ((struct buffer) { .size = ARRAY_COUNT(a), .data = (u8 *)a }) \ + ASSERT(sizeof((a)[0]) == sizeof(u8)), \ + ((struct buffer) { .size = ARRAY_COUNT(a), .data = (u8 *)(a) }) \ ) -#define BUFFER_FROM_STRING(str) ((struct buffer) { str.len, str.text }) +#define BUFFER_FROM_STRING(str) (CPPFRIENDLY_INITLIST_TYPE(struct buffer) { (str).len, (str).text }) -#define BUFFER_FROM_POINTERS(p1, p2) ((struct buffer) { (u8 *)(p2) - (u8 *)(p1), (u8 *)p1 }) +#define BUFFER_FROM_POINTERS(p1, p2) (CPPFRIENDLY_INITLIST_TYPE(struct buffer) { (u8 *)(p2) - (u8 *)(p1), (u8 *)p1 }) -#define BUFFER_FROM_STRUCT(ptr) ((struct buffer) { sizeof(*ptr), ptr }) +#define BUFFER_FROM_STRUCT(ptr) (CPPFRIENDLY_INITLIST_TYPE(struct buffer) { sizeof(*(ptr)), (ptr) }) /* ========================== * * String utils * ========================== */ /* Expand C string literal with size for string initialization */ -#ifdef __cplusplus -#define STR(cstr_lit) { \ - (sizeof((cstr_lit)) - 1), \ - (u8 *)(cstr_lit) \ -} -#else -#define STR(cstr_lit) (struct string) { \ - .len = (sizeof((cstr_lit)) - 1), \ - .text = (u8 *)(cstr_lit) \ -} -#endif +#define STR(cstr_lit) CPPFRIENDLY_INITLIST_TYPE(struct string) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } /* Same as `STR`, but works with static variable initialization */ -#define STR_NOCAST(cstr_lit) { \ - .len = (sizeof((cstr_lit)) - 1), \ - .text = (u8 *)(cstr_lit) \ -} +#define STR_NOCAST(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } -#define STRING_FROM_BUFFER(buff) ((struct string) { buff.size, buff.data }) +#define STRING_FROM_BUFFER(buff) (CPPFRIENDLY_INITLIST_TYPE(struct string) { buff.size, buff.data }) #define STRING_FROM_ARRAY(a) STRING_FROM_BUFFER(BUFFER_FROM_ARRAY(a)) @@ -537,7 +624,9 @@ INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? #define PROFILING_CAPTURE_FRAME_IMAGE 1 /* Clang/GCC cleanup macros */ -#if COMPILER_CLANG || COMPILER_GCC +#if COMPILER_MSVC +# error "MSVC not supported for profiling (cleanup attributes are required for profiling markup)" +#else # ifdef TRACY_NO_CALLSTACK # define __prof static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, __func__, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); # define __profscope(name) static const struct ___tracy_source_location_data CAT(__tracy_source_location,__LINE__) = { NULL, #name, __FILE__, (uint32_t)__LINE__, 0 }; __attribute((cleanup(__prof_zone_cleanup_func))) TracyCZoneCtx __tracy_ctx = ___tracy_emit_zone_begin( &CAT(__tracy_source_location,__LINE__), true ); diff --git a/src/entity.c b/src/entity.c index 1d0d5e70..9206e86b 100644 --- a/src/entity.c +++ b/src/entity.c @@ -3,9 +3,9 @@ /* Accessed via entity_nil() */ READONLY struct entity _g_entity_nil = { - .rel_xform = XFORM_IDENT, - .world_xform = XFORM_IDENT, - .sprite_quad_xform = XFORM_IDENT, + .rel_xform = XFORM_IDENT_NOCAST, + .world_xform = XFORM_IDENT_NOCAST, + .sprite_quad_xform = XFORM_IDENT_NOCAST, .sprite_tint = COLOR_WHITE }; diff --git a/src/game.c b/src/game.c index 93917e82..e700c34f 100644 --- a/src/game.c +++ b/src/game.c @@ -262,7 +262,7 @@ INTERNAL void game_update(void) e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase"));; e->sprite_span_name = STR("UNARMED"); - e->sprite_tint = RGBA_F(0.5, 0.5, 0, 1); + e->sprite_tint = RGBA_32_F(0.5, 0.5, 0, 1); //entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); //e->player_max_speed = 5.f; @@ -311,7 +311,7 @@ INTERNAL void game_update(void) e->sprite_quad_xform = xform_with_scale(XFORM_IDENT, sprite_size); e->sprite = sprite_tag_from_path(STR("res/graphics/sound.ase"));; - e->sprite_tint = RGBA_F(1, 1, 0, 1); + e->sprite_tint = RGBA_32_F(1, 1, 0, 1); entity_enable_prop(e, ENTITY_PROP_TEST_SOUND_EMITTER); e->sound_name = STR("res/sounds/test.mp3"); diff --git a/src/incbin.c b/src/incbin.c new file mode 100644 index 00000000..0c7cca8e --- /dev/null +++ b/src/incbin.c @@ -0,0 +1,91 @@ +#if COMPILER_MSVC + +/* ========================== * + * Msvc RC file lookup + * ========================== */ + +#include "incbin.h" +#include "scratch.h" +#include "string.h" +#include "atomic.h" +#include "intrinsics.h" + +#define WIN32_LEAN_AND_MEAN +#define UNICODE +#include + +struct rc_search_params { + /* In */ + struct string16 name; + /* Out */ + b32 found; + struct buffer data; +}; + +/* Find first resource with `type` and return the data in `udata`. */ +INTERNAL BOOL CALLBACK enum_func(HMODULE module, LPCWSTR type, LPCWSTR wstr_entry_name, LONG_PTR udata) +{ + struct rc_search_params *params = (struct rc_search_params *)udata; + + struct string16 entry_name = string16_from_wstr((LPWSTR)wstr_entry_name); + u64 cmp_size = min_u64(entry_name.len, params->name.len) * 2; + b32 match = MEMCMP(entry_name.text, params->name.text, cmp_size) == 0; + if (match) { + HRSRC hres = FindResourceW(module, wstr_entry_name, type); + if (hres) { + HGLOBAL hg = LoadResource(module, hres); + if (hg) { + params->found = true; + params->data.size = SizeofResource(module, hres); + params->data.data = LockResource(hg); + return true; + } + } + } + + params->found = false; + params->data = BUFFER(0, 0); + return false; +} + +struct buffer _incbin_get(struct _incbin_rc_resource *inc) +{ + enum inc_state state = atomic_i32_eval(&inc->state); + if (state == INCBIN_STATE_SEARCHED) { + return inc->data; + } + + if (state == INCBIN_STATE_UNSEARCHED) { + enum inc_state v = atomic_i32_eval_compare_exchange(&inc->state, state, INCBIN_STATE_SEARCHING) == state; + if (v == state) { + struct temp_arena scratch = scratch_begin_no_conflict(); + { + /* Search */ + struct string16 name16 = string16_from_string(scratch.arena, inc->rc_name); + struct rc_search_params params = { .name = name16 }; + EnumResourceNamesW(NULL, RT_RCDATA, &enum_func, (LONG_PTR)¶ms); + if (!params.found) { + sys_panic(string_format(scratch.arena, + STR("INCBIN include not found in RC file: \"%F\""), + FMT_STR(inc->rc_name))); + } + inc->data = params.data; + state = INCBIN_STATE_SEARCHED; + atomic_i32_eval_exchange(&inc->state, state); + } + scratch_end(scratch); + } else { + state = v; + } + } + + /* Spin while another thread is searching */ + while (state != INCBIN_STATE_SEARCHED) { + ix_pause(); + state = atomic_i32_eval(&inc->state); + } + + return inc->data; +} + +#endif diff --git a/src/incbin.h b/src/incbin.h index 3c708982..c62b935f 100644 --- a/src/incbin.h +++ b/src/incbin.h @@ -1,12 +1,47 @@ #ifndef INCBIN_H #define INCBIN_H +#if COMPILER_MSVC + +/* ========================== * + * Msvc RC file incbin + * + * NOTE: Msvc doesn't have an inline assembler that can include binary data. + * So instead these macros will trigger a lookup into the embedded RC file for + * entries matched by name (requires the build system to generate and link RC + * file). + * ========================== */ + +#define INCBIN_INCLUDE(var, _rc_name) static struct _incbin_rc_resource _incbin_ ## var = { .rc_name = STR_NOCAST((_rc_name)) } +#define INCBIN_GET(var) _incbin_get(&_incbin_ ## var) + +enum _incbin_state { + INCBIN_STATE_UNSEARCHED, + INCBIN_STATE_SEARCHING, + INCBIN_STATE_SEARCHED +}; + +struct _incbin_rc_resource { + struct atomic_i32 state; + struct string rc_name; + struct buffer data; +}; + +struct buffer _incbin_get(struct _incbin_rc_resource *inc); + +#else + + +/* ========================== * + * Clang incbin + * ========================== */ + #define INCBINSTR2(x) #x #define INCBINSTR(x) INCBINSTR2(x) -#if OS_WINDOWS +#if PLATFORM_WINDOWS # define INCBIN_SECTION ".rdata, \"dr\"" -#elif OS_MAC +#elif PLATFORM_MAC # define INCBIN_SECTION "__TEXT,__const" #else # define INCBIN_SECTION ".rodata" @@ -14,21 +49,23 @@ /* Includes raw binary data into the executable. */ /* https://gist.github.com/mmozeiko/ed9655cf50341553d282 */ -#define INCBIN_INCLUDE(name, file) \ +#define INCBIN_INCLUDE(var, filename) \ __asm__(".section " INCBIN_SECTION "\n" \ - ".global _incbin_" INCBINSTR(name) "_start\n" \ + ".global _incbin_" INCBINSTR(var) "_start\n" \ ".balign 16\n" \ - "_incbin_" INCBINSTR(name) "_start:\n" \ - ".incbin \"" file "\"\n" \ + "_incbin_" INCBINSTR(var) "_start:\n" \ + ".incbin \"" filename "\"\n" \ \ - ".global _incbin_" INCBINSTR(name) "_end\n" \ + ".global _incbin_" INCBINSTR(var) "_end\n" \ ".balign 1\n" \ - "_incbin_" INCBINSTR(name) "_end:\n" \ + "_incbin_" INCBINSTR(var) "_end:\n" \ ); \ - extern __attribute((aligned(16))) const char _incbin_ ## name ## _start[]; \ - extern const char _incbin_ ## name ## _end[] + extern __attribute((aligned(16))) const char _incbin_ ## var ## _start[]; \ + extern const char _incbin_ ## var ## _end[] -/* Retrieve a buffer for included data using the name supplied to INCBIN_INCLUDE */ -#define INCBIN_GET(name) BUFFER_FROM_POINTERS(_incbin_ ## name ## _start, _incbin_ ## name ## _end) +/* Retrieve a buffer for included data using the variable supplied to INCBIN_INCLUDE */ +#define INCBIN_GET(var) BUFFER_FROM_POINTERS(_incbin_ ## var ## _start, _incbin_ ## var ## _end) + +#endif #endif diff --git a/src/json.c b/src/json.c index 74195a28..758f8e4a 100644 --- a/src/json.c +++ b/src/json.c @@ -70,9 +70,9 @@ enum lex_number_state { }; GLOBAL READONLY struct string g_keyword_strings[] = { - ['t'] = STR("true"), - ['f'] = STR("false"), - ['n'] = STR("null") + ['t'] = STR_NOCAST("true"), + ['f'] = STR_NOCAST("false"), + ['n'] = STR_NOCAST("null") }; GLOBAL READONLY enum token_type g_keyword_types[] = { diff --git a/src/log.h b/src/log.h index 80553e86..0c7cf9e1 100644 --- a/src/log.h +++ b/src/log.h @@ -59,10 +59,10 @@ void log_register_callback(log_event_callback_func *func); #if LOG_LEVEL(LOG_LEVEL_CRITICAL) # if LOG_INCLUDE_SOURCE_LOCATION # define log_critical(msg) _log(LOG_LEVEL_CRITICAL, STR(__FILE__), __LINE__, msg) -# define logf_critical(fmt, ...) _logf(LOG_LEVEL_CRITICAL, STR(__FILE__), __LINE__, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_critical(fmt, ...) _logf(LOG_LEVEL_CRITICAL, STR(__FILE__), __LINE__, STR(fmt) , ## __VA_ARGS__, FMT_END) # else # define log_critical(msg) _log(LOG_LEVEL_CRITICAL, msg) -# define logf_critical(fmt, ...) _logf(LOG_LEVEL_CRITICAL, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_critical(fmt, ...) _logf(LOG_LEVEL_CRITICAL, STR(fmt) , ## __VA_ARGS__, FMT_END) # endif #else # define log_critical(msg) @@ -72,10 +72,10 @@ void log_register_callback(log_event_callback_func *func); #if LOG_LEVEL(LOG_LEVEL_ERROR) # if LOG_INCLUDE_SOURCE_LOCATION # define log_error(msg) _log(LOG_LEVEL_ERROR, STR(__FILE__), __LINE__, msg) -# define logf_error(fmt, ...) _logf(LOG_LEVEL_ERROR, STR(__FILE__), __LINE__, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_error(fmt, ...) _logf(LOG_LEVEL_ERROR, STR(__FILE__), __LINE__, STR(fmt) , ## __VA_ARGS__, FMT_END) # else # define log_error(msg) _log(LOG_LEVEL_ERROR, msg) -# define logf_error(fmt, ...) _logf(LOG_LEVEL_ERROR, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_error(fmt, ...) _logf(LOG_LEVEL_ERROR, STR(fmt) , ## __VA_ARGS__, FMT_END) # endif #else # define log_error(msg) @@ -85,10 +85,10 @@ void log_register_callback(log_event_callback_func *func); #if LOG_LEVEL(LOG_LEVEL_WARNING) # if LOG_INCLUDE_SOURCE_LOCATION # define log_warning(msg) _log(LOG_LEVEL_WARNING, STR(__FILE__), __LINE__, msg) -# define logf_warning(fmt, ...) _logf(LOG_LEVEL_WARNING, STR(__FILE__), __LINE__, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_warning(fmt, ...) _logf(LOG_LEVEL_WARNING, STR(__FILE__), __LINE__, STR(fmt) , ## __VA_ARGS__, FMT_END) # else # define log_warning(msg) _log(LOG_LEVEL_WARNING, msg) -# define logf_warning(fmt, ...) _logf(LOG_LEVEL_WARNING, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_warning(fmt, ...) _logf(LOG_LEVEL_WARNING, STR(fmt) , ## __VA_ARGS__, FMT_END) # endif #else # define log_warning(msg) @@ -98,10 +98,10 @@ void log_register_callback(log_event_callback_func *func); #if LOG_LEVEL(LOG_LEVEL_DEBUG) # if LOG_INCLUDE_SOURCE_LOCATION # define log_debug(msg) _log(LOG_LEVEL_DEBUG, STR(__FILE__), __LINE__, msg) -# define logf_debug(fmt, ...) _logf(LOG_LEVEL_DEBUG, STR(__FILE__), __LINE__, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_debug(fmt, ...) _logf(LOG_LEVEL_DEBUG, STR(__FILE__), __LINE__, STR(fmt) , ## __VA_ARGS__, FMT_END) # else # define log_debug(msg) _log(LOG_LEVEL_DEBUG, msg) -# define logf_debug(fmt, ...) _logf(LOG_LEVEL_DEBUG, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_debug(fmt, ...) _logf(LOG_LEVEL_DEBUG, STR(fmt) , ## __VA_ARGS__, FMT_END) # endif #else # define log_debug(msg) @@ -112,10 +112,10 @@ void log_register_callback(log_event_callback_func *func); #if LOG_LEVEL(LOG_LEVEL_INFO) # if LOG_INCLUDE_SOURCE_LOCATION # define log_info(msg) _log(LOG_LEVEL_INFO, STR(__FILE__), __LINE__, msg) -# define logf_info(fmt, ...) _logf(LOG_LEVEL_INFO, STR(__FILE__), __LINE__, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_info(fmt, ...) _logf(LOG_LEVEL_INFO, STR(__FILE__), __LINE__, STR(fmt) , ## __VA_ARGS__, FMT_END) # else # define log_info(msg) _log(LOG_LEVEL_INFO, msg) -# define logf_info(fmt, ...) _logf(LOG_LEVEL_INFO, STR(fmt), __VA_ARGS__, FMT_END) +# define logf_info(fmt, ...) _logf(LOG_LEVEL_INFO, STR(fmt) , ## __VA_ARGS__, FMT_END) # endif #else # define log_info(msg) diff --git a/src/math.h b/src/math.h index de2e170a..62245051 100644 --- a/src/math.h +++ b/src/math.h @@ -714,8 +714,9 @@ INLINE struct mat4x4 mat4x4_mul(struct mat4x4 m1, struct mat4x4 m2) /* Construct identity xform */ #define XFORM_IDENT ((struct xform) { .bx.x = 1, .by.y = 1 }) +#define XFORM_IDENT_NOCAST { .bx.x = 1, .by.y = 1 } -#define XFORM_POS(p) ((struct xform) { .bx.x = 1, .by.y = 1, .og = p }) +#define XFORM_POS(p) ((struct xform) { .bx.x = 1, .by.y = 1, .og = (p) }) /* Takes a translation, rotation, and scale as optional parameters for constructing an xform */ #define XFORM_TRS(...) xform_from_trs((struct trs) { .t = V2(0,0), .s = V2(1, 1), .r = 0, __VA_ARGS__ }) diff --git a/src/mp3_mmf.c b/src/mp3_mmf.c index b1d5ff2a..ef12aabe 100644 --- a/src/mp3_mmf.c +++ b/src/mp3_mmf.c @@ -8,6 +8,7 @@ #define COBJMACROS #define WIN32_LEAN_AND_MEAN +#define UNICODE #include #include #include diff --git a/src/playback_wasapi.c b/src/playback_wasapi.c index f8594e9c..06ce6936 100644 --- a/src/playback_wasapi.c +++ b/src/playback_wasapi.c @@ -14,6 +14,7 @@ #define COBJMACROS #define WIN32_LEAN_AND_MEAN +#define UNICODE #include #include #include diff --git a/src/renderer.h b/src/renderer.h index 369f23e7..9caf6f8b 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -26,11 +26,11 @@ struct texture_shader_parameters { struct sprite_tag sprite; }; -struct texture_shader_vertex { +PACK(struct texture_shader_vertex { struct v2 pos; struct v2 uv; u32 color; -} PACKED; +}); /* ========================== * diff --git a/src/renderer_d3d11.c b/src/renderer_d3d11.c index 17e58b6d..45ee3cd1 100644 --- a/src/renderer_d3d11.c +++ b/src/renderer_d3d11.c @@ -9,6 +9,7 @@ #include "tar.h" #include "sprite.h" +#define UNICODE #include #define CINTERFACE #define COBJMACROS diff --git a/src/scratch.h b/src/scratch.h index ec898bd7..88deff21 100644 --- a/src/scratch.h +++ b/src/scratch.h @@ -59,7 +59,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict) /* Use `scratch_begin_no_conflict` if no conflicts are present */ ASSERT(potential_conflict != NULL); - struct scratch_ctx *ctx = thread_local_var_eval(&tl_scratch_ctx); + struct scratch_ctx *ctx = (struct scratch_ctx *)thread_local_var_eval(&tl_scratch_ctx); struct arena *scratch_arena = &ctx->arenas[0]; if (potential_conflict && scratch_arena->base == potential_conflict->base) { scratch_arena = &ctx->arenas[1]; @@ -83,7 +83,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict) INLINE struct temp_arena _scratch_begin_no_conflict(void) { - struct scratch_ctx *ctx = thread_local_var_eval(&tl_scratch_ctx); + struct scratch_ctx *ctx = (struct scratch_ctx *)thread_local_var_eval(&tl_scratch_ctx); struct arena *scratch_arena = &ctx->arenas[0]; struct temp_arena temp = arena_temp_begin(scratch_arena); scratch_dbg_push(ctx, &temp); @@ -97,7 +97,7 @@ INLINE struct temp_arena _scratch_begin_no_conflict(void) INLINE void scratch_end(struct temp_arena scratch_temp) { #if RTC - struct scratch_ctx *ctx = thread_local_var_eval(&tl_scratch_ctx); + struct scratch_ctx *ctx = (struct scratch_ctx *)thread_local_var_eval(&tl_scratch_ctx); if (ctx->scratch_id_stack_count > 0) { u64 scratch_id = scratch_temp.scratch_id; u64 expected_id = ctx->scratch_id_stack[--ctx->scratch_id_stack_count]; diff --git a/src/sprite.c b/src/sprite.c index 5a908a69..851e0e65 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -321,12 +321,12 @@ struct sprite_tag sprite_tag_from_path(struct string path) b32 sprite_tag_is_nil(struct sprite_tag tag) { - return tag.hash == 0; + return u128_eq(tag.hash, U128(0, 0)); } b32 sprite_tag_eq(struct sprite_tag t1, struct sprite_tag t2) { - return t1.hash == t2.hash; + return u128_eq(t1.hash, t2.hash); } INTERNAL struct cache_node_hash cache_node_hash_from_tag_hash(u128 tag_hash, enum cache_node_kind kind) @@ -602,7 +602,7 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct struct cache_node **nonmatching_next = NULL; struct cache_node_hash hash = cache_node_hash_from_tag_hash(tag.hash, kind); - u64 cache_bucket_index = hash.v % CACHE_BUCKETS_COUNT; + u64 cache_bucket_index = U128_LO64(hash.v) % CACHE_BUCKETS_COUNT; struct cache_bucket *bucket = &G.cache.buckets[cache_bucket_index]; /* Lookup */ @@ -612,7 +612,7 @@ INTERNAL struct cache_node *node_lookup_touch(struct sprite_scope *scope, struct nonmatching_next = &bucket->first; n = *nonmatching_next; while (n) { - if (n->hash.v == hash.v) { + if (u128_eq(n->hash.v, hash.v)) { scope_ensure_reference(scope, n, cache_bucket_index); break; } else { diff --git a/src/tar.c b/src/tar.c index 49c1d00e..0ce0387f 100644 --- a/src/tar.c +++ b/src/tar.c @@ -24,7 +24,7 @@ #define TAR_TYPE_PAX_HEADER_X 'x' #define TAR_TYPE_PAX_HEADER_G 'g' -struct tar_header { +PACK(struct tar_header { /* Pre-posix */ u8 file_name[100]; u8 file_mode[8]; @@ -47,7 +47,7 @@ struct tar_header { u8 device_minor_number[8]; u8 file_name_prefix[155]; u8 padding[12]; -} PACKED; +}); INTERNAL u64 str_oct_to_u64(struct string str) { diff --git a/src/thread_local.c b/src/thread_local.c index f479b07f..93bb623c 100644 --- a/src/thread_local.c +++ b/src/thread_local.c @@ -10,14 +10,14 @@ #define MAX_THREAD_LOCAL_VARS 256 GLOBAL struct { - struct atomic_i64 metas_lock_flag; + struct atomic_i32 metas_lock_flag; u64 metas_count; struct thread_local_var_meta metas[MAX_THREAD_LOCAL_VARS]; } G = { 0 }, DEBUG_ALIAS(G, G_thread_local); INTERNAL void metas_lock(void) { - while (atomic_i64_eval_compare_exchange(&G.metas_lock_flag, 0, 1) == 0) { + while (atomic_i32_eval_compare_exchange(&G.metas_lock_flag, 0, 1) == 0) { /* Spinlock */ ix_pause(); } @@ -25,7 +25,7 @@ INTERNAL void metas_lock(void) INTERNAL void metas_unlock(void) { - atomic_i64_eval_exchange(&G.metas_lock_flag, 0); + atomic_i32_eval_exchange(&G.metas_lock_flag, 0); } struct thread_local_store thread_local_store_alloc(void) diff --git a/src/thread_local.h b/src/thread_local.h index f923be54..83450e2a 100644 --- a/src/thread_local.h +++ b/src/thread_local.h @@ -45,7 +45,7 @@ struct thread_local_var_meta { #define THREAD_LOCAL_VAR_DECL_EXTERN(var_name, type) struct __thread_local_struct##var_name { struct thread_local_var_meta meta; type *_t; }; extern struct __thread_local_struct##var_name var_name; #define THREAD_LOCAL_VAR_DEF_EXTERN(var_name, type, alloc_func, release_func) \ - typeof(var_name) var_name = { \ + struct __thread_local_struct##var_name var_name = { \ .meta = { \ .size = sizeof(type), \ .align = alignof(type), \ @@ -54,7 +54,12 @@ struct thread_local_var_meta { } \ } -#define thread_local_var_eval(var_ptr) (typeof((var_ptr)->_t))(_thread_local_var_eval(&(var_ptr)->meta)); +#if TYPEOF_DEFINED +# define thread_local_var_eval(var_ptr) (typeof((var_ptr)->_t))(_thread_local_var_eval(&(var_ptr)->meta)); +#else +# define thread_local_var_eval(var_ptr) (void *)(_thread_local_var_eval(&(var_ptr)->meta)); +#endif + void *_thread_local_var_eval(struct thread_local_var_meta *meta); #endif diff --git a/src/ttf_dwrite.cpp b/src/ttf_dwrite.cpp index 5ffbb969..f452e822 100644 --- a/src/ttf_dwrite.cpp +++ b/src/ttf_dwrite.cpp @@ -53,25 +53,29 @@ struct ttf_startup_receipt ttf_startup(void) * 10? Need to verify. Maybe should just use a custom loader. (We're only * using a factory5 since I think WriteInMemoryFileLoader wasn't * implemented until then) */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wlanguage-extension-token" /* for __uuidof */ +#if COMPILER_CLANG +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wlanguage-extension-token" /* for __uuidof */ +#endif HRESULT error = DWriteCreateFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory5), (IUnknown **)&G.factory ); -#pragma clang diagnostic pop +#if COMPILER_CLANG +# pragma clang diagnostic pop +#endif if (error) { sys_panic(STR("Error creating DWrite factory")); } - return (struct ttf_startup_receipt) { 0 }; + return { 0 }; } struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, f32 point_size, u32 *cache_codes, u32 cache_codes_count) { - COLORREF bg_color = RGB(0,0,0); - COLORREF fg_color = RGB(255,255,255); + COLORREF bg_color = RGB_32(0,0,0); + COLORREF fg_color = RGB_32(255,255,255); IDWriteFactory5 *factory = G.factory; @@ -251,7 +255,7 @@ struct ttf_decode_result ttf_decode(struct arena *arena, struct buffer encoded, u64 in_x = bounding_box.left + x; u32 *out_pixel = out_data + (out_x + (out_y * atlas_w)); u32 *in_pixel = in_data + (in_x + (in_y * in_pitch)); - *out_pixel = RGBA(0xFF, 0xFF, 0xFF, *in_pixel & 0xFF); + *out_pixel = RGBA_32(0xFF, 0xFF, 0xFF, *in_pixel & 0xFF); } } out_offset_x += tex_w; diff --git a/src/user.c b/src/user.c index b0e7866f..fb517e78 100644 --- a/src/user.c +++ b/src/user.c @@ -350,9 +350,9 @@ INTERNAL void debug_draw_xform(struct xform xf) { f32 thickness = 2.f; f32 arrowhead_len = 15.f; - u32 color = RGBA_F(0, 1, 1, 0.3); - u32 color_x = RGBA_F(1, 0, 0, 0.3); - u32 color_y = RGBA_F(0, 1, 0, 0.3); + u32 color = RGBA_32_F(0, 1, 1, 0.3); + u32 color_x = RGBA_32_F(1, 0, 0, 0.3); + u32 color_y = RGBA_32_F(0, 1, 0, 0.3); struct v2 pos = xform_mul_v2(G.world_view, xf.og); struct v2 x_ray = xform_basis_mul_v2(G.world_view, xform_get_right(xf)); @@ -372,8 +372,8 @@ INTERNAL void debug_draw_movement(struct entity *ent) f32 thickness = 2.f; f32 arrow_len = 15.f; - u32 color_vel = RGBA_F(1, 0.5, 0, 1); - u32 color_acc = RGBA_F(1, 1, 0.5, 1); + u32 color_vel = RGBA_32_F(1, 0.5, 0, 1); + u32 color_acc = RGBA_32_F(1, 1, 0.5, 1); struct v2 pos = xform_mul_v2(G.world_view, ent->world_xform.og); struct v2 vel_ray = xform_basis_mul_v2(G.world_view, ent->velocity); @@ -698,7 +698,7 @@ INTERNAL void user_update(void) * ========================== */ { - u32 color = RGBA_F(0.2f, 0.2f, 0.2f, 1.f); + u32 color = RGBA_32_F(0.2f, 0.2f, 0.2f, 1.f); draw_solid_rect(G.viewport_bg_canvas, RECT(0, 0, G.viewport_size.x, G.viewport_size.y), color); } @@ -708,9 +708,9 @@ INTERNAL void user_update(void) { f32 thickness = 3.f; - u32 color = RGBA(0x3f, 0x3f, 0x3f, 0xFF); - u32 x_color = RGBA(0x3f, 0, 0, 0xFF); - u32 y_color = RGBA(0, 0x3f, 0, 0xFF); + u32 color = RGBA_32(0x3f, 0x3f, 0x3f, 0xFF); + u32 x_color = RGBA_32(0x3f, 0, 0, 0xFF); + u32 y_color = RGBA_32(0, 0x3f, 0, 0xFF); i64 startx = -10; i64 starty = -10; @@ -802,7 +802,7 @@ INTERNAL void user_update(void) /* Debug draw sprite quad */ { f32 thickness = 2.f; - u32 color = RGBA_F(1, 1, 0, 0.25); + u32 color = RGBA_32_F(1, 1, 0, 0.25); draw_solid_quad_line(G.world_canvas, quad, (thickness / PIXELS_PER_UNIT / G.world_view.zoom), color); } @@ -813,7 +813,7 @@ INTERNAL void user_update(void) /* Debug draw sprite pivot */ { - u32 color = RGBA_F(1, 0, 0, 1); + u32 color = RGBA_32_F(1, 0, 0, 1); draw_solid_circle(G.world_canvas, ent->world_xform.og, 0.02, color, 20); } } @@ -870,7 +870,7 @@ INTERNAL void user_update(void) /* Draw hierarchy */ struct entity *parent = entity_from_handle(&G.world.entity_store, ent->parent); if (parent->valid) { - u32 color = RGBA_F(0.6, 0.6, 1, 0.75); + u32 color = RGBA_32_F(0.6, 0.6, 1, 0.75); f32 thickness = 5; f32 arrow_height = 15; @@ -881,7 +881,7 @@ INTERNAL void user_update(void) /* Draw aim */ if (entity_has_prop(ent, ENTITY_PROP_PLAYER_CONTROLLED)) { - u32 color = RGBA_F(0.75, 0, 0.75, 0.5); + u32 color = RGBA_32_F(0.75, 0, 0.75, 0.5); f32 thickness = 3; f32 arrow_height = 10; struct v2 pos = xform_mul_v2(G.world_view, ent->world_xform.og); @@ -891,7 +891,7 @@ INTERNAL void user_update(void) /* Draw camera rect */ if (entity_has_prop(ent, ENTITY_PROP_CAMERA)) { - u32 color = ent == active_camera ? RGBA_F(1, 1, 1, 0.5) : RGBA_F(0, 0.75, 0, 0.5); + u32 color = ent == active_camera ? RGBA_32_F(1, 1, 1, 0.5) : RGBA_32_F(0, 0.75, 0, 0.5); f32 thickness = 3; @@ -909,7 +909,7 @@ INTERNAL void user_update(void) /* Draw crosshair or show cursor */ if (!G.debug_camera) { struct v2 crosshair_pos = G.viewport_cursor; - u32 tint = RGBA_F(1, 1, 1, 1); + u32 tint = RGBA_32_F(1, 1, 1, 1); struct sprite_tag crosshair_tag = sprite_tag_from_path(STR("res/graphics/crosshair.ase")); struct sprite_texture *t = sprite_texture_from_tag_async(sprite_frame_scope, crosshair_tag); diff --git a/src/util.h b/src/util.h index 520ee078..8ae197db 100644 --- a/src/util.h +++ b/src/util.h @@ -34,8 +34,8 @@ INLINE u128 hash_fnv128(u128 seed, struct buffer buff) u128 hash = seed; for (u64 i = 0; i < buff.size; ++i) { u8 c = (u8)buff.data[i]; - hash ^= c; - hash *= U128(0x1000000, 0x000000000000013B); + hash = u128_xor_u8(hash, c); + hash = u128_mul(hash, U128(0x1000000, 0x000000000000013B)); } return hash; }