This commit is contained in:
PS 2022-03-22 19:13:06 +01:00
parent 5838345c09
commit 56518bdd66
35 changed files with 6024 additions and 226 deletions

6
.gitignore vendored
View File

@ -1,6 +1,10 @@
app_run_tree/
meta_run_tree/
*.exe
*.pdb
*.o
process/
reference/
working_data/
nssm_log.log
nssm_log.log
sysroot/

294
build/build.sh Normal file
View File

@ -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

View File

@ -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

View File

@ -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";

BIN
run_tree/text.txt Normal file

Binary file not shown.

View File

@ -0,0 +1,9 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
</head>
<body>
<script type="text/javascript" src="loader.js"></script>
</body>
</html>

View File

@ -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)
*/

Binary file not shown.

Binary file not shown.

View File

@ -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

View File

@ -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
}

View File

@ -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)
{
}

View File

@ -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);
}

View File

@ -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)
{
}

View File

@ -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

3089
src_v2/libs/HandmadeMath.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
}

48
src_v2/lumenarium_first.h Normal file
View File

@ -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

View File

@ -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);
}

View File

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

View File

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

View File

@ -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);
}

106
src_v2/lumenarium_types.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,36 @@
/* date = March 22nd 2022 2:12 am */
#ifndef LUMENARIUM_PLATFORM_COMMON_INCLUDES_H
#define LUMENARIUM_PLATFORM_COMMON_INCLUDES_H
#include <stdarg.h>
#if !defined(GUESS_INTS)
# include <stdint.h>
#endif // !defined(GUESS_INTS)
#include <math.h>
#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

View File

@ -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 <stdio.h>
#include <stdlib.h>
#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;
}

View File

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

View File

@ -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;

View File

@ -0,0 +1,249 @@
#include "../lumenarium_compiler_flags.h"
#include "../lumenarium_platform_common_includes.h"
#include "windows.h"
#include <gl/gl.h>
#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);
}

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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