Day 1
This commit is contained in:
parent
5838345c09
commit
56518bdd66
|
@ -1,6 +1,10 @@
|
|||
app_run_tree/
|
||||
meta_run_tree/
|
||||
*.exe
|
||||
*.pdb
|
||||
*.o
|
||||
process/
|
||||
reference/
|
||||
working_data/
|
||||
nssm_log.log
|
||||
sysroot/
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
|
|
Binary file not shown.
|
@ -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>
|
|
@ -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.
|
@ -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));
|
||||
Assert(DataIsNonEmpty(Memory));
|
||||
Assert(IsNullTerminated(Path));
|
||||
|
||||
gs_file Result = {0};
|
||||
u32 Error = 0;
|
||||
Result.FileInfo.Path = 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)
|
||||
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;
|
||||
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);
|
||||
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));
|
||||
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)
|
||||
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 = {};
|
||||
FILETIME Result = {};
|
||||
|
||||
WIN32_FIND_DATA FindData = {};
|
||||
HANDLE FileHandle = FindFirstFileA(Path, &FindData);
|
||||
WIN32_FIND_DATA FindData = {};
|
||||
HANDLE FileHandle = FindFirstFileA(Path, &FindData);
|
||||
|
||||
if (FileHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Result = FindData.ftLastWriteTime;
|
||||
FindClose(FileHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO(Peter): :ErrorLogging
|
||||
}
|
||||
if (FileHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Result = FindData.ftLastWriteTime;
|
||||
FindClose(FileHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO(Peter): :ErrorLogging
|
||||
}
|
||||
|
||||
return Result;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
// 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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
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)
|
||||
WIN32_FIND_DATA FindFileData;
|
||||
HANDLE SearchHandle = FindFirstFile(Path.Str, &FindFileData);
|
||||
if (SearchHandle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
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 (!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);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasFlag(FindFileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY))
|
||||
{
|
||||
gs_const_string SubDirName = ConstString(FindFileData.cFileName);
|
||||
bool IsNav = (StringsEqual(SubDirName, ConstString(".")) ||
|
||||
StringsEqual(SubDirName, ConstString("..")));
|
||||
AddFile = HasFlag(Flags, EnumerateDirectory_IncludeDirectories);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
return FilesCount;
|
||||
}
|
||||
|
||||
ENUMERATE_DIRECTORY(Win32EnumerateDirectory)
|
||||
{
|
||||
Assert(IsNullTerminated(Path));
|
||||
gs_file_info_array Result = {};
|
||||
Assert(IsNullTerminated(Path));
|
||||
gs_file_info_array Result = {};
|
||||
|
||||
temp_file_list TempList = {};
|
||||
Result.MaxCount = Win32EnumerateDirectoryIntoTempList(FileHandler, &TempList, Path, Storage, Flags);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define WIN32_FOLDHAUS_FILEIO_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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue