diff --git a/.gitignore b/.gitignore index 67d2a76..1335d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,10 @@ app_run_tree/ meta_run_tree/ +*.exe +*.pdb +*.o process/ reference/ working_data/ -nssm_log.log \ No newline at end of file +nssm_log.log +sysroot/ \ No newline at end of file diff --git a/build/build.sh b/build/build.sh new file mode 100644 index 0000000..6c61fa8 --- /dev/null +++ b/build/build.sh @@ -0,0 +1,294 @@ +#!/bin/bash + +# -------------------------------------------- +# Usage + +print_usage () { + echo + echo Build Command Syntax: + echo " $0 [mode] [platform] [arch]" + echo + echo "Release Mode Options:" + echo " debug" + echo " prod" + echo + echo "Platform Options:" + echo " win32" + echo " osx" + echo " webgl" + echo + echo "Arch Options: (architecture)" + echo " intel (valid with Platform Win32 and OSX) (default)" + echo " arm64 (only valid for Platform OSX)" +} + +# -------------------------------------------- +# Arguments +MODE=$1 +PLATFORM=$2 +ARCH=$3 +PACKAGE=$4 + +if [ "${MODE}" == "" ] | [ "${PLATFORM}" == "" ] +then + print_usage + exit 0 +fi + +# Default to Intel architecture if none provided +if [ "${ARCH}" == "" ] +then + ARCH="intel" +fi + +if [ "${ARCH}" != "intel" ] && [ "${ARCH}" != "arm64" ] +then + echo "Uknown target architecture: ${ARCH}" + print_usage + exit 0 + +fi + +# -------------------------------------------- +# Utilities + +pushdir () { + command pushd "$@" > /dev/null +} + +popdir () { + command popd "$@" > /dev/null +} + +# -------------------------------------------- +# Getting Project Path +# +# Project is stored in PROJECT_PATH + +SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}") +pushdir $SCRIPT_REL_DIR +pushdir .. +PROJECT_PATH=$(pwd) +popdir +popdir + +# -------------------------------------------- +# Platform/Mode Specific Variables + +# Compiler Selection + +Compiler_win32="cl" +Compiler_osx="clang++" +WasiSdk="/c/drive/apps/wasi-sdk" +Compiler_webgl="$WasiSdk/bin/clang++" +Compiler_linux="clang++" + +# Platform Entry Points + +PlatformEntry_win32="src_v2/platform/win32/lumenarium_first_win32.cpp" +PlatformEntry_osx="src_v2/platform/osx/lumenarium_first_osx.cpp" +PlatformEntry_webgl="src_v2/platform/webgl/lumenarium_first_webgl.cpp" +PlatformEntry_linux="src_v2/platform/linux/lumenarium_first_linux.cpp" + +# Intermediate Outputs + +CompilerOutput_win32="lumenarium.o" +CompilerOutput_osx="lumenarium" +CompilerOutput_webgl="lumenarium.wasm" +CompilerOutput_linux="" + +# Executables + +LinkerOutput_win32="lumenarium.exe" +LinkerOutput_osx="lumenarium" +LinkerOutput_webgl="lumenarium.wasm" +LinkerOutput_linux="" + +# Wasm Sys Root +WasmSysRoot="${PROJECT_PATH}/src_v2/platform/webgl/sysroot/" + +# Compiler Flags + +CompilerFlags_win32="-nologo -FC -WX -W4 -Z7 -Oi -MTd -fp:fast" +CompilerFlags_win32="$CompilerFlags_win32 -wd4505 -wd4100 -wd4189" + +CompilerFlags_osx="" + +CompilerFlags_webgl="-target wasm32 --sysroot ${WasmSysRoot} -s -fvisibility=hidden -fno-builtin -fno-exceptions -fno-threadsafe-statics" + +# CompilerFlags_webgl="-nostartfiles -fno-exceptions -fno-entry -strip-all -s -import-memory -fvisibility=hidden --sysroot ${WasmSysRoot}" + +CompilerFlags_linux="" + +CompilerFlags_DEBUG_win32="-Od -Zi -DDEBUG" +CompilerFlags_DEBUG="-O0 -g -DDEBUG" +CompilerFlags_PROD="-O3" + +# Compiler flags that no matter what, we want to define +# for the most part these pass the build parameters into the executable +CompilerFlags_common="-DPLATFORM=${PLATFORM} -DMODE=${MODE} -DARCH=${ARCH}" + +# Linker Flags + +LinkerFlags_win32="-NOLOGO -incremental:no -subsystem:windows -entry:WinMain -opt:ref" +LinkerFlags_osx="" +# LinkerFlags_webgl="--no-entry --export-dynamic -allow-undefined -import-memory -export=__wasm_call_ctors -export=malloc -export=free -export=main" +LinkerFlags_webgl="--no-entry --export-dynamic --unresolved-symbols=import-functions" +LinkerFlags_linux="" + +LinkerFlags_DEBUG="-debug" +LinkerFlags_PROD="" + +# Linker Libs + +LinkerLibs_win32="user32.lib kernel32.lib gdi32.lib opengl32.lib" +# winmm.lib gdi32.lib dsound.lib Ws2_32.lib Comdlg32.lib Winspool.lib" +LinkerLibs_osx="-framework OpenGL -framework Cocoa" +LinkerLibs_webgl="" +LinkerLibs_linux="" + +# -------------------------------------------- +# Varible Selection + +# Select Platform Variables + +if [ "${PLATFORM}" == "win32" ] +then + Compiler=$Compiler_win32 + PlatformEntry=$PlatformEntry_win32 + CompilerFlags=$CompilerFlags_win32 + CompilerOutput=$CompilerOutput_win32 + LinkerOutput=$LinkerOutput_win32 + LinkerFlags=$LinkerFlags_win32 + LinkerLibs=$LinkerLibs_win32 + +elif [ "${PLATFORM}" == "osx" ] +then + Compiler=$Compiler_osx + PlatformEntry=$PlatformEntry_osx + CompilerFlags=$CompilerFlags_osx + CompilerOutput=$CompilerOutput_osx + LinkerOutput=$LinkerOutput_osx + LinkerFlags=$LinkerFlags_osx + LinkerLibs=$LinkerLibs_osx + +elif [ "${PLATFORM}" == "webgl" ] +then + Compiler=$Compiler_webgl + PlatformEntry=$PlatformEntry_webgl + CompilerFlags=$CompilerFlags_webgl + CompilerOutput=$CompilerOutput_webgl + LinkerOutput=$LinkerOutput_webgl + LinkerFlags=$LinkerFlags_webgl + LinkerLibs=$LinkerLibs_webgl + +elif [ "${PLATFORM}" == "linux" ] +then + Compiler=$Compiler_linux + PlatformEntry=$PlatformEntry_linux + CompilerFlags=$CompilerFlags_linux + CompilerOutput=$CompilerOutput_linux + LinkerOutput=$LinkerOutput_linux + LinkerFlags=$LinkerFlags_linux + LinkerLibs=$LinkerLibs_linux + +else + echo "Attempting to build for an unknown platform: ${PLATFORM}" + print_usage + exit 0 + +fi + +# Select Release Mode Variables + +if [ "${MODE}" == "debug" ] +then + if [ $PLATFORM == "win32" ] + then + CompilerFlags="${CompilerFlags} ${CompilerFlags_DEBUG_win32}" + else + CompilerFlags="${CompilerFlags} ${CompilerFlags_DEBUG}" + fi + + LinkerFlags="${LinkerFlags} ${LinkerFlags_DEBUG}" + +elif [ "${MODE}" == "prod" ] +then + CompilerFlags="${CompilerFlags} ${CompilerFlags_PROD}" + LinkerFlags="${LinkerFlags} ${LinkerFlags_PROD}" + +else + echo "Attempting to build for an unknown release mode: ${MODE}" + print_usage + exit 0 + +fi + +# Common Flags +CompilerFlags="${CompilerFlags} ${CompilerFlags_common}" + +# -------------------------------------------- +# Build Path Construction +# +# This determines where the generated executable will +# be located. In general, it can be found at +# project_path/run_tree/platform/arch/release_mode/lumenarium.exe +# +# This section also ensures that the path requested actually exists + +BuildDir="${PROJECT_PATH}/run_tree/${PLATFORM}/${ARCH}/${MODE}" +EntryPath="${PROJECT_PATH}/${PlatformEntry}" + +# Exception for webgl, which doesn't care about cpu architecture +if [ $PLATFORM == "webgl" ] +then + BuildDir="${PROJECT_PATH}/run_tree/${PLATFORM}/${MODE}" + +fi + +# Make the build directory, +# "-p" flag makes it make the entire tree, and not emit errors if it +# exists. +mkdir -p "${BuildDir}" + +# -------------------------------------------- +# Compilation + +echo "Building To: ${BuildDir}/${LinkerOutput}" +echo +pushdir $BuildDir + +rm ${CompilerOutput} 2> /dev/null +rm ${LinkerOutput} 2> /dev/null + +echo "COMPILING..." +if [ $PLATFORM == "win32" ] +then + $Compiler $CompilerFlags $EntryPath \ + -link $LinkerFlags $LinkerLibs -OUT:${LinkerOutput} + +elif [ $PLATFORM == "webgl" ] +then + + LD="$WasiSdk/bin/wasm-ld" + echo $Compiler + CFlags="-O3 -flto --target=wasm32-unknown-wasi" + LDFlags="--no-entry --export-dynamic --allow-undefined --lto-O3 --import-memory" + + $Compiler \ + -Wno-writable-strings \ + --target=wasm32 \ + -nostdlib \ + -Wl,--export-all \ + -Wl,--no-entry \ + -Wl,--allow-undefined \ + -o lumenarium.wasm \ + $EntryPath \ + +else + $Compiler -o $LinkerOutput $CompilerFlags $EntryPath $LinkerLibs + +fi + +echo "Finished..." +popdir \ No newline at end of file diff --git a/build/build_app_msvc_win32_debug.bat b/build/build_app_msvc_win32_debug.bat index 1997c89..9f523a3 100644 --- a/build/build_app_msvc_win32_debug.bat +++ b/build/build_app_msvc_win32_debug.bat @@ -20,7 +20,7 @@ del *.pdb > NUL 2> NUL echo WAITING FOR PDB TO WRITE > lock.tmp -cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp /Fefoldhaus.dll /LD /link %CommonLinkerFlags% %DLLExports% +cl %CommonCompilerFlags% %SourceCodePath%\foldhaus_app.cpp /Fefoldhaus.dll /LD /link %CommoLinkerFlags% %DLLExports% SET LastError=%ERRORLEVEL% del lock.tmp diff --git a/project.4coder b/project.4coder index 830f111..8596496 100644 --- a/project.4coder +++ b/project.4coder @@ -14,6 +14,7 @@ blacklist_patterns = { }; load_paths_base = { { "src", .relative = true, .recursive = true, }, + { "src_v2", .relative = true, .recursive = true, }, { "meta", .relative = true, .recursive = true, }, { "gs_libs", .relative = true, .recursive = true, }, }; @@ -22,6 +23,7 @@ load_paths = { { load_paths_base, .os = "linux", }, { load_paths_base, .os = "mac", }, }; +enable_virtual_whitespace=true; command_list = { { .name = "build_application", @@ -34,6 +36,11 @@ command_list = { .cmd = { { "build\build_meta_msvc_win32_debug.bat" , .os = "win" }, { "./build_meta.sh", .os = "linux" }, { "./build_meta.sh", .os = "mac" }, }, }, + { .name = "build_v2", + .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, + .cmd = { { "bash build\build.sh debug win32 intel" , .os = "win" }, + { "./build_meta.sh", .os = "linux" }, + { "./build_meta.sh", .os = "mac" }, }, }, }; -fkey_command[1] = "build_application"; +fkey_command[1] = "build_v2"; fkey_command[2] = "build_meta"; diff --git a/run_tree/text.txt b/run_tree/text.txt new file mode 100644 index 0000000..ccfbc29 Binary files /dev/null and b/run_tree/text.txt differ diff --git a/run_tree/webgl/debug/loader.html b/run_tree/webgl/debug/loader.html new file mode 100644 index 0000000..af51233 --- /dev/null +++ b/run_tree/webgl/debug/loader.html @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/run_tree/webgl/debug/loader.js b/run_tree/webgl/debug/loader.js new file mode 100644 index 0000000..7e8633a --- /dev/null +++ b/run_tree/webgl/debug/loader.js @@ -0,0 +1,130 @@ + +let memory = null; +let memory_u8 = null; + +// TODO(PS): you need to figure out how to get text to convert to a string +function print (text) +{ + console.log(i, memory_u8.length, text); +} + +async function load_webassembly_module () +{ + const path = "lumenarium.wasm"; + const promise = fetch(path); + const module = await WebAssembly.compileStreaming(promise); + memory = new WebAssembly.Memory({ initial: 2 }); + memory_u8 = new Uint8Array(memory.buffer); + const env = { + memory, + print, + }; + const result = await WebAssembly.instantiate(module, { env }); + console.log(result); + + result.exports.main(); + +} + +window.addEventListener("load", load_webassembly_module) + + +/* +function load_webassembly_module (wa) +{ + fetch(wa.module) + .then(res => res.arrayBuffer()) + .then((wasm_bytes) => { + "use strict"; + wasm_bytes = new Uint8Array(wasm_bytes); + + // find start of heap and calc initial mem requirements + var wasm_heap_base = 65536; + + // see https://webassembly.org/docs/binary-encoding/ + for (let i = 8, section_end, type, length; + i < wasm_bytes.length; + i = section_end + ){ + + function get_b8() + { + return wasm_bytes[i++]; + } + + function get_leb() + { + for (var s = i, r = 0, n = 128; n & 128; i++) + { + r |= ((n = wasm_bytes[i]) & 127) << ((i - s) * 7); + } + return r; // TODO(PS): this might belong in the for loop? + } + + type = get_leb(); + length = get_leb(); + section_end = i + length; + + if (type < 0 || type > 11 || length <= 0 || section_end > wasm_bytes.length) + { + break; + } + + if (type == 6) + { + //Section 6 'Globals', llvm places the heap base pointer into the first value here + let count = get_leb(); + let gtype = get_b8(); + let mutable = get_b8(); + let opcode = get_leb(); + let offset = get_leb(); + let endcode = get_leb(); + wasm_heap_base = offset; + break; + } + } + + // Set the wasm memory size to [DATA] + [STACK] + [256KB HEAP] + // (This loader does not support memory growing so it stays at this size) + var wasm_mem_init = ((wasm_heap_base + 65535) >> 16 << 16) + (256 * 1024); + var env = { + env: { + memory: new WebAssembly.Memory( + { + initial: wasm_mem_init >> 16 + } + ), + }, + }; + + // Instantiate the wasm module by passing the prepared environment + WebAssembly.instantiate(wasm_bytes, env) + .then(function (output) + { + // Store the list of the functions exported by the wasm module in WA.asm + wa.asm = output.instance.exports; + + // If function '__wasm_call_ctors' (global C++ constructors) exists, call it + if (wa.asm.__wasm_call_ctors) wa.asm.__wasm_call_ctors(); + + // If function 'main' exists, call it with dummy arguments + if (wa.asm.main) wa.asm.main(0, 0); + + // If the outer HTML file supplied a 'started' callback, call it + if (wa.started) wa.started(); + }) + .catch(function (err) + { + // On an exception, if the err is 'abort' the error was already processed in the abort function above + if (err !== 'abort') { + let stack = err.stack ? "\n" + err.stack : ""; + console.error('BOOT: WASM instiantate error: ' + err + stack); + return; + } + }); + }); +} + +load_webassembly_module(web_assembly) + +*/ \ No newline at end of file diff --git a/run_tree/webgl/debug/lumenarium.wasm b/run_tree/webgl/debug/lumenarium.wasm new file mode 100644 index 0000000..85b7240 Binary files /dev/null and b/run_tree/webgl/debug/lumenarium.wasm differ diff --git a/run_tree/win32/intel/debug/lumenarium_first_win32.obj b/run_tree/win32/intel/debug/lumenarium_first_win32.obj new file mode 100644 index 0000000..551d7f3 Binary files /dev/null and b/run_tree/win32/intel/debug/lumenarium_first_win32.obj differ diff --git a/src/app/platform_win32/win32_foldhaus_fileio.h b/src/app/platform_win32/win32_foldhaus_fileio.h index a4f3edf..906d947 100644 --- a/src/app/platform_win32/win32_foldhaus_fileio.h +++ b/src/app/platform_win32/win32_foldhaus_fileio.h @@ -11,272 +11,272 @@ internal u64 Win32HighLowToU64(u32 LowPart, u32 HighPart) { - ULARGE_INTEGER Time = {}; - Time.LowPart = LowPart; - Time.HighPart = HighPart; - u64 Result = Time.QuadPart; - return Result; + ULARGE_INTEGER Time = {}; + Time.LowPart = LowPart; + Time.HighPart = HighPart; + u64 Result = Time.QuadPart; + return Result; } internal u64 Win32FileTimeToU64(FILETIME FileTime) { - u64 Result = Win32HighLowToU64(FileTime.dwLowDateTime, FileTime.dwHighDateTime); - return Result; + u64 Result = Win32HighLowToU64(FileTime.dwLowDateTime, FileTime.dwHighDateTime); + return Result; } GET_FILE_INFO(Win32GetFileInfo) { - Assert(IsNullTerminated(Path)); - gs_file_info Result = {}; - HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (FileHandle != INVALID_HANDLE_VALUE) + Assert(IsNullTerminated(Path)); + gs_file_info Result = {}; + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + Result.Path = Path; + Result.FileSize = (u64)GetFileSize(FileHandle, NULL) + 1; + FILETIME CreationTime, LastWriteTime; + if (GetFileTime(FileHandle, &CreationTime, (LPFILETIME)0, &LastWriteTime)) { - Result.Path = Path; - Result.FileSize = (u64)GetFileSize(FileHandle, NULL) + 1; - FILETIME CreationTime, LastWriteTime; - if (GetFileTime(FileHandle, &CreationTime, (LPFILETIME)0, &LastWriteTime)) - { - Result.CreationTime = Win32FileTimeToU64(CreationTime); - Result.LastWriteTime = Win32FileTimeToU64(LastWriteTime); - } - else - { - PrintLastError(); - } - CloseHandle(FileHandle); + Result.CreationTime = Win32FileTimeToU64(CreationTime); + Result.LastWriteTime = Win32FileTimeToU64(LastWriteTime); } else { - DWORD FileAttr = GetFileAttributes(Path.Str); - if (FileAttr != INVALID_FILE_ATTRIBUTES && - (FileAttr & FILE_ATTRIBUTE_DIRECTORY)) - { - Result.Path = Path; - Result.IsDirectory = true; - } - else - { - // Path is not a file or directory - } + PrintLastError(); } - return Result; + CloseHandle(FileHandle); + } + else + { + DWORD FileAttr = GetFileAttributes(Path.Str); + if (FileAttr != INVALID_FILE_ATTRIBUTES && + (FileAttr & FILE_ATTRIBUTE_DIRECTORY)) + { + Result.Path = Path; + Result.IsDirectory = true; + } + else + { + // Path is not a file or directory + } + } + return Result; } READ_ENTIRE_FILE(Win32ReadEntireFile) { - Assert(DataIsNonEmpty(Memory)); - Assert(IsNullTerminated(Path)); - - gs_file Result = {0}; - u32 Error = 0; - Result.FileInfo.Path = Path; - - HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (FileHandle != INVALID_HANDLE_VALUE) + Assert(DataIsNonEmpty(Memory)); + Assert(IsNullTerminated(Path)); + + gs_file Result = {0}; + u32 Error = 0; + Result.FileInfo.Path = Path; + + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesRead = 0; + if (ReadFile(FileHandle, (LPVOID)Memory.Memory, Memory.Size - 1, (LPDWORD)(&BytesRead), NULL)) { - DWORD BytesRead = 0; - if (ReadFile(FileHandle, (LPVOID)Memory.Memory, Memory.Size - 1, (LPDWORD)(&BytesRead), NULL)) - { - Memory.Memory[Memory.Size - 1] = 0; - Result.Data = Memory; - - gs_string AbsolutePath = PushString(FileHandler.Transient, 512); - AbsolutePath.Length = GetFullPathNameA(Path.Str, AbsolutePath.Size, AbsolutePath.Str, NULL); - if (AbsolutePath.Length == 0) - { - Error = GetLastError(); - InvalidCodePath; - } - Result.FileInfo.AbsolutePath = AbsolutePath.ConstString; - } - else - { - // NOTE(Peter): If we get to this error case, it means that the file exists, - // and was successfully opened, but we can't read from it. I'm choosing to - // treat this as a legitimate error at this point. - gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to read file: %S", Path); - if (MessageBox(NULL, Message.Str, "Error", MB_OK) == IDOK) - { - PostQuitMessage(-1); - } - } - CloseHandle(FileHandle); + Memory.Memory[Memory.Size - 1] = 0; + Result.Data = Memory; + + gs_string AbsolutePath = PushString(FileHandler.Transient, 512); + AbsolutePath.Length = GetFullPathNameA(Path.Str, AbsolutePath.Size, AbsolutePath.Str, NULL); + if (AbsolutePath.Length == 0) + { + Error = GetLastError(); + InvalidCodePath; + } + Result.FileInfo.AbsolutePath = AbsolutePath.ConstString; } else { - + // NOTE(Peter): If we get to this error case, it means that the file exists, + // and was successfully opened, but we can't read from it. I'm choosing to + // treat this as a legitimate error at this point. + gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to read file: %S", Path); + if (MessageBox(NULL, Message.Str, "Error", MB_OK) == IDOK) + { + PostQuitMessage(-1); + } } + CloseHandle(FileHandle); + } + else + { - return Result; + } + + return Result; } WRITE_ENTIRE_FILE(Win32WriteEntireFile) { - Assert(DataIsNonEmpty(Data)); - Assert(IsNullTerminated(Path)); - - bool Success = false; - HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if (FileHandle != INVALID_HANDLE_VALUE) + Assert(DataIsNonEmpty(Data)); + Assert(IsNullTerminated(Path)); + + bool Success = false; + HANDLE FileHandle = CreateFileA(Path.Str, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (FileHandle != INVALID_HANDLE_VALUE) + { + DWORD BytesWritten = 0; + if (WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL)) { - DWORD BytesWritten = 0; - if (WriteFile(FileHandle, Data.Memory, Data.Size, &BytesWritten, NULL)) - { - Success = (BytesWritten == Data.Size); - } - else - { - gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to write to file: %S", Path); - MessageBox(NULL, Message.Str, "Error", MB_OK); - } - CloseHandle(FileHandle); + Success = (BytesWritten == Data.Size); } else { - + gs_string Message = Win32DumpErrorAndPrepareMessageBoxString(FileHandler.Transient, "Attempting to write to file: %S", Path); + MessageBox(NULL, Message.Str, "Error", MB_OK); } + CloseHandle(FileHandle); + } + else + { - return Success; + } + + return Success; } internal FILETIME GetFileLastWriteTime(char* Path) { - FILETIME Result = {}; - - WIN32_FIND_DATA FindData = {}; - HANDLE FileHandle = FindFirstFileA(Path, &FindData); - - if (FileHandle != INVALID_HANDLE_VALUE) - { - Result = FindData.ftLastWriteTime; - FindClose(FileHandle); - } - else - { - // TODO(Peter): :ErrorLogging - } - - return Result; + FILETIME Result = {}; + + WIN32_FIND_DATA FindData = {}; + HANDLE FileHandle = FindFirstFileA(Path, &FindData); + + if (FileHandle != INVALID_HANDLE_VALUE) + { + Result = FindData.ftLastWriteTime; + FindClose(FileHandle); + } + else + { + // TODO(Peter): :ErrorLogging + } + + return Result; } struct temp_file_list_entry { - gs_file_info Info; - temp_file_list_entry* Next; + gs_file_info Info; + temp_file_list_entry* Next; }; struct temp_file_list { - temp_file_list_entry* First; - temp_file_list_entry* Last; + temp_file_list_entry* First; + temp_file_list_entry* Last; }; internal void Win32SetFileInfoFromFindFileData(gs_file_info* Info, WIN32_FIND_DATA FindFileData, gs_const_string SearchPath, gs_memory_arena* Storage) { - u32 FileNameLength = CharArrayLength(FindFileData.cFileName); - - Info->FileSize = Win32HighLowToU64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh); - Info->CreationTime = Win32FileTimeToU64(FindFileData.ftCreationTime); - Info->LastWriteTime = Win32FileTimeToU64(FindFileData.ftLastWriteTime); - Info->IsDirectory = HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY); - - // NOTE(Peter): String Storage - // Storing the string in the final storage means we don't have to copy the string later, and all - // strings will be continguous in memory at the calling site, though they will be before the array - gs_string FileName = PushString(Storage, SearchPath.Length + FileNameLength + 2); - PrintF(&FileName, "%S%.*s", SearchPath, FileName.Size, FindFileData.cFileName); - if (Info->IsDirectory) - { - AppendPrintF(&FileName, "\\"); - } - NullTerminate(&FileName); - - Info->Path = FileName.ConstString; + u32 FileNameLength = CharArrayLength(FindFileData.cFileName); + + Info->FileSize = Win32HighLowToU64(FindFileData.nFileSizeLow, FindFileData.nFileSizeHigh); + Info->CreationTime = Win32FileTimeToU64(FindFileData.ftCreationTime); + Info->LastWriteTime = Win32FileTimeToU64(FindFileData.ftLastWriteTime); + Info->IsDirectory = HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY); + + // NOTE(Peter): String Storage + // Storing the string in the final storage means we don't have to copy the string later, and all + // strings will be continguous in memory at the calling site, though they will be before the array + gs_string FileName = PushString(Storage, SearchPath.Length + FileNameLength + 2); + PrintF(&FileName, "%S%.*s", SearchPath, FileName.Size, FindFileData.cFileName); + if (Info->IsDirectory) + { + AppendPrintF(&FileName, "\\"); + } + NullTerminate(&FileName); + + Info->Path = FileName.ConstString; } internal u32 Win32EnumerateDirectoryIntoTempList(gs_file_handler FileHandler, temp_file_list* TempList, gs_const_string Path, gs_memory_arena* Storage, b32 Flags) { - u32 FilesCount = 0; - Assert(Path.Str[Path.Length - 1] != '\\' && - Path.Str[Path.Length - 1] != '/'); - gs_const_string SearchPath = Path; - - gs_const_string SearchPathDir = SearchPath; - s64 LastSlash = FindLastFromSet(SearchPath, "\\/"); - if (LastSlash >= 0) + u32 FilesCount = 0; + Assert(Path.Str[Path.Length - 1] != '\\' && + Path.Str[Path.Length - 1] != '/'); + gs_const_string SearchPath = Path; + + gs_const_string SearchPathDir = SearchPath; + s64 LastSlash = FindLastFromSet(SearchPath, "\\/"); + if (LastSlash >= 0) + { + SearchPathDir = Substring(SearchPath, 0, LastSlash + 1); + } + + WIN32_FIND_DATA FindFileData; + HANDLE SearchHandle = FindFirstFile(Path.Str, &FindFileData); + if (SearchHandle != INVALID_HANDLE_VALUE) + { + do { - SearchPathDir = Substring(SearchPath, 0, LastSlash + 1); - } - - WIN32_FIND_DATA FindFileData; - HANDLE SearchHandle = FindFirstFile(Path.Str, &FindFileData); - if (SearchHandle != INVALID_HANDLE_VALUE) - { - do + b32 AddFile = true; + + if (HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + gs_const_string SubDirName = ConstString(FindFileData.cFileName); + bool IsNav = (StringsEqual(SubDirName, ConstString(".")) || + StringsEqual(SubDirName, ConstString(".."))); + + if (HasFlag(Flags, EnumerateDirectory_Recurse)) { - b32 AddFile = true; - - if (HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) - { - gs_const_string SubDirName = ConstString(FindFileData.cFileName); - bool IsNav = (StringsEqual(SubDirName, ConstString(".")) || - StringsEqual(SubDirName, ConstString(".."))); - - if (HasFlag(Flags, EnumerateDirectory_Recurse)) - { - if (!IsNav) - { - gs_string SubDirectoryPath = PushString(FileHandler.Transient, SearchPath.Length + SubDirName.Length + 3); - PrintF(&SubDirectoryPath, "%S%S/*\0", SearchPath, SubDirName); - FilesCount += Win32EnumerateDirectoryIntoTempList(FileHandler, TempList, SubDirectoryPath.ConstString, - Storage, Flags); - } - } - - AddFile = HasFlag(Flags, EnumerateDirectory_IncludeDirectories); - } - - if (AddFile) - { - temp_file_list_entry* File = PushStruct(FileHandler.Transient, temp_file_list_entry); - *File = {0}; - Win32SetFileInfoFromFindFileData(&File->Info, FindFileData, SearchPathDir, Storage); - SLLPushOrInit(TempList->First, TempList->Last, File); - FilesCount += 1; - } - }while(FindNextFile(SearchHandle, &FindFileData)); - } - else - { - PrintLastError(); - } - - return FilesCount; + if (!IsNav) + { + gs_string SubDirectoryPath = PushString(FileHandler.Transient, SearchPath.Length + SubDirName.Length + 3); + PrintF(&SubDirectoryPath, "%S%S/*\0", SearchPath, SubDirName); + FilesCount += Win32EnumerateDirectoryIntoTempList(FileHandler, TempList, SubDirectoryPath.ConstString, + Storage, Flags); + } + } + + AddFile = HasFlag(Flags, EnumerateDirectory_IncludeDirectories); + } + + if (AddFile) + { + temp_file_list_entry* File = PushStruct(FileHandler.Transient, temp_file_list_entry); + *File = {0}; + Win32SetFileInfoFromFindFileData(&File->Info, FindFileData, SearchPathDir, Storage); + SLLPushOrInit(TempList->First, TempList->Last, File); + FilesCount += 1; + } + }while(FindNextFile(SearchHandle, &FindFileData)); + } + else + { + PrintLastError(); + } + + return FilesCount; } ENUMERATE_DIRECTORY(Win32EnumerateDirectory) { - Assert(IsNullTerminated(Path)); - gs_file_info_array Result = {}; - - temp_file_list TempList = {}; - Result.MaxCount = Win32EnumerateDirectoryIntoTempList(FileHandler, &TempList, Path, Storage, Flags); - - Result.Values = PushArray(Storage, gs_file_info, Result.MaxCount); - for (temp_file_list_entry* FileAt = TempList.First; - FileAt != 0; - FileAt = FileAt->Next) - { - // NOTE(Peter): We don't copy the file name here because its already in Storage. - // See String Storage note above ^^ - Result.Values[Result.Count++] = FileAt->Info; - } - - return Result; + Assert(IsNullTerminated(Path)); + gs_file_info_array Result = {}; + + temp_file_list TempList = {}; + Result.MaxCount = Win32EnumerateDirectoryIntoTempList(FileHandler, &TempList, Path, Storage, Flags); + + Result.Values = PushArray(Storage, gs_file_info, Result.MaxCount); + for (temp_file_list_entry* FileAt = TempList.First; + FileAt != 0; + FileAt = FileAt->Next) + { + // NOTE(Peter): We don't copy the file name here because its already in Storage. + // See String Storage note above ^^ + Result.Values[Result.Count++] = FileAt->Info; + } + + return Result; } #define WIN32_FOLDHAUS_FILEIO_H diff --git a/src/app/platform_win32/win32_foldhaus_timing.h b/src/app/platform_win32/win32_foldhaus_timing.h index 6d04a31..dee60bf 100644 --- a/src/app/platform_win32/win32_foldhaus_timing.h +++ b/src/app/platform_win32/win32_foldhaus_timing.h @@ -11,33 +11,33 @@ internal s64 GetPerformanceFrequency () { - LARGE_INTEGER Frequency; - if (!QueryPerformanceFrequency(&Frequency)) - { - s32 Error = GetLastError(); - // TODO(Peter): I'm waiting to see an error actually occur here - // to know what it could possibly be. - InvalidCodePath; - } - return (s64)Frequency.QuadPart; + LARGE_INTEGER Frequency; + if (!QueryPerformanceFrequency(&Frequency)) + { + s32 Error = GetLastError(); + // TODO(Peter): I'm waiting to see an error actually occur here + // to know what it could possibly be. + InvalidCodePath; + } + return (s64)Frequency.QuadPart; } internal s64 GetWallClock () { #if 0 - s64 Result = __rdtsc(); - return Result; + s64 Result = __rdtsc(); + return Result; #else - LARGE_INTEGER Time; - if (!QueryPerformanceCounter(&Time)) - { - s32 Error = GetLastError(); - // TODO(Peter): I'm waiting to see an error actually occur here - // to know what it could possibly be. - InvalidCodePath; - } - return (s64)Time.QuadPart; + LARGE_INTEGER Time; + if (!QueryPerformanceCounter(&Time)) + { + s32 Error = GetLastError(); + // TODO(Peter): I'm waiting to see an error actually occur here + // to know what it could possibly be. + InvalidCodePath; + } + return (s64)Time.QuadPart; #endif } diff --git a/src_v2/editor/lumenarium_editor.cpp b/src_v2/editor/lumenarium_editor.cpp new file mode 100644 index 0000000..8fc0d0e --- /dev/null +++ b/src_v2/editor/lumenarium_editor.cpp @@ -0,0 +1,25 @@ + +internal void +ed_init(App_State* state) +{ + +} + +internal void +ed_frame_prepare(App_State* state) +{ + +} + +internal void +ed_frame(App_State* state) +{ + edr_render(state); +} + +internal void +ed_cleanup(App_State* state) +{ + +} + diff --git a/src_v2/editor/lumenarium_editor_renderer.cpp b/src_v2/editor/lumenarium_editor_renderer.cpp new file mode 100644 index 0000000..452471c --- /dev/null +++ b/src_v2/editor/lumenarium_editor_renderer.cpp @@ -0,0 +1,20 @@ + +internal void +edr_render(App_State* state) +{ + glMatrixMode(GL_TEXTURE_2D); + glLoadIdentity(); + + glClearColor(0.1f, 0.1f, 0.1f, 1); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_TEXTURE_2D); + + glViewport(0, 0, 1600, 900); + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} \ No newline at end of file diff --git a/src_v2/engine/lumenarium_engine.cpp b/src_v2/engine/lumenarium_engine.cpp new file mode 100644 index 0000000..718c899 --- /dev/null +++ b/src_v2/engine/lumenarium_engine.cpp @@ -0,0 +1,25 @@ + +internal void +en_init(App_State* state) +{ + +} + +internal void +en_frame_prepare(App_State* state) +{ + +} + +internal void +en_frame(App_State* state) +{ + +} + +internal void +en_cleanup(App_State* state) +{ + +} + diff --git a/src_v2/engine/lumenarium_engine_assembly.h b/src_v2/engine/lumenarium_engine_assembly.h new file mode 100644 index 0000000..72d0271 --- /dev/null +++ b/src_v2/engine/lumenarium_engine_assembly.h @@ -0,0 +1,58 @@ +/* date = March 22nd 2022 6:40 pm */ + +#ifndef LUMENARIUM_ENGINE_ASSEMBLY_H +#define LUMENARIUM_ENGINE_ASSEMBLY_H + +struct Assembly_Handle +{ + u32 value; +}; + +union Assembly_Pixel +{ + struct { + u8 r; + u8 g; + u8 b; + }; + u8 channels[3]; +}; + +struct Assembly_Pixel_Buffer +{ + u32 cap; + u32 len; + Assembly_Pixel* pixels; + v4* positions; +}; + +struct Assembly_Strip +{ + u32 pixels_cap; + u32* pixels; +}; + +struct Assembly_Strip_Array +{ + u32 cap; + Assembly_Strip* strips; +}; + +struct Assembly_Array +{ + u32 cap; + u32 len; + String* names; + Assembly_Pixel_Buffer* pixel_buffers; + Assembly_Strip_Array* strip_arrays; + + Allocator* allocator; +}; + +Assembly_Handle assembly_add(Assembly_Array* a, String name, u64 pixels_cap, u64 strips_cap); +void assembly_rem(Assembly_Array* a, Assembly_Handle h); +Assembly_Strip* assembly_add_strip(Assembly_Array* a, Assembly_Handle h); +void assembly_add_led(Assembly_Array* a, Assembly_Handle h, Assembly_Strip* strip, v4 position); + + +#endif //LUMENARIUM_ENGINE_ASSEMBLY_H diff --git a/src_v2/libs/HandmadeMath.h b/src_v2/libs/HandmadeMath.h new file mode 100644 index 0000000..ef54521 --- /dev/null +++ b/src_v2/libs/HandmadeMath.h @@ -0,0 +1,3089 @@ +/* + HandmadeMath.h v1.2.0 + + This is a single header file with a bunch of useful functions for + basic game math operations. + + ============================================================================= + + You MUST + + #define HANDMADE_MATH_IMPLEMENTATION + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #include "HandmadeMath.h" + + All other files should just #include "HandmadeMath.h" without the #define. + + ============================================================================= + + For overloaded and operator overloaded versions of the base C functions, + you MUST + + #define HANDMADE_MATH_CPP_MODE + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_CPP_MODE + #include "HandmadeMath.h" + + All other files should just #include "HandmadeMath.h" without the #define. + + ============================================================================= + + To disable SSE intrinsics, you MUST + + #define HANDMADE_MATH_NO_SSE + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_CPP_MODE + #define HANDMADE_MATH_NO_SSE + #include "HandmadeMath.h" + + or + + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_NO_SSE + #include "HandmadeMath.h" + + ============================================================================= + + To disable inlining functions, you MUST + + #define HANDMADE_MATH_NO_INLINE + + in EXACTLY one C or C++ file that includes this header, BEFORE the + include, like this: + + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_CPP_MODE + #define HANDMADE_MATH_NO_INLINE + #include "HandmadeMath.h" + + All other files should just #include "HandmadeMath.h" without the #define. + + ============================================================================= + + To use HandmadeMath without the CRT, you MUST + + #define HMM_SINF MySinF + #define HMM_COSF MyCosF + #define HMM_TANF MyTanF + #define HMM_SQRTF MySqrtF + #define HMM_EXPF MyExpF + #define HMM_LOGF MyLogF + #define HMM_ACOSF MyACosF + #define HMM_ATANF MyATanF + #define HMM_ATAN2F MYATan2F + + Provide your own implementations of SinF, CosF, TanF, ACosF, ATanF, ATan2F, + ExpF, and LogF in EXACTLY one C or C++ file that includes this header, + BEFORE the include, like this: + + #define HMM_SINF MySinF + #define HMM_COSF MyCosF + #define HMM_TANF MyTanF + #define HMM_SQRTF MySqrtF + #define HMM_EXPF MyExpF + #define HMM_LOGF MyLogF + #define HMM_ACOSF MyACosF + #define HMM_ATANF MyATanF + #define HMM_ATAN2F MyATan2F + #define HANDMADE_MATH_IMPLEMENTATION + #define HANDMADE_MATH_CPP_MODE + #include "HandmadeMath.h" + + If you do not define all five of these, HandmadeMath.h will use the + versions of these functions that are provided by the CRT. + + ============================================================================= + + Version History: + 0.2 (*) Updated documentation + (*) Better C compliance + (*) Prefix all handmade math functions + (*) Better operator overloading + 0.2a + (*) Prefixed Macros + 0.2b + (*) Disabled warning 4201 on MSVC as it is legal is C11 + (*) Removed the f at the end of HMM_PI to get 64bit precision + 0.3 + (*) Added +=, -=, *=, /= for hmm_vec2, hmm_vec3, hmm_vec4 + 0.4 + (*) SSE Optimized HMM_SqrtF + (*) SSE Optimized HMM_RSqrtF + (*) Removed CRT + 0.5 + (*) Added scalar multiplication and division for vectors + and matrices + (*) Added matrix subtraction and += for hmm_mat4 + (*) Reconciled all headers and implementations + (*) Tidied up, and filled in a few missing operators + 0.5.1 + (*) Ensured column-major order for matrices throughout + (*) Fixed HMM_Translate producing row-major matrices + 0.5.2 + (*) Fixed SSE code in HMM_SqrtF + (*) Fixed SSE code in HMM_RSqrtF + 0.6 + (*) Added Unit testing + (*) Made HMM_Power faster + (*) Fixed possible efficiency problem with HMM_Normalize + (*) RENAMED HMM_LengthSquareRoot to HMM_LengthSquared + (*) RENAMED HMM_RSqrtF to HMM_RSquareRootF + (*) RENAMED HMM_SqrtF to HMM_SquareRootF + (*) REMOVED Inner function (user should use Dot now) + (*) REMOVED HMM_FastInverseSquareRoot function declaration + 0.7 + (*) REMOVED HMM_LengthSquared in HANDMADE_MATH_IMPLEMENTATION (should + use HMM_LengthSquaredVec3, or HANDMADE_MATH_CPP_MODE for function + overloaded version) + (*) REMOVED HMM_Length in HANDMADE_MATH_IMPLEMENTATION (should use + HMM_LengthVec3, HANDMADE_MATH_CPP_MODE for function + overloaded version) + (*) REMOVED HMM_Normalize in HANDMADE_MATH_IMPLEMENTATION (should use + HMM_NormalizeVec3, or HANDMADE_MATH_CPP_MODE for function + overloaded version) + (*) Added HMM_LengthSquaredVec2 + (*) Added HMM_LengthSquaredVec4 + (*) Addd HMM_LengthVec2 + (*) Added HMM_LengthVec4 + (*) Added HMM_NormalizeVec2 + (*) Added HMM_NormalizeVec4 + 1.0 + (*) Lots of testing! + 1.1 + (*) Quaternion support + (*) Added type hmm_quaternion + (*) Added HMM_Quaternion + (*) Added HMM_QuaternionV4 + (*) Added HMM_AddQuaternion + (*) Added HMM_SubtractQuaternion + (*) Added HMM_MultiplyQuaternion + (*) Added HMM_MultiplyQuaternionF + (*) Added HMM_DivideQuaternionF + (*) Added HMM_InverseQuaternion + (*) Added HMM_DotQuaternion + (*) Added HMM_NormalizeQuaternion + (*) Added HMM_Slerp + (*) Added HMM_QuaternionToMat4 + (*) Added HMM_QuaternionFromAxisAngle + 1.1.1 + (*) Resolved compiler warnings on gcc and g++ + 1.1.2 + (*) Fixed invalid HMMDEF's in the function definitions + 1.1.3 + (*) Fixed compile error in C mode + 1.1.4 + (*) Fixed SSE being included on platforms that don't support it + (*) Fixed divide-by-zero errors when normalizing zero vectors. + 1.1.5 + (*) Add Width and Height to HMM_Vec2 + (*) Made it so you can supply your own SqrtF + 1.2.0 + (*) Added equality functions for HMM_Vec2, HMM_Vec3, and HMM_Vec4. + (*) Added HMM_EqualsVec2, HMM_EqualsVec3, and HMM_EqualsVec4 + (*) Added C++ overloaded HMM_Equals for all three + (*) Added C++ == and != operators for all three + (*) SSE'd HMM_MultiplyMat4 (this is _WAY_ faster) + (*) SSE'd HMM_Transpose + + LICENSE + + This software is in the public domain. Where that dedication is not + recognized, you are granted a perpetual, irrevocable license to copy, + distribute, and modify this file as you see fit. + + CREDITS + + Written by Zakary Strange (zak@handmade.network && @strangezak) + + Functionality: + Matt Mascarenhas (@miblo_) + Aleph + FieryDrake (@fierydrake) + Gingerbill (@TheGingerBill) + Ben Visness (@bvisness) + Trinton Bullard (@Peliex_Dev) + + Fixes: + Jeroen van Rijn (@J_vanRijn) + Kiljacken (@Kiljacken) + Insofaras (@insofaras) + Daniel Gibson (@DanielGibson) +*/ + + +/* let's figure out if SSE is really available (unless disabled anyway) + (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support) + => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */ +#ifndef HANDMADE_MATH_NO_SSE + +# ifdef _MSC_VER +/* MSVC supports SSE in amd64 mode or _M_IX86_FP >= 1 (2 means SSE2) */ +# if defined(_M_AMD64) || ( defined(_M_IX86_FP) && _M_IX86_FP >= 1 ) +# define HANDMADE_MATH__USE_SSE 1 +# endif +# else /* not MSVC, probably GCC, clang, icc or something that doesn't support SSE anyway */ +# ifdef __SSE__ /* they #define __SSE__ if it's supported */ +# define HANDMADE_MATH__USE_SSE 1 +# endif /* __SSE__ */ +# endif /* not _MSC_VER */ + +#endif /* #ifndef HANDMADE_MATH_NO_SSE */ + +#include // This is for types + +#ifdef HANDMADE_MATH__USE_SSE +#include +#endif + +#ifndef HANDMADE_MATH_H +#define HANDMADE_MATH_H + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-anonymous-struct" +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef HANDMADE_MATH_STATIC +#define HMMDEF static +#else +#define HMMDEF extern +#endif + +#ifdef HANDMADE_MATH_NO_INLINE +#define HINLINE +#elif _MSC_VER && !__INTEL_COMPILER +#define HINLINE __inline +#else +#define HINLINE inline +#endif + +#if !defined(HMM_SINF) || !defined(HMM_COSF) || !defined(HMM_TANF) || \ +!defined(HMM_SQRTF) || !defined(HMM_EXPF) || !defined(HMM_LOGF) || \ +!defined(HMM_ACOSF) || !defined(HMM_ATANF)|| !defined(HMM_ATAN2F) +#include +#endif + +#ifndef HMM_SINF +#define HMM_SINF sinf +#endif + +#ifndef HMM_COSF +#define HMM_COSF cosf +#endif + +#ifndef HMM_TANF +#define HMM_TANF tanf +#endif + +#ifndef HMM_SQRTF +#define HMM_SQRTF sqrtf +#endif + +#ifndef HMM_EXPF +#define HMM_EXPF expf +#endif + +#ifndef HMM_LOGF +#define HMM_LOGF logf +#endif + +#ifndef HMM_ACOSF +#define HMM_ACOSF acosf +#endif + +#ifndef HMM_ATANF +#define HMM_ATANF atanf +#endif + +#ifndef HMM_ATAN2F +#define HMM_ATAN2F atan2f +#endif + +#define HMM_PI32 3.14159265359f +#define HMM_PI 3.14159265358979323846 + +#define HMM_MIN(a, b) (a) > (b) ? (b) : (a) +#define HMM_MAX(a, b) (a) < (b) ? (b) : (a) +#define HMM_ABS(a) ((a) > 0 ? (a) : -(a)) +#define HMM_MOD(a, m) ((a) % (m)) >= 0 ? ((a) % (m)) : (((a) % (m)) + (m)) +#define HMM_SQUARE(x) ((x) * (x)) + + typedef union hmm_vec2 + { + struct + { + float X, Y; + }; + struct + { + float x, y; + }; + struct + { + float U, V; + }; + + struct + { + float Left, Right; + }; + + struct + { + float Width, Height; + }; + + float Elements[2]; + } hmm_vec2; + + typedef union hmm_vec3 + { + struct + { + float X, Y, Z; + }; + + struct + { + float x, y, z; + }; + + struct + { + float U, V, W; + }; + + struct + { + float R, G, B; + }; + + struct + { + hmm_vec2 XY; + float Ignored0_; + }; + + struct + { + float Ignored1_; + hmm_vec2 YZ; + }; + + struct + { + hmm_vec2 UV; + float Ignored2_; + }; + + struct + { + float Ignored3_; + hmm_vec2 VW; + }; + + float Elements[3]; + } hmm_vec3; + + typedef union hmm_vec4 + { + struct + { + union + { + hmm_vec3 XYZ; + struct + { + float X, Y, Z; + }; + }; + + float W; + }; + struct + { + union + { + hmm_vec3 xyz; + struct + { + float x, y, z; + }; + }; + + float w; + }; + struct + { + union + { + hmm_vec3 RGB; + struct + { + float R, G, B; + }; + }; + + float A; + }; + + struct + { + hmm_vec2 XY; + float Ignored0_; + float Ignored1_; + }; + + struct + { + float Ignored2_; + hmm_vec2 YZ; + float Ignored3_; + }; + + struct + { + float Ignored4_; + float Ignored5_; + hmm_vec2 ZW; + }; + + float Elements[4]; + } hmm_vec4; + + typedef union hmm_mat4 + { + float Elements[4][4]; + + +#ifdef HANDMADE_MATH__USE_SSE + __m128 Rows[4]; +#endif + } hmm_mat4; + + typedef union hmm_quaternion + { + struct + { + union + { + hmm_vec3 XYZ; + struct + { + float X, Y, Z; + }; + }; + + float W; + }; + + float Elements[4]; + } hmm_quaternion; + + typedef struct + { + hmm_vec2 ValueMin; + hmm_vec2 ValueMax; + } hmm_vec2r; + + typedef struct + { + hmm_vec3 ValueMin; + hmm_vec3 ValueMax; + } hmm_vec3r; + + typedef struct + { + hmm_vec4 ValueMin; + hmm_vec4 ValueMax; + } hmm_vec4r; + + typedef int32_t hmm_bool; + + typedef hmm_vec2 hmm_v2; + typedef hmm_vec3 hmm_v3; + typedef hmm_vec4 hmm_v4; + typedef hmm_mat4 hmm_m4; + typedef hmm_vec2r hmm_v2r; + typedef hmm_vec3r hmm_v3r; + typedef hmm_vec4r hmm_v4r; + + HMMDEF float HMM_SinF(float Angle); + HMMDEF float HMM_TanF(float Angle); + HMMDEF float HMM_ATanF(float Theta); + HMMDEF float HMM_ATan2F(float Theta, float Theta2); + HMMDEF float HMM_CosF(float Angle); + HMMDEF float HMM_ACosF(float Theta); + HMMDEF float HMM_ExpF(float Float); + HMMDEF float HMM_LogF(float Float); + + HMMDEF float HMM_ToRadians(float Degrees); + HMMDEF float HMM_SquareRootF(float Float); + HMMDEF float HMM_RSquareRootF(float Float); + + HMMDEF float HMM_LengthSquaredVec2(hmm_vec2 A); + HMMDEF float HMM_LengthSquaredVec3(hmm_vec3 A); + HMMDEF float HMM_LengthSquaredVec4(hmm_vec4 A); + + HMMDEF float HMM_LengthVec2(hmm_vec2 A); + HMMDEF float HMM_LengthVec3(hmm_vec3 A); + HMMDEF float HMM_LengthVec4(hmm_vec4 A); + + HMMDEF float HMM_Power(float Base, int Exponent); + HMMDEF float HMM_PowerF(float Base, float Exponent); + HMMDEF float HMM_Lerp(float A, float Time, float B); + HMMDEF float HMM_Clamp(float Min, float Value, float Max); + + HMMDEF hmm_vec2 HMM_NormalizeVec2(hmm_vec2 A); + HMMDEF hmm_vec3 HMM_NormalizeVec3(hmm_vec3 A); + HMMDEF hmm_vec4 HMM_NormalizeVec4(hmm_vec4 A); + + HMMDEF float HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo); + HMMDEF float HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo); + HMMDEF float HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo); + + HMMDEF hmm_vec3 HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo); + + HMMDEF hmm_vec2 HMM_Vec2(float X, float Y); + HMMDEF hmm_vec2 HMM_Vec2i(int X, int Y); + HMMDEF hmm_vec3 HMM_Vec3(float X, float Y, float Z); + HMMDEF hmm_vec3 HMM_Vec3i(int X, int Y, int Z); + HMMDEF hmm_vec4 HMM_Vec4(float X, float Y, float Z, float W); + HMMDEF hmm_vec4 HMM_Vec4i(int X, int Y, int Z, int W); + HMMDEF hmm_vec4 HMM_Vec4v(hmm_vec3 Vector, float W); + + HMMDEF hmm_vec2 HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right); + HMMDEF hmm_vec3 HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right); + HMMDEF hmm_vec4 HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right); + + HMMDEF hmm_vec2 HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right); + HMMDEF hmm_vec3 HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right); + HMMDEF hmm_vec4 HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right); + + HMMDEF hmm_vec2 HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right); + HMMDEF hmm_vec2 HMM_MultiplyVec2f(hmm_vec2 Left, float Right); + HMMDEF hmm_vec3 HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right); + HMMDEF hmm_vec3 HMM_MultiplyVec3f(hmm_vec3 Left, float Right); + HMMDEF hmm_vec4 HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right); + HMMDEF hmm_vec4 HMM_MultiplyVec4f(hmm_vec4 Left, float Right); + + HMMDEF hmm_vec2 HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right); + HMMDEF hmm_vec2 HMM_DivideVec2f(hmm_vec2 Left, float Right); + HMMDEF hmm_vec3 HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right); + HMMDEF hmm_vec3 HMM_DivideVec3f(hmm_vec3 Left, float Right); + HMMDEF hmm_vec4 HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right); + HMMDEF hmm_vec4 HMM_DivideVec4f(hmm_vec4 Left, float Right); + + HMMDEF hmm_bool HMM_EqualsVec2(hmm_vec2 Left, hmm_vec2 Right); + HMMDEF hmm_bool HMM_EqualsVec3(hmm_vec3 Left, hmm_vec3 Right); + HMMDEF hmm_bool HMM_EqualsVec4(hmm_vec4 Left, hmm_vec4 Right); + + HMMDEF hmm_mat4 HMM_Mat4(void); + HMMDEF hmm_mat4 HMM_Mat4d(float Diagonal); + HMMDEF hmm_mat4 HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right); + HMMDEF hmm_mat4 HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right); + +#ifdef HANDMADE_MATH__USE_SSE + HMMDEF __m128 HMM_LinearCombineSSE(__m128 Left, hmm_mat4 Right); +#endif + + HMMDEF hmm_mat4 HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right); + HMMDEF hmm_mat4 HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar); + HMMDEF hmm_vec4 HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector); + HMMDEF hmm_mat4 HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar); + + HMMDEF hmm_mat4 HMM_Transpose(hmm_mat4 Matrix); + + HMMDEF hmm_mat4 HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far); + HMMDEF hmm_mat4 HMM_Perspective(float FOV, float AspectRatio, float Near, float Far); + + HMMDEF hmm_mat4 HMM_Translate(hmm_vec3 Translation); + HMMDEF hmm_mat4 HMM_Rotate(float Angle, hmm_vec3 Axis); + HMMDEF hmm_mat4 HMM_Scale(hmm_vec3 Scale); + + HMMDEF hmm_mat4 HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up); + + HMMDEF hmm_quaternion HMM_Quaternion(float X, float Y, float Z, float W); + HMMDEF hmm_quaternion HMM_QuaternionV4(hmm_vec4 Vector); + HMMDEF hmm_quaternion HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right); + HMMDEF hmm_quaternion HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right); + HMMDEF hmm_quaternion HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right); + HMMDEF hmm_quaternion HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative); + HMMDEF hmm_quaternion HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend); + HMMDEF hmm_quaternion HMM_InverseQuaternion(hmm_quaternion Left); + HMMDEF float HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right); + HMMDEF hmm_quaternion HMM_NormalizeQuaternion(hmm_quaternion Left); + HMMDEF hmm_quaternion HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right); + HMMDEF hmm_quaternion HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right); + HMMDEF hmm_mat4 HMM_QuaternionToMat4(hmm_quaternion Left); + HMMDEF hmm_quaternion HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation); + +#ifdef __cplusplus +} +#endif + +#ifdef HANDMADE_MATH_CPP_MODE + +HMMDEF float HMM_Length(hmm_vec2 A); +HMMDEF float HMM_Length(hmm_vec3 A); +HMMDEF float HMM_Length(hmm_vec4 A); + +HMMDEF float HMM_LengthSquared(hmm_vec2 A); +HMMDEF float HMM_LengthSquared(hmm_vec3 A); +HMMDEF float HMM_LengthSquared(hmm_vec4 A); + +HMMDEF hmm_vec2 HMM_Normalize(hmm_vec2 A); +HMMDEF hmm_vec3 HMM_Normalize(hmm_vec3 A); +HMMDEF hmm_vec4 HMM_Normalize(hmm_vec4 A); +HMMDEF hmm_quaternion HMM_Normalize(hmm_quaternion A); + +HMMDEF float HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo); +HMMDEF float HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo); +HMMDEF float HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo); +HMMDEF float HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo); + +HMMDEF hmm_vec2 HMM_Add(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 HMM_Add(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 HMM_Add(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_mat4 HMM_Add(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_quaternion HMM_Add(hmm_quaternion Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_mat4 HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_quaternion HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec2 HMM_Multiply(hmm_vec2 Left, float Right); +HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec3 HMM_Multiply(hmm_vec3 Left, float Right); +HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_vec4 HMM_Multiply(hmm_vec4 Left, float Right); +HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_mat4 HMM_Multiply(hmm_mat4 Left, float Right); +HMMDEF hmm_vec4 HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector); +HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right); +HMMDEF hmm_quaternion HMM_Multiply(hmm_quaternion Left, float Right); + +HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec2 HMM_Divide(hmm_vec2 Left, float Right); +HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec3 HMM_Divide(hmm_vec3 Left, float Right); +HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_vec4 HMM_Divide(hmm_vec4 Left, float Right); +HMMDEF hmm_mat4 HMM_Divide(hmm_mat4 Left, float Right); +HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, hmm_quaternion Right); +HMMDEF hmm_quaternion HMM_Divide(hmm_quaternion Left, float Right); + +HMMDEF hmm_bool HMM_Equals(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_bool HMM_Equals(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_bool HMM_Equals(hmm_vec4 Left, hmm_vec4 Right); + +HMMDEF hmm_vec2 operator+(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 operator+(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 operator+(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_mat4 operator+(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_quaternion operator+(hmm_quaternion Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 operator-(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 operator-(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 operator-(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_mat4 operator-(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_quaternion operator-(hmm_quaternion Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 operator*(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 operator*(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 operator*(hmm_vec4 Left, hmm_vec4 Right); +HMMDEF hmm_mat4 operator*(hmm_mat4 Left, hmm_mat4 Right); +HMMDEF hmm_quaternion operator*(hmm_quaternion Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 operator*(hmm_vec2 Left, float Right); +HMMDEF hmm_vec3 operator*(hmm_vec3 Left, float Right); +HMMDEF hmm_vec4 operator*(hmm_vec4 Left, float Right); +HMMDEF hmm_mat4 operator*(hmm_mat4 Left, float Right); +HMMDEF hmm_quaternion operator*(hmm_quaternion Left, float Right); + +HMMDEF hmm_vec2 operator*(float Left, hmm_vec2 Right); +HMMDEF hmm_vec3 operator*(float Left, hmm_vec3 Right); +HMMDEF hmm_vec4 operator*(float Left, hmm_vec4 Right); +HMMDEF hmm_mat4 operator*(float Left, hmm_mat4 Right); +HMMDEF hmm_quaternion operator*(float Left, hmm_quaternion Right); + +HMMDEF hmm_vec4 operator*(hmm_mat4 Matrix, hmm_vec4 Vector); + +HMMDEF hmm_vec2 operator/(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_vec3 operator/(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_vec4 operator/(hmm_vec4 Left, hmm_vec4 Right); + +HMMDEF hmm_vec2 operator/(hmm_vec2 Left, float Right); +HMMDEF hmm_vec3 operator/(hmm_vec3 Left, float Right); +HMMDEF hmm_vec4 operator/(hmm_vec4 Left, float Right); +HMMDEF hmm_mat4 operator/(hmm_mat4 Left, float Right); +HMMDEF hmm_quaternion operator/(hmm_quaternion Left, float Right); + +HMMDEF hmm_vec2 &operator+=(hmm_vec2 &Left, hmm_vec2 Right); +HMMDEF hmm_vec3 &operator+=(hmm_vec3 &Left, hmm_vec3 Right); +HMMDEF hmm_vec4 &operator+=(hmm_vec4 &Left, hmm_vec4 Right); +HMMDEF hmm_mat4 &operator+=(hmm_mat4 &Left, hmm_mat4 Right); +HMMDEF hmm_quaternion &operator+=(hmm_quaternion &Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 &operator-=(hmm_vec2 &Left, hmm_vec2 Right); +HMMDEF hmm_vec3 &operator-=(hmm_vec3 &Left, hmm_vec3 Right); +HMMDEF hmm_vec4 &operator-=(hmm_vec4 &Left, hmm_vec4 Right); +HMMDEF hmm_mat4 &operator-=(hmm_mat4 &Left, hmm_mat4 Right); +HMMDEF hmm_quaternion &operator-=(hmm_quaternion &Left, hmm_quaternion Right); + +HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, hmm_vec2 Right); +HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, hmm_vec3 Right); +HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, hmm_vec4 Right); + +HMMDEF hmm_vec2 &operator*=(hmm_vec2 &Left, float Right); +HMMDEF hmm_vec3 &operator*=(hmm_vec3 &Left, float Right); +HMMDEF hmm_vec4 &operator*=(hmm_vec4 &Left, float Right); +HMMDEF hmm_mat4 &operator*=(hmm_mat4 &Left, float Right); +HMMDEF hmm_quaternion &operator*=(hmm_quaternion &Left, float Right); + +HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, hmm_vec2 Right); +HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, hmm_vec3 Right); +HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, hmm_vec4 Right); + +HMMDEF hmm_vec2 &operator/=(hmm_vec2 &Left, float Right); +HMMDEF hmm_vec3 &operator/=(hmm_vec3 &Left, float Right); +HMMDEF hmm_vec4 &operator/=(hmm_vec4 &Left, float Right); +HMMDEF hmm_mat4 &operator/=(hmm_mat4 &Left, float Right); +HMMDEF hmm_quaternion &operator/=(hmm_quaternion &Left, float Right); + +HMMDEF hmm_bool operator==(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_bool operator==(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_bool operator==(hmm_vec4 Left, hmm_vec4 Right); + +HMMDEF hmm_bool operator!=(hmm_vec2 Left, hmm_vec2 Right); +HMMDEF hmm_bool operator!=(hmm_vec3 Left, hmm_vec3 Right); +HMMDEF hmm_bool operator!=(hmm_vec4 Left, hmm_vec4 Right); + +HMMDEF hmm_mat4 HMM_Mat4Identity(); +HMMDEF hmm_vec2 HMM_LerpV2(hmm_vec2 A, float T, hmm_vec2 B); +HMMDEF hmm_vec3 HMM_LerpV3(hmm_vec3 A, float T, hmm_vec3 B); +HMMDEF hmm_vec4 HMM_LerpV4(hmm_vec4 A, float T, hmm_vec4 B); +HMMDEF hmm_vec4 HMM_AverageVec3(hmm_vec4* Arr, unsigned int Len); +HMMDEF hmm_vec4 HMM_AverageVec4(hmm_vec4* Arr, unsigned int Len); +HMMDEF bool HMM_SameSide(hmm_vec3 P1, hmm_vec3 P2, hmm_vec3 A, hmm_vec3 B); +HMMDEF bool HMM_PointInTriangle(hmm_vec3 P, hmm_vec3 T0, hmm_vec3 T1, hmm_vec3 T2); + +#endif /* HANDMADE_MATH_CPP */ + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif /* HANDMADE_MATH_H */ + +#ifdef HANDMADE_MATH_IMPLEMENTATION + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#pragma clang diagnostic ignored "-Wmissing-braces" +#endif + +HINLINE float +HMM_SinF(float Angle) +{ + float Result = 0.0f; + + Result = HMM_SINF(Angle); + return (Result); +} + +HINLINE float +HMM_CosF(float Angle) +{ + float Result = 0.0f; + + Result = HMM_COSF(Angle); + return (Result); +} + +HINLINE float +HMM_TanF(float Radians) +{ + float Result = 0.0f; + + Result = HMM_TANF(Radians); + return (Result); +} + +HINLINE float +HMM_ACosF(float Radians) +{ + float Result = 0.0f; + + Result = HMM_ACOSF(Radians); + return (Result); +} + +HINLINE float +HMM_ATanF(float Radians) +{ + float Result = 0.0f; + + Result = HMM_ATANF(Radians); + return (Result); +} + +HINLINE float +HMM_Atan2F(float Left, float Right) +{ + float Result = 0.0f; + + Result = HMM_ATAN2F(Left, Right); + return (Result); +} + +HINLINE float +HMM_ExpF(float Float) +{ + float Result = 0.0f; + + Result = HMM_EXPF(Float); + return (Result); +} + +HINLINE float +HMM_LogF(float Float) +{ + float Result = 0.0f; + + Result = HMM_LOGF(Float); + return (Result); +} + +HINLINE float +HMM_ToRadians(float Degrees) +{ + float Result = 0.0f; + + Result = Degrees * (HMM_PI32 / 180.0f); + return (Result); +} + +HINLINE float +HMM_SquareRootF(float Value) +{ + float Result = 0.0f; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 In = _mm_set_ss(Value); + __m128 Out = _mm_sqrt_ss(In); + Result = _mm_cvtss_f32(Out); +#else + Result = HMM_SQRTF(Value); +#endif + + return(Result); +} + +HINLINE float +HMM_RSquareRootF(float Value) +{ + float Result = 0.0f; + +#ifdef HANDMADE_MATH__USE_SSE + __m128 In = _mm_set_ss(Value); + __m128 Out = _mm_rsqrt_ss(In); + Result = _mm_cvtss_f32(Out); +#else + Result = 1.0f/HMM_SquareRootF(Value); +#endif + + return(Result); +} + +HINLINE float +HMM_LengthSquaredVec2(hmm_vec2 A) +{ + float Result = 0.0f; + + Result = HMM_DotVec2(A, A); + + return(Result); +} + +HINLINE float +HMM_LengthSquaredVec3(hmm_vec3 A) +{ + float Result = 0.0f; + + Result = HMM_DotVec3(A, A); + + return (Result); +} + +HINLINE float +HMM_LengthSquaredVec4(hmm_vec4 A) +{ + float Result = 0.0f; + + Result = HMM_DotVec4(A, A); + + return(Result); +} + +HINLINE float +HMM_LengthVec2(hmm_vec2 A) +{ + float Result = 0.0f; + + Result = HMM_SquareRootF(HMM_LengthSquaredVec2(A)); + + return(Result); +} + +HINLINE float +HMM_LengthVec3(hmm_vec3 A) +{ + float Result = 0.0f; + + Result = HMM_SquareRootF(HMM_LengthSquaredVec3(A)); + + return (Result); +} + +HINLINE float +HMM_LengthVec4(hmm_vec4 A) +{ + float Result = 0.0f; + + Result = HMM_SquareRootF(HMM_LengthSquaredVec4(A)); + + return(Result); +} + +HINLINE float +HMM_Power(float Base, int Exponent) +{ + float Result = 1.0f; + float Mul = Exponent < 0 ? 1.f / Base : Base; + int X = Exponent < 0 ? -Exponent : Exponent; + while (X) + { + if (X & 1) + { + Result *= Mul; + } + + Mul *= Mul; + X >>= 1; + } + + return (Result); +} + +HINLINE float +HMM_PowerF(float Base, float Exponent) +{ + return HMM_EXPF(Exponent * HMM_LOGF(Base)); +} + +HINLINE float +HMM_Lerp(float A, float Time, float B) +{ + float Result = 0; + + Result = (1.0f - Time) * A + Time * B; + return (Result); +} + +HINLINE float +HMM_Clamp(float Min, float Value, float Max) +{ + float Result = Value; + + if(Result < Min) + { + Result = Min; + } + else if(Result > Max) + { + Result = Max; + } + + return (Result); +} + +HINLINE hmm_vec2 +HMM_NormalizeVec2(hmm_vec2 A) +{ + hmm_vec2 Result = {0}; + + float VectorLength = HMM_LengthVec2(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + Result.X = A.X * (1.0f / VectorLength); + Result.Y = A.Y * (1.0f / VectorLength); + } + + return (Result); +} + +HINLINE hmm_vec3 +HMM_NormalizeVec3(hmm_vec3 A) +{ + hmm_vec3 Result = {0}; + + float VectorLength = HMM_LengthVec3(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + Result.X = A.X * (1.0f / VectorLength); + Result.Y = A.Y * (1.0f / VectorLength); + Result.Z = A.Z * (1.0f / VectorLength); + } + + return (Result); +} + +HINLINE hmm_vec4 +HMM_NormalizeVec4(hmm_vec4 A) +{ + hmm_vec4 Result = {0}; + + float VectorLength = HMM_LengthVec4(A); + + /* NOTE(kiljacken): We need a zero check to not divide-by-zero */ + if (VectorLength != 0.0f) + { + Result.X = A.X * (1.0f / VectorLength); + Result.Y = A.Y * (1.0f / VectorLength); + Result.Z = A.Z * (1.0f / VectorLength); + Result.W = A.W * (1.0f / VectorLength); + } + + return (Result); +} + +HINLINE float +HMM_DotVec2(hmm_vec2 VecOne, hmm_vec2 VecTwo) +{ + float Result = 0.0f; + + Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y); + + return (Result); +} + +HINLINE float +HMM_DotVec3(hmm_vec3 VecOne, hmm_vec3 VecTwo) +{ + float Result = 0.0f; + + Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z); + + return (Result); +} + +HINLINE float +HMM_DotVec4(hmm_vec4 VecOne, hmm_vec4 VecTwo) +{ + float Result = 0.0f; + + Result = (VecOne.X * VecTwo.X) + (VecOne.Y * VecTwo.Y) + (VecOne.Z * VecTwo.Z) + (VecOne.W * VecTwo.W); + + return (Result); +} + +HINLINE hmm_vec3 +HMM_Cross(hmm_vec3 VecOne, hmm_vec3 VecTwo) +{ + hmm_vec3 Result = {0}; + + Result.X = (VecOne.Y * VecTwo.Z) - (VecOne.Z * VecTwo.Y); + Result.Y = (VecOne.Z * VecTwo.X) - (VecOne.X * VecTwo.Z); + Result.Z = (VecOne.X * VecTwo.Y) - (VecOne.Y * VecTwo.X); + + return (Result); +} + +HINLINE hmm_vec2 +HMM_Vec2(float X, float Y) +{ + hmm_vec2 Result = {0}; + + Result.X = X; + Result.Y = Y; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_Vec2i(int X, int Y) +{ + hmm_vec2 Result = {0}; + + Result.X = (float)X; + Result.Y = (float)Y; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_Vec3(float X, float Y, float Z) +{ + hmm_vec3 Result = {0}; + + Result.X = X; + Result.Y = Y; + Result.Z = Z; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_Vec3i(int X, int Y, int Z) +{ + hmm_vec3 Result = {0}; + + Result.X = (float)X; + Result.Y = (float)Y; + Result.Z = (float)Z; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_Vec4(float X, float Y, float Z, float W) +{ + hmm_vec4 Result = {0}; + + Result.X = X; + Result.Y = Y; + Result.Z = Z; + Result.W = W; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_Vec4i(int X, int Y, int Z, int W) +{ + hmm_vec4 Result = {0}; + + Result.X = (float)X; + Result.Y = (float)Y; + Result.Z = (float)Z; + Result.W = (float)W; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_Vec4v(hmm_vec3 Vector, float W) +{ + hmm_vec4 Result = {0}; + + Result.XYZ = Vector; + Result.W = W; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_AddVec2(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_AddVec3(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_AddVec4(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + Result.W = Left.W + Right.W; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_SubtractVec2(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_SubtractVec3(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_SubtractVec4(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + Result.W = Left.W - Right.W; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_MultiplyVec2(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_MultiplyVec2f(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_MultiplyVec3(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + Result.Z = Left.Z * Right.Z; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_MultiplyVec3f(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + Result.Z = Left.Z * Right; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_MultiplyVec4(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X * Right.X; + Result.Y = Left.Y * Right.Y; + Result.Z = Left.Z * Right.Z; + Result.W = Left.W * Right.W; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_MultiplyVec4f(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X * Right; + Result.Y = Left.Y * Right; + Result.Z = Left.Z * Right; + Result.W = Left.W * Right; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_DivideVec2(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + + return (Result); +} + +HINLINE hmm_vec2 +HMM_DivideVec2f(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_DivideVec3(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + Result.Z = Left.Z / Right.Z; + + return (Result); +} + +HINLINE hmm_vec3 +HMM_DivideVec3f(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + Result.Z = Left.Z / Right; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_DivideVec4(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X / Right.X; + Result.Y = Left.Y / Right.Y; + Result.Z = Left.Z / Right.Z; + Result.W = Left.W / Right.W; + + return (Result); +} + +HINLINE hmm_vec4 +HMM_DivideVec4f(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result.X = Left.X / Right; + Result.Y = Left.Y / Right; + Result.Z = Left.Z / Right; + Result.W = Left.W / Right; + + return (Result); +} + +HINLINE hmm_bool +HMM_EqualsVec2(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_bool Result = 0; + + Result = (Left.X == Right.X && Left.Y == Right.Y); + + return (Result); +} + +HINLINE hmm_bool +HMM_EqualsVec3(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_bool Result = 0; + + Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z); + + return (Result); +} + +HINLINE hmm_bool +HMM_EqualsVec4(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_bool Result = 0; + + Result = (Left.X == Right.X && Left.Y == Right.Y && Left.Z == Right.Z && Left.W == Right.W); + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Mat4(void) +{ + hmm_mat4 Result = {0}; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Mat4d(float Diagonal) +{ + hmm_mat4 Result = HMM_Mat4(); + + Result.Elements[0][0] = Diagonal; + Result.Elements[1][1] = Diagonal; + Result.Elements[2][2] = Diagonal; + Result.Elements[3][3] = Diagonal; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_AddMat4(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = HMM_Mat4(); + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] + Right.Elements[Columns][Rows]; + } + } + + return (Result); +} + +HINLINE hmm_mat4 +HMM_SubtractMat4(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = HMM_Mat4(); + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Left.Elements[Columns][Rows] - Right.Elements[Columns][Rows]; + } + } + + return (Result); +} + +#ifdef HANDMADE_MATH__USE_SSE +HINLINE __m128 +HMM_LinearCombineSSE(__m128 Left, hmm_mat4 Right) +{ + __m128 Result = {}; + Result = _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x00), Right.Rows[0]); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0x55), Right.Rows[1])); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xaa), Right.Rows[2])); + Result = _mm_add_ps(Result, _mm_mul_ps(_mm_shuffle_ps(Left, Left, 0xff), Right.Rows[3])); + + return(Result); +} +#endif + +HINLINE hmm_mat4 +HMM_MultiplyMat4(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = HMM_Mat4(); + +#ifdef HANDMADE_MATH__USE_SSE + + hmm_mat4 TransposedLeft = HMM_Transpose(Left); + hmm_mat4 TransposedRight = HMM_Transpose(Right); + + Result.Rows[0] = HMM_LinearCombineSSE(TransposedLeft.Rows[0], TransposedRight); + Result.Rows[1] = HMM_LinearCombineSSE(TransposedLeft.Rows[1], TransposedRight); + Result.Rows[2] = HMM_LinearCombineSSE(TransposedLeft.Rows[2], TransposedRight); + Result.Rows[3] = HMM_LinearCombineSSE(TransposedLeft.Rows[3], TransposedRight); + + Result = HMM_Transpose(Result); + +#else + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + float Sum = 0; + int CurrentMatrice; + for(CurrentMatrice = 0; CurrentMatrice < 4; ++CurrentMatrice) + { + Sum += Left.Elements[CurrentMatrice][Rows] * Right.Elements[Columns][CurrentMatrice]; + } + + Result.Elements[Columns][Rows] = Sum; + } + } +#endif + return (Result); +} + +HINLINE hmm_mat4 +HMM_MultiplyMat4f(hmm_mat4 Matrix, float Scalar) +{ + hmm_mat4 Result = HMM_Mat4(); + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] * Scalar; + } + } + + return (Result); +} + +HINLINE hmm_vec4 +HMM_MultiplyMat4ByVec4(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + hmm_vec4 Result = {0}; + + int Columns, Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + float Sum = 0; + for(Columns = 0; Columns < 4; ++Columns) + { + Sum += Matrix.Elements[Columns][Rows] * Vector.Elements[Columns]; + } + + Result.Elements[Rows] = Sum; + } + + return (Result); +} + +HINLINE hmm_mat4 +HMM_DivideMat4f(hmm_mat4 Matrix, float Scalar) +{ + hmm_mat4 Result = HMM_Mat4(); + + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Columns][Rows] = Matrix.Elements[Columns][Rows] / Scalar; + } + } + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Transpose(hmm_mat4 Matrix) +{ + hmm_mat4 Result = HMM_Mat4(); + +#ifdef HANDMADE_MATH__USE_SSE + Result = Matrix; + + _MM_TRANSPOSE4_PS(Result.Rows[0], Result.Rows[1], Result.Rows[2], Result.Rows[3]); +#else + int Columns; + for(Columns = 0; Columns < 4; ++Columns) + { + int Rows; + for(Rows = 0; Rows < 4; ++Rows) + { + Result.Elements[Rows][Columns] = Matrix.Elements[Columns][Rows]; + } + } +#endif + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Orthographic(float Left, float Right, float Bottom, float Top, float Near, float Far) +{ + hmm_mat4 Result = HMM_Mat4d(1.0f); + + Result.Elements[0][0] = 2.0f / (Right - Left); + Result.Elements[1][1] = 2.0f / (Top - Bottom); + Result.Elements[2][2] = 2.0f / (Near - Far); + + Result.Elements[3][0] = (Left + Right) / (Left - Right); + Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top); + Result.Elements[3][2] = (Far + Near) / (Near - Far); + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Perspective(float FOV, float AspectRatio, float Near, float Far) +{ + hmm_mat4 Result = HMM_Mat4d(1.0f); + + float TanThetaOver2 = HMM_TanF(FOV * (HMM_PI32 / 360.0f)); + + Result.Elements[0][0] = 1.0f / TanThetaOver2; + Result.Elements[1][1] = AspectRatio / TanThetaOver2; + Result.Elements[2][3] = -1.0f; + Result.Elements[2][2] = (Near + Far) / (Near - Far); + Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far); + Result.Elements[3][3] = 0.0f; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Translate(hmm_vec3 Translation) +{ + hmm_mat4 Result = HMM_Mat4d(1.0f); + + Result.Elements[3][0] = Translation.X; + Result.Elements[3][1] = Translation.Y; + Result.Elements[3][2] = Translation.Z; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Rotate(float Angle, hmm_vec3 Axis) +{ + hmm_mat4 Result = HMM_Mat4d(1.0f); + + Axis = HMM_NormalizeVec3(Axis); + + float SinTheta = HMM_SinF(HMM_ToRadians(Angle)); + float CosTheta = HMM_CosF(HMM_ToRadians(Angle)); + float CosValue = 1.0f - CosTheta; + + Result.Elements[0][0] = (Axis.X * Axis.X * CosValue) + CosTheta; + Result.Elements[0][1] = (Axis.X * Axis.Y * CosValue) + (Axis.Z * SinTheta); + Result.Elements[0][2] = (Axis.X * Axis.Z * CosValue) - (Axis.Y * SinTheta); + + Result.Elements[1][0] = (Axis.Y * Axis.X * CosValue) - (Axis.Z * SinTheta); + Result.Elements[1][1] = (Axis.Y * Axis.Y * CosValue) + CosTheta; + Result.Elements[1][2] = (Axis.Y * Axis.Z * CosValue) + (Axis.X * SinTheta); + + Result.Elements[2][0] = (Axis.Z * Axis.X * CosValue) + (Axis.Y * SinTheta); + Result.Elements[2][1] = (Axis.Z * Axis.Y * CosValue) - (Axis.X * SinTheta); + Result.Elements[2][2] = (Axis.Z * Axis.Z * CosValue) + CosTheta; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_Scale(hmm_vec3 Scale) +{ + hmm_mat4 Result = HMM_Mat4d(1.0f); + + Result.Elements[0][0] = Scale.X; + Result.Elements[1][1] = Scale.Y; + Result.Elements[2][2] = Scale.Z; + + return (Result); +} + +HINLINE hmm_mat4 +HMM_LookAt(hmm_vec3 Eye, hmm_vec3 Center, hmm_vec3 Up) +{ + hmm_mat4 Result = {0}; + + hmm_vec3 F = HMM_NormalizeVec3(HMM_SubtractVec3(Center, Eye)); + hmm_vec3 S = HMM_NormalizeVec3(HMM_Cross(F, Up)); + hmm_vec3 U = HMM_Cross(S, F); + + Result.Elements[0][0] = S.X; + Result.Elements[0][1] = U.X; + Result.Elements[0][2] = -F.X; + + Result.Elements[1][0] = S.Y; + Result.Elements[1][1] = U.Y; + Result.Elements[1][2] = -F.Y; + + Result.Elements[2][0] = S.Z; + Result.Elements[2][1] = U.Z; + Result.Elements[2][2] = -F.Z; + + Result.Elements[3][0] = -HMM_DotVec3(S, Eye); + Result.Elements[3][1] = -HMM_DotVec3(U, Eye); + Result.Elements[3][2] = HMM_DotVec3(F, Eye); + Result.Elements[3][3] = 1.0f; + + return (Result); +} + + +HINLINE hmm_quaternion +HMM_Quaternion(float X, float Y, float Z, float W) +{ + hmm_quaternion Result = {0}; + + Result.X = X; + Result.Y = Y; + Result.Z = Z; + Result.W = W; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_QuaternionV4(hmm_vec4 Vector) +{ + hmm_quaternion Result = {0}; + + Result.X = Vector.X; + Result.Y = Vector.Y; + Result.Z = Vector.Z; + Result.W = Vector.W; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_AddQuaternion(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result.X = Left.X + Right.X; + Result.Y = Left.Y + Right.Y; + Result.Z = Left.Z + Right.Z; + Result.W = Left.W + Right.W; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_SubtractQuaternion(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result.X = Left.X - Right.X; + Result.Y = Left.Y - Right.Y; + Result.Z = Left.Z - Right.Z; + Result.W = Left.W - Right.W; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_MultiplyQuaternion(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result.X = (Left.X * Right.W) + (Left.Y * Right.Z) - (Left.Z * Right.Y) + (Left.W * Right.X); + Result.Y = (-Left.X * Right.Z) + (Left.Y * Right.W) + (Left.Z * Right.X) + (Left.W * Right.Y); + Result.Z = (Left.X * Right.Y) - (Left.Y * Right.X) + (Left.Z * Right.W) + (Left.W * Right.Z); + Result.W = (-Left.X * Right.X) - (Left.Y * Right.Y) - (Left.Z * Right.Z) + (Left.W * Right.W); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_MultiplyQuaternionF(hmm_quaternion Left, float Multiplicative) +{ + hmm_quaternion Result = {0}; + + Result.X = Left.X * Multiplicative; + Result.Y = Left.Y * Multiplicative; + Result.Z = Left.Z * Multiplicative; + Result.W = Left.W * Multiplicative; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_DivideQuaternionF(hmm_quaternion Left, float Dividend) +{ + hmm_quaternion Result = {0}; + + Result.X = Left.X / Dividend; + Result.Y = Left.Y / Dividend; + Result.Z = Left.Z / Dividend; + Result.W = Left.W / Dividend; + + return(Result); +} + +HINLINE hmm_quaternion +HMM_InverseQuaternion(hmm_quaternion Left) +{ + hmm_quaternion Conjugate = {0}; + hmm_quaternion Result = {0}; + float Norm = 0; + float NormSquared = 0; + + Conjugate.X = -Left.X; + Conjugate.Y = -Left.Y; + Conjugate.Z = -Left.Z; + Conjugate.W = Left.W; + + Norm = HMM_SquareRootF(HMM_DotQuaternion(Left, Left)); + NormSquared = Norm * Norm; + + Result.X = Conjugate.X / NormSquared; + Result.Y = Conjugate.Y / NormSquared; + Result.Z = Conjugate.Z / NormSquared; + Result.W = Conjugate.W / NormSquared; + + return(Result); +} + +HINLINE float +HMM_DotQuaternion(hmm_quaternion Left, hmm_quaternion Right) +{ + float Result = 0.0f; + + Result = (Left.X * Right.X) + (Left.Y * Right.Y) + (Left.Z * Right.Z) + (Left.W * Right.W); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_NormalizeQuaternion(hmm_quaternion Left) +{ + hmm_quaternion Result; + + float Length = HMM_SquareRootF(HMM_DotQuaternion(Left, Left)); + Result = HMM_DivideQuaternionF(Left, Length); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_NLerp(hmm_quaternion Left, float Time, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result.X = HMM_Lerp(Left.X, Time, Right.X); + Result.Y = HMM_Lerp(Left.Y, Time, Right.Y); + Result.Z = HMM_Lerp(Left.Z, Time, Right.Z); + Result.W = HMM_Lerp(Left.W, Time, Right.W); + + Result = HMM_NormalizeQuaternion(Result); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_Slerp(hmm_quaternion Left, float Time, hmm_quaternion Right) +{ + hmm_quaternion Result; + hmm_quaternion QuaternionLeft; + hmm_quaternion QuaternionRight; + + float Cos_Theta = HMM_DotQuaternion(Left, Right); + float Angle = HMM_ACosF(Cos_Theta); + + float S1 = HMM_SinF((1.0f - Time) * Angle); + float S2 = HMM_SinF(Time * Angle); + float Is = 1.0f / HMM_SinF(Angle); + + QuaternionLeft = HMM_MultiplyQuaternionF(Left, S1); + QuaternionRight = HMM_MultiplyQuaternionF(Right, S2); + + Result = HMM_AddQuaternion(QuaternionLeft, QuaternionRight); + Result = HMM_MultiplyQuaternionF(Result, Is); + + return(Result); +} + +HINLINE hmm_mat4 +HMM_QuaternionToMat4(hmm_quaternion Left) +{ + hmm_mat4 Result; + Result = HMM_Mat4d(1); + + hmm_quaternion NormalizedQuaternion = HMM_NormalizeQuaternion(Left); + + float XX, YY, ZZ, + XY, XZ, YZ, + WX, WY, WZ; + + XX = NormalizedQuaternion.X * NormalizedQuaternion.X; + YY = NormalizedQuaternion.Y * NormalizedQuaternion.Y; + ZZ = NormalizedQuaternion.Z * NormalizedQuaternion.Z; + XY = NormalizedQuaternion.X * NormalizedQuaternion.Y; + XZ = NormalizedQuaternion.X * NormalizedQuaternion.Z; + YZ = NormalizedQuaternion.Y * NormalizedQuaternion.Z; + WX = NormalizedQuaternion.W * NormalizedQuaternion.X; + WY = NormalizedQuaternion.W * NormalizedQuaternion.Y; + WZ = NormalizedQuaternion.W * NormalizedQuaternion.Z; + + Result.Elements[0][0] = 1.0f - 2.0f * (YY + ZZ); + Result.Elements[0][1] = 2.0f * (XY + WZ); + Result.Elements[0][2] = 2.0f * (XZ - WY); + + Result.Elements[1][0] = 2.0f * (XY - WZ); + Result.Elements[1][1] = 1.0f - 2.0f * (XX + ZZ); + Result.Elements[1][2] = 2.0f * (YZ + WX); + + Result.Elements[2][0] = 2.0f * (XZ + WY); + Result.Elements[2][1] = 2.0f * (YZ - WX); + Result.Elements[2][2] = 1.0f - 2.0f * (XX + YY); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_QuaternionFromAxisAngle(hmm_vec3 Axis, float AngleOfRotation) +{ + hmm_quaternion Result = {0}; + float AxisNorm = 0; + float SineOfRotation = 0; + hmm_vec3 RotatedVector; + + AxisNorm = HMM_SquareRootF(HMM_DotVec3(Axis, Axis)); + SineOfRotation = HMM_SinF(AngleOfRotation / 2.0f); + RotatedVector = HMM_MultiplyVec3f(Axis, SineOfRotation); + + Result.W = HMM_CosF(AngleOfRotation / 2.0f); + Result.XYZ = HMM_DivideVec3f(RotatedVector, AxisNorm); + + return(Result); +} + +// Extensions + +HINLINE hmm_mat4 +HMM_Mat4Identity() +{ + hmm_mat4 Result = {}; + + Result.Elements[0][0] = 1; + Result.Elements[0][1] = 0; + Result.Elements[0][2] = 0; + Result.Elements[0][3] = 0; + + Result.Elements[1][0] = 0; + Result.Elements[1][1] = 1; + Result.Elements[1][2] = 0; + Result.Elements[1][3] = 0; + + Result.Elements[2][0] = 0; + Result.Elements[2][1] = 0; + Result.Elements[2][2] = 1; + Result.Elements[2][3] = 0; + + Result.Elements[3][0] = 0; + Result.Elements[3][1] = 0; + Result.Elements[3][2] = 0; + Result.Elements[3][3] = 1; + + return Result; +} + +#define HMMToV2(v) (v2){ (v).X, (v).Y } +#define HMMToV3(v) (v3){ (v).X, (v).Y, (v).Z } +#define HMMToV4(v) (v4){ (v).X, (v).Y, (v).Z, (v).W } + +#define ToHMMV2(v) (hmm_vec2){ (v).x, (v).y } +#define ToHMMV3(v) (hmm_vec3){ (v).x, (v).y, (v).z } +#define ToHMMV4(v) (hmm_vec4){ (v).x, (v).y, (v).z, (v).w } + +HINLINE hmm_vec2 +HMM_LerpV2(hmm_vec2 A, float T, hmm_vec2 B) +{ + hmm_vec2 Result = {}; + Result.X = HMM_Lerp(A.X, T, B.X); + Result.Y = HMM_Lerp(A.Y, T, B.Y); + return Result; +} +HINLINE hmm_vec3 +HMM_LerpV3(hmm_vec3 A, float T, hmm_vec3 B) +{ + hmm_vec3 Result = {}; + Result.X = HMM_Lerp(A.X, T, B.X); + Result.Y = HMM_Lerp(A.Y, T, B.Y); + Result.Z = HMM_Lerp(A.Z, T, B.Z); + return Result; +} +HINLINE hmm_vec4 +HMM_LerpV4(hmm_vec4 A, float T, hmm_vec4 B) +{ + hmm_vec4 Result = {}; + Result.X = HMM_Lerp(A.X, T, B.X); + Result.Y = HMM_Lerp(A.Y, T, B.Y); + Result.Z = HMM_Lerp(A.Z, T, B.Z); + Result.W = HMM_Lerp(A.W, T, B.W); + return Result; +} + +// Range + +static bool +HMM_V2RContains(hmm_v2r Range, hmm_v2 P) +{ + return (Range.ValueMin.x <= P.x && + Range.ValueMin.y <= P.y && + Range.ValueMax.x >= P.x && + Range.ValueMax.y >= P.y); +} + +static hmm_v2 +HMM_V2RSize(hmm_v2r Range) +{ + hmm_v2 Result = {}; + Result.x = Range.ValueMax.x - Range.ValueMin.x; + Result.y = Range.ValueMax.y - Range.ValueMin.y; + return Result; +} + +#define HMM_V2RWidth(r) HMM_V2RSize(r).x +#define HMM_V2RHeight(r) HMM_V2RSize(r).y + +static hmm_v2r +HMM_V2ROffset(hmm_v2r Range, hmm_v2 Offset) +{ + hmm_v2r Result = {}; + Result.ValueMin = HMM_AddVec2(Range.ValueMin, Offset); + Result.ValueMax = HMM_AddVec2(Range.ValueMax, Offset); + return Result; +} + +// Geometry + +static hmm_vec3 +HMM_AverageVec3(hmm_vec3* Arr, int Len) +{ + hmm_vec3 Total = {}; + for (int i = 0; i < Len; i++) + { + Total += HMM_AddVec3(Total, Arr[i]); + } + + hmm_vec3 Result = {}; + Result.x = Total.x / Len; + Result.y = Total.y / Len; + Result.z = Total.z / Len; + + return Result; +} + +static hmm_vec4 +HMM_AverageVec4(hmm_vec4* Arr, int Len) +{ + hmm_vec4 Total = {}; + for (int i = 0; i < Len; i++) + { + Total = HMM_AddVec4(Total, Arr[i]); + } + + hmm_vec4 Result = {}; + Result.x = Total.x / Len; + Result.y = Total.y / Len; + Result.z = Total.z / Len; + Result.w = Total.w / Len; + return Result; +} + +// Point In Triangle From: https://blackpawn.com/texts/pointinpoly/default.html +static bool +HMM_SameSide(hmm_vec3 P1, hmm_vec3 P2, hmm_vec3 A, hmm_vec3 B) +{ + hmm_vec3 BA = HMM_SubtractVec3(B, A); + hmm_vec3 P1A = HMM_SubtractVec3(P1, A); + hmm_vec3 P2A = HMM_SubtractVec3(P2, A); + hmm_vec3 CP1 = HMM_Cross(BA, P1A); + hmm_vec3 CP2 = HMM_Cross(BA, P2A); + return (HMM_DotVec3(CP1, CP2) >= 0); +} + +static bool +HMM_PointInTriangle(hmm_vec3 P, hmm_vec3 T0, hmm_vec3 T1, hmm_vec3 T2) +{ + return (HMM_SameSide(P, T0, T1, T2) && + HMM_SameSide(P, T1, T0, T2) && + HMM_SameSide(P, T2, T0, T1)); +} + +#ifdef HANDMADE_MATH_CPP_MODE + +HINLINE float +HMM_Length(hmm_vec2 A) +{ + float Result = 0.0f; + + Result = HMM_LengthVec2(A); + + return(Result); +} + +HINLINE float +HMM_Length(hmm_vec3 A) +{ + float Result = 0.0f; + + Result = HMM_LengthVec3(A); + + return(Result); +} + +HINLINE float +HMM_Length(hmm_vec4 A) +{ + float Result = 0.0f; + + Result = HMM_LengthVec4(A); + + return(Result); +} + +HINLINE float +HMM_LengthSquared(hmm_vec2 A) +{ + float Result = 0.0f; + + Result = HMM_LengthSquaredVec2(A); + + return(Result); +} + +HINLINE float +HMM_LengthSquared(hmm_vec3 A) +{ + float Result = 0.0f; + + Result = HMM_LengthSquaredVec3(A); + + return(Result); +} + +HINLINE float +HMM_LengthSquared(hmm_vec4 A) +{ + float Result = 0.0f; + + Result = HMM_LengthSquaredVec4(A); + + return(Result); +} + +HINLINE hmm_vec2 +HMM_Normalize(hmm_vec2 A) +{ + hmm_vec2 Result = {0}; + + Result = HMM_NormalizeVec2(A); + + return(Result); +} + +HINLINE hmm_vec3 +HMM_Normalize(hmm_vec3 A) +{ + hmm_vec3 Result = {0}; + + Result = HMM_NormalizeVec3(A); + + return(Result); +} + +HINLINE hmm_vec4 +HMM_Normalize(hmm_vec4 A) +{ + hmm_vec4 Result = {0}; + + Result = HMM_NormalizeVec4(A); + + return(Result); +} + +HINLINE hmm_quaternion +HMM_Normalize(hmm_quaternion A) +{ + hmm_quaternion Result = {0}; + + Result = HMM_NormalizeQuaternion(A); + + return(Result); +} + +HINLINE float +HMM_Dot(hmm_vec2 VecOne, hmm_vec2 VecTwo) +{ + float Result = 0; + + Result = HMM_DotVec2(VecOne, VecTwo); + + return(Result); +} + +HINLINE float +HMM_Dot(hmm_vec3 VecOne, hmm_vec3 VecTwo) +{ + float Result = 0; + + Result = HMM_DotVec3(VecOne, VecTwo); + + return(Result); +} + +HINLINE float +HMM_Dot(hmm_vec4 VecOne, hmm_vec4 VecTwo) +{ + float Result = 0; + + Result = HMM_DotVec4(VecOne, VecTwo); + + return(Result); +} + +HINLINE float +HMM_Dot(hmm_quaternion QuatOne, hmm_quaternion QuatTwo) +{ + float Result = 0; + + Result = HMM_DotQuaternion(QuatOne, QuatTwo); + + return(Result); +} + +HINLINE hmm_vec2 +HMM_Add(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_AddVec2(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Add(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_AddVec3(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Add(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_AddVec4(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +HMM_Add(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_AddMat4(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Add(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_AddQuaternion(Left, Right); + return(Result); +} + +HINLINE hmm_vec2 +HMM_Subtract(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_SubtractVec2(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Subtract(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_SubtractVec3(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Subtract(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_SubtractVec4(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +HMM_Subtract(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_SubtractMat4(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Subtract(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_SubtractQuaternion(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +HMM_Multiply(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_MultiplyVec2(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +HMM_Multiply(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_MultiplyVec2f(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Multiply(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_MultiplyVec3(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Multiply(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_MultiplyVec3f(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Multiply(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_MultiplyVec4(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Multiply(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_MultiplyVec4f(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +HMM_Multiply(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_MultiplyMat4(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +HMM_Multiply(hmm_mat4 Left, float Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_MultiplyMat4f(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Multiply(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + hmm_vec4 Result = {0}; + + Result = HMM_MultiplyMat4ByVec4(Matrix, Vector); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Multiply(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_MultiplyQuaternion(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Multiply(hmm_quaternion Left, float Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_MultiplyQuaternionF(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Multiply(float Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_MultiplyQuaternionF(Right, Left); + return (Result); +} + +HINLINE hmm_vec2 +HMM_Divide(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_DivideVec2(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +HMM_Divide(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_DivideVec2f(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Divide(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_DivideVec3(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +HMM_Divide(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_DivideVec3f(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Divide(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_DivideVec4(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +HMM_Divide(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_DivideVec4f(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +HMM_Divide(hmm_mat4 Left, float Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_DivideMat4f(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +HMM_Divide(hmm_quaternion Left, float Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_DivideQuaternionF(Left, Right); + return (Result); +} + +HINLINE hmm_bool +HMM_Equals(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_bool Result = 0; + + Result = HMM_EqualsVec2(Left, Right); + return (Result); +} + +HINLINE hmm_bool +HMM_Equals(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_bool Result = 0; + + Result = HMM_EqualsVec3(Left, Right); + return (Result); +} + +HINLINE hmm_bool +HMM_Equals(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_bool Result = 0; + + Result = HMM_EqualsVec4(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +operator+(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Add(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator+(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Add(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator+(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Add(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +operator+(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Add(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +operator+(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Add(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +operator-(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Subtract(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator-(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Subtract(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator-(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Subtract(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +operator-(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Subtract(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +operator-(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Subtract(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +operator*(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator*(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator*(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = HMM_Multiply(Left, Right); + + return (Result); +} + +HINLINE hmm_vec2 +operator*(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator*(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator*(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +operator*(hmm_mat4 Left, float Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +operator*(float Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Multiply(Right, Left); + return (Result); +} + +HINLINE hmm_vec3 +operator*(float Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Multiply(Right, Left); + return (Result); +} + +HINLINE hmm_vec4 +operator*(float Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Multiply(Right, Left); + return (Result); +} + +HINLINE hmm_mat4 +operator*(float Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Multiply(Right, Left); + return (Result); +} + +HINLINE hmm_mat4 +operator*(hmm_mat4 Left, hmm_mat4 Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator*(hmm_mat4 Matrix, hmm_vec4 Vector) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Multiply(Matrix, Vector); + return (Result); +} + +HINLINE hmm_quaternion +operator*(hmm_quaternion Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +operator*(hmm_quaternion Left, float Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Multiply(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +operator*(float Left, hmm_quaternion Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Multiply(Right, Left); + return (Result); +} + +HINLINE hmm_vec2 +operator/(hmm_vec2 Left, hmm_vec2 Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator/(hmm_vec3 Left, hmm_vec3 Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Divide(Left, Right); + + return (Result); +} + +HINLINE hmm_vec4 +operator/(hmm_vec4 Left, hmm_vec4 Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 +operator/(hmm_vec2 Left, float Right) +{ + hmm_vec2 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_vec3 +operator/(hmm_vec3 Left, float Right) +{ + hmm_vec3 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_vec4 +operator/(hmm_vec4 Left, float Right) +{ + hmm_vec4 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_mat4 +operator/(hmm_mat4 Left, float Right) +{ + hmm_mat4 Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_quaternion +operator/(hmm_quaternion Left, float Right) +{ + hmm_quaternion Result = {0}; + + Result = HMM_Divide(Left, Right); + return (Result); +} + +HINLINE hmm_vec2 & +operator+=(hmm_vec2 &Left, hmm_vec2 Right) +{ + return (Left = Left + Right); +} + +HINLINE hmm_vec3 & +operator+=(hmm_vec3 &Left, hmm_vec3 Right) +{ + return (Left = Left + Right); +} + +HINLINE hmm_vec4 & +operator+=(hmm_vec4 &Left, hmm_vec4 Right) +{ + return (Left = Left + Right); +} + +HINLINE hmm_mat4 & +operator+=(hmm_mat4 &Left, hmm_mat4 Right) +{ + return (Left = Left + Right); +} + +HINLINE hmm_quaternion & +operator+=(hmm_quaternion &Left, hmm_quaternion Right) +{ + return (Left = Left + Right); +} + +HINLINE hmm_vec2 & +operator-=(hmm_vec2 &Left, hmm_vec2 Right) +{ + return (Left = Left - Right); +} + +HINLINE hmm_vec3 & +operator-=(hmm_vec3 &Left, hmm_vec3 Right) +{ + return (Left = Left - Right); +} + +HINLINE hmm_vec4 & +operator-=(hmm_vec4 &Left, hmm_vec4 Right) +{ + return (Left = Left - Right); +} + +HINLINE hmm_mat4 & +operator-=(hmm_mat4 &Left, hmm_mat4 Right) +{ + return (Left = Left - Right); +} + +HINLINE hmm_quaternion & +operator-=(hmm_quaternion &Left, hmm_quaternion Right) +{ + return (Left = Left - Right); +} + +HINLINE hmm_vec2 & +operator/=(hmm_vec2 &Left, hmm_vec2 Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec3 & +operator/=(hmm_vec3 &Left, hmm_vec3 Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec4 & +operator/=(hmm_vec4 &Left, hmm_vec4 Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec2 & +operator/=(hmm_vec2 &Left, float Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec3 & +operator/=(hmm_vec3 &Left, float Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec4 & +operator/=(hmm_vec4 &Left, float Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_mat4 & +operator/=(hmm_mat4 &Left, float Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_quaternion & +operator/=(hmm_quaternion &Left, float Right) +{ + return (Left = Left / Right); +} + +HINLINE hmm_vec2 & +operator*=(hmm_vec2 &Left, hmm_vec2 Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_vec3 & +operator*=(hmm_vec3 &Left, hmm_vec3 Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_vec4 & +operator*=(hmm_vec4 &Left, hmm_vec4 Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_vec2 & +operator*=(hmm_vec2 &Left, float Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_vec3 & +operator*=(hmm_vec3 &Left, float Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_vec4 & +operator*=(hmm_vec4 &Left, float Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_mat4 & +operator*=(hmm_mat4 &Left, float Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_quaternion & +operator*=(hmm_quaternion &Left, float Right) +{ + return (Left = Left * Right); +} + +HINLINE hmm_bool +operator==(hmm_vec2 Left, hmm_vec2 Right) +{ + return HMM_EqualsVec2(Left, Right); +} + +HINLINE hmm_bool +operator==(hmm_vec3 Left, hmm_vec3 Right) +{ + return HMM_EqualsVec3(Left, Right); +} + +HINLINE hmm_bool +operator==(hmm_vec4 Left, hmm_vec4 Right) +{ + return HMM_EqualsVec4(Left, Right); +} + + +HINLINE hmm_bool +operator!=(hmm_vec2 Left, hmm_vec2 Right) +{ + return !HMM_EqualsVec2(Left, Right); +} + +HINLINE hmm_bool +operator!=(hmm_vec3 Left, hmm_vec3 Right) +{ + return !HMM_EqualsVec3(Left, Right); +} + +HINLINE hmm_bool +operator!=(hmm_vec4 Left, hmm_vec4 Right) +{ + return !HMM_EqualsVec4(Left, Right); +} + +#endif /* HANDMADE_MATH_CPP_MODE */ + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#endif /* HANDMADE_MATH_IMPLEMENTATION */ diff --git a/src_v2/lumenarium_first.cpp b/src_v2/lumenarium_first.cpp new file mode 100644 index 0000000..e81ff6a --- /dev/null +++ b/src_v2/lumenarium_first.cpp @@ -0,0 +1,87 @@ +#include "lumenarium_first.h" + +internal App_State* +lumenarium_init() +{ + permanent = bump_allocator_create_reserve(MB(64)); + scratch = bump_allocator_create_reserve(MB(64)); + + run_tests(); + + App_State* state = allocator_alloc_struct(permanent, App_State); + add_flag(state->flags, AppState_IsRunning); + + state->input_state = input_state_create(); + + en_init(state); + if (!has_flag(state->flags, AppState_NoEditor)) + { + ed_init(state); + } + + return state; +} + +internal void +lumenarium_frame_prepare(App_State* state) +{ + allocator_clear(scratch); + input_state_swap_frames(&state->input_state); + + en_frame_prepare(state); + if (!has_flag(state->flags, AppState_NoEditor)) + { + ed_frame_prepare(state); + } +} + +internal void +lumenarium_frame(App_State* state) +{ + en_frame(state); + if (!has_flag(state->flags, AppState_NoEditor)) + { + ed_frame(state); + } +} + +internal void +lumenarium_event(Platform_Window_Event evt, App_State* state) +{ + Input_Frame* frame = state->input_state.frame_hot; + switch (evt.kind) + { + case WindowEvent_MouseScroll: + { + frame->mouse_scroll = evt.scroll_amt; + } break; + + case WindowEvent_ButtonDown: + case WindowEvent_ButtonUp: + { + frame->key_flags[evt.key_code] = evt.key_flags; + } break; + + case WindowEvent_Char: + { + frame->string_input[frame->string_input_len++] = evt.char_value; + } break; + + case WindowEvent_WindowClosed: + { + rem_flag(state->flags, AppState_IsRunning); + } break; + + invalid_default_case; + } +} + +internal void +lumenarium_cleanup(App_State* state) +{ + en_cleanup(state); + if (!has_flag(state->flags, AppState_NoEditor)) + { + ed_cleanup(state); + } +} diff --git a/src_v2/lumenarium_first.h b/src_v2/lumenarium_first.h new file mode 100644 index 0000000..f6d93c0 --- /dev/null +++ b/src_v2/lumenarium_first.h @@ -0,0 +1,48 @@ +/* date = March 22nd 2022 2:29 am */ + +#ifndef LUMENARIUM_FIRST_H +#define LUMENARIUM_FIRST_H + +typedef struct App_State App_State; + +#include "lumenarium_memory.cpp" +#include "lumenarium_string.cpp" +#include "lumenarium_input.cpp" + +#include "engine/lumenarium_engine_assembly.h" +#include "engine/lumenarium_engine.cpp" + +#include "editor/lumenarium_editor_renderer.cpp" +#include "editor/lumenarium_editor.cpp" + +////////////////////////////////////////////// +// Lumenarium Runtime Environment + +global Allocator* permanent; +global Allocator* scratch; // gets reset at frame boundaries + +#if defined(DEBUG) +# include "lumenarium_tests.cpp" +#else +# define run_tests() +#endif + +////////////////////////////////////////////// +// Lumenarium State + +typedef b32 App_State_Flags; +enum +{ + AppState_None = 0, + AppState_IsRunning = 1, + AppState_NoEditor = 2, +}; + +struct App_State +{ + App_State_Flags flags; + + Input_State input_state; +}; + +#endif //LUMENARIUM_FIRST_H diff --git a/src_v2/lumenarium_input.cpp b/src_v2/lumenarium_input.cpp new file mode 100644 index 0000000..8937018 --- /dev/null +++ b/src_v2/lumenarium_input.cpp @@ -0,0 +1,81 @@ + +#define INPUT_FRAME_STRING_LENGTH 32 +struct Input_Frame +{ + Platform_Key_Flags key_flags[KeyCode_Count]; + + char string_input[INPUT_FRAME_STRING_LENGTH]; + u32 string_input_len; + + v2 mouse_pos; + s32 mouse_scroll; +}; + +struct Input_State +{ + Input_Frame frames[2]; + Input_Frame* frame_hot; + Input_Frame* frame_cold; + + // cross frame state tracking + v2 mouse_pos_delta; + v2 mouse_pos_down; +}; + +#define key_was_down(key_flags) has_flag((key_flags), KeyFlag_State_WasDown) +#define key_is_down(key_flags) has_flag((key_flags), KeyFlag_State_IsDown) +#define key_was_up(key_flags) (!has_flag((key_flags), KeyFlag_State_WasDown) +#define key_is_up(key_flags) (!has_flag((key_flags), KeyFlag_State_IsDown) + +internal Input_State +input_state_create() +{ + Input_State result = {}; + result.frame_hot = result.frames + 0; + result.frame_cold = result.frames + 1; + return result; +} + +internal void +input_state_swap_frames(Input_State* input_state) +{ + Input_Frame* next_hot = input_state->frame_cold; + input_state->frame_cold = input_state->frame_hot; + input_state->frame_hot = next_hot; + + // Clear the new hot input frame + Platform_Key_Flags* hot_key_flags = input_state->frame_hot->key_flags; + Platform_Key_Flags* cold_key_flags = input_state->frame_cold->key_flags; + for (u32 i = 0; i < KeyCode_Count; i++) hot_key_flags[i] = cold_key_flags[i]; + input_state->frame_hot->string_input_len = 0; +} + +// Key State Queries + +internal bool +input_key_is_down(Input_State* input_state, Platform_Key_Code key) +{ + Platform_Key_Flags flags = input_state->frame_hot->key_flags[key]; + return key_is_down(flags); +} + +internal bool +input_key_went_down(Input_State* input_state, Platform_Key_Code key) +{ + Platform_Key_Flags flags = input_state->frame_hot->key_flags[key]; + return key_is_down(flags) && !key_was_down(flags); +} + +internal bool +input_key_is_up(Input_State* input_state, Platform_Key_Code key) +{ + Platform_Key_Flags flags = input_state->frame_hot->key_flags[key]; + return !key_is_down(flags); +} + +internal bool +input_key_went_up(Input_State* input_state, Platform_Key_Code key) +{ + Platform_Key_Flags flags = input_state->frame_hot->key_flags[key]; + return !key_is_down(flags) && key_was_down(flags); +} diff --git a/src_v2/lumenarium_memory.cpp b/src_v2/lumenarium_memory.cpp new file mode 100644 index 0000000..6fa8123 --- /dev/null +++ b/src_v2/lumenarium_memory.cpp @@ -0,0 +1,226 @@ + +///////////////////////////////////////// +// Memory Functions + +void +memory_zero_no_simd(u8* base, u64 size) +{ + for (u64 i = 0; i < size; i++) base[i] = 0; +} + +void +memory_copy_no_simd(u8* from, u8* to, u64 size) +{ + for (u64 i = 0; i < size; i++) to[i] = from[i]; +} + +#if defined(PLATFORM_HAS_SIMD) + +// TODO(PS): +// TODO(PS): +// TODO(PS): + +void +memory_zero_simd(u8* base, u64 size) +{ + memory_zero_no_simd(base, size); +} + +void +memory_copy_simd(u8* from, u8* to, u64 size) +{ + memory_copy_no_simd(from, to, size); +} + +# define memory_zero(b,s) memory_zero_simd((b),(s)) +# define memory_copy(f,t,s) memory_copy_simd((f),(t),(s)) + +#else +# define memory_zero(b,s) memory_zero_no_simd((b),(s)) +# define memory_copy(f,t,s) memory_copy_no_simd((f),(t),(s)) + +#endif // defined(PLATFORM_HAS_SIMD) + +#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s)) + +u64 +size_to_pages(u64 size) +{ + u64 page_size = platform_page_size(); + u64 rem = size % page_size; + if (rem != 0 || size < page_size) + { + u64 grow = page_size - rem; + size += grow; + } + return size; +} + +///////////////////////////////////////// +// Allocator +// +// A generic interface for any memory-providing construct +// +// To implement a complete allocator, all that is really required +// is to create its Allocator_Alloc function + +typedef struct Allocator Allocator; + +typedef u8* Allocator_Alloc(Allocator* allocator, u64 size); +typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size); +typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size); +typedef void Allocator_Clear(Allocator* allocator); + +struct Allocator +{ + Allocator_Alloc* alloc; + Allocator_Free* free; + Allocator_Realloc* realloc; + Allocator_Clear* clear; + + Allocator* parent; + + u8* allocator_data; +}; + +#define allocator_alloc(a,s) (a)->alloc((a),(s)) +#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t)) +#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c)) + +#define allocator_free(a,b,s) (a)->free((a),(b),(s)) +#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t)) +#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c)) + +#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns)) +#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc)) + +#define allocator_clear(a) (a)->clear(a) + +///////////////////////////////////////// +// Bump Allocator + +struct Allocator_Bump +{ + u8* base; + u64 at; + u64 size_committed; + u64 size_reserved; +}; + +internal u8* +bump_allocator_alloc(Allocator* allocator, u64 size) +{ + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + + u64 at_after = bump->at + size; + // TODO(PS): align up to 8 bytes + + if (at_after >= bump->size_committed) + { + // determine new size of the arena + u64 new_size = bump->size_committed * 2; + if (new_size == 0) new_size = platform_page_size(); + if (new_size < at_after) new_size = size_to_pages(at_after); + + if (allocator->parent) + { + bump->base = allocator_realloc( + allocator->parent, + bump->base, + bump->size_committed, + new_size + ); + if (bump->base != 0) + { + bump->size_reserved = new_size; + bump->size_committed = new_size; + } + } + else + { + if (new_size < bump->size_reserved) + { + u64 next_page = size_to_pages(bump->at); + u64 commit_amt = new_size - next_page; + bump->base = platform_mem_commit(bump->base + next_page, commit_amt); + } + else + { + invalid_code_path; // out of reserved memory + } + } + } + + u8* result = bump->base; + bump->at = at_after; + + return result; +} + +internal u8* +bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size) +{ + u8* result = bump_allocator_alloc(allocator, new_size); + memory_copy(base, result, old_size); + return result; +} + +internal void +bump_allocator_clear(Allocator* allocator) +{ + if (!allocator->allocator_data) return; + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + bump->at = 0; +} + +internal Allocator* +bump_allocator_create_() +{ + u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump); + + u8* base = platform_mem_reserve(size_needed); + base = platform_mem_commit(base, size_needed); + + Allocator* result = (Allocator*)base; + zero_struct(*result); + + Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator); + zero_struct(*bump); + + result->alloc = bump_allocator_alloc; + result->realloc = bump_allocator_realloc; + result->clear = bump_allocator_clear; + result->allocator_data = (u8*)bump; + + return result; +} + +internal Allocator* +bump_allocator_create_reserve(u64 reserve_size) +{ + Allocator* result = bump_allocator_create_(); + Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data; + + u64 reserve_pages = size_to_pages(reserve_size); + bump->base = platform_mem_reserve(reserve_pages); + if (bump->base != 0) bump->size_reserved = reserve_pages; + + return result; +} + +internal Allocator* +bump_allocator_create_child(Allocator* parent, u64 init_size) +{ + Allocator* result = bump_allocator_create_(); + result->parent = parent; + + Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data; + bump->base = allocator_alloc(result->parent, init_size); + if (bump->base != 0) + { + bump->size_reserved = init_size; + bump->size_committed = init_size; + } + + return result; +} diff --git a/src_v2/lumenarium_string.cpp b/src_v2/lumenarium_string.cpp new file mode 100644 index 0000000..b7850a0 --- /dev/null +++ b/src_v2/lumenarium_string.cpp @@ -0,0 +1,226 @@ + +internal u64 +c_str_len(char* s) +{ + u64 result = 0; + for (; s[result] != 0; result++) {} + return result; +} + +#define str_varg(str) (int)(str).len, (char*)(str).str +#define lit_str(s) String{ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 } + +internal String +allocator_alloc_string(Allocator* a, u64 cap) +{ + String result = {}; + result.str = allocator_alloc_array(a, u8, cap); + result.cap = cap; + return result; +} + +///////////////////////////////////// +// Char Operations + +bool +char_is_space(u8 c) +{ + return c == ' ' || c == '\r' || c == '\t' || c == '\f' || c == '\v' || c == '\n'; +} + +u8 +char_to_upper(u8 c) +{ + return (c >= 'a' && c <= 'z') ? ('A' + (c - 'a')) : c; +} + +u8 +char_to_lower(u8 c) +{ + return (c >= 'A' && c <= 'Z') ? ('a' + (c - 'A')) : c; +} + +u8 +char_to_forward_slash(u8 c) +{ + return (c == '\\' ? '/' : c); +} + + +///////////////////////////////////// +// String Operations +// +// Note that these don't actually modify any memory +// just return structures that let you view it differently + +internal String +string_substring(String s, u64 min, u64 max) +{ + if (max > s.len) max = s.len; + if (min > s.len) min = s.len; + if (min > max) { + u64 t = min; + min = max; + max = min; + } + String result = {}; + result.str = s.str + min; + result.len = max - min; + result.cap = result.len; + return result; +} + +internal String +string_skip(String s, u64 min) +{ + return string_substring(s, min, s.len); +} + +internal String +string_chop(String s, u64 nmax) +{ + return string_substring(s, 0, s.len - nmax); +} + +internal String +string_get_prefix(String s, u64 max) +{ + return string_substring(s, 0, max); +} + +internal String +string_get_suffix(String s, u64 nmax) +{ + return string_substring(s, s.len - nmax, s.len); +} + +typedef u32 String_Match_Flags; +enum +{ + StringMatch_FindLast = 1, + StringMatch_CaseInsensitive = 2, + StringMatch_SlashInsensitive = 4, +}; + +internal bool +string_match(String a, String b, String_Match_Flags flags) +{ + bool result = false; + if (a.len == b.len) + { + result = true; + for (u64 i = 0; i < a.len; i++) + { + bool match = a.str[i] == b.str[i]; + if(flags & StringMatch_CaseInsensitive) + { + match |= (char_to_lower(a.str[i]) == char_to_lower(b.str[i])); + } + if(flags & StringMatch_SlashInsensitive) + { + match |= (char_to_forward_slash(a.str[i]) == char_to_forward_slash(b.str[i])); + } + if(match == 0) + { + result = 0; + break; + } + } + } + return result; +} + +internal u64 +string_find_substring(String s, String substr, u64 start_pos, String_Match_Flags flags) +{ + bool found = false; + u64 found_i = s.len; + for (u64 i = start_pos; i < s.len; i++) + { + if (i + substr.len <= s.len) + { + String at = string_substring(s, i, i + substr.len); + if (string_match(at, substr, flags)) + { + found = true; + found_i = i; + if (!(flags & StringMatch_FindLast)) break; + } + } + } + return found_i; +} + +///////////////////////////////////// +// Path Operations + +// good for removing extensions +internal String +string_chop_last_period(String s) +{ + u64 period_pos = string_find_substring(s, lit_str("."), 0, StringMatch_FindLast); + if(period_pos < s.len) + { + s.len = period_pos; + s.cap = s.len; + } + return s; +} + +// get the filename +internal String +string_skip_last_slash(String s) +{ + u64 slash_pos = string_find_substring(s, lit_str("/"), 0, StringMatch_FindLast | StringMatch_SlashInsensitive); + if(slash_pos < s.len) + { + s.str += slash_pos + 1; + s.len -= slash_pos + 1; + s.cap = s.len; + } + return s; +} + +// get the extension +internal String +string_skip_last_period(String s) +{ + u64 period_pos = string_find_substring(s, lit_str("."), 0, StringMatch_FindLast); + if(period_pos < s.len) + { + s.str += period_pos + 1; + s.len -= period_pos + 1; + s.cap = s.len; + } + return s; +} + +// good for getting the path to a file +internal String +string_chop_last_slash(String s) +{ + u64 slash_pos = string_find_substring(s, lit_str("/"), 0, StringMatch_FindLast | StringMatch_SlashInsensitive); + if(slash_pos < s.len) + { + s.len = slash_pos; + s.cap = s.len; + } + return s; +} + + +///////////////////////////////////// +// String Modifications + +internal String +string_copy(String s, Allocator* a) +{ + u64 size = s.cap; + if (s.str[s.cap] != 0) size += 1; + String result = allocator_alloc_string(a, size); + memory_copy(s.str, result.str, s.cap); + result.str[size] = 0; + result.len = size; + return result; +} + diff --git a/src_v2/lumenarium_tests.cpp b/src_v2/lumenarium_tests.cpp new file mode 100644 index 0000000..3bdfa5c --- /dev/null +++ b/src_v2/lumenarium_tests.cpp @@ -0,0 +1,46 @@ + +Platform_Thread_Result +thread_proc(Platform_Thread_Data* td) +{ + return {}; +} + +internal void +run_tests() +{ + // testing strings and exe path + String exe_file_path = platform_get_exe_path(scratch); + assert(exe_file_path.str != 0); + u64 run_tree_start = string_find_substring(exe_file_path, lit_str("run_tree"), 0, StringMatch_FindLast); + u64 run_tree_end = run_tree_start + lit_str("run_tree").len; + assert(run_tree_start < exe_file_path.len); + String run_tree_path = string_get_prefix(exe_file_path, run_tree_end); + String run_tree_path_nullterm = string_copy(run_tree_path, scratch); + assert(run_tree_path_nullterm.len > 0); + assert(platform_pwd_set(run_tree_path_nullterm)); + + // testing file io + Platform_File_Handle f = platform_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenExisting); + Platform_File_Info i = platform_file_get_info(f, scratch); + + Data d0 = platform_file_read_all(f, scratch); + assert(d0.size > 0); + + String s = lit_str("foooooooooobbbbbbaaaarrrrrr"); + Data d1 = { s.str, s.len }; + bool r = platform_file_write_all(f, d1); + assert(r); + + // testing threads + Platform_Thread_Handle threads[8]; + for (u32 j = 0; j < 8; j++) + { + threads[j] = platform_thread_begin(thread_proc, 0); + } + for (u32 j = 0; j < 8; j++) + { + platform_thread_end(threads[j]); + } + + allocator_clear(scratch); +} \ No newline at end of file diff --git a/src_v2/lumenarium_types.h b/src_v2/lumenarium_types.h new file mode 100644 index 0000000..29b96c9 --- /dev/null +++ b/src_v2/lumenarium_types.h @@ -0,0 +1,106 @@ +/* date = March 22nd 2022 2:08 am */ + +#ifndef LUMENARIUM_TYPES_H +#define LUMENARIUM_TYPES_H + +#define internal static +#define local_persist static +#define global static +#define local_const static const +#define global_const static const +#define external extern "C" + +#if defined(GUESS_INTS) +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +#else +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; +#endif + +typedef s8 b8; +typedef s32 b32; +typedef s64 b64; + +typedef float r32; +typedef double r64; + +struct Data +{ + u8* base; + u64 size; +}; + +#define Bytes(x) (x) +#define KB(x) ((x) << 10) +#define MB(x) ((x) << 20) +#define GB(x) ((x) << 30) +#define TB(x) (((u64)x) << 40) + +#define has_flag(data, flag) (((data) & (flag)) != 0) +#define has_flag_only(data, flag) (((data) & (flag)) == (data)) +#define add_flag(data, flag) ((data) |= (flag)) +#define rem_flag(data, flag) ((data) &= (~(flag))) + +////////////////////////////////////////////// +// Assert + +// this assert works by simply trying to write to an invalid address +// (in this case, 0x0), which will crash in most debuggers +#define assert_always (*((volatile s32*)0) = 0xFFFF) + +#ifdef USE_ASSERTS +# define assert(c) if (!(c)) { assert_always; } + +// useful for catching cases that you aren't sure you'll hit, but +// want to be alerted when they happen +# define invalid_code_path assert_always + +// useful for switch statements on enums that might grow. You'll +// break in the debugger the first time the default case is hit +// with a new enum value +# define invalid_default_case default: { assert_always; } break; + +#else +# define assert(c) +# define invalid_code_path +# define invalid_default_case default: { } break; +#endif + +////////////////////////////////////////////// +// List Helper Macros + +#define sll_push(first,last,ele) \ +if (!(first)) { (first) = (ele); }\ +else { (last)->next = (ele); } \ +(last) = (ele); (ele)->next = 0; + +// TODO(PS): Stack, Queue, DLL ops + +////////////////////////////////////////////// +// String + +// NOTE(PS): even though this has a len and cap, it should always be +// null terminated +struct String +{ + u8* str; + u64 len; + u64 cap; +}; + +typedef struct Allocator Allocator; + +#endif //LUMENARIUM_TYPES_H diff --git a/src_v2/platform/lumenarium_compiler_flags.h b/src_v2/platform/lumenarium_compiler_flags.h new file mode 100644 index 0000000..c137adf --- /dev/null +++ b/src_v2/platform/lumenarium_compiler_flags.h @@ -0,0 +1,17 @@ +/* date = March 22nd 2022 2:09 am */ + +#ifndef LUMENARIUM_COMPILER_FLAGS_H +#define LUMENARIUM_COMPILER_FLAGS_H + +#if defined(__clang__) +# pragma GCC diagnostic ignored "-Wunused-value" +# pragma GCC diagnostic ignored "-Wvarargs" +# pragma GCC diagnostic ignored "-Wwritable-strings" +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#ifdef DEBUG +# define USE_ASSERTS 1 +#endif + +#endif //LUMENARIUM_COMPILER_FLAGS_H diff --git a/src_v2/platform/lumenarium_platform.h b/src_v2/platform/lumenarium_platform.h new file mode 100644 index 0000000..4a74d1e --- /dev/null +++ b/src_v2/platform/lumenarium_platform.h @@ -0,0 +1,294 @@ +/* date = March 22nd 2022 2:05 am */ + +#ifndef LUMENARIUM_PLATFORM_H +#define LUMENARIUM_PLATFORM_H + +// This is a file that defines the things that every platform +// must expose to the entire program + +/////////////////////////////////////// +// Memory + +u64 platform_page_size(); + +u8* platform_mem_reserve(u64 size); +u8* platform_mem_commit(u8* base, u64 size); +bool platform_mem_decommit(u8* base, u64 size); +bool platform_mem_release(u8* base, u64 size); + +/////////////////////////////////////// +// File I/O + +struct Platform_File_Handle +{ + u64 value; +}; + +typedef u32 Platform_File_Access_Flags; +enum +{ + FileAccess_None = 0, + FileAccess_Read = 1, + FileAccess_Write = 2, +}; + +typedef u32 Platform_File_Create_Flags; +enum +{ + // these match https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + FileCreate_None = 0, + FileCreate_New = 1, + FileCreate_CreateAlways = 2, + FileCreate_OpenExisting = 3, + FileCreate_OpenAlways = 4, +}; + +typedef u32 Platform_File_Flags; +enum +{ + FileFlag_IsFile = 0, + FileFlag_IsDir = 1, +}; + +struct Platform_File_Info +{ + String path; + String path_abs; + u64 size; + u64 time_created; + u64 time_last_write; + Platform_File_Flags flags; +}; + +struct Platform_File_Info_List_Ele +{ + Platform_File_Info info; + Platform_File_Info_List_Ele* next; +}; + +struct Platform_File_Info_List +{ + Platform_File_Info_List_Ele* first; + Platform_File_Info_List_Ele* last; +}; + +Platform_File_Handle platform_file_open(String path, Platform_File_Access_Flags flags_access, Platform_File_Create_Flags flags_create); +void platform_file_close(Platform_File_Handle file_handle); +Platform_File_Info platform_file_get_info(Platform_File_Handle file_handle, Allocator* allocator); +Data platform_file_read_all(Platform_File_Handle file_handle, Allocator* allocator); +bool platform_file_write_all(Platform_File_Handle file_handle, Data file_data); + +typedef u32 Platform_Enum_Dir_Flags; +enum +{ + EnumDir_Recursive = 1, + EnumDir_IncludeDirectories = 2, +}; + +Platform_File_Info_List platform_dir_enum(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator); + +String platform_get_exe_path(Allocator* allocator); +bool platform_pwd_set(String path); + +/////////////////////////////////////// +// Windows & Events + +enum Platform_Window_Event_Kind +{ + WindowEvent_Invalid = 0, + + WindowEvent_MouseScroll, + WindowEvent_ButtonDown, + WindowEvent_ButtonUp, + WindowEvent_Char, + WindowEvent_WindowClosed, + + WindowEvent_Count, +}; + +typedef u32 Platform_Key_Code; +enum +{ + KeyCode_Invalid = 0, + + KeyCode_Esc, + + KeyCode_Space, + KeyCode_Tab, + KeyCode_CapsLock, + KeyCode_LeftShift, KeyCode_RightShift, + KeyCode_LeftCtrl, KeyCode_RightCtrl, + KeyCode_Fn, + KeyCode_Alt, + KeyCode_PageUp, KeyCode_PageDown, + KeyCode_Backspace, KeyCode_Delete, + KeyCode_Enter, + + // Function Keys + KeyCode_F0, KeyCode_F1, KeyCode_F2, KeyCode_F3, KeyCode_F4, KeyCode_F5, KeyCode_F6, KeyCode_F7, + KeyCode_F8, KeyCode_F9, KeyCode_F10, KeyCode_F11, KeyCode_F12, + + // Letters + KeyCode_a, KeyCode_b, KeyCode_c, KeyCode_d, KeyCode_e, KeyCode_f, KeyCode_g, KeyCode_h, + KeyCode_i, KeyCode_j, KeyCode_k, KeyCode_l, KeyCode_m, KeyCode_n, KeyCode_o, KeyCode_p, + KeyCode_q, KeyCode_r, KeyCode_s, KeyCode_t, KeyCode_u, KeyCode_v, KeyCode_w, KeyCode_x, + KeyCode_y, KeyCode_z, + + KeyCode_A, KeyCode_B, KeyCode_C, KeyCode_D, KeyCode_E, KeyCode_F, KeyCode_G, KeyCode_H, + KeyCode_I, KeyCode_J, KeyCode_K, KeyCode_L, KeyCode_M, KeyCode_N, KeyCode_O, KeyCode_P, + KeyCode_Q, KeyCode_R, KeyCode_S, KeyCode_T, KeyCode_U, KeyCode_V, KeyCode_W, KeyCode_X, + KeyCode_Y, KeyCode_Z, + + // Numbers + KeyCode_0, KeyCode_1, KeyCode_2, KeyCode_3, KeyCode_4, KeyCode_5, KeyCode_6, KeyCode_7, + KeyCode_8, KeyCode_9, + + KeyCode_Num0, KeyCode_Num1, KeyCode_Num2, KeyCode_Num3, KeyCode_Num4, KeyCode_Num5, + KeyCode_Num6, KeyCode_Num7, KeyCode_Num8, KeyCode_Num9, + + // Symbols + KeyCode_Bang, KeyCode_At, KeyCode_Pound, KeyCode_Dollar, KeyCode_Percent, KeyCode_Carrot, + KeyCode_Ampersand, KeyCode_Star, KeyCode_LeftParen, KeyCode_RightParen, KeyCode_Minus, KeyCode_Plus, + KeyCode_Equals, KeyCode_Underscore, KeyCode_LeftBrace, KeyCode_RightBrace, KeyCode_LeftBracket, + KeyCode_RightBracket, KeyCode_Colon, KeyCode_SemiColon, KeyCode_SingleQuote, KeyCode_DoubleQuote, + KeyCode_ForwardSlash, KeyCode_Backslash, KeyCode_Pipe, KeyCode_Comma, KeyCode_Period, + KeyCode_QuestionMark, KeyCode_LessThan, KeyCode_GreaterThan, KeyCode_Tilde, KeyCode_BackQuote, + + // Arrows + KeyCode_UpArrow, + KeyCode_DownArrow, + KeyCode_LeftArrow, + KeyCode_RightArrow, + + // Mouse + // NOTE(Peter): Including this here so we can utilize the same KeyDown, KeyUp etc. functions + KeyCode_MouseLeftButton, + KeyCode_MouseMiddleButton, + KeyCode_MouseRightButton, + + KeyCode_Count, +}; + +typedef u8 Platform_Key_Flags; +enum +{ + KeyFlag_None = 0, + + KeyFlag_Mod_Shift = 1, + KeyFlag_Mod_Ctrl = 2, + KeyFlag_Mod_Alt = 4, + KeyFlag_Mod_Sys = 8, + + KeyFlag_State_WasDown = 16, + KeyFlag_State_IsDown = 32, +}; + +struct Platform_Window_Event +{ + Platform_Window_Event_Kind kind; + Platform_Key_Code key_code; + Platform_Key_Flags key_flags; + s32 mouse_x; + s32 mouse_y; + s32 scroll_amt; + char char_value; +}; + +enum Platform_Cursor_Kind +{ + Cursor_Arrow, + Cursor_Pointer, + Cursor_Loading, + Cursor_HArrows, + Cursor_VArrows, + Cursor_DTopLeftArrows, + Cursor_DTopRightArrows, + Cursor_Count, +}; + +/////////////////////////////////////// +// Time + +global r64 target_seconds_per_frame = 1.0 / 30.0f; + +struct Platform_Ticks +{ + s64 value; +}; + +Platform_Ticks platform_get_ticks(); +r64 platform_ticks_to_seconds(Platform_Ticks ticks); + +Platform_Ticks +get_ticks_elapsed(Platform_Ticks start, Platform_Ticks end) +{ + Platform_Ticks result = {}; + result.value = end.value - start.value; + return result; +} + +r64 +get_seconds_elapsed(Platform_Ticks start, Platform_Ticks end) +{ + Platform_Ticks diff = get_ticks_elapsed(start, end); + return platform_ticks_to_seconds(diff); +} + +// TODO(PS): we have some stuff in v1 around system time, probably +// for timestamps etc. + +/////////////////////////////////////// +// Threads + +struct Platform_Thread_Handle +{ + u64 value; +}; + +struct Platform_Thread_Result +{ + u32 code; +}; + +typedef struct Platform_Thread_Data Platform_Thread_Data; +typedef Platform_Thread_Result Platform_Thread_Proc(Platform_Thread_Data* thread_data); + +struct Platform_Thread_Data +{ + Platform_Thread_Handle thread_handle; + u32 thread_id; + Platform_Thread_Proc* thread_proc; + Allocator* thread_memory; + u8* user_data; +}; + +Platform_Thread_Handle platform_thread_begin(Platform_Thread_Proc* proc, u8* user_data); +void platform_thread_end(Platform_Thread_Handle thread_handle); + +u32 platform_interlocked_increment(volatile u32* value); +u32 platform_interlocked_cmp_exchg(volatile u32* dest, u32 new_value, u32 old_value); + +/////////////////////////////////////// +// Network Access + +// TODO(PS): + +struct Platform_Socket_Handle +{ + u64 value; +}; + +Platform_Socket_Handle platform_socket_create(); +bool platform_socket_bind(); +bool platform_socket_connect(); +bool platform_socket_close(); +Data platform_socket_recv(); +s32 platform_Socket_set_listening(); +s32 platform_Socket_send(); +s32 platform_Socket_send_to(); +s32 platform_Socket_set_opt(); + +/////////////////////////////////////// +// Graphics Integration + +#endif //LUMENARIUM_PLATFORM_H diff --git a/src_v2/platform/lumenarium_platform_common_includes.h b/src_v2/platform/lumenarium_platform_common_includes.h new file mode 100644 index 0000000..46e6c47 --- /dev/null +++ b/src_v2/platform/lumenarium_platform_common_includes.h @@ -0,0 +1,36 @@ +/* date = March 22nd 2022 2:12 am */ + +#ifndef LUMENARIUM_PLATFORM_COMMON_INCLUDES_H +#define LUMENARIUM_PLATFORM_COMMON_INCLUDES_H + +#include + +#if !defined(GUESS_INTS) +# include +#endif // !defined(GUESS_INTS) + +#include + +#if 0 +#define HMM_SINF sin +#define HMM_COSF cos +#define HMM_TANF tan +#define HMM_SQRTF sqrt +#define HMM_EXPF exp +#define HMM_LOGF log +#define HMM_ACOSF acos +#define HMM_ATANF atan +#define HMM_ATAN2F atan2 +#endif + +#define HANDMADE_MATH_IMPLEMENTATION +#define HANDMADE_MATH_CPP_MODE +#define HANDMADE_MATH_STATIC +#include "../libs/HandmadeMath.h" + +typedef hmm_v2 v2; +typedef hmm_v3 v3; +typedef hmm_v4 v4; +typedef hmm_mat4 m44; + +#endif //LUMENARIUM_PLATFORM_COMMON_INCLUDES_H diff --git a/src_v2/platform/osx/lumenarium_first_osx.cpp b/src_v2/platform/osx/lumenarium_first_osx.cpp new file mode 100644 index 0000000..49d4820 --- /dev/null +++ b/src_v2/platform/osx/lumenarium_first_osx.cpp @@ -0,0 +1,28 @@ + +#include "../lumenarium_compiler_flags.h" +#include "../lumenarium_platform_common_includes.h" + +#include "../../lumenarium_types.h" +#include "../lumenarium_platform.h" +#include "../../lumenarium_first.cpp" + +#include +#include + +#include "lumenarium_osx_memory.cpp" + +int main (int arg_count, char** args) +{ + App_State* state = lumenarium_init(); + + while (has_flag(state->flags, AppState_IsRunning)) + { + // TODO(PS): event processing + + lumenarium_update(state); + } + + lumenarium_cleanup(state); + + return 0; +} \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_osx_memory.cpp b/src_v2/platform/osx/lumenarium_osx_memory.cpp new file mode 100644 index 0000000..0ae2d54 --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_memory.cpp @@ -0,0 +1,30 @@ +#define OSX_PAGE_SIZE KB(4) // TODO(PS): look this up + +u64 platform_page_size() { return OSX_PAGE_SIZE; } + +u8* +platform_mem_reserve(u64 size) +{ + size_t size_cvt = (size_t)size_to_pages(size); + u8* result = (u8*)malloc(size); + return result; +} + +u8* +platform_mem_commit(u8* base, u64 size) +{ + return base; +} + +bool +platform_mem_decommit(u8* base, u64 size) +{ + return true; +} + +bool +platform_mem_release(u8* base, u64 size) +{ + free(base); + return true; +} diff --git a/src_v2/platform/webgl/lumenarium_first_webgl.cpp b/src_v2/platform/webgl/lumenarium_first_webgl.cpp new file mode 100644 index 0000000..a6814e1 --- /dev/null +++ b/src_v2/platform/webgl/lumenarium_first_webgl.cpp @@ -0,0 +1,18 @@ +#define WEBGL_EXPORT __attribute__((visibility("default"))) +#define WEBGL_EXTERN extern "C" + +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } + +WEBGL_EXTERN void print(char* text); + +EXTERN_C_BEGIN; + +WEBGL_EXPORT int +main(void) +{ + print("Hi there!\n"); + return 5; +} + +EXTERN_C_END; \ No newline at end of file diff --git a/src_v2/platform/win32/lumenarium_first_win32.cpp b/src_v2/platform/win32/lumenarium_first_win32.cpp new file mode 100644 index 0000000..4eed08d --- /dev/null +++ b/src_v2/platform/win32/lumenarium_first_win32.cpp @@ -0,0 +1,249 @@ + +#include "../lumenarium_compiler_flags.h" +#include "../lumenarium_platform_common_includes.h" + +#include "windows.h" +#include + +#include "../../lumenarium_types.h" +#include "../lumenarium_platform.h" +#include "../../lumenarium_first.cpp" + +global DWORD win32_last_error = 0; +void +win32_get_last_error() +{ + win32_last_error = GetLastError(); +} + +#include "lumenarium_win32_memory.cpp" +#include "lumenarium_win32_window.cpp" +#include "lumenarium_win32_time.cpp" +#include "lumenarium_win32_file.cpp" +#include "lumenarium_win32_thread.cpp" + +internal Platform_Key_Flags +win32_get_key_flags_mod() +{ + Platform_Key_Flags result = 0; + if (GetKeyState(VK_SHIFT) & 0x8000) add_flag(result, KeyFlag_Mod_Shift); + if (GetKeyState(VK_MENU) & 0x8000) add_flag(result, KeyFlag_Mod_Alt); + if (GetKeyState(VK_CONTROL) & 0x8000) add_flag(result, KeyFlag_Mod_Ctrl); + return result; +} + +internal void +win32_mouse_capture(Win32_Window* win) +{ + // NOTE(Peter): We capture events when the mouse goes down so that + // if the user drags outside the window, we still get the mouse up + // event and can process it. Otherwise, we can get into cases where + // an event was started, didn't end, but the user can click again and + // try to start the event again. + // We relase event capture on mouse up. + SetCapture(win->window_handle); +} + +internal void +win32_mouse_release(Win32_Window* win) +{ + ReleaseCapture(); +} + +internal Platform_Window_Event +win32_button_event(Platform_Key_Code key, bool is_down, bool was_down) +{ + Platform_Window_Event evt = {}; + evt.kind = WindowEvent_ButtonDown; + evt.key_code = key; + evt.key_flags = win32_get_key_flags_mod(); + if (is_down) add_flag(evt.key_flags, KeyFlag_State_IsDown); + if (was_down) add_flag(evt.key_flags, KeyFlag_State_WasDown); + return evt; +} + +internal void +win32_window_handle_event(MSG msg, Win32_Window* win, App_State* state) +{ + switch (msg.message) + { + case WM_MOUSEWHEEL: + { + Platform_Window_Event evt = {}; + evt.kind = WindowEvent_MouseScroll; + evt.scroll_amt = GET_WHEEL_DELTA_WPARAM(msg.wParam); + lumenarium_event(evt, state); + }break; + + case WM_LBUTTONDOWN: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseLeftButton, + true, false + ); + lumenarium_event(evt, state); + win32_mouse_capture(win); + }break; + + case WM_MBUTTONDOWN: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseMiddleButton, + true, false + ); + lumenarium_event(evt, state); + win32_mouse_capture(win); + }break; + + case WM_RBUTTONDOWN: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseRightButton, + true, false + ); + lumenarium_event(evt, state); + win32_mouse_capture(win); + }break; + + case WM_LBUTTONUP: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseLeftButton, + false, true + ); + lumenarium_event(evt, state); + win32_mouse_release(win); + }break; + + case WM_MBUTTONUP: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseMiddleButton, + false, true + ); + lumenarium_event(evt, state); + win32_mouse_release(win); + }break; + + case WM_RBUTTONUP: + { + Platform_Window_Event evt = win32_button_event( + KeyCode_MouseRightButton, + false, true + ); + lumenarium_event(evt, state); + win32_mouse_release(win); + }break; + + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + case WM_KEYDOWN: + case WM_KEYUP: + { + Platform_Key_Code key = 0; + b32 was_down = (msg.lParam & (1 << 30)) != 0; + b32 is_down = (msg.lParam & (1 << 31)) == 0; + Platform_Window_Event evt = win32_button_event(key, is_down, was_down); + lumenarium_event(evt, state); + TranslateMessage(&msg); + DispatchMessage(&msg); + }break; + + case WM_CHAR: + { + Platform_Window_Event evt = {}; + evt.kind = WindowEvent_Char; + evt.char_value = (char)msg.wParam; + lumenarium_event(evt, state); + }break; + + default: + { + TranslateMessage(&msg); + DispatchMessage(&msg); + }break; + } +} + +INT WINAPI +WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + PSTR lpCmdLine, + INT nCmdShow) +{ + + App_State* state = lumenarium_init(); + if (!has_flag(state->flags, AppState_IsRunning)) return 0; + + // Window Setup + win32_main_window = win32_window_create( + hInstance, "Lumenarium", 1600, 900, win32_window_event_handler + ); + win32_window_opengl_ctx_create(&win32_main_window, { 32, 8, 0 }); + + win32_time_init(); + win32_files_init(); + win32_threads_init(); + + Platform_Ticks ticks_start = platform_get_ticks(); + while (has_flag(state->flags, AppState_IsRunning)) + { + win32_threads_reclaim(); + lumenarium_frame_prepare(state); + + // Potentially pass the window closed event to the runtime + if (win32_window_event_flags & WindowEventFlag_CloseRequested) + { + Platform_Window_Event evt = { + WindowEvent_WindowClosed, + }; + lumenarium_event(evt, state); + } + + // Pass Window Events to the runtime + MSG window_msg; + while (PeekMessageA( + &window_msg, + win32_main_window.window_handle, + 0, + 0, + PM_REMOVE) + ){ + win32_window_handle_event(window_msg, &win32_main_window, state); + } + + lumenarium_frame(state); + + // Swap Render Buffers + SwapBuffers(win32_main_window.dc); + + //////////////////////////////////////// + // Maintain Frame Rate + + Platform_Ticks ticks_end = platform_get_ticks(); + r64 seconds_elapsed = get_seconds_elapsed(ticks_start, ticks_end); + while (seconds_elapsed < target_seconds_per_frame) + { + u32 sleep_time = (u32)(1000.0f * (target_seconds_per_frame - seconds_elapsed)); + Sleep(sleep_time); + + ticks_end = platform_get_ticks(); + seconds_elapsed = get_seconds_elapsed(ticks_start, ticks_end); + } + ticks_start = ticks_end; + } + + lumenarium_cleanup(state); + + + // threads cleanup + for (u32 i = 1; i < win32_threads_cap; i++) + { + if (win32_threads[i] == INVALID_HANDLE_VALUE) continue; + TerminateThread(win32_threads[i], 0); + } + + ExitProcess(0); +} + diff --git a/src_v2/platform/win32/lumenarium_win32_file.cpp b/src_v2/platform/win32/lumenarium_win32_file.cpp new file mode 100644 index 0000000..344e785 --- /dev/null +++ b/src_v2/platform/win32/lumenarium_win32_file.cpp @@ -0,0 +1,258 @@ +#define win32_open_files_cap 32 +char win32_open_file_paths[win32_open_files_cap][MAX_PATH]; +u64 win32_open_files_len = 1; // zero is invalid +HANDLE win32_open_files[win32_open_files_cap]; + +void +win32_files_init() +{ + for (u32 i = 0; i < win32_open_files_cap; i++) + { + win32_open_files[i] = INVALID_HANDLE_VALUE; + } +} + +HANDLE +win32_get_open_file_handle(Platform_File_Handle file) +{ + return win32_open_files[file.value]; +} + +internal u64 +win32_high_low_to_u64(u32 low_part, u32 high_part) +{ + ULARGE_INTEGER Time = {}; + Time.LowPart = low_part; + Time.HighPart = high_part; + u64 result = Time.QuadPart; + return result; +} + +internal u64 +win32_file_time_to_u64(FILETIME file_time) +{ + return win32_high_low_to_u64(file_time.dwLowDateTime, file_time.dwHighDateTime); +} + +Platform_File_Handle +platform_file_open(String path, Platform_File_Access_Flags flags_access, Platform_File_Create_Flags flags_create) +{ + Platform_File_Handle result = {}; + + DWORD flags_create_ = OPEN_EXISTING; + + HANDLE file_handle = CreateFileA( + (char*)path.str, + (DWORD)flags_access, + 0, // share mode + NULL, // security attributes + (DWORD)flags_create, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (file_handle != INVALID_HANDLE_VALUE) + { + if (win32_open_files_len < win32_open_files_cap) + { + result.value = win32_open_files_len++; + } + else + { + // search for emtpy index + for (u32 i = 1; i < win32_open_files_cap; i++) + { + if (win32_open_files[i] == INVALID_HANDLE_VALUE) + { + result.value = i; + } + } + } + + assert(result.value != 0); + win32_open_files[result.value] = file_handle; + + memory_copy(path.str, (u8*)win32_open_file_paths[result.value], path.len); + win32_open_file_paths[result.value][path.len] = 0; // null term + } + else + { + win32_get_last_error(); + } + + return result; +} + +void +platform_file_close(Platform_File_Handle file_handle) +{ + assert(file_handle.value < win32_open_files_len); + CloseHandle(win32_get_open_file_handle(file_handle)); + win32_open_files[file_handle.value] = INVALID_HANDLE_VALUE; +} + +u64 +win32_get_file_size(HANDLE h) +{ + DWORD size_low, size_high; + size_low = GetFileSize(h, &size_high); + if (size_low == INVALID_FILE_SIZE) + { + win32_get_last_error(); + return 0; + } + LARGE_INTEGER win32_size; + win32_size.LowPart = size_low; + win32_size.HighPart = size_high; + return (u64)win32_size.QuadPart; +} + +Platform_File_Info +platform_file_get_info(Platform_File_Handle file_handle, Allocator* allocator) +{ + Platform_File_Info result = {}; + HANDLE h = win32_get_open_file_handle(file_handle); + if (h == INVALID_HANDLE_VALUE) return result; + + // File Size + u64 win32_size = win32_get_file_size(h); + if (win32_size == 0 && win32_last_error != 0) return result; + + // File Times + FILETIME time_created, time_last_write; + if (!GetFileTime(h, &time_created, (LPFILETIME)0, &time_last_write)) + { + win32_get_last_error(); + return result; + } + + // File Path + // call GetFullPathName with empty dest just to get the length needed + DWORD file_name_len_needed = GetFullPathName( + win32_open_file_paths[file_handle.value], 0, 0, 0 + ); + if (!file_name_len_needed) + { + win32_get_last_error(); + return result; + } + + result.path = allocator_alloc_string(allocator, (u64)file_name_len_needed); + result.path.len = (u64)GetFullPathName( + win32_open_file_paths[file_handle.value], + (DWORD)result.path.cap, + (char*)result.path.str, + 0 + ); + result.path_abs = result.path; + + // File Attributes + DWORD file_attrs = GetFileAttributesA((char*)result.path.str); + if (!file_attrs) + { + win32_get_last_error(); + return result; + } + + result.size = win32_size; + result.time_created = win32_file_time_to_u64(time_created); + result.time_last_write = win32_file_time_to_u64(time_last_write); + + if (has_flag(file_attrs, FILE_ATTRIBUTE_DIRECTORY)) + { + add_flag(result.flags, FileFlag_IsDir); + } + + return result; +} + +Data +platform_file_read_all(Platform_File_Handle file_handle, Allocator* allocator) +{ + Data result = {}; + + HANDLE h = win32_get_open_file_handle(file_handle); + if (h == INVALID_HANDLE_VALUE) return result; + + u64 file_size = win32_get_file_size(h); + if (file_size == 0 && win32_last_error != 0) return result; + + result.base = allocator_alloc(allocator, file_size + 1); + result.size = file_size + 1; + + DWORD bytes_read = 0; + if (ReadFile(h, (void*)result.base, (DWORD)result.size, &bytes_read, NULL)) + { + result.base[result.size - 1] = 0; + } + else + { + win32_get_last_error(); + } + + return result; +} + +bool +platform_file_write_all(Platform_File_Handle file_handle, Data file_data) +{ + bool result = false; + + HANDLE h = win32_get_open_file_handle(file_handle); + if (h == INVALID_HANDLE_VALUE) return result; + + // Set file pointer to beginning + SetFilePointer(h, 0, 0, FILE_BEGIN); + + DWORD bytes_written = 0; + if (WriteFile(h, file_data.base, (DWORD)file_data.size, &bytes_written, NULL)) + { + result = (bytes_written == file_data.size); + } + + return result; +} + +void +platform_dir_enum_(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator, Platform_File_Info_List* list) +{ + WIN32_FIND_DATA ffd; + HANDLE search_handle = FindFirstFile((char*)path.str, &ffd); + if (search_handle != INVALID_HANDLE_VALUE) + { + do + { + Platform_File_Info_List_Ele* ele = allocator_alloc_struct( + allocator, Platform_File_Info_List_Ele + ); + + sll_push(list->first, list->last, ele); + } while (FindNextFile(search_handle, &ffd)); + } +} + +Platform_File_Info_List +platform_dir_enum(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator) +{ + Platform_File_Info_List result = {}; + platform_dir_enum_(path, flags, allocator, &result); + return result; +} + +String +platform_get_exe_path(Allocator* allocator) +{ + String result = allocator_alloc_string(allocator, (u64)MAX_PATH); + result.len = (u64)GetModuleFileName(NULL, (char*)result.str, (DWORD)result.cap); + if (!result.len) return result; + + return result; +} + +bool +platform_pwd_set(String path) +{ + bool result = SetCurrentDirectory((char*)path.str); + if (!result) win32_get_last_error(); + return result; +} diff --git a/src_v2/platform/win32/lumenarium_win32_memory.cpp b/src_v2/platform/win32/lumenarium_win32_memory.cpp new file mode 100644 index 0000000..8a82089 --- /dev/null +++ b/src_v2/platform/win32/lumenarium_win32_memory.cpp @@ -0,0 +1,43 @@ +#define WIN32_PAGE_SIZE KB(4) + +u64 platform_page_size() { return WIN32_PAGE_SIZE; } + +u8* +platform_mem_reserve(u64 size) +{ + size_t size_cvt = (size_t)size_to_pages(size); + DWORD alloc_type = MEM_RESERVE; + DWORD protection = PAGE_READWRITE; + u8* result = (u8*)VirtualAlloc(0, size_cvt, alloc_type, protection); + if (!result) win32_get_last_error(); + return result; +} + +u8* +platform_mem_commit(u8* base, u64 size) +{ + size_t size_cvt = (size_t)size_to_pages(size); + DWORD alloc_type = MEM_COMMIT; + DWORD protection = PAGE_READWRITE; + u8* result = (u8*)VirtualAlloc(base, size_cvt, alloc_type, protection); + if (!result) win32_get_last_error(); + return result; +} + +bool +platform_mem_decommit(u8* base, u64 size) +{ + DWORD free_type = MEM_DECOMMIT; + bool result = VirtualFree(base, (size_t)size, free_type); + if (!result) win32_get_last_error(); + return result; +} + +bool +platform_mem_release(u8* base, u64 size) +{ + DWORD free_type = MEM_RELEASE; + bool result = VirtualFree(base, size, free_type); + if (!result) win32_get_last_error(); + return result; +} diff --git a/src_v2/platform/win32/lumenarium_win32_thread.cpp b/src_v2/platform/win32/lumenarium_win32_thread.cpp new file mode 100644 index 0000000..2285b4c --- /dev/null +++ b/src_v2/platform/win32/lumenarium_win32_thread.cpp @@ -0,0 +1,93 @@ + +#define win32_threads_cap 9 +global u32 win32_threads_len = 1; +global HANDLE win32_threads[win32_threads_cap]; +global Platform_Thread_Data win32_threads_data[win32_threads_cap]; + +DWORD WINAPI +win32_thread_wrapper(void* d) +{ + Platform_Thread_Result result = {}; + Platform_Thread_Data* thread_data = (Platform_Thread_Data*)d; + thread_data->thread_id = GetCurrentThreadId(); + if (thread_data->thread_proc) + { + result = thread_data->thread_proc(thread_data); + } + return result.code; +} + +void +win32_threads_init() +{ + for (u32 i = 1; i < win32_threads_cap; i++) win32_threads[i] = INVALID_HANDLE_VALUE; +} + +void +win32_threads_reclaim() +{ + u32 highest_valid = 0; + for (u32 i = 1; i < win32_threads_cap; i++) + { + if (win32_threads[i] != INVALID_HANDLE_VALUE) + { + highest_valid = i; + } + } + + win32_threads_len = highest_valid + 1; +} + +Platform_Thread_Handle +platform_thread_begin(Platform_Thread_Proc* proc, u8* user_data) +{ + Platform_Thread_Handle result = {}; + if (win32_threads_len < win32_threads_cap) + { + result.value = win32_threads_len++; + } + else + { + for (u32 i = 1; i < win32_threads_cap; i++) + { + if (win32_threads[i] == INVALID_HANDLE_VALUE) + { + result.value = i; + break; + } + } + } + assert(result.value != 0); + + Platform_Thread_Data* thread_data = &win32_threads_data[result.value]; + thread_data->thread_handle = result; + thread_data->thread_proc = proc; + thread_data->user_data = user_data; + + HANDLE thread_handle = CreateThread( + 0, 0, win32_thread_wrapper, (void*)thread_data, 0, 0 + ); + win32_threads[result.value] = thread_handle; + + return result; +} + +void +platform_thread_end(Platform_Thread_Handle thread) +{ + HANDLE thread_handle = win32_threads[thread.value]; + TerminateThread(thread_handle, 0); + win32_threads[thread.value] = INVALID_HANDLE_VALUE; +} + +u32 +platform_interlocked_increment(volatile u32* value) +{ + return InterlockedIncrement((LONG volatile*)value); +} + +u32 +platform_interlocked_cmp_exchg(volatile u32* dest, u32 new_value, u32 old_value) +{ + return InterlockedCompareExchange((LONG volatile*)dest, new_value, old_value); +} diff --git a/src_v2/platform/win32/lumenarium_win32_time.cpp b/src_v2/platform/win32/lumenarium_win32_time.cpp new file mode 100644 index 0000000..6bd090c --- /dev/null +++ b/src_v2/platform/win32/lumenarium_win32_time.cpp @@ -0,0 +1,48 @@ + +// set by calling win32_get_performance_frequency() +global s64 win32_performance_counter_freq_s64 = 0; +global r64 win32_performance_counter_freq_r64 = 0; + +s64 +win32_get_performance_frequency() +{ + LARGE_INTEGER freq; + if (!QueryPerformanceFrequency(&freq)) + { + win32_get_last_error(); + // TODO(Peter): I'm waiting to see an error actually occur here + // to know what it could possibly be. + invalid_code_path; + } + return (s64)freq.QuadPart; +} + +void +win32_time_init() +{ + win32_performance_counter_freq_s64 = win32_get_performance_frequency(); + win32_performance_counter_freq_r64 = (r64)win32_performance_counter_freq_s64; +} + +Platform_Ticks +platform_get_ticks() +{ + Platform_Ticks result = {}; + LARGE_INTEGER time; + if (!QueryPerformanceCounter(&time)) + { + win32_get_last_error(); + // TODO(Peter): I'm waiting to see an error actually occur here + // to know what it could possibly be. + invalid_code_path; + } + result.value = (s64)time.QuadPart; + return result; +} + +r64 +platform_ticks_to_seconds(Platform_Ticks ticks) +{ + r64 result = (r64)ticks.value / win32_performance_counter_freq_r64; + return result; +} \ No newline at end of file diff --git a/src_v2/platform/win32/lumenarium_win32_window.cpp b/src_v2/platform/win32/lumenarium_win32_window.cpp new file mode 100644 index 0000000..2241d0e --- /dev/null +++ b/src_v2/platform/win32/lumenarium_win32_window.cpp @@ -0,0 +1,203 @@ +typedef u32 Win32_Window_Event_Flags; +enum +{ + WindowEventFlag_None = 0, + WindowEventFlag_CloseRequested = 1, + WindowEventFlag_WindowIsActive = 2, +}; + +struct Win32_Window_OpenGL_Info +{ + BYTE bits_color; + BYTE bits_alpha; + BYTE bits_depth; + + HGLRC rc; +}; + +struct Win32_Window +{ + char* name; + char* class_name; + s32 width; + s32 height; + + WNDCLASS window_class; + WNDPROC window_event_handler; + HWND window_handle; + HDC dc; + + Win32_Window_OpenGL_Info opengl_info; +}; + +////////////////////////////////////////// +// Main Window +// +// At the moment, we only need one window, so this is easier to +// track globally. Replace this if we need more windows + +global Win32_Window_Event_Flags win32_window_event_flags = 0; +global Win32_Window win32_main_window = {}; + +////////////////////////////////////////// +// + +internal Win32_Window +win32_window_create( + HINSTANCE hinstance, + char* window_name, + s32 width, + s32 height, + WNDPROC window_event_handler + ) +{ + Win32_Window result = {}; + result.name = window_name; + result.class_name = window_name; + result.width = width; + result.height = height; + result.window_event_handler = window_event_handler; + + result.window_class = {}; + result.window_class.style = CS_HREDRAW | CS_VREDRAW; + result.window_class.lpfnWndProc = window_event_handler; + result.window_class.hInstance = hinstance; + result.window_class.lpszClassName = window_name; + + if (RegisterClass(&result.window_class)) + { + result.window_handle = CreateWindowEx( + 0, + result.window_class.lpszClassName, + window_name, + WS_OVERLAPPEDWINDOW | WS_VISIBLE, + CW_USEDEFAULT, + CW_USEDEFAULT, + width, + height, + 0, + 0, + hinstance, + 0 + ); + result.dc = GetDC(result.window_handle); + } + + return result; +} + +internal void +win32_window_update_dim(Win32_Window* win) +{ + RECT client_rect; + GetClientRect(win->window_handle, &client_rect); + win->width = client_rect.right - client_rect.left; + win->height = client_rect.bottom - client_rect.top; +} + +LRESULT CALLBACK +win32_window_event_handler(HWND window_handle, UINT msg, WPARAM wparam, LPARAM lparam) +{ + LRESULT result = 0; + + switch (msg) + { + case WM_SIZE: + { + win32_window_update_dim(&win32_main_window); + }break; + + case WM_CLOSE: + { + result = DefWindowProc(window_handle, msg, wparam, lparam); + add_flag(win32_window_event_flags, WindowEventFlag_CloseRequested); + }break; + + case WM_DESTROY: + { + }break; + + case WM_PAINT: + { + PAINTSTRUCT paint_struct; + HDC device_ctx; + b32 paint_result; + + device_ctx = BeginPaint(window_handle, &paint_struct); + paint_result = EndPaint(window_handle, &paint_struct); + }break; + + case WM_ACTIVATE: + { + bool WindowIsActive = ( + LOWORD(wparam) == WA_ACTIVE || LOWORD(wparam) == WA_CLICKACTIVE + ); + if (WindowIsActive) + { + add_flag(win32_window_event_flags, WindowEventFlag_WindowIsActive); + } + else + { + rem_flag(win32_window_event_flags, WindowEventFlag_WindowIsActive); + } + }break; + + default: + { + result = DefWindowProc(window_handle, msg, wparam, lparam); + } + } + + return result; +} + +internal void +win32_window_opengl_ctx_create(Win32_Window* win, Win32_Window_OpenGL_Info info) +{ + // Setup pixel format + { + PIXELFORMATDESCRIPTOR pixel_format_desc = { 0 }; + // TODO: Program seems to work perfectly fine without all other params except dwFlags. + // Can we skip other params for the sake of brevity? + pixel_format_desc.nSize = sizeof(PIXELFORMATDESCRIPTOR); + pixel_format_desc.nVersion = 1; + pixel_format_desc.dwFlags = ( + PFD_SUPPORT_OPENGL | + PFD_DRAW_TO_WINDOW | + PFD_DOUBLEBUFFER + ); + pixel_format_desc.cColorBits = info.bits_color; + pixel_format_desc.cAlphaBits = info.bits_alpha; + pixel_format_desc.cDepthBits = info.bits_depth; + + // TODO(Peter): include these in win32_opengl_window_info? + pixel_format_desc.iPixelType = PFD_TYPE_RGBA; + pixel_format_desc.dwLayerMask = PFD_MAIN_PLANE; + + s32 pixel_fmt = ChoosePixelFormat(win->dc, &pixel_format_desc); + if (!pixel_fmt) { invalid_code_path; } + if (!SetPixelFormat(win->dc, pixel_fmt, &pixel_format_desc)) + { + invalid_code_path; + } + } + + // Create rendering context + { + // TODO: Create "proper" context? + // https://www.opengl.org/wiki/Creating_an_OpenGL_Context_(WGL)#Proper_Context_Creation + + info.rc = wglCreateContext(win->dc); + wglMakeCurrent(win->dc, info.rc); + + // TODO(Peter): do we want this? + /* + glGetIntegerv(GL_MAJOR_VERSION, ); + glGetIntegerv(GL_MINOR_VERSION, ); + (char*)glGetString(GL_VENDOR); + (char*)glGetString(GL_RENDERER); + */ + } + + win->opengl_info = info; +}