diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index cc313c7..0000000 --- a/.editorconfig +++ /dev/null @@ -1,15 +0,0 @@ - -# top-most EditorConfig file -root = true - -# Unix-style newlines with a newline ending every file -[*] -end_of_line = lf -insert_final_newline = true -indent_style = space -indent_size = 2 - -# Matches multiple files with brace expansion notation -# Set default charset -[*.{c,h,js,py}] -charset = utf-8 \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index f9d668b..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# app_codebase - diff --git a/app_codebase_rdbg.rdbg b/app_codebase_rdbg.rdbg deleted file mode 100644 index 57f0e77..0000000 Binary files a/app_codebase_rdbg.rdbg and /dev/null differ diff --git a/base_app.10x b/base_app.10x deleted file mode 100644 index d77bfa5..0000000 --- a/base_app.10x +++ /dev/null @@ -1,110 +0,0 @@ - - - - *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, - - true - true - true - false - false - build.bat - - - - - - - - - - - false - - Debug - Release - - - x64 - Win32 - - - C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include -C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include -C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\ucrt -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\winrt -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\cppwinrt -C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\ATLMFC\include -C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Tools\MSVC\14.29.30133\include -C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\ucrt -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\shared -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\um -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\winrt -C:\Program Files (x86)\Windows Kits\10\include\10.0.22000.0\cppwinrt - - - - OS_WINDOWS 1 - - - - Debug:x64 - - - base_inc.h - os_inc.h - - - - Debug - - - - x64 - - - - - - .git - *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, - - true - true - true - false - - - - build - *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, - - true - true - true - false - - - - build.bat - - - src - *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,*.cu,*.jai, - - true - true - true - false - - - - run.bat - - - - diff --git a/build.bat b/build.bat index 6280fbd..fd41a54 100644 --- a/build.bat +++ b/build.bat @@ -2,15 +2,45 @@ ctime -begin timeBuild.ctm -set CommonCompilerFlags=/nologo /Zi /FC /WX /W4 /wd4201 /wd4100 /wd4189 /wd4244 /wd4127 /wd4456 -@rem set Sources=../src/main.c -@rem set OutputName=program.exe -set Sources=../src/algorithms_main.c -set OutputName=algorithms_test.exe +@rem /WX /W4 /wd4201 /wd4100 /wd4189 /wd4244 /wd4127 /wd4456 +@rem set CommonCompilerFlags="/nologo /Zi /FC" +set CommonCompilerFlags=/nologo /Zi /FC /Od +@rem /WX /W4 /wd4201 /wd4100 /wd4189 /wd4244 /wd4127 /wd4456 +@rem + +set mkl_root=D:/lib/oneAPI_mkl/mkl/2021.3.0 +set mkl_core=%mkl_root%/lib/intel64/mkl_core.lib +set mkl_intel_lp64=%mkl_root%/lib/intel64/mkl_intel_lp64.lib +set mkl_intel_thread=%mkl_root%/lib/intel64/mkl_intel_thread.lib +set MKLCOMPILER=D:/lib/oneAPI_mkl/compiler/2021.3.0/windows/compiler +set libiomp5md=%MKLCOMPILER%/lib/intel64_win/libiomp5md.lib + +set libiompdll_path=D:\lib\oneAPI_mkl\compiler\2021.3.0\windows\redist\intel64_win\compiler +set libiompdll_name=libiomp5md.dll +set libiompdll=%libiompdll_path%\%libiompdll_name% + +set Sources=../src/main.c + + + +IF NOT EXIST .\out mkdir .\out IF NOT EXIST .\build mkdir .\build pushd .\build -cl %CommonCompilerFlags% %Sources% -Fe%OutputName% + +if not exist "%libiompdll_name%" ( + echo Copying %libiompdll% + copy "%libiompdll%" . + if errorlevel 1 ( + echo Error copying openmp dll + ) else ( + echo Copied openmp dll: %libiompdll_name% + ) + +) + +cl %CommonCompilerFlags% %Sources% /I"%mkl_root%\include" /link %mkl_core% %mkl_intel_lp64% %mkl_intel_thread% %libiomp5md% + set LastError=%ERRORLEVEL% popd diff --git a/build/algorithms_test.rdi b/build/algorithms_test.rdi deleted file mode 100644 index 07e5098..0000000 Binary files a/build/algorithms_test.rdi and /dev/null differ diff --git a/build/program.raddbgi b/build/program.raddbgi deleted file mode 100644 index 4104d5f..0000000 Binary files a/build/program.raddbgi and /dev/null differ diff --git a/data/LiberationMono-Regular.ttf b/data/LiberationMono-Regular.ttf deleted file mode 100644 index e774859..0000000 Binary files a/data/LiberationMono-Regular.ttf and /dev/null differ diff --git a/data/arial.ttf b/data/arial.ttf deleted file mode 100644 index 8682d94..0000000 Binary files a/data/arial.ttf and /dev/null differ diff --git a/run.bat b/run.bat deleted file mode 100644 index 752c0f1..0000000 --- a/run.bat +++ /dev/null @@ -1,5 +0,0 @@ -@echo off -pushd build -@rem call program.exe -call algorithms_test.exe -popd diff --git a/src/algorithms_main.c b/src/algorithms_main.c deleted file mode 100644 index 23d6f0a..0000000 --- a/src/algorithms_main.c +++ /dev/null @@ -1,104 +0,0 @@ -// header includes -#include "base/base_inc.h" -#include "os/os_inc.h" - -// .c includes -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "os/os_entry_point.c" - -#define LOG DebugPrintf -function void -DebugPrintf(const char* format, ...) -{ - char buffer[4096]; - va_list args; - va_start(args, format); - vsprintf_s(buffer, sizeof(buffer), format, args); - OutputDebugString(buffer); - va_end(args); -} - -typedef struct F64Node F64Node; -struct F64Node -{ - F64Node *prev; - F64Node *next; - F64 value; -}; - -typedef struct F64List F64List; -struct F64List -{ - F64Node *first; - F64Node *last; - U32 length; -}; - -F64Node g_f64_nil_node = {0}; - -function void -F64_push_node(F64List *list, F64Node *n) -{ - if(list->first == 0) - { - list->first = n; - list->last = n; - } else { - list->last->next = n; - list->last = n; - } - list->length += 1; -} - -function void -F64_push(Arena *arena, F64List *list, F64 value) -{ - F64Node *node = PushArrayZero(arena, F64Node, 1); - node->value = value; - F64_push_node(list, node); -} - -function void -print_F64_ll(F64List *list) -{ - for(F64Node *n = list->first; n != 0; n = n->next) - { - LOG(" %2.f \n", n->value); - } -} - -function void -reverse_linked_list_lol(void) -{ - Arena *ll_arena = m_make_arena(); - F64List list = {0}; - for (U32 i = 0; i < 10; i++) - { - F64_push(ll_arena, &list, (F64)i); - } - - print_F64_ll(&list); - - F64Node *prev = 0; - F64Node *current = list.first; - F64Node *next_temp = 0; - while(current != 0) - { - next_temp = current->next; - current->next = prev; - prev = current; - current = next_temp; - } - list.first = prev; - - print_F64_ll(&list); -} - - - -void -EntryPoint(void) -{ - reverse_linked_list_lol(); -} diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h deleted file mode 100644 index f3ed4d6..0000000 --- a/src/base/base_context_cracking.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef BASE_CONTEXT_CRACKING_H -#define BASE_CONTEXT_CRACKING_H - -// NOTE(antonl): -// This header is used for "context cracking", ie figuring out compile time context things like -// platform etc. - -// For now this is just copy pasted from RJFs layer, and probably that's all that's needed. - - -/////////////////////////////////////////////// -//~ MSVC extraction - -#if defined(_MSC_VER) - -# define COMPILER_MSVC 1 - -# if defined(_WIN32) -# define OS_WINDOWS 1 -# else -# error _MSC_VER is defined, but _WIN32 is not. This setup is not supported. -# endif - -# if defined(_M_AMD64) -# define ARCH_X64 1 -# elif defined(_M_IX86) -# define ARCH_X86 1 -# elif defined(_M_ARM64) -# define ARCH_ARM64 1 -# elif defined(_M_ARM) -# define ARCH_ARM32 1 -# else -# error Target architecture is not supported. _MSC_VER is defined, but one of {_M_AMD64, _M_IX86, _M_ARM64, _M_ARM} is not. -# endif - -#if _MSC_VER >= 1920 -#define COMPILER_MSVC_YEAR 2019 -#elif _MSC_VER >= 1910 -#define COMPILER_MSVC_YEAR 2017 -#elif _MSC_VER >= 1900 -#define COMPILER_MSVC_YEAR 2015 -#elif _MSC_VER >= 1800 -#define COMPILER_MSVC_YEAR 2013 -#elif _MSC_VER >= 1700 -#define COMPILER_MSVC_YEAR 2012 -#elif _MSC_VER >= 1600 -#define COMPILER_MSVC_YEAR 2010 -#elif _MSC_VER >= 1500 -#define COMPILER_MSVC_YEAR 2008 -#elif _MSC_VER >= 1400 -#define COMPILER_MSVC_YEAR 2005 -#else -#define COMPILER_MSVC_YEAR 0 -#endif - -//////////////////////////////// -//~ rjf: Clang Extraction - -#elif defined(__clang__) - -# define COMPILER_CLANG 1 - -# if defined(__APPLE__) && defined(__MACH__) -# define OS_MAC 1 -# elif defined(__gnu_linux__) -# define OS_LINUX 1 -# else -# error __clang__ is defined, but one of {__APPLE__, __gnu_linux__} is not. This setup is not supported. -# endif - -# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) -# define ARCH_X64 1 -# elif defined(i386) || defined(__i386) || defined(__i386__) -# define ARCH_X86 1 -# elif defined(__aarch64__) -# define ARCH_ARM64 1 -# elif defined(__arm__) -# define ARCH_ARM32 1 -# else -# error Target architecture is not supported. __clang__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__} is not. -# endif - -//////////////////////////////// -//~ rjf: GCC Extraction - -#elif defined(__GNUC__) || defined(__GNUG__) - -# define COMPILER_GCC 1 - -# if defined(__gnu_linux__) -# define OS_LINUX 1 -# else -# error __GNUC__ or __GNUG__ is defined, but __gnu_linux__ is not. This setup is not supported. -# endif - -# if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) -# define ARCH_X64 1 -# elif defined(i386) || defined(__i386) || defined(__i386__) -# define ARCH_X86 1 -# elif defined(__aarch64__) -# define ARCH_ARM64 1 -# elif defined(__arm__) -# define ARCH_ARM32 1 -# else -# error Target architecture is not supported. __GNU_C__ or __GNUG__ is defined, but one of {__amd64__, __amd64, __x86_64__, __x86_64, i386, __i386, __i386__, __aarch64__, __arm__} is not. -# endif - -#else -# error Compiler is not supported. _MSC_VER, __clang__, __GNUC__, or __GNUG__ must be defined. -#endif - -#if defined(ARCH_X64) -# define ARCH_64BIT 1 -#elif defined(ARCH_X86) -# define ARCH_32BIT 1 - -#endif - -//////////////////////////////// -//~ rjf: Language - -#if defined(__cplusplus) -# define LANG_CPP 1 -#else -# define LANG_C 1 -#endif - -//////////////////////////////// -//~ rjf: Zero - -#if !defined(ARCH_32BIT) -# define ARCH_32BIT 0 -#endif -#if !defined(ARCH_64BIT) -# define ARCH_64BIT 0 -#endif -#if !defined(ARCH_X64) -# define ARCH_X64 0 -#endif -#if !defined(ARCH_X86) -# define ARCH_X86 0 -#endif -#if !defined(ARCH_ARM64) -# define ARCH_ARM64 0 -#endif -#if !defined(ARCH_ARM32) -# define ARCH_ARM32 0 -#endif -#if !defined(COMPILER_MSVC) -# define COMPILER_MSVC 0 -#endif -#if !defined(COMPILER_GCC) -# define COMPILER_GCC 0 -#endif -#if !defined(COMPILER_CLANG) -# define COMPILER_CLANG 0 -#endif -#if !defined(OS_WINDOWS) -# define OS_WINDOWS 0 -#endif -#if !defined(OS_LINUX) -# define OS_LINUX 0 -#endif -#if !defined(OS_MAC) -# define OS_MAC 0 -#endif -#if !defined(LANG_CPP) -# define LANG_CPP 0 -#endif -#if !defined(LANG_C) -# define LANG_C 0 -#endif - -// TODO(antonl); -// Build options context cracking, need to figure out what we should use here first. -#define BUILD_DEBUG 1 - -#endif /* BASE_CONTEXT_CRACKING_H */ diff --git a/src/base/base_core.h b/src/base/base_core.h deleted file mode 100644 index dbf3b67..0000000 --- a/src/base/base_core.h +++ /dev/null @@ -1,294 +0,0 @@ -#ifndef BASE_TYPES_H -#define BASE_TYPES_H - -#include -#include -#include - -///////////////////////// -//~ Macros - -///////////////////////// -//- Linking keywords - -// TODO(anton): Understand this, yoinked from rjf's layer. -#if LANG_CPP -# define no_name_mangle extern "C" -#else -# define no_name_mangle -#endif - -// TODO(anton): OS_WINDOWS dll import/export macros - -///////////////////////// -//- Keywords -// Static is stupid and means different things depending on context in C and C++. -// These defines increases readability. -#define function static // Function internal to compilation unit. -#define local_persist static -#define global static -#define fallthrough // for use in switch statements, for clarity.. - -// TODO(anton): Understand and add good comment on this. -#if LANG_CPP -# define root_global no_name_mangle -# define root_function function -#else -# define root_global extern -# define root_function function -#endif - -#define inline_function inline static - -#if OS_WINDOWS -# pragma section(".roglob", read) -# define read_only __declspec(allocate(".roglob")) -#else -# define read_only -#endif - -#if COMPILER_MSVC -# define per_thread __declspec(thread) -#else -# error Thread keyword not abstracted on compiler. -#endif - -///////////////////////// -//- Memory operations -// It's nice to put these in macros, so we can swap out the functionality from standard library, eventually. -#define MemoryCopy memcpy -#define MemoryMove memmove -#define MemorySet memset - -// NOTE(anton): This gives a 4127 compiler warning for the sizeof conditional. This should be ignored -#define MemoryCopyStruct(dst, src) do { Assert(sizeof(*(dst)) == sizeof(*(src))); MemoryCopy((dst), (src), sizeof(*(dst))); } while(0) - -#define MemoryZero(ptr, size) MemorySet((ptr), 0, (size)) -#define MemoryZeroStruct(ptr) MemoryZero((ptr), sizeof(*(ptr))) -#define MemoryZeroArray(arr) MemoryZero((arr), sizeof(arr)) - -///////////////////////// -//- Integer/pointer/array/type manipulations - -#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) -#define IntFromPtr(p) (U64)(((U8*)p) - 0) -#define PtrFromInt(i) (void*)(((U8*)0) + i) -#define Member(type, member_name) ((type *)0)->member_name -// TODO(anton): Understand why this becomes offset actually -#define OffsetOf(type, member_name) IntFromPtr(&Member(type, member_name)) -// TODO(anton): Understand this -#define BaseFromMember(type, member_name, ptr) (type *)((U8 *)(ptr) - OffsetOf(type, member_name)) - -#define Bytes(n) (n) -#define Kilobytes(n) (n << 10) // 2^10 == 1024 etc -#define Megabytes(n) (n << 20) -#define Gigabytes(n) (((U64)n) << 30) -#define Terabytes(n) (((U64)n) << 40) - -#define Thousand(n) ((n)*1000) -#define Million(n) ((n)*1000000) -#define Billion(n) ((n)*1000000000LL) - -#define AbsoluteValueU64(x) (U64)llabs((U64)(x)) - -///////////////////////// -//- Linked list helpers - -#define CheckNull(p) ((p)==0) -#define SetNull(p) ((p)=0) -// Link list helper macros that are a bit involved - -// Suffixes N,P,Z means that we have (N)ext, (P)rev arguments and/or a (Z)ero check and/or set argument -// f, l, n are "first", "last", "node" I think? -// DLL -// Doubly Linked List: Each node has a prev and next pointer. Operations: Push back, Push front, remove -#define DLLInsert_NPZ(f,l,p,n,next,prev,zchk,SetNull) \ -(zchk(f) ? (((f) = (l) = (n)), SetNull((n)->next), SetNull((n)->prev)) :\ -zchk(p) ? (SetNull((n)->prev), (n)->next = (f), (zchk(f) ? (0) : ((f)->prev = (n))), (f) = (n)) :\ -((zchk((p)->next) ? (0) : (((p)->next->prev) = (n))), (n)->next = (p)->next, (n)->prev = (p), (p)->next = (n),\ -((p) == (l) ? (l) = (n) : (0)))) - -#define DLLPushBack_NPZ(f,l,n,next,prev,zchk,SetNull) DLLInsert_NPZ(f,l,l,n,next,prev,zchk,SetNull) - -#define DLLPushBack_NP(f, l, n, next, prev, zchk) \ -(zchk(f) ? ((f)=(l)=(n),(n)->next=(n)->prev=0) : ((n)->prev=(l),(l)->next=(n),(l)=(n),(n)->next=0)) - -// If f == n we put f to f->next, and f->prev = 0. -// Else if l == n, we put l=l->prev, l->next = 0. -// If l != n and f != n we set n->next->prev to n->prev, and n->prev->next to n->next - -#define DLLRemove_NP(f, l, n, next, prev) (((f) == (n) ? \ -((f)=(f)->next, (f)->prev=0) : \ -(l) == (n) ? \ -((l)=(l)->prev, (l)->next=0) : \ -((n)->next->prev=(n)->prev, \ -(n)->prev->next=(n)->next) )) - -#define DLLRemove_NPZ(f,l,n,next,prev,zchk,SetNull) (((f)==(n))?\ -((f)=(f)->next, (zchk(f) ? (SetNull(l)) : SetNull((f)->prev))):\ -((l)==(n))?\ -((l)=(l)->prev, (zchk(l) ? (SetNull(f)) : SetNull((l)->next))):\ -((zchk((n)->next) ? (0) : ((n)->next->prev=(n)->prev)),\ -(zchk((n)->prev) ? (0) : ((n)->prev->next=(n)->next)))) - -#define DLLPushBack(f, l, n) DLLPushBack_NPZ(f, l, n, next, prev, CheckNull, SetNull) -// For front push I can just switch prev/next! -#define DLLPushFront(f, l, n) DLLPushBack_NPZ(l, f, n, prev, next, CheckNull, SetNull) -#define DLLRemove(f, l, n) DLLRemove_NPZ(f, l, n, next, prev, CheckNull, SetNull) - - -// SLL, queue or stack. -// These are from rjf's layer. - -//////////////// -// Queue -// Queue has only a next pointer. But we can push from front also. -// zchk = zero check, SetNull = zero set -#define QueuePush_NZ(f, l, n, next, zchk, SetNull) (zchk(f)?\ -(((f)=(l)=(n)), SetNull((n)->next)):\ -((l)->next=(n),(l)=(n),SetNull((n)->next))) - -#define QueuePushFront_NZ(f, l, n, next, zchk, SetNull) ( zchk(f) ? \ -((f)=(l)=(n)), SetNull((n)->next) : \ -((n)->next = (f)), ((f) = (n)) ) - -#define QueuePop_NZ(f, l, next, zchk, SetNull) ( (f)==(l) ? \ -(SetNull(f), SetNull(l)) : ((f)=(f)->next)) - -#define QueuePush(f, l, n) QueuePush_NZ(f, l, n, next, CheckNull, SetNull) -#define QueuePushFront(f, l, n) QueuePushFront_NZ(f, l, n, next, CheckNull, SetNull) -#define QueuePop(f, l) QueuePop_NZ(f, l, next, CheckNull, SetNull) - -//////////////// -// Stack -#define StackPush_N(f, n, next) ((n)->next=(f), (f)=(n)) // Take the first element and set it to n->next, and set the first element to the node n. -#define StackPop_NZ(f, next, zchk) (zchk(f) ? 0 : ((f)=(f)->next)) // If first element is not zero we say that the first element is f->next, ie we pop f and put f->next on top. - -#define StackPush(f, n) StackPush_N(f, n, next) -#define StackPop(f) StackPop_NZ(f, next, CheckNull) - -///////////////////////// -//- Clamp/min/max -#define Min(a, b) (((a)<(b)) ? (a) : (b)) -#define Max(a, b) (((a)>(b)) ? (a) : (b)) -#define ClampTop(x, a) Min(x,a) // "Top" since we are cutting off anything above Min(x,a) -#define ClampBot(a, x) Max(a,x) // "Bot" since we're cutting off anything below Max(a,x) -// If a > x we get a, else we see if b < x and then get b if true, else x. -// TODO(anton): Is this actually what we want from a Clamp? -#define Clamp(a, x, b) (((a)>(x))?(a):((b)<(x))?(b):(x)) - -//- loop -#define DeferLoop(start, end) for(int _i_ = ((start), 0); _i_ == 0; _i_ += 1, (end)) -#define DeferLoopChecked(begin, end) for(int _i_ = 2 * !(begin); (_i_ == 2 ? ((end), 0) : !_i_); _i_ += 1, (end)) - -#define EachEnumVal(type, it) type it = (type)0; it < type##_COUNT; it = (type)(it+1) -#define EachNonZeroEnumVal(type, it) type it = (type)1; it < type##_COUNT; it = (type)(it+1) - - -///////////////////////// -//~ Base types -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; -typedef S8 B8; -typedef S16 B16; -typedef S32 B32; -typedef S64 B64; -typedef float F32; -typedef double F64; -typedef void VoidFunction(void); - -///////////////////////// -//~ Numerical limits -read_only global U8 U8Max = 0xFF; -read_only global U8 U8Min = 0; -read_only global U32 U32Max = 0xFFFFFFFF; -read_only global U32 U32Min = 0; -read_only global U64 U64Max = 0xFFFFFFFFFFFFFFFF; - -// TODO(anton): Rest of the limits, unsigned and signed integer values -read_only global U32 SignF32 = 0x80000000; - - -//- compiler, shut up! helpers -#define unused_variable(name) (void)name - -///////////////////////// -//~ Base enums - -// Describing a 2-coordinate system -typedef enum Axis2 -{ - Axis2_Invalid = -1, - Axis2_X, - Axis2_Y, - Axis2_COUNT -} -Axis2; -#define Axis2_flip(a) ((Axis2)(!(a))) - -// Corners of a rectangle. -// 00 ----- 10 -// | | -// 01 ----- 11 -typedef enum Corner -{ - Corner_Invalid = -1, - Corner_00, - Corner_01, - Corner_10, - Corner_11, - Corner_COUNT -} -Corner; - -//////////////////////////////// -//~ Member Offset Helper - -typedef struct MemberOffset MemberOffset; -struct MemberOffset -{ - U64 v; -}; - -#define MemberOff(S, member) (MemberOffset){OffsetOf(S, member)} -#define MemberOffLit(S, member) {OffsetOf(S, member)} -#define MemberFromOff(ptr, type, memoff) (*(type *)((U8 *)ptr + memoff.v)) - -///////////////////////// -//~ Assertions - -#if OS_WINDOWS -# define break_debugger() __debugbreak() -#else -# error not implemented -#endif - -#undef Assert -#define Assert(b) do { if(!(b)) { break_debugger(); } } while(0) - -#if !defined(LOG_NOT_IMPLEMENTED) -# define LOG_NOT_IMPLEMENTED printf("\nFATAL ERROR: Not implemented yet.\n"); Assert(false); exit(1); -#endif - -///////////////////////// -//~ Bit patterns -#define AlignUpToPow2(bytes_to_align, alignment_bytes) (((bytes_to_align) + (alignment_bytes - 1)) & ~(alignment_bytes - 1)) - -inline_function F32 -absolute_value_F32(F32 f) -{ - union { U32 u; F32 f; } x; - x.f = f; - x.u = x.u & ~SignF32; - return x.f; -} - -// TODO(anton): Understand rjf's bit patterns - -#endif //BASE_TYPES_H diff --git a/src/base/base_inc.c b/src/base/base_inc.c deleted file mode 100644 index 7194c58..0000000 --- a/src/base/base_inc.c +++ /dev/null @@ -1,4 +0,0 @@ -#include "base_math.c" -#include "base_memory.c" -#include "base_strings.c" -#include "base_thread_context.c" \ No newline at end of file diff --git a/src/base/base_inc.h b/src/base/base_inc.h deleted file mode 100644 index 0598745..0000000 --- a/src/base/base_inc.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef BASE_H -#define BASE_H - -#include "base_context_cracking.h" -#include "base_core.h" -#include "base_math.h" -#include "base_memory.h" -#include "base_strings.h" -#include "base_thread_context.h" - -#endif //BASE_H diff --git a/src/base/base_math.c b/src/base/base_math.c deleted file mode 100644 index 40e9cb0..0000000 --- a/src/base/base_math.c +++ /dev/null @@ -1,107 +0,0 @@ -//- Vec2 F32 -root_function Vec2_F32 -vec2_F32(F32 x, F32 y) -{ - Vec2_F32 result; - result.x = x; - result.y = y; - return result; -} - -root_function Vec2_F32 add2_F32(Vec2_F32 a, Vec2_F32 b) { return vec2_F32(a.x+b.x, a.y+b.y); } -root_function Vec2_F32 sub2_F32(Vec2_F32 a, Vec2_F32 b) { return vec2_F32(a.x-b.x, a.y-b.y); } - -//- Vec2 S32 -root_function Vec2_S32 -vec2_S32(S32 x, S32 y) -{ - Vec2_S32 result; - result.x = x; - result.y = y; - return result; -} - - -root_function Vec2_S64 -vec2_S64(S64 x, S64 y) -{ - Vec2_S64 result; - result.x = x; - result.y = y; - return result; -} - -root_function Vec3_F32 -vec3_F32(F32 x, F32 y, F32 z) -{ - Vec3_F32 result; - result.x = x; - result.y = y; - result.z = z; - return result; -} - -root_function Vec4_F32 -vec4_F32(F32 x, F32 y, F32 z, F32 w) -{ - Vec4_F32 result; - result.x = x; - result.y = y; - result.z = z; - result.w = w; - return result; -} - -//~ Range functions -root_function Rng2_F32 -rng2_F32(Vec2_F32 min, Vec2_F32 max) -{ - Rng2_F32 result = { min, max }; - return result; -} - -root_function Rng2_F32 -shift2_F32(Rng2_F32 r, Vec2_F32 v) { - // Shift the rectangle r by vector v. - r.x0 += v.x; - r.y0 += v.y; - r.x1 += v.x; - r.y1 += v.y; - return r; -} - -root_function Rng2_F32 -pad2_F32(Rng2_F32 r, F32 x) -{ - // Pad subtracts the p0 by value x on both axes, and adds to p1 on both axes, - // resulting in a rectangle that is value x larger than input rectangle r on both axes. - Vec2_F32 min = sub2_F32(r.min, vec2_F32(x, x)); - Vec2_F32 max = add2_F32(r.max, vec2_F32(x, x)); - return rng2_F32(min, max); -} - -root_function Vec2_F32 -dim2_F32(Rng2_F32 rng) -{ - return vec2_F32(absolute_value_F32(rng.max.x - rng.min.x), - absolute_value_F32(rng.max.y - rng.min.y)); -} - -// Check if a rect contains a point -root_function B32 -rng2_contains_vec2_F32(Rng2_F32 r, Vec2_F32 x) -{ - B32 c = (r.min.x <= x.x && x.x < r.max.x && r.min.y <= x.y && x.y < r.max.y); - return c; -} - -root_function Rng2_F32 -rng2_intersect_f32(Rng2_F32 a, Rng2_F32 b) -{ - Rng2_F32 c; - c.p0.x = Max(a.min.x, b.min.x); - c.p0.y = Max(a.min.y, b.min.y); - c.p1.x = Min(a.max.x, b.max.x); - c.p1.y = Min(a.max.y, b.max.y); - return c; -} \ No newline at end of file diff --git a/src/base/base_math.h b/src/base/base_math.h deleted file mode 100644 index 9942379..0000000 --- a/src/base/base_math.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef BASE_MATH_H -#define BASE_MATH_H - -////////////////////////// -//~ Macros - -#define floor_F32(f) floorf(f) - - -////////////////////////// -//~ Vector types - -//- 2-vectors -typedef union Vec2_S32 Vec2_S32; -union Vec2_S32 -{ - struct - { - S32 x; - S32 y; - }; - S32 v[2]; -}; - -typedef union Vec2_S64 Vec2_S64; -union Vec2_S64 -{ - struct - { - S64 x; - S64 y; - }; - S64 v[2]; -}; - -typedef union Vec2_F32 Vec2_F32; -union Vec2_F32 -{ - struct - { - F32 x; - F32 y; - }; - F32 v[2]; -}; - -//- 3-vectors - -typedef union Vec3_F32 Vec3_F32; -union Vec3_F32 -{ - struct - { - F32 x; - F32 y; - F32 z; - }; - F32 v[3]; -}; - -//- 4-vectors -typedef union Vec4_F32 Vec4_F32; -union Vec4_F32 -{ - struct - { - F32 x; - F32 y; - F32 z; - F32 w; - }; - struct - { - Vec2_F32 xy; - Vec2_F32 zw; - }; - F32 v[4]; -}; - -//- vector macros -#define vec2_F32_from_vec(v) vec2_F32((F32)(v).x, (F32)(v).y); -#define vec2_S32_from_vec(v) vec2_S32((S32)(v).x, (S32)(v).y); -#define vec2_S64_from_vec(v) vec2_S64((S64)(v).x, (S64)(v).y); -////////////////////////// -//~ Matrix types -typedef struct Mat3x3_F32 Mat3x3_F32; -struct Mat3x3_F32 -{ - F32 elements[3][3]; -}; - -typedef struct Mat4x4_F32 Mat4x4_F32; -struct Mat4x4_F32 -{ - F32 elements[4][4]; -}; - -////////////////////////// -//~ Range types - -//- 2D interval -// -typedef union Rng2_F32 Rng2_F32; -union Rng2_F32 -{ - struct - { - Vec2_F32 min; - Vec2_F32 max; - }; - struct - { - Vec2_F32 p0; - Vec2_F32 p1; - }; - struct - { - F32 x0; - F32 y0; - F32 x1; - F32 y1; - }; - Vec2_F32 v[2]; -}; - -//~ Vector functions - -//- Vec2 F32 -root_function Vec2_F32 vec2_F32(F32 x, F32 y); -root_function Vec2_F32 add2_F32(Vec2_F32 a, Vec2_F32 b); -root_function Vec2_F32 sub2_F32(Vec2_F32 a, Vec2_F32 b); - -//- Vec2 S32 -root_function Vec2_S32 vec2_S32(S32 x, S32 y); - -root_function Vec2_S64 vec2_S64(S64 x, S64 y); - -root_function Vec3_F32 vec3_F32(F32 x, F32 y, F32 z); - -root_function Vec4_F32 vec4_F32(F32 x, F32 y, F32 z, F32 w); - -//~ Range functions -root_function Rng2_F32 rng2_F32(Vec2_F32 min, Vec2_F32 max); -root_function Rng2_F32 shift2_F32(Rng2_F32 r, Vec2_F32 v); -root_function Rng2_F32 pad2_F32(Rng2_F32 r, F32 x); -root_function Vec2_F32 dim2_F32(Rng2_F32 rng); -root_function B32 rng2_contains_vec2_F32(Rng2_F32 r, Vec2_F32 x); -root_function Rng2_F32 rng2_intersect_f32(Rng2_F32 a, Rng2_F32 b); -#endif //BASE_MATH_H diff --git a/src/base/base_memory.c b/src/base/base_memory.c deleted file mode 100644 index e92d4a1..0000000 --- a/src/base/base_memory.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include - -#if !defined(m_reserve) -#error missing definition for 'm_reserve' type: (U64)->void* -#endif -#if !defined(m_commit) -#error missing definition for 'm_commit' type: (void*, U64)->void -#endif -#if !defined(m_decommit) -#error missing definition for 'm_decommit' type: (void*, U64)->void -#endif -#if !defined(m_release) -#error missing definition for 'm_release' type: (void*, U64)->void -#endif - -static Arena *g_scratch_arena = 0; - -root_function void -m_change_memory_noop(void *ptr, U64 size) {} - -// Malloc implementation of the M_Base_memory -root_function void* -m_malloc_reserve(U64 size) { - return malloc(size); -} - -root_function void -m_malloc_release(void *ptr, U64 size) { - free(ptr); -} - -//~ 64-bit memory arena - -root_function Arena -*m_make_arena_reserve(U64 reserve_size) { - Arena *result = 0; - U64 initial_commit_size = ARENA_COMMIT_GRANULARITY; - if (reserve_size >= initial_commit_size) { - void *memory = m_reserve(reserve_size); - // Since we use "header" space we must ensure the initial commit can fit the Arena struct. - Assert(initial_commit_size >= sizeof(Arena)); - m_commit(memory, ARENA_COMMIT_GRANULARITY); - result = (Arena*)memory;//(Arena*)result; <- this has to be mistake in Allen's video.. ? - // After we have pointed to our newly reserved and commited memory, - // we fill in the "header" parts, which are just the members of the arena type. - result->capacity = reserve_size; - result->commit_pos = initial_commit_size; - result->align = 8; // 8-bytes alignment? - result->pos = sizeof(Arena); // Here we point the position to after the Arena "header" section. - } - return result; -} - -root_function Arena* -m_make_arena() { - Arena* result = m_make_arena_reserve(M_DEFAULT_RESERVE_SIZE); - return result; -} - -// NOTE(anton): rjf calls this "arena push no zero", as opposed to pushing a zeroed array. -// Not sure why we would make this differentiation, maybe not important. - -root_function void* -m_arena_push(Arena *arena, U64 size) { - void *result = 0; - if (arena->pos + size <= arena->capacity) { - /*U8 *base = (U8 *)arena; // Get memory base pointer. - // Adjust by any alignment if necessary. - // Doing modulo ensures we get a number in the 0-align-1 range. - U64 post_align_pos = (arena->pos + (arena->align-1)): - post_align_pos = post_align_pos % arena->align; - // What's happening here? Almost certainly the align will overflow here? - // Are we filling the allocated space backwards or what's up? - // TODO(anton): UNDERSTAND - U64 align = post_align_pos - arena->pos; - result = base + arena->pos + align; - arena->pos += size + align;*/ - // Do Allen4th version until I understand the above. - result = ((U8*) arena) + arena->pos; - arena->pos += size; // increment pos by what we want to push - - U64 p = arena->pos; - U64 commit_p = arena->commit_pos; - if (p > commit_p) { - U64 p_aligned = AlignUpToPow2(p, M_COMMIT_BLOCK_SIZE); - U64 next_commit_p = ClampTop(p_aligned, arena->capacity); // Make sure new commit_p won't overshoot capacity - U64 commit_size = next_commit_p - commit_p; - m_commit((U8 *)arena + commit_p, commit_size); - arena->commit_pos = next_commit_p; - } - } else { - // NOTE(anton): Should implement some fallback but now we fail. - } - return result; -} - -root_function void -m_arena_pop_to(Arena *arena, U64 pos) { - if (pos < arena->pos) { - arena->pos = pos; - - U64 p = arena->pos; - U64 p_aligned = AlignUpToPow2(p, M_COMMIT_BLOCK_SIZE); - U64 next_commit_p = ClampTop(p_aligned, arena->capacity); - - U64 commit_p = arena->commit_pos; - if (next_commit_p < commit_p) { - U64 decommit_size = commit_p - next_commit_p; - m_decommit((U8 *)arena + next_commit_p, decommit_size); - arena->commit_pos = next_commit_p; - } - } -} - -root_function void m_arena_pop(Arena* arena, U64 size) { - U64 min_pos = sizeof(Arena); - U64 size_to_pop = Min(size, arena->pos); - U64 new_pos = arena->pos - size_to_pop; - new_pos = Max(new_pos, min_pos); - m_arena_pop_to(arena, new_pos); -} - -/** Push size and set the memory to zero. */ -root_function void* -m_arena_push_zero(Arena *arena, U64 size) { - void *result = m_arena_push(arena, size); - MemoryZero(result, size); - return result; -} - -root_function void -m_arena_clear(Arena *arena) -{ - // We clear the input arena by popping off everything - // after the actual Arena information. - m_arena_pop_to(arena, sizeof(Arena)); -} - -root_function void -m_arena_align(Arena *arena, U64 pow2_alignment) { - U64 p = arena->pos; - U64 p_aligned = AlignUpToPow2(p, pow2_alignment); - U64 z = p_aligned - p; - if (z > 0) { - m_arena_push(arena, z); - } -} - -root_function void -m_arena_release(Arena* arena) { - m_release(arena, arena->capacity); -} - -root_function ArenaTemp -m_arena_temp_begin(Arena *arena) { - ArenaTemp temp = { 0 }; - temp.arena = arena; - temp.pos = arena->pos; - return temp; -} - -root_function void -m_arena_temp_end(ArenaTemp temp) { - m_arena_pop_to(temp.arena, temp.pos); -} diff --git a/src/base/base_memory.h b/src/base/base_memory.h deleted file mode 100644 index 907a14c..0000000 --- a/src/base/base_memory.h +++ /dev/null @@ -1,61 +0,0 @@ -/* date = April 20th 2023 9:43 pm */ - -#ifndef BASE_MEMORY_H -#define BASE_MEMORY_H - -#if !defined(ARENA_COMMIT_GRANULARITY) -#define ARENA_COMMIT_GRANULARITY Kilobytes(4) -#endif - -#if !defined(ARENA_DECOMMIT_THRESHOLD) -#define ARENA_DECOMMIT_THRESHOLD Megabytes(64) -#endif - -#if !defined(M_DEFAULT_RESERVE_SIZE) -#define M_DEFAULT_RESERVE_SIZE Megabytes(512) -#endif - -#if !defined(M_COMMIT_BLOCK_SIZE) -#define M_COMMIT_BLOCK_SIZE Megabytes(64) -#endif - -// We store this information in the header of the allocated memory for the arena!!! -typedef struct Arena Arena; -struct Arena { - U64 pos; - U64 commit_pos; - U64 capacity; - U64 align; -}; - -typedef struct ArenaTemp ArenaTemp; -struct ArenaTemp { - Arena *arena; - U64 pos; -}; - -root_function void m_change_memory_noop(void *ptr, U64 size); - -root_function Arena* m_make_arena_reserve(U64 reserve_size); -root_function Arena* m_make_arena(); - -root_function void m_arena_release(Arena *arena); -root_function void* m_arena_push(Arena *arena, U64 size); -root_function void m_arena_pop_to(Arena *arena, U64 pos); -root_function void m_arena_pop(Arena* arena, U64 size); -root_function void m_arena_align(Arena *arena, U64 pow2_alignment); -root_function void* m_arena_push_zero(Arena *arena, U64 size); -root_function void m_arena_clear(Arena *arena); - -#define PushArray(arena, type, count) (type *)m_arena_push((arena), sizeof(type)*(count)) -#define PushArrayZero(arena, type, count) (type *)m_arena_push_zero((arena), sizeof(type)*(count)) - -//~ temp arena - -root_function ArenaTemp m_arena_temp_begin(Arena *arena); -root_function void m_arena_temp_end(ArenaTemp temp); - -// TODO(anton): Not sure when I should use this? -#define ArenaTempBlock(arena, name) ArenaTemp name = { 0 }; DeferLoop(name = m_arena_temp_begin(arena), m_arena_temp_end(name)) - -#endif //BASE_MEMORY_H diff --git a/src/base/base_strings.c b/src/base/base_strings.c deleted file mode 100644 index 1e9be2f..0000000 --- a/src/base/base_strings.c +++ /dev/null @@ -1,510 +0,0 @@ -#include - -//~ Helpers -root_function U64 -calculate_string_C_string_length(char *cstr) { - /*U64 length = 0; - for(char* p = cstr; p != '\0'; p += 1) { - length += 1; - } - return length;*/ - // A cool way to write this is this while loop - U64 length = 0; - for (/* empty here means just while loop*/; - /* While we're not at null terminator */ cstr[length]; - /* Increment */ length += 1); - - // Then we're actually done and just return length; - return length; -} - - -//~ Constructors -root_function String8 -str8(U8 *str, U64 size) { - String8 string; - string.str = str; - string.size = size; - return string; -} - -root_function String8 -str8_range(U8 *first, U8 *one_past_last) { - String8 string; - string.str = first; - string.size = (U64)(one_past_last - first); - return string; -} - -//~ Substrings -//- String8 -root_function String8 -str8_substr(String8 string, U64 first, U64 one_past_last) { - // We get a substring from the range one_past_last - first - U64 min = first; - U64 max = one_past_last; - // Logic to prepare for swithing input to a range instead of first/one_past_last - if (max > string.size) { - max = string.size; - } - if (min > string.size) { - min = string.size; - } - if (min > max) { - U64 swap = min; - min = max; - max = swap; - } - string.size = max - min; - string.str += min; // Increment the pointer of the String8 to the min. - return string; -} - -root_function String8 str8_prefix(String8 string, U64 size) { return str8_substr(string, 0, size); } -root_function String8 str8_chop(String8 string, U64 amount) { return str8_substr(string, 0, string.size-amount); } -root_function String8 str8_suffix(String8 string, U64 size) { return str8_substr(string, string.size-size, string.size); } -root_function String8 str8_skip(String8 string, U64 amount) { return str8_substr(string, amount, string.size); } - -// String16 -// String32 - -//~ Lists -//- String8 -root_function void -str8_list_push_node(String8List *list, String8Node *n) { - QueuePush(list->first, list->last, n); - list->node_count += 1; - list->total_size += n->string.size; -} - -root_function void -str8_list_push_node_front(String8List *list, String8Node *n) { - QueuePushFront(list->first, list->last, n); - list->node_count += 1; - list->total_size += n->string.size; -} - -// Wrapper that pushes the memory for a node onto the arena, and then puts the node in the linked list (in the back). -root_function void -str8_list_push(Arena *arena, String8List *list, String8 string) { - String8Node *n = PushArrayZero(arena, String8Node, 1); - n->string = string; - str8_list_push_node(list, n); -} - -// Wrapper that pushes the memory for a node onto the arena, and then puts the node in the linked list (in the front). -root_function void -str8_list_push_front(Arena *arena, String8List *list, String8 string) { - String8Node *n = PushArrayZero(arena, String8Node, 1); - n->string = string; - str8_list_push_node_front(list, n); -} - -root_function void -str8_list_concat(String8List *list, String8List *to_push) { - // If to_push is a non-zero length String8List, - // we add it to the input list. - if (to_push->first) { - list->node_count += to_push->node_count; - list->total_size += to_push->total_size; - // If the input list's last element is null - // we had a zero length input list, and we just set the input list equal to to_push - if (list->last == 0) { - *list = *to_push; - } else { - // Else we append the to_push list to the input list. - list->last->next = to_push->first; - list->last = to_push->last; - } - } - // TODO(anton): Why are we zeroing the memory here? - MemoryZero(to_push, sizeof(*to_push)); - //LOG_NOT_IMPLEMENTED; -} - -// TODO(anton): Understand this function and write comments about the logic. -root_function String8List -str8_split(Arena *arena, String8 string, int split_count, String8 *splits) { - - String8List list = { 0 }; - - U64 split_start = 0; - for (U64 i = 0; i < string.size; i += 1) - { - B32 was_split = 0; - for (int split_idx = 0; split_idx < split_count; split_idx += 1) - { - B32 match = 0; - if (i + splits[split_idx].size <= string.size) - { - match = 1; - for (U64 split_i = 0; split_i < splits[split_idx].size && i + split_i < string.size; split_i += 1) - { - if (splits[split_idx].str[split_i] != string.str[i + split_i]) - { - match = 0; - break; - - } - } - } - if (match) - { - String8 split_string = str8(string.str + split_start, i - split_start); - str8_list_push(arena, &list, split_string); - split_start = i + splits[split_idx].size; - i += splits[split_idx].size - 1; - was_split = 1; - break; - } - } - - if (was_split == 0 && i == string.size - 1) - { - String8 split_string = str8(string.str + split_start, i + 1 - split_start); - str8_list_push(arena, &list, split_string); - break; - } - } - - return list; -} - -// TODO(anton): Understand this function and write good comments explaining. -root_function String8 -str8_list_join(Arena *arena, String8List list, StringJoin *optional_params) { - // rjf: setup join parameters - StringJoin join = { 0 }; - if (optional_params != 0) - { - MemoryCopy(&join, optional_params, sizeof(join)); - } - - // rjf: calculate size & allocate - U64 sep_count = 0; - if (list.node_count > 1) - { - sep_count = list.node_count - 1; - } - String8 result = { 0 }; - result.size = (list.total_size + join.pre.size + - sep_count*join.sep.size + join.post.size); - result.str = PushArray(arena, U8, result.size + 1); - - // rjf: fill - U8 *ptr = result.str; - MemoryCopy(ptr, join.pre.str, join.pre.size); - ptr += join.pre.size; - for (String8Node *node = list.first; node; node = node->next) - { - MemoryCopy(ptr, node->string.str, node->string.size); - ptr += node->string.size; - if (node != list.last) - { - MemoryCopy(ptr, join.sep.str, join.sep.size); - ptr += join.sep.size; - } - } - MemoryCopy(ptr, join.post.str, join.post.size); - ptr += join.post.size; - - // rjf: add null - result.str[result.size] = 0; - - return result; -} - -//~ Allocation and format strings -root_function String8 -str8_copy(Arena *arena, String8 string) { - String8 result; - result.size = string.size; - result.str = PushArray(arena, U8, string.size + 1); - MemoryCopy(result.str, string.str, string.size); - result.str[string.size] = 0; // TODO(anton): What is this? - return result; -} - -root_function String8 -str8_pushfv(Arena *arena, char *fmt, va_list args) { - - // Might need to try a second time so copy args - va_list args2; - va_copy(args2, args); - - // Try to build string using 1024 bytes - U64 buffer_size = 1024; - U8 *buffer = PushArray(arena, U8, buffer_size); - // The vsnprintf takes the bundled arguments list args and puts the format strings it into buffer. - U64 actual_size = vsnprintf((char*)buffer, buffer_size, fmt, args); - - String8 result = { 0 }; - if (actual_size < buffer_size) { - // The first try worked and we can pop whatever wasn't used from the buffer - // and get our resulting string. - m_arena_pop(arena, buffer_size - actual_size - 1); // -1 because of null terminated in char *fmt? - result = str8(buffer, actual_size); - } else { - // If first try failed we try again with better size - m_arena_pop(arena, buffer_size); - U8 *fixed_buffer = PushArray(arena, U8, actual_size + 1); - U64 final_size = vsnprintf((char*)fixed_buffer, actual_size + 1, fmt, args2); - result = str8(fixed_buffer, final_size); - } - - // va_end to help compiler do its thing. - va_end(args2); - - return result; -} - -root_function String8 -str8_pushf(Arena *arena, char*fmt, ...) { - String8 result = { 0 }; - va_list args; - va_start(args, fmt); - result = str8_pushfv(arena, fmt, args); - va_end(args); - return result; -} - -root_function void -str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...) { - va_list args; - va_start(args, fmt); - String8 string = str8_pushfv(arena, fmt, args); - va_end(args); - str8_list_push(arena, list, string); -} - -//~ Unicode conversions - -#define bitmask1 0x01 // Mask first bit -#define bitmask2 0x03 // Mask 2 bits, 3 = 0x03 = 0000 0011 = 2^2 - 1 -#define bitmask3 0x07 // Mask 3 bits, 7 = 0x07 = 0000 0111 = 2^3 - 1 -#define bitmask4 0x0F // Mask 4 bits, 15 = 0x0F = 0000 1111 = 2^4 - 1 -#define bitmask5 0x1F // Mask 5 bits, 31 = 0x1F = 0001 1111 = 2^5 - 1 -#define bitmask6 0x3F // Mask 6 bits, 63 = 0x3F = 0011 1111 = 2^6 - 1 -#define bitmask7 0x7F // Mask 7 bits, 127 = 0x7F = 0111 1111 = 2^7 - 1 -#define bitmask8 0xFF // Mask 8 bits, 255 = 0xFF = 1111 1111 = 2^8 - 1 - -// Note that we're only decoding valid cases and not handling invalid/errors -root_function DecodeCodepoint -decode_from_utf8(U8 *str, U64 max) { - // This table will give us wheter or not we have a codepoint encoded by one, two, three or four bytes. - local_persist U8 utf8_class[] = { - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 1, 1, 1, - 0, 0, 0, 0, - 0, 0, 0, 0, - 2, 2, 2, 2, - 3, 3, - 4, - 5 // error - }; - - DecodeCodepoint result = { ~((U32)0), 1 }; - // We'll shift out the lowest 3 bits since those are not important in the decoding. - // This is the byte >> 3 into the static array. - U8 byte = str[0]; - U8 byte_class = utf8_class[byte >> 3]; - - switch (byte_class) { - case 1: { - // Just a single byte encoding. - result.codepoint = byte; // Actually the 8th bit must be zero for valid UTF encoding. - } break; - - case 2: { - if (2 <= max) { - U8 cont_byte = str[1]; - // Check the second byte - if (utf8_class[cont_byte >> 3] == 0) { - // codepoint is 32-bits - // The case with two bytes has byte1 110xxxxx, ie encoded in the last 5 bits. - // and byte2 is 10xxxxxx, encoded in the last 6 bits. So we use mask5 on first byte, shift by 6, - // and mask6 on second byte. - result.codepoint = (byte & bitmask5) << 6; - result.codepoint |= (cont_byte & bitmask6); - result.advance = 2; - } - } - } break; - - case 3: { - if (3 <= max) { - // encoded by 3 bytes, so we have two more cont_bytes. - U8 cont_byte[2] = { str[1], str[2] }; - if (utf8_class[cont_byte[0] >> 3] == 0 && utf8_class[cont_byte[1] >> 3] == 0) { - // For this case the first byte is encoded in the last 4 bits, 1110xxxx - // The second and third is 10xxxxxx (last 6 bits) - result.codepoint = (byte & bitmask4) << 12; - result.codepoint |= (cont_byte[0] & bitmask6) << 6; - result.codepoint |= (cont_byte[1] & bitmask6); - result.advance = 3; - } - } - } break; - - case 4: { - if (4 <= max) { - U8 cont_byte[3] = { str[1], str[2], str[3] }; - if (utf8_class[cont_byte[0] >> 3] == 0 && - utf8_class[cont_byte[1] >> 3] == 0 && - utf8_class[cont_byte[2] >> 3] == 0) { - // Here first byte is encoded in last 3 bits, and byte 2,3,4 are encoded in last 6 bits. - // Thus we shift the first byte by 3*6 = 18 bits into the 32 bit codepoint; - result.codepoint = (byte & bitmask3) << 18; - result.codepoint |= (cont_byte[0] & bitmask6) << 12; - result.codepoint |= (cont_byte[1] & bitmask6) << 6; - result.codepoint |= (cont_byte[2] & bitmask6); - result.advance = 4; - } - } - } break; - } - - return result; -} - -// Encode function -root_function U32 -utf8_from_codepoint(U8* out, U32 codepoint) { - U8 bit8 = 0x80; - U32 advance = 0; - - if (codepoint <= bitmask7 /* 0111 1111 */) { - // We know that the whole encoding is in the last 7 bits, so it's a 1 byte encoding - out[0] = (U8)codepoint; - advance = 1; - - } else if (codepoint <= 0x07FF /*0000 0111 1111 1111*/) { - // The case with two bytes has byte1 110xxxxx, ie encoded in the last 5 bits. - // and byte2 is 10xxxxxx, encoded in the last 6 bits. - out[0] = (bitmask2 << 6) | ((codepoint >> 6) & bitmask5); - out[1] = bit8 | (codepoint & bitmask6); - advance = 2; - - } else if (codepoint <= 0xFFFF /* 1111 1111 1111 1111 */) { - // For this case the first byte is encoded in the last 4 bits, 1110xxxx - // The second and third is 10xxxxxx (last 6 bits) - out[0] = (bitmask3 << 5) | ((codepoint >> 12) & bitmask4); - out[1] = bit8 | ((codepoint >> 6) & bitmask6); - out[2] = bit8 | ((codepoint) & bitmask6); - advance = 3; - - } else if (codepoint <= 0x10FFFF /*0001 0000 1111 1111 1111 1111 */) { - // Here first byte is encoded in last 3 bits, and byte 2,3,4 are encoded in last 6 bits. - // Thus we shift the first byte by 3*6 = 18 bits into the 32 bit codepoint; - out[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3); - out[1] = bit8 | ((codepoint >> 12) & bitmask6); - out[2] = bit8 | ((codepoint >> 6) & bitmask6); - out[3] = bit8 | ((codepoint) & bitmask6); - advance = 4; - } else { - out[0] = '?'; // ERrror? - advance = 1; - } - - return advance; -} - -root_function DecodeCodepoint decode_from_utf16(U16 *str, U64 max) { - DecodeCodepoint result = { ~((U32)0), 1 }; - result.codepoint = str[0]; - result.advance = 1; - // Usually codepoints fit into a single 16 bit chunk. - // But when we're not in the ranges 0x0000 to 0xD7FF and 0xE000 to 0xFFFF, - // we need two 16 bit stores. - // So what we have in str[0] = W1 is the "high surrogate", and - // str[1] = W2 is the "low surrogate". We then get the codepoint U = U' + 0x10000, - // where U' is a 20-bit number with the 10 lower bits from W1 in the high bits, and 10 lower bits of W2 in the lower. - if (max > 1) { - U16 w1 = str[0]; - U16 w2 = str[1]; - if (0xD800 <= w1 && w1 < 0xDC00 && 0xDC00 <= w2 && w2 < 0xE000) { - // Get W1 ten bits - U16 y = w1 - 0xD800; - U16 x = w2 - 0xDC00; - U32 uprim = (y << 10) | x; - result.codepoint = uprim + 0x10000; - result.advance = 2; - } - } - return result; -} - -root_function U32 utf16_from_codepoint(U16* out, U32 codepoint) { - - U32 advance = 1; - if (codepoint == ~((U32)0)) { - // Error? - out[0] = (U16)'?'; - } else if (codepoint < 0x10000) { - // single 16 bit code unit - out[0] = (U16)codepoint; - } else { - // store 20 bits in uprim - U32 uprim = codepoint - 0x10000; - // create W1 - out[0] = 0xD800 + (uprim >> 10); - // 0x03FF = bitmask for 10 lowest bits - // create W2 - out[1] = 0xDC00 + (uprim & 0x03FF); - advance = 2; - } - return advance; -} - -// TODO(anton): understand this and write comments on steps -root_function String8 -str8_from16(Arena *arena, String16 string) { - U64 cap = string.size*3; - U8 *str = PushArray(arena, U8, cap + 1); - U16 *ptr = string.str; - U16 *one_past_last = ptr + string.size; - U64 size = 0; - DecodeCodepoint consume; - for (; ptr < one_past_last;) { - consume = decode_from_utf16(ptr, one_past_last - ptr); - ptr += consume.advance; - size += utf8_from_codepoint(str + size, consume.codepoint); - } - str[size] = 0; - m_arena_pop(arena, cap - size); - return str8(str, size); -} - -root_function String8 -str8_from32(Arena *arena, String32 string) { - -} - -// TODO(anton): understand this and write comments on steps -root_function String16 -str16_from8(Arena* arena, String8 string) { - U64 cap = string.size*2; - U16 *str = PushArray(arena, U16, cap + 1); - U8 *ptr = string.str; - U8 *one_past_last = ptr + string.size; - U64 size = 0; - DecodeCodepoint consume; - for (; ptr < one_past_last;) { - consume = decode_from_utf8(ptr, one_past_last - ptr); - ptr += consume.advance; - size += utf16_from_codepoint(str + size, consume.codepoint); - } - str[size] = 0; - m_arena_pop(arena, 2*(cap - size)); - String16 result; - result.str = str; - result.size = size; - return result; -} - -root_function String32 -str32_from8(Arena *arena, String8 string) { - -} \ No newline at end of file diff --git a/src/base/base_strings.h b/src/base/base_strings.h deleted file mode 100644 index acdaec7..0000000 --- a/src/base/base_strings.h +++ /dev/null @@ -1,124 +0,0 @@ -/* date = April 23rd 2023 10:47 am */ - -#ifndef BASE_STRINGS_H -#define BASE_STRINGS_H - -// We decide that the basic string handling will be immutable. -// This means that whatever memory we got when initialising the string is what we have to live with. -// This will give us easy interfaces and work for most cases. -// The downside is that it might not have the best performance, always. -// In such cases we will develop special code for handling the special cases. - -///////////////////////// -//~ Basic string types, lists and arrays - -typedef struct String8 String8; -struct String8 { - U8* str; - U64 size; -}; - -typedef struct String16 String16; -struct String16 { - U16 *str; - U64 size; -}; - -typedef struct String32 String32; -struct String32 { - U32 *str; - U64 size; -}; - -typedef struct String8Node String8Node; -struct String8Node { - String8Node *next; - String8 string; -}; - -typedef struct String8List String8List; -struct String8List { - String8Node *first; - String8Node *last; - U64 node_count; - U64 total_size; -}; - -typedef struct String8Array String8Array; -struct String8Array { - U64 count; - String8 *v; -}; - -///////////////////////// -//~ String operations -typedef struct StringJoin StringJoin; -struct StringJoin { - String8 pre; - String8 sep; - String8 post; -}; - -typedef struct DecodeCodepoint DecodeCodepoint; -struct DecodeCodepoint { - U32 codepoint; - U32 advance; -}; - - -///////////////////////// -//~ String operations -//~ String functions - -//- Helpers -root_function U64 calculate_string_C_string_length(char *cstr); - -//- Constructors -root_function String8 str8(U8 *str, U64 size); -// Get a String8 from a C-string. -#define str8_C(cstring) str8((U8 *)cstring,calculate_string_C_string_length(cstring)) -// Get a String8 from a literal -#define str8_lit(s) str8((U8*)(s), sizeof(s) - 1) // -1 since we don't want null terminated, - // but this still stores the null char for interop with APIs - // that expect Cstrings. -// Specify a Str8 as just its struct members -#define str8_lit_comp(s) {(U8*)(s), sizeof(s)-1} -root_function String8 str8_range(U8 *first, U8 *one_past_last); - -#define str8_struct(ptr) str8((U8 *)(ptr), sizeof(*(ptr))) - -//- Substrings -root_function String8 str8_substr(String8 string, U64 first, U64 one_past_last); -root_function String8 str8_prefix(String8 string, U64 size); -root_function String8 str8_chop(String8 string, U64 amount); -root_function String8 str8_suffix(String8 string, U64 size); -root_function String8 str8_skip(String8 string, U64 amount); - -// Used in format strings! -#define str8_expand(s) (int)((s).size), ((s).str) - -//- Lists -root_function void str8_list_push_node(String8List *list, String8Node *n); -root_function void str8_list_push_node_front(String8List *list, String8Node *n); -root_function void str8_list_push(Arena *arena, String8List *list, String8 string); -root_function void str8_list_push_front(Arena *arena, String8List *list, String8 string); -root_function void str8_list_concat(String8List *list, String8List *to_push); -root_function String8List str8_split(Arena *arena, String8 string, int split_count, String8 *splits); -root_function String8 str8_list_join(Arena *arena, String8List list, StringJoin *optional_params); - -//- Allocation and format strings -root_function String8 str8_copy(Arena *arena, String8 string); -root_function String8 str8_pushfv(Arena *arena, char *fmt, va_list args); -root_function String8 str8_pushf(Arena *arena, char* fmt, ...); -root_function void str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...); - -//~ Unicode conversions -root_function DecodeCodepoint decode_from_utf8(U8 *str, U64 max); -root_function U32 utf8_from_codepoint(U8* out, U32 codepoint); -root_function DecodeCodepoint decode_from_utf16(U16 *str, U64 max); -root_function U32 utf16_from_codepoint(U16* out, U32 codepoint); -root_function String8 str8_from16(Arena *arena, String16 string); -root_function String8 str8_from32(Arena *arena, String32 string); -root_function String16 str16_from8(Arena* arena, String8 string); -root_function String32 str32_from8(Arena *arena, String8 string); -#endif //BASE_STRINGS_H diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c deleted file mode 100644 index 124d84f..0000000 --- a/src/base/base_thread_context.c +++ /dev/null @@ -1,82 +0,0 @@ - -root_function ThreadContext -thread_context_alloc(void) -{ - ThreadContext result = { 0 }; - - for (U64 arena_index = 0; arena_index < ArrayCount(result.arenas); arena_index += 1) - { - result.arenas[arena_index] = m_make_arena_reserve(Gigabytes(8)); - } - return result; -} - -root_function void -thread_context_release(ThreadContext *context) -{ - for (U64 arena_index = 0; arena_index < ArrayCount(context->arenas); arena_index += 1) - { - m_arena_release(context->arenas[arena_index]); - } -} - - -per_thread ThreadContext *tl_thread_context; - -no_name_mangle void -thread_context_set(ThreadContext *context) -{ - tl_thread_context = context; -} - -no_name_mangle ThreadContext * -thread_context_get(void) -{ - return tl_thread_context; -} - - -root_function B32 is_main_thread(void) -{ - ThreadContext *context = thread_context_get(); - return context->is_main_thread; -} - -root_function ArenaTemp -scratch_get(Arena **conflicts, U64 conflict_count) -{ - ArenaTemp scratch = { 0 }; - ThreadContext *thread_context = thread_context_get(); - for (U64 arena_index = 0; arena_index < ArrayCount(thread_context->arenas); arena_index += 1) - { - B32 is_conflicting = 0; - for(Arena **conflict = conflicts; conflict < conflicts+conflict_count; conflict += 1) - { - if(*conflict == thread_context->arenas[arena_index]) - { - is_conflicting = 1; - break; - } - } - if(is_conflicting == 0) - { - scratch.arena = thread_context->arenas[arena_index]; - scratch.pos = scratch.arena->pos; - break; - } - } - return scratch; -} - -root_function void -base_main_thread_entry(void (*entry)(void), U64 argument_count, char **arguments) -{ - // Here we get memory for the thread arenas, and notify that it's a main thread. - ThreadContext thread_context = thread_context_alloc(); - thread_context.is_main_thread = 1; - // Here we set it to the global thread context variable - thread_context_set(&thread_context); - // Then call the entry point function for our program - entry(); - thread_context_release(&thread_context); -} \ No newline at end of file diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h deleted file mode 100644 index 42a0776..0000000 --- a/src/base/base_thread_context.h +++ /dev/null @@ -1,39 +0,0 @@ -/* date = April 29th 2023 9:18 pm */ - -#ifndef BASE_THREAD_CONTEXT_H -#define BASE_THREAD_CONTEXT_H - -typedef struct ThreadContext ThreadContext; -struct ThreadContext -{ - Arena *arenas[2]; // WHy 2 arenas? - char *file_name; - U64 line_number; - U8 thread_name[32]; - U64 thread_name_size; - B32 is_main_thread; -}; - -//root_function ThreadContext make_thread_context(void); - -root_function ThreadContext thread_context_alloc(void); -root_function void thread_context_release(ThreadContext *context); - -no_name_mangle void -thread_context_set(ThreadContext *context); -no_name_mangle ThreadContext * -thread_context_gett(void); - - -root_function B32 is_main_thread(void); - -//~ scratch memory -root_function ArenaTemp scratch_get(Arena **conflicts, U64 conflict_count); -#define scratch_release(temp) m_arena_temp_end(temp) - -//~ entry -// Takes a function pointer to the app entry function. -root_function void -base_main_thread_entry(void (*entry)(void), U64 argument_count, char **arguments); - -#endif //BASE_THREAD_CONTEXT_H diff --git a/src/draw/draw.c b/src/draw/draw.c deleted file mode 100644 index 9968281..0000000 --- a/src/draw/draw.c +++ /dev/null @@ -1,263 +0,0 @@ - - -///////////////////////// -//~ Draw globals -global D_State *d_state = 0; -per_thread D_ThreadCtx *d_thread_ctx = 0; - -// temp color stuff -global F32 g_text_color[4] = {0.95f, 0.9f, 0.94f, 1.0f}; -global F32 g_rect_color[4] = {0.6f, 0.5f, 0.6f, 1.0f}; - - -//////////////////////////////// -//~ Stack helper macros - -#define D_StackPush(node_type, val_type, name, new_val) \ -{\ -Arena *arena = D_active_arena();\ -D_Bucket *bucket = D_active_bucket();\ -node_type *node_v = bucket->name##_free;\ -if(node_v != 0) {StackPop(bucket->name##_free);}\ -else {node_v = PushArray(arena, node_type, 1);}\ -node_v->v = new_val;\ -new_val = bucket->name##_stack_top->v;\ -StackPush(bucket->name##_stack_top, node_v);\ -bucket->last_cmd_stack_gen = bucket->current_stack_gen;\ -bucket->current_stack_gen += 1;\ -return new_val;\ -} - -#define D_StackPop(node_type, val_type, name) \ -{\ -val_type result = d_thread_ctx->name##_nil_stack_top.v;\ -D_Bucket *bucket = D_active_bucket();\ -if(bucket->name##_stack_top != &d_thread_ctx->name##_nil_stack_top)\ -{\ -node_type *node = bucket->name##_stack_top;\ -result = node->v;\ -StackPop(bucket->name##_stack_top);\ -StackPush(bucket->name##_free, node);\ -bucket->last_cmd_stack_gen = bucket->current_stack_gen;\ -bucket->current_stack_gen += 1;\ -}\ -return result;\ -} - -#define D_StackTop(node_type, val_type, name) \ -{\ -D_Bucket *bucket = D_active_bucket();\ -val_type result = bucket->name##_stack_top->v;\ -return result;\ -} - -///////////////////////// -//~ "Generated" code -#include "draw_meta.c" - -///////////////////////// -//~ Layer init -root_function D_InitReceipt -D_init(R_InitReceipt r_init_receipt, F_InitReceipt f_init_receipt) -{ - if(is_main_thread() && d_state == 0) - { - Arena* arena = m_make_arena_reserve(Megabytes(2)); - d_state = PushArrayZero(arena, D_State, 1); - d_state->arena = arena; - d_state->font_texture = F_atlas_texture_handle(); - D_ensure_thread_initialised(); - } - D_InitReceipt receipt = {0}; - return receipt; -} - -root_function void -D_ensure_thread_initialised(void) -{ - if(d_thread_ctx == 0) - { - Arena *arena = m_make_arena_reserve(Megabytes(1)); - d_thread_ctx = PushArrayZero(arena, D_ThreadCtx, 1); - d_thread_ctx->arena = arena; - d_thread_ctx->fallback_arena = m_make_arena_reserve(Megabytes(256)); - D_InitBucketStacks(&d_thread_ctx->fallback_bucket); - d_thread_ctx->bucket_selection_fallback.arena = d_thread_ctx->fallback_arena; - d_thread_ctx->bucket_selection_fallback.bucket = &d_thread_ctx->fallback_bucket; - d_thread_ctx->bucket_selection_top = &d_thread_ctx->bucket_selection_fallback; - D_InitThreadStackTops; - } -} - -///////////////////////// -//~ Draw functions - - -root_function void -D_frame_begin() { - D_ensure_thread_initialised(); -} - -root_function void -D_frame_end() -{ - -} - -//- Rect -root_function R_Rect2DInst * -D_rect2D_(Rng2_F32 rect, D_RectParams *rect_params) -{ - Arena* arena = D_active_arena(); - D_Bucket *bucket = D_active_bucket(); - R_Pass *pass = D_pass_from_bucket(arena, bucket, R_PassKind_UI); - R_PassParams_UI *pass_params = pass->params_ui; - R_BatchGroup2DNode *batch_group = pass_params->rects.last; - R_Handle tex = d_state->font_texture; - - // If we don't have a batch group yet we initialise it here. - // Eventually we will also check for what different textures we have, since - // we batch by texture. What about transform? - // TODO(anton): understand buckets in rjf codebase. - if(batch_group == 0 || bucket->last_cmd_stack_gen != bucket->current_stack_gen) - { - batch_group = PushArrayZero(arena, R_BatchGroup2DNode, 1); - QueuePush(pass_params->rects.first, pass_params->rects.last, batch_group); - pass_params->rects.count += 1; - batch_group->params.albedo_tex = tex; - batch_group->params.albedo_tex_sample_kind = bucket->tex2d_sample_kind_stack_top->v; - Mat3x3_F32 xform2d = {0.0f}; - batch_group->params.xform2d = xform2d; - } - // Here we get the available memory in a batch of memory that can be filled with differen things. - // We get a chunk of that memory of the appropriate size for a R_Rect2DInst and fill it out. - R_Rect2DInst *inst = R_batch_list_push_struct(arena, &batch_group->batches, 256 /* capacity */, R_Rect2DInst); - inst->dst_rect = rect; - inst->src_rect = rect_params->src_rect; - inst->colors[Corner_00] = rect_params->color;//vec4_F32(0.6f, 0.5f, 0.6f, 1.0f); - inst->colors[Corner_01] = rect_params->color;//vec4_F32(0.6f, 0.5f, 0.6f, 1.0f); - inst->colors[Corner_10] = rect_params->color;//vec4_F32(0.6f, 0.5f, 0.6f, 1.0f); - inst->colors[Corner_11] = rect_params->color;//vec4_F32(0.6f, 0.5f, 0.6f, 1.0f); - inst->corner_radii[Corner_00] = rect_params->corner_radius; - inst->corner_radii[Corner_01] = rect_params->corner_radius; - inst->corner_radii[Corner_10] = rect_params->corner_radius; - inst->corner_radii[Corner_11] = rect_params->corner_radius; - inst->softness = rect_params->softness; - inst->border_thickness = rect_params->border_thickness; - inst->omit_texture = rect_params->omit_texture; - - return inst; -} - -root_function F32 -D_text2D(Vec2_F32 position, String8 string, Vec4_F32 color) -{ - Arena *arena = D_active_arena(); - ArenaTemp scratch = scratch_get(&arena, 1); - F_Run run = F_run_from_string(scratch.arena, string, position); - // The position we get in will be the start of where we want to put the text. - // Then we put a draw rectangle for each glyph in the string, and advance the pos. - // The return value from this function then is the length of the text string. - Vec2_F32 p = position; - for(F_Piece *piece = run.first_piece; piece != 0; piece = piece->next) - { - //break_debugger(); - D_RectParams params; - params.src_rect = piece->src_rect; - params.omit_texture = 0; - params.color = color; - Vec2_F32 dst_p0 = piece->dst_p0; - Vec2_F32 dst_p1 = piece->dst_p1; - Rng2_F32 rect = rng2_F32(dst_p0, dst_p1); - D_rect2D_(rect, ¶ms); - p.x += piece->advance; - } - scratch_release(scratch); - F32 result = p.x - position.x; - return result; -} - -/////////////////////////////////////////////////// -//~ Buckets - -root_function D_Bucket * -D_bucket_make(Arena *arena) -{ - D_Bucket *bucket = PushArrayZero(arena, D_Bucket, 1); - D_InitBucketStacks(bucket); - String8 name = str8_pushf(arena, "HejBucket"); - bucket->bucket_name = name; - return bucket; -} -// TODO(anton): bucket and pass list concat in place when needed - -root_function void -D_push_bucket(Arena *arena, D_Bucket *bucket) -{ - D_BucketSelectionNode *node = d_thread_ctx->bucket_selection_free; - if(node != 0) - { - StackPop(d_thread_ctx->bucket_selection_free); - } - else - { - node = PushArray(d_thread_ctx->arena, D_BucketSelectionNode, 1); - } - node->arena = arena; - node->bucket = bucket; - StackPush(d_thread_ctx->bucket_selection_top, node); -} - -root_function void -D_pop_bucket(void) -{ - // Get the top bucket node, pop it and put it on the free list. - // If the top node is the fallback arena we will clear and reinit the fallback. - D_BucketSelectionNode *node = d_thread_ctx->bucket_selection_top; - if(node != &d_thread_ctx->bucket_selection_fallback) - { - StackPop(d_thread_ctx->bucket_selection_top); - StackPush(d_thread_ctx->bucket_selection_free, node); - } - if(d_thread_ctx->bucket_selection_top == &d_thread_ctx->bucket_selection_fallback) - { - m_arena_clear(d_thread_ctx->fallback_arena); - MemoryZeroStruct(&d_thread_ctx->fallback_bucket); - D_InitBucketStacks(&d_thread_ctx->fallback_bucket); - } -} - -root_function R_Pass * -D_pass_from_bucket(Arena *arena, D_Bucket *bucket, R_PassKind kind) -{ - R_PassNode *node = bucket->passes.last; - R_Pass *pass = 0; - // If we dont have a pass node at the last position, we push the pass to the list. - if(node == 0) - { - pass = R_pass_list_push(arena, &bucket->passes, kind); - } - else - { - pass = &node->v; - } - return pass; -} - -root_function Arena * -D_active_arena() -{ - return d_thread_ctx->bucket_selection_top->arena; -} - -root_function D_Bucket * -D_active_bucket(void) -{ - return d_thread_ctx->bucket_selection_top->bucket; -} - -root_function void -D_submit(R_Handle window_r, D_Bucket *bucket) -{ - R_window_submit(window_r, &bucket->passes); -} \ No newline at end of file diff --git a/src/draw/draw.h b/src/draw/draw.h deleted file mode 100644 index 4355e67..0000000 --- a/src/draw/draw.h +++ /dev/null @@ -1,113 +0,0 @@ -/* date = March 19th 2024 10:21 am */ - -#ifndef DRAW_H -#define DRAW_H - -typedef struct D_InitReceipt D_InitReceipt; -struct D_InitReceipt -{ - U64 u64[1]; -}; - - -/////////////////////////////////////////////////// -//~ "Generated" code. -#include "draw_meta.h" - -// The drawing bucket contains whatever should be drawn for this frame. -// And we can have several buckets that we submit. -// Each bucket has a list of passes. Each pass has a set of batch groups, ie -// a collection of the data that is supposed to be rendered for that pass. We can have -// several render batches per pass. -typedef struct D_Bucket D_Bucket; -struct D_Bucket -{ - R_PassList passes; - String8 bucket_name; - U64 last_cmd_stack_gen; - U64 current_stack_gen; - D_DeclBucketStacks; -}; - -typedef struct D_State D_State; -struct D_State -{ - Arena *arena; - R_Handle font_texture; -}; - - -typedef struct D_BucketSelectionNode D_BucketSelectionNode; -struct D_BucketSelectionNode -{ - D_BucketSelectionNode *next; - D_Bucket *bucket; - Arena *arena; -}; - -typedef struct D_ThreadCtx D_ThreadCtx; -struct D_ThreadCtx -{ - Arena *arena; - Arena *fallback_arena; - D_Bucket fallback_bucket; - D_BucketSelectionNode bucket_selection_fallback; - D_BucketSelectionNode *bucket_selection_top; - D_BucketSelectionNode *bucket_selection_free; - D_DeclThreadStackTops; -}; - -typedef struct D_RectParams D_RectParams; -struct D_RectParams -{ - R_Handle albedo_texture; - Rng2_F32 src_rect; - Vec4_F32 color; - F32 corner_radius; - F32 softness; - F32 border_thickness; - F32 omit_texture; -}; - -/////////////////////////////////////////////////// -//~ Draw fwd declarations -root_function D_InitReceipt D_init(R_InitReceipt r_init_receipt, F_InitReceipt f_init_receipt); -root_function void D_ensure_thread_initialised(void); -root_function void D_frame_begin(); -root_function void D_frame_end(); - -/////////////////////////////////////////////////// -//~ Buckets -root_function Arena *D_active_arena(); -root_function D_Bucket *D_bucket_make(Arena *arena); -root_function void D_bucket_concat_in_place(D_Bucket *to_push); -root_function void D_push_bucket(Arena *arena, D_Bucket *bucket); -root_function void D_pop_bucket(void); -#define D_BucketScope(arena, bucket) DeferLoop(D_push_bucket((arena), (bucket)), D_pop_bucket()) -root_function D_Bucket *D_active_bucket(void); -root_function void D_submit(R_Handle window_r, D_Bucket *bucket); - -/////////////////////////////////////////////////// -//~ Pass helpers -root_function R_Pass *D_pass_from_bucket(Arena *arena, D_Bucket *bucket, R_PassKind kind); - -/////////////////////////////////////////////////// -//~ UI pass build commands - -//- Rect -root_function R_Rect2DInst *D_rect2D_(Rng2_F32 rect, D_RectParams *p); -#define D_rect2D(r, ...) D_rect2D_((r), &(D_RectParams){.color = {1, 1, 1, 1}, __VA_ARGS__}) -//- Text -root_function F32 D_text2D(Vec2_F32 pos, String8 string, Vec4_F32 color); - -/////////////////////////////////////////////////// -//~ Grid build commands - - -/////////////////////////////////////////////////// -//~ Draw stacks. -// The nodes are generated by metadesk code in Ryan's codebase, I will do it manually here first. -// TODO(anton): generate this. -root_function R_Tex2DSampleKind D_push_tex2D_sample_kind(R_Tex2DSampleKind v); - -#endif //DRAW_H diff --git a/src/draw/draw_inc.c b/src/draw/draw_inc.c deleted file mode 100644 index 609b7f0..0000000 --- a/src/draw/draw_inc.c +++ /dev/null @@ -1 +0,0 @@ -#include "draw.c" \ No newline at end of file diff --git a/src/draw/draw_inc.h b/src/draw/draw_inc.h deleted file mode 100644 index 373be01..0000000 --- a/src/draw/draw_inc.h +++ /dev/null @@ -1,8 +0,0 @@ -/* date = March 19th 2024 7:46 pm */ - -#ifndef DRAW_INC_H -#define DRAW_INC_H - -#include "draw.h" - -#endif //DRAW_INC_H diff --git a/src/draw/draw_meta.c b/src/draw/draw_meta.c deleted file mode 100644 index 784bc59..0000000 --- a/src/draw/draw_meta.c +++ /dev/null @@ -1,3 +0,0 @@ - - -root_function R_Tex2DSampleKind D_push_tex2D_sample_kind(R_Tex2DSampleKind v) D_StackPush(D_Tex2DSampleKindNode, R_Tex2DSampleKind, tex2d_sample_kind, v) \ No newline at end of file diff --git a/src/draw/draw_meta.h b/src/draw/draw_meta.h deleted file mode 100644 index 76fad8e..0000000 --- a/src/draw/draw_meta.h +++ /dev/null @@ -1,30 +0,0 @@ -/* date = April 6th 2024 11:04 am */ - -#ifndef DRAW_META_H -#define DRAW_META_H - -typedef struct D_Tex2DSampleKindNode D_Tex2DSampleKindNode; struct D_Tex2DSampleKindNode {D_Tex2DSampleKindNode *next; R_Tex2DSampleKind v;}; - -#define D_DeclThreadStackTops \ -struct\ -{\ -D_Tex2DSampleKindNode tex2d_sample_kind_nil_stack_top;\ -} - -#define D_InitThreadStackTops \ -d_thread_ctx->tex2d_sample_kind_nil_stack_top.v = R_Tex2DSampleKind_Nearest;\ - -#define D_DeclBucketStacks \ -struct\ -{\ -D_Tex2DSampleKindNode *tex2d_sample_kind_stack_top; D_Tex2DSampleKindNode *tex2d_sample_kind_free;\ -} - - -#define D_InitBucketStacks(b) \ -(b)->tex2d_sample_kind_stack_top = &d_thread_ctx->tex2d_sample_kind_nil_stack_top;\ - - - - -#endif //DRAW_META_H diff --git a/src/font/font.c b/src/font/font.c deleted file mode 100644 index 606517c..0000000 --- a/src/font/font.c +++ /dev/null @@ -1,135 +0,0 @@ - -global F_State f_state; - -root_function F_State * -F_get_state() -{ - return &f_state; -} - -root_function Arena * -F_get_arena() -{ - return f_state.arena; -} - -root_function F_InitReceipt -F_init() { - //String8 font_path = str8_lit("D:\\dev\\app_codebase\\data\\LiberationMono-Regular.ttf"); - String8 font_path = str8_lit("D:\\dev\\app_codebase\\data\\arial.ttf"); - - // Load the ttf data into a simple buffer which is just temporary - ArenaTemp scratch = scratch_get(0, 0); - OS_Handle font_file = OS_file_open(OS_AccessFlag_Read, font_path); - OS_FileAttributes attrs = OS_attributes_from_file(font_file); - String8 ttf_temp = OS_file_read(scratch.arena, font_file, 0, attrs.size); - - f_state.arena = m_make_arena_reserve(Megabytes(FONT_ARENA_MEMORY_SIZE_MB)); - Arena* arena = f_state.arena; - - U64 pixel_height = 16; - // ASCII 32..126, 96 glyphs - U64 num_glyphs = 96; - U64 start_glyph = 32; - U64 atlas_size_x = 512; - U64 atlas_size_y = atlas_size_x; - - stbtt_bakedchar *cdata = PushArrayZero(arena, stbtt_bakedchar, num_glyphs); - U8 *baked_atlas = PushArrayZero(arena, U8, atlas_size_x*atlas_size_y); - - stbtt_BakeFontBitmap(ttf_temp.str, /* loaded font data from file */ - 0, /* offset */ - (float)pixel_height, /* pixel height */ - baked_atlas, /* pixel bitmap */ - atlas_size_x, atlas_size_y, /* pixel width and height */ - start_glyph, num_glyphs, - cdata); - - f_state.cdata = cdata; - f_state.baked_atlas = baked_atlas; - - //U8 color = 0; - //for(U32 i = 0; i < atlas_size_x; i++) - //{ - //for(U32 j = 0; j < atlas_size_y; j++) - //{ - //U32 index = j+i*atlas_size_x; - //if(index % 32 == 0) { - //if(color != 0) { - //color = 0; - //} else { - //color = 255; - //} - //} - //baked_atlas[index] = Max(index, 255); - // - //} - //} - - Vec2_S64 atlas_size = vec2_S64(atlas_size_x, atlas_size_y); - f_state.atlas.texture = R_tex2d_font_atlas(atlas_size, baked_atlas); - f_state.atlas.size = atlas_size; - f_state.atlas.start_glyph = start_glyph; - f_state.atlas.last_glyph = start_glyph + num_glyphs; - - F_InitReceipt result = {0}; - scratch_release(scratch); - return result; -} - -root_function U8 * -F_get_baked_atlas() -{ - return f_state.baked_atlas; -} - -root_function R_Handle -F_atlas_texture_handle() -{ - return f_state.atlas.texture; -} - -root_function F_Run -F_run_from_string(Arena *arena, String8 string, Vec2_F32 pos) -{ - F_Run run = {0}; - U64 start_glyph = f_state.atlas.start_glyph; - U64 end_glyph = f_state.atlas.last_glyph; - U64 width = f_state.atlas.size.x; - U64 height = f_state.atlas.size.y; - - float xpos = pos.x; - float ypos = pos.y; - int fill_rule = 1; - for(U64 i = 0; i < string.size; i++) - { - char c = (char)string.str[i]; - if(c < start_glyph || c >= end_glyph) { - continue; - } - stbtt_aligned_quad q; - int glyph_index = c-start_glyph; - - stbtt_GetBakedQuad(f_state.cdata, width, height, glyph_index, - &xpos, &ypos, &q, fill_rule); - Vec2_F32 src_p0 = vec2_F32(width*q.s0, height*q.t0); - Vec2_F32 src_p1 = vec2_F32(width*q.s1, height*q.t1); - F_Piece *piece = PushArrayZero(arena, F_Piece, 1); - QueuePush(run.first_piece, run.last_piece, piece); - - piece->texture = f_state.atlas.texture; - piece->src_rect = rng2_F32(src_p0, src_p1); - piece->advance = xpos; - piece->offset = vec2_F32(0.0f, ypos); - - - piece->dst_p0 = vec2_F32(q.x0, q.y0); - piece->dst_p1 = vec2_F32(q.x1, q.y1); - run.piece_count += 1; - run.advance += piece->advance; - - - } - - return run; -} diff --git a/src/font/font.h b/src/font/font.h deleted file mode 100644 index 0991f3e..0000000 --- a/src/font/font.h +++ /dev/null @@ -1,69 +0,0 @@ -#define STB_TRUETYPE_IMPLEMENTATION -#define STBTT_STATIC - -#define FONT_ARENA_MEMORY_SIZE_MB 16 - -#include "stb_truetype.h" - -typedef struct F_InitReceipt F_InitReceipt; -struct F_InitReceipt -{ - U64 u64[1]; -}; - -typedef struct F_Atlas F_Atlas; -struct F_Atlas -{ - R_Handle texture; - U64 start_glyph; - U64 last_glyph; - Vec2_S64 size; -}; - - -typedef struct F_State F_State; -struct F_State -{ - Arena* arena; - U8 *baked_atlas; - F_Atlas atlas; - stbtt_bakedchar *cdata; -}; - -typedef struct F_Piece F_Piece; -struct F_Piece -{ - F_Piece *next; - R_Handle texture; - Rng2_F32 src_rect; - Vec2_F32 dst_p0; - Vec2_F32 dst_p1; - Vec2_F32 offset; - F32 advance; - U32 decode_size; -}; - -// A sequence of glyphs to render, linked list implementation -typedef struct F_Run F_Run; -struct F_Run -{ - F_Piece *first_piece; - F_Piece *last_piece; - U64 piece_count; - F32 advance; -}; - - - - - - - -//////////////////////////// -//~ Font forward declarations -root_function Arena *F_get_font_arena(); -root_function F_InitReceipt F_init(); -root_function U8 *F_get_baked_atlas(); -root_function R_Handle F_atlas_texture_handle(); -root_function F_Run F_run_from_string(Arena *arena, String8 string, Vec2_F32 position); -root_function F_State *F_get_state(); // TODO remove this its only for d3d11 shutdown crap \ No newline at end of file diff --git a/src/font/font_inc.c b/src/font/font_inc.c deleted file mode 100644 index 863d67b..0000000 --- a/src/font/font_inc.c +++ /dev/null @@ -1,3 +0,0 @@ - - -#include "font.c" diff --git a/src/font/font_inc.h b/src/font/font_inc.h deleted file mode 100644 index f1fd063..0000000 --- a/src/font/font_inc.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef FONT_INC_H -#define FONT_INC_H - -#include "font.h" - - -#endif /* FONT_INC_H */ diff --git a/src/font/stb_truetype.h b/src/font/stb_truetype.h deleted file mode 100644 index 4df0aac..0000000 --- a/src/font/stb_truetype.h +++ /dev/null @@ -1,5078 +0,0 @@ -// stb_truetype.h - v1.26 - public domain -// authored from 2009-2021 by Sean Barrett / RAD Game Tools -// -// ======================================================================= -// -// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES -// -// This library does no range checking of the offsets found in the file, -// meaning an attacker can use it to read arbitrary memory. -// -// ======================================================================= -// -// This library processes TrueType files: -// parse files -// extract glyph metrics -// extract glyph shapes -// render glyphs to one-channel bitmaps with antialiasing (box filter) -// render glyphs to one-channel SDF bitmaps (signed-distance field/function) -// -// Todo: -// non-MS cmaps -// crashproof on bad data -// hinting? (no longer patented) -// cleartype-style AA? -// optimize: use simple memory allocator for intermediates -// optimize: build edge-list directly from curves -// optimize: rasterize directly from curves? -// -// ADDITIONAL CONTRIBUTORS -// -// Mikko Mononen: compound shape support, more cmap formats -// Tor Andersson: kerning, subpixel rendering -// Dougall Johnson: OpenType / Type 2 font handling -// Daniel Ribeiro Maciel: basic GPOS-based kerning -// -// Misc other: -// Ryan Gordon -// Simon Glass -// github:IntellectualKitty -// Imanol Celaya -// Daniel Ribeiro Maciel -// -// Bug/warning reports/fixes: -// "Zer" on mollyrocket Fabian "ryg" Giesen github:NiLuJe -// Cass Everitt Martins Mozeiko github:aloucks -// stoiko (Haemimont Games) Cap Petschulat github:oyvindjam -// Brian Hook Omar Cornut github:vassvik -// Walter van Niftrik Ryan Griege -// David Gow Peter LaValle -// David Given Sergey Popov -// Ivan-Assen Ivanov Giumo X. Clanjor -// Anthony Pesch Higor Euripedes -// Johan Duparc Thomas Fields -// Hou Qiming Derek Vinyard -// Rob Loach Cort Stratton -// Kenney Phillis Jr. Brian Costabile -// Ken Voskuil (kaesve) -// -// VERSION HISTORY -// -// 1.26 (2021-08-28) fix broken rasterizer -// 1.25 (2021-07-11) many fixes -// 1.24 (2020-02-05) fix warning -// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) -// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined -// 1.21 (2019-02-25) fix warning -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() -// 1.19 (2018-02-11) GPOS kerning, STBTT_fmod -// 1.18 (2018-01-29) add missing function -// 1.17 (2017-07-23) make more arguments const; doc fix -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual -// 1.11 (2016-04-02) fix unused-variable warning -// 1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// variant PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer -// -// Full history can be found at the end of this file. -// -// LICENSE -// -// See end of file for license information. -// -// USAGE -// -// Include this file in whatever places need to refer to it. In ONE C/C++ -// file, write: -// #define STB_TRUETYPE_IMPLEMENTATION -// before the #include of this file. This expands out the actual -// implementation into that C/C++ file. -// -// To make the implementation private to the file that generates the implementation, -// #define STBTT_STATIC -// -// Simple 3D API (don't ship this, but it's fine for tools and quick start) -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture -// stbtt_GetBakedQuad() -- compute quad to draw for a given char -// -// Improved 3D API (more shippable): -// #include "stb_rect_pack.h" -- optional, but you really want it -// stbtt_PackBegin() -// stbtt_PackSetOversampling() -- for improved quality on small fonts -// stbtt_PackFontRanges() -- pack and renders -// stbtt_PackEnd() -// stbtt_GetPackedQuad() -// -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) -// stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- indexing for TTC font collections -// stbtt_GetNumberOfFonts() -- number of fonts for TTC font collections -// -// Render a unicode codepoint to a bitmap -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be -// -// Character advance/positioning -// stbtt_GetCodepointHMetrics() -// stbtt_GetFontVMetrics() -// stbtt_GetFontVMetricsOS2() -// stbtt_GetCodepointKernAdvance() -// -// Starting with version 1.06, the rasterizer was replaced with a new, -// faster and generally-more-precise rasterizer. The new rasterizer more -// accurately measures pixel coverage for anti-aliasing, except in the case -// where multiple shapes overlap, in which case it overestimates the AA pixel -// coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If -// this turns out to be a problem, you can re-enable the old rasterizer with -// #define STBTT_RASTERIZER_VERSION 1 -// which will incur about a 15% speed hit. -// -// ADDITIONAL DOCUMENTATION -// -// Immediately after this block comment are a series of sample programs. -// -// After the sample programs is the "header file" section. This section -// includes documentation for each API function. -// -// Some important concepts to understand to use this library: -// -// Codepoint -// Characters are defined by unicode codepoints, e.g. 65 is -// uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is -// the hiragana for "ma". -// -// Glyph -// A visual character shape (every codepoint is rendered as -// some glyph) -// -// Glyph index -// A font-specific integer ID representing a glyph -// -// Baseline -// Glyph shapes are defined relative to a baseline, which is the -// bottom of uppercase characters. Characters extend both above -// and below the baseline. -// -// Current Point -// As you draw text to the screen, you keep track of a "current point" -// which is the origin of each character. The current point's vertical -// position is the baseline. Even "baked fonts" use this model. -// -// Vertical Font Metrics -// The vertical qualities of the font, used to vertically position -// and space the characters. See docs for stbtt_GetFontVMetrics. -// -// Font Size in Pixels or Points -// The preferred interface for specifying font sizes in stb_truetype -// is to specify how tall the font's vertical extent should be in pixels. -// If that sounds good enough, skip the next paragraph. -// -// Most font APIs instead use "points", which are a common typographic -// measurement for describing font size, defined as 72 points per inch. -// stb_truetype provides a point API for compatibility. However, true -// "per inch" conventions don't make much sense on computer displays -// since different monitors have different number of pixels per -// inch. For example, Windows traditionally uses a convention that -// there are 96 pixels per inch, thus making 'inch' measurements have -// nothing to do with inches, and thus effectively defining a point to -// be 1.333 pixels. Additionally, the TrueType font data provides -// an explicit scale factor to scale a given font's glyphs to points, -// but the author has observed that this scale factor is often wrong -// for non-commercial fonts, thus making fonts scaled in points -// according to the TrueType spec incoherently sized in practice. -// -// DETAILED USAGE: -// -// Scale: -// Select how high you want the font to be, in points or pixels. -// Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute -// a scale factor SF that will be used by all other functions. -// -// Baseline: -// You need to select a y-coordinate that is the baseline of where -// your text will appear. Call GetFontBoundingBox to get the baseline-relative -// bounding box for all characters. SF*-y0 will be the distance in pixels -// that the worst-case character could extend above the baseline, so if -// you want the top edge of characters to appear at the top of the -// screen where y=0, then you would set the baseline to SF*-y0. -// -// Current point: -// Set the current point where the first character will appear. The -// first character could extend left of the current point; this is font -// dependent. You can either choose a current point that is the leftmost -// point and hope, or add some padding, or check the bounding box or -// left-side-bearing of the first character to be displayed and set -// the current point based on that. -// -// Displaying a character: -// Compute the bounding box of the character. It will contain signed values -// relative to . I.e. if it returns x0,y0,x1,y1, -// then the character should be displayed in the rectangle from -// to = 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9 - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} -#endif -// -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program (this compiles): get a single bitmap, print as ASCII art -// -#if 0 -#include -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -char ttf_buffer[1<<25]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif -// -// Output: -// -// .ii. -// @@@@@@. -// V@Mio@@o -// :i. V@V -// :oM@@M -// :@@@MM@M -// @@o o@M -// :@@. M@M -// @@@o@@@@ -// :M@@V:@@. -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program: print "Hello World!" banner, with bugs -// -#if 0 -char buffer[24<<20]; -unsigned char screen[20][79]; - -int main(int arg, char **argv) -{ - stbtt_fontinfo font; - int i,j,ascent,baseline,ch=0; - float scale, xpos=2; // leave a little padding in case the character extends left - char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness - - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); - stbtt_InitFont(&font, buffer, 0); - - scale = stbtt_ScaleForPixelHeight(&font, 15); - stbtt_GetFontVMetrics(&font, &ascent,0,0); - baseline = (int) (ascent*scale); - - while (text[ch]) { - int advance,lsb,x0,y0,x1,y1; - float x_shift = xpos - (float) floor(xpos); - stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb); - stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1); - stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]); - // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong - // because this API is really for baking character bitmaps into textures. if you want to render - // a sequence of characters, you really need to render each bitmap to a temp buffer, then - // "alpha blend" that into the working buffer - xpos += (advance * scale); - if (text[ch+1]) - xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]); - ++ch; - } - - for (j=0; j < 20; ++j) { - for (i=0; i < 78; ++i) - putchar(" .:ioVM@"[screen[j][i]>>5]); - putchar('\n'); - } - - return 0; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// INTEGRATION WITH YOUR CODEBASE -//// -//// The following sections allow you to supply alternate definitions -//// of C library functions used by stb_truetype, e.g. if you don't -//// link with the C runtime library. - -#ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - #ifndef STBTT_sqrt - #include - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif - - #ifndef STBTT_fmod - #include - #define STBTT_fmod(x,y) fmod(x,y) - #endif - - #ifndef STBTT_cos - #include - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif - - #ifndef STBTT_fabs - #include - #define STBTT_fabs(x) fabs(x) - #endif - - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// INTERFACE -//// -//// - -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ -#define __STB_INCLUDE_STB_TRUETYPE_H__ - -#ifdef STBTT_STATIC -#define STBTT_DEF static -#else -#define STBTT_DEF extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// private structure -typedef struct -{ - unsigned char *data; - int cursor; - int size; -} stbtt__buf; - -////////////////////////////////////////////////////////////////////////////// -// -// TEXTURE BAKING API -// -// If you use this API, you only have to call two functions ever. -// - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; -} stbtt_bakedchar; - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long -// if return is positive, the first unused row of the bitmap -// if return is negative, returns the negative of the number of characters that fit -// if return is 0, no characters fit and no rows were used -// This uses a very crappy packing. - -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right -} stbtt_aligned_quad; - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier -// Call GetBakedQuad with char_index = 'character - first_char', and it -// creates the quad you need to draw and advances the current position. -// -// The coordinate system used assumes y increases downwards. -// -// Characters will extend both above and below the current position; -// see discussion of "BASELINE" above. -// -// It's inefficient; you might want to c&p it and optimize it. - -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap); -// Query the font vertical metrics without having to create a font first. - - -////////////////////////////////////////////////////////////////////////////// -// -// NEW TEXTURE BAKING API -// -// This provides options for packing multiple fonts into one atlas, not -// perfectly but better than nothing. - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; - float xoff2,yoff2; -} stbtt_packedchar; - -typedef struct stbtt_pack_context stbtt_pack_context; -typedef struct stbtt_fontinfo stbtt_fontinfo; -#ifndef STB_RECT_PACK_VERSION -typedef struct stbrp_rect stbrp_rect; -#endif - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context); -// Initializes a packing context stored in the passed-in stbtt_pack_context. -// Future calls using this context will pack characters into the bitmap passed -// in here: a 1-channel bitmap that is width * height. stride_in_bytes is -// the distance from one row to the next (or 0 to mean they are packed tightly -// together). "padding" is the amount of padding to leave between each -// character (normally you want '1' for bitmaps you'll use as textures with -// bilinear filtering). -// -// Returns 0 on failure, 1 on success. - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); -// Cleans up the packing context and frees all memory. - -#define STBTT_POINT_SIZE(x) (-(x)) - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range); -// Creates character bitmaps from the font_index'th font found in fontdata (use -// font_index=0 if you don't know what that is). It creates num_chars_in_range -// bitmaps for characters with unicode values starting at first_unicode_char_in_range -// and increasing. Data for how to render them is stored in chardata_for_range; -// pass these to stbtt_GetPackedQuad to get back renderable quads. -// -// font_size is the full height of the character from ascender to descender, -// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed -// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() -// and pass that result as 'font_size': -// ..., 20 , ... // font max minus min y is 20 pixels tall -// ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall - -typedef struct -{ - float font_size; - int first_unicode_codepoint_in_range; // if non-zero, then the chars are continuous, and this is the first codepoint - int *array_of_unicode_codepoints; // if non-zero, then this is an array of unicode codepoints - int num_chars; - stbtt_packedchar *chardata_for_range; // output - unsigned char h_oversample, v_oversample; // don't set these, they're used internally -} stbtt_pack_range; - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges); -// Creates character bitmaps from multiple ranges of characters stored in -// ranges. This will usually create a better-packed bitmap than multiple -// calls to stbtt_PackFontRange. Note that you can call this multiple -// times within a single PackBegin/PackEnd. - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample); -// Oversampling a font increases the quality by allowing higher-quality subpixel -// positioning, and is especially valuable at smaller text sizes. -// -// This function sets the amount of oversampling for all following calls to -// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given -// pack context. The default (no oversampling) is achieved by h_oversample=1 -// and v_oversample=1. The total number of pixels required is -// h_oversample*v_oversample larger than the default; for example, 2x2 -// oversampling requires 4x the storage of 1x1. For best results, render -// oversampled textures with bilinear filtering. Look at the readme in -// stb/tests/oversample for information about oversampled fonts -// -// To use with PackFontRangesGather etc., you must set it before calls -// call to PackFontRangesGatherRects. - -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip); -// If skip != 0, this tells stb_truetype to skip any codepoints for which -// there is no corresponding glyph. If skip=0, which is the default, then -// codepoints without a glyph recived the font's "missing character" glyph, -// typically an empty box by convention. - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int align_to_integer); - -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects); -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects); -// Calling these functions in sequence is roughly equivalent to calling -// stbtt_PackFontRanges(). If you more control over the packing of multiple -// fonts, or if you want to pack custom data into a font texture, take a look -// at the source to of stbtt_PackFontRanges() and create a custom version -// using these functions, e.g. call GatherRects multiple times, -// building up a single array of rects, then call PackRects once, -// then call RenderIntoRects repeatedly. This may result in a -// better packing than calling PackFontRanges multiple times -// (or it may not). - -// this is an opaque structure that you shouldn't mess with which holds -// all the context needed from PackBegin to PackEnd. -struct stbtt_pack_context { - void *user_allocator_context; - void *pack_info; - int width; - int height; - int stride_in_bytes; - int padding; - int skip_missing; - unsigned int h_oversample, v_oversample; - unsigned char *pixels; - void *nodes; -}; - -////////////////////////////////////////////////////////////////////////////// -// -// FONT LOADING -// -// - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data); -// This function will determine the number of fonts in a font file. TrueType -// collection (.ttc) files may contain multiple fonts, while TrueType font -// (.ttf) files only contain one font. The number of fonts can be used for -// indexing with the previous function where the index is between zero and one -// less than the total fonts. If an error occurs, -1 is returned. - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); -// Each .ttf/.ttc file may have more than one font. Each font has a sequential -// index number starting from 0. Call this function to get the font offset for -// a given index; it returns -1 if the index is out of range. A regular .ttf -// file will only define one font and it always be at offset 0, so it will -// return '0' for index 0, and -1 for all other indices. - -// The following structure is defined publicly so you can declare one on -// the stack or as a global or etc, but you should treat it as opaque. -struct stbtt_fontinfo -{ - void * userdata; - unsigned char * data; // pointer to .ttf file - int fontstart; // offset of start of font - - int numGlyphs; // number of glyphs, needed for range checking - - int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph - - stbtt__buf cff; // cff font data - stbtt__buf charstrings; // the charstring index - stbtt__buf gsubrs; // global charstring subroutines index - stbtt__buf subrs; // private charstring subroutines index - stbtt__buf fontdicts; // array of font dicts - stbtt__buf fdselect; // map from glyph to fontdict -}; - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); -// Given an offset into the file that defines a font, this function builds -// the necessary cached info for the rest of the system. You must allocate -// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't -// need to do anything special to free it, because the contents are pure -// value data with no additional data structures. Returns 0 on failure. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER TO GLYPH-INDEX CONVERSIOn - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); -// If you're going to perform multiple operations on the same character -// and you want a speed-up, call this function with the character you're -// going to process, then use glyph-based functions instead of the -// codepoint-based functions. -// Returns 0 if the character codepoint is not defined in the font. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER PROPERTIES -// - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose "height" is 'pixels' tall. -// Height is measured as the distance from the highest ascender to the lowest -// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics -// and computing: -// scale = pixels / (ascent - descent) -// so if you prefer to measure height by the ascent only, use a similar calculation. - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose EM size is mapped to -// 'pixels' tall. This is probably what traditional APIs compute, but -// I'm not positive. - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); -// ascent is the coordinate above the baseline the font extends; descent -// is the coordinate below the baseline the font extends (i.e. it is typically negative) -// lineGap is the spacing between one row's descent and the next row's ascent... -// so you should advance the vertical position by "*ascent - *descent + *lineGap" -// these are expressed in unscaled coordinates, so you must multiply by -// the scale factor for a given size - -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap); -// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2 -// table (specific to MS/Windows TTF files). -// -// Returns 1 on success (table present), 0 on failure. - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1); -// the bounding box around all possible characters - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -// leftSideBearing is the offset from the current horizontal position to the left edge of the character -// advanceWidth is the offset from the current horizontal position to the next horizontal position -// these are expressed in unscaled coordinates - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); -// an additional amount to add to the 'advance' value between ch1 and ch2 - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -// as above, but takes one or more glyph indices for greater efficiency - -typedef struct stbtt_kerningentry -{ - int glyph1; // use stbtt_FindGlyphIndex - int glyph2; - int advance; -} stbtt_kerningentry; - -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info); -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length); -// Retrieves a complete list of all of the kerning pairs provided by the font -// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. -// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) - -////////////////////////////////////////////////////////////////////////////// -// -// GLYPH SHAPES (you probably don't need these, but they have to go before -// the bitmaps for C declaration-order reasons) -// - -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; -#endif - -#ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy,cx1,cy1; - unsigned char type,padding; - } stbtt_vertex; -#endif - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index); -// returns non-zero if nothing is drawn for this glyph - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); -// returns # of vertices and fills *vertices with the pointer to them -// these are expressed in "unscaled" coordinates -// -// The shape is a series of contours. Each one starts with -// a STBTT_moveto, then consists of a series of mixed -// STBTT_lineto and STBTT_curveto segments. A lineto -// draws a line from previous endpoint to its x,y; a curveto -// draws a quadratic bezier from previous endpoint to -// its x,y, using cx,cy as the bezier control point. - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); -// frees the data allocated above - -STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl); -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg); -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg); -// fills svg with the character's SVG data. -// returns data size or 0 if SVG not found. - -////////////////////////////////////////////////////////////////////////////// -// -// BITMAP RENDERING -// - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); -// frees the bitmap allocated below - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// allocates a large-enough single-channel 8bpp bitmap and renders the -// specified character/glyph at the specified scale into it, with -// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). -// *width & *height are filled out with the width & height of the bitmap, -// which is stored left-to-right, top-to-bottom. -// -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel -// shift for the character - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); -// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap -// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap -// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the -// width and height and positioning info for it first. - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint); -// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel -// shift for the character - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint); -// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering -// is performed (see stbtt_PackSetOversampling) - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -// get the bbox of the bitmap centered around the glyph origin; so the -// bitmap width is ix1-ix0, height is iy1-iy0, and location to place -// the bitmap top left is (leftSideBearing*scale,iy0). -// (Note that the bitmap uses y-increases-down, but the shape uses -// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); -// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel -// shift for the character - -// the following functions are equivalent to the above functions, but operate -// on glyph indices instead of Unicode codepoints (for efficiency) -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph); -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph); -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1); - - -// @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; -} stbtt__bitmap; - -// rasterize a shape with quadratic beziers into a bitmap -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap to draw into - float flatness_in_pixels, // allowable error of curve in pixels - stbtt_vertex *vertices, // array of vertices defining shape - int num_verts, // number of vertices in above array - float scale_x, float scale_y, // scale applied to input vertices - float shift_x, float shift_y, // translation applied to input vertices - int x_off, int y_off, // another translation applied to input - int invert, // if non-zero, vertically flip shape - void *userdata); // context for to STBTT_MALLOC - -////////////////////////////////////////////////////////////////////////////// -// -// Signed Distance Function (or Field) rendering - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata); -// frees the SDF bitmap allocated below - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff); -// These functions compute a discretized SDF field for a single character, suitable for storing -// in a single-channel texture, sampling with bilinear filtering, and testing against -// larger than some threshold to produce scalable fonts. -// info -- the font -// scale -- controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap -// glyph/codepoint -- the character to generate the SDF for -// padding -- extra "pixels" around the character which are filled with the distance to the character (not 0), -// which allows effects like bit outlines -// onedge_value -- value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) -// pixel_dist_scale -- what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale) -// if positive, > onedge_value is inside; if negative, < onedge_value is inside -// width,height -- output height & width of the SDF bitmap (including padding) -// xoff,yoff -- output origin of the character -// return value -- a 2D array of bytes 0..255, width*height in size -// -// pixel_dist_scale & onedge_value are a scale & bias that allows you to make -// optimal use of the limited 0..255 for your application, trading off precision -// and special effects. SDF values outside the range 0..255 are clamped to 0..255. -// -// Example: -// scale = stbtt_ScaleForPixelHeight(22) -// padding = 5 -// onedge_value = 180 -// pixel_dist_scale = 180/5.0 = 36.0 -// -// This will create an SDF bitmap in which the character is about 22 pixels -// high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled -// shape, sample the SDF at each pixel and fill the pixel if the SDF value -// is greater than or equal to 180/255. (You'll actually want to antialias, -// which is beyond the scope of this example.) Additionally, you can compute -// offset outlines (e.g. to stroke the character border inside & outside, -// or only outside). For example, to fill outside the character up to 3 SDF -// pixels, you would compare against (180-36.0*3)/255 = 72/255. The above -// choice of variables maps a range from 5 pixels outside the shape to -// 2 pixels inside the shape to 0..255; this is intended primarily for apply -// outside effects only (the interior range is needed to allow proper -// antialiasing of the font at *smaller* sizes) -// -// The function computes the SDF analytically at each SDF pixel, not by e.g. -// building a higher-res bitmap and approximating it. In theory the quality -// should be as high as possible for an SDF of this size & representation, but -// unclear if this is true in practice (perhaps building a higher-res bitmap -// and computing from that can allow drop-out prevention). -// -// The algorithm has not been optimized at all, so expect it to be slow -// if computing lots of characters or very large sizes. - - - -////////////////////////////////////////////////////////////////////////////// -// -// Finding the right font... -// -// You should really just solve this offline, keep your own tables -// of what font is what, and don't try to get it out of the .ttf file. -// That's because getting it out of the .ttf file is really hard, because -// the names in the file can appear in many possible encodings, in many -// possible languages, and e.g. if you need a case-insensitive comparison, -// the details of that depend on the encoding & language in a complex way -// (actually underspecified in truetype, but also gigantic). -// -// But you can use the provided functions in two possible ways: -// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on -// unicode-encoded names to try to find the font you want; -// you can run this before calling stbtt_InitFont() -// -// stbtt_GetFontNameString() lets you get any of the various strings -// from the file yourself and do your own comparisons on them. -// You have to have called stbtt_InitFont() first. - - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); -// returns the offset (not index) of the font that matches, or -1 if none -// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". -// if you use any other flag, use a font name like "Arial"; this checks -// the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); -// returns 1/0 whether the first string interpreted as utf8 is identical to -// the second string interpreted as big-endian utf16... useful for strings from next func - -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); -// returns the string (which may be big-endian double byte, e.g. for unicode) -// and puts the length in bytes in *length. -// -// some of the values for the IDs are below; for more see the truetype spec: -// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html -// http://www.microsoft.com/typography/otspec/name.htm - -enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7 -}; - -enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D -}; - -enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19 -}; - -#ifdef __cplusplus -} -#endif - -#endif // __STB_INCLUDE_STB_TRUETYPE_H__ - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// IMPLEMENTATION -//// -//// - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -#ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 -#endif - -#if STBTT_MAX_OVERSAMPLE > 255 -#error "STBTT_MAX_OVERSAMPLE cannot be > 255" -#endif - -typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1]; - -#ifndef STBTT_RASTERIZER_VERSION -#define STBTT_RASTERIZER_VERSION 2 -#endif - -#ifdef _MSC_VER -#define STBTT__NOTUSED(v) (void)(v) -#else -#define STBTT__NOTUSED(v) (void)sizeof(v) -#endif - -////////////////////////////////////////////////////////////////////////// -// -// stbtt__buf helpers to parse data from file -// - -static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor++]; -} - -static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b) -{ - if (b->cursor >= b->size) - return 0; - return b->data[b->cursor]; -} - -static void stbtt__buf_seek(stbtt__buf *b, int o) -{ - STBTT_assert(!(o > b->size || o < 0)); - b->cursor = (o > b->size || o < 0) ? b->size : o; -} - -static void stbtt__buf_skip(stbtt__buf *b, int o) -{ - stbtt__buf_seek(b, b->cursor + o); -} - -static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n) -{ - stbtt_uint32 v = 0; - int i; - STBTT_assert(n >= 1 && n <= 4); - for (i = 0; i < n; i++) - v = (v << 8) | stbtt__buf_get8(b); - return v; -} - -static stbtt__buf stbtt__new_buf(const void *p, size_t size) -{ - stbtt__buf r; - STBTT_assert(size < 0x40000000); - r.data = (stbtt_uint8*) p; - r.size = (int) size; - r.cursor = 0; - return r; -} - -#define stbtt__buf_get16(b) stbtt__buf_get((b), 2) -#define stbtt__buf_get32(b) stbtt__buf_get((b), 4) - -static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s) -{ - stbtt__buf r = stbtt__new_buf(NULL, 0); - if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r; - r.data = b->data + o; - r.size = s; - return r; -} - -static stbtt__buf stbtt__cff_get_index(stbtt__buf *b) -{ - int count, start, offsize; - start = b->cursor; - count = stbtt__buf_get16(b); - if (count) { - offsize = stbtt__buf_get8(b); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(b, offsize * count); - stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1); - } - return stbtt__buf_range(b, start, b->cursor - start); -} - -static stbtt_uint32 stbtt__cff_int(stbtt__buf *b) -{ - int b0 = stbtt__buf_get8(b); - if (b0 >= 32 && b0 <= 246) return b0 - 139; - else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108; - else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108; - else if (b0 == 28) return stbtt__buf_get16(b); - else if (b0 == 29) return stbtt__buf_get32(b); - STBTT_assert(0); - return 0; -} - -static void stbtt__cff_skip_operand(stbtt__buf *b) { - int v, b0 = stbtt__buf_peek8(b); - STBTT_assert(b0 >= 28); - if (b0 == 30) { - stbtt__buf_skip(b, 1); - while (b->cursor < b->size) { - v = stbtt__buf_get8(b); - if ((v & 0xF) == 0xF || (v >> 4) == 0xF) - break; - } - } else { - stbtt__cff_int(b); - } -} - -static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key) -{ - stbtt__buf_seek(b, 0); - while (b->cursor < b->size) { - int start = b->cursor, end, op; - while (stbtt__buf_peek8(b) >= 28) - stbtt__cff_skip_operand(b); - end = b->cursor; - op = stbtt__buf_get8(b); - if (op == 12) op = stbtt__buf_get8(b) | 0x100; - if (op == key) return stbtt__buf_range(b, start, end-start); - } - return stbtt__buf_range(b, 0, 0); -} - -static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out) -{ - int i; - stbtt__buf operands = stbtt__dict_get(b, key); - for (i = 0; i < outcount && operands.cursor < operands.size; i++) - out[i] = stbtt__cff_int(&operands); -} - -static int stbtt__cff_index_count(stbtt__buf *b) -{ - stbtt__buf_seek(b, 0); - return stbtt__buf_get16(b); -} - -static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) -{ - int count, offsize, start, end; - stbtt__buf_seek(&b, 0); - count = stbtt__buf_get16(&b); - offsize = stbtt__buf_get8(&b); - STBTT_assert(i >= 0 && i < count); - STBTT_assert(offsize >= 1 && offsize <= 4); - stbtt__buf_skip(&b, i*offsize); - start = stbtt__buf_get(&b, offsize); - end = stbtt__buf_get(&b, offsize); - return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start); -} - -////////////////////////////////////////////////////////////////////////// -// -// accessors to parse data from file -// - -// on platforms that don't allow misaligned reads, if we want to allow -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE - -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_int16 ttSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; } -static stbtt_uint32 ttULONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } -static stbtt_int32 ttLONG(stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag4(font, '1',0,0,0)) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - if (stbtt_tag(font, "true")) return 1; // Apple specification for TrueType fonts - return 0; -} - -// @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*4); - } - } - return -1; -} - -static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection) -{ - // if it's just a font, there's only one valid font - if (stbtt__isfont(font_collection)) - return 1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - return ttLONG(font_collection+8); - } - } - return 0; -} - -static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict) -{ - stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 }; - stbtt__buf pdict; - stbtt__dict_get_ints(&fontdict, 18, 2, private_loc); - if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0); - pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]); - stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff); - if (!subrsoff) return stbtt__new_buf(NULL, 0); - stbtt__buf_seek(&cff, private_loc[1]+subrsoff); - return stbtt__cff_get_index(&cff); -} - -// since most people won't use this, find this table the first time it's needed -static int stbtt__get_svg(stbtt_fontinfo *info) -{ - stbtt_uint32 t; - if (info->svg < 0) { - t = stbtt__find_table(info->data, info->fontstart, "SVG "); - if (t) { - stbtt_uint32 offset = ttULONG(info->data + t + 2); - info->svg = t + offset; - } else { - info->svg = 0; - } - } - return info->svg; -} - -static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart) -{ - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - info->cff = stbtt__new_buf(NULL, 0); - - cmap = stbtt__find_table(data, fontstart, "cmap"); // required - info->loca = stbtt__find_table(data, fontstart, "loca"); // required - info->head = stbtt__find_table(data, fontstart, "head"); // required - info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required - info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required - info->kern = stbtt__find_table(data, fontstart, "kern"); // not required - info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required - - if (!cmap || !info->head || !info->hhea || !info->hmtx) - return 0; - if (info->glyf) { - // required for truetype - if (!info->loca) return 0; - } else { - // initialization for CFF / Type2 fonts (OTF) - stbtt__buf b, topdict, topdictidx; - stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0; - stbtt_uint32 cff; - - cff = stbtt__find_table(data, fontstart, "CFF "); - if (!cff) return 0; - - info->fontdicts = stbtt__new_buf(NULL, 0); - info->fdselect = stbtt__new_buf(NULL, 0); - - // @TODO this should use size from table (not 512MB) - info->cff = stbtt__new_buf(data+cff, 512*1024*1024); - b = info->cff; - - // read the header - stbtt__buf_skip(&b, 2); - stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize - - // @TODO the name INDEX could list multiple fonts, - // but we just use the first one. - stbtt__cff_get_index(&b); // name INDEX - topdictidx = stbtt__cff_get_index(&b); - topdict = stbtt__cff_index_get(topdictidx, 0); - stbtt__cff_get_index(&b); // string INDEX - info->gsubrs = stbtt__cff_get_index(&b); - - stbtt__dict_get_ints(&topdict, 17, 1, &charstrings); - stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype); - stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff); - stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff); - info->subrs = stbtt__get_subrs(b, topdict); - - // we only support Type 2 charstrings - if (cstype != 2) return 0; - if (charstrings == 0) return 0; - - if (fdarrayoff) { - // looks like a CID font - if (!fdselectoff) return 0; - stbtt__buf_seek(&b, fdarrayoff); - info->fontdicts = stbtt__cff_get_index(&b); - info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff); - } - - stbtt__buf_seek(&b, charstrings); - info->charstrings = stbtt__cff_get_index(&b); - } - - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - info->svg = -1; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - case STBTT_PLATFORM_ID_UNICODE: - // Mac/iOS has these - // all the encodingIDs are unicode, so we don't bother to check it - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 end; - searchRange >>= 1; - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - { - stbtt_uint16 offset, start, last; - stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1); - - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - last = ttUSHORT(data + endCount + 2*item); - if (unicode_codepoint < start || unicode_codepoint > last) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item)); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } - } else if (format == 12 || format == 13) { - stbtt_uint32 ngroups = ttULONG(data+index_map+12); - stbtt_int32 low,high; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low < high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - if (format == 12) - return start_glyph + unicode_codepoint-start_char; - else // format == 13 - return start_glyph; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; -} - -STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy) -{ - v->type = type; - v->x = (stbtt_int16) x; - v->y = (stbtt_int16) y; - v->cx = (stbtt_int16) cx; - v->cy = (stbtt_int16) cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - STBTT_assert(!info->cff.size); - - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; // if length is 0, return -1 -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); - -STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - if (info->cff.size) { - stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1); - } else { - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - } - return 1; -} - -STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt_int16 numberOfContours; - int g; - if (info->cff.size) - return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0; - g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 1; - numberOfContours = ttSHORT(info->data + g); - return numberOfContours == 0; -} - -static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off, - stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy) -{ - if (start_off) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy); - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy); - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - return num_vertices; -} - -static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; - stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + 2*numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = (stbtt_int16) x; - } - - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = (stbtt_int16) y; - } - - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = scx = scy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - - if (next_move == i) { - if (i != 0) - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - - // now start the new one - start_off = !(flags & 1); - if (start_off) { - // if we start off with an off-curve point, then when we need to find a point on the curve - // where we can start, and we need to save some state for when we wraparound. - scx = x; - scy = y; - if (!(vertices[off+i+1].type & 1)) { - // next point is also a curve point, so interpolate an on-point curve - sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1; - sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1; - } else { - // otherwise just use the next point as our start point - sx = (stbtt_int32) vertices[off+i+1].x; - sy = (stbtt_int32) vertices[off+i+1].y; - ++i; // we're using point i+1 as the starting point, so skip it - } - } else { - sx = x; - sy = y; - } - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0); - was_off = 0; - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy); - } else if (numberOfContours < 0) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); - } - } else { - // numberOfCounters == 0, do nothing - } - - *pvertices = vertices; - return num_vertices; -} - -typedef struct -{ - int bounds; - int started; - float first_x, first_y; - float x, y; - stbtt_int32 min_x, max_x, min_y, max_y; - - stbtt_vertex *pvertices; - int num_vertices; -} stbtt__csctx; - -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} - -static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y) -{ - if (x > c->max_x || !c->started) c->max_x = x; - if (y > c->max_y || !c->started) c->max_y = y; - if (x < c->min_x || !c->started) c->min_x = x; - if (y < c->min_y || !c->started) c->min_y = y; - c->started = 1; -} - -static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1) -{ - if (c->bounds) { - stbtt__track_vertex(c, x, y); - if (type == STBTT_vcubic) { - stbtt__track_vertex(c, cx, cy); - stbtt__track_vertex(c, cx1, cy1); - } - } else { - stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy); - c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1; - c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1; - } - c->num_vertices++; -} - -static void stbtt__csctx_close_shape(stbtt__csctx *ctx) -{ - if (ctx->first_x != ctx->x || ctx->first_y != ctx->y) - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy) -{ - stbtt__csctx_close_shape(ctx); - ctx->first_x = ctx->x = ctx->x + dx; - ctx->first_y = ctx->y = ctx->y + dy; - stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy) -{ - ctx->x += dx; - ctx->y += dy; - stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0); -} - -static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3) -{ - float cx1 = ctx->x + dx1; - float cy1 = ctx->y + dy1; - float cx2 = cx1 + dx2; - float cy2 = cy1 + dy2; - ctx->x = cx2 + dx3; - ctx->y = cy2 + dy3; - stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2); -} - -static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n) -{ - int count = stbtt__cff_index_count(&idx); - int bias = 107; - if (count >= 33900) - bias = 32768; - else if (count >= 1240) - bias = 1131; - n += bias; - if (n < 0 || n >= count) - return stbtt__new_buf(NULL, 0); - return stbtt__cff_index_get(idx, n); -} - -static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index) -{ - stbtt__buf fdselect = info->fdselect; - int nranges, start, end, v, fmt, fdselector = -1, i; - - stbtt__buf_seek(&fdselect, 0); - fmt = stbtt__buf_get8(&fdselect); - if (fmt == 0) { - // untested - stbtt__buf_skip(&fdselect, glyph_index); - fdselector = stbtt__buf_get8(&fdselect); - } else if (fmt == 3) { - nranges = stbtt__buf_get16(&fdselect); - start = stbtt__buf_get16(&fdselect); - for (i = 0; i < nranges; i++) { - v = stbtt__buf_get8(&fdselect); - end = stbtt__buf_get16(&fdselect); - if (glyph_index >= start && glyph_index < end) { - fdselector = v; - break; - } - start = end; - } - } - if (fdselector == -1) stbtt__new_buf(NULL, 0); - return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector)); -} - -static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c) -{ - int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0; - int has_subrs = 0, clear_stack; - float s[48]; - stbtt__buf subr_stack[10], subrs = info->subrs, b; - float f; - -#define STBTT__CSERR(s) (0) - - // this currently ignores the initial width value, which isn't needed if we have hmtx - b = stbtt__cff_index_get(info->charstrings, glyph_index); - while (b.cursor < b.size) { - i = 0; - clear_stack = 1; - b0 = stbtt__buf_get8(&b); - switch (b0) { - // @TODO implement hinting - case 0x13: // hintmask - case 0x14: // cntrmask - if (in_header) - maskbits += (sp / 2); // implicit "vstem" - in_header = 0; - stbtt__buf_skip(&b, (maskbits + 7) / 8); - break; - - case 0x01: // hstem - case 0x03: // vstem - case 0x12: // hstemhm - case 0x17: // vstemhm - maskbits += (sp / 2); - break; - - case 0x15: // rmoveto - in_header = 0; - if (sp < 2) return STBTT__CSERR("rmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]); - break; - case 0x04: // vmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("vmoveto stack"); - stbtt__csctx_rmove_to(c, 0, s[sp-1]); - break; - case 0x16: // hmoveto - in_header = 0; - if (sp < 1) return STBTT__CSERR("hmoveto stack"); - stbtt__csctx_rmove_to(c, s[sp-1], 0); - break; - - case 0x05: // rlineto - if (sp < 2) return STBTT__CSERR("rlineto stack"); - for (; i + 1 < sp; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical - // starting from a different place. - - case 0x07: // vlineto - if (sp < 1) return STBTT__CSERR("vlineto stack"); - goto vlineto; - case 0x06: // hlineto - if (sp < 1) return STBTT__CSERR("hlineto stack"); - for (;;) { - if (i >= sp) break; - stbtt__csctx_rline_to(c, s[i], 0); - i++; - vlineto: - if (i >= sp) break; - stbtt__csctx_rline_to(c, 0, s[i]); - i++; - } - break; - - case 0x1F: // hvcurveto - if (sp < 4) return STBTT__CSERR("hvcurveto stack"); - goto hvcurveto; - case 0x1E: // vhcurveto - if (sp < 4) return STBTT__CSERR("vhcurveto stack"); - for (;;) { - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f); - i += 4; - hvcurveto: - if (i + 3 >= sp) break; - stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]); - i += 4; - } - break; - - case 0x08: // rrcurveto - if (sp < 6) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x18: // rcurveline - if (sp < 8) return STBTT__CSERR("rcurveline stack"); - for (; i + 5 < sp - 2; i += 6) - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack"); - stbtt__csctx_rline_to(c, s[i], s[i+1]); - break; - - case 0x19: // rlinecurve - if (sp < 8) return STBTT__CSERR("rlinecurve stack"); - for (; i + 1 < sp - 6; i += 2) - stbtt__csctx_rline_to(c, s[i], s[i+1]); - if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack"); - stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]); - break; - - case 0x1A: // vvcurveto - case 0x1B: // hhcurveto - if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack"); - f = 0.0; - if (sp & 1) { f = s[i]; i++; } - for (; i + 3 < sp; i += 4) { - if (b0 == 0x1B) - stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0); - else - stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]); - f = 0.0; - } - break; - - case 0x0A: // callsubr - if (!has_subrs) { - if (info->fdselect.size) - subrs = stbtt__cid_get_glyph_subrs(info, glyph_index); - has_subrs = 1; - } - // FALLTHROUGH - case 0x1D: // callgsubr - if (sp < 1) return STBTT__CSERR("call(g|)subr stack"); - v = (int) s[--sp]; - if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit"); - subr_stack[subr_stack_height++] = b; - b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v); - if (b.size == 0) return STBTT__CSERR("subr not found"); - b.cursor = 0; - clear_stack = 0; - break; - - case 0x0B: // return - if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr"); - b = subr_stack[--subr_stack_height]; - clear_stack = 0; - break; - - case 0x0E: // endchar - stbtt__csctx_close_shape(c); - return 1; - - case 0x0C: { // two-byte escape - float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6; - float dx, dy; - int b1 = stbtt__buf_get8(&b); - switch (b1) { - // @TODO These "flex" implementations ignore the flex-depth and resolution, - // and always draw beziers. - case 0x22: // hflex - if (sp < 7) return STBTT__CSERR("hflex stack"); - dx1 = s[0]; - dx2 = s[1]; - dy2 = s[2]; - dx3 = s[3]; - dx4 = s[4]; - dx5 = s[5]; - dx6 = s[6]; - stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0); - break; - - case 0x23: // flex - if (sp < 13) return STBTT__CSERR("flex stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = s[10]; - dy6 = s[11]; - //fd is s[12] - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - case 0x24: // hflex1 - if (sp < 9) return STBTT__CSERR("hflex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dx4 = s[5]; - dx5 = s[6]; - dy5 = s[7]; - dx6 = s[8]; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0); - stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5)); - break; - - case 0x25: // flex1 - if (sp < 11) return STBTT__CSERR("flex1 stack"); - dx1 = s[0]; - dy1 = s[1]; - dx2 = s[2]; - dy2 = s[3]; - dx3 = s[4]; - dy3 = s[5]; - dx4 = s[6]; - dy4 = s[7]; - dx5 = s[8]; - dy5 = s[9]; - dx6 = dy6 = s[10]; - dx = dx1+dx2+dx3+dx4+dx5; - dy = dy1+dy2+dy3+dy4+dy5; - if (STBTT_fabs(dx) > STBTT_fabs(dy)) - dy6 = -dy; - else - dx6 = -dx; - stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3); - stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6); - break; - - default: - return STBTT__CSERR("unimplemented"); - } - } break; - - default: - if (b0 != 255 && b0 != 28 && b0 < 32) - return STBTT__CSERR("reserved operator"); - - // push immediate - if (b0 == 255) { - f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000; - } else { - stbtt__buf_skip(&b, -1); - f = (float)(stbtt_int16)stbtt__cff_int(&b); - } - if (sp >= 48) return STBTT__CSERR("push stack overflow"); - s[sp++] = f; - clear_stack = 0; - break; - } - if (clear_stack) sp = 0; - } - return STBTT__CSERR("no endchar"); - -#undef STBTT__CSERR -} - -static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - // runs the charstring twice, once to count and once to output (to avoid realloc) - stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1); - stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0); - if (stbtt__run_charstring(info, glyph_index, &count_ctx)) { - *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata); - output_ctx.pvertices = *pvertices; - if (stbtt__run_charstring(info, glyph_index, &output_ctx)) { - STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices); - return output_ctx.num_vertices; - } - } - *pvertices = NULL; - return 0; -} - -static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - stbtt__csctx c = STBTT__CSCTX_INIT(1); - int r = stbtt__run_charstring(info, glyph_index, &c); - if (x0) *x0 = r ? c.min_x : 0; - if (y0) *y0 = r ? c.min_y : 0; - if (x1) *x1 = r ? c.max_x : 0; - if (y1) *y1 = r ? c.max_y : 0; - return r ? c.num_vertices : 0; -} - -STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - if (!info->cff.size) - return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices); - else - return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices); -} - -STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -STBTT_DEF int stbtt_GetKerningTableLength(const stbtt_fontinfo *info) -{ - stbtt_uint8 *data = info->data + info->kern; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - return ttUSHORT(data+10); -} - -STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length) -{ - stbtt_uint8 *data = info->data + info->kern; - int k, length; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - length = ttUSHORT(data+10); - if (table_length < length) - length = table_length; - - for (k = 0; k < length; k++) - { - table[k].glyph1 = ttUSHORT(data+18+(k*6)); - table[k].glyph2 = ttUSHORT(data+20+(k*6)); - table[k].advance = ttSHORT(data+22+(k*6)); - } - - return length; -} - -static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint8 *data = info->data + info->kern; - stbtt_uint32 needle, straw; - int l, r, m; - - // we only look at the first table. it must be 'horizontal' and format 0. - if (!info->kern) - return 0; - if (ttUSHORT(data+2) < 1) // number of tables, need at least 1 - return 0; - if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format - return 0; - - l = 0; - r = ttUSHORT(data+10) - 1; - needle = glyph1 << 16 | glyph2; - while (l <= r) { - m = (l + r) >> 1; - straw = ttULONG(data+18+(m*6)); // note: unaligned read - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else - return ttSHORT(data+22+(m*6)); - } - return 0; -} - -static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph) -{ - stbtt_uint16 coverageFormat = ttUSHORT(coverageTable); - switch (coverageFormat) { - case 1: { - stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2); - - // Binary search. - stbtt_int32 l=0, r=glyphCount-1, m; - int straw, needle=glyph; - while (l <= r) { - stbtt_uint8 *glyphArray = coverageTable + 4; - stbtt_uint16 glyphID; - m = (l + r) >> 1; - glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - return m; - } - } - break; - } - - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; - - // Binary search. - stbtt_int32 l=0, r=rangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *rangeRecord; - m = (l + r) >> 1; - rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; - } - } - break; - } - - default: return -1; // unsupported - } - - return -1; -} - -static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph) -{ - stbtt_uint16 classDefFormat = ttUSHORT(classDefTable); - switch (classDefFormat) - { - case 1: { - stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2); - stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4); - stbtt_uint8 *classDef1ValueArray = classDefTable + 6; - - if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) - return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - break; - } - - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; - - // Binary search. - stbtt_int32 l=0, r=classRangeCount-1, m; - int strawStart, strawEnd, needle=glyph; - while (l <= r) { - stbtt_uint8 *classRangeRecord; - m = (l + r) >> 1; - classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); - if (needle < strawStart) - r = m - 1; - else if (needle > strawEnd) - l = m + 1; - else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - break; - } - - default: - return -1; // Unsupported definition type, return an error. - } - - // "All glyphs not assigned to a class fall into class 0". (OpenType spec) - return 0; -} - -// Define to STBTT_assert(x) if you want to break on unimplemented formats. -#define STBTT_GPOS_TODO_assert(x) - -static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - stbtt_uint16 lookupListOffset; - stbtt_uint8 *lookupList; - stbtt_uint16 lookupCount; - stbtt_uint8 *data; - stbtt_int32 i, sti; - - if (!info->gpos) return 0; - - data = info->data + info->gpos; - - if (ttUSHORT(data+0) != 1) return 0; // Major version 1 - if (ttUSHORT(data+2) != 0) return 0; // Minor version 0 - - lookupListOffset = ttUSHORT(data+8); - lookupList = data + lookupListOffset; - lookupCount = ttUSHORT(lookupList); - - for (i=0; i= pairSetCount) return 0; - - needle=glyph2; - r=pairValueCount-1; - l=0; - - // Binary search. - while (l <= r) { - stbtt_uint16 secondGlyph; - stbtt_uint8 *pairValue; - m = (l + r) >> 1; - pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m; - secondGlyph = ttUSHORT(pairValue); - straw = secondGlyph; - if (needle < straw) - r = m - 1; - else if (needle > straw) - l = m + 1; - else { - stbtt_int16 xAdvance = ttSHORT(pairValue + 2); - return xAdvance; - } - } - } else - return 0; - break; - } - - case 2: { - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_uint16 classDef1Offset = ttUSHORT(table + 8); - stbtt_uint16 classDef2Offset = ttUSHORT(table + 10); - int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1); - int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2); - - stbtt_uint16 class1Count = ttUSHORT(table + 12); - stbtt_uint16 class2Count = ttUSHORT(table + 14); - stbtt_uint8 *class1Records, *class2Records; - stbtt_int16 xAdvance; - - if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed - if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed - - class1Records = table + 16; - class2Records = class1Records + 2 * (glyph1class * class2Count); - xAdvance = ttSHORT(class2Records + 2 * glyph2class); - return xAdvance; - } else - return 0; - break; - } - - default: - return 0; // Unsupported position format - } - } - } - - return 0; -} - -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) -{ - int xAdvance = 0; - - if (info->gpos) - xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); - else if (info->kern) - xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); - - return xAdvance; -} - -STBTT_DEF int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs - return 0; - return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2)); -} - -STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); -} - -STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); -} - -STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap) -{ - int tab = stbtt__find_table(info->data, info->fontstart, "OS/2"); - if (!tab) - return 0; - if (typoAscent ) *typoAscent = ttSHORT(info->data+tab + 68); - if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70); - if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72); - return 1; -} - -STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1) -{ - *x0 = ttSHORT(info->data + info->head + 36); - *y0 = ttSHORT(info->data + info->head + 38); - *x1 = ttSHORT(info->data + info->head + 40); - *y1 = ttSHORT(info->data + info->head + 42); -} - -STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; -} - -STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels) -{ - int unitsPerEm = ttUSHORT(info->data + info->head + 18); - return pixels / unitsPerEm; -} - -STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} - -STBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl) -{ - int i; - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info); - - int numEntries = ttUSHORT(svg_doc_list); - stbtt_uint8 *svg_docs = svg_doc_list + 2; - - for(i=0; i= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) - return svg_doc; - } - return 0; -} - -STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg) -{ - stbtt_uint8 *data = info->data; - stbtt_uint8 *svg_doc; - - if (info->svg == 0) - return 0; - - svg_doc = stbtt_FindSVGDoc(info, gl); - if (svg_doc != NULL) { - *svg = (char *) data + info->svg + ttULONG(svg_doc + 4); - return ttULONG(svg_doc + 8); - } else { - return 0; - } -} - -STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg) -{ - return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg); -} - -////////////////////////////////////////////////////////////////////////////// -// -// antialiasing software rasterizer -// - -STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) { - // e.g. space character - if (ix0) *ix0 = 0; - if (iy0) *iy0 = 0; - if (ix1) *ix1 = 0; - if (iy1) *iy1 = 0; - } else { - // move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x); - if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y); - if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x); - if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y); - } -} - -STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1); -} - -STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1); -} - -////////////////////////////////////////////////////////////////////////////// -// -// Rasterizer - -typedef struct stbtt__hheap_chunk -{ - struct stbtt__hheap_chunk *next; -} stbtt__hheap_chunk; - -typedef struct stbtt__hheap -{ - struct stbtt__hheap_chunk *head; - void *first_free; - int num_remaining_in_head_chunk; -} stbtt__hheap; - -static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata) -{ - if (hh->first_free) { - void *p = hh->first_free; - hh->first_free = * (void **) p; - return p; - } else { - if (hh->num_remaining_in_head_chunk == 0) { - int count = (size < 32 ? 2000 : size < 128 ? 800 : 100); - stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata); - if (c == NULL) - return NULL; - c->next = hh->head; - hh->head = c; - hh->num_remaining_in_head_chunk = count; - } - --hh->num_remaining_in_head_chunk; - return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk; - } -} - -static void stbtt__hheap_free(stbtt__hheap *hh, void *p) -{ - *(void **) p = hh->first_free; - hh->first_free = p; -} - -static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata) -{ - stbtt__hheap_chunk *c = hh->head; - while (c) { - stbtt__hheap_chunk *n = c->next; - STBTT_free(c, userdata); - c = n; - } -} - -typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; -} stbtt__edge; - - -typedef struct stbtt__active_edge -{ - struct stbtt__active_edge *next; - #if STBTT_RASTERIZER_VERSION==1 - int x,dx; - float ey; - int direction; - #elif STBTT_RASTERIZER_VERSION==2 - float fx,fdx,fdy; - float direction; - float sy; - float ey; - #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" - #endif -} stbtt__active_edge; - -#if STBTT_RASTERIZER_VERSION == 1 -#define STBTT_FIXSHIFT 10 -#define STBTT_FIX (1 << STBTT_FIXSHIFT) -#define STBTT_FIXMASK (STBTT_FIX-1) - -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - if (!z) return z; - - // round dx down to avoid overshooting - if (dxdy < 0) - z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy); - else - z->dx = STBTT_ifloor(STBTT_FIX * dxdy); - - z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount - z->x -= off_x * STBTT_FIX; - - z->ey = e->y1; - z->next = 0; - z->direction = e->invert ? 1 : -1; - return z; -} -#elif STBTT_RASTERIZER_VERSION == 2 -static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata); - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(z != NULL); - //STBTT_assert(e->y0 <= start_point); - if (!z) return z; - z->fdx = dxdy; - z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f; - z->fx = e->x0 + dxdy * (start_point - e->y0); - z->fx -= off_x; - z->direction = e->invert ? 1.0f : -1.0f; - z->sy = e->y0; - z->ey = e->y1; - z->next = 0; - return z; -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#if STBTT_RASTERIZER_VERSION == 1 -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; - - while (e) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->direction; - } else { - int x1 = e->x; w += e->direction; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> STBTT_FIXSHIFT; - int j = x1 >> STBTT_FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata); - if (z != NULL) { - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - } - ++e; - } - - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} - -#elif STBTT_RASTERIZER_VERSION == 2 - -// the edge passed in here does not cross the vertical line at x or the vertical line at x+1 -// (i.e. it has already been clipped to those) -static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1) -{ - if (y0 == y1) return; - STBTT_assert(y0 < y1); - STBTT_assert(e->sy <= e->ey); - if (y0 > e->ey) return; - if (y1 < e->sy) return; - if (y0 < e->sy) { - x0 += (x1-x0) * (e->sy - y0) / (y1-y0); - y0 = e->sy; - } - if (y1 > e->ey) { - x1 += (x1-x0) * (e->ey - y1) / (y1-y0); - y1 = e->ey; - } - - if (x0 == x) - STBTT_assert(x1 <= x+1); - else if (x0 == x+1) - STBTT_assert(x1 >= x); - else if (x0 <= x) - STBTT_assert(x1 <= x); - else if (x0 >= x+1) - STBTT_assert(x1 >= x+1); - else - STBTT_assert(x1 >= x && x1 <= x+1); - - if (x0 <= x && x1 <= x) - scanline[x] += e->direction * (y1-y0); - else if (x0 >= x+1 && x1 >= x+1) - ; - else { - STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1); - scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position - } -} - -static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width) -{ - STBTT_assert(top_width >= 0); - STBTT_assert(bottom_width >= 0); - return (top_width + bottom_width) / 2.0f * height; -} - -static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1) -{ - return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0); -} - -static float stbtt__sized_triangle_area(float height, float width) -{ - return height * width / 2; -} - -static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top) -{ - float y_bottom = y_top+1; - - while (e) { - // brute force every pixel - - // compute intersection points with top & bottom - STBTT_assert(e->ey >= y_top); - - if (e->fdx == 0) { - float x0 = e->fx; - if (x0 < len) { - if (x0 >= 0) { - stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom); - stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom); - } else { - stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom); - } - } - } else { - float x0 = e->fx; - float dx = e->fdx; - float xb = x0 + dx; - float x_top, x_bottom; - float sy0,sy1; - float dy = e->fdy; - STBTT_assert(e->sy <= y_bottom && e->ey >= y_top); - - // compute endpoints of line segment clipped to this scanline (if the - // line segment starts on this scanline. x0 is the intersection of the - // line with y_top, but that may be off the line segment. - if (e->sy > y_top) { - x_top = x0 + dx * (e->sy - y_top); - sy0 = e->sy; - } else { - x_top = x0; - sy0 = y_top; - } - if (e->ey < y_bottom) { - x_bottom = x0 + dx * (e->ey - y_top); - sy1 = e->ey; - } else { - x_bottom = xb; - sy1 = y_bottom; - } - - if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) { - // from here on, we don't have to range check x values - - if ((int) x_top == (int) x_bottom) { - float height; - // simple case, only spans one pixel - int x = (int) x_top; - height = (sy1 - sy0) * e->direction; - STBTT_assert(x >= 0 && x < len); - scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f); - scanline_fill[x] += height; // everything right of this pixel is filled - } else { - int x,x1,x2; - float y_crossing, y_final, step, sign, area; - // covers 2+ pixels - if (x_top > x_bottom) { - // flip scanline vertically; signed area is the same - float t; - sy0 = y_bottom - (sy0 - y_top); - sy1 = y_bottom - (sy1 - y_top); - t = sy0, sy0 = sy1, sy1 = t; - t = x_bottom, x_bottom = x_top, x_top = t; - dx = -dx; - dy = -dy; - t = x0, x0 = xb, xb = t; - } - STBTT_assert(dy >= 0); - STBTT_assert(dx >= 0); - - x1 = (int) x_top; - x2 = (int) x_bottom; - // compute intersection with y axis at x1+1 - y_crossing = y_top + dy * (x1+1 - x0); - - // compute intersection with y axis at x2 - y_final = y_top + dy * (x2 - x0); - - // x1 x_top x2 x_bottom - // y_top +------|-----+------------+------------+--------|---+------------+ - // | | | | | | - // | | | | | | - // sy0 | Txxxxx|............|............|............|............| - // y_crossing | *xxxxx.......|............|............|............| - // | | xxxxx..|............|............|............| - // | | /- xx*xxxx........|............|............| - // | | dy < | xxxxxx..|............|............| - // y_final | | \- | xx*xxx.........|............| - // sy1 | | | | xxxxxB...|............| - // | | | | | | - // | | | | | | - // y_bottom +------------+------------+------------+------------+------------+ - // - // goal is to measure the area covered by '.' in each pixel - - // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 - // @TODO: maybe test against sy1 rather than y_bottom? - if (y_crossing > y_bottom) - y_crossing = y_bottom; - - sign = e->direction; - - // area of the rectangle covered from sy0..y_crossing - area = sign * (y_crossing-sy0); - - // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) - scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top); - - // check if final y_crossing is blown up; no test case for this - if (y_final > y_bottom) { - y_final = y_bottom; - dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom - } - - // in second pixel, area covered by line segment found in first pixel - // is always a rectangle 1 wide * the height of that line segment; this - // is exactly what the variable 'area' stores. it also gets a contribution - // from the line segment within it. the THIRD pixel will get the first - // pixel's rectangle contribution, the second pixel's rectangle contribution, - // and its own contribution. the 'own contribution' is the same in every pixel except - // the leftmost and rightmost, a trapezoid that slides down in each pixel. - // the second pixel's contribution to the third pixel will be the - // rectangle 1 wide times the height change in the second pixel, which is dy. - - step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x, - // which multiplied by 1-pixel-width is how much pixel area changes for each step in x - // so the area advances by 'step' every time - - for (x = x1+1; x < x2; ++x) { - scanline[x] += area + step/2; // area of trapezoid is 1*step/2 - area += step; - } - STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down - STBTT_assert(sy1 > y_final-0.01f); - - // area covered in the last pixel is the rectangle from all the pixels to the left, - // plus the trapezoid filled by the line segment in this pixel all the way to the right edge - scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f); - - // the rest of the line is filled based on the total height of the line segment in this pixel - scanline_fill[x2] += sign * (sy1-sy0); - } - } else { - // if edge goes outside of box we're drawing, we require - // clipping logic. since this does not match the intended use - // of this library, we use a different, very slow brute - // force implementation - // note though that this does happen some of the time because - // x_top and x_bottom can be extrapolated at the top & bottom of - // the shape and actually lie outside the bounding box - int x; - for (x=0; x < len; ++x) { - // cases: - // - // there can be up to two intersections with the pixel. any intersection - // with left or right edges can be handled by splitting into two (or three) - // regions. intersections with top & bottom do not necessitate case-wise logic. - // - // the old way of doing this found the intersections with the left & right edges, - // then used some simple logic to produce up to three segments in sorted order - // from top-to-bottom. however, this had a problem: if an x edge was epsilon - // across the x border, then the corresponding y position might not be distinct - // from the other y segment, and it might ignored as an empty segment. to avoid - // that, we need to explicitly produce segments based on x positions. - - // rename variables to clearly-defined pairs - float y0 = y_top; - float x1 = (float) (x); - float x2 = (float) (x+1); - float x3 = xb; - float y3 = y_bottom; - - // x = e->x + e->dx * (y-y_top) - // (y-y_top) = (x - e->x) / e->dx - // y = (x - e->x) / e->dx + y_top - float y1 = (x - x0) / dx + y_top; - float y2 = (x+1 - x0) / dx + y_top; - - if (x0 < x1 && x3 > x2) { // three segments descending down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x1 && x0 > x2) { // three segments descending down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x1 && x3 > x1) { // two segments across x, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x3 < x1 && x0 > x1) { // two segments across x, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1); - stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3); - } else if (x0 < x2 && x3 > x2) { // two segments across x+1, down-right - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else if (x3 < x2 && x0 > x2) { // two segments across x+1, down-left - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2); - stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3); - } else { // one segment - stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3); - } - } - } - } - e = e->next; - } -} - -// directly AA rasterize edges w/o supersampling -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__hheap hh = { 0, 0, 0 }; - stbtt__active_edge *active = NULL; - int y,j=0, i; - float scanline_data[129], *scanline, *scanline2; - - STBTT__NOTUSED(vsubsample); - - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; - - scanline2 = scanline + result->w; - - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; - - while (j < result->h) { - // find center of pixel for this scanline - float scan_y_top = y + 0.0f; - float scan_y_bottom = y + 1.0f; - stbtt__active_edge **step = &active; - - STBTT_memset(scanline , 0, result->w*sizeof(scanline[0])); - STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0])); - - // update all active edges; - // remove all active edges that terminate before the top of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y_top) { - *step = z->next; // delete from list - STBTT_assert(z->direction); - z->direction = 0; - stbtt__hheap_free(&hh, z); - } else { - step = &((*step)->next); // advance through list - } - } - - // insert all edges that start before the bottom of this scanline - while (e->y0 <= scan_y_bottom) { - if (e->y0 != e->y1) { - stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata); - if (z != NULL) { - if (j == 0 && off_y != 0) { - if (z->ey < scan_y_top) { - // this can happen due to subpixel positioning and some kind of fp rounding error i think - z->ey = scan_y_top; - } - } - STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds - // insert at front - z->next = active; - active = z; - } - } - ++e; - } - - // now process all active edges - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); - - { - float sum = 0; - for (i=0; i < result->w; ++i) { - float k; - int m; - sum += scanline2[i]; - k = scanline[i] + sum; - k = (float) STBTT_fabs(k)*255 + 0.5f; - m = (int) k; - if (m > 255) m = 255; - result->pixels[j*result->stride + i] = (unsigned char) m; - } - } - // advance all the edges - step = &active; - while (*step) { - stbtt__active_edge *z = *step; - z->fx += z->fdx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - - ++y; - ++j; - } - - stbtt__hheap_cleanup(&hh, userdata); - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} -#else -#error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - -#define STBTT__COMPARE(a,b) ((a)->y0 < (b)->y0) - -static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n) -{ - int i,j; - for (i=1; i < n; ++i) { - stbtt__edge t = p[i], *a = &t; - j = i; - while (j > 0) { - stbtt__edge *b = &p[j-1]; - int c = STBTT__COMPARE(a,b); - if (!c) break; - p[j] = p[j-1]; - --j; - } - if (i != j) - p[j] = t; - } -} - -static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n) -{ - /* threshold for transitioning to insertion sort */ - while (n > 12) { - stbtt__edge t; - int c01,c12,c,m,i,j; - - /* compute median of three */ - m = n >> 1; - c01 = STBTT__COMPARE(&p[0],&p[m]); - c12 = STBTT__COMPARE(&p[m],&p[n-1]); - /* if 0 >= mid >= end, or 0 < mid < end, then use mid */ - if (c01 != c12) { - /* otherwise, we'll need to swap something else to middle */ - int z; - c = STBTT__COMPARE(&p[0],&p[n-1]); - /* 0>mid && midn => n; 0 0 */ - /* 0n: 0>n => 0; 0 n */ - z = (c == c12) ? 0 : n-1; - t = p[z]; - p[z] = p[m]; - p[m] = t; - } - /* now p[m] is the median-of-three */ - /* swap it to the beginning so it won't move around */ - t = p[0]; - p[0] = p[m]; - p[m] = t; - - /* partition loop */ - i=1; - j=n-1; - for(;;) { - /* handling of equality is crucial here */ - /* for sentinels & efficiency with duplicates */ - for (;;++i) { - if (!STBTT__COMPARE(&p[i], &p[0])) break; - } - for (;;--j) { - if (!STBTT__COMPARE(&p[0], &p[j])) break; - } - /* make sure we haven't crossed */ - if (i >= j) break; - t = p[i]; - p[i] = p[j]; - p[j] = t; - - ++i; - --j; - } - /* recurse on smaller side, iterate on larger */ - if (j < (n-i)) { - stbtt__sort_edges_quicksort(p,j); - p = p+i; - n = n-i; - } else { - stbtt__sort_edges_quicksort(p+i, n-i); - n = j; - } - } -} - -static void stbtt__sort_edges(stbtt__edge *p, int n) -{ - stbtt__sort_edges_quicksort(p, n); - stbtt__sort_edges_ins_sort(p, n); -} - -typedef struct -{ - float x,y; -} stbtt__point; - -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; -#if STBTT_RASTERIZER_VERSION == 1 - int vsubsample = result->h < 8 ? 15 : 5; -#elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; -#else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" -#endif - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x + shift_x; - e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample; - e[n].x1 = p[b].x * scale_x + shift_x; - e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample; - ++n; - } - } - - // now sort the edges by their highest point (should snap to integer, and then by x) - //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - stbtt__sort_edges(e, n); - - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - - STBTT_free(e, userdata); -} - -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; -} - -// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n) -{ - // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough - float dx0 = x1-x0; - float dy0 = y1-y0; - float dx1 = x2-x1; - float dy1 = y2-y1; - float dx2 = x3-x2; - float dy2 = y3-y2; - float dx = x3-x0; - float dy = y3-y0; - float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2)); - float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy); - float flatness_squared = longlen*longlen-shortlen*shortlen; - - if (n > 16) // 65536 segments on one curve better be enough! - return; - - if (flatness_squared > objspace_flatness_squared) { - float x01 = (x0+x1)/2; - float y01 = (y0+y1)/2; - float x12 = (x1+x2)/2; - float y12 = (y1+y2)/2; - float x23 = (x2+x3)/2; - float y23 = (y2+y3)/2; - - float xa = (x01+x12)/2; - float ya = (y01+y12)/2; - float xb = (x12+x23)/2; - float yb = (y12+y23)/2; - - float mx = (xa+xb)/2; - float my = (ya+yb)/2; - - stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x3,y3); - *num_points = *num_points+1; - } -} - -// returns number of contours -static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - case STBTT_vcubic: - stbtt__tesselate_cubic(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].cx1, vertices[i].cy1, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; -error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count = 0; - int *winding_lengths = NULL; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) { - STBTT_free(vertices, info->userdata); - return NULL; - } - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1); - - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error - - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; - - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; -} - -STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata); - - STBTT_free(vertices, info->userdata); -} - -STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint) -{ - stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff); -} - -STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint); -} - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-CRAPPY packing to keep source code small - -static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - f.userdata = NULL; - if (!stbtt_InitFont(&f, data, offset)) - return -1; - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 1; - if (y+gh+1 > bottom_y) - bottom_y = y+gh+1; - } - return bottom_y; -} - -STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, - float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// rectangle packing replacement routines if you don't have stb_rect_pack.h -// - -#ifndef STB_RECT_PACK_VERSION - -typedef int stbrp_coord; - -//////////////////////////////////////////////////////////////////////////////////// -// // -// // -// COMPILER WARNING ?!?!? // -// // -// // -// if you get a compile warning due to these symbols being defined more than // -// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h" // -// // -//////////////////////////////////////////////////////////////////////////////////// - -typedef struct -{ - int width,height; - int x,y,bottom_y; -} stbrp_context; - -typedef struct -{ - unsigned char x; -} stbrp_node; - -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; -}; - -static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes) -{ - con->width = pw; - con->height = ph; - con->x = 0; - con->y = 0; - con->bottom_y = 0; - STBTT__NOTUSED(nodes); - STBTT__NOTUSED(num_nodes); -} - -static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects) -{ - int i; - for (i=0; i < num_rects; ++i) { - if (con->x + rects[i].w > con->width) { - con->x = 0; - con->y = con->bottom_y; - } - if (con->y + rects[i].h > con->height) - break; - rects[i].x = con->x; - rects[i].y = con->y; - rects[i].was_packed = 1; - con->x += rects[i].w; - if (con->y + rects[i].h > con->bottom_y) - con->bottom_y = con->y + rects[i].h; - } - for ( ; i < num_rects; ++i) - rects[i].was_packed = 0; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If -// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. - -STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context) -{ - stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context) ,alloc_context); - int num_nodes = pw - padding; - stbrp_node *nodes = (stbrp_node *) STBTT_malloc(sizeof(*nodes ) * num_nodes,alloc_context); - - if (context == NULL || nodes == NULL) { - if (context != NULL) STBTT_free(context, alloc_context); - if (nodes != NULL) STBTT_free(nodes , alloc_context); - return 0; - } - - spc->user_allocator_context = alloc_context; - spc->width = pw; - spc->height = ph; - spc->pixels = pixels; - spc->pack_info = context; - spc->nodes = nodes; - spc->padding = padding; - spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw; - spc->h_oversample = 1; - spc->v_oversample = 1; - spc->skip_missing = 0; - - stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes); - - if (pixels) - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - - return 1; -} - -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc) -{ - STBTT_free(spc->nodes , spc->user_allocator_context); - STBTT_free(spc->pack_info, spc->user_allocator_context); -} - -STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample) -{ - STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE); - STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE); - if (h_oversample <= STBTT_MAX_OVERSAMPLE) - spc->h_oversample = h_oversample; - if (v_oversample <= STBTT_MAX_OVERSAMPLE) - spc->v_oversample = v_oversample; -} - -STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) -{ - spc->skip_missing = skip; -} - -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) - -static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_w = w - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < h; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_w; ++i) { - total += pixels[i] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i]; - pixels[i] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < w; ++i) { - STBTT_assert(pixels[i] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i] = (unsigned char) (total / kernel_width); - } - - pixels += stride_in_bytes; - } -} - -static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width) -{ - unsigned char buffer[STBTT_MAX_OVERSAMPLE]; - int safe_h = h - kernel_width; - int j; - STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze - for (j=0; j < w; ++j) { - int i; - unsigned int total; - STBTT_memset(buffer, 0, kernel_width); - - total = 0; - - // make kernel_width a constant in common cases so compiler can optimize out the divide - switch (kernel_width) { - case 2: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 2); - } - break; - case 3: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 3); - } - break; - case 4: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 4); - } - break; - case 5: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / 5); - } - break; - default: - for (i=0; i <= safe_h; ++i) { - total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK]; - buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - break; - } - - for (; i < h; ++i) { - STBTT_assert(pixels[i*stride_in_bytes] == 0); - total -= buffer[i & STBTT__OVER_MASK]; - pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width); - } - - pixels += 1; - } -} - -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; - - // The prefilter is a box filter of width "oversample", - // which shifts phase by (oversample - 1)/2 pixels in - // oversampled space. We want to shift in the opposite - // direction to counter this. - return (float)-(oversample - 1) / (2.0f * (float)oversample); -} - -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k; - int missing_glyph_added = 0; - - k=0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - ranges[i].h_oversample = (unsigned char) spc->h_oversample; - ranges[i].v_oversample = (unsigned char) spc->v_oversample; - for (j=0; j < ranges[i].num_chars; ++j) { - int x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) { - rects[k].w = rects[k].h = 0; - } else { - stbtt_GetGlyphBitmapBoxSubpixel(info,glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - &x0,&y0,&x1,&y1); - rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1); - rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1); - if (glyph == 0) - missing_glyph_added = 1; - } - ++k; - } - } - - return k; -} - -STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph) -{ - stbtt_MakeGlyphBitmapSubpixel(info, - output, - out_w - (prefilter_x - 1), - out_h - (prefilter_y - 1), - out_stride, - scale_x, - scale_y, - shift_x, - shift_y, - glyph); - - if (prefilter_x > 1) - stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x); - - if (prefilter_y > 1) - stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y); - - *sub_x = stbtt__oversample_shift(prefilter_x); - *sub_y = stbtt__oversample_shift(prefilter_y); -} - -// rects array must be big enough to accommodate all characters in the given ranges -STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects) -{ - int i,j,k, missing_glyph = -1, return_value = 1; - - // save current values - int old_h_over = spc->h_oversample; - int old_v_over = spc->v_oversample; - - k = 0; - for (i=0; i < num_ranges; ++i) { - float fh = ranges[i].font_size; - float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh); - float recip_h,recip_v,sub_x,sub_y; - spc->h_oversample = ranges[i].h_oversample; - spc->v_oversample = ranges[i].v_oversample; - recip_h = 1.0f / spc->h_oversample; - recip_v = 1.0f / spc->v_oversample; - sub_x = stbtt__oversample_shift(spc->h_oversample); - sub_y = stbtt__oversample_shift(spc->v_oversample); - for (j=0; j < ranges[i].num_chars; ++j) { - stbrp_rect *r = &rects[k]; - if (r->was_packed && r->w != 0 && r->h != 0) { - stbtt_packedchar *bc = &ranges[i].chardata_for_range[j]; - int advance, lsb, x0,y0,x1,y1; - int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j]; - int glyph = stbtt_FindGlyphIndex(info, codepoint); - stbrp_coord pad = (stbrp_coord) spc->padding; - - // pad on left and top - r->x += pad; - r->y += pad; - r->w -= pad; - r->h -= pad; - stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb); - stbtt_GetGlyphBitmapBox(info, glyph, - scale * spc->h_oversample, - scale * spc->v_oversample, - &x0,&y0,&x1,&y1); - stbtt_MakeGlyphBitmapSubpixel(info, - spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w - spc->h_oversample+1, - r->h - spc->v_oversample+1, - spc->stride_in_bytes, - scale * spc->h_oversample, - scale * spc->v_oversample, - 0,0, - glyph); - - if (spc->h_oversample > 1) - stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->h_oversample); - - if (spc->v_oversample > 1) - stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes, - r->w, r->h, spc->stride_in_bytes, - spc->v_oversample); - - bc->x0 = (stbtt_int16) r->x; - bc->y0 = (stbtt_int16) r->y; - bc->x1 = (stbtt_int16) (r->x + r->w); - bc->y1 = (stbtt_int16) (r->y + r->h); - bc->xadvance = scale * advance; - bc->xoff = (float) x0 * recip_h + sub_x; - bc->yoff = (float) y0 * recip_v + sub_y; - bc->xoff2 = (x0 + r->w) * recip_h + sub_x; - bc->yoff2 = (y0 + r->h) * recip_v + sub_y; - - if (glyph == 0) - missing_glyph = j; - } else if (spc->skip_missing) { - return_value = 0; - } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) { - ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph]; - } else { - return_value = 0; // if any fail, report failure - } - - ++k; - } - } - - // restore original values - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; - - return return_value; -} - -STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects) -{ - stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects); -} - -STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges) -{ - stbtt_fontinfo info; - int i,j,n, return_value = 1; - //stbrp_context *context = (stbrp_context *) spc->pack_info; - stbrp_rect *rects; - - // flag all characters as NOT packed - for (i=0; i < num_ranges; ++i) - for (j=0; j < ranges[i].num_chars; ++j) - ranges[i].chardata_for_range[j].x0 = - ranges[i].chardata_for_range[j].y0 = - ranges[i].chardata_for_range[j].x1 = - ranges[i].chardata_for_range[j].y1 = 0; - - n = 0; - for (i=0; i < num_ranges; ++i) - n += ranges[i].num_chars; - - rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context); - if (rects == NULL) - return 0; - - info.userdata = spc->user_allocator_context; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index)); - - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - - stbtt_PackFontRangesPackRects(spc, rects, n); - - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - - STBTT_free(rects, spc->user_allocator_context); - return return_value; -} - -STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size, - int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range) -{ - stbtt_pack_range range; - range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range; - range.array_of_unicode_codepoints = NULL; - range.num_chars = num_chars_in_range; - range.chardata_for_range = chardata_for_range; - range.font_size = font_size; - return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1); -} - -STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap) -{ - int i_ascent, i_descent, i_lineGap; - float scale; - stbtt_fontinfo info; - stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index)); - scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size); - stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap); - *ascent = (float) i_ascent * scale; - *descent = (float) i_descent * scale; - *lineGap = (float) i_lineGap * scale; -} - -STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer) -{ - float ipw = 1.0f / pw, iph = 1.0f / ph; - const stbtt_packedchar *b = chardata + char_index; - - if (align_to_integer) { - float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f); - float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f); - q->x0 = x; - q->y0 = y; - q->x1 = x + b->xoff2 - b->xoff; - q->y1 = y + b->yoff2 - b->yoff; - } else { - q->x0 = *xpos + b->xoff; - q->y0 = *ypos + b->yoff; - q->x1 = *xpos + b->xoff2; - q->y1 = *ypos + b->yoff2; - } - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * iph; - q->s1 = b->x1 * ipw; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// sdf computation -// - -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) - -static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2]) -{ - float q0perp = q0[1]*ray[0] - q0[0]*ray[1]; - float q1perp = q1[1]*ray[0] - q1[0]*ray[1]; - float q2perp = q2[1]*ray[0] - q2[0]*ray[1]; - float roperp = orig[1]*ray[0] - orig[0]*ray[1]; - - float a = q0perp - 2*q1perp + q2perp; - float b = q1perp - q0perp; - float c = q0perp - roperp; - - float s0 = 0., s1 = 0.; - int num_s = 0; - - if (a != 0.0) { - float discr = b*b - a*c; - if (discr > 0.0) { - float rcpna = -1 / a; - float d = (float) STBTT_sqrt(discr); - s0 = (b+d) * rcpna; - s1 = (b-d) * rcpna; - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) { - if (num_s == 0) s0 = s1; - ++num_s; - } - } - } else { - // 2*b*s + c = 0 - // s = -c / (2*b) - s0 = c / (-2 * b); - if (s0 >= 0.0 && s0 <= 1.0) - num_s = 1; - } - - if (num_s == 0) - return 0; - else { - float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]); - float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2; - - float q0d = q0[0]*rayn_x + q0[1]*rayn_y; - float q1d = q1[0]*rayn_x + q1[1]*rayn_y; - float q2d = q2[0]*rayn_x + q2[1]*rayn_y; - float rod = orig[0]*rayn_x + orig[1]*rayn_y; - - float q10d = q1d - q0d; - float q20d = q2d - q0d; - float q0rd = q0d - rod; - - hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d; - hits[0][1] = a*s0+b; - - if (num_s > 1) { - hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d; - hits[1][1] = a*s1+b; - return 2; - } else { - return 1; - } - } -} - -static int equal(float *a, float *b) -{ - return (a[0] == b[0] && a[1] == b[1]); -} - -static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts) -{ - int i; - float orig[2], ray[2] = { 1, 0 }; - float y_frac; - int winding = 0; - - // make sure y never passes through a vertex of the shape - y_frac = (float) STBTT_fmod(y, 1.0f); - if (y_frac < 0.01f) - y += 0.01f; - else if (y_frac > 0.99f) - y -= 0.01f; - - orig[0] = x; - orig[1] = y; - - // test a ray from (-infinity,y) to (x,y) - for (i=0; i < nverts; ++i) { - if (verts[i].type == STBTT_vline) { - int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y; - int x1 = (int) verts[i ].x, y1 = (int) verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } - if (verts[i].type == STBTT_vcurve) { - int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ; - int x1 = (int) verts[i ].cx, y1 = (int) verts[i ].cy; - int x2 = (int) verts[i ].x , y2 = (int) verts[i ].y ; - int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2)); - int by = STBTT_max(y0,STBTT_max(y1,y2)); - if (y > ay && y < by && x > ax) { - float q0[2],q1[2],q2[2]; - float hits[2][2]; - q0[0] = (float)x0; - q0[1] = (float)y0; - q1[0] = (float)x1; - q1[1] = (float)y1; - q2[0] = (float)x2; - q2[1] = (float)y2; - if (equal(q0,q1) || equal(q1,q2)) { - x0 = (int)verts[i-1].x; - y0 = (int)verts[i-1].y; - x1 = (int)verts[i ].x; - y1 = (int)verts[i ].y; - if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) { - float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0; - if (x_inter < x) - winding += (y0 < y1) ? 1 : -1; - } - } else { - int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits); - if (num_hits >= 1) - if (hits[0][0] < 0) - winding += (hits[0][1] < 0 ? -1 : 1); - if (num_hits >= 2) - if (hits[1][0] < 0) - winding += (hits[1][1] < 0 ? -1 : 1); - } - } - } - } - return winding; -} - -static float stbtt__cuberoot( float x ) -{ - if (x<0) - return -(float) STBTT_pow(-x,1.0f/3.0f); - else - return (float) STBTT_pow( x,1.0f/3.0f); -} - -// x^3 + a*x^2 + b*x + c = 0 -static int stbtt__solve_cubic(float a, float b, float c, float* r) -{ - float s = -a / 3; - float p = b - a*a / 3; - float q = a * (2*a*a - 9*b) / 27 + c; - float p3 = p*p*p; - float d = q*q + 4*p3 / 27; - if (d >= 0) { - float z = (float) STBTT_sqrt(d); - float u = (-q + z) / 2; - float v = (-q - z) / 2; - u = stbtt__cuberoot(u); - v = stbtt__cuberoot(v); - r[0] = s + u + v; - return 1; - } else { - float u = (float) STBTT_sqrt(-p/3); - float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative - float m = (float) STBTT_cos(v); - float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f; - r[0] = s + u * 2 * m; - r[1] = s - u * (m + n); - r[2] = s - u * (m - n); - - //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? - //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); - //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); - return 3; - } -} - -STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - float scale_x = scale, scale_y = scale; - int ix0,iy0,ix1,iy1; - int w,h; - unsigned char *data; - - if (scale == 0) return NULL; - - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); - - // if empty, return NULL - if (ix0 == ix1 || iy0 == iy1) - return NULL; - - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; - - w = (ix1 - ix0); - h = (iy1 - iy0); - - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - // invert for y-downwards bitmaps - scale_y = -scale_y; - - { - int x,y,i,j; - float *precompute; - stbtt_vertex *verts; - int num_verts = stbtt_GetGlyphShape(info, glyph, &verts); - data = (unsigned char *) STBTT_malloc(w * h, info->userdata); - precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata); - - for (i=0,j=num_verts-1; i < num_verts; j=i++) { - if (verts[i].type == STBTT_vline) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y; - float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0)); - precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist; - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y; - float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y; - float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float len2 = bx*bx + by*by; - if (len2 != 0.0f) - precompute[i] = 1.0f / (bx*bx + by*by); - else - precompute[i] = 0.0f; - } else - precompute[i] = 0.0f; - } - - for (y=iy0; y < iy1; ++y) { - for (x=ix0; x < ix1; ++x) { - float val; - float min_dist = 999999.0f; - float sx = (float) x + 0.5f; - float sy = (float) y + 0.5f; - float x_gspace = (sx / scale_x); - float y_gspace = (sy / scale_y); - - int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path - - for (i=0; i < num_verts; ++i) { - float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y; - - if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) { - float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y; - - float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - // coarse culling against bbox - //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && - // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) - dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i]; - STBTT_assert(i != 0); - if (dist < min_dist) { - // check position along line - // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) - // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) - float dx = x1-x0, dy = y1-y0; - float px = x0-sx, py = y0-sy; - // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy - // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve - float t = -(px*dx + py*dy) / (dx*dx + dy*dy); - if (t >= 0.0f && t <= 1.0f) - min_dist = dist; - } - } else if (verts[i].type == STBTT_vcurve) { - float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y; - float x1 = verts[i ].cx*scale_x, y1 = verts[i ].cy*scale_y; - float box_x0 = STBTT_min(STBTT_min(x0,x1),x2); - float box_y0 = STBTT_min(STBTT_min(y0,y1),y2); - float box_x1 = STBTT_max(STBTT_max(x0,x1),x2); - float box_y1 = STBTT_max(STBTT_max(y0,y1),y2); - // coarse culling against bbox to avoid computing cubic unnecessarily - if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) { - int num=0; - float ax = x1-x0, ay = y1-y0; - float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2; - float mx = x0 - sx, my = y0 - sy; - float res[3] = {0.f,0.f,0.f}; - float px,py,t,it,dist2; - float a_inv = precompute[i]; - if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula - float a = 3*(ax*bx + ay*by); - float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by); - float c = mx*ax+my*ay; - if (a == 0.0) { // if a is 0, it's linear - if (b != 0.0) { - res[num++] = -c/b; - } - } else { - float discriminant = b*b - 4*a*c; - if (discriminant < 0) - num = 0; - else { - float root = (float) STBTT_sqrt(discriminant); - res[0] = (-b - root)/(2*a); - res[1] = (-b + root)/(2*a); - num = 2; // don't bother distinguishing 1-solution case, as code below will still work - } - } - } else { - float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point - float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv; - float d = (mx*ax+my*ay) * a_inv; - num = stbtt__solve_cubic(b, c, d, res); - } - dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy); - if (dist2 < min_dist*min_dist) - min_dist = (float) STBTT_sqrt(dist2); - - if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) { - t = res[0], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) { - t = res[1], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) { - t = res[2], it = 1.0f - t; - px = it*it*x0 + 2*t*it*x1 + t*t*x2; - py = it*it*y0 + 2*t*it*y1 + t*t*y2; - dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy); - if (dist2 < min_dist * min_dist) - min_dist = (float) STBTT_sqrt(dist2); - } - } - } - } - if (winding == 0) - min_dist = -min_dist; // if outside the shape, value is negative - val = onedge_value + pixel_dist_scale * min_dist; - if (val < 0) - val = 0; - else if (val > 255) - val = 255; - data[(y-iy0)*w+(x-ix0)] = (unsigned char) val; - } - } - STBTT_free(precompute, info->userdata); - STBTT_free(verts, info->userdata); - } - return data; -} - -STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff); -} - -STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -////////////////////////////////////////////////////////////////////////////// -// -// font name matching -- recommended not to use this -// - -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); -} - -// returns results in whatever encoding you request... but note that 2-byte encodings -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8); - stbtt_int32 off = ttUSHORT(fc+loc+10); - - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - slen = ttUSHORT(fc+loc+12+8); - off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } - } - } - - // @TODO handle other encodings - } - } - return 0; -} - -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } - - return 0; -} - -static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - -STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset, - float pixel_height, unsigned char *pixels, int pw, int ph, - int first_char, int num_chars, stbtt_bakedchar *chardata) -{ - return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata); -} - -STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index) -{ - return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index); -} - -STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data) -{ - return stbtt_GetNumberOfFonts_internal((unsigned char *) data); -} - -STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset) -{ - return stbtt_InitFont_internal(info, (unsigned char *) data, offset); -} - -STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags) -{ - return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags); -} - -STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2); -} - -#if defined(__GNUC__) || defined(__clang__) -#pragma GCC diagnostic pop -#endif - -#endif // STB_TRUETYPE_IMPLEMENTATION - - -// FULL VERSION HISTORY -// -// 1.25 (2021-07-11) many fixes -// 1.24 (2020-02-05) fix warning -// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) -// 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined -// 1.21 (2019-02-25) fix warning -// 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() -// 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod -// 1.18 (2018-01-29) add missing function -// 1.17 (2017-07-23) make more arguments const; doc fix -// 1.16 (2017-07-12) SDF support -// 1.15 (2017-03-03) make more arguments const -// 1.14 (2017-01-16) num-fonts-in-TTC function -// 1.13 (2017-01-02) support OpenType fonts, certain Apple fonts -// 1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual -// 1.11 (2016-04-02) fix unused-variable warning -// 1.10 (2016-04-02) allow user-defined fabs() replacement -// fix memory leak if fontsize=0.0 -// fix warning from duplicate typedef -// 1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges -// 1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges -// 1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; -// allow PackFontRanges to pack and render in separate phases; -// fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); -// fixed an assert() bug in the new rasterizer -// replace assert() with STBTT_assert() in new rasterizer -// 1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) -// also more precise AA rasterizer, except if shapes overlap -// remove need for STBTT_sort -// 1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC -// 1.04 (2015-04-15) typo in example -// 1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes -// 1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ -// 1.01 (2014-12-08) fix subpixel position when oversampling to exactly match -// non-oversampled; STBTT_POINT_SIZE for packed case only -// 1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling -// 0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) -// 0.9 (2014-08-07) support certain mac/iOS fonts without an MS platformID -// 0.8b (2014-07-07) fix a warning -// 0.8 (2014-05-25) fix a few more warnings -// 0.7 (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back -// 0.6c (2012-07-24) improve documentation -// 0.6b (2012-07-20) fix a few more warnings -// 0.6 (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, -// stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty -// 0.5 (2011-12-09) bugfixes: -// subpixel glyph renderer computed wrong bounding box -// first vertex of shape can be off-curve (FreeSans) -// 0.4b (2011-12-03) fixed an error in the font baking example -// 0.4 (2011-12-01) kerning, subpixel rendering (tor) -// bugfixes for: -// codepoint-to-glyph conversion using table fmt=12 -// codepoint-to-glyph conversion using table fmt=4 -// stbtt_GetBakedQuad with non-square texture (Zer) -// updated Hello World! sample to use kerning and subpixel -// fixed some warnings -// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) -// userdata, malloc-from-userdata, non-zero fill (stb) -// 0.2 (2009-03-11) Fix unsigned/signed char warnings -// 0.1 (2009-03-09) First public release -// - -/* ------------------------------------------------------------------------------- -This software is available under 2 licenses -- choose whichever you prefer. ------------------------------------------------------------------------------- -ALTERNATIVE A - MIT License -Copyright (c) 2017 Sean Barrett -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. ------------------------------------------------------------------------------- -ALTERNATIVE B - Public Domain (www.unlicense.org) -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or distribute this -software, either in source code form or as a compiled binary, for any purpose, -commercial or non-commercial, and by any means. -In jurisdictions that recognize copyright laws, the author or authors of this -software dedicate any and all copyright interest in the software to the public -domain. We make this dedication for the benefit of the public at large and to -the detriment of our heirs and successors. We intend this dedication to be an -overt act of relinquishment in perpetuity of all present and future rights to -this software under copyright law. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- -*/ diff --git a/src/main.c b/src/main.c index d0a19f5..77dacf3 100644 --- a/src/main.c +++ b/src/main.c @@ -1,245 +1,10 @@ -// header includes -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "render/render_inc.h" -#include "font/font_inc.h" -#include "draw/draw_inc.h" -#include "ui/ui_inc.h" - -// .c includes -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "os/os_entry_point.c" -#include "render/render_inc.c" -#include "font/font_inc.c" -#include "draw/draw_inc.c" -#include "ui/ui_inc.c" - -#define APP_WINDOW_WIDTH 1280 -#define APP_WINDOW_HEIGHT 720 -#define OS_REFRESH_RATE 60.0f -#define FRAME_DT 1.0f/OS_REFRESH_RATE -void EntryPoint() + +int main() { - - OS_InitReceipt os_receipt = OS_init(); - OS_InitGfxReceipt os_gfx_receipt = OS_gfx_init(os_receipt); - //unused_variable(os_gfx_receipt); - R_InitReceipt r_init_receipt = R_init(os_receipt, os_gfx_receipt); - F_InitReceipt f_init_receipt = F_init(); - D_InitReceipt d_init_receipt = D_init(r_init_receipt, f_init_receipt); - unused_variable(d_init_receipt); - - UI_State *ui = UI_state_alloc(); - UI_state_set(ui); - - OS_Handle window_handle = OS_window_open(0, vec2_S64(APP_WINDOW_WIDTH, APP_WINDOW_HEIGHT), str8_lit("ello")); - R_Handle window_r = R_window_equip(window_handle); - - //break_debugger(); - //~ Main loop - MSG msg = {0}; - U64 frame_idx = 0; - for (B32 quit = 0; quit == 0;) - { - ArenaTemp scratch = scratch_get(0, 0); - OS_EventList events = OS_get_events(scratch.arena); - - if(window_handle.u64[0] == 0) - { - break_debugger(); - } - - F32 dt = FRAME_DT; - Rng2_F32 client_rect = OS_client_rect_from_window(window_handle); - Vec2_F32 client_rect_dim = dim2_F32(client_rect); - Vec2_S64 resolution = vec2_S64_from_vec(client_rect_dim); - - //- Begin frame - R_frame_begin(); - D_frame_begin(); - UI_frame_begin(dt); - R_window_start(window_r, resolution); - D_Bucket *bucket = D_bucket_make(scratch.arena); - // Anthing within this bucket scope will be pushed onto this the bucket. - D_BucketScope(scratch.arena, bucket) - { - - - //~ Build UI - UI_build_begin(window_handle, &events); // TODO(anton): events - - U64 top_pane_height = 25; - Vec2_F32 top_bar_p0 = vec2_F32(client_rect.x0, client_rect.y0); - Vec2_F32 top_bar_p1 = vec2_F32(client_rect.x0 + client_rect_dim.x, client_rect.y0 + top_pane_height); - Rng2_F32 top_bar_rect = rng2_F32(top_bar_p0, top_bar_p1); - unused_variable(top_bar_rect); - - U64 left_pane_width = 0.2f*APP_WINDOW_WIDTH; - - /////////////////////////// - //- Top bar - { - UI_push_fixed_rect(top_bar_rect); - UI_Box *top_bar_box = UI_box_make(UI_BoxFlag_DrawDropShadow|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawBorder, str8_lit("top_bar_pane")); - UI_pop_fixed_rect(); - UI_push_parent(top_bar_box); - - // Top pane - //UI_pane(top_bar_rect, str8_lit("top_bar_pane")) - //UI_width_fill - { - UI_Key file_menu_key = UI_key_from_string(UI_key_zero(), str8_lit("_file_menu_key_")); - UI_ctx_menu(file_menu_key) - { - UI_pref_width(UI_pixels(100, 0.0)) - UI_pref_height(UI_pixels(25, 0.0f)) - { - String8 buttons[] = {str8_lit("Open"), str8_lit("Exit")}; - - for(U64 i = 0; i < ArrayCount(buttons); i++) - { - UI_Signal sig = UI_button(buttons[i]); - if(UI_pressed(sig)) - { - UI_ctx_menu_close(); - } - } - - } - } - - // Buttons - { - B32 menu_open = 0; - if(ui_state->ctx_menu_open && UI_key_match(file_menu_key, ui_state->ctx_menu_key)) - { - menu_open = 1; - } - - UI_set_next_pref_width(UI_pixels(100, 0)); - UI_set_next_pref_height(UI_pixels(25, 0)); - UI_Signal file_button = UI_button(str8_lit("File")); - F32 button_size_y_px = file_button.box->rect.y1-file_button.box->rect.y0; - Vec2_F32 menu_offset = vec2_F32(0, button_size_y_px); - - if(menu_open) - { - if(UI_hovering(file_button) && !UI_ctx_menu_is_open(file_menu_key)) - { - UI_ctx_menu_open(file_menu_key, file_button.box->key, menu_offset); - } - } - else if(UI_pressed(file_button)) - { - if(UI_ctx_menu_is_open(file_menu_key)) - { - UI_ctx_menu_close(); - } - else - { - UI_ctx_menu_open(file_menu_key, file_button.box->key, menu_offset); - } - } - //UI_ctx_menu_close(); - - } - - } - UI_pop_parent(); - - } - - - - UI_build_end(); - - - - - //~ Submit and end frame - UI_draw(); - - // - //Rng2_F32 range = rng2_F32(vec2_F32(10,10), vec2_F32(100, 35)); - //D_rect2D(range, .color = vec4_F32(0, 0, 0, 1.f), - //.corner_radius = 0, - //.softness = 0, - //.omit_texture = 1); - //D_text2D(vec2_F32(range.p0.x, range.p1.y), str8_lit("Testing text")); - // - D_submit(window_r, bucket); - R_window_finish(window_r); - UI_frame_end(); - } - - //~ Handle Events - for(OS_Event *event = events.first; event != 0; event = event->next) - { - if(event->kind == OS_EventKind_WindowClose) - { - quit = 1; - break; - } - if(event->kind == OS_EventKind_Press && OS_handle_match(event->window, window_handle) && - event->key == OS_Key_Esc) - { - quit = 1; - break; - } - } - - // TODO(anton): Understand this? What is going on? - if(frame_idx == 0) - { - OS_window_first_paint(window_handle); - } - - frame_idx += 1; - if(frame_idx == U64Max) - { - frame_idx = 0; - } - - scratch_release(scratch); - } - - //~ Shutdown - R_window_unequip(window_handle, window_r); - R_shutdown(); + return 0; } - - - -// -// -//UI_padding(UI_pixels(10, 0)) -//UI_width_fill -//UI_row -//{ - //UI_spacer(UI_pixels(10, 0)); - // - //UI_set_next_pref_size(Axis2_X, UI_pixels(100, 1)); - //UI_set_next_pref_size(Axis2_Y, UI_pixels(30, 1)); - //UI_Signal button1 = UI_button(str8_lit("Button1")); - //unused_variable(button1); - // - //UI_spacer(UI_pixels(10, 0)); - //UI_set_next_pref_size(Axis2_X, UI_pixels(100, 0)); - //UI_set_next_pref_size(Axis2_Y, UI_pixels(30, 1)); - //UI_Signal button2 = UI_button(str8_lit("Button2")); - //unused_variable(button2); - // - //UI_spacer(UI_pixels(10, 0)); - //UI_set_next_pref_size(Axis2_X, UI_pixels(100, 0)); - //UI_set_next_pref_size(Axis2_Y, UI_pixels(30, 1)); - //UI_Signal button3 = UI_button(str8_lit("Button3")); - //unused_variable(button3); - // -//} -// diff --git a/src/os/os_core.c b/src/os/os_core.c deleted file mode 100644 index 24db847..0000000 --- a/src/os/os_core.c +++ /dev/null @@ -1,5 +0,0 @@ -root_function B32 -OS_handle_match(OS_Handle a, OS_Handle b) -{ - return a.u64[0] == b.u64[0]; -} \ No newline at end of file diff --git a/src/os/os_core.h b/src/os/os_core.h deleted file mode 100644 index a2d297c..0000000 --- a/src/os/os_core.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef OS_CORE_H -#define OS_CORE_H - -typedef U32 OS_AccessFlags; -enum { - OS_AccessFlag_Read = (1<<0), - OS_AccessFlag_Write = (1<<1), - OS_AccessFlag_Execute = (1<<2), - OS_AccessFlag_CreateNew = (1<<3), - OS_AccessFlag_All = 0xFFFFFFFF, -}; - -typedef struct OS_Handle OS_Handle; -struct OS_Handle { - U64 u64[1]; -}; - -typedef enum OS_ErrorCode -{ - OS_ErrorCode_Null, - OS_ErrorCode_COUNT -} OS_ErrorCode; - -typedef struct OS_Error OS_Error; -struct OS_Error { - OS_Error *next; - OS_ErrorCode code; -}; - -typedef struct OS_ErrorList OS_ErrorList; -struct OS_ErrorList { - OS_Error *first; - OS_Error *last; - U64 count; -}; - -typedef struct OS_InitReceipt OS_InitReceipt; -struct OS_InitReceipt -{ - U64 u64[1]; -}; - -typedef U64 OS_Timestamp; - -typedef struct OS_FileAttributes OS_FileAttributes; -struct OS_FileAttributes -{ - U64 size; - OS_Timestamp last_modified; -}; - -//////////////////////////////// -//~ Helpers -root_function B32 OS_handle_match(OS_Handle a, OS_Handle b); - -//////////////////////////////// -//~ @os_per_backend Memory - -root_function U64 OS_page_size(void); -root_function void* OS_reserve(U64 size); -root_function void OS_release(void *ptr, U64 size); -root_function void OS_commit(void *ptr, U64 size); -root_function void OS_decommit(void *ptr, U64 size); -root_function void OS_set_memory_access_flags(void *ptr, U64 size, OS_AccessFlags flags); - -//////////////////////////////// -//~ Thread and process types - -typedef void OS_Thread_Function(void *params); // void function pointer ? - -root_function OS_InitReceipt OS_init(void); -root_function void OS_thread_context_set(void *ptr); -root_function void* OS_thread_context_get(void); - -//////////////////////////////// -//~ @os_per_backend File System -root_function OS_Handle OS_file_open(OS_AccessFlags access_flags, String8 path); -root_function void OS_file_close(OS_Handle file); -root_function String8 OS_file_read(Arena *arena, OS_Handle file, U64 min, U64 max); -// We supply whatever we want to write as a String8List, -// so we can pull data from different places with no intermediate buffer. -root_function void OS_file_write(Arena *arena, OS_Handle file, U64 off, - String8List data, OS_ErrorList *out_errors); -root_function OS_FileAttributes OS_attributes_from_file(OS_Handle file); - - - - -#endif /* OS_CORE_H */ diff --git a/src/os/os_entry_point.c b/src/os/os_entry_point.c deleted file mode 100644 index cab9923..0000000 --- a/src/os/os_entry_point.c +++ /dev/null @@ -1,5 +0,0 @@ -#if OS_WINDOWS -#include "win32/os_entry_point_win32.c" -#else -#error Entry point not defined -#endif \ No newline at end of file diff --git a/src/os/os_gfx.c b/src/os/os_gfx.c deleted file mode 100644 index 4cb7229..0000000 --- a/src/os/os_gfx.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "os_gfx_meta.c" - - -root_function B32 -OS_key_press(OS_EventList *events, OS_Handle window, OS_Key key) -{ - B32 result = 0; - for(OS_Event *e = events->first; e != 0; e = e->next) - { - - if(e->kind == OS_EventKind_Press && OS_handle_match(window, e->window) && e->key == key) - // TODO(anton): modifiers - { - OS_consume_event(events, e); - result = 1; - break; - } - } - return result; -} \ No newline at end of file diff --git a/src/os/os_gfx.h b/src/os/os_gfx.h deleted file mode 100644 index 6eea74e..0000000 --- a/src/os/os_gfx.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef OS_GFX_H -#define OS_GFX_H - -typedef U32 OS_Window_Flags; - -typedef struct OS_InitGfxReceipt OS_InitGfxReceipt; -struct OS_InitGfxReceipt -{ - U64 u64[1]; -}; - -#include "os_gfx_meta.h" - -//////////////////////////////// -//~ Cursor Types - -typedef enum OS_Cursor -{ - OS_Cursor_Pointer, - OS_Cursor_IBar, - OS_Cursor_LeftRight, - OS_Cursor_UpDown, - OS_Cursor_DownRight, - OS_Cursor_UpRight, - OS_Cursor_UpDownLeftRight, - OS_Cursor_HandPoint, - OS_Cursor_Disabled, - OS_Cursor_COUNT, -} -OS_Cursor; - -//////////////////////////////// -//~ Events -typedef enum OS_EventKind -{ - OS_EventKind_Null, - OS_EventKind_Press, - OS_EventKind_Release, - OS_EventKind_MouseMove, - OS_EventKind_Text, - OS_EventKind_Scroll, - OS_EventKind_WindowLoseFocus, - OS_EventKind_WindowClose, - OS_EventKind_FileDrop, - OS_EventKind_Wakeup, - OS_EventKind_COUNT -} -OS_EventKind; - - -typedef struct OS_Event OS_Event; -struct OS_Event -{ - OS_Event *next; - OS_Event *prev; - OS_Handle window; - OS_EventKind kind; - //OS_Modifiers modifiers; - OS_Key key; - U32 character; - Vec2_F32 position; - Vec2_F32 scroll; - String8 path; -}; - -typedef struct OS_EventList OS_EventList; -struct OS_EventList -{ - OS_Event *first; - OS_Event *last; - U64 count; -}; - -//////////////////////////////// -//~ Event Helpers -root_function U64 OS_character_from_key(OS_Key key); -root_function String8 OS_string_from_event(Arena *arena, OS_Event *event); -root_function B32 OS_key_press(OS_EventList *events, OS_Handle window, OS_Key key); -root_function B32 OS_key_release(OS_EventList *events, OS_Handle window); -root_function B32 OS_text_codepoint(OS_EventList *events, OS_Handle window, U32 codepoint); -root_function Vec2_F32 OS_mouse_from_window(OS_Handle handle); - -//////////////////////////////// -//~ @os_per_backend Init and windowing -root_function OS_InitGfxReceipt OS_gfx_init(OS_InitReceipt os_init_receipt); -root_function OS_Handle OS_window_open(OS_Window_Flags flags, Vec2_S64 size, String8 title); -root_function Rng2_F32 OS_client_rect_from_window(OS_Handle window_handle); - -//////////////////////////////// -//~ @os_per_backend Events -root_function OS_EventList OS_get_events(Arena *arena); -root_function void OS_consume_event(OS_EventList *events, OS_Event *event); - -#endif /* OS_GFX_H */ diff --git a/src/os/os_gfx_meta.c b/src/os/os_gfx_meta.c deleted file mode 100644 index 5df8d70..0000000 --- a/src/os/os_gfx_meta.c +++ /dev/null @@ -1,95 +0,0 @@ -String8 os_g_key_string_table[92] = -{ - str8_lit_comp("Null"), - str8_lit_comp("Escape"), - str8_lit_comp("F1"), - str8_lit_comp("F2"), - str8_lit_comp("F3"), - str8_lit_comp("F4"), - str8_lit_comp("F5"), - str8_lit_comp("F6"), - str8_lit_comp("F7"), - str8_lit_comp("F8"), - str8_lit_comp("F9"), - str8_lit_comp("F10"), - str8_lit_comp("F11"), - str8_lit_comp("F12"), - str8_lit_comp("F13"), - str8_lit_comp("F14"), - str8_lit_comp("F15"), - str8_lit_comp("F16"), - str8_lit_comp("F17"), - str8_lit_comp("F18"), - str8_lit_comp("F19"), - str8_lit_comp("F20"), - str8_lit_comp("F21"), - str8_lit_comp("F22"), - str8_lit_comp("F23"), - str8_lit_comp("F24"), - str8_lit_comp("Grave Accent"), - str8_lit_comp("0"), - str8_lit_comp("1"), - str8_lit_comp("2"), - str8_lit_comp("3"), - str8_lit_comp("4"), - str8_lit_comp("5"), - str8_lit_comp("6"), - str8_lit_comp("7"), - str8_lit_comp("8"), - str8_lit_comp("9"), - str8_lit_comp("Minus"), - str8_lit_comp("Equal"), - str8_lit_comp("Backspace"), - str8_lit_comp("Delete"), - str8_lit_comp("Tab"), - str8_lit_comp("A"), - str8_lit_comp("B"), - str8_lit_comp("C"), - str8_lit_comp("D"), - str8_lit_comp("E"), - str8_lit_comp("F"), - str8_lit_comp("G"), - str8_lit_comp("H"), - str8_lit_comp("I"), - str8_lit_comp("J"), - str8_lit_comp("K"), - str8_lit_comp("L"), - str8_lit_comp("M"), - str8_lit_comp("N"), - str8_lit_comp("O"), - str8_lit_comp("P"), - str8_lit_comp("Q"), - str8_lit_comp("R"), - str8_lit_comp("S"), - str8_lit_comp("T"), - str8_lit_comp("U"), - str8_lit_comp("V"), - str8_lit_comp("W"), - str8_lit_comp("X"), - str8_lit_comp("Y"), - str8_lit_comp("Z"), - str8_lit_comp("Space"), - str8_lit_comp("Enter"), - str8_lit_comp("Ctrl"), - str8_lit_comp("Shift"), - str8_lit_comp("Alt"), - str8_lit_comp("Up"), - str8_lit_comp("Left"), - str8_lit_comp("Down"), - str8_lit_comp("Right"), - str8_lit_comp("Page Up"), - str8_lit_comp("Page Down"), - str8_lit_comp("Home"), - str8_lit_comp("End"), - str8_lit_comp("Forward Slash"), - str8_lit_comp("Period"), - str8_lit_comp("Comma"), - str8_lit_comp("Quote"), - str8_lit_comp("Left Bracket"), - str8_lit_comp("Right Bracket"), - str8_lit_comp("Insert"), - str8_lit_comp("Left Mouse Button"), - str8_lit_comp("Middle Mouse Button"), - str8_lit_comp("Right Mouse Button"), - str8_lit_comp("Semicolon"), -}; diff --git a/src/os/os_gfx_meta.h b/src/os/os_gfx_meta.h deleted file mode 100644 index 1cc6b07..0000000 --- a/src/os/os_gfx_meta.h +++ /dev/null @@ -1,114 +0,0 @@ -/* date = April 5th 2024 7:56 pm */ - -#ifndef OS_GFX_META_H -#define OS_GFX_META_H - -// TODO(anton): This is generated code in Ryans codebase. I just copy it here now and make some generation -// myself later. - - -typedef enum OS_Key -{ - OS_Key_Null, - OS_Key_Esc, - OS_Key_F1, - OS_Key_F2, - OS_Key_F3, - OS_Key_F4, - OS_Key_F5, - OS_Key_F6, - OS_Key_F7, - OS_Key_F8, - OS_Key_F9, - OS_Key_F10, - OS_Key_F11, - OS_Key_F12, - OS_Key_F13, - OS_Key_F14, - OS_Key_F15, - OS_Key_F16, - OS_Key_F17, - OS_Key_F18, - OS_Key_F19, - OS_Key_F20, - OS_Key_F21, - OS_Key_F22, - OS_Key_F23, - OS_Key_F24, - OS_Key_GraveAccent, - OS_Key_0, - OS_Key_1, - OS_Key_2, - OS_Key_3, - OS_Key_4, - OS_Key_5, - OS_Key_6, - OS_Key_7, - OS_Key_8, - OS_Key_9, - OS_Key_Minus, - OS_Key_Equal, - OS_Key_Backspace, - OS_Key_Delete, - OS_Key_Tab, - OS_Key_A, - OS_Key_B, - OS_Key_C, - OS_Key_D, - OS_Key_E, - OS_Key_F, - OS_Key_G, - OS_Key_H, - OS_Key_I, - OS_Key_J, - OS_Key_K, - OS_Key_L, - OS_Key_M, - OS_Key_N, - OS_Key_O, - OS_Key_P, - OS_Key_Q, - OS_Key_R, - OS_Key_S, - OS_Key_T, - OS_Key_U, - OS_Key_V, - OS_Key_W, - OS_Key_X, - OS_Key_Y, - OS_Key_Z, - OS_Key_Space, - OS_Key_Enter, - OS_Key_Ctrl, - OS_Key_Shift, - OS_Key_Alt, - OS_Key_Up, - OS_Key_Left, - OS_Key_Down, - OS_Key_Right, - OS_Key_PageUp, - OS_Key_PageDown, - OS_Key_Home, - OS_Key_End, - OS_Key_ForwardSlash, - OS_Key_Period, - OS_Key_Comma, - OS_Key_Quote, - OS_Key_LeftBracket, - OS_Key_RightBracket, - OS_Key_Insert, - OS_Key_MouseLeft, - OS_Key_MouseMiddle, - OS_Key_MouseRight, - OS_Key_Semicolon, - OS_Key_COUNT, -} -OS_Key; - -root_global String8 os_g_key_string_table[92]; - - - - - -#endif //OS_GFX_META_H diff --git a/src/os/os_inc.c b/src/os/os_inc.c deleted file mode 100644 index 9fa5346..0000000 --- a/src/os/os_inc.c +++ /dev/null @@ -1,9 +0,0 @@ -#include "os/os_core.c" -#include "os/os_gfx.c" - -#if OS_WINDOWS -#include "win32/os_core_win32.c" -#include "win32/os_gfx_win32.c" -#else -# error OS layer for this platform not implemented yet -#endif \ No newline at end of file diff --git a/src/os/os_inc.h b/src/os/os_inc.h deleted file mode 100644 index 876d7b4..0000000 --- a/src/os/os_inc.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef OS_INC_H -#define OS_INC_H - -// TODO(anton): Change this to OS implementations of the memory -#if !defined(m_reserve) -#define m_reserve OS_reserve -#endif -#if !defined(m_commit) -#define m_commit OS_commit -#endif -#if !defined(m_decommit) -#define m_decommit OS_decommit -#endif -#if !defined(m_release) -#define m_release OS_release -#endif - -#include "os/os_core.h" -#include "os/os_gfx.h" - -#if OS_WINDOWS -# include "win32/os_core_win32.h" -# include "win32/os_gfx_win32.h" -#else -# error OS layer for this platform not implemented yet -#endif - -#endif //OS_INC_H diff --git a/src/os/win32/os_core_win32.c b/src/os/win32/os_core_win32.c deleted file mode 100644 index d5cf17f..0000000 --- a/src/os/win32/os_core_win32.c +++ /dev/null @@ -1,260 +0,0 @@ -#pragma comment(lib, "user32") -#pragma comment(lib, "winmm") -#pragma comment(lib, "shell32") - -//~ Memory -root_function U64 -OS_page_size(void) { - SYSTEM_INFO info; - GetSystemInfo(&info); - return info.dwPageSize; -} - -root_function void -*OS_reserve(U64 size) { - U64 gb_snapped_size = size; - // Align the reserved memory to nearest gigabyte? - gb_snapped_size += M_DEFAULT_RESERVE_SIZE - 1; - gb_snapped_size -= gb_snapped_size % M_DEFAULT_RESERVE_SIZE; - void *ptr = VirtualAlloc(0, gb_snapped_size, MEM_RESERVE, PAGE_NOACCESS); - return ptr; -} - -root_function void -OS_release(void *ptr, U64 size) { - VirtualFree(ptr, 0, MEM_RELEASE); -} - -root_function void -OS_commit(void *ptr, U64 size) { - U64 page_snapped_size = size; - page_snapped_size += OS_page_size() - 1; - page_snapped_size -= page_snapped_size%OS_page_size(); - VirtualAlloc(ptr, page_snapped_size, MEM_COMMIT, PAGE_READWRITE); -} - -root_function void -OS_decommit(void *ptr, U64 size){ - VirtualFree(ptr, size, MEM_DECOMMIT); -} - -//~ Thread -root_function OS_InitReceipt OS_init(void) -{ - if (is_main_thread() && os_g_w32_state == 0) - { - Arena *arena = m_make_arena_reserve(Gigabytes(1)); - os_g_w32_state = PushArray(arena, OS_W32_State, 1); - os_g_w32_state->arena = arena; - - os_g_w32_state->thread_arena = m_make_arena_reserve(Kilobytes(256)); - - } - - OS_InitReceipt out; - out.u64[0] = 1; - return out; -} - - -root_function void OS_thread_context_set(void *ptr) { - TlsSetValue(os_g_w32_state->thread_context_index, ptr); -} - -root_function void* OS_thread_context_get(void) { - void *result = TlsGetValue(os_g_w32_state->thread_context_index); - return result; -} - -/* // TODO(anton): This is an interesting function to protect virtual allocs, but it doesn't look like it's -used in the app template right now. I'll add it when I need it. -root_function void -OS_set_memory_access_flags(void *ptr, U64 size, OS_AccessFlags flags) { - - U64 page_snapped_size = size; - page_snapped_size += OS_page_size() - 1; - page_snapped_size -= page_snapped_size%OS_page_size(); - - - DWORD new_flags = 0; - { - switch(flags) - { - default: - { - new_flags = PAGE_NOACCESS; - }break; -#define Map(win32_code, bitflags) case bitflags:{new_flags = win32_code;}break - Map(PAGE_EXECUTE, OS_AccessFlag_Execute); - Map(PAGE_EXECUTE_READ, OS_AccessFlag_Execute|OS_AccessFlag_Read); - Map(PAGE_EXECUTE_READWRITE, OS_AccessFlag_Execute|OS_AccessFlag_Read|OS_AccessFlag_Write); - Map(PAGE_EXECUTE_WRITECOPY, OS_AccessFlag_Execute|OS_AccessFlag_Write); - Map(PAGE_READONLY, OS_AccessFlag_Read); - Map(PAGE_READWRITE, OS_AccessFlag_Read|OS_AccessFlag_Write); -#undef Map - } - } - - - DWORD old_flags = 0; - VirtualProtect(ptr, page_snapped_size, new_flags, &old_flags); -} -*/ - - - -//~ @os_per_backend File System -root_function OS_Handle -OS_file_open(OS_AccessFlags access_flags, String8 path) { - ArenaTemp scratch = scratch_get(0, 0); - String16 path16 = str16_from8(scratch.arena, path); - - // Map to win32 access flags - DWORD desired_access = 0; - if(access_flags & OS_AccessFlag_Read) { desired_access |= GENERIC_READ; } - if(access_flags & OS_AccessFlag_Write) { desired_access |= GENERIC_WRITE; } - - DWORD share_mode = 0; - - SECURITY_ATTRIBUTES security_attributes = { - (DWORD)sizeof(SECURITY_ATTRIBUTES), - 0, - 0, - }; - - // Map to win32 creation disposition - DWORD creation_disposition = 0; - if(!(access_flags & OS_AccessFlag_CreateNew)) { - creation_disposition = OPEN_EXISTING; - } - - DWORD flags_and_attribs = 0; - HANDLE template_file = 0; - - HANDLE file = CreateFileW((WCHAR*)path16.str, - desired_access, - share_mode, - &security_attributes, - creation_disposition, - flags_and_attribs, - template_file); - - if(file == INVALID_HANDLE_VALUE) { - // TODO(anton): Append to errors - break_debugger(); - } - - // Map to abstract handle - OS_Handle handle = {0}; - handle.u64[0] = (U64)file; - - scratch_release(scratch); - return handle; -} - -root_function void -OS_file_close(OS_Handle file) { - HANDLE handle = (HANDLE)file.u64[0]; - if(handle != INVALID_HANDLE_VALUE) { - CloseHandle(handle); - } -} - -root_function String8 -OS_file_read(Arena *arena, OS_Handle file, U64 min, U64 max) { - String8 result = {0}; - - HANDLE handle = (HANDLE)file.u64[0]; - if(handle == INVALID_HANDLE_VALUE) { - // TODO(anton): accumulate errors - } else { - U64 bytes_to_read = AbsoluteValueU64(max - min); - U64 bytes_actually_read = 0; - result.str = PushArray(arena, U8, bytes_to_read); - result.size = 0; - U8 *ptr = result.str; - U8 *one_past_last = result.str + bytes_to_read; - - for(;;) { - U64 unread = (U64)(one_past_last - ptr); - DWORD to_read = (DWORD)(ClampTop(unread, U32Max)); - DWORD did_read = 0; - // TODO(anton): Understand WINAPI - if(!ReadFile(handle, ptr, to_read, &did_read, 0)) { - break; - } - ptr += did_read; - result.size += did_read; - if(ptr >= one_past_last) { - break; - } - - } - } - return result; -} - -root_function OS_FileAttributes -OS_attributes_from_file(OS_Handle file) -{ - HANDLE handle = (HANDLE)file.u64[0]; - OS_FileAttributes attrs = {0}; - U32 high_bits = 0; - U32 low_bits = GetFileSize(handle, (DWORD *)&high_bits); - FILETIME last_write_time = {0}; - GetFileTime(handle, 0, 0, &last_write_time); - attrs.size = (U64)low_bits | (((U64)high_bits) << 32); - attrs.last_modified = ((U64)last_write_time.dwLowDateTime) | - (((U64)last_write_time.dwHighDateTime) << 32); - return attrs; -} - -root_function void -OS_file_write(Arena *arena, OS_Handle file, U64 off, String8List data, OS_ErrorList *out_errors) { - HANDLE handle = (HANDLE)file.u64[0]; - if(handle == 0 || handle == INVALID_HANDLE_VALUE) - { - // TODO(anton): accumulate errors - } - else for(String8Node *node = data.first; node != 0; node = node->next) - { - U8 *ptr = node->string.str; - U8 *opl = ptr + node->string.size; - for(;;) - { - U64 unwritten = (U64)(opl - ptr); - DWORD to_write = (DWORD)(ClampTop(unwritten, U32Max)); - DWORD did_write = 0; - // TODO(anton): understand winapi - if(!WriteFile(handle, ptr, to_write, &did_write, 0)) - { - goto fail_out; - } - ptr += did_write; - if(ptr >= opl) - { - break; - } - } - } - fail_out:; -} - -root_function Rng2_F32 -OS_client_rect_from_window(OS_Handle window_handle) -{ - Rng2_F32 rect = {0}; - OS_W32_Window *window = (OS_W32_Window *)window_handle.u64[0]; - if(window != 0) - { - RECT w32_rect = {0}; - if(GetClientRect(window->hwnd, &w32_rect)) - { - rect.x0 = (F32)w32_rect.left; - rect.y0 = (F32)w32_rect.top; - rect.x1 = (F32)w32_rect.right; - rect.y1 = (F32)w32_rect.bottom; - } - } - return rect; -} \ No newline at end of file diff --git a/src/os/win32/os_core_win32.h b/src/os/win32/os_core_win32.h deleted file mode 100644 index dde3102..0000000 --- a/src/os/win32/os_core_win32.h +++ /dev/null @@ -1,49 +0,0 @@ -/* date = April 25th 2023 9:46 pm */ - -#ifndef OS_CORE_WIN32_H -#define OS_CORE_WIN32_H - -// To avoid C4042 error when including windows we use some -// preprocessor praga macro things.. So when including the windows headers we -// won't have defined the "function" keyword (we define it in base_core.h), -// and then we redefine it after when popping. -#pragma push_macro("function") -#undef function -#define WIN32_LEAN_AND_MEAN -#include -#pragma pop_macro("function") - - -// We have a nice debugbreak assert macro, but it is nice to have one also specifically for windows HRESULT -#define AssertHR(hr) Assert(SUCCEEDED(hr)) - -///////////////////////////////////// - -// Processes and threads -typedef struct OS_W32_Thread OS_W32_Thread; -struct OS_W32_Thread -{ - OS_W32_Thread *next; - HANDLE handle; - DWORD thread_id; - void *params; - OS_Thread_Function *func; -}; - - -///////////////////////////////////// -// Global state -typedef struct OS_W32_State OS_W32_State; -struct OS_W32_State -{ - Arena *arena; - - Arena *thread_arena; - DWORD thread_context_index; -}; - -global HINSTANCE os_g_w32_hinstance; -global OS_W32_State *os_g_w32_state; - -//root_function OS_W32_Window* OS_W32_window_from_handle(OS_Handle handle); -#endif //OS_CORE_WIN32_H diff --git a/src/os/win32/os_entry_point_win32.c b/src/os/win32/os_entry_point_win32.c deleted file mode 100644 index fa4078e..0000000 --- a/src/os/win32/os_entry_point_win32.c +++ /dev/null @@ -1,9 +0,0 @@ -function void EntryPoint(void); - - -int WinMain(HINSTANCE instance, HINSTANCE prev_instance, LPSTR lp_cmd_line, int n_show_cmd) -{ - os_g_w32_hinstance = instance; - base_main_thread_entry(EntryPoint, (U64)__argc, __argv); - return 0; -} \ No newline at end of file diff --git a/src/os/win32/os_gfx_win32.c b/src/os/win32/os_gfx_win32.c deleted file mode 100644 index 5d0a28f..0000000 --- a/src/os/win32/os_gfx_win32.c +++ /dev/null @@ -1,328 +0,0 @@ -#pragma comment(lib, "gdi32") - -#define OS_W32_GraphicalWindowClassName L"ApplicationWindowClass" - -root_function OS_InitGfxReceipt -OS_gfx_init(OS_InitReceipt os_init_receipt) -{ - if (is_main_thread() && os_g_w32_gfx_state == 0) - { - - { - // Global state - Arena *arena = m_make_arena_reserve(Gigabytes(1)); - os_g_w32_gfx_state = PushArray(arena, OS_W32_Gfx_State, 1); - os_g_w32_gfx_state->arena = arena; - os_g_w32_gfx_state->window_arena = m_make_arena_reserve(Gigabytes(1)); - } - // TODO(antonl) DPI awareness - - // Register window class - { - /* WNDCLASSW window_class = { 0 }; */ - /* window_class.style = CS_HREDRAW | CS_VREDRAW; */ - /* window_class.lpfnWndProc = OS_W32_WindowProc; */ - /* window_class.hInstance = g_os_w32_hinstance; */ - /* window_class.lpszClassName = OS_W32_GraphicalWindowClassName; */ - /* window_class.hCursor = LoadCursor(0, IDC_ARROW); */ - /* RegisterClassW(&window_class); */ - WNDCLASSEXW window_class = {0}; - window_class.cbSize = sizeof(WNDCLASSEXW); - window_class.lpfnWndProc = OS_W32_window_proc; - window_class.hInstance = os_g_w32_hinstance; - window_class.lpszClassName = OS_W32_GraphicalWindowClassName; - if(!RegisterClassExW(&window_class)) - { - break_debugger(); - } - } - - // Rjf makes a "global invisible window", but why? - { - os_g_w32_gfx_state->global_hwnd = CreateWindowExW(0, - OS_W32_GraphicalWindowClassName, - L"", - WS_OVERLAPPEDWINDOW, - 100,100, - 0,0, - 0,0, - os_g_w32_hinstance, 0); - os_g_w32_gfx_state->global_hdc = GetDC(os_g_w32_gfx_state->global_hwnd); - } - } - - OS_InitGfxReceipt out; - out.u64[0] = 1; - return out; -} - -root_function OS_Handle -OS_W32_handle_from_window(OS_W32_Window *window) -{ - OS_Handle handle = { 0 }; - handle.u64[0] = (U64)window; - return handle; -} - -root_function OS_W32_Window* -OS_W32_window_from_handle(OS_Handle handle) -{ - OS_W32_Window *window = (OS_W32_Window *)handle.u64[0]; - return window; -} - -root_function OS_Handle -OS_window_open(OS_Window_Flags flags, Vec2_S64 size, String8 title) -{ - OS_Handle handle = { 0 }; - - { - // Window allocation - OS_W32_Window *window = os_g_w32_gfx_state->free_window; - { - // Windows are stored in a stack on the gfx state - if (window != 0) - { - StackPop(os_g_w32_gfx_state->free_window); - } - else - { - window = PushArray(os_g_w32_gfx_state->window_arena, OS_W32_Window, 1); - } - MemoryZeroStruct(window); - DLLPushBack(os_g_w32_gfx_state->first_window, os_g_w32_gfx_state->last_window, window); - } - - // Open window - HWND hwnd = 0; - HDC hdc = 0; - { - ArenaTemp scratch = scratch_get(0, 0); - String16 title16 = str16_from8(scratch.arena, title); - hwnd = CreateWindowExW(0, - OS_W32_GraphicalWindowClassName, (LPCWSTR)title16.str, - WS_OVERLAPPEDWINDOW | WS_VISIBLE, - 100, 100, - size.x, size.y, 0, 0, os_g_w32_hinstance, 0); - hdc = GetDC(hwnd); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)window); - scratch_release(scratch); - } - - { - window->hwnd = hwnd; - window->hdc = hdc; - } - - handle = OS_W32_handle_from_window(window); - } - return handle; -} - -function LRESULT -OS_W32_window_proc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param) -{ - LRESULT result = 0; - - OS_Event *event = 0; - OS_W32_Window *window = (OS_W32_Window *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - OS_Handle window_handle = OS_W32_handle_from_window(window); - ArenaTemp scratch = scratch_get(&os_w32_tl_events_arena, 1); - OS_EventList fallback_event_list = {0}; - if(os_w32_tl_events_arena == 0) - { - os_w32_tl_events_arena = scratch.arena; - os_w32_tl_events_list = &fallback_event_list; - } - - B32 is_release = 0; - Axis2 scroll_axis = Axis2_Y; - switch(message) - { - default: - { - result = DefWindowProcW(hwnd, message, w_param, l_param); - } break; - - //- General window events - case WM_CLOSE: - { - event = PushArray(os_w32_tl_events_arena, OS_Event, 1); - event->kind = OS_EventKind_WindowClose; - event->window = window_handle; - } break; - - //- Mouse buttons - case WM_LBUTTONUP: - case WM_MBUTTONUP: - case WM_RBUTTONUP: - { - ReleaseCapture(); - is_release = 1; - } fallthrough; - case WM_LBUTTONDOWN: - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - { - if(is_release == 0) - { - SetCapture(hwnd); - } - OS_EventKind kind = is_release ? OS_EventKind_Release : OS_EventKind_Press; - OS_Key key = OS_Key_MouseLeft; - switch(message) - { - case WM_MBUTTONUP: case WM_MBUTTONDOWN: key = OS_Key_MouseMiddle; break; - case WM_RBUTTONUP: case WM_RBUTTONDOWN: key = OS_Key_MouseRight; break; - } - event = PushArray(os_w32_tl_events_arena, OS_Event, 1); - event->kind = kind; - event->window = window_handle; - event->key = key; - event->position = OS_mouse_from_window(window_handle); - } break; - - //- Keyboard events - case WM_SYSKEYDOWN: case WM_SYSKEYUP: - { - result = DefWindowProcW(hwnd, message, w_param, l_param); - } fallthrough; - case WM_KEYDOWN: - case WM_KEYUP: - { - // TODO(anton): Just check this thing with was down, is down.., WINAPI crap - B32 was_down = !!(l_param & (1 << 30)); - B32 is_down = !(l_param & (1 << 31)); - OS_EventKind kind = is_down ? OS_EventKind_Press : OS_EventKind_Release; - - // TODO(anton): Here we use statics but maybe we should not... - // Could just move this out and pre-init or generate it and include or whatever... - // probably should just be in some meta header. - local_persist OS_Key key_table[256] = {0}; - local_persist B32 key_table_initialised = 0; - if(!key_table_initialised) - { - key_table_initialised = 1; - - for (U32 i = 'A', j = OS_Key_A; i <= 'Z'; i += 1, j += 1) - { - key_table[i] = (OS_Key)j; - } - for (U32 i = '0', j = OS_Key_0; i <= '9'; i += 1, j += 1) - { - key_table[i] = (OS_Key)j; - } - for (U32 i = VK_F1, j = OS_Key_F1; i <= VK_F24; i += 1, j += 1) - { - key_table[i] = (OS_Key)j; - } - - key_table[VK_ESCAPE] = OS_Key_Esc; - key_table[VK_OEM_3] = OS_Key_GraveAccent; - key_table[VK_OEM_MINUS] = OS_Key_Minus; - key_table[VK_OEM_PLUS] = OS_Key_Equal; - key_table[VK_BACK] = OS_Key_Backspace; - key_table[VK_TAB] = OS_Key_Tab; - key_table[VK_SPACE] = OS_Key_Space; - key_table[VK_RETURN] = OS_Key_Enter; - key_table[VK_CONTROL] = OS_Key_Ctrl; - key_table[VK_SHIFT] = OS_Key_Shift; - key_table[VK_MENU] = OS_Key_Alt; - key_table[VK_UP] = OS_Key_Up; - key_table[VK_LEFT] = OS_Key_Left; - key_table[VK_DOWN] = OS_Key_Down; - key_table[VK_RIGHT] = OS_Key_Right; - key_table[VK_DELETE] = OS_Key_Delete; - key_table[VK_PRIOR] = OS_Key_PageUp; - key_table[VK_NEXT] = OS_Key_PageDown; - key_table[VK_HOME] = OS_Key_Home; - key_table[VK_END] = OS_Key_End; - key_table[VK_OEM_2] = OS_Key_ForwardSlash; - key_table[VK_OEM_PERIOD] = OS_Key_Period; - key_table[VK_OEM_COMMA] = OS_Key_Comma; - key_table[VK_OEM_7] = OS_Key_Quote; - key_table[VK_OEM_4] = OS_Key_LeftBracket; - key_table[VK_OEM_6] = OS_Key_RightBracket; - key_table[VK_INSERT] = OS_Key_Insert; - key_table[VK_OEM_1] = OS_Key_Semicolon; - } - - OS_Key key = OS_Key_Null; - if(w_param < ArrayCount(key_table)) - { - key = key_table[w_param]; - } - - event = PushArray(os_w32_tl_events_arena, OS_Event, 1); - event->kind = kind; - event->window = window_handle; - event->key = key; - } break; - - - } - // If we registered an event we push it to the event list. - if(event) - { - DLLPushBack(os_w32_tl_events_list->first, os_w32_tl_events_list->last, event); - os_w32_tl_events_list->count += 1; - } - - scratch_release(scratch); - return result; -} - -root_function Vec2_F32 -OS_mouse_from_window(OS_Handle handle) -{ - Vec2_F32 result = vec2_F32(-100, -100); - OS_W32_Window *window = OS_W32_window_from_handle(handle); - if(window != 0) - { - POINT point; - if(GetCursorPos(&point)) - { - if(ScreenToClient(window->hwnd, &point)) - { - result = vec2_F32(point.x, point.y); - } - } - } - - return result; -} - -root_function OS_EventList -OS_get_events(Arena* arena) -{ - OS_EventList list = {0}; - os_w32_tl_events_arena = arena; - os_w32_tl_events_list = &list; - for(MSG message; PeekMessage(&message, 0, 0, 0, PM_REMOVE);) - { - TranslateMessage(&message); - DispatchMessage(&message); - } - os_w32_tl_events_arena = 0; - os_w32_tl_events_list = 0; - - return list; -} - -root_function void -OS_consume_event(OS_EventList *events, OS_Event *event) -{ - DLLRemove(events->first, events->last, event); - events->count -= 1; - event->kind = OS_EventKind_Null; -} - -root_function void -OS_window_first_paint(OS_Handle handle) -{ - ArenaTemp scratch = scratch_get(0,0); - OS_W32_Window *window = OS_W32_window_from_handle(handle); - ShowWindow(window->hwnd, SW_SHOW); - UpdateWindow(window->hwnd); - scratch_release(scratch); -} \ No newline at end of file diff --git a/src/os/win32/os_gfx_win32.h b/src/os/win32/os_gfx_win32.h deleted file mode 100644 index 76a0f06..0000000 --- a/src/os/win32/os_gfx_win32.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef OS_GFX_WIN32_H -#define OS_GFX_WIN32_H - -typedef struct OS_W32_Window OS_W32_Window; -struct OS_W32_Window -{ - OS_W32_Window *next; - OS_W32_Window *prev; - HWND hwnd; - HDC hdc; -}; - -typedef struct OS_W32_Gfx_State OS_W32_Gfx_State; -struct OS_W32_Gfx_State -{ - Arena *arena; - HWND global_hwnd; - HDC global_hdc; - - Arena *window_arena; - OS_W32_Window *first_window; - OS_W32_Window *last_window; - OS_W32_Window *free_window; -}; - -root_global OS_W32_Gfx_State *os_g_w32_gfx_state = 0; -extern per_thread Arena *os_w32_tl_events_arena = 0; -extern per_thread OS_EventList *os_w32_tl_events_list = 0; - -root_function OS_Handle OS_W32_handle_from_window(OS_W32_Window *window); -root_function OS_W32_Window *OS_W32_window_from_handle(OS_Handle handle); -function LRESULT OS_W32_window_proc(HWND hwnd, UINT message, WPARAM w_param, LPARAM l_param); - - - -#endif // OS_GFX_WIN32_H diff --git a/src/render/d3d11/render_d3d11.c b/src/render/d3d11/render_d3d11.c deleted file mode 100644 index c2ebc1f..0000000 --- a/src/render/d3d11/render_d3d11.c +++ /dev/null @@ -1,798 +0,0 @@ -// Global tables generated by the metadesk code in Ryan's codebase, -// here I do them by hand, for now - -////////////////////////////////// -//~ Input element descriptions - -global D3D11_INPUT_ELEMENT_DESC r_d3d11_g_rect2d_input_layout_elems[] = -{ - {"POS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - 0, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - {"TEX", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - {"COL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - {"COL", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - {"COL", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - {"COL", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, - { "CRAD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1 }, - {"STY", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, - D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}, -}; - - - -global R_D3D11_CmdGlobalKindInfo r_d3d11_g_cmd_global_kind_info_table[R_D3D11_CmdGlobalKind_COUNT] = -{ - {0}, // Nil - {sizeof(R_D3D11_CmdGlobals_Rect2D)}, -}; - - -R_D3D11_ShaderPairKindInfo r_d3d11_g_shader_pair_kind_info_table[R_D3D11_ShaderPairKind_COUNT] = {0}; - -global R_D3D11_State *r_d3d11_state; - - - -////////////////////////////////// -//~ Render helpers - -// Create a buffer holding all the instance data for a current batch -r_function ID3D11Buffer * -R_D3D11_instance_buffer_from_batch_list(R_BatchList *list) -{ - U64 needed_size = list->byte_count; - if(needed_size > Kilobytes(64)) - { - break_debugger(); - } - - ID3D11Buffer *buffer = r_d3d11_state->scratch_buffer_64kb; - - D3D11_MAPPED_SUBRESOURCE sub_resource = {0}; - ID3D11DeviceContext_Map(r_d3d11_state->base_device_context, (ID3D11Resource *)buffer, 0, - D3D11_MAP_WRITE_DISCARD, 0, &sub_resource); - U8 *ptr = (U8 *)sub_resource.pData; - for(R_Batch *batch = list->first; batch != 0; batch = batch->next) - { - MemoryCopy(ptr, batch->v, batch->byte_count); - ptr += batch->byte_count; - } - ID3D11DeviceContext_Unmap(r_d3d11_state->base_device_context, (ID3D11Resource *)buffer, 0); - - - - return buffer; -} - - -// Temporary initialisation of the shader table, probably we just keep reading the shader src from file here -// in the end, and we generate a table through metaprogramming. -r_function void -R_D3D11_initialise_shader_table(Arena* shader_src_arena) -{ - String8 shader_paths[R_D3D11_ShaderPairKind_COUNT] = {0}; - shader_paths[R_D3D11_ShaderPairKind_Rect2D] = - str8_lit("D:\\dev\\app_codebase\\src\\render\\d3d11\\shaders\\rect2d.hlsl"); - - - - String8 shader_name[R_D3D11_ShaderPairKind_COUNT] = {0}; - shader_name[R_D3D11_ShaderPairKind_Rect2D] = str8_lit("r_d3d11_g_rect2d_shader_src"); - - - for(R_D3D11_ShaderPairKind kind = (R_D3D11_ShaderPairKind)(R_D3D11_ShaderPairKind_Nil+1); - kind < R_D3D11_ShaderPairKind_COUNT; - kind = (R_D3D11_ShaderPairKind)(kind+1)) - { - // We're on windows anyway so might as well - OS_Handle file = OS_file_open(OS_AccessFlag_Read, shader_paths[kind]); - OS_FileAttributes attrs = OS_attributes_from_file(file); - String8 shader_src = OS_file_read(shader_src_arena, file, 0, attrs.size); - r_d3d11_g_shader_pair_kind_info_table[kind].name = shader_name[kind]; - r_d3d11_g_shader_pair_kind_info_table[kind].shader_blob = shader_src; - if(kind == R_D3D11_ShaderPairKind_Rect2D) { - r_d3d11_g_shader_pair_kind_info_table[kind].element_description = r_d3d11_g_rect2d_input_layout_elems; - r_d3d11_g_shader_pair_kind_info_table[kind].element_description_count = - ArrayCount(r_d3d11_g_rect2d_input_layout_elems); - } - OS_file_close(file); - } -} - -r_function DXGI_FORMAT -R_D3D11_DXGI_format_from_tex2d_format(R_Tex2DFormat format) -{ - DXGI_FORMAT result = DXGI_FORMAT_R8G8B8A8_UNORM; - switch(format) - { - case R_Tex2DFormat_R8: { result = DXGI_FORMAT_R8_UNORM; } break; - default: - case R_Tex2DFormat_RGBA8: {} break; - } - - return result; -} - -r_function R_D3D11_Tex2D -R_D3D11_tex2d_from_handle(R_Handle handle) -{ - R_D3D11_Tex2D tex = {0}; - tex.texture = (ID3D11Texture2D *)handle.u64[0]; - tex.view = (ID3D11ShaderResourceView *)handle.u64[1]; - tex.size.x = handle.u32[4]; - tex.size.y = handle.u32[5]; - tex.format = (R_Tex2DFormat)handle.u32[6]; - tex.kind = (R_Tex2DKind)handle.u32[7]; - return tex; -} - -r_function R_Handle -R_D3D11_handle_from_tex2d(R_D3D11_Tex2D texture) -{ - R_Handle result = {0}; - result.u64[0] = (U64)texture.texture; - result.u64[1] = (U64)texture.view; - result.u32[4] = texture.size.x; - result.u32[5] = texture.size.y; - result.u32[6] = texture.format; - result.u32[7] = texture.kind; - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////////// -//~ Backend hooks, ie implementations of the render backend abstraction (render_core.h) -// - -// This initialises the D3D11 layer. We have a big struct that holds all the state. -// How this is done in RJFs codebase really looks like the mmozeiko example but with the big -// global struct holding the state. The Hidden Grove (rjf) uses the C++ style though, and -// also the d3d11_1 header which extends d3d11 in some way... But I will reproduce mmozeiko's C example here. -r_function R_InitReceipt -R_init(OS_InitReceipt os_init, OS_InitGfxReceipt os_gfx_init) -{ - - if(is_main_thread() && r_d3d11_state == 0) - { - Arena *arena = m_make_arena_reserve(Gigabytes(16)); - r_d3d11_state = PushArray(arena, R_D3D11_State, 1); - r_d3d11_state->arena = arena; - - HRESULT hr; - - // Create D3D11 device & context - UINT flags = 0; -#if BUILD_DEBUG - flags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - D3D_FEATURE_LEVEL feature_levels[] = { D3D_FEATURE_LEVEL_11_0 }; - hr = D3D11CreateDevice( - 0, // Primary adapter chosen automatically if null - D3D_DRIVER_TYPE_HARDWARE, - 0, // null for non-softweare driver types - flags, - feature_levels, - ArrayCount(feature_levels), - D3D11_SDK_VERSION, - &r_d3d11_state->base_device, - 0, - &r_d3d11_state->base_device_context - ); - AssertHR(hr); - - // Enable useful debug messages and breaks -#if BUILD_DEBUG - // for debug builds enable VERY USEFUL debug break on API errors - { - ID3D11InfoQueue* info; - ID3D11Device_QueryInterface(r_d3d11_state->base_device, &IID_ID3D11InfoQueue, (void**)&info); - ID3D11InfoQueue_SetBreakOnSeverity(info, D3D11_MESSAGE_SEVERITY_CORRUPTION, TRUE); - ID3D11InfoQueue_SetBreakOnSeverity(info, D3D11_MESSAGE_SEVERITY_ERROR, TRUE); - ID3D11InfoQueue_Release(info); - } - - // enable debug break for DXGI too - { - IDXGIInfoQueue* dxgiInfo; - hr = DXGIGetDebugInterface1(0, &IID_IDXGIInfoQueue, (void**)&dxgiInfo); - AssertHR(hr); - IDXGIInfoQueue_SetBreakOnSeverity(dxgiInfo, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION, TRUE); - IDXGIInfoQueue_SetBreakOnSeverity(dxgiInfo, DXGI_DEBUG_ALL, DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR, TRUE); - IDXGIInfoQueue_Release(dxgiInfo); - } - - // NOTE(anton): from mmozeiko's gist: - // "after this there's no need to check for any errors on device functions manually - // so all HRESULT return values in this code will be ignored - // debugger will break on errors anyway" - // TODO(anton): Remove AssertHR and use of hr below to check this. -#endif - - - // Create objects for swapchain-creation (dxgi) - { - hr = ID3D11Device_QueryInterface(r_d3d11_state->base_device, - &IID_IDXGIDevice, (void **)&r_d3d11_state->dxgi_device); - AssertHR(hr); - - hr = IDXGIDevice_GetAdapter(r_d3d11_state->dxgi_device, &r_d3d11_state->dxgi_adapter); - AssertHR(hr); - - hr = IDXGIAdapter_GetParent(r_d3d11_state->dxgi_adapter, &IID_IDXGIFactory2, - (void **)&r_d3d11_state->dxgi_factory2); - AssertHR(hr); - - } - } - - //- Set up initial pipeline state - { - D3D11_RASTERIZER_DESC desc = - { - .FillMode = D3D11_FILL_SOLID, - .CullMode = D3D11_CULL_NONE, - .DepthClipEnable = TRUE, - }; - ID3D11Device_CreateRasterizerState(r_d3d11_state->base_device, &desc, &r_d3d11_state->rasterizer_state); - } - { - { - D3D11_SAMPLER_DESC desc = {0}; - { - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - desc.ComparisonFunc = D3D11_COMPARISON_NEVER; - } - //r_d3d11_state->device->CreateSamplerState(&desc, &r_d3d11_state->nearest_sampler); - ID3D11Device_CreateSamplerState(r_d3d11_state->base_device, &desc, &r_d3d11_state->nearest_sampler); - } - { - D3D11_SAMPLER_DESC desc = {0}; - { - desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; - desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; - desc.ComparisonFunc = D3D11_COMPARISON_NEVER; - } - //r_d3d11_state->device->CreateSamplerState(&desc, &r_d3d11_state->linear_sampler); - ID3D11Device_CreateSamplerState(r_d3d11_state->base_device, &desc, &r_d3d11_state->linear_sampler); - } - } - { - D3D11_BLEND_DESC desc = - { - .RenderTarget[0] = - { - .BlendEnable = TRUE, - .SrcBlend = D3D11_BLEND_SRC_ALPHA, - .DestBlend = D3D11_BLEND_INV_SRC_ALPHA, - .BlendOp = D3D11_BLEND_OP_ADD, - .SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA, - .DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA, - .BlendOpAlpha = D3D11_BLEND_OP_ADD, - .RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL, - }, - }; - ID3D11Device_CreateBlendState(r_d3d11_state->base_device, &desc, &r_d3d11_state->main_blend_state); - } - - { - D3D11_DEPTH_STENCIL_DESC desc = - { - .DepthEnable = FALSE, - .DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL, - .DepthFunc = D3D11_COMPARISON_LESS, - .StencilEnable = FALSE, - .StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK, - .StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK - }; - ID3D11Device_CreateDepthStencilState(r_d3d11_state->base_device, &desc, - &r_d3d11_state->depth_stencil_state); - } - - //- Global command buffer creation - // Loop over the kind enums that are also the indices into the tables - for(R_D3D11_CmdGlobalKind kind = (R_D3D11_CmdGlobalKind)(R_D3D11_CmdGlobalKind_Nil+1); - kind < R_D3D11_CmdGlobalKind_COUNT; - kind = (R_D3D11_CmdGlobalKind)(kind + 1)) - { - D3D11_BUFFER_DESC desc = {0}; - // The ByteWidth of the buffer is the size of the CmdGlobalKind struct as defined in the table. - // Then we align it to 16 bytes by adding 15 and subtracting the size mod 16. - desc.ByteWidth = r_d3d11_g_cmd_global_kind_info_table[kind].size; - desc.ByteWidth += 15; - desc.ByteWidth -= desc.ByteWidth % 16; - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - ID3D11Device_CreateBuffer(r_d3d11_state->base_device, &desc, 0 /* subresource data*/, - &r_d3d11_state->cmd_global_buffer_table[kind]); - } - - // Temporary hold the source code of the shaders so we can compile them - Arena* shader_src_arena = m_make_arena_reserve(Megabytes(8)); - R_D3D11_initialise_shader_table(shader_src_arena); - - //- Create shader objects - for(R_D3D11_ShaderPairKind kind = (R_D3D11_ShaderPairKind)(R_D3D11_ShaderPairKind_Nil+1); - kind < R_D3D11_ShaderPairKind_COUNT; - kind = (R_D3D11_ShaderPairKind)(kind + 1)) - { - R_D3D11_ShaderPairKindInfo *info = &r_d3d11_g_shader_pair_kind_info_table[kind]; - - // Compile vertex shader - ID3DBlob *vs_src_blob = 0; - ID3DBlob *vs_src_errors = 0; - ID3D11VertexShader *vs = 0; - String8 vs_errors = {0}; - - HRESULT hr; - { - hr = D3DCompile(info->shader_blob.str, info->shader_blob.size, (char *)info->name.str, 0, 0, - "vs_main", "vs_5_0", 0 /* flags */, 0, &vs_src_blob, &vs_src_errors); - if(vs_src_errors) - { - vs_errors = str8( (U8 *)ID3D10Blob_GetBufferPointer(vs_src_errors), - (U64)ID3D10Blob_GetBufferSize(vs_src_errors)); - break_debugger(); - } - else - { - ID3D11Device_CreateVertexShader(r_d3d11_state->base_device, ID3D10Blob_GetBufferPointer(vs_src_blob), - ID3D10Blob_GetBufferSize(vs_src_blob), 0, &vs); - } - } - - // Make input layout - ID3D11InputLayout *input_layout = 0; - if(info->element_description != 0) - { - ID3D11Device_CreateInputLayout(r_d3d11_state->base_device, info->element_description, - info->element_description_count, - ID3D10Blob_GetBufferPointer(vs_src_blob), ID3D10Blob_GetBufferSize(vs_src_blob), - &input_layout); - } - - // Compile pixel shader - ID3DBlob *ps_src_blob = 0; - ID3DBlob *ps_src_errors = 0; - ID3D11PixelShader *ps = 0; - String8 ps_errors = {0}; - { - hr = D3DCompile(info->shader_blob.str, info->shader_blob.size, (char *)info->name.str, 0, 0, - "ps_main", "ps_5_0", 0, 0, &ps_src_blob, &ps_src_errors); - if(ps_src_errors) - { - ps_errors = str8( (U8 *)ID3D10Blob_GetBufferPointer(ps_src_errors), - (U64)ID3D10Blob_GetBufferSize(ps_src_errors)); - break_debugger(); - } - else - { - ID3D11Device_CreatePixelShader(r_d3d11_state->base_device, ID3D10Blob_GetBufferPointer(ps_src_blob), - ID3D10Blob_GetBufferSize(ps_src_blob), 0, &ps); - } - } - - // Store in state - r_d3d11_state->input_layout_table[kind] = input_layout; - r_d3d11_state->vs_table[kind] = vs; - r_d3d11_state->ps_table[kind] = ps; - - ID3D10Blob_Release(vs_src_blob); - ID3D10Blob_Release(ps_src_blob); - } - m_arena_release(shader_src_arena); - - //- Scratch buffer resources - // 64k - { - D3D11_BUFFER_DESC desc = {0}; - { - desc.ByteWidth = Kilobytes(64); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - } - ID3D11Device_CreateBuffer(r_d3d11_state->base_device, &desc, 0, &r_d3d11_state->scratch_buffer_64kb); - } - - R_InitReceipt out = {0}; - return out; -} - - -// This creates the swapchain and attaches it to the OS handle. -// Since we want to be able to do this dynamically we will store the necessary creation objects in -// the D3D11 state struct (dxgi device, adapter, factory2). - r_function R_Handle -R_window_equip(OS_Handle window_handle) -{ - // We are just doing regular OS alloc for this, ie no arena. - R_D3D11_WindowEquip *equip = (R_D3D11_WindowEquip *)OS_reserve(sizeof(R_D3D11_WindowEquip)); - OS_commit(equip, sizeof(*equip)); - OS_W32_Window *window = (OS_W32_Window *)window_handle.u64[0]; - HWND hwnd = window->hwnd; - DXGI_SWAP_CHAIN_DESC1 swapchain_desc = - { - // default 0 value for width & height means to get it from HWND automatically - //.Width = 0, - //.Height = 0, - - // or use DXGI_FORMAT_R8G8B8A8_UNORM_SRGB for storing sRGB - .Format = DXGI_FORMAT_R8G8B8A8_UNORM, - - // FLIP presentation model does not allow MSAA framebuffer - // if you want MSAA then you'll need to render offscreen and manually - // resolve to non-MSAA framebuffer - .SampleDesc = { 1, 0 }, - - .BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT, - .BufferCount = 2, - - // we don't want any automatic scaling of window content - // this is supported only on FLIP presentation model - .Scaling = DXGI_SCALING_NONE, - - // use more efficient FLIP presentation model - // Windows 10 allows to use DXGI_SWAP_EFFECT_FLIP_DISCARD - // for Windows 8 compatibility use DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL - // for Windows 7 compatibility use DXGI_SWAP_EFFECT_DISCARD - .SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD, - }; - - HRESULT hr = IDXGIFactory2_CreateSwapChainForHwnd( - r_d3d11_state->dxgi_factory2, - (IUnknown *)r_d3d11_state->base_device, - hwnd, - &swapchain_desc, - 0, 0, - &equip->swapchain - ); - - IDXGISwapChain1_GetBuffer(equip->swapchain, 0, &IID_ID3D11Texture2D, (void **)(&equip->framebuffer)); - ID3D11Device_CreateRenderTargetView(r_d3d11_state->base_device, (ID3D11Resource*)equip->framebuffer, - 0, &equip->framebuffer_rtv); - - - IDXGIFactory_MakeWindowAssociation(r_d3d11_state->dxgi_factory2, hwnd, DXGI_MWA_NO_ALT_ENTER); - - return R_D3D11_handle_from_window_equip(equip); -} - -r_function void -R_window_unequip(OS_Handle window, R_Handle window_equip) -{ - R_D3D11_WindowEquip *equip = R_D3D11_window_equip_from_handle(window_equip); - if(equip->framebuffer_rtv) { ID3D11RenderTargetView_Release(equip->framebuffer_rtv); } - if(equip->framebuffer) { ID3D11Texture2D_Release(equip->framebuffer); } - if(equip->swapchain) { IDXGISwapChain_Release(equip->swapchain); } - OS_release(equip, sizeof(*equip)); -} - -// The render handle is a nice way to abstract way whatever different ways to describe the -// swapchain we have in different graphics APIs... so we just get and set a pointer with these utilities. -r_function R_Handle -R_D3D11_handle_from_window_equip(R_D3D11_WindowEquip *equip) -{ - R_Handle handle = {0}; - handle.u64[0] = (U64)equip; - return handle; -} - -r_function R_D3D11_WindowEquip * -R_D3D11_window_equip_from_handle(R_Handle handle) -{ - R_D3D11_WindowEquip *result = (R_D3D11_WindowEquip *)handle.u64[0]; - return result; -} - -r_function void -R_frame_begin(void) -{ - // NOTE(anton): No-op - // TODO(anton): But why is there no-op here? Comment this -} - - r_function void -R_frame_end(void) -{ - // TODO(anton): Implement and understand OverflowBufferNode stuff -} - - r_function void -R_window_start(R_Handle window_equip_handle, Vec2_S64 resolution) -{ - R_D3D11_WindowEquip *wnd = R_D3D11_window_equip_from_handle(window_equip_handle); - // TODO(anton): Ryan uses Device1 and Context1 here, I need to understand why and know the difference. - ID3D11Device *device = r_d3d11_state->base_device; - ID3D11DeviceContext *d_ctx = r_d3d11_state->base_device_context; - - B32 resolution_changed = (wnd->last_resolution.x != resolution.x || - wnd->last_resolution.y != resolution.y); - wnd->last_resolution = resolution; - - // If the resolution changed we need to remake - // the swap chain and framebuffer. - if(resolution_changed) - { - ID3D11RenderTargetView_Release(wnd->framebuffer_rtv); - ID3D11Texture2D_Release(wnd->framebuffer); - // NOTE(anton): Since we are getting the buffers again I think we can resize it to zero here rather - // than to the resolution as is done in mmozeiko example? - HRESULT hr = IDXGISwapChain1_ResizeBuffers(wnd->swapchain, 0, - /* width*/0, /* height */0, DXGI_FORMAT_UNKNOWN, 0); - if(FAILED(hr)) - { - break_debugger(); - } - - IDXGISwapChain1_GetBuffer(wnd->swapchain, 0, &IID_ID3D11Texture2D, (void**)(&wnd->framebuffer)); - ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource*)wnd->framebuffer, - 0, &wnd->framebuffer_rtv); - - } - - - - - // Clear color - Vec4_F32 clear_color = {0}; - clear_color.x = 0.2f; - clear_color.y = 0.4f; - clear_color.z = 0.6f; - - ID3D11DeviceContext_ClearRenderTargetView(d_ctx, wnd->framebuffer_rtv, clear_color.v); -} - - - r_function void -R_window_submit(R_Handle window_equip, R_PassList *pass_list) -{ - - R_D3D11_WindowEquip *wnd = R_D3D11_window_equip_from_handle(window_equip); - ID3D11DeviceContext *d_ctx = r_d3d11_state->base_device_context; - - R_PassNode *pass_node = pass_list->first; - R_Pass *pass = &pass_node->v; - R_PassParams_UI* params = pass->params_ui; - - //- Draw rectangle batches - for(R_BatchGroup2DNode *group_node = params->rects.first; group_node != 0; group_node = group_node->next) - { - - // Unpack node - R_BatchList *batches = &group_node->batches; - R_BatchGroup2DParams *batch_params = &group_node->params; - ID3D11Buffer *instance_buffer = R_D3D11_instance_buffer_from_batch_list(batches); - U64 instance_count = batches->instance_count; - U64 bytes_per_instance = batches->byte_count/batches->instance_count; - R_Handle albedo_texture_handle = batch_params->albedo_tex; - R_D3D11_Tex2D albedo_texture = R_D3D11_tex2d_from_handle(albedo_texture_handle); - if(R_handle_is_zero(batch_params->albedo_tex)) - { - break_debugger(); - } - ID3D11SamplerState *sampler = r_d3d11_state->linear_sampler; - R_Tex2DSampleKind sample_kind = batch_params->albedo_tex_sample_kind; - switch(sample_kind) - { - default: - case R_Tex2DSampleKind_Nearest: { sampler = r_d3d11_state->nearest_sampler; } break; - case R_Tex2DSampleKind_Linear: { sampler = r_d3d11_state->linear_sampler; } break; - } - - /* - Vec2_F32 clip_min = vec2_F32( - Clamp(0, Min(batch_params->clip.x0, batch_params->clip.x1), wnd->last_resolution.x), - Clamp(0, Min(batch_params->clip.y0, batch_params->clip.y1), wnd->last_resolution.y) - ); - Vec2_F32 clip_max = vec2_F32( - Clamp(0, Max(batch_params->clip.x0, batch_params->clip.x1), wnd->last_resolution.x), - Clamp(0, Max(batch_params->clip.y0, batch_params->clip.y1), wnd->last_resolution.y) - ); - */ - //Rng2_F32 clip = rng2_F32(vec2_F32(0,0), vec2_F32(wnd->last_resolution.x, wnd->last_resolution.y)); - - // Viewport and rasteriser - { - Vec2_S64 resolution = wnd->last_resolution; - D3D11_VIEWPORT d3d11_viewport = { 0.0f, 0.0f, (F32)resolution.x, (F32)resolution.y, 0.0f, 1.0f }; - - if(params->viewport.x0 != 0 || params->viewport.x1 != 0 || - params->viewport.y0 != 0 || params->viewport.y1 != 0) - { - Vec2_F32 dim = dim2_F32(params->viewport); - d3d11_viewport.TopLeftX = params->viewport.x0; - d3d11_viewport.TopLeftY = params->viewport.y0; - d3d11_viewport.Width = dim.x; - d3d11_viewport.Height = dim.y; - } - ID3D11DeviceContext_RSSetViewports(d_ctx, 1, &d3d11_viewport); - ID3D11DeviceContext_RSSetState(d_ctx, r_d3d11_state->rasterizer_state); - } - - // Scissor rect - { - D3D11_RECT rect = - { - /* .left = */ 0, - /* .top = */ 0, - /* .right = */ (LONG)wnd->last_resolution.x, - /* .bottom = */ (LONG)wnd->last_resolution.y, - }; - /* if(clip.x0 != 0 || clip.y0 != 0 || clip.x1 != 0 || clip.y1 != 0) */ - /* { */ - /* rect.left = (LONG)clip.x0; */ - /* rect.right = (LONG)clip.x1; */ - /* rect.top = (LONG)clip.y0; */ - /* rect.bottom = (LONG)clip.y1; */ - /* } */ - ID3D11DeviceContext_RSSetScissorRects(d_ctx, 1, &rect); - } - - // Output merger - { - ID3D11DeviceContext_OMSetRenderTargets(d_ctx, 1, &wnd->framebuffer_rtv, 0); - ID3D11DeviceContext_OMSetBlendState(d_ctx, r_d3d11_state->main_blend_state, 0, 0xffffffff); - ID3D11DeviceContext_OMSetDepthStencilState(d_ctx, r_d3d11_state->depth_stencil_state, 0); - } - - // Get pipeline objects - ID3D11Buffer *cmd_global_buffer = r_d3d11_state->cmd_global_buffer_table[R_D3D11_CmdGlobalKind_Rect2D]; - ID3D11VertexShader *vs = r_d3d11_state->vs_table[R_D3D11_ShaderPairKind_Rect2D]; - ID3D11PixelShader *ps = r_d3d11_state->ps_table[R_D3D11_ShaderPairKind_Rect2D]; - ID3D11InputLayout *input_layout = r_d3d11_state->input_layout_table[R_D3D11_ShaderPairKind_Rect2D]; - - // Send per-cmd globals - R_D3D11_CmdGlobals_Rect2D cmd_globals = {0}; - { - cmd_globals.viewport_size = vec2_F32_from_vec(wnd->last_resolution); - cmd_globals.albedo_t2d_size = vec2_F32_from_vec(albedo_texture.size); - cmd_globals.transform[0] = vec3_F32(batch_params->xform2d.elements[0][0], - batch_params->xform2d.elements[1][0], - batch_params->xform2d.elements[2][0]); - cmd_globals.transform[1] = vec3_F32(batch_params->xform2d.elements[0][1], - batch_params->xform2d.elements[1][1], - batch_params->xform2d.elements[2][1]); - cmd_globals.transform[2] = vec3_F32(batch_params->xform2d.elements[0][2], - batch_params->xform2d.elements[1][2], - batch_params->xform2d.elements[2][2]); - } - - // TODO(anton): Make this into a function - { - D3D11_MAPPED_SUBRESOURCE sub_resource = {0}; - ID3D11DeviceContext_Map(d_ctx, (ID3D11Resource *)cmd_global_buffer, 0, - D3D11_MAP_WRITE_DISCARD, 0, &sub_resource); - String8 data = str8_struct(&cmd_globals); - U8 *ptr = (U8 *)sub_resource.pData; - MemoryCopy(ptr, data.str, data.size); - ID3D11DeviceContext_Unmap(d_ctx, (ID3D11Resource *)cmd_global_buffer, 0); - } - - // Setup input assembly - U32 stride = bytes_per_instance; - U32 offset = 0; - ID3D11DeviceContext_IASetPrimitiveTopology(d_ctx, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - ID3D11DeviceContext_IASetInputLayout(d_ctx, input_layout); - ID3D11DeviceContext_IASetVertexBuffers(d_ctx, 0, 1, &instance_buffer, &stride, &offset); - - // Setup shaders - ID3D11DeviceContext_VSSetShader(d_ctx, vs, 0, 0); - ID3D11DeviceContext_VSSetConstantBuffers(d_ctx, 0, 1, &cmd_global_buffer); - ID3D11DeviceContext_PSSetShader(d_ctx, ps, 0, 0); - ID3D11DeviceContext_PSSetConstantBuffers(d_ctx, 0, 1, &cmd_global_buffer); - ID3D11DeviceContext_PSSetShaderResources(d_ctx, 0, 1, &albedo_texture.view); - ID3D11DeviceContext_PSSetSamplers(d_ctx, 0, 1, &sampler); - - // Draw - ID3D11DeviceContext_DrawInstanced(d_ctx, /* 4 vertices for a rect */4, instance_count, 0, 0); - } - -} - - - - r_function void -R_window_finish(R_Handle window_eqp) -{ - R_D3D11_WindowEquip *wnd = R_D3D11_window_equip_from_handle(window_eqp); - HRESULT hr = IDXGISwapChain1_Present(wnd->swapchain, 1, 0); - if(FAILED(hr)) - { - break_debugger(); - } - - ID3D11DeviceContext_ClearState(r_d3d11_state->base_device_context); -} - - -r_function R_Handle -R_tex2d_font_atlas(Vec2_S64 size, U8 *data) -{ - D3D11_USAGE usage = data ? D3D11_USAGE_IMMUTABLE : D3D11_USAGE_DEFAULT; - UINT access_flags = 0; - // TODO(anton): Make switch on Tex2DKind here when we generalise - access_flags = 0; - - R_Tex2DFormat fmt = R_Tex2DFormat_R8; - - D3D11_TEXTURE2D_DESC tex_desc = {0}; - { - tex_desc.Width = size.x; - tex_desc.Height = size.y; - tex_desc.MipLevels = 1; - tex_desc.ArraySize = 1; - tex_desc.Format = R_D3D11_DXGI_format_from_tex2d_format(fmt); - tex_desc.SampleDesc.Count = 1; - tex_desc.SampleDesc.Quality = 0; - tex_desc.Usage = usage; - tex_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - tex_desc.CPUAccessFlags = access_flags; - } - - D3D11_SUBRESOURCE_DATA initial_data = {0}; - { - initial_data.pSysMem = data; - initial_data.SysMemPitch = R_bytes_per_pixel_from_tex2d_format(fmt) * size.x; - initial_data.SysMemSlicePitch = 0; - } - - R_D3D11_Tex2D texture = {0}; - ID3D11Device_CreateTexture2D(r_d3d11_state->base_device, &tex_desc, &initial_data, &texture.texture); - ID3D11Device_CreateShaderResourceView(r_d3d11_state->base_device, (ID3D11Resource *)texture.texture, 0, &texture.view); - - texture.size = vec2_S32_from_vec(size); - texture.format = fmt; - return R_D3D11_handle_from_tex2d(texture); -} - - -// TODO I kind of dont want this release code but I also dont want the debug output when closing app. -#define __ID3D11_Release(t, n) if(r_d3d11_state->##n) { t##_Release(r_d3d11_state->##n); } -// This is mostly to avoid annoying error message from d3d11 debug layer? -r_function void -R_shutdown() -{ - R_D3D11_Tex2D atlas_texture = R_D3D11_tex2d_from_handle(F_get_state()->atlas.texture); - if(atlas_texture.texture) { ID3D11Texture2D_Release(atlas_texture.texture); } - if(atlas_texture.view) { ID3D11ShaderResourceView_Release(atlas_texture.view); } - - for(R_D3D11_ShaderPairKind kind = (R_D3D11_ShaderPairKind)(R_D3D11_ShaderPairKind_Nil+1); - kind < R_D3D11_ShaderPairKind_COUNT; - kind = (R_D3D11_ShaderPairKind)(kind + 1)) - { - __ID3D11_Release(ID3D11InputLayout, input_layout_table[kind]); - __ID3D11_Release(ID3D11VertexShader, vs_table[kind]); - __ID3D11_Release(ID3D11PixelShader, ps_table[kind]); - } - - for(R_D3D11_CmdGlobalKind kind = (R_D3D11_CmdGlobalKind)(R_D3D11_CmdGlobalKind_Nil+1); - kind < R_D3D11_CmdGlobalKind_COUNT; - kind = (R_D3D11_CmdGlobalKind)(kind + 1)) - { - __ID3D11_Release(ID3D11Buffer, cmd_global_buffer_table[kind]); - } - - __ID3D11_Release(ID3D11Buffer, scratch_buffer_64kb); - __ID3D11_Release(ID3D11Buffer, scratch_buffer_8mb); - __ID3D11_Release(ID3D11SamplerState, nearest_sampler);//ID3D11SamplerState_Release(r_d3d11_state->nearest_sampler); - __ID3D11_Release(ID3D11SamplerState, linear_sampler);//ID3D11SamplerState_Release(r_d3d11_state->linear_sampler); - __ID3D11_Release(ID3D11DepthStencilState, depth_stencil_state); - __ID3D11_Release(ID3D11BlendState, main_blend_state); - __ID3D11_Release(ID3D11RasterizerState, rasterizer_state);//ID3D11RasterizerState_Release(r_d3d11_state->rasterizer_state); - __ID3D11_Release(IDXGIFactory2, dxgi_factory2); - __ID3D11_Release(IDXGIAdapter, dxgi_adapter); - __ID3D11_Release(IDXGIDevice, dxgi_device); - __ID3D11_Release(ID3D11Device, base_device); - __ID3D11_Release(ID3D11DeviceContext, base_device_context); -} diff --git a/src/render/d3d11/render_d3d11.h b/src/render/d3d11/render_d3d11.h deleted file mode 100644 index 5d908af..0000000 --- a/src/render/d3d11/render_d3d11.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef RENDER_D3D11_H -#define RENDER_D3D11_H - -#define COBJMACROS -#include -#include -#include -#include - -#pragma comment(lib, "user32") -#pragma comment(lib, "dxguid") -#pragma comment(lib, "dxgi") -#pragma comment(lib, "d3d11") -#pragma comment(lib, "d3dcompiler") - -///////////////////////////////// -//~ Metadata types. Ryan uses metadesk to generate tables, but I hardcode it for now. -// TODO(anton): Use metaprogramming to generate what is necessary here. - -typedef struct R_D3D11_CmdGlobalKindInfo R_D3D11_CmdGlobalKindInfo; -struct R_D3D11_CmdGlobalKindInfo -{ - U64 size; -}; - -typedef enum R_D3D11_CmdGlobalKind -{ - R_D3D11_CmdGlobalKind_Nil, - R_D3D11_CmdGlobalKind_Rect2D, - R_D3D11_CmdGlobalKind_Grid, - R_D3D11_CmdGlobalKind_COUNT -} -R_D3D11_CmdGlobalKind; - -typedef struct R_D3D11_ShaderPairKindInfo R_D3D11_ShaderPairKindInfo; -struct R_D3D11_ShaderPairKindInfo -{ - String8 name; - String8 shader_blob; //String8 shader_blob; - D3D11_INPUT_ELEMENT_DESC *element_description; - U64 element_description_count; -}; - -typedef enum R_D3D11_ShaderPairKind -{ - R_D3D11_ShaderPairKind_Nil, - R_D3D11_ShaderPairKind_Rect2D, - R_D3D11_ShaderPairKind_Grid, - R_D3D11_ShaderPairKind_COUNT -} -R_D3D11_ShaderPairKind; - - -///////////////////////////////// -//~ Pipeline data types -typedef struct R_D3D11_CmdGlobals_Rect2D R_D3D11_CmdGlobals_Rect2D; -struct R_D3D11_CmdGlobals_Rect2D -{ - Vec2_F32 viewport_size; - Vec2_F32 albedo_t2d_size; - Vec3_F32 transform[3]; - Vec2_F32 _16byte_padding0_; -}; - - - -///////////////////////////////// -//~ Resource types - -typedef struct R_D3D11_Tex2D R_D3D11_Tex2D; -struct R_D3D11_Tex2D -{ - ID3D11Texture2D *texture; - ID3D11ShaderResourceView *view; - Vec2_S32 size; - R_Tex2DFormat format; - R_Tex2DKind kind; -}; - -typedef struct R_D3D11_Buffer R_D3D11_Buffer; -struct R_D3D11_Buffer -{ - ID3D11Buffer *obj; - U64 size; -}; - -///////////////////////////////// -//~ Main state bundle -typedef struct R_D3D11_State R_D3D11_State; -struct R_D3D11_State -{ - Arena *arena; - - //- Base d3d11 objects - ID3D11Device *base_device; - ID3D11DeviceContext *base_device_context; - IDXGIDevice *dxgi_device; - IDXGIAdapter *dxgi_adapter; - IDXGIFactory2 *dxgi_factory2; - ID3D11RasterizerState *rasterizer_state; - ID3D11BlendState *main_blend_state; - ID3D11DepthStencilState *depth_stencil_state; - ID3D11SamplerState *nearest_sampler; - ID3D11SamplerState *linear_sampler; - - //- Global buffers - // NOTE(anton): We have an extra space for the nil buffer, which is how it will work with nil structs etc. - // That's "wasting" a bit of space, but with huge benefits in terms of codepaths and error handling. - // Nil is a valid state that does nothing. - ID3D11Buffer *cmd_global_buffer_table[R_D3D11_CmdGlobalKind_COUNT]; - - //- Shader tables - ID3D11InputLayout *input_layout_table[R_D3D11_ShaderPairKind_COUNT]; - ID3D11VertexShader *vs_table[R_D3D11_ShaderPairKind_COUNT]; - ID3D11PixelShader *ps_table[R_D3D11_ShaderPairKind_COUNT]; - - // Scratch buffers - ID3D11Buffer *scratch_buffer_64kb; - ID3D11Buffer *scratch_buffer_8mb; -}; - -typedef struct R_D3D11_WindowEquip R_D3D11_WindowEquip; -struct R_D3D11_WindowEquip -{ - IDXGISwapChain1 *swapchain; - ID3D11Texture2D *framebuffer; - ID3D11RenderTargetView *framebuffer_rtv; - - Vec2_S64 last_resolution; -}; - -///////////////////////////////// -//~ D3D11 Functions -r_function R_Handle R_D3D11_handle_from_window_equip(R_D3D11_WindowEquip *equip); -r_function R_D3D11_WindowEquip *R_D3D11_window_equip_from_handle(R_Handle handle); -r_function R_Handle R_D3D11_handle_from_tex2d(R_D3D11_Tex2D texture); -#endif /* RENDER_D3D11_H */ diff --git a/src/render/d3d11/shaders/rect2d.hlsl b/src/render/d3d11/shaders/rect2d.hlsl deleted file mode 100644 index 5db1ccd..0000000 --- a/src/render/d3d11/shaders/rect2d.hlsl +++ /dev/null @@ -1,173 +0,0 @@ -cbuffer CmdGlobals : register(b0) -{ - float2 viewport_size_px; - float2 albedo_t2d_size_px; - row_major float3x3 transform; -} - -Texture2D albedo_t2d : register(t0); -SamplerState albedo_t2d_sampler : register(s0); - -struct CPU2Vertex -{ - float4 dst_rect_px : POS; // Here we have two sets of 2D points, first is the top left corner of the rectnagle, and second is the bottom right corner. - float4 src_rect_px : TEX; - float4 color00 : COL0; - float4 color01 : COL1; - float4 color10 : COL2; - float4 color11 : COL3; - float4 corner_radii_px : CRAD; - float4 style_params : STY; // border_thickness_px, softness_px, omit_texture, unused - uint vertex_id : SV_VertexID; -}; - -struct Vertex2Pixel -{ - float4 position : SV_POSITION; - float2 rect_half_size_px : PSIZE; - float2 texcoord_pct : TEX; - float2 cornercoord_pct : CORC; - float4 color00 : COL0; - float4 color01 : COL1; - float4 color10 : COL2; - float4 color11 : COL3; - float corner_radius_px : CRAD; - float border_thickness_px : BTHC; - float softness_px : SFT; - float omit_texture : OTX; -}; - -//- Helpers - -float rect_SDF(float2 sample_pos, float2 rect_half_size, float radius) -{ - return length(max(abs(sample_pos) - rect_half_size + radius, 0.0)) - radius; -} - -//~ Vertex shader -Vertex2Pixel -vs_main(CPU2Vertex cpu2vertex) -{ - // Here we statically define the vertex as a rectangle over the entire NDC space [-1, 1] for x and y, I think? - // From debugging in RenderDoc I can confirm that -1,-1 is top left corner, and 1,1 bottom right corner. - // Then we can use the input data to scale these points to get proper screen space vertex coordinates for what we want to render. - static float2 vertices[] = - { - {-1, -1}, - {-1, +1}, - {+1, -1}, - {+1, +1}, - }; - - // Unpack input - float2 dst_p0_px = cpu2vertex.dst_rect_px.xy; // top left corner - float2 dst_p1_px = cpu2vertex.dst_rect_px.zw; // bottom right corner - float2 src_p0_px = cpu2vertex.src_rect_px.xy; - float2 src_p1_px = cpu2vertex.src_rect_px.zw; - float2 dst_size_px = abs(dst_p1_px - dst_p0_px); - - // unpack style - float border_thickness_px = cpu2vertex.style_params.x; - float softness_px = cpu2vertex.style_params.y; - float omit_texture = cpu2vertex.style_params.z; - - // Transform input points to screen destination coordinates - float2 dst_half_size = (dst_p1_px - dst_p0_px) / 2; - float2 dst_center = (dst_p1_px + dst_p0_px) / 2; - // transform the vertex according to the input points - float2 dst_pos = (vertices[cpu2vertex.vertex_id] * dst_half_size + dst_center); - - // Swap y-coordinate to have -1,-1 in top left - dst_pos.y = viewport_size_px.y - dst_pos.y; - - float2 src_pos[] = - { - float2(src_p0_px.x/albedo_t2d_size_px.x, src_p0_px.y/albedo_t2d_size_px.y), - float2(src_p0_px.x/albedo_t2d_size_px.x, src_p1_px.y/albedo_t2d_size_px.y), - float2(src_p1_px.x/albedo_t2d_size_px.x, src_p0_px.y/albedo_t2d_size_px.y), - float2(src_p1_px.x/albedo_t2d_size_px.x, src_p1_px.y/albedo_t2d_size_px.y), - }; - - float2 dst_c_verts_pct[] = - { - float2(0, 0), - float2(0, 1), - float2(1, 0), - float2(1, 1), - }; - - float dst_r_verts_px[] = - { - cpu2vertex.corner_radii_px.x, - cpu2vertex.corner_radii_px.y, - cpu2vertex.corner_radii_px.z, - cpu2vertex.corner_radii_px.w, - }; - - // Package output - Vertex2Pixel vertex2pixel; - { - vertex2pixel.position.x = 2 * dst_pos.x / viewport_size_px.x - 1.f; - vertex2pixel.position.y = 2 * dst_pos.y / viewport_size_px.y - 1.f; - vertex2pixel.position.z = 0.f; - vertex2pixel.position.w = 1.f; - vertex2pixel.rect_half_size_px = dst_size_px/2.0f; - vertex2pixel.texcoord_pct.x = src_pos[cpu2vertex.vertex_id].x; - vertex2pixel.texcoord_pct.y = src_pos[cpu2vertex.vertex_id].y; - vertex2pixel.cornercoord_pct = dst_c_verts_pct[cpu2vertex.vertex_id]; - vertex2pixel.color00 = cpu2vertex.color00; - vertex2pixel.color01 = cpu2vertex.color01; - vertex2pixel.color10 = cpu2vertex.color10; - vertex2pixel.color11 = cpu2vertex.color11; - vertex2pixel.corner_radius_px = dst_r_verts_px[cpu2vertex.vertex_id]; - vertex2pixel.border_thickness_px = border_thickness_px; - vertex2pixel.softness_px = softness_px; - vertex2pixel.omit_texture = omit_texture; - } - return vertex2pixel; -} - -//~ Pixel shader -float4 -ps_main(Vertex2Pixel vertex2pixel) : SV_TARGET -{ - float4 top_color = (1 - vertex2pixel.cornercoord_pct.x)*vertex2pixel.color00 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color10; - float4 bot_color = (1 - vertex2pixel.cornercoord_pct.x)*vertex2pixel.color01 + (vertex2pixel.cornercoord_pct.x)*vertex2pixel.color11; - float4 tint = (1 - vertex2pixel.cornercoord_pct.y)*top_color + (vertex2pixel.cornercoord_pct.y)*bot_color; - - float4 albedo_sample = float4(1, 1, 1, 1); - albedo_sample = albedo_t2d.Sample(albedo_t2d_sampler, vertex2pixel.texcoord_pct) * albedo_sample; - - - // Corners - float2 sdf_sample_pos = float2( - (2*vertex2pixel.cornercoord_pct.x - 1)*vertex2pixel.rect_half_size_px.x, - (2*vertex2pixel.cornercoord_pct.y - 1)*vertex2pixel.rect_half_size_px.y - ); - - float2 half_size = vertex2pixel.rect_half_size_px - float2(vertex2pixel.softness_px*2.f, vertex2pixel.softness_px*2.f); - float corner_sdf_s = rect_SDF(sdf_sample_pos, half_size, vertex2pixel.corner_radius_px); - float corner_sdf_t = 1-smoothstep(0, 2*vertex2pixel.softness_px, corner_sdf_s); - - // Borders - float border_radius = max(vertex2pixel.corner_radius_px-vertex2pixel.border_thickness_px, 0); - float border_sdf_s = rect_SDF(sdf_sample_pos, half_size - vertex2pixel.border_thickness_px, border_radius); - float border_sdf_t = smoothstep(0, 2*vertex2pixel.softness_px, border_sdf_s); - - if(vertex2pixel.border_thickness_px == 0) - { - border_sdf_t = 1; - } - - float4 final_color = float4(1, 1, 1, 1); - final_color *= tint; - final_color *= corner_sdf_t; - final_color *= border_sdf_t; - if(vertex2pixel.omit_texture < 1) - { - final_color = float4(1, 1, 1, albedo_sample.r); - } - //float4 final_color = vertex2pixel.color; - return final_color; -} - diff --git a/src/render/render_core.h b/src/render/render_core.h deleted file mode 100644 index 6c308fa..0000000 --- a/src/render/render_core.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef RENDER_CORE_H -#define RENDER_CORE_H - -// NOTE(anton): -// The Render layer is an abstraction over whatever rendering backend is chosen. -// Right now I will only support D3D11. - -////////////////////////////////////////// -//~ Backend asbtraction -// -r_function R_InitReceipt R_init(OS_InitReceipt os_init, OS_InitGfxReceipt os_gfx_init); -r_function R_Handle R_window_equip(OS_Handle window); -r_function void R_window_unequip(OS_Handle window, R_Handle window_equip); -r_function void R_shutdown(); -r_function void R_frame_begin(void); -r_function void R_frame_end(void); -r_function void R_window_start(R_Handle window_equip, Vec2_S64 resolution); -r_function void R_window_submit(R_Handle window_equip, R_PassList *pass_list); -r_function void R_window_finish(R_Handle window_equip); -r_function R_Handle R_tex2d_font_atlas(Vec2_S64 size, U8 *data); - -#endif /* RENDER_CORE_H */ diff --git a/src/render/render_inc.c b/src/render/render_inc.c deleted file mode 100644 index 29d9da6..0000000 --- a/src/render/render_inc.c +++ /dev/null @@ -1,11 +0,0 @@ -// Main includes -// - -#include "render_types.c" -//#include "render_core.c" // render_core is really whatever backend we have, ie the actual implementations. -// So render_d3d11.c should implement R_init, R_window_equip etc - -/////// -/// Direct include D3D11 ?? -/// -#include "d3d11/render_d3d11.c" diff --git a/src/render/render_inc.h b/src/render/render_inc.h deleted file mode 100644 index 122a612..0000000 --- a/src/render/render_inc.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef RENDER_INC_H -#define RENDER_INC_H - -// Backend constants -#define R_BACKEND_D3D11 1 - -// Pick backend -// -#if !defined(R_BACKEND) -# if OS_WINDOWS -# define R_BACKEND R_BACKEND_D3D11 -# else -# error No rendering backend defined for this operating system. -# endif -#endif - -//////////////// - -#include "render_types.h" -#include "render_core.h" - - -// NOTE(anton): Ryan is doing some thing where he is only directly including d3d11 -// if he is doing a C++ build. I think I always want to directly include? -// But why is he doing like this? Because of templating? -// Apparently there is no official C headers for DirectWrite? -#include "d3d11/render_d3d11.h" - -#endif /* RENDER_INC_H */ diff --git a/src/render/render_types.c b/src/render/render_types.c deleted file mode 100644 index 182705a..0000000 --- a/src/render/render_types.c +++ /dev/null @@ -1,92 +0,0 @@ -root_function R_Handle -R_handle_zero(void) -{ - R_Handle out = {0}; - return out; -} - -root_function B32 -R_handle_match(R_Handle a, R_Handle b) -{ - return (a.u64[0] == b.u64[0] && - a.u64[1] == b.u64[1] && - a.u64[2] == b.u64[2] && - a.u64[3] == b.u64[3]); -} - -root_function B32 -R_handle_is_zero(R_Handle handle) -{ - return R_handle_match(handle, R_handle_zero()); -} - -root_function U64 -R_bytes_per_pixel_from_tex2d_format(R_Tex2DFormat fmt) -{ - U64 result = 0; - switch(fmt) - { - default: - case R_Tex2DFormat_R8: {result = 1;} break; - case R_Tex2DFormat_RGBA8: {result = 4;} break; - } - return result; -} - -root_function R_Pass * -R_pass_list_push(Arena *arena, R_PassList *list, R_PassKind kind) -{ - R_PassNode *node = PushArrayZero(arena, R_PassNode, 1); - QueuePush(list->first, list->last, node); - list->count += 1; - R_Pass *pass = &node->v; - pass->kind = kind; - switch(kind) - { - default:{} break; - case R_PassKind_UI: { pass->params_ui = PushArrayZero(arena, R_PassParams_UI, 1); } break; - } - - return pass; -} - -root_function void * -R_batch_list_push(Arena *arena, R_BatchList *list, U64 cap, U64 instance_size) -{ - void *result = 0; - // TODO(anton): - // A batch is a collection of instances. We should make something - // that checks so we can grow batches if possible, or makes a new batch if - // the current batch is full. - // Right now we just have a single batch and we should fit cap number of instances in it. - R_Batch *batch = list->last; - if(batch == 0) - { - batch = PushArrayZero(arena, R_Batch, 1); - // v is just the collection of bytes for this batch. - batch->v = PushArray(arena, U8, instance_size*cap); - batch->instance_cap = cap; - batch->byte_cap = instance_size*cap; - QueuePush(list->first, list->last, batch); - list->batch_count += 1; - } - - // Catch full batch - if(batch->instance_count >= cap) - { - break_debugger(); - } - - // Grab pointer to the memory that holds the new instance. - // This is indexed by the current instance count (previous count) - // and the size in bytes of the instance type. - U64 instance_count = batch->instance_count; - result = &batch->v[instance_count*instance_size]; - // Increment count afterwards - batch->instance_count += 1; - batch->byte_count += instance_size; - list->instance_count += 1; - list->byte_count += instance_size; - - return result; -} \ No newline at end of file diff --git a/src/render/render_types.h b/src/render/render_types.h deleted file mode 100644 index 25b7e57..0000000 --- a/src/render/render_types.h +++ /dev/null @@ -1,211 +0,0 @@ -#ifndef RENDER_TYPES_H -#define RENDER_TYPES_H - - -////////////////////////////// -//~ -#if LANG_C -# define r_global extern -#else -# define r_global no_name_mangle -#endif -#define r_function no_name_mangle - -////////////////////////////// -//~ Basic types - -typedef struct R_InitReceipt R_InitReceipt; -struct R_InitReceipt -{ - U64 u64[1]; -}; - -////////////////////////////// -//~ Handle types - -typedef union R_Handle R_Handle; -union R_Handle -{ - U64 u64[4]; - U32 u32[8]; -}; - -////////////////////////////// -//~ Blending types -typedef enum R_BlendMode -{ - R_BlendMode_Normal, - R_BlendMode_Additive, - R_BlendMode_COUNT -} -R_BlendMode; - - -////////////////////////////// -//~ Texture types -typedef enum R_Tex2DFormat -{ - R_Tex2DFormat_Null, - R_Tex2DFormat_R8, - R_Tex2DFormat_RGBA8, - R_Tex2DFormat_COUNT -} -R_Tex2DFormat; - -typedef enum R_Tex2DSampleKind -{ - R_Tex2DSampleKind_Nearest, - R_Tex2DSampleKind_Linear, - R_Tex2DSampleKind_COUNT -} -R_Tex2DSampleKind; - -typedef enum R_Tex2DKind -{ - R_Tex2DKind_Static, - R_Tex2DKind_Dynamic, -} -R_Tex2DKind; - -typedef struct R_Slice2F32 R_Slice2F32; -struct R_Slice2F32 -{ - R_Handle texture; - Rng2_F32 region; -}; - - -////////////////////////////// -//~ Instance types -// These are the structures that pass information about render primitives down to the -// render backend. -typedef struct R_Rect2DInst R_Rect2DInst; -struct R_Rect2DInst -{ - Rng2_F32 dst_rect; - Rng2_F32 src_rect; - Vec4_F32 colors[Corner_COUNT]; - F32 corner_radii[Corner_COUNT]; - F32 border_thickness; - F32 softness; - F32 omit_texture; - F32 _unused_[1]; -}; - - -////////////////////////////// -//~ Batch type -typedef struct R_Batch R_Batch; -struct R_Batch -{ - R_Batch *next; - U8 *v; - U64 byte_count; - U64 byte_cap; - U64 instance_count; - U64 instance_cap; -}; - -typedef struct R_BatchList R_BatchList; -struct R_BatchList -{ - R_Batch *first; - R_Batch *last; - U64 batch_count; - U64 instance_count; - U64 byte_count; -}; - -typedef struct R_BatchGroup2DParams R_BatchGroup2DParams; -struct R_BatchGroup2DParams -{ - R_Handle albedo_tex; // Color texture to go with this batch of 2D renders - R_Tex2DSampleKind albedo_tex_sample_kind; - Mat3x3_F32 xform2d; - Rng2_F32 clip; -}; - -typedef struct R_BatchGroup2DNode R_BatchGroup2DNode; -struct R_BatchGroup2DNode -{ - R_BatchGroup2DNode *next; - R_BatchList batches; - R_BatchGroup2DParams params; -}; - -typedef struct R_BatchGroup2DList R_BatchGroup2DList; -struct R_BatchGroup2DList -{ - R_BatchGroup2DNode *first; - R_BatchGroup2DNode *last; - U64 count; -}; - - - - -////////////////////////////// -//~ Pass types -typedef enum R_PassKind -{ - R_PassKind_Null, - R_PassKind_UI, - R_PassKind_COUNT -} -R_PassKind; - -typedef struct R_PassParams_UI R_PassParams_UI; -struct R_PassParams_UI -{ - Rng2_F32 viewport; - R_BatchGroup2DList rects; -}; - -typedef struct R_Pass R_Pass; -struct R_Pass -{ - R_PassKind kind; - union - { - void *params; - R_PassParams_UI *params_ui; - }; -}; - -typedef struct R_PassNode R_PassNode; -struct R_PassNode -{ - R_PassNode *next; - R_Pass v; -}; - -typedef struct R_PassList R_PassList; -struct R_PassList -{ - R_PassNode *first; - R_PassNode *last; - U64 count; -}; - - -////////////////////////////// -//~ Handle type functions - -root_function R_Handle R_handle_zero(void); -root_function B32 R_handle_match(R_Handle a, R_Handle b); -root_function B32 R_handle_is_zero(R_Handle handle); - -////////////////////////////// -//~ Texture type functions -root_function U64 R_bytes_per_pixel_from_tex2d_format(R_Tex2DFormat fmt); -////////////////////////////// -//~ Pass building helper functions -root_function R_Pass *R_pass_list_push(Arena *arena, R_PassList *list, R_PassKind kind); -root_function void *R_batch_list_push(Arena *arena, R_BatchList *list, U64 cap, U64 instance_size); -#define R_batch_list_push_struct(arena, list, cap, type) (type *)R_batch_list_push((arena), (list), (cap), sizeof(type)) - -////////////////////////////// -//~ Other?? - - -#endif /* RENDER_TYPES_H */ diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c deleted file mode 100644 index 6024cc3..0000000 --- a/src/ui/ui_basic_widgets.c +++ /dev/null @@ -1,90 +0,0 @@ - -// We create a box with no flags of size size, and push it to -// the hierarchy. -root_function void -UI_spacer(UI_Size size) -{ - UI_Box *parent = UI_top_parent(); - Axis2 parent_axis = parent->child_layout_axis; - UI_set_next_pref_size(parent_axis, size); - UI_set_next_pref_size(Axis2_flip(parent_axis), UI_pixels(0, 0)); - UI_Box *box = UI_box_make(0, str8_lit("")); - unused_variable(box); -} - -root_function UI_Signal -UI_button(String8 string) -{ - UI_Box *box = UI_box_make(UI_BoxFlag_DrawBorder | - UI_BoxFlag_DrawBackground | - UI_BoxFlag_DrawText | - UI_BoxFlag_DrawHotEffects | - UI_BoxFlag_DrawActiveEffects | - //UI_BoxFlag_DrawDropShadow | - UI_BoxFlag_Clickable, - string); - UI_Signal result = UI_signal_from_box(box); - return result; -} - -root_function void -UI_named_column_begin(String8 name) -{ - UI_set_next_child_layout_axis(Axis2_Y); - UI_Box *box = UI_box_make(0, name); - UI_push_parent(box); -} - -root_function void -UI_column_begin(void) -{ - UI_named_column_begin(str8_lit("")); -} - -root_function void -UI_column_end(void) -{ - UI_pop_parent(); -} - -root_function void -UI_named_row_begin(String8 name) -{ - UI_set_next_child_layout_axis(Axis2_X); - UI_Box *box = UI_box_make(0, name); - UI_push_parent(box); -} - -root_function void -UI_row_begin(void) -{ - UI_named_row_begin(str8_lit("")); -} - -root_function void -UI_row_end(void) -{ - UI_pop_parent(); -} - - -root_function UI_Box * -UI_pane_begin(Rng2_F32 rect, String8 string) -{ - UI_push_rect(rect); - UI_set_next_child_layout_axis(Axis2_Y); - - UI_Box *box = UI_box_make(UI_BoxFlag_Clickable|UI_BoxFlag_Clip|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, - string); - UI_pop_rect(); - UI_push_parent(box); - UI_push_pref_width(UI_pct(1, 0)); - return box; -} - -root_function void -UI_pane_end(void) -{ - UI_pop_pref_width(); - UI_pop_parent(); -} \ No newline at end of file diff --git a/src/ui/ui_basic_widgets.h b/src/ui/ui_basic_widgets.h deleted file mode 100644 index f928332..0000000 --- a/src/ui/ui_basic_widgets.h +++ /dev/null @@ -1,20 +0,0 @@ -/* date = April 2nd 2024 2:13 pm */ - -#ifndef UI_BASIC_WIDGETS_H -#define UI_BASIC_WIDGETS_H - - -root_function void UI_spacer(UI_Size size); -root_function UI_Signal UI_button(String8 string); -root_function void UI_named_column_begin(String8 name); -root_function void UI_column_begin(void); -root_function void UI_column_end(void); -root_function void UI_named_row_begin(String8 name); -root_function void UI_row_begin(void); -root_function void UI_row_end(); - -#define UI_padding(size) DeferLoop(UI_spacer(size), UI_spacer(size)) -#define UI_column DeferLoop(UI_column_begin(), UI_column_end()) -#define UI_row DeferLoop(UI_row_begin(), UI_row_end()) - -#endif //UI_BASIC_WIDGETS_H diff --git a/src/ui/ui_colors.h b/src/ui/ui_colors.h deleted file mode 100644 index 7e19073..0000000 --- a/src/ui/ui_colors.h +++ /dev/null @@ -1,8 +0,0 @@ -/* date = April 10th 2024 8:19 pm */ - -#ifndef UI_COLORS_H -#define UI_COLORS_H - - - -#endif //UI_COLORS_H diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c deleted file mode 100644 index 085eb3f..0000000 --- a/src/ui/ui_core.c +++ /dev/null @@ -1,975 +0,0 @@ - -per_thread UI_State* ui_state; - -global F32 ui_g_dt; - -//////////////////////////////// -//~ "Generated"/meta functions -#include "ui_meta.c" - -//////////////////////////////// -//~ Basic type functions - -//- Boxes -root_function B32 -UI_box_is_nil(UI_Box *box) -{ - return box == 0 || box == &ui_g_nil_box; -} - -root_function UI_BoxRec -UI_box_recurse_depth_first(UI_Box *box, UI_Box *stopper, MemberOffset sib, MemberOffset child) -{ - UI_BoxRec rec = {0}; - rec.next = &ui_g_nil_box; - // We check what we get from the child offset. - // If it is not nil we set the next pointer to that box. - if(!UI_box_is_nil(MemberFromOff(box, UI_Box *, child))) - { - rec.next = MemberFromOff(box, UI_Box *, child); - rec.push_count = 1; - } - else - { - // If the child is nil, we loop over all boxes going up the parent chain, - // until we hit stopper. - // As soon as we hit a sibling that is non-nil, we put that in next and return. - for(UI_Box *b = box; !UI_box_is_nil(b) && b != stopper; b = b->parent) - { - if(!UI_box_is_nil(MemberFromOff(b, UI_Box *, sib))) - { - rec.next = MemberFromOff(b, UI_Box *, sib); - break; - } - rec.pop_count += 1; - } - } - - return rec; -} - -//- sizes -root_function UI_Size -UI_size_make(UI_SizeKind kind, F32 value, F32 strictness) -{ - UI_Size result = {0}; - result.kind = kind; - result.value = value; - result.strictness = strictness; - return result; -} - - - -//- ID strings -root_function String8 -UI_hash_part_from_box_string(String8 string) -{ - // TODO(anton): Implement ryans stuff here with substrings - return string; -} - -//- Keys -root_function UI_Key -UI_key_zero(void) -{ - UI_Key key = {0}; - return key; -} - -root_function UI_Key -UI_key_from_string(UI_Key seed, String8 string) -{ - UI_Key key = {0}; - if(string.size > 0) - { - MemoryCopyStruct(&key, &seed); - for(U64 i = 0; i < string.size; i += 1) - { - key.u64[0] = ((key.u64[0] << 5) + key.u64[0]) + string.str[i]; - } - } - return key; -} - -root_function B32 -UI_key_match(UI_Key a, UI_Key b) -{ - return a.u64[0] == b.u64[0]; -} - - -root_function UI_Signal UI_signal_from_box(UI_Box *box) -{ - UI_Signal sig = {box}; - // TODO(anton): possibly clipped box rect - Rng2_F32 rect = box->rect; - - - B32 ctx_menu_is_ancestor = 0; - { - for(UI_Box *parent = box; !UI_box_is_nil(parent); parent = parent->parent) - { - if(parent == ui_state->ctx_menu_root) - { - ctx_menu_is_ancestor = 1; - break; - } - } - } - - for(OS_Event *event = ui_state->events->first, *next = 0; event !=0; event = next) - { - B32 taken = 0; // flag for consume - next = event->next; - - //- unpack event - Vec2_F32 event_mouse = event->position; - B32 event_mouse_in_bounds = rng2_contains_vec2_F32(rect, event_mouse); - UI_MouseButtonKind event_mouse_button_kind = (event->key == OS_Key_MouseLeft ? UI_MouseButtonKind_Left : - event->key == OS_Key_MouseRight ? UI_MouseButtonKind_Right : - event->key == OS_Key_MouseMiddle ? UI_MouseButtonKind_Middle : - UI_MouseButtonKind_Left); - B32 event_key_is_mouse = (event->key == OS_Key_MouseLeft || - event->key == OS_Key_MouseRight || - event->key == OS_Key_MouseMiddle); - //- Mouse presses - if(box->flags & UI_BoxFlag_MouseClickable && - event->kind == OS_EventKind_Press && - event_mouse_in_bounds && - event_key_is_mouse) - { - ui_state->hot_box_key = box->key; - ui_state->active_box_key[event_mouse_button_kind] = box->key; - sig.flag |= (UI_SignalFlag_LeftPressed<events, event); - } - } - - - ////////////////////////////// - //- mouse is over this box's rect -> always mark mouse-over - // But the rect may be non-visible - Vec2_F32 mouse_pos = ui_state->mouse; - B32 rect_contains_mouse = rng2_contains_vec2_F32(rect, mouse_pos); - if(rect_contains_mouse) - { - sig.flag |= UI_SignalFlag_MouseOver; - } - - ////////////////////////////// - //- mouse is over this box's rect, no other hot key? -> set hot key, mark hovering - // - if(box->flags & UI_BoxFlag_MouseClickable && - rect_contains_mouse) // && - //(UI_key_match(ui_state->hot_box_key, UI_key_zero()) || UI_key_match(ui_state->hot_box_key, box->key)) //&& - //(UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], UI_key_zero()) || UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], box->key)) && - //(UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Middle], UI_key_zero()) || UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Middle], box->key)) && - //(UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Right], UI_key_zero()) || UI_key_match(ui_state->active_box_key[UI_MouseButtonKind_Right], box->key))) - - { - ui_state->hot_box_key = box->key; - sig.flag |= UI_SignalFlag_Hovering; - } - - ////////////////////////////// - //- rjf: clicking on something outside the context menu kills the context menu - // - if(!ctx_menu_is_ancestor && sig.flag & (UI_SignalFlag_LeftPressed|UI_SignalFlag_RightPressed|UI_SignalFlag_MiddlePressed)) - { - UI_ctx_menu_close(); - } - - return sig; -} - -//////////////////////////////// -//~ UI State functions -root_function UI_State* -UI_state_alloc(void) -{ - ui_g_nil_box.hash_next = &ui_g_nil_box; - ui_g_nil_box.hash_prev = &ui_g_nil_box; - ui_g_nil_box.first = &ui_g_nil_box; - ui_g_nil_box.last = &ui_g_nil_box; - ui_g_nil_box.next = &ui_g_nil_box; - ui_g_nil_box.prev = &ui_g_nil_box; - ui_g_nil_box.parent = &ui_g_nil_box; - - Arena* arena = m_make_arena_reserve(Gigabytes(1)); - UI_State *state = PushArrayZero(arena, UI_State, 1); - state->arena = arena; - state->box_table_size = 4096; - state->box_table = PushArrayZero(arena, UI_BoxSlot, state->box_table_size); - - // TODO(anton): make some better system for setting and getting theme colors - state->colors[UI_Color_Null] = vec4_F32(0, 0, 0, 1); - state->colors[UI_Color_PlainBackground] = vec4_F32(0.3f, 0.2f, 0.2f, 1); - state->colors[UI_Color_PlainBorder] = vec4_F32(0.4f, 0.4f, 0.4f, 1); - state->colors[UI_Color_PlainText] = vec4_F32(0.85f, 0.85f, 0.85f, 1); - state->colors[UI_Color_PlainOverlay] = vec4_F32(0.9f, 0.6f, 0.3f, 1); - - for(U64 index = 0; index < ArrayCount(state->frame_arenas); index += 1) - { - state->frame_arenas[index] = m_make_arena_reserve(Gigabytes(1)); - } - state->last_frame_arena_index = 1; - state->current_frame_arena_index = 0; - // TODO(anton): drag data arena - UI_init_stack_nils(state); - return state; -} - -root_function void -UI_state_set(UI_State *ui) -{ - ui_state = ui; -} - -//////////////////////////////// -//~ Build phase -root_function void -UI_build_begin(OS_Handle window, OS_EventList *events) -{ - - //- Reset per frame state - { - UI_init_stacks(ui_state); - ui_state->build_gen += 1; - m_arena_clear(UI_frame_arena()); - ui_state->root = &ui_g_nil_box; - ui_state->ctx_menu_touched_this_frame = 0; - ui_state->ctx_menu_changed = 0; - - } - - //- Fill per build parameters - { - ui_state->events = events; - ui_state->window = window; - ui_state->mouse = OS_mouse_from_window(window);// TODO(anton): window focused and last time moved stuff. - - } - - //- "Prune stale boxes" - - for(U64 slot = 0; slot < ui_state->box_table_size; slot += 1) - { - for(UI_Box *box = ui_state->box_table[slot].first, *next = 0; - !UI_box_is_nil(box); - box = next) - { - // Set the next box - next = box->hash_next; - // Any boxes existing in the hash table, that has a zero key or has a last_gen_touched+1 that is less - // than the current build gen, are removed from the table. The resulting free slots in the table are pushed - // onto the free list. - if(UI_key_match(box->key, UI_key_zero()) || box->last_gen_touched+1 < ui_state->build_gen) - { - DLLRemove_NPZ(ui_state->box_table[slot].first, ui_state->box_table[slot].last, - box, hash_next, hash_prev, - UI_box_is_nil, UI_box_set_nil); - StackPush(ui_state->first_free_box, box); - ui_state->free_box_list_count += 1; - } - } - } - - //- Build root - // This is a UI box that extends the whole of the window. - - { - Rng2_F32 client_rect = OS_client_rect_from_window(window); - Vec2_F32 client_rect_size = dim2_F32(client_rect); - UI_set_next_pref_width(UI_pixels(client_rect_size.x, 1)); - UI_set_next_pref_height(UI_pixels(client_rect_size.y, 1)); - UI_set_next_child_layout_axis(Axis2_Y); - String8 root_name = str8_lit("root_box"); - UI_Box *root = UI_box_make(0 /* zero box flags for root box */, root_name); - UI_push_parent(root); - ui_state->root = root; - } - //- Context menu setup - ui_state->ctx_menu_open = ui_state->next_ctx_menu_open; - ui_state->ctx_menu_anchor_key = ui_state->next_ctx_menu_anchor_key; - { - UI_Box *anchor_box = UI_box_from_key(ui_state->ctx_menu_anchor_key); - if(!UI_box_is_nil(anchor_box)) - { - ui_state->ctx_menu_anchor_box_last_pos = anchor_box->rect.p0; - } - Vec2_F32 anchor = add2_F32(ui_state->ctx_menu_anchor_box_last_pos, ui_state->ctx_menu_anchor_offset); - - UI_fixed_x(anchor.x) UI_fixed_y(anchor.y) - UI_pref_width(UI_size_by_children(0, 1)) UI_pref_height(UI_size_by_children(0, 1)) - { - UI_set_next_child_layout_axis(Axis2_Y); - - ui_state->ctx_menu_root = UI_box_make(UI_BoxFlag_FloatingX|UI_BoxFlag_FloatingY, str8_lit("ctx_menu")); - } - - } - - // Reset hot if we don't have an active widget - B32 has_active = 0; - for(EachEnumVal(UI_MouseButtonKind, k)) - { - if(!UI_key_match(ui_state->active_box_key[k], UI_key_zero())) - { - has_active = 1; - } - } - if(!has_active) - { - ui_state->hot_box_key = UI_key_zero(); - } - - //- rjf: reset active keys if they have been pruned - for(EachEnumVal(UI_MouseButtonKind, k)) - { - UI_Box *box = UI_box_from_key(ui_state->active_box_key[k]); - if(UI_box_is_nil(box)) - { - ui_state->active_box_key[k] = UI_key_zero(); - } - } - -} - -root_function void -UI_build_end(void) -{ - - ui_state->ctx_menu_touched_this_frame = 1; - if(ui_state->ctx_menu_open != 0 || ui_state->ctx_menu_touched_this_frame == 0) - { - //UI_ctx_menu_close(); - } - - UI_layout(); - - // TODO(anton): When I need this and understand why - //if(ui_state->ctx_menu_touched_this_frame && !ui_state->ctx_menu_changed) - //{ - //UI_Box *anchor_box = UI_box_from_key(ui_state->ctx_menu_anchor_key); - //if(!UI_box_is_nil(anchor_box)) - //{ - //Rng2_F32 root_rect = ui_state->ctx_menu_root->rect; - //Vec2_F32 pos = - //{ - //anchor_box->rect.x0 + ui_state->ctx_menu_anchor_offset.x, - //anchor_box->rect.y0 + ui_state->ctx_menu_anchor_offset.y, - //}; - //Vec2_F32 shift = sub2_F32(pos, root_rect.p0); - //Rng2_F32 new_root_rect = shift2_F32(root_rect, shift); - //ui_state->ctx_menu_root->fixed_position = new_root_rect.p0; - //ui_state->ctx_menu_root->fixed_size = dim2_F32(new_root_rect); - //ui_state->ctx_menu_root->rect = new_root_rect; - //} - //} - // -} - -//////////////////////////////// -//~ Context menu -root_function void -UI_ctx_menu_open(UI_Key key, UI_Key anchor_key, Vec2_F32 anchor_offset) -{ - anchor_offset.x = (F32)(int)anchor_offset.x; - anchor_offset.y = (F32)(int)anchor_offset.y; - ui_state->next_ctx_menu_open = 1; - ui_state->ctx_menu_changed = 1; - // TODO(anton): time parameter for ctx menu animation - ui_state->ctx_menu_key = key; - ui_state->next_ctx_menu_anchor_key = anchor_key; - ui_state->ctx_menu_anchor_offset = anchor_offset; - ui_state->ctx_menu_touched_this_frame = 1; - ui_state->ctx_menu_anchor_box_last_pos = vec2_F32(100, 100); -} - -root_function void -UI_ctx_menu_close(void) -{ - ui_state->next_ctx_menu_open = 0; -} - -root_function B32 -UI_begin_ctx_menu(UI_Key key) -{ - UI_push_parent(ui_state->root); - UI_push_parent(ui_state->ctx_menu_root); - B32 result = UI_key_match(key, ui_state->ctx_menu_key) && ui_state->ctx_menu_open; - if(result) - { - ui_state->ctx_menu_touched_this_frame = 1; - ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawBackground; - ui_state->ctx_menu_root->flags |= UI_BoxFlag_DrawDropShadow; - UI_push_pref_width(UI_pixels(100, 0)); - UI_push_pref_height(UI_pixels(200, 0)); - } - - - return result; -} - -root_function B32 -UI_ctx_menu_is_open(UI_Key key) -{ - return ui_state->ctx_menu_open && UI_key_match(key, ui_state->ctx_menu_key); -} - -root_function void -UI_end_ctx_menu(void) -{ - //UI_Box* top_parent = UI_top_parent(); - UI_pop_pref_width(); - UI_pop_pref_height(); - UI_pop_parent(); - //top_parent = UI_top_parent(); - UI_pop_parent(); - //top_parent = UI_top_parent(); -} - -//////////////////////////////// -//~ UI Frame -root_function Arena * -UI_frame_arena(void) -{ - return ui_state->frame_arenas[ui_state->current_frame_arena_index]; -} - -root_function void -UI_frame_begin(F32 delta_time) -{ - ui_g_dt = delta_time; -} - -root_function void -UI_frame_end(void) -{ - U32 last = ui_state->last_frame_arena_index; - ui_state->last_frame_arena_index = ui_state->current_frame_arena_index; - ui_state->current_frame_arena_index = last; -} - - -//////////////////////////////// -//~ Box hierarchy construction - -root_function UI_Box * -UI_box_from_key(UI_Key key) -{ - UI_Box *result = &ui_g_nil_box; - // The box table contains all the hashed boxes, so we mod by the size to get the slot in the table. - U64 slot = key.u64[0] % ui_state->box_table_size; - if(!UI_key_match(key, UI_key_zero())) - { - // We check if we have a box corresponding to the key in the hash table, and return that if we find it. - for(UI_Box *b = ui_state->box_table[slot].first; !UI_box_is_nil(b); b = b->hash_next) - { - if(UI_key_match(b->key, key)) - { - result = b; - break; - } - } - } - return result; -} - -root_function UI_Box * -UI_box_make_from_key(UI_BoxFlags flags, UI_Key key) -{ - // Get the nil box or a box from the hash table. - UI_Box *box = UI_box_from_key(key); - - // If the key has already been used, we "trample" over the key/box pair to make an id-less box. - if(box->last_gen_touched == ui_state->build_gen) - { - box = &ui_g_nil_box; - key = UI_key_zero(); - } - - // Allocate the box if it's not allocated, or if it's a duplicate key - B32 first_frame = 0; - if(UI_box_is_nil(box)) - { - U64 slot = key.u64[0] % ui_state->box_table_size; - first_frame = 1; - box = ui_state->first_free_box; - // If the first free box is nil we push a new box on the arena. - if(UI_box_is_nil(box)) - { - box = PushArrayZero(ui_state->arena, UI_Box, 1); - } - else - { - // If the first free box is non-nil, we pop it from the stack. - // This macro works since the first_free_box is a UI_Box type, which has a next member. - // So this will but the ui_state->first_free_box pointer to the next member of the previous - // element pointed to by ui_state->first_free_box. - StackPop(ui_state->first_free_box); - MemoryZeroStruct(box); - ui_state->free_box_list_count -= 1; - } - // We push back the box to the doubly linked list in the table slot, using custom functions for - // zero check and zero set. - DLLPushBack_NPZ(ui_state->box_table[slot].first, - ui_state->box_table[slot].last, box, hash_next, hash_prev, - UI_box_is_nil, UI_box_set_nil); - box->key = key; - } - - //- Link to the tree by getting the parent. If the parent is nil, the current box should actually be the root. - UI_Box *parent = UI_top_parent(); - if(UI_box_is_nil(parent)) - { - ui_state->root = box; - } - else - { - DLLPushBack_NPZ(parent->first, parent->last, box, next, prev, UI_box_is_nil, UI_box_set_nil); - parent->child_count += 1; - box->parent = parent; - } - - //- Fill the state of the current box - if(!UI_box_is_nil(box)) - { - - if(first_frame) - { - box->first_gen_touched = ui_state->build_gen; - } - - box->child_count = 0; - box->first = box->last = &ui_g_nil_box; - box->flags = flags | UI_top_flags(); - - if(ui_state->fixed_width_stack.top != &ui_state->fixed_width_nil_stack_top) - { - box->flags |= UI_BoxFlag_FixedWidth; - box->fixed_size.x = ui_state->fixed_width_stack.top->v; - } else { - box->pref_size[Axis2_X] = UI_top_pref_width(); - } - - if(ui_state->fixed_height_stack.top != &ui_state->fixed_height_nil_stack_top) - { - box->flags |= UI_BoxFlag_FixedHeight; - box->fixed_size.y = ui_state->fixed_height_stack.top->v; - } else { - box->pref_size[Axis2_Y] = UI_top_pref_height(); - } - - - box->calc_rel_pos.x = UI_top_fixed_x(); - box->calc_rel_pos.y = UI_top_fixed_y(); - - - box->child_layout_axis = UI_top_child_layout_axis(); - box->last_gen_touched = ui_state->build_gen; - - // TODO(anton): Text and color drawing properties here - box->background_color = ui_state->colors[UI_Color_PlainBackground]; - box->text_color = ui_state->colors[UI_Color_PlainText]; - box->border_color = ui_state->colors[UI_Color_PlainBorder]; - box->overlay_color = ui_state->colors[UI_Color_PlainOverlay]; - - } - - UI_auto_pop_stacks(ui_state); - - return box; -} - -root_function UI_Box * -UI_box_make(UI_BoxFlags flags, String8 string) -{ - UI_Key seed = UI_top_seed_key(); - - String8 string_hash_part = UI_hash_part_from_box_string(string); - UI_Key key = UI_key_from_string(seed, string_hash_part); - - UI_Box *box = UI_box_make_from_key(flags, key); - - box->string = str8_copy(UI_frame_arena(), string); - - return box; -} - -//////////////////////////////// -//~ layout - -root_function void -UI_solve_independent_sizes(UI_Box *root, Axis2 axis) -{ - switch(root->pref_size[axis].kind) - { - default:break; - case UI_SizeKind_Pixels: - { - root->calc_size.v[axis] = root->pref_size[axis].value; - root->calc_size.v[axis] = floor_F32(root->calc_size.v[axis]); - } break; - } - - // Recurse - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - UI_solve_independent_sizes(child, axis); - } - -} - -root_function void -UI_solve_upward_dependent_sizes(UI_Box *root, Axis2 axis) -{ - switch(root->pref_size[axis].kind) - { - default:break; - case UI_SizeKind_Percent: - { - UI_Box *ancestor = &ui_g_nil_box; - // Move up the parents and get the first ancestor that does not have - // size by children. - for(UI_Box *p = root->parent; !UI_box_is_nil(p); p = p->parent) - { - if(p->pref_size[axis].kind != UI_SizeKind_SizeByChildren) - { - ancestor = p; - break; - } - } - // The calculated size of the argument box to this function is then - // the ancestor calculated size, scaled by the preferred size of this box, which is - // assumed to be given as a percentage by the SizeKind - if(!UI_box_is_nil(ancestor)) - { - root->calc_size.v[axis] = ancestor->calc_size.v[axis] * root->pref_size[axis].value; - root->calc_size.v[axis] = floor_F32(root->calc_size.v[axis]); - } - } break; - } - - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - UI_solve_upward_dependent_sizes(child, axis); - } -} - -root_function void -UI_solve_downward_dependent_sizes(UI_Box *root, Axis2 axis) -{ - // Here we first recurse since we will depend on the result for this input. - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - UI_solve_downward_dependent_sizes(child, axis); - } - - switch(root->pref_size[axis].kind) - { - default:break; - case UI_SizeKind_SizeByChildren: - { - F32 value = 0; - { - // We will calculate the size to be the sum of the child sizes on this axis, - // if we are on the layout axis. - // If we are not on the layout axis the size will just be the maximum size of any child on that axis. - if(axis == root->child_layout_axis) - { - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - value += child->calc_size.v[axis]; - } - } - else - { - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - value = Max(value, child->calc_size.v[axis]); - } - } - } - root->calc_size.v[axis] = value; - root->calc_size.v[axis] = floor_F32(root->calc_size.v[axis]); - } break; - } -} - -root_function void -UI_solve_size_violations(UI_Box *root, Axis2 axis) -{ - // Determine maximum available space from the root size. - F32 available_space = root->calc_size.v[axis]; - - F32 taken_space = 0.0f; - F32 total_fix_budget = 0.0f; - B32 is_overflow_x_on_axis = (root->flags & (UI_BoxFlag_OverflowX<first; !UI_box_is_nil(child); child = child->next) - { - if(!(child->flags & (UI_BoxFlag_FloatingX<child_layout_axis) - { - taken_space += child->calc_size.v[axis]; - } - else - { - taken_space = Max(taken_space, child->calc_size.v[axis]); - } - - F32 fix_budget_this_child = child->calc_size.v[axis] * (1.0f - child->pref_size[axis].strictness); - total_fix_budget += fix_budget_this_child; - - } - } - } - - //- Fix children as much as possible within the calculated budget - if(!is_overflow_x_on_axis) - { - F32 violation = taken_space - available_space; - if(violation > 0 && total_fix_budget > 0) - { - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - if(!(child->flags & (UI_BoxFlag_FloatingX<calc_size.v[axis] * (1.0f - child->pref_size[axis].strictness); - F32 fix_size_this_child = 0.0f; - if(axis == root->child_layout_axis) - { - fix_size_this_child = fix_budget_this_child * (violation / total_fix_budget); - } - else - { - fix_size_this_child = child->calc_size.v[axis] - available_space; - } - fix_size_this_child = Clamp(0, fix_size_this_child, fix_budget_this_child); - child->calc_size.v[axis] -= fix_size_this_child; - child->calc_size.v[axis] = floor_F32(child->calc_size.v[axis]); - } - } - } - } - - //- Position all children after fixup - { - if(axis == root->child_layout_axis) - { - // Determine the relative offset by incrementing p by the size of a child on the relevant axis. - F32 p = 0.0f; - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - if(!(child->flags & (UI_BoxFlag_FloatingX<calc_rel_pos.v[axis] = p; - p += child->calc_size.v[axis]; - } - } - } - else - { - // If we're not on the layout axis the relative position is just zero - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - if(!(child->flags & (UI_BoxFlag_FloatingX<calc_rel_pos.v[axis] = 0; - } - } - } - - // Set the actual position values and rectangles - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - Rng2_F32 last_rel_rect = child->rel_rect; - unused_variable(last_rel_rect); - // The relative rectangle starts at the relative position, and ends at the relative rectangle p0 + size. - // TODO(anton): What does the relative rectangle mean? - child->rel_rect.p0.v[axis] = child->calc_rel_pos.v[axis]; - child->rel_rect.p1.v[axis] = child->rel_rect.p0.v[axis] + child->calc_size.v[axis]; - // TODO(anton): Corner stuff here - // The actual rectangle is the root rect p0, plus th relative p0, minus view offset of the root. - // And the p1 is the p0 + the size of the child. - child->rect.p0.v[axis] = root->rect.p0.v[axis] + child->rel_rect.p0.v[axis] - root->view_offset.v[axis]; - child->rect.p1.v[axis] = child->rect.p0.v[axis] + child->calc_size.v[axis]; - if(!(child->flags & (UI_BoxFlag_FloatingX<rect.p0.v[axis] = floor_F32(child->rect.p0.v[axis]); - child->rect.p1.v[axis] = floor_F32(child->rect.p1.v[axis]); - } - } - } - - // Recurse - for(UI_Box *child = root->first; !UI_box_is_nil(child); child = child->next) - { - UI_solve_size_violations(child, axis); - } - -} - -root_function void -UI_layout_root(UI_Box *root, Axis2 axis) -{ - UI_solve_independent_sizes(root, axis); - UI_solve_upward_dependent_sizes(root, axis); - UI_solve_downward_dependent_sizes(root, axis); - UI_solve_size_violations(root, axis); -} - -root_function void UI_layout(void) -{ - for(Axis2 axis = (Axis2)0; axis < Axis2_COUNT; axis = (Axis2)(axis+1)) - { - UI_layout_root(ui_state->root, axis); - } -} - -//////////////////////////////// -//~ Compositions -root_function void -UI_push_pref_size(Axis2 axis, UI_Size v) -{ - if(axis == Axis2_X) - { - UI_push_pref_width(v); - } - else - { - UI_push_pref_height(v); - } -} - -root_function void UI_pop_pref_size(Axis2 axis) -{ - if(axis == Axis2_X) - { - UI_pop_pref_width(); - } - else - { - UI_pop_pref_height(); - } -} - -root_function void -UI_set_next_pref_size(Axis2 axis, UI_Size v) -{ - if(axis == Axis2_X) - { - UI_set_next_pref_width(v); - } - else - { - UI_set_next_pref_height(v); - } -} - -root_function void -UI_push_fixed_pos(Vec2_F32 v) -{ - UI_push_fixed_x(v.x); - UI_push_fixed_y(v.y); -} - -root_function void -UI_pop_fixed_pos() -{ - UI_pop_fixed_x(); - UI_pop_fixed_y(); -} - -root_function void -UI_set_next_fixed_pos(Vec2_F32 v) -{ - UI_set_next_fixed_x(v.x); - UI_set_next_fixed_y(v.y); -} - -root_function void -UI_push_fixed_rect(Rng2_F32 rect) -{ - Vec2_F32 dim = dim2_F32(rect); - UI_push_fixed_pos(rect.p0); - UI_push_pref_size(Axis2_X, UI_pixels(dim.x, 1)); - UI_push_pref_size(Axis2_Y, UI_pixels(dim.y, 1)); -} - -root_function void -UI_pop_fixed_rect() -{ - UI_pop_fixed_pos(); - UI_pop_pref_size(Axis2_X); - UI_pop_pref_size(Axis2_Y); -} - -root_function void -UI_set_next_fixed_rect(Rng2_F32 rect) -{ - Vec2_F32 dim = dim2_F32(rect); - UI_set_next_fixed_pos(rect.p0); - UI_set_next_pref_size(Axis2_X, UI_pixels(dim.x, 1)); - UI_set_next_pref_size(Axis2_Y, UI_pixels(dim.y, 1)); -} - -root_function Rng2_F32 -UI_push_rect(Rng2_F32 rect) -{ - Rng2_F32 replaced = {0}; - Vec2_F32 size = dim2_F32(rect); - replaced.x0 = UI_push_fixed_x(rect.x0); - replaced.y0 = UI_push_fixed_y(rect.y0); - replaced.x1 = replaced.x0 + UI_push_fixed_width(size.x); - replaced.y1 = replaced.y0 + UI_push_fixed_height(size.y); - - return replaced; -} - -root_function Rng2_F32 -UI_pop_rect(void) -{ - Rng2_F32 popped = {0}; - popped.x0 = UI_pop_fixed_x(); - popped.y0 = UI_pop_fixed_y(); - popped.x1 = popped.x0 + UI_pop_fixed_width(); - popped.y1 = popped.y0 + UI_pop_fixed_height(); - return popped; -} - -//////////////////////////////// -//~ Drawing and text -root_function Vec2_F32 -UI_text_pos_from_box(UI_Box *box) -{ - // The stb assumes that the supplied start position will give - // the _BASELINE_ of the text that is to be produced. - // So the text position we give here is adjusted to x of the box rect's p0, - // and to the y of the box rect's p1. - F32 offset_x_pixels = 0.1f*(box->rect.x1-box->rect.x0); - F32 offset_y_pixels = 0.30*(box->rect.y1-box->rect.y0); - Vec2_F32 result = {0}; - result.x = box->rect.x0 + offset_x_pixels; - result.y = box->rect.y1 - offset_y_pixels; - - return result; -} - -root_function String8 -UI_display_string_from_box(UI_Box *box) -{ - return box->string; - -} \ No newline at end of file diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h deleted file mode 100644 index 6c8a9d6..0000000 --- a/src/ui/ui_core.h +++ /dev/null @@ -1,402 +0,0 @@ -/* date = March 25th 2024 10:14 pm */ - -#ifndef UI_CORE_H -#define UI_CORE_H - -//////////////////////////////// -//~ Keys -typedef enum UI_Color -{ - UI_Color_Null, - UI_Color_PlainBackground, - UI_Color_PlainText, - UI_Color_PlainBorder, - UI_Color_PlainOverlay, - UI_Color_COUNT -} UI_Color; - - - -//////////////////////////////// -//~ Keys - -// The UI Key is used to hash a "widget" so we can get events from it. -typedef struct UI_Key UI_Key; -struct UI_Key -{ - U64 u64[1]; -}; - -//////////////////////////////// -//~ Mouse Button Kinds - -typedef enum UI_MouseButtonKind -{ - UI_MouseButtonKind_Left, - UI_MouseButtonKind_Middle, - UI_MouseButtonKind_Right, - UI_MouseButtonKind_COUNT -} -UI_MouseButtonKind; - -//////////////////////////////// -//~ Focus Types (for hot, active widget states) - -typedef enum UI_FocusKind -{ - UI_FocusKind_Null, - UI_FocusKind_Off, - UI_FocusKind_On, - UI_FocusKind_Root, - UI_FocusKind_COUNT -} -UI_FocusKind; - -//////////////////////////////// -//~ Semantic sizes - -// The size kind specifies how the size of a box should be computed -typedef enum UI_SizeKind -{ - UI_SizeKind_Pixels, - UI_SizeKind_TextDim, - UI_SizeKind_Percent, - UI_SizeKind_SizeByChildren, - UI_SizeKind_COUNT -} -UI_SizeKind; - -typedef struct UI_Size UI_Size; -struct UI_Size -{ - UI_SizeKind kind; - F32 value; - F32 strictness; -}; - -//////////////////////////////// -//~ Main UI hierarchy - -typedef enum UI_TextAlignment -{ - UI_TextAlignment_Left, - UI_TextAlignment_COUNT, -} -UI_TextAlignment; - -typedef U32 UI_BoxFlags; -enum -{ - // Interaction - UI_BoxFlag_Disabled = (1<<0), - UI_BoxFlag_MouseClickable = (1<<1), - UI_BoxFlag_FocusHot = (1<<3), - UI_BoxFlag_FocusActive = (1<<4), - - // Layout - UI_BoxFlag_FloatingX = (1<<5), - UI_BoxFlag_FloatingY = (1<<6), - UI_BoxFlag_FixedWidth = (1<<7), - UI_BoxFlag_FixedHeight = (1<<8), - UI_BoxFlag_OverflowX = (1<<9), - UI_BoxFlag_OverflowY = (1<<10), - - // Appearance - UI_BoxFlag_Clip = (1<<11), - UI_BoxFlag_DrawText = (1<<12), - UI_BoxFlag_DrawBackground = (1<<13), - UI_BoxFlag_DrawBorder = (1<<14), - UI_BoxFlag_DrawHotEffects = (1<<15), - UI_BoxFlag_DrawActiveEffects = (1<<16), - UI_BoxFlag_DisableTextTruncate = (1<<17), - UI_BoxFlag_DrawDropShadow = (1<<18), - - // Helpers, when either X or Y is active etc. - UI_BoxFlag_Floating = UI_BoxFlag_FloatingX | UI_BoxFlag_FloatingY, - UI_BoxFlag_Clickable = UI_BoxFlag_MouseClickable, //| UI_BoxFlag_KeyboardClickable, -}; - -// UI Box is the big struct that handles all of the information of a "node" in the ui hierarchy. -// The box is a part of the composition that can be described as a "widget". -// It has both the tree information adn the state information in it. -typedef struct UI_Box UI_Box; -struct UI_Box -{ - // Hash links, persistent across frames - UI_Box *hash_next; - UI_Box *hash_prev; - - // Tree link data, updates every frame. - // This enables us to encode an n-ary tree to describe the "box" hierarchy that defines the UI. - UI_Box *first; - UI_Box *last; - UI_Box *next; - UI_Box *prev; - UI_Box *parent; - U64 child_count; - - // Key and generation info - UI_Key key; - U64 last_frame_touched_index; - - // Per-build parameters - UI_BoxFlags flags; - String8 string; - Vec2_F32 fixed_position; - Vec2_F32 fixed_size; - UI_Size pref_size[Axis2_COUNT]; - Axis2 child_layout_axis; - - Vec4_F32 background_color; - Vec4_F32 text_color; - Vec4_F32 border_color; - Vec4_F32 overlay_color; - F32 corner_radii[Corner_COUNT]; - - // Post size determination - Vec2_F32 calc_size; - Vec2_F32 calc_rel_pos; - - // Post-layout data - Rng2_F32 rel_rect; - Rng2_F32 rect; - - // State that is persistent across frames - F32 hot_t; - F32 active_t; - F32 disabled_t; - F32 focus_hot_t; - F32 focus_active_t; - U64 first_gen_touched; - U64 last_gen_touched; - Vec2_F32 view_offset; - Vec2_F32 target_view_offset; - - - -}; - -typedef struct UI_BoxRec UI_BoxRec; -struct UI_BoxRec -{ - UI_Box *next; - S32 push_count; - S32 pop_count; -}; - - -//~ Signal -typedef U32 UI_SignalFlags; -enum -{ - // mouse press -> box was pressed while hovering - UI_SignalFlag_LeftPressed = (1<<0), - UI_SignalFlag_MiddlePressed = (1<<1), - UI_SignalFlag_RightPressed = (1<<2), - - // released -> box was previously pressed & user released, in or out of bounds - UI_SignalFlag_LeftReleased = (1<<12), - UI_SignalFlag_MiddleReleased = (1<<13), - UI_SignalFlag_RightReleased = (1<<14), - - // clicked -> box was previously pressed & user released, in bounds - UI_SignalFlag_LeftClicked = (1<<15), - UI_SignalFlag_MiddleClicked = (1<<16), - UI_SignalFlag_RightClicked = (1<<17), - - UI_SignalFlag_Hovering = (1<<25), // hovering specifically this box - UI_SignalFlag_MouseOver = (1<<26), // mouse is over, but may be occluded - - UI_SignalFlag_Pressed = UI_SignalFlag_LeftPressed | UI_SignalFlag_MiddlePressed | UI_SignalFlag_RightPressed, - UI_SignalFlag_Clicked = UI_SignalFlag_LeftClicked | UI_SignalFlag_MiddleClicked | UI_SignalFlag_RightClicked -}; - -// The UI Signal is the struct which carries the information about user interaction with a box -typedef struct UI_Signal UI_Signal; -struct UI_Signal -{ - UI_Box *box; - UI_SignalFlags flag; -}; - -#define UI_hovering(s) !!((s).flag & UI_SignalFlag_Hovering) -#define UI_pressed(s) !!((s).flag & UI_SignalFlag_Pressed) -///////////////////////////////// -//~ Generated/meta - -// This is "metaprogramming" code that eventually will be generated externally. -// Right now I am doing some thing by hand, but it basically contains macros that define -// different stack members for the UI state. -#include "ui_meta.h" - - -//////////////////////////////// -//~ UI State - -// This is a slot in the hash table that helps caching of UI boxes between frames. -typedef struct UI_BoxSlot UI_BoxSlot; -struct UI_BoxSlot -{ - UI_Box *first; - UI_Box *last; -}; - -typedef struct UI_State UI_State; -struct UI_State -{ - // Permanent state - U64 build_gen; - Arena *arena; - - // Frame arenas. We have two since we want to use information from the previous frame to - // compute things in the current frame. - U32 last_frame_arena_index; - U32 current_frame_arena_index; - Arena *frame_arenas[2]; - - //- Persistent box state - UI_Box *first_free_box; - U64 free_box_list_count; - UI_BoxSlot *box_table; - U64 box_table_size; - - //- Per UI build parameters - OS_Handle window; - OS_EventList *events; - UI_Box *root; - UI_Box *ctx_menu_root; - B32 ctx_menu_touched_this_frame; - Vec2_F32 mouse; - - //- User interaction state - UI_Key hot_box_key; - UI_Key active_box_key[UI_MouseButtonKind_COUNT]; - - //- Color, rendering properties - Vec4_F32 colors[UI_Color_COUNT]; - - //- Context menu state - UI_Key ctx_menu_anchor_key; - UI_Key next_ctx_menu_anchor_key; - Vec2_F32 ctx_menu_anchor_box_last_pos; - Vec2_F32 ctx_menu_anchor_offset; - B32 ctx_menu_open; - B32 next_ctx_menu_open; - UI_Key ctx_menu_key; - B32 ctx_menu_changed; - - // TODO(anton): tooltip root - - // Stack state. Here Ryan uses generated code from metadesk. I will do it by hand to start with. - UI_declare_stack_nils; - UI_declare_stacks; -}; - -//////////////////////////////// -//~ Globals - -// Nil structs - -global UI_Box ui_g_nil_box; - -//////////////////////////////// -//~ Basic type functions - -//- Boxes -root_function B32 UI_box_is_nil(UI_Box *box); -#define UI_box_set_nil(b) ((b) = &ui_g_nil_box) - -root_function UI_BoxRec UI_box_recurse_depth_first(UI_Box *box, UI_Box *stopper, MemberOffset sib, MemberOffset child); -#define UI_box_recurse_depth_first_post(box, stopper) UI_box_recurse_depth_first((box), (stopper), MemberOff(UI_Box, prev), MemberOff(UI_Box, last)); - -//- Sizes -root_function UI_Size UI_size_make(UI_SizeKind kind, F32 value, F32 strictness); -#define UI_pixels(v, strictness) UI_size_make(UI_SizeKind_Pixels, (v), (strictness)) -#define UI_size_by_children(v, strictness) UI_size_make(UI_SizeKind_SizeByChildren, (v), (strictness)) -#define UI_pct(v, strictness) UI_size_make(UI_SizeKind_Percent, (v), (strictness)) - -//- ID strings -root_function String8 UI_hash_part_from_box_string(String8 string); - -//- Keys -root_function UI_Key UI_key_zero(void); -root_function UI_Key UI_key_from_string(UI_Key seed, String8 string); -root_function B32 UI_key_match(UI_Key a, UI_Key b); - -//- Signal -root_function UI_Signal UI_signal_from_box(UI_Box *box); - - -//////////////////////////////// -//~ UI State functions -root_function UI_State *UI_state_alloc(void); -root_function void UI_state_set(UI_State *ui); - -//////////////////////////////// -//~ Build phase -root_function void UI_build_begin(OS_Handle window, OS_EventList *events); -root_function void UI_build_end(void); - -//////////////////////////////// -//~ Context menu -root_function void UI_ctx_menu_open(UI_Key key, UI_Key anchor_key, Vec2_F32 anchor_offset); -root_function void UI_ctx_menu_close(void); -root_function B32 UI_begin_ctx_menu(UI_Key key); -root_function void UI_end_ctx_menu(void); - -//////////////////////////////// -//~ UI Frame -root_function Arena *UI_frame_arena(void); -root_function void UI_frame_begin(F32 delta_time); -root_function void UI_frame_end(void); - -//////////////////////////////// -//~ Box hierarchy construction -root_function UI_Box *UI_box_from_key(UI_Key key); -root_function UI_Box *UI_box_make_from_key(UI_BoxFlags flags, UI_Key key); -root_function UI_Box *UI_box_make(UI_BoxFlags flags, String8 string); - -//////////////////////////////// -//~ layout -root_function void UI_solve_independent_sizes(UI_Box *root, Axis2 axis); -root_function void UI_solve_upward_dependent_sizes(UI_Box *root, Axis2 axis); -root_function void UI_solve_downward_dependent_sizes(UI_Box *root, Axis2 axis); -root_function void UI_solve_size_violations(UI_Box *root, Axis2 axis); -root_function void UI_layout_root(UI_Box *root, Axis2 axis); -root_function void UI_layout(void); - -//////////////////////////////// -//~ Compositions -root_function void UI_push_pref_size(Axis2 axis, UI_Size v); -root_function void UI_pop_pref_size(Axis2 axis); -root_function void UI_set_next_pref_size(Axis2 axis, UI_Size v); -root_function void UI_push_fixed_pos(Vec2_F32 v); -root_function void UI_pop_fixed_pos(); -root_function void UI_set_next_fixed_pos(Vec2_F32 v); -root_function void UI_push_fixed_rect(Rng2_F32 rect); -root_function void UI_pop_fixed_rect(); -root_function void UI_set_next_fixed_rect(Rng2_F32 rect); - - -//////////////////////////////// -//~ Drawing and text -root_function Vec2_F32 UI_text_pos_from_box(UI_Box *box); -root_function String8 UI_display_string_from_box(UI_Box *box); -//////////////////////////////// -//~ Defer helpers - -//- base -#define UI_parent(v) DeferLoop(UI_push_parent(v), UI_pop_parent()) -#define UI_pref_width(v) DeferLoop(UI_push_pref_width(v), UI_pop_pref_width()) -#define UI_pref_height(v) DeferLoop(UI_push_pref_height(v), UI_pop_pref_height()) - -//- pane -#define UI_pane(r, s) DeferLoop(UI_pane_begin((r), (s)), UI_pane_end()) -//- compositions -#define UI_width_fill UI_pref_width(UI_pct(1, 0)) -#define UI_height_fill UI_pref_height(UI_pct(1, 0)) -#define UI_fixed_x(v) DeferLoop(UI_push_fixed_x((v)), UI_pop_fixed_x()) -#define UI_fixed_y(v) DeferLoop(UI_push_fixed_y((v)), UI_pop_fixed_y()) -#define UI_fixed_pos(v) DeferLoop(UI_push_fixed_pos(v), UI_pop_fixed_pos()) -#define UI_ctx_menu(key) DeferLoopChecked(UI_begin_ctx_menu(key), UI_end_ctx_menu()) -#endif //UI_CORE_H diff --git a/src/ui/ui_draw.c b/src/ui/ui_draw.c deleted file mode 100644 index ac9019a..0000000 --- a/src/ui/ui_draw.c +++ /dev/null @@ -1,92 +0,0 @@ - -root_function void -UI_draw(void) -{ - - - //OS_Handle window = ui_state->window; - for(UI_Box *box = ui_state->root, *next_box = &ui_g_nil_box; !UI_box_is_nil(box); box = next_box) - { - // We do a depth first recursion to go through the nodes. - // The post part means that the sibling is UI_Box prev, and the child is UI_Box last. - // TODO(anton): Draw this with pen and paper and make sure I understand how this works - UI_BoxRec rec = UI_box_recurse_depth_first_post(box, &ui_g_nil_box); - next_box = rec.next; - - //- Draw shadow - if(box->flags & UI_BoxFlag_DrawDropShadow) - { - F32 shift = 3.0f; // TODO make relative precent, is pixelsn ow - Rng2_F32 shadow_rect = shift2_F32(pad2_F32(box->rect, 2), vec2_F32(shift, shift)); - - - R_Rect2DInst *rect = D_rect2D(shadow_rect, - .color = vec4_F32(0, 0, 0, 1.f), - .corner_radius = 1, - .softness = 3.f, - .omit_texture = 1); - } - - //- Draw background - if(box->flags & UI_BoxFlag_DrawBackground) - { - - R_Rect2DInst *rect = D_rect2D(box->rect, - .color = box->background_color, - .corner_radius = 0.0f, - .softness = 0.0f, - .omit_texture = 1); - - if(box->flags & UI_BoxFlag_DrawHotEffects) - { - if(UI_key_match(ui_state->hot_box_key, box->key)) - { - - rect->colors[Corner_00] = box->overlay_color; - rect->colors[Corner_10] = box->overlay_color; - rect->colors[Corner_01] = box->background_color; - rect->colors[Corner_11] = box->background_color; - } - } - - } - - //- Draw text - if(box->flags & UI_BoxFlag_DrawText) - { - // The stb assumes that the supplied start position will give - // the _BASELINE_ of the text that is to be produced. - // So the text position we give here is adjusted to x of the box rect's p0, - // and to the y of the box rect's p1. - Vec2_F32 text_pos = UI_text_pos_from_box(box); - String8 display_string = UI_display_string_from_box(box); - B32 truncated = 0; - if(!(box->flags & UI_BoxFlag_DisableTextTruncate)) - { - // TODO(anton): Do stuff for truncating - D_text2D(text_pos, display_string, box->text_color); - } - } - - //- Draw border - if(box->flags & UI_BoxFlag_DrawBorder) - { - Rng2_F32 border_rect = pad2_F32(box->rect, 0); - R_Rect2DInst *rect = D_rect2D(border_rect); - Vec4_F32 border_top_color = box->border_color; - Vec4_F32 border_bot_color = box->background_color; - rect->colors[Corner_00] = border_top_color; - rect->colors[Corner_10] = border_top_color; - rect->colors[Corner_01] = border_bot_color; - rect->colors[Corner_11] = border_bot_color; - rect->corner_radii[Corner_00] = 1; - rect->corner_radii[Corner_10] = 1; - rect->corner_radii[Corner_01] = 1; - rect->corner_radii[Corner_11] = 1; - rect->border_thickness = 1.f; - rect->softness = 0.f; - rect->omit_texture = 1; - } - - } -} diff --git a/src/ui/ui_draw.h b/src/ui/ui_draw.h deleted file mode 100644 index 83cdc0d..0000000 --- a/src/ui/ui_draw.h +++ /dev/null @@ -1,6 +0,0 @@ -/* date = April 2nd 2024 3:11 pm */ - -#ifndef UI_DRAW_H -#define UI_DRAW_H -root_function void UI_draw(void); -#endif //UI_DRAW_H diff --git a/src/ui/ui_inc.c b/src/ui/ui_inc.c deleted file mode 100644 index 5aafb17..0000000 --- a/src/ui/ui_inc.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "ui_core.c" -#include "ui_basic_widgets.c" -#include "ui_draw.c" diff --git a/src/ui/ui_inc.h b/src/ui/ui_inc.h deleted file mode 100644 index 1300ca0..0000000 --- a/src/ui/ui_inc.h +++ /dev/null @@ -1,10 +0,0 @@ -/* date = March 25th 2024 10:14 pm */ - -#ifndef UI_INC_H -#define UI_INC_H - -#include "ui_core.h" -#include "ui_basic_widgets.h" -#include "ui_draw.h" - -#endif //UI_INC_H diff --git a/src/ui/ui_meta.c b/src/ui/ui_meta.c deleted file mode 100644 index 3314d0b..0000000 --- a/src/ui/ui_meta.c +++ /dev/null @@ -1,108 +0,0 @@ -// TODO(anton): This code should be generated by some metaprogram at some point. - - -// Macro that generalises the code for setting the next implementation on -// a particular stack. -// The convention is that a node type has UI_Node, -// and the corresponding stack struct in the UI state has a top pointer, a free pointer and an auto_pop B32 value. -// And that struct is called _stack. -// The nodes have values of different types, which the argument to this macro designates. -// A ParentNode, for example, has a UI_Box *value, and the PrefWidth has a UI_Size value. -#define UI_stack_top_impl(state, name_upper, name_lower) \ -return state->name_lower##_stack.top->v; - -#define UI_stack_push_impl(state, name_upper, name_lower, type, new_value) \ -UI_##name_upper##Node *node = state->name_lower##_stack.free; \ -if(node != 0) {StackPop(state->name_lower##_stack.free);} \ -else {node = PushArrayZero(UI_frame_arena(), UI_##name_upper##Node, 1);} \ -type old_value = state->name_lower##_stack.top->v; \ -node->v = new_value; \ -StackPush(state->name_lower##_stack.top, node); \ -state->name_lower##_stack.auto_pop = 0; \ -return old_value; - -#define UI_stack_pop_impl(state, name_upper, name_lower) \ -UI_##name_upper##Node *popped = state->name_lower##_stack.top;\ -if(popped != &state->name_lower##_nil_stack_top)\ -{\ -StackPop(state->name_lower##_stack.top);\ -StackPush(state->name_lower##_stack.free, popped);\ -state->name_lower##_stack.auto_pop = 0;\ -}\ -return popped->v;\ - -// NOTE(anton): Only difference from push is auto pop = 1? -#define UI_stack_set_next_impl(state, name_upper, name_lower, type, new_value) \ -UI_##name_upper##Node *node = state->name_lower##_stack.free; \ -if(node != 0) {StackPop(state->name_lower##_stack.free);}\ -else {node = PushArray(UI_frame_arena(), UI_##name_upper##Node, 1);}\ -type old_value = state->name_lower##_stack.top->v;\ -node->v = new_value;\ -StackPush(state->name_lower##_stack.top, node);\ -state->name_lower##_stack.auto_pop = 1;\ -return old_value; - - -/////////////////////////////////////// -//~ Stack functions - -//- Top -root_function UI_Box *UI_top_parent(void) { UI_stack_top_impl(ui_state, Parent, parent) } -root_function UI_BoxFlags UI_top_flags(void) { UI_stack_top_impl(ui_state, Flags, flags) } -root_function F32 UI_top_fixed_x(void) { UI_stack_top_impl(ui_state, FixedX, fixed_x) } -root_function F32 UI_top_fixed_y(void) { UI_stack_top_impl(ui_state, FixedY, fixed_y) } -root_function F32 UI_top_fixed_width(void) { UI_stack_top_impl(ui_state, FixedWidth, fixed_width) } -root_function F32 UI_top_fixed_height(void) { UI_stack_top_impl(ui_state, FixedHeight, fixed_height) } -root_function UI_Key UI_top_seed_key(void) { UI_stack_top_impl(ui_state, SeedKey, seed_key) } -root_function UI_Size UI_top_pref_width(void) { UI_stack_top_impl(ui_state, PrefWidth, pref_width) } -root_function UI_Size UI_top_pref_height(void) { UI_stack_top_impl(ui_state, PrefHeight, pref_height) } -root_function Axis2 UI_top_child_layout_axis(void) { UI_stack_top_impl(ui_state, ChildLayoutAxis, child_layout_axis) } - -//- Push -root_function UI_Box *UI_push_parent(UI_Box *v) { UI_stack_push_impl(ui_state, Parent, parent, UI_Box *, v) } -root_function UI_BoxFlags UI_push_flags(UI_BoxFlags v) { UI_stack_push_impl(ui_state, Flags, flags, UI_BoxFlags, v) } -root_function F32 UI_push_fixed_x(F32 v) { UI_stack_push_impl(ui_state, FixedX, fixed_x, F32, v) } -root_function F32 UI_push_fixed_y(F32 v) { UI_stack_push_impl(ui_state, FixedY, fixed_y, F32, v) } -root_function F32 UI_push_fixed_width(F32 v) { UI_stack_push_impl(ui_state, FixedWidth, fixed_width, F32, v) } -root_function F32 UI_push_fixed_height(F32 v) { UI_stack_push_impl(ui_state, FixedHeight, fixed_height, F32, v) } -root_function UI_Key UI_push_seed_key(UI_Key v) { UI_stack_push_impl(ui_state, SeedKey, seed_key, UI_Key, v) } -root_function UI_Size UI_push_pref_width(UI_Size v) { UI_stack_push_impl(ui_state, PrefWidth, pref_width, UI_Size, v) } -root_function UI_Size UI_push_pref_height(UI_Size v) { UI_stack_push_impl(ui_state, PrefHeight, pref_height, UI_Size, v) } -root_function Axis2 UI_push_child_layout_axis(Axis2 v) { UI_stack_push_impl(ui_state, ChildLayoutAxis, child_layout_axis, Axis2, v) } - -//- Pop -root_function UI_Box *UI_pop_parent(void) { UI_stack_pop_impl(ui_state, Parent, parent) } -root_function UI_BoxFlags UI_pop_flags(void) { UI_stack_pop_impl(ui_state, Flags, flags) } -root_function F32 UI_pop_fixed_x(void) { UI_stack_pop_impl(ui_state, FixedX, fixed_x) } -root_function F32 UI_pop_fixed_y(void) { UI_stack_pop_impl(ui_state, FixedY, fixed_y) } -root_function F32 UI_pop_fixed_width(void) { UI_stack_pop_impl(ui_state, FixedWidth, fixed_width) } -root_function F32 UI_pop_fixed_height(void) { UI_stack_pop_impl(ui_state, FixedHeight, fixed_height) } -root_function UI_Key UI_pop_seed_key(void) { UI_stack_pop_impl(ui_state, SeedKey, seed_key) } -root_function UI_Size UI_pop_pref_width(void) { UI_stack_pop_impl(ui_state, PrefWidth, pref_width) } -root_function UI_Size UI_pop_pref_height(void) { UI_stack_pop_impl(ui_state, PrefHeight, pref_height) } -root_function Axis2 UI_pop_child_layout_axis(void) { UI_stack_pop_impl(ui_state, ChildLayoutAxis, child_layout_axis) } - -//- Set next -root_function UI_Box *UI_set_next_parent(UI_Box *v) { UI_stack_set_next_impl(ui_state, Parent, parent, UI_Box *, v) } -root_function UI_BoxFlags UI_set_next_flags(UI_BoxFlags v) { UI_stack_set_next_impl(ui_state, Flags, flags, UI_BoxFlags, v) } -root_function F32 UI_set_next_fixed_x(F32 v) { UI_stack_set_next_impl(ui_state, FixedX, fixed_x, F32, v) } -root_function F32 UI_set_next_fixed_y(F32 v) { UI_stack_set_next_impl(ui_state, FixedY, fixed_y, F32, v) } -root_function F32 UI_set_next_fixed_width(F32 v) { UI_stack_set_next_impl(ui_state, FixedWidth, fixed_width, F32, v) } -root_function F32 UI_set_next_fixed_height(F32 v) { UI_stack_set_next_impl(ui_state, FixedHeight, fixed_height, F32, v) } -root_function UI_Key UI_set_next_seed_key(UI_Key v) { UI_stack_set_next_impl(ui_state, SeedKey, seed_key, UI_Key, v) } -root_function UI_Size UI_set_next_pref_width(UI_Size v) { UI_stack_set_next_impl(ui_state, PrefWidth, pref_width, UI_Size, v) } -root_function UI_Size UI_set_next_pref_height(UI_Size v) { UI_stack_set_next_impl(ui_state, PrefHeight, pref_height, UI_Size, v) } -root_function Axis2 UI_set_next_child_layout_axis(Axis2 v) { UI_stack_set_next_impl(ui_state, ChildLayoutAxis, child_layout_axis, Axis2, v) } - -#define UI_auto_pop_stacks(state) \ -if(state->parent_stack.auto_pop) { UI_pop_parent(); state->parent_stack.auto_pop = 0; }\ -if(state->flags_stack.auto_pop) { UI_pop_flags(); state->flags_stack.auto_pop = 0; }\ -if(state->fixed_x_stack.auto_pop) { UI_pop_fixed_x(); state->fixed_x_stack.auto_pop = 0; }\ -if(state->fixed_y_stack.auto_pop) { UI_pop_fixed_y(); state->fixed_y_stack.auto_pop = 0; }\ -if(state->fixed_x_stack.auto_pop) { UI_pop_fixed_width(); state->fixed_width_stack.auto_pop = 0; }\ -if(state->fixed_y_stack.auto_pop) { UI_pop_fixed_height(); state->fixed_height_stack.auto_pop = 0; }\ -if(state->seed_key_stack.auto_pop) { UI_pop_seed_key(); state->seed_key_stack.auto_pop = 0; }\ -if(state->pref_width_stack.auto_pop) { UI_pop_pref_width(); state->pref_width_stack.auto_pop = 0; }\ -if(state->pref_height_stack.auto_pop) { UI_pop_pref_height(); state->pref_height_stack.auto_pop = 0; }\ -if(state->child_layout_axis_stack.auto_pop) { UI_pop_child_layout_axis(); state->child_layout_axis_stack.auto_pop = 0; }\ - diff --git a/src/ui/ui_meta.h b/src/ui/ui_meta.h deleted file mode 100644 index 58e0d06..0000000 --- a/src/ui/ui_meta.h +++ /dev/null @@ -1,80 +0,0 @@ -/* date = April 1st 2024 9:04 pm */ - -#ifndef UI_META_H -#define UI_META_H - -// TODO(anton): This code should be generated by a metaprogram at some point. - -//~ Node structs - -typedef struct UI_ParentNode UI_ParentNode; struct UI_ParentNode{UI_ParentNode *next; UI_Box * v;}; -typedef struct UI_FlagsNode UI_FlagsNode; struct UI_FlagsNode{UI_FlagsNode *next; UI_BoxFlags v;}; -typedef struct UI_FixedXNode UI_FixedXNode; struct UI_FixedXNode{UI_FixedXNode *next; F32 v;}; -typedef struct UI_FixedYNode UI_FixedYNode; struct UI_FixedYNode{UI_FixedYNode *next; F32 v;}; -typedef struct UI_FixedWidthNode UI_FixedWidthNode; struct UI_FixedWidthNode{UI_FixedWidthNode *next; F32 v;}; -typedef struct UI_FixedHeightNode UI_FixedHeightNode; struct UI_FixedHeightNode{UI_FixedHeightNode *next; F32 v;}; -typedef struct UI_PrefWidthNode UI_PrefWidthNode; struct UI_PrefWidthNode{UI_PrefWidthNode *next; UI_Size v;}; -typedef struct UI_PrefHeightNode UI_PrefHeightNode; struct UI_PrefHeightNode{UI_PrefHeightNode *next; UI_Size v;}; -typedef struct UI_ChildLayoutAxisNode UI_ChildLayoutAxisNode; struct UI_ChildLayoutAxisNode{UI_ChildLayoutAxisNode *next; Axis2 v;}; -typedef struct UI_SeedKeyNode UI_SeedKeyNode; struct UI_SeedKeyNode{UI_SeedKeyNode *next; UI_Key v;}; - - -//~ Declaration macros for use in the UI_State - -//- Stacks -#define UI_declare_stacks \ -struct \ -{ \ -struct { UI_ParentNode *top; UI_ParentNode *free; B32 auto_pop; } parent_stack; \ -struct { UI_FlagsNode *top; UI_FlagsNode *free; B32 auto_pop; } flags_stack; \ -struct { UI_FixedXNode *top; UI_FixedXNode *free; B32 auto_pop; } fixed_x_stack; \ -struct { UI_FixedYNode *top; UI_FixedYNode *free; B32 auto_pop; } fixed_y_stack; \ -struct { UI_FixedWidthNode *top; UI_FixedWidthNode *free; B32 auto_pop; } fixed_width_stack; \ -struct { UI_FixedHeightNode *top; UI_FixedHeightNode *free; B32 auto_pop; } fixed_height_stack; \ -struct { UI_PrefWidthNode *top; UI_PrefWidthNode *free; B32 auto_pop; } pref_width_stack; \ -struct { UI_PrefHeightNode *top; UI_PrefHeightNode *free; B32 auto_pop; } pref_height_stack; \ -struct { UI_ChildLayoutAxisNode *top; UI_ChildLayoutAxisNode *free; B32 auto_pop; } child_layout_axis_stack; \ -struct { UI_SeedKeyNode *top; UI_SeedKeyNode *free; B32 auto_pop; } seed_key_stack; \ -} - -#define UI_init_stacks(state) \ -state->parent_stack.top = &state->parent_nil_stack_top; state->parent_stack.free = 0; state->parent_stack.auto_pop = 0; \ -state->flags_stack.top = &state->flags_nil_stack_top; state->flags_stack.free = 0; state->flags_stack.auto_pop = 0; \ -state->fixed_x_stack.top = &state->fixed_x_nil_stack_top; state->fixed_x_stack.free = 0; state->fixed_x_stack.auto_pop = 0;\ -state->fixed_y_stack.top = &state->fixed_y_nil_stack_top; state->fixed_y_stack.free = 0; state->fixed_y_stack.auto_pop = 0;\ -state->fixed_width_stack.top = &state->fixed_width_nil_stack_top; state->fixed_width_stack.free = 0; state->fixed_width_stack.auto_pop = 0;\ -state->fixed_height_stack.top = &state->fixed_height_nil_stack_top; state->fixed_height_stack.free = 0; state->fixed_height_stack.auto_pop = 0;\ -state->pref_width_stack.top = &state->pref_width_nil_stack_top; state->pref_width_stack.free = 0; state->pref_width_stack.auto_pop = 0; \ -state->pref_height_stack.top = &state->pref_height_nil_stack_top; state->pref_height_stack.free = 0; state->pref_height_stack.auto_pop = 0; \ -state->child_layout_axis_stack.top = &state->child_layout_axis_nil_stack_top; state->child_layout_axis_stack.free = 0; state->child_layout_axis_stack.auto_pop = 0; \ -state->seed_key_stack.top = &state->seed_key_nil_stack_top; state->seed_key_stack.free = 0; state->seed_key_stack.auto_pop = 0; \ - - -//- Stack nils -#define UI_declare_stack_nils \ -struct \ -{ \ -UI_ParentNode parent_nil_stack_top; \ -UI_FlagsNode flags_nil_stack_top; \ -UI_FixedXNode fixed_x_nil_stack_top; \ -UI_FixedYNode fixed_y_nil_stack_top; \ -UI_FixedWidthNode fixed_width_nil_stack_top; \ -UI_FixedHeightNode fixed_height_nil_stack_top; \ -UI_PrefWidthNode pref_width_nil_stack_top; \ -UI_PrefHeightNode pref_height_nil_stack_top; \ -UI_ChildLayoutAxisNode child_layout_axis_nil_stack_top; \ -UI_SeedKeyNode seed_key_nil_stack_top; \ -} -#define UI_init_stack_nils(state) \ -state->parent_nil_stack_top.v = &ui_g_nil_box; \ -state->flags_nil_stack_top.v = 0; \ -state->fixed_x_nil_stack_top.v = 0; \ -state->fixed_y_nil_stack_top.v = 0; \ -state->fixed_width_nil_stack_top.v = 0; \ -state->fixed_height_nil_stack_top.v = 0; \ -state->pref_width_nil_stack_top.v = UI_pixels(200.f, 1.f); \ -state->pref_height_nil_stack_top.v = UI_pixels(2.f, 1.f); \ -state->child_layout_axis_nil_stack_top.v = Axis2_X;\ -state->seed_key_nil_stack_top.v = UI_key_zero(); \ - -#endif //UI_META_H