lumenarium working on OSX

This commit is contained in:
Peter Slattery 2022-04-16 04:00:32 -07:00
parent 89e92467ae
commit 4ef76dacbe
73 changed files with 10483 additions and 987 deletions

4
build/build.sh Normal file → Executable file
View File

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

70
build/build_.sh Normal file → Executable file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,6 +3,7 @@
#ifndef LUMENARIUM_RANDOM_H
#define LUMENARIUM_RANDOM_H
typedef struct Random_Series Random_Series;
struct Random_Series
{
u32 last_value;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,7 @@
// TODO(PS) @DEPRECATE - new os layer
#define INPUT_FRAME_STRING_LENGTH 32
struct Input_Frame
{

View File

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

View File

@ -1,3 +1,5 @@
// TODO(PS) @DEPRECATE - new os layer
/* date = April 6th 2022 7:55 pm */
#ifndef LUMENARIUM_MEMORY_H

View File

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

View File

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

View File

@ -1,3 +1,5 @@
// TODO(PS) @DEPRECATE - new os layer
/* date = March 22nd 2022 2:08 am */
#ifndef LUMENARIUM_TYPES_H

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +0,0 @@
// I think this SO post might be helpful
// https://stackoverflow.com/questions/30575995/multi-platform-equivalent-to-queryperformancecounter

View File

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

View File

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

View File

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

View File

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

View File

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

BIN
src_v2/scratch/lumenarium Executable file

Binary file not shown.

View File

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