lumenarium working on OSX
This commit is contained in:
parent
89e92467ae
commit
4ef76dacbe
|
@ -1,3 +1,3 @@
|
|||
SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
$SCRIPT_REL_DIR/build_.sh debug win32 intel
|
||||
$SCRIPT_REL_DIR/build_.sh debug wasm intel
|
||||
$SCRIPT_REL_DIR/build_.sh debug osx arm64
|
||||
# $SCRIPT_REL_DIR/build_.sh debug wasm intel
|
|
@ -83,7 +83,7 @@ popdir
|
|||
# Compiler Selection
|
||||
|
||||
Compiler_win32="cl"
|
||||
Compiler_osx="clang++"
|
||||
Compiler_osx="clang"
|
||||
WasiSdk="/c/drive/apps/wasi-sdk"
|
||||
Compiler_wasm="$WasiSdk/bin/clang++"
|
||||
Compiler_linux="clang++"
|
||||
|
@ -91,7 +91,7 @@ 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_osx="src_v2/platform/osx/lumenarium_first_osx.c"
|
||||
PlatformEntry_wasm="src_v2/platform/wasm/lumenarium_first_wasm.cpp"
|
||||
PlatformEntry_linux="src_v2/platform/linux/lumenarium_first_linux.cpp"
|
||||
|
||||
|
@ -115,60 +115,61 @@ WasmSysRoot="${PROJECT_PATH}/src_v2/platform/wasm/sysroot/"
|
|||
# Compiler Flags
|
||||
|
||||
CompilerFlags_win32="-nologo"
|
||||
add_flag CompilerFlags_win32 "-FC" # display errors with full path
|
||||
add_flag CompilerFlags_win32 "-WX" # treat warnings as errors
|
||||
add_flag CompilerFlags_win32 "-W4" # output warning level
|
||||
add_flag CompilerFlags_win32 "-Z7" # generate C compatible debug info
|
||||
# add_flag CompilerFlags_win32 "-Oi" # generate intrinsic functions
|
||||
# add_flag CompilerFlags_win32 "-MTd" # create a debug multithreaded exe w/ Libcmtd.lib
|
||||
# add_flag CompilerFlags_win32 "-fp:fast" # fast floating point model
|
||||
add_flag CompilerFlags_win32 "-wd4505" #
|
||||
add_flag CompilerFlags_win32 "-wd4100" #
|
||||
add_flag CompilerFlags_win32 "-wd4189" #
|
||||
add_flag CompilerFlags_win32 "-wd4702" #
|
||||
add_flag CompilerFlags_win32 "-wd4996" # _CRT_SECURE_NO_WARNINGS
|
||||
CompilerFlags_win32+=" -FC" # display errors with full path
|
||||
CompilerFlags_win32+=" -WX" # treat warnings as errors
|
||||
CompilerFlags_win32+=" -W4" # output warning level
|
||||
CompilerFlags_win32+=" -Z7" # generate C compatible debug info
|
||||
# CompilerFlags_win32+="-Oi" # generate intrinsic functions
|
||||
# CompilerFlags_win32+="-MTd" # create a debug multithreaded exe w/ Libcmtd.lib
|
||||
# CompilerFlags_win32+="-fp:fast" # fast floating point model
|
||||
CompilerFlags_win32+=" -wd4505" #
|
||||
CompilerFlags_win32+=" -wd4100" #
|
||||
CompilerFlags_win32+=" -wd4189" #
|
||||
CompilerFlags_win32+=" -wd4702" #
|
||||
CompilerFlags_win32+=" -wd4996" # _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
CompilerFlags_osx=""
|
||||
|
||||
CompilerFlags_wasm=""
|
||||
add_flag CompilerFlags_wasm "-Wno-writable-strings" #
|
||||
add_flag CompilerFlags_wasm "--target=wasm32" #
|
||||
add_flag CompilerFlags_wasm "-nostdlib" #
|
||||
add_flag CompilerFlags_wasm "-Wl,--no-entry" #
|
||||
add_flag CompilerFlags_wasm "-Wl,--allow-undefined" #
|
||||
add_flag CompilerFlags_wasm "-Wl,--export-all" #
|
||||
CompilerFlags_wasm+=" -Wno-writable-strings" #
|
||||
CompilerFlags_wasm+=" --target=wasm32" #
|
||||
CompilerFlags_wasm+=" -nostdlib" #
|
||||
CompilerFlags_wasm+=" -Wl,--no-entry" #
|
||||
CompilerFlags_wasm+=" -Wl,--allow-undefined" #
|
||||
CompilerFlags_wasm+=" -Wl,--export-all" #
|
||||
|
||||
CompilerFlags_linux=""
|
||||
|
||||
CompilerFlags_DEBUG_win32=""
|
||||
add_flag CompilerFlags_DEBUG_win32 "-Od" #
|
||||
add_flag CompilerFlags_DEBUG_win32 "-Zi" #
|
||||
add_flag CompilerFlags_DEBUG_win32 "-DDEBUG" #
|
||||
CompilerFlags_DEBUG_win32+=" -Od" #
|
||||
CompilerFlags_DEBUG_win32+=" -Zi" #
|
||||
CompilerFlags_DEBUG_win32+=" -DDEBUG" #
|
||||
# add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS"
|
||||
|
||||
CompilerFlags_DEBUG="-O0"
|
||||
add_flag CompilerFlags_DEBUG "-g" #
|
||||
add_flag CompilerFlags_DEBUG "-DDEBUG" #
|
||||
CompilerFlags_DEBUG+=" -g" #
|
||||
CompilerFlags_DEBUG+=" -DDEBUG" #
|
||||
CompilerFlags_DEBUG+=" -fsanitize=address" #address sanitizer
|
||||
|
||||
CompilerFlags_PROD="-O3"
|
||||
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}=1 -DMODE_${MODE}=1 -DARCH_${ARCH}=1"
|
||||
CompilerFlags_common=" -DPLATFORM_${PLATFORM}=1 -DMODE_${MODE}=1 -DARCH_${ARCH}=1"
|
||||
|
||||
# Linker Flags
|
||||
|
||||
LinkerFlags_win32="-NOLOGO"
|
||||
add_flag LinkerFlags_win32 "-incremental:no" #
|
||||
add_flag LinkerFlags_win32 "-subsystem:windows" #
|
||||
LinkerFlags_win32=" -NOLOGO"
|
||||
LinkerFlags_win32+=" -incremental:no" #
|
||||
LinkerFlags_win32+=" -subsystem:windows" #
|
||||
# add_flag LinkerFlags_win32 "-entry:WinMain" #
|
||||
add_flag LinkerFlags_win32 "-opt:ref" # eliminate functions that are never referenced
|
||||
LinkerFlags_win32+=" -opt:ref" # eliminate functions that are never referenced
|
||||
|
||||
LinkerFlags_osx=""
|
||||
|
||||
LinkerFlags_wasm="--no-entry"
|
||||
add_flag LinkerFlags_wasm "--export-dynamic" #
|
||||
add_flag LinkerFlags_wasm "--unresolved-symbols=import-functions" #
|
||||
LinkerFlags_wasm+=" --export-dynamic" #
|
||||
LinkerFlags_wasm+=" --unresolved-symbols=import-functions" #
|
||||
|
||||
LinkerFlags_linux=""
|
||||
|
||||
|
@ -180,7 +181,7 @@ LinkerFlags_PROD=""
|
|||
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_osx="-framework OpenGL -framework Cocoa -framework IOKit ${PROJECT_PATH}/src_v2/libs/glfw_osx/lib-universal/libglfw3.a"
|
||||
LinkerLibs_wasm=""
|
||||
LinkerLibs_linux=""
|
||||
|
||||
|
@ -320,6 +321,7 @@ then
|
|||
./lumenarium_wasm_imports.js
|
||||
|
||||
else
|
||||
echo "$Compiler -o $LinkerOutput $CompilerFlags $EntryPath $LinkerLibs"
|
||||
$Compiler -o $LinkerOutput $CompilerFlags $EntryPath $LinkerLibs
|
||||
|
||||
fi
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,44 @@
|
|||
// NOTE(PS):
|
||||
// need to include before this:
|
||||
// #include <stdarg.h>
|
||||
// #include <stdint.h>
|
||||
// #include <math.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
|
||||
|
||||
#if defined(DEBUG)
|
||||
# define USE_ASSERTS 1
|
||||
#endif
|
||||
|
||||
#include "lumenarium_core_assert.h"
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#define STB_SPRINTF_IMPLEMENTATION
|
||||
#define STBTT_assert(x) assert(x)
|
||||
#include "../libs/stb_truetype.h"
|
||||
#include "../libs/stb_sprintf.h"
|
||||
|
||||
#define HANDMADE_MATH_IMPLEMENTATION
|
||||
#define HANDMADE_MATH_STATIC
|
||||
#include "../libs/HandmadeMath.h"
|
||||
typedef hmm_v2 v2;
|
||||
typedef hmm_v3 v3;
|
||||
typedef hmm_v4 v4;
|
||||
typedef hmm_mat4 m44;
|
||||
|
||||
#include "lumenarium_core_types.h"
|
||||
#include "lumenarium_core_memory.h"
|
||||
#include "lumenarium_core_string.h"
|
||||
#include "lumenarium_core_hash.h"
|
||||
#include "lumenarium_core_random.h"
|
||||
|
||||
#include "lumenarium_core_file.h"
|
||||
#include "lumenarium_core_window.h"
|
||||
#include "lumenarium_core_time.h"
|
||||
#include "lumenarium_core_threads.h"
|
||||
#include "lumenarium_core_socket.h"
|
|
@ -0,0 +1,60 @@
|
|||
/* date = March 26th 2022 3:42 pm */
|
||||
|
||||
#ifndef LUMENARIUM_CORE_ASSERT_H
|
||||
#define LUMENARIUM_CORE_ASSERT_H
|
||||
|
||||
#if defined(PRINT_ASSERTS)
|
||||
# include <stdio.h>
|
||||
# define err_write(s,...) err_write_(s,__VA_ARGS__)
|
||||
static FILE* file_err;
|
||||
void err_write_(char* fmt, ...) {
|
||||
if (!file_err) return;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vfprintf(file_err, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
void open_err_file() { file_err = fopen("./err.txt", "wb"); }
|
||||
void close_err_file() { fclose(file_err); }
|
||||
#else
|
||||
# define err_write(s,...)
|
||||
void open_err_file() {}
|
||||
void close_err_file() {}
|
||||
#endif
|
||||
|
||||
#if !defined(PLATFORM_wasm)
|
||||
|
||||
// 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 int*)0) = 0xFFFF)
|
||||
|
||||
#else
|
||||
WASM_EXTERN void wasm_assert_always(char* file, unsigned int file_len, unsigned int line);
|
||||
# define assert_always wasm_assert_always(__FILE__, sizeof(__FILE__), __LINE__)
|
||||
#endif // defined(PLATFORM_WASM)
|
||||
|
||||
#ifdef USE_ASSERTS
|
||||
# define assert(c) do { \
|
||||
if (!(c)) { \
|
||||
err_write("Assert Hit: %s:%u\n", __FILE__, (u32)__LINE__); \
|
||||
close_err_file(); \
|
||||
assert_always; \
|
||||
} \
|
||||
} while(false)
|
||||
|
||||
// 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(0);
|
||||
|
||||
// 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(0); } break;
|
||||
|
||||
#else
|
||||
# define assert(c)
|
||||
# define invalid_code_path
|
||||
# define invalid_default_case default: { } break;
|
||||
#endif
|
||||
|
||||
#endif //LUMENARIUM_CORE_ASSERT_H
|
|
@ -0,0 +1,252 @@
|
|||
#if !defined(LUMENARIUM_CORE_FILE_H)
|
||||
#define LUMENARIUM_CORE_FILE_H
|
||||
|
||||
typedef struct File_Handle File_Handle;
|
||||
struct File_Handle
|
||||
{
|
||||
u64 value;
|
||||
};
|
||||
|
||||
typedef u32 File_Access_Flags;
|
||||
enum
|
||||
{
|
||||
FileAccess_None = 0,
|
||||
FileAccess_Read = 1,
|
||||
FileAccess_Write = 2,
|
||||
};
|
||||
|
||||
typedef u32 File_Create_Flags;
|
||||
enum
|
||||
{
|
||||
// these match https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
|
||||
FileCreate_None = 0,
|
||||
|
||||
// Creates a new file, only if it does not already exist.
|
||||
// If the file exists, an error is returned
|
||||
FileCreate_New = 1,
|
||||
|
||||
// Creates a new file, always.
|
||||
// If the specified file exists and is writable, the file is overwritten
|
||||
FileCreate_CreateAlways = 2,
|
||||
|
||||
// Opens a file or device, only if it exists.
|
||||
FileCreate_OpenExisting = 3,
|
||||
|
||||
// Opens a file, always.
|
||||
FileCreate_OpenAlways = 4,
|
||||
};
|
||||
|
||||
typedef u32 File_Flags;
|
||||
enum
|
||||
{
|
||||
FileFlag_IsFile = 0,
|
||||
FileFlag_IsDir = 1,
|
||||
};
|
||||
|
||||
typedef struct File_Info File_Info;
|
||||
struct File_Info
|
||||
{
|
||||
String path;
|
||||
String path_abs;
|
||||
u64 size;
|
||||
u64 time_created;
|
||||
u64 time_last_write;
|
||||
File_Flags flags;
|
||||
};
|
||||
|
||||
typedef struct File_Info_List_Ele File_Info_List_Ele;
|
||||
struct File_Info_List_Ele
|
||||
{
|
||||
File_Info info;
|
||||
File_Info_List_Ele* next;
|
||||
};
|
||||
|
||||
typedef struct File_Info_List File_Info_List;
|
||||
struct File_Info_List
|
||||
{
|
||||
File_Info_List_Ele* first;
|
||||
File_Info_List_Ele* last;
|
||||
};
|
||||
|
||||
// For Cross Platform File Operations use these:
|
||||
|
||||
typedef u32 File_Async_Job_Flags;
|
||||
enum
|
||||
{
|
||||
FileAsyncJob_Invalid = 0,
|
||||
FileAsyncJob_Read = 1 << 0,
|
||||
FileAsyncJob_Write = 1 << 1,
|
||||
FileAsyncJob_InFlight = 1 << 2,
|
||||
FileAsyncJob_Success = 1 << 3,
|
||||
FileAsyncJob_Failed = 1 << 4,
|
||||
};
|
||||
|
||||
typedef struct File_Async_Job_Args File_Async_Job_Args;
|
||||
struct File_Async_Job_Args
|
||||
{
|
||||
String path;
|
||||
Data data;
|
||||
File_Async_Job_Flags flags;
|
||||
u32 error;
|
||||
};
|
||||
|
||||
typedef void File_Async_Cb(File_Async_Job_Args args, u8* user_data);
|
||||
|
||||
typedef struct File_Async_Job File_Async_Job;
|
||||
struct File_Async_Job
|
||||
{
|
||||
Data job_memory;
|
||||
File_Async_Job_Args args;
|
||||
File_Async_Cb* cb;
|
||||
};
|
||||
|
||||
typedef void File_Async_Job_System_Do_Job(File_Async_Job* job);
|
||||
|
||||
typedef struct File_Async_Job_System File_Async_Job_System;
|
||||
struct File_Async_Job_System
|
||||
{
|
||||
File_Async_Job_System_Do_Job* do_job;
|
||||
};
|
||||
|
||||
global Allocator* file_jobs_arena = 0;
|
||||
#define FILE_ASYNC_MAX_JOBS 32
|
||||
global File_Async_Job file_async_jobs[FILE_ASYNC_MAX_JOBS];
|
||||
global u32 file_async_jobs_len = 0;
|
||||
|
||||
internal File_Async_Job_System file_async_jobs_init(File_Async_Job_System_Do_Job* do_job);
|
||||
internal bool file_async_job_add(File_Async_Job job);
|
||||
internal File_Async_Job file_async_job_rem(u64 index);
|
||||
internal bool file_async_read(String path, File_Async_Cb* cb);
|
||||
internal bool file_async_write(String path, Data data, File_Async_Cb* cb);
|
||||
internal void file_async_job_complete(File_Async_Job* job, u8* user_data);
|
||||
internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data);
|
||||
internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data);
|
||||
|
||||
typedef u32 Platform_Enum_Dir_Flags;
|
||||
enum
|
||||
{
|
||||
EnumDir_Recursive = 1,
|
||||
EnumDir_IncludeDirectories = 2,
|
||||
};
|
||||
|
||||
///////////////////////////////////////
|
||||
///////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
///////////////////////////////////////
|
||||
///////////////////////////////////////
|
||||
|
||||
internal File_Async_Job_System
|
||||
file_async_jobs_init(File_Async_Job_System_Do_Job* do_job)
|
||||
{
|
||||
file_jobs_arena = paged_allocator_create_reserve(MB(4), 256);
|
||||
File_Async_Job_System result = {};
|
||||
result.do_job = do_job;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool
|
||||
file_async_job_add(File_Async_Job job)
|
||||
{
|
||||
if (file_async_jobs_len >= FILE_ASYNC_MAX_JOBS) return false;
|
||||
|
||||
// Copy data to job local memory
|
||||
u64 size_needed = job.args.path.len + job.args.data.size + 1;
|
||||
u8* job_mem = allocator_alloc(file_jobs_arena, size_needed);
|
||||
String job_path = string_create(job_mem, 0, job.args.path.len + 1);
|
||||
u64 copied = string_copy_to(&job_path, job.args.path);
|
||||
Data job_data = data_create(job_mem + job_path.cap + 1, size_needed - (job_path.cap + 1));
|
||||
memory_copy(job.args.data.base, job_data.base, job.args.data.size);
|
||||
job.args.path = job_path;
|
||||
job.args.data = job_data;
|
||||
job.job_memory = data_create(job_mem, size_needed);
|
||||
|
||||
file_async_jobs[file_async_jobs_len++] = job;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal File_Async_Job
|
||||
file_async_job_rem(u64 index)
|
||||
{
|
||||
assert(index < file_async_jobs_len);
|
||||
File_Async_Job result = file_async_jobs[index];
|
||||
|
||||
file_async_jobs_len -= 1;
|
||||
if (file_async_jobs_len > 0)
|
||||
{
|
||||
u32 last_job = file_async_jobs_len;
|
||||
file_async_jobs[index] = file_async_jobs[last_job];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool
|
||||
file_async_read(String path, File_Async_Cb* cb)
|
||||
{
|
||||
File_Async_Job job = {};
|
||||
job.args.path = path;
|
||||
job.args.flags = (
|
||||
FileAsyncJob_Read |
|
||||
FileAsyncJob_InFlight
|
||||
);
|
||||
job.cb = cb;
|
||||
bool result = file_async_job_add(job);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal bool
|
||||
file_async_write(String path, Data data, File_Async_Cb* cb)
|
||||
{
|
||||
File_Async_Job job = {};
|
||||
job.args.path = path;
|
||||
job.args.data = data;
|
||||
job.args.flags = (
|
||||
FileAsyncJob_Write |
|
||||
FileAsyncJob_InFlight
|
||||
);
|
||||
job.cb = cb;
|
||||
bool result = file_async_job_add(job);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
file_async_job_complete(File_Async_Job* job, u8* user_data)
|
||||
{
|
||||
job->cb(job->args, user_data);
|
||||
allocator_free(file_jobs_arena, job->job_memory.base, job->job_memory.size);
|
||||
if (has_flag(job->args.flags, FileAsyncJob_Write))
|
||||
{
|
||||
allocator_free(file_jobs_arena, job->args.data.base, job->args.data.size);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data)
|
||||
{
|
||||
assert(system->do_job);
|
||||
|
||||
u64 to_do = max_jobs;
|
||||
if (max_jobs > file_async_jobs_len) to_do = file_async_jobs_len;
|
||||
|
||||
File_Async_Job_Flags completed = (
|
||||
FileAsyncJob_Success |
|
||||
FileAsyncJob_Failed
|
||||
);
|
||||
|
||||
for (u64 i = to_do - 1; i < to_do; i--)
|
||||
{
|
||||
File_Async_Job* job = file_async_jobs + i;
|
||||
system->do_job(job);
|
||||
if (has_flag(job->args.flags, completed))
|
||||
{
|
||||
if (has_flag_exact(job->args.flags, FileAsyncJob_Success))
|
||||
{
|
||||
file_async_job_complete(job, user_data);
|
||||
}
|
||||
file_async_job_rem(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // LUMENARIUM_CORE_FILE_H
|
|
@ -1,14 +1,14 @@
|
|||
/* date = April 1st 2022 7:29 pm */
|
||||
|
||||
#ifndef LUMENARIUM_HASH_CPP
|
||||
#define LUMENARIUM_HASH_CPP
|
||||
#ifndef LUMENARIUM_CORE_HASH_H
|
||||
#define LUMENARIUM_CORE_HASH_H
|
||||
|
||||
//
|
||||
// DJB2
|
||||
// Source: http://www.cse.yorku.ca/~oz/hash.html
|
||||
|
||||
internal u32
|
||||
hash_djb2_to_u32(char* str, u64 len)
|
||||
hash_djb2_str_to_u32(char* str, u64 len)
|
||||
{
|
||||
u32 result = 5381;
|
||||
for (u64 i = 0; i < len; i++)
|
||||
|
@ -19,20 +19,20 @@ hash_djb2_to_u32(char* str, u64 len)
|
|||
}
|
||||
|
||||
internal u32
|
||||
hash_djb2_to_u32(char* str)
|
||||
hash_djb2_cstr_to_u32(char* str)
|
||||
{
|
||||
u64 len = c_str_len(str);
|
||||
return hash_djb2_to_u32(str, len);
|
||||
return hash_djb2_str_to_u32(str, len);
|
||||
}
|
||||
|
||||
internal u32
|
||||
hash_djb2_to_u32(String str)
|
||||
hash_djb2_string_to_u32(String str)
|
||||
{
|
||||
return hash_djb2_to_u32((char*)str.str, str.len);
|
||||
return hash_djb2_str_to_u32((char*)str.str, str.len);
|
||||
}
|
||||
|
||||
internal u64
|
||||
hash_djb2_to_u64(char* str, u64 len)
|
||||
hash_djb2_str_to_u64(char* str, u64 len)
|
||||
{
|
||||
u64 result = 5381;
|
||||
for (u64 i = 0; i < len; i++)
|
||||
|
@ -43,16 +43,16 @@ hash_djb2_to_u64(char* str, u64 len)
|
|||
}
|
||||
|
||||
internal u64
|
||||
hash_djb2_to_u64(char* str)
|
||||
hash_djb2_cstr_to_u64(char* str)
|
||||
{
|
||||
u64 len = c_str_len(str);
|
||||
return hash_djb2_to_u64(str, len);
|
||||
return hash_djb2_str_to_u64(str, len);
|
||||
}
|
||||
|
||||
internal u64
|
||||
hash_djb2_to_u64(String str)
|
||||
hash_djb2_string_to_u64(String str)
|
||||
{
|
||||
return hash_djb2_to_u64((char*)str.str, str.len);
|
||||
return hash_djb2_str_to_u64((char*)str.str, str.len);
|
||||
}
|
||||
|
||||
#endif //LUMENARIUM_HASH_CPP
|
||||
#endif //LUMENARIUM_HASH_H
|
|
@ -0,0 +1,802 @@
|
|||
#ifndef LUMENARIUM_CORE_MEMORY_H
|
||||
#define LUMENARIUM_CORE_MEMORY_H
|
||||
|
||||
#if !defined(OS_MEM_PAGE_SIZE)
|
||||
# error "You must define OS_MEM_PAGE_SIZE for core_memory.h to compile properly"
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Memory Helpers
|
||||
|
||||
#define Bytes(x) (x)
|
||||
#define KB(x) ((x) << 10)
|
||||
#define MB(x) ((x) << 20)
|
||||
#define GB(x) (((u64)x) << 30)
|
||||
#define TB(x) (((u64)x) << 40)
|
||||
|
||||
#define memory_zero_array(b,t,c) memory_zero((u8*)(b), sizeof(t) * (c))
|
||||
internal void memory_zero(u8* base, u64 size);
|
||||
internal void memory_copy(u8* from, u8* to, u64 size);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Data
|
||||
|
||||
#define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF)
|
||||
|
||||
typedef struct Data Data;
|
||||
struct Data
|
||||
{
|
||||
u8* base;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
internal Data
|
||||
data_create(u8* base, u64 size)
|
||||
{
|
||||
Data result = {};
|
||||
result.base = base;
|
||||
result.size = size;
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Data Writer
|
||||
|
||||
typedef struct Data_Writer Data_Writer;
|
||||
struct Data_Writer
|
||||
{
|
||||
Data data;
|
||||
u64 at;
|
||||
};
|
||||
|
||||
// NOTE(PS): functions ending in _b treat data in the Data_Writer as big endian
|
||||
// order (network ordering) where functions ending in _l treat data into little
|
||||
// endian order
|
||||
// It is always assumed that values not in the Data_Writer (ie the other args
|
||||
// to the function or the functions return value) are in little endian order
|
||||
|
||||
internal u8 dw_get_u8(Data_Writer* w);
|
||||
// TODO(PS): get functions
|
||||
|
||||
internal void dw_put_u8(Data_Writer* w, u8 b);
|
||||
internal void dw_put_u16_b(Data_Writer* w, u16 b);
|
||||
internal void dw_put_u16_l(Data_Writer* w, u16 b);
|
||||
internal void dw_put_u32_b(Data_Writer* w, u32 b);
|
||||
internal void dw_put_u32_l(Data_Writer* w, u32 b);
|
||||
internal void dw_put_u64_b(Data_Writer* w, u64 b);
|
||||
internal void dw_put_u64_l(Data_Writer* w, u64 b);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Allocator
|
||||
|
||||
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);
|
||||
typedef void Allocator_Destroy(Allocator* allocator);
|
||||
|
||||
struct Allocator
|
||||
{
|
||||
Allocator_Alloc* alloc;
|
||||
Allocator_Free* free;
|
||||
Allocator_Realloc* realloc;
|
||||
Allocator_Clear* clear;
|
||||
Allocator_Destroy* destroy;
|
||||
|
||||
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)
|
||||
#define allocator_destroy(a) (a)->destroy(a)
|
||||
|
||||
internal Allocator* paged_allocator_create_reserve(u64 reserve_size, u64 page_size);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//////////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
//////////////////////////////////////////////
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////
|
||||
// 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))
|
||||
|
||||
internal void memory_zero(u8* base, u64 size) { memory_zero_(base, size); }
|
||||
internal void memory_copy(u8* from, u8* to, u64 size) {
|
||||
memory_copy_(from, to, size);
|
||||
}
|
||||
|
||||
// @Maintenance - if the function only has one argument, it should become
|
||||
// round_to_os_page_multiple
|
||||
u64
|
||||
round_size_to_page_multiple(u64 size, u64 page_size)
|
||||
{
|
||||
u64 rem = size % page_size;
|
||||
if (rem != 0 || size < page_size)
|
||||
{
|
||||
u64 grow = page_size - rem;
|
||||
size += grow;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
u64
|
||||
round_size_to_os_page_multiple(u64 size)
|
||||
{
|
||||
return round_size_to_page_multiple(size, OS_MEM_PAGE_SIZE);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Data Writer
|
||||
|
||||
internal void
|
||||
dw_put_u8(Data_Writer* w, u8 b)
|
||||
{
|
||||
if (w->at < w->data.size)
|
||||
{
|
||||
w->data.base[w->at++] = b;
|
||||
}
|
||||
}
|
||||
|
||||
internal u8
|
||||
dw_get_u8(Data_Writer* w)
|
||||
{
|
||||
u8 result = 0;
|
||||
if (w->at < w->data.size)
|
||||
{
|
||||
result = w->data.base[w->at++];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u16_b(Data_Writer* w, u16 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u16_l(Data_Writer* w, u16 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u32_b(Data_Writer* w, u32 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 3));
|
||||
dw_put_u8(w, get_byte(b, 2));
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u32_l(Data_Writer* w, u32 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
dw_put_u8(w, get_byte(b, 2));
|
||||
dw_put_u8(w, get_byte(b, 3));
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u64_b(Data_Writer* w, u64 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 7));
|
||||
dw_put_u8(w, get_byte(b, 6));
|
||||
dw_put_u8(w, get_byte(b, 5));
|
||||
dw_put_u8(w, get_byte(b, 4));
|
||||
dw_put_u8(w, get_byte(b, 3));
|
||||
dw_put_u8(w, get_byte(b, 2));
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_u64_l(Data_Writer* w, u64 b)
|
||||
{
|
||||
dw_put_u8(w, get_byte(b, 0));
|
||||
dw_put_u8(w, get_byte(b, 1));
|
||||
dw_put_u8(w, get_byte(b, 2));
|
||||
dw_put_u8(w, get_byte(b, 3));
|
||||
dw_put_u8(w, get_byte(b, 4));
|
||||
dw_put_u8(w, get_byte(b, 5));
|
||||
dw_put_u8(w, get_byte(b, 6));
|
||||
dw_put_u8(w, get_byte(b, 7));
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
internal void
|
||||
allocator_destroy_(Allocator* allocator, u64 custom_data_size)
|
||||
{
|
||||
zero_struct(*allocator);
|
||||
u64 size = sizeof(Allocator) + custom_data_size;
|
||||
os_mem_decommit((u8*)allocator, size);
|
||||
os_mem_release((u8*)allocator, size);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Bump Allocator
|
||||
|
||||
typedef struct Allocator_Bump Allocator_Bump;
|
||||
struct Allocator_Bump
|
||||
{
|
||||
u8* base;
|
||||
u64 at;
|
||||
u64 size_committed;
|
||||
u64 size_reserved;
|
||||
u64 page_size;
|
||||
u64 high_water_mark;
|
||||
};
|
||||
|
||||
#if defined(DEBUG)
|
||||
# define bump_allocator_validate(a) bump_allocator_validate_(a)
|
||||
#else
|
||||
# define bump_allocator_validate(a)
|
||||
#endif
|
||||
internal void
|
||||
bump_allocator_validate_(Allocator* allocator)
|
||||
{
|
||||
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||
assert(bump != 0);
|
||||
if (bump->size_reserved > 0)
|
||||
{
|
||||
assert(bump->base != 0);
|
||||
}
|
||||
assert(bump->at <= bump->size_committed);
|
||||
assert(bump->size_committed <= bump->size_reserved);
|
||||
assert(bump->page_size > 0);
|
||||
assert(bump->high_water_mark <= bump->size_reserved);
|
||||
}
|
||||
|
||||
internal u8*
|
||||
bump_allocator_alloc_inner(Allocator* allocator, Allocator_Bump* bump, u64 size)
|
||||
{
|
||||
bump_allocator_validate(allocator);
|
||||
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)
|
||||
{
|
||||
if (bump->page_size == 0) bump->page_size = OS_MEM_PAGE_SIZE;
|
||||
new_size = bump->page_size;
|
||||
}
|
||||
if (new_size < at_after)
|
||||
{
|
||||
new_size = round_size_to_page_multiple(at_after, bump->page_size);
|
||||
}
|
||||
|
||||
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 = round_size_to_os_page_multiple(bump->at);
|
||||
if (bump->at == 0 && bump->size_committed == 0) next_page = 0;
|
||||
u64 commit_amt = new_size - next_page;
|
||||
u8* new_page = os_mem_commit(bump->base + next_page, commit_amt);
|
||||
if (new_page != 0)
|
||||
{
|
||||
bump->size_committed = new_size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
invalid_code_path; // out of reserved memory
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8* result = bump->base + bump->at;
|
||||
bump->at = at_after;
|
||||
bump->high_water_mark = max(bump->at, bump->high_water_mark);
|
||||
|
||||
bump_allocator_validate(allocator);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal u8*
|
||||
bump_allocator_alloc(Allocator* allocator, u64 size)
|
||||
{
|
||||
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||
u8* result = bump_allocator_alloc_inner(allocator, bump, size);
|
||||
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;
|
||||
bump_allocator_validate(allocator);
|
||||
}
|
||||
|
||||
internal void
|
||||
bump_allocator_destroy_(Allocator_Bump* bump)
|
||||
{
|
||||
os_mem_decommit(bump->base, bump->size_committed);
|
||||
os_mem_release(bump->base, bump->size_reserved);
|
||||
}
|
||||
|
||||
internal void
|
||||
bump_allocator_destroy(Allocator* allocator)
|
||||
{
|
||||
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||
bump_allocator_destroy_(bump);
|
||||
allocator_destroy_(allocator, sizeof(Allocator_Bump));
|
||||
}
|
||||
|
||||
internal void
|
||||
bump_allocator_rewind(Allocator* allocator, u64 to_point)
|
||||
{
|
||||
Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data;
|
||||
bump_allocator_validate(allocator);
|
||||
#if defined(DEBUG)
|
||||
memory_zero(bump->base + to_point, bump->at - to_point);
|
||||
#endif
|
||||
bump->at = to_point;
|
||||
bump_allocator_validate(allocator);
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
bump_allocator_create_(u64 page_size)
|
||||
{
|
||||
u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump);
|
||||
|
||||
u8* base = os_mem_reserve(size_needed);
|
||||
base = os_mem_commit(base, size_needed);
|
||||
|
||||
Allocator* result = (Allocator*)base;
|
||||
zero_struct(*result);
|
||||
|
||||
Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator);
|
||||
zero_struct(*bump);
|
||||
bump->page_size = page_size;
|
||||
|
||||
result->alloc = bump_allocator_alloc;
|
||||
result->realloc = bump_allocator_realloc;
|
||||
result->clear = bump_allocator_clear;
|
||||
result->destroy = bump_allocator_destroy;
|
||||
result->allocator_data = (u8*)bump;
|
||||
|
||||
bump_allocator_validate(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
bump_allocator_create_reserve(u64 reserve_size)
|
||||
{
|
||||
Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE);
|
||||
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
||||
|
||||
u64 reserve_pages = round_size_to_os_page_multiple(reserve_size);
|
||||
bump->base = os_mem_reserve(reserve_pages);
|
||||
if (bump->base != 0) bump->size_reserved = reserve_pages;
|
||||
|
||||
bump_allocator_validate(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
bump_allocator_create_child(Allocator* parent, u64 init_size)
|
||||
{
|
||||
Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE);
|
||||
result->parent = parent;
|
||||
|
||||
Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data;
|
||||
zero_struct(*bump);
|
||||
bump->base = allocator_alloc(result->parent, init_size);
|
||||
if (bump->base != 0)
|
||||
{
|
||||
bump->size_reserved = init_size;
|
||||
bump->size_committed = init_size;
|
||||
}
|
||||
|
||||
bump_allocator_validate(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Scratch Allocator
|
||||
|
||||
typedef struct Allocator_Scratch Allocator_Scratch;
|
||||
struct Allocator_Scratch
|
||||
{
|
||||
Allocator* a;
|
||||
u64 at_before;
|
||||
};
|
||||
|
||||
internal Allocator_Scratch
|
||||
allocator_scratch_begin(Allocator* allocator)
|
||||
{
|
||||
Allocator_Scratch result = {};
|
||||
result.a = allocator;
|
||||
Allocator_Bump* bump = (Allocator_Bump*)result.a->allocator_data;
|
||||
result.at_before = bump->at;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
allocator_scratch_end(Allocator_Scratch* scratch)
|
||||
{
|
||||
bump_allocator_rewind(scratch->a, scratch->at_before);
|
||||
zero_struct(*scratch);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Paged Allocator
|
||||
|
||||
typedef struct Allocator_Paged_Free_Region Allocator_Paged_Free_Region;
|
||||
struct Allocator_Paged_Free_Region
|
||||
{
|
||||
u64 pages;
|
||||
Allocator_Paged_Free_Region* prev;
|
||||
Allocator_Paged_Free_Region* next;
|
||||
};
|
||||
|
||||
typedef struct Allocator_Paged Allocator_Paged;
|
||||
struct Allocator_Paged
|
||||
{
|
||||
Allocator_Bump bump;
|
||||
Allocator_Paged_Free_Region* free_first;
|
||||
};
|
||||
|
||||
internal u8*
|
||||
paged_allocator_alloc(Allocator* allocator, u64 size)
|
||||
{
|
||||
// 1. Find the number of pages we need
|
||||
// 2. Find a run of free pages that we can use
|
||||
// If found,
|
||||
// remove those pages from the run they are in
|
||||
// return those pages of memory
|
||||
// 3. Commit pages on the end
|
||||
|
||||
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||
if (paged->bump.page_size == 0) paged->bump.page_size = OS_MEM_PAGE_SIZE;
|
||||
|
||||
u64 rounded_size = round_size_to_page_multiple(size, paged->bump.page_size);
|
||||
u64 pages_needed = rounded_size / paged->bump.page_size;
|
||||
|
||||
u8* result = 0;
|
||||
|
||||
// Find free pages
|
||||
if (paged->free_first)
|
||||
{
|
||||
Allocator_Paged_Free_Region* found = 0;
|
||||
for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next)
|
||||
{
|
||||
// NOTE(PS): this set of conditions checks to see if is bigger than what
|
||||
// we need. If it is, we also check to see if this is smaller than any
|
||||
// region we've found before. And we abort the search if this region
|
||||
// perfectly fits the size needed.
|
||||
//
|
||||
// This should make sure that we are always choosing the closest fit we
|
||||
// can. I'm not sure this is the best strategy for dealing with fragmentation
|
||||
// but its a decent first pass
|
||||
if (at->pages >= pages_needed)
|
||||
{
|
||||
if (!found || (found->pages > at->pages))
|
||||
{
|
||||
found = at;
|
||||
if (found->pages == pages_needed) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
result = (u8*)found;
|
||||
if (found->pages > pages_needed)
|
||||
{
|
||||
Allocator_Paged_Free_Region* region_after = (Allocator_Paged_Free_Region*)(result + rounded_size);
|
||||
if (found->prev != 0) found->prev->next = region_after;
|
||||
region_after = found->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found->prev != 0) found->prev->next = found->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
{
|
||||
result = bump_allocator_alloc_inner(allocator, &paged->bump, size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#define region_end(r,page_size) ((u8*)(r) + ((r)->pages * page_size))
|
||||
|
||||
internal void
|
||||
paged_region_insert(
|
||||
Allocator_Paged_Free_Region* before,
|
||||
Allocator_Paged_Free_Region* new_region,
|
||||
Allocator_Paged_Free_Region* after,
|
||||
u64 page_size
|
||||
){
|
||||
assert(after == 0 || before < after);
|
||||
assert(before < new_region);
|
||||
assert(after == 0 || new_region < after);
|
||||
assert(new_region->prev == 0 && new_region->next == 0);
|
||||
|
||||
u8* before_end = region_end(before, page_size);
|
||||
u8* new_region_end = region_end(new_region, page_size);
|
||||
|
||||
// Before
|
||||
if (before_end == (u8*)new_region)
|
||||
{
|
||||
// merge the regions
|
||||
before->pages += new_region->pages;
|
||||
new_region = before;
|
||||
assert(new_region_end == region_end(new_region, page_size));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(before_end < (u8*)new_region);
|
||||
before->next = new_region;
|
||||
new_region->prev = before;
|
||||
}
|
||||
|
||||
// After
|
||||
if (after != 0)
|
||||
{
|
||||
if (new_region_end == (u8*)after)
|
||||
{
|
||||
// merge the regions
|
||||
new_region->pages += after->pages;
|
||||
u8* a = region_end(after, page_size);
|
||||
u8* b = region_end(new_region, page_size);
|
||||
assert(a == b);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(new_region_end < (u8*)after);
|
||||
new_region->next = after;
|
||||
after->prev = new_region;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
paged_allocator_free(Allocator* allocator, u8* base, u64 size)
|
||||
{
|
||||
// Figure out which page base is the base of, assert its the base
|
||||
// figure out how many pages size represents.
|
||||
// create a free range
|
||||
// stick it in between contiguous free ranges
|
||||
// if the ranges before or after meet this new one, merge them all
|
||||
|
||||
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||
|
||||
u64 page_base_rel = (base - paged->bump.base);
|
||||
assert((page_base_rel % paged->bump.page_size) == 0);
|
||||
u64 page_index = page_base_rel / paged->bump.page_size;
|
||||
u64 size_pages_mult = round_size_to_page_multiple(size, paged->bump.page_size);
|
||||
assert((size_pages_mult % paged->bump.page_size) == 0);
|
||||
u64 page_count = size_pages_mult / paged->bump.page_size;
|
||||
|
||||
Allocator_Paged_Free_Region* region = (Allocator_Paged_Free_Region*)base;
|
||||
zero_struct(*region);
|
||||
region->pages = page_count;
|
||||
|
||||
Allocator_Paged_Free_Region* prev = 0;
|
||||
Allocator_Paged_Free_Region* next = 0;
|
||||
for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next)
|
||||
{
|
||||
if (at < region)
|
||||
{
|
||||
prev = at;
|
||||
next = at->next;
|
||||
if (next != 0)
|
||||
{
|
||||
assert(next > region);
|
||||
assert((u8*)next >= ((u8*)region + size_pages_mult));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prev && next)
|
||||
{
|
||||
// found a region to insert into
|
||||
paged_region_insert(prev, region, next, paged->bump.page_size);
|
||||
}
|
||||
else if (prev)
|
||||
{
|
||||
// got to the end and all were before the free region in memory
|
||||
paged_region_insert(prev, region, 0, paged->bump.page_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
// free list is empty
|
||||
paged->free_first = region;
|
||||
}
|
||||
}
|
||||
|
||||
internal u8*
|
||||
paged_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size)
|
||||
{
|
||||
// TODO(PS):
|
||||
// Process:
|
||||
// 1. Figure out which page base starts on
|
||||
// 2. Find if there is a free region after base that is big enough to house
|
||||
// the new size
|
||||
// 3. If there is a free region, pull the needed memory out of it
|
||||
// 4. Otherwise, alloc new_size, copy base into it, and free base
|
||||
|
||||
// TODO(PS): you could do a simple version where you just always alloc, copy, free
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
paged_allocator_clear(Allocator* allocator)
|
||||
{
|
||||
if (!allocator->allocator_data) return;
|
||||
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||
paged->bump.at = 0;
|
||||
paged->free_first = 0;
|
||||
}
|
||||
|
||||
internal void
|
||||
paged_allocator_destroy(Allocator* allocator)
|
||||
{
|
||||
Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data;
|
||||
bump_allocator_destroy_(&paged->bump);
|
||||
allocator_destroy_(allocator, sizeof(Allocator_Paged));
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
paged_allocator_create_()
|
||||
{
|
||||
u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump);
|
||||
|
||||
u8* base = os_mem_reserve(size_needed);
|
||||
base = os_mem_commit(base, size_needed);
|
||||
|
||||
Allocator* result = (Allocator*)base;
|
||||
zero_struct(*result);
|
||||
|
||||
Allocator_Paged* paged = (Allocator_Paged*)base + sizeof(Allocator);
|
||||
zero_struct(*paged);
|
||||
|
||||
result->alloc = paged_allocator_alloc;
|
||||
result->free = paged_allocator_free;
|
||||
result->realloc = paged_allocator_realloc;
|
||||
result->clear = paged_allocator_clear;
|
||||
result->destroy = paged_allocator_destroy;
|
||||
result->allocator_data = (u8*)paged;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
paged_allocator_create_reserve(u64 reserve_size, u64 page_size)
|
||||
{
|
||||
Allocator* result = paged_allocator_create_();
|
||||
Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data;
|
||||
|
||||
u64 reserve_pages = round_size_to_os_page_multiple(reserve_size);
|
||||
paged->bump.page_size = page_size;
|
||||
paged->bump.base = os_mem_reserve(reserve_pages);
|
||||
if (paged->bump.base != 0) paged->bump.size_reserved = reserve_pages;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
paged_allocator_create_reserve_os_page_size(u64 reserve_size)
|
||||
{
|
||||
u64 page_size = OS_MEM_PAGE_SIZE;
|
||||
return paged_allocator_create_reserve(reserve_size, page_size);
|
||||
}
|
||||
|
||||
internal Allocator*
|
||||
paged_allocator_create_child(Allocator* parent, u64 init_size)
|
||||
{
|
||||
Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE);
|
||||
result->parent = parent;
|
||||
|
||||
Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data;
|
||||
paged->bump.base = allocator_alloc(result->parent, init_size);
|
||||
if (paged->bump.base != 0)
|
||||
{
|
||||
paged->bump.size_reserved = init_size;
|
||||
paged->bump.size_committed = init_size;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef LUMENARIUM_RANDOM_H
|
||||
#define LUMENARIUM_RANDOM_H
|
||||
|
||||
typedef struct Random_Series Random_Series;
|
||||
struct Random_Series
|
||||
{
|
||||
u32 last_value;
|
|
@ -0,0 +1,8 @@
|
|||
#if !defined(LUMENARIUM_CORE_SOCKET_H)
|
||||
#define LUMENARIUM_CORE_SOCKET_H
|
||||
|
||||
typedef struct { u64 value; } Socket_Handle;
|
||||
|
||||
// TODO
|
||||
|
||||
#endif // LUMENARIUM_CORE_SOCKET_H
|
|
@ -1,3 +1,24 @@
|
|||
//////////////////////////////////////////////
|
||||
// String
|
||||
|
||||
// NOTE(PS): even though this has a len and cap, it should always be
|
||||
// null terminated
|
||||
typedef struct String String;
|
||||
struct String
|
||||
{
|
||||
u8* str;
|
||||
u64 len;
|
||||
u64 cap;
|
||||
};
|
||||
|
||||
internal String string_create(u8* str, u64 len, u64 cap);
|
||||
internal u64 string_copy_to(String* dest, String src);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
//////////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
//////////////////////////////////////////////
|
||||
//////////////////////////////////////////////
|
||||
|
||||
internal u64
|
||||
c_str_len(char* s)
|
||||
|
@ -9,7 +30,7 @@ c_str_len(char* s)
|
|||
|
||||
#define str_varg(s) (int)(s).len, (char*)(s).str
|
||||
#define str_expand(s) (char*)(s).str, (u64)(s).len
|
||||
#define lit_str(s) String{ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 }
|
||||
#define lit_str(s) (String){ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 }
|
||||
|
||||
internal String
|
||||
allocator_alloc_string(Allocator* a, u64 cap)
|
||||
|
@ -266,4 +287,13 @@ string_f(Allocator* a, char* fmt, ...)
|
|||
String result = string_fv(a, fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_put_str(Data_Writer* w, String str)
|
||||
{
|
||||
for (u64 i = 0; i < str.len; i++)
|
||||
{
|
||||
dw_put_u8(w, str.str[i]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#if !defined(LUMENARIUM_CORE_THREADS_H)
|
||||
#define LUMENARIUM_CORE_THREADS_H
|
||||
|
||||
typedef struct Thread_Handle Thread_Handle;
|
||||
struct Thread_Handle { u64 value; };
|
||||
|
||||
typedef struct Thread_Result Thread_Result;
|
||||
struct Thread_Result { u32 code; };
|
||||
|
||||
typedef struct Thread_Data Thread_Data;
|
||||
typedef Thread_Result Thread_Proc(Thread_Data* data);
|
||||
struct Thread_Data
|
||||
{
|
||||
Thread_Handle thread_handle;
|
||||
u32 thread_id;
|
||||
Thread_Proc* thread_proc;
|
||||
Allocator* thread_memory;
|
||||
u8* user_data;
|
||||
};
|
||||
|
||||
#endif // LUMENARIUM_CORE_THREADS_H
|
|
@ -0,0 +1,39 @@
|
|||
#if !defined(LUMENARIUM_CORE_TIME_H)
|
||||
#define LUMENARIUM_CORE_TIME_H
|
||||
|
||||
typedef struct { s64 value; } Ticks;
|
||||
|
||||
internal Ticks get_ticks_elapsed(Ticks start, Ticks end);
|
||||
internal r64 ticks_to_seconds(Ticks t, r64 ticks_per_second);
|
||||
internal r64 get_seconds_elapsed(Ticks start, Ticks end, r64 ticks_per_second);
|
||||
|
||||
///////////////////////////////////////
|
||||
///////////////////////////////////////
|
||||
// Implementation
|
||||
///////////////////////////////////////
|
||||
///////////////////////////////////////
|
||||
|
||||
internal Ticks
|
||||
get_ticks_elapsed(Ticks start, Ticks end)
|
||||
{
|
||||
Ticks result = {};
|
||||
result.value = end.value - start.value;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal r64
|
||||
ticks_to_seconds(Ticks t, r64 ticks_per_second)
|
||||
{
|
||||
r64 result = t.value / ticks_per_second;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal r64
|
||||
get_seconds_elapsed(Ticks start, Ticks end, r64 ticks_per_second)
|
||||
{
|
||||
Ticks diff = get_ticks_elapsed(start, end);
|
||||
return ticks_to_seconds(diff, ticks_per_second);
|
||||
}
|
||||
|
||||
|
||||
#endif // LUMENARIUM_CORE_TIME_H
|
|
@ -0,0 +1,215 @@
|
|||
#ifndef LUMENARIUM_CORE_TYPES_H
|
||||
#define LUMENARIUM_CORE_TYPES_H
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Explicit Names for static keyword
|
||||
#define internal static
|
||||
#define local_persist static
|
||||
#define global static
|
||||
#define local_const static const
|
||||
#define global_const static const
|
||||
#define external extern "C"
|
||||
|
||||
#define STMT(x) do {(x);}while(false)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Integer Sizing
|
||||
#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 // !defined(GUESS_INTS)
|
||||
|
||||
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 // defined(GUESS_INTS)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Basic Types
|
||||
|
||||
typedef s8 b8;
|
||||
typedef s32 b32;
|
||||
typedef s64 b64;
|
||||
|
||||
typedef float r32;
|
||||
typedef double r64;
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Basic Type Constants
|
||||
|
||||
#define u8_max 0xFF
|
||||
#define u16_max 0xFFFF
|
||||
#define u32_max 0xFFFFFFFF
|
||||
#define u64_max 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
#define s8_max 127
|
||||
#define s16_max 32767
|
||||
#define s32_max 2147483647
|
||||
#define s64_max 9223372036854775807
|
||||
|
||||
#define s8_min -127 - 1
|
||||
#define s16_min -32767 - 1
|
||||
#define s32_min -2147483647 - 1
|
||||
#define s64_min -9223372036854775807 - 1
|
||||
|
||||
#define r32_max 3.402823466e+38f
|
||||
#define r32_min -3.402823466e+38f
|
||||
#define r32_smallest_positive 1.1754943508e-38f
|
||||
#define r32_epsilon 5.96046448e-8f
|
||||
#define r32_pi 3.14159265359f
|
||||
#define r32_half_pi 1.5707963267f
|
||||
#define r32_tau 6.28318530717f
|
||||
|
||||
#define r64_max 1.79769313486231e+308
|
||||
#define r64_min -1.79769313486231e+308
|
||||
#define r64_smallest_positive 4.94065645841247e-324
|
||||
#define r64_epsilon 1.11022302462515650e-16
|
||||
#define r64_pi 3.14159265359
|
||||
#define r64_half_pi 1.5707963267
|
||||
#define r64_tau 6.28318530717
|
||||
|
||||
#define NanosToSeconds 1 / 10000000.0
|
||||
#define SecondsToNanos 10000000.0
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Math
|
||||
|
||||
#ifndef max
|
||||
# define max(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
# define min(a,b) ((a) > (b) ? (b) : (a))
|
||||
#endif
|
||||
|
||||
#define lerp(a,t,b) (a) + ((1.0f - (t)) * (b))
|
||||
#define clamp(r0,v,r1) min((r1),max((r0),(v)))
|
||||
#define lerp_clamp(a,t,b) clamp((a),lerp((a),(t),(b)),(b))
|
||||
|
||||
internal u32
|
||||
round_up_to_pow2_u32(u32 v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Flags
|
||||
|
||||
#define has_flag(data, flag) (((data) & (flag)) != 0)
|
||||
#define has_flag_exact(data, flag) (((data) & (flag)) == (flag))
|
||||
#define add_flag(data, flag) STMT((data) |= (flag))
|
||||
#define rem_flag(data, flag) STMT((data) &= (~(flag)))
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Hash Table
|
||||
//
|
||||
// Rather than define a data structure, to allow the most flexibility,
|
||||
// this is just a set of functions that can be integrated into other
|
||||
// routines.
|
||||
// In general, they expect you to track a u32* of ids and a u32 capacity
|
||||
|
||||
internal void
|
||||
hash_table_init(u32* ids, u32 cap)
|
||||
{
|
||||
for (u32 i = 0; i < cap; i++) ids[i] = 0;
|
||||
}
|
||||
|
||||
internal u32
|
||||
hash_table_find_(u32* ids, u32 cap, u32 start_id, u32 target_value)
|
||||
{
|
||||
u32 index = start_id % cap;
|
||||
u32 start = index;
|
||||
do {
|
||||
if (ids[index] == target_value) break;
|
||||
index = (index + 1) % cap;
|
||||
} while (index != start);
|
||||
return index;
|
||||
}
|
||||
|
||||
internal u32
|
||||
hash_table_register(u32* ids, u32 cap, u32 new_id)
|
||||
{
|
||||
u32 index = hash_table_find_(ids, cap, new_id, 0);
|
||||
if (ids[index] != 0) return cap;
|
||||
ids[index] = new_id;
|
||||
return index;
|
||||
}
|
||||
|
||||
internal u32
|
||||
hash_table_find(u32* ids, u32 cap, u32 value)
|
||||
{
|
||||
u32 result = hash_table_find_(ids, cap, value, value);
|
||||
if (ids[result] != value) return cap;
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Predeclaring Memory Functions
|
||||
|
||||
u64 round_size_to_page_multiple(u64 size, u64 page_size);
|
||||
u64 round_size_to_os_page_multiple(u64 size);
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Vector Extensions
|
||||
|
||||
#if defined(HANDMADE_MATH_IMPLEMENTATION)
|
||||
|
||||
#define v2_to_v3(xy,z) (v3){(xy).x, (xy).y, (z)}
|
||||
#define v2_floor(v) (v2){ floorf(v.x), floorf(v.y) }
|
||||
#define v3_floor(v) (v3){ floorf(v.x), floorf(v.y), floorf(v.z) }
|
||||
|
||||
internal bool
|
||||
rect2_contains(v2 min, v2 max, v2 point)
|
||||
{
|
||||
return (
|
||||
min.x <= point.x && min.y <= point.y &&
|
||||
max.x >= point.x && max.y >= point.y
|
||||
);
|
||||
}
|
||||
|
||||
#endif // defined(HANDMADE_MATH_IMPLEMENTATION)
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Color Constants
|
||||
|
||||
#define WHITE_V4 (v4){1,1,1,1}
|
||||
#define BLACK_V4 (v4){0,0,0,1}
|
||||
#define RED_V4 (v4){1,0,0,1}
|
||||
#define GREEN_V4 (v4){0,1,0,1}
|
||||
#define BLUE_V4 (v4){0,0,1,1}
|
||||
#define YELLOW_V4 (v4){1,1,0,1}
|
||||
#define TEAL_V4 (v4){0,1,1,1}
|
||||
#define PINK_V4 (v4){1,0,1,1}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,235 @@
|
|||
#if !defined(LUMENARIUM_CORE_WINDOW_H)
|
||||
#define LUMENARIUM_CORE_WINDOW_H
|
||||
|
||||
typedef u32 Window_Event_Kind;
|
||||
enum
|
||||
{
|
||||
WindowEvent_Invalid = 0,
|
||||
|
||||
WindowEvent_MouseScroll,
|
||||
WindowEvent_MouseMoved,
|
||||
WindowEvent_ButtonDown,
|
||||
WindowEvent_ButtonUp,
|
||||
WindowEvent_Char,
|
||||
WindowEvent_WindowClosed,
|
||||
|
||||
WindowEvent_Count,
|
||||
};
|
||||
|
||||
typedef u32 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 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,
|
||||
};
|
||||
|
||||
typedef struct Window_Event Window_Event;
|
||||
struct Window_Event
|
||||
{
|
||||
Window_Event_Kind kind;
|
||||
Key_Code key_code;
|
||||
Key_Flags key_flags;
|
||||
s32 mouse_x;
|
||||
s32 mouse_y;
|
||||
s32 scroll_amt;
|
||||
char char_value;
|
||||
};
|
||||
|
||||
typedef u32 Cursor_Kind;
|
||||
enum
|
||||
{
|
||||
Cursor_Arrow,
|
||||
Cursor_Pointer,
|
||||
Cursor_Loading,
|
||||
Cursor_HArrows,
|
||||
Cursor_VArrows,
|
||||
Cursor_DTopLeftArrows,
|
||||
Cursor_DTopRightArrows,
|
||||
Cursor_Count,
|
||||
};
|
||||
|
||||
#define INPUT_FRAME_STRING_LENGTH 32
|
||||
typedef struct Input_Frame Input_Frame;
|
||||
struct Input_Frame
|
||||
{
|
||||
Key_Flags key_flags[KeyCode_Count];
|
||||
|
||||
char string_input[INPUT_FRAME_STRING_LENGTH];
|
||||
u32 string_input_len;
|
||||
|
||||
v2 mouse_pos;
|
||||
s32 mouse_scroll;
|
||||
};
|
||||
|
||||
typedef struct Input_State Input_State;
|
||||
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(Allocator* a);
|
||||
internal Key_Flags input_key_advance(Key_Flags flag);
|
||||
internal void input_state_swap_frames(Input_State* input_state);
|
||||
internal bool input_key_is_down(Input_State* input_state, Key_Code key);
|
||||
internal bool input_key_went_down(Input_State* input_state, Key_Code key);
|
||||
internal bool input_key_is_up(Input_State* input_state, Key_Code key);
|
||||
internal bool input_key_went_up(Input_State* input_state, Key_Code key);
|
||||
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
|
||||
internal Input_State*
|
||||
input_state_create(Allocator* a)
|
||||
{
|
||||
Input_State* result = allocator_alloc_struct(a, Input_State);
|
||||
result->frame_hot = result->frames + 0;
|
||||
result->frame_cold = result->frames + 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Key_Flags
|
||||
input_key_advance(Key_Flags flag)
|
||||
{
|
||||
Key_Flags result = flag;
|
||||
if (key_is_down(flag))
|
||||
{
|
||||
add_flag(result, KeyFlag_State_WasDown);
|
||||
}
|
||||
if (key_is_up(flag))
|
||||
{
|
||||
rem_flag(result, KeyFlag_State_WasDown);
|
||||
}
|
||||
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
|
||||
Key_Flags* hot_key_flags = input_state->frame_hot->key_flags;
|
||||
Key_Flags* cold_key_flags = input_state->frame_cold->key_flags;
|
||||
for (u32 i = 0; i < KeyCode_Count; i++)
|
||||
{
|
||||
hot_key_flags[i] = input_key_advance(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, Key_Code key)
|
||||
{
|
||||
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, Key_Code key)
|
||||
{
|
||||
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, Key_Code key)
|
||||
{
|
||||
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, Key_Code key)
|
||||
{
|
||||
Key_Flags flags = input_state->frame_hot->key_flags[key];
|
||||
return !key_is_down(flags) && key_was_down(flags);
|
||||
}
|
||||
#endif // LUMENARIUM_CORE_WINDOW_H
|
|
@ -0,0 +1,419 @@
|
|||
#if !defined(LUMENARIUM_EDITOR_GRAPHICS_H)
|
||||
#define LUMENARIUM_EDITOR_GRAPHICS_H
|
||||
|
||||
#define os_gl_no_error() os_gl_no_error_((char*)__FILE__, (u32)__LINE__)
|
||||
void os_gl_no_error_(char* file, u32 line);
|
||||
|
||||
#define GL_NULL (u32)0
|
||||
|
||||
#define SHADER_MAX_ATTRS 8
|
||||
#define SHADER_ATTR_LAST (u32)(1 << 31)
|
||||
typedef struct Shader Shader;
|
||||
struct Shader
|
||||
{
|
||||
u32 id;
|
||||
u32 attrs[SHADER_MAX_ATTRS];
|
||||
u32 uniforms[SHADER_MAX_ATTRS];
|
||||
};
|
||||
|
||||
typedef struct XPlatform_Shader_Program_Src XPlatform_Shader_Program_Src;
|
||||
struct XPlatform_Shader_Program_Src
|
||||
{
|
||||
String win32_vert;
|
||||
String win32_frag;
|
||||
|
||||
String osx_vert;
|
||||
String osx_frag;
|
||||
|
||||
String wasm_vert;
|
||||
String wasm_frag;
|
||||
};
|
||||
|
||||
String xplatform_shader_program_get_vert(XPlatform_Shader_Program_Src src);
|
||||
String xplatform_shader_program_get_frag(XPlatform_Shader_Program_Src src);
|
||||
|
||||
typedef struct Geometry_Buffer Geometry_Buffer;
|
||||
struct Geometry_Buffer
|
||||
{
|
||||
u32 buffer_id_vao;
|
||||
u32 buffer_id_vertices;
|
||||
u32 buffer_id_indices;
|
||||
u32 vertices_len;
|
||||
u32 indices_len;
|
||||
};
|
||||
|
||||
typedef struct Texture Texture;
|
||||
struct Texture
|
||||
{
|
||||
u32 id;
|
||||
|
||||
u32 w, h, s;
|
||||
};
|
||||
|
||||
typedef struct Graphics_Frame_Desc Graphics_Frame_Desc;
|
||||
struct Graphics_Frame_Desc
|
||||
{
|
||||
v4 clear_color;
|
||||
v2 viewport_min;
|
||||
v2 viewport_max;
|
||||
};
|
||||
|
||||
void frame_begin(Graphics_Frame_Desc desc);
|
||||
void frame_clear();
|
||||
|
||||
// Geometry
|
||||
Geometry_Buffer geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len);
|
||||
Shader shader_create(String code_vert, String code_frag, String* attribs, u32 attribs_len, String* uniforms, u32 uniforms_len);
|
||||
void geometry_buffer_update(Geometry_Buffer* buffer, r32* verts, u32 verts_offset, u32 verts_len, u32* indices, u32 indices_offset, u32 indices_len);
|
||||
|
||||
// Shaders
|
||||
void geometry_bind(Geometry_Buffer geo);
|
||||
void shader_bind(Shader shader);
|
||||
void geometry_drawi(Geometry_Buffer geo, u32 indices);
|
||||
void geometry_draw(Geometry_Buffer geo);
|
||||
void vertex_attrib_pointer(Geometry_Buffer geo, Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset);
|
||||
void set_uniform(Shader shader, u32 index, m44 u);
|
||||
|
||||
// Textures
|
||||
Texture texture_create(u8* pixels, u32 width, u32 height, u32 stride);
|
||||
void texture_bind(Texture tex);
|
||||
void texture_update(Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride);
|
||||
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
//////////////////////////////////////////
|
||||
//////////////////////////////////////////
|
||||
|
||||
Geometry_Buffer
|
||||
geometry_buffer_create(
|
||||
r32* vertices, u32 vertices_len,
|
||||
u32* indices, u32 indices_len
|
||||
){
|
||||
Geometry_Buffer result = {};
|
||||
|
||||
gl.glGenVertexArrays(1, &result.buffer_id_vao);
|
||||
os_gl_no_error();
|
||||
|
||||
GLuint buffers[2];
|
||||
gl.glGenBuffers(2, (GLuint*)buffers);
|
||||
os_gl_no_error();
|
||||
|
||||
result.buffer_id_vertices = buffers[0];
|
||||
result.buffer_id_indices = buffers[1];
|
||||
|
||||
// Vertices
|
||||
gl.glBindVertexArray(result.buffer_id_vao);
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, result.buffer_id_vertices);
|
||||
os_gl_no_error();
|
||||
|
||||
gl.glBufferData(GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW);
|
||||
os_gl_no_error();
|
||||
result.vertices_len = vertices_len;
|
||||
|
||||
// Indices
|
||||
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices);
|
||||
os_gl_no_error();
|
||||
|
||||
gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(u32) * indices_len, indices, GL_STATIC_DRAW);
|
||||
os_gl_no_error();
|
||||
result.indices_len = indices_len;
|
||||
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, GL_NULL);
|
||||
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
geometry_buffer_update(
|
||||
Geometry_Buffer* buffer,
|
||||
r32* verts,
|
||||
u32 verts_offset,
|
||||
u32 verts_len,
|
||||
u32* indices,
|
||||
u32 indices_offset,
|
||||
u32 indices_len
|
||||
){
|
||||
gl.glBindVertexArray(buffer->buffer_id_vao);
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices);
|
||||
os_gl_no_error();
|
||||
|
||||
if (verts_len > buffer->vertices_len)
|
||||
{
|
||||
// NOTE(PS): this is because we're going to delete the old buffer and
|
||||
// create a new one. In order to do that and not lose data, the update
|
||||
// function needs to have been passed all the buffer's data
|
||||
assert(verts_offset == 0);
|
||||
gl.glBufferData(GL_ARRAY_BUFFER, verts_len * sizeof(r32), (void*)verts, GL_STATIC_DRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.glBufferSubData(GL_ARRAY_BUFFER, verts_offset * sizeof(r32), verts_len * sizeof(r32), (void*)verts);
|
||||
}
|
||||
os_gl_no_error();
|
||||
|
||||
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->buffer_id_indices);
|
||||
os_gl_no_error();
|
||||
if (indices_len > buffer->indices_len)
|
||||
{
|
||||
// NOTE(PS): this is because we're going to delete the old buffer and
|
||||
// create a new one. In order to do that and not lose data, the update
|
||||
// function needs to have been passed all the buffer's data
|
||||
assert(indices_offset == 0);
|
||||
gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_len * sizeof(u32), (void*)indices, GL_STATIC_DRAW);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl.glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indices_offset * sizeof(u32), indices_len * sizeof(u32), (void*)indices);
|
||||
}
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
Shader
|
||||
shader_create(String code_vert, String code_frag, String* attrs, u32 attrs_len, String* uniforms, u32 uniforms_len){
|
||||
Shader result = {};
|
||||
|
||||
GLuint shader_vert = gl.glCreateShader(GL_VERTEX_SHADER);
|
||||
s32* code_vert_len = (s32*)&code_vert.len;
|
||||
gl.glShaderSource(shader_vert, 1, (const char**)&code_vert.str, code_vert_len);
|
||||
gl.glCompileShader(shader_vert);
|
||||
{ // errors
|
||||
GLint shader_vert_compiled;
|
||||
gl.glGetShaderiv(shader_vert, GL_COMPILE_STATUS, &shader_vert_compiled);
|
||||
if (!shader_vert_compiled)
|
||||
{
|
||||
GLsizei log_length = 0;
|
||||
GLchar message[1024];
|
||||
gl.glGetShaderInfoLog(shader_vert, 1024, &log_length, message);
|
||||
printf("GLSL Error: %s\n", message);
|
||||
invalid_code_path;
|
||||
}
|
||||
}
|
||||
|
||||
GLuint shader_frag = gl.glCreateShader(GL_FRAGMENT_SHADER);
|
||||
s32* code_frag_len = (s32*)&code_frag.len;
|
||||
gl.glShaderSource(shader_frag, 1, (const char**)&code_frag.str, code_frag_len);
|
||||
gl.glCompileShader(shader_frag);
|
||||
{ // errors
|
||||
GLint shader_frag_compiled;
|
||||
gl.glGetShaderiv(shader_frag, GL_COMPILE_STATUS, &shader_frag_compiled);
|
||||
if (!shader_frag_compiled)
|
||||
{
|
||||
GLsizei log_length = 0;
|
||||
GLchar message[1024];
|
||||
gl.glGetShaderInfoLog(shader_frag, 1024, &log_length, message);
|
||||
printf("GLSL Error: %s\n", message);
|
||||
printf("%.*s\n", str_varg(code_frag));
|
||||
invalid_code_path;
|
||||
}
|
||||
}
|
||||
|
||||
result.id = (u32)gl.glCreateProgram();
|
||||
gl.glAttachShader(result.id, shader_vert);
|
||||
gl.glAttachShader(result.id, shader_frag);
|
||||
gl.glLinkProgram(result.id);
|
||||
|
||||
GLint program_linked;
|
||||
gl.glGetProgramiv(result.id, GL_LINK_STATUS, &program_linked);
|
||||
if (program_linked != GL_TRUE)
|
||||
{
|
||||
GLsizei log_length = 0;
|
||||
GLchar message[1024];
|
||||
gl.glGetProgramInfoLog(result.id, 1024, &log_length, message);
|
||||
printf("GLSL Error: %s\n", message);
|
||||
invalid_code_path;
|
||||
}
|
||||
|
||||
gl.glUseProgram(result.id);
|
||||
|
||||
// TODO(PS): delete the vert and frag programs
|
||||
|
||||
assert(attrs_len < SHADER_MAX_ATTRS);
|
||||
for (u32 i = 0; i < attrs_len; i++)
|
||||
{
|
||||
result.attrs[i] = gl.glGetAttribLocation(result.id, (char*)attrs[i].str);
|
||||
os_gl_no_error();
|
||||
}
|
||||
result.attrs[attrs_len] = SHADER_ATTR_LAST;
|
||||
|
||||
assert(uniforms_len < SHADER_MAX_ATTRS);
|
||||
for (GLuint i = 0; i < uniforms_len; i++)
|
||||
{
|
||||
s32 len = (s32)uniforms[i].len;
|
||||
result.uniforms[i] = gl.glGetUniformLocation(result.id, (char*)uniforms[i].str);
|
||||
}
|
||||
result.uniforms[uniforms_len] = SHADER_ATTR_LAST;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
set_uniform(Shader shader, u32 index, m44 u)
|
||||
{
|
||||
gl.glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements);
|
||||
}
|
||||
|
||||
void
|
||||
geometry_bind(Geometry_Buffer geo)
|
||||
{
|
||||
gl.glBindVertexArray(geo.buffer_id_vao);
|
||||
os_gl_no_error();
|
||||
|
||||
gl.glBindBuffer(GL_ARRAY_BUFFER, geo.buffer_id_vertices);
|
||||
os_gl_no_error();
|
||||
|
||||
gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geo.buffer_id_indices);
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
void
|
||||
shader_bind(Shader shader)
|
||||
{
|
||||
gl.glUseProgram(shader.id);
|
||||
os_gl_no_error();
|
||||
for (u32 i = 0;
|
||||
((i < SHADER_MAX_ATTRS) && (shader.attrs[i] != SHADER_ATTR_LAST));
|
||||
i++)
|
||||
{
|
||||
gl.glEnableVertexAttribArray(shader.attrs[i]);
|
||||
os_gl_no_error();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
geometry_drawi(Geometry_Buffer geo, u32 indices){
|
||||
glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_INT, 0);
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
void
|
||||
geometry_draw(Geometry_Buffer geo){
|
||||
geometry_drawi(geo, geo.indices_len);
|
||||
}
|
||||
|
||||
void vertex_attrib_pointer(Geometry_Buffer geo, Shader shader, GLuint count, GLuint attr_index, GLuint stride, GLuint offset){
|
||||
geometry_bind(geo);
|
||||
gl.glVertexAttribPointer(shader.attrs[attr_index], count, GL_FLOAT, false, stride * sizeof(float), (void*)(offset * sizeof(float)));
|
||||
os_gl_no_error();
|
||||
gl.glEnableVertexAttribArray(shader.attrs[attr_index]);
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
Texture
|
||||
texture_create(u8* pixels, u32 width, u32 height, u32 stride)
|
||||
{
|
||||
Texture result = {};
|
||||
glGenTextures(1, &result.id);
|
||||
os_gl_no_error();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, result.id);
|
||||
os_gl_no_error();
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
os_gl_no_error();
|
||||
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
GL_RGBA,
|
||||
width,
|
||||
height,
|
||||
0,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
pixels
|
||||
);
|
||||
os_gl_no_error();
|
||||
|
||||
result.w = width;
|
||||
result.h = height;
|
||||
result.s = stride;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
texture_update(Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride)
|
||||
{
|
||||
// NOTE(PS): this function simply replaces the entire image
|
||||
// we can write a more granular version if we need it
|
||||
|
||||
assert(tex.w == width && tex.h == height && tex.s == stride);
|
||||
texture_bind(tex);
|
||||
glTexSubImage2D(
|
||||
GL_TEXTURE_2D,
|
||||
0,
|
||||
0, 0, // offset
|
||||
width, height,
|
||||
GL_RGBA,
|
||||
GL_UNSIGNED_BYTE,
|
||||
new_pixels
|
||||
);
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
void
|
||||
texture_bind(Texture tex)
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, tex.id);
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
void
|
||||
frame_begin(Graphics_Frame_Desc desc)
|
||||
{
|
||||
v4 cc = desc.clear_color;
|
||||
glClearColor(cc.r, cc.g, cc.b, cc.a);
|
||||
|
||||
v2 vmin = desc.viewport_min;
|
||||
v2 vmax = desc.viewport_max;
|
||||
glViewport((GLsizei)vmin.x, (GLsizei)vmin.y, (GLint)vmax.x, (GLint)vmax.y);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
os_gl_no_error();
|
||||
}
|
||||
|
||||
void
|
||||
frame_clear()
|
||||
{
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
|
||||
String
|
||||
xplatform_shader_program_get_vert(XPlatform_Shader_Program_Src src)
|
||||
{
|
||||
#if defined(PLATFORM_win32)
|
||||
return src.win32_vert;
|
||||
#elif defined(PLATFORM_osx)
|
||||
return src.osx_vert;
|
||||
#elif defined(PLATFORM_wasm)
|
||||
return src.wasm_vert;
|
||||
#endif
|
||||
}
|
||||
|
||||
String
|
||||
xplatform_shader_program_get_frag(XPlatform_Shader_Program_Src src)
|
||||
{
|
||||
#if defined(PLATFORM_win32)
|
||||
return src.win32_frag;
|
||||
#elif defined(PLATFORM_osx)
|
||||
return src.osx_frag;
|
||||
#elif defined(PLATFORM_wasm)
|
||||
return src.wasm_frag;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif // LUMENARIUM_EDITOR_GRAPHICS_H
|
|
@ -0,0 +1,76 @@
|
|||
/* date = March 24th 2022 6:05 pm */
|
||||
|
||||
#ifndef LUMENARIUM_EDITOR_OPENGL_H
|
||||
#define LUMENARIUM_EDITOR_OPENGL_H
|
||||
|
||||
// glext.h - https://github.com/KhronosGroup/OpenGL-Registry/blob/main/api/GL/glext.h
|
||||
// wglext.h -
|
||||
|
||||
void os_gl_no_error();
|
||||
|
||||
// OpenGL 3.3+ Context Creation
|
||||
#if defined(PLATFORM_win32)
|
||||
typedef const char *WINAPI proc_wglGetExtensionsStringARB(HDC hdc);
|
||||
typedef BOOL proc_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
|
||||
typedef HGLRC proc_wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList);
|
||||
#endif
|
||||
|
||||
// OpenGL 3.3+ Extensions
|
||||
typedef void proc_glGenVertexArrays(GLsizei n, GLuint *arrays);
|
||||
typedef void proc_glBindVertexArray(GLuint array);
|
||||
typedef void proc_glGenBuffers (GLsizei n, GLuint *buffers);
|
||||
typedef void proc_glBindBuffer(GLenum target, GLuint buffer);
|
||||
typedef void proc_glBufferData(GLenum target, size_t size, const void *data, GLenum usage);
|
||||
typedef void proc_glBufferSubData(GLenum target, size_t offset, size_t size, const void* data);
|
||||
typedef GLuint proc_glCreateShader(GLenum type);
|
||||
typedef void proc_glShaderSource(GLuint shader, u32 count, const char* const* string, const GLint *length);
|
||||
typedef void proc_glCompileShader(GLuint shader);
|
||||
typedef GLuint proc_glCreateProgram(void);
|
||||
typedef void proc_glAttachShader(GLuint program, GLuint shader);
|
||||
typedef void proc_glLinkProgram(GLuint program);
|
||||
typedef void proc_glUseProgram(GLuint program);
|
||||
typedef GLuint proc_glGetAttribLocation(GLuint program, const char* name);
|
||||
typedef void proc_glVertexAttribPointer(GLuint attr, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
|
||||
typedef void proc_glEnableVertexAttribArray(GLuint index);
|
||||
typedef void proc_glGetShaderiv(GLuint shader, GLenum ele, GLint* value_out);
|
||||
typedef void proc_glGetShaderInfoLog(GLuint shader, GLuint buf_len, GLsizei* len_out, GLchar* buf);
|
||||
typedef void proc_glGetProgramiv(GLuint program, GLenum ele, GLint* value_out);
|
||||
typedef void proc_glGetProgramInfoLog(GLuint program, GLuint cap, GLsizei* len_out, GLchar* buf);
|
||||
typedef GLuint proc_glGetUniformLocation(GLuint program, const char* name);
|
||||
typedef void proc_glUniformMatrix4fv(GLuint uniform, GLuint count, GLenum normalize, GLfloat* elements);
|
||||
typedef struct OpenGL_Extensions OpenGL_Extensions;
|
||||
struct OpenGL_Extensions
|
||||
{
|
||||
#if defined(PLATFORM_win32)
|
||||
proc_wglGetExtensionsStringARB* wglGetExtensionsStringARB;
|
||||
proc_wglChoosePixelFormatARB* wglChoosePixelFormatARB;
|
||||
proc_wglCreateContextAttribsARB* wglCreateContextAttribsARB;
|
||||
#endif
|
||||
|
||||
proc_glGenVertexArrays* glGenVertexArrays;
|
||||
proc_glBindVertexArray* glBindVertexArray;
|
||||
proc_glGenBuffers* glGenBuffers;
|
||||
proc_glBindBuffer* glBindBuffer;
|
||||
proc_glBufferData* glBufferData;
|
||||
proc_glBufferSubData* glBufferSubData;
|
||||
proc_glCreateShader* glCreateShader;
|
||||
proc_glShaderSource* glShaderSource;
|
||||
proc_glCompileShader* glCompileShader;
|
||||
proc_glCreateProgram* glCreateProgram;
|
||||
proc_glAttachShader* glAttachShader;
|
||||
proc_glLinkProgram* glLinkProgram;
|
||||
proc_glUseProgram* glUseProgram;
|
||||
proc_glGetAttribLocation* glGetAttribLocation;
|
||||
proc_glVertexAttribPointer* glVertexAttribPointer;
|
||||
proc_glEnableVertexAttribArray* glEnableVertexAttribArray;
|
||||
proc_glGetShaderiv* glGetShaderiv;
|
||||
proc_glGetShaderInfoLog* glGetShaderInfoLog;
|
||||
proc_glGetProgramiv* glGetProgramiv;
|
||||
proc_glGetProgramInfoLog* glGetProgramInfoLog;
|
||||
proc_glGetUniformLocation* glGetUniformLocation;
|
||||
proc_glUniformMatrix4fv* glUniformMatrix4fv;
|
||||
};
|
||||
|
||||
global OpenGL_Extensions gl = {};
|
||||
|
||||
#endif //LUMENARIUM_EDITOR_OPENGL_H
|
|
@ -0,0 +1,327 @@
|
|||
internal void
|
||||
ed_load_font_cb(File_Async_Job_Args result, u8* user_data)
|
||||
{
|
||||
App_State* state = (App_State*)user_data;
|
||||
UI* ui = &state->editor->ui;
|
||||
|
||||
u8* f = result.data.base;
|
||||
stbtt_fontinfo font;
|
||||
if (!stbtt_InitFont(&font, f, stbtt_GetFontOffsetForIndex(f, 0)))
|
||||
{
|
||||
invalid_code_path;
|
||||
}
|
||||
|
||||
r32 scale = stbtt_ScaleForPixelHeight(&font, 18.0f);
|
||||
s32 ascent, descent, line_gap;
|
||||
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
|
||||
ui->font_ascent = (r32)ascent * scale;
|
||||
ui->font_descent = (r32)descent * scale;
|
||||
ui->font_line_gap = (r32)line_gap * scale;
|
||||
if (ui->font_line_gap == 0) ui->font_line_gap = 5;
|
||||
|
||||
String c = lit_str("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{}\\|;:'\",<.>/?`~");
|
||||
for (u64 i = 0; i < c.len; i++)
|
||||
{
|
||||
s32 w, h, xoff, yoff;
|
||||
u32 id = (u32)c.str[i];
|
||||
u8* bp = stbtt_GetCodepointBitmap(&font, 0, scale, (char)c.str[i], &w, &h, &xoff, &yoff);
|
||||
s32 x0, y0, x1, y1;
|
||||
stbtt_GetCodepointBitmapBoxSubpixel(&font, (char)c.str[i], scale, scale, 0, 0, &x0, &y0, &x1, &y1);
|
||||
|
||||
v2 offset = (v2){ 0, (r32)y0 };
|
||||
texture_atlas_register(&state->editor->ui.atlas, bp, (u32)w, (u32)h, id, offset, TextureAtlasRegistration_PixelFormat_Alpha);
|
||||
stbtt_FreeBitmap(bp, 0);
|
||||
}
|
||||
|
||||
Texture_Atlas_Sprite m_sprite = texture_atlas_sprite_get(&state->editor->ui.atlas, (u32)'m');
|
||||
ui->font_space_width = (r32)(m_sprite.max_x - m_sprite.min_x);
|
||||
|
||||
texture_update(ui->atlas_texture, ui->atlas.pixels, 1024, 1024, 1024);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_draw_panel(u8* user_data, BSP_Node_Id id, BSP_Node node, BSP_Area area)
|
||||
{
|
||||
App_State* state = (App_State*)user_data;
|
||||
UI* ui = &state->editor->ui;
|
||||
scratch_get(scratch);
|
||||
|
||||
UI_Layout title_layout = {};
|
||||
ui_layout_set_row_info(ui, &title_layout);
|
||||
title_layout.bounds_min = (v2){ area.min.x, area.max.y - title_layout.row_height };
|
||||
title_layout.bounds_max = area.max;
|
||||
title_layout.at = title_layout.bounds_min;
|
||||
|
||||
UI_Layout panel_layout = {};
|
||||
ui_layout_set_row_info(ui, &panel_layout);
|
||||
panel_layout.bounds_min = area.min;
|
||||
panel_layout.bounds_max = (v2){ area.max.x, title_layout.bounds_max.y };
|
||||
panel_layout.at = panel_layout.bounds_min;
|
||||
|
||||
ui_layout_push(ui, &panel_layout);
|
||||
|
||||
String title = {};
|
||||
switch (node.user_data)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
title = lit_str("None");
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
ed_sculpture_visualizer(state);
|
||||
title = lit_str("Sculpture");
|
||||
} break;
|
||||
|
||||
invalid_default_case;
|
||||
}
|
||||
ui_layout_pop(ui);
|
||||
|
||||
ui_layout_push(ui, &title_layout);
|
||||
UI_Widget_Desc bg = {};
|
||||
bg.style.flags = UIWidgetStyle_Bg;
|
||||
bg.style.color_bg = (v4){.4f,.4f,.4f,1};
|
||||
bg.style.sprite = WHITE_SPRITE_ID;
|
||||
bg.string = string_f(scratch.a, "%.*s_%u_title_bg", str_varg(title), id.value);
|
||||
bg.p_min = title_layout.bounds_min;
|
||||
bg.p_max = title_layout.bounds_max;
|
||||
UI_Widget_Result r = ui_widget_push(ui, bg);
|
||||
ui_layout_row_begin(&title_layout, 4);
|
||||
{
|
||||
ui_textc(ui, title, BLACK_V4);
|
||||
}
|
||||
ui_layout_row_end(&title_layout);
|
||||
ui_widget_pop(ui, r.id);
|
||||
ui_layout_pop(ui);
|
||||
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
Geometry_Buffer b;
|
||||
Shader shd;
|
||||
Texture tex;
|
||||
|
||||
internal void
|
||||
ed_init(App_State* state)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
|
||||
Editor* editor = allocator_alloc_struct(permanent, Editor);
|
||||
zero_struct(*editor);
|
||||
state->editor = editor;
|
||||
editor->content_scale = (v2){1,1};
|
||||
editor->ui = ui_create(4096, 4096, state->input_state, permanent);
|
||||
editor->ui.draw_panel_cb = ed_draw_panel;
|
||||
editor->ui.draw_panel_cb_data = (u8*)state;
|
||||
//bsp_split(&editor->ui.panels, editor->ui.panels.root, 700, BSPSplit_YAxis, 0, 1);
|
||||
|
||||
file_async_read(lit_str("data/font.ttf"), ed_load_font_cb);
|
||||
|
||||
r32 w = 1400;
|
||||
r32 h = 700;
|
||||
r32 z = -1;
|
||||
r32 tri[] = {
|
||||
0, 0, 0, 0, 0,
|
||||
w, 0, z, 1, 0,
|
||||
w, h, z, 1, 1,
|
||||
0, h, z, 0, 1,
|
||||
};
|
||||
u32 indices[] = { 0, 1, 2, 0, 2, 3 };
|
||||
|
||||
String shd_v = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 pos;\n"
|
||||
"layout (location = 1) in vec2 auv;\n"
|
||||
"out vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) { \n"
|
||||
" gl_Position = proj * vec4(pos, 1); \n"
|
||||
" uv = auv;\n"
|
||||
"}\n"
|
||||
);
|
||||
String shd_f = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) { FragColor = texture(tex, uv) * vec4(1,1,1,1); }"
|
||||
);
|
||||
String shd_a[] = { lit_str("pos"), lit_str("auv") };
|
||||
String shd_u[] = { lit_str("proj") };
|
||||
b = geometry_buffer_create(
|
||||
tri, sizeof(tri) / sizeof(r32),
|
||||
indices, 6
|
||||
);
|
||||
shd = shader_create(shd_v, shd_f, shd_a, 2, shd_u, 1);
|
||||
vertex_attrib_pointer(b, shd, 3, shd.attrs[0], 5, 0);
|
||||
vertex_attrib_pointer(b, shd, 2, shd.attrs[1], 5, 3);
|
||||
|
||||
u32 tex_pix[] = { 0xFFFFFFFF, 0xFF00FFFF, 0xFFFFFF00, 0xFFFF00FF };
|
||||
tex = texture_create((u8*)tex_pix, 2, 2, 2);
|
||||
|
||||
ed_sculpture_visualizer_init(state);
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal u8*
|
||||
ed_leds_to_texture(App_State* state, Allocator_Scratch* scratch, u32 pixels_dim)
|
||||
{
|
||||
u32 at = 0;
|
||||
u32* pixels = allocator_alloc_array(scratch->a, u32, pixels_dim * pixels_dim);
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer leds = state->assemblies.pixel_buffers[a];
|
||||
for (u32 p = 0; p < leds.len; p++)
|
||||
{
|
||||
Assembly_Pixel led = leds.pixels[p];
|
||||
u32 index = at++;
|
||||
pixels[index] = (
|
||||
led.r << 0 |
|
||||
led.g << 8 |
|
||||
led.b << 16 |
|
||||
0xFF << 24
|
||||
);
|
||||
}
|
||||
}
|
||||
return (u8*)pixels;
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_sculpture_updated(App_State* state, r32 scale, r32 led_size)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
Editor* ed = state->editor;
|
||||
if (!ed) return;
|
||||
|
||||
scratch_get(scratch);
|
||||
|
||||
// NOTE(PS): we need to know the total number of leds in order to give them
|
||||
// texture coordinates
|
||||
u32 leds_count = 0;
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
|
||||
leds_count += pixels.len;
|
||||
}
|
||||
|
||||
// round up to a texture whose sides are powers of two
|
||||
u32 pixels_dim = (u32)floorf(sqrtf((r32)leds_count));
|
||||
pixels_dim = round_up_to_pow2_u32(pixels_dim);
|
||||
u32 pixels_count = pixels_dim * pixels_dim;
|
||||
r32 texel_dim = 1 / (r32)pixels_dim;
|
||||
|
||||
// NOTE(PS): Rebuild the sculpture geometry to point to the new
|
||||
// sculpture.
|
||||
Geo_Vertex_Buffer_Storage storage = (
|
||||
GeoVertexBufferStorage_Position |
|
||||
GeoVertexBufferStorage_TexCoord
|
||||
);
|
||||
|
||||
u32 verts_cap = leds_count * 4;
|
||||
u32 indices_cap = leds_count * 6;
|
||||
Geo_Quad_Buffer_Builder geo = geo_quad_buffer_builder_create(scratch.a, verts_cap, storage, indices_cap);
|
||||
geo_vertex_buffers_validate(&geo.buffer_vertex);
|
||||
|
||||
r32 r = led_size;
|
||||
u32 pixels_created = 0;
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
|
||||
for (u32 p = 0; p < pixels.len; p++)
|
||||
{
|
||||
v3 c = pixels.positions[p].xyz;
|
||||
c = HMM_MultiplyVec3f(c, scale);
|
||||
|
||||
u32 pixel_count = pixels_created++;
|
||||
u32 pixel_x = pixel_count % pixels_dim;
|
||||
u32 pixel_y = pixel_count / pixels_dim;
|
||||
r32 texel_x_min = (r32)pixel_x / (r32)pixels_dim;
|
||||
r32 texel_y_min = (r32)pixel_y / (r32)pixels_dim;
|
||||
r32 texel_x_max = texel_x_min + texel_dim;
|
||||
r32 texel_y_max = texel_y_min + texel_dim;
|
||||
|
||||
v2 t0 = (v2){texel_x_min, texel_y_min};
|
||||
v2 t1 = (v2){texel_x_max, texel_y_min};
|
||||
v2 t2 = (v2){texel_x_max, texel_y_max};
|
||||
v2 t3 = (v2){texel_x_min, texel_y_max};
|
||||
|
||||
v3 p0 = HMM_AddVec3(c, (v3){ -r, -r, 0 });
|
||||
v3 p1 = HMM_AddVec3(c, (v3){ r, -r, 0 });
|
||||
v3 p2 = HMM_AddVec3(c, (v3){ r, r, 0 });
|
||||
v3 p3 = HMM_AddVec3(c, (v3){ -r, r, 0 });
|
||||
geo_quad_buffer_builder_push_vt(&geo, p0, p1, p2, p3, t0, t1, t2, t3);
|
||||
if (p == 1008)
|
||||
{
|
||||
s32 x = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
geo_vertex_buffers_validate(&geo.buffer_vertex);
|
||||
|
||||
if (ed->sculpture_geo.indices_len != 0)
|
||||
{
|
||||
invalid_code_path;
|
||||
// TODO(PS): destroy the old geometry buffer or update it
|
||||
}
|
||||
ed->sculpture_geo = geometry_buffer_create(
|
||||
geo.buffer_vertex.values,
|
||||
geo.buffer_vertex.len,
|
||||
geo.buffer_index.values,
|
||||
geo.buffer_index.len
|
||||
);
|
||||
|
||||
vertex_attrib_pointer(ed->sculpture_geo, ed->sculpture_shd, 3, ed->sculpture_shd.attrs[0], 5, 0);
|
||||
vertex_attrib_pointer(ed->sculpture_geo, ed->sculpture_shd, 2, ed->sculpture_shd.attrs[1], 5, 3);
|
||||
|
||||
// TODO(PS): make this have enough pixels for the sculpture
|
||||
// TODO(PS): map leds to pixels
|
||||
|
||||
if (ed->sculpture_tex.w != 0)
|
||||
{
|
||||
invalid_code_path;
|
||||
// TODO(PS): destroy the old texture
|
||||
}
|
||||
|
||||
u8* pixels = ed_leds_to_texture(state, &scratch, pixels_dim);
|
||||
ed->sculpture_tex = texture_create(pixels, pixels_dim, pixels_dim, pixels_dim);
|
||||
|
||||
scratch_release(scratch);
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_frame_prepare(App_State* state)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
ui_frame_prepare(&state->editor->ui, state->editor->window_dim);
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_frame(App_State* state)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
Editor* ed = state->editor;
|
||||
UI* ui = &ed->ui;
|
||||
|
||||
{
|
||||
scratch_get(scratch);
|
||||
u32 w = ed->sculpture_tex.w;
|
||||
u8* pixels = ed_leds_to_texture(state, &scratch, w);
|
||||
texture_update(ed->sculpture_tex, pixels, w, w, w);
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
edr_render_begin(state);
|
||||
ui_draw(&state->editor->ui);
|
||||
edr_render(state);
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_cleanup(App_State* state)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
|
@ -1,376 +0,0 @@
|
|||
|
||||
static r32 z_ = 0;
|
||||
static r32 r_ = 0.3f;
|
||||
static r32 quad_verts[] = {
|
||||
-r_, -r_, z_, 1.0f, 0, 0,
|
||||
r_, -r_, z_, 1.0f, 1, 0,
|
||||
r_, r_, z_, 1.0f, 1, 1,
|
||||
-r_, r_, z_, 1.0f, 0, 1,
|
||||
};
|
||||
|
||||
static u32 quad_indices[] = {
|
||||
0, 1, 2,
|
||||
0, 2, 3,
|
||||
};
|
||||
|
||||
static String shader_code_vert_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec4 coordinates;\n"
|
||||
"layout (location = 1) in vec2 uv;\n"
|
||||
"out vec2 tex_coord;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = coordinates;\n"
|
||||
" tex_coord = uv;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String shader_code_vert_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"attribute vec4 coordinates;\n"
|
||||
"attribute vec2 uv;\n"
|
||||
"varying vec2 tex_coord;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = coordinates;\n"
|
||||
" tex_coord = uv;\n"
|
||||
"}");
|
||||
|
||||
static String shader_code_frag_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 tex_coord;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
"// FragColor = vec4(1,tex_coord.x,tex_coord.y,1);\n"
|
||||
" FragColor = texture(texture, tex_coord);\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String shader_code_frag_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"varying vec2 tex_coord;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = texture2D(texture, tex_coord);\n"
|
||||
" // vec4(1, tex_coord.x, tex_coord.y, 1);\n"
|
||||
"}");
|
||||
|
||||
static u32 pix[] = {
|
||||
0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000,
|
||||
0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF,
|
||||
0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000,
|
||||
};
|
||||
|
||||
void make_quad(Platform_Geometry_Buffer* geo, Platform_Shader* shd, Platform_Texture* tex)
|
||||
{
|
||||
// TODO(PS): TEMP
|
||||
#if defined(PLATFORM_win32)
|
||||
String shader_code_vert = shader_code_vert_win32;
|
||||
String shader_code_frag = shader_code_frag_win32;
|
||||
#elif defined(PLATFORM_wasm)
|
||||
String shader_code_vert = shader_code_vert_wasm;
|
||||
String shader_code_frag = shader_code_frag_wasm;
|
||||
#endif
|
||||
|
||||
*geo = platform_geometry_buffer_create(
|
||||
quad_verts, 24, quad_indices, 6
|
||||
);
|
||||
|
||||
String attribs[] = {
|
||||
lit_str("coordinates"),
|
||||
lit_str("uv"),
|
||||
};
|
||||
*shd = platform_shader_create(
|
||||
shader_code_vert, shader_code_frag, attribs, 2, 0, 0
|
||||
);
|
||||
|
||||
platform_vertex_attrib_pointer(*geo, *shd, 4, shd->attrs[0], 6, 0);
|
||||
platform_vertex_attrib_pointer(*geo, *shd, 2, shd->attrs[1], 6, 4);
|
||||
|
||||
*tex = platform_texture_create((u8*)pix, 4, 4, 4);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_load_font_cb(Platform_File_Async_Job_Args result, u8* user_data)
|
||||
{
|
||||
App_State* state = (App_State*)user_data;
|
||||
UI* ui = &state->editor->ui;
|
||||
|
||||
u8* f = result.data.base;
|
||||
stbtt_fontinfo font;
|
||||
if (!stbtt_InitFont(&font, f, stbtt_GetFontOffsetForIndex(f, 0)))
|
||||
{
|
||||
invalid_code_path;
|
||||
}
|
||||
|
||||
r32 scale = stbtt_ScaleForPixelHeight(&font, 18.0f);
|
||||
s32 ascent, descent, line_gap;
|
||||
stbtt_GetFontVMetrics(&font, &ascent, &descent, &line_gap);
|
||||
ui->font_ascent = (r32)ascent * scale;
|
||||
ui->font_descent = (r32)descent * scale;
|
||||
ui->font_line_gap = (r32)line_gap * scale;
|
||||
if (ui->font_line_gap == 0) ui->font_line_gap = 5;
|
||||
|
||||
String c = lit_str("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-=_+[]{}\\|;:'\",<.>/?`~");
|
||||
for (u64 i = 0; i < c.len; i++)
|
||||
{
|
||||
s32 w, h, xoff, yoff;
|
||||
u32 id = (u32)c.str[i];
|
||||
u8* bp = stbtt_GetCodepointBitmap(&font, 0, scale, (char)c.str[i], &w, &h, &xoff, &yoff);
|
||||
s32 x0, y0, x1, y1;
|
||||
stbtt_GetCodepointBitmapBoxSubpixel(&font, (char)c.str[i], scale, scale, 0, 0, &x0, &y0, &x1, &y1);
|
||||
|
||||
v2 offset = v2{ 0, (r32)y0 };
|
||||
texture_atlas_register(&state->editor->ui.atlas, bp, (u32)w, (u32)h, id, offset, TextureAtlasRegistration_PixelFormat_Alpha);
|
||||
stbtt_FreeBitmap(bp, 0);
|
||||
}
|
||||
|
||||
Texture_Atlas_Sprite m_sprite = texture_atlas_sprite_get(&state->editor->ui.atlas, (u32)'m');
|
||||
ui->font_space_width = (r32)(m_sprite.max_x - m_sprite.min_x);
|
||||
|
||||
platform_texture_update(ui->atlas_texture, ui->atlas.pixels, 1024, 1024, 1024);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_draw_panel(u8* user_data, BSP_Node_Id id, BSP_Node node, BSP_Area area)
|
||||
{
|
||||
App_State* state = (App_State*)user_data;
|
||||
UI* ui = &state->editor->ui;
|
||||
scratch_get(scratch);
|
||||
|
||||
UI_Layout title_layout = {};
|
||||
ui_layout_set_row_info(ui, &title_layout);
|
||||
title_layout.bounds_min = v2{ area.min.x, area.max.y - title_layout.row_height };
|
||||
title_layout.bounds_max = area.max;
|
||||
title_layout.at = title_layout.bounds_min;
|
||||
|
||||
UI_Layout panel_layout = {};
|
||||
ui_layout_set_row_info(ui, &panel_layout);
|
||||
panel_layout.bounds_min = area.min;
|
||||
panel_layout.bounds_max = v2{ area.max.x, title_layout.bounds_max.y };
|
||||
panel_layout.at = panel_layout.bounds_min;
|
||||
|
||||
ui_layout_push(ui, &panel_layout);
|
||||
|
||||
String title = {};
|
||||
switch (node.user_data)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
title = lit_str("None");
|
||||
} break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
ed_sculpture_visualizer(state);
|
||||
title = lit_str("Sculpture");
|
||||
} break;
|
||||
|
||||
invalid_default_case;
|
||||
}
|
||||
ui_layout_pop(ui);
|
||||
|
||||
ui_layout_push(ui, &title_layout);
|
||||
UI_Widget_Desc bg = {};
|
||||
bg.style.flags = UIWidgetStyle_Bg;
|
||||
bg.style.color_bg = v4{.4f,.4f,.4f,1};
|
||||
bg.style.sprite = WHITE_SPRITE_ID;
|
||||
bg.string = string_f(scratch.a, "%.*s_%u_title_bg", str_varg(title), id.value);
|
||||
bg.p_min = title_layout.bounds_min;
|
||||
bg.p_max = title_layout.bounds_max;
|
||||
UI_Widget_Result r = ui_widget_push(ui, bg);
|
||||
ui_layout_row_begin(&title_layout, 4);
|
||||
{
|
||||
ui_text(ui, title, BLACK_V4);
|
||||
}
|
||||
ui_layout_row_end(&title_layout);
|
||||
ui_widget_pop(ui, r.id);
|
||||
ui_layout_pop(ui);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_init(App_State* state)
|
||||
{
|
||||
Editor* editor = allocator_alloc_struct(permanent, Editor);
|
||||
state->editor = editor;
|
||||
editor->ui = ui_create(4096, 4096, state->input_state, permanent);
|
||||
editor->ui.draw_panel_cb = ed_draw_panel;
|
||||
editor->ui.draw_panel_cb_data = (u8*)state;
|
||||
//bsp_split(&editor->ui.panels, editor->ui.panels.root, 700, BSPSplit_YAxis, 0, 1);
|
||||
|
||||
// make the default quad for us to draw with
|
||||
// TODO(PS): this might be unnecessary with the per-frame buffer we use now
|
||||
make_quad(&editor->renderer.geo, &editor->renderer.shd, &editor->renderer.tex);
|
||||
|
||||
platform_file_async_read(lit_str("data/font.ttf"), ed_load_font_cb);
|
||||
|
||||
ed_sculpture_visualizer_init(state);
|
||||
}
|
||||
|
||||
internal u8*
|
||||
ed_leds_to_texture(App_State* state, Allocator_Scratch* scratch, u32 pixels_dim)
|
||||
{
|
||||
u32 at = 0;
|
||||
u32* pixels = allocator_alloc_array(scratch->a, u32, pixels_dim * pixels_dim);
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer leds = state->assemblies.pixel_buffers[a];
|
||||
for (u32 p = 0; p < leds.len; p++)
|
||||
{
|
||||
Assembly_Pixel led = leds.pixels[p];
|
||||
u32 index = at++;
|
||||
pixels[index] = (
|
||||
led.r << 0 |
|
||||
led.g << 8 |
|
||||
led.b << 16 |
|
||||
0xFF << 24
|
||||
);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
for (u32 y = 0; y < pixels_dim; y++)
|
||||
{
|
||||
for (u32 x = 0; x < pixels_dim; x++)
|
||||
{
|
||||
r32 rp = (r32)y / (r32)pixels_dim;
|
||||
r32 bp = (r32)x / (r32)pixels_dim;
|
||||
u8 rb = (u8)(255 * rp);
|
||||
u8 bb = (u8)(255 * bp);
|
||||
u32 c = (
|
||||
0xFF0000FF |
|
||||
(rb << 8) |
|
||||
(bb << 16)
|
||||
);
|
||||
pixels[(y * pixels_dim) + x] = c;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return (u8*)pixels;
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_sculpture_updated(App_State* state, r32 scale, r32 led_size)
|
||||
{
|
||||
Editor* ed = state->editor;
|
||||
if (!ed) return;
|
||||
|
||||
scratch_get(scratch);
|
||||
|
||||
// NOTE(PS): we need to know the total number of leds in order to give them
|
||||
// texture coordinates
|
||||
u32 leds_count = 0;
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
|
||||
leds_count += pixels.len;
|
||||
}
|
||||
|
||||
// round up to a texture whose sides are powers of two
|
||||
u32 pixels_dim = (u32)floorf(sqrtf((r32)leds_count));
|
||||
pixels_dim = round_up_to_pow2(pixels_dim);
|
||||
u32 pixels_count = pixels_dim * pixels_dim;
|
||||
r32 texel_dim = 1 / (r32)pixels_dim;
|
||||
|
||||
// NOTE(PS): Rebuild the sculpture geometry to point to the new
|
||||
// sculpture.
|
||||
Geo_Vertex_Buffer_Storage storage = (
|
||||
GeoVertexBufferStorage_Position |
|
||||
GeoVertexBufferStorage_TexCoord
|
||||
);
|
||||
u32 verts_cap = leds_count * 4;
|
||||
u32 indices_cap = leds_count * 6;
|
||||
Geo_Quad_Buffer_Builder geo = geo_quad_buffer_builder_create(scratch.a, verts_cap, storage, indices_cap);
|
||||
r32 r = led_size;
|
||||
|
||||
u32 pixels_created = 0;
|
||||
for (u32 a = 0; a < state->assemblies.len; a++)
|
||||
{
|
||||
Assembly_Pixel_Buffer pixels = state->assemblies.pixel_buffers[a];
|
||||
for (u32 p = 0; p < pixels.len; p++)
|
||||
{
|
||||
v3 c = pixels.positions[p].xyz;
|
||||
c *= scale;
|
||||
|
||||
u32 pixel_count = pixels_created++;
|
||||
u32 pixel_x = pixel_count % pixels_dim;
|
||||
u32 pixel_y = pixel_count / pixels_dim;
|
||||
r32 texel_x_min = (r32)pixel_x / (r32)pixels_dim;
|
||||
r32 texel_y_min = (r32)pixel_y / (r32)pixels_dim;
|
||||
r32 texel_x_max = texel_x_min + texel_dim;
|
||||
r32 texel_y_max = texel_y_min + texel_dim;
|
||||
|
||||
v2 t0 = v2{texel_x_min, texel_y_min};
|
||||
v2 t1 = v2{texel_x_max, texel_y_min};
|
||||
v2 t2 = v2{texel_x_max, texel_y_max};
|
||||
v2 t3 = v2{texel_x_min, texel_y_max};
|
||||
|
||||
v3 p0 = c + v3{ -r, -r, 0 };
|
||||
v3 p1 = c + v3{ r, -r, 0 };
|
||||
v3 p2 = c + v3{ r, r, 0 };
|
||||
v3 p3 = c + v3{ -r, r, 0 };
|
||||
geo_quad_buffer_builder_push(&geo, p0, p1, p2, p3, t0, t1, t2, t3);
|
||||
}
|
||||
}
|
||||
|
||||
if (ed->sculpture_geo.indices_len != 0)
|
||||
{
|
||||
invalid_code_path;
|
||||
// TODO(PS): destroy the old geometry buffer or update it
|
||||
}
|
||||
ed->sculpture_geo = platform_geometry_buffer_create(
|
||||
geo.buffer_vertex.values,
|
||||
geo.buffer_vertex.len,
|
||||
geo.buffer_index.values,
|
||||
geo.buffer_index.len
|
||||
);
|
||||
|
||||
platform_vertex_attrib_pointer(
|
||||
ed->sculpture_geo, ed->sculpture_shd, 3, ed->sculpture_shd.attrs[0], 5, 0
|
||||
);
|
||||
platform_vertex_attrib_pointer(
|
||||
ed->sculpture_geo, ed->sculpture_shd, 2, ed->sculpture_shd.attrs[1], 5, 3
|
||||
);
|
||||
|
||||
// TODO(PS): make this have enough pixels for the sculpture
|
||||
// TODO(PS): map leds to pixels
|
||||
|
||||
if (ed->sculpture_tex.w != 0)
|
||||
{
|
||||
invalid_code_path;
|
||||
// TODO(PS): destroy the old texture
|
||||
}
|
||||
|
||||
u8* pixels = ed_leds_to_texture(state, &scratch, pixels_dim);
|
||||
ed->sculpture_tex = platform_texture_create(pixels, pixels_dim, pixels_dim, pixels_dim);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_frame_prepare(App_State* state)
|
||||
{
|
||||
ui_frame_prepare(&state->editor->ui, state->editor->window_dim);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_frame(App_State* state)
|
||||
{
|
||||
Editor* ed = state->editor;
|
||||
UI* ui = &ed->ui;
|
||||
|
||||
{
|
||||
scratch_get(scratch);
|
||||
u32 w = ed->sculpture_tex.w;
|
||||
u8* pixels = ed_leds_to_texture(state, &scratch, w);
|
||||
platform_texture_update(ed->sculpture_tex, pixels, w, w, w);
|
||||
}
|
||||
|
||||
edr_render_begin(state);
|
||||
ui_draw(&state->editor->ui);
|
||||
edr_render(state);
|
||||
}
|
||||
|
||||
internal void
|
||||
ed_cleanup(App_State* state)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -3,21 +3,23 @@
|
|||
#ifndef LUMENARIUM_EDITOR_H
|
||||
#define LUMENARIUM_EDITOR_H
|
||||
|
||||
typedef struct Editor Editor;
|
||||
struct Editor
|
||||
{
|
||||
v2 content_scale;
|
||||
v2 window_dim;
|
||||
Editor_Renderer renderer;
|
||||
UI ui;
|
||||
|
||||
v3 camera_pos;
|
||||
|
||||
Platform_Geometry_Buffer sculpture_geo;
|
||||
Platform_Shader sculpture_shd;
|
||||
Platform_Texture sculpture_tex;
|
||||
Geometry_Buffer sculpture_geo;
|
||||
Shader sculpture_shd;
|
||||
Texture sculpture_tex;
|
||||
};
|
||||
|
||||
// NOTE(PS): call this any time sculpture data is updated if
|
||||
// you want to see the sculpture in the visualizer
|
||||
internal void ed_sculpture_updated(App_State* state);
|
||||
internal void ed_sculpture_updated(App_State* state, r32 scale, r32 led_size);
|
||||
|
||||
#endif //LUMENARIUM_EDITOR_H
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
|
||||
internal void
|
||||
edr_render_begin(App_State* state)
|
||||
{
|
||||
Graphics_Frame_Desc desc = {};
|
||||
desc.clear_color = (v4){ 0.1f, 0.1f, 0.1f, 1 };
|
||||
desc.viewport_min = (v2){ 0, 0 };
|
||||
v2 wd = state->editor->window_dim;
|
||||
v2 cs = state->editor->content_scale;
|
||||
desc.viewport_max = HMM_MultiplyVec2(wd, cs);
|
||||
frame_begin(desc);
|
||||
frame_clear();
|
||||
}
|
||||
|
||||
internal void
|
||||
edr_render(App_State* state)
|
||||
{
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
internal void
|
||||
edr_render_begin(App_State* state)
|
||||
{
|
||||
Platform_Graphics_Frame_Desc desc = {};
|
||||
desc.clear_color = { 0.1f, 0.1f, 0.1f, 1 };
|
||||
desc.viewport_min = { 0, 0 };
|
||||
desc.viewport_max = state->editor->window_dim;
|
||||
platform_frame_begin(desc);
|
||||
platform_frame_clear();
|
||||
}
|
||||
|
||||
internal void
|
||||
edr_render(App_State* state)
|
||||
{
|
||||
#if 0
|
||||
platform_geometry_bind(state->editor->renderer.geo);
|
||||
platform_texture_bind(state->editor->ui.atlas_texture);
|
||||
platform_shader_bind(state->editor->renderer.shd);
|
||||
platform_geometry_draw(state->editor->renderer.geo);
|
||||
#endif
|
||||
}
|
|
@ -3,11 +3,9 @@
|
|||
#ifndef LUMENARIUM_EDITOR_RENDERER_H
|
||||
#define LUMENARIUM_EDITOR_RENDERER_H
|
||||
|
||||
typedef struct Editor_Renderer Editor_Renderer;
|
||||
struct Editor_Renderer
|
||||
{
|
||||
Platform_Shader shd;
|
||||
Platform_Geometry_Buffer geo;
|
||||
Platform_Texture tex;
|
||||
};
|
||||
|
||||
#endif //LUMENARIUM_EDITOR_RENDERER_H
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#include "lumenarium_editor_sculpture_visualizer_shaders.h"
|
||||
|
||||
internal void
|
||||
ed_sculpture_visualizer_init(App_State* state)
|
||||
{
|
||||
Editor* editor = state->editor;
|
||||
|
||||
String vert = xplatform_shader_program_get_vert(sculpture_shd);
|
||||
String frag = xplatform_shader_program_get_frag(sculpture_shd);
|
||||
|
||||
String attrs[] = { lit_str("a_pos"), lit_str("a_uv") };
|
||||
String uniforms[] = { lit_str("proj") };
|
||||
editor->sculpture_shd = shader_create(vert, frag, attrs, 2, uniforms, 1);
|
||||
}
|
||||
|
||||
r32 cam_theta = 0;
|
||||
|
||||
internal void
|
||||
ed_sculpture_visualizer(App_State* state)
|
||||
{
|
||||
Editor* ed = state->editor;
|
||||
|
||||
// Set the viewport to the current layout's region so that the sculpture
|
||||
// never overlaps any other ui elements
|
||||
UI_Layout l = *ed->ui.layout;
|
||||
v2 view_dim = HMM_SubtractVec2(l.bounds_max, l.bounds_min);
|
||||
v2 view_min = l.bounds_min;
|
||||
v2 view_max = l.bounds_max;
|
||||
v2 view_min_scaled = HMM_MultiplyVec2(view_min, ed->content_scale);
|
||||
v2 view_dim_scaled = HMM_MultiplyVec2(view_dim, ed->content_scale);
|
||||
glViewport(
|
||||
(s32)view_min_scaled.x,
|
||||
(s32)view_min_scaled.y,
|
||||
(u32)view_dim_scaled.x,
|
||||
(u32)view_dim_scaled.y
|
||||
);
|
||||
|
||||
// TODO(PS): TEMPORARY CAMERA CODE
|
||||
cam_theta += 0.01f;
|
||||
r32 cam_r = 100;
|
||||
v3 camera_pos = (v3){sinf(cam_theta) * cam_r, 25, cosf(cam_theta) * cam_r};
|
||||
r32 aspect = view_dim.x / view_dim.y;
|
||||
m44 proj = HMM_Perspective(45.0, aspect, 0.01f, 500);
|
||||
m44 view = HMM_LookAt(camera_pos, (v3){0,0,0}, (v3){0,1,0});
|
||||
|
||||
shader_bind(ed->sculpture_shd);
|
||||
set_uniform(ed->sculpture_shd, 0, HMM_MultiplyMat4(proj, view));
|
||||
texture_bind(ed->sculpture_tex);
|
||||
geometry_bind(ed->sculpture_geo);
|
||||
|
||||
u32 i = 1008;
|
||||
u32 j = 2868;
|
||||
u32 k = ed->sculpture_geo.indices_len;
|
||||
u32 h = (i * 6) + 3;
|
||||
geometry_drawi(ed->sculpture_geo, k);
|
||||
|
||||
// reset the viewport for all other rendering
|
||||
v2 wds = HMM_MultiplyVec2(ed->window_dim, ed->content_scale);
|
||||
glViewport(0, 0, (s32)wds.x, (s32)wds.y);
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
|
||||
static String sculpture_shd_vert_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"out vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String sculpture_shd_vert_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"attribute vec3 a_pos;\n"
|
||||
"attribute vec2 a_uv;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String sculpture_shd_frag_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(texture, uv);\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String sculpture_shd_frag_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
" //gl_FragColor = texture2D(texture, uv) * color;\n"
|
||||
" gl_FragColor = vec4(uv.x,1,uv.y,1);\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
internal void
|
||||
ed_sculpture_visualizer_init(App_State* state)
|
||||
{
|
||||
Editor* editor = state->editor;
|
||||
|
||||
|
||||
#if defined(PLATFORM_win32)
|
||||
String vert = sculpture_shd_vert_win32;
|
||||
String frag = sculpture_shd_frag_win32;
|
||||
#elif defined(PLATFORM_wasm)
|
||||
String vert = sculpture_shd_vert_wasm;
|
||||
String frag = sculpture_shd_frag_wasm;
|
||||
#endif
|
||||
|
||||
String attrs[] = { lit_str("a_pos"), lit_str("a_uv") };
|
||||
String uniforms[] = { lit_str("proj") };
|
||||
editor->sculpture_shd = platform_shader_create(
|
||||
vert, frag, attrs, 2, uniforms, 1
|
||||
);
|
||||
}
|
||||
|
||||
r32 cam_theta = 0;
|
||||
|
||||
internal void
|
||||
ed_sculpture_visualizer(App_State* state)
|
||||
{
|
||||
Editor* ed = state->editor;
|
||||
|
||||
// Set the viewport to the current layout's region so that the sculpture
|
||||
// never overlaps any other ui elements
|
||||
UI_Layout l = *ed->ui.layout;
|
||||
v2 view_dim = l.bounds_max - l.bounds_min;
|
||||
glViewport(
|
||||
(s32)l.bounds_min.x,
|
||||
(s32)l.bounds_min.y,
|
||||
(s32)view_dim.x,
|
||||
(s32)view_dim.y
|
||||
);
|
||||
|
||||
// TODO(PS): TEMPORARY CAMERA CODE
|
||||
//cam_theta += 0.05f;
|
||||
v3 camera_pos = v3{sinf(cam_theta) * 50, 0, cosf(cam_theta) * 50};
|
||||
r32 aspect = view_dim.x / view_dim.y;
|
||||
m44 proj = HMM_Perspective(45.0, aspect, 0.01f, 500);
|
||||
m44 view = HMM_LookAt(camera_pos, v3{0,0,0}, v3{0,1,0});
|
||||
|
||||
platform_shader_bind(ed->sculpture_shd);
|
||||
platform_set_uniform(ed->sculpture_shd, 0, proj * view);
|
||||
platform_texture_bind(ed->sculpture_tex);
|
||||
platform_geometry_bind(ed->sculpture_geo);
|
||||
platform_geometry_draw(ed->sculpture_geo, ed->sculpture_geo.indices_len);
|
||||
|
||||
// reset the viewport for all other rendering
|
||||
glViewport(0, 0, (s32)ed->window_dim.x, (s32)ed->window_dim.y);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
global XPlatform_Shader_Program_Src sculpture_shd = {
|
||||
.win32_vert = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"out vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
"}"
|
||||
),
|
||||
.win32_frag = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(tex, uv);\n"
|
||||
"}"
|
||||
),
|
||||
|
||||
.osx_vert = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"out vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
"}"
|
||||
),
|
||||
.osx_frag = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(tex, uv);\n"
|
||||
"}"
|
||||
),
|
||||
|
||||
.wasm_vert = lit_str(
|
||||
"precision highp float;\n"
|
||||
"attribute vec3 a_pos;\n"
|
||||
"attribute vec2 a_uv;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
"}"
|
||||
),
|
||||
.wasm_frag = lit_str(
|
||||
"precision highp float;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" //gl_FragColor = texture2D(tex, uv) * color;\n"
|
||||
" gl_FragColor = vec4(uv.x,1,uv.y,1);\n"
|
||||
"}"
|
||||
),
|
||||
};
|
|
@ -1,55 +1,6 @@
|
|||
#define WHITE_SPRITE_ID 511
|
||||
|
||||
static String ui_shader_vert_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"layout (location = 2) in vec4 a_color;\n"
|
||||
"out vec2 uv;\n"
|
||||
"out vec4 color;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
" color = a_color;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String ui_shader_vert_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"attribute vec3 a_pos;\n"
|
||||
"attribute vec2 a_uv;\n"
|
||||
"attribute vec4 a_color;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"varying vec4 color;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
" color = a_color;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String ui_shader_frag_win32 = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"in vec4 color;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(texture, uv) * color;\n"
|
||||
"}"
|
||||
);
|
||||
|
||||
static String ui_shader_frag_wasm = lit_str(
|
||||
"precision highp float;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"varying vec4 color;\n"
|
||||
"uniform sampler2D texture;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = texture2D(texture, uv) * color;\n"
|
||||
"}"
|
||||
);
|
||||
#include "lumenarium_editor_ui_shaders.h"
|
||||
|
||||
internal UI
|
||||
ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
|
||||
|
@ -66,7 +17,7 @@ ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
|
|||
result.widgets.states_hash = allocator_alloc_array(a, u32, result.widgets.states_cap);
|
||||
|
||||
result.panels = bsp_create(a, 32);
|
||||
result.panels.root = bsp_push(&result.panels, {0}, {v2{},v2{1400, 800}}, 1);
|
||||
result.panels.root = bsp_push(&result.panels, (BSP_Node_Id){0}, (BSP_Area){(v2){},(v2){1400, 800}}, 1);
|
||||
|
||||
// Per Frame Vertex Buffer
|
||||
Geo_Vertex_Buffer_Storage storage = (
|
||||
|
@ -76,40 +27,27 @@ ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a)
|
|||
);
|
||||
result.geo = geo_quad_buffer_builder_create(a, verts_cap, storage, verts_cap * 2);
|
||||
|
||||
result.per_frame_buffer = platform_geometry_buffer_create(
|
||||
result.geo.buffer_vertex.values,
|
||||
result.geo.buffer_vertex.cap,
|
||||
result.geo.buffer_index.values,
|
||||
result.geo.buffer_index.cap
|
||||
);
|
||||
result.per_frame_buffer = geometry_buffer_create(
|
||||
result.geo.buffer_vertex.values,
|
||||
result.geo.buffer_vertex.cap,
|
||||
result.geo.buffer_index.values,
|
||||
result.geo.buffer_index.cap
|
||||
);
|
||||
|
||||
#if defined(PLATFORM_win32)
|
||||
String vert = ui_shader_vert_win32;
|
||||
String frag = ui_shader_frag_win32;
|
||||
#elif defined(PLATFORM_wasm)
|
||||
String vert = ui_shader_vert_wasm;
|
||||
String frag = ui_shader_frag_wasm;
|
||||
#endif
|
||||
String vert = xplatform_shader_program_get_vert(ui_shader);
|
||||
String frag = xplatform_shader_program_get_frag(ui_shader);
|
||||
|
||||
String attrs[] = { lit_str("a_pos"), lit_str("a_uv"), lit_str("a_color") };
|
||||
String uniforms[] = { lit_str("proj") };
|
||||
result.shader = platform_shader_create(
|
||||
vert, frag, attrs, 3, uniforms, 1
|
||||
);
|
||||
result.shader = shader_create(vert, frag, attrs, 3, uniforms, 1);
|
||||
|
||||
platform_vertex_attrib_pointer(
|
||||
result.per_frame_buffer, result.shader, 3, result.shader.attrs[0], 9, 0
|
||||
);
|
||||
platform_vertex_attrib_pointer(
|
||||
result.per_frame_buffer, result.shader, 2, result.shader.attrs[1], 9, 3
|
||||
);
|
||||
platform_vertex_attrib_pointer(
|
||||
result.per_frame_buffer, result.shader, 4, result.shader.attrs[2], 9, 5
|
||||
);
|
||||
vertex_attrib_pointer(result.per_frame_buffer, result.shader, 3, result.shader.attrs[0], 9, 0);
|
||||
vertex_attrib_pointer(result.per_frame_buffer, result.shader, 2, result.shader.attrs[1], 9, 3);
|
||||
vertex_attrib_pointer(result.per_frame_buffer, result.shader, 4, result.shader.attrs[2], 9, 5);
|
||||
|
||||
// Texture Atlas
|
||||
result.atlas = texture_atlas_create(1024, 1024, 512, permanent);
|
||||
result.atlas_texture = platform_texture_create(result.atlas.pixels, 1024, 1024, 1024);
|
||||
result.atlas_texture = texture_create(result.atlas.pixels, 1024, 1024, 1024);
|
||||
|
||||
u32 white_sprite[] = {
|
||||
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
|
||||
|
@ -127,39 +65,40 @@ internal void
|
|||
ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c)
|
||||
{
|
||||
v3 p0 = pmin;
|
||||
v3 p1 = v3{pmax.x, pmin.y, pmin.z};
|
||||
v3 p1 = (v3){pmax.x, pmin.y, pmin.z};
|
||||
v3 p2 = pmax;
|
||||
v3 p3 = v3{pmin.x, pmax.y, pmin.z};
|
||||
v3 p3 = (v3){pmin.x, pmax.y, pmin.z};
|
||||
v2 t0 = tmin;
|
||||
v2 t1 = v2{tmax.x,tmin.y};
|
||||
v2 t1 = (v2){tmax.x,tmin.y};
|
||||
v2 t2 = tmax;
|
||||
v2 t3 = v2{tmin.x,tmax.y};
|
||||
geo_quad_buffer_builder_push(&ui->geo, p0, p1, p2, p3, t0, t1, t2, t3, c);
|
||||
v2 t3 = (v2){tmin.x,tmax.y};
|
||||
geo_quad_buffer_builder_push_vtc(&ui->geo, p0, p1, p2, p3, t0, t1, t2, t3, c);
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_sprite_register(UI* ui, u8* pixels, u32 w, u32 h, u32 id)
|
||||
{
|
||||
texture_atlas_register(&ui->atlas, pixels, w, h, id, v2{0,0}, TextureAtlasRegistration_PixelFormat_RGBA);
|
||||
platform_texture_update(ui->atlas_texture, ui->atlas.pixels, ui->atlas.width, ui->atlas.height, ui->atlas.width);
|
||||
texture_atlas_register(&ui->atlas, pixels, w, h, id, (v2){0,0}, TextureAtlasRegistration_PixelFormat_RGBA);
|
||||
texture_update(ui->atlas_texture, ui->atlas.pixels, ui->atlas.width, ui->atlas.height, ui->atlas.width);
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color)
|
||||
ui_sprite_push_color(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color)
|
||||
{
|
||||
Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(&ui->atlas, id);
|
||||
v4 uv = texture_atlas_sprite_get_uvs(&ui->atlas, sprite);
|
||||
pmin.XY += sprite.draw_offset;
|
||||
pmax.XY += sprite.draw_offset;
|
||||
pmin.XY = HMM_AddVec2(pmin.XY, sprite.draw_offset);
|
||||
pmax.XY = HMM_AddVec2(pmax.XY, sprite.draw_offset);
|
||||
ui_quad_push(ui, pmin, pmax, uv.xy, uv.zw, color);
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id)
|
||||
{
|
||||
ui_sprite_push(ui, pmin, pmax, id, v4{1,1,1,1});
|
||||
ui_sprite_push_color(ui, pmin, pmax, id, (v4){1,1,1,1});
|
||||
}
|
||||
|
||||
typedef struct UI_Char_Draw_Cmd UI_Char_Draw_Cmd;
|
||||
struct UI_Char_Draw_Cmd
|
||||
{
|
||||
v4 uv;
|
||||
|
@ -177,17 +116,17 @@ ui_sprite_char_get_draw_cmd(UI* ui, v3 at, u32 codepoint)
|
|||
Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(&ui->atlas, codepoint);
|
||||
result.uv = texture_atlas_sprite_get_uvs(&ui->atlas, sprite);
|
||||
|
||||
v3 dim = v3{
|
||||
v3 dim = (v3){
|
||||
(r32)(sprite.max_x - sprite.min_x),
|
||||
(r32)(sprite.max_y - sprite.min_y),
|
||||
0,
|
||||
};
|
||||
result.pmin = at;
|
||||
result.pmin.XY += sprite.draw_offset;
|
||||
result.pmin.XY = HMM_AddVec2(result.pmin.XY, sprite.draw_offset);
|
||||
result.pmin.XY = v2_floor(result.pmin.XY);
|
||||
result.pmax = result.pmin + dim;
|
||||
result.pmax = HMM_AddVec3(result.pmin, dim);
|
||||
|
||||
result.baseline_after = v3{ result.pmax.x, at.y, at.z };
|
||||
result.baseline_after = (v3){ result.pmax.x, at.y, at.z };
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -204,15 +143,15 @@ ui_frame_prepare(UI* ui, v2 window_dim)
|
|||
ui->widgets.active_parent = ui->widgets.root;
|
||||
|
||||
BSP_Node* panel_root = bsp_get(&ui->panels, ui->panels.root);
|
||||
if (window_dim.x != 0 && window_dim.y != 0 && window_dim != panel_root->area.max)
|
||||
if (window_dim.x != 0 && window_dim.y != 0 && !HMM_EqualsVec2(window_dim, panel_root->area.max))
|
||||
{
|
||||
BSP_Area area = {};
|
||||
area.min = v2{0,0};
|
||||
area.min = (v2){0,0};
|
||||
area.max = window_dim;
|
||||
bsp_node_area_update(&ui->panels, ui->panels.root, area);
|
||||
}
|
||||
|
||||
v2 half_d = window_dim * 0.5f;
|
||||
v2 half_d = HMM_MultiplyVec2f(window_dim, 0.5f);
|
||||
ui->proj = HMM_Orthographic(0, window_dim.x, window_dim.y, 0, 0.01f, 100);
|
||||
|
||||
if (ui->widget_next_hot.value != 0)
|
||||
|
@ -237,16 +176,16 @@ ui_draw_panel(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data)
|
|||
BSP_Area area = node->area;
|
||||
|
||||
if (ui->draw_panel_cb) ui->draw_panel_cb(ui->draw_panel_cb_data, id, *node, area);
|
||||
|
||||
|
||||
r32 z = -1;
|
||||
v3 l0p0 = v3{ area.min.x, area.min.y, z }; // left side
|
||||
v3 l0p1 = v3{ area.min.x + 1, area.max.y, z };
|
||||
v3 l1p0 = v3{ area.max.x - 1, area.min.y, z }; // right side
|
||||
v3 l1p1 = v3{ area.max.x, area.max.y, z };
|
||||
v3 l2p0 = v3{ area.min.x, area.min.y , z }; // bottom side
|
||||
v3 l2p1 = v3{ area.max.x, area.min.y + 1, z };
|
||||
v3 l3p0 = v3{ area.min.x, area.max.y , z }; // top side
|
||||
v3 l3p1 = v3{ area.max.x, area.max.y + 1, z };
|
||||
v3 l0p0 = (v3){ area.min.x, area.min.y, z }; // left side
|
||||
v3 l0p1 = (v3){ area.min.x + 1, area.max.y, z };
|
||||
v3 l1p0 = (v3){ area.max.x - 1, area.min.y, z }; // right side
|
||||
v3 l1p1 = (v3){ area.max.x, area.max.y, z };
|
||||
v3 l2p0 = (v3){ area.min.x, area.min.y , z }; // bottom side
|
||||
v3 l2p1 = (v3){ area.max.x, area.min.y + 1, z };
|
||||
v3 l3p0 = (v3){ area.min.x, area.max.y , z }; // top side
|
||||
v3 l3p1 = (v3){ area.max.x, area.max.y + 1, z };
|
||||
u32 sid = WHITE_SPRITE_ID;
|
||||
v4 c = WHITE_V4;
|
||||
if (rect2_contains(area.min, area.max, ui->input->frame_hot->mouse_pos))
|
||||
|
@ -254,37 +193,39 @@ ui_draw_panel(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data)
|
|||
c = PINK_V4;
|
||||
}
|
||||
|
||||
ui_sprite_push(ui, l0p0, l0p1, sid, c);
|
||||
ui_sprite_push(ui, l1p0, l1p1, sid, c);
|
||||
ui_sprite_push(ui, l2p0, l2p1, sid, c);
|
||||
ui_sprite_push(ui, l3p0, l3p1, sid, c);
|
||||
#if 0
|
||||
ui_sprite_push_color(ui, l0p0, l0p1, sid, c);
|
||||
ui_sprite_push_color(ui, l1p0, l1p1, sid, c);
|
||||
ui_sprite_push_color(ui, l2p0, l2p1, sid, c);
|
||||
ui_sprite_push_color(ui, l3p0, l3p1, sid, c);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal void
|
||||
ui_draw(UI* ui)
|
||||
{
|
||||
bsp_walk_inorder(&ui->panels, ui->panels.root, ui_draw_panel, (u8*)ui);
|
||||
|
||||
|
||||
u32 widget_count = ui->widgets.free_len;
|
||||
r32 range_min = -10;
|
||||
r32 range_max = -1;
|
||||
r32 range_step = (range_max - range_min) / (r32)(widget_count * 4);
|
||||
ui_widgets_to_geometry_recursive(ui, ui->widgets.root, -10, range_step);
|
||||
|
||||
platform_geometry_buffer_update(
|
||||
&ui->per_frame_buffer,
|
||||
(r32*)ui->geo.buffer_vertex.values,
|
||||
0,
|
||||
ui->geo.buffer_vertex.len * ui->geo.buffer_vertex.stride,
|
||||
ui->geo.buffer_index.values,
|
||||
0,
|
||||
ui->geo.buffer_index.len
|
||||
);
|
||||
platform_shader_bind(ui->shader);
|
||||
platform_set_uniform(ui->shader, 0, ui->proj);
|
||||
platform_texture_bind(ui->atlas_texture);
|
||||
platform_geometry_bind(ui->per_frame_buffer);
|
||||
platform_geometry_draw(ui->per_frame_buffer, ui->geo.buffer_index.len);
|
||||
geometry_buffer_update(
|
||||
&ui->per_frame_buffer,
|
||||
(r32*)ui->geo.buffer_vertex.values,
|
||||
0,
|
||||
ui->geo.buffer_vertex.len * ui->geo.buffer_vertex.stride,
|
||||
ui->geo.buffer_index.values,
|
||||
0,
|
||||
ui->geo.buffer_index.len
|
||||
);
|
||||
shader_bind(ui->shader);
|
||||
set_uniform(ui->shader, 0, ui->proj);
|
||||
texture_bind(ui->atlas_texture);
|
||||
geometry_bind(ui->per_frame_buffer);
|
||||
geometry_drawi(ui->per_frame_buffer, ui->geo.buffer_index.len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
@ -296,13 +237,13 @@ ui_widget_id_create(String string, u32 index)
|
|||
assert(string.len != 0 && string.str != 0);
|
||||
UI_Widget_Id result = {};
|
||||
zero_struct(result);
|
||||
result.value = hash_djb2_to_u32(string);
|
||||
result.value = hash_djb2_string_to_u32(string);
|
||||
result.index = index;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal UI_Widget_State*
|
||||
ui_widget_state_get(UI_Widget_Pool* pool, UI_Widget_Id id)
|
||||
ui_widget_pool_state_get(UI_Widget_Pool* pool, UI_Widget_Id id)
|
||||
{
|
||||
u32 index = hash_table_find(pool->states_hash, pool->states_cap, id.value);
|
||||
assert(index != pool->states_cap);
|
||||
|
@ -312,7 +253,7 @@ ui_widget_state_get(UI_Widget_Pool* pool, UI_Widget_Id id)
|
|||
internal UI_Widget_State*
|
||||
ui_widget_state_get(UI* ui, UI_Widget_Id id)
|
||||
{
|
||||
return ui_widget_state_get(&ui->widgets, id);
|
||||
return ui_widget_pool_state_get(&ui->widgets, id);
|
||||
}
|
||||
|
||||
internal UI_Widget*
|
||||
|
@ -377,7 +318,7 @@ ui_widget_next_hot_set(UI* ui, UI_Widget* w)
|
|||
if (w) {
|
||||
ui->widget_next_hot = w->id;
|
||||
} else {
|
||||
ui->widget_next_hot = UI_Widget_Id{0};
|
||||
ui->widget_next_hot = (UI_Widget_Id){0};
|
||||
}
|
||||
ui->widget_next_hot_frames = 0;
|
||||
}
|
||||
|
@ -388,7 +329,7 @@ ui_widget_hot_set(UI* ui, UI_Widget* w)
|
|||
if (w) {
|
||||
ui->widget_hot = w->id;
|
||||
} else {
|
||||
ui->widget_hot = UI_Widget_Id{0};
|
||||
ui->widget_hot = (UI_Widget_Id){0};
|
||||
}
|
||||
ui->widget_hot_frames = 0;
|
||||
}
|
||||
|
@ -398,7 +339,7 @@ ui_widget_push(UI* ui, UI_Widget_Desc desc)
|
|||
{
|
||||
UI_Widget_Result result = {};
|
||||
zero_struct(result);
|
||||
v2 dim = desc.p_max - desc.p_min;
|
||||
v2 dim = HMM_SubtractVec2(desc.p_max, desc.p_min);
|
||||
if (dim.x == 0 || dim.y == 0) return result;
|
||||
|
||||
UI_Widget* w = ui_widget_pool_push(&ui->widgets, desc.string);
|
||||
|
@ -410,9 +351,9 @@ ui_widget_push(UI* ui, UI_Widget_Desc desc)
|
|||
|
||||
v2 mouse_p = ui->input->frame_hot->mouse_pos;
|
||||
bool mouse_over = (
|
||||
mouse_p.x >= desc.p_min.x && mouse_p.x <= desc.p_max.x &&
|
||||
mouse_p.y >= desc.p_min.y && mouse_p.y <= desc.p_max.y
|
||||
);
|
||||
mouse_p.x >= desc.p_min.x && mouse_p.x <= desc.p_max.x &&
|
||||
mouse_p.y >= desc.p_min.y && mouse_p.y <= desc.p_max.y
|
||||
);
|
||||
|
||||
UI_Widget_Style_Flags flags = desc.style.flags;
|
||||
UI_Widget_Style_Flags mask_drag = (UIWidgetStyle_MouseDragH | UIWidgetStyle_MouseDragV);
|
||||
|
@ -473,11 +414,12 @@ ui_widget_push(UI* ui, UI_Widget_Desc desc)
|
|||
has_flag(flags, UIWidgetStyle_MouseDragH) ? 1.0f : 0.0f,
|
||||
has_flag(flags, UIWidgetStyle_MouseDragV) ? 1.0f : 0.0f
|
||||
};
|
||||
v2 drag = ui->input->frame_hot->mouse_pos - w->desc.p_min;
|
||||
drag = v2{ clamp(0, drag.x, w->desc.p_max.x), clamp(0, drag.y, w->desc.p_max.y) };
|
||||
drag *= drag_pct_mask;
|
||||
v2 drag_pct = drag / dim;
|
||||
drag_pct = v2{ clamp(0, drag_pct.x, 1), clamp(0, drag_pct.y, 1) };
|
||||
v2 mp = ui->input->frame_hot->mouse_pos;
|
||||
v2 drag = HMM_SubtractVec2(mp, w->desc.p_min);
|
||||
drag = (v2){ clamp(0, drag.x, w->desc.p_max.x), clamp(0, drag.y, w->desc.p_max.y) };
|
||||
drag = HMM_MultiplyVec2(drag, drag_pct_mask);
|
||||
v2 drag_pct = HMM_DivideVec2(drag, dim);
|
||||
drag_pct = (v2){ clamp(0, drag_pct.x, 1), clamp(0, drag_pct.y, 1) };
|
||||
result.drag = drag_pct;
|
||||
|
||||
state->scroll = drag_pct;
|
||||
|
@ -520,17 +462,17 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s
|
|||
|
||||
if (has_flag(child->desc.style.flags, UIWidgetStyle_Outline))
|
||||
{
|
||||
ui_sprite_push(ui, bg_min, bg_max, WHITE_SPRITE_ID, color_fg);
|
||||
ui_sprite_push_color(ui, bg_min, bg_max, WHITE_SPRITE_ID, color_fg);
|
||||
z_at += z_step;
|
||||
bg_min += v3{ 1, 1, 0};
|
||||
bg_max -= v3{ 1, 1, 0};
|
||||
bg_min = HMM_AddVec3(bg_min, (v3){ 1, 1, 0});
|
||||
bg_max = HMM_SubtractVec3(bg_max, (v3){ 1, 1, 0});
|
||||
}
|
||||
|
||||
if (has_flag(child->desc.style.flags, UIWidgetStyle_Bg))
|
||||
{
|
||||
bg_min.z = z_at;
|
||||
bg_max.z = z_at;
|
||||
ui_sprite_push(ui, bg_min, bg_max, desc.style.sprite, color_bg);
|
||||
ui_sprite_push_color(ui, bg_min, bg_max, desc.style.sprite, color_bg);
|
||||
z_at += z_step;
|
||||
}
|
||||
|
||||
|
@ -546,13 +488,13 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s
|
|||
|
||||
if (has_flag(child->desc.style.flags, UIWidgetStyle_LineInsteadOfFill))
|
||||
{
|
||||
fill_min = v3{ fill_x, bg_min.y, z_at };
|
||||
fill_max = v3{ fill_x + 1, bg_max.y, z_at };
|
||||
fill_min = (v3){ fill_x, bg_min.y, z_at };
|
||||
fill_max = (v3){ fill_x + 1, bg_max.y, z_at };
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_min = bg_min;
|
||||
fill_max = v3{ fill_x, bg_max.y, z_at };
|
||||
fill_max = (v3){ fill_x, bg_max.y, z_at };
|
||||
}
|
||||
}
|
||||
else if (has_flag(child->desc.style.flags, UIWidgetStyle_FillV))
|
||||
|
@ -561,17 +503,17 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s
|
|||
|
||||
if (has_flag(child->desc.style.flags, UIWidgetStyle_LineInsteadOfFill))
|
||||
{
|
||||
fill_min = v3{ bg_min.x, fill_y, z_at };
|
||||
fill_max = v3{ bg_max.x, fill_y + 1, z_at };
|
||||
fill_min = (v3){ bg_min.x, fill_y, z_at };
|
||||
fill_max = (v3){ bg_max.x, fill_y + 1, z_at };
|
||||
}
|
||||
else
|
||||
{
|
||||
fill_min = bg_min;
|
||||
fill_max = v3{ bg_max.x, fill_y, z_at };
|
||||
fill_max = (v3){ bg_max.x, fill_y, z_at };
|
||||
}
|
||||
}
|
||||
|
||||
ui_sprite_push(ui, fill_min, fill_max, WHITE_SPRITE_ID, color_fg);
|
||||
ui_sprite_push_color(ui, fill_min, fill_max, WHITE_SPRITE_ID, color_fg);
|
||||
z_at += z_step;
|
||||
}
|
||||
|
||||
|
@ -667,7 +609,7 @@ ui_layout_row_begin(UI_Layout* layout, u32 cols)
|
|||
layout->cols = cols;
|
||||
}
|
||||
internal void
|
||||
ui_layout_row_begin(UI* ui, u32 cols) { ui_layout_row_begin(ui->layout, cols); }
|
||||
ui_row_begin(UI* ui, u32 cols) { ui_layout_row_begin(ui->layout, cols); }
|
||||
|
||||
internal void
|
||||
ui_layout_row_end(UI_Layout* layout)
|
||||
|
@ -675,7 +617,7 @@ ui_layout_row_end(UI_Layout* layout)
|
|||
layout->mode = UILayout_Columns;
|
||||
}
|
||||
internal void
|
||||
ui_layout_row_end(UI* ui) { ui_layout_row_end(ui->layout); }
|
||||
ui_row_end(UI* ui) { ui_layout_row_end(ui->layout); }
|
||||
|
||||
internal UI_Layout_Bounds
|
||||
ui_layout_get_next(UI_Layout* layout)
|
||||
|
@ -693,8 +635,8 @@ ui_layout_get_next(UI_Layout* layout)
|
|||
case UILayout_Columns:
|
||||
{
|
||||
result.min = layout->at;
|
||||
result.max = v2{ layout->bounds_max.x, layout->at.y + layout->row_height };
|
||||
layout->at = v2{ layout->bounds_min.x, result.max.y + layout->row_gap};
|
||||
result.max = (v2){ layout->bounds_max.x, layout->at.y + layout->row_height };
|
||||
layout->at = (v2){ layout->bounds_min.x, result.max.y + layout->row_gap};
|
||||
} break;
|
||||
|
||||
case UILayout_Rows:
|
||||
|
@ -702,11 +644,11 @@ ui_layout_get_next(UI_Layout* layout)
|
|||
r32 col_width = (layout->bounds_max.x - layout->bounds_min.x) / layout->cols;
|
||||
col_width -= (layout->cols - 1) * layout->col_gap;
|
||||
result.min = layout->at;
|
||||
result.max = v2{ layout->at.x + col_width, layout->at.y + layout->row_height };
|
||||
layout->at = v2{ result.max.x + layout->col_gap, layout->at.y };
|
||||
result.max = (v2){ layout->at.x + col_width, layout->at.y + layout->row_height };
|
||||
layout->at = (v2){ result.max.x + layout->col_gap, layout->at.y };
|
||||
if (layout->at.x >= layout->bounds_max.x)
|
||||
{
|
||||
layout->at = v2{
|
||||
layout->at = (v2){
|
||||
layout->bounds_min.x,
|
||||
layout->at.y + layout->row_height + layout->row_gap
|
||||
};
|
||||
|
@ -725,8 +667,6 @@ ui_layout_get_next(UI_Layout* layout)
|
|||
|
||||
return result;
|
||||
}
|
||||
internal UI_Layout_Bounds
|
||||
ui_layout_get_next(UI* ui) { return ui_layout_get_next(ui->layout); }
|
||||
|
||||
|
||||
///////////////////////////////////////////
|
||||
|
@ -739,32 +679,32 @@ global UI_Style_Sheet ui_default_style_sheet = {};
|
|||
internal void
|
||||
ui_create_default_style_sheet()
|
||||
{
|
||||
ui_default_style_sheet.styles[UIWidget_Text] = {
|
||||
(UIWidgetStyle_TextWrap), v4{0,0,0,0}, WHITE_V4, WHITE_SPRITE_ID
|
||||
ui_default_style_sheet.styles[UIWidget_Text] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextWrap), (v4){0,0,0,0}, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_Button] = {
|
||||
ui_default_style_sheet.styles[UIWidget_Button] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseClick), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_Toggle] = {
|
||||
ui_default_style_sheet.styles[UIWidget_Toggle] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_MouseClick), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_Menu] = ui_default_style_sheet.styles[UIWidget_Toggle];
|
||||
ui_default_style_sheet.styles[UIWidget_Dropdown] = ui_default_style_sheet.styles[UIWidget_Toggle];
|
||||
|
||||
ui_default_style_sheet.styles[UIWidget_HSlider] = {
|
||||
ui_default_style_sheet.styles[UIWidget_HSlider] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDragH | UIWidgetStyle_FillH ), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_VSlider] = {
|
||||
ui_default_style_sheet.styles[UIWidget_VSlider] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDragV | UIWidgetStyle_FillV ), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_HScroll] = {
|
||||
ui_default_style_sheet.styles[UIWidget_HScroll] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDragH | UIWidgetStyle_FillH | UIWidgetStyle_LineInsteadOfFill ), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
ui_default_style_sheet.styles[UIWidget_VScroll] = {
|
||||
ui_default_style_sheet.styles[UIWidget_VScroll] = (UI_Widget_Style) {
|
||||
(UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDragV | UIWidgetStyle_FillV | UIWidgetStyle_LineInsteadOfFill ), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
|
||||
ui_default_style_sheet.styles[UIWidget_Window] = {
|
||||
ui_default_style_sheet.styles[UIWidget_Window] = (UI_Widget_Style){
|
||||
(UIWidgetStyle_TextWrap), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID
|
||||
};
|
||||
|
||||
|
@ -780,7 +720,7 @@ ui_get_style(UI* ui, UI_Widget_Kind kind)
|
|||
internal UI_Widget_Desc
|
||||
ui_layout_next_widget(UI* ui, UI_Widget_Kind kind)
|
||||
{
|
||||
UI_Layout_Bounds b = ui_layout_get_next(ui);
|
||||
UI_Layout_Bounds b = ui_layout_get_next(ui->layout);
|
||||
UI_Widget_Desc d = {};
|
||||
zero_struct(d);
|
||||
d.p_min = b.min;
|
||||
|
@ -790,7 +730,7 @@ ui_layout_next_widget(UI* ui, UI_Widget_Kind kind)
|
|||
}
|
||||
|
||||
internal void
|
||||
ui_text(UI* ui, String string, v4 color)
|
||||
ui_textc(UI* ui, String string, v4 color)
|
||||
{
|
||||
UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Text);
|
||||
d.string = string;
|
||||
|
@ -818,7 +758,8 @@ ui_text_f(UI* ui, char* fmt, ...)
|
|||
String string = string_fv(scratch.a, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return ui_text(ui, string);
|
||||
ui_text(ui, string);
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
internal bool
|
||||
|
@ -854,25 +795,25 @@ ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 ro
|
|||
scratch_get(scratch);
|
||||
|
||||
r32 scroll_bar_dim = 15;
|
||||
v2 scroll_bars_area = v2{0, 0};
|
||||
v2 scroll_bars_area = (v2){0, 0};
|
||||
v2 scroll_area_min = bounds_min;
|
||||
v2 scroll_area_max = bounds_max - scroll_bars_area;
|
||||
v2 scroll_area_dim = scroll_area_max - scroll_area_min;
|
||||
v2 scroll_area_max = HMM_SubtractVec2(bounds_max, scroll_bars_area);
|
||||
v2 scroll_area_dim = HMM_SubtractVec2(scroll_area_max, scroll_area_min);
|
||||
|
||||
v2 scroll_offset = {};
|
||||
zero_struct(scroll_offset);
|
||||
r32 rows_avail = floorf(scroll_area_dim.y / ui->layout->row_height);
|
||||
if (rows > rows_avail)
|
||||
{
|
||||
scroll_bars_area = v2{ scroll_bar_dim, 0};
|
||||
scroll_bars_area = (v2){ scroll_bar_dim, 0};
|
||||
scroll_area_min = bounds_min;
|
||||
scroll_area_max = bounds_max - scroll_bars_area;
|
||||
scroll_area_dim = scroll_area_max - scroll_area_min;
|
||||
scroll_area_max = HMM_SubtractVec2(bounds_max, scroll_bars_area);
|
||||
scroll_area_dim = HMM_SubtractVec2(scroll_area_max, scroll_area_min);
|
||||
|
||||
UI_Widget_Desc vscroll_d = {};
|
||||
zero_struct(vscroll_d);
|
||||
vscroll_d.p_min = { bounds_max.x - scroll_bar_dim, bounds_min.y };
|
||||
vscroll_d.p_max = { bounds_max.x, bounds_max.y };
|
||||
vscroll_d.p_min = (v2){ bounds_max.x - scroll_bar_dim, bounds_min.y };
|
||||
vscroll_d.p_max = (v2){ bounds_max.x, bounds_max.y };
|
||||
vscroll_d.style = ui_get_style(ui, UIWidget_VScroll);
|
||||
vscroll_d.string = string_f(scratch.a, "%.*s_vscroll", str_varg(string));
|
||||
UI_Widget_Result r = ui_widget_push(ui, vscroll_d);
|
||||
|
@ -885,16 +826,17 @@ ui_scroll_view_begin(UI* ui, String string, v2 bounds_min, v2 bounds_max, u32 ro
|
|||
r32 rows_scroll_to = max(0, rows - (rows_avail - 1));
|
||||
r32 y_scroll_dist = rows_scroll_to * ui->layout->row_height;
|
||||
|
||||
scroll_offset *= v2{ 0, y_scroll_dist };
|
||||
scroll_offset = HMM_MultiplyVec2(scroll_offset, (v2){ 0, y_scroll_dist });
|
||||
|
||||
UI_Layout* layout = allocator_alloc_struct(scratch.a, UI_Layout);
|
||||
layout->mode = UILayout_Columns;
|
||||
layout->bounds_min = scroll_area_min;
|
||||
layout->bounds_max = scroll_area_max;
|
||||
ui_layout_set_row_info(ui, layout);
|
||||
layout->at = bounds_min - scroll_offset;
|
||||
layout->at = HMM_SubtractVec2(bounds_min, scroll_offset);
|
||||
ui_layout_push(ui, layout);
|
||||
|
||||
scratch_release(scratch);
|
||||
return layout;
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@
|
|||
/////////////////////////////////////////////////////////////
|
||||
// Interface
|
||||
|
||||
typedef struct UI_Vertex UI_Vertex;
|
||||
struct UI_Vertex
|
||||
{
|
||||
v4 pos;
|
||||
|
@ -15,6 +16,7 @@ struct UI_Vertex
|
|||
|
||||
#define UI_WIDGET_ID_VALID_BIT 1 << 31
|
||||
|
||||
typedef union UI_Widget_Id UI_Widget_Id;
|
||||
union UI_Widget_Id
|
||||
{
|
||||
// equality of widget id's only relies on the value field
|
||||
|
@ -45,6 +47,7 @@ enum
|
|||
|
||||
// akin to a css class, could be used to style multiple
|
||||
// elements
|
||||
typedef struct UI_Widget_Style UI_Widget_Style;
|
||||
struct UI_Widget_Style
|
||||
{
|
||||
UI_Widget_Style_Flags flags;
|
||||
|
@ -54,6 +57,7 @@ struct UI_Widget_Style
|
|||
};
|
||||
|
||||
// combination of style info and per-instance data
|
||||
typedef struct UI_Widget_Desc UI_Widget_Desc;
|
||||
struct UI_Widget_Desc
|
||||
{
|
||||
UI_Widget_Style style;
|
||||
|
@ -63,6 +67,7 @@ struct UI_Widget_Desc
|
|||
v2 p_max;
|
||||
};
|
||||
|
||||
typedef struct UI_Widget UI_Widget;
|
||||
struct UI_Widget
|
||||
{
|
||||
UI_Widget_Id id;
|
||||
|
@ -82,6 +87,7 @@ enum
|
|||
UIWidgetResult_MouseLeft_WentUp = 2,
|
||||
};
|
||||
|
||||
typedef struct UI_Widget_Result UI_Widget_Result;
|
||||
struct UI_Widget_Result
|
||||
{
|
||||
UI_Widget_Id id;
|
||||
|
@ -89,7 +95,8 @@ struct UI_Widget_Result
|
|||
v2 drag;
|
||||
};
|
||||
|
||||
enum UI_Widget_Kind
|
||||
typedef u32 UI_Widget_Kind;
|
||||
enum
|
||||
{
|
||||
UIWidget_Text,
|
||||
|
||||
|
@ -111,16 +118,19 @@ enum UI_Widget_Kind
|
|||
UIWidget_Count,
|
||||
};
|
||||
|
||||
typedef struct UI_Style_Sheet UI_Style_Sheet;
|
||||
struct UI_Style_Sheet
|
||||
{
|
||||
UI_Widget_Style styles[UIWidget_Count];
|
||||
};
|
||||
|
||||
typedef struct UI_Widget_State UI_Widget_State;
|
||||
struct UI_Widget_State
|
||||
{
|
||||
v2 scroll;
|
||||
};
|
||||
|
||||
typedef struct UI_Widget_Pool UI_Widget_Pool;
|
||||
struct UI_Widget_Pool
|
||||
{
|
||||
UI_Widget* free;
|
||||
|
@ -135,7 +145,8 @@ struct UI_Widget_Pool
|
|||
u32 states_cap;
|
||||
};
|
||||
|
||||
enum UI_Layout_Mode
|
||||
typedef u8 UI_Layout_Mode;
|
||||
enum
|
||||
{
|
||||
// each element takes up a whole row
|
||||
UILayout_Columns,
|
||||
|
@ -145,6 +156,7 @@ enum UI_Layout_Mode
|
|||
UILayout_Rows,
|
||||
};
|
||||
|
||||
typedef struct UI_Layout UI_Layout;
|
||||
struct UI_Layout
|
||||
{
|
||||
UI_Layout_Mode mode;
|
||||
|
@ -159,6 +171,7 @@ struct UI_Layout
|
|||
u32 cols;
|
||||
};
|
||||
|
||||
typedef struct UI_Layout_Bounds UI_Layout_Bounds;
|
||||
struct UI_Layout_Bounds
|
||||
{
|
||||
v2 min;
|
||||
|
@ -167,6 +180,7 @@ struct UI_Layout_Bounds
|
|||
|
||||
typedef void UI_Draw_Panel_Cb(u8* user_data, BSP_Node_Id id, BSP_Node node, BSP_Area area);
|
||||
|
||||
typedef struct UI UI;
|
||||
struct UI
|
||||
{
|
||||
Geo_Quad_Buffer_Builder geo;
|
||||
|
@ -193,9 +207,9 @@ struct UI
|
|||
Input_State* input;
|
||||
|
||||
m44 proj;
|
||||
Platform_Shader shader;
|
||||
Platform_Texture atlas_texture;
|
||||
Platform_Geometry_Buffer per_frame_buffer;
|
||||
Shader shader;
|
||||
Texture atlas_texture;
|
||||
Geometry_Buffer per_frame_buffer;
|
||||
};
|
||||
|
||||
// Interface
|
||||
|
@ -203,16 +217,16 @@ struct UI
|
|||
internal UI ui_create();
|
||||
internal void ui_quad_push(UI* ui, v3 pmin, v3 pmax, v2 tmin, v2 tmax, v4 c);
|
||||
internal void ui_sprite_register(UI* ui, u8* pixels, u32 w, u32 h, u32 id);
|
||||
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color);
|
||||
internal void ui_sprite_push_color(UI* ui, v3 pmin, v3 pmax, u32 id, v4 color);
|
||||
internal void ui_sprite_push(UI* ui, v3 pmin, v3 pmax, u32 id);
|
||||
internal v3 ui_sprite_char_push(UI* ui, v2 at, u32 codepoint, v4 color);
|
||||
internal void ui_draw(App_State* state);
|
||||
internal void ui_draw(UI* ui);
|
||||
|
||||
// Widgets
|
||||
|
||||
internal void ui_create_default_style_sheet();
|
||||
|
||||
internal UI_Widget_Id ui_widget_id_create(u32 index_in_parent, String string);
|
||||
internal UI_Widget_Id ui_widget_id_create(String string, u32 index_in_parent);
|
||||
internal bool ui_widget_id_equals(UI_Widget_Id a, UI_Widget_Id b);
|
||||
internal bool ui_widget_id_is_valid(UI_Widget_Id h);
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
global XPlatform_Shader_Program_Src ui_shader = {
|
||||
.win32_vert = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"layout (location = 2) in vec4 a_color;\n"
|
||||
"out vec2 uv;\n"
|
||||
"out vec4 color;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
" color = a_color;\n"
|
||||
"}"
|
||||
),
|
||||
.win32_frag = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"in vec4 color;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(tex, uv) * color;\n"
|
||||
"}"
|
||||
),
|
||||
|
||||
.osx_vert = lit_str(
|
||||
"#version 330 core\n"
|
||||
"layout (location = 0) in vec3 a_pos;\n"
|
||||
"layout (location = 1) in vec2 a_uv;\n"
|
||||
"layout (location = 2) in vec4 a_color;\n"
|
||||
"out vec2 uv;\n"
|
||||
"out vec4 color;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
" color = a_color;\n"
|
||||
"}"
|
||||
),
|
||||
.osx_frag = lit_str(
|
||||
"#version 330 core\n"
|
||||
"in vec2 uv;\n"
|
||||
"in vec4 color;\n"
|
||||
"out vec4 FragColor;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" FragColor = texture(tex, uv) * color;\n"
|
||||
"}"
|
||||
),
|
||||
|
||||
.wasm_vert = lit_str(
|
||||
"precision highp float;\n"
|
||||
"attribute vec3 a_pos;\n"
|
||||
"attribute vec2 a_uv;\n"
|
||||
"attribute vec4 a_color;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"varying vec4 color;\n"
|
||||
"uniform mat4 proj;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_Position = proj * vec4(a_pos, 1.0);\n"
|
||||
" uv = a_uv;\n"
|
||||
" color = a_color;\n"
|
||||
"}"
|
||||
),
|
||||
.wasm_frag = lit_str(
|
||||
"precision highp float;\n"
|
||||
"varying vec2 uv;\n"
|
||||
"varying vec4 color;\n"
|
||||
"uniform sampler2D tex;\n"
|
||||
"void main(void) {\n"
|
||||
" gl_FragColor = texture2D(tex, uv) * color;\n"
|
||||
"}"
|
||||
),
|
||||
};
|
|
@ -2,18 +2,22 @@
|
|||
internal void
|
||||
en_init(App_State* state, App_Init_Desc desc)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
|
||||
state->assemblies = assembly_array_create(permanent, desc.assembly_cap);
|
||||
|
||||
Output* o = &state->output;
|
||||
register_output_method(o, OutputData_Invalid, 0, 0);
|
||||
register_output_method(o, OutputData_NetworkSACN, output_network_sacn_build, output_network_sacn_init());
|
||||
register_output_method(o, OutputData_ComUART, output_network_sacn_build, output_com_uart_init());
|
||||
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal void
|
||||
en_frame_prepare(App_State* state)
|
||||
{
|
||||
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
global r32 tt = 0;
|
||||
|
@ -21,6 +25,8 @@ global r32 tt = 0;
|
|||
internal void
|
||||
en_frame(App_State* state)
|
||||
{
|
||||
lumenarium_env_validate();
|
||||
|
||||
scratch_get(scratch);
|
||||
Assembly_Array assemblies = state->assemblies;
|
||||
|
||||
|
@ -87,11 +93,14 @@ en_frame(App_State* state)
|
|||
invalid_code_path;
|
||||
}
|
||||
}
|
||||
|
||||
scratch_release(scratch);
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
||||
internal void
|
||||
en_cleanup(App_State* state)
|
||||
{
|
||||
|
||||
lumenarium_env_validate();
|
||||
}
|
||||
|
|
@ -2,12 +2,13 @@
|
|||
Assembly_Array
|
||||
assembly_array_create(Allocator* allocator, u32 cap)
|
||||
{
|
||||
Assembly_Array result = {};
|
||||
result.cap = cap;
|
||||
result.names = allocator_alloc_array(allocator, String, cap);
|
||||
result.pixel_buffers = allocator_alloc_array(allocator, Assembly_Pixel_Buffer, cap);
|
||||
result.strip_arrays = allocator_alloc_array(allocator, Assembly_Strip_Array, cap);
|
||||
result.allocator = allocator;
|
||||
Assembly_Array result = {
|
||||
.cap = cap,
|
||||
.names = allocator_alloc_array(allocator, String, cap),
|
||||
.pixel_buffers = allocator_alloc_array(allocator, Assembly_Pixel_Buffer, cap),
|
||||
.strip_arrays = allocator_alloc_array(allocator, Assembly_Strip_Array, cap),
|
||||
.allocator = allocator,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -49,11 +50,13 @@ assembly_add(Assembly_Array* a, String name, u32 pixels_cap, u32 strips_cap)
|
|||
a->names[index] = name;
|
||||
|
||||
Assembly_Pixel_Buffer* pixel_buffer = a->pixel_buffers + index;
|
||||
zero_struct(*pixel_buffer);
|
||||
pixel_buffer->cap = pixels_cap;
|
||||
pixel_buffer->pixels = allocator_alloc_array(a->allocator, Assembly_Pixel, pixels_cap);
|
||||
pixel_buffer->positions = allocator_alloc_array(a->allocator, v4, pixels_cap);
|
||||
|
||||
Assembly_Strip_Array* strip_array = a->strip_arrays + index;
|
||||
zero_struct(*strip_array);
|
||||
strip_array->cap = strips_cap;
|
||||
strip_array->strips = allocator_alloc_array(a->allocator, Assembly_Strip, strips_cap);
|
||||
|
||||
|
@ -94,7 +97,7 @@ assembly_add_led(
|
|||
assert(pixel_buffer->len < pixel_buffer->cap);
|
||||
|
||||
u32 pixel_index = pixel_buffer->len++;
|
||||
pixel_buffer->pixels[pixel_index] = {};
|
||||
pixel_buffer->pixels[pixel_index] = (Assembly_Pixel){};
|
||||
pixel_buffer->positions[pixel_index] = position;
|
||||
|
||||
assert(strip->pixels_len < strip->pixels_cap);
|
||||
|
@ -109,13 +112,14 @@ assembly_strip_create_leds(
|
|||
v3 start, v3 end,
|
||||
u32 led_count
|
||||
){
|
||||
v3 delta_total = end - start;
|
||||
v3 delta_step = delta_total / (r32)led_count;
|
||||
v3 delta_total = HMM_SubtractVec3(end, start);
|
||||
v3 delta_step = HMM_MultiplyVec3f(delta_total, 1.0f / (r32)led_count);
|
||||
|
||||
for (u32 i = 0; i < led_count; i++)
|
||||
{
|
||||
v4 pos = {0,0,0,1};
|
||||
pos.XYZ = start + ((r32)i * delta_step);
|
||||
v3 offset = HMM_MultiplyVec3f(delta_step, (r32)i);
|
||||
pos.XYZ = HMM_AddVec3(start, offset);
|
||||
assembly_add_led(a, h, strip, pos);
|
||||
}
|
||||
}
|
|
@ -13,11 +13,13 @@
|
|||
// more than 128 sculptures in a scene - but who knows, maybe someday O.o?
|
||||
#define ASSEMBLY_HANDLE_VALID_BIT (1 << 31)
|
||||
#define ASSEMBLY_HANDLE_INDEX_MASK ~ASSEMBLY_HANDLE_VALID_BIT
|
||||
typedef struct Assembly_Handle Assembly_Handle;
|
||||
struct Assembly_Handle
|
||||
{
|
||||
u32 value;
|
||||
};
|
||||
|
||||
typedef union Assembly_Pixel Assembly_Pixel;
|
||||
union Assembly_Pixel
|
||||
{
|
||||
struct {
|
||||
|
@ -28,6 +30,7 @@ union Assembly_Pixel
|
|||
u8 channels[3];
|
||||
};
|
||||
|
||||
typedef struct Assembly_Pixel_Buffer Assembly_Pixel_Buffer;
|
||||
struct Assembly_Pixel_Buffer
|
||||
{
|
||||
u32 cap;
|
||||
|
@ -36,6 +39,7 @@ struct Assembly_Pixel_Buffer
|
|||
v4* positions;
|
||||
};
|
||||
|
||||
typedef struct Assembly_Strip Assembly_Strip;
|
||||
struct Assembly_Strip
|
||||
{
|
||||
u32 pixels_cap;
|
||||
|
@ -47,6 +51,7 @@ struct Assembly_Strip
|
|||
u32 sacn_universe;
|
||||
};
|
||||
|
||||
typedef struct Assembly_Strip_Array Assembly_Strip_Array;
|
||||
struct Assembly_Strip_Array
|
||||
{
|
||||
u32 cap;
|
||||
|
@ -54,6 +59,7 @@ struct Assembly_Strip_Array
|
|||
Assembly_Strip* strips;
|
||||
};
|
||||
|
||||
typedef struct Assembly_Array Assembly_Array;
|
||||
struct Assembly_Array
|
||||
{
|
||||
u32 cap;
|
||||
|
|
|
@ -12,6 +12,7 @@ enum
|
|||
OutputData_Count,
|
||||
};
|
||||
|
||||
typedef struct Output_Data_Network Output_Data_Network;
|
||||
struct Output_Data_Network
|
||||
{
|
||||
// Platform_Socket_Handle socket;
|
||||
|
@ -19,11 +20,13 @@ struct Output_Data_Network
|
|||
u32 port;
|
||||
};
|
||||
|
||||
typedef struct Output_Data_Com Output_Data_Com;
|
||||
struct Output_Data_Com
|
||||
{
|
||||
String port;
|
||||
};
|
||||
|
||||
typedef struct Output_Data Output_Data;
|
||||
struct Output_Data
|
||||
{
|
||||
Output_Data_Kind kind;
|
||||
|
@ -37,6 +40,7 @@ struct Output_Data
|
|||
Output_Data* next;
|
||||
};
|
||||
|
||||
typedef struct Output_Data_Queue Output_Data_Queue;
|
||||
struct Output_Data_Queue
|
||||
{
|
||||
Output_Data* first;
|
||||
|
@ -47,12 +51,14 @@ struct Output_Data_Queue
|
|||
|
||||
typedef void Build_Output_Data_Buffer(App_State* state, u32 assembly_id, Assembly_Strip* strip, u8* method_data, Output_Data_Queue* queue);
|
||||
|
||||
typedef struct Output_Methods Output_Methods;
|
||||
struct Output_Methods
|
||||
{
|
||||
Build_Output_Data_Buffer* procs[OutputData_Count];
|
||||
u8* method_data[OutputData_Count];
|
||||
};
|
||||
|
||||
typedef struct Output Output;
|
||||
struct Output
|
||||
{
|
||||
Output_Methods methods;
|
||||
|
|
|
@ -165,7 +165,7 @@ sacn_fill_buffer_body(Output_Data* d, u32* leds_placed)
|
|||
internal Sacn_Cid
|
||||
sacn_string_to_cid(String str)
|
||||
{
|
||||
return {};
|
||||
return (Sacn_Cid){};
|
||||
}
|
||||
|
||||
internal u32
|
|
@ -4,11 +4,13 @@
|
|||
#define LUMENARIUM_OUTPUT_SACN_H
|
||||
|
||||
#define SACN_CID_BYTES 16
|
||||
typedef struct Sacn_Cid Sacn_Cid;
|
||||
struct Sacn_Cid
|
||||
{
|
||||
u8 bytes[SACN_CID_BYTES];
|
||||
};
|
||||
|
||||
typedef struct Sacn Sacn;
|
||||
struct Sacn
|
||||
{
|
||||
Sacn_Cid cid;
|
||||
|
|
|
@ -2122,7 +2122,7 @@ HMM_AverageVec3(hmm_vec3* Arr, int Len)
|
|||
hmm_vec3 Total = {};
|
||||
for (int i = 0; i < Len; i++)
|
||||
{
|
||||
Total += HMM_AddVec3(Total, Arr[i]);
|
||||
Total = HMM_AddVec3(Total, Arr[i]);
|
||||
}
|
||||
|
||||
hmm_vec3 Result = {};
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,594 @@
|
|||
/*************************************************************************
|
||||
* GLFW 3.3 - www.glfw.org
|
||||
* A library for OpenGL, window and input
|
||||
*------------------------------------------------------------------------
|
||||
* Copyright (c) 2002-2006 Marcus Geelnard
|
||||
* Copyright (c) 2006-2018 Camilla Löwy <elmindreda@glfw.org>
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would
|
||||
* be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
*************************************************************************/
|
||||
|
||||
#ifndef _glfw3_native_h_
|
||||
#define _glfw3_native_h_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Doxygen documentation
|
||||
*************************************************************************/
|
||||
|
||||
/*! @file glfw3native.h
|
||||
* @brief The header of the native access functions.
|
||||
*
|
||||
* This is the header file of the native access functions. See @ref native for
|
||||
* more information.
|
||||
*/
|
||||
/*! @defgroup native Native access
|
||||
* @brief Functions related to accessing native handles.
|
||||
*
|
||||
* **By using the native access functions you assert that you know what you're
|
||||
* doing and how to fix problems caused by using them. If you don't, you
|
||||
* shouldn't be using them.**
|
||||
*
|
||||
* Before the inclusion of @ref glfw3native.h, you may define zero or more
|
||||
* window system API macro and zero or more context creation API macros.
|
||||
*
|
||||
* The chosen backends must match those the library was compiled for. Failure
|
||||
* to do this will cause a link-time error.
|
||||
*
|
||||
* The available window API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WIN32`
|
||||
* * `GLFW_EXPOSE_NATIVE_COCOA`
|
||||
* * `GLFW_EXPOSE_NATIVE_X11`
|
||||
* * `GLFW_EXPOSE_NATIVE_WAYLAND`
|
||||
*
|
||||
* The available context API macros are:
|
||||
* * `GLFW_EXPOSE_NATIVE_WGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_NSGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_GLX`
|
||||
* * `GLFW_EXPOSE_NATIVE_EGL`
|
||||
* * `GLFW_EXPOSE_NATIVE_OSMESA`
|
||||
*
|
||||
* These macros select which of the native access functions that are declared
|
||||
* and which platform-specific headers to include. It is then up your (by
|
||||
* definition platform-specific) code to handle which of these should be
|
||||
* defined.
|
||||
*/
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* System headers and types
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
|
||||
// example to allow applications to correctly declare a GL_KHR_debug callback)
|
||||
// but windows.h assumes no one will define APIENTRY before it does
|
||||
#if defined(GLFW_APIENTRY_DEFINED)
|
||||
#undef APIENTRY
|
||||
#undef GLFW_APIENTRY_DEFINED
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
#if defined(__OBJC__)
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#else
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
typedef void* id;
|
||||
#endif
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
#include <wayland-client.h>
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/* WGL is declared by windows.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/* NSGL is declared by Cocoa.h */
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
#include <GL/glx.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
#include <EGL/egl.h>
|
||||
#endif
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
#include <GL/osmesa.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Functions
|
||||
*************************************************************************/
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WIN32)
|
||||
/*! @brief Returns the adapter device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`)
|
||||
* of the specified monitor, or `NULL` if an [error](@ref error_handling)
|
||||
* occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the display device name of the specified monitor.
|
||||
*
|
||||
* @return The UTF-8 encoded display device name (for example
|
||||
* `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `HWND` of the specified window.
|
||||
*
|
||||
* @return The `HWND` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark The `HDC` associated with the window can be queried with the
|
||||
* [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
|
||||
* function.
|
||||
* @code
|
||||
* HDC dc = GetDC(glfwGetWin32Window(window));
|
||||
* @endcode
|
||||
* This DC is private and does not need to be released.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WGL)
|
||||
/*! @brief Returns the `HGLRC` of the specified window.
|
||||
*
|
||||
* @return The `HGLRC` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark The `HDC` associated with the window can be queried with the
|
||||
* [GetDC](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdc)
|
||||
* function.
|
||||
* @code
|
||||
* HDC dc = GetDC(glfwGetWin32Window(window));
|
||||
* @endcode
|
||||
* This DC is private and does not need to be released.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_COCOA)
|
||||
/*! @brief Returns the `CGDirectDisplayID` of the specified monitor.
|
||||
*
|
||||
* @return The `CGDirectDisplayID` of the specified monitor, or
|
||||
* `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `NSWindow` of the specified window.
|
||||
*
|
||||
* @return The `NSWindow` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
|
||||
/*! @brief Returns the `NSOpenGLContext` of the specified window.
|
||||
*
|
||||
* @return The `NSOpenGLContext` of the specified window, or `nil` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI id glfwGetNSGLContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_X11)
|
||||
/*! @brief Returns the `Display` used by GLFW.
|
||||
*
|
||||
* @return The `Display` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Display* glfwGetX11Display(void);
|
||||
|
||||
/*! @brief Returns the `RRCrtc` of the specified monitor.
|
||||
*
|
||||
* @return The `RRCrtc` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `RROutput` of the specified monitor.
|
||||
*
|
||||
* @return The `RROutput` of the specified monitor, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the `Window` of the specified window.
|
||||
*
|
||||
* @return The `Window` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI Window glfwGetX11Window(GLFWwindow* window);
|
||||
|
||||
/*! @brief Sets the current primary selection to the specified string.
|
||||
*
|
||||
* @param[in] string A UTF-8 encoded string.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The specified string is copied before this function
|
||||
* returns.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwGetX11SelectionString
|
||||
* @sa glfwSetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI void glfwSetX11SelectionString(const char* string);
|
||||
|
||||
/*! @brief Returns the contents of the current primary selection as a string.
|
||||
*
|
||||
* If the selection is empty or if its contents cannot be converted, `NULL`
|
||||
* is returned and a @ref GLFW_FORMAT_UNAVAILABLE error is generated.
|
||||
*
|
||||
* @return The contents of the selection as a UTF-8 encoded string, or `NULL`
|
||||
* if an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||
* GLFW_PLATFORM_ERROR.
|
||||
*
|
||||
* @pointer_lifetime The returned string is allocated and freed by GLFW. You
|
||||
* should not free it yourself. It is valid until the next call to @ref
|
||||
* glfwGetX11SelectionString or @ref glfwSetX11SelectionString, or until the
|
||||
* library is terminated.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref clipboard
|
||||
* @sa glfwSetX11SelectionString
|
||||
* @sa glfwGetClipboardString
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI const char* glfwGetX11SelectionString(void);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||
/*! @brief Returns the `GLXContext` of the specified window.
|
||||
*
|
||||
* @return The `GLXContext` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `GLXWindow` of the specified window.
|
||||
*
|
||||
* @return The `GLXWindow` of the specified window, or `None` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
|
||||
/*! @brief Returns the `struct wl_display*` used by GLFW.
|
||||
*
|
||||
* @return The `struct wl_display*` used by GLFW, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_display* glfwGetWaylandDisplay(void);
|
||||
|
||||
/*! @brief Returns the `struct wl_output*` of the specified monitor.
|
||||
*
|
||||
* @return The `struct wl_output*` of the specified monitor, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor);
|
||||
|
||||
/*! @brief Returns the main `struct wl_surface*` of the specified window.
|
||||
*
|
||||
* @return The main `struct wl_surface*` of the specified window, or `NULL` if
|
||||
* an [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.2.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_EGL)
|
||||
/*! @brief Returns the `EGLDisplay` used by GLFW.
|
||||
*
|
||||
* @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLDisplay glfwGetEGLDisplay(void);
|
||||
|
||||
/*! @brief Returns the `EGLContext` of the specified window.
|
||||
*
|
||||
* @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns the `EGLSurface` of the specified window.
|
||||
*
|
||||
* @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.0.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
|
||||
/*! @brief Retrieves the color buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose color buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the color buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the color buffer, or `NULL`.
|
||||
* @param[out] format Where to store the OSMesa pixel format of the color
|
||||
* buffer, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the color buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaColorBuffer(GLFWwindow* window, int* width, int* height, int* format, void** buffer);
|
||||
|
||||
/*! @brief Retrieves the depth buffer associated with the specified window.
|
||||
*
|
||||
* @param[in] window The window whose depth buffer to retrieve.
|
||||
* @param[out] width Where to store the width of the depth buffer, or `NULL`.
|
||||
* @param[out] height Where to store the height of the depth buffer, or `NULL`.
|
||||
* @param[out] bytesPerValue Where to store the number of bytes per depth
|
||||
* buffer element, or `NULL`.
|
||||
* @param[out] buffer Where to store the address of the depth buffer, or
|
||||
* `NULL`.
|
||||
* @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height, int* bytesPerValue, void** buffer);
|
||||
|
||||
/*! @brief Returns the `OSMesaContext` of the specified window.
|
||||
*
|
||||
* @return The `OSMesaContext` of the specified window, or `NULL` if an
|
||||
* [error](@ref error_handling) occurred.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NO_WINDOW_CONTEXT and @ref
|
||||
* GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @thread_safety This function may be called from any thread. Access is not
|
||||
* synchronized.
|
||||
*
|
||||
* @since Added in version 3.3.
|
||||
*
|
||||
* @ingroup native
|
||||
*/
|
||||
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _glfw3_native_h_ */
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -8,12 +8,14 @@
|
|||
// - a node with no children has not been split
|
||||
|
||||
#define BTREE_NODE_ID_VALID_BIT (1 << 31)
|
||||
typedef struct BSP_Node_Id BSP_Node_Id;
|
||||
struct BSP_Node_Id
|
||||
{
|
||||
u32 value;
|
||||
};
|
||||
|
||||
enum BSP_Split_Kind
|
||||
typedef u8 BSP_Split_Kind;
|
||||
enum
|
||||
{
|
||||
BSPSplit_XAxis = 1,
|
||||
BSPSplit_YAxis = 0,
|
||||
|
@ -21,19 +23,22 @@ enum BSP_Split_Kind
|
|||
BSPSplit_None = 3,
|
||||
};
|
||||
|
||||
typedef struct BSP_Split BSP_Split;
|
||||
struct BSP_Split
|
||||
{
|
||||
BSP_Split_Kind kind;
|
||||
r32 value;
|
||||
};
|
||||
|
||||
enum BSP_Split_Update_Flags
|
||||
typedef u8 BSP_Split_Update_Flags;
|
||||
enum
|
||||
{
|
||||
BSPSplitUpdate_None = 0,
|
||||
BSPSplitUpdate_FreeZeroAreaChildren = 1,
|
||||
};
|
||||
|
||||
enum BSP_Child_Selector
|
||||
typedef u8 BSP_Child_Selector;
|
||||
enum
|
||||
{
|
||||
// NOTE(PS): these values are intentionally overlapping since
|
||||
// they access the data structure of the B-Tree in a particular
|
||||
|
@ -46,12 +51,14 @@ enum BSP_Child_Selector
|
|||
BSPChild_Bottom = 1,
|
||||
};
|
||||
|
||||
typedef struct BSP_Area BSP_Area;
|
||||
struct BSP_Area
|
||||
{
|
||||
v2 min;
|
||||
v2 max;
|
||||
};
|
||||
|
||||
typedef struct BSP_Node BSP_Node;
|
||||
struct BSP_Node
|
||||
{
|
||||
union
|
||||
|
@ -84,6 +91,7 @@ struct BSP_Node
|
|||
BSP_Area area;
|
||||
};
|
||||
|
||||
typedef struct BSP BSP;
|
||||
struct BSP
|
||||
{
|
||||
BSP_Node* nodes;
|
||||
|
@ -101,8 +109,9 @@ internal BSP bsp_create(Allocator* allocator, u32 cap);
|
|||
internal BSP_Node* bsp_get(BSP* tree, BSP_Node_Id id);
|
||||
internal BSP_Node_Id bsp_push(BSP* tree, BSP_Node_Id parent, BSP_Area area, u32 user_data);
|
||||
internal void bsp_free(BSP* tree, BSP_Node_Id id);
|
||||
internal void bsp_free_cb(BSP* tree, BSP_Node_Id id, BSP* node, u8* user_data);
|
||||
internal void bsp_free_cb(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data);
|
||||
|
||||
typedef union BSP_Split_Result BSP_Split_Result;
|
||||
union BSP_Split_Result
|
||||
{
|
||||
BSP_Node_Id children[2];
|
||||
|
@ -122,7 +131,7 @@ union BSP_Split_Result
|
|||
};
|
||||
|
||||
internal BSP_Split_Result bsp_split(BSP* tree, BSP_Node_Id id, r32 split, BSP_Split_Kind kind, u32 user_data_0, u32 user_data_1);
|
||||
internal void bsp_join_recursive(BSP* tree, BSP_Node* parent, BSP_Child_Selector keep);
|
||||
internal void bsp_join_recursive(BSP* tree, BSP_Node_Id parent_id, BSP_Child_Selector keep);
|
||||
|
||||
// left, parent, right
|
||||
internal void bsp_walk_inorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* cb, u8* user_data);
|
||||
|
@ -133,7 +142,7 @@ internal void bsp_walk_postorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* cb,
|
|||
|
||||
internal void bsp_node_update_child_areas(BSP* tree, BSP_Node_Id id, BSP_Node* node, u8* user_data);
|
||||
internal void bsp_node_area_update(BSP* tree, BSP_Node_Id id, BSP_Area new_area);
|
||||
internal void bsp_child_split_update(BSP* tree, BSP_Node_Id node, u32 new_split);
|
||||
internal void bsp_child_split_update(BSP* tree, BSP_Node_Id node_id, r32 new_split, BSP_Split_Update_Flags flags);
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
|
@ -165,7 +174,7 @@ bsp_get(BSP* tree, BSP_Node_Id id)
|
|||
internal BSP_Node_Id
|
||||
bsp_push(BSP* tree, BSP_Node_Id parent_id, BSP_Area area, u32 user_data)
|
||||
{
|
||||
BSP_Node_Id result = BSP_Node_Id{0};
|
||||
BSP_Node_Id result = (BSP_Node_Id){0};
|
||||
BSP_Node* node = 0;
|
||||
|
||||
if (tree->nodes_len >= tree->nodes_cap)
|
||||
|
@ -188,6 +197,7 @@ bsp_push(BSP* tree, BSP_Node_Id parent_id, BSP_Area area, u32 user_data)
|
|||
|
||||
if (bsp_node_id_is_valid(result))
|
||||
{
|
||||
zero_struct(*node);
|
||||
node->split.kind = BSPSplit_None;
|
||||
node->parent = parent_id;
|
||||
node->area = area;
|
||||
|
@ -245,8 +255,8 @@ bsp_split(BSP* tree, BSP_Node_Id node_id, r32 split, BSP_Split_Kind kind, u32 us
|
|||
split = clamp(node->area.min.Elements[kind], split, node->area.max.Elements[kind]);
|
||||
node->split.value = split;
|
||||
node->split.kind = kind;
|
||||
node->children[0] = bsp_push(tree, node_id, {}, user_data_0);
|
||||
node->children[1] = bsp_push(tree, node_id, {}, user_data_1);
|
||||
node->children[0] = bsp_push(tree, node_id, (BSP_Area){}, user_data_0);
|
||||
node->children[1] = bsp_push(tree, node_id, (BSP_Area){}, user_data_1);
|
||||
bsp_node_update_child_areas(tree, node_id, node, 0);
|
||||
|
||||
BSP_Split_Result result = {};
|
||||
|
@ -260,8 +270,8 @@ bsp_join_recursive(BSP* tree, BSP_Node_Id parent_id, BSP_Child_Selector keep)
|
|||
{
|
||||
BSP_Node* parent = bsp_get(tree, parent_id);
|
||||
BSP_Node keep_node = *bsp_get(tree, parent->children[keep]);
|
||||
bsp_walk_preorder(tree, parent->children[0], bsp_free_cb, 0);
|
||||
bsp_walk_preorder(tree, parent->children[1], bsp_free_cb, 0);
|
||||
bsp_walk_preorder(tree, parent->children[0], (BSP_Walk_Cb*)bsp_free_cb, 0);
|
||||
bsp_walk_preorder(tree, parent->children[1], (BSP_Walk_Cb*)bsp_free_cb, 0);
|
||||
parent->user_data = keep_node.user_data;
|
||||
zero_struct(parent->children[0]);
|
||||
zero_struct(parent->children[1]);
|
||||
|
@ -315,6 +325,7 @@ bsp_walk_inorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_data
|
|||
at = n->children[1];
|
||||
}
|
||||
}
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
// parent, left right
|
||||
|
@ -345,6 +356,7 @@ bsp_walk_preorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_dat
|
|||
BSP_Node* n = bsp_get(tree, at);
|
||||
at = n->children[1];
|
||||
}
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
// parent, right, parent
|
||||
|
@ -388,6 +400,7 @@ bsp_walk_postorder(BSP* tree, BSP_Node_Id first, BSP_Walk_Cb* visit, u8* user_da
|
|||
}
|
||||
}
|
||||
}
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
@ -462,16 +475,16 @@ bsp_tests()
|
|||
{
|
||||
scratch_get(scratch);
|
||||
BSP tree = bsp_create(scratch.a, 256);
|
||||
tree.root = bsp_push(&tree, {0}, {{0,0},{512,512}}, 0);
|
||||
tree.root = bsp_push(&tree, (BSP_Node_Id){0}, (BSP_Area){ (v2){0,0},(v2){512,512}}, 0);
|
||||
|
||||
BSP_Split_Result r0 = bsp_split(&tree, tree.root, 256, BSPSplit_YAxis, 0, 0);
|
||||
BSP_Node* root = bsp_get(&tree, tree.root);
|
||||
BSP_Node* n0 = bsp_get(&tree, r0.children[0]);
|
||||
BSP_Node* n1 = bsp_get(&tree, r0.children[1]);
|
||||
assert(root != 0 && n0 != 0 && n1 != 0);
|
||||
assert(n0->area.min == root->area.min);
|
||||
assert(HMM_EqualsVec2(n0->area.min, root->area.min));
|
||||
assert(n0->area.max.x == 256 && n0->area.max.y == root->area.max.y);
|
||||
assert(n1->area.max == root->area.max);
|
||||
assert(HMM_EqualsVec2(n1->area.max, root->area.max));
|
||||
assert(n1->area.min.x == 256 && n0->area.min.y == root->area.min.y);
|
||||
assert(n0->split.kind == BSPSplit_None);
|
||||
assert(n1->split.kind == BSPSplit_None);
|
||||
|
@ -481,6 +494,7 @@ bsp_tests()
|
|||
BSP_Split_Result r2 = bsp_split(&tree, r1.children[1], 64, BSPSplit_XAxis, 0, 0);
|
||||
|
||||
bsp_walk_postorder(&tree, root->children[0], bsp_free_cb, 0);
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
@ -7,8 +7,7 @@ lumenarium_init()
|
|||
App_State* state = 0;
|
||||
|
||||
permanent = bump_allocator_create_reserve(GB(2));
|
||||
global_scratch_ = bump_allocator_create_reserve(GB(8));
|
||||
platform_file_jobs_init();
|
||||
global_scratch_ = bump_allocator_create_reserve(GB(4));
|
||||
|
||||
run_tests();
|
||||
scratch_get(scratch);
|
||||
|
@ -18,22 +17,22 @@ lumenarium_init()
|
|||
state = allocator_alloc_struct(permanent, App_State);
|
||||
add_flag(state->flags, AppState_IsRunning);
|
||||
add_flag(state->flags, AppState_RunEditor);
|
||||
add_flag(state->flags, AppState_RunUserSpace);
|
||||
|
||||
state->file_async_job_system = os_file_jobs_init();
|
||||
state->input_state = input_state_create(permanent);
|
||||
|
||||
String exe_file_path = platform_get_exe_path(scratch.a);
|
||||
String exe_file_path = os_get_exe_path(scratch.a);
|
||||
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;
|
||||
String run_tree_path = string_get_prefix(exe_file_path, run_tree_end);
|
||||
String run_tree_path_nullterm = string_copy(run_tree_path, scratch.a);
|
||||
platform_pwd_set(run_tree_path_nullterm);
|
||||
|
||||
os_pwd_set(run_tree_path_nullterm);
|
||||
|
||||
en_init(state, desc);
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
ed_init(state);
|
||||
}
|
||||
incenter_init(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor)) ed_init(state);
|
||||
if (has_flag(state->flags, AppState_RunUserSpace)) incenter_init(state);
|
||||
scratch_release(scratch);
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -43,30 +42,24 @@ lumenarium_frame_prepare(App_State* state)
|
|||
allocator_clear(global_scratch_);
|
||||
|
||||
input_state_swap_frames(state->input_state);
|
||||
|
||||
|
||||
en_frame_prepare(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
ed_frame_prepare(state);
|
||||
}
|
||||
incenter_frame_prepare(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor)) ed_frame_prepare(state);
|
||||
if (has_flag(state->flags, AppState_RunUserSpace)) incenter_frame_prepare(state);
|
||||
|
||||
platform_file_async_jobs_do_work(4, (u8*)state);
|
||||
file_async_jobs_do_work(&state->file_async_job_system, 4, (u8*)state);
|
||||
}
|
||||
|
||||
internal void
|
||||
lumenarium_frame(App_State* state)
|
||||
{
|
||||
en_frame(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
ed_frame(state);
|
||||
}
|
||||
incenter_frame(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor)) ed_frame(state);
|
||||
if (has_flag(state->flags, AppState_RunUserSpace)) incenter_frame(state);
|
||||
}
|
||||
|
||||
internal void
|
||||
lumenarium_event(Platform_Window_Event evt, App_State* state)
|
||||
lumenarium_event(Window_Event evt, App_State* state)
|
||||
{
|
||||
Input_Frame* frame = state->input_state->frame_hot;
|
||||
switch (evt.kind)
|
||||
|
@ -79,8 +72,8 @@ lumenarium_event(Platform_Window_Event evt, App_State* state)
|
|||
case WindowEvent_MouseMoved:
|
||||
{
|
||||
v2 mouse_pos_old = frame->mouse_pos;
|
||||
frame->mouse_pos = v2{ (r32)evt.mouse_x, (r32)evt.mouse_y };
|
||||
state->input_state->mouse_pos_delta = frame->mouse_pos - mouse_pos_old;
|
||||
frame->mouse_pos = (v2){ (r32)evt.mouse_x, (r32)evt.mouse_y };
|
||||
state->input_state->mouse_pos_delta = HMM_SubtractVec2(frame->mouse_pos, mouse_pos_old);
|
||||
} break;
|
||||
|
||||
case WindowEvent_ButtonDown:
|
||||
|
@ -89,7 +82,7 @@ lumenarium_event(Platform_Window_Event evt, App_State* state)
|
|||
frame->key_flags[evt.key_code] = evt.key_flags;
|
||||
if (evt.key_code == KeyCode_MouseLeftButton)
|
||||
{
|
||||
state->input_state->mouse_pos_down = v2{
|
||||
state->input_state->mouse_pos_down = (v2){
|
||||
(r32)evt.mouse_x, (r32)evt.mouse_y
|
||||
};
|
||||
}
|
||||
|
@ -112,10 +105,7 @@ lumenarium_event(Platform_Window_Event evt, App_State* state)
|
|||
internal void
|
||||
lumenarium_cleanup(App_State* state)
|
||||
{
|
||||
incenter_cleanup(state);
|
||||
if (has_flag(state->flags, AppState_RunUserSpace)) incenter_cleanup(state);
|
||||
en_cleanup(state);
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
ed_cleanup(state);
|
||||
}
|
||||
if (has_flag(state->flags, AppState_RunEditor)) ed_cleanup(state);
|
||||
}
|
|
@ -6,16 +6,13 @@
|
|||
typedef struct App_State App_State;
|
||||
|
||||
// Environment
|
||||
#include "lumenarium_memory.cpp"
|
||||
#include "lumenarium_string.cpp"
|
||||
#include "lumenarium_random.h"
|
||||
#include "lumenarium_input.cpp"
|
||||
#include "lumenarium_texture_atlas.cpp"
|
||||
#include "lumenarium_hash.cpp"
|
||||
#include "lumenarium_texture_atlas.c"
|
||||
#include "lumenarium_geometry.h"
|
||||
|
||||
global Allocator* global_scratch_; // gets reset at frame boundaries
|
||||
#define scratch_get(ident) Allocator_Scratch ident = Allocator_Scratch(global_scratch_)
|
||||
// TODO make sure all scratch_get's have a release
|
||||
#define scratch_get(ident) Allocator_Scratch ident = allocator_scratch_begin(global_scratch_)
|
||||
#define scratch_release(ident) allocator_scratch_end(&ident)
|
||||
#include "lumenarium_bsp.h"
|
||||
|
||||
// Engine
|
||||
|
@ -26,6 +23,8 @@ typedef struct Assembly_Strip Assembly_Strip;
|
|||
#include "engine/output/lumenarium_output_sacn.h"
|
||||
|
||||
// Editor
|
||||
#include "editor/graphics/lumenarium_editor_opengl.h"
|
||||
#include "editor/graphics/lumenarium_editor_graphics.h"
|
||||
#include "editor/lumenarium_editor_ui.h"
|
||||
#include "editor/lumenarium_editor_renderer.h"
|
||||
#include "editor/lumenarium_editor.h"
|
||||
|
@ -37,10 +36,22 @@ global Allocator* permanent;
|
|||
|
||||
#if defined(DEBUG)
|
||||
# include "lumenarium_tests.cpp"
|
||||
#define lumenarium_env_validate() lumenarium_env_validate_()
|
||||
#else
|
||||
# define run_tests()
|
||||
#define lumenarium_env_validate()
|
||||
#endif
|
||||
|
||||
internal void
|
||||
lumenarium_env_validate_()
|
||||
{
|
||||
bump_allocator_validate(permanent);
|
||||
bump_allocator_validate(global_scratch_);
|
||||
bump_allocator_validate(file_jobs_arena);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Lumenarium State
|
||||
|
||||
|
@ -50,16 +61,20 @@ enum
|
|||
AppState_None = 0,
|
||||
AppState_IsRunning = 1,
|
||||
AppState_RunEditor = 2,
|
||||
AppState_RunUserSpace = 4,
|
||||
};
|
||||
|
||||
typedef struct App_Init_Desc App_Init_Desc;
|
||||
struct App_Init_Desc
|
||||
{
|
||||
u32 assembly_cap;
|
||||
};
|
||||
|
||||
typedef struct App_State App_State;
|
||||
struct App_State
|
||||
{
|
||||
App_State_Flags flags;
|
||||
File_Async_Job_System file_async_job_system;
|
||||
|
||||
Input_State* input_state;
|
||||
|
||||
|
@ -69,16 +84,16 @@ struct App_State
|
|||
Editor* editor;
|
||||
};
|
||||
|
||||
#include "engine/lumenarium_engine_assembly.cpp"
|
||||
#include "engine/lumenarium_engine.cpp"
|
||||
#include "engine/lumenarium_engine_output.cpp"
|
||||
#include "engine/output/lumenarium_output_uart.cpp"
|
||||
#include "engine/output/lumenarium_output_sacn.cpp"
|
||||
|
||||
#include "editor/lumenarium_editor_ui.cpp"
|
||||
#include "editor/lumenarium_editor_renderer.cpp"
|
||||
#include "editor/lumenarium_editor_sculpture_visualizer.cpp"
|
||||
#include "editor/lumenarium_editor.cpp"
|
||||
#include "engine/lumenarium_engine_assembly.c"
|
||||
#include "engine/lumenarium_engine.c"
|
||||
#include "engine/lumenarium_engine_output.c"
|
||||
#include "engine/output/lumenarium_output_uart.c"
|
||||
#include "engine/output/lumenarium_output_sacn.c"
|
||||
|
||||
#include "editor/lumenarium_editor_ui.c"
|
||||
#include "editor/lumenarium_editor_renderer.c"
|
||||
#include "editor/lumenarium_editor_sculpture_visualizer.c"
|
||||
#include "editor/lumenarium_editor.c"
|
||||
|
||||
#endif //LUMENARIUM_FIRST_H
|
||||
|
|
|
@ -23,6 +23,7 @@ enum
|
|||
GeoVertexBufferStorage_Color = 4
|
||||
};
|
||||
|
||||
typedef struct Geo_Vertex_Buffer Geo_Vertex_Buffer;
|
||||
struct Geo_Vertex_Buffer
|
||||
{
|
||||
r32* values;
|
||||
|
@ -31,6 +32,7 @@ struct Geo_Vertex_Buffer
|
|||
u32 stride;
|
||||
};
|
||||
|
||||
typedef struct Geo_Vertex_Buffer_Builder Geo_Vertex_Buffer_Builder;
|
||||
struct Geo_Vertex_Buffer_Builder
|
||||
{
|
||||
union
|
||||
|
@ -49,12 +51,14 @@ struct Geo_Vertex_Buffer_Builder
|
|||
u32 cap;
|
||||
};
|
||||
|
||||
typedef struct Geo_Index_Buffer Geo_Index_Buffer;
|
||||
struct Geo_Index_Buffer
|
||||
{
|
||||
u32* values;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
typedef struct Geo_Index_Buffer_Builder Geo_Index_Buffer_Builder;
|
||||
struct Geo_Index_Buffer_Builder
|
||||
{
|
||||
union
|
||||
|
@ -71,36 +75,38 @@ struct Geo_Index_Buffer_Builder
|
|||
u32 cap;
|
||||
};
|
||||
|
||||
typedef struct Geo_Quad_Buffer Geo_Quad_Buffer;
|
||||
struct Geo_Quad_Buffer
|
||||
{
|
||||
Geo_Vertex_Buffer buffer_vertex;
|
||||
Geo_Index_Buffer buffer_index;
|
||||
};
|
||||
|
||||
typedef struct Geo_Quad_Buffer_Builder Geo_Quad_Buffer_Builder;
|
||||
struct Geo_Quad_Buffer_Builder
|
||||
{
|
||||
Geo_Vertex_Buffer_Builder buffer_vertex;
|
||||
Geo_Index_Buffer_Builder buffer_index;
|
||||
};
|
||||
|
||||
internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap);
|
||||
internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap, Geo_Vertex_Buffer_Storage storage);
|
||||
internal Geo_Index_Buffer_Builder geo_index_buffer_builder_create(Allocator* a, u32 cap);
|
||||
internal Geo_Quad_Buffer_Builder geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, u32 index_cap);
|
||||
internal Geo_Quad_Buffer_Builder ggeo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, Geo_Vertex_Buffer_Storage storage, u32 index_cap);
|
||||
|
||||
// Vertex Buffer
|
||||
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c);
|
||||
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t);
|
||||
internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v);
|
||||
internal u32 geo_vertex_buffer_builder_push_vtc(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c);
|
||||
internal u32 geo_vertex_buffer_builder_push_vt(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t);
|
||||
internal u32 geo_vertex_buffer_builder_push_v(Geo_Vertex_Buffer_Builder* b, v3 v);
|
||||
|
||||
// Index Buffer
|
||||
internal u32 geo_index_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, u32 i);
|
||||
internal void geo_index_buffer_builder_push_tri(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2);
|
||||
internal void geo_index_buffer_builder_push_quad(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3);
|
||||
internal u32 geo_index_buffer_builder_push(Geo_Index_Buffer_Builder* b, u32 i);
|
||||
internal void geo_index_buffer_builder_push_tri(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2);
|
||||
internal void geo_index_buffer_builder_push_quad(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3);
|
||||
|
||||
// Quad Buffer
|
||||
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c);
|
||||
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3);
|
||||
internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3);
|
||||
internal void geo_quad_buffer_builder_push_vtc(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c);
|
||||
internal void geo_quad_buffer_builder_push_vt(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3);
|
||||
internal void geo_quad_buffer_builder_push_v(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3);
|
||||
internal Geo_Quad_Buffer geo_quad_buffer_builder_get_static_buffer(Geo_Quad_Buffer_Builder* b);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
|
@ -116,26 +122,61 @@ geo_vertex_buffer_builder_stride(Geo_Vertex_Buffer_Storage storage)
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
# define geo_vertex_buffers_validate(g) geo_vertex_buffers_validate_(g)
|
||||
#else
|
||||
# define geo_vertex_buffers_validate(g)
|
||||
#endif
|
||||
|
||||
void
|
||||
geo_vertex_buffers_validate_(Geo_Vertex_Buffer_Builder* b)
|
||||
{
|
||||
// before start
|
||||
u32* sentinel = (u32*)(b->values - 2);
|
||||
assert(sentinel[0] == 0xF0F0F0F0);
|
||||
assert(sentinel[1] == 0x0F0F0F0F);
|
||||
|
||||
// after end
|
||||
sentinel = (u32*)(b->values + (b->cap * b->stride));
|
||||
assert(sentinel[0] == 0xFFFF000F);
|
||||
assert(sentinel[1] == 0xF000FFFF);
|
||||
}
|
||||
|
||||
internal Geo_Vertex_Buffer_Builder
|
||||
geo_vertex_buffer_builder_create(Allocator* a, u32 cap, Geo_Vertex_Buffer_Storage storage)
|
||||
{
|
||||
u32 stride = geo_vertex_buffer_builder_stride(storage);
|
||||
u32 size = cap * stride;
|
||||
u32 alloc_size = size;
|
||||
#ifdef DEBUG
|
||||
alloc_size += 4;
|
||||
#endif
|
||||
|
||||
Geo_Vertex_Buffer_Builder result = {};
|
||||
zero_struct(result);
|
||||
result.cap = cap;
|
||||
result.storage = storage;
|
||||
result.stride = stride;
|
||||
result.values = allocator_alloc_array(a, r32, size);
|
||||
result.values = allocator_alloc_array(a, r32, alloc_size);
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
u32* sentinel = (u32*)result.values;
|
||||
sentinel[0] = 0xF0F0F0F0;
|
||||
sentinel[1] = 0x0F0F0F0F;
|
||||
sentinel = (u32*)(result.values + alloc_size - 2);
|
||||
result.values += 2;
|
||||
sentinel[0] = 0xFFFF000F;
|
||||
sentinel[1] = 0xF000FFFF;
|
||||
#endif
|
||||
|
||||
geo_vertex_buffers_validate(&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Geo_Index_Buffer_Builder
|
||||
geo_index_buffer_builder_create(Allocator* a, u32 cap)
|
||||
{
|
||||
|
||||
Geo_Index_Buffer_Builder result = {};
|
||||
zero_struct(result);
|
||||
result.cap = cap;
|
||||
|
@ -155,42 +196,46 @@ geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, Geo_Vertex_Buffer_S
|
|||
// Vertex Buffer
|
||||
|
||||
internal u32
|
||||
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c)
|
||||
geo_vertex_buffer_builder_push_vtc(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c)
|
||||
{
|
||||
geo_vertex_buffers_validate(b);
|
||||
assert(b->len < b->cap);
|
||||
u32 result = b->len++;
|
||||
u32 offset = result * b->stride;
|
||||
assert((offset + b->stride) <= (b->cap * b->stride));
|
||||
r32* at = b->values + offset;
|
||||
if (has_flag(b->storage, GeoVertexBufferStorage_Position))
|
||||
{
|
||||
b->values[offset++] = v.x;
|
||||
b->values[offset++] = v.y;
|
||||
b->values[offset++] = v.z;
|
||||
*at++ = v.x;
|
||||
*at++ = v.y;
|
||||
*at++ = v.z;
|
||||
}
|
||||
if (has_flag(b->storage, GeoVertexBufferStorage_TexCoord))
|
||||
{
|
||||
b->values[offset++] = t.x;
|
||||
b->values[offset++] = t.y;
|
||||
*at++ = t.x;
|
||||
*at++ = t.y;
|
||||
}
|
||||
if (has_flag(b->storage, GeoVertexBufferStorage_Color))
|
||||
{
|
||||
b->values[offset++] = c.x;
|
||||
b->values[offset++] = c.y;
|
||||
b->values[offset++] = c.z;
|
||||
b->values[offset++] = c.w;
|
||||
*at++ = c.x;
|
||||
*at++ = c.y;
|
||||
*at++ = c.z;
|
||||
*at++ = c.w;
|
||||
}
|
||||
geo_vertex_buffers_validate(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal u32
|
||||
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t)
|
||||
geo_vertex_buffer_builder_push_vt(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t)
|
||||
{
|
||||
return geo_vertex_buffer_builder_push(b, v, t, v4{0});
|
||||
return geo_vertex_buffer_builder_push_vtc(b, v, t, (v4){0});
|
||||
}
|
||||
|
||||
internal u32
|
||||
geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v)
|
||||
geo_vertex_buffer_builder_push_v(Geo_Vertex_Buffer_Builder* b, v3 v)
|
||||
{
|
||||
return geo_vertex_buffer_builder_push(b, v, v2{0}, v4{0});
|
||||
return geo_vertex_buffer_builder_push_vtc(b, v, (v2){0}, (v4){0});
|
||||
}
|
||||
|
||||
|
||||
|
@ -224,34 +269,34 @@ geo_index_buffer_builder_push_quad(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1,
|
|||
// Quad Buffer
|
||||
|
||||
internal void
|
||||
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c)
|
||||
geo_quad_buffer_builder_push_vtc(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c)
|
||||
{
|
||||
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, c);
|
||||
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, c);
|
||||
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, c);
|
||||
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, c);
|
||||
u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, t0, c);
|
||||
u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, t1, c);
|
||||
u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, t2, c);
|
||||
u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, t3, c);
|
||||
|
||||
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
|
||||
}
|
||||
|
||||
internal void
|
||||
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3)
|
||||
geo_quad_buffer_builder_push_vt(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3)
|
||||
{
|
||||
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, v4{});
|
||||
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, v4{});
|
||||
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, v4{});
|
||||
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, v4{});
|
||||
u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, t0, (v4){});
|
||||
u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, t1, (v4){});
|
||||
u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, t2, (v4){});
|
||||
u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, t3, (v4){});
|
||||
|
||||
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
|
||||
}
|
||||
|
||||
internal void
|
||||
geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3)
|
||||
geo_quad_buffer_builder_push_v(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3)
|
||||
{
|
||||
u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, v2{}, v4{});
|
||||
u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, v2{}, v4{});
|
||||
u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, v2{}, v4{});
|
||||
u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, v2{}, v4{});
|
||||
u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, (v2){}, (v4){});
|
||||
u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, (v2){}, (v4){});
|
||||
u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, (v2){}, (v4){});
|
||||
u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, (v2){}, (v4){});
|
||||
|
||||
geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
|
||||
|
||||
// TODO(PS) @DEPRECATE - new os layer
|
||||
|
||||
#define INPUT_FRAME_STRING_LENGTH 32
|
||||
struct Input_Frame
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// TODO(PS) @DEPRECATE - new os layer
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Memory Functions
|
||||
|
@ -467,6 +468,7 @@ paged_allocator_free(Allocator* allocator, u8* base, u64 size)
|
|||
else
|
||||
{
|
||||
// free list is empty
|
||||
region->next = 0;
|
||||
paged->free_first = region;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// TODO(PS) @DEPRECATE - new os layer
|
||||
|
||||
/* date = April 6th 2022 7:55 pm */
|
||||
|
||||
#ifndef LUMENARIUM_MEMORY_H
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
Platform_Thread_Result
|
||||
thread_proc(Platform_Thread_Data* td)
|
||||
Thread_Result
|
||||
thread_proc(Thread_Data* td)
|
||||
{
|
||||
//Sleep(100);
|
||||
return {};
|
||||
return (Thread_Result){};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -75,15 +75,15 @@ memory_tests()
|
|||
size = KB(4);
|
||||
#endif
|
||||
|
||||
u8* base = platform_mem_reserve(size);
|
||||
platform_mem_commit(base, KB(4));
|
||||
u8* base = os_mem_reserve(size);
|
||||
os_mem_commit(base, KB(4));
|
||||
base[4095] = 200;
|
||||
assert(base[4095] == 200);
|
||||
platform_mem_commit(base + KB(4), KB(4));
|
||||
os_mem_commit(base + KB(4), KB(4));
|
||||
base[5000] = 200;
|
||||
assert(base[5000] == 200);
|
||||
platform_mem_decommit(base, KB(8));
|
||||
platform_mem_release(base, GB(32));
|
||||
os_mem_decommit(base, KB(8));
|
||||
os_mem_release(base, GB(32));
|
||||
}
|
||||
|
||||
Allocator* bump = bump_allocator_create_reserve(KB(32));
|
||||
|
@ -155,11 +155,11 @@ run_tests()
|
|||
}
|
||||
|
||||
|
||||
assert(round_up_to_pow2(1) == 1);
|
||||
assert(round_up_to_pow2(3) == 4);
|
||||
assert(round_up_to_pow2(29) == 32);
|
||||
assert(round_up_to_pow2(32) == 32);
|
||||
assert(round_up_to_pow2(120) == 128);
|
||||
assert(round_up_to_pow2_u32(1) == 1);
|
||||
assert(round_up_to_pow2_u32(3) == 4);
|
||||
assert(round_up_to_pow2_u32(29) == 32);
|
||||
assert(round_up_to_pow2_u32(32) == 32);
|
||||
assert(round_up_to_pow2_u32(120) == 128);
|
||||
|
||||
memory_tests();
|
||||
bsp_tests();
|
||||
|
@ -172,7 +172,7 @@ run_tests()
|
|||
|
||||
|
||||
// testing strings and exe path
|
||||
String exe_file_path = platform_get_exe_path(scratch.a);
|
||||
String exe_file_path = os_get_exe_path(scratch.a);
|
||||
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;
|
||||
|
@ -180,18 +180,18 @@ run_tests()
|
|||
String run_tree_path = string_get_prefix(exe_file_path, run_tree_end);
|
||||
String run_tree_path_nullterm = string_copy(run_tree_path, scratch.a);
|
||||
assert(run_tree_path_nullterm.len > 0);
|
||||
assert(platform_pwd_set(run_tree_path_nullterm));
|
||||
assert(os_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.a);
|
||||
File_Handle f = os_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenExisting);
|
||||
File_Info i = os_file_get_info(f, scratch.a);
|
||||
|
||||
Data d0 = platform_file_read_all(f, scratch.a);
|
||||
Data d0 = os_file_read_all(f, scratch.a);
|
||||
assert(d0.size > 0);
|
||||
|
||||
String s = lit_str("foooooooooobbbbbbaaaarrrrrr");
|
||||
Data d1 = { s.str, s.len };
|
||||
bool r = platform_file_write_all(f, d1);
|
||||
bool r = os_file_write_all(f, d1);
|
||||
assert(r);
|
||||
|
||||
#if 0
|
||||
|
@ -211,5 +211,5 @@ run_tests()
|
|||
platform_thread_end(threads[j]);
|
||||
}
|
||||
#endif
|
||||
|
||||
scratch_release(scratch);
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
#ifndef LUMENARIUM_TEXTURE_ATLAS_CPP
|
||||
#define LUMENARIUM_TEXTURE_ATLAS_CPP
|
||||
|
||||
typedef struct Texture_Atlas_Sprite Texture_Atlas_Sprite;
|
||||
struct Texture_Atlas_Sprite
|
||||
{
|
||||
u16 min_x;
|
||||
|
@ -13,6 +14,7 @@ struct Texture_Atlas_Sprite
|
|||
v2 draw_offset;
|
||||
};
|
||||
|
||||
typedef struct Texture_Atlas Texture_Atlas;
|
||||
struct Texture_Atlas
|
||||
{
|
||||
u8* pixels;
|
||||
|
@ -38,7 +40,7 @@ texture_atlas_create(u32 width, u32 height, u32 cap, Allocator* allocator)
|
|||
result.height = (u16)height;
|
||||
for (u32 i = 0; i < width * height; i++) {
|
||||
u8* base = result.pixels + (i * 4);
|
||||
*(u32*)base = 0x00FFFFFF;
|
||||
*(u32*)base = 0xFF00FFFF;
|
||||
}
|
||||
|
||||
result.ids = allocator_alloc_array(allocator, u32, cap);
|
||||
|
@ -180,7 +182,7 @@ texture_atlas_sprite_get_uvs(Texture_Atlas* ta, Texture_Atlas_Sprite sprite)
|
|||
}
|
||||
|
||||
internal v4
|
||||
texture_atlas_sprite_get_uvs(Texture_Atlas* ta, u32 id)
|
||||
texture_atlas_sprite_id_get_uvs(Texture_Atlas* ta, u32 id)
|
||||
{
|
||||
Texture_Atlas_Sprite sprite = texture_atlas_sprite_get(ta, id);
|
||||
return texture_atlas_sprite_get_uvs(ta, sprite);
|
|
@ -1,3 +1,5 @@
|
|||
// TODO(PS) @DEPRECATE - new os layer
|
||||
|
||||
/* date = March 22nd 2022 2:08 am */
|
||||
|
||||
#ifndef LUMENARIUM_TYPES_H
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
#if !defined(LUMENARIUM_OS)
|
||||
#define LUMENARIUM_OS
|
||||
|
||||
///////////////////////////////////////
|
||||
// Memory
|
||||
|
||||
u8* os_mem_reserve(u64 size);
|
||||
u8* os_mem_commit(u8* base, u64 size);
|
||||
bool os_mem_decommit(u8* base, u64 size);
|
||||
bool os_mem_release(u8* base, u64 size);
|
||||
|
||||
///////////////////////////////////////
|
||||
// File I/O
|
||||
|
||||
File_Async_Job_System os_file_jobs_init();
|
||||
File_Handle os_file_open(String path, File_Access_Flags flags_access, File_Create_Flags flags_create);
|
||||
void os_file_close(File_Handle file_handle);
|
||||
File_Info os_file_get_info(File_Handle file_handle, Allocator* allocator);
|
||||
Data os_file_read_all(File_Handle file_handle, Allocator* allocator);
|
||||
bool os_file_write_all(File_Handle file_handle, Data file_data);
|
||||
|
||||
String os_get_exe_path(Allocator* allocator);
|
||||
bool os_pwd_set(String path);
|
||||
|
||||
File_Info_List os_dir_enum(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator);
|
||||
|
||||
// Asnyc Jobs
|
||||
void os_file_async_work_on_job(File_Async_Job* job);
|
||||
|
||||
///////////////////////////////////////
|
||||
// Time
|
||||
|
||||
Ticks os_get_ticks();
|
||||
r64 os_get_ticks_per_second();
|
||||
|
||||
///////////////////////////////////////
|
||||
// Threads
|
||||
|
||||
Thread_Handle os_thread_begin(Thread_Proc* proc, u8* user_data);
|
||||
void os_thread_end(Thread_Handle thread_handle);
|
||||
|
||||
u32 os_interlocked_increment(volatile u32* value);
|
||||
u32 os_interlocked_cmp_exchg(volatile u32* dest, u32 new_value, u32 old_value);
|
||||
|
||||
///////////////////////////////////////
|
||||
// Network Access
|
||||
|
||||
Socket_Handle os_socket_create();
|
||||
bool os_socket_bind();
|
||||
bool os_socket_connect();
|
||||
bool os_socket_close();
|
||||
Data os_socket_recv();
|
||||
s32 os_Socket_set_listening();
|
||||
s32 os_Socket_send();
|
||||
s32 os_Socket_send_to();
|
||||
s32 os_Socket_set_opt();
|
||||
|
||||
#endif // LUMENARIUM_OS
|
|
@ -0,0 +1,239 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#include "lumenarium_osx_memory.h"
|
||||
#include "../../core/lumenarium_core.h"
|
||||
#include "../lumenarium_os.h"
|
||||
#include "../../lumenarium_first.c"
|
||||
|
||||
#undef internal
|
||||
#undef external
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/syslimits.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach/mach_time.h>
|
||||
|
||||
#include "../../libs/glfw_osx/include/GLFW/glfw3.h"
|
||||
|
||||
#define osx_err_print(sub_proc) osx_err_print_((char*)__FUNCTION__, (char*)(sub_proc), errno)
|
||||
void
|
||||
osx_err_print_(char* proc, char* sub_proc, s32 errsv)
|
||||
{
|
||||
printf("Error: %s:%s - %d\n\t%s\n\n", proc, sub_proc, errsv, strerror(errsv));
|
||||
}
|
||||
|
||||
#define OS_FILE_HANDLE_TYPE s32
|
||||
#define OS_FILE_MAX_PATH PATH_MAX
|
||||
#define OS_FILE_INVALID_HANDLE -1
|
||||
#include "../shared/lumenarium_shared_file_tracker.h"
|
||||
#include "../shared/lumenarium_shared_file_async_work_on_job.h"
|
||||
#include "lumenarium_osx_file.h"
|
||||
#include "lumenarium_osx_time.h"
|
||||
#include "lumenarium_osx_graphics.h"
|
||||
|
||||
void osx_tests()
|
||||
{
|
||||
Ticks t0 = os_get_ticks();
|
||||
|
||||
// File Tests
|
||||
File_Handle file = os_file_open(lit_str("text.txt"), FileAccess_Read | FileAccess_Write, FileCreate_OpenAlways);
|
||||
File_Info info = os_file_get_info(file, global_scratch_);
|
||||
Data d = os_file_read_all(file, global_scratch_);
|
||||
os_file_write_all(file, d);
|
||||
os_file_close(file);
|
||||
|
||||
// Path tests
|
||||
String path_exe = os_get_exe_path(global_scratch_);
|
||||
printf("%.*s\n", str_varg(path_exe));
|
||||
String path = string_chop_last_slash(path_exe);
|
||||
String path0 = string_copy(path, global_scratch_);
|
||||
os_pwd_set(path0);
|
||||
|
||||
Ticks t1 = os_get_ticks();
|
||||
Ticks td = get_ticks_elapsed(t0, t1);
|
||||
r64 sd = ticks_to_seconds(td, os_get_ticks_per_second());
|
||||
}
|
||||
|
||||
void
|
||||
glfw_error_callback(int error, const char* description)
|
||||
{
|
||||
fprintf(stderr, "Error: %s\n", description);
|
||||
}
|
||||
|
||||
global u8* app_state_data = 0;
|
||||
|
||||
global Key_Code glfw_key_translation_table[] = {
|
||||
|
||||
};
|
||||
|
||||
Key_Code
|
||||
osx_translate_key(int glfw_key)
|
||||
{
|
||||
// TODO: turn this into an actual key_code
|
||||
return (Key_Code)glfw_key;
|
||||
}
|
||||
|
||||
Key_Code
|
||||
osx_translate_mouse_button(int glfw_button)
|
||||
{
|
||||
switch (glfw_button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_LEFT: return KeyCode_MouseLeftButton; break;
|
||||
case GLFW_MOUSE_BUTTON_RIGHT: return KeyCode_MouseRightButton; break;
|
||||
case GLFW_MOUSE_BUTTON_MIDDLE: return KeyCode_MouseMiddleButton; break;
|
||||
invalid_default_case;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
button_event(Key_Code key, int action, int mods)
|
||||
{
|
||||
Window_Event evt = {
|
||||
.kind = WindowEvent_ButtonDown,
|
||||
.key_code = key,
|
||||
};
|
||||
|
||||
if (has_flag(mods, GLFW_MOD_SHIFT)) add_flag(evt.key_flags, KeyFlag_Mod_Shift);
|
||||
if (has_flag(mods, GLFW_MOD_CONTROL)) add_flag(evt.key_flags, KeyFlag_Mod_Shift);
|
||||
if (has_flag(mods, GLFW_MOD_ALT)) add_flag(evt.key_flags, KeyFlag_Mod_Shift);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GLFW_PRESS: { evt.key_flags = KeyFlag_State_IsDown; } break;
|
||||
case GLFW_REPEAT: {
|
||||
evt.key_flags = KeyFlag_State_IsDown | KeyFlag_State_WasDown;
|
||||
} break;
|
||||
case GLFW_RELEASE: {
|
||||
evt.key_flags = KeyFlag_State_WasDown;
|
||||
} break;
|
||||
invalid_default_case;
|
||||
}
|
||||
lumenarium_event(evt, (App_State*)app_state_data);
|
||||
}
|
||||
|
||||
void
|
||||
key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
||||
{
|
||||
Key_Code kc = osx_translate_key(key);
|
||||
button_event(kc, action, mods);
|
||||
}
|
||||
|
||||
void
|
||||
cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
Window_Event evt = {
|
||||
.kind = WindowEvent_MouseMoved,
|
||||
.mouse_x = (u32)xpos,
|
||||
.mouse_y = (u32)ypos,
|
||||
};
|
||||
lumenarium_event(evt, (App_State*)app_state_data);
|
||||
}
|
||||
|
||||
void
|
||||
mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
Key_Code kc = osx_translate_mouse_button(button);
|
||||
button_event(kc, action, mods);
|
||||
}
|
||||
|
||||
void
|
||||
scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
|
||||
{
|
||||
Window_Event evt = {};
|
||||
evt.kind = WindowEvent_MouseScroll;
|
||||
evt.scroll_amt = xoffset;
|
||||
lumenarium_event(evt, (App_State*)app_state_data);
|
||||
}
|
||||
|
||||
int main (int arg_count, char** args)
|
||||
{
|
||||
// osx_tests();
|
||||
|
||||
if (!glfwInit())
|
||||
{
|
||||
printf("Error: Could not initialize glfw.\n");
|
||||
return 1;
|
||||
}
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
|
||||
glfwWindowHint(GLFW_DOUBLEBUFFER, true);
|
||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
GLFWwindow* window = glfwCreateWindow(1400, 700, "Lumenarium", NULL, NULL);
|
||||
if (!window)
|
||||
{
|
||||
printf("Error: Unable to create a glfw window\n");
|
||||
return 1;
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSwapInterval(1);
|
||||
gl = osx_load_opengl_ext();
|
||||
|
||||
// Input Callbacks
|
||||
glfwSetKeyCallback(window, key_callback);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetScrollCallback(window, scroll_callback);
|
||||
|
||||
App_State* state = lumenarium_init();
|
||||
app_state_data = (u8*)state;
|
||||
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
float xscale, yscale;
|
||||
glfwGetWindowContentScale(window, &xscale, &yscale);
|
||||
state->editor->content_scale = (v2){ xscale, yscale };
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
r64 target_seconds_per_frame = 1.0 / 30.0f;
|
||||
Ticks ticks_start = os_get_ticks();
|
||||
while(!glfwWindowShouldClose(window) && running && has_flag(state->flags, AppState_IsRunning)) {
|
||||
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
s32 w, h;
|
||||
glfwGetWindowSize(window, &w, &h);
|
||||
state->editor->window_dim = (v2){ (r32)w, (r32)h };
|
||||
}
|
||||
|
||||
lumenarium_frame_prepare(state);
|
||||
lumenarium_frame(state);
|
||||
lumenarium_env_validate();
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
|
||||
Ticks ticks_end = os_get_ticks();
|
||||
r64 seconds_elapsed = get_seconds_elapsed(ticks_start, ticks_end, os_get_ticks_per_second());
|
||||
while (seconds_elapsed < target_seconds_per_frame)
|
||||
{
|
||||
u32 sleep_time = (u32)(1000.0f * (target_seconds_per_frame - seconds_elapsed));
|
||||
usleep(sleep_time);
|
||||
|
||||
ticks_end = os_get_ticks();
|
||||
seconds_elapsed = get_seconds_elapsed(ticks_start, ticks_end, os_get_ticks_per_second());
|
||||
}
|
||||
ticks_start = ticks_end;
|
||||
}
|
||||
|
||||
lumenarium_cleanup(state);
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
|
||||
#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,213 @@
|
|||
File_Async_Job_System
|
||||
os_file_jobs_init()
|
||||
{
|
||||
open_files_init();
|
||||
File_Async_Job_System result = file_async_jobs_init(os_file_async_work_on_job);
|
||||
return result;
|
||||
}
|
||||
|
||||
File_Handle
|
||||
os_file_open(String path, File_Access_Flags flags_access, File_Create_Flags flags_create)
|
||||
{
|
||||
File_Handle result = {};
|
||||
|
||||
s32 flags = 0;
|
||||
if (has_flag_exact(flags_access, (FileAccess_Read | FileAccess_Write)))
|
||||
{
|
||||
add_flag(flags, O_RDWR);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (has_flag(flags_access, FileAccess_Read))
|
||||
{
|
||||
add_flag(flags, O_RDONLY);
|
||||
}
|
||||
else if (has_flag(flags_access, FileAccess_Write))
|
||||
{
|
||||
add_flag(flags, O_WRONLY);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
switch (flags_create)
|
||||
{
|
||||
case FileCreate_New: { add_flag(flags, O_CREAT | O_EXCL ); } break;
|
||||
case FileCreate_CreateAlways: { add_flag(flags, O_CREAT); } break;
|
||||
case FileCreate_OpenExisting: { /* add_flag(flags, O_); */ } break;
|
||||
case FileCreate_OpenAlways: { /* add_flag(flags, O_); */ } break;
|
||||
invalid_default_case;
|
||||
}
|
||||
|
||||
s32 file_handle = open((char*)path.str, flags);
|
||||
if (file_handle >= 0)
|
||||
{
|
||||
result = open_files_put_handle(file_handle, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error: os_file_open - %d\n", errsv);
|
||||
printf("\tAttempting to open: %.*s\n", str_varg(path));
|
||||
printf("\tFlags: %u %u\n", flags_access, flags_create);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
os_file_close(File_Handle file_handle)
|
||||
{
|
||||
s32 os_handle = open_files_get_handle(file_handle);
|
||||
if (close(os_handle) != -1)
|
||||
{
|
||||
open_files_rem_file(file_handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error: os_file_close - %d\n", errsv);
|
||||
}
|
||||
}
|
||||
|
||||
File_Info
|
||||
os_file_get_info(File_Handle file_handle, Allocator* allocator)
|
||||
{
|
||||
File_Info info = {};
|
||||
s32 os_handle = open_files_get_handle(file_handle);
|
||||
if (os_handle != -1)
|
||||
{
|
||||
String path = open_files_get_path(file_handle);
|
||||
|
||||
struct stat os_info = {};
|
||||
if (fstat(os_handle, &os_info) != -1)
|
||||
{
|
||||
info.path = string_copy(path, allocator);
|
||||
info.path_abs = allocator_alloc_string(allocator, PATH_MAX);
|
||||
if (realpath((char*)path.str, (char*)info.path_abs.str) != 0)
|
||||
{
|
||||
info.path_abs.len = c_str_len((char*)info.path_abs.str);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error - os_file_get_info - %d - realpath\n", errsv);
|
||||
}
|
||||
info.size = (u64)os_info.st_size;
|
||||
if (S_ISDIR(os_info.st_mode))
|
||||
{
|
||||
add_flag(info.flags, FileFlag_IsDir);
|
||||
}
|
||||
else if (!S_ISREG(os_info.st_mode))
|
||||
{
|
||||
printf("Error - os_file_get_info - stat-ing a handle that is not a directory or a file\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error: os_file_get_info - %d\n", errsv);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
Data
|
||||
os_file_read_all(File_Handle file_handle, Allocator* allocator)
|
||||
{
|
||||
Data result = {};
|
||||
s32 os_handle = open_files_get_handle(file_handle);
|
||||
if (os_handle == -1) return result;
|
||||
|
||||
// get file size
|
||||
s32 offset = lseek(os_handle, 0, SEEK_END);
|
||||
if (offset == -1)
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error: os_file_read_all:lseek - %d\n", errsv);
|
||||
return result;
|
||||
}
|
||||
lseek(os_handle, 0, SEEK_SET);
|
||||
|
||||
result.base = allocator_alloc(allocator, offset + 1);
|
||||
result.size = offset + 1;
|
||||
|
||||
s32 bytes_read = read(os_handle, result.base, result.size);
|
||||
if (bytes_read == (result.size - 1))
|
||||
{
|
||||
result.base[bytes_read] = 0; // null term
|
||||
}
|
||||
else if (bytes_read >= 0)
|
||||
{
|
||||
printf("Error: os_file_read:read - whole file not read.\n");
|
||||
}
|
||||
else if (bytes_read == -1)
|
||||
{
|
||||
s32 errsv = errno;
|
||||
printf("Error: os_file_read_all:read - %d\n", errsv);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
os_file_write_all(File_Handle file_handle, Data file_data)
|
||||
{
|
||||
s32 os_handle = open_files_get_handle(file_handle);
|
||||
if (os_handle == -1) return false;
|
||||
|
||||
lseek(os_handle, 0, SEEK_SET);
|
||||
s32 size_written = write(os_handle, file_data.base, file_data.size);
|
||||
if (size_written > 0 && size_written != file_data.size)
|
||||
{
|
||||
printf("Error: os_file_write_all:write - whole file not written\n");
|
||||
return true;
|
||||
}
|
||||
else if (size_written < 0)
|
||||
{
|
||||
osx_err_print("write");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String
|
||||
os_get_exe_path(Allocator* allocator)
|
||||
{
|
||||
u32 needed = 0;
|
||||
_NSGetExecutablePath(0, &needed);
|
||||
|
||||
String result = allocator_alloc_string(allocator, needed + 1);
|
||||
|
||||
u32 cap = (u64)result.cap;
|
||||
s32 r = _NSGetExecutablePath((char*)result.str, &cap);
|
||||
if (r == 0)
|
||||
{
|
||||
result.len = cap;
|
||||
result.str[result.len] = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
os_pwd_set(String path)
|
||||
{
|
||||
s32 result = chdir((char*)path.str);
|
||||
if (result == -1)
|
||||
{
|
||||
osx_err_print("chdir");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
File_Info_List
|
||||
os_dir_enum(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
#define OSX_GL_ERROR_CASE(e) case e: { result = #e; } break
|
||||
char*
|
||||
osx_gl_error_to_string(u32 error)
|
||||
{
|
||||
char* result = 0;
|
||||
switch (error)
|
||||
{
|
||||
OSX_GL_ERROR_CASE(GL_INVALID_VALUE);
|
||||
OSX_GL_ERROR_CASE(GL_INVALID_ENUM );
|
||||
OSX_GL_ERROR_CASE(GL_INVALID_OPERATION);
|
||||
default: { result = "unknown"; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
os_gl_no_error_(char* file, u32 line) {
|
||||
u32 error = glGetError();
|
||||
char* str = 0;
|
||||
if (error) {
|
||||
str = osx_gl_error_to_string(error);
|
||||
}
|
||||
if (error != 0)
|
||||
{
|
||||
fprintf(stderr, "OpenGL error: %s:%d\n\t%s :: %d\n", file, line, str, error);
|
||||
invalid_code_path;
|
||||
}
|
||||
}
|
||||
|
||||
#define load_ext(r,n) r.n = (proc_##n*)glfwGetProcAddress(#n); assert((r.n) != 0)
|
||||
OpenGL_Extensions
|
||||
osx_load_opengl_ext()
|
||||
{
|
||||
OpenGL_Extensions result = {};
|
||||
load_ext(result, glGenVertexArrays);
|
||||
load_ext(result, glBindVertexArray);
|
||||
load_ext(result, glGenBuffers);
|
||||
load_ext(result, glBindBuffer);
|
||||
load_ext(result, glBufferData);
|
||||
load_ext(result, glBufferSubData);
|
||||
load_ext(result, glCreateShader);
|
||||
load_ext(result, glShaderSource);
|
||||
load_ext(result, glCompileShader);
|
||||
load_ext(result, glCreateProgram);
|
||||
load_ext(result, glAttachShader);
|
||||
load_ext(result, glLinkProgram);
|
||||
load_ext(result, glUseProgram);
|
||||
load_ext(result, glGetAttribLocation);
|
||||
load_ext(result, glVertexAttribPointer);
|
||||
load_ext(result, glEnableVertexAttribArray);
|
||||
load_ext(result, glGetShaderiv);
|
||||
load_ext(result, glGetShaderInfoLog);
|
||||
load_ext(result, glGetProgramiv);
|
||||
load_ext(result, glGetProgramInfoLog);
|
||||
load_ext(result, glGetUniformLocation);
|
||||
load_ext(result, glUniformMatrix4fv);
|
||||
return result;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
#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,41 @@
|
|||
// TODO(PS): come back and do this properly
|
||||
#define OS_MEM_PAGE_SIZE 4096
|
||||
|
||||
size_t
|
||||
osx_round_to_page_size(uint64_t size)
|
||||
{
|
||||
uint64_t rem = size % OS_MEM_PAGE_SIZE;
|
||||
if (rem != 0 || size < OS_MEM_PAGE_SIZE)
|
||||
{
|
||||
uint64_t grow = OS_MEM_PAGE_SIZE - rem;
|
||||
size += grow;
|
||||
}
|
||||
return (size_t)size;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
os_mem_reserve(uint64_t size)
|
||||
{
|
||||
size_t size_cvt = osx_round_to_page_size(size);
|
||||
uint8_t* result = (uint8_t*)malloc(size_cvt);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
os_mem_commit(uint8_t* base, uint64_t size)
|
||||
{
|
||||
return base;
|
||||
}
|
||||
|
||||
bool
|
||||
os_mem_decommit(uint8_t* base, uint64_t size)
|
||||
{
|
||||
return 1; // true
|
||||
}
|
||||
|
||||
bool
|
||||
os_mem_release(uint8_t* base, uint64_t size)
|
||||
{
|
||||
free(base);
|
||||
return 1; // true
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
// I think this SO post might be helpful
|
||||
// https://stackoverflow.com/questions/30575995/multi-platform-equivalent-to-queryperformancecounter
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
// I think this SO post might be helpful
|
||||
// https://stackoverflow.com/questions/30575995/multi-platform-equivalent-to-queryperformancecounter
|
||||
|
||||
Ticks
|
||||
os_get_ticks()
|
||||
{
|
||||
Ticks result = {
|
||||
.value = mach_absolute_time()
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
r64
|
||||
os_get_ticks_per_second()
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
r64 to_nanos = (r64)info.numer / (r64)info.denom;
|
||||
r64 to_secs = to_nanos / 10e9;
|
||||
return to_secs;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#if defined(PLATFORM_win32) || defined(PLATFORM_osx)
|
||||
|
||||
void
|
||||
os_file_async_work_on_job(File_Async_Job* job)
|
||||
{
|
||||
File_Handle file = {};
|
||||
if (has_flag(job->args.flags, FileAsyncJob_Read))
|
||||
{
|
||||
file = os_file_open(job->args.path, FileAccess_Read, FileCreate_OpenExisting);
|
||||
Data result = os_file_read_all(file, file_jobs_arena);
|
||||
if (result.base != 0)
|
||||
{
|
||||
job->args.data = result;
|
||||
add_flag(job->args.flags, FileAsyncJob_Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_flag(job->args.flags, FileAsyncJob_Failed);
|
||||
}
|
||||
}
|
||||
else if (has_flag(job->args.flags, FileAsyncJob_Write))
|
||||
{
|
||||
file = os_file_open(job->args.path, FileAccess_Write, FileCreate_OpenAlways);
|
||||
if (os_file_write_all(file, job->args.data))
|
||||
{
|
||||
add_flag(job->args.flags, FileAsyncJob_Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_flag(job->args.flags, FileAsyncJob_Failed);
|
||||
}
|
||||
}
|
||||
os_file_close(file);
|
||||
}
|
||||
|
||||
#endif // defined(win32) || defined(osx)
|
|
@ -0,0 +1,106 @@
|
|||
#if !defined(LUMENARIUM_SHARED_FILE_TRACKER_H)
|
||||
#define LUMENARIUM_SHARED_FILE_TRACKER_H
|
||||
|
||||
#if !defined(OS_FILE_HANDLE_TYPE)
|
||||
# error "You must define an OS_FILE_HANDLE_TYPE"
|
||||
#endif
|
||||
|
||||
#if !defined(OS_FILE_MAX_PATH)
|
||||
# error "You must define an OS_FILE_MAX_PATH"
|
||||
#endif
|
||||
|
||||
#if !defined(OS_FILE_INVALID_HANDLE)
|
||||
# error "You must define an OS_FILE_INVALID_HANDLE"
|
||||
#endif
|
||||
|
||||
#define open_files_cap 32
|
||||
global u64 open_files_len = 1; // zero is invalid
|
||||
global char open_file_paths[open_files_cap][OS_FILE_MAX_PATH];
|
||||
global u64 open_file_paths_len[open_files_cap];
|
||||
global OS_FILE_HANDLE_TYPE open_files[open_files_cap];
|
||||
|
||||
void open_files_init();
|
||||
bool open_files_has_room();
|
||||
OS_FILE_HANDLE_TYPE open_files_get_handle(File_Handle handle);
|
||||
String open_files_get_path(File_Handle handle);
|
||||
File_Handle open_files_put_handle(OS_FILE_HANDLE_TYPE os_handle, String path);
|
||||
void open_files_rem_file(File_Handle handle);
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// IMPLEMENTATION
|
||||
|
||||
void
|
||||
open_files_init()
|
||||
{
|
||||
for (u32 i = 0; i < open_files_cap; i++)
|
||||
{
|
||||
open_files[i] = OS_FILE_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
bool open_files_has_room() { return open_files_len < open_files_cap; }
|
||||
|
||||
OS_FILE_HANDLE_TYPE
|
||||
open_files_get_handle(File_Handle handle)
|
||||
{
|
||||
assert(handle.value < open_files_len);
|
||||
return open_files[handle.value];
|
||||
}
|
||||
|
||||
String
|
||||
open_files_get_path(File_Handle handle)
|
||||
{
|
||||
assert(handle.value < open_files_len);
|
||||
String result = {
|
||||
.str = (u8*)open_file_paths[handle.value],
|
||||
.len = open_file_paths_len[handle.value],
|
||||
.cap = open_file_paths_len[handle.value],
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
File_Handle
|
||||
open_files_put_handle(OS_FILE_HANDLE_TYPE os_handle, String path)
|
||||
{
|
||||
assert(path.len < OS_FILE_MAX_PATH);
|
||||
|
||||
File_Handle result = {};
|
||||
if (os_handle != OS_FILE_INVALID_HANDLE)
|
||||
{
|
||||
if (open_files_has_room())
|
||||
{
|
||||
result.value = open_files_len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// search for emtpy index
|
||||
for (u32 i = 1; i < open_files_cap; i++)
|
||||
{
|
||||
if (open_files[i] == OS_FILE_INVALID_HANDLE)
|
||||
{
|
||||
result.value = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.value != 0)
|
||||
{
|
||||
open_files[result.value] = os_handle;
|
||||
memory_copy(path.str, (u8*)open_file_paths[result.value], path.len);
|
||||
open_file_paths[result.value][path.len] = 0; // null term
|
||||
open_file_paths_len[result.value] = path.len;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
open_files_rem_file(File_Handle handle)
|
||||
{
|
||||
assert(handle.value < open_files_len);
|
||||
open_files[handle.value] = OS_FILE_INVALID_HANDLE;;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // LUMENARIUM_SHARED_FILE_TRACKER_H
|
|
@ -268,7 +268,7 @@ WinMain(
|
|||
// Update window size
|
||||
if (has_flag(state->flags, AppState_RunEditor))
|
||||
{
|
||||
state->editor->window_dim = v2{
|
||||
state->editor->window_dim = (v2){
|
||||
(r32)win32_main_window.info.width,
|
||||
(r32)win32_main_window.info.height
|
||||
};
|
||||
|
|
|
@ -255,37 +255,4 @@ platform_pwd_set(String path)
|
|||
bool result = SetCurrentDirectory((char*)path.str);
|
||||
if (!result) win32_get_last_error();
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
platform_file_async_work_on_job(Platform_File_Async_Job* job)
|
||||
{
|
||||
Platform_File_Handle file = {};
|
||||
if (has_flag(job->args.flags, PlatformFileAsyncJob_Read))
|
||||
{
|
||||
file = platform_file_open(job->args.path, FileAccess_Read, FileCreate_OpenExisting);
|
||||
Data result = platform_file_read_all(file, platform_file_jobs_arena);
|
||||
if (result.base != 0)
|
||||
{
|
||||
job->args.data = result;
|
||||
add_flag(job->args.flags, PlatformFileAsyncJob_Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_flag(job->args.flags, PlatformFileAsyncJob_Failed);
|
||||
}
|
||||
}
|
||||
else if (has_flag(job->args.flags, PlatformFileAsyncJob_Write))
|
||||
{
|
||||
file = platform_file_open(job->args.path, FileAccess_Write, FileCreate_OpenAlways);
|
||||
if (platform_file_write_all(file, job->args.data))
|
||||
{
|
||||
add_flag(job->args.flags, PlatformFileAsyncJob_Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_flag(job->args.flags, PlatformFileAsyncJob_Failed);
|
||||
}
|
||||
}
|
||||
platform_file_close(file);
|
||||
}
|
Binary file not shown.
|
@ -22,21 +22,21 @@ incenter_init(App_State* state)
|
|||
scratch_get(scratch);
|
||||
Allocator* s = scratch.a;
|
||||
|
||||
v3 start_p = v3{0, 0, 0};
|
||||
v3 start_p = (v3){0, 0, 0};
|
||||
|
||||
Assembly_Strip* vertical_strip = assembly_add_strip(&state->assemblies, ah, 123);
|
||||
assembly_strip_create_leds(
|
||||
&state->assemblies,
|
||||
ah,
|
||||
vertical_strip,
|
||||
start_p,
|
||||
v3{0, INCENTER_FEET(-6.5f), 0},
|
||||
123
|
||||
);
|
||||
&state->assemblies,
|
||||
ah,
|
||||
vertical_strip,
|
||||
start_p,
|
||||
(v3){0, INCENTER_FEET(-6.5f), 0},
|
||||
123
|
||||
);
|
||||
|
||||
r32 radius = INCENTER_FEET(10);
|
||||
|
||||
Random_Series rand = random_series_create(hash_djb2_to_u32("slkdjfalksdjf"));
|
||||
Random_Series rand = random_series_create(hash_djb2_cstr_to_u32("slfalksdjf"));
|
||||
for (u32 i = 0; i < 40; i++)
|
||||
{
|
||||
Assembly_Strip* strip = assembly_add_strip(&state->assemblies, ah, 123);
|
||||
|
@ -53,7 +53,9 @@ incenter_init(App_State* state)
|
|||
assembly_strip_create_leds(&state->assemblies, ah, strip, start_p, end_p, 123);
|
||||
}
|
||||
|
||||
ed_sculpture_updated(state, 5, 0.025f);
|
||||
r32 rad = 0.05f;
|
||||
ed_sculpture_updated(state, 10, rad);
|
||||
scratch_release(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
|
|
Loading…
Reference in New Issue