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;
+}