diff --git a/build/build.sh b/build/build.sh old mode 100644 new mode 100755 index d2ffa2d..bb270e8 --- a/build/build.sh +++ b/build/build.sh @@ -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 \ No newline at end of file +$SCRIPT_REL_DIR/build_.sh debug osx arm64 +# $SCRIPT_REL_DIR/build_.sh debug wasm intel \ No newline at end of file diff --git a/build/build_.sh b/build/build_.sh old mode 100644 new mode 100755 index 81df051..b42d9a6 --- a/build/build_.sh +++ b/build/build_.sh @@ -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 diff --git a/run_tree/osx/arm64/debug/lumenarium b/run_tree/osx/arm64/debug/lumenarium new file mode 100755 index 0000000..c44bd32 Binary files /dev/null and b/run_tree/osx/arm64/debug/lumenarium differ diff --git a/run_tree/osx/intel/debug/lumenarium b/run_tree/osx/intel/debug/lumenarium new file mode 100755 index 0000000..b6ea3bd Binary files /dev/null and b/run_tree/osx/intel/debug/lumenarium differ diff --git a/run_tree/text.txt b/run_tree/text.txt index ccfbc29..fc36187 100644 Binary files a/run_tree/text.txt and b/run_tree/text.txt differ diff --git a/src_v2/core/lumenarium_core.h b/src_v2/core/lumenarium_core.h new file mode 100644 index 0000000..38607a8 --- /dev/null +++ b/src_v2/core/lumenarium_core.h @@ -0,0 +1,44 @@ +// NOTE(PS): +// need to include before this: +// #include +// #include +// #include + +#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" \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_assert.h b/src_v2/core/lumenarium_core_assert.h new file mode 100644 index 0000000..ca7896d --- /dev/null +++ b/src_v2/core/lumenarium_core_assert.h @@ -0,0 +1,60 @@ +/* date = March 26th 2022 3:42 pm */ + +#ifndef LUMENARIUM_CORE_ASSERT_H +#define LUMENARIUM_CORE_ASSERT_H + +#if defined(PRINT_ASSERTS) +# include +# 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 diff --git a/src_v2/core/lumenarium_core_file.h b/src_v2/core/lumenarium_core_file.h new file mode 100644 index 0000000..6113182 --- /dev/null +++ b/src_v2/core/lumenarium_core_file.h @@ -0,0 +1,252 @@ +#if !defined(LUMENARIUM_CORE_FILE_H) +#define LUMENARIUM_CORE_FILE_H + +typedef struct File_Handle File_Handle; +struct File_Handle +{ + u64 value; +}; + +typedef u32 File_Access_Flags; +enum +{ + FileAccess_None = 0, + FileAccess_Read = 1, + FileAccess_Write = 2, +}; + +typedef u32 File_Create_Flags; +enum +{ + // these match https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea + FileCreate_None = 0, + + // Creates a new file, only if it does not already exist. + // If the file exists, an error is returned + FileCreate_New = 1, + + // Creates a new file, always. + // If the specified file exists and is writable, the file is overwritten + FileCreate_CreateAlways = 2, + + // Opens a file or device, only if it exists. + FileCreate_OpenExisting = 3, + + // Opens a file, always. + FileCreate_OpenAlways = 4, +}; + +typedef u32 File_Flags; +enum +{ + FileFlag_IsFile = 0, + FileFlag_IsDir = 1, +}; + +typedef struct File_Info File_Info; +struct File_Info +{ + String path; + String path_abs; + u64 size; + u64 time_created; + u64 time_last_write; + File_Flags flags; +}; + +typedef struct File_Info_List_Ele File_Info_List_Ele; +struct File_Info_List_Ele +{ + File_Info info; + File_Info_List_Ele* next; +}; + +typedef struct File_Info_List File_Info_List; +struct File_Info_List +{ + File_Info_List_Ele* first; + File_Info_List_Ele* last; +}; + +// For Cross Platform File Operations use these: + +typedef u32 File_Async_Job_Flags; +enum +{ + FileAsyncJob_Invalid = 0, + FileAsyncJob_Read = 1 << 0, + FileAsyncJob_Write = 1 << 1, + FileAsyncJob_InFlight = 1 << 2, + FileAsyncJob_Success = 1 << 3, + FileAsyncJob_Failed = 1 << 4, +}; + +typedef struct File_Async_Job_Args File_Async_Job_Args; +struct File_Async_Job_Args +{ + String path; + Data data; + File_Async_Job_Flags flags; + u32 error; +}; + +typedef void File_Async_Cb(File_Async_Job_Args args, u8* user_data); + +typedef struct File_Async_Job File_Async_Job; +struct File_Async_Job +{ + Data job_memory; + File_Async_Job_Args args; + File_Async_Cb* cb; +}; + +typedef void File_Async_Job_System_Do_Job(File_Async_Job* job); + +typedef struct File_Async_Job_System File_Async_Job_System; +struct File_Async_Job_System +{ + File_Async_Job_System_Do_Job* do_job; +}; + +global Allocator* file_jobs_arena = 0; +#define FILE_ASYNC_MAX_JOBS 32 +global File_Async_Job file_async_jobs[FILE_ASYNC_MAX_JOBS]; +global u32 file_async_jobs_len = 0; + +internal File_Async_Job_System file_async_jobs_init(File_Async_Job_System_Do_Job* do_job); +internal bool file_async_job_add(File_Async_Job job); +internal File_Async_Job file_async_job_rem(u64 index); +internal bool file_async_read(String path, File_Async_Cb* cb); +internal bool file_async_write(String path, Data data, File_Async_Cb* cb); +internal void file_async_job_complete(File_Async_Job* job, u8* user_data); +internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data); +internal void file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data); + +typedef u32 Platform_Enum_Dir_Flags; +enum +{ + EnumDir_Recursive = 1, + EnumDir_IncludeDirectories = 2, +}; + +/////////////////////////////////////// +/////////////////////////////////////// +// IMPLEMENTATION +/////////////////////////////////////// +/////////////////////////////////////// + +internal File_Async_Job_System +file_async_jobs_init(File_Async_Job_System_Do_Job* do_job) +{ + file_jobs_arena = paged_allocator_create_reserve(MB(4), 256); + File_Async_Job_System result = {}; + result.do_job = do_job; + return result; +} + +internal bool +file_async_job_add(File_Async_Job job) +{ + if (file_async_jobs_len >= FILE_ASYNC_MAX_JOBS) return false; + + // Copy data to job local memory + u64 size_needed = job.args.path.len + job.args.data.size + 1; + u8* job_mem = allocator_alloc(file_jobs_arena, size_needed); + String job_path = string_create(job_mem, 0, job.args.path.len + 1); + u64 copied = string_copy_to(&job_path, job.args.path); + Data job_data = data_create(job_mem + job_path.cap + 1, size_needed - (job_path.cap + 1)); + memory_copy(job.args.data.base, job_data.base, job.args.data.size); + job.args.path = job_path; + job.args.data = job_data; + job.job_memory = data_create(job_mem, size_needed); + + file_async_jobs[file_async_jobs_len++] = job; + return true; +} + +internal File_Async_Job +file_async_job_rem(u64 index) +{ + assert(index < file_async_jobs_len); + File_Async_Job result = file_async_jobs[index]; + + file_async_jobs_len -= 1; + if (file_async_jobs_len > 0) + { + u32 last_job = file_async_jobs_len; + file_async_jobs[index] = file_async_jobs[last_job]; + } + + return result; +} + +internal bool +file_async_read(String path, File_Async_Cb* cb) +{ + File_Async_Job job = {}; + job.args.path = path; + job.args.flags = ( + FileAsyncJob_Read | + FileAsyncJob_InFlight + ); + job.cb = cb; + bool result = file_async_job_add(job); + return result; +} + +internal bool +file_async_write(String path, Data data, File_Async_Cb* cb) +{ + File_Async_Job job = {}; + job.args.path = path; + job.args.data = data; + job.args.flags = ( + FileAsyncJob_Write | + FileAsyncJob_InFlight + ); + job.cb = cb; + bool result = file_async_job_add(job); + return result; +} + +internal void +file_async_job_complete(File_Async_Job* job, u8* user_data) +{ + job->cb(job->args, user_data); + allocator_free(file_jobs_arena, job->job_memory.base, job->job_memory.size); + if (has_flag(job->args.flags, FileAsyncJob_Write)) + { + allocator_free(file_jobs_arena, job->args.data.base, job->args.data.size); + } +} + +internal void +file_async_jobs_do_work(File_Async_Job_System* system, u64 max_jobs, u8* user_data) +{ + assert(system->do_job); + + u64 to_do = max_jobs; + if (max_jobs > file_async_jobs_len) to_do = file_async_jobs_len; + + File_Async_Job_Flags completed = ( + FileAsyncJob_Success | + FileAsyncJob_Failed + ); + + for (u64 i = to_do - 1; i < to_do; i--) + { + File_Async_Job* job = file_async_jobs + i; + system->do_job(job); + if (has_flag(job->args.flags, completed)) + { + if (has_flag_exact(job->args.flags, FileAsyncJob_Success)) + { + file_async_job_complete(job, user_data); + } + file_async_job_rem(i); + } + } +} + + +#endif // LUMENARIUM_CORE_FILE_H \ No newline at end of file diff --git a/src_v2/lumenarium_hash.cpp b/src_v2/core/lumenarium_core_hash.h similarity index 50% rename from src_v2/lumenarium_hash.cpp rename to src_v2/core/lumenarium_core_hash.h index d219110..dba3a11 100644 --- a/src_v2/lumenarium_hash.cpp +++ b/src_v2/core/lumenarium_core_hash.h @@ -1,14 +1,14 @@ /* date = April 1st 2022 7:29 pm */ -#ifndef LUMENARIUM_HASH_CPP -#define LUMENARIUM_HASH_CPP +#ifndef LUMENARIUM_CORE_HASH_H +#define LUMENARIUM_CORE_HASH_H // // DJB2 // Source: http://www.cse.yorku.ca/~oz/hash.html internal u32 -hash_djb2_to_u32(char* str, u64 len) +hash_djb2_str_to_u32(char* str, u64 len) { u32 result = 5381; for (u64 i = 0; i < len; i++) @@ -19,20 +19,20 @@ hash_djb2_to_u32(char* str, u64 len) } internal u32 -hash_djb2_to_u32(char* str) +hash_djb2_cstr_to_u32(char* str) { u64 len = c_str_len(str); - return hash_djb2_to_u32(str, len); + return hash_djb2_str_to_u32(str, len); } internal u32 -hash_djb2_to_u32(String str) +hash_djb2_string_to_u32(String str) { - return hash_djb2_to_u32((char*)str.str, str.len); + return hash_djb2_str_to_u32((char*)str.str, str.len); } internal u64 -hash_djb2_to_u64(char* str, u64 len) +hash_djb2_str_to_u64(char* str, u64 len) { u64 result = 5381; for (u64 i = 0; i < len; i++) @@ -43,16 +43,16 @@ hash_djb2_to_u64(char* str, u64 len) } internal u64 -hash_djb2_to_u64(char* str) +hash_djb2_cstr_to_u64(char* str) { u64 len = c_str_len(str); - return hash_djb2_to_u64(str, len); + return hash_djb2_str_to_u64(str, len); } internal u64 -hash_djb2_to_u64(String str) +hash_djb2_string_to_u64(String str) { - return hash_djb2_to_u64((char*)str.str, str.len); + return hash_djb2_str_to_u64((char*)str.str, str.len); } -#endif //LUMENARIUM_HASH_CPP +#endif //LUMENARIUM_HASH_H diff --git a/src_v2/core/lumenarium_core_memory.h b/src_v2/core/lumenarium_core_memory.h new file mode 100644 index 0000000..2f4e7ef --- /dev/null +++ b/src_v2/core/lumenarium_core_memory.h @@ -0,0 +1,802 @@ +#ifndef LUMENARIUM_CORE_MEMORY_H +#define LUMENARIUM_CORE_MEMORY_H + +#if !defined(OS_MEM_PAGE_SIZE) +# error "You must define OS_MEM_PAGE_SIZE for core_memory.h to compile properly" +#endif + +////////////////////////////////////////////// +// Memory Helpers + +#define Bytes(x) (x) +#define KB(x) ((x) << 10) +#define MB(x) ((x) << 20) +#define GB(x) (((u64)x) << 30) +#define TB(x) (((u64)x) << 40) + +#define memory_zero_array(b,t,c) memory_zero((u8*)(b), sizeof(t) * (c)) +internal void memory_zero(u8* base, u64 size); +internal void memory_copy(u8* from, u8* to, u64 size); + +////////////////////////////////////////////// +// Data + +#define get_byte(value, byte_index) ((value >> (8 * byte_index)) & 0xFF) + +typedef struct Data Data; +struct Data +{ + u8* base; + u64 size; +}; + +internal Data +data_create(u8* base, u64 size) +{ + Data result = {}; + result.base = base; + result.size = size; + return result; +} + +////////////////////////////////////////////// +// Data Writer + +typedef struct Data_Writer Data_Writer; +struct Data_Writer +{ + Data data; + u64 at; +}; + +// NOTE(PS): functions ending in _b treat data in the Data_Writer as big endian +// order (network ordering) where functions ending in _l treat data into little +// endian order +// It is always assumed that values not in the Data_Writer (ie the other args +// to the function or the functions return value) are in little endian order + +internal u8 dw_get_u8(Data_Writer* w); +// TODO(PS): get functions + +internal void dw_put_u8(Data_Writer* w, u8 b); +internal void dw_put_u16_b(Data_Writer* w, u16 b); +internal void dw_put_u16_l(Data_Writer* w, u16 b); +internal void dw_put_u32_b(Data_Writer* w, u32 b); +internal void dw_put_u32_l(Data_Writer* w, u32 b); +internal void dw_put_u64_b(Data_Writer* w, u64 b); +internal void dw_put_u64_l(Data_Writer* w, u64 b); + +////////////////////////////////////////////// +// Allocator + +typedef struct Allocator Allocator; + +typedef u8* Allocator_Alloc(Allocator* allocator, u64 size); +typedef void Allocator_Free(Allocator* allocator, u8* base, u64 size); +typedef u8* Allocator_Realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size); +typedef void Allocator_Clear(Allocator* allocator); +typedef void Allocator_Destroy(Allocator* allocator); + +struct Allocator +{ + Allocator_Alloc* alloc; + Allocator_Free* free; + Allocator_Realloc* realloc; + Allocator_Clear* clear; + Allocator_Destroy* destroy; + + Allocator* parent; + + u8* allocator_data; +}; + +#define allocator_alloc(a,s) (a)->alloc((a),(s)) +#define allocator_alloc_struct(a,t) (t*)(a)->alloc((a),sizeof(t)) +#define allocator_alloc_array(a,t,c) (t*)(a)->alloc((a),sizeof(t)*(c)) + +#define allocator_free(a,b,s) (a)->free((a),(b),(s)) +#define allocator_free_struct(a,b,t) (a)->free((a),(b),sizeof(t)) +#define allocator_free_array(a,b,t,c) (a)->free((a),(b),sizeof(t)*(c)) + +#define allocator_realloc(a,b,os,ns) (a)->realloc((a),(b),(os),(ns)) +#define allocator_realloc_array(a,b,t,oc,nc) (t*)(a)->realloc((a),(b),sizeof(t)*(oc),sizeof(t)*(nc)) + +#define allocator_clear(a) (a)->clear(a) +#define allocator_destroy(a) (a)->destroy(a) + +internal Allocator* paged_allocator_create_reserve(u64 reserve_size, u64 page_size); + +////////////////////////////////////////////// +////////////////////////////////////////////// +// IMPLEMENTATION +////////////////////////////////////////////// +////////////////////////////////////////////// + +///////////////////////////////////////// +// Memory Functions + +void +memory_zero_no_simd(u8* base, u64 size) +{ + for (u64 i = 0; i < size; i++) base[i] = 0; +} + +void +memory_copy_no_simd(u8* from, u8* to, u64 size) +{ + for (u64 i = 0; i < size; i++) to[i] = from[i]; +} + +#if defined(PLATFORM_HAS_SIMD) + +// TODO(PS): +// TODO(PS): +// TODO(PS): + +void +memory_zero_simd(u8* base, u64 size) +{ + memory_zero_no_simd(base, size); +} + +void +memory_copy_simd(u8* from, u8* to, u64 size) +{ + memory_copy_no_simd(from, to, size); +} + +# define memory_zero_(b,s) memory_zero_simd((b),(s)) +# define memory_copy_(f,t,s) memory_copy_simd((f),(t),(s)) + +#else +# define memory_zero_(b,s) memory_zero_no_simd((b),(s)) +# define memory_copy_(f,t,s) memory_copy_no_simd((f),(t),(s)) + +#endif // defined(PLATFORM_HAS_SIMD) + +#define zero_struct(s) memory_zero((u8*)(&s), sizeof(s)) + +internal void memory_zero(u8* base, u64 size) { memory_zero_(base, size); } +internal void memory_copy(u8* from, u8* to, u64 size) { + memory_copy_(from, to, size); +} + +// @Maintenance - if the function only has one argument, it should become +// round_to_os_page_multiple +u64 +round_size_to_page_multiple(u64 size, u64 page_size) +{ + u64 rem = size % page_size; + if (rem != 0 || size < page_size) + { + u64 grow = page_size - rem; + size += grow; + } + return size; +} + +u64 +round_size_to_os_page_multiple(u64 size) +{ + return round_size_to_page_multiple(size, OS_MEM_PAGE_SIZE); +} + +///////////////////////////////////////// +// Data Writer + +internal void +dw_put_u8(Data_Writer* w, u8 b) +{ + if (w->at < w->data.size) + { + w->data.base[w->at++] = b; + } +} + +internal u8 +dw_get_u8(Data_Writer* w) +{ + u8 result = 0; + if (w->at < w->data.size) + { + result = w->data.base[w->at++]; + } + return result; +} + +internal void +dw_put_u16_b(Data_Writer* w, u16 b) +{ + dw_put_u8(w, get_byte(b, 1)); + dw_put_u8(w, get_byte(b, 0)); +} + +internal void +dw_put_u16_l(Data_Writer* w, u16 b) +{ + dw_put_u8(w, get_byte(b, 0)); + dw_put_u8(w, get_byte(b, 1)); +} + +internal void +dw_put_u32_b(Data_Writer* w, u32 b) +{ + dw_put_u8(w, get_byte(b, 3)); + dw_put_u8(w, get_byte(b, 2)); + dw_put_u8(w, get_byte(b, 1)); + dw_put_u8(w, get_byte(b, 0)); +} + +internal void +dw_put_u32_l(Data_Writer* w, u32 b) +{ + dw_put_u8(w, get_byte(b, 0)); + dw_put_u8(w, get_byte(b, 1)); + dw_put_u8(w, get_byte(b, 2)); + dw_put_u8(w, get_byte(b, 3)); +} + +internal void +dw_put_u64_b(Data_Writer* w, u64 b) +{ + dw_put_u8(w, get_byte(b, 7)); + dw_put_u8(w, get_byte(b, 6)); + dw_put_u8(w, get_byte(b, 5)); + dw_put_u8(w, get_byte(b, 4)); + dw_put_u8(w, get_byte(b, 3)); + dw_put_u8(w, get_byte(b, 2)); + dw_put_u8(w, get_byte(b, 1)); + dw_put_u8(w, get_byte(b, 0)); +} + +internal void +dw_put_u64_l(Data_Writer* w, u64 b) +{ + dw_put_u8(w, get_byte(b, 0)); + dw_put_u8(w, get_byte(b, 1)); + dw_put_u8(w, get_byte(b, 2)); + dw_put_u8(w, get_byte(b, 3)); + dw_put_u8(w, get_byte(b, 4)); + dw_put_u8(w, get_byte(b, 5)); + dw_put_u8(w, get_byte(b, 6)); + dw_put_u8(w, get_byte(b, 7)); +} + +//////////////////////////////////////// +// Allocator +// +// A generic interface for any memory-providing construct +// +// To implement a complete allocator, all that is really required +// is to create its Allocator_Alloc function + +internal void +allocator_destroy_(Allocator* allocator, u64 custom_data_size) +{ + zero_struct(*allocator); + u64 size = sizeof(Allocator) + custom_data_size; + os_mem_decommit((u8*)allocator, size); + os_mem_release((u8*)allocator, size); +} + +///////////////////////////////////////// +// Bump Allocator + +typedef struct Allocator_Bump Allocator_Bump; +struct Allocator_Bump +{ + u8* base; + u64 at; + u64 size_committed; + u64 size_reserved; + u64 page_size; + u64 high_water_mark; +}; + +#if defined(DEBUG) +# define bump_allocator_validate(a) bump_allocator_validate_(a) +#else +# define bump_allocator_validate(a) +#endif +internal void +bump_allocator_validate_(Allocator* allocator) +{ + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + assert(bump != 0); + if (bump->size_reserved > 0) + { + assert(bump->base != 0); + } + assert(bump->at <= bump->size_committed); + assert(bump->size_committed <= bump->size_reserved); + assert(bump->page_size > 0); + assert(bump->high_water_mark <= bump->size_reserved); +} + +internal u8* +bump_allocator_alloc_inner(Allocator* allocator, Allocator_Bump* bump, u64 size) +{ + bump_allocator_validate(allocator); + u64 at_after = bump->at + size; + // TODO(PS): align up to 8 bytes + + if (at_after >= bump->size_committed) + { + // determine new size of the arena + u64 new_size = bump->size_committed * 2; + if (new_size == 0) + { + if (bump->page_size == 0) bump->page_size = OS_MEM_PAGE_SIZE; + new_size = bump->page_size; + } + if (new_size < at_after) + { + new_size = round_size_to_page_multiple(at_after, bump->page_size); + } + + if (allocator->parent) + { + bump->base = allocator_realloc( + allocator->parent, + bump->base, + bump->size_committed, + new_size + ); + if (bump->base != 0) + { + bump->size_reserved = new_size; + bump->size_committed = new_size; + } + } + else + { + if (new_size <= bump->size_reserved) + { + u64 next_page = round_size_to_os_page_multiple(bump->at); + if (bump->at == 0 && bump->size_committed == 0) next_page = 0; + u64 commit_amt = new_size - next_page; + u8* new_page = os_mem_commit(bump->base + next_page, commit_amt); + if (new_page != 0) + { + bump->size_committed = new_size; + } + } + else + { + invalid_code_path; // out of reserved memory + } + } + } + + u8* result = bump->base + bump->at; + bump->at = at_after; + bump->high_water_mark = max(bump->at, bump->high_water_mark); + + bump_allocator_validate(allocator); + return result; +} + +internal u8* +bump_allocator_alloc(Allocator* allocator, u64 size) +{ + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + u8* result = bump_allocator_alloc_inner(allocator, bump, size); + return result; +} + +internal u8* +bump_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size) +{ + u8* result = bump_allocator_alloc(allocator, new_size); + memory_copy(base, result, old_size); + return result; +} + +internal void +bump_allocator_clear(Allocator* allocator) +{ + if (!allocator->allocator_data) return; + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + bump->at = 0; + bump_allocator_validate(allocator); +} + +internal void +bump_allocator_destroy_(Allocator_Bump* bump) +{ + os_mem_decommit(bump->base, bump->size_committed); + os_mem_release(bump->base, bump->size_reserved); +} + +internal void +bump_allocator_destroy(Allocator* allocator) +{ + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + bump_allocator_destroy_(bump); + allocator_destroy_(allocator, sizeof(Allocator_Bump)); +} + +internal void +bump_allocator_rewind(Allocator* allocator, u64 to_point) +{ + Allocator_Bump* bump = (Allocator_Bump*)allocator->allocator_data; + bump_allocator_validate(allocator); +#if defined(DEBUG) + memory_zero(bump->base + to_point, bump->at - to_point); +#endif + bump->at = to_point; + bump_allocator_validate(allocator); +} + +internal Allocator* +bump_allocator_create_(u64 page_size) +{ + u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump); + + u8* base = os_mem_reserve(size_needed); + base = os_mem_commit(base, size_needed); + + Allocator* result = (Allocator*)base; + zero_struct(*result); + + Allocator_Bump* bump = (Allocator_Bump*)base + sizeof(Allocator); + zero_struct(*bump); + bump->page_size = page_size; + + result->alloc = bump_allocator_alloc; + result->realloc = bump_allocator_realloc; + result->clear = bump_allocator_clear; + result->destroy = bump_allocator_destroy; + result->allocator_data = (u8*)bump; + + bump_allocator_validate(result); + return result; +} + +internal Allocator* +bump_allocator_create_reserve(u64 reserve_size) +{ + Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE); + Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data; + + u64 reserve_pages = round_size_to_os_page_multiple(reserve_size); + bump->base = os_mem_reserve(reserve_pages); + if (bump->base != 0) bump->size_reserved = reserve_pages; + + bump_allocator_validate(result); + return result; +} + +internal Allocator* +bump_allocator_create_child(Allocator* parent, u64 init_size) +{ + Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE); + result->parent = parent; + + Allocator_Bump* bump = (Allocator_Bump*)result->allocator_data; + zero_struct(*bump); + bump->base = allocator_alloc(result->parent, init_size); + if (bump->base != 0) + { + bump->size_reserved = init_size; + bump->size_committed = init_size; + } + + bump_allocator_validate(result); + return result; +} + + +///////////////////////////////////////// +// Scratch Allocator + +typedef struct Allocator_Scratch Allocator_Scratch; +struct Allocator_Scratch +{ + Allocator* a; + u64 at_before; +}; + +internal Allocator_Scratch +allocator_scratch_begin(Allocator* allocator) +{ + Allocator_Scratch result = {}; + result.a = allocator; + Allocator_Bump* bump = (Allocator_Bump*)result.a->allocator_data; + result.at_before = bump->at; + return result; +} + +internal void +allocator_scratch_end(Allocator_Scratch* scratch) +{ + bump_allocator_rewind(scratch->a, scratch->at_before); + zero_struct(*scratch); +} + +///////////////////////////////////////// +// Paged Allocator + +typedef struct Allocator_Paged_Free_Region Allocator_Paged_Free_Region; +struct Allocator_Paged_Free_Region +{ + u64 pages; + Allocator_Paged_Free_Region* prev; + Allocator_Paged_Free_Region* next; +}; + +typedef struct Allocator_Paged Allocator_Paged; +struct Allocator_Paged +{ + Allocator_Bump bump; + Allocator_Paged_Free_Region* free_first; +}; + +internal u8* +paged_allocator_alloc(Allocator* allocator, u64 size) +{ + // 1. Find the number of pages we need + // 2. Find a run of free pages that we can use + // If found, + // remove those pages from the run they are in + // return those pages of memory + // 3. Commit pages on the end + + Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data; + if (paged->bump.page_size == 0) paged->bump.page_size = OS_MEM_PAGE_SIZE; + + u64 rounded_size = round_size_to_page_multiple(size, paged->bump.page_size); + u64 pages_needed = rounded_size / paged->bump.page_size; + + u8* result = 0; + + // Find free pages + if (paged->free_first) + { + Allocator_Paged_Free_Region* found = 0; + for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next) + { + // NOTE(PS): this set of conditions checks to see if is bigger than what + // we need. If it is, we also check to see if this is smaller than any + // region we've found before. And we abort the search if this region + // perfectly fits the size needed. + // + // This should make sure that we are always choosing the closest fit we + // can. I'm not sure this is the best strategy for dealing with fragmentation + // but its a decent first pass + if (at->pages >= pages_needed) + { + if (!found || (found->pages > at->pages)) + { + found = at; + if (found->pages == pages_needed) break; + } + } + } + + if (found) + { + result = (u8*)found; + if (found->pages > pages_needed) + { + Allocator_Paged_Free_Region* region_after = (Allocator_Paged_Free_Region*)(result + rounded_size); + if (found->prev != 0) found->prev->next = region_after; + region_after = found->next; + } + else + { + if (found->prev != 0) found->prev->next = found->next; + } + } + } + + if (!result) + { + result = bump_allocator_alloc_inner(allocator, &paged->bump, size); + } + + return result; +} + +#define region_end(r,page_size) ((u8*)(r) + ((r)->pages * page_size)) + +internal void +paged_region_insert( + Allocator_Paged_Free_Region* before, + Allocator_Paged_Free_Region* new_region, + Allocator_Paged_Free_Region* after, + u64 page_size + ){ + assert(after == 0 || before < after); + assert(before < new_region); + assert(after == 0 || new_region < after); + assert(new_region->prev == 0 && new_region->next == 0); + + u8* before_end = region_end(before, page_size); + u8* new_region_end = region_end(new_region, page_size); + + // Before + if (before_end == (u8*)new_region) + { + // merge the regions + before->pages += new_region->pages; + new_region = before; + assert(new_region_end == region_end(new_region, page_size)); + } + else + { + assert(before_end < (u8*)new_region); + before->next = new_region; + new_region->prev = before; + } + + // After + if (after != 0) + { + if (new_region_end == (u8*)after) + { + // merge the regions + new_region->pages += after->pages; + u8* a = region_end(after, page_size); + u8* b = region_end(new_region, page_size); + assert(a == b); + } + else + { + assert(new_region_end < (u8*)after); + new_region->next = after; + after->prev = new_region; + } + } +} + +internal void +paged_allocator_free(Allocator* allocator, u8* base, u64 size) +{ + // Figure out which page base is the base of, assert its the base + // figure out how many pages size represents. + // create a free range + // stick it in between contiguous free ranges + // if the ranges before or after meet this new one, merge them all + + Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data; + + u64 page_base_rel = (base - paged->bump.base); + assert((page_base_rel % paged->bump.page_size) == 0); + u64 page_index = page_base_rel / paged->bump.page_size; + u64 size_pages_mult = round_size_to_page_multiple(size, paged->bump.page_size); + assert((size_pages_mult % paged->bump.page_size) == 0); + u64 page_count = size_pages_mult / paged->bump.page_size; + + Allocator_Paged_Free_Region* region = (Allocator_Paged_Free_Region*)base; + zero_struct(*region); + region->pages = page_count; + + Allocator_Paged_Free_Region* prev = 0; + Allocator_Paged_Free_Region* next = 0; + for (Allocator_Paged_Free_Region* at = paged->free_first; at != 0; at = at->next) + { + if (at < region) + { + prev = at; + next = at->next; + if (next != 0) + { + assert(next > region); + assert((u8*)next >= ((u8*)region + size_pages_mult)); + } + } + } + + if (prev && next) + { + // found a region to insert into + paged_region_insert(prev, region, next, paged->bump.page_size); + } + else if (prev) + { + // got to the end and all were before the free region in memory + paged_region_insert(prev, region, 0, paged->bump.page_size); + } + else + { + // free list is empty + paged->free_first = region; + } +} + +internal u8* +paged_allocator_realloc(Allocator* allocator, u8* base, u64 old_size, u64 new_size) +{ + // TODO(PS): + // Process: + // 1. Figure out which page base starts on + // 2. Find if there is a free region after base that is big enough to house + // the new size + // 3. If there is a free region, pull the needed memory out of it + // 4. Otherwise, alloc new_size, copy base into it, and free base + + // TODO(PS): you could do a simple version where you just always alloc, copy, free + return 0; +} + +internal void +paged_allocator_clear(Allocator* allocator) +{ + if (!allocator->allocator_data) return; + Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data; + paged->bump.at = 0; + paged->free_first = 0; +} + +internal void +paged_allocator_destroy(Allocator* allocator) +{ + Allocator_Paged* paged = (Allocator_Paged*)allocator->allocator_data; + bump_allocator_destroy_(&paged->bump); + allocator_destroy_(allocator, sizeof(Allocator_Paged)); +} + +internal Allocator* +paged_allocator_create_() +{ + u64 size_needed = sizeof(Allocator) + sizeof(Allocator_Bump); + + u8* base = os_mem_reserve(size_needed); + base = os_mem_commit(base, size_needed); + + Allocator* result = (Allocator*)base; + zero_struct(*result); + + Allocator_Paged* paged = (Allocator_Paged*)base + sizeof(Allocator); + zero_struct(*paged); + + result->alloc = paged_allocator_alloc; + result->free = paged_allocator_free; + result->realloc = paged_allocator_realloc; + result->clear = paged_allocator_clear; + result->destroy = paged_allocator_destroy; + result->allocator_data = (u8*)paged; + + return result; +} + +internal Allocator* +paged_allocator_create_reserve(u64 reserve_size, u64 page_size) +{ + Allocator* result = paged_allocator_create_(); + Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data; + + u64 reserve_pages = round_size_to_os_page_multiple(reserve_size); + paged->bump.page_size = page_size; + paged->bump.base = os_mem_reserve(reserve_pages); + if (paged->bump.base != 0) paged->bump.size_reserved = reserve_pages; + + return result; +} + +internal Allocator* +paged_allocator_create_reserve_os_page_size(u64 reserve_size) +{ + u64 page_size = OS_MEM_PAGE_SIZE; + return paged_allocator_create_reserve(reserve_size, page_size); +} + +internal Allocator* +paged_allocator_create_child(Allocator* parent, u64 init_size) +{ + Allocator* result = bump_allocator_create_(OS_MEM_PAGE_SIZE); + result->parent = parent; + + Allocator_Paged* paged = (Allocator_Paged*)result->allocator_data; + paged->bump.base = allocator_alloc(result->parent, init_size); + if (paged->bump.base != 0) + { + paged->bump.size_reserved = init_size; + paged->bump.size_committed = init_size; + } + + return result; +} + +#endif \ No newline at end of file diff --git a/src_v2/lumenarium_random.h b/src_v2/core/lumenarium_core_random.h similarity index 94% rename from src_v2/lumenarium_random.h rename to src_v2/core/lumenarium_core_random.h index 625a842..cffb7bd 100644 --- a/src_v2/lumenarium_random.h +++ b/src_v2/core/lumenarium_core_random.h @@ -3,6 +3,7 @@ #ifndef LUMENARIUM_RANDOM_H #define LUMENARIUM_RANDOM_H +typedef struct Random_Series Random_Series; struct Random_Series { u32 last_value; diff --git a/src_v2/core/lumenarium_core_socket.h b/src_v2/core/lumenarium_core_socket.h new file mode 100644 index 0000000..c59b228 --- /dev/null +++ b/src_v2/core/lumenarium_core_socket.h @@ -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 \ No newline at end of file diff --git a/src_v2/lumenarium_string.cpp b/src_v2/core/lumenarium_core_string.h similarity index 87% rename from src_v2/lumenarium_string.cpp rename to src_v2/core/lumenarium_core_string.h index 6c6ed7e..92a81ef 100644 --- a/src_v2/lumenarium_string.cpp +++ b/src_v2/core/lumenarium_core_string.h @@ -1,3 +1,24 @@ +////////////////////////////////////////////// +// String + +// NOTE(PS): even though this has a len and cap, it should always be +// null terminated +typedef struct String String; +struct String +{ + u8* str; + u64 len; + u64 cap; +}; + +internal String string_create(u8* str, u64 len, u64 cap); +internal u64 string_copy_to(String* dest, String src); + +////////////////////////////////////////////// +////////////////////////////////////////////// +// IMPLEMENTATION +////////////////////////////////////////////// +////////////////////////////////////////////// internal u64 c_str_len(char* s) @@ -9,7 +30,7 @@ c_str_len(char* s) #define str_varg(s) (int)(s).len, (char*)(s).str #define str_expand(s) (char*)(s).str, (u64)(s).len -#define lit_str(s) String{ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 } +#define lit_str(s) (String){ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 } internal String allocator_alloc_string(Allocator* a, u64 cap) @@ -266,4 +287,13 @@ string_f(Allocator* a, char* fmt, ...) String result = string_fv(a, fmt, args); va_end(args); return result; +} + +internal void +dw_put_str(Data_Writer* w, String str) +{ + for (u64 i = 0; i < str.len; i++) + { + dw_put_u8(w, str.str[i]); + } } \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_threads.h b/src_v2/core/lumenarium_core_threads.h new file mode 100644 index 0000000..203ded3 --- /dev/null +++ b/src_v2/core/lumenarium_core_threads.h @@ -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 \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_time.h b/src_v2/core/lumenarium_core_time.h new file mode 100644 index 0000000..5a47360 --- /dev/null +++ b/src_v2/core/lumenarium_core_time.h @@ -0,0 +1,39 @@ +#if !defined(LUMENARIUM_CORE_TIME_H) +#define LUMENARIUM_CORE_TIME_H + +typedef struct { s64 value; } Ticks; + +internal Ticks get_ticks_elapsed(Ticks start, Ticks end); +internal r64 ticks_to_seconds(Ticks t, r64 ticks_per_second); +internal r64 get_seconds_elapsed(Ticks start, Ticks end, r64 ticks_per_second); + +/////////////////////////////////////// +/////////////////////////////////////// +// Implementation +/////////////////////////////////////// +/////////////////////////////////////// + +internal Ticks +get_ticks_elapsed(Ticks start, Ticks end) +{ + Ticks result = {}; + result.value = end.value - start.value; + return result; +} + +internal r64 +ticks_to_seconds(Ticks t, r64 ticks_per_second) +{ + r64 result = t.value / ticks_per_second; + return result; +} + +internal r64 +get_seconds_elapsed(Ticks start, Ticks end, r64 ticks_per_second) +{ + Ticks diff = get_ticks_elapsed(start, end); + return ticks_to_seconds(diff, ticks_per_second); +} + + +#endif // LUMENARIUM_CORE_TIME_H \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_types.h b/src_v2/core/lumenarium_core_types.h new file mode 100644 index 0000000..46bb7b1 --- /dev/null +++ b/src_v2/core/lumenarium_core_types.h @@ -0,0 +1,215 @@ +#ifndef LUMENARIUM_CORE_TYPES_H +#define LUMENARIUM_CORE_TYPES_H + +////////////////////////////////////////////// +// Explicit Names for static keyword +#define internal static +#define local_persist static +#define global static +#define local_const static const +#define global_const static const +#define external extern "C" + +#define STMT(x) do {(x);}while(false) + +////////////////////////////////////////////// +// Integer Sizing +#if defined(GUESS_INTS) + +typedef signed char s8; +typedef signed short s16; +typedef signed int s32; +typedef signed long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; + +#else // !defined(GUESS_INTS) + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +#endif // defined(GUESS_INTS) + +////////////////////////////////////////////// +// Basic Types + +typedef s8 b8; +typedef s32 b32; +typedef s64 b64; + +typedef float r32; +typedef double r64; + +////////////////////////////////////////////// +// Basic Type Constants + +#define u8_max 0xFF +#define u16_max 0xFFFF +#define u32_max 0xFFFFFFFF +#define u64_max 0xFFFFFFFFFFFFFFFF + +#define s8_max 127 +#define s16_max 32767 +#define s32_max 2147483647 +#define s64_max 9223372036854775807 + +#define s8_min -127 - 1 +#define s16_min -32767 - 1 +#define s32_min -2147483647 - 1 +#define s64_min -9223372036854775807 - 1 + +#define r32_max 3.402823466e+38f +#define r32_min -3.402823466e+38f +#define r32_smallest_positive 1.1754943508e-38f +#define r32_epsilon 5.96046448e-8f +#define r32_pi 3.14159265359f +#define r32_half_pi 1.5707963267f +#define r32_tau 6.28318530717f + +#define r64_max 1.79769313486231e+308 +#define r64_min -1.79769313486231e+308 +#define r64_smallest_positive 4.94065645841247e-324 +#define r64_epsilon 1.11022302462515650e-16 +#define r64_pi 3.14159265359 +#define r64_half_pi 1.5707963267 +#define r64_tau 6.28318530717 + +#define NanosToSeconds 1 / 10000000.0 +#define SecondsToNanos 10000000.0 + +////////////////////////////////////////////// +// Math + +#ifndef max +# define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef min +# define min(a,b) ((a) > (b) ? (b) : (a)) +#endif + +#define lerp(a,t,b) (a) + ((1.0f - (t)) * (b)) +#define clamp(r0,v,r1) min((r1),max((r0),(v))) +#define lerp_clamp(a,t,b) clamp((a),lerp((a),(t),(b)),(b)) + +internal u32 +round_up_to_pow2_u32(u32 v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +////////////////////////////////////////////// +// Flags + +#define has_flag(data, flag) (((data) & (flag)) != 0) +#define has_flag_exact(data, flag) (((data) & (flag)) == (flag)) +#define add_flag(data, flag) STMT((data) |= (flag)) +#define rem_flag(data, flag) STMT((data) &= (~(flag))) + +////////////////////////////////////////////// +// List Helper Macros + +#define sll_push(first,last,ele) \ +if (!(first)) { (first) = (ele); }\ +else { (last)->next = (ele); } \ +(last) = (ele); (ele)->next = 0; + +// TODO(PS): Stack, Queue, DLL ops + +////////////////////////////////////////////// +// Hash Table +// +// Rather than define a data structure, to allow the most flexibility, +// this is just a set of functions that can be integrated into other +// routines. +// In general, they expect you to track a u32* of ids and a u32 capacity + +internal void +hash_table_init(u32* ids, u32 cap) +{ + for (u32 i = 0; i < cap; i++) ids[i] = 0; +} + +internal u32 +hash_table_find_(u32* ids, u32 cap, u32 start_id, u32 target_value) +{ + u32 index = start_id % cap; + u32 start = index; + do { + if (ids[index] == target_value) break; + index = (index + 1) % cap; + } while (index != start); + return index; +} + +internal u32 +hash_table_register(u32* ids, u32 cap, u32 new_id) +{ + u32 index = hash_table_find_(ids, cap, new_id, 0); + if (ids[index] != 0) return cap; + ids[index] = new_id; + return index; +} + +internal u32 +hash_table_find(u32* ids, u32 cap, u32 value) +{ + u32 result = hash_table_find_(ids, cap, value, value); + if (ids[result] != value) return cap; + return result; +} + +////////////////////////////////////////////// +// Predeclaring Memory Functions + +u64 round_size_to_page_multiple(u64 size, u64 page_size); +u64 round_size_to_os_page_multiple(u64 size); + +////////////////////////////////////////////// +// Vector Extensions + +#if defined(HANDMADE_MATH_IMPLEMENTATION) + +#define v2_to_v3(xy,z) (v3){(xy).x, (xy).y, (z)} +#define v2_floor(v) (v2){ floorf(v.x), floorf(v.y) } +#define v3_floor(v) (v3){ floorf(v.x), floorf(v.y), floorf(v.z) } + +internal bool +rect2_contains(v2 min, v2 max, v2 point) +{ + return ( + min.x <= point.x && min.y <= point.y && + max.x >= point.x && max.y >= point.y + ); +} + +#endif // defined(HANDMADE_MATH_IMPLEMENTATION) + +////////////////////////////////////////////// +// Color Constants + +#define WHITE_V4 (v4){1,1,1,1} +#define BLACK_V4 (v4){0,0,0,1} +#define RED_V4 (v4){1,0,0,1} +#define GREEN_V4 (v4){0,1,0,1} +#define BLUE_V4 (v4){0,0,1,1} +#define YELLOW_V4 (v4){1,1,0,1} +#define TEAL_V4 (v4){0,1,1,1} +#define PINK_V4 (v4){1,0,1,1} + +#endif \ No newline at end of file diff --git a/src_v2/core/lumenarium_core_window.h b/src_v2/core/lumenarium_core_window.h new file mode 100644 index 0000000..704366f --- /dev/null +++ b/src_v2/core/lumenarium_core_window.h @@ -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 \ No newline at end of file diff --git a/src_v2/editor/graphics/lumenarium_editor_graphics.h b/src_v2/editor/graphics/lumenarium_editor_graphics.h new file mode 100644 index 0000000..9e50c91 --- /dev/null +++ b/src_v2/editor/graphics/lumenarium_editor_graphics.h @@ -0,0 +1,419 @@ +#if !defined(LUMENARIUM_EDITOR_GRAPHICS_H) +#define LUMENARIUM_EDITOR_GRAPHICS_H + +#define os_gl_no_error() os_gl_no_error_((char*)__FILE__, (u32)__LINE__) +void os_gl_no_error_(char* file, u32 line); + +#define GL_NULL (u32)0 + +#define SHADER_MAX_ATTRS 8 +#define SHADER_ATTR_LAST (u32)(1 << 31) +typedef struct Shader Shader; +struct Shader +{ + u32 id; + u32 attrs[SHADER_MAX_ATTRS]; + u32 uniforms[SHADER_MAX_ATTRS]; +}; + +typedef struct XPlatform_Shader_Program_Src XPlatform_Shader_Program_Src; +struct XPlatform_Shader_Program_Src +{ + String win32_vert; + String win32_frag; + + String osx_vert; + String osx_frag; + + String wasm_vert; + String wasm_frag; +}; + +String xplatform_shader_program_get_vert(XPlatform_Shader_Program_Src src); +String xplatform_shader_program_get_frag(XPlatform_Shader_Program_Src src); + +typedef struct Geometry_Buffer Geometry_Buffer; +struct Geometry_Buffer +{ + u32 buffer_id_vao; + u32 buffer_id_vertices; + u32 buffer_id_indices; + u32 vertices_len; + u32 indices_len; +}; + +typedef struct Texture Texture; +struct Texture +{ + u32 id; + + u32 w, h, s; +}; + +typedef struct Graphics_Frame_Desc Graphics_Frame_Desc; +struct Graphics_Frame_Desc +{ + v4 clear_color; + v2 viewport_min; + v2 viewport_max; +}; + +void frame_begin(Graphics_Frame_Desc desc); +void frame_clear(); + +// Geometry +Geometry_Buffer geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len); +Shader shader_create(String code_vert, String code_frag, String* attribs, u32 attribs_len, String* uniforms, u32 uniforms_len); +void geometry_buffer_update(Geometry_Buffer* buffer, r32* verts, u32 verts_offset, u32 verts_len, u32* indices, u32 indices_offset, u32 indices_len); + +// Shaders +void geometry_bind(Geometry_Buffer geo); +void shader_bind(Shader shader); +void geometry_drawi(Geometry_Buffer geo, u32 indices); +void geometry_draw(Geometry_Buffer geo); +void vertex_attrib_pointer(Geometry_Buffer geo, Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset); +void set_uniform(Shader shader, u32 index, m44 u); + +// Textures +Texture texture_create(u8* pixels, u32 width, u32 height, u32 stride); +void texture_bind(Texture tex); +void texture_update(Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride); + +////////////////////////////////////////// +////////////////////////////////////////// +// IMPLEMENTATION +////////////////////////////////////////// +////////////////////////////////////////// + +Geometry_Buffer +geometry_buffer_create( + r32* vertices, u32 vertices_len, + u32* indices, u32 indices_len +){ + Geometry_Buffer result = {}; + + gl.glGenVertexArrays(1, &result.buffer_id_vao); + os_gl_no_error(); + + GLuint buffers[2]; + gl.glGenBuffers(2, (GLuint*)buffers); + os_gl_no_error(); + + result.buffer_id_vertices = buffers[0]; + result.buffer_id_indices = buffers[1]; + + // Vertices + gl.glBindVertexArray(result.buffer_id_vao); + gl.glBindBuffer(GL_ARRAY_BUFFER, result.buffer_id_vertices); + os_gl_no_error(); + + gl.glBufferData(GL_ARRAY_BUFFER, sizeof(r32) * vertices_len, vertices, GL_STATIC_DRAW); + os_gl_no_error(); + result.vertices_len = vertices_len; + + // Indices + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffer_id_indices); + os_gl_no_error(); + + gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(u32) * indices_len, indices, GL_STATIC_DRAW); + os_gl_no_error(); + result.indices_len = indices_len; + + gl.glBindBuffer(GL_ARRAY_BUFFER, GL_NULL); + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_NULL); + + return result; +} + +void +geometry_buffer_update( + Geometry_Buffer* buffer, + r32* verts, + u32 verts_offset, + u32 verts_len, + u32* indices, + u32 indices_offset, + u32 indices_len +){ + gl.glBindVertexArray(buffer->buffer_id_vao); + gl.glBindBuffer(GL_ARRAY_BUFFER, buffer->buffer_id_vertices); + os_gl_no_error(); + + if (verts_len > buffer->vertices_len) + { + // NOTE(PS): this is because we're going to delete the old buffer and + // create a new one. In order to do that and not lose data, the update + // function needs to have been passed all the buffer's data + assert(verts_offset == 0); + gl.glBufferData(GL_ARRAY_BUFFER, verts_len * sizeof(r32), (void*)verts, GL_STATIC_DRAW); + } + else + { + gl.glBufferSubData(GL_ARRAY_BUFFER, verts_offset * sizeof(r32), verts_len * sizeof(r32), (void*)verts); + } + os_gl_no_error(); + + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer->buffer_id_indices); + os_gl_no_error(); + if (indices_len > buffer->indices_len) + { + // NOTE(PS): this is because we're going to delete the old buffer and + // create a new one. In order to do that and not lose data, the update + // function needs to have been passed all the buffer's data + assert(indices_offset == 0); + gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_len * sizeof(u32), (void*)indices, GL_STATIC_DRAW); + } + else + { + gl.glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, indices_offset * sizeof(u32), indices_len * sizeof(u32), (void*)indices); + } + os_gl_no_error(); +} + +Shader +shader_create(String code_vert, String code_frag, String* attrs, u32 attrs_len, String* uniforms, u32 uniforms_len){ + Shader result = {}; + + GLuint shader_vert = gl.glCreateShader(GL_VERTEX_SHADER); + s32* code_vert_len = (s32*)&code_vert.len; + gl.glShaderSource(shader_vert, 1, (const char**)&code_vert.str, code_vert_len); + gl.glCompileShader(shader_vert); + { // errors + GLint shader_vert_compiled; + gl.glGetShaderiv(shader_vert, GL_COMPILE_STATUS, &shader_vert_compiled); + if (!shader_vert_compiled) + { + GLsizei log_length = 0; + GLchar message[1024]; + gl.glGetShaderInfoLog(shader_vert, 1024, &log_length, message); + printf("GLSL Error: %s\n", message); + invalid_code_path; + } + } + + GLuint shader_frag = gl.glCreateShader(GL_FRAGMENT_SHADER); + s32* code_frag_len = (s32*)&code_frag.len; + gl.glShaderSource(shader_frag, 1, (const char**)&code_frag.str, code_frag_len); + gl.glCompileShader(shader_frag); + { // errors + GLint shader_frag_compiled; + gl.glGetShaderiv(shader_frag, GL_COMPILE_STATUS, &shader_frag_compiled); + if (!shader_frag_compiled) + { + GLsizei log_length = 0; + GLchar message[1024]; + gl.glGetShaderInfoLog(shader_frag, 1024, &log_length, message); + printf("GLSL Error: %s\n", message); + printf("%.*s\n", str_varg(code_frag)); + invalid_code_path; + } + } + + result.id = (u32)gl.glCreateProgram(); + gl.glAttachShader(result.id, shader_vert); + gl.glAttachShader(result.id, shader_frag); + gl.glLinkProgram(result.id); + + GLint program_linked; + gl.glGetProgramiv(result.id, GL_LINK_STATUS, &program_linked); + if (program_linked != GL_TRUE) + { + GLsizei log_length = 0; + GLchar message[1024]; + gl.glGetProgramInfoLog(result.id, 1024, &log_length, message); + printf("GLSL Error: %s\n", message); + invalid_code_path; + } + + gl.glUseProgram(result.id); + + // TODO(PS): delete the vert and frag programs + + assert(attrs_len < SHADER_MAX_ATTRS); + for (u32 i = 0; i < attrs_len; i++) + { + result.attrs[i] = gl.glGetAttribLocation(result.id, (char*)attrs[i].str); + os_gl_no_error(); + } + result.attrs[attrs_len] = SHADER_ATTR_LAST; + + assert(uniforms_len < SHADER_MAX_ATTRS); + for (GLuint i = 0; i < uniforms_len; i++) + { + s32 len = (s32)uniforms[i].len; + result.uniforms[i] = gl.glGetUniformLocation(result.id, (char*)uniforms[i].str); + } + result.uniforms[uniforms_len] = SHADER_ATTR_LAST; + + return result; +} + +void +set_uniform(Shader shader, u32 index, m44 u) +{ + gl.glUniformMatrix4fv(shader.uniforms[index], 1, GL_FALSE, (r32*)u.Elements); +} + +void +geometry_bind(Geometry_Buffer geo) +{ + gl.glBindVertexArray(geo.buffer_id_vao); + os_gl_no_error(); + + gl.glBindBuffer(GL_ARRAY_BUFFER, geo.buffer_id_vertices); + os_gl_no_error(); + + gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geo.buffer_id_indices); + os_gl_no_error(); +} + +void +shader_bind(Shader shader) +{ + gl.glUseProgram(shader.id); + os_gl_no_error(); + for (u32 i = 0; + ((i < SHADER_MAX_ATTRS) && (shader.attrs[i] != SHADER_ATTR_LAST)); + i++) + { + gl.glEnableVertexAttribArray(shader.attrs[i]); + os_gl_no_error(); + } +} + +void +geometry_drawi(Geometry_Buffer geo, u32 indices){ + glDrawElements(GL_TRIANGLES, indices, GL_UNSIGNED_INT, 0); + os_gl_no_error(); +} + +void +geometry_draw(Geometry_Buffer geo){ + geometry_drawi(geo, geo.indices_len); +} + +void vertex_attrib_pointer(Geometry_Buffer geo, Shader shader, GLuint count, GLuint attr_index, GLuint stride, GLuint offset){ + geometry_bind(geo); + gl.glVertexAttribPointer(shader.attrs[attr_index], count, GL_FLOAT, false, stride * sizeof(float), (void*)(offset * sizeof(float))); + os_gl_no_error(); + gl.glEnableVertexAttribArray(shader.attrs[attr_index]); + os_gl_no_error(); +} + +Texture +texture_create(u8* pixels, u32 width, u32 height, u32 stride) +{ + Texture result = {}; + glGenTextures(1, &result.id); + os_gl_no_error(); + + glBindTexture(GL_TEXTURE_2D, result.id); + os_gl_no_error(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + os_gl_no_error(); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixels + ); + os_gl_no_error(); + + result.w = width; + result.h = height; + result.s = stride; + + return result; +} + +void +texture_update(Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride) +{ + // NOTE(PS): this function simply replaces the entire image + // we can write a more granular version if we need it + + assert(tex.w == width && tex.h == height && tex.s == stride); + texture_bind(tex); + glTexSubImage2D( + GL_TEXTURE_2D, + 0, + 0, 0, // offset + width, height, + GL_RGBA, + GL_UNSIGNED_BYTE, + new_pixels + ); + os_gl_no_error(); +} + +void +texture_bind(Texture tex) +{ + glBindTexture(GL_TEXTURE_2D, tex.id); + os_gl_no_error(); +} + +void +frame_begin(Graphics_Frame_Desc desc) +{ + v4 cc = desc.clear_color; + glClearColor(cc.r, cc.g, cc.b, cc.a); + + v2 vmin = desc.viewport_min; + v2 vmax = desc.viewport_max; + glViewport((GLsizei)vmin.x, (GLsizei)vmin.y, (GLint)vmax.x, (GLint)vmax.y); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glDisable(GL_CULL_FACE); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + os_gl_no_error(); +} + +void +frame_clear() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + + +String +xplatform_shader_program_get_vert(XPlatform_Shader_Program_Src src) +{ +#if defined(PLATFORM_win32) + return src.win32_vert; +#elif defined(PLATFORM_osx) + return src.osx_vert; +#elif defined(PLATFORM_wasm) + return src.wasm_vert; +#endif +} + +String +xplatform_shader_program_get_frag(XPlatform_Shader_Program_Src src) +{ +#if defined(PLATFORM_win32) + return src.win32_frag; +#elif defined(PLATFORM_osx) + return src.osx_frag; +#elif defined(PLATFORM_wasm) + return src.wasm_frag; +#endif +} + + +#endif // LUMENARIUM_EDITOR_GRAPHICS_H \ No newline at end of file diff --git a/src_v2/editor/graphics/lumenarium_editor_opengl.h b/src_v2/editor/graphics/lumenarium_editor_opengl.h new file mode 100644 index 0000000..caaa02f --- /dev/null +++ b/src_v2/editor/graphics/lumenarium_editor_opengl.h @@ -0,0 +1,76 @@ +/* date = March 24th 2022 6:05 pm */ + +#ifndef LUMENARIUM_EDITOR_OPENGL_H +#define LUMENARIUM_EDITOR_OPENGL_H + +// glext.h - https://github.com/KhronosGroup/OpenGL-Registry/blob/main/api/GL/glext.h +// wglext.h - + +void os_gl_no_error(); + +// OpenGL 3.3+ Context Creation +#if defined(PLATFORM_win32) +typedef const char *WINAPI proc_wglGetExtensionsStringARB(HDC hdc); +typedef BOOL proc_wglChoosePixelFormatARB(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); +typedef HGLRC proc_wglCreateContextAttribsARB(HDC hDC, HGLRC hshareContext, const int *attribList); +#endif + +// OpenGL 3.3+ Extensions +typedef void proc_glGenVertexArrays(GLsizei n, GLuint *arrays); +typedef void proc_glBindVertexArray(GLuint array); +typedef void proc_glGenBuffers (GLsizei n, GLuint *buffers); +typedef void proc_glBindBuffer(GLenum target, GLuint buffer); +typedef void proc_glBufferData(GLenum target, size_t size, const void *data, GLenum usage); +typedef void proc_glBufferSubData(GLenum target, size_t offset, size_t size, const void* data); +typedef GLuint proc_glCreateShader(GLenum type); +typedef void proc_glShaderSource(GLuint shader, u32 count, const char* const* string, const GLint *length); +typedef void proc_glCompileShader(GLuint shader); +typedef GLuint proc_glCreateProgram(void); +typedef void proc_glAttachShader(GLuint program, GLuint shader); +typedef void proc_glLinkProgram(GLuint program); +typedef void proc_glUseProgram(GLuint program); +typedef GLuint proc_glGetAttribLocation(GLuint program, const char* name); +typedef void proc_glVertexAttribPointer(GLuint attr, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); +typedef void proc_glEnableVertexAttribArray(GLuint index); +typedef void proc_glGetShaderiv(GLuint shader, GLenum ele, GLint* value_out); +typedef void proc_glGetShaderInfoLog(GLuint shader, GLuint buf_len, GLsizei* len_out, GLchar* buf); +typedef void proc_glGetProgramiv(GLuint program, GLenum ele, GLint* value_out); +typedef void proc_glGetProgramInfoLog(GLuint program, GLuint cap, GLsizei* len_out, GLchar* buf); +typedef GLuint proc_glGetUniformLocation(GLuint program, const char* name); +typedef void proc_glUniformMatrix4fv(GLuint uniform, GLuint count, GLenum normalize, GLfloat* elements); +typedef struct OpenGL_Extensions OpenGL_Extensions; +struct OpenGL_Extensions +{ + #if defined(PLATFORM_win32) + proc_wglGetExtensionsStringARB* wglGetExtensionsStringARB; + proc_wglChoosePixelFormatARB* wglChoosePixelFormatARB; + proc_wglCreateContextAttribsARB* wglCreateContextAttribsARB; + #endif + + proc_glGenVertexArrays* glGenVertexArrays; + proc_glBindVertexArray* glBindVertexArray; + proc_glGenBuffers* glGenBuffers; + proc_glBindBuffer* glBindBuffer; + proc_glBufferData* glBufferData; + proc_glBufferSubData* glBufferSubData; + proc_glCreateShader* glCreateShader; + proc_glShaderSource* glShaderSource; + proc_glCompileShader* glCompileShader; + proc_glCreateProgram* glCreateProgram; + proc_glAttachShader* glAttachShader; + proc_glLinkProgram* glLinkProgram; + proc_glUseProgram* glUseProgram; + proc_glGetAttribLocation* glGetAttribLocation; + proc_glVertexAttribPointer* glVertexAttribPointer; + proc_glEnableVertexAttribArray* glEnableVertexAttribArray; + proc_glGetShaderiv* glGetShaderiv; + proc_glGetShaderInfoLog* glGetShaderInfoLog; + proc_glGetProgramiv* glGetProgramiv; + proc_glGetProgramInfoLog* glGetProgramInfoLog; + proc_glGetUniformLocation* glGetUniformLocation; + proc_glUniformMatrix4fv* glUniformMatrix4fv; +}; + +global OpenGL_Extensions gl = {}; + +#endif //LUMENARIUM_EDITOR_OPENGL_H \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor.c b/src_v2/editor/lumenarium_editor.c new file mode 100644 index 0000000..610f2cc --- /dev/null +++ b/src_v2/editor/lumenarium_editor.c @@ -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(); +} + diff --git a/src_v2/editor/lumenarium_editor.cpp b/src_v2/editor/lumenarium_editor.cpp deleted file mode 100644 index 833730d..0000000 --- a/src_v2/editor/lumenarium_editor.cpp +++ /dev/null @@ -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) -{ - -} - diff --git a/src_v2/editor/lumenarium_editor.h b/src_v2/editor/lumenarium_editor.h index b623912..f275a99 100644 --- a/src_v2/editor/lumenarium_editor.h +++ b/src_v2/editor/lumenarium_editor.h @@ -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 diff --git a/src_v2/editor/lumenarium_editor_renderer.c b/src_v2/editor/lumenarium_editor_renderer.c new file mode 100644 index 0000000..fa1714b --- /dev/null +++ b/src_v2/editor/lumenarium_editor_renderer.c @@ -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) +{ +} \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_renderer.cpp b/src_v2/editor/lumenarium_editor_renderer.cpp deleted file mode 100644 index 67d9e34..0000000 --- a/src_v2/editor/lumenarium_editor_renderer.cpp +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_renderer.h b/src_v2/editor/lumenarium_editor_renderer.h index bebff8e..4129499 100644 --- a/src_v2/editor/lumenarium_editor_renderer.h +++ b/src_v2/editor/lumenarium_editor_renderer.h @@ -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 diff --git a/src_v2/editor/lumenarium_editor_sculpture_visualizer.c b/src_v2/editor/lumenarium_editor_sculpture_visualizer.c new file mode 100644 index 0000000..b70efda --- /dev/null +++ b/src_v2/editor/lumenarium_editor_sculpture_visualizer.c @@ -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); +} \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_sculpture_visualizer.cpp b/src_v2/editor/lumenarium_editor_sculpture_visualizer.cpp deleted file mode 100644 index 40e86ac..0000000 --- a/src_v2/editor/lumenarium_editor_sculpture_visualizer.cpp +++ /dev/null @@ -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); -} \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_sculpture_visualizer_shaders.h b/src_v2/editor/lumenarium_editor_sculpture_visualizer_shaders.h new file mode 100644 index 0000000..07444ca --- /dev/null +++ b/src_v2/editor/lumenarium_editor_sculpture_visualizer_shaders.h @@ -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" + "}" + ), +}; \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_ui.cpp b/src_v2/editor/lumenarium_editor_ui.c similarity index 66% rename from src_v2/editor/lumenarium_editor_ui.cpp rename to src_v2/editor/lumenarium_editor_ui.c index 44bccc5..894c11e 100644 --- a/src_v2/editor/lumenarium_editor_ui.cpp +++ b/src_v2/editor/lumenarium_editor_ui.c @@ -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; } diff --git a/src_v2/editor/lumenarium_editor_ui.h b/src_v2/editor/lumenarium_editor_ui.h index 6a9b4e7..2bea01e 100644 --- a/src_v2/editor/lumenarium_editor_ui.h +++ b/src_v2/editor/lumenarium_editor_ui.h @@ -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); diff --git a/src_v2/editor/lumenarium_editor_ui_shaders.h b/src_v2/editor/lumenarium_editor_ui_shaders.h new file mode 100644 index 0000000..1db4635 --- /dev/null +++ b/src_v2/editor/lumenarium_editor_ui_shaders.h @@ -0,0 +1,75 @@ +global XPlatform_Shader_Program_Src ui_shader = { + .win32_vert = lit_str( + "#version 330 core\n" + "layout (location = 0) in vec3 a_pos;\n" + "layout (location = 1) in vec2 a_uv;\n" + "layout (location = 2) in vec4 a_color;\n" + "out vec2 uv;\n" + "out vec4 color;\n" + "uniform mat4 proj;\n" + "void main(void) {\n" + " gl_Position = proj * vec4(a_pos, 1.0);\n" + " uv = a_uv;\n" + " color = a_color;\n" + "}" + ), + .win32_frag = lit_str( + "#version 330 core\n" + "in vec2 uv;\n" + "in vec4 color;\n" + "out vec4 FragColor;\n" + "uniform sampler2D tex;\n" + "void main(void) {\n" + " FragColor = texture(tex, uv) * color;\n" + "}" + ), + + .osx_vert = lit_str( + "#version 330 core\n" + "layout (location = 0) in vec3 a_pos;\n" + "layout (location = 1) in vec2 a_uv;\n" + "layout (location = 2) in vec4 a_color;\n" + "out vec2 uv;\n" + "out vec4 color;\n" + "uniform mat4 proj;\n" + "void main(void) {\n" + " gl_Position = proj * vec4(a_pos, 1.0);\n" + " uv = a_uv;\n" + " color = a_color;\n" + "}" + ), + .osx_frag = lit_str( + "#version 330 core\n" + "in vec2 uv;\n" + "in vec4 color;\n" + "out vec4 FragColor;\n" + "uniform sampler2D tex;\n" + "void main(void) {\n" + " FragColor = texture(tex, uv) * color;\n" + "}" + ), + + .wasm_vert = lit_str( + "precision highp float;\n" + "attribute vec3 a_pos;\n" + "attribute vec2 a_uv;\n" + "attribute vec4 a_color;\n" + "varying vec2 uv;\n" + "varying vec4 color;\n" + "uniform mat4 proj;\n" + "void main(void) {\n" + " gl_Position = proj * vec4(a_pos, 1.0);\n" + " uv = a_uv;\n" + " color = a_color;\n" + "}" + ), + .wasm_frag = lit_str( + "precision highp float;\n" + "varying vec2 uv;\n" + "varying vec4 color;\n" + "uniform sampler2D tex;\n" + "void main(void) {\n" + " gl_FragColor = texture2D(tex, uv) * color;\n" + "}" + ), +}; \ No newline at end of file diff --git a/src_v2/engine/lumenarium_engine.cpp b/src_v2/engine/lumenarium_engine.c similarity index 92% rename from src_v2/engine/lumenarium_engine.cpp rename to src_v2/engine/lumenarium_engine.c index 2f0704f..747a923 100644 --- a/src_v2/engine/lumenarium_engine.cpp +++ b/src_v2/engine/lumenarium_engine.c @@ -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(); } diff --git a/src_v2/engine/lumenarium_engine_assembly.cpp b/src_v2/engine/lumenarium_engine_assembly.c similarity index 82% rename from src_v2/engine/lumenarium_engine_assembly.cpp rename to src_v2/engine/lumenarium_engine_assembly.c index 156b3fc..db10fba 100644 --- a/src_v2/engine/lumenarium_engine_assembly.cpp +++ b/src_v2/engine/lumenarium_engine_assembly.c @@ -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); } } \ No newline at end of file diff --git a/src_v2/engine/lumenarium_engine_assembly.h b/src_v2/engine/lumenarium_engine_assembly.h index 2c94fac..8dbed50 100644 --- a/src_v2/engine/lumenarium_engine_assembly.h +++ b/src_v2/engine/lumenarium_engine_assembly.h @@ -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; diff --git a/src_v2/engine/lumenarium_engine_output.cpp b/src_v2/engine/lumenarium_engine_output.c similarity index 100% rename from src_v2/engine/lumenarium_engine_output.cpp rename to src_v2/engine/lumenarium_engine_output.c diff --git a/src_v2/engine/lumenarium_engine_output.h b/src_v2/engine/lumenarium_engine_output.h index d8b9a76..3d3ff56 100644 --- a/src_v2/engine/lumenarium_engine_output.h +++ b/src_v2/engine/lumenarium_engine_output.h @@ -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; diff --git a/src_v2/engine/output/lumenarium_output_sacn.cpp b/src_v2/engine/output/lumenarium_output_sacn.c similarity index 99% rename from src_v2/engine/output/lumenarium_output_sacn.cpp rename to src_v2/engine/output/lumenarium_output_sacn.c index c7f961a..ada76ca 100644 --- a/src_v2/engine/output/lumenarium_output_sacn.cpp +++ b/src_v2/engine/output/lumenarium_output_sacn.c @@ -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 diff --git a/src_v2/engine/output/lumenarium_output_sacn.h b/src_v2/engine/output/lumenarium_output_sacn.h index 568020a..0f762c7 100644 --- a/src_v2/engine/output/lumenarium_output_sacn.h +++ b/src_v2/engine/output/lumenarium_output_sacn.h @@ -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; diff --git a/src_v2/engine/output/lumenarium_output_uart.cpp b/src_v2/engine/output/lumenarium_output_uart.c similarity index 100% rename from src_v2/engine/output/lumenarium_output_uart.cpp rename to src_v2/engine/output/lumenarium_output_uart.c diff --git a/src_v2/libs/HandmadeMath.h b/src_v2/libs/HandmadeMath.h index 8f71b31..63f883b 100644 --- a/src_v2/libs/HandmadeMath.h +++ b/src_v2/libs/HandmadeMath.h @@ -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 = {}; diff --git a/src_v2/libs/glfw_osx/include/GLFW/glfw3.h b/src_v2/libs/glfw_osx/include/GLFW/glfw3.h new file mode 100644 index 0000000..d074de1 --- /dev/null +++ b/src_v2/libs/glfw_osx/include/GLFW/glfw3.h @@ -0,0 +1,5913 @@ +/************************************************************************* + * GLFW 3.3 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2019 Camilla Löwy + * + * 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_h_ +#define _glfw3_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @file glfw3.h + * @brief The header of the GLFW 3 API. + * + * This is the header file of the GLFW 3 API. It defines all its types and + * declares all its functions. + * + * For more information about how to use this file, see @ref build_include. + */ +/*! @defgroup context Context reference + * @brief Functions and types related to OpenGL and OpenGL ES contexts. + * + * This is the reference documentation for OpenGL and OpenGL ES context related + * functions. For more task-oriented information, see the @ref context_guide. + */ +/*! @defgroup vulkan Vulkan support reference + * @brief Functions and types related to Vulkan. + * + * This is the reference documentation for Vulkan related functions and types. + * For more task-oriented information, see the @ref vulkan_guide. + */ +/*! @defgroup init Initialization, version and error reference + * @brief Functions and types related to initialization and error handling. + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more task-oriented + * information, see the @ref intro_guide. + */ +/*! @defgroup input Input reference + * @brief Functions and types related to input handling. + * + * This is the reference documentation for input related functions and types. + * For more task-oriented information, see the @ref input_guide. + */ +/*! @defgroup monitor Monitor reference + * @brief Functions and types related to monitors. + * + * This is the reference documentation for monitor related functions and types. + * For more task-oriented information, see the @ref monitor_guide. + */ +/*! @defgroup window Window reference + * @brief Functions and types related to windows. + * + * This is the reference documentation for window related functions and types, + * including creation, deletion and event polling. For more task-oriented + * information, see the @ref window_guide. + */ + + +/************************************************************************* + * Compiler- and platform-specific preprocessor work + *************************************************************************/ + +/* If we are we on Windows, we want a single define for it. + */ +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) + #define _WIN32 +#endif /* _WIN32 */ + +/* Include because most Windows GLU headers need wchar_t and + * the macOS OpenGL header blocks the definition of ptrdiff_t by glext.h. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +/* Include because it is needed by Vulkan and related functions. + * Include it unconditionally to avoid surprising side-effects. + */ +#include + +#if defined(GLFW_INCLUDE_VULKAN) + #include +#endif /* Vulkan header */ + +/* The Vulkan header may have indirectly included windows.h (because of + * VK_USE_PLATFORM_WIN32_KHR) so we offer our replacement symbols after it. + */ + +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. + */ +#if !defined(APIENTRY) + #if defined(_WIN32) + #define APIENTRY __stdcall + #else + #define APIENTRY + #endif + #define GLFW_APIENTRY_DEFINED +#endif /* APIENTRY */ + +/* Some Windows OpenGL headers need this. + */ +#if !defined(WINGDIAPI) && defined(_WIN32) + #define WINGDIAPI __declspec(dllimport) + #define GLFW_WINGDIAPI_DEFINED +#endif /* WINGDIAPI */ + +/* Some Windows GLU headers need this. + */ +#if !defined(CALLBACK) && defined(_WIN32) + #define CALLBACK __stdcall + #define GLFW_CALLBACK_DEFINED +#endif /* CALLBACK */ + +/* Include the chosen OpenGL or OpenGL ES headers. + */ +#if defined(GLFW_INCLUDE_ES1) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES2) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES3) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES31) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_ES32) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + +#elif defined(GLFW_INCLUDE_GLCOREARB) + + #if defined(__APPLE__) + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif /*GLFW_INCLUDE_GLEXT*/ + + #else /*__APPLE__*/ + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + + #endif /*__APPLE__*/ + +#elif defined(GLFW_INCLUDE_GLU) + + #if defined(__APPLE__) + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #else /*__APPLE__*/ + + #if defined(GLFW_INCLUDE_GLU) + #include + #endif + + #endif /*__APPLE__*/ + +#elif !defined(GLFW_INCLUDE_NONE) && \ + !defined(__gl_h_) && \ + !defined(__gles1_gl_h_) && \ + !defined(__gles2_gl2_h_) && \ + !defined(__gles2_gl3_h_) && \ + !defined(__gles2_gl31_h_) && \ + !defined(__gles2_gl32_h_) && \ + !defined(__gl_glcorearb_h_) && \ + !defined(__gl2_h_) /*legacy*/ && \ + !defined(__gl3_h_) /*legacy*/ && \ + !defined(__gl31_h_) /*legacy*/ && \ + !defined(__gl32_h_) /*legacy*/ && \ + !defined(__glcorearb_h_) /*legacy*/ && \ + !defined(__GL_H__) /*non-standard*/ && \ + !defined(__gltypes_h_) /*non-standard*/ && \ + !defined(__glee_h_) /*non-standard*/ + + #if defined(__APPLE__) + + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY + #endif + #include + + #else /*__APPLE__*/ + + #include + #if defined(GLFW_INCLUDE_GLEXT) + #include + #endif + + #endif /*__APPLE__*/ + +#endif /* OpenGL and OpenGL ES headers */ + +#if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. + */ + #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" +#endif + +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ +#if defined(_WIN32) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllexport) +#elif defined(_WIN32) && defined(GLFW_DLL) + /* We are calling GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllimport) +#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) + /* We are building GLFW as a shared / dynamic library */ + #define GLFWAPI __attribute__((visibility("default"))) +#else + /* We are building or calling GLFW as a static library */ + #define GLFWAPI +#endif + + +/************************************************************************* + * GLFW API tokens + *************************************************************************/ + +/*! @name GLFW version macros + * @{ */ +/*! @brief The major version number of the GLFW header. + * + * The major version number of the GLFW header. This is incremented when the + * API is changed in non-compatible ways. + * @ingroup init + */ +#define GLFW_VERSION_MAJOR 3 +/*! @brief The minor version number of the GLFW header. + * + * The minor version number of the GLFW header. This is incremented when + * features are added to the API but it remains backward-compatible. + * @ingroup init + */ +#define GLFW_VERSION_MINOR 3 +/*! @brief The revision number of the GLFW header. + * + * The revision number of the GLFW header. This is incremented when a bug fix + * release is made that does not contain any API changes. + * @ingroup init + */ +#define GLFW_VERSION_REVISION 7 +/*! @} */ + +/*! @brief One. + * + * This is only semantic sugar for the number 1. You can instead use `1` or + * `true` or `_True` or `GL_TRUE` or `VK_TRUE` or anything else that is equal + * to one. + * + * @ingroup init + */ +#define GLFW_TRUE 1 +/*! @brief Zero. + * + * This is only semantic sugar for the number 0. You can instead use `0` or + * `false` or `_False` or `GL_FALSE` or `VK_FALSE` or anything else that is + * equal to zero. + * + * @ingroup init + */ +#define GLFW_FALSE 0 + +/*! @name Key and button actions + * @{ */ +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * + * @ingroup input + */ +#define GLFW_RELEASE 0 +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * + * @ingroup input + */ +#define GLFW_PRESS 1 +/*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * + * @ingroup input + */ +#define GLFW_REPEAT 2 +/*! @} */ + +/*! @defgroup hat_state Joystick hat states + * @brief Joystick hat states. + * + * See [joystick hat input](@ref joystick_hat) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_HAT_CENTERED 0 +#define GLFW_HAT_UP 1 +#define GLFW_HAT_RIGHT 2 +#define GLFW_HAT_DOWN 4 +#define GLFW_HAT_LEFT 8 +#define GLFW_HAT_RIGHT_UP (GLFW_HAT_RIGHT | GLFW_HAT_UP) +#define GLFW_HAT_RIGHT_DOWN (GLFW_HAT_RIGHT | GLFW_HAT_DOWN) +#define GLFW_HAT_LEFT_UP (GLFW_HAT_LEFT | GLFW_HAT_UP) +#define GLFW_HAT_LEFT_DOWN (GLFW_HAT_LEFT | GLFW_HAT_DOWN) +/*! @} */ + +/*! @defgroup keys Keyboard keys + * @brief Keyboard key IDs. + * + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) + * + * @ingroup input + * @{ + */ + +/* The unknown key */ +#define GLFW_KEY_UNKNOWN -1 + +/* Printable keys */ +#define GLFW_KEY_SPACE 32 +#define GLFW_KEY_APOSTROPHE 39 /* ' */ +#define GLFW_KEY_COMMA 44 /* , */ +#define GLFW_KEY_MINUS 45 /* - */ +#define GLFW_KEY_PERIOD 46 /* . */ +#define GLFW_KEY_SLASH 47 /* / */ +#define GLFW_KEY_0 48 +#define GLFW_KEY_1 49 +#define GLFW_KEY_2 50 +#define GLFW_KEY_3 51 +#define GLFW_KEY_4 52 +#define GLFW_KEY_5 53 +#define GLFW_KEY_6 54 +#define GLFW_KEY_7 55 +#define GLFW_KEY_8 56 +#define GLFW_KEY_9 57 +#define GLFW_KEY_SEMICOLON 59 /* ; */ +#define GLFW_KEY_EQUAL 61 /* = */ +#define GLFW_KEY_A 65 +#define GLFW_KEY_B 66 +#define GLFW_KEY_C 67 +#define GLFW_KEY_D 68 +#define GLFW_KEY_E 69 +#define GLFW_KEY_F 70 +#define GLFW_KEY_G 71 +#define GLFW_KEY_H 72 +#define GLFW_KEY_I 73 +#define GLFW_KEY_J 74 +#define GLFW_KEY_K 75 +#define GLFW_KEY_L 76 +#define GLFW_KEY_M 77 +#define GLFW_KEY_N 78 +#define GLFW_KEY_O 79 +#define GLFW_KEY_P 80 +#define GLFW_KEY_Q 81 +#define GLFW_KEY_R 82 +#define GLFW_KEY_S 83 +#define GLFW_KEY_T 84 +#define GLFW_KEY_U 85 +#define GLFW_KEY_V 86 +#define GLFW_KEY_W 87 +#define GLFW_KEY_X 88 +#define GLFW_KEY_Y 89 +#define GLFW_KEY_Z 90 +#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ +#define GLFW_KEY_BACKSLASH 92 /* \ */ +#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +/* Function keys */ +#define GLFW_KEY_ESCAPE 256 +#define GLFW_KEY_ENTER 257 +#define GLFW_KEY_TAB 258 +#define GLFW_KEY_BACKSPACE 259 +#define GLFW_KEY_INSERT 260 +#define GLFW_KEY_DELETE 261 +#define GLFW_KEY_RIGHT 262 +#define GLFW_KEY_LEFT 263 +#define GLFW_KEY_DOWN 264 +#define GLFW_KEY_UP 265 +#define GLFW_KEY_PAGE_UP 266 +#define GLFW_KEY_PAGE_DOWN 267 +#define GLFW_KEY_HOME 268 +#define GLFW_KEY_END 269 +#define GLFW_KEY_CAPS_LOCK 280 +#define GLFW_KEY_SCROLL_LOCK 281 +#define GLFW_KEY_NUM_LOCK 282 +#define GLFW_KEY_PRINT_SCREEN 283 +#define GLFW_KEY_PAUSE 284 +#define GLFW_KEY_F1 290 +#define GLFW_KEY_F2 291 +#define GLFW_KEY_F3 292 +#define GLFW_KEY_F4 293 +#define GLFW_KEY_F5 294 +#define GLFW_KEY_F6 295 +#define GLFW_KEY_F7 296 +#define GLFW_KEY_F8 297 +#define GLFW_KEY_F9 298 +#define GLFW_KEY_F10 299 +#define GLFW_KEY_F11 300 +#define GLFW_KEY_F12 301 +#define GLFW_KEY_F13 302 +#define GLFW_KEY_F14 303 +#define GLFW_KEY_F15 304 +#define GLFW_KEY_F16 305 +#define GLFW_KEY_F17 306 +#define GLFW_KEY_F18 307 +#define GLFW_KEY_F19 308 +#define GLFW_KEY_F20 309 +#define GLFW_KEY_F21 310 +#define GLFW_KEY_F22 311 +#define GLFW_KEY_F23 312 +#define GLFW_KEY_F24 313 +#define GLFW_KEY_F25 314 +#define GLFW_KEY_KP_0 320 +#define GLFW_KEY_KP_1 321 +#define GLFW_KEY_KP_2 322 +#define GLFW_KEY_KP_3 323 +#define GLFW_KEY_KP_4 324 +#define GLFW_KEY_KP_5 325 +#define GLFW_KEY_KP_6 326 +#define GLFW_KEY_KP_7 327 +#define GLFW_KEY_KP_8 328 +#define GLFW_KEY_KP_9 329 +#define GLFW_KEY_KP_DECIMAL 330 +#define GLFW_KEY_KP_DIVIDE 331 +#define GLFW_KEY_KP_MULTIPLY 332 +#define GLFW_KEY_KP_SUBTRACT 333 +#define GLFW_KEY_KP_ADD 334 +#define GLFW_KEY_KP_ENTER 335 +#define GLFW_KEY_KP_EQUAL 336 +#define GLFW_KEY_LEFT_SHIFT 340 +#define GLFW_KEY_LEFT_CONTROL 341 +#define GLFW_KEY_LEFT_ALT 342 +#define GLFW_KEY_LEFT_SUPER 343 +#define GLFW_KEY_RIGHT_SHIFT 344 +#define GLFW_KEY_RIGHT_CONTROL 345 +#define GLFW_KEY_RIGHT_ALT 346 +#define GLFW_KEY_RIGHT_SUPER 347 +#define GLFW_KEY_MENU 348 + +#define GLFW_KEY_LAST GLFW_KEY_MENU + +/*! @} */ + +/*! @defgroup mods Modifier key flags + * @brief Modifier key flags. + * + * See [key input](@ref input_key) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief If this bit is set one or more Shift keys were held down. + * + * If this bit is set one or more Shift keys were held down. + */ +#define GLFW_MOD_SHIFT 0x0001 +/*! @brief If this bit is set one or more Control keys were held down. + * + * If this bit is set one or more Control keys were held down. + */ +#define GLFW_MOD_CONTROL 0x0002 +/*! @brief If this bit is set one or more Alt keys were held down. + * + * If this bit is set one or more Alt keys were held down. + */ +#define GLFW_MOD_ALT 0x0004 +/*! @brief If this bit is set one or more Super keys were held down. + * + * If this bit is set one or more Super keys were held down. + */ +#define GLFW_MOD_SUPER 0x0008 +/*! @brief If this bit is set the Caps Lock key is enabled. + * + * If this bit is set the Caps Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_CAPS_LOCK 0x0010 +/*! @brief If this bit is set the Num Lock key is enabled. + * + * If this bit is set the Num Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_NUM_LOCK 0x0020 + +/*! @} */ + +/*! @defgroup buttons Mouse buttons + * @brief Mouse button IDs. + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_MOUSE_BUTTON_1 0 +#define GLFW_MOUSE_BUTTON_2 1 +#define GLFW_MOUSE_BUTTON_3 2 +#define GLFW_MOUSE_BUTTON_4 3 +#define GLFW_MOUSE_BUTTON_5 4 +#define GLFW_MOUSE_BUTTON_6 5 +#define GLFW_MOUSE_BUTTON_7 6 +#define GLFW_MOUSE_BUTTON_8 7 +#define GLFW_MOUSE_BUTTON_LAST GLFW_MOUSE_BUTTON_8 +#define GLFW_MOUSE_BUTTON_LEFT GLFW_MOUSE_BUTTON_1 +#define GLFW_MOUSE_BUTTON_RIGHT GLFW_MOUSE_BUTTON_2 +#define GLFW_MOUSE_BUTTON_MIDDLE GLFW_MOUSE_BUTTON_3 +/*! @} */ + +/*! @defgroup joysticks Joysticks + * @brief Joystick IDs. + * + * See [joystick input](@ref joystick) for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_JOYSTICK_1 0 +#define GLFW_JOYSTICK_2 1 +#define GLFW_JOYSTICK_3 2 +#define GLFW_JOYSTICK_4 3 +#define GLFW_JOYSTICK_5 4 +#define GLFW_JOYSTICK_6 5 +#define GLFW_JOYSTICK_7 6 +#define GLFW_JOYSTICK_8 7 +#define GLFW_JOYSTICK_9 8 +#define GLFW_JOYSTICK_10 9 +#define GLFW_JOYSTICK_11 10 +#define GLFW_JOYSTICK_12 11 +#define GLFW_JOYSTICK_13 12 +#define GLFW_JOYSTICK_14 13 +#define GLFW_JOYSTICK_15 14 +#define GLFW_JOYSTICK_16 15 +#define GLFW_JOYSTICK_LAST GLFW_JOYSTICK_16 +/*! @} */ + +/*! @defgroup gamepad_buttons Gamepad buttons + * @brief Gamepad buttons. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_BUTTON_A 0 +#define GLFW_GAMEPAD_BUTTON_B 1 +#define GLFW_GAMEPAD_BUTTON_X 2 +#define GLFW_GAMEPAD_BUTTON_Y 3 +#define GLFW_GAMEPAD_BUTTON_LEFT_BUMPER 4 +#define GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER 5 +#define GLFW_GAMEPAD_BUTTON_BACK 6 +#define GLFW_GAMEPAD_BUTTON_START 7 +#define GLFW_GAMEPAD_BUTTON_GUIDE 8 +#define GLFW_GAMEPAD_BUTTON_LEFT_THUMB 9 +#define GLFW_GAMEPAD_BUTTON_RIGHT_THUMB 10 +#define GLFW_GAMEPAD_BUTTON_DPAD_UP 11 +#define GLFW_GAMEPAD_BUTTON_DPAD_RIGHT 12 +#define GLFW_GAMEPAD_BUTTON_DPAD_DOWN 13 +#define GLFW_GAMEPAD_BUTTON_DPAD_LEFT 14 +#define GLFW_GAMEPAD_BUTTON_LAST GLFW_GAMEPAD_BUTTON_DPAD_LEFT + +#define GLFW_GAMEPAD_BUTTON_CROSS GLFW_GAMEPAD_BUTTON_A +#define GLFW_GAMEPAD_BUTTON_CIRCLE GLFW_GAMEPAD_BUTTON_B +#define GLFW_GAMEPAD_BUTTON_SQUARE GLFW_GAMEPAD_BUTTON_X +#define GLFW_GAMEPAD_BUTTON_TRIANGLE GLFW_GAMEPAD_BUTTON_Y +/*! @} */ + +/*! @defgroup gamepad_axes Gamepad axes + * @brief Gamepad axes. + * + * See @ref gamepad for how these are used. + * + * @ingroup input + * @{ */ +#define GLFW_GAMEPAD_AXIS_LEFT_X 0 +#define GLFW_GAMEPAD_AXIS_LEFT_Y 1 +#define GLFW_GAMEPAD_AXIS_RIGHT_X 2 +#define GLFW_GAMEPAD_AXIS_RIGHT_Y 3 +#define GLFW_GAMEPAD_AXIS_LEFT_TRIGGER 4 +#define GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER 5 +#define GLFW_GAMEPAD_AXIS_LAST GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER +/*! @} */ + +/*! @defgroup errors Error codes + * @brief Error codes. + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init + * @{ */ +/*! @brief No error has occurred. + * + * No error has occurred. + * + * @analysis Yay. + */ +#define GLFW_NO_ERROR 0 +/*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that must not be called unless the + * library is [initialized](@ref intro_init). + * + * @analysis Application programmer error. Initialize GLFW before calling any + * function that requires initialization. + */ +#define GLFW_NOT_INITIALIZED 0x00010001 +/*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @analysis Application programmer error. Ensure a context is current before + * calling functions that require a current context. + */ +#define GLFW_NO_CURRENT_CONTEXT 0x00010002 +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting @ref GLFW_RED_BITS with @ref glfwGetWindowAttrib. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_ENUM 0x00010003 +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_INVALID_VALUE 0x00010004 +/*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @analysis A bug in GLFW or the underlying operating system. Report the bug + * to our [issue tracker](https://github.com/glfw/glfw/issues). + */ +#define GLFW_OUT_OF_MEMORY 0x00010005 +/*! @brief GLFW could not find support for the requested API on the system. + * + * GLFW could not find support for the requested API on the system. + * + * @analysis The installed graphics driver does not support the requested + * API, or does not support it via the chosen context creation backend. + * Below are a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only support it via + * a WGL or GLX extension. macOS does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. Older graphics drivers do not support Vulkan. + */ +#define GLFW_API_UNAVAILABLE 0x00010006 +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @analysis The machine does not support your requirements. If your + * application is sufficiently flexible, downgrade your requirements and try + * again. Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. + */ +#define GLFW_VERSION_UNAVAILABLE 0x00010007 +/*! @brief A platform-specific error occurred that does not match any of the + * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @analysis A bug or configuration error in GLFW, the underlying operating + * system or its drivers, or a lack of required resources. Report the issue to + * our [issue tracker](https://github.com/glfw/glfw/issues). + */ +#define GLFW_PLATFORM_ERROR 0x00010008 +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @analysis If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. + */ +#define GLFW_FORMAT_UNAVAILABLE 0x00010009 +/*! @brief The specified window does not have an OpenGL or OpenGL ES context. + * + * A window that does not have an OpenGL or OpenGL ES context was passed to + * a function that requires it to have one. + * + * @analysis Application programmer error. Fix the offending call. + */ +#define GLFW_NO_WINDOW_CONTEXT 0x0001000A +/*! @} */ + +/*! @addtogroup window + * @{ */ +/*! @brief Input focus window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUSED_hint) or + * [window attribute](@ref GLFW_FOCUSED_attrib). + */ +#define GLFW_FOCUSED 0x00020001 +/*! @brief Window iconification window attribute + * + * Window iconification [window attribute](@ref GLFW_ICONIFIED_attrib). + */ +#define GLFW_ICONIFIED 0x00020002 +/*! @brief Window resize-ability window hint and attribute + * + * Window resize-ability [window hint](@ref GLFW_RESIZABLE_hint) and + * [window attribute](@ref GLFW_RESIZABLE_attrib). + */ +#define GLFW_RESIZABLE 0x00020003 +/*! @brief Window visibility window hint and attribute + * + * Window visibility [window hint](@ref GLFW_VISIBLE_hint) and + * [window attribute](@ref GLFW_VISIBLE_attrib). + */ +#define GLFW_VISIBLE 0x00020004 +/*! @brief Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_DECORATED_hint) and + * [window attribute](@ref GLFW_DECORATED_attrib). + */ +#define GLFW_DECORATED 0x00020005 +/*! @brief Window auto-iconification window hint and attribute + * + * Window auto-iconification [window hint](@ref GLFW_AUTO_ICONIFY_hint) and + * [window attribute](@ref GLFW_AUTO_ICONIFY_attrib). + */ +#define GLFW_AUTO_ICONIFY 0x00020006 +/*! @brief Window decoration window hint and attribute + * + * Window decoration [window hint](@ref GLFW_FLOATING_hint) and + * [window attribute](@ref GLFW_FLOATING_attrib). + */ +#define GLFW_FLOATING 0x00020007 +/*! @brief Window maximization window hint and attribute + * + * Window maximization [window hint](@ref GLFW_MAXIMIZED_hint) and + * [window attribute](@ref GLFW_MAXIMIZED_attrib). + */ +#define GLFW_MAXIMIZED 0x00020008 +/*! @brief Cursor centering window hint + * + * Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint). + */ +#define GLFW_CENTER_CURSOR 0x00020009 +/*! @brief Window framebuffer transparency hint and attribute + * + * Window framebuffer transparency + * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and + * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). + */ +#define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A +/*! @brief Mouse cursor hover window attribute. + * + * Mouse cursor hover [window attribute](@ref GLFW_HOVERED_attrib). + */ +#define GLFW_HOVERED 0x0002000B +/*! @brief Input focus on calling show window hint and attribute + * + * Input focus [window hint](@ref GLFW_FOCUS_ON_SHOW_hint) or + * [window attribute](@ref GLFW_FOCUS_ON_SHOW_attrib). + */ +#define GLFW_FOCUS_ON_SHOW 0x0002000C + +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). + */ +#define GLFW_RED_BITS 0x00021001 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_GREEN_BITS). + */ +#define GLFW_GREEN_BITS 0x00021002 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_BLUE_BITS). + */ +#define GLFW_BLUE_BITS 0x00021003 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ALPHA_BITS). + */ +#define GLFW_ALPHA_BITS 0x00021004 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_DEPTH_BITS). + */ +#define GLFW_DEPTH_BITS 0x00021005 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_STENCIL_BITS). + */ +#define GLFW_STENCIL_BITS 0x00021006 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_RED_BITS). + */ +#define GLFW_ACCUM_RED_BITS 0x00021007 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_GREEN_BITS). + */ +#define GLFW_ACCUM_GREEN_BITS 0x00021008 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_BLUE_BITS). + */ +#define GLFW_ACCUM_BLUE_BITS 0x00021009 +/*! @brief Framebuffer bit depth hint. + * + * Framebuffer bit depth [hint](@ref GLFW_ACCUM_ALPHA_BITS). + */ +#define GLFW_ACCUM_ALPHA_BITS 0x0002100A +/*! @brief Framebuffer auxiliary buffer hint. + * + * Framebuffer auxiliary buffer [hint](@ref GLFW_AUX_BUFFERS). + */ +#define GLFW_AUX_BUFFERS 0x0002100B +/*! @brief OpenGL stereoscopic rendering hint. + * + * OpenGL stereoscopic rendering [hint](@ref GLFW_STEREO). + */ +#define GLFW_STEREO 0x0002100C +/*! @brief Framebuffer MSAA samples hint. + * + * Framebuffer MSAA samples [hint](@ref GLFW_SAMPLES). + */ +#define GLFW_SAMPLES 0x0002100D +/*! @brief Framebuffer sRGB hint. + * + * Framebuffer sRGB [hint](@ref GLFW_SRGB_CAPABLE). + */ +#define GLFW_SRGB_CAPABLE 0x0002100E +/*! @brief Monitor refresh rate hint. + * + * Monitor refresh rate [hint](@ref GLFW_REFRESH_RATE). + */ +#define GLFW_REFRESH_RATE 0x0002100F +/*! @brief Framebuffer double buffering hint. + * + * Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER). + */ +#define GLFW_DOUBLEBUFFER 0x00021010 + +/*! @brief Context client API hint and attribute. + * + * Context client API [hint](@ref GLFW_CLIENT_API_hint) and + * [attribute](@ref GLFW_CLIENT_API_attrib). + */ +#define GLFW_CLIENT_API 0x00022001 +/*! @brief Context client API major version hint and attribute. + * + * Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib). + */ +#define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 +/*! @brief Context client API minor version hint and attribute. + * + * Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). + */ +#define GLFW_CONTEXT_VERSION_MINOR 0x00022003 +/*! @brief Context client API revision number attribute. + * + * Context client API revision number + * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). + */ +#define GLFW_CONTEXT_REVISION 0x00022004 +/*! @brief Context robustness hint and attribute. + * + * Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint) + * and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib). + */ +#define GLFW_CONTEXT_ROBUSTNESS 0x00022005 +/*! @brief OpenGL forward-compatibility hint and attribute. + * + * OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) + * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). + */ +#define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 +/*! @brief Debug mode context hint and attribute. + * + * Debug mode context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and + * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). + */ +#define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 +/*! @brief OpenGL profile hint and attribute. + * + * OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and + * [attribute](@ref GLFW_OPENGL_PROFILE_attrib). + */ +#define GLFW_OPENGL_PROFILE 0x00022008 +/*! @brief Context flush-on-release hint and attribute. + * + * Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and + * [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib). + */ +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 +/*! @brief Context error suppression hint and attribute. + * + * Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and + * [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib). + */ +#define GLFW_CONTEXT_NO_ERROR 0x0002200A +/*! @brief Context creation API hint and attribute. + * + * Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and + * [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib). + */ +#define GLFW_CONTEXT_CREATION_API 0x0002200B +/*! @brief Window content area scaling window + * [window hint](@ref GLFW_SCALE_TO_MONITOR). + */ +#define GLFW_SCALE_TO_MONITOR 0x0002200C +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint). + */ +#define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_FRAME_NAME_hint). + */ +#define GLFW_COCOA_FRAME_NAME 0x00023002 +/*! @brief macOS specific + * [window hint](@ref GLFW_COCOA_GRAPHICS_SWITCHING_hint). + */ +#define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 +/*! @brief X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ +#define GLFW_X11_CLASS_NAME 0x00024001 +/*! @brief X11 specific + * [window hint](@ref GLFW_X11_CLASS_NAME_hint). + */ +#define GLFW_X11_INSTANCE_NAME 0x00024002 +/*! @} */ + +#define GLFW_NO_API 0 +#define GLFW_OPENGL_API 0x00030001 +#define GLFW_OPENGL_ES_API 0x00030002 + +#define GLFW_NO_ROBUSTNESS 0 +#define GLFW_NO_RESET_NOTIFICATION 0x00031001 +#define GLFW_LOSE_CONTEXT_ON_RESET 0x00031002 + +#define GLFW_OPENGL_ANY_PROFILE 0 +#define GLFW_OPENGL_CORE_PROFILE 0x00032001 +#define GLFW_OPENGL_COMPAT_PROFILE 0x00032002 + +#define GLFW_CURSOR 0x00033001 +#define GLFW_STICKY_KEYS 0x00033002 +#define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 +#define GLFW_LOCK_KEY_MODS 0x00033004 +#define GLFW_RAW_MOUSE_MOTION 0x00033005 + +#define GLFW_CURSOR_NORMAL 0x00034001 +#define GLFW_CURSOR_HIDDEN 0x00034002 +#define GLFW_CURSOR_DISABLED 0x00034003 + +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +#define GLFW_NATIVE_CONTEXT_API 0x00036001 +#define GLFW_EGL_CONTEXT_API 0x00036002 +#define GLFW_OSMESA_CONTEXT_API 0x00036003 + +/*! @defgroup shapes Standard cursor shapes + * @brief Standard system cursor shapes. + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + +#define GLFW_CONNECTED 0x00040001 +#define GLFW_DISCONNECTED 0x00040002 + +/*! @addtogroup init + * @{ */ +/*! @brief Joystick hat buttons init hint. + * + * Joystick hat buttons [init hint](@ref GLFW_JOYSTICK_HAT_BUTTONS). + */ +#define GLFW_JOYSTICK_HAT_BUTTONS 0x00050001 +/*! @brief macOS specific init hint. + * + * macOS specific [init hint](@ref GLFW_COCOA_CHDIR_RESOURCES_hint). + */ +#define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 +/*! @brief macOS specific init hint. + * + * macOS specific [init hint](@ref GLFW_COCOA_MENUBAR_hint). + */ +#define GLFW_COCOA_MENUBAR 0x00051002 +/*! @} */ + +#define GLFW_DONT_CARE -1 + + +/************************************************************************* + * GLFW API types + *************************************************************************/ + +/*! @brief Client API function pointer type. + * + * Generic function pointer used for returning client API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * @since Added in version 3.0. + * + * @ingroup context + */ +typedef void (*GLFWglproc)(void); + +/*! @brief Vulkan API function pointer type. + * + * Generic function pointer used for returning Vulkan API function pointers + * without forcing a cast from a regular pointer. + * + * @sa @ref vulkan_proc + * @sa @ref glfwGetInstanceProcAddress + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +typedef void (*GLFWvkproc)(void); + +/*! @brief Opaque monitor object. + * + * Opaque monitor object. + * + * @see @ref monitor_object + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWmonitor GLFWmonitor; + +/*! @brief Opaque window object. + * + * Opaque window object. + * + * @see @ref window_object + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef struct GLFWwindow GLFWwindow; + +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @see @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef struct GLFWcursor GLFWcursor; + +/*! @brief The function pointer type for error callbacks. + * + * This is the function pointer type for error callbacks. An error callback + * function has the following signature: + * @code + * void callback_name(int error_code, const char* description) + * @endcode + * + * @param[in] error_code An [error code](@ref errors). Future releases may add + * more error codes. + * @param[in] description A UTF-8 encoded string describing the error. + * + * @pointer_lifetime The error description string is valid until the callback + * function returns. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * @since Added in version 3.0. + * + * @ingroup init + */ +typedef void (* GLFWerrorfun)(int error_code, const char* description); + +/*! @brief The function pointer type for window position callbacks. + * + * This is the function pointer type for window position callbacks. A window + * position callback function has the following signature: + * @code + * void callback_name(GLFWwindow* window, int xpos, int ypos) + * @endcode + * + * @param[in] window The window that was moved. + * @param[in] xpos The new x-coordinate, in screen coordinates, of the + * upper-left corner of the content area of the window. + * @param[in] ypos The new y-coordinate, in screen coordinates, of the + * upper-left corner of the content area of the window. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPosCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowposfun)(GLFWwindow* window, int xpos, int ypos); + +/*! @brief The function pointer type for window size callbacks. + * + * This is the function pointer type for window size callbacks. A window size + * callback function has the following signature: + * @code + * void callback_name(GLFWwindow* window, int width, int height) + * @endcode + * + * @param[in] window The window that was resized. + * @param[in] width The new width, in screen coordinates, of the window. + * @param[in] height The new height, in screen coordinates, of the window. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSizeCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowsizefun)(GLFWwindow* window, int width, int height); + +/*! @brief The function pointer type for window close callbacks. + * + * This is the function pointer type for window close callbacks. A window + * close callback function has the following signature: + * @code + * void function_name(GLFWwindow* window) + * @endcode + * + * @param[in] window The window that the user attempted to close. + * + * @sa @ref window_close + * @sa @ref glfwSetWindowCloseCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowclosefun)(GLFWwindow* window); + +/*! @brief The function pointer type for window content refresh callbacks. + * + * This is the function pointer type for window content refresh callbacks. + * A window content refresh callback function has the following signature: + * @code + * void function_name(GLFWwindow* window); + * @endcode + * + * @param[in] window The window whose content needs to be refreshed. + * + * @sa @ref window_refresh + * @sa @ref glfwSetWindowRefreshCallback + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +typedef void (* GLFWwindowrefreshfun)(GLFWwindow* window); + +/*! @brief The function pointer type for window focus callbacks. + * + * This is the function pointer type for window focus callbacks. A window + * focus callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int focused) + * @endcode + * + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GLFW_TRUE` if the window was given input focus, or + * `GLFW_FALSE` if it lost it. + * + * @sa @ref window_focus + * @sa @ref glfwSetWindowFocusCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowfocusfun)(GLFWwindow* window, int focused); + +/*! @brief The function pointer type for window iconify callbacks. + * + * This is the function pointer type for window iconify callbacks. A window + * iconify callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int iconified) + * @endcode + * + * @param[in] window The window that was iconified or restored. + * @param[in] iconified `GLFW_TRUE` if the window was iconified, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_iconify + * @sa @ref glfwSetWindowIconifyCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWwindowiconifyfun)(GLFWwindow* window, int iconified); + +/*! @brief The function pointer type for window maximize callbacks. + * + * This is the function pointer type for window maximize callbacks. A window + * maximize callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int maximized) + * @endcode + * + * @param[in] window The window that was maximized or restored. + * @param[in] maximized `GLFW_TRUE` if the window was maximized, or + * `GLFW_FALSE` if it was restored. + * + * @sa @ref window_maximize + * @sa glfwSetWindowMaximizeCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowmaximizefun)(GLFWwindow* window, int maximized); + +/*! @brief The function pointer type for framebuffer size callbacks. + * + * This is the function pointer type for framebuffer size callbacks. + * A framebuffer size callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode + * + * @param[in] window The window whose framebuffer was resized. + * @param[in] width The new width, in pixels, of the framebuffer. + * @param[in] height The new height, in pixels, of the framebuffer. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +typedef void (* GLFWframebuffersizefun)(GLFWwindow* window, int width, int height); + +/*! @brief The function pointer type for window content scale callbacks. + * + * This is the function pointer type for window content scale callbacks. + * A window content scale callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, float xscale, float yscale) + * @endcode + * + * @param[in] window The window whose content scale changed. + * @param[in] xscale The new x-axis content scale of the window. + * @param[in] yscale The new y-axis content scale of the window. + * + * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowcontentscalefun)(GLFWwindow* window, float xscale, float yscale); + +/*! @brief The function pointer type for mouse button callbacks. + * + * This is the function pointer type for mouse button callback functions. + * A mouse button callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int button, int action, int mods) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] button The [mouse button](@ref buttons) that was pressed or + * released. + * @param[in] action One of `GLFW_PRESS` or `GLFW_RELEASE`. Future releases + * may add more actions. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_mouse_button + * @sa @ref glfwSetMouseButtonCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWmousebuttonfun)(GLFWwindow* window, int button, int action, int mods); + +/*! @brief The function pointer type for cursor position callbacks. + * + * This is the function pointer type for cursor position callbacks. A cursor + * position callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, double xpos, double ypos); + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] xpos The new cursor x-coordinate, relative to the left edge of + * the content area. + * @param[in] ypos The new cursor y-coordinate, relative to the top edge of the + * content area. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPosCallback + * + * @since Added in version 3.0. Replaces `GLFWmouseposfun`. + * + * @ingroup input + */ +typedef void (* GLFWcursorposfun)(GLFWwindow* window, double xpos, double ypos); + +/*! @brief The function pointer type for cursor enter/leave callbacks. + * + * This is the function pointer type for cursor enter/leave callbacks. + * A cursor enter/leave callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int entered) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] entered `GLFW_TRUE` if the cursor entered the window's content + * area, or `GLFW_FALSE` if it left it. + * + * @sa @ref cursor_enter + * @sa @ref glfwSetCursorEnterCallback + * + * @since Added in version 3.0. + * + * @ingroup input + */ +typedef void (* GLFWcursorenterfun)(GLFWwindow* window, int entered); + +/*! @brief The function pointer type for scroll callbacks. + * + * This is the function pointer type for scroll callbacks. A scroll callback + * function has the following signature: + * @code + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] xoffset The scroll offset along the x-axis. + * @param[in] yoffset The scroll offset along the y-axis. + * + * @sa @ref scrolling + * @sa @ref glfwSetScrollCallback + * + * @since Added in version 3.0. Replaces `GLFWmousewheelfun`. + * + * @ingroup input + */ +typedef void (* GLFWscrollfun)(GLFWwindow* window, double xoffset, double yoffset); + +/*! @brief The function pointer type for keyboard key callbacks. + * + * This is the function pointer type for keyboard key callbacks. A keyboard + * key callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] key The [keyboard key](@ref keys) that was pressed or released. + * @param[in] scancode The system-specific scancode of the key. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. Future + * releases may add more actions. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_key + * @sa @ref glfwSetKeyCallback + * + * @since Added in version 1.0. + * @glfw3 Added window handle, scancode and modifier mask parameters. + * + * @ingroup input + */ +typedef void (* GLFWkeyfun)(GLFWwindow* window, int key, int scancode, int action, int mods); + +/*! @brief The function pointer type for Unicode character callbacks. + * + * This is the function pointer type for Unicode character callbacks. + * A Unicode character callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * + * @sa @ref input_char + * @sa @ref glfwSetCharCallback + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint); + +/*! @brief The function pointer type for Unicode character with modifiers + * callbacks. + * + * This is the function pointer type for Unicode character with modifiers + * callbacks. It is called for each input character, regardless of what + * modifier keys are held down. A Unicode character with modifiers callback + * function has the following signature: + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa @ref input_char + * @sa @ref glfwSetCharModsCallback + * + * @deprecated Scheduled for removal in version 4.0. + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods); + +/*! @brief The function pointer type for path drop callbacks. + * + * This is the function pointer type for path drop callbacks. A path drop + * callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] path_count The number of dropped paths. + * @param[in] paths The UTF-8 encoded file and/or directory path names. + * + * @pointer_lifetime The path array and its strings are valid until the + * callback function returns. + * + * @sa @ref path_drop + * @sa @ref glfwSetDropCallback + * + * @since Added in version 3.1. + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]); + +/*! @brief The function pointer type for monitor configuration callbacks. + * + * This is the function pointer type for monitor configuration callbacks. + * A monitor callback function has the following signature: + * @code + * void function_name(GLFWmonitor* monitor, int event) + * @endcode + * + * @param[in] monitor The monitor that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. + * + * @sa @ref monitor_event + * @sa @ref glfwSetMonitorCallback + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); + +/*! @brief The function pointer type for joystick configuration callbacks. + * + * This is the function pointer type for joystick configuration callbacks. + * A joystick configuration callback function has the following signature: + * @code + * void function_name(int jid, int event) + * @endcode + * + * @param[in] jid The joystick that was connected or disconnected. + * @param[in] event One of `GLFW_CONNECTED` or `GLFW_DISCONNECTED`. Future + * releases may add more events. + * + * @sa @ref joystick_event + * @sa @ref glfwSetJoystickCallback + * + * @since Added in version 3.2. + * + * @ingroup input + */ +typedef void (* GLFWjoystickfun)(int jid, int event); + +/*! @brief Video mode type. + * + * This describes a single video mode. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * @sa @ref glfwGetVideoModes + * + * @since Added in version 1.0. + * @glfw3 Added refresh rate member. + * + * @ingroup monitor + */ +typedef struct GLFWvidmode +{ + /*! The width, in screen coordinates, of the video mode. + */ + int width; + /*! The height, in screen coordinates, of the video mode. + */ + int height; + /*! The bit depth of the red channel of the video mode. + */ + int redBits; + /*! The bit depth of the green channel of the video mode. + */ + int greenBits; + /*! The bit depth of the blue channel of the video mode. + */ + int blueBits; + /*! The refresh rate, in Hz, of the video mode. + */ + int refreshRate; +} GLFWvidmode; + +/*! @brief Gamma ramp. + * + * This describes the gamma ramp for a monitor. + * + * @sa @ref monitor_gamma + * @sa @ref glfwGetGammaRamp + * @sa @ref glfwSetGammaRamp + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +typedef struct GLFWgammaramp +{ + /*! An array of value describing the response of the red channel. + */ + unsigned short* red; + /*! An array of value describing the response of the green channel. + */ + unsigned short* green; + /*! An array of value describing the response of the blue channel. + */ + unsigned short* blue; + /*! The number of elements in each array. + */ + unsigned int size; +} GLFWgammaramp; + +/*! @brief Image data. + * + * This describes a single 2D image. See the documentation for each related + * function what the expected pixel format is. + * + * @sa @ref cursor_custom + * @sa @ref window_icon + * + * @since Added in version 2.1. + * @glfw3 Removed format and bytes-per-pixel members. + * + * @ingroup window + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + +/*! @brief Gamepad input state + * + * This describes the input state of a gamepad. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + * + * @ingroup input + */ +typedef struct GLFWgamepadstate +{ + /*! The states of each [gamepad button](@ref gamepad_buttons), `GLFW_PRESS` + * or `GLFW_RELEASE`. + */ + unsigned char buttons[15]; + /*! The states of each [gamepad axis](@ref gamepad_axes), in the range -1.0 + * to 1.0 inclusive. + */ + float axes[6]; +} GLFWgamepadstate; + + +/************************************************************************* + * GLFW API functions + *************************************************************************/ + +/*! @brief Initializes the GLFW library. + * + * This function initializes the GLFW library. Before most GLFW functions can + * be used, GLFW must be initialized, and before an application terminates GLFW + * should be terminated in order to free any resources allocated during or + * after initialization. + * + * If this function fails, it calls @ref glfwTerminate before returning. If it + * succeeds, you should call @ref glfwTerminate before the application exits. + * + * Additional calls to this function after successful initialization but before + * termination will return `GLFW_TRUE` immediately. + * + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. This can be disabled with the @ref + * GLFW_COCOA_CHDIR_RESOURCES init hint. + * + * @remark @x11 This function will set the `LC_CTYPE` category of the + * application locale according to the current environment if that category is + * still "C". This is because the "C" locale breaks Unicode text input. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwTerminate + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI int glfwInit(void); + +/*! @brief Terminates the GLFW library. + * + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. + * + * If GLFW has been successfully initialized, this function should be called + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. + * + * This function has no effect if GLFW is not initialized. + * + * @errors Possible errors include @ref GLFW_PLATFORM_ERROR. + * + * @remark This function may be called before @ref glfwInit. + * + * @warning The contexts of any remaining windows must not be current on any + * other thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref intro_init + * @sa @ref glfwInit + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwTerminate(void); + +/*! @brief Sets the specified init hint to the desired value. + * + * This function sets hints for the next initialization of GLFW. + * + * The values you set hints to are never reset by GLFW, but they only take + * effect during initialization. Once GLFW has been initialized, any values + * you set will be ignored until the library is terminated and initialized + * again. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [init hint](@ref init_hints) to set. + * @param[in] value The new value of the init hint. + * + * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref + * GLFW_INVALID_VALUE. + * + * @remarks This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa init_hints + * @sa glfwInit + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI void glfwInitHint(int hint, int value); + +/*! @brief Retrieves the version of the GLFW library. + * + * This function retrieves the major, minor and revision numbers of the GLFW + * library. It is intended for when you are using GLFW as a shared library and + * want to ensure that you are using the minimum required version. + * + * Any or all of the version arguments may be `NULL`. + * + * @param[out] major Where to store the major version number, or `NULL`. + * @param[out] minor Where to store the minor version number, or `NULL`. + * @param[out] rev Where to store the revision number, or `NULL`. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersionString + * + * @since Added in version 1.0. + * + * @ingroup init + */ +GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); + +/*! @brief Returns a string describing the compile-time configuration. + * + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. It should not be confused with the OpenGL or OpenGL + * ES version string, queried with `glGetString`. + * + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function provides the version of the running library + * binary in numerical format. + * + * @return The ASCII encoded GLFW version string. + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @pointer_lifetime The returned string is static and compile-time generated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref intro_version + * @sa @ref glfwGetVersion + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI const char* glfwGetVersionString(void); + +/*! @brief Returns and clears the last error for the calling thread. + * + * This function returns and clears the [error code](@ref errors) of the last + * error that occurred on the calling thread, and optionally a UTF-8 encoded + * human-readable description of it. If no error has occurred since the last + * call, it returns @ref GLFW_NO_ERROR (zero) and the description pointer is + * set to `NULL`. + * + * @param[in] description Where to store the error description pointer, or `NULL`. + * @return The last error code for the calling thread, or @ref GLFW_NO_ERROR + * (zero). + * + * @errors None. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * next error occurs or the library is terminated. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref error_handling + * @sa @ref glfwSetErrorCallback + * + * @since Added in version 3.3. + * + * @ingroup init + */ +GLFWAPI int glfwGetError(const char** description); + +/*! @brief Sets the error callback. + * + * This function sets the error callback, which is called with an error code + * and a human-readable description each time a GLFW error occurs. + * + * The error code is set before the callback is called. Calling @ref + * glfwGetError from the error callback will return the same value as the error + * code argument. + * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set. + * + * @callback_signature + * @code + * void callback_name(int error_code, const char* description) + * @endcode + * For more information about the callback parameters, see the + * [callback pointer type](@ref GLFWerrorfun). + * + * @errors None. + * + * @remark This function may be called before @ref glfwInit. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref error_handling + * @sa @ref glfwGetError + * + * @since Added in version 3.0. + * + * @ingroup init + */ +GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun callback); + +/*! @brief Returns the currently connected monitors. + * + * This function returns an array of handles for all currently connected + * monitors. The primary monitor is always first in the returned array. If no + * monitors were found, this function returns `NULL`. + * + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if no monitors were found or + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * monitor configuration changes or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_monitors + * @sa @ref monitor_event + * @sa @ref glfwGetPrimaryMonitor + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); + +/*! @brief Returns the primary monitor. + * + * This function returns the primary monitor. This is usually the monitor + * where elements like the task bar or global menu bar are located. + * + * @return The primary monitor, or `NULL` if no monitors were found or if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @remark The primary monitor is always first in the array returned by @ref + * glfwGetMonitors. + * + * @sa @ref monitor_monitors + * @sa @ref glfwGetMonitors + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); + +/*! @brief Returns the position of the monitor's viewport on the virtual screen. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the specified monitor. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); + +/*! @brief Retrieves the work area of the monitor. + * + * This function returns the position, in screen coordinates, of the upper-left + * corner of the work area of the specified monitor along with the work area + * size in screen coordinates. The work area is defined as the area of the + * monitor not occluded by the operating system task bar where present. If no + * task bar exists then the work area is the monitor resolution in screen + * coordinates. + * + * Any or all of the position and size arguments may be `NULL`. If an error + * occurs, all non-`NULL` position and size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. + * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. + * @param[out] width Where to store the monitor width, or `NULL`. + * @param[out] height Where to store the monitor height, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_workarea + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorWorkarea(GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height); + +/*! @brief Returns the physical size of the monitor. + * + * This function returns the size, in millimetres, of the display area of the + * specified monitor. + * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] monitor The monitor to query. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @win32 On Windows 8 and earlier the physical size is calculated from + * the current resolution and system DPI instead of querying the monitor EDID data. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); + +/*! @brief Retrieves the content scale for the specified monitor. + * + * This function retrieves the content scale for the specified monitor. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. + * + * The content scale may depend on both the monitor resolution and pixel + * density and on user settings. It may be very different from the raw DPI + * calculated from the physical size and current resolution. + * + * @param[in] monitor The monitor to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_scale + * @sa @ref glfwGetWindowContentScale + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, float* yscale); + +/*! @brief Returns the name of the specified monitor. + * + * This function returns a human-readable name, encoded as UTF-8, of the + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. + * + * @param[in] monitor The monitor to query. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); + +/*! @brief Sets the user pointer of the specified monitor. + * + * This function sets the user-defined pointer of the specified monitor. The + * current value is retained until the monitor is disconnected. The initial + * value is `NULL`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * @param[in] monitor The monitor whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwGetMonitorUserPointer + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer); + +/*! @brief Returns the user pointer of the specified monitor. + * + * This function returns the current value of the user-defined pointer of the + * specified monitor. The initial value is `NULL`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * @param[in] monitor The monitor whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwSetMonitorUserPointer + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); + +/*! @brief Sets the monitor configuration callback. + * + * This function sets the monitor configuration callback, or removes the + * currently set callback. This is called when a monitor is connected to or + * disconnected from the system. + * + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWmonitor* monitor, int event) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmonitorfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun callback); + +/*! @brief Returns the available video modes for the specified monitor. + * + * This function returns an array of all video modes supported by the specified + * monitor. The returned array is sorted in ascending order, first by color + * bit depth (the sum of all channel depths), then by resolution area (the + * product of width and height), then resolution width and finally by refresh + * rate. + * + * @param[in] monitor The monitor to query. + * @param[out] count Where to store the number of video modes in the returned + * array. This is set to zero if an error occurred. + * @return An array of video modes, 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 array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected, this function is called again for that monitor or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoMode + * + * @since Added in version 1.0. + * @glfw3 Changed to return an array of modes for a specific monitor. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); + +/*! @brief Returns the current mode of the specified monitor. + * + * This function returns the current video mode of the specified monitor. If + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. + * + * @param[in] monitor The monitor to query. + * @return The current mode of the monitor, 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 array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified monitor is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_modes + * @sa @ref glfwGetVideoModes + * + * @since Added in version 3.0. Replaces `glfwGetDesktopMode`. + * + * @ingroup monitor + */ +GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); + +/*! @brief Generates a gamma ramp and sets it for the specified monitor. + * + * This function generates an appropriately sized gamma ramp from the specified + * exponent and then calls @ref glfwSetGammaRamp with it. The value must be + * a finite number greater than zero. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] gamma The desired exponent. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); + +/*! @brief Returns the current gamma ramp for the specified monitor. + * + * This function returns the current gamma ramp of the specified monitor. + * + * @param[in] monitor The monitor to query. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while + * returning `NULL`. + * + * @pointer_lifetime The returned structure and its arrays are allocated and + * freed by GLFW. You should not free them yourself. They are valid until the + * specified monitor is disconnected, this function is called again for that + * monitor or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); + +/*! @brief Sets the current gamma ramp for the specified monitor. + * + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. + * + * The software controlled gamma ramp is applied _in addition_ to the hardware + * gamma correction, which today is usually an approximation of sRGB gamma. + * This means that setting a perfectly linear ramp, or gamma 1.0, will produce + * the default (usually sRGB-like) behavior. + * + * For gamma correct rendering with OpenGL or OpenGL ES, see the @ref + * GLFW_SRGB_CAPABLE hint. + * + * @param[in] monitor The monitor whose gamma ramp to set. + * @param[in] ramp The gamma ramp to use. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The size of the specified gamma ramp should match the size of the + * current ramp for that monitor. + * + * @remark @win32 The gamma ramp size must be 256. + * + * @remark @wayland Gamma handling is a privileged protocol, this function + * will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified gamma ramp is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in version 3.0. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); + +/*! @brief Resets all window hints to their default values. + * + * This function resets all window hints to their + * [default values](@ref window_hints_values). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHint + * @sa @ref glfwWindowHintString + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwDefaultWindowHints(void); + +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only integer value hints can be set with this function. String value hints + * are set with @ref glfwWindowHintString. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHintString + * @sa @ref glfwDefaultWindowHints + * + * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. + * + * @ingroup window + */ +GLFWAPI void glfwWindowHint(int hint, int value); + +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only string type hints can be set with this function. Integer value hints + * are set with @ref glfwWindowHint. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @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 window_hints + * @sa @ref glfwWindowHint + * @sa @ref glfwDefaultWindowHints + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwWindowHintString(int hint, const char* value); + +/*! @brief Creates a window and its associated context. + * + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). + * + * Successful creation does not change which context is current. Before you + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. + * + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are + * [hard constraints](@ref window_hints_hard). This includes the size of the + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, see @ref + * glfwGetWindowAttrib, @ref glfwGetWindowSize and @ref glfwGetFramebufferSize. + * + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, the window will be windowed mode. + * Unless you have a way for the user to choose a specific monitor, it is + * recommended that you pick the primary monitor. For more information on how + * to query connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window is not + * iconified, the supported video mode most closely matching the desired video + * mode is set for the specified monitor. For more information about full + * screen windows, including the creation of so called _windowed full screen_ + * or _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * Once you have created the window, you can switch it between windowed and + * full screen mode with @ref glfwSetWindowMonitor. This will not affect its + * OpenGL or OpenGL ES context. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * As long as at least one full screen window is not iconified, the screensaver + * is prohibited from starting. + * + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. + * + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. + * + * @param[in] width The desired width, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] height The desired height, in screen coordinates, of the window. + * This must be greater than zero. + * @param[in] title The initial, UTF-8 encoded window title. + * @param[in] monitor The monitor to use for full screen mode, or `NULL` for + * windowed mode. + * @param[in] share The window whose context to share resources with, or `NULL` + * to not share resources. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref + * GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @win32 Window creation will fail if the Microsoft GDI software + * OpenGL implementation is the only one available. + * + * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it + * will be set as the initial icon for the window. If no such icon is present, + * the `IDI_APPLICATION` icon will be used instead. To set a different icon, + * see @ref glfwSetWindowIcon. + * + * @remark @win32 The context to share resources with must not be current on + * any other thread. + * + * @remark @macos The OS only supports forward-compatible core profile contexts + * for OpenGL versions 3.2 and later. Before creating an OpenGL context of + * version 3.2 or later you must set the + * [GLFW_OPENGL_FORWARD_COMPAT](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) and + * [GLFW_OPENGL_PROFILE](@ref GLFW_OPENGL_PROFILE_hint) hints accordingly. + * OpenGL 3.0 and 3.1 contexts are not supported at all on macOS. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, but the dock icon will be the same as the application bundle's icon. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @macos The first time a window is created the menu bar is created. + * If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu + * bar. Otherwise a minimal menu bar is created manually with common commands + * like Hide, Quit and About. The About entry opens a minimal about dialog + * with information from the application's bundle. Menu bar creation can be + * disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint. + * + * @remark @macos On OS X 10.10 and later the window frame will not be rendered + * at full resolution on Retina displays unless the + * [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint) + * hint is `GLFW_TRUE` and the `NSHighResolutionCapable` key is enabled in the + * application bundle's `Info.plist`. For more information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. The GLFW test and example programs use + * a custom `Info.plist` template for this, which can be found as + * `CMake/MacOSXBundleInfo.plist.in` in the source tree. + * + * @remark @macos When activating frame autosaving with + * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified + * window size and position may be overridden by previously saved values. + * + * @remark @x11 Some window managers will not respect the placement of + * initially hidden windows. + * + * @remark @x11 Due to the asynchronous nature of X11, it may take a moment for + * a window to reach its requested state. This means you may not be able to + * query the final size, position or other attributes directly after window + * creation. + * + * @remark @x11 The class part of the `WM_CLASS` window property will by + * default be set to the window title passed to this function. The instance + * part will use the contents of the `RESOURCE_NAME` environment variable, if + * present and not empty, or fall back to the window title. Set the + * [GLFW_X11_CLASS_NAME](@ref GLFW_X11_CLASS_NAME_hint) and + * [GLFW_X11_INSTANCE_NAME](@ref GLFW_X11_INSTANCE_NAME_hint) window hints to + * override this. + * + * @remark @wayland Compositors should implement the xdg-decoration protocol + * for GLFW to decorate the window properly. If this protocol isn't + * supported, or if the compositor prefers client-side decorations, a very + * simple fallback frame will be drawn using the wp_viewporter protocol. A + * compositor can still emit close, maximize or fullscreen events, using for + * instance a keybind mechanism. If neither of these protocols is supported, + * the window won't be decorated. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size or refresh rate. + * + * @remark @wayland Screensaver inhibition requires the idle-inhibit protocol + * to be implemented in the user's compositor. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwDestroyWindow + * + * @since Added in version 3.0. Replaces `glfwOpenWindow`. + * + * @ingroup window + */ +GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); + +/*! @brief Destroys the specified window and its context. + * + * This function destroys the specified window and its context. On calling + * this function, no further callbacks will be called for that window. + * + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. + * + * @param[in] window The window to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @note The context of the specified window must not be current on any other + * thread when this function is called. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_creation + * @sa @ref glfwCreateWindow + * + * @since Added in version 3.0. Replaces `glfwCloseWindow`. + * + * @ingroup window + */ +GLFWAPI void glfwDestroyWindow(GLFWwindow* window); + +/*! @brief Checks the close flag of the specified window. + * + * This function returns the value of the close flag of the specified window. + * + * @param[in] window The window to query. + * @return The value of the close flag. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); + +/*! @brief Sets the close flag of the specified window. + * + * This function sets the value of the close flag of the specified window. + * This can be used to override the user's attempt to close the window, or + * to signal that it should be closed. + * + * @param[in] window The window whose flag to change. + * @param[in] value The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_close + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); + +/*! @brief Sets the title of the specified window. + * + * This function sets the window title, encoded as UTF-8, of the specified + * window. + * + * @param[in] window The window whose title to change. + * @param[in] title The UTF-8 encoded window title. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos The window title will not be updated until the next time you + * process events. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); + +/*! @brief Sets the icon for the specified window. + * + * This function sets the icon of the specified window. If passed an array of + * candidate images, those of or closest to the sizes desired by the system are + * selected. If no images are specified, the window reverts to its default + * icon. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The desired image sizes varies depending on platform and system settings. + * The selected images will be rescaled as needed. Good sizes include 16x16, + * 32x32 and 48x48. + * + * @param[in] window The window whose icon to set. + * @param[in] count The number of images in the specified array, or zero to + * revert to the default window icon. + * @param[in] images The images to create the icon from. This is ignored if + * count is zero. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The specified image data is copied before this function + * returns. + * + * @remark @macos The GLFW window has no icon, as it is not a document + * window, so this function does nothing. The dock icon will be the same as + * the application bundle's icon. For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remark @wayland There is no existing protocol to change an icon, the + * window will thus inherit the one defined in the application's desktop file. + * This function always emits @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_icon + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowIcon(GLFWwindow* window, int count, const GLFWimage* images); + +/*! @brief Retrieves the position of the content area of the specified window. + * + * This function retrieves the position, in screen coordinates, of the + * upper-left corner of the content area of the specified window. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The window to query. + * @param[out] xpos Where to store the x-coordinate of the upper-left corner of + * the content area, or `NULL`. + * @param[out] ypos Where to store the y-coordinate of the upper-left corner of + * the content area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to retrieve the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwSetWindowPos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); + +/*! @brief Sets the position of the content area of the specified window. + * + * This function sets the position, in screen coordinates, of the upper-left + * corner of the content area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. + * + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. + * + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. + * + * @param[in] window The window to query. + * @param[in] xpos The x-coordinate of the upper-left corner of the content area. + * @param[in] ypos The y-coordinate of the upper-left corner of the content area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no way for an application to set the global + * position of its windows, this function will always emit @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * @sa @ref glfwGetWindowPos + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); + +/*! @brief Retrieves the size of the content area of the specified window. + * + * This function retrieves the size, in screen coordinates, of the content area + * of the specified window. If you wish to retrieve the size of the + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose size to retrieve. + * @param[out] width Where to store the width, in screen coordinates, of the + * content area, or `NULL`. + * @param[out] height Where to store the height, in screen coordinates, of the + * content area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwSetWindowSize + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Sets the size limits of the specified window. + * + * This function sets the size limits of the content area of the specified + * window. If the window is full screen, the size limits only take effect + * once it is made windowed. If the window is not resizable, this function + * does nothing. + * + * The size limits are applied immediately to a windowed mode window and may + * cause it to be resized. + * + * The maximum dimensions must be greater than or equal to the minimum + * dimensions and all must be greater than or equal to zero. + * + * @param[in] window The window to set limits for. + * @param[in] minwidth The minimum width, in screen coordinates, of the content + * area, or `GLFW_DONT_CARE`. + * @param[in] minheight The minimum height, in screen coordinates, of the + * content area, or `GLFW_DONT_CARE`. + * @param[in] maxwidth The maximum width, in screen coordinates, of the content + * area, or `GLFW_DONT_CARE`. + * @param[in] maxheight The maximum height, in screen coordinates, of the + * content area, or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The size limits will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowAspectRatio + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSizeLimits(GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight); + +/*! @brief Sets the aspect ratio of the specified window. + * + * This function sets the required aspect ratio of the content area of the + * specified window. If the window is full screen, the aspect ratio only takes + * effect once it is made windowed. If the window is not resizable, this + * function does nothing. + * + * The aspect ratio is specified as a numerator and a denominator and both + * values must be greater than zero. For example, the common 16:9 aspect ratio + * is specified as 16 and 9, respectively. + * + * If the numerator and denominator is set to `GLFW_DONT_CARE` then the aspect + * ratio limit is disabled. + * + * The aspect ratio is applied immediately to a windowed mode window and may + * cause it to be resized. + * + * @param[in] window The window to set limits for. + * @param[in] numer The numerator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * @param[in] denom The denominator of the desired aspect ratio, or + * `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark If you set size limits and an aspect ratio that conflict, the + * results are undefined. + * + * @remark @wayland The aspect ratio will not be applied until the window is + * actually resized, either by the user or by the compositor. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_sizelimits + * @sa @ref glfwSetWindowSizeLimits + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAspectRatio(GLFWwindow* window, int numer, int denom); + +/*! @brief Sets the size of the content area of the specified window. + * + * This function sets the size, in screen coordinates, of the content area of + * the specified window. + * + * For full screen windows, this function updates the resolution of its desired + * video mode and switches to the video mode closest to it, without affecting + * the window's context. As the context is unaffected, the bit depths of the + * framebuffer remain unchanged. + * + * If you wish to update the refresh rate of the desired video mode in addition + * to its resolution, see @ref glfwSetWindowMonitor. + * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * + * @param[in] window The window to resize. + * @param[in] width The desired width, in screen coordinates, of the window + * content area. + * @param[in] height The desired height, in screen coordinates, of the window + * content area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland A full screen window will not attempt to change the mode, + * no matter what the requested size. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * @sa @ref glfwGetWindowSize + * @sa @ref glfwSetWindowMonitor + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); + +/*! @brief Retrieves the size of the framebuffer of the specified window. + * + * This function retrieves the size, in pixels, of the framebuffer of the + * specified window. If you wish to retrieve the size of the window in screen + * coordinates, see @ref glfwGetWindowSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose framebuffer to query. + * @param[out] width Where to store the width, in pixels, of the framebuffer, + * or `NULL`. + * @param[out] height Where to store the height, in pixels, of the framebuffer, + * or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * @sa @ref glfwSetFramebufferSizeCallback + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); + +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + +/*! @brief Retrieves the content scale for the specified window. + * + * This function retrieves the content scale for the specified window. The + * content scale is the ratio between the current DPI and the platform's + * default DPI. This is especially important for text and any UI elements. If + * the pixel dimensions of your UI scaled by this look appropriate on your + * machine then it should appear at a reasonable size on other machines + * regardless of their DPI and scaling settings. This relies on the system DPI + * and scaling settings being somewhat correct. + * + * On systems where each monitors can have its own content scale, the window + * content scale will depend on which monitor the system considers the window + * to be on. + * + * @param[in] window The window to query. + * @param[out] xscale Where to store the x-axis content scale, or `NULL`. + * @param[out] yscale Where to store the y-axis content scale, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback + * @sa @ref glfwGetMonitorContentScale + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); + +/*! @brief Returns the opacity of the whole window. + * + * This function returns the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. If the system + * does not support whole window transparency, this function always returns one. + * + * The initial opacity value for newly created windows is one. + * + * @param[in] window The window to query. + * @return The opacity value of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwSetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); + +/*! @brief Sets the opacity of the whole window. + * + * This function sets the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. + * + * The initial opacity value for newly created windows is one. + * + * A window created with framebuffer transparency may not use whole window + * transparency. The results of doing this are undefined. + * + * @param[in] window The window to set the opacity for. + * @param[in] opacity The desired opacity of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwGetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); + +/*! @brief Iconifies the specified window. + * + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. + * + * @param[in] window The window to iconify. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland There is no concept of iconification in wl_shell, this + * function will emit @ref GLFW_PLATFORM_ERROR when using this deprecated + * protocol. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwRestoreWindow + * @sa @ref glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwIconifyWindow(GLFWwindow* window); + +/*! @brief Restores the specified window. + * + * This function restores the specified window if it was previously iconified + * (minimized) or maximized. If the window is already restored, this function + * does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. + * + * @param[in] window The window to restore. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwMaximizeWindow + * + * @since Added in version 2.1. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwRestoreWindow(GLFWwindow* window); + +/*! @brief Maximizes the specified window. + * + * This function maximizes the specified window if it was previously not + * maximized. If the window is already maximized, this function does nothing. + * + * If the specified window is a full screen window, this function does nothing. + * + * @param[in] window The window to maximize. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * @sa @ref glfwIconifyWindow + * @sa @ref glfwRestoreWindow + * + * @since Added in GLFW 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwMaximizeWindow(GLFWwindow* window); + +/*! @brief Makes the specified window visible. + * + * This function makes the specified window visible if it was previously + * hidden. If the window is already visible or is in full screen mode, this + * function does nothing. + * + * By default, windowed mode windows are focused when shown + * Set the [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) window hint + * to change this behavior for all newly created windows, or change the + * behavior for an existing window with @ref glfwSetWindowAttrib. + * + * @param[in] window The window to make visible. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland Because Wayland wants every frame of the desktop to be + * complete, this function does not immediately make the window visible. + * Instead it will become visible the next time the window framebuffer is + * updated after this call. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwHideWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwShowWindow(GLFWwindow* window); + +/*! @brief Hides the specified window. + * + * This function hides the specified window if it was previously visible. If + * the window is already hidden or is in full screen mode, this function does + * nothing. + * + * @param[in] window The window to hide. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hide + * @sa @ref glfwShowWindow + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwHideWindow(GLFWwindow* window); + +/*! @brief Brings the specified window to front and sets input focus. + * + * This function brings the specified window to front and sets input focus. + * The window should already be visible and not iconified. + * + * By default, both windowed and full screen mode windows are focused when + * initially created. Set the [GLFW_FOCUSED](@ref GLFW_FOCUSED_hint) to + * disable this behavior. + * + * Also by default, windowed mode windows are focused when shown + * with @ref glfwShowWindow. Set the + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_hint) to disable this behavior. + * + * __Do not use this function__ to steal focus from other applications unless + * you are certain that is what the user wants. Focus stealing can be + * extremely disruptive. + * + * For a less disruptive way of getting the user's attention, see + * [attention requests](@ref window_attention). + * + * @param[in] window The window to give input focus. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland It is not possible for an application to bring its windows + * to front, this function will always emit @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * @sa @ref window_attention + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwFocusWindow(GLFWwindow* window); + +/*! @brief Requests user attention to the specified window. + * + * This function requests user attention to the specified window. On + * platforms where this is not supported, attention is requested to the + * application as a whole. + * + * Once the user has given attention, usually by focusing the window or + * application, the system will end the request automatically. + * + * @param[in] window The window to request attention to. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos Attention is requested to the application as a whole, not the + * specific window. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attention + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); + +/*! @brief Returns the monitor that the window uses for full screen mode. + * + * This function returns the handle of the monitor that the specified window is + * in full screen on. + * + * @param[in] window The window to query. + * @return The monitor, or `NULL` if the window is in windowed mode or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref glfwSetWindowMonitor + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); + +/*! @brief Sets the mode, monitor, video mode and placement of a window. + * + * This function sets the monitor that the window uses for full screen mode or, + * if the monitor is `NULL`, makes it windowed mode. + * + * When setting a monitor, this function updates the width, height and refresh + * rate of the desired video mode and switches to the video mode closest to it. + * The window position is ignored when setting a monitor. + * + * When the monitor is `NULL`, the position, width and height are used to + * place the window content area. The refresh rate is ignored when no monitor + * is specified. + * + * If you only wish to update the resolution of a full screen window or the + * size of a windowed mode window, see @ref glfwSetWindowSize. + * + * When a window transitions from full screen to windowed mode, this function + * restores any previous window settings such as whether it is decorated, + * floating, resizable, has size or aspect ratio limits, etc. + * + * @param[in] window The window whose monitor, size or video mode to set. + * @param[in] monitor The desired monitor, or `NULL` to set windowed mode. + * @param[in] xpos The desired x-coordinate of the upper-left corner of the + * content area. + * @param[in] ypos The desired y-coordinate of the upper-left corner of the + * content area. + * @param[in] width The desired with, in screen coordinates, of the content + * area or video mode. + * @param[in] height The desired height, in screen coordinates, of the content + * area or video mode. + * @param[in] refreshRate The desired refresh rate, in Hz, of the video mode, + * or `GLFW_DONT_CARE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The OpenGL or OpenGL ES context will not be destroyed or otherwise + * affected by any resizing or mode switching, although you may need to update + * your viewport if the framebuffer size has changed. + * + * @remark @wayland The desired window position is ignored, as there is no way + * for an application to set this property. + * + * @remark @wayland Setting the window to full screen will not attempt to + * change the mode, no matter what the requested size or refresh rate. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_monitor + * @sa @ref window_full_screen + * @sa @ref glfwGetWindowMonitor + * @sa @ref glfwSetWindowSize + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate); + +/*! @brief Returns an attribute of the specified window. + * + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. + * + * @param[in] window The window to query. + * @param[in] attrib The [window attribute](@ref window_attribs) whose value to + * return. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @remark Framebuffer related hints are not window attributes. See @ref + * window_attribs_fb for more information. + * + * @remark Zero is a valid value for many window and context related + * attributes so you cannot use a return value of zero as an indication of + * errors. However, this function should not fail as long as it is passed + * valid arguments and the library has been [initialized](@ref intro_init). + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwSetWindowAttrib + * + * @since Added in version 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. + * + * @ingroup window + */ +GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); + +/*! @brief Sets an attribute of the specified window. + * + * This function sets the value of an attribute of the specified window. + * + * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), + * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), + * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib), + * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib) and + * [GLFW_FOCUS_ON_SHOW](@ref GLFW_FOCUS_ON_SHOW_attrib). + * + * Some of these attributes are ignored for full screen windows. The new + * value will take effect if the window is later made windowed. + * + * Some of these attributes are ignored for windowed mode windows. The new + * value will take effect if the window is later made full screen. + * + * @param[in] window The window to set the attribute for. + * @param[in] attrib A supported window attribute. + * @param[in] value `GLFW_TRUE` or `GLFW_FALSE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @remark Calling @ref glfwGetWindowAttrib will always return the latest + * value, even if that value is ignored by the current mode of the window. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_attribs + * @sa @ref glfwGetWindowAttrib + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowAttrib(GLFWwindow* window, int attrib, int value); + +/*! @brief Sets the user pointer of the specified window. + * + * This function sets the user-defined pointer of the specified window. The + * current value is retained until the window is destroyed. The initial value + * is `NULL`. + * + * @param[in] window The window whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwGetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); + +/*! @brief Returns the user pointer of the specified window. + * + * This function returns the current value of the user-defined pointer of the + * specified window. The initial value is `NULL`. + * + * @param[in] window The window whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref window_userptr + * @sa @ref glfwSetWindowUserPointer + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); + +/*! @brief Sets the position callback for the specified window. + * + * This function sets the position callback of the specified window, which is + * called when the window is moved. The callback is provided with the + * position, in screen coordinates, of the upper-left corner of the content + * area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int xpos, int ypos) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowposfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland This callback will never be called, as there is no way for + * an application to know its global position. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindowposfun callback); + +/*! @brief Sets the size callback for the specified window. + * + * This function sets the size callback of the specified window, which is + * called when the window is resized. The callback is provided with the size, + * in screen coordinates, of the content area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowsizefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwindowsizefun callback); + +/*! @brief Sets the close callback for the specified window. + * + * This function sets the close callback of the specified window, which is + * called when the user attempts to close the window, for example by clicking + * the close widget in the title bar. + * + * The close flag is set before this callback is called, but you can modify it + * at any time with @ref glfwSetWindowShouldClose. + * + * The close callback is not triggered by @ref glfwDestroyWindow. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowclosefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @macos Selecting Quit from the application menu will trigger the + * close callback for all windows. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun callback); + +/*! @brief Sets the refresh callback for the specified window. + * + * This function sets the refresh callback of the specified window, which is + * called when the content area of the window needs to be redrawn, for example + * if the window has been exposed after having been covered by another window. + * + * On compositing window systems such as Aero, Compiz, Aqua or Wayland, where + * the window contents are saved off-screen, this callback may be called only + * very infrequently or never at all. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window); + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowrefreshfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in version 2.5. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup window + */ +GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GLFWwindowrefreshfun callback); + +/*! @brief Sets the focus callback for the specified window. + * + * This function sets the focus callback of the specified window, which is + * called when the window gains or loses input focus. + * + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int focused) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowfocusfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwindowfocusfun callback); + +/*! @brief Sets the iconify callback for the specified window. + * + * This function sets the iconification callback of the specified window, which + * is called when the window is iconified or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int iconified) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowiconifyfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland The wl_shell protocol has no concept of iconification, + * this callback will never be called when using this deprecated protocol. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GLFWwindowiconifyfun callback); + +/*! @brief Sets the maximize callback for the specified window. + * + * This function sets the maximization callback of the specified window, which + * is called when the window is maximized or restored. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int maximized) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowmaximizefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_maximize + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, GLFWwindowmaximizefun callback); + +/*! @brief Sets the framebuffer resize callback for the specified window. + * + * This function sets the framebuffer resize callback of the specified window, + * which is called when the framebuffer of the specified window is resized. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int width, int height) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWframebuffersizefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in version 3.0. + * + * @ingroup window + */ +GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun callback); + +/*! @brief Sets the window content scale callback for the specified window. + * + * This function sets the window content scale callback of the specified window, + * which is called when the content scale of the specified window changes. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, float xscale, float yscale) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWwindowcontentscalefun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwGetWindowContentScale + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun callback); + +/*! @brief Processes all pending events. + * + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 1.0. + * + * @ingroup window + */ +GLFWAPI void glfwPollEvents(void); + +/*! @brief Waits until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 2.5. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEvents(void); + +/*! @brief Waits with timeout until events are queued and processes them. + * + * This function puts the calling thread to sleep until at least one event is + * available in the event queue, or until the specified timeout is reached. If + * one or more events are available, it behaves exactly like @ref + * glfwPollEvents, i.e. the events in the queue are processed and the function + * then returns immediately. Processing events will cause the window and input + * callbacks associated with those events to be called. + * + * The timeout value must be a positive finite number. + * + * Since not all events are associated with callbacks, this function may return + * without a callback having been called even if you are monitoring all + * callbacks. + * + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. + * + * Do not assume that callbacks you set will _only_ be called in response to + * event processing functions like this one. While it is necessary to poll for + * events, window systems that require GLFW to register callbacks of its own + * can pass events to GLFW in response to many window system function calls. + * GLFW will pass those events on to the application callbacks before + * returning. + * + * Event processing is not required for joystick input to work. + * + * @param[in] timeout The maximum amount of time, in seconds, to wait. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref events + * @sa @ref glfwPollEvents + * @sa @ref glfwWaitEvents + * + * @since Added in version 3.2. + * + * @ingroup window + */ +GLFWAPI void glfwWaitEventsTimeout(double timeout); + +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref events + * @sa @ref glfwWaitEvents + * @sa @ref glfwWaitEventsTimeout + * + * @since Added in version 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + +/*! @brief Returns the value of an input option for the specified window. + * + * This function returns the value of an input option for the specified window. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. + * + * @param[in] window The window to query. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref glfwSetInputMode + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); + +/*! @brief Sets an input option for the specified window. + * + * This function sets an input mode option for the specified window. The mode + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS, @ref GLFW_LOCK_KEY_MODS or + * @ref GLFW_RAW_MOUSE_MOTION. + * + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor + * modes: + * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. + * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the + * content area of the window but does not restrict the cursor from leaving. + * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual + * and unlimited cursor movement. This is useful for implementing for + * example 3D camera controls. + * + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to + * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GLFW_TRUE` to enable sticky mouse buttons, or `GLFW_FALSE` to disable it. + * If sticky mouse buttons are enabled, a mouse button press will ensure that + * @ref glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even + * if the mouse button had been released before the call. This is useful when + * you are only interested in whether mouse buttons have been pressed but not + * when or in which order. + * + * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to + * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, + * callbacks that receive modifier bits will also have the @ref + * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, + * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. + * + * If the mode is `GLFW_RAW_MOUSE_MOTION`, the value must be either `GLFW_TRUE` + * to enable raw (unscaled and unaccelerated) mouse motion when the cursor is + * disabled, or `GLFW_FALSE` to disable it. If raw motion is not supported, + * attempting to set this will emit @ref GLFW_PLATFORM_ERROR. Call @ref + * glfwRawMouseMotionSupported to check for support. + * + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS`, `GLFW_LOCK_KEY_MODS` or + * `GLFW_RAW_MOUSE_MOTION`. + * @param[in] value The new value of the specified input mode. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref glfwGetInputMode + * + * @since Added in version 3.0. Replaces `glfwEnable` and `glfwDisable`. + * + * @ingroup input + */ +GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); + +/*! @brief Returns whether raw mouse motion is supported. + * + * This function returns whether raw mouse motion is supported on the current + * system. This status does not change after GLFW has been initialized so you + * only need to check this once. If you attempt to enable raw motion on + * a system that does not support it, @ref GLFW_PLATFORM_ERROR will be emitted. + * + * Raw mouse motion is closer to the actual motion of the mouse across + * a surface. It is not affected by the scaling and acceleration applied to + * the motion of the desktop cursor. That processing is suitable for a cursor + * while raw motion is better for controlling for example a 3D camera. Because + * of this, raw mouse motion is only provided when the cursor is disabled. + * + * @return `GLFW_TRUE` if raw mouse motion is supported on the current machine, + * or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref raw_mouse_motion + * @sa @ref glfwSetInputMode + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwRawMouseMotionSupported(void); + +/*! @brief Returns the layout-specific name of the specified printable key. + * + * This function returns the name of the specified printable key, encoded as + * UTF-8. This is typically the character that key would produce without any + * modifier keys, intended for displaying key bindings to the user. For dead + * keys, it is typically the diacritic it would add to a character. + * + * __Do not use this function__ for [text input](@ref input_char). You will + * break text input for many languages even if it happens to work for yours. + * + * If the key is `GLFW_KEY_UNKNOWN`, the scancode is used to identify the key, + * otherwise the scancode is ignored. If you specify a non-printable key, or + * `GLFW_KEY_UNKNOWN` and a scancode that maps to a non-printable key, this + * function returns `NULL` but does not emit an error. + * + * This behavior allows you to always pass in the arguments in the + * [key callback](@ref input_key) without modification. + * + * The printable keys are: + * - `GLFW_KEY_APOSTROPHE` + * - `GLFW_KEY_COMMA` + * - `GLFW_KEY_MINUS` + * - `GLFW_KEY_PERIOD` + * - `GLFW_KEY_SLASH` + * - `GLFW_KEY_SEMICOLON` + * - `GLFW_KEY_EQUAL` + * - `GLFW_KEY_LEFT_BRACKET` + * - `GLFW_KEY_RIGHT_BRACKET` + * - `GLFW_KEY_BACKSLASH` + * - `GLFW_KEY_WORLD_1` + * - `GLFW_KEY_WORLD_2` + * - `GLFW_KEY_0` to `GLFW_KEY_9` + * - `GLFW_KEY_A` to `GLFW_KEY_Z` + * - `GLFW_KEY_KP_0` to `GLFW_KEY_KP_9` + * - `GLFW_KEY_KP_DECIMAL` + * - `GLFW_KEY_KP_DIVIDE` + * - `GLFW_KEY_KP_MULTIPLY` + * - `GLFW_KEY_KP_SUBTRACT` + * - `GLFW_KEY_KP_ADD` + * - `GLFW_KEY_KP_EQUAL` + * + * Names for printable keys depend on keyboard layout, while names for + * non-printable keys are the same across layouts but depend on the application + * language and should be localized along with other user interface text. + * + * @param[in] key The key to query, or `GLFW_KEY_UNKNOWN`. + * @param[in] scancode The scancode of the key to query. + * @return The UTF-8 encoded, layout-specific name of the key, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark The contents of the returned string may change when a keyboard + * layout change event is received. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key_name + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetKeyName(int key, int scancode); + +/*! @brief Returns the platform-specific scancode of the specified key. + * + * This function returns the platform-specific scancode of the specified key. + * + * If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this + * method will return `-1`. + * + * @param[in] key Any [named key](@ref keys). + * @return The platform-specific scancode for the key, or `-1` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref input_key + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwGetKeyScancode(int key); + +/*! @brief Returns the last reported state of a keyboard key for the specified + * window. + * + * This function returns the last state reported for the specified key to the + * specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to + * the key callback. + * + * If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. + * + * The key functions deal with physical keys, with [key tokens](@ref keys) + * named after their use on the standard US keyboard layout. If you want to + * input text, use the Unicode character callback instead. + * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * + * __Do not use this function__ to implement [text input](@ref input_char). + * + * @param[in] window The desired window. + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetKey(GLFWwindow* window, int key); + +/*! @brief Returns the last reported state of a mouse button for the specified + * window. + * + * This function returns the last state reported for the specified mouse button + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. + * + * If the @ref GLFW_STICKY_MOUSE_BUTTONS input mode is enabled, this function + * returns `GLFW_PRESS` the first time you call it for a mouse button that was + * pressed, even if that mouse button has already been released. + * + * @param[in] window The desired window. + * @param[in] button The desired [mouse button](@ref buttons). + * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup input + */ +GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); + +/*! @brief Retrieves the position of the cursor relative to the content area of + * the window. + * + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the content area of the specified + * window. + * + * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor + * position is unbounded and limited only by the minimum and maximum values of + * a `double`. + * + * The coordinate can be converted to their integer equivalents with the + * `floor` function. Casting directly to an integer type works for positive + * coordinates, but fails for negative ones. + * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * + * @param[in] window The desired window. + * @param[out] xpos Where to store the cursor x-coordinate, relative to the + * left edge of the content area, or `NULL`. + * @param[out] ypos Where to store the cursor y-coordinate, relative to the to + * top edge of the content area, or `NULL`. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwSetCursorPos + * + * @since Added in version 3.0. Replaces `glfwGetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); + +/*! @brief Sets the position of the cursor, relative to the content area of the + * window. + * + * This function sets the position, in screen coordinates, of the cursor + * relative to the upper-left corner of the content area of the specified + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. + * + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of + * a `double`. + * + * @param[in] window The desired window. + * @param[in] xpos The desired x-coordinate, relative to the left edge of the + * content area. + * @param[in] ypos The desired y-coordinate, relative to the top edge of the + * content area. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @wayland This function will only work when the cursor mode is + * `GLFW_CURSOR_DISABLED`, otherwise it will do nothing. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * @sa @ref glfwGetCursorPos + * + * @since Added in version 3.0. Replaces `glfwSetMousePos`. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); + +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit, little-endian, non-premultiplied RGBA, i.e. eight + * bits per channel with the red channel first. They are arranged canonically + * as packed sequential rows, starting from the top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * @return The handle of the created cursor, 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 specified image data is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwDestroyCursor + * @sa @ref glfwCreateStandardCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * If the specified cursor is current for any window, that window will be + * reverted to the default cursor. This does not affect the cursor mode. + * + * @param[in] cursor The cursor object to destroy. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @reentrancy This function must not be called from a callback. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * @sa @ref glfwCreateCursor + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * content area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + +/*! @brief Sets the key callback. + * + * This function sets the key callback of the specified window, which is called + * when a key is pressed, repeated or released. + * + * The key functions deal with physical keys, with layout independent + * [key tokens](@ref keys) named after their values in the standard US keyboard + * layout. If you want to input text, use the + * [character callback](@ref glfwSetCharCallback) instead. + * + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * The scancode of a key is specific to that platform or sometimes even to that + * machine. Scancodes are intended to allow users to bind keys that don't have + * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their + * state is not saved and so it cannot be queried with @ref glfwGetKey. + * + * Sometimes GLFW needs to generate synthetic key events, in which case the + * scancode may be zero. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new key callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int key, int scancode, int action, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWkeyfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun callback); + +/*! @brief Sets the Unicode character callback. + * + * This function sets the character callback of the specified window, which is + * called when a Unicode character is input. + * + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on macOS or Alt key + * on Windows. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 2.4. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun callback); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the + * [key callback](@ref glfwSetKeyCallback) instead. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * [error](@ref error_handling) occurred. + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, unsigned int codepoint, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcharmodsfun). + * + * @deprecated Scheduled for removal in version 4.0. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun callback); + +/*! @brief Sets the mouse button callback. + * + * This function sets the mouse button callback of the specified window, which + * is called when a mouse button is pressed or released. + * + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int button, int action, int mods) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWmousebuttonfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter and return value. + * + * @ingroup input + */ +GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmousebuttonfun callback); + +/*! @brief Sets the cursor position callback. + * + * This function sets the cursor position callback of the specified window, + * which is called when the cursor is moved. The callback is provided with the + * position, in screen coordinates, relative to the upper-left corner of the + * content area of the window. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double xpos, double ypos); + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorposfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in version 3.0. Replaces `glfwSetMousePosCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursorposfun callback); + +/*! @brief Sets the cursor enter/leave callback. + * + * This function sets the cursor boundary crossing callback of the specified + * window, which is called when the cursor enters or leaves the content area of + * the window. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int entered) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWcursorenterfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcursorenterfun callback); + +/*! @brief Sets the scroll callback. + * + * This function sets the scroll callback of the specified window, which is + * called when a scrolling device is used, such as a mouse wheel or scrolling + * area of a touchpad. + * + * The scroll callback receives all scrolling input, like that from a mouse + * wheel or a touchpad scrolling area. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new scroll callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, double xoffset, double yoffset) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWscrollfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in version 3.0. Replaces `glfwSetMouseWheelCallback`. + * + * @ingroup input + */ +GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback); + +/*! @brief Sets the path drop callback. + * + * This function sets the path drop callback of the specified window, which is + * called when one or more dragged paths are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, int path_count, const char* paths[]) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWdropfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @remark @wayland File drop is currently unimplemented. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in version 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback); + +/*! @brief Returns whether the specified joystick is present. + * + * This function returns whether the specified joystick is present. + * + * There is no need to call this function before other functions that accept + * a joystick ID, as they all check for presence before performing any other + * work. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if the joystick is present, or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in version 3.0. Replaces `glfwGetJoystickParam`. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickPresent(int jid); + +/*! @brief Returns the values of all axes of the specified joystick. + * + * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of axis values, or `NULL` if the joystick is not present or + * an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_axis + * + * @since Added in version 3.0. Replaces `glfwGetJoystickPos`. + * + * @ingroup input + */ +GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count); + +/*! @brief Returns the state of all buttons of the specified joystick. + * + * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. + * + * For backward compatibility with earlier versions that did not have @ref + * glfwGetJoystickHats, the button array also includes all hats, each + * represented as four buttons. The hats are in the same order as returned by + * __glfwGetJoystickHats__ and are in the order _up_, _right_, _down_ and + * _left_. To disable these extra buttons, set the @ref + * GLFW_JOYSTICK_HAT_BUTTONS init hint before initialization. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of button states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_button + * + * @since Added in version 2.2. + * @glfw3 Changed to return a dynamic array. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); + +/*! @brief Returns the state of all hats of the specified joystick. + * + * This function returns the state of all hats of the specified joystick. + * Each element in the array is one of the following values: + * + * Name | Value + * ---- | ----- + * `GLFW_HAT_CENTERED` | 0 + * `GLFW_HAT_UP` | 1 + * `GLFW_HAT_RIGHT` | 2 + * `GLFW_HAT_DOWN` | 4 + * `GLFW_HAT_LEFT` | 8 + * `GLFW_HAT_RIGHT_UP` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_UP` + * `GLFW_HAT_RIGHT_DOWN` | `GLFW_HAT_RIGHT` \| `GLFW_HAT_DOWN` + * `GLFW_HAT_LEFT_UP` | `GLFW_HAT_LEFT` \| `GLFW_HAT_UP` + * `GLFW_HAT_LEFT_DOWN` | `GLFW_HAT_LEFT` \| `GLFW_HAT_DOWN` + * + * The diagonal directions are bitwise combinations of the primary (up, right, + * down and left) directions and you can test for these individually by ANDing + * it with the corresponding direction. + * + * @code + * if (hats[2] & GLFW_HAT_RIGHT) + * { + * // State of hat 2 could be right-up, right or right-down + * } + * @endcode + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of hat states in the returned + * array. This is set to zero if the joystick is not present or an error + * occurred. + * @return An array of hat states, or `NULL` if the joystick is not present + * or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, this function is called again for that joystick or the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_hat + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count); + +/*! @brief Returns the name of the specified joystick. + * + * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM 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 specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_name + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickName(int jid); + +/*! @brief Returns the SDL compatible GUID of the specified joystick. + * + * This function returns the SDL compatible GUID, as a UTF-8 encoded + * hexadecimal string, of the specified joystick. The returned string is + * allocated and freed by GLFW. You should not free it yourself. + * + * The GUID is what connects a joystick to a gamepad mapping. A connected + * joystick will always have a GUID even if there is no gamepad mapping + * assigned to it. + * + * If the specified joystick is not present this function will return `NULL` + * but will not generate an error. This can be used instead of first calling + * @ref glfwJoystickPresent. + * + * The GUID uses the format introduced in SDL 2.0.5. This GUID tries to + * uniquely identify the make and model of a joystick but does not identify + * a specific unit, e.g. all wired Xbox 360 controllers will have the same + * GUID on that platform. The GUID for a unit may vary between platforms + * depending on what hardware information the platform specific APIs provide. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded GUID of the joystick, or `NULL` if the joystick + * is not present or an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_INVALID_ENUM 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 specified joystick is + * disconnected or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetJoystickGUID(int jid); + +/*! @brief Sets the user pointer of the specified joystick. + * + * This function sets the user-defined pointer of the specified joystick. The + * current value is retained until the joystick is disconnected. The initial + * value is `NULL`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * @param[in] jid The joystick whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwGetJoystickUserPointer + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer); + +/*! @brief Returns the user pointer of the specified joystick. + * + * This function returns the current value of the user-defined pointer of the + * specified joystick. The initial value is `NULL`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * @param[in] jid The joystick whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwSetJoystickUserPointer + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI void* glfwGetJoystickUserPointer(int jid); + +/*! @brief Returns whether the specified joystick has a gamepad mapping. + * + * This function returns whether the specified joystick is both present and has + * a gamepad mapping. + * + * If the specified joystick is present but does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check if a joystick is present regardless of + * whether it has a mapping. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return `GLFW_TRUE` if a joystick is both present and has a gamepad mapping, + * or `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwGetGamepadState + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwJoystickIsGamepad(int jid); + +/*! @brief Sets the joystick configuration callback. + * + * This function sets the joystick configuration callback, or removes the + * currently set callback. This is called when a joystick is connected to or + * disconnected from the system. + * + * For joystick connection and disconnection events to be delivered on all + * platforms, you need to call one of the [event processing](@ref events) + * functions. Joystick disconnection may also be detected and the callback + * called by joystick functions. The function will then return whatever it + * returns if the joystick is not present. + * + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(int jid, int event) + * @endcode + * For more information about the callback parameters, see the + * [function pointer type](@ref GLFWjoystickfun). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref joystick_event + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun callback); + +/*! @brief Adds the specified SDL_GameControllerDB gamepad mappings. + * + * This function parses the specified ASCII encoded string and updates the + * internal list with any gamepad mappings it finds. This string may + * contain either a single gamepad mapping or many mappings separated by + * newlines. The parser supports the full format of the `gamecontrollerdb.txt` + * source file including empty lines and comments. + * + * See @ref gamepad_mapping for a description of the format. + * + * If there is already a gamepad mapping for a given GUID in the internal list, + * it will be replaced by the one passed to this function. If the library is + * terminated and re-initialized the internal list will revert to the built-in + * default. + * + * @param[in] string The string containing the gamepad mappings. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * @sa @ref glfwGetGamepadName + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwUpdateGamepadMappings(const char* string); + +/*! @brief Returns the human-readable gamepad name for the specified joystick. + * + * This function returns the human-readable name of the gamepad from the + * gamepad mapping assigned to the specified joystick. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `NULL` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @return The UTF-8 encoded name of the gamepad, or `NULL` if the + * joystick is not present, does not have a mapping or an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref GLFW_INVALID_ENUM. + * + * @pointer_lifetime The returned string is allocated and freed by GLFW. You + * should not free it yourself. It is valid until the specified joystick is + * disconnected, the gamepad mappings are updated or the library is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetGamepadName(int jid); + +/*! @brief Retrieves the state of the specified joystick remapped as a gamepad. + * + * This function retrieves the state of the specified joystick remapped to + * an Xbox-like gamepad. + * + * If the specified joystick is not present or does not have a gamepad mapping + * this function will return `GLFW_FALSE` but will not generate an error. Call + * @ref glfwJoystickPresent to check whether it is present regardless of + * whether it has a mapping. + * + * The Guide button may not be available for input as it is often hooked by the + * system or the Steam client. + * + * Not all devices have all the buttons or axes provided by @ref + * GLFWgamepadstate. Unavailable buttons and axes will always report + * `GLFW_RELEASE` and 0.0 respectively. + * + * @param[in] jid The [joystick](@ref joysticks) to query. + * @param[out] state The gamepad input state of the joystick. + * @return `GLFW_TRUE` if successful, or `GLFW_FALSE` if no joystick is + * connected, it has no gamepad mapping or an [error](@ref error_handling) + * occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref gamepad + * @sa @ref glfwUpdateGamepadMappings + * @sa @ref glfwJoystickIsGamepad + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); + +/*! @brief Sets the clipboard to the specified string. + * + * This function sets the system clipboard to the specified, UTF-8 encoded + * string. + * + * @param[in] window Deprecated. Any valid window or `NULL`. + * @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 @ref glfwGetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); + +/*! @brief Returns the contents of the clipboard as a string. + * + * This function returns the contents of the system clipboard, if it contains + * or is convertible to a UTF-8 encoded string. If the clipboard is empty or + * if its contents cannot be converted, `NULL` is returned and a @ref + * GLFW_FORMAT_UNAVAILABLE error is generated. + * + * @param[in] window Deprecated. Any valid window or `NULL`. + * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` + * if an [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_FORMAT_UNAVAILABLE 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 + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref clipboard + * @sa @ref glfwSetClipboardString + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); + +/*! @brief Returns the GLFW time. + * + * This function returns the current GLFW time, in seconds. Unless the time + * has been set using @ref glfwSetTime it measures time elapsed since GLFW was + * initialized. + * + * This function and @ref glfwSetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. + * + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * @return The current time, in seconds, or zero 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. Reading and + * writing of the internal base time is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwSetTime. + * + * @sa @ref time + * + * @since Added in version 1.0. + * + * @ingroup input + */ +GLFWAPI double glfwGetTime(void); + +/*! @brief Sets the GLFW time. + * + * This function sets the current GLFW time, in seconds. The value must be + * a positive finite number less than or equal to 18446744073.0, which is + * approximately 584.5 years. + * + * This function and @ref glfwGetTime are helper functions on top of @ref + * glfwGetTimerFrequency and @ref glfwGetTimerValue. + * + * @param[in] time The new value, in seconds. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_VALUE. + * + * @remark The upper limit of GLFW time is calculated as + * floor((264 - 1) / 109) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @thread_safety This function may be called from any thread. Reading and + * writing of the internal base time is not atomic, so it needs to be + * externally synchronized with calls to @ref glfwGetTime. + * + * @sa @ref time + * + * @since Added in version 2.2. + * + * @ingroup input + */ +GLFWAPI void glfwSetTime(double time); + +/*! @brief Returns the current value of the raw timer. + * + * This function returns the current value of the raw timer, measured in + * 1 / frequency seconds. To get the frequency, call @ref + * glfwGetTimerFrequency. + * + * @return The value of the timer, or zero 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. + * + * @sa @ref time + * @sa @ref glfwGetTimerFrequency + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerValue(void); + +/*! @brief Returns the frequency, in Hz, of the raw timer. + * + * This function returns the frequency, in Hz, of the raw timer. + * + * @return The frequency of the timer, in Hz, or zero 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. + * + * @sa @ref time + * @sa @ref glfwGetTimerValue + * + * @since Added in version 3.2. + * + * @ingroup input + */ +GLFWAPI uint64_t glfwGetTimerFrequency(void); + +/*! @brief Makes the context of the specified window current for the calling + * thread. + * + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context must only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) + * hint. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * @param[in] window The window whose context to make current, or `NULL` to + * detach the current context. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwGetCurrentContext + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); + +/*! @brief Returns the window whose context is current on the calling thread. + * + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. + * + * @return The window whose context is current, or `NULL` if no window's + * context is current. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_current + * @sa @ref glfwMakeContextCurrent + * + * @since Added in version 3.0. + * + * @ingroup context + */ +GLFWAPI GLFWwindow* glfwGetCurrentContext(void); + +/*! @brief Swaps the front and back buffers of the specified window. + * + * This function swaps the front and back buffers of the specified window when + * rendering with OpenGL or OpenGL ES. If the swap interval is greater than + * zero, the GPU driver waits the specified number of screen updates before + * swapping the buffers. + * + * The specified window must have an OpenGL or OpenGL ES context. Specifying + * a window without a context will generate a @ref GLFW_NO_WINDOW_CONTEXT + * error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see `vkQueuePresentKHR` instead. + * + * @param[in] window The window whose buffers to swap. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark __EGL:__ The context of the specified window must be current on the + * calling thread. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapInterval + * + * @since Added in version 1.0. + * @glfw3 Added window handle parameter. + * + * @ingroup window + */ +GLFWAPI void glfwSwapBuffers(GLFWwindow* window); + +/*! @brief Sets the swap interval for the current context. + * + * This function sets the swap interval for the current OpenGL or OpenGL ES + * context, i.e. the number of screen updates to wait from the time @ref + * glfwSwapBuffers was called before swapping the buffers and returning. This + * is sometimes called _vertical synchronization_, _vertical retrace + * synchronization_ or just _vsync_. + * + * A context that supports either of the `WGL_EXT_swap_control_tear` and + * `GLX_EXT_swap_control_tear` extensions also accepts _negative_ swap + * intervals, which allows the driver to swap immediately even if a frame + * arrives a little bit late. You can check for these extensions with @ref + * glfwExtensionSupported. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see the present mode of your swapchain instead. + * + * @param[in] interval The minimum number of screen updates to wait for + * until the buffers are swapped by @ref glfwSwapBuffers. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done + * because some swap interval extensions used by GLFW do not allow the swap + * interval to be reset to zero once it has been set to a non-zero value. + * + * @remark Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref buffer_swap + * @sa @ref glfwSwapBuffers + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI void glfwSwapInterval(int interval); + +/*! @brief Returns whether the specified extension is available. + * + * This function returns whether the specified + * [API extension](@ref context_glext) is supported by the current OpenGL or + * OpenGL ES context. It searches both for client API extension and context + * creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. + * + * This function does not apply to Vulkan. If you are using Vulkan, see @ref + * glfwGetRequiredInstanceExtensions, `vkEnumerateInstanceExtensionProperties` + * and `vkEnumerateDeviceExtensionProperties` instead. + * + * @param[in] extension The ASCII encoded name of the extension. + * @return `GLFW_TRUE` if the extension is available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT, @ref GLFW_INVALID_VALUE and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwGetProcAddress + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI int glfwExtensionSupported(const char* extension); + +/*! @brief Returns the address of the specified function for the current + * context. + * + * This function returns the address of the specified OpenGL or OpenGL ES + * [core or extension function](@ref context_glext), if it is supported + * by the current context. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * This function does not apply to Vulkan. If you are rendering with Vulkan, + * see @ref glfwGetInstanceProcAddress, `vkGetInstanceProcAddr` and + * `vkGetDeviceProcAddr` instead. + * + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_NO_CURRENT_CONTEXT and @ref GLFW_PLATFORM_ERROR. + * + * @remark The address of a given function is not guaranteed to be the same + * between contexts. + * + * @remark This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string first. + * + * @pointer_lifetime The returned function pointer is valid until the context + * is destroyed or the library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref context_glext + * @sa @ref glfwExtensionSupported + * + * @since Added in version 1.0. + * + * @ingroup context + */ +GLFWAPI GLFWglproc glfwGetProcAddress(const char* procname); + +/*! @brief Returns whether the Vulkan loader and an ICD have been found. + * + * This function returns whether the Vulkan loader and any minimally functional + * ICD have been found. + * + * The availability of a Vulkan loader and even an ICD does not by itself guarantee that + * surface creation or even instance creation is possible. Call @ref + * glfwGetRequiredInstanceExtensions to check whether the extensions necessary for Vulkan + * surface creation are available and @ref glfwGetPhysicalDevicePresentationSupport to + * check whether a queue family of a physical device supports image presentation. + * + * @return `GLFW_TRUE` if Vulkan is minimally available, or `GLFW_FALSE` + * otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_support + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwVulkanSupported(void); + +/*! @brief Returns the Vulkan instance extensions required by GLFW. + * + * This function returns an array of names of Vulkan instance extensions required + * by GLFW for creating Vulkan surfaces for GLFW windows. If successful, the + * list will always contain `VK_KHR_surface`, so if you don't require any + * additional extensions you can pass this list directly to the + * `VkInstanceCreateInfo` struct. + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * If Vulkan is available but no set of extensions allowing window surface + * creation was found, this function returns `NULL`. You may still use Vulkan + * for off-screen rendering and compute work. + * + * @param[out] count Where to store the number of extensions in the returned + * array. This is set to zero if an error occurred. + * @return An array of ASCII encoded extension names, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @remark Additional extensions may be required by future versions of GLFW. + * You should check if any extensions you wish to enable are already in the + * returned array, as it is an error to specify an extension more than once in + * the `VkInstanceCreateInfo` struct. + * + * @pointer_lifetime The returned array is allocated and freed by GLFW. You + * should not free it yourself. It is guaranteed to be valid only until the + * library is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_ext + * @sa @ref glfwCreateWindowSurface + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count); + +#if defined(VK_VERSION_1_0) + +/*! @brief Returns the address of the specified Vulkan instance function. + * + * This function returns the address of the specified Vulkan core or extension + * function for the specified instance. If instance is set to `NULL` it can + * return any function exported from the Vulkan loader, including at least the + * following functions: + * + * - `vkEnumerateInstanceExtensionProperties` + * - `vkEnumerateInstanceLayerProperties` + * - `vkCreateInstance` + * - `vkGetInstanceProcAddr` + * + * If Vulkan is not available on the machine, this function returns `NULL` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available. + * + * This function is equivalent to calling `vkGetInstanceProcAddr` with + * a platform-specific query of the Vulkan loader as a fallback. + * + * @param[in] instance The Vulkan instance to query, or `NULL` to retrieve + * functions related to instance creation. + * @param[in] procname The ASCII encoded name of the function. + * @return The address of the function, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_API_UNAVAILABLE. + * + * @pointer_lifetime The returned function pointer is valid until the library + * is terminated. + * + * @thread_safety This function may be called from any thread. + * + * @sa @ref vulkan_proc + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance, const char* procname); + +/*! @brief Returns whether the specified queue family can present images. + * + * This function returns whether the specified queue family of the specified + * physical device supports presentation to the platform GLFW was built for. + * + * If Vulkan or the required window surface creation instance extensions are + * not available on the machine, or if the specified instance was not created + * with the required extensions, this function returns `GLFW_FALSE` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported + * to check whether Vulkan is at least minimally available and @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * @param[in] instance The instance that the physical device belongs to. + * @param[in] device The physical device that the queue family belongs to. + * @param[in] queuefamily The index of the queue family to query. + * @return `GLFW_TRUE` if the queue family supports presentation, or + * `GLFW_FALSE` otherwise. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE and @ref GLFW_PLATFORM_ERROR. + * + * @remark @macos This function currently always returns `GLFW_TRUE`, as the + * `VK_MVK_macos_surface` and `VK_EXT_metal_surface` extensions do not provide + * a `vkGetPhysicalDevice*PresentationSupport` type function. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_present + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily); + +/*! @brief Creates a Vulkan surface for the specified window. + * + * This function creates a Vulkan surface for the specified window. + * + * If the Vulkan loader or at least one minimally functional ICD were not found, + * this function returns `VK_ERROR_INITIALIZATION_FAILED` and generates a @ref + * GLFW_API_UNAVAILABLE error. Call @ref glfwVulkanSupported to check whether + * Vulkan is at least minimally available. + * + * If the required window surface creation instance extensions are not + * available or if the specified instance was not created with these extensions + * enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` and + * generates a @ref GLFW_API_UNAVAILABLE error. Call @ref + * glfwGetRequiredInstanceExtensions to check what instance extensions are + * required. + * + * The window surface cannot be shared with another API so the window must + * have been created with the [client api hint](@ref GLFW_CLIENT_API_attrib) + * set to `GLFW_NO_API` otherwise it generates a @ref GLFW_INVALID_VALUE error + * and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`. + * + * The window surface must be destroyed before the specified Vulkan instance. + * It is the responsibility of the caller to destroy the window surface. GLFW + * does not destroy it for you. Call `vkDestroySurfaceKHR` to destroy the + * surface. + * + * @param[in] instance The Vulkan instance to create the surface in. + * @param[in] window The window to create the surface for. + * @param[in] allocator The allocator to use, or `NULL` to use the default + * allocator. + * @param[out] surface Where to store the handle of the surface. This is set + * to `VK_NULL_HANDLE` if an error occurred. + * @return `VK_SUCCESS` if successful, or a Vulkan error code if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref + * GLFW_API_UNAVAILABLE, @ref GLFW_PLATFORM_ERROR and @ref GLFW_INVALID_VALUE + * + * @remark If an error occurs before the creation call is made, GLFW returns + * the Vulkan error code most appropriate for the error. Appropriate use of + * @ref glfwVulkanSupported and @ref glfwGetRequiredInstanceExtensions should + * eliminate almost all occurrences of these errors. + * + * @remark @macos GLFW prefers the `VK_EXT_metal_surface` extension, with the + * `VK_MVK_macos_surface` extension as a fallback. The name of the selected + * extension, if any, is included in the array returned by @ref + * glfwGetRequiredInstanceExtensions. + * + * @remark @macos This function creates and sets a `CAMetalLayer` instance for + * the window content view, which is required for MoltenVK to function. + * + * @thread_safety This function may be called from any thread. For + * synchronization details of Vulkan objects, see the Vulkan specification. + * + * @sa @ref vulkan_surface + * @sa @ref glfwGetRequiredInstanceExtensions + * + * @since Added in version 3.2. + * + * @ingroup vulkan + */ +GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface); + +#endif /*VK_VERSION_1_0*/ + + +/************************************************************************* + * Global definition cleanup + *************************************************************************/ + +/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ + +#ifdef GLFW_WINGDIAPI_DEFINED + #undef WINGDIAPI + #undef GLFW_WINGDIAPI_DEFINED +#endif + +#ifdef GLFW_CALLBACK_DEFINED + #undef CALLBACK + #undef GLFW_CALLBACK_DEFINED +#endif + +/* Some OpenGL related headers need GLAPIENTRY, but it is unconditionally + * defined by some gl.h variants (OpenBSD) so define it after if needed. + */ +#ifndef GLAPIENTRY + #define GLAPIENTRY APIENTRY +#endif + +/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ + + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_h_ */ + diff --git a/src_v2/libs/glfw_osx/include/GLFW/glfw3native.h b/src_v2/libs/glfw_osx/include/GLFW/glfw3native.h new file mode 100644 index 0000000..fe74c73 --- /dev/null +++ b/src_v2/libs/glfw_osx/include/GLFW/glfw3native.h @@ -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 + * + * 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 +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL) + #if defined(__OBJC__) + #import + #else + #include + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX) + #include + #include +#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) + #include +#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 +#endif +#if defined(GLFW_EXPOSE_NATIVE_EGL) + #include +#endif +#if defined(GLFW_EXPOSE_NATIVE_OSMESA) + #include +#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_ */ + diff --git a/src_v2/libs/glfw_osx/lib-arm64/libglfw.3.dylib b/src_v2/libs/glfw_osx/lib-arm64/libglfw.3.dylib new file mode 100755 index 0000000..5fbb9fb Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-arm64/libglfw.3.dylib differ diff --git a/src_v2/libs/glfw_osx/lib-arm64/libglfw3.a b/src_v2/libs/glfw_osx/lib-arm64/libglfw3.a new file mode 100644 index 0000000..ae5433c Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-arm64/libglfw3.a differ diff --git a/src_v2/libs/glfw_osx/lib-universal/libglfw.3.dylib b/src_v2/libs/glfw_osx/lib-universal/libglfw.3.dylib new file mode 100755 index 0000000..4d12877 Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-universal/libglfw.3.dylib differ diff --git a/src_v2/libs/glfw_osx/lib-universal/libglfw3.a b/src_v2/libs/glfw_osx/lib-universal/libglfw3.a new file mode 100644 index 0000000..afc2148 Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-universal/libglfw3.a differ diff --git a/src_v2/libs/glfw_osx/lib-x86_64/libglfw.3.dylib b/src_v2/libs/glfw_osx/lib-x86_64/libglfw.3.dylib new file mode 100755 index 0000000..392b8b4 Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-x86_64/libglfw.3.dylib differ diff --git a/src_v2/libs/glfw_osx/lib-x86_64/libglfw3.a b/src_v2/libs/glfw_osx/lib-x86_64/libglfw3.a new file mode 100644 index 0000000..0c113d7 Binary files /dev/null and b/src_v2/libs/glfw_osx/lib-x86_64/libglfw3.a differ diff --git a/src_v2/lumenarium_bsp.h b/src_v2/lumenarium_bsp.h index bd18720..65291bf 100644 --- a/src_v2/lumenarium_bsp.h +++ b/src_v2/lumenarium_bsp.h @@ -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 diff --git a/src_v2/lumenarium_first.cpp b/src_v2/lumenarium_first.c similarity index 62% rename from src_v2/lumenarium_first.cpp rename to src_v2/lumenarium_first.c index fa40abd..8f97144 100644 --- a/src_v2/lumenarium_first.cpp +++ b/src_v2/lumenarium_first.c @@ -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); } diff --git a/src_v2/lumenarium_first.h b/src_v2/lumenarium_first.h index 2dbf1b8..92d2067 100644 --- a/src_v2/lumenarium_first.h +++ b/src_v2/lumenarium_first.h @@ -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 diff --git a/src_v2/lumenarium_geometry.h b/src_v2/lumenarium_geometry.h index abfe1ce..a2d6428 100644 --- a/src_v2/lumenarium_geometry.h +++ b/src_v2/lumenarium_geometry.h @@ -23,6 +23,7 @@ enum GeoVertexBufferStorage_Color = 4 }; +typedef struct Geo_Vertex_Buffer Geo_Vertex_Buffer; struct Geo_Vertex_Buffer { r32* values; @@ -31,6 +32,7 @@ struct Geo_Vertex_Buffer u32 stride; }; +typedef struct Geo_Vertex_Buffer_Builder Geo_Vertex_Buffer_Builder; struct Geo_Vertex_Buffer_Builder { union @@ -49,12 +51,14 @@ struct Geo_Vertex_Buffer_Builder u32 cap; }; +typedef struct Geo_Index_Buffer Geo_Index_Buffer; struct Geo_Index_Buffer { u32* values; u32 len; }; +typedef struct Geo_Index_Buffer_Builder Geo_Index_Buffer_Builder; struct Geo_Index_Buffer_Builder { union @@ -71,36 +75,38 @@ struct Geo_Index_Buffer_Builder u32 cap; }; +typedef struct Geo_Quad_Buffer Geo_Quad_Buffer; struct Geo_Quad_Buffer { Geo_Vertex_Buffer buffer_vertex; Geo_Index_Buffer buffer_index; }; +typedef struct Geo_Quad_Buffer_Builder Geo_Quad_Buffer_Builder; struct Geo_Quad_Buffer_Builder { Geo_Vertex_Buffer_Builder buffer_vertex; Geo_Index_Buffer_Builder buffer_index; }; -internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap); +internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap, Geo_Vertex_Buffer_Storage storage); internal Geo_Index_Buffer_Builder geo_index_buffer_builder_create(Allocator* a, u32 cap); -internal Geo_Quad_Buffer_Builder geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, u32 index_cap); +internal Geo_Quad_Buffer_Builder ggeo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, Geo_Vertex_Buffer_Storage storage, u32 index_cap); // Vertex Buffer -internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c); -internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t); -internal u32 geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v); +internal u32 geo_vertex_buffer_builder_push_vtc(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c); +internal u32 geo_vertex_buffer_builder_push_vt(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t); +internal u32 geo_vertex_buffer_builder_push_v(Geo_Vertex_Buffer_Builder* b, v3 v); // Index Buffer -internal u32 geo_index_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, u32 i); -internal void geo_index_buffer_builder_push_tri(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2); -internal void geo_index_buffer_builder_push_quad(Geo_Vertex_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3); +internal u32 geo_index_buffer_builder_push(Geo_Index_Buffer_Builder* b, u32 i); +internal void geo_index_buffer_builder_push_tri(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2); +internal void geo_index_buffer_builder_push_quad(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, u32 i2, u32 i3); // Quad Buffer -internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c); -internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3); -internal void geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3); +internal void geo_quad_buffer_builder_push_vtc(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c); +internal void geo_quad_buffer_builder_push_vt(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3); +internal void geo_quad_buffer_builder_push_v(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3); internal Geo_Quad_Buffer geo_quad_buffer_builder_get_static_buffer(Geo_Quad_Buffer_Builder* b); ///////////////////////////////////////////// @@ -116,26 +122,61 @@ geo_vertex_buffer_builder_stride(Geo_Vertex_Buffer_Storage storage) return result; } +#ifdef DEBUG +# define geo_vertex_buffers_validate(g) geo_vertex_buffers_validate_(g) +#else +# define geo_vertex_buffers_validate(g) +#endif + +void +geo_vertex_buffers_validate_(Geo_Vertex_Buffer_Builder* b) +{ + // before start + u32* sentinel = (u32*)(b->values - 2); + assert(sentinel[0] == 0xF0F0F0F0); + assert(sentinel[1] == 0x0F0F0F0F); + + // after end + sentinel = (u32*)(b->values + (b->cap * b->stride)); + assert(sentinel[0] == 0xFFFF000F); + assert(sentinel[1] == 0xF000FFFF); +} + internal Geo_Vertex_Buffer_Builder geo_vertex_buffer_builder_create(Allocator* a, u32 cap, Geo_Vertex_Buffer_Storage storage) { u32 stride = geo_vertex_buffer_builder_stride(storage); u32 size = cap * stride; + u32 alloc_size = size; +#ifdef DEBUG + alloc_size += 4; +#endif Geo_Vertex_Buffer_Builder result = {}; zero_struct(result); result.cap = cap; result.storage = storage; result.stride = stride; - result.values = allocator_alloc_array(a, r32, size); + result.values = allocator_alloc_array(a, r32, alloc_size); + +#ifdef DEBUG + u32* sentinel = (u32*)result.values; + sentinel[0] = 0xF0F0F0F0; + sentinel[1] = 0x0F0F0F0F; + sentinel = (u32*)(result.values + alloc_size - 2); + result.values += 2; + sentinel[0] = 0xFFFF000F; + sentinel[1] = 0xF000FFFF; +#endif + + geo_vertex_buffers_validate(&result); return result; } internal Geo_Index_Buffer_Builder geo_index_buffer_builder_create(Allocator* a, u32 cap) { - Geo_Index_Buffer_Builder result = {}; zero_struct(result); result.cap = cap; @@ -155,42 +196,46 @@ geo_quad_buffer_builder_create(Allocator* a, u32 vertex_cap, Geo_Vertex_Buffer_S // Vertex Buffer internal u32 -geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c) +geo_vertex_buffer_builder_push_vtc(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t, v4 c) { + geo_vertex_buffers_validate(b); assert(b->len < b->cap); u32 result = b->len++; u32 offset = result * b->stride; + assert((offset + b->stride) <= (b->cap * b->stride)); + r32* at = b->values + offset; if (has_flag(b->storage, GeoVertexBufferStorage_Position)) { - b->values[offset++] = v.x; - b->values[offset++] = v.y; - b->values[offset++] = v.z; + *at++ = v.x; + *at++ = v.y; + *at++ = v.z; } if (has_flag(b->storage, GeoVertexBufferStorage_TexCoord)) { - b->values[offset++] = t.x; - b->values[offset++] = t.y; + *at++ = t.x; + *at++ = t.y; } if (has_flag(b->storage, GeoVertexBufferStorage_Color)) { - b->values[offset++] = c.x; - b->values[offset++] = c.y; - b->values[offset++] = c.z; - b->values[offset++] = c.w; + *at++ = c.x; + *at++ = c.y; + *at++ = c.z; + *at++ = c.w; } + geo_vertex_buffers_validate(b); return result; } internal u32 -geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t) +geo_vertex_buffer_builder_push_vt(Geo_Vertex_Buffer_Builder* b, v3 v, v2 t) { - return geo_vertex_buffer_builder_push(b, v, t, v4{0}); + return geo_vertex_buffer_builder_push_vtc(b, v, t, (v4){0}); } internal u32 -geo_vertex_buffer_builder_push(Geo_Vertex_Buffer_Builder* b, v3 v) +geo_vertex_buffer_builder_push_v(Geo_Vertex_Buffer_Builder* b, v3 v) { - return geo_vertex_buffer_builder_push(b, v, v2{0}, v4{0}); + return geo_vertex_buffer_builder_push_vtc(b, v, (v2){0}, (v4){0}); } @@ -224,34 +269,34 @@ geo_index_buffer_builder_push_quad(Geo_Index_Buffer_Builder* b, u32 i0, u32 i1, // Quad Buffer internal void -geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c) +geo_quad_buffer_builder_push_vtc(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3, v4 c) { - u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, c); - u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, c); - u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, c); - u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, c); + u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, t0, c); + u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, t1, c); + u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, t2, c); + u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, t3, c); geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3); } internal void -geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3) +geo_quad_buffer_builder_push_vt(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3, v2 t0, v2 t1, v2 t2, v2 t3) { - u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, t0, v4{}); - u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, t1, v4{}); - u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, t2, v4{}); - u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, t3, v4{}); + u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, t0, (v4){}); + u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, t1, (v4){}); + u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, t2, (v4){}); + u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, t3, (v4){}); geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3); } internal void -geo_quad_buffer_builder_push(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3) +geo_quad_buffer_builder_push_v(Geo_Quad_Buffer_Builder* b, v3 p0, v3 p1, v3 p2, v3 p3) { - u32 i0 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p0, v2{}, v4{}); - u32 i1 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p1, v2{}, v4{}); - u32 i2 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p2, v2{}, v4{}); - u32 i3 = geo_vertex_buffer_builder_push(&b->buffer_vertex, p3, v2{}, v4{}); + u32 i0 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p0, (v2){}, (v4){}); + u32 i1 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p1, (v2){}, (v4){}); + u32 i2 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p2, (v2){}, (v4){}); + u32 i3 = geo_vertex_buffer_builder_push_vtc(&b->buffer_vertex, p3, (v2){}, (v4){}); geo_index_buffer_builder_push_quad(&b->buffer_index, i0, i1, i2, i3); } diff --git a/src_v2/lumenarium_input.cpp b/src_v2/lumenarium_input.cpp index 9b6344b..d983076 100644 --- a/src_v2/lumenarium_input.cpp +++ b/src_v2/lumenarium_input.cpp @@ -1,4 +1,7 @@ + +// TODO(PS) @DEPRECATE - new os layer + #define INPUT_FRAME_STRING_LENGTH 32 struct Input_Frame { diff --git a/src_v2/lumenarium_memory.cpp b/src_v2/lumenarium_memory.cpp index ea32b7b..71e4f94 100644 --- a/src_v2/lumenarium_memory.cpp +++ b/src_v2/lumenarium_memory.cpp @@ -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; } } diff --git a/src_v2/lumenarium_memory.h b/src_v2/lumenarium_memory.h index 8b6a79f..b18a813 100644 --- a/src_v2/lumenarium_memory.h +++ b/src_v2/lumenarium_memory.h @@ -1,3 +1,5 @@ +// TODO(PS) @DEPRECATE - new os layer + /* date = April 6th 2022 7:55 pm */ #ifndef LUMENARIUM_MEMORY_H diff --git a/src_v2/lumenarium_tests.cpp b/src_v2/lumenarium_tests.cpp index 6379b7b..1c08d84 100644 --- a/src_v2/lumenarium_tests.cpp +++ b/src_v2/lumenarium_tests.cpp @@ -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); } \ No newline at end of file diff --git a/src_v2/lumenarium_texture_atlas.cpp b/src_v2/lumenarium_texture_atlas.c similarity index 96% rename from src_v2/lumenarium_texture_atlas.cpp rename to src_v2/lumenarium_texture_atlas.c index c60b7fe..92cc764 100644 --- a/src_v2/lumenarium_texture_atlas.cpp +++ b/src_v2/lumenarium_texture_atlas.c @@ -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); diff --git a/src_v2/lumenarium_types.h b/src_v2/lumenarium_types.h index 988b636..85e32dc 100644 --- a/src_v2/lumenarium_types.h +++ b/src_v2/lumenarium_types.h @@ -1,3 +1,5 @@ +// TODO(PS) @DEPRECATE - new os layer + /* date = March 22nd 2022 2:08 am */ #ifndef LUMENARIUM_TYPES_H diff --git a/src_v2/platform/lumenarium_os.h b/src_v2/platform/lumenarium_os.h new file mode 100644 index 0000000..b83cf91 --- /dev/null +++ b/src_v2/platform/lumenarium_os.h @@ -0,0 +1,58 @@ +#if !defined(LUMENARIUM_OS) +#define LUMENARIUM_OS + +/////////////////////////////////////// +// Memory + +u8* os_mem_reserve(u64 size); +u8* os_mem_commit(u8* base, u64 size); +bool os_mem_decommit(u8* base, u64 size); +bool os_mem_release(u8* base, u64 size); + +/////////////////////////////////////// +// File I/O + +File_Async_Job_System os_file_jobs_init(); +File_Handle os_file_open(String path, File_Access_Flags flags_access, File_Create_Flags flags_create); +void os_file_close(File_Handle file_handle); +File_Info os_file_get_info(File_Handle file_handle, Allocator* allocator); +Data os_file_read_all(File_Handle file_handle, Allocator* allocator); +bool os_file_write_all(File_Handle file_handle, Data file_data); + +String os_get_exe_path(Allocator* allocator); +bool os_pwd_set(String path); + +File_Info_List os_dir_enum(String path, Platform_Enum_Dir_Flags flags, Allocator* allocator); + +// Asnyc Jobs +void os_file_async_work_on_job(File_Async_Job* job); + +/////////////////////////////////////// +// Time + +Ticks os_get_ticks(); +r64 os_get_ticks_per_second(); + +/////////////////////////////////////// +// Threads + +Thread_Handle os_thread_begin(Thread_Proc* proc, u8* user_data); +void os_thread_end(Thread_Handle thread_handle); + +u32 os_interlocked_increment(volatile u32* value); +u32 os_interlocked_cmp_exchg(volatile u32* dest, u32 new_value, u32 old_value); + +/////////////////////////////////////// +// Network Access + +Socket_Handle os_socket_create(); +bool os_socket_bind(); +bool os_socket_connect(); +bool os_socket_close(); +Data os_socket_recv(); +s32 os_Socket_set_listening(); +s32 os_Socket_send(); +s32 os_Socket_send_to(); +s32 os_Socket_set_opt(); + +#endif // LUMENARIUM_OS \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_first_osx.c b/src_v2/platform/osx/lumenarium_first_osx.c new file mode 100644 index 0000000..ccbc76b --- /dev/null +++ b/src_v2/platform/osx/lumenarium_first_osx.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include + +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#include + +#include "lumenarium_osx_memory.h" +#include "../../core/lumenarium_core.h" +#include "../lumenarium_os.h" +#include "../../lumenarium_first.c" + +#undef internal +#undef external + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_first_osx.cpp b/src_v2/platform/osx/lumenarium_first_osx.cpp deleted file mode 100644 index 49d4820..0000000 --- a/src_v2/platform/osx/lumenarium_first_osx.cpp +++ /dev/null @@ -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 -#include - -#include "lumenarium_osx_memory.cpp" - -int main (int arg_count, char** args) -{ - App_State* state = lumenarium_init(); - - while (has_flag(state->flags, AppState_IsRunning)) - { - // TODO(PS): event processing - - lumenarium_update(state); - } - - lumenarium_cleanup(state); - - return 0; -} \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_osx_file.h b/src_v2/platform/osx/lumenarium_osx_file.h new file mode 100644 index 0000000..d33d261 --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_file.h @@ -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 diff --git a/src_v2/platform/osx/lumenarium_osx_graphics.h b/src_v2/platform/osx/lumenarium_osx_graphics.h new file mode 100644 index 0000000..289051f --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_graphics.h @@ -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; +} \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_osx_memory.cpp b/src_v2/platform/osx/lumenarium_osx_memory.cpp deleted file mode 100644 index 0ae2d54..0000000 --- a/src_v2/platform/osx/lumenarium_osx_memory.cpp +++ /dev/null @@ -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; -} diff --git a/src_v2/platform/osx/lumenarium_osx_memory.h b/src_v2/platform/osx/lumenarium_osx_memory.h new file mode 100644 index 0000000..388b9f9 --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_memory.h @@ -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 +} \ No newline at end of file diff --git a/src_v2/platform/osx/lumenarium_osx_time.cpp b/src_v2/platform/osx/lumenarium_osx_time.cpp deleted file mode 100644 index 39c1331..0000000 --- a/src_v2/platform/osx/lumenarium_osx_time.cpp +++ /dev/null @@ -1,4 +0,0 @@ - -// I think this SO post might be helpful -// https://stackoverflow.com/questions/30575995/multi-platform-equivalent-to-queryperformancecounter - diff --git a/src_v2/platform/osx/lumenarium_osx_time.h b/src_v2/platform/osx/lumenarium_osx_time.h new file mode 100644 index 0000000..eedc719 --- /dev/null +++ b/src_v2/platform/osx/lumenarium_osx_time.h @@ -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; +} \ No newline at end of file diff --git a/src_v2/platform/shared/lumenarium_shared_file_async_work_on_job.h b/src_v2/platform/shared/lumenarium_shared_file_async_work_on_job.h new file mode 100644 index 0000000..cfe29f6 --- /dev/null +++ b/src_v2/platform/shared/lumenarium_shared_file_async_work_on_job.h @@ -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) \ No newline at end of file diff --git a/src_v2/platform/shared/lumenarium_shared_file_tracker.h b/src_v2/platform/shared/lumenarium_shared_file_tracker.h new file mode 100644 index 0000000..779e445 --- /dev/null +++ b/src_v2/platform/shared/lumenarium_shared_file_tracker.h @@ -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 \ No newline at end of file diff --git a/src_v2/platform/win32/lumenarium_first_win32.cpp b/src_v2/platform/win32/lumenarium_first_win32.cpp index df682e2..e90418e 100644 --- a/src_v2/platform/win32/lumenarium_first_win32.cpp +++ b/src_v2/platform/win32/lumenarium_first_win32.cpp @@ -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 }; diff --git a/src_v2/platform/win32/lumenarium_win32_file.cpp b/src_v2/platform/win32/lumenarium_win32_file.cpp index 6db4fc4..5ca09e3 100644 --- a/src_v2/platform/win32/lumenarium_win32_file.cpp +++ b/src_v2/platform/win32/lumenarium_win32_file.cpp @@ -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); } \ No newline at end of file diff --git a/src_v2/scratch/lumenarium b/src_v2/scratch/lumenarium new file mode 100755 index 0000000..3c26db2 Binary files /dev/null and b/src_v2/scratch/lumenarium differ diff --git a/src_v2/user_space/user_space_incenter.cpp b/src_v2/user_space/user_space_incenter.cpp index 8a894c2..35fd847 100644 --- a/src_v2/user_space/user_space_incenter.cpp +++ b/src_v2/user_space/user_space_incenter.cpp @@ -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