diff options
Diffstat (limited to 'src')
31 files changed, 21345 insertions, 21881 deletions
diff --git a/src/cross_os.c b/src/cross_os.c index 41ec036..e7c1a0c 100644 --- a/src/cross_os.c +++ b/src/cross_os.c @@ -25,23 +25,23 @@ #define _CRT_SECURE_NO_WARNINGS -int directoryExists (const char* path) { +int directoryExists(const char *path) { #if defined(_WIN32) || defined(_WIN64) #elif __APPLE__ #elif __unix__ - struct stat st = {0}; - return stat(path, &st)+1; + struct stat st = {0}; + return stat(path, &st) + 1; #else - return -1; + return -1; #endif } -const char* getUserDir () { +const char *getUserDir() { #if defined(_WIN32) || defined(_WIN64) - return getenv("HOME"); + return getenv("HOME"); #elif __APPLE__ #elif __unix__ - struct passwd *pw = getpwuid(getuid()); - return pw->pw_dir; + struct passwd *pw = getpwuid(getuid()); + return pw->pw_dir; #endif } @@ -53,20 +53,20 @@ const char* getUserDir () { #include <unistd.h> void handler(int sig) { - void *array[100]; - size_t size; + void *array[100]; + size_t size; - // get void*'s for all entries on the stack - size = backtrace(array, 100); + // get void*'s for all entries on the stack + size = backtrace(array, 100); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - exit(1); + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + exit(1); } -void _linux_register_error_handler () { - signal(SIGSEGV, handler); // install our handler - signal(SIGABRT, handler); // install our handler +void _linux_register_error_handler() { + signal(SIGSEGV, handler); // install our handler + signal(SIGABRT, handler); // install our handler } #endif diff --git a/src/cross_os.h b/src/cross_os.h index e2d4350..e047ba8 100644 --- a/src/cross_os.h +++ b/src/cross_os.h @@ -22,36 +22,36 @@ #ifndef CROSS_OS_H #define CROSS_OS_H -//cross platform os helpers +// cross platform os helpers #if defined(_WIN32) || defined(_WIN64) - //disable warning on iostream functions on windows - #define _CRT_SECURE_NO_WARNINGS - #include "windows.h" - #if defined(_WIN64) - #ifndef isnan - #define isnan _isnanf - #endif - #endif - #define vkvg_inline __forceinline - #define disable_warning (warn) - #define reset_warning (warn) +// disable warning on iostream functions on windows +#define _CRT_SECURE_NO_WARNINGS +#include "windows.h" +#if defined(_WIN64) +#ifndef isnan +#define isnan _isnanf +#endif +#endif +#define vkvg_inline __forceinline +#define disable_warning (warn) +#define reset_warning (warn) #elif __APPLE__ - #include <math.h> - #define vkvg_inline static - #define disable_warning (warn) - #define reset_warning (warn) +#include <math.h> +#define vkvg_inline static +#define disable_warning (warn) +#define reset_warning (warn) #elif __unix__ - #include <unistd.h> - #include <sys/types.h> - #include <pwd.h> - #define vkvg_inline static inline __attribute((always_inline)) - #define disable_warning (warn) #pragma GCC diagnostic ignored "-W"#warn - #define reset_warning (warn) #pragma GCC diagnostic warning "-W"#warn - #if __linux__ - void _linux_register_error_handler (); - #endif +#include <unistd.h> +#include <sys/types.h> +#include <pwd.h> +#define vkvg_inline static inline __attribute((always_inline)) +#define disable_warning (warn) #pragma GCC diagnostic ignored "-W" #warn +#define reset_warning (warn) #pragma GCC diagnostic warning "-W" #warn +#if __linux__ +void _linux_register_error_handler(); +#endif #endif -const char* getUserDir (); +const char *getUserDir(); #endif // CROSS_OS_H diff --git a/src/deps/tinycthread.c b/src/deps/tinycthread.c index f9cea2e..5dcf01f 100644 --- a/src/deps/tinycthread.c +++ b/src/deps/tinycthread.c @@ -32,103 +32,96 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include <signal.h> - #include <sched.h> - #include <unistd.h> - #include <sys/time.h> - #include <errno.h> +#include <signal.h> +#include <sched.h> +#include <unistd.h> +#include <sys/time.h> +#include <errno.h> #elif defined(_TTHREAD_WIN32_) - #include <process.h> - #include <sys/timeb.h> +#include <process.h> +#include <sys/timeb.h> #endif /* Standard, good-to-have defines */ #ifndef NULL - #define NULL (void*)0 +#define NULL (void *)0 #endif #ifndef TRUE - #define TRUE 1 +#define TRUE 1 #endif #ifndef FALSE - #define FALSE 0 +#define FALSE 0 #endif -int mtx_init(mtx_t *mtx, int type) -{ +int mtx_init(mtx_t *mtx, int type) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - mtx->mRecursive = type & mtx_recursive; - InitializeCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + mtx->mRecursive = type & mtx_recursive; + InitializeCriticalSection(&mtx->mHandle); + return thrd_success; #else - int ret; - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - if (type & mtx_recursive) - { - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - } - ret = pthread_mutex_init(mtx, &attr); - pthread_mutexattr_destroy(&attr); - return ret == 0 ? thrd_success : thrd_error; + int ret; + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + if (type & mtx_recursive) { + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + } + ret = pthread_mutex_init(mtx, &attr); + pthread_mutexattr_destroy(&attr); + return ret == 0 ? thrd_success : thrd_error; #endif } -void mtx_destroy(mtx_t *mtx) -{ +void mtx_destroy(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mtx->mHandle); + DeleteCriticalSection(&mtx->mHandle); #else - pthread_mutex_destroy(mtx); + pthread_mutex_destroy(mtx); #endif } -int mtx_lock(mtx_t *mtx) -{ +int mtx_lock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mtx->mHandle); - if (!mtx->mRecursive) - { - while(mtx->mAlreadyLocked) Sleep(1000); /* Simulate deadlock... */ - mtx->mAlreadyLocked = TRUE; - } - return thrd_success; + EnterCriticalSection(&mtx->mHandle); + if (!mtx->mRecursive) { + while (mtx->mAlreadyLocked) + Sleep(1000); /* Simulate deadlock... */ + mtx->mAlreadyLocked = TRUE; + } + return thrd_success; #else - return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; + return pthread_mutex_lock(mtx) == 0 ? thrd_success : thrd_error; #endif } -int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) -{ - /* FIXME! */ - (void)mtx; - (void)ts; - return thrd_error; +int mtx_timedlock(mtx_t *mtx, const struct timespec *ts) { + /* FIXME! */ + (void)mtx; + (void)ts; + return thrd_error; } -int mtx_trylock(mtx_t *mtx) -{ +int mtx_trylock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; - if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) - { - LeaveCriticalSection(&mtx->mHandle); - ret = thrd_busy; - } - return ret; + int ret = TryEnterCriticalSection(&mtx->mHandle) ? thrd_success : thrd_busy; + if ((!mtx->mRecursive) && (ret == thrd_success) && mtx->mAlreadyLocked) { + LeaveCriticalSection(&mtx->mHandle); + ret = thrd_busy; + } + return ret; #else - return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; + return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy; #endif } -int mtx_unlock(mtx_t *mtx) -{ +int mtx_unlock(mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - mtx->mAlreadyLocked = FALSE; - LeaveCriticalSection(&mtx->mHandle); - return thrd_success; + mtx->mAlreadyLocked = FALSE; + LeaveCriticalSection(&mtx->mHandle); + return thrd_success; #else - return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error;; + return pthread_mutex_unlock(mtx) == 0 ? thrd_success : thrd_error; + ; #endif } @@ -137,458 +130,397 @@ int mtx_unlock(mtx_t *mtx) #define _CONDITION_EVENT_ALL 1 #endif -int cnd_init(cnd_t *cond) -{ +int cnd_init(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - cond->mWaitersCount = 0; + cond->mWaitersCount = 0; - /* Init critical section */ - InitializeCriticalSection(&cond->mWaitersCountLock); + /* Init critical section */ + InitializeCriticalSection(&cond->mWaitersCountLock); - /* Init events */ - cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) - { - cond->mEvents[_CONDITION_EVENT_ALL] = NULL; - return thrd_error; - } - cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - cond->mEvents[_CONDITION_EVENT_ONE] = NULL; - return thrd_error; - } + /* Init events */ + cond->mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ONE] == NULL) { + cond->mEvents[_CONDITION_EVENT_ALL] = NULL; + return thrd_error; + } + cond->mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); + if (cond->mEvents[_CONDITION_EVENT_ALL] == NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + cond->mEvents[_CONDITION_EVENT_ONE] = NULL; + return thrd_error; + } - return thrd_success; + return thrd_success; #else - return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; + return pthread_cond_init(cond, NULL) == 0 ? thrd_success : thrd_error; #endif } -void cnd_destroy(cnd_t *cond) -{ +void cnd_destroy(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); - } - if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) - { - CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); - } - DeleteCriticalSection(&cond->mWaitersCountLock); + if (cond->mEvents[_CONDITION_EVENT_ONE] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ONE]); + } + if (cond->mEvents[_CONDITION_EVENT_ALL] != NULL) { + CloseHandle(cond->mEvents[_CONDITION_EVENT_ALL]); + } + DeleteCriticalSection(&cond->mWaitersCountLock); #else - pthread_cond_destroy(cond); + pthread_cond_destroy(cond); #endif } -int cnd_signal(cnd_t *cond) -{ +int cnd_signal(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; + int haveWaiters; - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) - { - return thrd_error; + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ONE]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } -int cnd_broadcast(cnd_t *cond) -{ +int cnd_broadcast(cnd_t *cond) { #if defined(_TTHREAD_WIN32_) - int haveWaiters; + int haveWaiters; - /* Are there any waiters? */ - EnterCriticalSection(&cond->mWaitersCountLock); - haveWaiters = (cond->mWaitersCount > 0); - LeaveCriticalSection(&cond->mWaitersCountLock); + /* Are there any waiters? */ + EnterCriticalSection(&cond->mWaitersCountLock); + haveWaiters = (cond->mWaitersCount > 0); + LeaveCriticalSection(&cond->mWaitersCountLock); - /* If we have any waiting threads, send them a signal */ - if(haveWaiters) - { - if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; + /* If we have any waiting threads, send them a signal */ + if (haveWaiters) { + if (SetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - return thrd_success; + return thrd_success; #else - return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; + return pthread_cond_signal(cond) == 0 ? thrd_success : thrd_error; #endif } #if defined(_TTHREAD_WIN32_) -static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) -{ - int result, lastWaiter; +static int _cnd_timedwait_win32(cnd_t *cond, mtx_t *mtx, DWORD timeout) { + int result, lastWaiter; - /* Increment number of waiters */ - EnterCriticalSection(&cond->mWaitersCountLock); - ++ cond->mWaitersCount; - LeaveCriticalSection(&cond->mWaitersCountLock); + /* Increment number of waiters */ + EnterCriticalSection(&cond->mWaitersCountLock); + ++cond->mWaitersCount; + LeaveCriticalSection(&cond->mWaitersCountLock); - /* Release the mutex while waiting for the condition (will decrease - the number of waiters when done)... */ - mtx_unlock(mtx); + /* Release the mutex while waiting for the condition (will decrease + the number of waiters when done)... */ + mtx_unlock(mtx); - /* Wait for either event to become signaled due to cnd_signal() or - cnd_broadcast() being called */ - result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); - if (result == WAIT_TIMEOUT) - { - return thrd_timeout; - } - else if (result == (int)WAIT_FAILED) - { - return thrd_error; - } + /* Wait for either event to become signaled due to cnd_signal() or + cnd_broadcast() being called */ + result = WaitForMultipleObjects(2, cond->mEvents, FALSE, timeout); + if (result == WAIT_TIMEOUT) { + return thrd_timeout; + } else if (result == (int)WAIT_FAILED) { + return thrd_error; + } - /* Check if we are the last waiter */ - EnterCriticalSection(&cond->mWaitersCountLock); - -- cond->mWaitersCount; - lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (cond->mWaitersCount == 0); - LeaveCriticalSection(&cond->mWaitersCountLock); + /* Check if we are the last waiter */ + EnterCriticalSection(&cond->mWaitersCountLock); + --cond->mWaitersCount; + lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && (cond->mWaitersCount == 0); + LeaveCriticalSection(&cond->mWaitersCountLock); - /* If we are the last waiter to be notified to stop waiting, reset the event */ - if (lastWaiter) - { - if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) - { - return thrd_error; + /* If we are the last waiter to be notified to stop waiting, reset the event */ + if (lastWaiter) { + if (ResetEvent(cond->mEvents[_CONDITION_EVENT_ALL]) == 0) { + return thrd_error; + } } - } - /* Re-acquire the mutex */ - mtx_lock(mtx); + /* Re-acquire the mutex */ + mtx_lock(mtx); - return thrd_success; + return thrd_success; } #endif -int cnd_wait(cnd_t *cond, mtx_t *mtx) -{ +int cnd_wait(cnd_t *cond, mtx_t *mtx) { #if defined(_TTHREAD_WIN32_) - return _cnd_timedwait_win32(cond, mtx, INFINITE); + return _cnd_timedwait_win32(cond, mtx, INFINITE); #else - return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; + return pthread_cond_wait(cond, mtx) == 0 ? thrd_success : thrd_error; #endif } -int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) -{ +int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct timespec now; - if (clock_gettime(CLOCK_REALTIME, &now) == 0) - { - DWORD delta = (DWORD) ((ts->tv_sec - now.tv_sec) * 1000 + - (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); - return _cnd_timedwait_win32(cond, mtx, delta); - } - else - return thrd_error; + struct timespec now; + if (clock_gettime(CLOCK_REALTIME, &now) == 0) { + DWORD delta = (DWORD)((ts->tv_sec - now.tv_sec) * 1000 + (ts->tv_nsec - now.tv_nsec + 500000) / 1000000); + return _cnd_timedwait_win32(cond, mtx, delta); + } else + return thrd_error; #else - int ret; - ret = pthread_cond_timedwait(cond, mtx, ts); - if (ret == ETIMEDOUT) - { - return thrd_timeout; - } - return ret == 0 ? thrd_success : thrd_error; + int ret; + ret = pthread_cond_timedwait(cond, mtx, ts); + if (ret == ETIMEDOUT) { + return thrd_timeout; + } + return ret == 0 ? thrd_success : thrd_error; #endif } - /** Information to pass to the new thread (what to run). */ typedef struct { - thrd_start_t mFunction; /**< Pointer to the function to be executed. */ - void * mArg; /**< Function argument for the thread function. */ + thrd_start_t mFunction; /**< Pointer to the function to be executed. */ + void *mArg; /**< Function argument for the thread function. */ } _thread_start_info; /* Thread wrapper function. */ #if defined(_TTHREAD_WIN32_) -static unsigned WINAPI _thrd_wrapper_function(void * aArg) +static unsigned WINAPI _thrd_wrapper_function(void *aArg) #elif defined(_TTHREAD_POSIX_) -static void * _thrd_wrapper_function(void * aArg) +static void *_thrd_wrapper_function(void *aArg) #endif { - thrd_start_t fun; - void *arg; - int res; + thrd_start_t fun; + void *arg; + int res; #if defined(_TTHREAD_POSIX_) - void *pres; + void *pres; #endif - /* Get thread startup information */ - _thread_start_info *ti = (_thread_start_info *) aArg; - fun = ti->mFunction; - arg = ti->mArg; + /* Get thread startup information */ + _thread_start_info *ti = (_thread_start_info *)aArg; + fun = ti->mFunction; + arg = ti->mArg; - /* The thread is responsible for freeing the startup information */ - free((void *)ti); + /* The thread is responsible for freeing the startup information */ + free((void *)ti); - /* Call the actual client thread function */ - res = fun(arg); + /* Call the actual client thread function */ + res = fun(arg); #if defined(_TTHREAD_WIN32_) - return res; + return res; #else - pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - return pres; + pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + return pres; #endif } -int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) -{ - /* Fill out the thread startup information (passed to the thread wrapper, - which will eventually free it) */ - _thread_start_info* ti = (_thread_start_info*)malloc(sizeof(_thread_start_info)); - if (ti == NULL) - { - return thrd_nomem; - } - ti->mFunction = func; - ti->mArg = arg; +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg) { + /* Fill out the thread startup information (passed to the thread wrapper, + which will eventually free it) */ + _thread_start_info *ti = (_thread_start_info *)malloc(sizeof(_thread_start_info)); + if (ti == NULL) { + return thrd_nomem; + } + ti->mFunction = func; + ti->mArg = arg; - /* Create the thread */ + /* Create the thread */ #if defined(_TTHREAD_WIN32_) - *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); + *thr = (HANDLE)_beginthreadex(NULL, 0, _thrd_wrapper_function, (void *)ti, 0, NULL); #elif defined(_TTHREAD_POSIX_) - if(pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) - { - *thr = 0; - } + if (pthread_create(thr, NULL, _thrd_wrapper_function, (void *)ti) != 0) { + *thr = 0; + } #endif - /* Did we fail to create the thread? */ - if(!*thr) - { - free(ti); - return thrd_error; - } + /* Did we fail to create the thread? */ + if (!*thr) { + free(ti); + return thrd_error; + } - return thrd_success; + return thrd_success; } -thrd_t thrd_current(void) -{ +thrd_t thrd_current(void) { #if defined(_TTHREAD_WIN32_) - return GetCurrentThread(); + return GetCurrentThread(); #else - return pthread_self(); + return pthread_self(); #endif } -int thrd_detach(thrd_t thr) -{ - /* FIXME! */ - (void)thr; - return thrd_error; +int thrd_detach(thrd_t thr) { + /* FIXME! */ + (void)thr; + return thrd_error; } -int thrd_equal(thrd_t thr0, thrd_t thr1) -{ +int thrd_equal(thrd_t thr0, thrd_t thr1) { #if defined(_TTHREAD_WIN32_) - return thr0 == thr1; + return thr0 == thr1; #else - return pthread_equal(thr0, thr1); + return pthread_equal(thr0, thr1); #endif } -void thrd_exit(int res) -{ +void thrd_exit(int res) { #if defined(_TTHREAD_WIN32_) - ExitThread(res); + ExitThread(res); #else - void *pres = malloc(sizeof(int)); - if (pres != NULL) - { - *(int*)pres = res; - } - pthread_exit(pres); + void *pres = malloc(sizeof(int)); + if (pres != NULL) { + *(int *)pres = res; + } + pthread_exit(pres); #endif } -int thrd_join(thrd_t thr, int *res) -{ +int thrd_join(thrd_t thr, int *res) { #if defined(_TTHREAD_WIN32_) - if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) - { - return thrd_error; - } - if (res != NULL) - { - DWORD dwRes; - GetExitCodeThread(thr, &dwRes); - *res = dwRes; - } + if (WaitForSingleObject(thr, INFINITE) == WAIT_FAILED) { + return thrd_error; + } + if (res != NULL) { + DWORD dwRes; + GetExitCodeThread(thr, &dwRes); + *res = dwRes; + } #elif defined(_TTHREAD_POSIX_) - void *pres; - int ires = 0; - if (pthread_join(thr, &pres) != 0) - { - return thrd_error; - } - if (pres != NULL) - { - ires = *(int*)pres; - free(pres); - } - if (res != NULL) - { - *res = ires; - } + void *pres; + int ires = 0; + if (pthread_join(thr, &pres) != 0) { + return thrd_error; + } + if (pres != NULL) { + ires = *(int *)pres; + free(pres); + } + if (res != NULL) { + *res = ires; + } #endif - return thrd_success; + return thrd_success; } -int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) -{ - struct timespec now; +int thrd_sleep(const struct timespec *time_point, struct timespec *remaining) { + struct timespec now; #if defined(_TTHREAD_WIN32_) - DWORD delta; + DWORD delta; #else - long delta; + long delta; #endif - /* Get the current time */ - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return -2; // FIXME: Some specific error code? + /* Get the current time */ + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return -2; // FIXME: Some specific error code? #if defined(_TTHREAD_WIN32_) - /* Delta in milliseconds */ - delta = (DWORD) ((time_point->tv_sec - now.tv_sec) * 1000 + - (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); - if (delta > 0) - { - Sleep(delta); - } + /* Delta in milliseconds */ + delta = (DWORD)((time_point->tv_sec - now.tv_sec) * 1000 + (time_point->tv_nsec - now.tv_nsec + 500000) / 1000000); + if (delta > 0) { + Sleep(delta); + } #else - /* Delta in microseconds */ - delta = (time_point->tv_sec - now.tv_sec) * 1000000L + - (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; + /* Delta in microseconds */ + delta = (time_point->tv_sec - now.tv_sec) * 1000000L + (time_point->tv_nsec - now.tv_nsec + 500L) / 1000L; - /* On some systems, the usleep argument must be < 1000000 */ - while (delta > 999999L) - { - usleep(999999); - delta -= 999999L; - } - if (delta > 0L) - { - usleep((useconds_t)delta); - } + /* On some systems, the usleep argument must be < 1000000 */ + while (delta > 999999L) { + usleep(999999); + delta -= 999999L; + } + if (delta > 0L) { + usleep((useconds_t)delta); + } #endif - /* We don't support waking up prematurely (yet) */ - if (remaining) - { - remaining->tv_sec = 0; - remaining->tv_nsec = 0; - } - return 0; + /* We don't support waking up prematurely (yet) */ + if (remaining) { + remaining->tv_sec = 0; + remaining->tv_nsec = 0; + } + return 0; } -void thrd_yield(void) -{ +void thrd_yield(void) { #if defined(_TTHREAD_WIN32_) - Sleep(0); + Sleep(0); #else - sched_yield(); + sched_yield(); #endif } -int tss_create(tss_t *key, tss_dtor_t dtor) -{ +int tss_create(tss_t *key, tss_dtor_t dtor) { #if defined(_TTHREAD_WIN32_) - /* FIXME: The destructor function is not supported yet... */ - if (dtor != NULL) - { - return thrd_error; - } - *key = TlsAlloc(); - if (*key == TLS_OUT_OF_INDEXES) - { - return thrd_error; - } + /* FIXME: The destructor function is not supported yet... */ + if (dtor != NULL) { + return thrd_error; + } + *key = TlsAlloc(); + if (*key == TLS_OUT_OF_INDEXES) { + return thrd_error; + } #else - if (pthread_key_create(key, dtor) != 0) - { - return thrd_error; - } + if (pthread_key_create(key, dtor) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } -void tss_delete(tss_t key) -{ +void tss_delete(tss_t key) { #if defined(_TTHREAD_WIN32_) - TlsFree(key); + TlsFree(key); #else - pthread_key_delete(key); + pthread_key_delete(key); #endif } -void *tss_get(tss_t key) -{ +void *tss_get(tss_t key) { #if defined(_TTHREAD_WIN32_) - return TlsGetValue(key); + return TlsGetValue(key); #else - return pthread_getspecific(key); + return pthread_getspecific(key); #endif } -int tss_set(tss_t key, void *val) -{ +int tss_set(tss_t key, void *val) { #if defined(_TTHREAD_WIN32_) - if (TlsSetValue(key, val) == 0) - { - return thrd_error; - } + if (TlsSetValue(key, val) == 0) { + return thrd_error; + } #else - if (pthread_setspecific(key, val) != 0) - { - return thrd_error; - } + if (pthread_setspecific(key, val) != 0) { + return thrd_error; + } #endif - return thrd_success; + return thrd_success; } #if defined(_TTHREAD_EMULATE_CLOCK_GETTIME_) -int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) -{ +int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts) { #if defined(_TTHREAD_WIN32_) - struct _timeb tb; - _ftime(&tb); - ts->tv_sec = (time_t)tb.time; - ts->tv_nsec = 1000000L * (long)tb.millitm; + struct _timeb tb; + _ftime(&tb); + ts->tv_sec = (time_t)tb.time; + ts->tv_nsec = 1000000L * (long)tb.millitm; #else - struct timeval tv; - gettimeofday(&tv, NULL); - ts->tv_sec = (time_t)tv.tv_sec; - ts->tv_nsec = 1000L * (long)tv.tv_usec; + struct timeval tv; + gettimeofday(&tv, NULL); + ts->tv_sec = (time_t)tv.tv_sec; + ts->tv_nsec = 1000L * (long)tv.tv_usec; #endif - return 0; + return 0; } #endif // _TTHREAD_EMULATE_CLOCK_GETTIME_ - diff --git a/src/deps/tinycthread.h b/src/deps/tinycthread.h index 42958c3..eaacfbe 100644 --- a/src/deps/tinycthread.h +++ b/src/deps/tinycthread.h @@ -25,52 +25,52 @@ freely, subject to the following restrictions: #define _TINYCTHREAD_H_ /** -* @file -* @mainpage TinyCThread API Reference -* -* @section intro_sec Introduction -* TinyCThread is a minimal, portable implementation of basic threading -* classes for C. -* -* They closely mimic the functionality and naming of the C11 standard, and -* should be easily replaceable with the corresponding standard variants. -* -* @section port_sec Portability -* The Win32 variant uses the native Win32 API for implementing the thread -* classes, while for other systems, the POSIX threads API (pthread) is used. -* -* @section misc_sec Miscellaneous -* The following special keywords are available: #_Thread_local. -* -* For more detailed information, browse the different sections of this -* documentation. A good place to start is: -* tinycthread.h. -*/ + * @file + * @mainpage TinyCThread API Reference + * + * @section intro_sec Introduction + * TinyCThread is a minimal, portable implementation of basic threading + * classes for C. + * + * They closely mimic the functionality and naming of the C11 standard, and + * should be easily replaceable with the corresponding standard variants. + * + * @section port_sec Portability + * The Win32 variant uses the native Win32 API for implementing the thread + * classes, while for other systems, the POSIX threads API (pthread) is used. + * + * @section misc_sec Miscellaneous + * The following special keywords are available: #_Thread_local. + * + * For more detailed information, browse the different sections of this + * documentation. A good place to start is: + * tinycthread.h. + */ /* Which platform are we on? */ #if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ +#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) +#define _TTHREAD_WIN32_ +#else +#define _TTHREAD_POSIX_ +#endif +#define _TTHREAD_PLATFORM_DEFINED_ #endif /* Activate some POSIX functionality (e.g. clock_gettime and recursive mutexes) */ #if defined(_TTHREAD_POSIX_) - #undef _FEATURES_H - #if !defined(_GNU_SOURCE) - #define _GNU_SOURCE - #endif - #if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) - #undef _POSIX_C_SOURCE - #define _POSIX_C_SOURCE 199309L - #endif - #if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) - #undef _XOPEN_SOURCE - #define _XOPEN_SOURCE 500 - #endif +#undef _FEATURES_H +#if !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif +#if !defined(_POSIX_C_SOURCE) || ((_POSIX_C_SOURCE - 0) < 199309L) +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 199309L +#endif +#if !defined(_XOPEN_SOURCE) || ((_XOPEN_SOURCE - 0) < 500) +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif #endif /* Generic includes */ @@ -78,18 +78,18 @@ freely, subject to the following restrictions: /* Platform specific includes */ #if defined(_TTHREAD_POSIX_) - #include <sys/time.h> - #include <pthread.h> +#include <sys/time.h> +#include <pthread.h> #elif defined(_TTHREAD_WIN32_) - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include <windows.h> - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define __UNDEF_LEAN_AND_MEAN +#endif +#include <windows.h> +#ifdef __UNDEF_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#undef __UNDEF_LEAN_AND_MEAN +#endif #endif /* Workaround for missing TIME_UTC: If time.h doesn't provide TIME_UTC, @@ -97,11 +97,11 @@ freely, subject to the following restrictions: the only other supported time specifier: CLOCK_REALTIME (and if that fails, we're probably emulating clock_gettime anyway, so anything goes). */ #ifndef TIME_UTC - #ifdef CLOCK_REALTIME - #define TIME_UTC CLOCK_REALTIME - #else - #define TIME_UTC 0 - #endif +#ifdef CLOCK_REALTIME +#define TIME_UTC CLOCK_REALTIME +#else +#define TIME_UTC 0 +#endif #endif /* Workaround for missing clock_gettime (most Windows compilers, afaik) */ @@ -110,8 +110,8 @@ freely, subject to the following restrictions: /* Emulate struct timespec */ #if defined(_TTHREAD_WIN32_) struct _ttherad_timespec { - time_t tv_sec; - long tv_nsec; + time_t tv_sec; + long tv_nsec; }; #define timespec _ttherad_timespec #endif @@ -124,11 +124,10 @@ typedef int _tthread_clockid_t; int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define clock_gettime _tthread_clock_gettime #ifndef CLOCK_REALTIME - #define CLOCK_REALTIME 0 +#define CLOCK_REALTIME 0 #endif #endif - /** TinyCThread version (major number). */ #define TINYCTHREAD_VERSION_MAJOR 1 /** TinyCThread version (minor number). */ @@ -137,42 +136,44 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); #define TINYCTHREAD_VERSION (TINYCTHREAD_VERSION_MAJOR * 100 + TINYCTHREAD_VERSION_MINOR) /** -* @def _Thread_local -* Thread local storage keyword. -* A variable that is declared with the @c _Thread_local keyword makes the -* value of the variable local to each thread (known as thread-local storage, -* or TLS). Example usage: -* @code -* // This variable is local to each thread. -* _Thread_local int variable; -* @endcode -* @note The @c _Thread_local keyword is a macro that maps to the corresponding -* compiler directive (e.g. @c __declspec(thread)). -* @note This directive is currently not supported on Mac OS X (it will give -* a compiler error), since compile-time TLS is not supported in the Mac OS X -* executable format. Also, some older versions of MinGW (before GCC 4.x) do -* not support this directive. -* @hideinitializer -*/ + * @def _Thread_local + * Thread local storage keyword. + * A variable that is declared with the @c _Thread_local keyword makes the + * value of the variable local to each thread (known as thread-local storage, + * or TLS). Example usage: + * @code + * // This variable is local to each thread. + * _Thread_local int variable; + * @endcode + * @note The @c _Thread_local keyword is a macro that maps to the corresponding + * compiler directive (e.g. @c __declspec(thread)). + * @note This directive is currently not supported on Mac OS X (it will give + * a compiler error), since compile-time TLS is not supported in the Mac OS X + * executable format. Also, some older versions of MinGW (before GCC 4.x) do + * not support this directive. + * @hideinitializer + */ /* FIXME: Check for a PROPER value of __STDC_VERSION__ to know if we have C11 */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201102L)) && !defined(_Thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define _Thread_local __thread - #else - #define _Thread_local __declspec(thread) - #endif +#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +#define _Thread_local __thread +#else +#define _Thread_local __declspec(thread) +#endif #endif /* Macros */ #define TSS_DTOR_ITERATIONS 0 /* Function return values */ -#define thrd_error 0 /**< The requested operation failed */ -#define thrd_success 1 /**< The requested operation succeeded */ -#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ -#define thrd_busy 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use */ -#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ +#define thrd_error 0 /**< The requested operation failed */ +#define thrd_success 1 /**< The requested operation succeeded */ +#define thrd_timeout 2 /**< The time specified in the call was reached without acquiring the requested resource */ +#define thrd_busy \ + 3 /**< The requested operation failed because a tesource requested by a test and return function is already in use \ + */ +#define thrd_nomem 4 /**< The requested operation failed because it was unable to allocate memory */ /* Mutex types */ #define mtx_plain 1 @@ -183,261 +184,259 @@ int _tthread_clock_gettime(clockid_t clk_id, struct timespec *ts); /* Mutex */ #if defined(_TTHREAD_WIN32_) typedef struct { - CRITICAL_SECTION mHandle; /* Critical section handle */ - int mAlreadyLocked; /* TRUE if the mutex is already locked */ - int mRecursive; /* TRUE if the mutex is recursive */ + CRITICAL_SECTION mHandle; /* Critical section handle */ + int mAlreadyLocked; /* TRUE if the mutex is already locked */ + int mRecursive; /* TRUE if the mutex is recursive */ } mtx_t; #else typedef pthread_mutex_t mtx_t; #endif /** Create a mutex object. -* @param mtx A mutex object. -* @param type Bit-mask that must have one of the following six values: -* @li @c mtx_plain for a simple non-recursive mutex -* @li @c mtx_timed for a non-recursive mutex that supports timeout -* @li @c mtx_try for a non-recursive mutex that supports test and return -* @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) -* @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) -* @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @param type Bit-mask that must have one of the following six values: + * @li @c mtx_plain for a simple non-recursive mutex + * @li @c mtx_timed for a non-recursive mutex that supports timeout + * @li @c mtx_try for a non-recursive mutex that supports test and return + * @li @c mtx_plain | @c mtx_recursive (same as @c mtx_plain, but recursive) + * @li @c mtx_timed | @c mtx_recursive (same as @c mtx_timed, but recursive) + * @li @c mtx_try | @c mtx_recursive (same as @c mtx_try, but recursive) + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_init(mtx_t *mtx, int type); /** Release any resources used by the given mutex. -* @param mtx A mutex object. -*/ + * @param mtx A mutex object. + */ void mtx_destroy(mtx_t *mtx); /** Lock the given mutex. -* Blocks until the given mutex can be locked. If the mutex is non-recursive, and -* the calling thread already has a lock on the mutex, this call will block -* forever. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Blocks until the given mutex can be locked. If the mutex is non-recursive, and + * the calling thread already has a lock on the mutex, this call will block + * forever. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_lock(mtx_t *mtx); /** NOT YET IMPLEMENTED. -*/ + */ int mtx_timedlock(mtx_t *mtx, const struct timespec *ts); /** Try to lock the given mutex. -* The specified mutex shall support either test and return or timeout. If the -* mutex is already locked, the function returns without blocking. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_busy if the resource -* requested is already in use, or @ref thrd_error if the request could not be -* honored. -*/ + * The specified mutex shall support either test and return or timeout. If the + * mutex is already locked, the function returns without blocking. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_busy if the resource + * requested is already in use, or @ref thrd_error if the request could not be + * honored. + */ int mtx_trylock(mtx_t *mtx); /** Unlock the given mutex. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int mtx_unlock(mtx_t *mtx); /* Condition variable */ #if defined(_TTHREAD_WIN32_) typedef struct { - HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ - unsigned int mWaitersCount; /* Count of the number of waiters. */ - CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ + HANDLE mEvents[2]; /* Signal and broadcast event HANDLEs. */ + unsigned int mWaitersCount; /* Count of the number of waiters. */ + CRITICAL_SECTION mWaitersCountLock; /* Serialize access to mWaitersCount. */ } cnd_t; #else -typedef pthread_cond_t cnd_t; +typedef pthread_cond_t cnd_t; #endif /** Create a condition variable object. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_init(cnd_t *cond); /** Release any resources used by the given condition variable. -* @param cond A condition variable object. -*/ + * @param cond A condition variable object. + */ void cnd_destroy(cnd_t *cond); /** Signal a condition variable. -* Unblocks one of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks one of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_signal(cnd_t *cond); /** Broadcast a condition variable. -* Unblocks all of the threads that are blocked on the given condition variable -* at the time of the call. If no threads are blocked on the condition variable -* at the time of the call, the function does nothing and return success. -* @param cond A condition variable object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * Unblocks all of the threads that are blocked on the given condition variable + * at the time of the call. If no threads are blocked on the condition variable + * at the time of the call, the function does nothing and return success. + * @param cond A condition variable object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_broadcast(cnd_t *cond); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast. When the calling thread becomes unblocked it locks the mutex -* before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast. When the calling thread becomes unblocked it locks the mutex + * before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int cnd_wait(cnd_t *cond, mtx_t *mtx); /** Wait for a condition variable to become signaled. -* The function atomically unlocks the given mutex and endeavors to block until -* the given condition variable is signaled by a call to cnd_signal or to -* cnd_broadcast, or until after the specified time. When the calling thread -* becomes unblocked it locks the mutex before it returns. -* @param cond A condition variable object. -* @param mtx A mutex object. -* @param xt A point in time at which the request will time out (absolute time). -* @return @ref thrd_success upon success, or @ref thrd_timeout if the time -* specified in the call was reached without acquiring the requested resource, or -* @ref thrd_error if the request could not be honored. -*/ + * The function atomically unlocks the given mutex and endeavors to block until + * the given condition variable is signaled by a call to cnd_signal or to + * cnd_broadcast, or until after the specified time. When the calling thread + * becomes unblocked it locks the mutex before it returns. + * @param cond A condition variable object. + * @param mtx A mutex object. + * @param xt A point in time at which the request will time out (absolute time). + * @return @ref thrd_success upon success, or @ref thrd_timeout if the time + * specified in the call was reached without acquiring the requested resource, or + * @ref thrd_error if the request could not be honored. + */ int cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts); /* Thread */ #if defined(_TTHREAD_WIN32_) typedef HANDLE thrd_t; #else -typedef pthread_t thrd_t; +typedef pthread_t thrd_t; #endif /** Thread start function. -* Any thread that is started with the @ref thrd_create() function must be -* started through a function of this type. -* @param arg The thread argument (the @c arg argument of the corresponding -* @ref thrd_create() call). -* @return The thread return value, which can be obtained by another thread -* by using the @ref thrd_join() function. -*/ + * Any thread that is started with the @ref thrd_create() function must be + * started through a function of this type. + * @param arg The thread argument (the @c arg argument of the corresponding + * @ref thrd_create() call). + * @return The thread return value, which can be obtained by another thread + * by using the @ref thrd_join() function. + */ typedef int (*thrd_start_t)(void *arg); /** Create a new thread. -* @param thr Identifier of the newly created thread. -* @param func A function pointer to the function that will be executed in -* the new thread. -* @param arg An argument to the thread function. -* @return @ref thrd_success on success, or @ref thrd_nomem if no memory could -* be allocated for the thread requested, or @ref thrd_error if the request -* could not be honored. -* @note A thread’s identifier may be reused for a different thread once the -* original thread has exited and either been detached or joined to another -* thread. -*/ + * @param thr Identifier of the newly created thread. + * @param func A function pointer to the function that will be executed in + * the new thread. + * @param arg An argument to the thread function. + * @return @ref thrd_success on success, or @ref thrd_nomem if no memory could + * be allocated for the thread requested, or @ref thrd_error if the request + * could not be honored. + * @note A thread’s identifier may be reused for a different thread once the + * original thread has exited and either been detached or joined to another + * thread. + */ int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); /** Identify the calling thread. -* @return The identifier of the calling thread. -*/ + * @return The identifier of the calling thread. + */ thrd_t thrd_current(void); /** NOT YET IMPLEMENTED. -*/ + */ int thrd_detach(thrd_t thr); /** Compare two thread identifiers. -* The function determines if two thread identifiers refer to the same thread. -* @return Zero if the two thread identifiers refer to different threads. -* Otherwise a nonzero value is returned. -*/ + * The function determines if two thread identifiers refer to the same thread. + * @return Zero if the two thread identifiers refer to different threads. + * Otherwise a nonzero value is returned. + */ int thrd_equal(thrd_t thr0, thrd_t thr1); /** Terminate execution of the calling thread. -* @param res Result code of the calling thread. -*/ + * @param res Result code of the calling thread. + */ void thrd_exit(int res); /** Wait for a thread to terminate. -* The function joins the given thread with the current thread by blocking -* until the other thread has terminated. -* @param thr The thread to join with. -* @param res If this pointer is not NULL, the function will store the result -* code of the given thread in the integer pointed to by @c res. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * The function joins the given thread with the current thread by blocking + * until the other thread has terminated. + * @param thr The thread to join with. + * @param res If this pointer is not NULL, the function will store the result + * code of the given thread in the integer pointed to by @c res. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int thrd_join(thrd_t thr, int *res); /** Put the calling thread to sleep. -* Suspend execution of the calling thread. -* @param time_point A point in time at which the thread will resume (absolute time). -* @param remaining If non-NULL, this parameter will hold the remaining time until -* time_point upon return. This will typically be zero, but if -* the thread was woken up by a signal that is not ignored before -* time_point was reached @c remaining will hold a positive -* time. -* @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. -*/ + * Suspend execution of the calling thread. + * @param time_point A point in time at which the thread will resume (absolute time). + * @param remaining If non-NULL, this parameter will hold the remaining time until + * time_point upon return. This will typically be zero, but if + * the thread was woken up by a signal that is not ignored before + * time_point was reached @c remaining will hold a positive + * time. + * @return 0 (zero) on successful sleep, or -1 if an interrupt occurred. + */ int thrd_sleep(const struct timespec *time_point, struct timespec *remaining); /** Yield execution to another thread. -* Permit other threads to run, even if the current thread would ordinarily -* continue to run. -*/ + * Permit other threads to run, even if the current thread would ordinarily + * continue to run. + */ void thrd_yield(void); /* Thread local storage */ #if defined(_TTHREAD_WIN32_) typedef DWORD tss_t; #else -typedef pthread_key_t tss_t; +typedef pthread_key_t tss_t; #endif /** Destructor function for a thread-specific storage. -* @param val The value of the destructed thread-specific storage. -*/ + * @param val The value of the destructed thread-specific storage. + */ typedef void (*tss_dtor_t)(void *val); /** Create a thread-specific storage. -* @param key The unique key identifier that will be set if the function is -* successful. -* @param dtor Destructor function. This can be NULL. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -* @note The destructor function is not supported under Windows. If @c dtor is -* not NULL when calling this function under Windows, the function will fail -* and return @ref thrd_error. -*/ + * @param key The unique key identifier that will be set if the function is + * successful. + * @param dtor Destructor function. This can be NULL. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + * @note The destructor function is not supported under Windows. If @c dtor is + * not NULL when calling this function under Windows, the function will fail + * and return @ref thrd_error. + */ int tss_create(tss_t *key, tss_dtor_t dtor); /** Delete a thread-specific storage. -* The function releases any resources used by the given thread-specific -* storage. -* @param key The key that shall be deleted. -*/ + * The function releases any resources used by the given thread-specific + * storage. + * @param key The key that shall be deleted. + */ void tss_delete(tss_t key); /** Get the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @return The value for the current thread held in the given thread-specific -* storage. -*/ + * @param key The thread-specific storage identifier. + * @return The value for the current thread held in the given thread-specific + * storage. + */ void *tss_get(tss_t key); /** Set the value for a thread-specific storage. -* @param key The thread-specific storage identifier. -* @param val The value of the thread-specific storage to set for the current -* thread. -* @return @ref thrd_success on success, or @ref thrd_error if the request could -* not be honored. -*/ + * @param key The thread-specific storage identifier. + * @param val The value of the thread-specific storage to set for the current + * thread. + * @return @ref thrd_success on success, or @ref thrd_error if the request could + * not be honored. + */ int tss_set(tss_t key, void *val); - #endif /* _TINYTHREAD_H_ */ - diff --git a/src/nsvg/nanosvg.h b/src/nsvg/nanosvg.h index 809bc87..5f6951b 100644 --- a/src/nsvg/nanosvg.h +++ b/src/nsvg/nanosvg.h @@ -27,7 +27,6 @@ * */ - #ifndef NANOSVG_H #define NANOSVG_H @@ -54,128 +53,107 @@ extern "C" { // // If you don't know or care about the units stuff, "px" and 96 should get you going. - /* Example Usage: - // Load SVG - NSVGimage* image; - image = nsvgParseFromFile("test.svg", "px", 96); - printf("size: %f x %f\n", image->width, image->height); - // Use... - for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { - for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { - for (int i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); - } - } - } - // Delete - nsvgDelete(image); + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); */ enum NSVGpaintType { - NSVG_PAINT_NONE = 0, - NSVG_PAINT_COLOR = 1, - NSVG_PAINT_LINEAR_GRADIENT = 2, - NSVG_PAINT_RADIAL_GRADIENT = 3 + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 }; -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2 -}; +enum NSVGspreadType { NSVG_SPREAD_PAD = 0, NSVG_SPREAD_REFLECT = 1, NSVG_SPREAD_REPEAT = 2 }; -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2 -}; +enum NSVGlineJoin { NSVG_JOIN_MITER = 0, NSVG_JOIN_ROUND = 1, NSVG_JOIN_BEVEL = 2 }; -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2 -}; +enum NSVGlineCap { NSVG_CAP_BUTT = 0, NSVG_CAP_ROUND = 1, NSVG_CAP_SQUARE = 2 }; -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1 -}; +enum NSVGfillRule { NSVG_FILLRULE_NONZERO = 0, NSVG_FILLRULE_EVENODD = 1 }; -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; +enum NSVGflags { NSVG_FLAGS_VISIBLE = 0x01 }; typedef struct NSVGgradientStop { - unsigned int color; - float offset; + unsigned int color; + float offset; } NSVGgradientStop; typedef struct NSVGgradient { - float xform[6]; - char spread; - float fx, fy; - int nstops; - NSVGgradientStop stops[1]; + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; } NSVGgradient; typedef struct NSVGpaint { - char type; - union { - unsigned int color; - NSVGgradient* gradient; - }; + char type; + union { + unsigned int color; + NSVGgradient *gradient; + }; } NSVGpaint; -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. +typedef struct NSVGpath { + float *pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath *next; // Pointer to next path, or NULL if last element. } NSVGpath; -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - float miterLimit; // Miter limit - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +typedef struct NSVGshape { + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + NSVGpath *paths; // Linked list of paths in the image. + struct NSVGshape *next; // Pointer to next shape, or NULL if last element. } NSVGshape; -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. - NSVGshape* shapes; // Linked list of shapes in the image. +typedef struct NSVGimage { + float width; // Width of the image. + float height; // Height of the image. + NSVGshape *shapes; // Linked list of shapes in the image. } NSVGimage; // Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi); // Parses SVG file from a null terminated string, returns SVG image as paths. // Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); +NSVGimage *nsvgParse(char *input, const char *units, float dpi); // Duplicates a path. -NSVGpath* nsvgDuplicatePath(NSVGpath* p); +NSVGpath *nsvgDuplicatePath(NSVGpath *p); // Deletes an image. -void nsvgDelete(NSVGimage* image); +void nsvgDelete(NSVGimage *image); #ifndef NANOSVG_CPLUSPLUS #ifdef __cplusplus @@ -191,2817 +169,2827 @@ void nsvgDelete(NSVGimage* image); #include <stdlib.h> #include <math.h> -#define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. -#define NSVG_ALIGN_MIN 0 -#define NSVG_ALIGN_MID 1 -#define NSVG_ALIGN_MAX 2 -#define NSVG_ALIGN_NONE 0 -#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 #define NSVG_ALIGN_SLICE 2 -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_NOTUSED(v) \ + do { \ + (void)(1 ? (void)0 : ((void)(v))); \ + } while (0) #define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) #ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif +#pragma warning(disable : 4996) // Switch off security warnings +#pragma warning(disable : 4100) // Switch off unreferenced formal parameter warnings +#ifdef __cplusplus +#define NSVG_INLINE inline +#else +#define NSVG_INLINE +#endif #else - #define NSVG_INLINE inline +#define NSVG_INLINE inline #endif #ifndef NANOSVG_DEBUG #define NANOSVG_DEBUG(...) -//#define NANOSVG_DEBUG printf +// #define NANOSVG_DEBUG printf #endif -static int nsvg__isspace(char c) -{ - return strchr(" \t\n\v\f\r", c) != 0; -} +static int nsvg__isspace(char c) { return strchr(" \t\n\v\f\r", c) != 0; } -static int nsvg__isdigit(char c) -{ - return c >= '0' && c <= '9'; -} +static int nsvg__isdigit(char c) { return c >= '0' && c <= '9'; } -static int nsvg__isnum(char c) -{ - return strchr("0123456789+-.eE", c) != 0; -} +static int nsvg__isnum(char c) { return strchr("0123456789+-.eE", c) != 0; } static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - // Simple XML parser -#define NSVG_XML_TAG 1 -#define NSVG_XML_CONTENT 2 +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 #define NSVG_XML_MAX_ATTRIBS 256 -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - // Trim start white spaces - while (nsvg__isspace(*s)) s++; - if (!*s) return; +static void nsvg__parseContent(char *s, void (*contentCb)(void *ud, const char *s), void *ud) { + // Trim start white spaces + while (nsvg__isspace(*s)) + s++; + if (!*s) + return; - if (contentCb) - (*contentCb)(ud, s); + if (contentCb) + (*contentCb)(ud, s); } -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) -{ - const char* attr[NSVG_XML_MAX_ATTRIBS]; - int nattr = 0; - char* name; - int start = 0; - int end = 0; - char quote; +static void nsvg__parseElement(char *s, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void *ud) { + const char *attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char *name; + int start = 0; + int end = 0; + char quote; - // Skip white space after the '<' - while (nsvg__isspace(*s)) s++; + // Skip white space after the '<' + while (nsvg__isspace(*s)) + s++; - // Check if the tag is end tag - if (*s == '/') { - s++; - end = 1; - } else { - start = 1; - } + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } - // Skip comments, data and preprocessor stuff. - if (!*s || *s == '?' || *s == '!') - return; + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; - // Get tag name - name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) + s++; + if (*s) { + *s++ = '\0'; + } - // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - char* name = NULL; - char* value = NULL; + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS - 3) { + char *name = NULL; + char *value = NULL; - // Skip white space before the attrib name - while (nsvg__isspace(*s)) s++; - if (!*s) break; - if (*s == '/') { - end = 1; - break; - } - name = s; - // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } - // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; - quote = *s; - s++; - // Store value and find the end of it. - value = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } + // Skip white space before the attrib name + while (nsvg__isspace(*s)) + s++; + if (!*s) + break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') + s++; + if (*s) { + *s++ = '\0'; + } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') + s++; + if (!*s) + break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) + s++; + if (*s) { + *s++ = '\0'; + } - // Store only well formed attributes - if (name && value) { - attr[nattr++] = name; - attr[nattr++] = value; - } - } + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } - // List terminator - attr[nattr++] = 0; - attr[nattr++] = 0; + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; - // Call callbacks. - if (start && startelCb) - (*startelCb)(ud, name, attr); - if (end && endelCb) - (*endelCb)(ud, name); + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); } -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - char* s = input; - char* mark = s; - int state = NSVG_XML_CONTENT; - while (*s) { - if (*s == '<' && state == NSVG_XML_CONTENT) { - // Start of a tag - *s++ = '\0'; - nsvg__parseContent(mark, contentCb, ud); - mark = s; - state = NSVG_XML_TAG; - } else if (*s == '>' && state == NSVG_XML_TAG) { - // Start of a content or new tag. - *s++ = '\0'; - nsvg__parseElement(mark, startelCb, endelCb, ud); - mark = s; - state = NSVG_XML_CONTENT; - } else { - s++; - } - } +int nsvg__parseXML(char *input, void (*startelCb)(void *ud, const char *el, const char **attr), + void (*endelCb)(void *ud, const char *el), void (*contentCb)(void *ud, const char *s), void *ud) { + char *s = input; + char *mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } - return 1; + return 1; } - /* Simple SVG parser. */ #define NSVG_MAX_ATTR 128 -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1 -}; +enum NSVGgradientUnits { NSVG_USER_SPACE = 0, NSVG_OBJECT_SPACE = 1 }; #define NSVG_MAX_DASHES 8 enum NSVGunits { - NSVG_UNITS_USER, - NSVG_UNITS_PX, - NSVG_UNITS_PT, - NSVG_UNITS_PC, - NSVG_UNITS_MM, - NSVG_UNITS_CM, - NSVG_UNITS_IN, - NSVG_UNITS_PERCENT, - NSVG_UNITS_EM, - NSVG_UNITS_EX + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX }; typedef struct NSVGcoordinate { - float value; - int units; + float value; + int units; } NSVGcoordinate; typedef struct NSVGlinearData { - NSVGcoordinate x1, y1, x2, y2; + NSVGcoordinate x1, y1, x2, y2; } NSVGlinearData; typedef struct NSVGradialData { - NSVGcoordinate cx, cy, r, fx, fy; + NSVGcoordinate cx, cy, r, fx, fy; } NSVGradialData; -typedef struct NSVGgradientData -{ - char id[64]; - char ref[64]; - char type; - union { - NSVGlinearData linear; - NSVGradialData radial; - }; - char spread; - char units; - float xform[6]; - int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; +typedef struct NSVGgradientData { + char id[64]; + char ref[64]; + char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop *stops; + struct NSVGgradientData *next; } NSVGgradientData; -typedef struct NSVGattrib -{ - char id[64]; - float xform[6]; - unsigned int fillColor; - unsigned int strokeColor; - float opacity; - float fillOpacity; - float strokeOpacity; - char fillGradient[64]; - char strokeGradient[64]; - float strokeWidth; - float strokeDashOffset; - float strokeDashArray[NSVG_MAX_DASHES]; - int strokeDashCount; - char strokeLineJoin; - char strokeLineCap; - float miterLimit; - char fillRule; - float fontSize; - unsigned int stopColor; - float stopOpacity; - float stopOffset; - char hasFill; - char hasStroke; - char visible; +typedef struct NSVGattrib { + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; } NSVGattrib; -typedef struct NSVGparser -{ - NSVGattrib attr[NSVG_MAX_ATTR]; - int attrHead; - float* pts; - int npts; - int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - NSVGshape* shapesTail; - float viewMinx, viewMiny, viewWidth, viewHeight; - int alignX, alignY, alignType; - float dpi; - char pathFlag; - char defsFlag; +typedef struct NSVGparser { + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float *pts; + int npts; + int cpts; + NSVGpath *plist; + NSVGimage *image; + NSVGgradientData *gradients; + NSVGshape *shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; } NSVGparser; -static void nsvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; +static void nsvg__xformIdentity(float *t) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetTranslation(float* t, float tx, float ty) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; +static void nsvg__xformSetTranslation(float *t, float tx, float ty) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = tx; + t[5] = ty; } -static void nsvg__xformSetScale(float* t, float sx, float sy) -{ - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; +static void nsvg__xformSetScale(float *t, float sx, float sy) { + t[0] = sx; + t[1] = 0.0f; + t[2] = 0.0f; + t[3] = sy; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetSkewX(float* t, float a) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; +static void nsvg__xformSetSkewX(float *t, float a) { + t[0] = 1.0f; + t[1] = 0.0f; + t[2] = tanf(a); + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetSkewY(float* t, float a) -{ - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; +static void nsvg__xformSetSkewY(float *t, float a) { + t[0] = 1.0f; + t[1] = tanf(a); + t[2] = 0.0f; + t[3] = 1.0f; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformSetRotation(float* t, float a) -{ - float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; +static void nsvg__xformSetRotation(float *t, float a) { + float cs = cosf(a), sn = sinf(a); + t[0] = cs; + t[1] = sn; + t[2] = -sn; + t[3] = cs; + t[4] = 0.0f; + t[5] = 0.0f; } -static void nsvg__xformMultiply(float* t, float* s) -{ - float t0 = t[0] * s[0] + t[1] * s[2]; - float t2 = t[2] * s[0] + t[3] * s[2]; - float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; - t[1] = t[0] * s[1] + t[1] * s[3]; - t[3] = t[2] * s[1] + t[3] * s[3]; - t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; - t[0] = t0; - t[2] = t2; - t[4] = t4; +static void nsvg__xformMultiply(float *t, float *s) { + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; } -static void nsvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - nsvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +static void nsvg__xformInverse(float *inv, float *t) { + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); } -static void nsvg__xformPremultiply(float* t, float* s) -{ - float s2[6]; - memcpy(s2, s, sizeof(float)*6); - nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); +static void nsvg__xformPremultiply(float *t, float *s) { + float s2[6]; + memcpy(s2, s, sizeof(float) * 6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float) * 6); } -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; +static void nsvg__xformPoint(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2] + t[4]; + *dy = x * t[1] + y * t[3] + t[5]; } -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; +static void nsvg__xformVec(float *dx, float *dy, float x, float y, float *t) { + *dx = x * t[0] + y * t[2]; + *dy = x * t[1] + y * t[3]; } #define NSVG_EPSILON (1e-12) -static int nsvg__ptInBounds(float* pt, float* bounds) -{ - return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +static int nsvg__ptInBounds(float *pt, float *bounds) { + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; } - -static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) -{ - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) { + double it = 1.0 - t; + return it * it * it * p0 + 3.0 * it * it * t * p1 + 3.0 * it * t * t * p2 + t * t * t * p3; } -static void nsvg__curveBounds(float* bounds, float* curve) -{ - int i, j, count; - double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; +static void nsvg__curveBounds(float *bounds, float *curve) { + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float *v0 = &curve[0]; + float *v1 = &curve[2]; + float *v2 = &curve[4]; + float *v3 = &curve[6]; - // Start the bounding box by end points - bounds[0] = nsvg__minf(v0[0], v3[0]); - bounds[1] = nsvg__minf(v0[1], v3[1]); - bounds[2] = nsvg__maxf(v0[0], v3[0]); - bounds[3] = nsvg__maxf(v0[1], v3[1]); + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); - // Bezier curve fits inside the convex hull of it's control points. - // If control points are inside the bounds, we're done. - if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) - return; + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; - // Add bezier curve inflection points in X and Y. - for (i = 0; i < 2; i++) { - a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; - b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; - c = 3.0 * v1[i] - 3.0 * v0[i]; - count = 0; - if (fabs(a) < NSVG_EPSILON) { - if (fabs(b) > NSVG_EPSILON) { - t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } else { - b2ac = b*b - 4.0*c*a; - if (b2ac > NSVG_EPSILON) { - t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } - for (j = 0; j < count; j++) { - v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); - } - } + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b * b - 4.0 * c * a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0 - NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0 + i] = nsvg__minf(bounds[0 + i], (float)v); + bounds[2 + i] = nsvg__maxf(bounds[2 + i], (float)v); + } + } } -static NSVGparser* nsvg__createParser() -{ - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; - memset(p, 0, sizeof(NSVGparser)); +static NSVGparser *nsvg__createParser() { + NSVGparser *p; + p = (NSVGparser *)malloc(sizeof(NSVGparser)); + if (p == NULL) + goto error; + memset(p, 0, sizeof(NSVGparser)); - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; - memset(p->image, 0, sizeof(NSVGimage)); + p->image = (NSVGimage *)malloc(sizeof(NSVGimage)); + if (p->image == NULL) + goto error; + memset(p->image, 0, sizeof(NSVGimage)); - // Init style - nsvg__xformIdentity(p->attr[0].xform); - memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); - p->attr[0].opacity = 1; - p->attr[0].fillOpacity = 1; - p->attr[0].strokeOpacity = 1; - p->attr[0].stopOpacity = 1; - p->attr[0].strokeWidth = 1; - p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; - p->attr[0].strokeLineCap = NSVG_CAP_BUTT; - p->attr[0].miterLimit = 4; - p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; - p->attr[0].hasFill = 1; - p->attr[0].visible = 1; + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0, 0, 0); + p->attr[0].strokeColor = NSVG_RGB(0, 0, 0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; - return p; + return p; error: - if (p) { - if (p->image) free(p->image); - free(p); - } - return NULL; + if (p) { + if (p->image) + free(p->image); + free(p); + } + return NULL; } -static void nsvg__deletePaths(NSVGpath* path) -{ - while (path) { - NSVGpath *next = path->next; - if (path->pts != NULL) - free(path->pts); - free(path); - path = next; - } +static void nsvg__deletePaths(NSVGpath *path) { + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } } -static void nsvg__deletePaint(NSVGpaint* paint) -{ - if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) - free(paint->gradient); +static void nsvg__deletePaint(NSVGpaint *paint) { + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); } -static void nsvg__deleteGradientData(NSVGgradientData* grad) -{ - NSVGgradientData* next; - while (grad != NULL) { - next = grad->next; - free(grad->stops); - free(grad); - grad = next; - } +static void nsvg__deleteGradientData(NSVGgradientData *grad) { + NSVGgradientData *next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } } -static void nsvg__deleteParser(NSVGparser* p) -{ - if (p != NULL) { - nsvg__deletePaths(p->plist); - nsvg__deleteGradientData(p->gradients); - nsvgDelete(p->image); - free(p->pts); - free(p); - } +static void nsvg__deleteParser(NSVGparser *p) { + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } } -static void nsvg__resetPath(NSVGparser* p) -{ - p->npts = 0; -} +static void nsvg__resetPath(NSVGparser *p) { p->npts = 0; } -static void nsvg__addPoint(NSVGparser* p, float x, float y) -{ - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; - } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; - p->npts++; +static void nsvg__addPoint(NSVGparser *p, float x, float y) { + if (p->npts + 1 > p->cpts) { + p->cpts = p->cpts ? p->cpts * 2 : 8; + p->pts = (float *)realloc(p->pts, p->cpts * 2 * sizeof(float)); + if (!p->pts) + return; + } + p->pts[p->npts * 2 + 0] = x; + p->pts[p->npts * 2 + 1] = y; + p->npts++; } -static void nsvg__moveTo(NSVGparser* p, float x, float y) -{ - if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; - } else { - nsvg__addPoint(p, x, y); - } +static void nsvg__moveTo(NSVGparser *p, float x, float y) { + if (p->npts > 0) { + p->pts[(p->npts - 1) * 2 + 0] = x; + p->pts[(p->npts - 1) * 2 + 1] = y; + } else { + nsvg__addPoint(p, x, y); + } } -static void nsvg__lineTo(NSVGparser* p, float x, float y) -{ - float px,py, dx,dy; - if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; - dx = x - px; - dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); - nsvg__addPoint(p, x, y); - } +static void nsvg__lineTo(NSVGparser *p, float x, float y) { + float px, py, dx, dy; + if (p->npts > 0) { + px = p->pts[(p->npts - 1) * 2 + 0]; + py = p->pts[(p->npts - 1) * 2 + 1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx / 3.0f, py + dy / 3.0f); + nsvg__addPoint(p, x - dx / 3.0f, y - dy / 3.0f); + nsvg__addPoint(p, x, y); + } } -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) -{ - nsvg__addPoint(p, cpx1, cpy1); - nsvg__addPoint(p, cpx2, cpy2); - nsvg__addPoint(p, x, y); +static void nsvg__cubicBezTo(NSVGparser *p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); } -static NSVGattrib* nsvg__getAttr(NSVGparser* p) -{ - return &p->attr[p->attrHead]; -} +static NSVGattrib *nsvg__getAttr(NSVGparser *p) { return &p->attr[p->attrHead]; } -static void nsvg__pushAttr(NSVGparser* p) -{ - if (p->attrHead < NSVG_MAX_ATTR-1) { - p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); - } +static void nsvg__pushAttr(NSVGparser *p) { + if (p->attrHead < NSVG_MAX_ATTR - 1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead - 1], sizeof(NSVGattrib)); + } } -static void nsvg__popAttr(NSVGparser* p) -{ - if (p->attrHead > 0) - p->attrHead--; +static void nsvg__popAttr(NSVGparser *p) { + if (p->attrHead > 0) + p->attrHead--; } -static float nsvg__actualOrigX(NSVGparser* p) -{ - return p->viewMinx; -} +static float nsvg__actualOrigX(NSVGparser *p) { return p->viewMinx; } -static float nsvg__actualOrigY(NSVGparser* p) -{ - return p->viewMiny; -} +static float nsvg__actualOrigY(NSVGparser *p) { return p->viewMiny; } -static float nsvg__actualWidth(NSVGparser* p) -{ - return p->viewWidth; -} +static float nsvg__actualWidth(NSVGparser *p) { return p->viewWidth; } -static float nsvg__actualHeight(NSVGparser* p) -{ - return p->viewHeight; -} +static float nsvg__actualHeight(NSVGparser *p) { return p->viewHeight; } -static float nsvg__actualLength(NSVGparser* p) -{ - float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); +static float nsvg__actualLength(NSVGparser *p) { + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w * w + h * h) / sqrtf(2.0f); } -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) -{ - NSVGattrib* attr = nsvg__getAttr(p); - switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; - } - return c.value; +static float nsvg__convertToPixels(NSVGparser *p, NSVGcoordinate c, float orig, float length) { + NSVGattrib *attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: + return c.value; + case NSVG_UNITS_PX: + return c.value; + case NSVG_UNITS_PT: + return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: + return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: + return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: + return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: + return c.value * p->dpi; + case NSVG_UNITS_EM: + return c.value * attr->fontSize; + case NSVG_UNITS_EX: + return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: + return orig + c.value / 100.0f * length; + default: + return c.value; + } + return c.value; } -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) -{ - NSVGgradientData* grad = p->gradients; - while (grad) { - if (strcmp(grad->id, id) == 0) - return grad; - grad = grad->next; - } - return NULL; +static NSVGgradientData *nsvg__findGradientData(NSVGparser *p, const char *id) { + NSVGgradientData *grad = p->gradients; + while (grad) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; } -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; - float ox, oy, sw, sh, sl; - int nstops = 0; +static NSVGgradient *nsvg__createGradient(NSVGparser *p, const char *id, const float *localBounds, char *paintType) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGgradientData *data = NULL; + NSVGgradientData *ref = NULL; + NSVGgradientStop *stops = NULL; + NSVGgradient *grad; + float ox, oy, sw, sh, sl; + int nstops = 0; - data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; + data = nsvg__findGradientData(p, id); + if (data == NULL) + return NULL; - // TODO: use ref to fill in all unset values too. - ref = data; - while (ref != NULL) { - if (stops == NULL && ref->stops != NULL) { - stops = ref->stops; - nstops = ref->nstops; - break; - } - ref = nsvg__findGradientData(p, ref->ref); - } - if (stops == NULL) return NULL; + // TODO: use ref to fill in all unset values too. + ref = data; + while (ref != NULL) { + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + ref = nsvg__findGradientData(p, ref->ref); + } + if (stops == NULL) + return NULL; - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; + grad = (NSVGgradient *)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop) * (nstops - 1)); + if (grad == NULL) + return NULL; - // The shape width and height. - if (data->units == NSVG_OBJECT_SPACE) { - ox = localBounds[0]; - oy = localBounds[1]; - sw = localBounds[2] - localBounds[0]; - sh = localBounds[3] - localBounds[1]; - } else { - ox = nsvg__actualOrigX(p); - oy = nsvg__actualOrigY(p); - sw = nsvg__actualWidth(p); - sh = nsvg__actualHeight(p); - } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw * sw + sh * sh) / sqrtf(2.0f); - if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { - float x1, y1, x2, y2, dx, dy; - x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); - y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); - x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); - y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); - // Calculate transform aligned to the line - dx = x2 - x1; - dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; - } else { - float cx, cy, fx, fy, r; - cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); - cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); - fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); - fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); - r = nsvg__convertToPixels(p, data->radial.r, 0, sl); - // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; - grad->fx = fx / r; - grad->fy = fy / r; - } + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; + grad->xform[1] = -dx; + grad->xform[2] = dx; + grad->xform[3] = dy; + grad->xform[4] = x1; + grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; + grad->xform[1] = 0; + grad->xform[2] = 0; + grad->xform[3] = r; + grad->xform[4] = cx; + grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } - nsvg__xformMultiply(grad->xform, data->xform); - nsvg__xformMultiply(grad->xform, attr->xform); + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, attr->xform); - grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); - grad->nstops = nstops; + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops * sizeof(NSVGgradientStop)); + grad->nstops = nstops; - *paintType = data->type; + *paintType = data->type; - return grad; + return grad; } -static float nsvg__getAverageScale(float* t) -{ - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); - return (sx + sy) * 0.5f; +static float nsvg__getAverageScale(float *t) { + float sx = sqrtf(t[0] * t[0] + t[2] * t[2]); + float sy = sqrtf(t[1] * t[1] + t[3] * t[3]); + return (sx + sy) * 0.5f; } -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) -{ - NSVGpath* path; - float curve[4*2], curveBounds[4]; - int i, first = 1; - for (path = shape->paths; path != NULL; path = path->next) { - nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); - nsvg__curveBounds(curveBounds, curve); - if (first) { - bounds[0] = curveBounds[0]; - bounds[1] = curveBounds[1]; - bounds[2] = curveBounds[2]; - bounds[3] = curveBounds[3]; - first = 0; - } else { - bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); - bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); - bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); - bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); - } - curve[0] = curve[6]; - curve[1] = curve[7]; - } - } +static void nsvg__getLocalBounds(float *bounds, NSVGshape *shape, float *xform) { + NSVGpath *path; + float curve[4 * 2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts - 1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i + 1) * 2], path->pts[(i + 1) * 2 + 1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i + 2) * 2], path->pts[(i + 2) * 2 + 1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i + 3) * 2], path->pts[(i + 3) * 2 + 1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } } -static void nsvg__addShape(NSVGparser* p) -{ - NSVGattrib* attr = nsvg__getAttr(p); - float scale = 1.0f; - NSVGshape* shape; - NSVGpath* path; - int i; +static void nsvg__addShape(NSVGparser *p) { + NSVGattrib *attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape *shape; + NSVGpath *path; + int i; - if (p->plist == NULL) - return; + if (p->plist == NULL) + return; - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; - memset(shape, 0, sizeof(NSVGshape)); + shape = (NSVGshape *)malloc(sizeof(NSVGshape)); + if (shape == NULL) + goto error; + memset(shape, 0, sizeof(NSVGshape)); - memcpy(shape->id, attr->id, sizeof shape->id); - scale = nsvg__getAverageScale(attr->xform); - shape->strokeWidth = attr->strokeWidth * scale; - shape->strokeDashOffset = attr->strokeDashOffset * scale; - shape->strokeDashCount = (char)attr->strokeDashCount; - for (i = 0; i < attr->strokeDashCount; i++) - shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; - shape->strokeLineJoin = attr->strokeLineJoin; - shape->strokeLineCap = attr->strokeLineCap; - shape->miterLimit = attr->miterLimit; - shape->fillRule = attr->fillRule; - shape->opacity = attr->opacity; + memcpy(shape->id, attr->id, sizeof shape->id); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; - shape->paths = p->plist; - p->plist = NULL; + shape->paths = p->plist; + p->plist = NULL; - // Calculate shape bounds - shape->bounds[0] = shape->paths->bounds[0]; - shape->bounds[1] = shape->paths->bounds[1]; - shape->bounds[2] = shape->paths->bounds[2]; - shape->bounds[3] = shape->paths->bounds[3]; - for (path = shape->paths->next; path != NULL; path = path->next) { - shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); - shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); - shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); - shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); - } + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } - // Set fill - if (attr->hasFill == 0) { - shape->fill.type = NSVG_PAINT_NONE; - } else if (attr->hasFill == 1) { - shape->fill.type = NSVG_PAINT_COLOR; - shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; - } else if (attr->hasFill == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); - if (shape->fill.gradient == NULL) { - shape->fill.type = NSVG_PAINT_NONE; - } - } + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity * 255) << 24; + } else if (attr->hasFill == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); + if (shape->fill.gradient == NULL) { + shape->fill.type = NSVG_PAINT_NONE; + } + } - // Set stroke - if (attr->hasStroke == 0) { - shape->stroke.type = NSVG_PAINT_NONE; - } else if (attr->hasStroke == 1) { - shape->stroke.type = NSVG_PAINT_COLOR; - shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; - } else if (attr->hasStroke == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); - if (shape->stroke.gradient == NULL) - shape->stroke.type = NSVG_PAINT_NONE; - } + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity * 255) << 24; + } else if (attr->hasStroke == 2) { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, attr->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); + if (shape->stroke.gradient == NULL) + shape->stroke.type = NSVG_PAINT_NONE; + } - // Set flags - shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); - // Add to tail - if (p->image->shapes == NULL) - p->image->shapes = shape; - else - p->shapesTail->next = shape; - p->shapesTail = shape; + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; - return; + return; error: - if (shape) free(shape); + if (shape) + free(shape); } -static void nsvg__addPath(NSVGparser* p, char closed) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; - float bounds[4]; - float* curve; - int i; +static void nsvg__addPath(NSVGparser *p, char closed) { + NSVGattrib *attr = nsvg__getAttr(p); + NSVGpath *path = NULL; + float bounds[4]; + float *curve; + int i; - if (p->npts < 4) - return; + if (p->npts < 4) + return; - if (closed) - nsvg__lineTo(p, p->pts[0], p->pts[1]); + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; - memset(path, 0, sizeof(NSVGpath)); + path = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (path == NULL) + goto error; + memset(path, 0, sizeof(NSVGpath)); - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; - path->closed = closed; - path->npts = p->npts; + path->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (path->pts == NULL) + goto error; + path->closed = closed; + path->npts = p->npts; - // Transform path. - for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i * 2], &path->pts[i * 2 + 1], p->pts[i * 2], p->pts[i * 2 + 1], attr->xform); - // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; - nsvg__curveBounds(bounds, curve); - if (i == 0) { - path->bounds[0] = bounds[0]; - path->bounds[1] = bounds[1]; - path->bounds[2] = bounds[2]; - path->bounds[3] = bounds[3]; - } else { - path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); - path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); - path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); - path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); - } - } + // Find bounds + for (i = 0; i < path->npts - 1; i += 3) { + curve = &path->pts[i * 2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } - path->next = p->plist; - p->plist = path; + path->next = p->plist; + p->plist = path; - return; + return; error: - if (path != NULL) { - if (path->pts != NULL) free(path->pts); - free(path); - } + if (path != NULL) { + if (path->pts != NULL) + free(path->pts); + free(path); + } } // We roll our own string to float because the std library one uses locale and messes things up. -static double nsvg__atof(const char* s) -{ - char* cur = (char*)s; - char* end = NULL; - double res = 0.0, sign = 1.0; - long long intPart = 0, fracPart = 0; - char hasIntPart = 0, hasFracPart = 0; +static double nsvg__atof(const char *s) { + char *cur = (char *)s; + char *end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; - // Parse optional sign - if (*cur == '+') { - cur++; - } else if (*cur == '-') { - sign = -1; - cur++; - } + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } - // Parse integer part - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - intPart = (double)strtoll(cur, &end, 10); - if (cur != end) { - res = (double)intPart; - hasIntPart = 1; - cur = end; - } - } + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = (double)strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } - // Parse fractional part. - if (*cur == '.') { - cur++; // Skip '.' - if (nsvg__isdigit(*cur)) { - // Parse digit sequence - fracPart = strtoll(cur, &end, 10); - if (cur != end) { - res += (double)fracPart / pow(10.0, (double)(end - cur)); - hasFracPart = 1; - cur = end; - } - } - } + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } - // A valid number should have integer or fractional part. - if (!hasIntPart && !hasFracPart) - return 0.0; + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; - // Parse optional exponent - if (*cur == 'e' || *cur == 'E') { - long expPart = 0; - cur++; // skip 'E' - expPart = strtol(cur, &end, 10); // Parse digit sequence with sign - if (cur != end) { - res *= pow(10.0, (double)expPart); - } - } + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } - return res * sign; + return res * sign; } +static const char *nsvg__parseNumber(const char *s, char *it, const int size) { + const int last = size - 1; + int i = 0; -static const char* nsvg__parseNumber(const char* s, char* it, const int size) -{ - const int last = size-1; - int i = 0; - - // sign - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - // integer part - // leading zero - if (*s == '0') { - if (i < last) it[i++] = *s; - s++; - } - else - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - if (*s == '.') { - // decimal point - if (i < last) it[i++] = *s; - s++; - // fraction part - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - // exponent - if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { - if (i < last) it[i++] = *s; - s++; - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - while (nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - it[i] = '\0'; + // sign + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + // integer part + // leading zero + if (*s == '0') { + if (i < last) + it[i++] = *s; + s++; + } else + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) + it[i++] = *s; + s++; + // fraction part + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) + it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) + it[i++] = *s; + s++; + } + while (nsvg__isdigit(*s)) { + if (i < last) + it[i++] = *s; + s++; + } + } + it[i] = '\0'; - return s; + return s; } -static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it) -{ - it[0] = '\0'; - while (nsvg__isspace(*s) || *s == ',') s++; - if (*s == '0' || *s == '1') { - it[0] = *s++; - it[1] = '\0'; - return s; - } - return s; +static const char *nsvg__getNextPathItemWhenArcFlag(const char *s, char *it) { + it[0] = '\0'; + while (nsvg__isspace(*s) || *s == ',') + s++; + if (*s == '0' || *s == '1') { + it[0] = *s++; + it[1] = '\0'; + return s; + } + return s; } -static const char* nsvg__getNextPathItem(const char* s, char* it) -{ - it[0] = '\0'; - // Skip white spaces and commas - while (nsvg__isspace(*s) || *s == ',') s++; - if (!*s) return s; - if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { - s = nsvg__parseNumber(s, it, 64); - } else { - // Parse command - it[0] = *s++; - it[1] = '\0'; - return s; - } +static const char *nsvg__getNextPathItem(const char *s, char *it) { + it[0] = '\0'; + // Skip white spaces and commas + while (nsvg__isspace(*s) || *s == ',') + s++; + if (!*s) + return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } - return s; + return s; } -static unsigned int nsvg__parseColorHex(const char* str) -{ - unsigned int c = 0, r = 0, g = 0, b = 0; - int n = 0; - str++; // skip # - // Calculate number of characters. - while(str[n] && !nsvg__isspace(str[n])) - n++; - if (n == 6) { - sscanf(str, "%x", &c); - } else if (n == 3) { - sscanf(str, "%x", &c); - c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); - c |= c<<4; - } - r = (c >> 16) & 0xff; - g = (c >> 8) & 0xff; - b = c & 0xff; - return NSVG_RGB(r,g,b); +static unsigned int nsvg__parseColorHex(const char *str) { + unsigned int c = 0, r = 0, g = 0, b = 0; + int n = 0; + str++; // skip # + // Calculate number of characters. + while (str[n] && !nsvg__isspace(str[n])) + n++; + if (n == 6) { + sscanf(str, "%x", &c); + } else if (n == 3) { + sscanf(str, "%x", &c); + c = (c & 0xf) | ((c & 0xf0) << 4) | ((c & 0xf00) << 8); + c |= c << 4; + } + r = (c >> 16) & 0xff; + g = (c >> 8) & 0xff; + b = c & 0xff; + return NSVG_RGB(r, g, b); } -static unsigned int nsvg__parseColorRGB(const char* str) -{ - int r = -1, g = -1, b = -1; - char s1[32]="", s2[32]=""; - sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); - if (strchr(s1, '%')) { - return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); - } else { - return NSVG_RGB(r,g,b); - } +static unsigned int nsvg__parseColorRGB(const char *str) { + int r = -1, g = -1, b = -1; + char s1[32] = "", s2[32] = ""; + sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); + if (strchr(s1, '%')) { + return NSVG_RGB((r * 255) / 100, (g * 255) / 100, (b * 255) / 100); + } else { + return NSVG_RGB(r, g, b); + } } typedef struct NSVGNamedColor { - const char* name; - unsigned int color; + const char *name; + unsigned int color; } NSVGNamedColor; NSVGNamedColor nsvg__colors[] = { - { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, - { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, - { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, - { "grey", NSVG_RGB(128, 128, 128) }, - { "gray", NSVG_RGB(128, 128, 128) }, - { "white", NSVG_RGB(255, 255, 255) }, + {"red", NSVG_RGB(255, 0, 0)}, + {"green", NSVG_RGB(0, 128, 0)}, + {"blue", NSVG_RGB(0, 0, 255)}, + {"yellow", NSVG_RGB(255, 255, 0)}, + {"cyan", NSVG_RGB(0, 255, 255)}, + {"magenta", NSVG_RGB(255, 0, 255)}, + {"black", NSVG_RGB(0, 0, 0)}, + {"grey", NSVG_RGB(128, 128, 128)}, + {"gray", NSVG_RGB(128, 128, 128)}, + {"white", NSVG_RGB(255, 255, 255)}, #ifdef NANOSVG_ALL_COLOR_KEYWORDS - { "aliceblue", NSVG_RGB(240, 248, 255) }, - { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, - { "aquamarine", NSVG_RGB(127, 255, 212) }, - { "azure", NSVG_RGB(240, 255, 255) }, - { "beige", NSVG_RGB(245, 245, 220) }, - { "bisque", NSVG_RGB(255, 228, 196) }, - { "blanchedalmond", NSVG_RGB(255, 235, 205) }, - { "blueviolet", NSVG_RGB(138, 43, 226) }, - { "brown", NSVG_RGB(165, 42, 42) }, - { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, - { "chartreuse", NSVG_RGB(127, 255, 0) }, - { "chocolate", NSVG_RGB(210, 105, 30) }, - { "coral", NSVG_RGB(255, 127, 80) }, - { "cornflowerblue", NSVG_RGB(100, 149, 237) }, - { "cornsilk", NSVG_RGB(255, 248, 220) }, - { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, - { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, - { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, - { "darkgrey", NSVG_RGB(169, 169, 169) }, - { "darkkhaki", NSVG_RGB(189, 183, 107) }, - { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, - { "darkorange", NSVG_RGB(255, 140, 0) }, - { "darkorchid", NSVG_RGB(153, 50, 204) }, - { "darkred", NSVG_RGB(139, 0, 0) }, - { "darksalmon", NSVG_RGB(233, 150, 122) }, - { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, - { "darkviolet", NSVG_RGB(148, 0, 211) }, - { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, - { "dimgray", NSVG_RGB(105, 105, 105) }, - { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, - { "firebrick", NSVG_RGB(178, 34, 34) }, - { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, - { "fuchsia", NSVG_RGB(255, 0, 255) }, - { "gainsboro", NSVG_RGB(220, 220, 220) }, - { "ghostwhite", NSVG_RGB(248, 248, 255) }, - { "gold", NSVG_RGB(255, 215, 0) }, - { "goldenrod", NSVG_RGB(218, 165, 32) }, - { "greenyellow", NSVG_RGB(173, 255, 47) }, - { "honeydew", NSVG_RGB(240, 255, 240) }, - { "hotpink", NSVG_RGB(255, 105, 180) }, - { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, - { "ivory", NSVG_RGB(255, 255, 240) }, - { "khaki", NSVG_RGB(240, 230, 140) }, - { "lavender", NSVG_RGB(230, 230, 250) }, - { "lavenderblush", NSVG_RGB(255, 240, 245) }, - { "lawngreen", NSVG_RGB(124, 252, 0) }, - { "lemonchiffon", NSVG_RGB(255, 250, 205) }, - { "lightblue", NSVG_RGB(173, 216, 230) }, - { "lightcoral", NSVG_RGB(240, 128, 128) }, - { "lightcyan", NSVG_RGB(224, 255, 255) }, - { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, - { "lightgray", NSVG_RGB(211, 211, 211) }, - { "lightgreen", NSVG_RGB(144, 238, 144) }, - { "lightgrey", NSVG_RGB(211, 211, 211) }, - { "lightpink", NSVG_RGB(255, 182, 193) }, - { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, - { "lightskyblue", NSVG_RGB(135, 206, 250) }, - { "lightslategray", NSVG_RGB(119, 136, 153) }, - { "lightslategrey", NSVG_RGB(119, 136, 153) }, - { "lightsteelblue", NSVG_RGB(176, 196, 222) }, - { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, - { "linen", NSVG_RGB(250, 240, 230) }, - { "maroon", NSVG_RGB(128, 0, 0) }, - { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, - { "mediumorchid", NSVG_RGB(186, 85, 211) }, - { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, - { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, - { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, - { "mintcream", NSVG_RGB(245, 255, 250) }, - { "mistyrose", NSVG_RGB(255, 228, 225) }, - { "moccasin", NSVG_RGB(255, 228, 181) }, - { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, - { "oldlace", NSVG_RGB(253, 245, 230) }, - { "olive", NSVG_RGB(128, 128, 0) }, - { "olivedrab", NSVG_RGB(107, 142, 35) }, - { "orange", NSVG_RGB(255, 165, 0) }, - { "orangered", NSVG_RGB(255, 69, 0) }, - { "orchid", NSVG_RGB(218, 112, 214) }, - { "palegoldenrod", NSVG_RGB(238, 232, 170) }, - { "palegreen", NSVG_RGB(152, 251, 152) }, - { "paleturquoise", NSVG_RGB(175, 238, 238) }, - { "palevioletred", NSVG_RGB(219, 112, 147) }, - { "papayawhip", NSVG_RGB(255, 239, 213) }, - { "peachpuff", NSVG_RGB(255, 218, 185) }, - { "peru", NSVG_RGB(205, 133, 63) }, - { "pink", NSVG_RGB(255, 192, 203) }, - { "plum", NSVG_RGB(221, 160, 221) }, - { "powderblue", NSVG_RGB(176, 224, 230) }, - { "purple", NSVG_RGB(128, 0, 128) }, - { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, - { "saddlebrown", NSVG_RGB(139, 69, 19) }, - { "salmon", NSVG_RGB(250, 128, 114) }, - { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, - { "seashell", NSVG_RGB(255, 245, 238) }, - { "sienna", NSVG_RGB(160, 82, 45) }, - { "silver", NSVG_RGB(192, 192, 192) }, - { "skyblue", NSVG_RGB(135, 206, 235) }, - { "slateblue", NSVG_RGB(106, 90, 205) }, - { "slategray", NSVG_RGB(112, 128, 144) }, - { "slategrey", NSVG_RGB(112, 128, 144) }, - { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, - { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, - { "thistle", NSVG_RGB(216, 191, 216) }, - { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, - { "violet", NSVG_RGB(238, 130, 238) }, - { "wheat", NSVG_RGB(245, 222, 179) }, - { "whitesmoke", NSVG_RGB(245, 245, 245) }, - { "yellowgreen", NSVG_RGB(154, 205, 50) }, + {"aliceblue", NSVG_RGB(240, 248, 255)}, + {"antiquewhite", NSVG_RGB(250, 235, 215)}, + {"aqua", NSVG_RGB(0, 255, 255)}, + {"aquamarine", NSVG_RGB(127, 255, 212)}, + {"azure", NSVG_RGB(240, 255, 255)}, + {"beige", NSVG_RGB(245, 245, 220)}, + {"bisque", NSVG_RGB(255, 228, 196)}, + {"blanchedalmond", NSVG_RGB(255, 235, 205)}, + {"blueviolet", NSVG_RGB(138, 43, 226)}, + {"brown", NSVG_RGB(165, 42, 42)}, + {"burlywood", NSVG_RGB(222, 184, 135)}, + {"cadetblue", NSVG_RGB(95, 158, 160)}, + {"chartreuse", NSVG_RGB(127, 255, 0)}, + {"chocolate", NSVG_RGB(210, 105, 30)}, + {"coral", NSVG_RGB(255, 127, 80)}, + {"cornflowerblue", NSVG_RGB(100, 149, 237)}, + {"cornsilk", NSVG_RGB(255, 248, 220)}, + {"crimson", NSVG_RGB(220, 20, 60)}, + {"darkblue", NSVG_RGB(0, 0, 139)}, + {"darkcyan", NSVG_RGB(0, 139, 139)}, + {"darkgoldenrod", NSVG_RGB(184, 134, 11)}, + {"darkgray", NSVG_RGB(169, 169, 169)}, + {"darkgreen", NSVG_RGB(0, 100, 0)}, + {"darkgrey", NSVG_RGB(169, 169, 169)}, + {"darkkhaki", NSVG_RGB(189, 183, 107)}, + {"darkmagenta", NSVG_RGB(139, 0, 139)}, + {"darkolivegreen", NSVG_RGB(85, 107, 47)}, + {"darkorange", NSVG_RGB(255, 140, 0)}, + {"darkorchid", NSVG_RGB(153, 50, 204)}, + {"darkred", NSVG_RGB(139, 0, 0)}, + {"darksalmon", NSVG_RGB(233, 150, 122)}, + {"darkseagreen", NSVG_RGB(143, 188, 143)}, + {"darkslateblue", NSVG_RGB(72, 61, 139)}, + {"darkslategray", NSVG_RGB(47, 79, 79)}, + {"darkslategrey", NSVG_RGB(47, 79, 79)}, + {"darkturquoise", NSVG_RGB(0, 206, 209)}, + {"darkviolet", NSVG_RGB(148, 0, 211)}, + {"deeppink", NSVG_RGB(255, 20, 147)}, + {"deepskyblue", NSVG_RGB(0, 191, 255)}, + {"dimgray", NSVG_RGB(105, 105, 105)}, + {"dimgrey", NSVG_RGB(105, 105, 105)}, + {"dodgerblue", NSVG_RGB(30, 144, 255)}, + {"firebrick", NSVG_RGB(178, 34, 34)}, + {"floralwhite", NSVG_RGB(255, 250, 240)}, + {"forestgreen", NSVG_RGB(34, 139, 34)}, + {"fuchsia", NSVG_RGB(255, 0, 255)}, + {"gainsboro", NSVG_RGB(220, 220, 220)}, + {"ghostwhite", NSVG_RGB(248, 248, 255)}, + {"gold", NSVG_RGB(255, 215, 0)}, + {"goldenrod", NSVG_RGB(218, 165, 32)}, + {"greenyellow", NSVG_RGB(173, 255, 47)}, + {"honeydew", NSVG_RGB(240, 255, 240)}, + {"hotpink", NSVG_RGB(255, 105, 180)}, + {"indianred", NSVG_RGB(205, 92, 92)}, + {"indigo", NSVG_RGB(75, 0, 130)}, + {"ivory", NSVG_RGB(255, 255, 240)}, + {"khaki", NSVG_RGB(240, 230, 140)}, + {"lavender", NSVG_RGB(230, 230, 250)}, + {"lavenderblush", NSVG_RGB(255, 240, 245)}, + {"lawngreen", NSVG_RGB(124, 252, 0)}, + {"lemonchiffon", NSVG_RGB(255, 250, 205)}, + {"lightblue", NSVG_RGB(173, 216, 230)}, + {"lightcoral", NSVG_RGB(240, 128, 128)}, + {"lightcyan", NSVG_RGB(224, 255, 255)}, + {"lightgoldenrodyellow", NSVG_RGB(250, 250, 210)}, + {"lightgray", NSVG_RGB(211, 211, 211)}, + {"lightgreen", NSVG_RGB(144, 238, 144)}, + {"lightgrey", NSVG_RGB(211, 211, 211)}, + {"lightpink", NSVG_RGB(255, 182, 193)}, + {"lightsalmon", NSVG_RGB(255, 160, 122)}, + {"lightseagreen", NSVG_RGB(32, 178, 170)}, + {"lightskyblue", NSVG_RGB(135, 206, 250)}, + {"lightslategray", NSVG_RGB(119, 136, 153)}, + {"lightslategrey", NSVG_RGB(119, 136, 153)}, + {"lightsteelblue", NSVG_RGB(176, 196, 222)}, + {"lightyellow", NSVG_RGB(255, 255, 224)}, + {"lime", NSVG_RGB(0, 255, 0)}, + {"limegreen", NSVG_RGB(50, 205, 50)}, + {"linen", NSVG_RGB(250, 240, 230)}, + {"maroon", NSVG_RGB(128, 0, 0)}, + {"mediumaquamarine", NSVG_RGB(102, 205, 170)}, + {"mediumblue", NSVG_RGB(0, 0, 205)}, + {"mediumorchid", NSVG_RGB(186, 85, 211)}, + {"mediumpurple", NSVG_RGB(147, 112, 219)}, + {"mediumseagreen", NSVG_RGB(60, 179, 113)}, + {"mediumslateblue", NSVG_RGB(123, 104, 238)}, + {"mediumspringgreen", NSVG_RGB(0, 250, 154)}, + {"mediumturquoise", NSVG_RGB(72, 209, 204)}, + {"mediumvioletred", NSVG_RGB(199, 21, 133)}, + {"midnightblue", NSVG_RGB(25, 25, 112)}, + {"mintcream", NSVG_RGB(245, 255, 250)}, + {"mistyrose", NSVG_RGB(255, 228, 225)}, + {"moccasin", NSVG_RGB(255, 228, 181)}, + {"navajowhite", NSVG_RGB(255, 222, 173)}, + {"navy", NSVG_RGB(0, 0, 128)}, + {"oldlace", NSVG_RGB(253, 245, 230)}, + {"olive", NSVG_RGB(128, 128, 0)}, + {"olivedrab", NSVG_RGB(107, 142, 35)}, + {"orange", NSVG_RGB(255, 165, 0)}, + {"orangered", NSVG_RGB(255, 69, 0)}, + {"orchid", NSVG_RGB(218, 112, 214)}, + {"palegoldenrod", NSVG_RGB(238, 232, 170)}, + {"palegreen", NSVG_RGB(152, 251, 152)}, + {"paleturquoise", NSVG_RGB(175, 238, 238)}, + {"palevioletred", NSVG_RGB(219, 112, 147)}, + {"papayawhip", NSVG_RGB(255, 239, 213)}, + {"peachpuff", NSVG_RGB(255, 218, 185)}, + {"peru", NSVG_RGB(205, 133, 63)}, + {"pink", NSVG_RGB(255, 192, 203)}, + {"plum", NSVG_RGB(221, 160, 221)}, + {"powderblue", NSVG_RGB(176, 224, 230)}, + {"purple", NSVG_RGB(128, 0, 128)}, + {"rosybrown", NSVG_RGB(188, 143, 143)}, + {"royalblue", NSVG_RGB(65, 105, 225)}, + {"saddlebrown", NSVG_RGB(139, 69, 19)}, + {"salmon", NSVG_RGB(250, 128, 114)}, + {"sandybrown", NSVG_RGB(244, 164, 96)}, + {"seagreen", NSVG_RGB(46, 139, 87)}, + {"seashell", NSVG_RGB(255, 245, 238)}, + {"sienna", NSVG_RGB(160, 82, 45)}, + {"silver", NSVG_RGB(192, 192, 192)}, + {"skyblue", NSVG_RGB(135, 206, 235)}, + {"slateblue", NSVG_RGB(106, 90, 205)}, + {"slategray", NSVG_RGB(112, 128, 144)}, + {"slategrey", NSVG_RGB(112, 128, 144)}, + {"snow", NSVG_RGB(255, 250, 250)}, + {"springgreen", NSVG_RGB(0, 255, 127)}, + {"steelblue", NSVG_RGB(70, 130, 180)}, + {"tan", NSVG_RGB(210, 180, 140)}, + {"teal", NSVG_RGB(0, 128, 128)}, + {"thistle", NSVG_RGB(216, 191, 216)}, + {"tomato", NSVG_RGB(255, 99, 71)}, + {"turquoise", NSVG_RGB(64, 224, 208)}, + {"violet", NSVG_RGB(238, 130, 238)}, + {"wheat", NSVG_RGB(245, 222, 179)}, + {"whitesmoke", NSVG_RGB(245, 245, 245)}, + {"yellowgreen", NSVG_RGB(154, 205, 50)}, #endif }; -static unsigned int nsvg__parseColorName(const char* str) -{ - int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); +static unsigned int nsvg__parseColorName(const char *str) { + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); - for (i = 0; i < ncolors; i++) { - if (strcmp(nsvg__colors[i].name, str) == 0) { - return nsvg__colors[i].color; - } - } + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } - return NSVG_RGB(128, 128, 128); + return NSVG_RGB(128, 128, 128); } -static unsigned int nsvg__parseColor(const char* str) -{ - size_t len = 0; - while(*str == ' ') ++str; - len = strlen(str); - if (len >= 1 && *str == '#') - return nsvg__parseColorHex(str); - else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') - return nsvg__parseColorRGB(str); - return nsvg__parseColorName(str); +static unsigned int nsvg__parseColor(const char *str) { + size_t len = 0; + while (*str == ' ') + ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); } -static float nsvg__parseOpacity(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; - return val; +static float nsvg__parseOpacity(const char *str) { + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + if (val > 1.0f) + val = 1.0f; + return val; } -static float nsvg__parseMiterLimit(const char* str) -{ - float val = nsvg__atof(str); - if (val < 0.0f) val = 0.0f; - return val; +static float nsvg__parseMiterLimit(const char *str) { + float val = nsvg__atof(str); + if (val < 0.0f) + val = 0.0f; + return val; } -static int nsvg__parseUnits(const char* units) -{ - if (units[0] == 'p' && units[1] == 'x') - return NSVG_UNITS_PX; - else if (units[0] == 'p' && units[1] == 't') - return NSVG_UNITS_PT; - else if (units[0] == 'p' && units[1] == 'c') - return NSVG_UNITS_PC; - else if (units[0] == 'm' && units[1] == 'm') - return NSVG_UNITS_MM; - else if (units[0] == 'c' && units[1] == 'm') - return NSVG_UNITS_CM; - else if (units[0] == 'i' && units[1] == 'n') - return NSVG_UNITS_IN; - else if (units[0] == '%') - return NSVG_UNITS_PERCENT; - else if (units[0] == 'e' && units[1] == 'm') - return NSVG_UNITS_EM; - else if (units[0] == 'e' && units[1] == 'x') - return NSVG_UNITS_EX; - return NSVG_UNITS_USER; +static int nsvg__parseUnits(const char *units) { + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; } -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) -{ - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; - char buf[64]; - coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); - coord.value = nsvg__atof(buf); - return coord; +static NSVGcoordinate nsvg__parseCoordinateRaw(const char *str) { + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; } -static NSVGcoordinate nsvg__coord(float v, int units) -{ - NSVGcoordinate coord = {v, units}; - return coord; +static NSVGcoordinate nsvg__coord(float v, int units) { + NSVGcoordinate coord = {v, units}; + return coord; } -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) -{ - NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); - return nsvg__convertToPixels(p, coord, orig, length); +static float nsvg__parseCoordinate(NSVGparser *p, const char *str, float orig, float length) { + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); } -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) -{ - const char* end; - const char* ptr; - char it[64]; +static int nsvg__parseTransformArgs(const char *str, float *args, int maxNa, int *na) { + const char *end; + const char *ptr; + char it[64]; - *na = 0; - ptr = str; - while (*ptr && *ptr != '(') ++ptr; - if (*ptr == 0) - return 1; - end = ptr; - while (*end && *end != ')') ++end; - if (*end == 0) - return 1; + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') + ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') + ++end; + if (*end == 0) + return 1; - while (ptr < end) { - if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; - ptr = nsvg__parseNumber(ptr, it, 64); - args[(*na)++] = (float)nsvg__atof(it); - } else { - ++ptr; - } - } - return (int)(end - str); + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) + return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); } - -static int nsvg__parseMatrix(float* xform, const char* str) -{ - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); - return len; +static int nsvg__parseMatrix(float *xform, const char *str) { + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) + return len; + memcpy(xform, t, sizeof(float) * 6); + return len; } -static int nsvg__parseTranslate(float* xform, const char* str) -{ - float args[2]; - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; +static int nsvg__parseTranslate(float *xform, const char *str) { + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = 0.0; - nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; } -static int nsvg__parseScale(float* xform, const char* str) -{ - float args[2]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; - nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; +static int nsvg__parseScale(float *xform, const char *str) { + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) + args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float) * 6); + return len; } -static int nsvg__parseSkewX(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; +static int nsvg__parseSkewX(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; } -static int nsvg__parseSkewY(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; +static int nsvg__parseSkewY(float *xform, const char *str) { + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0] / 180.0f * NSVG_PI); + memcpy(xform, t, sizeof(float) * 6); + return len; } -static int nsvg__parseRotate(float* xform, const char* str) -{ - float args[3]; - int na = 0; - float m[6]; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 3, &na); - if (na == 1) - args[1] = args[2] = 0.0f; - nsvg__xformIdentity(m); +static int nsvg__parseRotate(float *xform, const char *str) { + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); - if (na > 1) { - nsvg__xformSetTranslation(t, -args[1], -args[2]); - nsvg__xformMultiply(m, t); - } + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); - nsvg__xformMultiply(m, t); + nsvg__xformSetRotation(t, args[0] / 180.0f * NSVG_PI); + nsvg__xformMultiply(m, t); - if (na > 1) { - nsvg__xformSetTranslation(t, args[1], args[2]); - nsvg__xformMultiply(m, t); - } + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } - memcpy(xform, m, sizeof(float)*6); + memcpy(xform, m, sizeof(float) * 6); - return len; + return len; } -static void nsvg__parseTransform(float* xform, const char* str) -{ - float t[6]; - nsvg__xformIdentity(xform); - while (*str) - { - if (strncmp(str, "matrix", 6) == 0) - str += nsvg__parseMatrix(t, str); - else if (strncmp(str, "translate", 9) == 0) - str += nsvg__parseTranslate(t, str); - else if (strncmp(str, "scale", 5) == 0) - str += nsvg__parseScale(t, str); - else if (strncmp(str, "rotate", 6) == 0) - str += nsvg__parseRotate(t, str); - else if (strncmp(str, "skewX", 5) == 0) - str += nsvg__parseSkewX(t, str); - else if (strncmp(str, "skewY", 5) == 0) - str += nsvg__parseSkewY(t, str); - else{ - ++str; - continue; - } +static void nsvg__parseTransform(float *xform, const char *str) { + float t[6]; + nsvg__xformIdentity(xform); + while (*str) { + if (strncmp(str, "matrix", 6) == 0) + str += nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + str += nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + str += nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + str += nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + str += nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + str += nsvg__parseSkewY(t, str); + else { + ++str; + continue; + } - nsvg__xformPremultiply(xform, t); - } + nsvg__xformPremultiply(xform, t); + } } -static void nsvg__parseUrl(char* id, const char* str) -{ - int i = 0; - str += 4; // "url("; - if (*str == '#') - str++; - while (i < 63 && *str != ')') { - id[i] = *str++; - i++; - } - id[i] = '\0'; +static void nsvg__parseUrl(char *id, const char *str) { + int i = 0; + str += 4; // "url("; + if (*str == '#') + str++; + while (i < 63 && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; } -static char nsvg__parseLineCap(const char* str) -{ - if (strcmp(str, "butt") == 0) - return NSVG_CAP_BUTT; - else if (strcmp(str, "round") == 0) - return NSVG_CAP_ROUND; - else if (strcmp(str, "square") == 0) - return NSVG_CAP_SQUARE; - // TODO: handle inherit. - return NSVG_CAP_BUTT; +static char nsvg__parseLineCap(const char *str) { + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; } -static char nsvg__parseLineJoin(const char* str) -{ - if (strcmp(str, "miter") == 0) - return NSVG_JOIN_MITER; - else if (strcmp(str, "round") == 0) - return NSVG_JOIN_ROUND; - else if (strcmp(str, "bevel") == 0) - return NSVG_JOIN_BEVEL; - // TODO: handle inherit. - return NSVG_JOIN_MITER; +static char nsvg__parseLineJoin(const char *str) { + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; } -static char nsvg__parseFillRule(const char* str) -{ - if (strcmp(str, "nonzero") == 0) - return NSVG_FILLRULE_NONZERO; - else if (strcmp(str, "evenodd") == 0) - return NSVG_FILLRULE_EVENODD; - // TODO: handle inherit. - return NSVG_FILLRULE_NONZERO; +static char nsvg__parseFillRule(const char *str) { + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; } -static const char* nsvg__getNextDashItem(const char* s, char* it) -{ - int n = 0; - it[0] = '\0'; - // Skip white spaces and commas - while (nsvg__isspace(*s) || *s == ',') s++; - // Advance until whitespace, comma or end. - while (*s && (!nsvg__isspace(*s) && *s != ',')) { - if (n < 63) - it[n++] = *s; - s++; - } - it[n++] = '\0'; - return s; +static const char *nsvg__getNextDashItem(const char *s, char *it) { + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (nsvg__isspace(*s) || *s == ',') + s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; } -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) -{ - char item[64]; - int count = 0, i; - float sum = 0.0f; +static int nsvg__parseStrokeDashArray(NSVGparser *p, const char *str, float *strokeDashArray) { + char item[64]; + int count = 0, i; + float sum = 0.0f; - // Handle "none" - if (str[0] == 'n') - return 0; + // Handle "none" + if (str[0] == 'n') + return 0; - // Parse dashes - while (*str) { - str = nsvg__getNextDashItem(str, item); - if (!*item) break; - if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); - } + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) + break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } - for (i = 0; i < count; i++) - sum += strokeDashArray[i]; - if (sum <= 1e-6f) - count = 0; + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; - return count; + return count; } -static void nsvg__parseStyle(NSVGparser* p, const char* str); +static void nsvg__parseStyle(NSVGparser *p, const char *str); -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) -{ - float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; +static int nsvg__parseAttr(NSVGparser *p, const char *name, const char *value) { + float xform[6]; + NSVGattrib *attr = nsvg__getAttr(p); + if (!attr) + return 0; - if (strcmp(name, "style") == 0) { - nsvg__parseStyle(p, value); - } else if (strcmp(name, "display") == 0) { - if (strcmp(value, "none") == 0) - attr->visible = 0; - // Don't reset ->visible on display:inline, one display:none hides the whole subtree + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree - } else if (strcmp(name, "fill") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasFill = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasFill = 2; - nsvg__parseUrl(attr->fillGradient, value); - } else { - attr->hasFill = 1; - attr->fillColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "opacity") == 0) { - attr->opacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "fill-opacity") == 0) { - attr->fillOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasStroke = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasStroke = 2; - nsvg__parseUrl(attr->strokeGradient, value); - } else { - attr->hasStroke = 1; - attr->strokeColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "stroke-width") == 0) { - attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-dasharray") == 0) { - attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); - } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-opacity") == 0) { - attr->strokeOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke-linecap") == 0) { - attr->strokeLineCap = nsvg__parseLineCap(value); - } else if (strcmp(name, "stroke-linejoin") == 0) { - attr->strokeLineJoin = nsvg__parseLineJoin(value); - } else if (strcmp(name, "stroke-miterlimit") == 0) { - attr->miterLimit = nsvg__parseMiterLimit(value); - } else if (strcmp(name, "fill-rule") == 0) { - attr->fillRule = nsvg__parseFillRule(value); - } else if (strcmp(name, "font-size") == 0) { - attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "transform") == 0) { - nsvg__parseTransform(xform, value); - nsvg__xformPremultiply(attr->xform, xform); - } else if (strcmp(name, "stop-color") == 0) { - attr->stopColor = nsvg__parseColor(value); - } else if (strcmp(name, "stop-opacity") == 0) { - attr->stopOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "offset") == 0) { - attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); - } else if (strcmp(name, "id") == 0) { - strncpy(attr->id, value, 63); - attr->id[63] = '\0'; - } else { - return 0; - } - return 1; + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; } -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) -{ - const char* str; - const char* val; - char name[512]; - char value[512]; - int n; +static int nsvg__parseNameValue(NSVGparser *p, const char *start, const char *end) { + const char *str; + const char *val; + char name[512]; + char value[512]; + int n; - str = start; - while (str < end && *str != ':') ++str; + str = start; + while (str < end && *str != ':') + ++str; - val = str; + val = str; - // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; - ++str; + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) + --str; + ++str; - n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); - name[n] = 0; + n = (int)(str - start); + if (n > 511) + n = 511; + if (n) + memcpy(name, start, n); + name[n] = 0; - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + while (val < end && (*val == ':' || nsvg__isspace(*val))) + ++val; - n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); - value[n] = 0; + n = (int)(end - val); + if (n > 511) + n = 511; + if (n) + memcpy(value, val, n); + value[n] = 0; - return nsvg__parseAttr(p, name, value); + return nsvg__parseAttr(p, name, value); } -static void nsvg__parseStyle(NSVGparser* p, const char* str) -{ - const char* start; - const char* end; +static void nsvg__parseStyle(NSVGparser *p, const char *str) { + const char *start; + const char *end; - while (*str) { - // Left Trim - while(nsvg__isspace(*str)) ++str; - start = str; - while(*str && *str != ';') ++str; - end = str; + while (*str) { + // Left Trim + while (nsvg__isspace(*str)) + ++str; + start = str; + while (*str && *str != ';') + ++str; + end = str; - // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; - ++end; + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) + --end; + ++end; - nsvg__parseNameValue(p, start, end); - if (*str) ++str; - } + nsvg__parseNameValue(p, start, end); + if (*str) + ++str; + } } -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) - { - if (strcmp(attr[i], "style") == 0) - nsvg__parseStyle(p, attr[i + 1]); - else - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } +static void nsvg__parseAttribs(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } } -static int nsvg__getArgsPerElement(char cmd) -{ - switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - } - return 0; +static int nsvg__getArgsPerElement(char cmd) { + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + } + return 0; } -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__moveTo(p, *cpx, *cpy); +static void nsvg__pathMoveTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); } -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__lineTo(p, *cpx, *cpy); +static void nsvg__pathLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpx += args[0]; - else - *cpx = args[0]; - nsvg__lineTo(p, *cpx, *cpy); +static void nsvg__pathHLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpy += args[0]; - else - *cpy = args[0]; - nsvg__lineTo(p, *cpx, *cpy); +static void nsvg__pathVLineTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); } -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x2, y2, cx1, cy1, cx2, cy2; +static void nsvg__pathCubicBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x2, y2, cx1, cy1, cx2, cy2; - if (rel) { - cx1 = *cpx + args[0]; - cy1 = *cpy + args[1]; - cx2 = *cpx + args[2]; - cy2 = *cpy + args[3]; - x2 = *cpx + args[4]; - y2 = *cpy + args[5]; - } else { - cx1 = args[0]; - cy1 = args[1]; - cx2 = args[2]; - cy2 = args[3]; - x2 = args[4]; - y2 = args[5]; - } + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; } -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx1, cy1, cx2, cy2; +static void nsvg__pathCubicBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx2 = *cpx + args[0]; - cy2 = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx2 = args[0]; - cy2 = args[1]; - x2 = args[2]; - y2 = args[3]; - } + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; + cx1 = 2 * x1 - *cpx2; + cy1 = 2 * y1 - *cpy2; - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; } -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; +static void nsvg__pathQuadBezTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx = *cpx + args[0]; - cy = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx = args[0]; - cy = args[1]; - x2 = args[2]; - y2 = args[3]; - } + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } - // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); + // Convert to cubic bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; } -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; +static void nsvg__pathQuadBezShortTo(NSVGparser *p, float *cpx, float *cpy, float *cpx2, float *cpy2, float *args, + int rel) { + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; - x1 = *cpx; - y1 = *cpy; - if (rel) { - x2 = *cpx + args[0]; - y2 = *cpy + args[1]; - } else { - x2 = args[0]; - y2 = args[1]; - } + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; + cx = 2 * x1 - *cpx2; + cy = 2 * y1 - *cpy2; - // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); + // Convert to cubix bezier + cx1 = x1 + 2.0f / 3.0f * (cx - x1); + cy1 = y1 + 2.0f / 3.0f * (cy - y1); + cx2 = x2 + 2.0f / 3.0f * (cx - x2); + cy2 = y2 + 2.0f / 3.0f * (cy - y2); - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + nsvg__cubicBezTo(p, cx1, cy1, cx2, cy2, x2, y2); - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; } -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } +static float nsvg__sqr(float x) { return x * x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x * x + y * y); } -static float nsvg__vecrat(float ux, float uy, float vx, float vy) -{ - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +static float nsvg__vecrat(float ux, float uy, float vx, float vy) { + return (ux * vx + uy * vy) / (nsvg__vmag(ux, uy) * nsvg__vmag(vx, vy)); } -static float nsvg__vecang(float ux, float uy, float vx, float vy) -{ - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +static float nsvg__vecang(float ux, float uy, float vx, float vy) { + float r = nsvg__vecrat(ux, uy, vx, vy); + if (r < -1.0f) + r = -1.0f; + if (r > 1.0f) + r = 1.0f; + return ((ux * vy < uy * vx) ? -1.0f : 1.0f) * acosf(r); } -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - // Ported from canvg (https://code.google.com/p/canvg/) - float rx, ry, rotx; - float x1, y1, x2, y2, cx, cy, dx, dy, d; - float x1p, y1p, cxp, cyp, s, sa, sb; - float ux, uy, vx, vy, a1, da; - float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; - float sinrx, cosrx; - int fa, fs; - int i, ndivs; - float hda, kappa; +static void nsvg__pathArcTo(NSVGparser *p, float *cpx, float *cpy, float *args, int rel) { + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point - y1 = *cpy; - if (rel) { // end point - x2 = *cpx + args[5]; - y2 = *cpy + args[6]; - } else { - x2 = args[5]; - y2 = args[6]; - } + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } - dx = x1 - x2; - dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); - if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { - // The arc degenerates to a line - nsvg__lineTo(p, x2, y2); - *cpx = x2; - *cpy = y2; - return; - } + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx * dx + dy * dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } - sinrx = sinf(rotx); - cosrx = cosf(rotx); + sinrx = sinf(rotx); + cosrx = cosf(rotx); - // Convert to center point parameterization. - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - // 1) Compute x1', y1' - x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; - y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); - if (d > 1) { - d = sqrtf(d); - rx *= d; - ry *= d; - } - // 2) Compute cx', cy' - s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; - if (sb > 0.0f) - s = sqrtf(sa / sb); - if (fa == fs) - s = -s; - cxp = s * rx * y1p / ry; - cyp = s * -ry * x1p / rx; + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p) / nsvg__sqr(rx) + nsvg__sqr(y1p) / nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx) * nsvg__sqr(ry) - nsvg__sqr(rx) * nsvg__sqr(y1p) - nsvg__sqr(ry) * nsvg__sqr(x1p); + sb = nsvg__sqr(rx) * nsvg__sqr(y1p) + nsvg__sqr(ry) * nsvg__sqr(x1p); + if (sa < 0.0f) + sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; - // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2) / 2.0f + cosrx * cxp - sinrx * cyp; + cy = (y1 + y2) / 2.0f + sinrx * cxp + cosrx * cyp; - // 4) Calculate theta1, and delta theta. - ux = (x1p - cxp) / rx; - uy = (y1p - cyp) / ry; - vx = (-x1p - cxp) / rx; - vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f, 0.0f, ux, uy); // Initial angle + da = nsvg__vecang(ux, uy, vx, vy); // Delta angle -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + // if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; + // if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; - if (fs == 0 && da > 0) - da -= 2 * NSVG_PI; - else if (fs == 1 && da < 0) - da += 2 * NSVG_PI; + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; - // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; + // Approximate the arc using cubic spline segments. + t[0] = cosrx; + t[1] = sinrx; + t[2] = -sinrx; + t[3] = cosrx; + t[4] = cx; + t[5] = cy; - // Split arc into max 90 degree segments. - // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); - hda = (da / (float)ndivs) / 2.0f; - kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); - if (da < 0.0f) - kappa = -kappa; + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI * 0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); + if (da < 0.0f) + kappa = -kappa; - for (i = 0; i <= ndivs; i++) { - a = a1 + da * ((float)i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent - if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); - px = x; - py = y; - ptanx = tanx; - ptany = tany; - } + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i / (float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx * rx, dy * ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy * rx * kappa, dx * ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px + ptanx, py + ptany, x - tanx, y - tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } - *cpx = x2; - *cpy = y2; + *cpx = x2; + *cpy = y2; } -static void nsvg__parsePath(NSVGparser* p, const char** attr) -{ - const char* s = NULL; - char cmd = '\0'; - float args[10]; - int nargs; - int rargs = 0; - float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; - char closedFlag; - int i; - char item[64]; +static void nsvg__parsePath(NSVGparser *p, const char **attr) { + const char *s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + float cpx, cpy, cpx2, cpy2; + const char *tmp[4]; + char closedFlag; + int i; + char item[64]; - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "d") == 0) { - s = attr[i + 1]; - } else { - tmp[0] = attr[i]; - tmp[1] = attr[i + 1]; - tmp[2] = 0; - tmp[3] = 0; - nsvg__parseAttribs(p, tmp); - } - } + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } - if (s) { - nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; - closedFlag = 0; - nargs = 0; + if (s) { + nsvg__resetPath(p); + cpx = 0; + cpy = 0; + cpx2 = 0; + cpy2 = 0; + closedFlag = 0; + nargs = 0; - while (*s) { - item[0] = '\0'; - if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) - s = nsvg__getNextPathItemWhenArcFlag(s, item); - if (!*item) - s = nsvg__getNextPathItem(s, item); - if (!*item) break; - if (nsvg__isnum(item[0])) { - if (nargs < 10) - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= rargs) { - switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; - } - nargs = 0; - } - } else { - // New command - if (nargs) { - NANOSVG_DEBUG("unfinished command '%c' %d/%d args\n", cmd, nargs, rargs); - } - cmd = item[0]; - rargs = nsvg__getArgsPerElement(cmd); - if (cmd == 'M' || cmd == 'm') { - // Commit path. - if (p->npts > 0) - nsvg__addPath(p, closedFlag); - // Start new subpath. - nsvg__resetPath(p); - closedFlag = 0; - nargs = 0; - } else if (cmd == 'Z' || cmd == 'z') { - closedFlag = 1; - // Commit path. - if (p->npts > 0) { - // Move current point to first point - cpx = p->pts[0]; - cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; - nsvg__addPath(p, closedFlag); - } - // Start new subpath. - nsvg__resetPath(p); - nsvg__moveTo(p, cpx, cpy); - closedFlag = 0; - nargs = 0; - } - } - } - // Commit path. - if (p->npts) - nsvg__addPath(p, closedFlag); - } + while (*s) { + item[0] = '\0'; + if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) + s = nsvg__getNextPathItemWhenArcFlag(s, item); + if (!*item) + s = nsvg__getNextPathItem(s, item); + if (!*item) + break; + if (nsvg__isnum(item[0])) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; + cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs - 2]; + cpy = args[nargs - 1]; + cpx2 = cpx; + cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + // New command + if (nargs) { + NANOSVG_DEBUG("unfinished command '%c' %d/%d args\n", cmd, nargs, rargs); + } + cmd = item[0]; + rargs = nsvg__getArgsPerElement(cmd); + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; + cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } - nsvg__addShape(p); + nsvg__addShape(p); } -static void nsvg__parseRect(NSVGparser* p, const char** attr) -{ - float x = 0.0f; - float y = 0.0f; - float w = 0.0f; - float h = 0.0f; - float rx = -1.0f; // marks not set - float ry = -1.0f; - int i; +static void nsvg__parseRect(NSVGparser *p, const char **attr) { + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) + x = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) + y = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) + w = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) + h = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; + if (rx < 0.0f && ry > 0.0f) + rx = ry; + if (ry < 0.0f && rx > 0.0f) + ry = rx; + if (rx < 0.0f) + rx = 0.0f; + if (ry < 0.0f) + ry = 0.0f; + if (rx > w / 2.0f) + rx = w / 2.0f; + if (ry > h / 2.0f) + ry = h / 2.0f; - if (w != 0.0f && h != 0.0f) { - nsvg__resetPath(p); + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); - if (rx < 0.00001f || ry < 0.0001f) { - nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); - } else { - // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); - } + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x + w, y); + nsvg__lineTo(p, x + w, y + h); + nsvg__lineTo(p, x, y + h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x + rx, y); + nsvg__lineTo(p, x + w - rx, y); + nsvg__cubicBezTo(p, x + w - rx * (1 - NSVG_KAPPA90), y, x + w, y + ry * (1 - NSVG_KAPPA90), x + w, y + ry); + nsvg__lineTo(p, x + w, y + h - ry); + nsvg__cubicBezTo(p, x + w, y + h - ry * (1 - NSVG_KAPPA90), x + w - rx * (1 - NSVG_KAPPA90), y + h, + x + w - rx, y + h); + nsvg__lineTo(p, x + rx, y + h); + nsvg__cubicBezTo(p, x + rx * (1 - NSVG_KAPPA90), y + h, x, y + h - ry * (1 - NSVG_KAPPA90), x, y + h - ry); + nsvg__lineTo(p, x, y + ry); + nsvg__cubicBezTo(p, x, y + ry * (1 - NSVG_KAPPA90), x + rx * (1 - NSVG_KAPPA90), y, x + rx, y); + } - nsvg__addPath(p, 1); + nsvg__addPath(p, 1); - nsvg__addShape(p); - } + nsvg__addShape(p); + } } -static void nsvg__parseCircle(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float r = 0.0f; - int i; +static void nsvg__parseCircle(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); - } - } + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) + r = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualLength(p))); + } + } - if (r > 0.0f) { - nsvg__resetPath(p); + if (r > 0.0f) { + nsvg__resetPath(p); - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + nsvg__moveTo(p, cx + r, cy); + nsvg__cubicBezTo(p, cx + r, cy + r * NSVG_KAPPA90, cx + r * NSVG_KAPPA90, cy + r, cx, cy + r); + nsvg__cubicBezTo(p, cx - r * NSVG_KAPPA90, cy + r, cx - r, cy + r * NSVG_KAPPA90, cx - r, cy); + nsvg__cubicBezTo(p, cx - r, cy - r * NSVG_KAPPA90, cx - r * NSVG_KAPPA90, cy - r, cx, cy - r); + nsvg__cubicBezTo(p, cx + r * NSVG_KAPPA90, cy - r, cx + r, cy - r * NSVG_KAPPA90, cx + r, cy); - nsvg__addPath(p, 1); + nsvg__addPath(p, 1); - nsvg__addShape(p); - } + nsvg__addShape(p); + } } -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float rx = 0.0f; - float ry = 0.0f; - int i; +static void nsvg__parseEllipse(NSVGparser *p, const char **attr) { + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) + cx = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) + cy = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) + rx = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) + ry = fabsf(nsvg__parseCoordinate(p, attr[i + 1], 0.0f, nsvg__actualHeight(p))); + } + } - if (rx > 0.0f && ry > 0.0f) { + if (rx > 0.0f && ry > 0.0f) { - nsvg__resetPath(p); + nsvg__resetPath(p); - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + nsvg__moveTo(p, cx + rx, cy); + nsvg__cubicBezTo(p, cx + rx, cy + ry * NSVG_KAPPA90, cx + rx * NSVG_KAPPA90, cy + ry, cx, cy + ry); + nsvg__cubicBezTo(p, cx - rx * NSVG_KAPPA90, cy + ry, cx - rx, cy + ry * NSVG_KAPPA90, cx - rx, cy); + nsvg__cubicBezTo(p, cx - rx, cy - ry * NSVG_KAPPA90, cx - rx * NSVG_KAPPA90, cy - ry, cx, cy - ry); + nsvg__cubicBezTo(p, cx + rx * NSVG_KAPPA90, cy - ry, cx + rx, cy - ry * NSVG_KAPPA90, cx + rx, cy); - nsvg__addPath(p, 1); + nsvg__addPath(p, 1); - nsvg__addShape(p); - } + nsvg__addShape(p); + } } -static void nsvg__parseLine(NSVGparser* p, const char** attr) -{ - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - int i; +static void nsvg__parseLine(NSVGparser *p, const char **attr) { + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - } - } + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) + x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) + y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) + x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) + y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } - nsvg__resetPath(p); + nsvg__resetPath(p); - nsvg__moveTo(p, x1, y1); - nsvg__lineTo(p, x2, y2); + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); - nsvg__addPath(p, 0); + nsvg__addPath(p, 0); - nsvg__addShape(p); + nsvg__addShape(p); } -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) -{ - int i; - const char* s; - float args[2]; - int nargs, npts = 0; - char item[64]; +static void nsvg__parsePoly(NSVGparser *p, const char **attr, int closeFlag) { + int i; + const char *s; + float args[2]; + int nargs, npts = 0; + char item[64]; - nsvg__resetPath(p); + nsvg__resetPath(p); - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "points") == 0) { - s = attr[i + 1]; - nargs = 0; - while (*s) { - s = nsvg__getNextPathItem(s, item); - args[nargs++] = (float)nsvg__atof(item); - if (nargs >= 2) { - if (npts == 0) - nsvg__moveTo(p, args[0], args[1]); - else - nsvg__lineTo(p, args[0], args[1]); - nargs = 0; - npts++; - } - } - } - } - } + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } - nsvg__addPath(p, (char)closeFlag); + nsvg__addPath(p, (char)closeFlag); - nsvg__addShape(p); + nsvg__addShape(p); } -static void nsvg__parseSVG(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "width") == 0) { - p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); - } else if (strcmp(attr[i], "viewBox") == 0) { - const char *s = attr[i + 1]; - char buf[64]; - s = nsvg__parseNumber(s, buf, 64); - p->viewMinx = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewMiny = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewWidth = nsvg__atof(buf); - while (nsvg__isspace(*s) || *s == '%' || *s == ',') s++; - if (!*s) return; - s = nsvg__parseNumber(s, buf, 64); - p->viewHeight = nsvg__atof(buf); - } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { - if (strstr(attr[i + 1], "none") != 0) { - // No uniform scaling - p->alignType = NSVG_ALIGN_NONE; - } else { - // Parse X align - if (strstr(attr[i + 1], "xMin") != 0) - p->alignX = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "xMid") != 0) - p->alignX = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "xMax") != 0) - p->alignX = NSVG_ALIGN_MAX; - // Parse X align - if (strstr(attr[i + 1], "yMin") != 0) - p->alignY = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "yMid") != 0) - p->alignY = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "yMax") != 0) - p->alignY = NSVG_ALIGN_MAX; - // Parse meet/slice - p->alignType = NSVG_ALIGN_MEET; - if (strstr(attr[i + 1], "slice") != 0) - p->alignType = NSVG_ALIGN_SLICE; - } - } - } - } +static void nsvg__parseSVG(NSVGparser *p, const char **attr) { + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (nsvg__isspace(*s) || *s == '%' || *s == ',') + s++; + if (!*s) + return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } } -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) -{ - int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; - memset(grad, 0, sizeof(NSVGgradientData)); - grad->units = NSVG_OBJECT_SPACE; - grad->type = type; - if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { - grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); - grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { - grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - } +static void nsvg__parseGradient(NSVGparser *p, const char **attr, char type) { + int i; + NSVGgradientData *grad = (NSVGgradientData *)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) + return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } - nsvg__xformIdentity(grad->xform); + nsvg__xformIdentity(grad->xform); - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); - grad->id[63] = '\0'; - } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) - grad->units = NSVG_OBJECT_SPACE; - else - grad->units = NSVG_USER_SPACE; - } else if (strcmp(attr[i], "gradientTransform") == 0) { - nsvg__parseTransform(grad->xform, attr[i + 1]); - } else if (strcmp(attr[i], "cx") == 0) { - grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "cy") == 0) { - grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "r") == 0) { - grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fx") == 0) { - grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fy") == 0) { - grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x1") == 0) { - grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y1") == 0) { - grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x2") == 0) { - grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y2") == 0) { - grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) - grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) - grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) - grad->spread = NSVG_SPREAD_REPEAT; - } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); - grad->ref[62] = '\0'; - } - } - } + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i + 1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i + 1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i + 1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i + 1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i + 1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i + 1]; + strncpy(grad->ref, href + 1, 62); + grad->ref[62] = '\0'; + } + } + } - grad->next = p->gradients; - p->gradients = grad; + grad->next = p->gradients; + p->gradients = grad; } -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) -{ - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; - int i, idx; +static void nsvg__parseGradientStop(NSVGparser *p, const char **attr) { + NSVGattrib *curAttr = nsvg__getAttr(p); + NSVGgradientData *grad; + NSVGgradientStop *stop; + int i, idx; - curAttr->stopOffset = 0; - curAttr->stopColor = 0; - curAttr->stopOpacity = 1.0f; + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; - for (i = 0; attr[i]; i += 2) { - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } - // Add stop to the last gradient. - grad = p->gradients; - if (grad == NULL) return; + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) + return; - grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; + grad->nstops++; + grad->stops = (NSVGgradientStop *)realloc(grad->stops, sizeof(NSVGgradientStop) * grad->nstops); + if (grad->stops == NULL) + return; - // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { - if (curAttr->stopOffset < grad->stops[i].offset) { - idx = i; - break; - } - } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; - } + // Insert + idx = grad->nstops - 1; + for (i = 0; i < grad->nstops - 1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops - 1) { + for (i = grad->nstops - 1; i > idx; i--) + grad->stops[i] = grad->stops[i - 1]; + } - stop = &grad->stops[idx]; - stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; - stop->offset = curAttr->stopOffset; + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity * 255) << 24; + stop->offset = curAttr->stopOffset; } -static void nsvg__startElement(void* ud, const char* el, const char** attr) -{ - NSVGparser* p = (NSVGparser*)ud; +static void nsvg__startElement(void *ud, const char *el, const char **attr) { + NSVGparser *p = (NSVGparser *)ud; - if (p->defsFlag) { - // Skip everything but gradients in defs - if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } - return; - } + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } - if (strcmp(el, "g") == 0) { - nsvg__pushAttr(p); - nsvg__parseAttribs(p, attr); - } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. - return; - nsvg__pushAttr(p); - nsvg__parsePath(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "rect") == 0) { - nsvg__pushAttr(p); - nsvg__parseRect(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "circle") == 0) { - nsvg__pushAttr(p); - nsvg__parseCircle(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "ellipse") == 0) { - nsvg__pushAttr(p); - nsvg__parseEllipse(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { - nsvg__pushAttr(p); - nsvg__parseLine(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 0); - nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 1); - nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 1; - } else if (strcmp(el, "svg") == 0) { - nsvg__parseSVG(p, attr); - } + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } } -static void nsvg__endElement(void* ud, const char* el) -{ - NSVGparser* p = (NSVGparser*)ud; +static void nsvg__endElement(void *ud, const char *el) { + NSVGparser *p = (NSVGparser *)ud; - if (strcmp(el, "g") == 0) { - nsvg__popAttr(p); - } else if (strcmp(el, "path") == 0) { - p->pathFlag = 0; - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 0; - } + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } } -static void nsvg__content(void* ud, const char* s) -{ - NSVG_NOTUSED(ud); - NSVG_NOTUSED(s); - // empty +static void nsvg__content(void *ud, const char *s) { + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty } -static void nsvg__imageBounds(NSVGparser* p, float* bounds) -{ - NSVGshape* shape; - shape = p->image->shapes; - if (shape == NULL) { - bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; - return; - } - bounds[0] = shape->bounds[0]; - bounds[1] = shape->bounds[1]; - bounds[2] = shape->bounds[2]; - bounds[3] = shape->bounds[3]; - for (shape = shape->next; shape != NULL; shape = shape->next) { - bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); - bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); - bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); - bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); - } +static void nsvg__imageBounds(NSVGparser *p, float *bounds) { + NSVGshape *shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } } -static float nsvg__viewAlign(float content, float container, int type) -{ - if (type == NSVG_ALIGN_MIN) - return 0; - else if (type == NSVG_ALIGN_MAX) - return container - content; - // mid - return (container - content) * 0.5f; +static float nsvg__viewAlign(float content, float container, int type) { + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; } -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) -{ - float t[6]; - nsvg__xformSetTranslation(t, tx, ty); - nsvg__xformMultiply (grad->xform, t); +static void nsvg__scaleGradient(NSVGgradient *grad, float tx, float ty, float sx, float sy) { + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply(grad->xform, t); - nsvg__xformSetScale(t, sx, sy); - nsvg__xformMultiply (grad->xform, t); + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply(grad->xform, t); } -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) -{ - NSVGshape* shape; - NSVGpath* path; - float tx, ty, sx, sy, us, bounds[4], t[6], avgs; - int i; - float* pt; +static void nsvg__scaleToViewbox(NSVGparser *p, const char *units) { + NSVGshape *shape; + NSVGpath *path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float *pt; - // Guess image size if not set completely. - nsvg__imageBounds(p, bounds); + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); - if (p->viewWidth == 0) { - if (p->image->width > 0) { - p->viewWidth = p->image->width; - } else { - p->viewMinx = bounds[0]; - p->viewWidth = bounds[2] - bounds[0]; - } - } - if (p->viewHeight == 0) { - if (p->image->height > 0) { - p->viewHeight = p->image->height; - } else { - p->viewMiny = bounds[1]; - p->viewHeight = bounds[3] - bounds[1]; - } - } - if (p->image->width == 0) - p->image->width = p->viewWidth; - if (p->image->height == 0) - p->image->height = p->viewHeight; + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; - tx = -p->viewMinx; - ty = -p->viewMiny; - sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; - sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; - // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); - // Fix aspect ratio - if (p->alignType == NSVG_ALIGN_MEET) { - // fit whole image into viewbox - sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } else if (p->alignType == NSVG_ALIGN_SLICE) { - // fill whole viewbox with image - sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth * sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight * sy, p->image->height, p->alignY) / sy; + } - // Transform - sx *= us; - sy *= us; - avgs = (sx+sy) / 2.0f; - for (shape = p->image->shapes; shape != NULL; shape = shape->next) { - shape->bounds[0] = (shape->bounds[0] + tx) * sx; - shape->bounds[1] = (shape->bounds[1] + ty) * sy; - shape->bounds[2] = (shape->bounds[2] + tx) * sx; - shape->bounds[3] = (shape->bounds[3] + ty) * sy; - for (path = shape->paths; path != NULL; path = path->next) { - path->bounds[0] = (path->bounds[0] + tx) * sx; - path->bounds[1] = (path->bounds[1] + ty) * sy; - path->bounds[2] = (path->bounds[2] + tx) * sx; - path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; - pt[0] = (pt[0] + tx) * sx; - pt[1] = (pt[1] + ty) * sy; - } - } + // Transform + sx *= us; + sy *= us; + avgs = (sx + sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i = 0; i < path->npts; i++) { + pt = &path->pts[i * 2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->fill.gradient->xform, t); - } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->stroke.gradient->xform, t); - } + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx, ty, sx, sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx, ty, sx, sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float) * 6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } - shape->strokeWidth *= avgs; - shape->strokeDashOffset *= avgs; - for (i = 0; i < shape->strokeDashCount; i++) - shape->strokeDashArray[i] *= avgs; - } + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } } -NSVGimage* nsvgParse(char* input, const char* units, float dpi) -{ - NSVGparser* p; - NSVGimage* ret = 0; +NSVGimage *nsvgParse(char *input, const char *units, float dpi) { + NSVGparser *p; + NSVGimage *ret = 0; - p = nsvg__createParser(); - if (p == NULL) { - return NULL; - } - p->dpi = dpi; + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; - nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); - // Scale to viewBox - nsvg__scaleToViewbox(p, units); + // Scale to viewBox + nsvg__scaleToViewbox(p, units); - ret = p->image; - p->image = NULL; + ret = p->image; + p->image = NULL; - nsvg__deleteParser(p); + nsvg__deleteParser(p); - return ret; + return ret; } -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) -{ - FILE* fp = NULL; - size_t size; - char* data = NULL; - NSVGimage* image = NULL; +NSVGimage *nsvgParseFromFile(const char *filename, const char *units, float dpi) { + FILE *fp = NULL; + size_t size; + char *data = NULL; + NSVGimage *image = NULL; - fp = fopen(filename, "rb"); - if (!fp) goto error; - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. - fclose(fp); - image = nsvgParse(data, units, dpi); - free(data); + fp = fopen(filename, "rb"); + if (!fp) + goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char *)malloc(size + 1); + if (data == NULL) + goto error; + if (fread(data, 1, size, fp) != size) + goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); - return image; + return image; error: - if (fp) fclose(fp); - if (data) free(data); - if (image) nsvgDelete(image); - return NULL; + if (fp) + fclose(fp); + if (data) + free(data); + if (image) + nsvgDelete(image); + return NULL; } -NSVGpath* nsvgDuplicatePath(NSVGpath* p) -{ - NSVGpath* res = NULL; +NSVGpath *nsvgDuplicatePath(NSVGpath *p) { + NSVGpath *res = NULL; - if (p == NULL) - return NULL; + if (p == NULL) + return NULL; - res = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (res == NULL) goto error; - memset(res, 0, sizeof(NSVGpath)); + res = (NSVGpath *)malloc(sizeof(NSVGpath)); + if (res == NULL) + goto error; + memset(res, 0, sizeof(NSVGpath)); - res->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (res->pts == NULL) goto error; - memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); - res->npts = p->npts; + res->pts = (float *)malloc(p->npts * 2 * sizeof(float)); + if (res->pts == NULL) + goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; - memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); - res->closed = p->closed; + res->closed = p->closed; - return res; + return res; error: - if (res != NULL) { - free(res->pts); - free(res); - } - return NULL; + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; } -void nsvgDelete(NSVGimage* image) -{ - NSVGshape *snext, *shape; - if (image == NULL) return; - shape = image->shapes; - while (shape != NULL) { - snext = shape->next; - nsvg__deletePaths(shape->paths); - nsvg__deletePaint(&shape->fill); - nsvg__deletePaint(&shape->stroke); - free(shape); - shape = snext; - } - free(image); +void nsvgDelete(NSVGimage *image) { + NSVGshape *snext, *shape; + if (image == NULL) + return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); } #endif diff --git a/src/nsvg/vkvg_nsvg.c b/src/nsvg/vkvg_nsvg.c index 681471a..1e37caa 100644 --- a/src/nsvg/vkvg_nsvg.c +++ b/src/nsvg/vkvg_nsvg.c @@ -23,120 +23,114 @@ #include "vkvg_device_internal.h" #include "vkvg_context_internal.h" -#define NANOSVG_IMPLEMENTATION // Expands implementation +#define NANOSVG_IMPLEMENTATION // Expands implementation #include "nanosvg.h" #include "vkvg-svg.h" -void _svg_set_color (VkvgContext ctx, uint32_t c, float alpha) { - float a = (c >> 24 & 255) / 255.f; - float b = (c >> 16 & 255) / 255.f; - float g = (c >> 8 & 255) / 255.f; - float r = (c & 255) / 255.f; - vkvg_set_source_rgba(ctx,r,g,b,a*alpha); +void _svg_set_color(VkvgContext ctx, uint32_t c, float alpha) { + float a = (c >> 24 & 255) / 255.f; + float b = (c >> 16 & 255) / 255.f; + float g = (c >> 8 & 255) / 255.f; + float r = (c & 255) / 255.f; + vkvg_set_source_rgba(ctx, r, g, b, a * alpha); } -VkvgSurface _svg_load (VkvgDevice dev, NSVGimage* svg) { - if (svg == NULL) { - LOG(VKVG_LOG_ERR, "nsvg error"); - return NULL; - } - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (!surf) - return NULL; +VkvgSurface _svg_load(VkvgDevice dev, NSVGimage *svg) { + if (svg == NULL) { + LOG(VKVG_LOG_ERR, "nsvg error"); + return NULL; + } + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (!surf) + return NULL; - surf->width = (uint32_t)svg->width; - surf->height = (uint32_t)svg->height; - surf->newSurf = true; + surf->width = (uint32_t)svg->width; + surf->height = (uint32_t)svg->height; + surf->newSurf = true; - _create_surface_images (surf); + _create_surface_images(surf); - VkvgContext ctx = vkvg_create(surf); - vkvg_svg_render(svg, ctx, NULL); - vkvg_destroy(ctx); + VkvgContext ctx = vkvg_create(surf); + vkvg_svg_render(svg, ctx, NULL); + vkvg_destroy(ctx); - nsvgDelete(svg); + nsvgDelete(svg); - surf->references = 1; - vkvg_device_reference (surf->dev); + surf->references = 1; + vkvg_device_reference(surf->dev); - return surf; + return surf; } -VkvgSurface vkvg_surface_create_from_svg (VkvgDevice dev, uint32_t width, uint32_t height, const char* filePath) { - return _svg_load(dev, nsvgParseFromFile(filePath, "px", (float)dev->hdpi)); +VkvgSurface vkvg_surface_create_from_svg(VkvgDevice dev, uint32_t width, uint32_t height, const char *filePath) { + return _svg_load(dev, nsvgParseFromFile(filePath, "px", (float)dev->hdpi)); } -VkvgSurface vkvg_surface_create_from_svg_fragment (VkvgDevice dev, uint32_t width, uint32_t height, char* svgFragment) { - return _svg_load(dev, nsvgParse(svgFragment, "px", (float)dev->hdpi)); +VkvgSurface vkvg_surface_create_from_svg_fragment(VkvgDevice dev, uint32_t width, uint32_t height, char *svgFragment) { + return _svg_load(dev, nsvgParse(svgFragment, "px", (float)dev->hdpi)); } -VkvgSvg vkvg_svg_load (const char* svgFilePath) { - return nsvgParseFromFile(svgFilePath, "px", 96.0f); -} -VkvgSvg vkvg_svg_load_fragment (char* svgFragment) { - return nsvgParse (svgFragment, "px", 96.0f); -} -void vkvg_svg_destroy (VkvgSvg svg) { - nsvgDelete(svg); -} -void vkvg_svg_get_dimensions (VkvgSvg svg, uint32_t* width, uint32_t* height) { - *width = (uint32_t)svg->width; - *height = (uint32_t)svg->height; +VkvgSvg vkvg_svg_load(const char *svgFilePath) { return nsvgParseFromFile(svgFilePath, "px", 96.0f); } +VkvgSvg vkvg_svg_load_fragment(char *svgFragment) { return nsvgParse(svgFragment, "px", 96.0f); } +void vkvg_svg_destroy(VkvgSvg svg) { nsvgDelete(svg); } +void vkvg_svg_get_dimensions(VkvgSvg svg, uint32_t *width, uint32_t *height) { + *width = (uint32_t)svg->width; + *height = (uint32_t)svg->height; } -void vkvg_svg_render (VkvgSvg svg, VkvgContext ctx, const char* subId){ - NSVGshape* shape; - NSVGpath* path; - vkvg_save (ctx); +void vkvg_svg_render(VkvgSvg svg, VkvgContext ctx, const char *subId) { + NSVGshape *shape; + NSVGpath *path; + vkvg_save(ctx); - vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); + vkvg_set_fill_rule(ctx, VKVG_FILL_RULE_EVEN_ODD); - vkvg_set_source_rgba(ctx,0.0,0.0,0.0,1); + vkvg_set_source_rgba(ctx, 0.0, 0.0, 0.0, 1); - for (shape = svg->shapes; shape != NULL; shape = shape->next) { - if (subId != NULL) { - if (strcmp(shape->id, subId)!=0) - continue; - } + for (shape = svg->shapes; shape != NULL; shape = shape->next) { + if (subId != NULL) { + if (strcmp(shape->id, subId) != 0) + continue; + } - vkvg_new_path(ctx); + vkvg_new_path(ctx); - float o = shape->opacity; + float o = shape->opacity; - vkvg_set_line_width(ctx, shape->strokeWidth); + vkvg_set_line_width(ctx, shape->strokeWidth); - for (path = shape->paths; path != NULL; path = path->next) { - float* p = path->pts; - vkvg_move_to(ctx, p[0],p[1]); - for (int i = 1; i < path->npts; i += 3) { - p = &path->pts[i*2]; - vkvg_curve_to(ctx, p[0],p[1], p[2],p[3], p[4],p[5]); - } - if (path->closed) - vkvg_close_path(ctx); - } + for (path = shape->paths; path != NULL; path = path->next) { + float *p = path->pts; + vkvg_move_to(ctx, p[0], p[1]); + for (int i = 1; i < path->npts; i += 3) { + p = &path->pts[i * 2]; + vkvg_curve_to(ctx, p[0], p[1], p[2], p[3], p[4], p[5]); + } + if (path->closed) + vkvg_close_path(ctx); + } - if (shape->fill.type == NSVG_PAINT_COLOR) - _svg_set_color(ctx, shape->fill.color, o); - else if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT){ - NSVGgradient* g = shape->fill.gradient; - _svg_set_color(ctx, g->stops[0].color, o); - } + if (shape->fill.type == NSVG_PAINT_COLOR) + _svg_set_color(ctx, shape->fill.color, o); + else if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT) { + NSVGgradient *g = shape->fill.gradient; + _svg_set_color(ctx, g->stops[0].color, o); + } - if (shape->fill.type != NSVG_PAINT_NONE){ - if (shape->stroke.type == NSVG_PAINT_NONE){ - vkvg_fill(ctx); - continue; - } - vkvg_fill_preserve (ctx); - } + if (shape->fill.type != NSVG_PAINT_NONE) { + if (shape->stroke.type == NSVG_PAINT_NONE) { + vkvg_fill(ctx); + continue; + } + vkvg_fill_preserve(ctx); + } - if (shape->stroke.type == NSVG_PAINT_COLOR) - _svg_set_color(ctx, shape->stroke.color, o); - else if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT){ - NSVGgradient* g = shape->stroke.gradient; - _svg_set_color(ctx, g->stops[0].color, o); - } + if (shape->stroke.type == NSVG_PAINT_COLOR) + _svg_set_color(ctx, shape->stroke.color, o); + else if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT) { + NSVGgradient *g = shape->stroke.gradient; + _svg_set_color(ctx, g->stops[0].color, o); + } - vkvg_stroke(ctx); - } - vkvg_restore (ctx); + vkvg_stroke(ctx); + } + vkvg_restore(ctx); } diff --git a/src/recording/vkvg_record.c b/src/recording/vkvg_record.c index a70ee18..9184b5f 100644 --- a/src/recording/vkvg_record.c +++ b/src/recording/vkvg_record.c @@ -25,53 +25,52 @@ #include "vkvg_record_internal.h" #ifdef VKVG_RECORDING -void vkvg_start_recording (VkvgContext ctx) { - if (ctx->status) - return; - _start_recording(ctx); +void vkvg_start_recording(VkvgContext ctx) { + if (ctx->status) + return; + _start_recording(ctx); } -VkvgRecording vkvg_stop_recording (VkvgContext ctx) { - if (ctx->status) - return NULL; - return _stop_recording (ctx); +VkvgRecording vkvg_stop_recording(VkvgContext ctx) { + if (ctx->status) + return NULL; + return _stop_recording(ctx); } -uint32_t vkvg_recording_get_count (VkvgRecording rec) { - if (!rec) - return 0; - return rec->commandsCount; +uint32_t vkvg_recording_get_count(VkvgRecording rec) { + if (!rec) + return 0; + return rec->commandsCount; } -void* vkvg_recording_get_data (VkvgRecording rec) { - if (!rec) - return 0; - return rec->buffer; +void *vkvg_recording_get_data(VkvgRecording rec) { + if (!rec) + return 0; + return rec->buffer; } -void vkvg_recording_get_command (VkvgRecording rec, uint32_t cmdIndex, uint32_t* cmd, void** dataOffset) { - if (!rec) - return; - if (cmdIndex < rec->commandsCount) { - *cmd = rec->commands[cmdIndex].cmd; - *dataOffset = (void*)rec->commands[cmdIndex].dataOffset; - } else { - *cmd = 0; - *dataOffset = NULL; - } - +void vkvg_recording_get_command(VkvgRecording rec, uint32_t cmdIndex, uint32_t *cmd, void **dataOffset) { + if (!rec) + return; + if (cmdIndex < rec->commandsCount) { + *cmd = rec->commands[cmdIndex].cmd; + *dataOffset = (void *)rec->commands[cmdIndex].dataOffset; + } else { + *cmd = 0; + *dataOffset = NULL; + } } -void vkvg_replay (VkvgContext ctx, VkvgRecording rec) { - if (!rec) - return; - for (uint32_t i=0; i<rec->commandsCount; i++) - _replay_command(ctx, rec, i); +void vkvg_replay(VkvgContext ctx, VkvgRecording rec) { + if (!rec) + return; + for (uint32_t i = 0; i < rec->commandsCount; i++) + _replay_command(ctx, rec, i); } -void vkvg_replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex) { - if (!rec) - return; - if (cmdIndex < rec->commandsCount) - _replay_command(ctx, rec, cmdIndex); +void vkvg_replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t cmdIndex) { + if (!rec) + return; + if (cmdIndex < rec->commandsCount) + _replay_command(ctx, rec, cmdIndex); } -void vkvg_recording_destroy (VkvgRecording rec) { - if (!rec) - return; - _destroy_recording(rec); +void vkvg_recording_destroy(VkvgRecording rec) { + if (!rec) + return; + _destroy_recording(rec); } #endif diff --git a/src/recording/vkvg_record_internal.c b/src/recording/vkvg_record_internal.c index 29c91c9..e30363c 100644 --- a/src/recording/vkvg_record_internal.c +++ b/src/recording/vkvg_record_internal.c @@ -24,429 +24,419 @@ #include "vkvg_record_internal.h" #include "vkvg_context_internal.h" -#define VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD 64 -#define VKVG_RECORDING_INIT_BUFFER_SIZE 1024 -#define VKVG_RECORDING_INIT_COMMANDS_COUNT 64 +#define VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD 64 +#define VKVG_RECORDING_INIT_BUFFER_SIZE 1024 +#define VKVG_RECORDING_INIT_COMMANDS_COUNT 64 -vkvg_recording_t* _new_recording () { +vkvg_recording_t *_new_recording() { - vkvg_recording_t* rec = (vkvg_recording_t*)calloc(1,sizeof (vkvg_recording_t)); + vkvg_recording_t *rec = (vkvg_recording_t *)calloc(1, sizeof(vkvg_recording_t)); - rec->commandsReservedCount = VKVG_RECORDING_INIT_COMMANDS_COUNT; - rec->bufferReservedSize = VKVG_RECORDING_INIT_BUFFER_SIZE; - rec->commands = (vkvg_record_t*)malloc(rec->commandsReservedCount * sizeof (vkvg_record_t)); - rec->buffer = malloc (rec->bufferReservedSize); + rec->commandsReservedCount = VKVG_RECORDING_INIT_COMMANDS_COUNT; + rec->bufferReservedSize = VKVG_RECORDING_INIT_BUFFER_SIZE; + rec->commands = (vkvg_record_t *)malloc(rec->commandsReservedCount * sizeof(vkvg_record_t)); + rec->buffer = malloc(rec->bufferReservedSize); - return rec; + return rec; } -void _destroy_recording (vkvg_recording_t* rec) { - if (!rec) - return; - for (uint32_t i=0; i<rec->commandsCount; i++) { - if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE) - vkvg_pattern_destroy((VkvgPattern)(rec->buffer + rec->commands[i].dataOffset)); - else if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE_SURFACE) - vkvg_surface_destroy ((VkvgSurface)(rec->buffer + rec->commands[i].dataOffset + 2 * sizeof(float))); - } - free(rec->commands); - free(rec->buffer); - free(rec); +void _destroy_recording(vkvg_recording_t *rec) { + if (!rec) + return; + for (uint32_t i = 0; i < rec->commandsCount; i++) { + if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE) + vkvg_pattern_destroy((VkvgPattern)(rec->buffer + rec->commands[i].dataOffset)); + else if (rec->commands[i].cmd == VKVG_CMD_SET_SOURCE_SURFACE) + vkvg_surface_destroy((VkvgSurface)(rec->buffer + rec->commands[i].dataOffset + 2 * sizeof(float))); + } + free(rec->commands); + free(rec->buffer); + free(rec); } -void _start_recording (VkvgContext ctx) { - if (ctx->recording) - _destroy_recording(ctx->recording); - ctx->recording = _new_recording(); +void _start_recording(VkvgContext ctx) { + if (ctx->recording) + _destroy_recording(ctx->recording); + ctx->recording = _new_recording(); } -vkvg_recording_t* _stop_recording (VkvgContext ctx) { - vkvg_recording_t* rec = ctx->recording; - if (!rec) - return NULL; - if (!rec->commandsCount) { - _destroy_recording(rec); - ctx->recording = NULL; - return NULL; - } - /*rec->buffer = realloc(rec->buffer, rec->bufferSize); - rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsCount * sizeof (vkvg_record_t));*/ - ctx->recording = NULL; - return rec; +vkvg_recording_t *_stop_recording(VkvgContext ctx) { + vkvg_recording_t *rec = ctx->recording; + if (!rec) + return NULL; + if (!rec->commandsCount) { + _destroy_recording(rec); + ctx->recording = NULL; + return NULL; + } + /*rec->buffer = realloc(rec->buffer, rec->bufferSize); + rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsCount * sizeof (vkvg_record_t));*/ + ctx->recording = NULL; + return rec; } -void* _ensure_recording_buffer (vkvg_recording_t* rec, size_t size) { - if (rec->bufferReservedSize >= rec->bufferSize - VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD - size) { - rec->bufferReservedSize += VKVG_RECORDING_INIT_BUFFER_SIZE; - rec->buffer = realloc(rec->buffer, rec->bufferReservedSize); - } - return rec->buffer + rec->bufferSize; +void *_ensure_recording_buffer(vkvg_recording_t *rec, size_t size) { + if (rec->bufferReservedSize >= rec->bufferSize - VKVG_RECORDING_INIT_BUFFER_SIZE_TRESHOLD - size) { + rec->bufferReservedSize += VKVG_RECORDING_INIT_BUFFER_SIZE; + rec->buffer = realloc(rec->buffer, rec->bufferReservedSize); + } + return rec->buffer + rec->bufferSize; } -void* _advance_recording_buffer_unchecked (vkvg_recording_t* rec, size_t size) { - rec->bufferSize += size; - return rec->buffer + rec->bufferSize; +void *_advance_recording_buffer_unchecked(vkvg_recording_t *rec, size_t size) { + rec->bufferSize += size; + return rec->buffer + rec->bufferSize; } -#define STORE_FLOATS(floatcount) \ - for (i=0; i<floatcount; i++) { \ - buff = _ensure_recording_buffer (rec, sizeof(float)); \ - *(float*)buff = (float)va_arg(args, double); \ - buff = _advance_recording_buffer_unchecked (rec, sizeof(float));\ - } -#define STORE_BOOLS(count) \ - for (i=0; i<count; i++) { \ - buff = _ensure_recording_buffer (rec, sizeof(bool)); \ - *(bool*)buff = (bool)va_arg(args, int); \ - _advance_recording_buffer_unchecked (rec, sizeof(bool)); \ - } -#define STORE_UINT32(count) \ - for (i=0; i<count; i++) { \ - buff = _ensure_recording_buffer (rec, sizeof(uint32_t)); \ - *(uint32_t*)buff = (uint32_t)va_arg(args, uint32_t); \ - buff = _advance_recording_buffer_unchecked (rec, sizeof(uint32_t)); \ - } +#define STORE_FLOATS(floatcount) \ + for (i = 0; i < floatcount; i++) { \ + buff = _ensure_recording_buffer(rec, sizeof(float)); \ + *(float *)buff = (float)va_arg(args, double); \ + buff = _advance_recording_buffer_unchecked(rec, sizeof(float)); \ + } +#define STORE_BOOLS(count) \ + for (i = 0; i < count; i++) { \ + buff = _ensure_recording_buffer(rec, sizeof(bool)); \ + *(bool *)buff = (bool)va_arg(args, int); \ + _advance_recording_buffer_unchecked(rec, sizeof(bool)); \ + } +#define STORE_UINT32(count) \ + for (i = 0; i < count; i++) { \ + buff = _ensure_recording_buffer(rec, sizeof(uint32_t)); \ + *(uint32_t *)buff = (uint32_t)va_arg(args, uint32_t); \ + buff = _advance_recording_buffer_unchecked(rec, sizeof(uint32_t)); \ + } -void _record (vkvg_recording_t* rec,...) { - va_list args; - va_start(args, rec); +void _record(vkvg_recording_t *rec, ...) { + va_list args; + va_start(args, rec); - uint32_t cmd = va_arg(args, uint32_t); + uint32_t cmd = va_arg(args, uint32_t); - if (rec->commandsCount == rec->commandsReservedCount) { - rec->commandsReservedCount += VKVG_RECORDING_INIT_COMMANDS_COUNT; - rec->commands = (vkvg_record_t*)realloc(rec->commands, rec->commandsReservedCount * sizeof (vkvg_record_t)); - } - vkvg_record_t* r = &rec->commands[rec->commandsCount++]; - r->cmd = cmd; - r->dataOffset = rec->bufferSize; + if (rec->commandsCount == rec->commandsReservedCount) { + rec->commandsReservedCount += VKVG_RECORDING_INIT_COMMANDS_COUNT; + rec->commands = (vkvg_record_t *)realloc(rec->commands, rec->commandsReservedCount * sizeof(vkvg_record_t)); + } + vkvg_record_t *r = &rec->commands[rec->commandsCount++]; + r->cmd = cmd; + r->dataOffset = rec->bufferSize; - char* buff; - int i = 0; + char *buff; + int i = 0; - if (cmd & VKVG_CMD_PATH_COMMANDS) { - if ((cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_LINE_WIDTH: - case VKVG_CMD_SET_MITER_LIMIT: - STORE_FLOATS(1); - break; - case VKVG_CMD_SET_LINE_JOIN: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_LINE_CAP: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_OPERATOR: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_FILL_RULE: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_DASH: - break; - } - } else { - switch (cmd) { - case VKVG_CMD_MOVE_TO: - case VKVG_CMD_LINE_TO: - case VKVG_CMD_REL_MOVE_TO: - case VKVG_CMD_REL_LINE_TO: - STORE_FLOATS(2); - break; - case VKVG_CMD_RECTANGLE: - case VKVG_CMD_QUADRATIC_TO: - case VKVG_CMD_REL_QUADRATIC_TO: - STORE_FLOATS(4); - break; - case VKVG_CMD_ARC: - case VKVG_CMD_ARC_NEG: - STORE_FLOATS(5); - break; - case VKVG_CMD_CURVE_TO: - case VKVG_CMD_REL_CURVE_TO: - STORE_FLOATS(6); - break; - case VKVG_CMD_ELLIPTICAL_ARC_TO: - case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: - STORE_FLOATS(5); - STORE_BOOLS(2); - break; - case VKVG_CMD_NEW_PATH: - case VKVG_CMD_NEW_SUB_PATH: - case VKVG_CMD_CLOSE_PATH: - break; - } - } - } else if (!(r->cmd & VKVG_CMD_DRAW_COMMANDS)) { - if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_TRANSLATE: - case VKVG_CMD_SCALE: - STORE_FLOATS(2); - break; - case VKVG_CMD_ROTATE: - STORE_FLOATS(1); - break; - case VKVG_CMD_IDENTITY_MATRIX: - break; - case VKVG_CMD_SET_MATRIX: - case VKVG_CMD_TRANSFORM: - { - buff = _ensure_recording_buffer (rec, sizeof(vkvg_matrix_t)); - vkvg_matrix_t* mat = (vkvg_matrix_t*)va_arg(args, vkvg_matrix_t*); - memcpy(buff, mat, sizeof(vkvg_matrix_t)); - buff = _advance_recording_buffer_unchecked (rec, sizeof(vkvg_matrix_t)); + if (cmd & VKVG_CMD_PATH_COMMANDS) { + if ((cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_LINE_WIDTH: + case VKVG_CMD_SET_MITER_LIMIT: + STORE_FLOATS(1); + break; + case VKVG_CMD_SET_LINE_JOIN: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_LINE_CAP: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_OPERATOR: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_FILL_RULE: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_DASH: + break; + } + } else { + switch (cmd) { + case VKVG_CMD_MOVE_TO: + case VKVG_CMD_LINE_TO: + case VKVG_CMD_REL_MOVE_TO: + case VKVG_CMD_REL_LINE_TO: + STORE_FLOATS(2); + break; + case VKVG_CMD_RECTANGLE: + case VKVG_CMD_QUADRATIC_TO: + case VKVG_CMD_REL_QUADRATIC_TO: + STORE_FLOATS(4); + break; + case VKVG_CMD_ARC: + case VKVG_CMD_ARC_NEG: + STORE_FLOATS(5); + break; + case VKVG_CMD_CURVE_TO: + case VKVG_CMD_REL_CURVE_TO: + STORE_FLOATS(6); + break; + case VKVG_CMD_ELLIPTICAL_ARC_TO: + case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: + STORE_FLOATS(5); + STORE_BOOLS(2); + break; + case VKVG_CMD_NEW_PATH: + case VKVG_CMD_NEW_SUB_PATH: + case VKVG_CMD_CLOSE_PATH: + break; + } + } + } else if (!(r->cmd & VKVG_CMD_DRAW_COMMANDS)) { + if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_TRANSLATE: + case VKVG_CMD_SCALE: + STORE_FLOATS(2); + break; + case VKVG_CMD_ROTATE: + STORE_FLOATS(1); + break; + case VKVG_CMD_IDENTITY_MATRIX: + break; + case VKVG_CMD_SET_MATRIX: + case VKVG_CMD_TRANSFORM: { + buff = _ensure_recording_buffer(rec, sizeof(vkvg_matrix_t)); + vkvg_matrix_t *mat = (vkvg_matrix_t *)va_arg(args, vkvg_matrix_t *); + memcpy(buff, mat, sizeof(vkvg_matrix_t)); + buff = _advance_recording_buffer_unchecked(rec, sizeof(vkvg_matrix_t)); - } - break; - } - } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_SOURCE_RGBA: - STORE_FLOATS(4); - break; - case VKVG_CMD_SET_SOURCE_RGB: - STORE_FLOATS(3); - break; - case VKVG_CMD_SET_SOURCE_COLOR: - STORE_UINT32(1); - break; - case VKVG_CMD_SET_SOURCE: - { - buff = _ensure_recording_buffer (rec, sizeof(VkvgPattern)); - VkvgPattern pat = (VkvgPattern)va_arg(args, VkvgPattern); - vkvg_pattern_reference(pat); - VkvgPattern* pPat = (VkvgPattern*)buff; - *pPat = pat; - _advance_recording_buffer_unchecked (rec, sizeof(VkvgPattern)); - } - break; - case VKVG_CMD_SET_SOURCE_SURFACE: - STORE_FLOATS(2); - { - buff = _ensure_recording_buffer (rec, sizeof(VkvgSurface)); - VkvgSurface surf = (VkvgSurface)va_arg(args, VkvgSurface); - vkvg_surface_reference(surf); - *(VkvgSurface*)buff = surf; - _advance_recording_buffer_unchecked (rec, sizeof(VkvgSurface)); - } - break; - } - } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { - char* txt; - int txtLen; - switch (r->cmd) { - case VKVG_CMD_SET_FONT_SIZE: - STORE_UINT32(1); - break; - case VKVG_CMD_SHOW_TEXT: - case VKVG_CMD_SET_FONT_FACE: - txt = (char*)va_arg(args, char*); - txtLen = strlen(txt); - buff = _ensure_recording_buffer (rec, txtLen * sizeof(char)); - strcpy(buff, txt); - _advance_recording_buffer_unchecked (rec, txtLen * sizeof(char)); - break; - case VKVG_CMD_SET_FONT_PATH: - break; - } - } - } - va_end(args); + } break; + } + } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_SOURCE_RGBA: + STORE_FLOATS(4); + break; + case VKVG_CMD_SET_SOURCE_RGB: + STORE_FLOATS(3); + break; + case VKVG_CMD_SET_SOURCE_COLOR: + STORE_UINT32(1); + break; + case VKVG_CMD_SET_SOURCE: { + buff = _ensure_recording_buffer(rec, sizeof(VkvgPattern)); + VkvgPattern pat = (VkvgPattern)va_arg(args, VkvgPattern); + vkvg_pattern_reference(pat); + VkvgPattern *pPat = (VkvgPattern *)buff; + *pPat = pat; + _advance_recording_buffer_unchecked(rec, sizeof(VkvgPattern)); + } break; + case VKVG_CMD_SET_SOURCE_SURFACE: + STORE_FLOATS(2); + { + buff = _ensure_recording_buffer(rec, sizeof(VkvgSurface)); + VkvgSurface surf = (VkvgSurface)va_arg(args, VkvgSurface); + vkvg_surface_reference(surf); + *(VkvgSurface *)buff = surf; + _advance_recording_buffer_unchecked(rec, sizeof(VkvgSurface)); + } + break; + } + } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { + char *txt; + int txtLen; + switch (r->cmd) { + case VKVG_CMD_SET_FONT_SIZE: + STORE_UINT32(1); + break; + case VKVG_CMD_SHOW_TEXT: + case VKVG_CMD_SET_FONT_FACE: + txt = (char *)va_arg(args, char *); + txtLen = strlen(txt); + buff = _ensure_recording_buffer(rec, txtLen * sizeof(char)); + strcpy(buff, txt); + _advance_recording_buffer_unchecked(rec, txtLen * sizeof(char)); + break; + case VKVG_CMD_SET_FONT_PATH: + break; + } + } + } + va_end(args); } -void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index) { - vkvg_record_t* r = &rec->commands[index]; - float* floats = (float*)(rec->buffer + r->dataOffset); - uint32_t* uints = (uint32_t*)floats; - if (r->cmd&VKVG_CMD_PATH_COMMANDS) { - if ((r->cmd&VKVG_CMD_RELATIVE_COMMANDS)==VKVG_CMD_RELATIVE_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_REL_MOVE_TO: - vkvg_rel_move_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_REL_LINE_TO: - vkvg_rel_line_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_REL_CURVE_TO: - vkvg_rel_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); - return; - case VKVG_CMD_REL_QUADRATIC_TO: - vkvg_rel_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: - { - bool* flags = (bool*)&floats[5]; - vkvg_rel_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); - } - return; - } - }else if ((r->cmd&VKVG_CMD_PATHPROPS_COMMANDS)==VKVG_CMD_PATHPROPS_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_LINE_WIDTH: - vkvg_set_line_width (ctx, floats[0]); - return; - case VKVG_CMD_SET_MITER_LIMIT: - vkvg_set_miter_limit (ctx, floats[0]); - return; - case VKVG_CMD_SET_LINE_JOIN: - vkvg_set_line_join (ctx, (vkvg_line_join_t)uints[0]); - return; - case VKVG_CMD_SET_LINE_CAP: - vkvg_set_line_cap (ctx, (vkvg_line_cap_t)uints[0]); - return; - case VKVG_CMD_SET_OPERATOR: - vkvg_set_operator (ctx, (vkvg_operator_t)uints[0]); - return; - case VKVG_CMD_SET_FILL_RULE: - vkvg_set_fill_rule (ctx, (vkvg_fill_rule_t)uints[0]); - return; - case VKVG_CMD_SET_DASH: - vkvg_set_dash(ctx, &floats[2], uints[0], floats[1]); - return; - } - } else { - switch (r->cmd) { - case VKVG_CMD_NEW_PATH: - vkvg_new_path (ctx); - return; - case VKVG_CMD_NEW_SUB_PATH: - vkvg_new_sub_path (ctx); - return; - case VKVG_CMD_CLOSE_PATH: - vkvg_close_path (ctx); - return; - case VKVG_CMD_RECTANGLE: - vkvg_rectangle (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_ARC: - vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - return; - case VKVG_CMD_ARC_NEG: - vkvg_arc (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - return; - /*case VKVG_CMD_ELLIPSE: - vkvg_ellipse (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); - break;*/ - case VKVG_CMD_MOVE_TO: - vkvg_move_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_LINE_TO: - vkvg_line_to(ctx, floats[0], floats[1]); - return; - case VKVG_CMD_CURVE_TO: - vkvg_curve_to (ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); - return; - case VKVG_CMD_ELLIPTICAL_ARC_TO: - { - bool* flags = (bool*)&floats[5]; - vkvg_elliptic_arc_to (ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); - } - return; - case VKVG_CMD_QUADRATIC_TO: - vkvg_quadratic_to (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - } - } - } else if (r->cmd & VKVG_CMD_DRAW_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_PAINT: - vkvg_paint (ctx); - return; - case VKVG_CMD_FILL: - vkvg_fill (ctx); - return; - case VKVG_CMD_STROKE: - vkvg_stroke (ctx); - return; - case VKVG_CMD_CLIP: - vkvg_clip (ctx); - return; - case VKVG_CMD_CLEAR: - vkvg_clear (ctx); - return; - case VKVG_CMD_FILL_PRESERVE: - vkvg_fill_preserve (ctx); - return; - case VKVG_CMD_STROKE_PRESERVE: - vkvg_stroke_preserve (ctx); - return; - case VKVG_CMD_CLIP_PRESERVE: - vkvg_clip_preserve (ctx); - return; - } - } else if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_TRANSLATE: - vkvg_translate (ctx, floats[0], floats[1]); - return; - case VKVG_CMD_SCALE: - vkvg_scale (ctx, floats[0], floats[1]); - return; - case VKVG_CMD_ROTATE: - vkvg_rotate (ctx, floats[0]); - return; - case VKVG_CMD_IDENTITY_MATRIX: - vkvg_identity_matrix (ctx); - return; - case VKVG_CMD_TRANSFORM: - { - vkvg_matrix_t* mat = (vkvg_matrix_t*)&floats[0]; - vkvg_transform (ctx, mat); - } - return; - case VKVG_CMD_SET_MATRIX: - { - vkvg_matrix_t* mat = (vkvg_matrix_t*)&floats[0]; - vkvg_set_matrix (ctx, mat); - } - return; - } - } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { - switch (r->cmd) { - case VKVG_CMD_SET_SOURCE_RGB: - vkvg_set_source_rgb (ctx, floats[0], floats[1], floats[2]); - return; - case VKVG_CMD_SET_SOURCE_RGBA: - vkvg_set_source_rgba (ctx, floats[0], floats[1], floats[2], floats[3]); - return; - case VKVG_CMD_SET_SOURCE_COLOR: - vkvg_set_source_color (ctx, uints[0]); - return; - case VKVG_CMD_SET_SOURCE: - { - VkvgPattern pat = *((VkvgPattern*)(rec->buffer + r->dataOffset)); - vkvg_set_source (ctx, pat); - } - return; - case VKVG_CMD_SET_SOURCE_SURFACE: - { - VkvgSurface surf = *((VkvgSurface*)&floats[2]); - vkvg_set_source_surface (ctx, surf, floats[0], floats[1]); - } - return; - } - } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { - char* txt = (char*)floats; - switch (r->cmd) { - case VKVG_CMD_SET_FONT_SIZE: - vkvg_set_font_size (ctx, uints[0]); - return; - case VKVG_CMD_SET_FONT_FACE: - vkvg_select_font_face (ctx, txt); - return; - /*case VKVG_CMD_SET_FONT_PATH: - vkvg_load_font_from_path (ctx, txt); - return; */ - case VKVG_CMD_SHOW_TEXT: - vkvg_show_text (ctx, txt); - return; - } - } else { - switch (r->cmd) { - case VKVG_CMD_SAVE: - vkvg_save (ctx); - return; - case VKVG_CMD_RESTORE: - vkvg_restore (ctx); - return; - } - } - LOG(VKVG_LOG_ERR, "[REPLAY] unimplemented command: %.4x\n", r->cmd); +void _replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t index) { + vkvg_record_t *r = &rec->commands[index]; + float *floats = (float *)(rec->buffer + r->dataOffset); + uint32_t *uints = (uint32_t *)floats; + if (r->cmd & VKVG_CMD_PATH_COMMANDS) { + if ((r->cmd & VKVG_CMD_RELATIVE_COMMANDS) == VKVG_CMD_RELATIVE_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_REL_MOVE_TO: + vkvg_rel_move_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_REL_LINE_TO: + vkvg_rel_line_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_REL_CURVE_TO: + vkvg_rel_curve_to(ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); + return; + case VKVG_CMD_REL_QUADRATIC_TO: + vkvg_rel_quadratic_to(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_REL_ELLIPTICAL_ARC_TO: { + bool *flags = (bool *)&floats[5]; + vkvg_rel_elliptic_arc_to(ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], + floats[4]); + } + return; + } + } else if ((r->cmd & VKVG_CMD_PATHPROPS_COMMANDS) == VKVG_CMD_PATHPROPS_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_LINE_WIDTH: + vkvg_set_line_width(ctx, floats[0]); + return; + case VKVG_CMD_SET_MITER_LIMIT: + vkvg_set_miter_limit(ctx, floats[0]); + return; + case VKVG_CMD_SET_LINE_JOIN: + vkvg_set_line_join(ctx, (vkvg_line_join_t)uints[0]); + return; + case VKVG_CMD_SET_LINE_CAP: + vkvg_set_line_cap(ctx, (vkvg_line_cap_t)uints[0]); + return; + case VKVG_CMD_SET_OPERATOR: + vkvg_set_operator(ctx, (vkvg_operator_t)uints[0]); + return; + case VKVG_CMD_SET_FILL_RULE: + vkvg_set_fill_rule(ctx, (vkvg_fill_rule_t)uints[0]); + return; + case VKVG_CMD_SET_DASH: + vkvg_set_dash(ctx, &floats[2], uints[0], floats[1]); + return; + } + } else { + switch (r->cmd) { + case VKVG_CMD_NEW_PATH: + vkvg_new_path(ctx); + return; + case VKVG_CMD_NEW_SUB_PATH: + vkvg_new_sub_path(ctx); + return; + case VKVG_CMD_CLOSE_PATH: + vkvg_close_path(ctx); + return; + case VKVG_CMD_RECTANGLE: + vkvg_rectangle(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_ARC: + vkvg_arc(ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + return; + case VKVG_CMD_ARC_NEG: + vkvg_arc(ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + return; + /*case VKVG_CMD_ELLIPSE: + vkvg_ellipse (ctx, floats[0], floats[1], floats[2], floats[3], floats[4]); + break;*/ + case VKVG_CMD_MOVE_TO: + vkvg_move_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_LINE_TO: + vkvg_line_to(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_CURVE_TO: + vkvg_curve_to(ctx, floats[0], floats[1], floats[2], floats[3], floats[4], floats[5]); + return; + case VKVG_CMD_ELLIPTICAL_ARC_TO: { + bool *flags = (bool *)&floats[5]; + vkvg_elliptic_arc_to(ctx, floats[0], floats[1], flags[0], flags[1], floats[2], floats[3], floats[4]); + } + return; + case VKVG_CMD_QUADRATIC_TO: + vkvg_quadratic_to(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + } + } + } else if (r->cmd & VKVG_CMD_DRAW_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_PAINT: + vkvg_paint(ctx); + return; + case VKVG_CMD_FILL: + vkvg_fill(ctx); + return; + case VKVG_CMD_STROKE: + vkvg_stroke(ctx); + return; + case VKVG_CMD_CLIP: + vkvg_clip(ctx); + return; + case VKVG_CMD_CLEAR: + vkvg_clear(ctx); + return; + case VKVG_CMD_FILL_PRESERVE: + vkvg_fill_preserve(ctx); + return; + case VKVG_CMD_STROKE_PRESERVE: + vkvg_stroke_preserve(ctx); + return; + case VKVG_CMD_CLIP_PRESERVE: + vkvg_clip_preserve(ctx); + return; + } + } else if (r->cmd & VKVG_CMD_TRANSFORM_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_TRANSLATE: + vkvg_translate(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_SCALE: + vkvg_scale(ctx, floats[0], floats[1]); + return; + case VKVG_CMD_ROTATE: + vkvg_rotate(ctx, floats[0]); + return; + case VKVG_CMD_IDENTITY_MATRIX: + vkvg_identity_matrix(ctx); + return; + case VKVG_CMD_TRANSFORM: { + vkvg_matrix_t *mat = (vkvg_matrix_t *)&floats[0]; + vkvg_transform(ctx, mat); + } + return; + case VKVG_CMD_SET_MATRIX: { + vkvg_matrix_t *mat = (vkvg_matrix_t *)&floats[0]; + vkvg_set_matrix(ctx, mat); + } + return; + } + } else if (r->cmd & VKVG_CMD_PATTERN_COMMANDS) { + switch (r->cmd) { + case VKVG_CMD_SET_SOURCE_RGB: + vkvg_set_source_rgb(ctx, floats[0], floats[1], floats[2]); + return; + case VKVG_CMD_SET_SOURCE_RGBA: + vkvg_set_source_rgba(ctx, floats[0], floats[1], floats[2], floats[3]); + return; + case VKVG_CMD_SET_SOURCE_COLOR: + vkvg_set_source_color(ctx, uints[0]); + return; + case VKVG_CMD_SET_SOURCE: { + VkvgPattern pat = *((VkvgPattern *)(rec->buffer + r->dataOffset)); + vkvg_set_source(ctx, pat); + } + return; + case VKVG_CMD_SET_SOURCE_SURFACE: { + VkvgSurface surf = *((VkvgSurface *)&floats[2]); + vkvg_set_source_surface(ctx, surf, floats[0], floats[1]); + } + return; + } + } else if (r->cmd & VKVG_CMD_TEXT_COMMANDS) { + char *txt = (char *)floats; + switch (r->cmd) { + case VKVG_CMD_SET_FONT_SIZE: + vkvg_set_font_size(ctx, uints[0]); + return; + case VKVG_CMD_SET_FONT_FACE: + vkvg_select_font_face(ctx, txt); + return; + /*case VKVG_CMD_SET_FONT_PATH: + vkvg_load_font_from_path (ctx, txt); + return; */ + case VKVG_CMD_SHOW_TEXT: + vkvg_show_text(ctx, txt); + return; + } + } else { + switch (r->cmd) { + case VKVG_CMD_SAVE: + vkvg_save(ctx); + return; + case VKVG_CMD_RESTORE: + vkvg_restore(ctx); + return; + } + } + LOG(VKVG_LOG_ERR, "[REPLAY] unimplemented command: %.4x\n", r->cmd); } - diff --git a/src/recording/vkvg_record_internal.h b/src/recording/vkvg_record_internal.h index c18801a..fcc905f 100644 --- a/src/recording/vkvg_record_internal.h +++ b/src/recording/vkvg_record_internal.h @@ -25,110 +25,108 @@ #include "vkvg.h" #include "vkvg_internal.h" -#define VKVG_CMD_SAVE 0x0001 -#define VKVG_CMD_RESTORE 0x0002 +#define VKVG_CMD_SAVE 0x0001 +#define VKVG_CMD_RESTORE 0x0002 -#define VKVG_CMD_PATH_COMMANDS 0x0100 -#define VKVG_CMD_DRAW_COMMANDS 0x0200 -#define VKVG_CMD_RELATIVE_COMMANDS (0x0400|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_PATHPROPS_COMMANDS (0x1000|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_PRESERVE_COMMANDS (0x0400|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_PATTERN_COMMANDS 0x0800 -#define VKVG_CMD_TRANSFORM_COMMANDS 0x2000 -#define VKVG_CMD_TEXT_COMMANDS 0x4000 +#define VKVG_CMD_PATH_COMMANDS 0x0100 +#define VKVG_CMD_DRAW_COMMANDS 0x0200 +#define VKVG_CMD_RELATIVE_COMMANDS (0x0400 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_PATHPROPS_COMMANDS (0x1000 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_PRESERVE_COMMANDS (0x0400 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_PATTERN_COMMANDS 0x0800 +#define VKVG_CMD_TRANSFORM_COMMANDS 0x2000 +#define VKVG_CMD_TEXT_COMMANDS 0x4000 -#define VKVG_CMD_NEW_PATH (0x0001|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_NEW_SUB_PATH (0x0002|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_CLOSE_PATH (0x0003|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_MOVE_TO (0x0004|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_LINE_TO (0x0005|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_RECTANGLE (0x0006|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ARC (0x0007|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ARC_NEG (0x0008|VKVG_CMD_PATH_COMMANDS) -//#define VKVG_CMD_ELLIPSE (0x0009|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_CURVE_TO (0x000A|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_QUADRATIC_TO (0x000B|VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_ELLIPTICAL_ARC_TO (0x000C|VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_NEW_PATH (0x0001 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_NEW_SUB_PATH (0x0002 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_CLOSE_PATH (0x0003 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_MOVE_TO (0x0004 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_LINE_TO (0x0005 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_RECTANGLE (0x0006 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ARC (0x0007 | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ARC_NEG (0x0008 | VKVG_CMD_PATH_COMMANDS) +// #define VKVG_CMD_ELLIPSE (0x0009|VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_CURVE_TO (0x000A | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_QUADRATIC_TO (0x000B | VKVG_CMD_PATH_COMMANDS) +#define VKVG_CMD_ELLIPTICAL_ARC_TO (0x000C | VKVG_CMD_PATH_COMMANDS) -#define VKVG_CMD_SET_LINE_WIDTH (0x0001|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_MITER_LIMIT (0x0002|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_JOIN (0x0003|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_LINE_CAP (0x0004|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_OPERATOR (0x0005|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_FILL_RULE (0x0006|VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_SET_DASH (0x0007|VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_WIDTH (0x0001 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_MITER_LIMIT (0x0002 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_JOIN (0x0003 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_LINE_CAP (0x0004 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_OPERATOR (0x0005 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_FILL_RULE (0x0006 | VKVG_CMD_PATHPROPS_COMMANDS) +#define VKVG_CMD_SET_DASH (0x0007 | VKVG_CMD_PATHPROPS_COMMANDS) -#define VKVG_CMD_TRANSLATE (0x0001|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_ROTATE (0x0002|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_SCALE (0x0003|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_TRANSFORM (0x0004|VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_IDENTITY_MATRIX (0x0005|VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_TRANSLATE (0x0001 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_ROTATE (0x0002 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_SCALE (0x0003 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_TRANSFORM (0x0004 | VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_IDENTITY_MATRIX (0x0005 | VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_SET_MATRIX (0x0006|VKVG_CMD_TRANSFORM_COMMANDS) +#define VKVG_CMD_SET_MATRIX (0x0006 | VKVG_CMD_TRANSFORM_COMMANDS) -#define VKVG_CMD_SET_FONT_SIZE (0x0001|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SET_FONT_FACE (0x0002|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SET_FONT_PATH (0x0003|VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_SHOW_TEXT (0x0004|VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SET_FONT_SIZE (0x0001 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SET_FONT_FACE (0x0002 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SET_FONT_PATH (0x0003 | VKVG_CMD_TEXT_COMMANDS) +#define VKVG_CMD_SHOW_TEXT (0x0004 | VKVG_CMD_TEXT_COMMANDS) -#define VKVG_CMD_REL_MOVE_TO (VKVG_CMD_MOVE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_LINE_TO (VKVG_CMD_LINE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_CURVE_TO (VKVG_CMD_CURVE_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_QUADRATIC_TO (VKVG_CMD_QUADRATIC_TO |VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_REL_ELLIPTICAL_ARC_TO (VKVG_CMD_ELLIPTICAL_ARC_TO |VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_MOVE_TO (VKVG_CMD_MOVE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_LINE_TO (VKVG_CMD_LINE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_CURVE_TO (VKVG_CMD_CURVE_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_QUADRATIC_TO (VKVG_CMD_QUADRATIC_TO | VKVG_CMD_RELATIVE_COMMANDS) +#define VKVG_CMD_REL_ELLIPTICAL_ARC_TO (VKVG_CMD_ELLIPTICAL_ARC_TO | VKVG_CMD_RELATIVE_COMMANDS) -#define VKVG_CMD_PAINT (0x0001|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_FILL (0x0002|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_STROKE (0x0003|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_CLIP (0x0004|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_RESET_CLIP (0x0005|VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_CLEAR (0x0006|VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_PAINT (0x0001 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_FILL (0x0002 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_STROKE (0x0003 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_CLIP (0x0004 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_RESET_CLIP (0x0005 | VKVG_CMD_DRAW_COMMANDS) +#define VKVG_CMD_CLEAR (0x0006 | VKVG_CMD_DRAW_COMMANDS) -#define VKVG_CMD_FILL_PRESERVE (VKVG_CMD_FILL |VKVG_CMD_PRESERVE_COMMANDS) -#define VKVG_CMD_STROKE_PRESERVE (VKVG_CMD_STROKE |VKVG_CMD_PRESERVE_COMMANDS) -#define VKVG_CMD_CLIP_PRESERVE (VKVG_CMD_CLIP |VKVG_CMD_PRESERVE_COMMANDS) +#define VKVG_CMD_FILL_PRESERVE (VKVG_CMD_FILL | VKVG_CMD_PRESERVE_COMMANDS) +#define VKVG_CMD_STROKE_PRESERVE (VKVG_CMD_STROKE | VKVG_CMD_PRESERVE_COMMANDS) +#define VKVG_CMD_CLIP_PRESERVE (VKVG_CMD_CLIP | VKVG_CMD_PRESERVE_COMMANDS) -#define VKVG_CMD_SET_SOURCE_RGB (0x0001|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_RGBA (0x0002|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_COLOR (0x0003|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE (0x0004|VKVG_CMD_PATTERN_COMMANDS) -#define VKVG_CMD_SET_SOURCE_SURFACE (0x0005|VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_RGB (0x0001 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_RGBA (0x0002 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_COLOR (0x0003 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE (0x0004 | VKVG_CMD_PATTERN_COMMANDS) +#define VKVG_CMD_SET_SOURCE_SURFACE (0x0005 | VKVG_CMD_PATTERN_COMMANDS) +typedef struct _vkvg_record_t { + uint16_t cmd; + size_t dataOffset; +} vkvg_record_t; +typedef struct _vkvg_recording_t { + vkvg_record_t *commands; + uint32_t commandsCount; + uint32_t commandsReservedCount; + size_t bufferSize; + size_t bufferReservedSize; + char *buffer; +} vkvg_recording_t; -typedef struct _vkvg_record_t{ - uint16_t cmd; - size_t dataOffset; -}vkvg_record_t; - -typedef struct _vkvg_recording_t{ - vkvg_record_t* commands; - uint32_t commandsCount; - uint32_t commandsReservedCount; - size_t bufferSize; - size_t bufferReservedSize; - char* buffer; -}vkvg_recording_t; - - -void _start_recording (VkvgContext ctx); -vkvg_recording_t* _stop_recording (VkvgContext ctx); -void _destroy_recording (vkvg_recording_t* rec); -void _replay_command (VkvgContext ctx, VkvgRecording rec, uint32_t index); -void _record (vkvg_recording_t* rec,...); - -#define RECORD(ctx,...) {\ - if (ctx->recording) {\ - _record (ctx->recording,__VA_ARGS__);\ - return;\ - }\ -} -#define RECORD2(ctx,...) {\ - if (ctx->recording) {\ - _record (ctx->recording,__VA_ARGS__);\ - return 0;\ - }\ -} +void _start_recording(VkvgContext ctx); +vkvg_recording_t *_stop_recording(VkvgContext ctx); +void _destroy_recording(vkvg_recording_t *rec); +void _replay_command(VkvgContext ctx, VkvgRecording rec, uint32_t index); +void _record(vkvg_recording_t *rec, ...); +#define RECORD(ctx, ...) \ + { \ + if (ctx->recording) { \ + _record(ctx->recording, __VA_ARGS__); \ + return; \ + } \ + } +#define RECORD2(ctx, ...) \ + { \ + if (ctx->recording) { \ + _record(ctx->recording, __VA_ARGS__); \ + return 0; \ + } \ + } #endif diff --git a/src/shaders.h b/src/shaders.h index b4a8c8e..9e48365 100644 --- a/src/shaders.h +++ b/src/shaders.h @@ -1,2262 +1,1431 @@ unsigned char shader_comp_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, - 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x60, 0x09, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x16, 0x45, 0x17, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xe3, 0xbe, 0x2c, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x8f, 0xc2, 0x15, 0x40, - 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x43, 0x17, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x9a, 0x99, 0x99, 0x3e, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0xbe, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0xbe, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x66, 0x66, 0x06, 0x40, 0x2b, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, - 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x83, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0xd0, 0x0f, 0xc9, 0x40, 0x19, 0x00, 0x09, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x47, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x49, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0xba, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x64, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x46, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, - 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x86, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, - 0x8f, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x91, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x82, 0x00, 0x00, 0x00, - 0x94, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x95, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x99, 0x00, 0x00, 0x00, - 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00 -}; -unsigned int shader_comp_spv_len = 3580; -unsigned char shader2_comp_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, - 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0a, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x46, - 0x72, 0x61, 0x6d, 0x65, 0x28, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, - 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x66, 0x31, 0x3b, 0x66, 0x31, 0x3b, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, - 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x6e, 0x76, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x33, 0x33, 0x73, 0x3f, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0xcd, 0xcc, 0x4c, 0x3d, 0x14, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x19, 0x3f, - 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0xcc, 0x3d, - 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x6f, 0x12, 0x03, 0x3b, - 0x17, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x6a, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int shader2_comp_spv_len = 2604; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, + 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, + 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1f, + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x73, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x84, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x97, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x80, + 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, 0x16, 0x00, 0x03, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, + 0x17, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x0a, 0xd7, 0xe3, 0xbe, 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x8f, 0xc2, + 0x15, 0x40, 0x2c, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x3f, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x17, 0x00, + 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x72, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0x3e, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x74, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0xbe, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x9a, 0x99, 0x99, 0xbe, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7c, 0x00, + 0x00, 0x00, 0x66, 0x66, 0x06, 0x40, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x00, 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x06, 0x00, 0x71, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x32, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x82, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0xd0, 0x0f, 0xc9, + 0x40, 0x19, 0x00, 0x09, 0x00, 0x95, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x99, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x2c, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, + 0x9f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x40, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, + 0x00, 0x73, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x76, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x72, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x13, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x1b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x1a, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0a, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x2a, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, + 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x04, 0x00, 0x45, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x47, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x47, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4a, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x44, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, + 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x52, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, + 0x00, 0x51, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x57, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, + 0x00, 0x56, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x5a, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0x55, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5e, 0x00, + 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5d, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0xba, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x65, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x64, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x45, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x65, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x67, + 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x31, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x46, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x43, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x45, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x31, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6f, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x73, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x76, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x7f, 0x00, + 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x73, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x71, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x1d, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x71, + 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x8c, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, + 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x71, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x85, + 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x71, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, + 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x82, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, + 0x00, 0x92, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x95, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x97, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x07, 0x00, 0x99, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, + 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int shader_comp_spv_len = 3580; +unsigned char shader2_comp_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x10, 0x00, 0x06, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, + 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x65, 0x64, 0x46, 0x72, 0x61, + 0x6d, 0x65, 0x28, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x76, 0x66, 0x32, 0x3b, 0x66, 0x31, 0x3b, 0x66, + 0x31, 0x3b, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, + 0x65, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, + 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x74, 0x68, 0x69, 0x63, 0x6b, 0x6e, 0x65, 0x73, 0x73, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, + 0x2b, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x49, 0x6e, 0x76, 0x6f, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x70, 0x6f, + 0x73, 0x00, 0x05, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x55, 0x00, 0x00, 0x00, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x61, 0x00, 0x00, 0x00, 0x62, 0x75, 0x66, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x61, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x03, 0x00, 0x61, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x6b, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x21, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x33, + 0x33, 0x73, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0x4c, 0x3d, + 0x14, 0x00, 0x02, 0x00, 0x27, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2d, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x80, 0x0c, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x60, 0x09, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x45, 0x2b, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x45, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x9a, 0x99, 0x19, 0x3f, 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4c, + 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x4d, 0x00, 0x00, 0x00, 0xcd, 0xcc, 0xcc, 0x3d, 0x2c, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, + 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x00, + 0x00, 0x00, 0x6f, 0x12, 0x03, 0x3b, 0x17, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x09, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x60, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x63, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x66, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, + 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2f, 0x00, + 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xae, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x31, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, + 0x00, 0x32, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x33, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf5, 0x00, + 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x39, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x3b, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x43, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2d, 0x00, + 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x46, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, + 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x49, 0x00, + 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, + 0x00, 0x4c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x55, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x09, 0x00, 0x06, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x50, 0x00, 0x07, 0x00, 0x57, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5b, 0x00, + 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x63, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x67, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x65, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x04, 0x00, 0x62, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, + 0x00, 0x38, 0x00, 0x01, 0x00, 0x36, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x37, + 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x37, 0x00, 0x03, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x07, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x38, 0x00, 0x01, + 0x00}; +unsigned int shader2_comp_spv_len = 2604; unsigned char vkvg_main_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x94, 0x01, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xc2, 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, - 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, - 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, - 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, - 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, - 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, - 0x6f, 0x63, 0x6b, 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, - 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x64, 0x69, 0x73, 0x74, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x70, 0x30, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, - 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x70, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x9e, 0x00, 0x00, 0x00, 0x62, 0x62, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xf9, 0x00, 0x00, 0x00, 0x63, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x72, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x06, 0x01, 0x00, 0x00, 0x72, 0x31, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x0c, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, - 0x74, 0x68, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x64, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x72, 0x61, 0x79, 0x44, 0x69, 0x72, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x28, 0x01, 0x00, 0x00, 0x64, 0x69, 0x73, 0x63, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x40, 0x01, 0x00, 0x00, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x7f, 0x01, 0x00, 0x00, - 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, - 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x94, 0x01, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x96, 0x01, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, - 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x88, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x94, 0x01, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x96, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0xcb, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x40, 0x17, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x7e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x7d, 0x01, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x85, 0x01, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x86, 0x01, 0x00, 0x00, - 0x85, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x87, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x87, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x93, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x06, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x35, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x40, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x60, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x73, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x84, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x89, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x28, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xab, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0xac, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xb1, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, - 0xb6, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, - 0xb7, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, - 0xb7, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xba, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xbd, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x52, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xbe, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0xc3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0xc5, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, - 0xc1, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, - 0xd2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0xd6, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, - 0xd6, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00, - 0xd8, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0xd9, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xce, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0xdd, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xdf, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0xe4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, - 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0xe9, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, - 0xea, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xf0, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, - 0xf0, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, - 0xf1, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xf3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, - 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, - 0xfe, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf9, 0x00, 0x00, 0x00, - 0xff, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, - 0x02, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, - 0x07, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x09, 0x01, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x09, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x0b, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, - 0xf2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, 0x00, - 0x0f, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0d, 0x01, 0x00, 0x00, - 0x10, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x12, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, - 0x12, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x19, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1d, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, - 0x1d, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x1f, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, - 0x0d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x22, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, - 0x22, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x24, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, - 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, - 0x26, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x27, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x29, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, - 0x29, 0x01, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, - 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, - 0x2e, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, - 0x30, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x28, 0x01, 0x00, 0x00, - 0x31, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x32, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x35, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x33, 0x01, 0x00, 0x00, - 0x34, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x34, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x37, 0x01, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, - 0x28, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3a, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x39, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x3a, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3c, 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, - 0x16, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3e, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, - 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, - 0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x36, 0x01, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, - 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x43, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, - 0x43, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x45, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x40, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x47, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4a, 0x01, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x35, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x4c, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, - 0x4d, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x4f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, - 0x4f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x51, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, - 0x51, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4b, 0x01, 0x00, 0x00, - 0x52, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x53, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x54, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, - 0x57, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, - 0x59, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x5a, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, - 0x5a, 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, - 0x56, 0x01, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x5f, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x60, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0x62, 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, - 0x65, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, - 0x67, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, - 0x67, 0x01, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, - 0x69, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x69, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, - 0x62, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x61, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x6b, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x6b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, - 0x5f, 0x01, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x6f, 0x01, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, - 0x70, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x72, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, - 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x71, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, - 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, - 0x76, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x78, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x6a, 0x01, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x63, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x63, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x79, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, - 0x7a, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0x7f, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, - 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, - 0x81, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x82, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x83, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x86, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, - 0x7f, 0x01, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x8b, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, - 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x8e, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, - 0x8d, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x84, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, - 0x8f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x91, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, - 0x90, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x92, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x95, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x94, 0x01, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, - 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_frag_spv_len = 9532; -unsigned char vkvg_main_vert_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, - 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, - 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, - 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x6f, 0x75, 0x74, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x50, 0x75, 0x73, 0x68, - 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x66, 0x75, 0x6c, 0x6c, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x51, 0x75, - 0x61, 0x64, 0x5f, 0x73, 0x72, 0x63, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x06, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x74, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x6d, 0x61, 0x74, 0x49, 0x6e, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x74, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x53, - 0x72, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4f, 0x70, 0x61, 0x63, 0x69, - 0x74, 0x79, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x69, 0x6e, 0x74, - 0x53, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, - 0x6c, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x00, - 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x67, 0x6c, 0x5f, 0x43, 0x75, 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, - 0x6e, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x55, 0x56, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x14, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x15, 0x00, 0x04, 0x00, - 0x3b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x3d, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, - 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x3f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x17, 0x00, 0x04, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, - 0x2c, 0x00, 0x06, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2c, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x12, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x29, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x25, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, - 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x3a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x63, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x67, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, - 0x68, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x6e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x54, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x7a, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x5d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x7f, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_vert_spv_len = 3704; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x97, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x21, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x10, 0x00, + 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, + 0x01, 0x00, 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, + 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, + 0x00, 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, + 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, + 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, + 0x6f, 0x63, 0x6b, 0x5f, 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, + 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, + 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, + 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x18, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, + 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, 0x52, 0x00, 0x00, 0x00, 0x64, 0x69, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, + 0x00, 0x54, 0x00, 0x00, 0x00, 0x70, 0x30, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x5f, 0x75, + 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x75, + 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, 0x64, 0x00, 0x00, 0x00, 0x70, 0x31, 0x00, 0x00, + 0x05, 0x00, 0x03, 0x00, 0x70, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, + 0x00, 0x75, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x62, 0x62, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x63, 0x30, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x63, 0x31, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x72, 0x30, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x72, 0x31, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0c, 0x01, + 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0d, + 0x01, 0x00, 0x00, 0x64, 0x69, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x11, 0x01, 0x00, 0x00, + 0x72, 0x61, 0x79, 0x44, 0x69, 0x72, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x61, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x20, 0x01, + 0x00, 0x00, 0x63, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x28, 0x01, 0x00, 0x00, 0x64, 0x69, 0x73, 0x63, 0x00, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x04, + 0x00, 0x4b, 0x01, 0x00, 0x00, 0x67, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x5f, 0x01, + 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, + 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, + 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x05, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, + 0x74, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x94, 0x01, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, + 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x96, 0x01, 0x00, 0x00, 0x4e, + 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, + 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x5a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, + 0x47, 0x00, 0x03, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x88, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, + 0x00, 0x8f, 0x01, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x8f, 0x01, 0x00, 0x00, 0x1e, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x94, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x96, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, + 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x15, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x47, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x57, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, + 0x59, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x56, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5b, + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xc2, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2b, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x17, 0x00, 0x04, 0x00, 0x7d, + 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x85, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x86, 0x01, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x87, 0x01, 0x00, + 0x00, 0x88, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x8f, 0x01, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x93, 0x01, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x32, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xcb, + 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, + 0xf2, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, + 0x00, 0x11, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x16, 0x01, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x4b, + 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfb, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0x25, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x36, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3a, 0x00, + 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x25, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x37, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x46, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x48, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x4e, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, + 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0x62, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6b, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6b, + 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x6e, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x73, 0x00, + 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, + 0x00, 0x64, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x54, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x77, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x75, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0xb4, + 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, + 0xf7, 0x00, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x00, + 0x00, 0x7f, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, + 0x7d, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, + 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x84, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, + 0x00, 0x88, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8a, + 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x8b, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, + 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8b, 0x00, + 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x94, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, + 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0x95, + 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x85, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x96, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x9b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, + 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x97, 0x00, 0x00, 0x00, 0x9d, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa6, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa7, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, + 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x28, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, + 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, + 0xaa, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0x9e, 0x00, + 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xad, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, + 0xb2, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, + 0x00, 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x70, 0x00, + 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xb5, + 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x28, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xb7, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x05, 0x00, 0x7d, 0x00, + 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xbb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, + 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xba, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xbc, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xbd, 0x00, + 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x52, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x80, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0xbe, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xc4, + 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xc9, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, + 0x00, 0xcf, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd1, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xd2, + 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, + 0xd2, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0xd4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0xd6, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x23, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, + 0xd8, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xd9, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0xce, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xda, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xcc, + 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xde, 0x00, + 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xcc, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, + 0x00, 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0xcc, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, + 0x00, 0xe4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, + 0x00, 0xe7, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, + 0x00, 0xcc, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xea, 0x00, + 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xf9, + 0x00, 0x02, 0x00, 0xcd, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, + 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, + 0x00, 0xed, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xee, 0x00, + 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, + 0x15, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0xee, 0x00, + 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf3, 0x00, 0x00, + 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xf4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xf6, + 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, + 0xf6, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, + 0x00, 0x15, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0xf2, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0xfa, + 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x4f, + 0x00, 0x07, 0x00, 0x15, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xf9, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, + 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, + 0x00, 0x0b, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x01, + 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, 0x02, + 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x01, 0x00, 0x00, + 0x41, 0x00, 0x07, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x01, + 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, + 0x09, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x08, 0x01, 0x00, + 0x00, 0x0a, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x06, 0x01, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0e, + 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x0e, 0x01, 0x00, + 0x00, 0x0f, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x15, 0x00, 0x00, + 0x00, 0x15, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x11, 0x01, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, + 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, + 0x11, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x17, 0x01, 0x00, + 0x00, 0x18, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x16, 0x01, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x1e, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x1f, 0x01, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1a, 0x01, + 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x0d, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, + 0x94, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x22, 0x01, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00, 0x26, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x20, 0x01, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x29, 0x01, + 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x1a, + 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x29, 0x01, 0x00, 0x00, + 0x2a, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, + 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x2c, 0x01, 0x00, 0x00, 0x2d, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x85, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, 0x2f, 0x01, 0x00, 0x00, + 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, 0x30, 0x01, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x28, 0x01, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x33, + 0x01, 0x00, 0x00, 0x32, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x35, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x33, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x35, 0x01, 0x00, + 0x00, 0xf8, 0x00, 0x02, 0x00, 0x34, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x01, + 0x00, 0x00, 0x1a, 0x01, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x37, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, + 0x00, 0x39, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3c, + 0x01, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x3b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x3d, 0x01, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x00, + 0x00, 0x1b, 0x01, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x01, + 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x3e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x36, 0x01, 0x00, 0x00, 0x3f, + 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x15, 0x00, + 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x15, + 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, + 0x40, 0x01, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0xf2, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, + 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x49, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4a, 0x01, 0x00, + 0x00, 0x48, 0x01, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x4a, 0x01, + 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x35, 0x01, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x4e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x4d, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x83, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x88, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x53, + 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x53, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, + 0x00, 0x55, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0xc2, + 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x41, 0x00, 0x06, + 0x00, 0xc2, 0x00, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x59, 0x01, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, + 0x00, 0x5a, 0x01, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5d, 0x01, + 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x5c, 0x01, 0x00, 0x00, 0x0c, + 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, + 0x54, 0x01, 0x00, 0x00, 0x56, 0x01, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x5e, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0xf9, 0x00, + 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x60, 0x01, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0x62, + 0x01, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x64, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x65, 0x01, 0x00, + 0x00, 0x5f, 0x01, 0x00, 0x00, 0x7c, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x65, 0x01, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xd5, 0x00, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0xd4, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, + 0xb0, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x69, 0x01, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, + 0x00, 0xfa, 0x00, 0x04, 0x00, 0x69, 0x01, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf8, 0x00, + 0x02, 0x00, 0x61, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6b, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, + 0x00, 0x6b, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x6c, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x82, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x6e, 0x01, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x6f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x71, 0x01, 0x00, 0x00, 0x70, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x41, + 0x00, 0x06, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x72, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x73, 0x01, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x0c, 0x00, + 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x71, + 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x77, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, 0x76, 0x01, 0x00, + 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, + 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, 0x77, 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x63, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x63, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, 0x5f, 0x01, 0x00, + 0x00, 0x80, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, 0x2c, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x5f, 0x01, 0x00, 0x00, 0x7a, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x60, + 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x62, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x25, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, + 0x00, 0x7f, 0x01, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x81, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x81, + 0x01, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x82, 0x01, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x83, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x86, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x88, 0x01, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x7d, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, 0x57, + 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x00, + 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x8c, 0x01, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x84, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, + 0x00, 0x8f, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x8e, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x90, + 0x01, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x94, 0x01, 0x00, + 0x00, 0x95, 0x01, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_frag_spv_len = 9532; +unsigned char vkvg_main_vert_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x4c, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, + 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, + 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, + 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x50, + 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x50, 0x75, 0x73, + 0x68, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x73, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x09, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6c, 0x6c, 0x53, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x51, 0x75, 0x61, 0x64, 0x5f, + 0x73, 0x72, 0x63, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x6f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x06, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x6d, 0x61, 0x74, 0x00, 0x06, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x74, 0x49, 0x6e, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x63, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x53, 0x72, 0x63, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x05, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, + 0x6f, 0x69, 0x6e, 0x74, 0x53, 0x69, 0x7a, 0x65, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, 0x6c, 0x69, 0x70, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, + 0x65, 0x00, 0x06, 0x00, 0x07, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x43, 0x75, + 0x6c, 0x6c, 0x44, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x00, 0x05, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x6f, 0x73, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x54, + 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x48, + 0x00, 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48, 0x00, + 0x05, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x03, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x3e, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, + 0x3e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x51, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, + 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x08, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, + 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x26, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, + 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, + 0x31, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x15, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x06, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x45, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x17, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xbf, 0x2c, 0x00, 0x06, 0x00, 0x4a, 0x00, + 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x2c, 0x00, 0x05, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x7a, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x53, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, + 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, + 0x00, 0x29, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x24, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x05, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0x25, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x23, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x31, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x2f, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x34, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x35, 0x00, + 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x05, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x37, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfa, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x39, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x49, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4a, 0x00, 0x00, + 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x52, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, + 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x58, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5b, 0x00, + 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, + 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, + 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x63, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, + 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x56, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, + 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x68, + 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, + 0x00, 0x69, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x68, 0x00, + 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x59, 0x00, 0x00, + 0x00, 0x6e, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, + 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x71, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, + 0x00, 0x72, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3c, 0x00, + 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x81, + 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x54, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x7a, 0x00, 0x00, 0x00, + 0x7b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7d, 0x00, + 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x7f, + 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, + 0x00, 0x81, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x45, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x1f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x2e, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_vert_spv_len = 3704; unsigned char vkvg_main_lcd_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, - 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, - 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, - 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, - 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, - 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x04, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, - 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x09, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x72, - 0x74, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x67, 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x50, - 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x88, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x78, 0x4c, 0x6f, 0x63, - 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x00, 0x05, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, - 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0x66, 0x6f, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x06, 0x00, - 0xec, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, - 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0xee, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, - 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xdc, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0xec, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0xee, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x4b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x5b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x06, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, - 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x98, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0xdb, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x09, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x03, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xe3, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, - 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0xeb, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xee, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x88, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfb, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x2d, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x36, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, - 0x2f, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, - 0x37, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, - 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, - 0x4e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x53, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, - 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, - 0x69, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x65, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x6d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x6f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x75, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x74, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x76, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x71, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x79, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x7b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x7e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, - 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x82, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, - 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, - 0x7d, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x87, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x88, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x8b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x90, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, - 0x91, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, - 0x93, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, - 0x96, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, - 0x99, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x98, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0x9e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0x9f, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0xa1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, - 0x5f, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, - 0xa3, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, - 0xa8, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, - 0xf6, 0x00, 0x04, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x7c, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, - 0xb4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xb7, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, - 0xb8, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00, - 0xba, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, - 0xb0, 0x00, 0x05, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, - 0xb5, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0xbc, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, - 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, - 0xc0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc2, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, - 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, - 0xc4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, - 0xc6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xc8, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, - 0xca, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, - 0xcc, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0xcb, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, - 0xcd, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xc9, 0x00, 0x00, 0x00, - 0xcf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xd1, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x06, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x31, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, - 0xd1, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, - 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, - 0xd3, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, - 0xd4, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0xd5, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, - 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, - 0xd5, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0xae, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x00, 0x00, - 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x13, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, - 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, - 0x29, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x5a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, - 0xde, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, - 0xbb, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xe1, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xdf, 0x00, 0x00, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xe3, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0xda, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, - 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, - 0xe6, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, - 0xe9, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x09, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, - 0xe1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, - 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xec, 0x00, 0x00, 0x00, - 0xed, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; -unsigned int vkvg_main_lcd_frag_spv_len = 5784; -unsigned char wired_frag_spv[] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x09, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64, - 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, - 0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, - 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, - 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, - 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, - 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x63, 0x70, - 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, - 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, - 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c, - 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, - 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, - 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, - 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, - 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, - 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x05, 0x00, 0x24, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, - 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x26, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, - 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, - 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, - 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x03, 0x00, 0x24, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, - 0x2a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x80, 0x3f, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, - 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x15, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x1d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, - 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x17, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x27, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, - 0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, - 0x2b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, - 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 -}; + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x25, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x0e, 0x00, + 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x16, + 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, + 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x22, 0x00, 0x00, 0x00, 0x75, 0x76, + 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, + 0x56, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, + 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x5e, 0x00, + 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, 0x09, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x67, + 0x72, 0x61, 0x64, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, + 0x74, 0x65, 0x64, 0x58, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x78, 0x00, 0x00, 0x00, 0x67, 0x72, 0x61, + 0x64, 0x69, 0x65, 0x6e, 0x74, 0x45, 0x6e, 0x64, 0x50, 0x6f, 0x73, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, 0x58, + 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x88, + 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x78, 0x4c, 0x6f, 0x63, 0x52, 0x6f, 0x74, 0x61, 0x74, 0x65, 0x64, + 0x00, 0x05, 0x00, 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0xdc, 0x00, + 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0xe5, + 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x4d, 0x61, 0x70, 0x00, 0x05, 0x00, 0x06, 0x00, 0xec, 0x00, 0x00, 0x00, + 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, + 0x00, 0xee, 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, + 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, + 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, + 0x00, 0x04, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x5e, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xdc, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0xec, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0xee, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, + 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, + 0x00, 0x27, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x4d, 0x00, 0x00, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x57, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x59, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x57, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x06, 0x00, 0x5c, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, + 0x00, 0x3b, 0x00, 0x04, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x98, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xb7, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, + 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xda, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xdb, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x19, 0x00, 0x09, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, + 0x00, 0x03, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xeb, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x32, + 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, + 0x00, 0x05, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, + 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x6c, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x78, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, + 0x00, 0x2c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0xad, 0x00, + 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0xf7, 0x00, 0x03, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x0b, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x16, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, + 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, 0x00, 0x19, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x31, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, + 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x35, 0x00, + 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x36, + 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, + 0x00, 0x39, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x37, 0x00, + 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, + 0x00, 0x1b, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x25, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x43, 0x00, + 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, + 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x45, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x29, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x50, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, + 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x22, 0x00, + 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x4e, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x07, + 0x00, 0x19, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x51, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00, 0x19, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x50, + 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x12, 0x00, 0x00, 0x00, 0x41, 0x00, + 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, + 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0x63, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, + 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, + 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, + 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x69, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x19, + 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x6b, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x6f, + 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x71, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, + 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x33, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x74, 0x00, + 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x75, + 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x76, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, + 0x00, 0x5f, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, + 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x79, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, + 0x00, 0x7b, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x7a, 0x00, + 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x07, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0x81, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, + 0x00, 0x78, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x85, 0x00, + 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x6c, + 0x00, 0x00, 0x00, 0x83, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, + 0x86, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x84, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, + 0x00, 0x29, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x88, + 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, + 0x00, 0x8c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x91, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x06, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x83, 0x00, + 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x3e, + 0x00, 0x03, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, 0x00, 0x00, + 0x99, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, 0x00, + 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, + 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, + 0x00, 0x9e, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x3d, 0x00, + 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xa2, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, + 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xa4, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xa6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa7, 0x00, + 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xa8, + 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xa9, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa9, 0x00, + 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, + 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x3e, 0x00, + 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf8, + 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf6, 0x00, 0x04, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb3, 0x00, 0x00, + 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x7c, 0x00, + 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0xb7, + 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x27, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x82, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, + 0x00, 0xba, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x05, 0x00, 0xbb, 0x00, + 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xbc, + 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x0c, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x98, + 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, + 0x00, 0x06, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xc4, + 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xc6, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc7, 0x00, + 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xc8, + 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xc9, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, + 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0xca, 0x00, + 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x5f, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x5e, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xcd, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0xcd, 0x00, + 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, 0x81, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xc9, + 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, + 0x8e, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x31, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, 0x50, 0x00, + 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0xd2, + 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x07, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xb2, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd5, + 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x80, 0x00, 0x05, 0x00, 0x0c, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, + 0xd5, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xae, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, + 0x00, 0xf9, 0x00, 0x02, 0x00, 0xaf, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xb1, 0x00, 0x00, 0x00, 0xf9, 0x00, + 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x14, + 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x29, 0x00, 0x00, 0x00, + 0xdd, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, + 0x00, 0xde, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x05, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xdf, 0x00, + 0x00, 0x00, 0xde, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, 0xdf, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xe3, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, + 0x00, 0xe5, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0xda, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0xdc, 0x00, + 0x00, 0x00, 0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, 0xe7, + 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, + 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0xe1, 0x00, + 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0xe1, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0xed, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0xec, 0x00, 0x00, 0x00, 0xed, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; +unsigned int vkvg_main_lcd_frag_spv_len = 5784; +unsigned char wired_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, + 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, + 0x00, 0x24, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x04, + 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, + 0x73, 0x68, 0x61, 0x64, 0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00, 0x04, 0x00, 0x09, + 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x5f, 0x34, 0x32, 0x30, 0x70, 0x61, 0x63, 0x6b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, + 0x4c, 0x5f, 0x45, 0x58, 0x54, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x61, 0x72, 0x5f, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, + 0x6c, 0x61, 0x79, 0x6f, 0x75, 0x74, 0x00, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, + 0x4c, 0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, + 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, + 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x00, 0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, + 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6e, 0x74, 0x4d, + 0x61, 0x70, 0x00, 0x05, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x5f, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x73, + 0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x70, 0x73, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x04, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x63, 0x70, 0x00, 0x00, + 0x06, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x47, 0x72, 0x61, 0x64, 0x00, 0x05, 0x00, + 0x05, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x46, 0x6f, 0x6e, 0x74, 0x55, 0x56, 0x00, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x53, 0x72, 0x63, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x50, 0x61, 0x74, 0x54, 0x79, 0x70, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, + 0x00, 0x26, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4f, 0x70, 0x61, 0x63, 0x69, 0x74, 0x79, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x4d, 0x61, 0x74, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x2b, + 0x00, 0x00, 0x00, 0x4e, 0x55, 0x4d, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, 0x45, 0x53, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x21, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x13, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x19, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x1a, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x1a, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x47, 0x00, 0x04, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, + 0x04, 0x00, 0x21, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, + 0x00, 0x26, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2a, 0x00, + 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, + 0x00, 0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, + 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x2c, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x19, 0x00, + 0x09, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x19, 0x00, 0x09, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x03, 0x00, 0x11, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, + 0x00, 0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x14, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x06, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x1c, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, + 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3b, 0x00, + 0x04, 0x00, 0x25, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x28, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x32, 0x00, 0x04, 0x00, 0x22, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x36, + 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00}; unsigned int wired_frag_spv_len = 1700; diff --git a/src/stb_image.h b/src/stb_image.h index 8b4af4d..b79dd50 100644 --- a/src/stb_image.h +++ b/src/stb_image.h @@ -1,8 +1,8 @@ /* stb_image - v2.19 - public domain image loader - http://nothings.org/stb - no warranty implied; use at your own risk + no warranty implied; use at your own risk Do this: - #define STB_IMAGE_IMPLEMENTATION + #define STB_IMAGE_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. // i.e. it should look like this: @@ -17,27 +17,27 @@ QUICK NOTES: - Primarily of interest to game developers and other people who can - avoid problematic images and only need the trivial interface + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface - JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) - PNG 1/2/4/8/16-bit-per-channel + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel - TGA (not sure what subset, if a subset) - BMP non-1bpp, non-RLE - PSD (composited view only, no extra channels, 8/16 bit-per-channel) + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) - GIF (*comp always reports as 4-channel) - HDR (radiance rgbE format) - PIC (Softimage PIC) - PNM (PPM and PGM binary only) + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) - Animated GIF still needs a proper API, but here's one way to do it: - http://gist.github.com/urraka/685d9a6340b26b830d49 + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 - - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - - decode from arbitrary I/O callbacks - - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) Full documentation under "DOCUMENTATION" below. @@ -48,20 +48,20 @@ LICENSE RECENT REVISION HISTORY: - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings - 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes - 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 - RGB-format JPEG; remove white matting in PSD; - allocate large structures on the stack; - correct channel count for PNG & BMP - 2.10 (2016-01-22) avoid warning introduced in 2.09 - 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED See end of file for full revision history. @@ -69,38 +69,38 @@ RECENT REVISION HISTORY: ============================ Contributors ========================= Image formats Extensions, features - Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) - Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) - Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) - Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) - Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) - Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) - Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) - github:urraka (animated gif) Junggon Kim (PNM comments) - Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) - socks-the-fox (16-bit PNG) - Jeremy Sawicki (handle all ImageNet JPGs) + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) - Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine - John-Mark Allen + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan + Dave Moore Roy Eltham Hayaki Saito Nathan Reed + Won Chun Luke Graham Johan Duparc Nick Verigakis + the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar + Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex + Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 + Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw + Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus + Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo + Christian Floisand Kevin Schmidt github:darealshinji + Blazej Dariusz Roszkowski github:Michaelangel007 */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -302,24 +302,22 @@ RECENT REVISION HISTORY: // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - #ifndef STBI_NO_STDIO #include <stdio.h> #endif // STBI_NO_STDIO #define STBI_VERSION 1 -enum -{ - STBI_default = 0, // only used for desired_channels +enum { + STBI_default = 0, // only used for desired_channels - STBI_grey = 1, - STBI_grey_alpha = 2, - STBI_rgb = 3, - STBI_rgb_alpha = 4 + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 }; -typedef unsigned char stbi_uc; +typedef unsigned char stbi_uc; typedef unsigned short stbi_us; #ifdef __cplusplus @@ -341,11 +339,11 @@ extern "C" { // load image by filename, open file, or memory buffer // -typedef struct -{ - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read - void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative - int (*eof) (void *user); // returns nonzero if we are at end of file/data +typedef struct { + int (*read)(void *user, char *data, + int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip)(void *user, int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof)(void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; //////////////////////////////////// @@ -353,16 +351,18 @@ typedef struct // 8-bits-per-channel interface // -STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, + int *comp, int req_comp); #endif - #ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); // for stbi_load_from_file, file pointer is left pointing immediately after image #endif @@ -371,11 +371,13 @@ STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in // 16-bits-per-channel interface // -STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); #ifndef STBI_NO_STDIO -STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); #endif @@ -384,56 +386,55 @@ STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_i // float-per-channel interface // #ifndef STBI_NO_LINEAR - STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels); +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels); - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); - #endif +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif #endif #ifndef STBI_NO_HDR - STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); - STBIDEF void stbi_hdr_to_ldr_scale(float scale); +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); +STBIDEF void stbi_hdr_to_ldr_scale(float scale); #endif // STBI_NO_HDR #ifndef STBI_NO_LINEAR - STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); - STBIDEF void stbi_ldr_to_hdr_scale(float scale); +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); +STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_LINEAR // stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename); -STBIDEF int stbi_is_hdr_from_file(FILE *f); +STBIDEF int stbi_is_hdr(char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); #endif // STBI_NO_STDIO - // get a VERY brief reason for failure // NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); +STBIDEF const char *stbi_failure_reason(void); // free the loaded image -- this is just free() -STBIDEF void stbi_image_free (void *retval_from_stbi_load); +STBIDEF void stbi_image_free(void *retval_from_stbi_load); // get image dimensions & components without fully decoding -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); #ifndef STBI_NO_STDIO -STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); -STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); -STBIDEF int stbi_is_16_bit (char const *filename); -STBIDEF int stbi_is_16_bit_from_file(FILE *f); +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit(char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); #endif - - // for image formats that explicitly notate that they have premultiplied alpha, // we just return the colors as stored in the file. set this flag to force // unpremultiplication. results are undefined if the unpremultiply overflow. @@ -449,13 +450,13 @@ STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, + int parse_header); STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); - +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); #ifdef __cplusplus } @@ -468,44 +469,42 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #ifdef STB_IMAGE_IMPLEMENTATION -#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ - || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ - || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ - || defined(STBI_ONLY_ZLIB) - #ifndef STBI_ONLY_JPEG - #define STBI_NO_JPEG - #endif - #ifndef STBI_ONLY_PNG - #define STBI_NO_PNG - #endif - #ifndef STBI_ONLY_BMP - #define STBI_NO_BMP - #endif - #ifndef STBI_ONLY_PSD - #define STBI_NO_PSD - #endif - #ifndef STBI_ONLY_TGA - #define STBI_NO_TGA - #endif - #ifndef STBI_ONLY_GIF - #define STBI_NO_GIF - #endif - #ifndef STBI_ONLY_HDR - #define STBI_NO_HDR - #endif - #ifndef STBI_ONLY_PIC - #define STBI_NO_PIC - #endif - #ifndef STBI_ONLY_PNM - #define STBI_NO_PNM - #endif +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) || defined(STBI_ONLY_TGA) || \ + defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || \ + defined(STBI_ONLY_PNM) || defined(STBI_ONLY_ZLIB) +#ifndef STBI_ONLY_JPEG +#define STBI_NO_JPEG +#endif +#ifndef STBI_ONLY_PNG +#define STBI_NO_PNG +#endif +#ifndef STBI_ONLY_BMP +#define STBI_NO_BMP +#endif +#ifndef STBI_ONLY_PSD +#define STBI_NO_PSD +#endif +#ifndef STBI_ONLY_TGA +#define STBI_NO_TGA +#endif +#ifndef STBI_ONLY_GIF +#define STBI_NO_GIF +#endif +#ifndef STBI_ONLY_HDR +#define STBI_NO_HDR +#endif +#ifndef STBI_ONLY_PIC +#define STBI_NO_PIC +#endif +#ifndef STBI_ONLY_PNM +#define STBI_NO_PNM +#endif #endif #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) #define STBI_NO_ZLIB #endif - #include <stdarg.h> #include <stddef.h> // ptrdiff_t on osx #include <stdlib.h> @@ -513,7 +512,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #include <limits.h> #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -#include <math.h> // ldexp, pow +#include <math.h> // ldexp, pow #endif #ifndef STBI_NO_STDIO @@ -525,38 +524,36 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define STBI_ASSERT(x) assert(x) #endif - #ifndef _MSC_VER - #ifdef __cplusplus - #define stbi_inline inline - #else - #define stbi_inline - #endif +#ifdef __cplusplus +#define stbi_inline inline #else - #define stbi_inline __forceinline +#define stbi_inline +#endif +#else +#define stbi_inline __forceinline #endif - #ifdef _MSC_VER typedef unsigned short stbi__uint16; -typedef signed short stbi__int16; +typedef signed short stbi__int16; typedef unsigned int stbi__uint32; -typedef signed int stbi__int32; +typedef signed int stbi__int32; #else #include <stdint.h> typedef uint16_t stbi__uint16; -typedef int16_t stbi__int16; +typedef int16_t stbi__int16; typedef uint32_t stbi__uint32; -typedef int32_t stbi__int32; +typedef int32_t stbi__int32; #endif // should produce compiler error if size is wrong -typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; +typedef unsigned char validate_uint32[sizeof(stbi__uint32) == 4 ? 1 : -1]; #ifdef _MSC_VER -#define STBI_NOTUSED(v) (void)(v) +#define STBI_NOTUSED(v) (void)(v) #else -#define STBI_NOTUSED(v) (void)sizeof(v) +#define STBI_NOTUSED(v) (void)sizeof(v) #endif #ifdef _MSC_VER @@ -564,9 +561,9 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifdef STBI_HAS_LROTL - #define stbi_lrot(x,y) _lrotl(x,y) +#define stbi_lrot(x, y) _lrotl(x, y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#define stbi_lrot(x, y) (((x) << (y)) | ((x) >> (32 - (y)))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -578,13 +575,13 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #endif #ifndef STBI_MALLOC -#define STBI_MALLOC(sz) malloc(sz) -#define STBI_REALLOC(p,newsz) realloc(p,newsz) -#define STBI_FREE(p) free(p) +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p, newsz) realloc(p, newsz) +#define STBI_FREE(p) free(p) #endif #ifndef STBI_REALLOC_SIZED -#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#define STBI_REALLOC_SIZED(p, oldsz, newsz) STBI_REALLOC(p, newsz) #endif // x86/x64 detection @@ -626,43 +623,39 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef _MSC_VER -#if _MSC_VER >= 1400 // not VC6 -#include <intrin.h> // __cpuid -static int stbi__cpuid3(void) -{ - int info[4]; - __cpuid(info,1); - return info[3]; +#if _MSC_VER >= 1400 // not VC6 +#include <intrin.h> // __cpuid +static int stbi__cpuid3(void) { + int info[4]; + __cpuid(info, 1); + return info[3]; } #else -static int stbi__cpuid3(void) -{ - int res; - __asm { +static int stbi__cpuid3(void) { + int res; + __asm { mov eax,1 cpuid mov res,edx - } - return res; + } + return res; } #endif #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name -static int stbi__sse2_available(void) -{ - int info3 = stbi__cpuid3(); - return ((info3 >> 26) & 1) != 0; +static int stbi__sse2_available(void) { + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; } #else // assume GCC-style if not VC++ #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) -static int stbi__sse2_available(void) -{ - // If we're even attempting to compile this on GCC/Clang, that means - // -msse2 is on, which means the compiler is allowed to use SSE2 - // instructions at will, and so are we. - return 1; +static int stbi__sse2_available(void) { + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; } #endif #endif @@ -688,176 +681,146 @@ static int stbi__sse2_available(void) // stbi__context structure is our basic context used by all images, so it // contains all the IO context, plus some basic image information -typedef struct -{ - stbi__uint32 img_x, img_y; - int img_n, img_out_n; +typedef struct { + stbi__uint32 img_x, img_y; + int img_n, img_out_n; - stbi_io_callbacks io; - void *io_user_data; + stbi_io_callbacks io; + void *io_user_data; - int read_from_callbacks; - int buflen; - stbi_uc buffer_start[128]; + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; - stbi_uc *img_buffer, *img_buffer_end; - stbi_uc *img_buffer_original, *img_buffer_original_end; + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; } stbi__context; - static void stbi__refill_buffer(stbi__context *s); // initialize a memory-decode context -static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) -{ - s->io.read = NULL; - s->read_from_callbacks = 0; - s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; - s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { + s->io.read = NULL; + s->read_from_callbacks = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *)buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *)buffer + len; } // initialize a callback-based context -static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) -{ - s->io = *c; - s->io_user_data = user; - s->buflen = sizeof(s->buffer_start); - s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; - stbi__refill_buffer(s); - s->img_buffer_original_end = s->img_buffer_end; +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) { + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; } #ifndef STBI_NO_STDIO -static int stbi__stdio_read(void *user, char *data, int size) -{ - return (int) fread(data,1,size,(FILE*) user); -} +static int stbi__stdio_read(void *user, char *data, int size) { return (int)fread(data, 1, size, (FILE *)user); } -static void stbi__stdio_skip(void *user, int n) -{ - fseek((FILE*) user, n, SEEK_CUR); -} +static void stbi__stdio_skip(void *user, int n) { fseek((FILE *)user, n, SEEK_CUR); } -static int stbi__stdio_eof(void *user) -{ - return feof((FILE*) user); -} +static int stbi__stdio_eof(void *user) { return feof((FILE *)user); } -static stbi_io_callbacks stbi__stdio_callbacks = -{ - stbi__stdio_read, - stbi__stdio_skip, - stbi__stdio_eof, +static stbi_io_callbacks stbi__stdio_callbacks = { + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, }; -static void stbi__start_file(stbi__context *s, FILE *f) -{ - stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); -} +static void stbi__start_file(stbi__context *s, FILE *f) { stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *)f); } -//static void stop_file(stbi__context *s) { } +// static void stop_file(stbi__context *s) { } #endif // !STBI_NO_STDIO -static void stbi__rewind(stbi__context *s) -{ - // conceptually rewind SHOULD rewind to the beginning of the stream, - // but we just rewind to the beginning of the initial buffer, because - // we only use it after doing 'test', which only ever looks at at most 92 bytes - s->img_buffer = s->img_buffer_original; - s->img_buffer_end = s->img_buffer_original_end; +static void stbi__rewind(stbi__context *s) { + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; } -enum -{ - STBI_ORDER_RGB, - STBI_ORDER_BGR -}; +enum { STBI_ORDER_RGB, STBI_ORDER_BGR }; -typedef struct -{ - int bits_per_channel; - int num_channels; - int channel_order; +typedef struct { + int bits_per_channel; + int num_channels; + int channel_order; } stbi__result_info; #ifndef STBI_NO_JPEG -static int stbi__jpeg_test(stbi__context *s); -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNG -static int stbi__png_test(stbi__context *s); -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__png_is16(stbi__context *s); +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); #endif #ifndef STBI_NO_BMP -static int stbi__bmp_test(stbi__context *s); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_TGA -static int stbi__tga_test(stbi__context *s); -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s); -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); -static int stbi__psd_is16(stbi__context *s); +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); #endif #ifndef STBI_NO_HDR -static int stbi__hdr_test(stbi__context *s); -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PIC -static int stbi__pic_test(stbi__context *s); -static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_GIF -static int stbi__gif_test(stbi__context *s); -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); #endif #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s); -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); #endif // this is not threadsafe static const char *stbi__g_failure_reason; -STBIDEF const char *stbi_failure_reason(void) -{ - return stbi__g_failure_reason; -} +STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } -static int stbi__err(const char *str) -{ - stbi__g_failure_reason = str; - return 0; +static int stbi__err(const char *str) { + stbi__g_failure_reason = str; + return 0; } -static void *stbi__malloc(size_t size) -{ - return STBI_MALLOC(size); -} +static void *stbi__malloc(size_t size) { return STBI_MALLOC(size); } // stb_image uses ints pervasively, including for offset calculations. // therefore the largest decoded image size we can support with the @@ -871,66 +834,63 @@ static void *stbi__malloc(size_t size) // return 1 if the sum is valid, 0 on overflow. // negative terms are considered invalid. -static int stbi__addsizes_valid(int a, int b) -{ - if (b < 0) return 0; - // now 0 <= b <= INT_MAX, hence also - // 0 <= INT_MAX - b <= INTMAX. - // And "a + b <= INT_MAX" (which might overflow) is the - // same as a <= INT_MAX - b (no overflow) - return a <= INT_MAX - b; +static int stbi__addsizes_valid(int a, int b) { + if (b < 0) + return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; } // returns 1 if the product is valid, 0 on overflow. // negative factors are considered invalid. -static int stbi__mul2sizes_valid(int a, int b) -{ - if (a < 0 || b < 0) return 0; - if (b == 0) return 1; // mul-by-0 is always safe - // portable way to check for no overflows in a*b - return a <= INT_MAX/b; +static int stbi__mul2sizes_valid(int a, int b) { + if (a < 0 || b < 0) + return 0; + if (b == 0) + return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX / b; } // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow -static int stbi__mad2sizes_valid(int a, int b, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +static int stbi__mad2sizes_valid(int a, int b, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a * b, add); } // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow -static int stbi__mad3sizes_valid(int a, int b, int c, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__addsizes_valid(a*b*c, add); +static int stbi__mad3sizes_valid(int a, int b, int c, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && stbi__addsizes_valid(a * b * c, add); } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) -{ - return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && - stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a * b, c) && stbi__mul2sizes_valid(a * b * c, d) && + stbi__addsizes_valid(a * b * c * d, add); } #endif // mallocs with size overflow checking -static void *stbi__malloc_mad2(int a, int b, int add) -{ - if (!stbi__mad2sizes_valid(a, b, add)) return NULL; - return stbi__malloc(a*b + add); +static void *stbi__malloc_mad2(int a, int b, int add) { + if (!stbi__mad2sizes_valid(a, b, add)) + return NULL; + return stbi__malloc(a * b + add); } -static void *stbi__malloc_mad3(int a, int b, int c, int add) -{ - if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; - return stbi__malloc(a*b*c + add); +static void *stbi__malloc_mad3(int a, int b, int c, int add) { + if (!stbi__mad3sizes_valid(a, b, c, add)) + return NULL; + return stbi__malloc(a * b * c + add); } #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) -static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) -{ - if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; - return stbi__malloc(a*b*c*d + add); +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { + if (!stbi__mad4sizes_valid(a, b, c, d, add)) + return NULL; + return stbi__malloc(a * b * c * d + add); } #endif @@ -939,365 +899,356 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) // stbi__errpuc - error returning pointer to unsigned char #ifdef STBI_NO_FAILURE_STRINGS - #define stbi__err(x,y) 0 +#define stbi__err(x, y) 0 #elif defined(STBI_FAILURE_USERMSG) - #define stbi__err(x,y) stbi__err(y) +#define stbi__err(x, y) stbi__err(y) #else - #define stbi__err(x,y) stbi__err(x) +#define stbi__err(x, y) stbi__err(x) #endif -#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) -#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpf(x, y) ((float *)(size_t)(stbi__err(x, y) ? NULL : NULL)) +#define stbi__errpuc(x, y) ((unsigned char *)(size_t)(stbi__err(x, y) ? NULL : NULL)) -STBIDEF void stbi_image_free(void *retval_from_stbi_load) -{ - STBI_FREE(retval_from_stbi_load); -} +STBIDEF void stbi_image_free(void *retval_from_stbi_load) { STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); #endif #ifndef STBI_NO_HDR -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif static int stbi__vertically_flip_on_load = 0; -STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) -{ - stbi__vertically_flip_on_load = flag_true_if_should_flip; +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { + stbi__vertically_flip_on_load = flag_true_if_should_flip; } -static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields - ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed - ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order - ri->num_channels = 0; +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, + int bpc) { + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNG - if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_BMP - if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_GIF - if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PSD - if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); - #endif - #ifndef STBI_NO_PIC - if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); - #endif - #ifndef STBI_NO_PNM - if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); - #endif +#ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) + return stbi__jpeg_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNG + if (stbi__png_test(s)) + return stbi__png_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) + return stbi__bmp_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_GIF + if (stbi__gif_test(s)) + return stbi__gif_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PSD + if (stbi__psd_test(s)) + return stbi__psd_load(s, x, y, comp, req_comp, ri, bpc); +#endif +#ifndef STBI_NO_PIC + if (stbi__pic_test(s)) + return stbi__pic_load(s, x, y, comp, req_comp, ri); +#endif +#ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) + return stbi__pnm_load(s, x, y, comp, req_comp, ri); +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); - return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); - } - #endif +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x, y, comp, req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } +#endif - #ifndef STBI_NO_TGA - // test tga last because it's a crappy test! - if (stbi__tga_test(s)) - return stbi__tga_load(s,x,y,comp,req_comp, ri); - #endif +#ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s, x, y, comp, req_comp, ri); +#endif - return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); } -static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi_uc *reduced; +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi_uc *reduced; - reduced = (stbi_uc *) stbi__malloc(img_len); - if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + reduced = (stbi_uc *)stbi__malloc(img_len); + if (reduced == NULL) + return stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + for (i = 0; i < img_len; ++i) + reduced[i] = + (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling - STBI_FREE(orig); - return reduced; + STBI_FREE(orig); + return reduced; } -static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) -{ - int i; - int img_len = w * h * channels; - stbi__uint16 *enlarged; +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) { + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; - enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); - if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + enlarged = (stbi__uint16 *)stbi__malloc(img_len * 2); + if (enlarged == NULL) + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); - for (i = 0; i < img_len; ++i) - enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + for (i = 0; i < img_len; ++i) + enlarged[i] = + (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff - STBI_FREE(orig); - return enlarged; + STBI_FREE(orig); + return enlarged; } -static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) -{ - int row; - size_t bytes_per_row = (size_t)w * bytes_per_pixel; - stbi_uc temp[2048]; - stbi_uc *bytes = (stbi_uc *)image; +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) { + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; - for (row = 0; row < (h>>1); row++) { - stbi_uc *row0 = bytes + row*bytes_per_row; - stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; - // swap row0 with row1 - size_t bytes_left = bytes_per_row; - while (bytes_left) { - size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); - memcpy(temp, row0, bytes_copy); - memcpy(row0, row1, bytes_copy); - memcpy(row1, temp, bytes_copy); - row0 += bytes_copy; - row1 += bytes_copy; - bytes_left -= bytes_copy; - } - } + for (row = 0; row < (h >> 1); row++) { + stbi_uc *row0 = bytes + row * bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1) * bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } } -static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) -{ - int slice; - int slice_size = w * h * bytes_per_pixel; +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) { + int slice; + int slice_size = w * h * bytes_per_pixel; - stbi_uc *bytes = (stbi_uc *)image; - for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; - } + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } } -static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); - result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 8; - } + if (ri.bits_per_channel != 8) { + STBI_ASSERT(ri.bits_per_channel == 16); + result = stbi__convert_16_to_8((stbi__uint16 *)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } - // @TODO: move stbi__convert_format to here + // @TODO: move stbi__convert_format to here - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } - return (unsigned char *) result; + return (unsigned char *)result; } -static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - stbi__result_info ri; - void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); - if (result == NULL) - return NULL; + if (result == NULL) + return NULL; - if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); - result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); - ri.bits_per_channel = 16; - } + if (ri.bits_per_channel != 16) { + STBI_ASSERT(ri.bits_per_channel == 8); + result = stbi__convert_8_to_16((stbi_uc *)result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } - // @TODO: move stbi__convert_format16 to here - // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision - if (stbi__vertically_flip_on_load) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); - } + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } - return (stbi__uint16 *) result; + return (stbi__uint16 *)result; } #if !defined(STBI_NO_HDR) || !defined(STBI_NO_LINEAR) -static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) -{ - if (stbi__vertically_flip_on_load && result != NULL) { - int channels = req_comp ? req_comp : *comp; - stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); - } +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) { + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } } #endif #ifndef STBI_NO_STDIO -static FILE *stbi__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbi__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } - -STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - unsigned char *result; - if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) + return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__uint16 *result; - stbi__context s; - stbi__start_file(&s,f); - result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); - if (result) { - // need to 'unget' all the characters in the IO buffer - fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); - } - return result; +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) { + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s, f); + result = stbi__load_and_postprocess_16bit(&s, x, y, comp, req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, -(int)(s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; } -STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - stbi__uint16 *result; - if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); - result = stbi_load_from_file_16(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) { + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) + return (stbi_us *)stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f, x, y, comp, req_comp); + fclose(f); + return result; } +#endif //! STBI_NO_STDIO -#endif //!STBI_NO_STDIO - -STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, + int desired_channels) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); - return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, + int *channels_in_file, int desired_channels) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s, x, y, channels_in_file, desired_channels); } -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } -STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_8bit(&s, x, y, comp, req_comp); } #ifndef STBI_NO_GIF -STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); - - result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); - if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); - } +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, + int *comp, int req_comp) { + unsigned char *result; + stbi__context s; + stbi__start_mem(&s, buffer, len); + + result = (unsigned char *)stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices(result, *x, *y, *z, *comp); + } - return result; + return result; } #endif #ifndef STBI_NO_LINEAR -static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) -{ - unsigned char *data; - #ifndef STBI_NO_HDR - if (stbi__hdr_test(s)) { - stbi__result_info ri; - float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); - if (hdr_data) - stbi__float_postprocess(hdr_data,x,y,comp,req_comp); - return hdr_data; - } - #endif - data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); - if (data) - return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); - return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) { + unsigned char *data; +#ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s, x, y, comp, req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data, x, y, comp, req_comp); + return hdr_data; + } +#endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); } -STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__loadf_main(&s, x, y, comp, req_comp); } -STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, + int req_comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #ifndef STBI_NO_STDIO -STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) -{ - float *result; - FILE *f = stbi__fopen(filename, "rb"); - if (!f) return stbi__errpf("can't fopen", "Unable to open file"); - result = stbi_loadf_from_file(f,x,y,comp,req_comp); - fclose(f); - return result; +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) { + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) + return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f, x, y, comp, req_comp); + fclose(f); + return result; } -STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) -{ - stbi__context s; - stbi__start_file(&s,f); - return stbi__loadf_main(&s,x,y,comp,req_comp); +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { + stbi__context s; + stbi__start_file(&s, f); + return stbi__loadf_main(&s, x, y, comp, req_comp); } #endif // !STBI_NO_STDIO @@ -1307,198 +1258,180 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_ // defined, for API simplicity; if STBI_NO_LINEAR is defined, it always // reports false! -STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(buffer); - STBI_NOTUSED(len); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; +#endif } #ifndef STBI_NO_STDIO -STBIDEF int stbi_is_hdr (char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result=0; - if (f) { - result = stbi_is_hdr_from_file(f); - fclose(f); - } - return result; +STBIDEF int stbi_is_hdr(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result = 0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; } -STBIDEF int stbi_is_hdr_from_file(FILE *f) -{ - #ifndef STBI_NO_HDR - long pos = ftell(f); - int res; - stbi__context s; - stbi__start_file(&s,f); - res = stbi__hdr_test(&s); - fseek(f, pos, SEEK_SET); - return res; - #else - STBI_NOTUSED(f); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_file(FILE *f) { +#ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s, f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; +#else + STBI_NOTUSED(f); + return 0; +#endif } #endif // !STBI_NO_STDIO -STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) -{ - #ifndef STBI_NO_HDR - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); - return stbi__hdr_test(&s); - #else - STBI_NOTUSED(clbk); - STBI_NOTUSED(user); - return 0; - #endif +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) { +#ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__hdr_test(&s); +#else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; +#endif } #ifndef STBI_NO_LINEAR -static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; +static float stbi__l2h_gamma = 2.2f, stbi__l2h_scale = 1.0f; -STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } #endif -static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; - -STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +static float stbi__h2l_gamma_i = 1.0f / 2.2f, stbi__h2l_scale_i = 1.0f; +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1 / gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1 / scale; } ////////////////////////////////////////////////////////////////////////////// // // Common code used by all image loaders // -enum -{ - STBI__SCAN_load=0, - STBI__SCAN_type, - STBI__SCAN_header -}; +enum { STBI__SCAN_load = 0, STBI__SCAN_type, STBI__SCAN_header }; -static void stbi__refill_buffer(stbi__context *s) -{ - int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); - if (n == 0) { - // at end of file, treat same as if from memory, but need to handle case - // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file - s->read_from_callbacks = 0; - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start+1; - *s->img_buffer = 0; - } else { - s->img_buffer = s->buffer_start; - s->img_buffer_end = s->buffer_start + n; - } +static void stbi__refill_buffer(stbi__context *s) { + int n = (s->io.read)(s->io_user_data, (char *)s->buffer_start, s->buflen); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + 1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } } -stbi_inline static stbi_uc stbi__get8(stbi__context *s) -{ - if (s->img_buffer < s->img_buffer_end) - return *s->img_buffer++; - if (s->read_from_callbacks) { - stbi__refill_buffer(s); - return *s->img_buffer++; - } - return 0; +stbi_inline static stbi_uc stbi__get8(stbi__context *s) { + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; } -stbi_inline static int stbi__at_eof(stbi__context *s) -{ - if (s->io.read) { - if (!(s->io.eof)(s->io_user_data)) return 0; - // if feof() is true, check if buffer = end - // special case: we've only got the special 0 character at the end - if (s->read_from_callbacks == 0) return 1; - } +stbi_inline static int stbi__at_eof(stbi__context *s) { + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) + return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) + return 1; + } - return s->img_buffer >= s->img_buffer_end; + return s->img_buffer >= s->img_buffer_end; } -static void stbi__skip(stbi__context *s, int n) -{ - if (n < 0) { - s->img_buffer = s->img_buffer_end; - return; - } - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - s->img_buffer = s->img_buffer_end; - (s->io.skip)(s->io_user_data, n - blen); - return; - } - } - s->img_buffer += n; +static void stbi__skip(stbi__context *s, int n) { + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; } -static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) -{ - if (s->io.read) { - int blen = (int) (s->img_buffer_end - s->img_buffer); - if (blen < n) { - int res, count; +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { + if (s->io.read) { + int blen = (int)(s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; - memcpy(buffer, s->img_buffer, blen); + memcpy(buffer, s->img_buffer, blen); - count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); - res = (count == (n-blen)); - s->img_buffer = s->img_buffer_end; - return res; - } - } + count = (s->io.read)(s->io_user_data, (char *)buffer + blen, n - blen); + res = (count == (n - blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } - if (s->img_buffer+n <= s->img_buffer_end) { - memcpy(buffer, s->img_buffer, n); - s->img_buffer += n; - return 1; - } else - return 0; + if (s->img_buffer + n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; } -static int stbi__get16be(stbi__context *s) -{ - int z = stbi__get8(s); - return (z << 8) + stbi__get8(s); +static int stbi__get16be(stbi__context *s) { + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); } -static stbi__uint32 stbi__get32be(stbi__context *s) -{ - stbi__uint32 z = stbi__get16be(s); - return (z << 16) + stbi__get16be(s); +static stbi__uint32 stbi__get32be(stbi__context *s) { + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); } #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing #else -static int stbi__get16le(stbi__context *s) -{ - int z = stbi__get8(s); - return z + (stbi__get8(s) << 8); +static int stbi__get16le(stbi__context *s) { + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); } #endif #ifndef STBI_NO_BMP -static stbi__uint32 stbi__get32le(stbi__context *s) -{ - stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); +static stbi__uint32 stbi__get32le(stbi__context *s) { + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); } #endif -#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#define STBI__BYTECAST(x) ((stbi_uc)((x)&255)) // truncate int to byte without warnings ////////////////////////////////////////////////////////////////////////////// // @@ -1511,152 +1444,197 @@ static stbi__uint32 stbi__get32le(stbi__context *s) // assume data buffer is malloced, so malloc a new one and free that one // only failure mode is malloc failing -static stbi_uc stbi__compute_y(int r, int g, int b) -{ - return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); -} +static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc)(((r * 77) + (g * 150) + (29 * b)) >> 8); } -static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - unsigned char *good; +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, + unsigned int y) { + int i, j; + unsigned char *good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); - if (good == NULL) { - STBI_FREE(data); - return stbi__errpuc("outofmem", "Out of memory"); - } + good = (unsigned char *)stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - unsigned char *src = data + j * x * img_n ; - unsigned char *dest = good + j * x * req_comp; + for (j = 0; j < (int)y; ++j) { + unsigned char *src = data + j * x * img_n; + unsigned char *dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { dest[0] = src[0], dest[1] = 255; } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = 255; } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = src[1]; } + break; + STBI__CASE(3, 4) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2], dest[3] = 255; } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { dest[0] = stbi__compute_y(src[0], src[1], src[2]), dest[1] = 255; } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { dest[0] = stbi__compute_y(src[0], src[1], src[2]), dest[1] = src[3]; } + break; + STBI__CASE(4, 3) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; } + break; + default: + STBI_ASSERT(0); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } -static stbi__uint16 stbi__compute_y_16(int r, int g, int b) -{ - return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { + return (stbi__uint16)(((r * 77) + (g * 150) + (29 * b)) >> 8); } -static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) -{ - int i,j; - stbi__uint16 *good; +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, + unsigned int y) { + int i, j; + stbi__uint16 *good; - if (req_comp == img_n) return data; - STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + if (req_comp == img_n) + return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); - good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); - if (good == NULL) { - STBI_FREE(data); - return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); - } + good = (stbi__uint16 *)stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *)stbi__errpuc("outofmem", "Out of memory"); + } - for (j=0; j < (int) y; ++j) { - stbi__uint16 *src = data + j * x * img_n ; - stbi__uint16 *dest = good + j * x * req_comp; + for (j = 0; j < (int)y; ++j) { + stbi__uint16 *src = data + j * x * img_n; + stbi__uint16 *dest = good + j * x * req_comp; - #define STBI__COMBO(a,b) ((a)*8+(b)) - #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) - // convert source image with img_n components to one with req_comp components; - // avoid switch per pixel, so use switch per scanline and massive macros - switch (STBI__COMBO(img_n, req_comp)) { - STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break; - STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break; - STBI__CASE(2,1) { dest[0]=src[0]; } break; - STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; - STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break; - STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break; - STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break; - STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; - STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break; - STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break; - default: STBI_ASSERT(0); - } - #undef STBI__CASE - } +#define STBI__COMBO(a, b) ((a)*8 + (b)) +#define STBI__CASE(a, b) \ + case STBI__COMBO(a, b): \ + for (i = x - 1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1, 2) { dest[0] = src[0], dest[1] = 0xffff; } + break; + STBI__CASE(1, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(1, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = 0xffff; } + break; + STBI__CASE(2, 1) { dest[0] = src[0]; } + break; + STBI__CASE(2, 3) { dest[0] = dest[1] = dest[2] = src[0]; } + break; + STBI__CASE(2, 4) { dest[0] = dest[1] = dest[2] = src[0], dest[3] = src[1]; } + break; + STBI__CASE(3, 4) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2], dest[3] = 0xffff; } + break; + STBI__CASE(3, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(3, 2) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]), dest[1] = 0xffff; } + break; + STBI__CASE(4, 1) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]); } + break; + STBI__CASE(4, 2) { dest[0] = stbi__compute_y_16(src[0], src[1], src[2]), dest[1] = src[3]; } + break; + STBI__CASE(4, 3) { dest[0] = src[0], dest[1] = src[1], dest[2] = src[2]; } + break; + default: + STBI_ASSERT(0); + } +#undef STBI__CASE + } - STBI_FREE(data); - return good; + STBI_FREE(data); + return good; } #ifndef STBI_NO_LINEAR -static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) -{ - int i,k,n; - float *output; - if (!data) return NULL; - output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); - } - if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; - } - STBI_FREE(data); - return output; +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { + int i, k, n; + float *output; + if (!data) + return NULL; + output = (float *)stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpf("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + output[i * comp + k] = (float)(pow(data[i * comp + k] / 255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + if (k < comp) + output[i * comp + k] = data[i * comp + k] / 255.0f; + } + STBI_FREE(data); + return output; } #endif #ifndef STBI_NO_HDR -#define stbi__float2int(x) ((int) (x)) -static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) -{ - int i,k,n; - stbi_uc *output; - if (!data) return NULL; - output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); - if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } - // compute number of non-alpha components - if (comp & 1) n = comp; else n = comp-1; - for (i=0; i < x*y; ++i) { - for (k=0; k < n; ++k) { - float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - if (k < comp) { - float z = data[i*comp+k] * 255 + 0.5f; - if (z < 0) z = 0; - if (z > 255) z = 255; - output[i*comp + k] = (stbi_uc) stbi__float2int(z); - } - } - STBI_FREE(data); - return output; +#define stbi__float2int(x) ((int)(x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { + int i, k, n; + stbi_uc *output; + if (!data) + return NULL; + output = (stbi_uc *)stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + // compute number of non-alpha components + if (comp & 1) + n = comp; + else + n = comp - 1; + for (i = 0; i < x * y; ++i) { + for (k = 0; k < n; ++k) { + float z = (float)pow(data[i * comp + k] * stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + if (k < comp) { + float z = data[i * comp + k] * 255 + 0.5f; + if (z < 0) + z = 0; + if (z > 255) + z = 255; + output[i * comp + k] = (stbi_uc)stbi__float2int(z); + } + } + STBI_FREE(data); + return output; } #endif @@ -1684,749 +1662,760 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) #ifndef STBI_NO_JPEG // huffman decoding acceleration -#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache -typedef struct -{ - stbi_uc fast[1 << FAST_BITS]; - // weirdly, repacking this into AoS is a 10% speed loss, instead of a win - stbi__uint16 code[256]; - stbi_uc values[256]; - stbi_uc size[257]; - unsigned int maxcode[18]; - int delta[17]; // old 'firstsymbol' - old 'firstcode' +typedef struct { + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' } stbi__huffman; -typedef struct -{ - stbi__context *s; - stbi__huffman huff_dc[4]; - stbi__huffman huff_ac[4]; - stbi__uint16 dequant[4][64]; - stbi__int16 fast_ac[4][1 << FAST_BITS]; +typedef struct { + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; -// sizes for components, interleaved MCUs - int img_h_max, img_v_max; - int img_mcu_x, img_mcu_y; - int img_mcu_w, img_mcu_h; + // sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; -// definition of jpeg image component - struct - { - int id; - int h,v; - int tq; - int hd,ha; - int dc_pred; + // definition of jpeg image component + struct { + int id; + int h, v; + int tq; + int hd, ha; + int dc_pred; - int x,y,w2,h2; - stbi_uc *data; - void *raw_data, *raw_coeff; - stbi_uc *linebuf; - short *coeff; // progressive only - int coeff_w, coeff_h; // number of 8x8 coefficient blocks - } img_comp[4]; + int x, y, w2, h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; - stbi__uint32 code_buffer; // jpeg entropy-coded buffer - int code_bits; // number of valid bits - unsigned char marker; // marker seen while filling entropy buffer - int nomore; // flag if we saw a marker so must stop + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop - int progressive; - int spec_start; - int spec_end; - int succ_high; - int succ_low; - int eob_run; - int jfif; - int app14_color_transform; // Adobe APP14 tag - int rgb; + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; - int scan_n, order[4]; - int restart_interval, todo; + int scan_n, order[4]; + int restart_interval, todo; -// kernels - void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); - void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); - stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); + // kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, + int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); } stbi__jpeg; -static int stbi__build_huffman(stbi__huffman *h, int *count) -{ - int i,j,k=0; - unsigned int code; - // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) - h->size[k++] = (stbi_uc) (i+1); - h->size[k] = 0; +static int stbi__build_huffman(stbi__huffman *h, int *count) { + int i, j, k = 0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i = 0; i < 16; ++i) + for (j = 0; j < count[i]; ++j) + h->size[k++] = (stbi_uc)(i + 1); + h->size[k] = 0; - // compute actual symbols (from jpeg spec) - code = 0; - k = 0; - for(j=1; j <= 16; ++j) { - // compute delta to add to code to compute symbol id - h->delta[j] = k - code; - if (h->size[k] == j) { - while (h->size[k] == j) - h->code[k++] = (stbi__uint16) (code++); - if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); - } - // compute largest code + 1 for this size, preshifted as needed later - h->maxcode[j] = code << (16-j); - code <<= 1; - } - h->maxcode[j] = 0xffffffff; + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for (j = 1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16)(code++); + if (code - 1 >= (1u << j)) + return stbi__err("bad code lengths", "Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16 - j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; - // build non-spec acceleration table; 255 is flag for not-accelerated - memset(h->fast, 255, 1 << FAST_BITS); - for (i=0; i < k; ++i) { - int s = h->size[i]; - if (s <= FAST_BITS) { - int c = h->code[i] << (FAST_BITS-s); - int m = 1 << (FAST_BITS-s); - for (j=0; j < m; ++j) { - h->fast[c+j] = (stbi_uc) i; - } - } - } - return 1; + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i = 0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS - s); + int m = 1 << (FAST_BITS - s); + for (j = 0; j < m; ++j) { + h->fast[c + j] = (stbi_uc)i; + } + } + } + return 1; } // build a table that decodes both magnitude and value of small ACs in // one go. -static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) -{ - int i; - for (i=0; i < (1 << FAST_BITS); ++i) { - stbi_uc fast = h->fast[i]; - fast_ac[i] = 0; - if (fast < 255) { - int rs = h->values[fast]; - int run = (rs >> 4) & 15; - int magbits = rs & 15; - int len = h->size[fast]; +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) { + int i; + for (i = 0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; - if (magbits && len + magbits <= FAST_BITS) { - // magnitude code followed by receive_extend code - int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); - int m = 1 << (magbits - 1); - if (k < m) k += (~0U << magbits) + 1; - // if the result is small enough, we can fit it in fast_ac table - if (k >= -128 && k <= 127) - fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); - } - } - } + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) + k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16)((k * 256) + (run * 16) + (len + magbits)); + } + } + } } -static void stbi__grow_buffer_unsafe(stbi__jpeg *j) -{ - do { - unsigned int b = j->nomore ? 0 : stbi__get8(j->s); - if (b == 0xff) { - int c = stbi__get8(j->s); - while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes - if (c != 0) { - j->marker = (unsigned char) c; - j->nomore = 1; - return; - } - } - j->code_buffer |= b << (24 - j->code_bits); - j->code_bits += 8; - } while (j->code_bits <= 24); +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) { + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) + c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char)c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); } // (1 << n) - 1 -static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; +static const stbi__uint32 stbi__bmask[17] = {0, 1, 3, 7, 15, 31, 63, 127, 255, + 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535}; // decode a jpeg huffman value from the bitstream -stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) -{ - unsigned int temp; - int c,k; +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) { + unsigned int temp; + int c, k; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); - // look at the top FAST_BITS and determine what symbol ID it is, - // if the code is <= FAST_BITS - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - k = h->fast[c]; - if (k < 255) { - int s = h->size[k]; - if (s > j->code_bits) - return -1; - j->code_buffer <<= s; - j->code_bits -= s; - return h->values[k]; - } + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } - // naive test is to shift the code_buffer down so k bits are - // valid, then test against maxcode. To speed this up, we've - // preshifted maxcode left so that it has (16-k) 0s at the - // end; in other words, regardless of the number of bits, it - // wants to be compared against something shifted to have 16; - // that way we don't need to shift inside the loop. - temp = j->code_buffer >> 16; - for (k=FAST_BITS+1 ; ; ++k) - if (temp < h->maxcode[k]) - break; - if (k == 17) { - // error! code not found - j->code_bits -= 16; - return -1; - } + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k = FAST_BITS + 1;; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } - if (k > j->code_bits) - return -1; + if (k > j->code_bits) + return -1; - // convert the huffman code to the symbol id - c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; - STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); - // convert the id to a symbol - j->code_bits -= k; - j->code_buffer <<= k; - return h->values[c]; + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; } // bias[n] = (-1<<n) + 1 -static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; +static const int stbi__jbias[16] = {0, -1, -3, -7, -15, -31, -63, -127, + -255, -511, -1023, -2047, -4095, -8191, -16383, -32767}; // combined JPEG 'receive' and JPEG 'extend', since baseline // always extends everything it receives. -stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) -{ - unsigned int k; - int sgn; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) { + unsigned int k; + int sgn; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB - k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + STBI_ASSERT(n >= 0 && n < (int)(sizeof(stbi__bmask) / sizeof(*stbi__bmask))); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); } // get some unsigned bits -stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) -{ - unsigned int k; - if (j->code_bits < n) stbi__grow_buffer_unsafe(j); - k = stbi_lrot(j->code_buffer, n); - j->code_buffer = k & ~stbi__bmask[n]; - k &= stbi__bmask[n]; - j->code_bits -= n; - return k; +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { + unsigned int k; + if (j->code_bits < n) + stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; } -stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) -{ - unsigned int k; - if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); - k = j->code_buffer; - j->code_buffer <<= 1; - --j->code_bits; - return k & 0x80000000; +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { + unsigned int k; + if (j->code_bits < 1) + stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; } // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? -static const stbi_uc stbi__jpeg_dezigzag[64+15] = -{ - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63, - // let corrupt input sample past end - 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 63, 63, 63 -}; +static const stbi_uc stbi__jpeg_dezigzag[64 + 15] = {0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, + 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, + 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, + 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63}; // decode one 64-entry block-- -static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) -{ - int diff,dc,k; - int t; +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, + stbi__int16 *fac, int b, stbi__uint16 *dequant) { + int diff, dc, k; + int t; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); - // 0 all the ac values now so we can do it 32-bits at a time - memset(data,0,64*sizeof(data[0])); + // 0 all the ac values now so we can do it 32-bits at a time + memset(data, 0, 64 * sizeof(data[0])); - diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc * dequant[0]); + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc * dequant[0]); - // decode AC components, see JPEG spec - k = 1; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) * dequant[zig]); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (rs != 0xf0) break; // end block - k += 16; - } else { - k += r; - // decode into unzigzag'd location - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); - } - } - } while (k < 64); - return 1; + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) + break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) * dequant[zig]); + } + } + } while (k < 64); + return 1; } -static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) -{ - int diff,dc; - int t; - if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) { + int diff, dc; + int t; + if (j->spec_end != 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); - if (j->succ_high == 0) { - // first scan for DC coefficient, must be first - memset(data,0,64*sizeof(data[0])); // 0 all the ac values now - t = stbi__jpeg_huff_decode(j, hdc); - diff = t ? stbi__extend_receive(j, t) : 0; + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data, 0, 64 * sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; - dc = j->img_comp[b].dc_pred + diff; - j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); - } else { - // refinement scan for DC coefficient - if (stbi__jpeg_get_bit(j)) - data[0] += (short) (1 << j->succ_low); - } - return 1; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short)(dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short)(1 << j->succ_low); + } + return 1; } // @OPTIMIZE: store non-zigzagged during the decode passes, // and only de-zigzag when dequantizing -static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) -{ - int k; - if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) { + int k; + if (j->spec_start == 0) + return stbi__err("can't merge dc and ac", "Corrupt JPEG"); - if (j->succ_high == 0) { - int shift = j->succ_low; + if (j->succ_high == 0) { + int shift = j->succ_low; - if (j->eob_run) { - --j->eob_run; - return 1; - } + if (j->eob_run) { + --j->eob_run; + return 1; + } - k = j->spec_start; - do { - unsigned int zig; - int c,r,s; - if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); - c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); - r = fac[c]; - if (r) { // fast-AC path - k += (r >> 4) & 15; // run - s = r & 15; // combined length - j->code_buffer <<= s; - j->code_bits -= s; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); - } else { - int rs = stbi__jpeg_huff_decode(j, hac); - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r); - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - --j->eob_run; - break; - } - k += 16; - } else { - k += r; - zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); - } - } - } while (k <= j->spec_end); - } else { - // refinement scan for these AC coefficients + k = j->spec_start; + do { + unsigned int zig; + int c, r, s; + if (j->code_bits < 16) + stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS) - 1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short)(stbi__extend_receive(j, s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients - short bit = (short) (1 << j->succ_low); + short bit = (short)(1 << j->succ_low); - if (j->eob_run) { - --j->eob_run; - for (k = j->spec_start; k <= j->spec_end; ++k) { - short *p = &data[stbi__jpeg_dezigzag[k]]; - if (*p != 0) - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } - } else { - k = j->spec_start; - do { - int r,s; - int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh - if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); - s = rs & 15; - r = rs >> 4; - if (s == 0) { - if (r < 15) { - j->eob_run = (1 << r) - 1; - if (r) - j->eob_run += stbi__jpeg_get_bits(j, r); - r = 64; // force end of block - } else { - // r=15 s=0 should write 16 0s, so we just do - // a run of 15 0s and then write s (which is 0), - // so we don't have to do anything special here - } - } else { - if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); - // sign bit - if (stbi__jpeg_get_bit(j)) - s = bit; - else - s = -bit; - } + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r, s; + int rs = stbi__jpeg_huff_decode( + j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) + return stbi__err("bad huffman code", "Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) + return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } - // advance by r - while (k <= j->spec_end) { - short *p = &data[stbi__jpeg_dezigzag[k++]]; - if (*p != 0) { - if (stbi__jpeg_get_bit(j)) - if ((*p & bit)==0) { - if (*p > 0) - *p += bit; - else - *p -= bit; - } - } else { - if (r == 0) { - *p = (short) s; - break; - } - --r; - } - } - } while (k <= j->spec_end); - } - } - return 1; + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit) == 0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short)s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; } // take a -128..127 value and stbi__clamp it and convert to 0..255 -stbi_inline static stbi_uc stbi__clamp(int x) -{ - // trick to use a single test to catch both cases - if ((unsigned int) x > 255) { - if (x < 0) return 0; - if (x > 255) return 255; - } - return (stbi_uc) x; +stbi_inline static stbi_uc stbi__clamp(int x) { + // trick to use a single test to catch both cases + if ((unsigned int)x > 255) { + if (x < 0) + return 0; + if (x > 255) + return 255; + } + return (stbi_uc)x; } -#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) -#define stbi__fsh(x) ((x) * 4096) +#define stbi__f2f(x) ((int)(((x)*4096 + 0.5))) +#define stbi__fsh(x) ((x)*4096) // derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ - int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ - p2 = s2; \ - p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ - p2 = s0; \ - p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ - x0 = t0+t3; \ - x3 = t0-t3; \ - x1 = t1+t2; \ - x2 = t1-t2; \ - t0 = s7; \ - t1 = s5; \ - t2 = s3; \ - t3 = s1; \ - p3 = t0+t2; \ - p4 = t1+t3; \ - p1 = t0+t3; \ - p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ - t3 += p1+p4; \ - t2 += p2+p3; \ - t1 += p2+p4; \ - t0 += p1+p3; +#define STBI__IDCT_1D(s0, s1, s2, s3, s4, s5, s6, s7) \ + int t0, t1, t2, t3, p1, p2, p3, p4, p5, x0, x1, x2, x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2 + p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3 * stbi__f2f(-1.847759065f); \ + t3 = p1 + p2 * stbi__f2f(0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2 + p3); \ + t1 = stbi__fsh(p2 - p3); \ + x0 = t0 + t3; \ + x3 = t0 - t3; \ + x1 = t1 + t2; \ + x2 = t1 - t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0 + t2; \ + p4 = t1 + t3; \ + p1 = t0 + t3; \ + p2 = t1 + t2; \ + p5 = (p3 + p4) * stbi__f2f(1.175875602f); \ + t0 = t0 * stbi__f2f(0.298631336f); \ + t1 = t1 * stbi__f2f(2.053119869f); \ + t2 = t2 * stbi__f2f(3.072711026f); \ + t3 = t3 * stbi__f2f(1.501321110f); \ + p1 = p5 + p1 * stbi__f2f(-0.899976223f); \ + p2 = p5 + p2 * stbi__f2f(-2.562915447f); \ + p3 = p3 * stbi__f2f(-1.961570560f); \ + p4 = p4 * stbi__f2f(-0.390180644f); \ + t3 += p1 + p4; \ + t2 += p2 + p3; \ + t1 += p2 + p4; \ + t0 += p1 + p3; -static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) -{ - int i,val[64],*v=val; - stbi_uc *o; - short *d = data; +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) { + int i, val[64], *v = val; + stbi_uc *o; + short *d = data; - // columns - for (i=0; i < 8; ++i,++d, ++v) { - // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing - if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 - && d[40]==0 && d[48]==0 && d[56]==0) { - // no shortcut 0 seconds - // (1|2|3|4|5|6|7)==0 0 seconds - // all separate -0.047 seconds - // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds - int dcterm = d[0]*4; - v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; - } else { - STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) - // constants scaled things up by 1<<12; let's bring them back - // down, but keep 2 extra bits of precision - x0 += 512; x1 += 512; x2 += 512; x3 += 512; - v[ 0] = (x0+t3) >> 10; - v[56] = (x0-t3) >> 10; - v[ 8] = (x1+t2) >> 10; - v[48] = (x1-t2) >> 10; - v[16] = (x2+t1) >> 10; - v[40] = (x2-t1) >> 10; - v[24] = (x3+t0) >> 10; - v[32] = (x3-t0) >> 10; - } - } + // columns + for (i = 0; i < 8; ++i, ++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[8] == 0 && d[16] == 0 && d[24] == 0 && d[32] == 0 && d[40] == 0 && d[48] == 0 && d[56] == 0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0] * 4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[0], d[8], d[16], d[24], d[32], d[40], d[48], d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; + x1 += 512; + x2 += 512; + x3 += 512; + v[0] = (x0 + t3) >> 10; + v[56] = (x0 - t3) >> 10; + v[8] = (x1 + t2) >> 10; + v[48] = (x1 - t2) >> 10; + v[16] = (x2 + t1) >> 10; + v[40] = (x2 - t1) >> 10; + v[24] = (x3 + t0) >> 10; + v[32] = (x3 - t0) >> 10; + } + } - for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { - // no fast case since the first 1D IDCT spread components out - STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) - // constants scaled things up by 1<<12, plus we had 1<<2 from first - // loop, plus horizontal and vertical each scale by sqrt(8) so together - // we've got an extra 1<<3, so 1<<17 total we need to remove. - // so we want to round that, which means adding 0.5 * 1<<17, - // aka 65536. Also, we'll end up with -128 to 127 that we want - // to encode as 0..255 by adding 128, so we'll add that before the shift - x0 += 65536 + (128<<17); - x1 += 65536 + (128<<17); - x2 += 65536 + (128<<17); - x3 += 65536 + (128<<17); - // tried computing the shifts into temps, or'ing the temps to see - // if any were out of range, but that was slower - o[0] = stbi__clamp((x0+t3) >> 17); - o[7] = stbi__clamp((x0-t3) >> 17); - o[1] = stbi__clamp((x1+t2) >> 17); - o[6] = stbi__clamp((x1-t2) >> 17); - o[2] = stbi__clamp((x2+t1) >> 17); - o[5] = stbi__clamp((x2-t1) >> 17); - o[3] = stbi__clamp((x3+t0) >> 17); - o[4] = stbi__clamp((x3-t0) >> 17); - } + for (i = 0, v = val, o = out; i < 8; ++i, v += 8, o += out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128 << 17); + x1 += 65536 + (128 << 17); + x2 += 65536 + (128 << 17); + x3 += 65536 + (128 << 17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0 + t3) >> 17); + o[7] = stbi__clamp((x0 - t3) >> 17); + o[1] = stbi__clamp((x1 + t2) >> 17); + o[6] = stbi__clamp((x1 - t2) >> 17); + o[2] = stbi__clamp((x2 + t1) >> 17); + o[5] = stbi__clamp((x2 - t1) >> 17); + o[3] = stbi__clamp((x3 + t0) >> 17); + o[4] = stbi__clamp((x3 - t0) >> 17); + } } #ifdef STBI_SSE2 // sse2 integer IDCT. not the fastest possible implementation but it // produces bit-identical results to the generic C version so it's // fully "transparent". -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - // This is constructed to match our regular (generic) integer IDCT exactly. - __m128i row0, row1, row2, row3, row4, row5, row6, row7; - __m128i tmp; +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; - // dot product constant: even elems=x, odd elems=y - #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) +// dot product constant: even elems=x, odd elems=y +#define dct_const(x, y) _mm_setr_epi16((x), (y), (x), (y), (x), (y), (x), (y)) - // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) - // out(1) = c1[even]*x + c1[odd]*y - #define dct_rot(out0,out1, x,y,c0,c1) \ - __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ - __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ - __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ - __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ - __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ - __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) +// out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) +// out(1) = c1[even]*x + c1[odd]*y +#define dct_rot(out0, out1, x, y, c0, c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x), (y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x), (y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) - // out = in << 12 (in 16-bit, out 32-bit) - #define dct_widen(out, in) \ - __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ - __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) +// out = in << 12 (in 16-bit, out 32-bit) +#define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) - // wide add - #define dct_wadd(out, a, b) \ - __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_add_epi32(a##_h, b##_h) +// wide add +#define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) - // wide sub - #define dct_wsub(out, a, b) \ - __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ - __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) +// wide sub +#define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) - // butterfly a/b, add bias, then shift by "s" and pack - #define dct_bfly32o(out0, out1, a,b,bias,s) \ - { \ - __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ - __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ - dct_wadd(sum, abiased, b); \ - dct_wsub(dif, abiased, b); \ - out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ - out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ - } +// butterfly a/b, add bias, then shift by "s" and pack +#define dct_bfly32o(out0, out1, a, b, bias, s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } - // 8-bit interleave step (for transposes) - #define dct_interleave8(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi8(a, b); \ - b = _mm_unpackhi_epi8(tmp, b) +// 8-bit interleave step (for transposes) +#define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) - // 16-bit interleave step (for transposes) - #define dct_interleave16(a, b) \ - tmp = a; \ - a = _mm_unpacklo_epi16(a, b); \ - b = _mm_unpackhi_epi16(tmp, b) +// 16-bit interleave step (for transposes) +#define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) - #define dct_pass(bias,shift) \ - { \ - /* even part */ \ - dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ - __m128i sum04 = _mm_add_epi16(row0, row4); \ - __m128i dif04 = _mm_sub_epi16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ - dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ - __m128i sum17 = _mm_add_epi16(row1, row7); \ - __m128i sum35 = _mm_add_epi16(row3, row5); \ - dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ - dct_wadd(x4, y0o, y4o); \ - dct_wadd(x5, y1o, y5o); \ - dct_wadd(x6, y2o, y5o); \ - dct_wadd(x7, y3o, y4o); \ - dct_bfly32o(row0,row7, x0,x7,bias,shift); \ - dct_bfly32o(row1,row6, x1,x6,bias,shift); \ - dct_bfly32o(row2,row5, x2,x5,bias,shift); \ - dct_bfly32o(row3,row4, x3,x4,bias,shift); \ - } +#define dct_pass(bias, shift) \ + { \ + /* even part */ \ + dct_rot(t2e, t3e, row2, row6, rot0_0, rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o, y2o, row7, row3, rot2_0, rot2_1); \ + dct_rot(y1o, y3o, row5, row1, rot3_0, rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o, y5o, sum17, sum35, rot1_0, rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0, row7, x0, x7, bias, shift); \ + dct_bfly32o(row1, row6, x1, x6, bias, shift); \ + dct_bfly32o(row2, row5, x2, x5, bias, shift); \ + dct_bfly32o(row3, row4, x3, x4, bias, shift); \ + } - __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); - __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); - __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); - __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); - __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); - __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); - __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); - __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f(0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f(0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f(3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f(2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f(1.501321110f)); - // rounding biases in column/row passes, see stbi__idct_block for explanation. - __m128i bias_0 = _mm_set1_epi32(512); - __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128 << 17)); - // load - row0 = _mm_load_si128((const __m128i *) (data + 0*8)); - row1 = _mm_load_si128((const __m128i *) (data + 1*8)); - row2 = _mm_load_si128((const __m128i *) (data + 2*8)); - row3 = _mm_load_si128((const __m128i *) (data + 3*8)); - row4 = _mm_load_si128((const __m128i *) (data + 4*8)); - row5 = _mm_load_si128((const __m128i *) (data + 5*8)); - row6 = _mm_load_si128((const __m128i *) (data + 6*8)); - row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + // load + row0 = _mm_load_si128((const __m128i *)(data + 0 * 8)); + row1 = _mm_load_si128((const __m128i *)(data + 1 * 8)); + row2 = _mm_load_si128((const __m128i *)(data + 2 * 8)); + row3 = _mm_load_si128((const __m128i *)(data + 3 * 8)); + row4 = _mm_load_si128((const __m128i *)(data + 4 * 8)); + row5 = _mm_load_si128((const __m128i *)(data + 5 * 8)); + row6 = _mm_load_si128((const __m128i *)(data + 6 * 8)); + row7 = _mm_load_si128((const __m128i *)(data + 7 * 8)); - // column pass - dct_pass(bias_0, 10); + // column pass + dct_pass(bias_0, 10); - { - // 16bit 8x8 transpose pass 1 - dct_interleave16(row0, row4); - dct_interleave16(row1, row5); - dct_interleave16(row2, row6); - dct_interleave16(row3, row7); + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); - // transpose pass 2 - dct_interleave16(row0, row2); - dct_interleave16(row1, row3); - dct_interleave16(row4, row6); - dct_interleave16(row5, row7); + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); - // transpose pass 3 - dct_interleave16(row0, row1); - dct_interleave16(row2, row3); - dct_interleave16(row4, row5); - dct_interleave16(row6, row7); - } + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } - // row pass - dct_pass(bias_1, 17); + // row pass + dct_pass(bias_1, 17); - { - // pack - __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 - __m128i p1 = _mm_packus_epi16(row2, row3); - __m128i p2 = _mm_packus_epi16(row4, row5); - __m128i p3 = _mm_packus_epi16(row6, row7); + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); - // 8bit 8x8 transpose pass 1 - dct_interleave8(p0, p2); // a0e0a1e1... - dct_interleave8(p1, p3); // c0g0c1g1... + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... - // transpose pass 2 - dct_interleave8(p0, p1); // a0c0e0g0... - dct_interleave8(p2, p3); // b0d0f0h0... + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... - // transpose pass 3 - dct_interleave8(p0, p2); // a0b0c0d0... - dct_interleave8(p1, p3); // a4b4c4d4... + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... - // store - _mm_storel_epi64((__m128i *) out, p0); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p2); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p1); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; - _mm_storel_epi64((__m128i *) out, p3); out += out_stride; - _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); - } + // store + _mm_storel_epi64((__m128i *)out, p0); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p0, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p2); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p2, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p1); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p1, 0x4e)); + out += out_stride; + _mm_storel_epi64((__m128i *)out, p3); + out += out_stride; + _mm_storel_epi64((__m128i *)out, _mm_shuffle_epi32(p3, 0x4e)); + } #undef dct_const #undef dct_rot @@ -2445,198 +2434,235 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) // NEON integer IDCT. should produce bit-identical // results to the generic C version. -static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) -{ - int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) { + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; - int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); - int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); - int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); - int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); - int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); - int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); - int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); - int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); - int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); - int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); - int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); - int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f(0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f(1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f(0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f(2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f(3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f(1.501321110f)); -#define dct_long_mul(out, inq, coeff) \ - int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) -#define dct_long_mac(out, acc, inq, coeff) \ - int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ - int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) -#define dct_widen(out, inq) \ - int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ - int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) // wide add -#define dct_wadd(out, a, b) \ - int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vaddq_s32(a##_h, b##_h) +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) // wide sub -#define dct_wsub(out, a, b) \ - int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ - int32x4_t out##_h = vsubq_s32(a##_h, b##_h) +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) // butterfly a/b, then shift using "shiftop" by "s" and pack -#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ - { \ - dct_wadd(sum, a, b); \ - dct_wsub(dif, a, b); \ - out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ - out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ - } +#define dct_bfly32o(out0, out1, a, b, shiftop, s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } -#define dct_pass(shiftop, shift) \ - { \ - /* even part */ \ - int16x8_t sum26 = vaddq_s16(row2, row6); \ - dct_long_mul(p1e, sum26, rot0_0); \ - dct_long_mac(t2e, p1e, row6, rot0_1); \ - dct_long_mac(t3e, p1e, row2, rot0_2); \ - int16x8_t sum04 = vaddq_s16(row0, row4); \ - int16x8_t dif04 = vsubq_s16(row0, row4); \ - dct_widen(t0e, sum04); \ - dct_widen(t1e, dif04); \ - dct_wadd(x0, t0e, t3e); \ - dct_wsub(x3, t0e, t3e); \ - dct_wadd(x1, t1e, t2e); \ - dct_wsub(x2, t1e, t2e); \ - /* odd part */ \ - int16x8_t sum15 = vaddq_s16(row1, row5); \ - int16x8_t sum17 = vaddq_s16(row1, row7); \ - int16x8_t sum35 = vaddq_s16(row3, row5); \ - int16x8_t sum37 = vaddq_s16(row3, row7); \ - int16x8_t sumodd = vaddq_s16(sum17, sum35); \ - dct_long_mul(p5o, sumodd, rot1_0); \ - dct_long_mac(p1o, p5o, sum17, rot1_1); \ - dct_long_mac(p2o, p5o, sum35, rot1_2); \ - dct_long_mul(p3o, sum37, rot2_0); \ - dct_long_mul(p4o, sum15, rot2_1); \ - dct_wadd(sump13o, p1o, p3o); \ - dct_wadd(sump24o, p2o, p4o); \ - dct_wadd(sump23o, p2o, p3o); \ - dct_wadd(sump14o, p1o, p4o); \ - dct_long_mac(x4, sump13o, row7, rot3_0); \ - dct_long_mac(x5, sump24o, row5, rot3_1); \ - dct_long_mac(x6, sump23o, row3, rot3_2); \ - dct_long_mac(x7, sump14o, row1, rot3_3); \ - dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ - dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ - dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ - dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ - } +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0, row7, x0, x7, shiftop, shift); \ + dct_bfly32o(row1, row6, x1, x6, shiftop, shift); \ + dct_bfly32o(row2, row5, x2, x5, shiftop, shift); \ + dct_bfly32o(row3, row4, x3, x4, shiftop, shift); \ + } - // load - row0 = vld1q_s16(data + 0*8); - row1 = vld1q_s16(data + 1*8); - row2 = vld1q_s16(data + 2*8); - row3 = vld1q_s16(data + 3*8); - row4 = vld1q_s16(data + 4*8); - row5 = vld1q_s16(data + 5*8); - row6 = vld1q_s16(data + 6*8); - row7 = vld1q_s16(data + 7*8); + // load + row0 = vld1q_s16(data + 0 * 8); + row1 = vld1q_s16(data + 1 * 8); + row2 = vld1q_s16(data + 2 * 8); + row3 = vld1q_s16(data + 3 * 8); + row4 = vld1q_s16(data + 4 * 8); + row5 = vld1q_s16(data + 5 * 8); + row6 = vld1q_s16(data + 6 * 8); + row7 = vld1q_s16(data + 7 * 8); - // add DC bias - row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); - // column pass - dct_pass(vrshrn_n_s32, 10); + // column pass + dct_pass(vrshrn_n_s32, 10); - // 16bit 8x8 transpose - { + // 16bit 8x8 transpose + { // these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. // whether compilers actually get this is another story, sadly. -#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } -#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } +#define dct_trn16(x, y) \ + { \ + int16x8x2_t t = vtrnq_s16(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn32(x, y) \ + { \ + int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); \ + x = vreinterpretq_s16_s32(t.val[0]); \ + y = vreinterpretq_s16_s32(t.val[1]); \ + } +#define dct_trn64(x, y) \ + { \ + int16x8_t x0 = x; \ + int16x8_t y0 = y; \ + x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); \ + y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); \ + } - // pass 1 - dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 - dct_trn16(row2, row3); - dct_trn16(row4, row5); - dct_trn16(row6, row7); + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); - // pass 2 - dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 - dct_trn32(row1, row3); - dct_trn32(row4, row6); - dct_trn32(row5, row7); + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); - // pass 3 - dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 - dct_trn64(row1, row5); - dct_trn64(row2, row6); - dct_trn64(row3, row7); + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); #undef dct_trn16 #undef dct_trn32 #undef dct_trn64 - } + } - // row pass - // vrshrn_n_s32 only supports shifts up to 16, we need - // 17. so do a non-rounding shift of 16 first then follow - // up with a rounding shift by 1. - dct_pass(vshrn_n_s32, 16); + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); - { - // pack and round - uint8x8_t p0 = vqrshrun_n_s16(row0, 1); - uint8x8_t p1 = vqrshrun_n_s16(row1, 1); - uint8x8_t p2 = vqrshrun_n_s16(row2, 1); - uint8x8_t p3 = vqrshrun_n_s16(row3, 1); - uint8x8_t p4 = vqrshrun_n_s16(row4, 1); - uint8x8_t p5 = vqrshrun_n_s16(row5, 1); - uint8x8_t p6 = vqrshrun_n_s16(row6, 1); - uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); - // again, these can translate into one instruction, but often don't. -#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } -#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } -#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) \ + { \ + uint8x8x2_t t = vtrn_u8(x, y); \ + x = t.val[0]; \ + y = t.val[1]; \ + } +#define dct_trn8_16(x, y) \ + { \ + uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); \ + x = vreinterpret_u8_u16(t.val[0]); \ + y = vreinterpret_u8_u16(t.val[1]); \ + } +#define dct_trn8_32(x, y) \ + { \ + uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); \ + x = vreinterpret_u8_u32(t.val[0]); \ + y = vreinterpret_u8_u32(t.val[1]); \ + } - // sadly can't use interleaved stores here since we only write - // 8 bytes to each scan line! + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! - // 8x8 8-bit transpose pass 1 - dct_trn8_8(p0, p1); - dct_trn8_8(p2, p3); - dct_trn8_8(p4, p5); - dct_trn8_8(p6, p7); + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); - // pass 2 - dct_trn8_16(p0, p2); - dct_trn8_16(p1, p3); - dct_trn8_16(p4, p6); - dct_trn8_16(p5, p7); + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); - // pass 3 - dct_trn8_32(p0, p4); - dct_trn8_32(p1, p5); - dct_trn8_32(p2, p6); - dct_trn8_32(p3, p7); + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); - // store - vst1_u8(out, p0); out += out_stride; - vst1_u8(out, p1); out += out_stride; - vst1_u8(out, p2); out += out_stride; - vst1_u8(out, p3); out += out_stride; - vst1_u8(out, p4); out += out_stride; - vst1_u8(out, p5); out += out_stride; - vst1_u8(out, p6); out += out_stride; - vst1_u8(out, p7); + // store + vst1_u8(out, p0); + out += out_stride; + vst1_u8(out, p1); + out += out_stride; + vst1_u8(out, p2); + out += out_stride; + vst1_u8(out, p3); + out += out_stride; + vst1_u8(out, p4); + out += out_stride; + vst1_u8(out, p5); + out += out_stride; + vst1_u8(out, p6); + out += out_stride; + vst1_u8(out, p7); #undef dct_trn8_8 #undef dct_trn8_16 #undef dct_trn8_32 - } + } #undef dct_long_mul #undef dct_long_mac @@ -2649,1130 +2675,1221 @@ static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) #endif // STBI_NEON -#define STBI__MARKER_none 0xff +#define STBI__MARKER_none 0xff // if there's a pending marker from the entropy stream, return that // otherwise, fetch from the stream and get a marker. if there's no // marker, return 0xff, which is never a valid marker value -static stbi_uc stbi__get_marker(stbi__jpeg *j) -{ - stbi_uc x; - if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } - x = stbi__get8(j->s); - if (x != 0xff) return STBI__MARKER_none; - while (x == 0xff) - x = stbi__get8(j->s); // consume repeated 0xff fill bytes - return x; +static stbi_uc stbi__get_marker(stbi__jpeg *j) { + stbi_uc x; + if (j->marker != STBI__MARKER_none) { + x = j->marker; + j->marker = STBI__MARKER_none; + return x; + } + x = stbi__get8(j->s); + if (x != 0xff) + return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; } // in each scan, we'll have scan_n components, and the order // of the components is specified by order[] -#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) // after a restart interval, stbi__jpeg_reset the entropy decoder and // the dc prediction -static void stbi__jpeg_reset(stbi__jpeg *j) -{ - j->code_bits = 0; - j->code_buffer = 0; - j->nomore = 0; - j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; - j->marker = STBI__MARKER_none; - j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; - j->eob_run = 0; - // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, - // since we don't even allow 1<<30 pixels +static void stbi__jpeg_reset(stbi__jpeg *j) { + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels } -static int stbi__parse_entropy_coded_data(stbi__jpeg *z) -{ - stbi__jpeg_reset(z); - if (!z->progressive) { - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } else { - if (z->scan_n == 1) { - int i,j; - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - if (z->spec_start == 0) { - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } else { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) - return 0; - } - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } else { // interleaved - int i,j,k,x,y; - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x); - int y2 = (j*z->img_comp[n].v + y); - short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); - if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) - return 0; - } - } - } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - return 1; - } - } +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i, j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, + z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, + data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + STBI_SIMD_ALIGN(short, data[64]); + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x) * 8; + int y2 = (j * z->img_comp[n].v + y) * 8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc + z->img_comp[n].hd, z->huff_ac + ha, + z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * y2 + x2, + z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i, j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i, j, k, x, y; + for (j = 0; j < z->img_mcu_y; ++j) { + for (i = 0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k = 0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y = 0; y < z->img_comp[n].v; ++y) { + for (x = 0; x < z->img_comp[n].h; ++x) { + int x2 = (i * z->img_comp[n].h + x); + int y2 = (j * z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) + stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) + return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } } -static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) -{ - int i; - for (i=0; i < 64; ++i) - data[i] *= dequant[i]; +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) { + int i; + for (i = 0; i < 64; ++i) + data[i] *= dequant[i]; } -static void stbi__jpeg_finish(stbi__jpeg *z) -{ - if (z->progressive) { - // dequantize and idct the data - int i,j,n; - for (n=0; n < z->s->img_n; ++n) { - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); - stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - } - } - } - } +static void stbi__jpeg_finish(stbi__jpeg *z) { + if (z->progressive) { + // dequantize and idct the data + int i, j, n; + for (n = 0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x + 7) >> 3; + int h = (z->img_comp[n].y + 7) >> 3; + for (j = 0; j < h; ++j) { + for (i = 0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data + z->img_comp[n].w2 * j * 8 + i * 8, z->img_comp[n].w2, + data); + } + } + } + } } -static int stbi__process_marker(stbi__jpeg *z, int m) -{ - int L; - switch (m) { - case STBI__MARKER_none: // no marker found - return stbi__err("expected marker","Corrupt JPEG"); +static int stbi__process_marker(stbi__jpeg *z, int m) { + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker", "Corrupt JPEG"); - case 0xDD: // DRI - specify restart interval - if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); - z->restart_interval = stbi__get16be(z->s); - return 1; + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) + return stbi__err("bad DRI len", "Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; - case 0xDB: // DQT - define quantization table - L = stbi__get16be(z->s)-2; - while (L > 0) { - int q = stbi__get8(z->s); - int p = q >> 4, sixteen = (p != 0); - int t = q & 15,i; - if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); - if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15, i; + if (p != 0 && p != 1) + return stbi__err("bad DQT type", "Corrupt JPEG"); + if (t > 3) + return stbi__err("bad DQT table", "Corrupt JPEG"); - for (i=0; i < 64; ++i) - z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); - L -= (sixteen ? 129 : 65); - } - return L==0; + for (i = 0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = + (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L == 0; - case 0xC4: // DHT - define huffman table - L = stbi__get16be(z->s)-2; - while (L > 0) { - stbi_uc *v; - int sizes[16],i,n=0; - int q = stbi__get8(z->s); - int tc = q >> 4; - int th = q & 15; - if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); - for (i=0; i < 16; ++i) { - sizes[i] = stbi__get8(z->s); - n += sizes[i]; - } - L -= 17; - if (tc == 0) { - if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; - v = z->huff_dc[th].values; - } else { - if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; - v = z->huff_ac[th].values; - } - for (i=0; i < n; ++i) - v[i] = stbi__get8(z->s); - if (tc != 0) - stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); - L -= n; - } - return L==0; - } + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s) - 2; + while (L > 0) { + stbi_uc *v; + int sizes[16], i, n = 0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) + return stbi__err("bad DHT header", "Corrupt JPEG"); + for (i = 0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc + th, sizes)) + return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac + th, sizes)) + return 0; + v = z->huff_ac[th].values; + } + for (i = 0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L == 0; + } - // check for comment block or APP blocks - if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { - L = stbi__get16be(z->s); - if (L < 2) { - if (m == 0xFE) - return stbi__err("bad COM len","Corrupt JPEG"); - else - return stbi__err("bad APP len","Corrupt JPEG"); - } - L -= 2; + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len", "Corrupt JPEG"); + else + return stbi__err("bad APP len", "Corrupt JPEG"); + } + L -= 2; - if (m == 0xE0 && L >= 5) { // JFIF APP0 segment - static const unsigned char tag[5] = {'J','F','I','F','\0'}; - int ok = 1; - int i; - for (i=0; i < 5; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 5; - if (ok) - z->jfif = 1; - } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment - static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; - int ok = 1; - int i; - for (i=0; i < 6; ++i) - if (stbi__get8(z->s) != tag[i]) - ok = 0; - L -= 6; - if (ok) { - stbi__get8(z->s); // version - stbi__get16be(z->s); // flags0 - stbi__get16be(z->s); // flags1 - z->app14_color_transform = stbi__get8(z->s); // color transform - L -= 6; - } - } + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J', 'F', 'I', 'F', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A', 'd', 'o', 'b', 'e', '\0'}; + int ok = 1; + int i; + for (i = 0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } - stbi__skip(z->s, L); - return 1; - } + stbi__skip(z->s, L); + return 1; + } - return stbi__err("unknown marker","Corrupt JPEG"); + return stbi__err("unknown marker", "Corrupt JPEG"); } // after we see SOS -static int stbi__process_scan_header(stbi__jpeg *z) -{ - int i; - int Ls = stbi__get16be(z->s); - z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); - for (i=0; i < z->scan_n; ++i) { - int id = stbi__get8(z->s), which; - int q = stbi__get8(z->s); - for (which = 0; which < z->s->img_n; ++which) - if (z->img_comp[which].id == id) - break; - if (which == z->s->img_n) return 0; // no match - z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); - z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); - z->order[i] = which; - } +static int stbi__process_scan_header(stbi__jpeg *z) { + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int)z->s->img_n) + return stbi__err("bad SOS component count", "Corrupt JPEG"); + if (Ls != 6 + 2 * z->scan_n) + return stbi__err("bad SOS len", "Corrupt JPEG"); + for (i = 0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) + return 0; // no match + z->img_comp[which].hd = q >> 4; + if (z->img_comp[which].hd > 3) + return stbi__err("bad DC huff", "Corrupt JPEG"); + z->img_comp[which].ha = q & 15; + if (z->img_comp[which].ha > 3) + return stbi__err("bad AC huff", "Corrupt JPEG"); + z->order[i] = which; + } - { - int aa; - z->spec_start = stbi__get8(z->s); - z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 - aa = stbi__get8(z->s); - z->succ_high = (aa >> 4); - z->succ_low = (aa & 15); - if (z->progressive) { - if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) - return stbi__err("bad SOS", "Corrupt JPEG"); - } else { - if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); - if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); - z->spec_end = 63; - } - } + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || + z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) + return stbi__err("bad SOS", "Corrupt JPEG"); + z->spec_end = 63; + } + } - return 1; + return 1; } -static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) -{ - int i; - for (i=0; i < ncomp; ++i) { - if (z->img_comp[i].raw_data) { - STBI_FREE(z->img_comp[i].raw_data); - z->img_comp[i].raw_data = NULL; - z->img_comp[i].data = NULL; - } - if (z->img_comp[i].raw_coeff) { - STBI_FREE(z->img_comp[i].raw_coeff); - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].coeff = 0; - } - if (z->img_comp[i].linebuf) { - STBI_FREE(z->img_comp[i].linebuf); - z->img_comp[i].linebuf = NULL; - } - } - return why; +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) { + int i; + for (i = 0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; } -static int stbi__process_frame_header(stbi__jpeg *z, int scan) -{ - stbi__context *s = z->s; - int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline - s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG - s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires - c = stbi__get8(s); - if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); - s->img_n = c; - for (i=0; i < c; ++i) { - z->img_comp[i].data = NULL; - z->img_comp[i].linebuf = NULL; - } +static int stbi__process_frame_header(stbi__jpeg *z, int scan) { + stbi__context *s = z->s; + int Lf, p, i, q, h_max = 1, v_max = 1, c; + Lf = stbi__get16be(s); + if (Lf < 11) + return stbi__err("bad SOF len", "Corrupt JPEG"); // JPEG + p = stbi__get8(s); + if (p != 8) + return stbi__err("only 8-bit", "JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); + if (s->img_y == 0) + return stbi__err( + "no header height", + "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); + if (s->img_x == 0) + return stbi__err("0 width", "Corrupt JPEG"); // JPEG requires + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) + return stbi__err("bad component count", "Corrupt JPEG"); + s->img_n = c; + for (i = 0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } - if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + if (Lf != 8 + 3 * s->img_n) + return stbi__err("bad SOF len", "Corrupt JPEG"); - z->rgb = 0; - for (i=0; i < s->img_n; ++i) { - static const unsigned char rgb[3] = { 'R', 'G', 'B' }; - z->img_comp[i].id = stbi__get8(s); - if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) - ++z->rgb; - q = stbi__get8(s); - z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); - z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); - z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); - } + z->rgb = 0; + for (i = 0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = {'R', 'G', 'B'}; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); + if (!z->img_comp[i].h || z->img_comp[i].h > 4) + return stbi__err("bad H", "Corrupt JPEG"); + z->img_comp[i].v = q & 15; + if (!z->img_comp[i].v || z->img_comp[i].v > 4) + return stbi__err("bad V", "Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); + if (z->img_comp[i].tq > 3) + return stbi__err("bad TQ", "Corrupt JPEG"); + } - if (scan != STBI__SCAN_load) return 1; + if (scan != STBI__SCAN_load) + return 1; - if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) + return stbi__err("too large", "Image too large to decode"); - for (i=0; i < s->img_n; ++i) { - if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; - if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; - } + for (i = 0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) + h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) + v_max = z->img_comp[i].v; + } - // compute interleaved mcu info - z->img_h_max = h_max; - z->img_v_max = v_max; - z->img_mcu_w = h_max * 8; - z->img_mcu_h = v_max * 8; - // these sizes can't be more than 17 bits - z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; - z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w - 1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h - 1) / z->img_mcu_h; - for (i=0; i < s->img_n; ++i) { - // number of effective pixels (e.g. for non-interleaved MCU) - z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; - z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; - // to simplify generation, we'll allocate enough memory to decode - // the bogus oversized data from using interleaved MCUs and their - // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't - // discard the extra data until colorspace conversion - // - // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) - // so these muls can't overflow with 32-bit ints (which we require) - z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; - z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; - z->img_comp[i].coeff = 0; - z->img_comp[i].raw_coeff = 0; - z->img_comp[i].linebuf = NULL; - z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); - if (z->img_comp[i].raw_data == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - // align blocks for idct using mmx/sse - z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); - if (z->progressive) { - // w2, h2 are multiples of 8 (see above) - z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; - z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; - z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); - if (z->img_comp[i].raw_coeff == NULL) - return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); - z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); - } - } + for (i = 0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max - 1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max - 1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc *)(((size_t)z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i + 1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short *)(((size_t)z->img_comp[i].raw_coeff + 15) & ~15); + } + } - return 1; + return 1; } // use comparisons since in some cases we handle more than one case (e.g. SOF) -#define stbi__DNL(x) ((x) == 0xdc) -#define stbi__SOI(x) ((x) == 0xd8) -#define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) -#define stbi__SOS(x) ((x) == 0xda) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) -#define stbi__SOF_progressive(x) ((x) == 0xc2) +#define stbi__SOF_progressive(x) ((x) == 0xc2) -static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) -{ - int m; - z->jfif = 0; - z->app14_color_transform = -1; // valid values are 0,1,2 - z->marker = STBI__MARKER_none; // initialize cached marker to empty - m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); - if (scan == STBI__SCAN_type) return 1; - m = stbi__get_marker(z); - while (!stbi__SOF(m)) { - if (!stbi__process_marker(z,m)) return 0; - m = stbi__get_marker(z); - while (m == STBI__MARKER_none) { - // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); - m = stbi__get_marker(z); - } - } - z->progressive = stbi__SOF_progressive(m); - if (!stbi__process_frame_header(z, scan)) return 0; - return 1; +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) + return stbi__err("no SOI", "Corrupt JPEG"); + if (scan == STBI__SCAN_type) + return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z, m)) + return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) + return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) + return 0; + return 1; } // decode image to YCbCr format -static int stbi__decode_jpeg_image(stbi__jpeg *j) -{ - int m; - for (m = 0; m < 4; m++) { - j->img_comp[m].raw_data = NULL; - j->img_comp[m].raw_coeff = NULL; - } - j->restart_interval = 0; - if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; - m = stbi__get_marker(j); - while (!stbi__EOI(m)) { - if (stbi__SOS(m)) { - if (!stbi__process_scan_header(j)) return 0; - if (!stbi__parse_entropy_coded_data(j)) return 0; - if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } - // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 - } - } else if (stbi__DNL(m)) { - int Ld = stbi__get16be(j->s); - stbi__uint32 NL = stbi__get16be(j->s); - if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); - if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); - } else { - if (!stbi__process_marker(j, m)) return 0; - } - m = stbi__get_marker(j); - } - if (j->progressive) - stbi__jpeg_finish(j); - return 1; +static int stbi__decode_jpeg_image(stbi__jpeg *j) { + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) + return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) + return 0; + if (!stbi__parse_entropy_coded_data(j)) + return 0; + if (j->marker == STBI__MARKER_none) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually + // return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) + return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) + return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) + return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; } // static jfif-centered resampling (across block boundaries) -typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, - int w, int hs); +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, int w, int hs); -#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) +#define stbi__div4(x) ((stbi_uc)((x) >> 2)) -static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - STBI_NOTUSED(out); - STBI_NOTUSED(in_far); - STBI_NOTUSED(w); - STBI_NOTUSED(hs); - return in_near; +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; } -static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples vertically for every one in input - int i; - STBI_NOTUSED(hs); - for (i=0; i < w; ++i) - out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); - return out; +static stbi_uc *stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i = 0; i < w; ++i) + out[i] = stbi__div4(3 * in_near[i] + in_far[i] + 2); + return out; } -static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate two samples horizontally for every one in input - int i; - stbi_uc *input = in_near; +static stbi_uc *stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; - if (w == 1) { - // if only one sample, can't do any interpolation - out[0] = out[1] = input[0]; - return out; - } + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } - out[0] = input[0]; - out[1] = stbi__div4(input[0]*3 + input[1] + 2); - for (i=1; i < w-1; ++i) { - int n = 3*input[i]+2; - out[i*2+0] = stbi__div4(n+input[i-1]); - out[i*2+1] = stbi__div4(n+input[i+1]); - } - out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); - out[i*2+1] = input[w-1]; + out[0] = input[0]; + out[1] = stbi__div4(input[0] * 3 + input[1] + 2); + for (i = 1; i < w - 1; ++i) { + int n = 3 * input[i] + 2; + out[i * 2 + 0] = stbi__div4(n + input[i - 1]); + out[i * 2 + 1] = stbi__div4(n + input[i + 1]); + } + out[i * 2 + 0] = stbi__div4(input[w - 2] * 3 + input[w - 1] + 2); + out[i * 2 + 1] = input[w - 1]; - STBI_NOTUSED(in_far); - STBI_NOTUSED(hs); + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); - return out; + return out; } -#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) +#define stbi__div16(x) ((stbi_uc)((x) >> 4)) -static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i,t0,t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i, t0, t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - out[0] = stbi__div4(t1+2); - for (i=1; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + t1 = 3 * in_near[0] + in_far[0]; + out[0] = stbi__div4(t1 + 2); + for (i = 1; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #if defined(STBI_SSE2) || defined(STBI_NEON) -static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // need to generate 2x2 samples for every one in input - int i=0,t0,t1; +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // need to generate 2x2 samples for every one in input + int i = 0, t0, t1; - if (w == 1) { - out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); - return out; - } + if (w == 1) { + out[0] = out[1] = stbi__div4(3 * in_near[0] + in_far[0] + 2); + return out; + } - t1 = 3*in_near[0] + in_far[0]; - // process groups of 8 pixels for as long as we can. - // note we can't handle the last pixel in a row in this loop - // because we need to handle the filter boundary conditions. - for (; i < ((w-1) & ~7); i += 8) { + t1 = 3 * in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w - 1) & ~7); i += 8) { #if defined(STBI_SSE2) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - __m128i zero = _mm_setzero_si128(); - __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); - __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); - __m128i farw = _mm_unpacklo_epi8(farb, zero); - __m128i nearw = _mm_unpacklo_epi8(nearb, zero); - __m128i diff = _mm_sub_epi16(farw, nearw); - __m128i nears = _mm_slli_epi16(nearw, 2); - __m128i curr = _mm_add_epi16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *)(in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *)(in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - __m128i prv0 = _mm_slli_si128(curr, 2); - __m128i nxt0 = _mm_srli_si128(curr, 2); - __m128i prev = _mm_insert_epi16(prv0, t1, 0); - __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3 * in_near[i + 8] + in_far[i + 8], 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - __m128i bias = _mm_set1_epi16(8); - __m128i curs = _mm_slli_epi16(curr, 2); - __m128i prvd = _mm_sub_epi16(prev, curr); - __m128i nxtd = _mm_sub_epi16(next, curr); - __m128i curb = _mm_add_epi16(curs, bias); - __m128i even = _mm_add_epi16(prvd, curb); - __m128i odd = _mm_add_epi16(nxtd, curb); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); - // interleave even and odd pixels, then undo scaling. - __m128i int0 = _mm_unpacklo_epi16(even, odd); - __m128i int1 = _mm_unpackhi_epi16(even, odd); - __m128i de0 = _mm_srli_epi16(int0, 4); - __m128i de1 = _mm_srli_epi16(int1, 4); + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); - // pack and write output - __m128i outv = _mm_packus_epi16(de0, de1); - _mm_storeu_si128((__m128i *) (out + i*2), outv); + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *)(out + i * 2), outv); #elif defined(STBI_NEON) - // load and perform the vertical filtering pass - // this uses 3*x + y = 4*x + (y - x) - uint8x8_t farb = vld1_u8(in_far + i); - uint8x8_t nearb = vld1_u8(in_near + i); - int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); - int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); - int16x8_t curr = vaddq_s16(nears, diff); // current row + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row - // horizontal filter works the same based on shifted vers of current - // row. "prev" is current row shifted right by 1 pixel; we need to - // insert the previous pixel value (from t1). - // "next" is current row shifted left by 1 pixel, with first pixel - // of next block of 8 pixels added in. - int16x8_t prv0 = vextq_s16(curr, curr, 7); - int16x8_t nxt0 = vextq_s16(curr, curr, 1); - int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); - int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3 * in_near[i + 8] + in_far[i + 8], nxt0, 7); - // horizontal filter, polyphase implementation since it's convenient: - // even pixels = 3*cur + prev = cur*4 + (prev - cur) - // odd pixels = 3*cur + next = cur*4 + (next - cur) - // note the shared term. - int16x8_t curs = vshlq_n_s16(curr, 2); - int16x8_t prvd = vsubq_s16(prev, curr); - int16x8_t nxtd = vsubq_s16(next, curr); - int16x8_t even = vaddq_s16(curs, prvd); - int16x8_t odd = vaddq_s16(curs, nxtd); + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); - // undo scaling and round, then store with even/odd phases interleaved - uint8x8x2_t o; - o.val[0] = vqrshrun_n_s16(even, 4); - o.val[1] = vqrshrun_n_s16(odd, 4); - vst2_u8(out + i*2, o); + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i * 2, o); #endif - // "previous" value for next iter - t1 = 3*in_near[i+7] + in_far[i+7]; - } + // "previous" value for next iter + t1 = 3 * in_near[i + 7] + in_far[i + 7]; + } - t0 = t1; - t1 = 3*in_near[i] + in_far[i]; - out[i*2] = stbi__div16(3*t1 + t0 + 8); + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); - for (++i; i < w; ++i) { - t0 = t1; - t1 = 3*in_near[i]+in_far[i]; - out[i*2-1] = stbi__div16(3*t0 + t1 + 8); - out[i*2 ] = stbi__div16(3*t1 + t0 + 8); - } - out[w*2-1] = stbi__div4(t1+2); + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3 * in_near[i] + in_far[i]; + out[i * 2 - 1] = stbi__div16(3 * t0 + t1 + 8); + out[i * 2] = stbi__div16(3 * t1 + t0 + 8); + } + out[w * 2 - 1] = stbi__div4(t1 + 2); - STBI_NOTUSED(hs); + STBI_NOTUSED(hs); - return out; + return out; } #endif -static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) -{ - // resample with nearest-neighbor - int i,j; - STBI_NOTUSED(in_far); - for (i=0; i < w; ++i) - for (j=0; j < hs; ++j) - out[i*hs+j] = in_near[i]; - return out; +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) { + // resample with nearest-neighbor + int i, j; + STBI_NOTUSED(in_far); + for (i = 0; i < w; ++i) + for (j = 0; j < hs; ++j) + out[i * hs + j] = in_near[i]; + return out; } // this is a reduced-precision calculation of YCbCr-to-RGB introduced // to make sure the code produces the same results in both SIMD and scalar -#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) -static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) -{ - int i; - for (i=0; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } +#define stbi__float2fixed(x) (((int)((x)*4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, + int step) { + int i; + for (i = 0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + (cr * -stbi__float2fixed(0.71414f)) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #if defined(STBI_SSE2) || defined(STBI_NEON) -static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) -{ - int i = 0; +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, + int step) { + int i = 0; #ifdef STBI_SSE2 - // step == 3 is pretty ugly on the final interleave, and i'm not convinced - // it's useful in practice (you wouldn't use it for textures, for example). - // so just accelerate step == 4 case. - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); - __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); - __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); - __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); - __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); - __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); - __m128i xw = _mm_set1_epi16(255); // alpha channel + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16((short)(1.40200f * 4096.0f + 0.5f)); + __m128i cr_const1 = _mm_set1_epi16(-(short)(0.71414f * 4096.0f + 0.5f)); + __m128i cb_const0 = _mm_set1_epi16(-(short)(0.34414f * 4096.0f + 0.5f)); + __m128i cb_const1 = _mm_set1_epi16((short)(1.77200f * 4096.0f + 0.5f)); + __m128i y_bias = _mm_set1_epi8((char)(unsigned char)128); + __m128i xw = _mm_set1_epi16(255); // alpha channel - for (; i+7 < count; i += 8) { - // load - __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); - __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); - __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); - __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 - __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + for (; i + 7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *)(y + i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *)(pcr + i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *)(pcb + i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 - // unpack to short (and left-shift cr, cb by 8) - __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); - __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); - __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); - // color transform - __m128i yws = _mm_srli_epi16(yw, 4); - __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); - __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); - __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); - __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); - __m128i rws = _mm_add_epi16(cr0, yws); - __m128i gwt = _mm_add_epi16(cb0, yws); - __m128i bws = _mm_add_epi16(yws, cb1); - __m128i gws = _mm_add_epi16(gwt, cr1); + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); - // descale - __m128i rw = _mm_srai_epi16(rws, 4); - __m128i bw = _mm_srai_epi16(bws, 4); - __m128i gw = _mm_srai_epi16(gws, 4); + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); - // back to byte, set up for transpose - __m128i brb = _mm_packus_epi16(rw, bw); - __m128i gxb = _mm_packus_epi16(gw, xw); + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); - // transpose to interleave channels - __m128i t0 = _mm_unpacklo_epi8(brb, gxb); - __m128i t1 = _mm_unpackhi_epi8(brb, gxb); - __m128i o0 = _mm_unpacklo_epi16(t0, t1); - __m128i o1 = _mm_unpackhi_epi16(t0, t1); + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); - // store - _mm_storeu_si128((__m128i *) (out + 0), o0); - _mm_storeu_si128((__m128i *) (out + 16), o1); - out += 32; - } - } + // store + _mm_storeu_si128((__m128i *)(out + 0), o0); + _mm_storeu_si128((__m128i *)(out + 16), o1); + out += 32; + } + } #endif #ifdef STBI_NEON - // in this version, step=3 support would be easy to add. but is there demand? - if (step == 4) { - // this is a fairly straightforward implementation and not super-optimized. - uint8x8_t signflip = vdup_n_u8(0x80); - int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); - int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); - int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); - int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16((short)(1.40200f * 4096.0f + 0.5f)); + int16x8_t cr_const1 = vdupq_n_s16(-(short)(0.71414f * 4096.0f + 0.5f)); + int16x8_t cb_const0 = vdupq_n_s16(-(short)(0.34414f * 4096.0f + 0.5f)); + int16x8_t cb_const1 = vdupq_n_s16((short)(1.77200f * 4096.0f + 0.5f)); - for (; i+7 < count; i += 8) { - // load - uint8x8_t y_bytes = vld1_u8(y + i); - uint8x8_t cr_bytes = vld1_u8(pcr + i); - uint8x8_t cb_bytes = vld1_u8(pcb + i); - int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); - int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + for (; i + 7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); - // expand to s16 - int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); - int16x8_t crw = vshll_n_s8(cr_biased, 7); - int16x8_t cbw = vshll_n_s8(cb_biased, 7); + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); - // color transform - int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); - int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); - int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); - int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); - int16x8_t rws = vaddq_s16(yws, cr0); - int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); - int16x8_t bws = vaddq_s16(yws, cb1); + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); - // undo scaling, round, convert to byte - uint8x8x4_t o; - o.val[0] = vqrshrun_n_s16(rws, 4); - o.val[1] = vqrshrun_n_s16(gws, 4); - o.val[2] = vqrshrun_n_s16(bws, 4); - o.val[3] = vdup_n_u8(255); + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); - // store, interleaving r/g/b/a - vst4_u8(out, o); - out += 8*4; - } - } + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8 * 4; + } + } #endif - for (; i < count; ++i) { - int y_fixed = (y[i] << 20) + (1<<19); // rounding - int r,g,b; - int cr = pcr[i] - 128; - int cb = pcb[i] - 128; - r = y_fixed + cr* stbi__float2fixed(1.40200f); - g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); - b = y_fixed + cb* stbi__float2fixed(1.77200f); - r >>= 20; - g >>= 20; - b >>= 20; - if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } - if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } - if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } - out[0] = (stbi_uc)r; - out[1] = (stbi_uc)g; - out[2] = (stbi_uc)b; - out[3] = 255; - out += step; - } + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1 << 19); // rounding + int r, g, b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr * stbi__float2fixed(1.40200f); + g = y_fixed + cr * -stbi__float2fixed(0.71414f) + ((cb * -stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb * stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned)r > 255) { + if (r < 0) + r = 0; + else + r = 255; + } + if ((unsigned)g > 255) { + if (g < 0) + g = 0; + else + g = 255; + } + if ((unsigned)b > 255) { + if (b < 0) + b = 0; + else + b = 255; + } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } } #endif // set up the kernels -static void stbi__setup_jpeg(stbi__jpeg *j) -{ - j->idct_block_kernel = stbi__idct_block; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; +static void stbi__setup_jpeg(stbi__jpeg *j) { + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; #ifdef STBI_SSE2 - if (stbi__sse2_available()) { - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; - } + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } #endif #ifdef STBI_NEON - j->idct_block_kernel = stbi__idct_simd; - j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; - j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; #endif } // clean up the temporary component buffers -static void stbi__cleanup_jpeg(stbi__jpeg *j) -{ - stbi__free_jpeg_components(j, j->s->img_n, 0); -} +static void stbi__cleanup_jpeg(stbi__jpeg *j) { stbi__free_jpeg_components(j, j->s->img_n, 0); } -typedef struct -{ - resample_row_func resample; - stbi_uc *line0,*line1; - int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion - int ystep; // how far through vertical expansion we are - int ypos; // which pre-expansion row we're on +typedef struct { + resample_row_func resample; + stbi_uc *line0, *line1; + int hs, vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on } stbi__resample; // fast 0..255 * 0..255 => 0..255 rounded multiplication -static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) -{ - unsigned int t = x*y + 128; - return (stbi_uc) ((t + (t >>8)) >> 8); +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) { + unsigned int t = x * y + 128; + return (stbi_uc)((t + (t >> 8)) >> 8); } -static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) -{ - int n, decode_n, is_rgb; - z->s->img_n = 0; // make stbi__cleanup_jpeg safe +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) { + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe - // validate req_comp - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + // validate req_comp + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); - // load a jpeg image from whichever source, but leave in YCbCr format - if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { + stbi__cleanup_jpeg(z); + return NULL; + } - // determine actual number of components to generate - n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; - is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); - if (z->s->img_n == 3 && n < 3 && !is_rgb) - decode_n = 1; - else - decode_n = z->s->img_n; + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; - // resample and color-convert - { - int k; - unsigned int i,j; - stbi_uc *output; - stbi_uc *coutput[4]; + // resample and color-convert + { + int k; + unsigned int i, j; + stbi_uc *output; + stbi_uc *coutput[4]; - stbi__resample res_comp[4]; + stbi__resample res_comp[4]; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; - // allocate line buffer big enough for upsampling off the edges - // with upsample factor of 4 - z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); - if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *)stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } - r->hs = z->img_h_max / z->img_comp[k].h; - r->vs = z->img_v_max / z->img_comp[k].v; - r->ystep = r->vs >> 1; - r->w_lores = (z->s->img_x + r->hs-1) / r->hs; - r->ypos = 0; - r->line0 = r->line1 = z->img_comp[k].data; + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs - 1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; - if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; - else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; - else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; - else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; - else r->resample = stbi__resample_row_generic; - } + if (r->hs == 1 && r->vs == 1) + r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) + r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) + r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) + r->resample = z->resample_row_hv_2_kernel; + else + r->resample = stbi__resample_row_generic; + } - // can't error after this so, this is safe - output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); - if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + // can't error after this so, this is safe + output = (stbi_uc *)stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { + stbi__cleanup_jpeg(z); + return stbi__errpuc("outofmem", "Out of memory"); + } - // now go ahead and resample - for (j=0; j < z->s->img_y; ++j) { - stbi_uc *out = output + n * z->s->img_x * j; - for (k=0; k < decode_n; ++k) { - stbi__resample *r = &res_comp[k]; - int y_bot = r->ystep >= (r->vs >> 1); - coutput[k] = r->resample(z->img_comp[k].linebuf, - y_bot ? r->line1 : r->line0, - y_bot ? r->line0 : r->line1, - r->w_lores, r->hs); - if (++r->ystep >= r->vs) { - r->ystep = 0; - r->line0 = r->line1; - if (++r->ypos < z->img_comp[k].y) - r->line1 += z->img_comp[k].w2; - } - } - if (n >= 3) { - stbi_uc *y = coutput[0]; - if (z->s->img_n == 3) { - if (is_rgb) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = y[i]; - out[1] = coutput[1][i]; - out[2] = coutput[2][i]; - out[3] = 255; - out += n; - } - } else { - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else if (z->s->img_n == 4) { - if (z->app14_color_transform == 0) { // CMYK - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(coutput[0][i], m); - out[1] = stbi__blinn_8x8(coutput[1][i], m); - out[2] = stbi__blinn_8x8(coutput[2][i], m); - out[3] = 255; - out += n; - } - } else if (z->app14_color_transform == 2) { // YCCK - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - out[0] = stbi__blinn_8x8(255 - out[0], m); - out[1] = stbi__blinn_8x8(255 - out[1], m); - out[2] = stbi__blinn_8x8(255 - out[2], m); - out += n; - } - } else { // YCbCr + alpha? Ignore the fourth channel for now - z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); - } - } else - for (i=0; i < z->s->img_x; ++i) { - out[0] = out[1] = out[2] = y[i]; - out[3] = 255; // not used if n==3 - out += n; - } - } else { - if (is_rgb) { - if (n == 1) - for (i=0; i < z->s->img_x; ++i) - *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - else { - for (i=0; i < z->s->img_x; ++i, out += 2) { - out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); - out[1] = 255; - } - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { - for (i=0; i < z->s->img_x; ++i) { - stbi_uc m = coutput[3][i]; - stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); - stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); - stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); - out[0] = stbi__compute_y(r, g, b); - out[1] = 255; - out += n; - } - } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { - for (i=0; i < z->s->img_x; ++i) { - out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); - out[1] = 255; - out += n; - } - } else { - stbi_uc *y = coutput[0]; - if (n == 1) - for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; - else - for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255; - } - } - } - stbi__cleanup_jpeg(z); - *out_x = z->s->img_x; - *out_y = z->s->img_y; - if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output - return output; - } + // now go ahead and resample + for (j = 0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k = 0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i = 0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i = 0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i = 0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i = 0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i = 0; i < z->s->img_x; ++i) + out[i] = y[i]; + else + for (i = 0; i < z->s->img_x; ++i) + *out++ = y[i], *out++ = 255; + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) + *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } } -static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - unsigned char* result; - stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); - STBI_NOTUSED(ri); - j->s = s; - stbi__setup_jpeg(j); - result = load_jpeg_image(j, x,y,comp,req_comp); - STBI_FREE(j); - return result; +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + unsigned char *result; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x, y, comp, req_comp); + STBI_FREE(j); + return result; } -static int stbi__jpeg_test(stbi__context *s) -{ - int r; - stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); - j->s = s; - stbi__setup_jpeg(j); - r = stbi__decode_jpeg_header(j, STBI__SCAN_type); - stbi__rewind(s); - STBI_FREE(j); - return r; +static int stbi__jpeg_test(stbi__context *s) { + int r; + stbi__jpeg *j = (stbi__jpeg *)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; } -static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) -{ - if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { - stbi__rewind( j->s ); - return 0; - } - if (x) *x = j->s->img_x; - if (y) *y = j->s->img_y; - if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; - return 1; +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) { + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind(j->s); + return 0; + } + if (x) + *x = j->s->img_x; + if (y) + *y = j->s->img_y; + if (comp) + *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; } -static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) -{ - int result; - stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); - j->s = s; - result = stbi__jpeg_info_raw(j, x, y, comp); - STBI_FREE(j); - return result; +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { + int result; + stbi__jpeg *j = (stbi__jpeg *)(stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; } #endif @@ -3786,83 +3903,80 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_ZLIB // fast-way is faster to check than jpeg huffman, but slow way is slower -#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables -#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) -typedef struct -{ - stbi__uint16 fast[1 << STBI__ZFAST_BITS]; - stbi__uint16 firstcode[16]; - int maxcode[17]; - stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; +typedef struct { + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; } stbi__zhuffman; -stbi_inline static int stbi__bitreverse16(int n) -{ - n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); - n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); - n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); - n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); - return n; +stbi_inline static int stbi__bitreverse16(int n) { + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; } -stbi_inline static int stbi__bit_reverse(int v, int bits) -{ - STBI_ASSERT(bits <= 16); - // to bit reverse n bits, reverse 16 and shift - // e.g. 11 bits, bit reverse and shift away 5 - return stbi__bitreverse16(v) >> (16-bits); +stbi_inline static int stbi__bit_reverse(int v, int bits) { + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16 - bits); } -static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) -{ - int i,k=0; - int code, next_code[16], sizes[17]; +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) { + int i, k = 0; + int code, next_code[16], sizes[17]; - // DEFLATE spec for generating codes - memset(sizes, 0, sizeof(sizes)); - memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) - ++sizes[sizelist[i]]; - sizes[0] = 0; - for (i=1; i < 16; ++i) - if (sizes[i] > (1 << i)) - return stbi__err("bad sizes", "Corrupt PNG"); - code = 0; - for (i=1; i < 16; ++i) { - next_code[i] = code; - z->firstcode[i] = (stbi__uint16) code; - z->firstsymbol[i] = (stbi__uint16) k; - code = (code + sizes[i]); - if (sizes[i]) - if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); - z->maxcode[i] = code << (16-i); // preshift for inner loop - code <<= 1; - k += sizes[i]; - } - z->maxcode[16] = 0x10000; // sentinel - for (i=0; i < num; ++i) { - int s = sizelist[i]; - if (s) { - int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; - stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); - z->size [c] = (stbi_uc ) s; - z->value[c] = (stbi__uint16) i; - if (s <= STBI__ZFAST_BITS) { - int j = stbi__bit_reverse(next_code[s],s); - while (j < (1 << STBI__ZFAST_BITS)) { - z->fast[j] = fastv; - j += (1 << s); - } - } - ++next_code[s]; - } - } - return 1; + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i = 0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i = 1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i = 1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16)code; + z->firstsymbol[i] = (stbi__uint16)k; + code = (code + sizes[i]); + if (sizes[i]) + if (code - 1 >= (1 << i)) + return stbi__err("bad codelengths", "Corrupt PNG"); + z->maxcode[i] = code << (16 - i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i = 0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16)((s << 9) | i); + z->size[c] = (stbi_uc)s; + z->value[c] = (stbi__uint16)i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s], s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; } // zlib-from-memory implementation for PNG reading @@ -3871,259 +3985,277 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int // we require PNG read all the IDATs and combine them into a single // memory buffer -typedef struct -{ - stbi_uc *zbuffer, *zbuffer_end; - int num_bits; - stbi__uint32 code_buffer; +typedef struct { + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; - char *zout; - char *zout_start; - char *zout_end; - int z_expandable; + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; - stbi__zhuffman z_length, z_distance; + stbi__zhuffman z_length, z_distance; } stbi__zbuf; -stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) -{ - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { + if (z->zbuffer >= z->zbuffer_end) + return 0; + return *z->zbuffer++; } -static void stbi__fill_bits(stbi__zbuf *z) -{ - do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); - z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; - z->num_bits += 8; - } while (z->num_bits <= 24); +static void stbi__fill_bits(stbi__zbuf *z) { + do { + STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= (unsigned int)stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); } -stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) -{ - unsigned int k; - if (z->num_bits < n) stbi__fill_bits(z); - k = z->code_buffer & ((1 << n) - 1); - z->code_buffer >>= n; - z->num_bits -= n; - return k; +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) { + unsigned int k; + if (z->num_bits < n) + stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; } -static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s,k; - // not resolved by fast table, so compute it the slow way - // use jpeg approach, which requires MSbits at top - k = stbi__bit_reverse(a->code_buffer, 16); - for (s=STBI__ZFAST_BITS+1; ; ++s) - if (k < z->maxcode[s]) - break; - if (s == 16) return -1; // invalid code! - // code size is s, so: - b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); - a->code_buffer >>= s; - a->num_bits -= s; - return z->value[b]; +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s, k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s = STBI__ZFAST_BITS + 1;; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) + return -1; // invalid code! + // code size is s, so: + b = (k >> (16 - s)) - z->firstcode[s] + z->firstsymbol[s]; + STBI_ASSERT(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; } -stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) -{ - int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); - b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; - if (b) { - s = b >> 9; - a->code_buffer >>= s; - a->num_bits -= s; - return b & 511; - } - return stbi__zhuffman_decode_slowpath(a, z); +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { + int b, s; + if (a->num_bits < 16) + stbi__fill_bits(a); + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); } -static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { - char *q; - int cur, limit, old_limit; - z->zout = zout; - if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) - limit *= 2; - q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); - STBI_NOTUSED(old_limit); - if (q == NULL) return stbi__err("outofmem", "Out of memory"); - z->zout_start = q; - z->zout = q + cur; - z->zout_end = q + limit; - return 1; + char *q; + int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) + return stbi__err("output buffer limit", "Corrupt PNG"); + cur = (int)(z->zout - z->zout_start); + limit = old_limit = (int)(z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *)STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) + return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; } -static const int stbi__zlength_base[31] = { - 3,4,5,6,7,8,9,10,11,13, - 15,17,19,23,27,31,35,43,51,59, - 67,83,99,115,131,163,195,227,258,0,0 }; +static const int stbi__zlength_base[31] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; -static const int stbi__zlength_extra[31]= -{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; +static const int stbi__zlength_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0}; -static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, -257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; +static const int stbi__zdist_base[32] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; -static const int stbi__zdist_extra[32] = -{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; +static const int stbi__zdist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; -static int stbi__parse_huffman_block(stbi__zbuf *a) -{ - char *zout = a->zout; - for(;;) { - int z = stbi__zhuffman_decode(a, &a->z_length); - if (z < 256) { - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes - if (zout >= a->zout_end) { - if (!stbi__zexpand(a, zout, 1)) return 0; - zout = a->zout; - } - *zout++ = (char) z; - } else { - stbi_uc *p; - int len,dist; - if (z == 256) { - a->zout = zout; - return 1; - } - z -= 257; - len = stbi__zlength_base[z]; - if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); - z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); - dist = stbi__zdist_base[z]; - if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); - if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { - if (!stbi__zexpand(a, zout, len)) return 0; - zout = a->zout; - } - p = (stbi_uc *) (zout - dist); - if (dist == 1) { // run of one byte; common in images. - stbi_uc v = *p; - if (len) { do *zout++ = v; while (--len); } - } else { - if (len) { do *zout++ = *p++; while (--len); } - } - } - } +static int stbi__parse_huffman_block(stbi__zbuf *a) { + char *zout = a->zout; + for (;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) + return stbi__err("bad huffman code", "Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) + return 0; + zout = a->zout; + } + *zout++ = (char)z; + } else { + stbi_uc *p; + int len, dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) + len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) + return stbi__err("bad huffman code", "Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) + dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) + return stbi__err("bad dist", "Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) + return 0; + zout = a->zout; + } + p = (stbi_uc *)(zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { + do + *zout++ = v; + while (--len); + } + } else { + if (len) { + do + *zout++ = *p++; + while (--len); + } + } + } + } } -static int stbi__compute_huffman_codes(stbi__zbuf *a) -{ - static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - stbi__zhuffman z_codelength; - stbi_uc lencodes[286+32+137];//padding for maximum single op - stbi_uc codelength_sizes[19]; - int i,n; +static int stbi__compute_huffman_codes(stbi__zbuf *a) { + static const stbi_uc length_dezigzag[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286 + 32 + 137]; // padding for maximum single op + stbi_uc codelength_sizes[19]; + int i, n; - int hlit = stbi__zreceive(a,5) + 257; - int hdist = stbi__zreceive(a,5) + 1; - int hclen = stbi__zreceive(a,4) + 4; - int ntot = hlit + hdist; + int hlit = stbi__zreceive(a, 5) + 257; + int hdist = stbi__zreceive(a, 5) + 1; + int hclen = stbi__zreceive(a, 4) + 4; + int ntot = hlit + hdist; - memset(codelength_sizes, 0, sizeof(codelength_sizes)); - for (i=0; i < hclen; ++i) { - int s = stbi__zreceive(a,3); - codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; - } - if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i = 0; i < hclen; ++i) { + int s = stbi__zreceive(a, 3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc)s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) + return 0; - n = 0; - while (n < ntot) { - int c = stbi__zhuffman_decode(a, &z_codelength); - if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); - if (c < 16) - lencodes[n++] = (stbi_uc) c; - else { - stbi_uc fill = 0; - if (c == 16) { - c = stbi__zreceive(a,2)+3; - if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); - fill = lencodes[n-1]; - } else if (c == 17) - c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); - c = stbi__zreceive(a,7)+11; - } - if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); - memset(lencodes+n, fill, c); - n += c; - } - } - if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); - if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; - return 1; + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc)c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a, 2) + 3; + if (n == 0) + return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n - 1]; + } else if (c == 17) + c = stbi__zreceive(a, 3) + 3; + else { + STBI_ASSERT(c == 18); + c = stbi__zreceive(a, 7) + 11; + } + if (ntot - n < c) + return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes + n, fill, c); + n += c; + } + } + if (n != ntot) + return stbi__err("bad codelengths", "Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes + hlit, hdist)) + return 0; + return 1; } -static int stbi__parse_uncompressed_block(stbi__zbuf *a) -{ - stbi_uc header[4]; - int len,nlen,k; - if (a->num_bits & 7) - stbi__zreceive(a, a->num_bits & 7); // discard - // drain the bit-packed data into header - k = 0; - while (a->num_bits > 0) { - header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check - a->code_buffer >>= 8; - a->num_bits -= 8; - } - STBI_ASSERT(a->num_bits == 0); - // now fill header the normal way - while (k < 4) - header[k++] = stbi__zget8(a); - len = header[1] * 256 + header[0]; - nlen = header[3] * 256 + header[2]; - if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); - if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); - if (a->zout + len > a->zout_end) - if (!stbi__zexpand(a, a->zout, len)) return 0; - memcpy(a->zout, a->zbuffer, len); - a->zbuffer += len; - a->zout += len; - return 1; +static int stbi__parse_uncompressed_block(stbi__zbuf *a) { + stbi_uc header[4]; + int len, nlen, k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc)(a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + STBI_ASSERT(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) + return stbi__err("zlib corrupt", "Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) + return stbi__err("read past buffer", "Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) + return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; } -static int stbi__parse_zlib_header(stbi__zbuf *a) -{ - int cmf = stbi__zget8(a); - int cm = cmf & 15; - /* int cinfo = cmf >> 4; */ - int flg = stbi__zget8(a); - if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec - if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png - if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png - // window = 1 << (8 + cinfo)... but who cares, we fully buffer output - return 1; +static int stbi__parse_zlib_header(stbi__zbuf *a) { + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if ((cmf * 256 + flg) % 31 != 0) + return stbi__err("bad zlib header", "Corrupt PNG"); // zlib spec + if (flg & 32) + return stbi__err("no preset dict", "Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) + return stbi__err("bad compression", "Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; } -static const stbi_uc stbi__zdefault_length[288] = -{ - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 -}; -static const stbi_uc stbi__zdefault_distance[32] = -{ - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 -}; +static const stbi_uc stbi__zdefault_length[288] = { + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8}; +static const stbi_uc stbi__zdefault_distance[32] = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}; /* Init algorithm: { @@ -4137,117 +4269,122 @@ Init algorithm: } */ -static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) -{ - int final, type; - if (parse_header) - if (!stbi__parse_zlib_header(a)) return 0; - a->num_bits = 0; - a->code_buffer = 0; - do { - final = stbi__zreceive(a,1); - type = stbi__zreceive(a,2); - if (type == 0) { - if (!stbi__parse_uncompressed_block(a)) return 0; - } else if (type == 3) { - return 0; - } else { - if (type == 1) { - // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; - if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; - } else { - if (!stbi__compute_huffman_codes(a)) return 0; - } - if (!stbi__parse_huffman_block(a)) return 0; - } - } while (!final); - return 1; +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) { + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) + return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a, 1); + type = stbi__zreceive(a, 2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) + return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length, stbi__zdefault_length, 288)) + return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) + return 0; + } else { + if (!stbi__compute_huffman_codes(a)) + return 0; + } + if (!stbi__parse_huffman_block(a)) + return 0; + } + } while (!final); + return 1; } -static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) -{ - a->zout_start = obuf; - a->zout = obuf; - a->zout_end = obuf + olen; - a->z_expandable = exp; +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) { + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; - return stbi__parse_zlib(a, parse_header); + return stbi__parse_zlib(a, parse_header); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) -{ - return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) { + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); } -STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(initial_size); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer + len; - if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, + int parse_header) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(initial_size); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int)(a.zout - a.zout_start); + else + return -1; } -STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) -{ - stbi__zbuf a; - char *p = (char *) stbi__malloc(16384); - if (p == NULL) return NULL; - a.zbuffer = (stbi_uc *) buffer; - a.zbuffer_end = (stbi_uc *) buffer+len; - if (stbi__do_zlib(&a, p, 16384, 1, 0)) { - if (outlen) *outlen = (int) (a.zout - a.zout_start); - return a.zout_start; - } else { - STBI_FREE(a.zout_start); - return NULL; - } +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) { + stbi__zbuf a; + char *p = (char *)stbi__malloc(16384); + if (p == NULL) + return NULL; + a.zbuffer = (stbi_uc *)buffer; + a.zbuffer_end = (stbi_uc *)buffer + len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) + *outlen = (int)(a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } } -STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) -{ - stbi__zbuf a; - a.zbuffer = (stbi_uc *) ibuffer; - a.zbuffer_end = (stbi_uc *) ibuffer + ilen; - if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) - return (int) (a.zout - a.zout_start); - else - return -1; +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) { + stbi__zbuf a; + a.zbuffer = (stbi_uc *)ibuffer; + a.zbuffer_end = (stbi_uc *)ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int)(a.zout - a.zout_start); + else + return -1; } #endif @@ -4262,1057 +4399,1203 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char // - uses stb_zlib, a PD zlib implementation with fast huffman decoding #ifndef STBI_NO_PNG -typedef struct -{ - stbi__uint32 length; - stbi__uint32 type; +typedef struct { + stbi__uint32 length; + stbi__uint32 type; } stbi__pngchunk; -static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) -{ - stbi__pngchunk c; - c.length = stbi__get32be(s); - c.type = stbi__get32be(s); - return c; +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) { + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; } -static int stbi__check_png_header(stbi__context *s) -{ - static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; - int i; - for (i=0; i < 8; ++i) - if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); - return 1; +static int stbi__check_png_header(stbi__context *s) { + static const stbi_uc png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + int i; + for (i = 0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) + return stbi__err("bad png sig", "Not a PNG"); + return 1; } -typedef struct -{ - stbi__context *s; - stbi_uc *idata, *expanded, *out; - int depth; +typedef struct { + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; } stbi__png; - enum { - STBI__F_none=0, - STBI__F_sub=1, - STBI__F_up=2, - STBI__F_avg=3, - STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_none = 0, + STBI__F_sub = 1, + STBI__F_up = 2, + STBI__F_avg = 3, + STBI__F_paeth = 4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first }; -static stbi_uc first_row_filter[5] = -{ - STBI__F_none, - STBI__F_sub, - STBI__F_none, - STBI__F_avg_first, - STBI__F_paeth_first -}; +static stbi_uc first_row_filter[5] = {STBI__F_none, STBI__F_sub, STBI__F_none, STBI__F_avg_first, STBI__F_paeth_first}; -static int stbi__paeth(int a, int b, int c) -{ - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; +static int stbi__paeth(int a, int b, int c) { + int p = a + b - c; + int pa = abs(p - a); + int pb = abs(p - b); + int pc = abs(p - c); + if (pa <= pb && pa <= pc) + return a; + if (pb <= pc) + return b; + return c; } -static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +static const stbi_uc stbi__depth_scale_table[9] = {0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01}; // create the png data from post-deflated data -static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) -{ - int bytes = (depth == 16? 2 : 1); - stbi__context *s = a->s; - stbi__uint32 i,j,stride = x*out_n*bytes; - stbi__uint32 img_len, img_width_bytes; - int k; - int img_n = s->img_n; // copy it into a local for later +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, + stbi__uint32 y, int depth, int color) { + int bytes = (depth == 16 ? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i, j, stride = x * out_n * bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later - int output_bytes = out_n*bytes; - int filter_bytes = img_n*bytes; - int width = x; + int output_bytes = out_n * bytes; + int filter_bytes = img_n * bytes; + int width = x; - STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); - a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into - if (!a->out) return stbi__err("outofmem", "Out of memory"); + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n + 1); + a->out = (stbi_uc *)stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) + return stbi__err("outofmem", "Out of memory"); - if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); - img_width_bytes = (((img_n * x * depth) + 7) >> 3); - img_len = (img_width_bytes + 1) * y; + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) + return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; - // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, - // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), - // so just check for raw_len < img_len always. - if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) + return stbi__err("not enough pixels", "Corrupt PNG"); - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; - int filter = *raw++; + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *prior; + int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); + if (filter > 4) + return stbi__err("invalid filter", "Corrupt PNG"); - if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; - } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + if (depth < 8) { + STBI_ASSERT(img_width_bytes <= x); + cur += + x * out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above - // if first row, use special filter that doesn't sample previous row - if (j == 0) filter = first_row_filter[filter]; + // if first row, use special filter that doesn't sample previous row + if (j == 0) + filter = first_row_filter[filter]; - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } - } + // handle first byte explicitly + for (k = 0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none: + cur[k] = raw[k]; + break; + case STBI__F_sub: + cur[k] = raw[k]; + break; + case STBI__F_up: + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + cur[k] = STBI__BYTECAST(raw[k] + (prior[k] >> 1)); + break; + case STBI__F_paeth: + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0, prior[k], 0)); + break; + case STBI__F_avg_first: + cur[k] = raw[k]; + break; + case STBI__F_paeth_first: + cur[k] = raw[k]; + break; + } + } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes + 1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1) * filter_bytes; +#define STBI__CASE(f) \ + case f: \ + for (k = 0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: + memcpy(cur, raw, nk); + break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k - filter_bytes]); } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k - filter_bytes]) >> 1)); } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], prior[k], prior[k - filter_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k - filter_bytes] >> 1)); } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - filter_bytes], 0, 0)); + } + break; + } +#undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n + 1 == out_n); +#define STBI__CASE(f) \ + case f: \ + for (i = x - 1; i >= 1; \ + --i, cur[filter_bytes] = 255, raw += filter_bytes, cur += output_bytes, prior += output_bytes) \ + for (k = 0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } + break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k - output_bytes]); } + break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } + break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k - output_bytes]) >> 1)); } + break; + STBI__CASE(STBI__F_paeth) { + cur[k] = + STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - output_bytes], prior[k], prior[k - output_bytes])); + } + break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k - output_bytes] >> 1)); } + break; + STBI__CASE(STBI__F_paeth_first) { + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k - output_bytes], 0, 0)); + } + break; + } +#undef STBI__CASE - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride * j; // start at the beginning of the row again + for (i = 0; i < x; ++i, cur += output_bytes) { + cur[filter_bytes + 1] = 255; + } + } + } + } - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop - stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j = 0; j < y; ++j) { + stbi_uc *cur = a->out + stride * j; + stbi_uc *in = a->out + stride * j + x * out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for + // 1/2/4-bit png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data + // that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones - if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); - } - if (k > 0) *cur++ = scale * ((*in >> 4) ); - } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); - } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); - } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); - } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; - if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; - } - } else { - STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; - } - } - } - } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; + if (depth == 4) { + for (k = x * img_n; k >= 2; k -= 2, ++in) { + *cur++ = scale * ((*in >> 4)); + *cur++ = scale * ((*in) & 0x0f); + } + if (k > 0) + *cur++ = scale * ((*in >> 4)); + } else if (depth == 2) { + for (k = x * img_n; k >= 4; k -= 4, ++in) { + *cur++ = scale * ((*in >> 6)); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in) & 0x03); + } + if (k > 0) + *cur++ = scale * ((*in >> 6)); + if (k > 1) + *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) + *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k = x * img_n; k >= 8; k -= 8, ++in) { + *cur++ = scale * ((*in >> 7)); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in) & 0x01); + } + if (k > 0) + *cur++ = scale * ((*in >> 7)); + if (k > 1) + *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) + *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) + *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) + *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) + *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) + *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride * j; + if (img_n == 1) { + for (q = x - 1; q >= 0; --q) { + cur[q * 2 + 1] = 255; + cur[q * 2 + 0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q = x - 1; q >= 0; --q) { + cur[q * 4 + 3] = 255; + cur[q * 4 + 2] = cur[q * 3 + 2]; + cur[q * 4 + 1] = cur[q * 3 + 1]; + cur[q * 4 + 0] = cur[q * 3 + 0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16 *)cur; - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } - } + for (i = 0; i < x * y * out_n; ++i, cur16++, cur += 2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } - return 1; + return 1; } -static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) -{ - int bytes = (depth == 16 ? 2 : 1); - int out_bytes = out_n * bytes; - stbi_uc *final; - int p; - if (!interlaced) - return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, + int color, int interlaced) { + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); - // de-interlacing - final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); - for (p=0; p < 7; ++p) { - int xorig[] = { 0,4,0,2,0,1,0 }; - int yorig[] = { 0,0,4,0,2,0,1 }; - int xspc[] = { 8,8,4,4,2,2,1 }; - int yspc[] = { 8,8,8,4,4,2,2 }; - int i,j,x,y; - // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 - x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; - y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; - if (x && y) { - stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; - if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - STBI_FREE(final); - return 0; - } - for (j=0; j < y; ++j) { - for (i=0; i < x; ++i) { - int out_y = j*yspc[p]+yorig[p]; - int out_x = i*xspc[p]+xorig[p]; - memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, - a->out + (j*x+i)*out_bytes, out_bytes); - } - } - STBI_FREE(a->out); - image_data += img_len; - image_data_len -= img_len; - } - } - a->out = final; + // de-interlacing + final = (stbi_uc *)stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p = 0; p < 7; ++p) { + int xorig[] = {0, 4, 0, 2, 0, 1, 0}; + int yorig[] = {0, 0, 4, 0, 2, 0, 1}; + int xspc[] = {8, 8, 4, 4, 2, 2, 1}; + int yspc[] = {8, 8, 8, 4, 4, 2, 2}; + int i, j, x, y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p] - 1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p] - 1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j = 0; j < y; ++j) { + for (i = 0; i < x; ++i) { + int out_y = j * yspc[p] + yorig[p]; + int out_x = i * xspc[p] + xorig[p]; + memcpy(final + out_y * a->s->img_x * out_bytes + out_x * out_bytes, + a->out + (j * x + i) * out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; - return 1; + return 1; } -static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; - // compute color-based transparency, assuming we've - // already got 255 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i=0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 255); - p += 2; - } - } else { - for (i=0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi__uint16 *p = (stbi__uint16*) z->out; +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16 *)z->out; - // compute color-based transparency, assuming we've - // already got 65535 as the alpha value in the output - STBI_ASSERT(out_n == 2 || out_n == 4); + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); - if (out_n == 2) { - for (i = 0; i < pixel_count; ++i) { - p[1] = (p[0] == tc[0] ? 0 : 65535); - p += 2; - } - } else { - for (i = 0; i < pixel_count; ++i) { - if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) - p[3] = 0; - p += 4; - } - } - return 1; + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; } -static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) -{ - stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; - stbi_uc *p, *temp_out, *orig = a->out; +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) { + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; - p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); - if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (stbi_uc *)stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); - // between here and free(out) below, exitting would leak - temp_out = p; + // between here and free(out) below, exitting would leak + temp_out = p; - if (pal_img_n == 3) { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p += 3; - } - } else { - for (i=0; i < pixel_count; ++i) { - int n = orig[i]*4; - p[0] = palette[n ]; - p[1] = palette[n+1]; - p[2] = palette[n+2]; - p[3] = palette[n+3]; - p += 4; - } - } - STBI_FREE(a->out); - a->out = temp_out; + if (pal_img_n == 3) { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p += 3; + } + } else { + for (i = 0; i < pixel_count; ++i) { + int n = orig[i] * 4; + p[0] = palette[n]; + p[1] = palette[n + 1]; + p[2] = palette[n + 2]; + p[3] = palette[n + 3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; - STBI_NOTUSED(len); + STBI_NOTUSED(len); - return 1; + return 1; } static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__de_iphone_flag = 0; -STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) -{ - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; } -STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) -{ - stbi__de_iphone_flag = flag_true_if_should_convert; +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { + stbi__de_iphone_flag = flag_true_if_should_convert; } -static void stbi__de_iphone(stbi__png *z) -{ - stbi__context *s = z->s; - stbi__uint32 i, pixel_count = s->img_x * s->img_y; - stbi_uc *p = z->out; +static void stbi__de_iphone(stbi__png *z) { + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; - if (s->img_out_n == 3) { // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 3; - } - } else { - STBI_ASSERT(s->img_out_n == 4); - if (stbi__unpremultiply_on_load) { - // convert bgr to rgb and unpremultiply - for (i=0; i < pixel_count; ++i) { - stbi_uc a = p[3]; - stbi_uc t = p[0]; - if (a) { - stbi_uc half = a / 2; - p[0] = (p[2] * 255 + half) / a; - p[1] = (p[1] * 255 + half) / a; - p[2] = ( t * 255 + half) / a; - } else { - p[0] = p[2]; - p[2] = t; - } - p += 4; - } - } else { - // convert bgr to rgb - for (i=0; i < pixel_count; ++i) { - stbi_uc t = p[0]; - p[0] = p[2]; - p[2] = t; - p += 4; - } - } - } + if (s->img_out_n == 3) { // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i = 0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = (t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i = 0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } } -#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) +#define STBI__PNG_TYPE(a, b, c, d) \ + (((unsigned)(a) << 24) + ((unsigned)(b) << 16) + ((unsigned)(c) << 8) + (unsigned)(d)) -static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) -{ - stbi_uc palette[1024], pal_img_n=0; - stbi_uc has_trans=0, tc[3]; - stbi__uint16 tc16[3]; - stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; - int first=1,k,interlace=0, color=0, is_iphone=0; - stbi__context *s = z->s; +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) { + stbi_uc palette[1024], pal_img_n = 0; + stbi_uc has_trans = 0, tc[3]; + stbi__uint16 tc16[3]; + stbi__uint32 ioff = 0, idata_limit = 0, i, pal_len = 0; + int first = 1, k, interlace = 0, color = 0, is_iphone = 0; + stbi__context *s = z->s; - z->expanded = NULL; - z->idata = NULL; - z->out = NULL; + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; - if (!stbi__check_png_header(s)) return 0; + if (!stbi__check_png_header(s)) + return 0; - if (scan == STBI__SCAN_type) return 1; + if (scan == STBI__SCAN_type) + return 1; - for (;;) { - stbi__pngchunk c = stbi__get_chunk_header(s); - switch (c.type) { - case STBI__PNG_TYPE('C','g','B','I'): - is_iphone = 1; - stbi__skip(s, c.length); - break; - case STBI__PNG_TYPE('I','H','D','R'): { - int comp,filter; - if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); - first = 0; - if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); - color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); - if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); - comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); - filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); - interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); - if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); - if (!pal_img_n) { - s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); - if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; - } else { - // if paletted, then pal_n is our final components, and - // img_n is # components to decompress/filter. - s->img_n = 1; - if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS - } - break; - } + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C', 'g', 'B', 'I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I', 'H', 'D', 'R'): { + int comp, filter; + if (!first) + return stbi__err("multiple IHDR", "Corrupt PNG"); + first = 0; + if (c.length != 13) + return stbi__err("bad IHDR len", "Corrupt PNG"); + s->img_x = stbi__get32be(s); + if (s->img_x > (1 << 24)) + return stbi__err("too large", "Very large image (corrupt?)"); + s->img_y = stbi__get32be(s); + if (s->img_y > (1 << 24)) + return stbi__err("too large", "Very large image (corrupt?)"); + z->depth = stbi__get8(s); + if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) + return stbi__err("1/2/4/8/16-bit only", "PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); + if (color > 6) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3 && z->depth == 16) + return stbi__err("bad ctype", "Corrupt PNG"); + if (color == 3) + pal_img_n = 3; + else if (color & 1) + return stbi__err("bad ctype", "Corrupt PNG"); + comp = stbi__get8(s); + if (comp) + return stbi__err("bad comp method", "Corrupt PNG"); + filter = stbi__get8(s); + if (filter) + return stbi__err("bad filter method", "Corrupt PNG"); + interlace = stbi__get8(s); + if (interlace > 1) + return stbi__err("bad interlace method", "Corrupt PNG"); + if (!s->img_x || !s->img_y) + return stbi__err("0-pixel image", "Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) + return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) + return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) + return stbi__err("too large", "Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } - case STBI__PNG_TYPE('P','L','T','E'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); - pal_len = c.length / 3; - if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); - for (i=0; i < pal_len; ++i) { - palette[i*4+0] = stbi__get8(s); - palette[i*4+1] = stbi__get8(s); - palette[i*4+2] = stbi__get8(s); - palette[i*4+3] = 255; - } - break; - } + case STBI__PNG_TYPE('P', 'L', 'T', 'E'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256 * 3) + return stbi__err("invalid PLTE", "Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) + return stbi__err("invalid PLTE", "Corrupt PNG"); + for (i = 0; i < pal_len; ++i) { + palette[i * 4 + 0] = stbi__get8(s); + palette[i * 4 + 1] = stbi__get8(s); + palette[i * 4 + 2] = stbi__get8(s); + palette[i * 4 + 3] = 255; + } + break; + } - case STBI__PNG_TYPE('t','R','N','S'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); - if (pal_img_n) { - if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } - if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); - if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); - pal_img_n = 4; - for (i=0; i < c.length; ++i) - palette[i*4+3] = stbi__get8(s); - } else { - if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); - if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); - has_trans = 1; - if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is - } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger - } - } - break; - } + case STBI__PNG_TYPE('t', 'R', 'N', 'S'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) + return stbi__err("tRNS after IDAT", "Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { + s->img_n = 4; + return 1; + } + if (pal_len == 0) + return stbi__err("tRNS before PLTE", "Corrupt PNG"); + if (c.length > pal_len) + return stbi__err("bad tRNS len", "Corrupt PNG"); + pal_img_n = 4; + for (i = 0; i < c.length; ++i) + palette[i * 4 + 3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) + return stbi__err("tRNS with alpha", "Corrupt PNG"); + if (c.length != (stbi__uint32)s->img_n * 2) + return stbi__err("bad tRNS len", "Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * + stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } - case STBI__PNG_TYPE('I','D','A','T'): { - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } - if ((int)(ioff + c.length) < (int)ioff) return 0; - if (ioff + c.length > idata_limit) { - stbi__uint32 idata_limit_old = idata_limit; - stbi_uc *p; - if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; - while (ioff + c.length > idata_limit) - idata_limit *= 2; - STBI_NOTUSED(idata_limit_old); - p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); - z->idata = p; - } - if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); - ioff += c.length; - break; - } + case STBI__PNG_TYPE('I', 'D', 'A', 'T'): { + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) + return stbi__err("no PLTE", "Corrupt PNG"); + if (scan == STBI__SCAN_header) { + s->img_n = pal_img_n; + return 1; + } + if ((int)(ioff + c.length) < (int)ioff) + return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) + idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *)STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); + if (p == NULL) + return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata + ioff, c.length)) + return stbi__err("outofdata", "Corrupt PNG"); + ioff += c.length; + break; + } - case STBI__PNG_TYPE('I','E','N','D'): { - stbi__uint32 raw_len, bpl; - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if (scan != STBI__SCAN_load) return 1; - if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); - // initial guess for decoded data size to avoid unnecessary reallocs - bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component - raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; - z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); - if (z->expanded == NULL) return 0; // zlib should set error - STBI_FREE(z->idata); z->idata = NULL; - if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) - s->img_out_n = s->img_n+1; - else - s->img_out_n = s->img_n; - if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; - if (has_trans) { - if (z->depth == 16) { - if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; - } else { - if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; - } - } - if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) - stbi__de_iphone(z); - if (pal_img_n) { - // pal_img_n == 3 or 4 - s->img_n = pal_img_n; // record the actual colors we had - s->img_out_n = pal_img_n; - if (req_comp >= 3) s->img_out_n = req_comp; - if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) - return 0; - } else if (has_trans) { - // non-paletted image with tRNS -> source image has (constant) alpha - ++s->img_n; - } - STBI_FREE(z->expanded); z->expanded = NULL; - return 1; - } + case STBI__PNG_TYPE('I', 'E', 'N', 'D'): { + stbi__uint32 raw_len, bpl; + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) + return 1; + if (z->idata == NULL) + return stbi__err("no IDAT", "Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *)stbi_zlib_decode_malloc_guesssize_headerflag((char *)z->idata, ioff, raw_len, + (int *)&raw_len, !is_iphone); + if (z->expanded == NULL) + return 0; // zlib should set error + STBI_FREE(z->idata); + z->idata = NULL; + if ((req_comp == s->img_n + 1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n + 1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) + return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) + return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) + return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) + s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); + z->expanded = NULL; + return 1; + } - default: - // if critical, fail - if (first) return stbi__err("first not IHDR", "Corrupt PNG"); - if ((c.type & (1 << 29)) == 0) { - #ifndef STBI_NO_FAILURE_STRINGS - // not threadsafe - static char invalid_chunk[] = "XXXX PNG chunk not known"; - invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); - invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); - invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); - invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); - #endif - return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); - } - stbi__skip(s, c.length); - break; - } - // end of PNG chunk, read and skip CRC - stbi__get32be(s); - } + default: + // if critical, fail + if (first) + return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { +#ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); +#endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } } -static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) -{ - void *result=NULL; - if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) - ri->bits_per_channel = 8; - else - ri->bits_per_channel = p->depth; - result = p->out; - p->out = NULL; - if (req_comp && req_comp != p->s->img_out_n) { - if (ri->bits_per_channel == 8) - result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - else - result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); - p->s->img_out_n = req_comp; - if (result == NULL) return result; - } - *x = p->s->img_x; - *y = p->s->img_y; - if (n) *n = p->s->img_n; - } - STBI_FREE(p->out); p->out = NULL; - STBI_FREE(p->expanded); p->expanded = NULL; - STBI_FREE(p->idata); p->idata = NULL; +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) { + void *result = NULL; + if (req_comp < 0 || req_comp > 4) + return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth < 8) + ri->bits_per_channel = 8; + else + ri->bits_per_channel = p->depth; + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = + stbi__convert_format((unsigned char *)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = + stbi__convert_format16((stbi__uint16 *)result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) + return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) + *n = p->s->img_n; + } + STBI_FREE(p->out); + p->out = NULL; + STBI_FREE(p->expanded); + p->expanded = NULL; + STBI_FREE(p->idata); + p->idata = NULL; - return result; + return result; } -static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi__png p; - p.s = s; - return stbi__do_png(&p, x,y,comp,req_comp, ri); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi__png p; + p.s = s; + return stbi__do_png(&p, x, y, comp, req_comp, ri); } -static int stbi__png_test(stbi__context *s) -{ - int r; - r = stbi__check_png_header(s); - stbi__rewind(s); - return r; +static int stbi__png_test(stbi__context *s) { + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; } -static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) -{ - if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { - stbi__rewind( p->s ); - return 0; - } - if (x) *x = p->s->img_x; - if (y) *y = p->s->img_y; - if (comp) *comp = p->s->img_n; - return 1; +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) { + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind(p->s); + return 0; + } + if (x) + *x = p->s->img_x; + if (y) + *y = p->s->img_y; + if (comp) + *comp = p->s->img_n; + return 1; } -static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__png p; - p.s = s; - return stbi__png_info_raw(&p, x, y, comp); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) { + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); } -static int stbi__png_is16(stbi__context *s) -{ - stbi__png p; - p.s = s; - if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) - return 0; - if (p.depth != 16) { - stbi__rewind(p.s); - return 0; - } - return 1; +static int stbi__png_is16(stbi__context *s) { + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; } #endif // Microsoft/Windows BMP image #ifndef STBI_NO_BMP -static int stbi__bmp_test_raw(stbi__context *s) -{ - int r; - int sz; - if (stbi__get8(s) != 'B') return 0; - if (stbi__get8(s) != 'M') return 0; - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - stbi__get32le(s); // discard data offset - sz = stbi__get32le(s); - r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); - return r; +static int stbi__bmp_test_raw(stbi__context *s) { + int r; + int sz; + if (stbi__get8(s) != 'B') + return 0; + if (stbi__get8(s) != 'M') + return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; } -static int stbi__bmp_test(stbi__context *s) -{ - int r = stbi__bmp_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__bmp_test(stbi__context *s) { + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; } - // returns 0..31 for the highest set bit -static int stbi__high_bit(unsigned int z) -{ - int n=0; - if (z == 0) return -1; - if (z >= 0x10000) n += 16, z >>= 16; - if (z >= 0x00100) n += 8, z >>= 8; - if (z >= 0x00010) n += 4, z >>= 4; - if (z >= 0x00004) n += 2, z >>= 2; - if (z >= 0x00002) n += 1, z >>= 1; - return n; +static int stbi__high_bit(unsigned int z) { + int n = 0; + if (z == 0) + return -1; + if (z >= 0x10000) + n += 16, z >>= 16; + if (z >= 0x00100) + n += 8, z >>= 8; + if (z >= 0x00010) + n += 4, z >>= 4; + if (z >= 0x00004) + n += 2, z >>= 2; + if (z >= 0x00002) + n += 1, z >>= 1; + return n; } -static int stbi__bitcount(unsigned int a) -{ - a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 - a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 - a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits - a = (a + (a >> 8)); // max 16 per 8 bits - a = (a + (a >> 16)); // max 32 per 8 bits - return a & 0xff; +static int stbi__bitcount(unsigned int a) { + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; } // extract an arbitrarily-aligned N-bit value (N=bits) // from v, and then make it 8-bits long and fractionally // extend it to full full range. -static int stbi__shiftsigned(int v, int shift, int bits) -{ - static unsigned int mul_table[9] = { - 0, - 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, - 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, - }; - static unsigned int shift_table[9] = { - 0, 0,0,1,0,2,4,6,0, - }; - if (shift < 0) - v <<= -shift; - else - v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); - v >>= (8-bits); - STBI_ASSERT(bits >= 0 && bits <= 8); - return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +static int stbi__shiftsigned(int v, int shift, int bits) { + static unsigned int mul_table[9] = { + 0, + 0xff /*0b11111111*/, + 0x55 /*0b01010101*/, + 0x49 /*0b01001001*/, + 0x11 /*0b00010001*/, + 0x21 /*0b00100001*/, + 0x41 /*0b01000001*/, + 0x81 /*0b10000001*/, + 0x01 /*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0, 0, 1, 0, 2, 4, 6, 0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v >= 0 && v < 256); + v >>= (8 - bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int)((unsigned)v * mul_table[bits]) >> shift_table[bits]; } -typedef struct -{ - int bpp, offset, hsz; - unsigned int mr,mg,mb,ma, all_a; +typedef struct { + int bpp, offset, hsz; + unsigned int mr, mg, mb, ma, all_a; } stbi__bmp_data; -static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) -{ - int hsz; - if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); - stbi__get32le(s); // discard filesize - stbi__get16le(s); // discard reserved - stbi__get16le(s); // discard reserved - info->offset = stbi__get32le(s); - info->hsz = hsz = stbi__get32le(s); - info->mr = info->mg = info->mb = info->ma = 0; +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') + return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; - if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); - if (hsz == 12) { - s->img_x = stbi__get16le(s); - s->img_y = stbi__get16le(s); - } else { - s->img_x = stbi__get32le(s); - s->img_y = stbi__get32le(s); - } - if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); - info->bpp = stbi__get16le(s); - if (hsz != 12) { - int compress = stbi__get32le(s); - if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); - stbi__get32le(s); // discard sizeof - stbi__get32le(s); // discard hres - stbi__get32le(s); // discard vres - stbi__get32le(s); // discard colorsused - stbi__get32le(s); // discard max important - if (hsz == 40 || hsz == 56) { - if (hsz == 56) { - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - stbi__get32le(s); - } - if (info->bpp == 16 || info->bpp == 32) { - if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } - } else if (compress == 3) { - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - // not documented, but generated by photoshop and handled by mspaint - if (info->mr == info->mg && info->mg == info->mb) { - // ?!?!? - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else - return stbi__errpuc("bad BMP", "bad BMP"); - } - } else { - int i; - if (hsz != 108 && hsz != 124) - return stbi__errpuc("bad BMP", "bad BMP"); - info->mr = stbi__get32le(s); - info->mg = stbi__get32le(s); - info->mb = stbi__get32le(s); - info->ma = stbi__get32le(s); - stbi__get32le(s); // discard color space - for (i=0; i < 12; ++i) - stbi__get32le(s); // discard color space parameters - if (hsz == 124) { - stbi__get32le(s); // discard rendering intent - stbi__get32le(s); // discard offset of profile data - stbi__get32le(s); // discard size of profile data - stbi__get32le(s); // discard reserved - } - } - } - return (void *) 1; + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) + return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) + return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) + return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i = 0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *)1; } +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *out; + unsigned int mr = 0, mg = 0, mb = 0, ma = 0, all_a; + stbi_uc pal[256][4]; + int psize = 0, i, j, width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); -static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - unsigned int mr=0,mg=0,mb=0,ma=0, all_a; - stbi_uc pal[256][4]; - int psize=0,i,j,width; - int flip_vertically, pad, target; - stbi__bmp_data info; - STBI_NOTUSED(ri); - - info.all_a = 255; - if (stbi__bmp_parse_header(s, &info) == NULL) - return NULL; // error code already set + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set - flip_vertically = ((int) s->img_y) > 0; - s->img_y = abs((int) s->img_y); + flip_vertically = ((int)s->img_y) > 0; + s->img_y = abs((int)s->img_y); - mr = info.mr; - mg = info.mg; - mb = info.mb; - ma = info.ma; - all_a = info.all_a; + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; - if (info.hsz == 12) { - if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; - } else { - if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; - } + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - 14 - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - 14 - info.hsz) >> 2; + } - s->img_n = ma ? 4 : 3; - if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 - target = req_comp; - else - target = s->img_n; // if they want monochrome, we'll post-convert + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert - // sanity-check size - if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "Corrupt BMP"); + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); - out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - if (info.bpp < 16) { - int z=0; - if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } - for (i=0; i < psize; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - if (info.hsz != 12) stbi__get8(s); - pal[i][3] = 255; - } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); - if (info.bpp == 1) width = (s->img_x + 7) >> 3; - else if (info.bpp == 4) width = (s->img_x + 1) >> 1; - else if (info.bpp == 8) width = s->img_x; - else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } - pad = (-width)&3; - if (info.bpp == 1) { - for (j=0; j < (int) s->img_y; ++j) { - int bit_offset = 7, v = stbi__get8(s); - for (i=0; i < (int) s->img_x; ++i) { - int color = (v>>bit_offset)&0x1; - out[z++] = pal[color][0]; - out[z++] = pal[color][1]; - out[z++] = pal[color][2]; - if((--bit_offset) < 0) { - bit_offset = 7; - v = stbi__get8(s); - } - } - stbi__skip(s, pad); - } - } else { - for (j=0; j < (int) s->img_y; ++j) { - for (i=0; i < (int) s->img_x; i += 2) { - int v=stbi__get8(s),v2=0; - if (info.bpp == 4) { - v2 = v & 15; - v >>= 4; - } - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - if (i+1 == (int) s->img_x) break; - v = (info.bpp == 8) ? stbi__get8(s) : v2; - out[z++] = pal[v][0]; - out[z++] = pal[v][1]; - out[z++] = pal[v][2]; - if (target == 4) out[z++] = 255; - } - stbi__skip(s, pad); - } - } - } else { - int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; - int z = 0; - int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); - if (info.bpp == 24) width = 3 * s->img_x; - else if (info.bpp == 16) width = 2*s->img_x; - else /* bpp = 32 and pad = 0 */ width=0; - pad = (-width) & 3; - if (info.bpp == 24) { - easy = 1; - } else if (info.bpp == 32) { - if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) - easy = 2; - } - if (!easy) { - if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } - // right shift amt to put high bit in position #7 - rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); - gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); - bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); - ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); - } - for (j=0; j < (int) s->img_y; ++j) { - if (easy) { - for (i=0; i < (int) s->img_x; ++i) { - unsigned char a; - out[z+2] = stbi__get8(s); - out[z+1] = stbi__get8(s); - out[z+0] = stbi__get8(s); - z += 3; - a = (easy == 2 ? stbi__get8(s) : 255); - all_a |= a; - if (target == 4) out[z++] = a; - } - } else { - int bpp = info.bpp; - for (i=0; i < (int) s->img_x; ++i) { - stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); - unsigned int a; - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); - out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); - a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - all_a |= a; - if (target == 4) out[z++] = STBI__BYTECAST(a); - } - } - stbi__skip(s, pad); - } - } + out = (stbi_uc *)stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z = 0; + if (psize == 0 || psize > 256) { + STBI_FREE(out); + return stbi__errpuc("invalid", "Corrupt BMP"); + } + for (i = 0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) + stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) + width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) + width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) + width = s->img_x; + else { + STBI_FREE(out); + return stbi__errpuc("bad bpp", "Corrupt BMP"); + } + pad = (-width) & 3; + if (info.bpp == 1) { + for (j = 0; j < (int)s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i = 0; i < (int)s->img_x; ++i) { + int color = (v >> bit_offset) & 0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if ((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j = 0; j < (int)s->img_y; ++j) { + for (i = 0; i < (int)s->img_x; i += 2) { + int v = stbi__get8(s), v2 = 0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + if (i + 1 == (int)s->img_x) + break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) + out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift = 0, gshift = 0, bshift = 0, ashift = 0, rcount = 0, gcount = 0, bcount = 0, acount = 0; + int z = 0; + int easy = 0; + stbi__skip(s, info.offset - 14 - info.hsz); + if (info.bpp == 24) + width = 3 * s->img_x; + else if (info.bpp == 16) + width = 2 * s->img_x; + else /* bpp = 32 and pad = 0 */ + width = 0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { + STBI_FREE(out); + return stbi__errpuc("bad masks", "Corrupt BMP"); + } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr) - 7; + rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg) - 7; + gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb) - 7; + bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma) - 7; + acount = stbi__bitcount(ma); + } + for (j = 0; j < (int)s->img_y; ++j) { + if (easy) { + for (i = 0; i < (int)s->img_x; ++i) { + unsigned char a; + out[z + 2] = stbi__get8(s); + out[z + 1] = stbi__get8(s); + out[z + 0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) + out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i = 0; i < (int)s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32)stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) + out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } - // if alpha channel is all 0s, replace with all 255s - if (target == 4 && all_a == 0) - for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) - out[i] = 255; + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i = 4 * s->img_x * s->img_y - 1; i >= 0; i -= 4) + out[i] = 255; - if (flip_vertically) { - stbi_uc t; - for (j=0; j < (int) s->img_y>>1; ++j) { - stbi_uc *p1 = out + j *s->img_x*target; - stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; - for (i=0; i < (int) s->img_x*target; ++i) { - t = p1[i], p1[i] = p2[i], p2[i] = t; - } - } - } + if (flip_vertically) { + stbi_uc t; + for (j = 0; j < (int)s->img_y >> 1; ++j) { + stbi_uc *p1 = out + j * s->img_x * target; + stbi_uc *p2 = out + (s->img_y - 1 - j) * s->img_x * target; + for (i = 0; i < (int)s->img_x * target; ++i) { + t = p1[i], p1[i] = p2[i], p2[i] = t; + } + } + } - if (req_comp && req_comp != target) { - out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; - return out; + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; + return out; } #endif @@ -5320,330 +5603,332 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req // by Jonathan Dummer #ifndef STBI_NO_TGA // returns STBI_rgb or whatever, 0 on error -static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) -{ - // only RGB or RGBA (incl. 16bit) or grey allowed - if (is_rgb16) *is_rgb16 = 0; - switch(bits_per_pixel) { - case 8: return STBI_grey; - case 16: if(is_grey) return STBI_grey_alpha; - // fallthrough - case 15: if(is_rgb16) *is_rgb16 = 1; - return STBI_rgb; - case 24: // fallthrough - case 32: return bits_per_pixel/8; - default: return 0; - } +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int *is_rgb16) { + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) + *is_rgb16 = 0; + switch (bits_per_pixel) { + case 8: + return STBI_grey; + case 16: + if (is_grey) + return STBI_grey_alpha; + // fallthrough + case 15: + if (is_rgb16) + *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: + return bits_per_pixel / 8; + default: + return 0; + } } -static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) -{ - int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; - int sz, tga_colormap_type; - stbi__get8(s); // discard Offset - tga_colormap_type = stbi__get8(s); // colormap type - if( tga_colormap_type > 1 ) { - stbi__rewind(s); - return 0; // only RGB or indexed allowed - } - tga_image_type = stbi__get8(s); // image type - if ( tga_colormap_type == 1 ) { // colormapped (paletted) image - if (tga_image_type != 1 && tga_image_type != 9) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { - stbi__rewind(s); - return 0; - } - stbi__skip(s,4); // skip image x and y origin - tga_colormap_bpp = sz; - } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE - if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { - stbi__rewind(s); - return 0; // only RGB or grey allowed, +/- RLE - } - stbi__skip(s,9); // skip colormap specification and image x/y origin - tga_colormap_bpp = 0; - } - tga_w = stbi__get16le(s); - if( tga_w < 1 ) { - stbi__rewind(s); - return 0; // test width - } - tga_h = stbi__get16le(s); - if( tga_h < 1 ) { - stbi__rewind(s); - return 0; // test height - } - tga_bits_per_pixel = stbi__get8(s); // bits per pixel - stbi__get8(s); // ignore alpha bits - if (tga_colormap_bpp != 0) { - if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { - // when using a colormap, tga_bits_per_pixel is the size of the indexes - // I don't think anything but 8 or 16bit indexes makes sense - stbi__rewind(s); - return 0; - } - tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); - } else { - tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); - } - if(!tga_comp) { - stbi__rewind(s); - return 0; - } - if (x) *x = tga_w; - if (y) *y = tga_h; - if (comp) *comp = tga_comp; - return 1; // seems to have passed everything +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) { + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if (tga_colormap_type > 1) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if (tga_colormap_type == 1) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ((tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11)) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s, 9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if (tga_w < 1) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if (tga_h < 1) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if (!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) + *x = tga_w; + if (y) + *y = tga_h; + if (comp) + *comp = tga_comp; + return 1; // seems to have passed everything } -static int stbi__tga_test(stbi__context *s) -{ - int res = 0; - int sz, tga_color_type; - stbi__get8(s); // discard Offset - tga_color_type = stbi__get8(s); // color type - if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed - sz = stbi__get8(s); // image type - if ( tga_color_type == 1 ) { // colormapped (paletted) image - if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 - stbi__skip(s,4); // skip index of first colormap entry and number of entries - sz = stbi__get8(s); // check bits per palette color entry - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; - stbi__skip(s,4); // skip image x and y origin - } else { // "normal" image w/o colormap - if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE - stbi__skip(s,9); // skip colormap specification and image x/y origin - } - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width - if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height - sz = stbi__get8(s); // bits per pixel - if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index - if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; +static int stbi__tga_test(stbi__context *s) { + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if (tga_color_type > 1) + goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if (tga_color_type == 1) { // colormapped (paletted) image + if (sz != 1 && sz != 9) + goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s, 4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; + stbi__skip(s, 4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ((sz != 2) && (sz != 3) && (sz != 10) && (sz != 11)) + goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s, 9); // skip colormap specification and image x/y origin + } + if (stbi__get16le(s) < 1) + goto errorEnd; // test width + if (stbi__get16le(s) < 1) + goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ((tga_color_type == 1) && (sz != 8) && (sz != 16)) + goto errorEnd; // for colormapped images, bpp is size of an index + if ((sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32)) + goto errorEnd; - res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 errorEnd: - stbi__rewind(s); - return res; + stbi__rewind(s); + return res; } // read 16bit value and convert to 24bit RGB -static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) -{ - stbi__uint16 px = (stbi__uint16)stbi__get16le(s); - stbi__uint16 fiveBitMask = 31; - // we have 3 channels with 5bits each - int r = (px >> 10) & fiveBitMask; - int g = (px >> 5) & fiveBitMask; - int b = px & fiveBitMask; - // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later - out[0] = (stbi_uc)((r * 255)/31); - out[1] = (stbi_uc)((g * 255)/31); - out[2] = (stbi_uc)((b * 255)/31); +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc *out) { + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255) / 31); + out[1] = (stbi_uc)((g * 255) / 31); + out[2] = (stbi_uc)((b * 255) / 31); - // some people claim that the most significant bit might be used for alpha - // (possibly if an alpha-bit is set in the "image descriptor byte") - // but that only made 16bit test images completely translucent.. - // so let's treat all 15 and 16bit TGAs as RGB with no alpha. + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. } -static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - // read in the TGA header stuff - int tga_offset = stbi__get8(s); - int tga_indexed = stbi__get8(s); - int tga_image_type = stbi__get8(s); - int tga_is_RLE = 0; - int tga_palette_start = stbi__get16le(s); - int tga_palette_len = stbi__get16le(s); - int tga_palette_bits = stbi__get8(s); - int tga_x_origin = stbi__get16le(s); - int tga_y_origin = stbi__get16le(s); - int tga_width = stbi__get16le(s); - int tga_height = stbi__get16le(s); - int tga_bits_per_pixel = stbi__get8(s); - int tga_comp, tga_rgb16=0; - int tga_inverted = stbi__get8(s); - // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) - // image data - unsigned char *tga_data; - unsigned char *tga_palette = NULL; - int i, j; - unsigned char raw_data[4] = {0}; - int RLE_count = 0; - int RLE_repeating = 0; - int read_next_pixel = 1; - STBI_NOTUSED(ri); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16 = 0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); - // do a tiny bit of precessing - if ( tga_image_type >= 8 ) - { - tga_image_type -= 8; - tga_is_RLE = 1; - } - tga_inverted = 1 - ((tga_inverted >> 5) & 1); + // do a tiny bit of precessing + if (tga_image_type >= 8) { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); - // If I'm paletted, then I'll use the number of bits from the palette - if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); - else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + // If I'm paletted, then I'll use the number of bits from the palette + if (tga_indexed) + tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); - if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency - return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + if (!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); - // tga info - *x = tga_width; - *y = tga_height; - if (comp) *comp = tga_comp; + // tga info + *x = tga_width; + *y = tga_height; + if (comp) + *comp = tga_comp; - if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) - return stbi__errpuc("too large", "Corrupt TGA"); + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); - tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); - if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + tga_data = (unsigned char *)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) + return stbi__errpuc("outofmem", "Out of memory"); - // skip to the data's starting position (offset usually = 0) - stbi__skip(s, tga_offset ); + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset); - if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { - for (i=0; i < tga_height; ++i) { - int row = tga_inverted ? tga_height -i - 1 : i; - stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; - stbi__getn(s, tga_row, tga_width * tga_comp); - } - } else { - // do I need to load a palette? - if ( tga_indexed) - { - // any data to skip? (offset usually = 0) - stbi__skip(s, tga_palette_start ); - // load the palette - tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); - if (!tga_palette) { - STBI_FREE(tga_data); - return stbi__errpuc("outofmem", "Out of memory"); - } - if (tga_rgb16) { - stbi_uc *pal_entry = tga_palette; - STBI_ASSERT(tga_comp == STBI_rgb); - for (i=0; i < tga_palette_len; ++i) { - stbi__tga_read_rgb16(s, pal_entry); - pal_entry += tga_comp; - } - } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { - STBI_FREE(tga_data); - STBI_FREE(tga_palette); - return stbi__errpuc("bad palette", "Corrupt TGA"); - } - } - // load the data - for (i=0; i < tga_width * tga_height; ++i) - { - // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? - if ( tga_is_RLE ) - { - if ( RLE_count == 0 ) - { - // yep, get the next byte as a RLE command - int RLE_cmd = stbi__get8(s); - RLE_count = 1 + (RLE_cmd & 127); - RLE_repeating = RLE_cmd >> 7; - read_next_pixel = 1; - } else if ( !RLE_repeating ) - { - read_next_pixel = 1; - } - } else - { - read_next_pixel = 1; - } - // OK, if I need to read a pixel, do it now - if ( read_next_pixel ) - { - // load however much data we did have - if ( tga_indexed ) - { - // read in index, then perform the lookup - int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); - if ( pal_idx >= tga_palette_len ) { - // invalid index - pal_idx = 0; - } - pal_idx *= tga_comp; - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = tga_palette[pal_idx+j]; - } - } else if(tga_rgb16) { - STBI_ASSERT(tga_comp == STBI_rgb); - stbi__tga_read_rgb16(s, raw_data); - } else { - // read in the data raw - for (j = 0; j < tga_comp; ++j) { - raw_data[j] = stbi__get8(s); - } - } - // clear the reading flag for the next pixel - read_next_pixel = 0; - } // end of reading a pixel + if (!tga_indexed && !tga_is_RLE && !tga_rgb16) { + for (i = 0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height - i - 1 : i; + stbi_uc *tga_row = tga_data + row * tga_width * tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if (tga_indexed) { + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start); + // load the palette + tga_palette = (unsigned char *)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i = 0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i = 0; i < tga_width * tga_height; ++i) { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if (tga_is_RLE) { + if (RLE_count == 0) { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if (!RLE_repeating) { + read_next_pixel = 1; + } + } else { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if (read_next_pixel) { + // load however much data we did have + if (tga_indexed) { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if (pal_idx >= tga_palette_len) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx + j]; + } + } else if (tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel - // copy data - for (j = 0; j < tga_comp; ++j) - tga_data[i*tga_comp+j] = raw_data[j]; + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i * tga_comp + j] = raw_data[j]; - // in case we're in RLE mode, keep counting down - --RLE_count; - } - // do I need to invert the image? - if ( tga_inverted ) - { - for (j = 0; j*2 < tga_height; ++j) - { - int index1 = j * tga_width * tga_comp; - int index2 = (tga_height - 1 - j) * tga_width * tga_comp; - for (i = tga_width * tga_comp; i > 0; --i) - { - unsigned char temp = tga_data[index1]; - tga_data[index1] = tga_data[index2]; - tga_data[index2] = temp; - ++index1; - ++index2; - } - } - } - // clear my palette, if I had one - if ( tga_palette != NULL ) - { - STBI_FREE( tga_palette ); - } - } + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if (tga_inverted) { + for (j = 0; j * 2 < tga_height; ++j) { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if (tga_palette != NULL) { + STBI_FREE(tga_palette); + } + } - // swap RGB - if the source data was RGB16, it already is in the right order - if (tga_comp >= 3 && !tga_rgb16) - { - unsigned char* tga_pixel = tga_data; - for (i=0; i < tga_width * tga_height; ++i) - { - unsigned char temp = tga_pixel[0]; - tga_pixel[0] = tga_pixel[2]; - tga_pixel[2] = temp; - tga_pixel += tga_comp; - } - } + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) { + unsigned char *tga_pixel = tga_data; + for (i = 0; i < tga_width * tga_height; ++i) { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } - // convert to target component count - if (req_comp && req_comp != tga_comp) - tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); - // the things I do to get rid of an error message, and yet keep - // Microsoft's C compilers happy... [8^( - tga_palette_start = tga_palette_len = tga_palette_bits = - tga_x_origin = tga_y_origin = 0; - // OK, done - return tga_data; + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; } #endif @@ -5651,247 +5936,249 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB #ifndef STBI_NO_PSD -static int stbi__psd_test(stbi__context *s) -{ - int r = (stbi__get32be(s) == 0x38425053); - stbi__rewind(s); - return r; +static int stbi__psd_test(stbi__context *s) { + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; } -static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) -{ - int count, nleft, len; +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) { + int count, nleft, len; - count = 0; - while ((nleft = pixelCount - count) > 0) { - len = stbi__get8(s); - if (len == 128) { - // No-op. - } else if (len < 128) { - // Copy next len+1 bytes literally. - len++; - if (len > nleft) return 0; // corrupt data - count += len; - while (len) { - *p = stbi__get8(s); - p += 4; - len--; - } - } else if (len > 128) { - stbi_uc val; - // Next -len+1 bytes in the dest are replicated from next source byte. - // (Interpret len as a negative 8-bit int.) - len = 257 - len; - if (len > nleft) return 0; // corrupt data - val = stbi__get8(s); - count += len; - while (len) { - *p = val; - p += 4; - len--; - } - } - } + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) + return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) + return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } - return 1; + return 1; } -static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) -{ - int pixelCount; - int channelCount, compression; - int channel, i; - int bitdepth; - int w,h; - stbi_uc *out; - STBI_NOTUSED(ri); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w, h; + stbi_uc *out; + STBI_NOTUSED(ri); - // Check identifier - if (stbi__get32be(s) != 0x38425053) // "8BPS" - return stbi__errpuc("not PSD", "Corrupt PSD image"); + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); - // Check file type version. - if (stbi__get16be(s) != 1) - return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); - // Skip 6 reserved bytes. - stbi__skip(s, 6 ); + // Skip 6 reserved bytes. + stbi__skip(s, 6); - // Read the number of channels (R, G, B, A, etc). - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) - return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); - // Read the rows and columns of the image. - h = stbi__get32be(s); - w = stbi__get32be(s); + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); - // Make sure the depth is 8 bits. - bitdepth = stbi__get16be(s); - if (bitdepth != 8 && bitdepth != 16) - return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); - // Make sure the color mode is RGB. - // Valid options are: - // 0: Bitmap - // 1: Grayscale - // 2: Indexed color - // 3: RGB color - // 4: CMYK color - // 7: Multichannel - // 8: Duotone - // 9: Lab color - if (stbi__get16be(s) != 3) - return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); - // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) - stbi__skip(s,stbi__get32be(s) ); + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s, stbi__get32be(s)); - // Skip the image resources. (resolution, pen tool paths, etc) - stbi__skip(s, stbi__get32be(s) ); + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s)); - // Skip the reserved data. - stbi__skip(s, stbi__get32be(s) ); + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s)); - // Find out if the data is compressed. - // Known values: - // 0: no compression - // 1: RLE compressed - compression = stbi__get16be(s); - if (compression > 1) - return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); - // Check size - if (!stbi__mad3sizes_valid(4, w, h, 0)) - return stbi__errpuc("too large", "Corrupt PSD"); + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); - // Create the destination image. + // Create the destination image. - if (!compression && bitdepth == 16 && bpc == 16) { - out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); - ri->bits_per_channel = 16; - } else - out = (stbi_uc *) stbi__malloc(4 * w*h); + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *)stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *)stbi__malloc(4 * w * h); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - pixelCount = w*h; + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w * h; - // Initialize the data to zero. - //memset( out, 0, pixelCount * 4 ); + // Initialize the data to zero. + // memset( out, 0, pixelCount * 4 ); - // Finally, the image data. - if (compression) { - // RLE as used by .PSD and .TIFF - // Loop until you get the number of unpacked bytes you are expecting: - // Read the next source byte into n. - // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. - // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. - // Else if n is 128, noop. - // Endloop + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop - // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, - // which we're going to just skip. - stbi__skip(s, h * channelCount * 2 ); + // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2); - // Read the RLE data by channel. - for (channel = 0; channel < 4; channel++) { - stbi_uc *p; + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; - p = out+channel; - if (channel >= channelCount) { - // Fill this channel with default data. - for (i = 0; i < pixelCount; i++, p += 4) - *p = (channel == 3 ? 255 : 0); - } else { - // Read the RLE data. - if (!stbi__psd_decode_rle(s, p, pixelCount)) { - STBI_FREE(out); - return stbi__errpuc("corrupt", "bad RLE data"); - } - } - } + p = out + channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } - } else { - // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) - // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. - // Read the data by channel. - for (channel = 0; channel < 4; channel++) { - if (channel >= channelCount) { - // Fill this channel with default data. - if (bitdepth == 16 && bpc == 16) { - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - stbi__uint16 val = channel == 3 ? 65535 : 0; - for (i = 0; i < pixelCount; i++, q += 4) - *q = val; - } else { - stbi_uc *p = out+channel; - stbi_uc val = channel == 3 ? 255 : 0; - for (i = 0; i < pixelCount; i++, p += 4) - *p = val; - } - } else { - if (ri->bits_per_channel == 16) { // output bpc - stbi__uint16 *q = ((stbi__uint16 *) out) + channel; - for (i = 0; i < pixelCount; i++, q += 4) - *q = (stbi__uint16) stbi__get16be(s); - } else { - stbi_uc *p = out+channel; - if (bitdepth == 16) { // input bpc - for (i = 0; i < pixelCount; i++, p += 4) - *p = (stbi_uc) (stbi__get16be(s) >> 8); - } else { - for (i = 0; i < pixelCount; i++, p += 4) - *p = stbi__get8(s); - } - } - } - } - } + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out + channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *)out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16)stbi__get16be(s); + } else { + stbi_uc *p = out + channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc)(stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } - // remove weird white matte from PSD - if (channelCount >= 4) { - if (ri->bits_per_channel == 16) { - for (i=0; i < w*h; ++i) { - stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; - if (pixel[3] != 0 && pixel[3] != 65535) { - float a = pixel[3] / 65535.0f; - float ra = 1.0f / a; - float inv_a = 65535.0f * (1 - ra); - pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); - pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); - pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); - } - } - } else { - for (i=0; i < w*h; ++i) { - unsigned char *pixel = out + 4*i; - if (pixel[3] != 0 && pixel[3] != 255) { - float a = pixel[3] / 255.0f; - float ra = 1.0f / a; - float inv_a = 255.0f * (1 - ra); - pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); - pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); - pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); - } - } - } - } + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i = 0; i < w * h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *)out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16)(pixel[0] * ra + inv_a); + pixel[1] = (stbi__uint16)(pixel[1] * ra + inv_a); + pixel[2] = (stbi__uint16)(pixel[2] * ra + inv_a); + } + } + } else { + for (i = 0; i < w * h; ++i) { + unsigned char *pixel = out + 4 * i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char)(pixel[0] * ra + inv_a); + pixel[1] = (unsigned char)(pixel[1] * ra + inv_a); + pixel[2] = (unsigned char)(pixel[2] * ra + inv_a); + } + } + } + } - // convert to desired output format - if (req_comp && req_comp != 4) { - if (ri->bits_per_channel == 16) - out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); - else - out = stbi__convert_format(out, 4, req_comp, w, h); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *)stbi__convert_format16((stbi__uint16 *)out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } - if (comp) *comp = 4; - *y = h; - *x = w; + if (comp) + *comp = 4; + *y = h; + *x = w; - return out; + return out; } #endif @@ -5903,211 +6190,213 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req // See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ #ifndef STBI_NO_PIC -static int stbi__pic_is4(stbi__context *s,const char *str) -{ - int i; - for (i=0; i<4; ++i) - if (stbi__get8(s) != (stbi_uc)str[i]) - return 0; +static int stbi__pic_is4(stbi__context *s, const char *str) { + int i; + for (i = 0; i < 4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; - return 1; + return 1; } -static int stbi__pic_test_core(stbi__context *s) -{ - int i; +static int stbi__pic_test_core(stbi__context *s) { + int i; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) - return 0; + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) + return 0; - for(i=0;i<84;++i) - stbi__get8(s); + for (i = 0; i < 84; ++i) + stbi__get8(s); - if (!stbi__pic_is4(s,"PICT")) - return 0; + if (!stbi__pic_is4(s, "PICT")) + return 0; - return 1; + return 1; } -typedef struct -{ - stbi_uc size,type,channel; +typedef struct { + stbi_uc size, type, channel; } stbi__pic_packet; -static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) -{ - int mask=0x80, i; +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) { + int mask = 0x80, i; - for (i=0; i<4; ++i, mask>>=1) { - if (channel & mask) { - if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); - dest[i]=stbi__get8(s); - } - } + for (i = 0; i < 4; ++i, mask >>= 1) { + if (channel & mask) { + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "PIC file too short"); + dest[i] = stbi__get8(s); + } + } - return dest; + return dest; } -static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) -{ - int mask=0x80,i; +static void stbi__copyval(int channel, stbi_uc *dest, const stbi_uc *src) { + int mask = 0x80, i; - for (i=0;i<4; ++i, mask>>=1) - if (channel&mask) - dest[i]=src[i]; + for (i = 0; i < 4; ++i, mask >>= 1) + if (channel & mask) + dest[i] = src[i]; } -static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) -{ - int act_comp=0,num_packets=0,y,chained; - stbi__pic_packet packets[10]; +static stbi_uc *stbi__pic_load_core(stbi__context *s, int width, int height, int *comp, stbi_uc *result) { + int act_comp = 0, num_packets = 0, y, chained; + stbi__pic_packet packets[10]; - // this will (should...) cater for even some bizarre stuff like having data - // for the same channel in multiple packets. - do { - stbi__pic_packet *packet; + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return stbi__errpuc("bad format","too many packets"); + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return stbi__errpuc("bad format", "too many packets"); - packet = &packets[num_packets++]; + packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); - act_comp |= packet->channel; + act_comp |= packet->channel; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); - if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); - } while (chained); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (reading packets)"); + if (packet->size != 8) + return stbi__errpuc("bad format", "packet isn't 8bpp"); + } while (chained); - *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? - for(y=0; y<height; ++y) { - int packet_idx; + for (y = 0; y < height; ++y) { + int packet_idx; - for(packet_idx=0; packet_idx < num_packets; ++packet_idx) { - stbi__pic_packet *packet = &packets[packet_idx]; - stbi_uc *dest = result+y*width*4; + for (packet_idx = 0; packet_idx < num_packets; ++packet_idx) { + stbi__pic_packet *packet = &packets[packet_idx]; + stbi_uc *dest = result + y * width * 4; - switch (packet->type) { - default: - return stbi__errpuc("bad format","packet has bad compression type"); + switch (packet->type) { + default: + return stbi__errpuc("bad format", "packet has bad compression type"); - case 0: {//uncompressed - int x; + case 0: { // uncompressed + int x; - for(x=0;x<width;++x, dest+=4) - if (!stbi__readval(s,packet->channel,dest)) - return 0; - break; - } + for (x = 0; x < width; ++x, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + break; + } - case 1://Pure RLE - { - int left=width, i; + case 1: // Pure RLE + { + int left = width, i; - while (left>0) { - stbi_uc count,value[4]; + while (left > 0) { + stbi_uc count, value[4]; - count=stbi__get8(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + count = stbi__get8(s); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pure read count)"); - if (count > left) - count = (stbi_uc) left; + if (count > left) + count = (stbi_uc)left; - if (!stbi__readval(s,packet->channel,value)) return 0; + if (!stbi__readval(s, packet->channel, value)) + return 0; - for(i=0; i<count; ++i,dest+=4) - stbi__copyval(packet->channel,dest,value); - left -= count; - } - } - break; + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + left -= count; + } + } break; - case 2: {//Mixed RLE - int left=width; - while (left>0) { - int count = stbi__get8(s), i; - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + case 2: { // Mixed RLE + int left = width; + while (left > 0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (mixed read count)"); - if (count >= 128) { // Repeated - stbi_uc value[4]; + if (count >= 128) { // Repeated + stbi_uc value[4]; - if (count==128) - count = stbi__get16be(s); - else - count -= 127; - if (count > left) - return stbi__errpuc("bad file","scanline overrun"); + if (count == 128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); - if (!stbi__readval(s,packet->channel,value)) - return 0; + if (!stbi__readval(s, packet->channel, value)) + return 0; - for(i=0;i<count;++i, dest += 4) - stbi__copyval(packet->channel,dest,value); - } else { // Raw - ++count; - if (count>left) return stbi__errpuc("bad file","scanline overrun"); + for (i = 0; i < count; ++i, dest += 4) + stbi__copyval(packet->channel, dest, value); + } else { // Raw + ++count; + if (count > left) + return stbi__errpuc("bad file", "scanline overrun"); - for(i=0;i<count;++i, dest+=4) - if (!stbi__readval(s,packet->channel,dest)) - return 0; - } - left-=count; - } - break; - } - } - } - } + for (i = 0; i < count; ++i, dest += 4) + if (!stbi__readval(s, packet->channel, dest)) + return 0; + } + left -= count; + } + break; + } + } + } + } - return result; + return result; } -static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) -{ - stbi_uc *result; - int i, x,y, internal_comp; - STBI_NOTUSED(ri); +static void *stbi__pic_load(stbi__context *s, int *px, int *py, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *result; + int i, x, y, internal_comp; + STBI_NOTUSED(ri); - if (!comp) comp = &internal_comp; + if (!comp) + comp = &internal_comp; - for (i=0; i<92; ++i) - stbi__get8(s); + for (i = 0; i < 92; ++i) + stbi__get8(s); - x = stbi__get16be(s); - y = stbi__get16be(s); - if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); - if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + x = stbi__get16be(s); + y = stbi__get16be(s); + if (stbi__at_eof(s)) + return stbi__errpuc("bad file", "file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) + return stbi__errpuc("too large", "PIC image too large to decode"); - stbi__get32be(s); //skip `ratio' - stbi__get16be(s); //skip `fields' - stbi__get16be(s); //skip `pad' + stbi__get32be(s); // skip `ratio' + stbi__get16be(s); // skip `fields' + stbi__get16be(s); // skip `pad' - // intermediate buffer is RGBA - result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); - memset(result, 0xff, x*y*4); + // intermediate buffer is RGBA + result = (stbi_uc *)stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x * y * 4); - if (!stbi__pic_load_core(s,x,y,comp, result)) { - STBI_FREE(result); - result=0; - } - *px = x; - *py = y; - if (req_comp == 0) req_comp = *comp; - result=stbi__convert_format(result,4,req_comp,x,y); + if (!stbi__pic_load_core(s, x, y, comp, result)) { + STBI_FREE(result); + result = 0; + } + *px = x; + *py = y; + if (req_comp == 0) + req_comp = *comp; + result = stbi__convert_format(result, 4, req_comp, x, y); - return result; + return result; } -static int stbi__pic_test(stbi__context *s) -{ - int r = stbi__pic_test_core(s); - stbi__rewind(s); - return r; +static int stbi__pic_test(stbi__context *s) { + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; } #endif @@ -6115,868 +6404,901 @@ static int stbi__pic_test(stbi__context *s) // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb #ifndef STBI_NO_GIF -typedef struct -{ - stbi__int16 prefix; - stbi_uc first; - stbi_uc suffix; +typedef struct { + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; } stbi__gif_lzw; -typedef struct -{ - int w,h; - stbi_uc *out; // output buffer (always 4 components) - stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; - int flags, bgindex, ratio, transparent, eflags; - stbi_uc pal[256][4]; - stbi_uc lpal[256][4]; - stbi__gif_lzw codes[8192]; - stbi_uc *color_table; - int parse, step; - int lflags; - int start_x, start_y; - int max_x, max_y; - int cur_x, cur_y; - int line_size; - int delay; +typedef struct { + int w, h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; } stbi__gif; -static int stbi__gif_test_raw(stbi__context *s) -{ - int sz; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; - sz = stbi__get8(s); - if (sz != '9' && sz != '7') return 0; - if (stbi__get8(s) != 'a') return 0; - return 1; +static int stbi__gif_test_raw(stbi__context *s) { + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') + return 0; + if (stbi__get8(s) != 'a') + return 0; + return 1; } -static int stbi__gif_test(stbi__context *s) -{ - int r = stbi__gif_test_raw(s); - stbi__rewind(s); - return r; +static int stbi__gif_test(stbi__context *s) { + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; } -static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) -{ - int i; - for (i=0; i < num_entries; ++i) { - pal[i][2] = stbi__get8(s); - pal[i][1] = stbi__get8(s); - pal[i][0] = stbi__get8(s); - pal[i][3] = transp == i ? 0 : 255; - } +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) { + int i; + for (i = 0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } } -static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) -{ - stbi_uc version; - if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') - return stbi__err("not GIF", "Corrupt GIF"); +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) { + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); - version = stbi__get8(s); - if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + version = stbi__get8(s); + if (version != '7' && version != '9') + return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') + return stbi__err("not GIF", "Corrupt GIF"); - stbi__g_failure_reason = ""; - g->w = stbi__get16le(s); - g->h = stbi__get16le(s); - g->flags = stbi__get8(s); - g->bgindex = stbi__get8(s); - g->ratio = stbi__get8(s); - g->transparent = -1; + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; - if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + if (comp != 0) + *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments - if (is_info) return 1; + if (is_info) + return 1; - if (g->flags & 0x80) - stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + if (g->flags & 0x80) + stbi__gif_parse_colortable(s, g->pal, 2 << (g->flags & 7), -1); - return 1; + return 1; } -static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) -{ - stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); - if (!stbi__gif_header(s, g, comp, 1)) { - STBI_FREE(g); - stbi__rewind( s ); - return 0; - } - if (x) *x = g->w; - if (y) *y = g->h; - STBI_FREE(g); - return 1; +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { + stbi__gif *g = (stbi__gif *)stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind(s); + return 0; + } + if (x) + *x = g->w; + if (y) + *y = g->h; + STBI_FREE(g); + return 1; } -static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) -{ - stbi_uc *p, *c; - int idx; +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { + stbi_uc *p, *c; + int idx; - // recurse to decode the prefixes, since the linked-list is backwards, - // and working backwards through an interleaved image would be nasty - if (g->codes[code].prefix >= 0) - stbi__out_gif_code(g, g->codes[code].prefix); + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); - if (g->cur_y >= g->max_y) return; + if (g->cur_y >= g->max_y) + return; - idx = g->cur_x + g->cur_y; - p = &g->out[idx]; - g->history[idx / 4] = 1; + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; - c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; - p[0] = c[2]; - p[1] = c[1]; - p[2] = c[0]; - p[3] = c[3]; - } - g->cur_x += 4; + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; - if (g->cur_x >= g->max_x) { - g->cur_x = g->start_x; - g->cur_y += g->step; + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; - while (g->cur_y >= g->max_y && g->parse > 0) { - g->step = (1 << g->parse) * g->line_size; - g->cur_y = g->start_y + (g->step >> 1); - --g->parse; - } - } + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } } -static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) -{ - stbi_uc lzw_cs; - stbi__int32 len, init_code; - stbi__uint32 first; - stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; - stbi__gif_lzw *p; +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) { + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; - lzw_cs = stbi__get8(s); - if (lzw_cs > 12) return NULL; - clear = 1 << lzw_cs; - first = 1; - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - bits = 0; - valid_bits = 0; - for (init_code = 0; init_code < clear; init_code++) { - g->codes[init_code].prefix = -1; - g->codes[init_code].first = (stbi_uc) init_code; - g->codes[init_code].suffix = (stbi_uc) init_code; - } + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) + return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc)init_code; + g->codes[init_code].suffix = (stbi_uc)init_code; + } - // support no starting clear code - avail = clear+2; - oldcode = -1; + // support no starting clear code + avail = clear + 2; + oldcode = -1; - len = 0; - for(;;) { - if (valid_bits < codesize) { - if (len == 0) { - len = stbi__get8(s); // start new block - if (len == 0) - return g->out; - } - --len; - bits |= (stbi__int32) stbi__get8(s) << valid_bits; - valid_bits += 8; - } else { - stbi__int32 code = bits & codemask; - bits >>= codesize; - valid_bits -= codesize; - // @OPTIMIZE: is there some way we can accelerate the non-clear path? - if (code == clear) { // clear code - codesize = lzw_cs + 1; - codemask = (1 << codesize) - 1; - avail = clear + 2; - oldcode = -1; - first = 0; - } else if (code == clear + 1) { // end of stream code - stbi__skip(s, len); - while ((len = stbi__get8(s)) > 0) - stbi__skip(s,len); - return g->out; - } else if (code <= avail) { - if (first) { - return stbi__errpuc("no clear code", "Corrupt GIF"); - } + len = 0; + for (;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32)stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s, len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } - if (oldcode >= 0) { - p = &g->codes[avail++]; - if (avail > 8192) { - return stbi__errpuc("too many codes", "Corrupt GIF"); - } + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } - p->prefix = (stbi__int16) oldcode; - p->first = g->codes[oldcode].first; - p->suffix = (code == avail) ? p->first : g->codes[code].first; - } else if (code == avail) - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + p->prefix = (stbi__int16)oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - stbi__out_gif_code(g, (stbi__uint16) code); + stbi__out_gif_code(g, (stbi__uint16)code); - if ((avail & codemask) == 0 && avail <= 0x0FFF) { - codesize++; - codemask = (1 << codesize) - 1; - } + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } - oldcode = code; - } else { - return stbi__errpuc("illegal code in raster", "Corrupt GIF"); - } - } - } + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } } // this function is designed to support animated gifs, although stb_image doesn't support it // two back is the image from two frames ago, used for a very specific disposal format -static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) -{ - int dispose; - int first_frame; - int pi; - int pcount; +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { + int dispose; + int first_frame; + int pi; + int pcount; + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp, 0)) + return 0; // stbi__g_failure_reason set by stbi__gif_header + g->out = (stbi_uc *)stbi__malloc(4 * g->w * g->h); + g->background = (stbi_uc *)stbi__malloc(4 * g->w * g->h); + g->history = (stbi_uc *)stbi__malloc(g->w * g->h); + if (g->out == 0) + return stbi__errpuc("outofmem", "Out of memory"); - // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; - if (g->out == 0) { - if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header - g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->background = (stbi_uc *) stbi__malloc(4 * g->w * g->h); - g->history = (stbi_uc *) stbi__malloc(g->w * g->h); - if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory"); + // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to teh color that was there the previous frame. + memset(g->out, 0x00, 4 * g->w * g->h); + memset(g->background, 0x00, 4 * g->w * g->h); // state of the background (starts transparent) + memset(g->history, 0x00, g->w * g->h); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispoase of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; - // image is treated as "tranparent" at the start - ie, nothing overwrites the current background; - // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to teh color that was there the previous frame. - memset( g->out, 0x00, 4 * g->w * g->h ); - memset( g->background, 0x00, 4 * g->w * g->h ); // state of the background (starts transparent) - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame - first_frame = 1; - } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } - if ((dispose == 3) && (two_back == 0)) { - dispose = 2; // if I don't have an image to revert back to, default to the old background - } + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &two_back[pi * 4], 4); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy(&g->out[pi * 4], &g->background[pi * 4], 4); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } - if (dispose == 3) { // use previous graphic - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); - } - } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); - } - } - } else { - // This is a non-disposal case eithe way, so just - // leave the pixels as is, and they will become the new background - // 1: do not dispose - // 0: not specified. - } + // background is what out is after the undoing of the previou frame; + memcpy(g->background, g->out, 4 * g->w * g->h); + } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); - } + // clear my history; + memset(g->history, 0x00, g->w * g->h); // pixels that were affected previous frame - // clear my history; - memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; - for (;;) { - int tag = stbi__get8(s); - switch (tag) { - case 0x2C: /* Image Descriptor */ - { - stbi__int32 x, y, w, h; - stbi_uc *o; + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); - x = stbi__get16le(s); - y = stbi__get16le(s); - w = stbi__get16le(s); - h = stbi__get16le(s); - if (((x + w) > (g->w)) || ((y + h) > (g->h))) - return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; - g->line_size = g->w * 4; - g->start_x = x * 4; - g->start_y = y * g->line_size; - g->max_x = g->start_x + w * 4; - g->max_y = g->start_y + h * g->line_size; - g->cur_x = g->start_x; - g->cur_y = g->start_y; + g->lflags = stbi__get8(s); - g->lflags = stbi__get8(s); + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } - if (g->lflags & 0x40) { - g->step = 8 * g->line_size; // first interlaced spacing - g->parse = 3; - } else { - g->step = g->line_size; - g->parse = 0; - } + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s, g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *)g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *)g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); - if (g->lflags & 0x80) { - stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; - } else if (g->flags & 0x80) { - g->color_table = (stbi_uc *) g->pal; - } else - return stbi__errpuc("missing color table", "Corrupt GIF"); - - o = stbi__process_gif_raster(s, g); - if (o == NULL) return NULL; + o = stbi__process_gif_raster(s, g); + if (o == NULL) + return NULL; - // if this was the first frame, - pcount = g->w * g->h; - if (first_frame && (g->bgindex > 0)) { - // if first frame, any pixel not drawn to gets the background color - for (pi = 0; pi < pcount; ++pi) { - if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); - } - } - } + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be + // reset next frame if need be; + memcpy(&g->out[pi * 4], &g->pal[g->bgindex], 4); + } + } + } - return o; - } + return o; + } - case 0x21: // Comment Extension. - { - int len; - int ext = stbi__get8(s); - if (ext == 0xF9) { // Graphic Control Extension. - len = stbi__get8(s); - if (len == 4) { - g->eflags = stbi__get8(s); - g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. - // unset old transparent - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } - if (g->eflags & 0x01) { - g->transparent = stbi__get8(s); - if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; - } - } else { - // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; - } - } else { - stbi__skip(s, len); - break; - } - } - while ((len = stbi__get8(s)) != 0) { - stbi__skip(s, len); - } - break; - } + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } - case 0x3B: // gif stream termination code - return (stbi_uc *) s; // using '1' causes warning on some compilers + case 0x3B: // gif stream termination code + return (stbi_uc *)s; // using '1' causes warning on some compilers - default: - return stbi__errpuc("unknown code", "Corrupt GIF"); - } - } + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } } -static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) -{ - if (stbi__gif_test(s)) { - int layers = 0; - stbi_uc *u = 0; - stbi_uc *out = 0; - stbi_uc *two_back = 0; - stbi__gif g; - int stride; - memset(&g, 0, sizeof(g)); - if (delays) { - *delays = 0; - } +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker - do { - u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; - if (u) { - *x = g.w; - *y = g.h; - ++layers; - stride = g.w * g.h * 4; - - if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); - if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); - } - } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); - if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); - } - } - memcpy( out + ((layers - 1) * stride), u, stride ); - if (layers >= 2) { - two_back = out - 2 * stride; - } + if (out) { + out = (stbi_uc *)STBI_REALLOC(out, layers * stride); + if (delays) { + *delays = (int *)STBI_REALLOC(*delays, sizeof(int) * layers); + } + } else { + out = (stbi_uc *)stbi__malloc(layers * stride); + if (delays) { + *delays = (int *)stbi__malloc(layers * sizeof(int)); + } + } + memcpy(out + ((layers - 1) * stride), u, stride); + if (layers >= 2) { + two_back = out - 2 * stride; + } - if (delays) { - (*delays)[layers - 1U] = g.delay; - } - } - } while (u != 0); + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; - if (req_comp && req_comp != 4) - out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; - return out; - } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); - } + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } } -static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *u = 0; - stbi__gif g; - memset(&g, 0, sizeof(g)); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); - u = stbi__gif_load_next(s, &g, comp, req_comp, 0); - if (u == (stbi_uc *) s) u = 0; // end of animated gif marker - if (u) { - *x = g.w; - *y = g.h; + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *)s) + u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; - // moved conversion to after successful load so that the same - // can be done for multiple frames. - if (req_comp && req_comp != 4) - u = stbi__convert_format(u, 4, req_comp, g.w, g.h); - } + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } - // free buffers needed for multiple frame loading; - STBI_FREE(g.history); - STBI_FREE(g.background); + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); - return u; + return u; } -static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) -{ - return stbi__gif_info_raw(s,x,y,comp); -} +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) { return stbi__gif_info_raw(s, x, y, comp); } #endif // ************************************************************************************************* // Radiance RGBE HDR loader // originally by Nicolas Schulz #ifndef STBI_NO_HDR -static int stbi__hdr_test_core(stbi__context *s, const char *signature) -{ - int i; - for (i=0; signature[i]; ++i) - if (stbi__get8(s) != signature[i]) - return 0; - stbi__rewind(s); - return 1; +static int stbi__hdr_test_core(stbi__context *s, const char *signature) { + int i; + for (i = 0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; } -static int stbi__hdr_test(stbi__context* s) -{ - int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); - stbi__rewind(s); - if(!r) { - r = stbi__hdr_test_core(s, "#?RGBE\n"); - stbi__rewind(s); - } - return r; +static int stbi__hdr_test(stbi__context *s) { + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if (!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; } -#define STBI__HDR_BUFLEN 1024 -static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) -{ - int len=0; - char c = '\0'; +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) { + int len = 0; + char c = '\0'; - c = (char) stbi__get8(z); + c = (char)stbi__get8(z); - while (!stbi__at_eof(z) && c != '\n') { - buffer[len++] = c; - if (len == STBI__HDR_BUFLEN-1) { - // flush to end of line - while (!stbi__at_eof(z) && stbi__get8(z) != '\n') - ; - break; - } - c = (char) stbi__get8(z); - } + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN - 1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char)stbi__get8(z); + } - buffer[len] = 0; - return buffer; + buffer[len] = 0; + return buffer; } -static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) -{ - if ( input[3] != 0 ) { - float f1; - // Exponent - f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); - if (req_comp <= 2) - output[0] = (input[0] + input[1] + input[2]) * f1 / 3; - else { - output[0] = input[0] * f1; - output[1] = input[1] * f1; - output[2] = input[2] * f1; - } - if (req_comp == 2) output[1] = 1; - if (req_comp == 4) output[3] = 1; - } else { - switch (req_comp) { - case 4: output[3] = 1; /* fallthrough */ - case 3: output[0] = output[1] = output[2] = 0; - break; - case 2: output[1] = 1; /* fallthrough */ - case 1: output[0] = 0; - break; - } - } +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) { + if (input[3] != 0) { + float f1; + // Exponent + f1 = (float)ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) + output[1] = 1; + if (req_comp == 4) + output[3] = 1; + } else { + switch (req_comp) { + case 4: + output[3] = 1; /* fallthrough */ + case 3: + output[0] = output[1] = output[2] = 0; + break; + case 2: + output[1] = 1; /* fallthrough */ + case 1: + output[0] = 0; + break; + } + } } -static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int width, height; - stbi_uc *scanline; - float *hdr_data; - int len; - unsigned char count, value; - int i, j, k, c1,c2, z; - const char *headerToken; - STBI_NOTUSED(ri); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1, c2, z; + const char *headerToken; + STBI_NOTUSED(ri); - // Check identifier - headerToken = stbi__hdr_gettoken(s,buffer); - if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) - return stbi__errpf("not HDR", "Corrupt HDR image"); + // Check identifier + headerToken = stbi__hdr_gettoken(s, buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); - // Parse header - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + // Parse header + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } - if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + if (!valid) + return stbi__errpf("unsupported format", "Unsupported HDR format"); - // Parse width and height - // can't use sscanf() if we're not using stdio! - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - height = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); - token += 3; - width = (int) strtol(token, NULL, 10); + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) + return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int)strtol(token, NULL, 10); - *x = width; - *y = height; + *x = width; + *y = height; - if (comp) *comp = 3; - if (req_comp == 0) req_comp = 3; + if (comp) + *comp = 3; + if (req_comp == 0) + req_comp = 3; - if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) - return stbi__errpf("too large", "HDR image is too large"); + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); - // Read data - hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); - if (!hdr_data) - return stbi__errpf("outofmem", "Out of memory"); + // Read data + hdr_data = (float *)stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); - // Load image data - // image data is stored as some number of sca - if ( width < 8 || width >= 32768) { - // Read flat data - for (j=0; j < height; ++j) { - for (i=0; i < width; ++i) { - stbi_uc rgbe[4]; - main_decode_loop: - stbi__getn(s, rgbe, 4); - stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); - } - } - } else { - // Read RLE-encoded data - scanline = NULL; + // Load image data + // image data is stored as some number of sca + if (width < 8 || width >= 32768) { + // Read flat data + for (j = 0; j < height; ++j) { + for (i = 0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; - for (j = 0; j < height; ++j) { - c1 = stbi__get8(s); - c2 = stbi__get8(s); - len = stbi__get8(s); - if (c1 != 2 || c2 != 2 || (len & 0x80)) { - // not run-length encoded, so we have to actually use THIS data as a decoded - // pixel (note this can't be a valid pixel--one of RGB must be >= 128) - stbi_uc rgbe[4]; - rgbe[0] = (stbi_uc) c1; - rgbe[1] = (stbi_uc) c2; - rgbe[2] = (stbi_uc) len; - rgbe[3] = (stbi_uc) stbi__get8(s); - stbi__hdr_convert(hdr_data, rgbe, req_comp); - i = 1; - j = 0; - STBI_FREE(scanline); - goto main_decode_loop; // yes, this makes no sense - } - len <<= 8; - len |= stbi__get8(s); - if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } - if (scanline == NULL) { - scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); - if (!scanline) { - STBI_FREE(hdr_data); - return stbi__errpf("outofmem", "Out of memory"); - } - } + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc)c1; + rgbe[1] = (stbi_uc)c2; + rgbe[2] = (stbi_uc)len; + rgbe[3] = (stbi_uc)stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); + } + if (scanline == NULL) { + scanline = (stbi_uc *)stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } - for (k = 0; k < 4; ++k) { - int nleft; - i = 0; - while ((nleft = width - i) > 0) { - count = stbi__get8(s); - if (count > 128) { - // Run - value = stbi__get8(s); - count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = value; - } else { - // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } - for (z = 0; z < count; ++z) - scanline[i++ * 4 + k] = stbi__get8(s); - } - } - } - for (i=0; i < width; ++i) - stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); - } - if (scanline) - STBI_FREE(scanline); - } + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { + STBI_FREE(hdr_data); + STBI_FREE(scanline); + return stbi__errpf("corrupt", "bad RLE data in HDR"); + } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i = 0; i < width; ++i) + stbi__hdr_convert(hdr_data + (j * width + i) * req_comp, scanline + i * 4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } - return hdr_data; + return hdr_data; } -static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) -{ - char buffer[STBI__HDR_BUFLEN]; - char *token; - int valid = 0; - int dummy; +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) { + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - if (stbi__hdr_test(s) == 0) { - stbi__rewind( s ); - return 0; - } + if (stbi__hdr_test(s) == 0) { + stbi__rewind(s); + return 0; + } - for(;;) { - token = stbi__hdr_gettoken(s,buffer); - if (token[0] == 0) break; - if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; - } + for (;;) { + token = stbi__hdr_gettoken(s, buffer); + if (token[0] == 0) + break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) + valid = 1; + } - if (!valid) { - stbi__rewind( s ); - return 0; - } - token = stbi__hdr_gettoken(s,buffer); - if (strncmp(token, "-Y ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *y = (int) strtol(token, &token, 10); - while (*token == ' ') ++token; - if (strncmp(token, "+X ", 3)) { - stbi__rewind( s ); - return 0; - } - token += 3; - *x = (int) strtol(token, NULL, 10); - *comp = 3; - return 1; + if (!valid) { + stbi__rewind(s); + return 0; + } + token = stbi__hdr_gettoken(s, buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *y = (int)strtol(token, &token, 10); + while (*token == ' ') + ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind(s); + return 0; + } + token += 3; + *x = (int)strtol(token, NULL, 10); + *comp = 3; + return 1; } #endif // STBI_NO_HDR #ifndef STBI_NO_BMP -static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) -{ - void *p; - stbi__bmp_data info; +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) { + void *p; + stbi__bmp_data info; - info.all_a = 255; - p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) - return 0; - if (x) *x = s->img_x; - if (y) *y = s->img_y; - if (comp) *comp = info.ma ? 4 : 3; - return 1; + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind(s); + if (p == NULL) + return 0; + if (x) + *x = s->img_x; + if (y) + *y = s->img_y; + if (comp) + *comp = info.ma ? 4 : 3; + return 1; } #endif #ifndef STBI_NO_PSD -static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) -{ - int channelCount, dummy, depth; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - *y = stbi__get32be(s); - *x = stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 8 && depth != 16) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 3) { - stbi__rewind( s ); - return 0; - } - *comp = 4; - return 1; +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) { + int channelCount, dummy, depth; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind(s); + return 0; + } + *comp = 4; + return 1; } -static int stbi__psd_is16(stbi__context *s) -{ - int channelCount, depth; - if (stbi__get32be(s) != 0x38425053) { - stbi__rewind( s ); - return 0; - } - if (stbi__get16be(s) != 1) { - stbi__rewind( s ); - return 0; - } - stbi__skip(s, 6); - channelCount = stbi__get16be(s); - if (channelCount < 0 || channelCount > 16) { - stbi__rewind( s ); - return 0; - } - (void) stbi__get32be(s); - (void) stbi__get32be(s); - depth = stbi__get16be(s); - if (depth != 16) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__psd_is16(stbi__context *s) { + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind(s); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind(s); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind(s); + return 0; + } + (void)stbi__get32be(s); + (void)stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind(s); + return 0; + } + return 1; } #endif #ifndef STBI_NO_PIC -static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) -{ - int act_comp=0,num_packets=0,chained,dummy; - stbi__pic_packet packets[10]; +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) { + int act_comp = 0, num_packets = 0, chained, dummy; + stbi__pic_packet packets[10]; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { - stbi__rewind(s); - return 0; - } + if (!stbi__pic_is4(s, "\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } - stbi__skip(s, 88); + stbi__skip(s, 88); - *x = stbi__get16be(s); - *y = stbi__get16be(s); - if (stbi__at_eof(s)) { - stbi__rewind( s); - return 0; - } - if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { - stbi__rewind( s ); - return 0; - } + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if ((*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind(s); + return 0; + } - stbi__skip(s, 8); + stbi__skip(s, 8); - do { - stbi__pic_packet *packet; + do { + stbi__pic_packet *packet; - if (num_packets==sizeof(packets)/sizeof(packets[0])) - return 0; + if (num_packets == sizeof(packets) / sizeof(packets[0])) + return 0; - packet = &packets[num_packets++]; - chained = stbi__get8(s); - packet->size = stbi__get8(s); - packet->type = stbi__get8(s); - packet->channel = stbi__get8(s); - act_comp |= packet->channel; + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; - if (stbi__at_eof(s)) { - stbi__rewind( s ); - return 0; - } - if (packet->size != 8) { - stbi__rewind( s ); - return 0; - } - } while (chained); + if (stbi__at_eof(s)) { + stbi__rewind(s); + return 0; + } + if (packet->size != 8) { + stbi__rewind(s); + return 0; + } + } while (chained); - *comp = (act_comp & 0x10 ? 4 : 3); + *comp = (act_comp & 0x10 ? 4 : 3); - return 1; + return 1; } #endif @@ -6994,431 +7316,426 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) #ifndef STBI_NO_PNM -static int stbi__pnm_test(stbi__context *s) -{ - char p, t; - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind( s ); - return 0; - } - return 1; +static int stbi__pnm_test(stbi__context *s) { + char p, t; + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + return 1; } -static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) -{ - stbi_uc *out; - STBI_NOTUSED(ri); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) { + stbi_uc *out; + STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) - return 0; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; - *x = s->img_x; - *y = s->img_y; - if (comp) *comp = s->img_n; + *x = s->img_x; + *y = s->img_y; + if (comp) + *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) - return stbi__errpuc("too large", "PNM too large"); + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); - if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + out = (stbi_uc *)stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) + return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); - if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); - if (out == NULL) return out; // stbi__convert_format frees input on failure - } - return out; + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) + return out; // stbi__convert_format frees input on failure + } + return out; } -static int stbi__pnm_isspace(char c) -{ - return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +static int stbi__pnm_isspace(char c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } -static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) -{ - for (;;) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) - *c = (char) stbi__get8(s); +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) { + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char)stbi__get8(s); - if (stbi__at_eof(s) || *c != '#') - break; + if (stbi__at_eof(s) || *c != '#') + break; - while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) - *c = (char) stbi__get8(s); - } + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r') + *c = (char)stbi__get8(s); + } } -static int stbi__pnm_isdigit(char c) -{ - return c >= '0' && c <= '9'; -} +static int stbi__pnm_isdigit(char c) { return c >= '0' && c <= '9'; } -static int stbi__pnm_getinteger(stbi__context *s, char *c) -{ - int value = 0; +static int stbi__pnm_getinteger(stbi__context *s, char *c) { + int value = 0; - while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value = value*10 + (*c - '0'); - *c = (char) stbi__get8(s); - } + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value * 10 + (*c - '0'); + *c = (char)stbi__get8(s); + } - return value; + return value; } -static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) -{ - int maxv, dummy; - char c, p, t; +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { + int maxv, dummy; + char c, p, t; - if (!x) x = &dummy; - if (!y) y = &dummy; - if (!comp) comp = &dummy; + if (!x) + x = &dummy; + if (!y) + y = &dummy; + if (!comp) + comp = &dummy; - stbi__rewind(s); + stbi__rewind(s); - // Get identifier - p = (char) stbi__get8(s); - t = (char) stbi__get8(s); - if (p != 'P' || (t != '5' && t != '6')) { - stbi__rewind(s); - return 0; - } + // Get identifier + p = (char)stbi__get8(s); + t = (char)stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } - *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - c = (char) stbi__get8(s); - stbi__pnm_skip_whitespace(s, &c); + c = (char)stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); - *x = stbi__pnm_getinteger(s, &c); // read width - stbi__pnm_skip_whitespace(s, &c); + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); - *y = stbi__pnm_getinteger(s, &c); // read height - stbi__pnm_skip_whitespace(s, &c); + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); - maxv = stbi__pnm_getinteger(s, &c); // read max value + maxv = stbi__pnm_getinteger(s, &c); // read max value - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); - else - return 1; + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; } #endif -static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) -{ - #ifndef STBI_NO_JPEG - if (stbi__jpeg_info(s, x, y, comp)) return 1; - #endif +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) { +#ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNG - if (stbi__png_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_GIF - if (stbi__gif_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_BMP - if (stbi__bmp_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PIC - if (stbi__pic_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_PNM - if (stbi__pnm_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) + return 1; +#endif - #ifndef STBI_NO_HDR - if (stbi__hdr_info(s, x, y, comp)) return 1; - #endif +#ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) + return 1; +#endif - // test tga last because it's a crappy test! - #ifndef STBI_NO_TGA - if (stbi__tga_info(s, x, y, comp)) - return 1; - #endif - return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +// test tga last because it's a crappy test! +#ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; +#endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); } -static int stbi__is_16_main(stbi__context *s) -{ - #ifndef STBI_NO_PNG - if (stbi__png_is16(s)) return 1; - #endif +static int stbi__is_16_main(stbi__context *s) { +#ifndef STBI_NO_PNG + if (stbi__png_is16(s)) + return 1; +#endif - #ifndef STBI_NO_PSD - if (stbi__psd_is16(s)) return 1; - #endif +#ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) + return 1; +#endif - return 0; + return 0; } #ifndef STBI_NO_STDIO -STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_info_from_file(f, x, y, comp); - fclose(f); - return result; +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; } -STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__info_main(&s,x,y,comp); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s, x, y, comp); + fseek(f, pos, SEEK_SET); + return r; } -STBIDEF int stbi_is_16_bit(char const *filename) -{ - FILE *f = stbi__fopen(filename, "rb"); - int result; - if (!f) return stbi__err("can't fopen", "Unable to open file"); - result = stbi_is_16_bit_from_file(f); - fclose(f); - return result; +STBIDEF int stbi_is_16_bit(char const *filename) { + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) + return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; } -STBIDEF int stbi_is_16_bit_from_file(FILE *f) -{ - int r; - stbi__context s; - long pos = ftell(f); - stbi__start_file(&s, f); - r = stbi__is_16_main(&s); - fseek(f,pos,SEEK_SET); - return r; +STBIDEF int stbi_is_16_bit_from_file(FILE *f) { + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f, pos, SEEK_SET); + return r; } #endif // !STBI_NO_STDIO -STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__info_main(&s,x,y,comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__info_main(&s, x, y, comp); } -STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) -{ - stbi__context s; - stbi__start_mem(&s,buffer,len); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) { + stbi__context s; + stbi__start_mem(&s, buffer, len); + return stbi__is_16_main(&s); } -STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) -{ - stbi__context s; - stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); - return stbi__is_16_main(&s); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) { + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)c, user); + return stbi__is_16_main(&s); } #endif // STB_IMAGE_IMPLEMENTATION /* revision history: - 2.19 (2018-02-11) fix warning - 2.18 (2018-01-30) fix warnings - 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug - 1-bit BMP - *_is_16_bit api - avoid warnings - 2.16 (2017-07-23) all functions have 16-bit variants; - STBI_NO_STDIO works again; - compilation fixes; - fix rounding in unpremultiply; - optimize vertical flip; - disable raw_len validation; - documentation fixes - 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; - warning fixes; disable run-time SSE detection on gcc; - uniform handling of optional "return" values; - thread-safe initialization of zlib tables - 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs - 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now - 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes - 2.11 (2016-04-02) allocate large structures on the stack - remove white matting for transparent PSD - fix reported channel count for PNG & BMP - re-enable SSE2 in non-gcc 64-bit - support RGB-formatted JPEG - read 16-bit PNGs (only as 8-bit) - 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED - 2.09 (2016-01-16) allow comments in PNM files - 16-bit-per-pixel TGA (not bit-per-component) - info() for TGA could break due to .hdr handling - info() for BMP to shares code instead of sloppy parse - can use STBI_REALLOC_SIZED if allocator doesn't support realloc - code cleanup - 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA - 2.07 (2015-09-13) fix compiler warnings - partial animated GIF support - limited 16-bpc PSD support - #ifdef unused functions - bug with < 92 byte PIC,PNM,HDR,TGA - 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value - 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning - 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit - 2.03 (2015-04-12) extra corruption checking (mmozeiko) - stbi_set_flip_vertically_on_load (nguillemot) - fix NEON support; fix mingw support - 2.02 (2015-01-19) fix incorrect assert, fix warning - 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 - 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG - 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) - progressive JPEG (stb) - PGM/PPM support (Ken Miller) - STBI_MALLOC,STBI_REALLOC,STBI_FREE - GIF bugfix -- seemingly never worked - STBI_NO_*, STBI_ONLY_* - 1.48 (2014-12-14) fix incorrectly-named assert() - 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) - optimize PNG (ryg) - fix bug in interlaced PNG with user-specified channel count (stb) - 1.46 (2014-08-26) - fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG - 1.45 (2014-08-16) - fix MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) - various warning fixes from Ronny Chevalier - 1.43 (2014-07-15) - fix MSVC-only compiler problem in code changed in 1.42 - 1.42 (2014-07-09) - don't define _CRT_SECURE_NO_WARNINGS (affects user code) - fixes to stbi__cleanup_jpeg path - added STBI_ASSERT to avoid requiring assert.h - 1.41 (2014-06-25) - fix search&replace from 1.36 that messed up comments/error messages - 1.40 (2014-06-22) - fix gcc struct-initialization warning - 1.39 (2014-06-15) - fix to TGA optimization when req_comp != number of components in TGA; - fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) - add support for BMP version 5 (more ignored fields) - 1.38 (2014-06-06) - suppress MSVC warnings on integer casts truncating values - fix accidental rename of 'skip' field of I/O - 1.37 (2014-06-04) - remove duplicate typedef - 1.36 (2014-06-03) - convert to header file single-file library - if de-iphone isn't set, load iphone images color-swapped instead of returning NULL - 1.35 (2014-05-27) - various warnings - fix broken STBI_SIMD path - fix bug where stbi_load_from_file no longer left file pointer in correct place - fix broken non-easy path for 32-bit BMP (possibly never used) - TGA optimization by Arseny Kapoulkine - 1.34 (unknown) - use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case - 1.33 (2011-07-14) - make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements - 1.32 (2011-07-13) - support for "info" function for all supported filetypes (SpartanJ) - 1.31 (2011-06-20) - a few more leak fixes, bug in PNG handling (SpartanJ) - 1.30 (2011-06-11) - added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) - removed deprecated format-specific test/load functions - removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway - error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) - fix inefficiency in decoding 32-bit BMP (David Woo) - 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville - 1.28 (2010-08-01) - fix bug in GIF palette transparency (SpartanJ) - 1.27 (2010-08-01) - cast-to-stbi_uc to fix warnings - 1.26 (2010-07-24) - fix bug in file buffering for PNG reported by SpartanJ - 1.25 (2010-07-17) - refix trans_data warning (Won Chun) - 1.24 (2010-07-12) - perf improvements reading from files on platforms with lock-heavy fgetc() - minor perf improvements for jpeg - deprecated type-specific functions so we'll get feedback if they're needed - attempt to fix trans_data warning (Won Chun) - 1.23 fixed bug in iPhone support - 1.22 (2010-07-10) - removed image *writing* support - stbi_info support from Jetro Lauha - GIF support from Jean-Marc Lienher - iPhone PNG-extensions from James Brown - warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) - 1.21 fix use of 'stbi_uc' in header (reported by jon blow) - 1.20 added support for Softimage PIC, by Tom Seddon - 1.19 bug in interlaced PNG corruption check (found by ryg) - 1.18 (2008-08-02) - fix a threading bug (local mutable static) - 1.17 support interlaced PNG - 1.16 major bugfix - stbi__convert_format converted one too many pixels - 1.15 initialize some fields for thread safety - 1.14 fix threadsafe conversion bug - header-file-only version (#define STBI_HEADER_FILE_ONLY before including) - 1.13 threadsafe - 1.12 const qualifiers in the API - 1.11 Support installable IDCT, colorspace conversion routines - 1.10 Fixes for 64-bit (don't use "unsigned long") - optimized upsampling by Fabian "ryg" Giesen - 1.09 Fix format-conversion for PSD code (bad global variables!) - 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz - 1.07 attempt to fix C++ warning/errors again - 1.06 attempt to fix C++ warning/errors again - 1.05 fix TGA loading to return correct *comp and use good luminance calc - 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free - 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR - 1.02 support for (subset of) HDR files, float interface for preferred access to them - 1.01 fix bug: possible bug in handling right-side up bmps... not sure - fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all - 1.00 interface to zlib that skips zlib header - 0.99 correct handling of alpha in palette - 0.98 TGA loader by lonesock; dynamically add loaders (untested) - 0.97 jpeg errors on too large a file; also catch another malloc failure - 0.96 fix detection of invalid v value - particleman@mollyrocket forum - 0.95 during header scan, seek to markers in case of padding - 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same - 0.93 handle jpegtran output; verbose errors - 0.92 read 4,8,16,24,32-bit BMP files of several formats - 0.91 output 24-bit Windows 3.0 BMP files - 0.90 fix a few more warnings; bump version number to approach 1.0 - 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd - 0.60 fix compiling as c++ - 0.59 fix warnings: merge Dave Moore's -Wall fixes - 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian - 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available - 0.56 fix bug: zlib uncompressed mode len vs. nlen - 0.55 fix bug: restart_interval not initialized to 0 - 0.54 allow NULL for 'int *comp' - 0.53 fix bug in png 3->4; speedup png decoding - 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments - 0.51 obey req_comp requests, 1-component jpegs return as 1-component, - on 'test' only check type, not whether we support this variant - 0.50 (2006-11-19) - first released version + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks + anyway error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in + decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version */ - /* ------------------------------------------------------------------------------ This software is available under 2 licenses -- choose whichever you prefer. diff --git a/src/stb_image_write.h b/src/stb_image_write.h index 082eb69..c61ec30 100644 --- a/src/stb_image_write.h +++ b/src/stb_image_write.h @@ -55,11 +55,11 @@ USAGE: There are also five equivalent functions that use an arbitrary write function. You are expected to open/close your file-equivalent before and after calling these: - int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); - int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); - int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); - int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); + int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int +stride_in_bytes); int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void +*data); int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); int +stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); int +stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); where the callback is: void stbi_write_func(void *context, void *data, int size); @@ -105,7 +105,7 @@ USAGE: TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed data, set the global variable 'stbi_write_tga_with_rle' to 0. - + JPEG does ignore alpha channels in input data; quality is between 1 and 100. Higher quality looks better but results in a bigger image. JPEG baseline (no JPEG progressive). @@ -113,7 +113,7 @@ USAGE: CREDITS: - Sean Barrett - PNG/BMP/TGA + Sean Barrett - PNG/BMP/TGA Baldur Karlsson - HDR Jean-Sebastien Guay - TGA monochrome Tim Kelsey - misc enhancements @@ -155,55 +155,57 @@ LICENSE // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline' #ifndef STBIWDEF #ifdef STB_IMAGE_WRITE_STATIC -#define STBIWDEF static +#define STBIWDEF static #else #ifdef __cplusplus -#define STBIWDEF extern "C" +#define STBIWDEF extern "C" #else -#define STBIWDEF extern +#define STBIWDEF extern #endif #endif #endif -#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations +#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations extern int stbi_write_tga_with_rle; extern int stbi_write_png_compression_level; extern int stbi_write_force_png_filter; #endif #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); #ifdef STBI_WINDOWS_UTF8 -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t *input); #endif #endif typedef void stbi_write_func(void *context, void *data, int size); -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, + int stride_in_bytes); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int quality); STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); -#endif//INCLUDE_STB_IMAGE_WRITE_H +#endif // INCLUDE_STB_IMAGE_WRITE_H #ifdef STB_IMAGE_WRITE_IMPLEMENTATION #ifdef _WIN32 - #ifndef _CRT_SECURE_NO_WARNINGS - #define _CRT_SECURE_NO_WARNINGS - #endif - #ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE - #endif +#ifndef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif #endif #ifndef STBI_WRITE_NO_STDIO @@ -225,63 +227,53 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); #ifndef STBIW_MALLOC #define STBIW_MALLOC(sz) malloc(sz) -#define STBIW_REALLOC(p,newsz) realloc(p,newsz) +#define STBIW_REALLOC(p, newsz) realloc(p, newsz) #define STBIW_FREE(p) free(p) #endif #ifndef STBIW_REALLOC_SIZED -#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) +#define STBIW_REALLOC_SIZED(p, oldsz, newsz) STBIW_REALLOC(p, newsz) #endif - #ifndef STBIW_MEMMOVE -#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) +#define STBIW_MEMMOVE(a, b, sz) memmove(a, b, sz) #endif - #ifndef STBIW_ASSERT #include <assert.h> #define STBIW_ASSERT(x) assert(x) #endif -#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) +#define STBIW_UCHAR(x) (unsigned char)((x)&0xff) #ifdef STB_IMAGE_WRITE_STATIC -static int stbi__flip_vertically_on_write=0; +static int stbi__flip_vertically_on_write = 0; static int stbi_write_png_compression_level = 8; -static int stbi_write_tga_with_rle = 1; -static int stbi_write_force_png_filter = -1; +static int stbi_write_tga_with_rle = 1; +static int stbi_write_force_png_filter = -1; #else int stbi_write_png_compression_level = 8; -int stbi__flip_vertically_on_write=0; -int stbi_write_tga_with_rle = 1; -int stbi_write_force_png_filter = -1; +int stbi__flip_vertically_on_write = 0; +int stbi_write_tga_with_rle = 1; +int stbi_write_force_png_filter = -1; #endif -STBIWDEF void stbi_flip_vertically_on_write(int flag) -{ - stbi__flip_vertically_on_write = flag; -} +STBIWDEF void stbi_flip_vertically_on_write(int flag) { stbi__flip_vertically_on_write = flag; } -typedef struct -{ - stbi_write_func *func; - void *context; +typedef struct { + stbi_write_func *func; + void *context; } stbi__write_context; // initialize a callback-based context -static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) -{ - s->func = c; - s->context = context; +static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) { + s->func = c; + s->context = context; } #ifndef STBI_WRITE_NO_STDIO -static void stbi__stdio_write(void *context, void *data, int size) -{ - fwrite(data,1,size,(FILE*) context); -} +static void stbi__stdio_write(void *context, void *data, int size) { fwrite(data, 1, size, (FILE *)context); } #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) #ifdef __cplusplus @@ -289,306 +281,305 @@ static void stbi__stdio_write(void *context, void *data, int size) #else #define STBIW_EXTERN extern #endif -STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); -STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, + const char *str, int cbmb, wchar_t *widestr, + int cchwide); +STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, + const wchar_t *widestr, int cchwide, char *str, + int cbmb, const char *defchar, int *used_default); -STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) -{ - return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t *input) { + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int)bufferlen, NULL, NULL); } #endif -static FILE *stbiw__fopen(char const *filename, char const *mode) -{ - FILE *f; +static FILE *stbiw__fopen(char const *filename, char const *mode) { + FILE *f; #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) - wchar_t wMode[64]; - wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) - return 0; - - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) - return 0; + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; #if _MSC_VER >= 1400 - if (0 != _wfopen_s(&f, wFilename, wMode)) - f = 0; + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; #else - f = _wfopen(wFilename, wMode); + f = _wfopen(wFilename, wMode); #endif #elif defined(_MSC_VER) && _MSC_VER >= 1400 - if (0 != fopen_s(&f, filename, mode)) - f=0; + if (0 != fopen_s(&f, filename, mode)) + f = 0; #else - f = fopen(filename, mode); + f = fopen(filename, mode); #endif - return f; + return f; } -static int stbi__start_write_file(stbi__write_context *s, const char *filename) -{ - FILE *f = stbiw__fopen(filename, "wb"); - stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f); - return f != NULL; +static int stbi__start_write_file(stbi__write_context *s, const char *filename) { + FILE *f = stbiw__fopen(filename, "wb"); + stbi__start_write_callbacks(s, stbi__stdio_write, (void *)f); + return f != NULL; } -static void stbi__end_write_file(stbi__write_context *s) -{ - fclose((FILE *)s->context); -} +static void stbi__end_write_file(stbi__write_context *s) { fclose((FILE *)s->context); } #endif // !STBI_WRITE_NO_STDIO typedef unsigned int stbiw_uint32; -typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; +typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1]; -static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) -{ - while (*fmt) { - switch (*fmt++) { - case ' ': break; - case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); - s->func(s->context,&x,1); - break; } - case '2': { int x = va_arg(v,int); - unsigned char b[2]; - b[0] = STBIW_UCHAR(x); - b[1] = STBIW_UCHAR(x>>8); - s->func(s->context,b,2); - break; } - case '4': { stbiw_uint32 x = va_arg(v,int); - unsigned char b[4]; - b[0]=STBIW_UCHAR(x); - b[1]=STBIW_UCHAR(x>>8); - b[2]=STBIW_UCHAR(x>>16); - b[3]=STBIW_UCHAR(x>>24); - s->func(s->context,b,4); - break; } - default: +static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) { + while (*fmt) { + switch (*fmt++) { + case ' ': + break; + case '1': { + unsigned char x = STBIW_UCHAR(va_arg(v, int)); + s->func(s->context, &x, 1); + break; + } + case '2': { + int x = va_arg(v, int); + unsigned char b[2]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + s->func(s->context, b, 2); + break; + } + case '4': { + stbiw_uint32 x = va_arg(v, int); + unsigned char b[4]; + b[0] = STBIW_UCHAR(x); + b[1] = STBIW_UCHAR(x >> 8); + b[2] = STBIW_UCHAR(x >> 16); + b[3] = STBIW_UCHAR(x >> 24); + s->func(s->context, b, 4); + break; + } + default: STBIW_ASSERT(0); return; - } - } + } + } } -static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) -{ - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); +static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); } -static void stbiw__putc(stbi__write_context *s, unsigned char c) -{ - s->func(s->context, &c, 1); -} +static void stbiw__putc(stbi__write_context *s, unsigned char c) { s->func(s->context, &c, 1); } -static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) -{ - unsigned char arr[3]; - arr[0] = a; arr[1] = b; arr[2] = c; - s->func(s->context, arr, 3); +static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) { + unsigned char arr[3]; + arr[0] = a; + arr[1] = b; + arr[2] = c; + s->func(s->context, arr, 3); } -static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) -{ - unsigned char bg[3] = { 255, 0, 255}, px[3]; - int k; +static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, + unsigned char *d) { + unsigned char bg[3] = {255, 0, 255}, px[3]; + int k; - if (write_alpha < 0) - s->func(s->context, &d[comp - 1], 1); + if (write_alpha < 0) + s->func(s->context, &d[comp - 1], 1); - switch (comp) { - case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case - case 1: - if (expand_mono) + switch (comp) { + case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case + case 1: + if (expand_mono) stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp - else - s->func(s->context, d, 1); // monochrome TGA - break; - case 4: - if (!write_alpha) { + else + s->func(s->context, d, 1); // monochrome TGA + break; + case 4: + if (!write_alpha) { // composite against pink background for (k = 0; k < 3; ++k) - px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; + px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); break; - } - /* FALLTHROUGH */ - case 3: - stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); - break; - } - if (write_alpha > 0) - s->func(s->context, &d[comp - 1], 1); + } + /* FALLTHROUGH */ + case 3: + stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); + break; + } + if (write_alpha > 0) + s->func(s->context, &d[comp - 1], 1); } -static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) -{ - stbiw_uint32 zero = 0; - int i,j, j_end; +static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, + int write_alpha, int scanline_pad, int expand_mono) { + stbiw_uint32 zero = 0; + int i, j, j_end; - if (y <= 0) - return; + if (y <= 0) + return; - if (stbi__flip_vertically_on_write) - vdir *= -1; + if (stbi__flip_vertically_on_write) + vdir *= -1; - if (vdir < 0) { - j_end = -1; j = y-1; - } else { - j_end = y; j = 0; - } + if (vdir < 0) { + j_end = -1; + j = y - 1; + } else { + j_end = y; + j = 0; + } - for (; j != j_end; j += vdir) { - for (i=0; i < x; ++i) { - unsigned char *d = (unsigned char *) data + (j*x+i)*comp; - stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); - } - s->func(s->context, &zero, scanline_pad); - } + for (; j != j_end; j += vdir) { + for (i = 0; i < x; ++i) { + unsigned char *d = (unsigned char *)data + (j * x + i) * comp; + stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); + } + s->func(s->context, &zero, scanline_pad); + } } -static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) -{ - if (y < 0 || x < 0) { - return 0; - } else { - va_list v; - va_start(v, fmt); - stbiw__writefv(s, fmt, v); - va_end(v); - stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono); - return 1; - } +static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, + void *data, int alpha, int pad, const char *fmt, ...) { + if (y < 0 || x < 0) { + return 0; + } else { + va_list v; + va_start(v, fmt); + stbiw__writefv(s, fmt, v); + va_end(v); + stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono); + return 1; + } } -static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) -{ - int pad = (-x*3) & 3; - return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, - "11 4 22 4" "4 44 22 444444", - 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header - 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) { + int pad = (-x * 3) & 3; + return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *)data, 0, pad, + "11 4 22 4" + "4 44 22 444444", + 'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, 14 + 40, // file header + 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header } -STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_bmp_core(&s, x, y, comp, data); +STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_bmp_core(&s, x, y, comp, data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_bmp_core(&s, x, y, comp, data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_bmp_core(&s, x, y, comp, data); + stbi__end_write_file(&s); + return r; + } else + return 0; } -#endif //!STBI_WRITE_NO_STDIO +#endif //! STBI_WRITE_NO_STDIO -static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) -{ - int has_alpha = (comp == 2 || comp == 4); - int colorbytes = has_alpha ? comp-1 : comp; - int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 +static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) { + int has_alpha = (comp == 2 || comp == 4); + int colorbytes = has_alpha ? comp - 1 : comp; + int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 - if (y < 0 || x < 0) - return 0; + if (y < 0 || x < 0) + return 0; - if (!stbi_write_tga_with_rle) { - return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0, - "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); - } else { - int i,j,k; - int jend, jdir; + if (!stbi_write_tga_with_rle) { + return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *)data, has_alpha, 0, "111 221 2222 11", 0, 0, format, 0, + 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); + } else { + int i, j, k; + int jend, jdir; - stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8); + stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, + has_alpha * 8); - if (stbi__flip_vertically_on_write) { - j = 0; - jend = y; - jdir = 1; - } else { - j = y-1; - jend = -1; - jdir = -1; - } - for (; j != jend; j += jdir) { - unsigned char *row = (unsigned char *) data + j * x * comp; - int len; + if (stbi__flip_vertically_on_write) { + j = 0; + jend = y; + jdir = 1; + } else { + j = y - 1; + jend = -1; + jdir = -1; + } + for (; j != jend; j += jdir) { + unsigned char *row = (unsigned char *)data + j * x * comp; + int len; - for (i = 0; i < x; i += len) { - unsigned char *begin = row + i * comp; - int diff = 1; - len = 1; + for (i = 0; i < x; i += len) { + unsigned char *begin = row + i * comp; + int diff = 1; + len = 1; - if (i < x - 1) { - ++len; - diff = memcmp(begin, row + (i + 1) * comp, comp); - if (diff) { - const unsigned char *prev = begin; - for (k = i + 2; k < x && len < 128; ++k) { - if (memcmp(prev, row + k * comp, comp)) { - prev += comp; - ++len; - } else { - --len; - break; - } - } - } else { - for (k = i + 2; k < x && len < 128; ++k) { - if (!memcmp(begin, row + k * comp, comp)) { - ++len; - } else { - break; - } - } - } - } + if (i < x - 1) { + ++len; + diff = memcmp(begin, row + (i + 1) * comp, comp); + if (diff) { + const unsigned char *prev = begin; + for (k = i + 2; k < x && len < 128; ++k) { + if (memcmp(prev, row + k * comp, comp)) { + prev += comp; + ++len; + } else { + --len; + break; + } + } + } else { + for (k = i + 2; k < x && len < 128; ++k) { + if (!memcmp(begin, row + k * comp, comp)) { + ++len; + } else { + break; + } + } + } + } - if (diff) { - unsigned char header = STBIW_UCHAR(len - 1); - s->func(s->context, &header, 1); - for (k = 0; k < len; ++k) { - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); - } - } else { - unsigned char header = STBIW_UCHAR(len - 129); - s->func(s->context, &header, 1); - stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + if (diff) { + unsigned char header = STBIW_UCHAR(len - 1); + s->func(s->context, &header, 1); + for (k = 0; k < len; ++k) { + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); + } + } else { + unsigned char header = STBIW_UCHAR(len - 129); + s->func(s->context, &header, 1); + stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); + } } - } - } - } - return 1; + } + } + return 1; } -STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_tga_core(&s, x, y, comp, (void *) data); +STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_tga_core(&s, x, y, comp, (void *)data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_tga_core(&s, x, y, comp, (void *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -596,177 +587,175 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const // Radiance RGBE HDR writer // by Baldur Karlsson -#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) +#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) -static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) -{ - int exponent; - float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); +static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) { + int exponent; + float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); - if (maxcomp < 1e-32f) { - rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; - } else { - float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp; + if (maxcomp < 1e-32f) { + rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; + } else { + float normalize = (float)frexp(maxcomp, &exponent) * 256.0f / maxcomp; - rgbe[0] = (unsigned char)(linear[0] * normalize); - rgbe[1] = (unsigned char)(linear[1] * normalize); - rgbe[2] = (unsigned char)(linear[2] * normalize); - rgbe[3] = (unsigned char)(exponent + 128); - } + rgbe[0] = (unsigned char)(linear[0] * normalize); + rgbe[1] = (unsigned char)(linear[1] * normalize); + rgbe[2] = (unsigned char)(linear[2] * normalize); + rgbe[3] = (unsigned char)(exponent + 128); + } } -static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) -{ - unsigned char lengthbyte = STBIW_UCHAR(length+128); - STBIW_ASSERT(length+128 <= 255); - s->func(s->context, &lengthbyte, 1); - s->func(s->context, &databyte, 1); +static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) { + unsigned char lengthbyte = STBIW_UCHAR(length + 128); + STBIW_ASSERT(length + 128 <= 255); + s->func(s->context, &lengthbyte, 1); + s->func(s->context, &databyte, 1); } -static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) -{ - unsigned char lengthbyte = STBIW_UCHAR(length); - STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code - s->func(s->context, &lengthbyte, 1); - s->func(s->context, data, length); +static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) { + unsigned char lengthbyte = STBIW_UCHAR(length); + STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code + s->func(s->context, &lengthbyte, 1); + s->func(s->context, data, length); } -static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) -{ - unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; - unsigned char rgbe[4]; - float linear[3]; - int x; +static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, + float *scanline) { + unsigned char scanlineheader[4] = {2, 2, 0, 0}; + unsigned char rgbe[4]; + float linear[3]; + int x; - scanlineheader[2] = (width&0xff00)>>8; - scanlineheader[3] = (width&0x00ff); + scanlineheader[2] = (width & 0xff00) >> 8; + scanlineheader[3] = (width & 0x00ff); - /* skip RLE for images too small or large */ - if (width < 8 || width >= 32768) { - for (x=0; x < width; x++) { - switch (ncomp) { + /* skip RLE for images too small or large */ + if (width < 8 || width >= 32768) { + for (x = 0; x < width; x++) { + switch (ncomp) { case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - s->func(s->context, rgbe, 4); - } - } else { - int c,r; - /* encode into scratch buffer */ - for (x=0; x < width; x++) { - switch(ncomp) { + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + s->func(s->context, rgbe, 4); + } + } else { + int c, r; + /* encode into scratch buffer */ + for (x = 0; x < width; x++) { + switch (ncomp) { case 4: /* fallthrough */ - case 3: linear[2] = scanline[x*ncomp + 2]; - linear[1] = scanline[x*ncomp + 1]; - linear[0] = scanline[x*ncomp + 0]; - break; + case 3: + linear[2] = scanline[x * ncomp + 2]; + linear[1] = scanline[x * ncomp + 1]; + linear[0] = scanline[x * ncomp + 0]; + break; default: - linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; - break; - } - stbiw__linear_to_rgbe(rgbe, linear); - scratch[x + width*0] = rgbe[0]; - scratch[x + width*1] = rgbe[1]; - scratch[x + width*2] = rgbe[2]; - scratch[x + width*3] = rgbe[3]; - } + linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0]; + break; + } + stbiw__linear_to_rgbe(rgbe, linear); + scratch[x + width * 0] = rgbe[0]; + scratch[x + width * 1] = rgbe[1]; + scratch[x + width * 2] = rgbe[2]; + scratch[x + width * 3] = rgbe[3]; + } - s->func(s->context, scanlineheader, 4); + s->func(s->context, scanlineheader, 4); - /* RLE each component separately */ - for (c=0; c < 4; c++) { - unsigned char *comp = &scratch[width*c]; + /* RLE each component separately */ + for (c = 0; c < 4; c++) { + unsigned char *comp = &scratch[width * c]; - x = 0; - while (x < width) { - // find first run - r = x; - while (r+2 < width) { - if (comp[r] == comp[r+1] && comp[r] == comp[r+2]) - break; - ++r; - } - if (r+2 >= width) - r = width; - // dump up to first run - while (x < r) { - int len = r-x; - if (len > 128) len = 128; - stbiw__write_dump_data(s, len, &comp[x]); - x += len; - } - // if there's a run, output it - if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd - // find next byte after run - while (r < width && comp[r] == comp[x]) - ++r; - // output run up to r - while (x < r) { - int len = r-x; - if (len > 127) len = 127; - stbiw__write_run_data(s, len, comp[x]); - x += len; - } + x = 0; + while (x < width) { + // find first run + r = x; + while (r + 2 < width) { + if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2]) + break; + ++r; + } + if (r + 2 >= width) + r = width; + // dump up to first run + while (x < r) { + int len = r - x; + if (len > 128) + len = 128; + stbiw__write_dump_data(s, len, &comp[x]); + x += len; + } + // if there's a run, output it + if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd + // find next byte after run + while (r < width && comp[r] == comp[x]) + ++r; + // output run up to r + while (x < r) { + int len = r - x; + if (len > 127) + len = 127; + stbiw__write_run_data(s, len, comp[x]); + x += len; + } + } } - } - } - } + } + } } -static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) -{ - if (y <= 0 || x <= 0 || data == NULL) - return 0; - else { - // Each component is stored separately. Allocate scratch space for full output scanline. - unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4); - int i, len; - char buffer[128]; - char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; - s->func(s->context, header, sizeof(header)-1); +static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) { + if (y <= 0 || x <= 0 || data == NULL) + return 0; + else { + // Each component is stored separately. Allocate scratch space for full output scanline. + unsigned char *scratch = (unsigned char *)STBIW_MALLOC(x * 4); + int i, len; + char buffer[128]; + char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; + s->func(s->context, header, sizeof(header) - 1); #ifdef __STDC_WANT_SECURE_LIB__ - len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif - s->func(s->context, buffer, len); + s->func(s->context, buffer, len); - for(i=0; i < y; i++) - stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)); - STBIW_FREE(scratch); - return 1; - } + for (i = 0; i < y; i++) + stbiw__write_hdr_scanline(s, x, comp, scratch, + data + comp * x * (stbi__flip_vertically_on_write ? y - 1 - i : i)); + STBIW_FREE(scratch); + return 1; + } } -STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_hdr_core(&s, x, y, comp, (float *) data); +STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_hdr_core(&s, x, y, comp, (float *)data); } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_hdr_core(&s, x, y, comp, (float *)data); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif // STBI_WRITE_NO_STDIO - ////////////////////////////////////////////////////////////////////////////// // // PNG writer @@ -774,417 +763,472 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const #ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() -#define stbiw__sbraw(a) ((int *) (a) - 2) -#define stbiw__sbm(a) stbiw__sbraw(a)[0] -#define stbiw__sbn(a) stbiw__sbraw(a)[1] +#define stbiw__sbraw(a) ((int *)(a)-2) +#define stbiw__sbm(a) stbiw__sbraw(a)[0] +#define stbiw__sbn(a) stbiw__sbraw(a)[1] -#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) -#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) -#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) +#define stbiw__sbneedgrow(a, n) ((a) == 0 || stbiw__sbn(a) + n >= stbiw__sbm(a)) +#define stbiw__sbmaybegrow(a, n) (stbiw__sbneedgrow(a, (n)) ? stbiw__sbgrow(a, n) : 0) +#define stbiw__sbgrow(a, n) stbiw__sbgrowf((void **)&(a), (n), sizeof(*(a))) -#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) +#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a, 1), (a)[stbiw__sbn(a)++] = (v)) #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) -#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) +#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)), 0 : 0) -static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) -{ - int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1; - void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2); - STBIW_ASSERT(p); - if (p) { - if (!*arr) ((int *) p)[1] = 0; - *arr = (void *) ((int *) p + 2); - stbiw__sbm(*arr) = m; - } - return *arr; +static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) { + int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1; + void *p = + STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr) * itemsize + sizeof(int) * 2) : 0, + itemsize * m + sizeof(int) * 2); + STBIW_ASSERT(p); + if (p) { + if (!*arr) + ((int *)p)[1] = 0; + *arr = (void *)((int *)p + 2); + stbiw__sbm(*arr) = m; + } + return *arr; } -static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) -{ - while (*bitcount >= 8) { - stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); - *bitbuffer >>= 8; - *bitcount -= 8; - } - return data; +static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) { + while (*bitcount >= 8) { + stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; } -static int stbiw__zlib_bitrev(int code, int codebits) -{ - int res=0; - while (codebits--) { - res = (res << 1) | (code & 1); - code >>= 1; - } - return res; +static int stbiw__zlib_bitrev(int code, int codebits) { + int res = 0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; } -static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) -{ - int i; - for (i=0; i < limit && i < 258; ++i) - if (a[i] != b[i]) break; - return i; +static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) { + int i; + for (i = 0; i < limit && i < 258; ++i) + if (a[i] != b[i]) + break; + return i; } -static unsigned int stbiw__zhash(unsigned char *data) -{ - stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - return hash; +static unsigned int stbiw__zhash(unsigned char *data) { + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; } -#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) -#define stbiw__zlib_add(code,codebits) \ - (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) -#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) +#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbiw__zlib_add(code, codebits) (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) +#define stbiw__zlib_huffa(b, c) stbiw__zlib_add(stbiw__zlib_bitrev(b, c), c) // default huffman tables -#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) -#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) -#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) -#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) -#define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) +#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) +#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) +#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256, 7) +#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280, 8) +#define stbiw__zlib_huff(n) \ + ((n) <= 143 ? stbiw__zlib_huff1(n) \ + : (n) <= 255 ? stbiw__zlib_huff2(n) \ + : (n) <= 279 ? stbiw__zlib_huff3(n) \ + : stbiw__zlib_huff4(n)) #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) -#define stbiw__ZHASH 16384 +#define stbiw__ZHASH 16384 #endif // STBIW_ZLIB_COMPRESS -STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) -{ +STBIWDEF unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { #ifdef STBIW_ZLIB_COMPRESS - // user provided a zlib compress implementation, use that - return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); -#else // use builtin - static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; - static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; - static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; - static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; - unsigned int bitbuf=0; - int i,j, bitcount=0; - unsigned char *out = NULL; - unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); - if (hash_table == NULL) - return NULL; - if (quality < 5) quality = 5; + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin + static unsigned short lengthc[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, + 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 259}; + static unsigned char lengtheb[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static unsigned short distc[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32768}; + static unsigned char disteb[] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, + 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + unsigned int bitbuf = 0; + int i, j, bitcount = 0; + unsigned char *out = NULL; + unsigned char ***hash_table = (unsigned char ***)STBIW_MALLOC(stbiw__ZHASH * sizeof(char **)); + if (hash_table == NULL) + return NULL; + if (quality < 5) + quality = 5; - stbiw__sbpush(out, 0x78); // DEFLATE 32K window - stbiw__sbpush(out, 0x5e); // FLEVEL = 1 - stbiw__zlib_add(1,1); // BFINAL = 1 - stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + stbiw__sbpush(out, 0x78); // DEFLATE 32K window + stbiw__sbpush(out, 0x5e); // FLEVEL = 1 + stbiw__zlib_add(1, 1); // BFINAL = 1 + stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman - for (i=0; i < stbiw__ZHASH; ++i) - hash_table[i] = NULL; + for (i = 0; i < stbiw__ZHASH; ++i) + hash_table[i] = NULL; - i=0; - while (i < data_len-3) { - // hash next 3 bytes of data to be compressed - int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3; - unsigned char *bestloc = 0; - unsigned char **hlist = hash_table[h]; - int n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32768) { // if entry lies within window - int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); - if (d >= best) { best=d; bestloc=hlist[j]; } - } - } - // when hash table entry is too long, delete half the entries - if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) { - STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); - stbiw__sbn(hash_table[h]) = quality; - } - stbiw__sbpush(hash_table[h],data+i); + i = 0; + while (i < data_len - 3) { + // hash next 3 bytes of data to be compressed + int h = stbiw__zhash(data + i) & (stbiw__ZHASH - 1), best = 3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32768) { // if entry lies within window + int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i); + if (d >= best) { + best = d; + bestloc = hlist[j]; + } + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) { + STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0]) * quality); + stbiw__sbn(hash_table[h]) = quality; + } + stbiw__sbpush(hash_table[h], data + i); - if (bestloc) { - // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal - h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1); - hlist = hash_table[h]; - n = stbiw__sbcount(hlist); - for (j=0; j < n; ++j) { - if (hlist[j]-data > i-32767) { - int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1); - if (e > best) { // if next match is better, bail on current match - bestloc = NULL; - break; - } + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbiw__zhash(data + i + 1) & (stbiw__ZHASH - 1); + hlist = hash_table[h]; + n = stbiw__sbcount(hlist); + for (j = 0; j < n; ++j) { + if (hlist[j] - data > i - 32767) { + int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } } - } - } + } - if (bestloc) { - int d = (int) (data+i - bestloc); // distance back - STBIW_ASSERT(d <= 32767 && best <= 258); - for (j=0; best > lengthc[j+1]-1; ++j); - stbiw__zlib_huff(j+257); - if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); - for (j=0; d > distc[j+1]-1; ++j); - stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5); - if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); - i += best; - } else { - stbiw__zlib_huffb(data[i]); - ++i; - } - } - // write out final bytes - for (;i < data_len; ++i) - stbiw__zlib_huffb(data[i]); - stbiw__zlib_huff(256); // end of block - // pad with 0 bits to byte boundary - while (bitcount) - stbiw__zlib_add(0,1); + if (bestloc) { + int d = (int)(data + i - bestloc); // distance back + STBIW_ASSERT(d <= 32767 && best <= 258); + for (j = 0; best > lengthc[j + 1] - 1; ++j) + ; + stbiw__zlib_huff(j + 257); + if (lengtheb[j]) + stbiw__zlib_add(best - lengthc[j], lengtheb[j]); + for (j = 0; d > distc[j + 1] - 1; ++j) + ; + stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5); + if (disteb[j]) + stbiw__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbiw__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (; i < data_len; ++i) + stbiw__zlib_huffb(data[i]); + stbiw__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbiw__zlib_add(0, 1); - for (i=0; i < stbiw__ZHASH; ++i) - (void) stbiw__sbfree(hash_table[i]); - STBIW_FREE(hash_table); + for (i = 0; i < stbiw__ZHASH; ++i) + (void)stbiw__sbfree(hash_table[i]); + STBIW_FREE(hash_table); - { - // compute adler32 on input - unsigned int s1=1, s2=0; - int blocklen = (int) (data_len % 5552); - j=0; - while (j < data_len) { - for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } - s1 %= 65521; s2 %= 65521; - j += blocklen; - blocklen = 5552; - } - stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s2)); - stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); - stbiw__sbpush(out, STBIW_UCHAR(s1)); - } - *out_len = stbiw__sbn(out); - // make returned pointer freeable - STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); - return (unsigned char *) stbiw__sbraw(out); + { + // compute adler32 on input + unsigned int s1 = 1, s2 = 0; + int blocklen = (int)(data_len % 5552); + j = 0; + while (j < data_len) { + for (i = 0; i < blocklen; ++i) { + s1 += data[j + i]; + s2 += s1; + } + s1 %= 65521; + s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s2)); + stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); + stbiw__sbpush(out, STBIW_UCHAR(s1)); + } + *out_len = stbiw__sbn(out); + // make returned pointer freeable + STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); + return (unsigned char *)stbiw__sbraw(out); #endif // STBIW_ZLIB_COMPRESS } -static unsigned int stbiw__crc32(unsigned char *buffer, int len) -{ +static unsigned int stbiw__crc32(unsigned char *buffer, int len) { #ifdef STBIW_CRC32 return STBIW_CRC32(buffer, len); #else - static unsigned int crc_table[256] = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D - }; + static unsigned int crc_table[256] = { + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0eDB8832, + 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, + 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, + 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, + 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, + 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, + 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, + 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, + 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, + 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, + 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, + 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, + 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, + 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, + 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, + 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, + 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, + 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, + 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, + 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; - unsigned int crc = ~0u; - int i; - for (i=0; i < len; ++i) - crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; - return ~crc; + unsigned int crc = ~0u; + int i; + for (i = 0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; #endif } -#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) -#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); -#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) +#define stbiw__wpng4(o, a, b, c, d) \ + ((o)[0] = STBIW_UCHAR(a), (o)[1] = STBIW_UCHAR(b), (o)[2] = STBIW_UCHAR(c), (o)[3] = STBIW_UCHAR(d), (o) += 4) +#define stbiw__wp32(data, v) stbiw__wpng4(data, (v) >> 24, (v) >> 16, (v) >> 8, (v)); +#define stbiw__wptag(data, s) stbiw__wpng4(data, s[0], s[1], s[2], s[3]) -static void stbiw__wpcrc(unsigned char **data, int len) -{ - unsigned int crc = stbiw__crc32(*data - len - 4, len+4); - stbiw__wp32(*data, crc); +static void stbiw__wpcrc(unsigned char **data, int len) { + unsigned int crc = stbiw__crc32(*data - len - 4, len + 4); + stbiw__wp32(*data, crc); } -static unsigned char stbiw__paeth(int a, int b, int c) -{ - int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); - if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); - if (pb <= pc) return STBIW_UCHAR(b); - return STBIW_UCHAR(c); +static unsigned char stbiw__paeth(int a, int b, int c) { + int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c); + if (pa <= pb && pa <= pc) + return STBIW_UCHAR(a); + if (pb <= pc) + return STBIW_UCHAR(b); + return STBIW_UCHAR(c); } // @OPTIMIZE: provide an option that always forces left-predict or paeth predict -static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer) -{ - static int mapping[] = { 0,1,2,3,4 }; - static int firstmap[] = { 0,1,0,5,6 }; - int *mymap = (y != 0) ? mapping : firstmap; - int i; - int type = mymap[filter_type]; - unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); - int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; - - if (type==0) { - memcpy(line_buffer, z, width*n); - return; - } +static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, + int filter_type, signed char *line_buffer) { + static int mapping[] = {0, 1, 2, 3, 4}; + static int firstmap[] = {0, 1, 0, 5, 6}; + int *mymap = (y != 0) ? mapping : firstmap; + int i; + int type = mymap[filter_type]; + unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y); + int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; - // first loop isn't optimized since it's just one pixel - for (i = 0; i < n; ++i) { - switch (type) { - case 1: line_buffer[i] = z[i]; break; - case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break; - case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break; - case 5: line_buffer[i] = z[i]; break; - case 6: line_buffer[i] = z[i]; break; - } - } - switch (type) { - case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break; - case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break; - case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break; - case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break; - case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break; - case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break; - } + if (type == 0) { + memcpy(line_buffer, z, width * n); + return; + } + + // first loop isn't optimized since it's just one pixel + for (i = 0; i < n; ++i) { + switch (type) { + case 1: + line_buffer[i] = z[i]; + break; + case 2: + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + line_buffer[i] = z[i] - (z[i - signed_stride] >> 1); + break; + case 4: + line_buffer[i] = (signed char)(z[i] - stbiw__paeth(0, z[i - signed_stride], 0)); + break; + case 5: + line_buffer[i] = z[i]; + break; + case 6: + line_buffer[i] = z[i]; + break; + } + } + switch (type) { + case 1: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - n]; + break; + case 2: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - z[i - signed_stride]; + break; + case 3: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1); + break; + case 4: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], z[i - signed_stride - n]); + break; + case 5: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - (z[i - n] >> 1); + break; + case 6: + for (i = n; i < width * n; ++i) + line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0); + break; + } } -STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) -{ - int force_filter = stbi_write_force_png_filter; - int ctype[5] = { -1, 0, 4, 2, 6 }; - unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; - unsigned char *out,*o, *filt, *zlib; - signed char *line_buffer; - int j,zlen; +STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, + int *out_len) { + int force_filter = stbi_write_force_png_filter; + int ctype[5] = {-1, 0, 4, 2, 6}; + unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + unsigned char *out, *o, *filt, *zlib; + signed char *line_buffer; + int j, zlen; - if (stride_bytes == 0) - stride_bytes = x * n; + if (stride_bytes == 0) + stride_bytes = x * n; - if (force_filter >= 5) { - force_filter = -1; - } + if (force_filter >= 5) { + force_filter = -1; + } - filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0; - line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } - for (j=0; j < y; ++j) { - int filter_type; - if (force_filter > -1) { - filter_type = force_filter; - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); - } else { // Estimate the best filter by running through all of them: - int best_filter = 0, best_filter_val = 0x7fffffff, est, i; - for (filter_type = 0; filter_type < 5; filter_type++) { - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); + filt = (unsigned char *)STBIW_MALLOC((x * n + 1) * y); + if (!filt) + return 0; + line_buffer = (signed char *)STBIW_MALLOC(x * n); + if (!line_buffer) { + STBIW_FREE(filt); + return 0; + } + for (j = 0; j < y; ++j) { + int filter_type; + if (force_filter > -1) { + filter_type = force_filter; + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer); + } else { // Estimate the best filter by running through all of them: + int best_filter = 0, best_filter_val = 0x7fffffff, est, i; + for (filter_type = 0; filter_type < 5; filter_type++) { + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer); - // Estimate the entropy of the line using this filter; the less, the better. - est = 0; - for (i = 0; i < x*n; ++i) { - est += abs((signed char) line_buffer[i]); + // Estimate the entropy of the line using this filter; the less, the better. + est = 0; + for (i = 0; i < x * n; ++i) { + est += abs((signed char)line_buffer[i]); + } + if (est < best_filter_val) { + best_filter_val = est; + best_filter = filter_type; + } } - if (est < best_filter_val) { - best_filter_val = est; - best_filter = filter_type; + if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it + stbiw__encode_png_line((unsigned char *)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); + filter_type = best_filter; } - } - if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it - stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer); - filter_type = best_filter; - } - } - // when we get here, filter_type contains the filter type, and line_buffer contains the data - filt[j*(x*n+1)] = (unsigned char) filter_type; - STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); - } - STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level); - STBIW_FREE(filt); - if (!zlib) return 0; + } + // when we get here, filter_type contains the filter type, and line_buffer contains the data + filt[j * (x * n + 1)] = (unsigned char)filter_type; + STBIW_MEMMOVE(filt + j * (x * n + 1) + 1, line_buffer, x * n); + } + STBIW_FREE(line_buffer); + zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, stbi_write_png_compression_level); + STBIW_FREE(filt); + if (!zlib) + return 0; - // each tag requires 12 bytes of overhead - out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12); - if (!out) return 0; - *out_len = 8 + 12+13 + 12+zlen + 12; + // each tag requires 12 bytes of overhead + out = (unsigned char *)STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12); + if (!out) + return 0; + *out_len = 8 + 12 + 13 + 12 + zlen + 12; - o=out; - STBIW_MEMMOVE(o,sig,8); o+= 8; - stbiw__wp32(o, 13); // header length - stbiw__wptag(o, "IHDR"); - stbiw__wp32(o, x); - stbiw__wp32(o, y); - *o++ = 8; - *o++ = STBIW_UCHAR(ctype[n]); - *o++ = 0; - *o++ = 0; - *o++ = 0; - stbiw__wpcrc(&o,13); + o = out; + STBIW_MEMMOVE(o, sig, 8); + o += 8; + stbiw__wp32(o, 13); // header length + stbiw__wptag(o, "IHDR"); + stbiw__wp32(o, x); + stbiw__wp32(o, y); + *o++ = 8; + *o++ = STBIW_UCHAR(ctype[n]); + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbiw__wpcrc(&o, 13); - stbiw__wp32(o, zlen); - stbiw__wptag(o, "IDAT"); - STBIW_MEMMOVE(o, zlib, zlen); - o += zlen; - STBIW_FREE(zlib); - stbiw__wpcrc(&o, zlen); + stbiw__wp32(o, zlen); + stbiw__wptag(o, "IDAT"); + STBIW_MEMMOVE(o, zlib, zlen); + o += zlen; + STBIW_FREE(zlib); + stbiw__wpcrc(&o, zlen); - stbiw__wp32(o,0); - stbiw__wptag(o, "IEND"); - stbiw__wpcrc(&o,0); + stbiw__wp32(o, 0); + stbiw__wptag(o, "IEND"); + stbiw__wpcrc(&o, 0); - STBIW_ASSERT(o == out + *out_len); + STBIW_ASSERT(o == out + *out_len); - return out; + return out; } #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) -{ - FILE *f; - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; +STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) { + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; - f = stbiw__fopen(filename, "wb"); - if (!f) { STBIW_FREE(png); return 0; } - fwrite(png, 1, len, f); - fclose(f); - STBIW_FREE(png); - return 1; + f = stbiw__fopen(filename, "wb"); + if (!f) { + STBIW_FREE(png); + return 0; + } + fwrite(png, 1, len, f); + fclose(f); + STBIW_FREE(png); + return 1; } #endif -STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) -{ - int len; - unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len); - if (png == NULL) return 0; - func(context, png, len); - STBIW_FREE(png); - return 1; +STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int stride_bytes) { + int len; + unsigned char *png = stbi_write_png_to_mem((const unsigned char *)data, stride_bytes, x, y, comp, &len); + if (png == NULL) + return 0; + func(context, png, len); + STBIW_FREE(png); + return 1; } - /* *************************************************************************** * * JPEG writer @@ -1193,337 +1237,406 @@ STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html */ -static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18, - 24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 }; +static const unsigned char stbiw__jpg_ZigZag[] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63}; static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) { - int bitBuf = *bitBufP, bitCnt = *bitCntP; - bitCnt += bs[1]; - bitBuf |= bs[0] << (24 - bitCnt); - while(bitCnt >= 8) { - unsigned char c = (bitBuf >> 16) & 255; - stbiw__putc(s, c); - if(c == 255) { - stbiw__putc(s, 0); - } - bitBuf <<= 8; - bitCnt -= 8; - } - *bitBufP = bitBuf; - *bitCntP = bitCnt; + int bitBuf = *bitBufP, bitCnt = *bitCntP; + bitCnt += bs[1]; + bitBuf |= bs[0] << (24 - bitCnt); + while (bitCnt >= 8) { + unsigned char c = (bitBuf >> 16) & 255; + stbiw__putc(s, c); + if (c == 255) { + stbiw__putc(s, 0); + } + bitBuf <<= 8; + bitCnt -= 8; + } + *bitBufP = bitBuf; + *bitCntP = bitCnt; } -static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) { - float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; - float z1, z2, z3, z4, z5, z11, z13; +static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, + float *d7p) { + float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p; + float z1, z2, z3, z4, z5, z11, z13; - float tmp0 = d0 + d7; - float tmp7 = d0 - d7; - float tmp1 = d1 + d6; - float tmp6 = d1 - d6; - float tmp2 = d2 + d5; - float tmp5 = d2 - d5; - float tmp3 = d3 + d4; - float tmp4 = d3 - d4; + float tmp0 = d0 + d7; + float tmp7 = d0 - d7; + float tmp1 = d1 + d6; + float tmp6 = d1 - d6; + float tmp2 = d2 + d5; + float tmp5 = d2 - d5; + float tmp3 = d3 + d4; + float tmp4 = d3 - d4; - // Even part - float tmp10 = tmp0 + tmp3; // phase 2 - float tmp13 = tmp0 - tmp3; - float tmp11 = tmp1 + tmp2; - float tmp12 = tmp1 - tmp2; + // Even part + float tmp10 = tmp0 + tmp3; // phase 2 + float tmp13 = tmp0 - tmp3; + float tmp11 = tmp1 + tmp2; + float tmp12 = tmp1 - tmp2; - d0 = tmp10 + tmp11; // phase 3 - d4 = tmp10 - tmp11; + d0 = tmp10 + tmp11; // phase 3 + d4 = tmp10 - tmp11; - z1 = (tmp12 + tmp13) * 0.707106781f; // c4 - d2 = tmp13 + z1; // phase 5 - d6 = tmp13 - z1; + z1 = (tmp12 + tmp13) * 0.707106781f; // c4 + d2 = tmp13 + z1; // phase 5 + d6 = tmp13 - z1; - // Odd part - tmp10 = tmp4 + tmp5; // phase 2 - tmp11 = tmp5 + tmp6; - tmp12 = tmp6 + tmp7; + // Odd part + tmp10 = tmp4 + tmp5; // phase 2 + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; - // The rotator is modified from fig 4-8 to avoid extra negations. - z5 = (tmp10 - tmp12) * 0.382683433f; // c6 - z2 = tmp10 * 0.541196100f + z5; // c2-c6 - z4 = tmp12 * 1.306562965f + z5; // c2+c6 - z3 = tmp11 * 0.707106781f; // c4 + // The rotator is modified from fig 4-8 to avoid extra negations. + z5 = (tmp10 - tmp12) * 0.382683433f; // c6 + z2 = tmp10 * 0.541196100f + z5; // c2-c6 + z4 = tmp12 * 1.306562965f + z5; // c2+c6 + z3 = tmp11 * 0.707106781f; // c4 - z11 = tmp7 + z3; // phase 5 - z13 = tmp7 - z3; + z11 = tmp7 + z3; // phase 5 + z13 = tmp7 - z3; - *d5p = z13 + z2; // phase 6 - *d3p = z13 - z2; - *d1p = z11 + z4; - *d7p = z11 - z4; + *d5p = z13 + z2; // phase 6 + *d3p = z13 - z2; + *d1p = z11 + z4; + *d7p = z11 - z4; - *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6; + *d0p = d0; + *d2p = d2; + *d4p = d4; + *d6p = d6; } static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { - int tmp1 = val < 0 ? -val : val; - val = val < 0 ? val-1 : val; - bits[1] = 1; - while(tmp1 >>= 1) { - ++bits[1]; - } - bits[0] = val & ((1<<bits[1])-1); + int tmp1 = val < 0 ? -val : val; + val = val < 0 ? val - 1 : val; + bits[1] = 1; + while (tmp1 >>= 1) { + ++bits[1]; + } + bits[0] = val & ((1 << bits[1]) - 1); } -static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { - const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; - const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; - int dataOff, i, diff, end0pos; - int DU[64]; +static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, + const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { + const unsigned short EOB[2] = {HTAC[0x00][0], HTAC[0x00][1]}; + const unsigned short M16zeroes[2] = {HTAC[0xF0][0], HTAC[0xF0][1]}; + int dataOff, i, diff, end0pos; + int DU[64]; - // DCT rows - for(dataOff=0; dataOff<64; dataOff+=8) { - stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); - } - // DCT columns - for(dataOff=0; dataOff<8; ++dataOff) { - stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]); - } - // Quantize/descale/zigzag the coefficients - for(i=0; i<64; ++i) { - float v = CDU[i]*fdtbl[i]; - // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); - // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? - DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); - } + // DCT rows + for (dataOff = 0; dataOff < 64; dataOff += 8) { + stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 1], &CDU[dataOff + 2], &CDU[dataOff + 3], &CDU[dataOff + 4], + &CDU[dataOff + 5], &CDU[dataOff + 6], &CDU[dataOff + 7]); + } + // DCT columns + for (dataOff = 0; dataOff < 8; ++dataOff) { + stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 8], &CDU[dataOff + 16], &CDU[dataOff + 24], &CDU[dataOff + 32], + &CDU[dataOff + 40], &CDU[dataOff + 48], &CDU[dataOff + 56]); + } + // Quantize/descale/zigzag the coefficients + for (i = 0; i < 64; ++i) { + float v = CDU[i] * fdtbl[i]; + // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); + // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? + DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); + } - // Encode DC - diff = DU[0] - DC; - if (diff == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]); - } else { - unsigned short bits[2]; - stbiw__jpg_calcBits(diff, bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - // Encode ACs - end0pos = 63; - for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) { - } - // end0pos = first element in reverse order !=0 - if(end0pos == 0) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - return DU[0]; - } - for(i = 1; i <= end0pos; ++i) { - int startpos = i; - int nrzeroes; - unsigned short bits[2]; - for (; DU[i]==0 && i<=end0pos; ++i) { - } - nrzeroes = i-startpos; - if ( nrzeroes >= 16 ) { - int lng = nrzeroes>>4; - int nrmarker; - for (nrmarker=1; nrmarker <= lng; ++nrmarker) - stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); - nrzeroes &= 15; - } - stbiw__jpg_calcBits(DU[i], bits); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]); - stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); - } - if(end0pos != 63) { - stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); - } - return DU[0]; + // Encode DC + diff = DU[0] - DC; + if (diff == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]); + } else { + unsigned short bits[2]; + stbiw__jpg_calcBits(diff, bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + // Encode ACs + end0pos = 63; + for (; (end0pos > 0) && (DU[end0pos] == 0); --end0pos) { + } + // end0pos = first element in reverse order !=0 + if (end0pos == 0) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + return DU[0]; + } + for (i = 1; i <= end0pos; ++i) { + int startpos = i; + int nrzeroes; + unsigned short bits[2]; + for (; DU[i] == 0 && i <= end0pos; ++i) { + } + nrzeroes = i - startpos; + if (nrzeroes >= 16) { + int lng = nrzeroes >> 4; + int nrmarker; + for (nrmarker = 1; nrmarker <= lng; ++nrmarker) + stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes); + nrzeroes &= 15; + } + stbiw__jpg_calcBits(DU[i], bits); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]); + stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits); + } + if (end0pos != 63) { + stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB); + } + return DU[0]; } -static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) { - // Constants that don't pollute global namespace - static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0}; - static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d}; - static const unsigned char std_ac_luminance_values[] = { - 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08, - 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28, - 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59, - 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, - 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6, - 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2, - 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0}; - static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11}; - static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77}; - static const unsigned char std_ac_chrominance_values[] = { - 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91, - 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26, - 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58, - 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, - 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4, - 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda, - 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa - }; - // Huffman tables - static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}}; - static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}}; - static const unsigned short YAC_HT[256][2] = { - {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const unsigned short UVAC_HT[256][2] = { - {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, - {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0}, - {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0} - }; - static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22, - 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; - static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, - 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; - static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, - 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; +static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void *data, int quality) { + // Constants that don't pollute global namespace + static const unsigned char std_dc_luminance_nrcodes[] = {0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_luminance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_luminance_nrcodes[] = {0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d}; + static const unsigned char std_ac_luminance_values[] = { + 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, + 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, + 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, + 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, + 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, + 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, + 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + static const unsigned char std_dc_chrominance_nrcodes[] = {0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; + static const unsigned char std_dc_chrominance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + static const unsigned char std_ac_chrominance_nrcodes[] = {0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77}; + static const unsigned char std_ac_chrominance_values[] = { + 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, + 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, + 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, + 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, + 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}; + // Huffman tables + static const unsigned short YDC_HT[256][2] = {{0, 2}, {2, 3}, {3, 3}, {4, 3}, {5, 3}, {6, 3}, + {14, 4}, {30, 5}, {62, 6}, {126, 7}, {254, 8}, {510, 9}}; + static const unsigned short UVDC_HT[256][2] = {{0, 2}, {1, 2}, {2, 2}, {6, 3}, {14, 4}, {30, 5}, + {62, 6}, {126, 7}, {254, 8}, {510, 9}, {1022, 10}, {2046, 11}}; + static const unsigned short YAC_HT[256][2] = { + {10, 4}, {0, 2}, {1, 2}, {4, 3}, {11, 4}, {26, 5}, {120, 7}, {248, 8}, + {1014, 10}, {65410, 16}, {65411, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {12, 4}, {27, 5}, {121, 7}, {502, 9}, {2038, 11}, {65412, 16}, {65413, 16}, + {65414, 16}, {65415, 16}, {65416, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {28, 5}, {249, 8}, {1015, 10}, {4084, 12}, {65417, 16}, {65418, 16}, {65419, 16}, + {65420, 16}, {65421, 16}, {65422, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {58, 6}, {503, 9}, {4085, 12}, {65423, 16}, {65424, 16}, {65425, 16}, {65426, 16}, + {65427, 16}, {65428, 16}, {65429, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {59, 6}, {1016, 10}, {65430, 16}, {65431, 16}, {65432, 16}, {65433, 16}, {65434, 16}, + {65435, 16}, {65436, 16}, {65437, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {122, 7}, {2039, 11}, {65438, 16}, {65439, 16}, {65440, 16}, {65441, 16}, {65442, 16}, + {65443, 16}, {65444, 16}, {65445, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {123, 7}, {4086, 12}, {65446, 16}, {65447, 16}, {65448, 16}, {65449, 16}, {65450, 16}, + {65451, 16}, {65452, 16}, {65453, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {250, 8}, {4087, 12}, {65454, 16}, {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, + {65459, 16}, {65460, 16}, {65461, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {504, 9}, {32704, 15}, {65462, 16}, {65463, 16}, {65464, 16}, {65465, 16}, {65466, 16}, + {65467, 16}, {65468, 16}, {65469, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {505, 9}, {65470, 16}, {65471, 16}, {65472, 16}, {65473, 16}, {65474, 16}, {65475, 16}, + {65476, 16}, {65477, 16}, {65478, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {506, 9}, {65479, 16}, {65480, 16}, {65481, 16}, {65482, 16}, {65483, 16}, {65484, 16}, + {65485, 16}, {65486, 16}, {65487, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {1017, 10}, {65488, 16}, {65489, 16}, {65490, 16}, {65491, 16}, {65492, 16}, {65493, 16}, + {65494, 16}, {65495, 16}, {65496, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {1018, 10}, {65497, 16}, {65498, 16}, {65499, 16}, {65500, 16}, {65501, 16}, {65502, 16}, + {65503, 16}, {65504, 16}, {65505, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {2040, 11}, {65506, 16}, {65507, 16}, {65508, 16}, {65509, 16}, {65510, 16}, {65511, 16}, + {65512, 16}, {65513, 16}, {65514, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {65515, 16}, {65516, 16}, {65517, 16}, {65518, 16}, {65519, 16}, {65520, 16}, {65521, 16}, + {65522, 16}, {65523, 16}, {65524, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {2041, 11}, {65525, 16}, {65526, 16}, {65527, 16}, {65528, 16}, {65529, 16}, {65530, 16}, {65531, 16}, + {65532, 16}, {65533, 16}, {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; + static const unsigned short UVAC_HT[256][2] = { + {0, 2}, {1, 2}, {4, 3}, {10, 4}, {24, 5}, {25, 5}, {56, 6}, {120, 7}, + {500, 9}, {1014, 10}, {4084, 12}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {11, 4}, {57, 6}, {246, 8}, {501, 9}, {2038, 11}, {4085, 12}, {65416, 16}, + {65417, 16}, {65418, 16}, {65419, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {26, 5}, {247, 8}, {1015, 10}, {4086, 12}, {32706, 15}, {65420, 16}, {65421, 16}, + {65422, 16}, {65423, 16}, {65424, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {27, 5}, {248, 8}, {1016, 10}, {4087, 12}, {65425, 16}, {65426, 16}, {65427, 16}, + {65428, 16}, {65429, 16}, {65430, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {58, 6}, {502, 9}, {65431, 16}, {65432, 16}, {65433, 16}, {65434, 16}, {65435, 16}, + {65436, 16}, {65437, 16}, {65438, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {59, 6}, {1017, 10}, {65439, 16}, {65440, 16}, {65441, 16}, {65442, 16}, {65443, 16}, + {65444, 16}, {65445, 16}, {65446, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {121, 7}, {2039, 11}, {65447, 16}, {65448, 16}, {65449, 16}, {65450, 16}, {65451, 16}, + {65452, 16}, {65453, 16}, {65454, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {122, 7}, {2040, 11}, {65455, 16}, {65456, 16}, {65457, 16}, {65458, 16}, {65459, 16}, + {65460, 16}, {65461, 16}, {65462, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {249, 8}, {65463, 16}, {65464, 16}, {65465, 16}, {65466, 16}, {65467, 16}, {65468, 16}, + {65469, 16}, {65470, 16}, {65471, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {503, 9}, {65472, 16}, {65473, 16}, {65474, 16}, {65475, 16}, {65476, 16}, {65477, 16}, + {65478, 16}, {65479, 16}, {65480, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {504, 9}, {65481, 16}, {65482, 16}, {65483, 16}, {65484, 16}, {65485, 16}, {65486, 16}, + {65487, 16}, {65488, 16}, {65489, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {505, 9}, {65490, 16}, {65491, 16}, {65492, 16}, {65493, 16}, {65494, 16}, {65495, 16}, + {65496, 16}, {65497, 16}, {65498, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {506, 9}, {65499, 16}, {65500, 16}, {65501, 16}, {65502, 16}, {65503, 16}, {65504, 16}, + {65505, 16}, {65506, 16}, {65507, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {2041, 11}, {65508, 16}, {65509, 16}, {65510, 16}, {65511, 16}, {65512, 16}, {65513, 16}, + {65514, 16}, {65515, 16}, {65516, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {0, 0}, {16352, 14}, {65517, 16}, {65518, 16}, {65519, 16}, {65520, 16}, {65521, 16}, {65522, 16}, + {65523, 16}, {65524, 16}, {65525, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, + {1018, 10}, {32707, 15}, {65526, 16}, {65527, 16}, {65528, 16}, {65529, 16}, {65530, 16}, {65531, 16}, + {65532, 16}, {65533, 16}, {65534, 16}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}; + static const int YQT[] = {16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99}; + static const int UVQT[] = {17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, + 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}; + static const float aasf[] = {1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, + 1.175875602f * 2.828427125f, 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, + 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f}; - int row, col, i, k; - float fdtbl_Y[64], fdtbl_UV[64]; - unsigned char YTable[64], UVTable[64]; + int row, col, i, k; + float fdtbl_Y[64], fdtbl_UV[64]; + unsigned char YTable[64], UVTable[64]; - if(!data || !width || !height || comp > 4 || comp < 1) { - return 0; - } + if (!data || !width || !height || comp > 4 || comp < 1) { + return 0; + } - quality = quality ? quality : 90; - quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; - quality = quality < 50 ? 5000 / quality : 200 - quality * 2; + quality = quality ? quality : 90; + quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; + quality = quality < 50 ? 5000 / quality : 200 - quality * 2; - for(i = 0; i < 64; ++i) { - int uvti, yti = (YQT[i]*quality+50)/100; - YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti); - uvti = (UVQT[i]*quality+50)/100; - UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); - } + for (i = 0; i < 64; ++i) { + int uvti, yti = (YQT[i] * quality + 50) / 100; + YTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(yti < 1 ? 1 : yti > 255 ? 255 : yti); + uvti = (UVQT[i] * quality + 50) / 100; + UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(uvti < 1 ? 1 : uvti > 255 ? 255 : uvti); + } - for(row = 0, k = 0; row < 8; ++row) { - for(col = 0; col < 8; ++col, ++k) { - fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); - } - } + for (row = 0, k = 0; row < 8; ++row) { + for (col = 0; col < 8; ++col, ++k) { + fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]); + } + } - // Write Headers - { - static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; - static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; - const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), - 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; - s->func(s->context, (void*)head0, sizeof(head0)); - s->func(s->context, (void*)YTable, sizeof(YTable)); - stbiw__putc(s, 1); - s->func(s->context, UVTable, sizeof(UVTable)); - s->func(s->context, (void*)head1, sizeof(head1)); - s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1); - s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values)); - stbiw__putc(s, 0x10); // HTYACinfo - s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1); - s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values)); - stbiw__putc(s, 1); // HTUDCinfo - s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); - stbiw__putc(s, 0x11); // HTUACinfo - s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1); - s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); - s->func(s->context, (void*)head2, sizeof(head2)); - } + // Write Headers + { + static const unsigned char head0[] = {0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 'J', 'F', 'I', 'F', 0, 1, 1, + 0, 0, 1, 0, 1, 0, 0, 0xFF, 0xDB, 0, 0x84, 0}; + static const unsigned char head2[] = {0xFF, 0xDA, 0, 0xC, 3, 1, 0, 2, 0x11, 3, 0x11, 0, 0x3F, 0}; + const unsigned char head1[] = {0xFF, + 0xC0, + 0, + 0x11, + 8, + (unsigned char)(height >> 8), + STBIW_UCHAR(height), + (unsigned char)(width >> 8), + STBIW_UCHAR(width), + 3, + 1, + 0x11, + 0, + 2, + 0x11, + 1, + 3, + 0x11, + 1, + 0xFF, + 0xC4, + 0x01, + 0xA2, + 0}; + s->func(s->context, (void *)head0, sizeof(head0)); + s->func(s->context, (void *)YTable, sizeof(YTable)); + stbiw__putc(s, 1); + s->func(s->context, UVTable, sizeof(UVTable)); + s->func(s->context, (void *)head1, sizeof(head1)); + s->func(s->context, (void *)(std_dc_luminance_nrcodes + 1), sizeof(std_dc_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_luminance_values, sizeof(std_dc_luminance_values)); + stbiw__putc(s, 0x10); // HTYACinfo + s->func(s->context, (void *)(std_ac_luminance_nrcodes + 1), sizeof(std_ac_luminance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_luminance_values, sizeof(std_ac_luminance_values)); + stbiw__putc(s, 1); // HTUDCinfo + s->func(s->context, (void *)(std_dc_chrominance_nrcodes + 1), sizeof(std_dc_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_dc_chrominance_values, sizeof(std_dc_chrominance_values)); + stbiw__putc(s, 0x11); // HTUACinfo + s->func(s->context, (void *)(std_ac_chrominance_nrcodes + 1), sizeof(std_ac_chrominance_nrcodes) - 1); + s->func(s->context, (void *)std_ac_chrominance_values, sizeof(std_ac_chrominance_values)); + s->func(s->context, (void *)head2, sizeof(head2)); + } - // Encode 8x8 macroblocks - { - static const unsigned short fillBits[] = {0x7F, 7}; - const unsigned char *imageData = (const unsigned char *)data; - int DCY=0, DCU=0, DCV=0; - int bitBuf=0, bitCnt=0; - // comp == 2 is grey+alpha (alpha is ignored) - int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; - int x, y, pos; - for(y = 0; y < height; y += 8) { - for(x = 0; x < width; x += 8) { - float YDU[64], UDU[64], VDU[64]; - for(row = y, pos = 0; row < y+8; ++row) { - // row >= height => use last input row - int clamped_row = (row < height) ? row : height - 1; - int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; - for(col = x; col < x+8; ++col, ++pos) { - float r, g, b; - // if col >= width => use pixel from last input column - int p = base_p + ((col < width) ? col : (width-1))*comp; + // Encode 8x8 macroblocks + { + static const unsigned short fillBits[] = {0x7F, 7}; + const unsigned char *imageData = (const unsigned char *)data; + int DCY = 0, DCU = 0, DCV = 0; + int bitBuf = 0, bitCnt = 0; + // comp == 2 is grey+alpha (alpha is ignored) + int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; + int x, y, pos; + for (y = 0; y < height; y += 8) { + for (x = 0; x < width; x += 8) { + float YDU[64], UDU[64], VDU[64]; + for (row = y, pos = 0; row < y + 8; ++row) { + // row >= height => use last input row + int clamped_row = (row < height) ? row : height - 1; + int base_p = + (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width * comp; + for (col = x; col < x + 8; ++col, ++pos) { + float r, g, b; + // if col >= width => use pixel from last input column + int p = base_p + ((col < width) ? col : (width - 1)) * comp; - r = imageData[p+0]; - g = imageData[p+ofsG]; - b = imageData[p+ofsB]; - YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; - UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; - VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; - } - } + r = imageData[p + 0]; + g = imageData[p + ofsG]; + b = imageData[p + ofsB]; + YDU[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128; + UDU[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b; + VDU[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b; + } + } - DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); - DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); - DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); - } - } + DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); + DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); + DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); + } + } - // Do the bit alignment of the EOI marker - stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); - } + // Do the bit alignment of the EOI marker + stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits); + } - // EOI - stbiw__putc(s, 0xFF); - stbiw__putc(s, 0xD9); + // EOI + stbiw__putc(s, 0xFF); + stbiw__putc(s, 0xD9); - return 1; + return 1; } -STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s; - stbi__start_write_callbacks(&s, func, context); - return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); +STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, + int quality) { + stbi__write_context s; + stbi__start_write_callbacks(&s, func, context); + return stbi_write_jpg_core(&s, x, y, comp, (void *)data, quality); } - #ifndef STBI_WRITE_NO_STDIO -STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) -{ - stbi__write_context s; - if (stbi__start_write_file(&s,filename)) { - int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); - stbi__end_write_file(&s); - return r; - } else - return 0; +STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) { + stbi__write_context s; + if (stbi__start_write_file(&s, filename)) { + int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); + stbi__end_write_file(&s); + return r; + } else + return 0; } #endif @@ -1531,7 +1644,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const /* Revision history 1.10 (2019-02-07) - support utf8 filenames in Windows; fix warnings and platform ifdefs + support utf8 filenames in Windows; fix warnings and platform ifdefs 1.09 (2018-02-11) fix typo in zlib quality API, improve STB_I_W_STATIC in C++ 1.08 (2018-01-29) @@ -1562,7 +1675,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const add HDR output fix monochrome BMP 0.95 (2014-08-17) - add monochrome TGA output + add monochrome TGA output 0.94 (2014-05-31) rename private functions to avoid conflicts with stb_image.h 0.93 (2014-05-27) @@ -1580,38 +1693,38 @@ 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 +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 +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 +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, +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 +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 +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/stb_truetype.h b/src/stb_truetype.h index bbf2284..622e4ef 100644 --- a/src/stb_truetype.h +++ b/src/stb_truetype.h @@ -275,7 +275,7 @@ // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. // See "tests/truetype_demo_win32.c" for a complete version. #if 0 -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" unsigned char ttf_buffer[1<<20]; @@ -326,7 +326,7 @@ void my_stbtt_print(float x, float y, char *text) // #if 0 #include <stdio.h> -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation +#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation #include "stb_truetype.h" char ttf_buffer[1<<25]; @@ -412,7 +412,6 @@ int main(int arg, char **argv) } #endif - ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// @@ -423,70 +422,70 @@ int main(int arg, char **argv) //// 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 +// #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]; +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 <math.h> - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif +// e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h +#ifndef STBTT_ifloor +#include <math.h> +#define STBTT_ifloor(x) ((int)floor(x)) +#define STBTT_iceil(x) ((int)ceil(x)) +#endif - #ifndef STBTT_sqrt - #include <math.h> - #define STBTT_sqrt(x) sqrt(x) - #define STBTT_pow(x,y) pow(x,y) - #endif +#ifndef STBTT_sqrt +#include <math.h> +#define STBTT_sqrt(x) sqrt(x) +#define STBTT_pow(x, y) pow(x, y) +#endif - #ifndef STBTT_fmod - #include <math.h> - #define STBTT_fmod(x,y) fmod(x,y) - #endif +#ifndef STBTT_fmod +#include <math.h> +#define STBTT_fmod(x, y) fmod(x, y) +#endif - #ifndef STBTT_cos - #include <math.h> - #define STBTT_cos(x) cos(x) - #define STBTT_acos(x) acos(x) - #endif +#ifndef STBTT_cos +#include <math.h> +#define STBTT_cos(x) cos(x) +#define STBTT_acos(x) acos(x) +#endif - #ifndef STBTT_fabs - #include <math.h> - #define STBTT_fabs(x) fabs(x) - #endif +#ifndef STBTT_fabs +#include <math.h> +#define STBTT_fabs(x) fabs(x) +#endif - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include <stdlib.h> - #define STBTT_malloc(x,u) ((void)(u),malloc(x)) - #define STBTT_free(x,u) ((void)(u),free(x)) - #endif +// #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h +#ifndef STBTT_malloc +#include <stdlib.h> +#define STBTT_malloc(x, u) ((void)(u), malloc(x)) +#define STBTT_free(x, u) ((void)(u), free(x)) +#endif - #ifndef STBTT_assert - #include <assert.h> - #define STBTT_assert(x) assert(x) - #endif +#ifndef STBTT_assert +#include <assert.h> +#define STBTT_assert(x) assert(x) +#endif - #ifndef STBTT_strlen - #include <string.h> - #define STBTT_strlen(x) strlen(x) - #endif +#ifndef STBTT_strlen +#include <string.h> +#define STBTT_strlen(x) strlen(x) +#endif - #ifndef STBTT_memcpy - #include <string.h> - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif +#ifndef STBTT_memcpy +#include <string.h> +#define STBTT_memcpy memcpy +#define STBTT_memset memset +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -510,11 +509,10 @@ extern "C" { #endif // private structure -typedef struct -{ - unsigned char *data; - int cursor; - int size; +typedef struct { + unsigned char *data; + int cursor; + int size; } stbtt__buf; ////////////////////////////////////////////////////////////////////////////// @@ -524,33 +522,31 @@ typedef struct // 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; +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 +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 +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 +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. // @@ -561,10 +557,10 @@ STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int p // // 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); +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 @@ -572,20 +568,20 @@ STBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int in // 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; +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; +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); +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 @@ -596,13 +592,14 @@ STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, i // // Returns 0 on failure, 1 on success. -STBTT_DEF void stbtt_PackEnd (stbtt_pack_context *spc); +STBTT_DEF void stbtt_PackEnd(stbtt_pack_context *spc); // Cleans up the packing context and frees all memory. -#define STBTT_POINT_SIZE(x) (-(x)) +#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); +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 @@ -616,17 +613,17 @@ STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char // ..., 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 +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); +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 @@ -654,15 +651,17 @@ STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int s // 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 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 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); +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 @@ -676,16 +675,16 @@ STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, cons // 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; + 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; }; ////////////////////////////////////////////////////////////////////////////// @@ -710,24 +709,23 @@ STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); // 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 +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 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 + 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__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); @@ -737,7 +735,6 @@ STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, in // 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 @@ -749,7 +746,6 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep // codepoint-based functions. // Returns 0 if the character codepoint is not defined in the font. - ////////////////////////////////////////////////////////////////////////////// // // CHARACTER PROPERTIES @@ -776,7 +772,7 @@ STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, in // 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); +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). // @@ -785,31 +781,32 @@ STBTT_DEF int stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAsc 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); +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); +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 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; +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); +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) @@ -821,22 +818,16 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningen // #ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve, - STBTT_vcubic - }; +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; +#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); @@ -858,8 +849,8 @@ STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertice // 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); +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. @@ -871,7 +862,8 @@ STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char * 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); +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). @@ -880,63 +872,83 @@ STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, fl // // 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); +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); +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); +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); +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); +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); +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); - +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; +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 +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 ////////////////////////////////////////////////////////////////////////////// // @@ -945,18 +957,23 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, // 1-channel bitmap 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); +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), +// 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) +// 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 @@ -994,8 +1011,6 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // 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... @@ -1017,23 +1032,23 @@ STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, floa // 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 +#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); +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. // @@ -1042,52 +1057,69 @@ STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *l // 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 + 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 + 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 + 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 + 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 + 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 + 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 @@ -1106,23 +1138,23 @@ enum { // languageID for STBTT_PLATFORM_ID_MAC #ifdef STB_TRUETYPE_IMPLEMENTATION #ifndef STBTT_MAX_OVERSAMPLE -#define STBTT_MAX_OVERSAMPLE 8 +#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]; +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) +#define STBTT__NOTUSED(v) (void)(v) #else -#define STBTT__NOTUSED(v) (void)sizeof(v) +#define STBTT__NOTUSED(v) (void)sizeof(v) #endif ////////////////////////////////////////////////////////////////////////// @@ -1130,145 +1162,138 @@ typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERS // 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_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 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_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 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_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; +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) +#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__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__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 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); - } + 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 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 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 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); +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); } ////////////////////////////////////////////////////////////////////////// @@ -1279,1438 +1304,1495 @@ static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i) // 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) +#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]; } +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]) +#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; +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 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; +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; + // 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; +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; + // 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); +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__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; +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); + 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 + 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; + 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; + 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); + 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; + // @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 + // 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); + // @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); + 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; + // 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); - } + 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); - } + 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; + t = stbtt__find_table(data, fontstart, "maxp"); + if (t) + info->numGlyphs = ttUSHORT(data + t + 4); + else + info->numGlyphs = 0xffff; - info->svg = -1; + 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; + // 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); + info->index_map = cmap + ttULONG(data + encoding_record + 4); break; - } - } - if (info->index_map == 0) - return 0; + } + } + if (info->index_map == 0) + return 0; - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; + 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_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; + 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; + // do a binary search of the segments + stbtt_uint32 endCount = index_map + 14; + stbtt_uint32 search = endCount; - if (unicode_codepoint > 0xffff) - return 0; + 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; + // 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; + // 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); + { + 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; + 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)); + 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; + 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); +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 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; +static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) { + int g1, g2; - STBTT_assert(!info->cff.size); + 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 (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); - } + 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 + 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; +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; + 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_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; +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__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); +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; + *pvertices = NULL; - if (g < 0) return 0; + if (g < 0) + return 0; - numberOfContours = ttSHORT(data + g); + 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; + 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); + 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; + 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; + 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 + // 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 + off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - // first load flags + // 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; - } + 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; + // 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; - } + 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; + // 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; - } + 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; + // 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); + 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; + // 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 (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; + 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; + } + 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; + 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; + 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 { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; + // @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; } - } - 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]); + // 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])); + // 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; } - // 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 - } + // More components ? + more = flags & (1 << 5); + } + } else { + // numberOfCounters == 0, do nothing + } - *pvertices = vertices; - return num_vertices; + *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; +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_vertex *pvertices; + int num_vertices; } stbtt__csctx; -#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0} +#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__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_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_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_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_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 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__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; +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)); + 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; +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; + // 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 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 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; + 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. + // 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 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 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 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 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 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]); + case 0x1A: // vvcurveto + case 0x1B: // hhcurveto + if (sp < 4) + return STBTT__CSERR("(vv|hh)curveto stack"); f = 0.0; - } - break; + 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 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 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 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 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 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 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; + 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: + return STBTT__CSERR("unimplemented"); + } + } break; - default: - if (b0 != 255 && b0 != 28 && b0 < 32) - return STBTT__CSERR("reserved operator"); + 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"); + // 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__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; +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 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 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; +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; + // 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); + 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; +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; + // 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; + 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)); - } + 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; + 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; +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; + // 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; + 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); +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) { + // 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; + m = (l + r) >> 1; glyphID = ttUSHORT(glyphArray + 2 * m); - straw = glyphID; + straw = glyphID; if (needle < straw) - r = m - 1; + r = m - 1; else if (needle > straw) - l = m + 1; + l = m + 1; else { - return m; + return m; } - } - break; - } + } + break; + } - case 2: { - stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2); - stbtt_uint8 *rangeArray = coverageTable + 4; + 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) { + // 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; + m = (l + r) >> 1; rangeRecord = rangeArray + 6 * m; - strawStart = ttUSHORT(rangeRecord); - strawEnd = ttUSHORT(rangeRecord + 2); + strawStart = ttUSHORT(rangeRecord); + strawEnd = ttUSHORT(rangeRecord + 2); if (needle < strawStart) - r = m - 1; + r = m - 1; else if (needle > strawEnd) - l = m + 1; + l = m + 1; else { - stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); - return startCoverageIndex + glyph - strawStart; + stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4); + return startCoverageIndex + glyph - strawStart; } - } - break; - } + } + break; + } - default: return -1; // unsupported - } + default: + return -1; // unsupported + } - return -1; + 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; +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) + if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount) return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID)); - break; - } + break; + } - case 2: { - stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2); - stbtt_uint8 *classRangeRecords = classDefTable + 4; + 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) { + // 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; + m = (l + r) >> 1; classRangeRecord = classRangeRecords + 6 * m; - strawStart = ttUSHORT(classRangeRecord); - strawEnd = ttUSHORT(classRangeRecord + 2); + strawStart = ttUSHORT(classRangeRecord); + strawEnd = ttUSHORT(classRangeRecord + 2); if (needle < strawStart) - r = m - 1; + r = m - 1; else if (needle > strawEnd) - l = m + 1; + l = m + 1; else - return (stbtt_int32)ttUSHORT(classRangeRecord + 4); - } - break; - } + return (stbtt_int32)ttUSHORT(classRangeRecord + 4); + } + break; + } - default: - return -1; // Unsupported definition type, return an error. - } + default: + return -1; // Unsupported definition type, return an error. + } - // "All glyphs not assigned to a class fall into class 0". (OpenType spec) - return 0; + // "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; +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; + if (!info->gpos) + return 0; - data = info->data + info->gpos; + 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 + 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); + lookupListOffset = ttUSHORT(data + 8); + lookupList = data + lookupListOffset; + lookupCount = ttUSHORT(lookupList); - for (i=0; i<lookupCount; ++i) { - stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); - stbtt_uint8 *lookupTable = lookupList + lookupOffset; + for (i = 0; i < lookupCount; ++i) { + stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i); + stbtt_uint8 *lookupTable = lookupList + lookupOffset; - stbtt_uint16 lookupType = ttUSHORT(lookupTable); - stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); - stbtt_uint8 *subTableOffsets = lookupTable + 6; - if (lookupType != 2) // Pair Adjustment Positioning Subtable - continue; + stbtt_uint16 lookupType = ttUSHORT(lookupTable); + stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4); + stbtt_uint8 *subTableOffsets = lookupTable + 6; + if (lookupType != 2) // Pair Adjustment Positioning Subtable + continue; - for (sti=0; sti<subTableCount; sti++) { - stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); - stbtt_uint8 *table = lookupTable + subtableOffset; - stbtt_uint16 posFormat = ttUSHORT(table); - stbtt_uint16 coverageOffset = ttUSHORT(table + 2); - stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); - if (coverageIndex == -1) continue; + for (sti = 0; sti < subTableCount; sti++) { + stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti); + stbtt_uint8 *table = lookupTable + subtableOffset; + stbtt_uint16 posFormat = ttUSHORT(table); + stbtt_uint16 coverageOffset = ttUSHORT(table + 2); + stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1); + if (coverageIndex == -1) + continue; - switch (posFormat) { + switch (posFormat) { case 1: { - stbtt_int32 l, r, m; - int straw, needle; - stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); - stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); - if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? - stbtt_int32 valueRecordPairSizeInBytes = 2; - stbtt_uint16 pairSetCount = ttUSHORT(table + 8); - stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); - stbtt_uint8 *pairValueTable = table + pairPosOffset; - stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); - stbtt_uint8 *pairValueArray = pairValueTable + 2; + stbtt_int32 l, r, m; + int straw, needle; + stbtt_uint16 valueFormat1 = ttUSHORT(table + 4); + stbtt_uint16 valueFormat2 = ttUSHORT(table + 6); + if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats? + stbtt_int32 valueRecordPairSizeInBytes = 2; + stbtt_uint16 pairSetCount = ttUSHORT(table + 8); + stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex); + stbtt_uint8 *pairValueTable = table + pairPosOffset; + stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable); + stbtt_uint8 *pairValueArray = pairValueTable + 2; - if (coverageIndex >= pairSetCount) return 0; + if (coverageIndex >= pairSetCount) + return 0; - needle=glyph2; - r=pairValueCount-1; - l=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; + // 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 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; + 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 + 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; + 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; // Unsupported position format + } + } + } - return 0; + return 0; } -STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2) -{ - int xAdvance = 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); + if (info->gpos) + xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2); + else if (info->kern) + xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2); - return xAdvance; + 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 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_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 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 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 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_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 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 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); +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; + int numEntries = ttUSHORT(svg_doc_list); + stbtt_uint8 *svg_docs = svg_doc_list + 2; - for(i=0; i<numEntries; i++) { - stbtt_uint8 *svg_doc = svg_docs + (12 * i); - if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2))) - return svg_doc; - } - return 0; + for (i = 0; i < numEntries; i++) { + stbtt_uint8 *svg_doc = svg_docs + (12 * i); + if ((gl >= 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; +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; + 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; - } + 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); +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); } ////////////////////////////////////////////////////////////////////////////// @@ -2718,158 +2800,165 @@ STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_code // 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_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_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_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); +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; +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; +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_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_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; - } +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; + 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 +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) +#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; +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); + // 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->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; + 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; +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" @@ -2879,929 +2968,957 @@ static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, i // 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; +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; + 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 (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 + 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; - } + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = scanline[i] + (stbtt_uint8)max_weight; + } + } } - } - } + } - e = e->next; - } + 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; +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; + 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; + 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; + 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 + // 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; + // 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; + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) + break; } - 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; - } - } + // 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; } - ++e; - } - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); + // 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; - } + ++y; + } + STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); + ++j; + } - stbtt__hheap_cleanup(&hh, userdata); + stbtt__hheap_cleanup(&hh, userdata); - if (scanline != scanline_data) - STBTT_free(scanline, 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; - } +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) + 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 - } + 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__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__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 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; +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 + while (e) { + // brute force every pixel - // compute intersection points with top & bottom - STBTT_assert(e->ey >= y_top); + // 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); + 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); + } 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; - } + // 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 (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); + 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); + 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); + // 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 + // 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; + // 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; + sign = e->direction; - // area of the rectangle covered from sy0..y_crossing - area = sign * (y_crossing-sy0); + // 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); + // 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 - } + // 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. + // 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 + 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); + 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); + // 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. + // 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; + // 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; + // 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); - } + 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; - } + } + 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; +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); + STBTT__NOTUSED(vsubsample); - if (result->w > 64) - scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata); - else - scanline = scanline_data; + if (result->w > 64) + scanline = (float *)STBTT_malloc((result->w * 2 + 1) * sizeof(float), userdata); + else + scanline = scanline_data; - scanline2 = scanline + result->w; + scanline2 = scanline + result->w; - y = off_y; - e[n].y0 = (float) (off_y + result->h) + 1; + 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; + 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])); + 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 - } - } + // 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; + // 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; - } + ++e; + } - // now process all active edges - if (active) - stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top); + // 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 - } + { + 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; - } + ++y; + ++j; + } - stbtt__hheap_cleanup(&hh, userdata); + stbtt__hheap_cleanup(&hh, userdata); - if (scanline != scanline_data) - STBTT_free(scanline, 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) +#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_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; +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 && mid<n: 0>n => n; 0<n => 0 */ - /* 0<mid && mid>n: 0>n => 0; 0<n => 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; + /* 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 && mid<n: 0>n => n; 0<n => 0 */ + /* 0<mid && mid>n: 0>n => 0; 0<n => 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; + /* 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; - } - } + ++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); +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; +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; +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; + int vsubsample = result->h < 8 ? 15 : 5; #elif STBTT_RASTERIZER_VERSION == 2 - int vsubsample = 1; + int vsubsample = 1; #else - #error "Unrecognized value of STBTT_RASTERIZER_VERSION" +#error "Unrecognized value of STBTT_RASTERIZER_VERSION" #endif - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity + // 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]; + // 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; + 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; - } - } + 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 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); + // 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); + 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; +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 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; +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 (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; + 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 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; + 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; - } + 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; +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; + 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; + // 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; + *num_contours = n; + if (n == 0) + return 0; - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); + *contour_lengths = (int *)STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } + 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) { + // 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; + // 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; + 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; + 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; + 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; - } + 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; + return points; error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; + 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_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 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); +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; - } + 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); + 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 + // 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 (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; + 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_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 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_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; + 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); + 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_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 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 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_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 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 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); +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); } ////////////////////////////////////////////////////////////////////////////// @@ -3810,71 +3927,70 @@ STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned ch // // 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; +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); + 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; + 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); +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->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; + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; - *xpos += b->xadvance; + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -3897,53 +4013,48 @@ typedef int stbrp_coord; // // //////////////////////////////////////////////////////////////////////////////////// -typedef struct -{ - int width,height; - int x,y,bottom_y; +typedef struct { + int width, height; + int x, y, bottom_y; } stbrp_context; -typedef struct -{ - unsigned char x; +typedef struct { + unsigned char x; } stbrp_node; -struct stbrp_rect -{ - stbrp_coord x,y; - int id,w,h,was_packed; +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_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; +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 @@ -3954,437 +4065,415 @@ static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rect // 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); +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; - } + 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; + 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); + stbrp_init_target(context, pw - padding, ph - padding, nodes, num_nodes); - if (pixels) - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels + if (pixels) + STBTT_memset(pixels, 0, pw * ph); // background of 0 around pixels - return 1; + 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_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_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; -} +STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip) { spc->skip_missing = skip; } -#define STBTT__OVER_MASK (STBTT_MAX_OVERSAMPLE-1) +#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); +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; + 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); + // 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); + 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); + 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); + 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); + 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); - } + 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; - } + 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); +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; + 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); + // 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); + 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); + 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); + 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); + 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); - } + 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; - } + pixels += 1; + } } -static float stbtt__oversample_shift(int oversample) -{ - if (!oversample) - return 0.0f; +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); + // 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; +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; - } - } + 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; + 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); +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_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); + 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); + *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; +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; + // 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; + 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); + // 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->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); + 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; + 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 - } + 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; - } - } + ++k; + } + } - // restore original values - spc->h_oversample = old_h_over; - spc->v_oversample = old_v_over; + // restore original values + spc->h_oversample = old_h_over; + spc->v_oversample = old_v_over; - return return_value; + 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 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; +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; + // 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; + 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; + 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)); + info.userdata = spc->user_allocator_context; + stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, font_index)); - n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); + n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects); - stbtt_PackFontRangesPackRects(spc, rects, n); + stbtt_PackFontRangesPackRects(spc, rects, n); - return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); + return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects); - STBTT_free(rects, spc->user_allocator_context); - return return_value; + 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 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_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; +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; - } + 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; + q->s0 = b->x0 * ipw; + q->t0 = b->y0 * iph; + q->s1 = b->x1 * ipw; + q->t1 = b->y1 * iph; - *xpos += b->xadvance; + *xpos += b->xadvance; } ////////////////////////////////////////////////////////////////////////////// @@ -4392,380 +4481,385 @@ STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int // sdf computation // -#define STBTT_min(a,b) ((a) < (b) ? (a) : (b)) -#define STBTT_max(a,b) ((a) < (b) ? (b) : (a)) +#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]; +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 a = q0perp - 2 * q1perp + q2perp; + float b = q1perp - q0perp; + float c = q0perp - roperp; - float s0 = 0., s1 = 0.; - int num_s = 0; + 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) + 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 (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; + 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 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; + 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; + 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; - } - } + 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 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; +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; + // 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; + 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); + // 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; } - } - } - } - return winding; + } + 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); +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); +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_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; +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; + if (scale == 0) + return NULL; - stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1); + 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; + // if empty, return NULL + if (ix0 == ix1 || iy0 == iy1) + return NULL; - ix0 -= padding; - iy0 -= padding; - ix1 += padding; - iy1 += padding; + ix0 -= padding; + iy0 -= padding; + ix1 += padding; + iy1 += padding; - w = (ix1 - ix0); - h = (iy1 - iy0); + w = (ix1 - ix0); + h = (iy1 - iy0); - if (width ) *width = w; - if (height) *height = h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = 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; + // 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); + { + 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 (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); + 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 + 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; + 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; + 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); + 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 - } + // 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 { - 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); + } 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 (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; } - 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_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 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); -} +STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) { STBTT_free(bitmap, userdata); } ////////////////////////////////////////////////////////////////////////////// // @@ -4773,158 +4867,185 @@ STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata) // // 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; +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; + // 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); +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; +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; + 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); +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); + 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); + // 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; - } + // 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; + // @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; +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; - } + // 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; + 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; - } + 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; + 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; - } +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__) @@ -4932,36 +5053,30 @@ static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char #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_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_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_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_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_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); +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__) @@ -4970,7 +5085,6 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const #endif // STB_TRUETYPE_IMPLEMENTATION - // FULL VERSION HISTORY // // 1.25 (2021-07-11) many fixes diff --git a/src/vectors.h b/src/vectors.h index 090dfab..88800c6 100644 --- a/src/vectors.h +++ b/src/vectors.h @@ -25,192 +25,143 @@ #include "vkvg_internal.h" typedef struct { - float x; - float y; -}vec2; + float x; + float y; +} vec2; -static const vec2 vec2_unit_x = {1.f,0}; -static const vec2 vec2_unit_y = {0,1.f}; +static const vec2 vec2_unit_x = {1.f, 0}; +static const vec2 vec2_unit_y = {0, 1.f}; typedef struct { - double x; - double y; -}vec2d; + double x; + double y; +} vec2d; /*const vec2d vec2d_unit_x = {1.0,0}; const vec2d vec2d_unit_y = {0,1.0};*/ typedef struct { - float x; - float y; - float z; -}vec3; + float x; + float y; + float z; +} vec3; typedef struct { - union { - float x; - float r; - float xMin; - }; - union { - float y; - float g; - float yMin; - }; - union { - float z; - float width; - float b; - float xMax; - }; - union { - float w; - float height; - float a; - float yMax; - }; + union { + float x; + float r; + float xMin; + }; + union { + float y; + float g; + float yMin; + }; + union { + float z; + float width; + float b; + float xMax; + }; + union { + float w; + float height; + float a; + float yMax; + }; -}vec4; +} vec4; typedef struct { - uint16_t x; - uint16_t y; - uint16_t z; - uint16_t w; -}vec4i16; + uint16_t x; + uint16_t y; + uint16_t z; + uint16_t w; +} vec4i16; typedef struct { - int16_t x; - int16_t y; -}vec2i16; + int16_t x; + int16_t y; +} vec2i16; typedef struct { - vec2 row0; - vec2 row1; -}mat2; + vec2 row0; + vec2 row1; +} mat2; // compute length of float vector 2d -vkvg_inline float vec2_length(vec2 v){ - return sqrtf (v.x*v.x + v.y*v.y); -} +vkvg_inline float vec2_length(vec2 v) { return sqrtf(v.x * v.x + v.y * v.y); } // compute normal direction vector from line defined by 2 points in double precision -vkvg_inline vec2d vec2d_line_norm(vec2d a, vec2d b) -{ - vec2d d = {b.x - a.x, b.y - a.y}; - double md = sqrt (d.x*d.x + d.y*d.y); - d.x/=md; - d.y/=md; - return d; +vkvg_inline vec2d vec2d_line_norm(vec2d a, vec2d b) { + vec2d d = {b.x - a.x, b.y - a.y}; + double md = sqrt(d.x * d.x + d.y * d.y); + d.x /= md; + d.y /= md; + return d; } // compute normal direction vector from line defined by 2 points -vkvg_inline vec2 vec2_line_norm(vec2 a, vec2 b) -{ - vec2 d = {b.x - a.x, b.y - a.y}; - float md = sqrtf (d.x*d.x + d.y*d.y); - d.x/=md; - d.y/=md; - return d; +vkvg_inline vec2 vec2_line_norm(vec2 a, vec2 b) { + vec2 d = {b.x - a.x, b.y - a.y}; + float md = sqrtf(d.x * d.x + d.y * d.y); + d.x /= md; + d.y /= md; + return d; } // compute sum of two double precision vectors -vkvg_inline vec2d vec2d_add (vec2d a, vec2d b){ - return (vec2d){a.x + b.x, a.y + b.y}; -} +vkvg_inline vec2d vec2d_add(vec2d a, vec2d b) { return (vec2d){a.x + b.x, a.y + b.y}; } // compute subbstraction of two double precision vectors -vkvg_inline vec2d vec2d_sub (vec2d a, vec2d b){ - return (vec2d){a.x - b.x, a.y - b.y}; -} +vkvg_inline vec2d vec2d_sub(vec2d a, vec2d b) { return (vec2d){a.x - b.x, a.y - b.y}; } // multiply 2d vector by scalar -vkvg_inline vec2d vec2d_mult_s(vec2d a, double m){ - return (vec2d){a.x*m,a.y*m}; -} -vkvg_inline vec2d vec2d_div_s(vec2d a, double m){ - return (vec2d){a.x/m,a.y/m}; -} +vkvg_inline vec2d vec2d_mult_s(vec2d a, double m) { return (vec2d){a.x * m, a.y * m}; } +vkvg_inline vec2d vec2d_div_s(vec2d a, double m) { return (vec2d){a.x / m, a.y / m}; } // compute length of double vector 2d -vkvg_inline double vec2d_length(vec2d v){ - return sqrt (v.x*v.x + v.y*v.y); -} +vkvg_inline double vec2d_length(vec2d v) { return sqrt(v.x * v.x + v.y * v.y); } // normalize double vector -vkvg_inline vec2d vec2d_norm(vec2d a) -{ - double m = sqrt (a.x*a.x + a.y*a.y); - return (vec2d){a.x/m, a.y/m}; +vkvg_inline vec2d vec2d_norm(vec2d a) { + double m = sqrt(a.x * a.x + a.y * a.y); + return (vec2d){a.x / m, a.y / m}; } // compute perpendicular vector -vkvg_inline vec2d vec2d_perp (vec2d a){ - return (vec2d){a.y, -a.x}; -} -vkvg_inline bool vec2d_isnan (vec2d v){ - return (bool)(isnan (v.x) || isnan (v.y)); -} - +vkvg_inline vec2d vec2d_perp(vec2d a) { return (vec2d){a.y, -a.x}; } +vkvg_inline bool vec2d_isnan(vec2d v) { return (bool)(isnan(v.x) || isnan(v.y)); } // test equality of two single precision vectors -vkvg_inline bool vec2_equ (vec2 a, vec2 b){ - return (EQUF(a.x,b.x)&EQUF(a.y,b.y)); -} +vkvg_inline bool vec2_equ(vec2 a, vec2 b) { return (EQUF(a.x, b.x) & EQUF(a.y, b.y)); } // compute sum of two single precision vectors -vkvg_inline vec2 vec2_add (vec2 a, vec2 b){ - return (vec2){a.x + b.x, a.y + b.y}; -} +vkvg_inline vec2 vec2_add(vec2 a, vec2 b) { return (vec2){a.x + b.x, a.y + b.y}; } // compute subbstraction of two single precision vectors -vkvg_inline vec2 vec2_sub (vec2 a, vec2 b){ - return (vec2){a.x - b.x, a.y - b.y}; -} +vkvg_inline vec2 vec2_sub(vec2 a, vec2 b) { return (vec2){a.x - b.x, a.y - b.y}; } // multiply 2d vector by scalar -vkvg_inline vec2 vec2_mult_s(vec2 a, float m){ - return (vec2){a.x*m,a.y*m}; -} +vkvg_inline vec2 vec2_mult_s(vec2 a, float m) { return (vec2){a.x * m, a.y * m}; } // devide 2d vector by scalar -vkvg_inline vec2 vec2_div_s(vec2 a, float m){ - return (vec2){a.x/m,a.y/m}; -} +vkvg_inline vec2 vec2_div_s(vec2 a, float m) { return (vec2){a.x / m, a.y / m}; } // normalize float vector -vkvg_inline vec2 vec2_norm(vec2 a) -{ - float m = sqrtf (a.x*a.x + a.y*a.y); - return (vec2){a.x/m, a.y/m}; +vkvg_inline vec2 vec2_norm(vec2 a) { + float m = sqrtf(a.x * a.x + a.y * a.y); + return (vec2){a.x / m, a.y / m}; } // compute perpendicular vector -vkvg_inline vec2 vec2_perp (vec2 a){ - return (vec2){a.y, -a.x}; -} +vkvg_inline vec2 vec2_perp(vec2 a) { return (vec2){a.y, -a.x}; } // compute opposite of single precision vector -vkvg_inline void vec2_inv (vec2* v){ - v->x = -v->x; - v->y = -v->y; +vkvg_inline void vec2_inv(vec2 *v) { + v->x = -v->x; + v->y = -v->y; } // test if one component of float vector is nan -vkvg_inline bool vec2_isnan (vec2 v){ - return (bool)(isnan (v.x) || isnan (v.y)); -} +vkvg_inline bool vec2_isnan(vec2 v) { return (bool)(isnan(v.x) || isnan(v.y)); } // test if one component of double vector is nan -vkvg_inline float vec2_dot (vec2 a, vec2 b) { - return (a.x * b.x) + (a.y * b.y); -} -vkvg_inline float vec2_det (vec2 a, vec2 b) { - return a.x * b.y - a.y * b.x; -} -vkvg_inline float vec2_slope (vec2 a, vec2 b) { - return (b.y - a.y) / (b.x - a.x); -} - +vkvg_inline float vec2_dot(vec2 a, vec2 b) { return (a.x * b.x) + (a.y * b.y); } +vkvg_inline float vec2_det(vec2 a, vec2 b) { return a.x * b.y - a.y * b.x; } +vkvg_inline float vec2_slope(vec2 a, vec2 b) { return (b.y - a.y) / (b.x - a.x); } // convert double precision vector to single precision -vkvg_inline vec2 vec2d_to_vec2(vec2d vd){ - return (vec2){(float)vd.x,(float)vd.y}; -} -vkvg_inline bool vec4_equ (vec4 a, vec4 b){ - return (EQUF(a.x,b.x)&EQUF(a.y,b.y)&EQUF(a.z,b.z)&EQUF(a.w,b.w)); -} -vkvg_inline vec2 mat2_mult_vec2 (mat2 m, vec2 v) { - return (vec2){ - (m.row0.x * v.x) + (m.row0.y * v.y), - (m.row1.x * v.x) + (m.row1.y * v.y) - }; +vkvg_inline vec2 vec2d_to_vec2(vec2d vd) { return (vec2){(float)vd.x, (float)vd.y}; } +vkvg_inline bool vec4_equ(vec4 a, vec4 b) { + return (EQUF(a.x, b.x) & EQUF(a.y, b.y) & EQUF(a.z, b.z) & EQUF(a.w, b.w)); } -vkvg_inline float mat2_det (mat2* m) { - return (m->row0.x * m->row1.y) - (m->row0.y * m->row1.y); +vkvg_inline vec2 mat2_mult_vec2(mat2 m, vec2 v) { + return (vec2){(m.row0.x * v.x) + (m.row0.y * v.y), (m.row1.x * v.x) + (m.row1.y * v.y)}; } +vkvg_inline float mat2_det(mat2 *m) { return (m->row0.x * m->row1.y) - (m->row0.y * m->row1.y); } #endif diff --git a/src/vkvg_context.c b/src/vkvg_context.c index cfbabe8..877afb8 100644 --- a/src/vkvg_context.c +++ b/src/vkvg_context.c @@ -9,1681 +9,1674 @@ #include "vkh_queue.h" #ifdef DEBUG - static vec2 debugLinePoints[1000]; - static uint32_t dlpCount = 0; - #if defined (VKVG_DBG_UTILS) - const float DBG_LAB_COLOR_SAV[4] = {1,0,1,1}; - const float DBG_LAB_COLOR_CLIP[4] = {0,1,1,1}; - #endif +static vec2 debugLinePoints[1000]; +static uint32_t dlpCount = 0; +#if defined(VKVG_DBG_UTILS) +const float DBG_LAB_COLOR_SAV[4] = {1, 0, 1, 1}; +const float DBG_LAB_COLOR_CLIP[4] = {0, 1, 1, 1}; +#endif #endif -//todo:this could be used to define a default background +// todo:this could be used to define a default background static VkClearValue clearValues[3] = { - { .color.float32 = {0,0,0,0} }, - { .depthStencil = {1.0f, 0} }, - { .color.float32 = {0,0,0,0} } -}; + {.color.float32 = {0, 0, 0, 0}}, {.depthStencil = {1.0f, 0}}, {.color.float32 = {0, 0, 0, 0}}}; -void _init_ctx (VkvgContext ctx) { - ctx->lineWidth = 1; - ctx->miterLimit = 10; - ctx->curOperator = VKVG_OPERATOR_OVER; - ctx->curFillRule = VKVG_FILL_RULE_NON_ZERO; - ctx->bounds = (VkRect2D) {{0,0},{ctx->pSurf->width,ctx->pSurf->height}}; - ctx->pushConsts = (push_constants) { - {.a = 1}, - {(float)ctx->pSurf->width,(float)ctx->pSurf->height}, - VKVG_PATTERN_TYPE_SOLID, - 1.0f, - VKVG_IDENTITY_MATRIX, - VKVG_IDENTITY_MATRIX - }; - ctx->clearRect = (VkClearRect) {{{0},{ctx->pSurf->width, ctx->pSurf->height}},0,1}; - ctx->renderPassBeginInfo.framebuffer = ctx->pSurf->fb; - ctx->renderPassBeginInfo.renderArea.extent.width = ctx->pSurf->width; - ctx->renderPassBeginInfo.renderArea.extent.height = ctx->pSurf->height; - ctx->renderPassBeginInfo.pClearValues = clearValues; +void _init_ctx(VkvgContext ctx) { + ctx->lineWidth = 1; + ctx->miterLimit = 10; + ctx->curOperator = VKVG_OPERATOR_OVER; + ctx->curFillRule = VKVG_FILL_RULE_NON_ZERO; + ctx->bounds = (VkRect2D){{0, 0}, {ctx->pSurf->width, ctx->pSurf->height}}; + ctx->pushConsts = (push_constants){{.a = 1}, + {(float)ctx->pSurf->width, (float)ctx->pSurf->height}, + VKVG_PATTERN_TYPE_SOLID, + 1.0f, + VKVG_IDENTITY_MATRIX, + VKVG_IDENTITY_MATRIX}; + ctx->clearRect = (VkClearRect){{{0}, {ctx->pSurf->width, ctx->pSurf->height}}, 0, 1}; + ctx->renderPassBeginInfo.framebuffer = ctx->pSurf->fb; + ctx->renderPassBeginInfo.renderArea.extent.width = ctx->pSurf->width; + ctx->renderPassBeginInfo.renderArea.extent.height = ctx->pSurf->height; + ctx->renderPassBeginInfo.pClearValues = clearValues; - LOCK_SURFACE (ctx->pSurf) + LOCK_SURFACE(ctx->pSurf) - if (ctx->pSurf->newSurf) - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; - else - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; - ctx->pSurf->newSurf = false; + if (ctx->pSurf->newSurf) + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; + else + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; + ctx->pSurf->newSurf = false; - UNLOCK_SURFACE (ctx->pSurf); + UNLOCK_SURFACE(ctx->pSurf); - vkvg_surface_reference (ctx->pSurf); + vkvg_surface_reference(ctx->pSurf); - if (ctx->dev->samples == VK_SAMPLE_COUNT_1_BIT) - ctx->renderPassBeginInfo.clearValueCount = 2; - else - ctx->renderPassBeginInfo.clearValueCount = 3; + if (ctx->dev->samples == VK_SAMPLE_COUNT_1_BIT) + ctx->renderPassBeginInfo.clearValueCount = 2; + else + ctx->renderPassBeginInfo.clearValueCount = 3; - ctx->selectedCharSize = 10 << 6; - ctx->currentFont = NULL; - ctx->selectedFontName[0]= 0; - ctx->pattern = NULL; - ctx->curColor = 0xff000000;//opaque black - ctx->cmdStarted = false; - ctx->curClipState = vkvg_clip_state_none; - ctx->vertCount = ctx->indCount = 0; + ctx->selectedCharSize = 10 << 6; + ctx->currentFont = NULL; + ctx->selectedFontName[0] = 0; + ctx->pattern = NULL; + ctx->curColor = 0xff000000; // opaque black + ctx->cmdStarted = false; + ctx->curClipState = vkvg_clip_state_none; + ctx->vertCount = ctx->indCount = 0; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ctx->timelineStep = 0; + ctx->timelineStep = 0; #endif } -VkvgContext vkvg_create(VkvgSurface surf) -{ - VkvgDevice dev = surf->dev; - VkvgContext ctx = NULL; +VkvgContext vkvg_create(VkvgSurface surf) { + VkvgDevice dev = surf->dev; + VkvgContext ctx = NULL; - if (_device_try_get_cached_context (dev, &ctx) ) { - ctx->pSurf = surf; + if (_device_try_get_cached_context(dev, &ctx)) { + ctx->pSurf = surf; - if (!surf || surf->status) { - ctx->status = VKVG_STATUS_INVALID_SURFACE; - return ctx; - } + if (!surf || surf->status) { + ctx->status = VKVG_STATUS_INVALID_SURFACE; + return ctx; + } - _init_ctx (ctx); - _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); - _clear_path (ctx); - ctx->cmd = ctx->cmdBuffers[0];//current recording buffer - ctx->status = VKVG_STATUS_SUCCESS; - return ctx; - } - ctx = (vkvg_context*)calloc(1, sizeof(vkvg_context)); + _init_ctx(ctx); + _update_descriptor_set(ctx, surf->dev->emptyImg, ctx->dsSrc); + _clear_path(ctx); + ctx->cmd = ctx->cmdBuffers[0]; // current recording buffer + ctx->status = VKVG_STATUS_SUCCESS; + return ctx; + } + ctx = (vkvg_context *)calloc(1, sizeof(vkvg_context)); - LOG(VKVG_LOG_INFO, "CREATE Context: ctx = %p; surf = %p\n", ctx, surf); + LOG(VKVG_LOG_INFO, "CREATE Context: ctx = %p; surf = %p\n", ctx, surf); - if (!ctx) - return (VkvgContext)&_no_mem_status; + if (!ctx) + return (VkvgContext)&_no_mem_status; - ctx->pSurf = surf; + ctx->pSurf = surf; - if (!surf || surf->status) { - ctx->status = VKVG_STATUS_INVALID_SURFACE; - return ctx; - } + if (!surf || surf->status) { + ctx->status = VKVG_STATUS_INVALID_SURFACE; + return ctx; + } - ctx->sizePoints = VKVG_PTS_SIZE; - ctx->sizeVertices = ctx->sizeVBO = VKVG_VBO_SIZE; - ctx->sizeIndices = ctx->sizeIBO = VKVG_IBO_SIZE; - ctx->sizePathes = VKVG_PATHES_SIZE; - ctx->renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + ctx->sizePoints = VKVG_PTS_SIZE; + ctx->sizeVertices = ctx->sizeVBO = VKVG_VBO_SIZE; + ctx->sizeIndices = ctx->sizeIBO = VKVG_IBO_SIZE; + ctx->sizePathes = VKVG_PATHES_SIZE; + ctx->renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - ctx->dev = surf->dev; + ctx->dev = surf->dev; - _init_ctx (ctx); + _init_ctx(ctx); - ctx->points = (vec2*)malloc (VKVG_VBO_SIZE * sizeof(vec2)); - ctx->pathes = (uint32_t*)malloc (VKVG_PATHES_SIZE * sizeof(uint32_t)); - ctx->vertexCache = (Vertex*)malloc (ctx->sizeVertices * sizeof(Vertex)); - ctx->indexCache = (VKVG_IBO_INDEX_TYPE*)malloc (ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); + ctx->points = (vec2 *)malloc(VKVG_VBO_SIZE * sizeof(vec2)); + ctx->pathes = (uint32_t *)malloc(VKVG_PATHES_SIZE * sizeof(uint32_t)); + ctx->vertexCache = (Vertex *)malloc(ctx->sizeVertices * sizeof(Vertex)); + ctx->indexCache = (VKVG_IBO_INDEX_TYPE *)malloc(ctx->sizeIndices * sizeof(VKVG_IBO_INDEX_TYPE)); - if (!ctx->points || !ctx->pathes || !ctx->vertexCache || !ctx->indexCache) { - dev->status = VKVG_STATUS_NO_MEMORY; - if (ctx->points) - free(ctx->points); - if (ctx->pathes) - free(ctx->pathes); - if (ctx->vertexCache) - free(ctx->vertexCache); - if (ctx->indexCache) - free(ctx->indexCache); - return NULL; - } + if (!ctx->points || !ctx->pathes || !ctx->vertexCache || !ctx->indexCache) { + dev->status = VKVG_STATUS_NO_MEMORY; + if (ctx->points) + free(ctx->points); + if (ctx->pathes) + free(ctx->pathes); + if (ctx->vertexCache) + free(ctx->vertexCache); + if (ctx->indexCache) + free(ctx->indexCache); + return NULL; + } - //for context to be thread safe, command pool and descriptor pool have to be created in the thread of the context. - ctx->cmdPool = vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + // for context to be thread safe, command pool and descriptor pool have to be created in the thread of the context. + ctx->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ctx->flushFence = vkh_fence_create_signaled ((VkhDevice)ctx->dev); + ctx->flushFence = vkh_fence_create_signaled((VkhDevice)ctx->dev); #endif - _create_vertices_buff (ctx); - _create_gradient_buff (ctx); - _create_cmd_buff (ctx); - _createDescriptorPool (ctx); - _init_descriptor_sets (ctx); - _font_cache_update_context_descset (ctx); - _update_descriptor_set (ctx, surf->dev->emptyImg, ctx->dsSrc); - _update_gradient_desc_set(ctx); + _create_vertices_buff(ctx); + _create_gradient_buff(ctx); + _create_cmd_buff(ctx); + _createDescriptorPool(ctx); + _init_descriptor_sets(ctx); + _font_cache_update_context_descset(ctx); + _update_descriptor_set(ctx, surf->dev->emptyImg, ctx->dsSrc); + _update_gradient_desc_set(ctx); - _clear_path (ctx); + _clear_path(ctx); - ctx->cmd = ctx->cmdBuffers[0];//current recording buffer + ctx->cmd = ctx->cmdBuffers[0]; // current recording buffer - ctx->references = 1; - ctx->status = VKVG_STATUS_SUCCESS; + ctx->references = 1; + ctx->status = VKVG_STATUS_SUCCESS; - LOG(VKVG_LOG_DBG_ARRAYS, "INIT\tctx = %p; pathes:%ju pts:%ju vch:%d vbo:%d ich:%d ibo:%d\n", ctx, (uint64_t)ctx->sizePathes, (uint64_t)ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + LOG(VKVG_LOG_DBG_ARRAYS, "INIT\tctx = %p; pathes:%ju pts:%ju vch:%d vbo:%d ich:%d ibo:%d\n", ctx, + (uint64_t)ctx->sizePathes, (uint64_t)ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, + ctx->sizeIBO); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)ctx->cmdPool, "CTX Cmd Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[0], "CTX Cmd Buff A"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[1], "CTX Cmd Buff B"); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)ctx->cmdPool, "CTX Cmd Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[0], + "CTX Cmd Buff A"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)ctx->cmdBuffers[1], + "CTX Cmd Buff B"); #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->flushFence, "CTX Flush Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)ctx->flushFence, "CTX Flush Fence"); #endif - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, "CTX Descriptor Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, "CTX DescSet SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, "CTX DescSet FONT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsGrad, "CTX DescSet GRADIENT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_POOL, (uint64_t)ctx->descriptorPool, + "CTX Descriptor Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsSrc, + "CTX DescSet SOURCE"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsFont, + "CTX DescSet FONT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET, (uint64_t)ctx->dsGrad, + "CTX DescSet GRADIENT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->indices.buffer, "CTX Index Buff"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->vertices.buffer, "CTX Vertex Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->indices.buffer, "CTX Index Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_BUFFER, (uint64_t)ctx->vertices.buffer, + "CTX Vertex Buff"); #endif - return ctx; + return ctx; } -void vkvg_flush (VkvgContext ctx){ - if (ctx->status) - return; - _flush_cmd_buff (ctx); - _wait_ctx_flush_end (ctx); -/* -#ifdef DEBUG +void vkvg_flush(VkvgContext ctx) { + if (ctx->status) + return; + _flush_cmd_buff(ctx); + _wait_ctx_flush_end(ctx); + /* + #ifdef DEBUG - vec4 red = {0,0,1,1}; - vec4 green = {0,1,0,1}; - vec4 white = {1,1,1,1}; + vec4 red = {0,0,1,1}; + vec4 green = {0,1,0,1}; + vec4 white = {1,1,1,1}; - int j = 0; - while (j < dlpCount) { - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],green); - j+=2; - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],red); - j+=2; - add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],white); - j+=2; - } - dlpCount = 0; - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); - CmdDrawIndexed(ctx->cmd, ctx->indCount-ctx->curIndStart, 1, ctx->curIndStart, 0, 1); - _flush_cmd_buff(ctx); -#endif -*/ + int j = 0; + while (j < dlpCount) { + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],green); + j+=2; + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],red); + j+=2; + add_line(ctx, debugLinePoints[j], debugLinePoints[j+1],white); + j+=2; + } + dlpCount = 0; + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); + CmdDrawIndexed(ctx->cmd, ctx->indCount-ctx->curIndStart, 1, ctx->curIndStart, 0, 1); + _flush_cmd_buff(ctx); + #endif + */ } -void _clear_context (VkvgContext ctx) { - //free saved context stack elmt - vkvg_context_save_t* next = ctx->pSavedCtxs; - ctx->pSavedCtxs = NULL; - while (next != NULL) { - vkvg_context_save_t* cur = next; - next = cur->pNext; - _free_ctx_save (cur); - } - //free additional stencil use in save/restore process - if (ctx->savedStencils) { - uint8_t curSaveStencil = ctx->curSavBit / 6; - for (int i=curSaveStencil;i>0;i--) - vkh_image_destroy(ctx->savedStencils[i-1]); - free(ctx->savedStencils); - ctx->savedStencils = NULL; - ctx->curSavBit = 0; - } +void _clear_context(VkvgContext ctx) { + // free saved context stack elmt + vkvg_context_save_t *next = ctx->pSavedCtxs; + ctx->pSavedCtxs = NULL; + while (next != NULL) { + vkvg_context_save_t *cur = next; + next = cur->pNext; + _free_ctx_save(cur); + } + // free additional stencil use in save/restore process + if (ctx->savedStencils) { + uint8_t curSaveStencil = ctx->curSavBit / 6; + for (int i = curSaveStencil; i > 0; i--) + vkh_image_destroy(ctx->savedStencils[i - 1]); + free(ctx->savedStencils); + ctx->savedStencils = NULL; + ctx->curSavBit = 0; + } - //remove context from double linked list of context in device - /*if (ctx->dev->lastCtx == ctx){ - ctx->dev->lastCtx = ctx->pPrev; - if (ctx->pPrev != NULL) - ctx->pPrev->pNext = NULL; - }else if (ctx->pPrev == NULL){ - //first elmt, and it's not last one so pnext is not null - ctx->pNext->pPrev = NULL; - }else{ - ctx->pPrev->pNext = ctx->pNext; - ctx->pNext->pPrev = ctx->pPrev; - }*/ - if (ctx->dashCount > 0) { - free(ctx->dashes); - ctx->dashCount = 0; - } + // remove context from double linked list of context in device + /*if (ctx->dev->lastCtx == ctx){ + ctx->dev->lastCtx = ctx->pPrev; + if (ctx->pPrev != NULL) + ctx->pPrev->pNext = NULL; + }else if (ctx->pPrev == NULL){ + //first elmt, and it's not last one so pnext is not null + ctx->pNext->pPrev = NULL; + }else{ + ctx->pPrev->pNext = ctx->pNext; + ctx->pNext->pPrev = ctx->pPrev; + }*/ + if (ctx->dashCount > 0) { + free(ctx->dashes); + ctx->dashCount = 0; + } } -void vkvg_destroy (VkvgContext ctx) -{ - if (ctx->status) - return; +void vkvg_destroy(VkvgContext ctx) { + if (ctx->status) + return; - ctx->references--; - if (ctx->references > 0) - return; + ctx->references--; + if (ctx->references > 0) + return; - LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p (status:%d); surf = %p\n", ctx, ctx->status, ctx->pSurf); + LOG(VKVG_LOG_INFO, "DESTROY Context: ctx = %p (status:%d); surf = %p\n", ctx, ctx->status, ctx->pSurf); - vkvg_flush (ctx); + vkvg_flush(ctx); - LOG(VKVG_LOG_DBG_ARRAYS, "END\tctx = %p; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); + LOG(VKVG_LOG_DBG_ARRAYS, "END\tctx = %p; pathes:%d pts:%d vch:%d vbo:%d ich:%d ibo:%d\n", ctx, ctx->sizePathes, + ctx->sizePoints, ctx->sizeVertices, ctx->sizeVBO, ctx->sizeIndices, ctx->sizeIBO); #if VKVG_RECORDING - if (ctx->recording) - _destroy_recording(ctx->recording); + if (ctx->recording) + _destroy_recording(ctx->recording); #endif - if (ctx->pattern) - vkvg_pattern_destroy (ctx->pattern); + if (ctx->pattern) + vkvg_pattern_destroy(ctx->pattern); - _clear_context (ctx); + _clear_context(ctx); #if VKVG_DBG_STATS - if (ctx->dev->threadAware) - mtx_lock (&ctx->dev->mutex); - - vkvg_debug_stats_t* dbgstats = &ctx->dev->debug_stats; - if (dbgstats->sizePoints < ctx->sizePoints) - dbgstats->sizePoints = ctx->sizePoints; - if (dbgstats->sizePathes < ctx->sizePathes) - dbgstats->sizePathes = ctx->sizePathes; - if (dbgstats->sizeVertices < ctx->sizeVertices) - dbgstats->sizeVertices = ctx->sizeVertices; - if (dbgstats->sizeIndices < ctx->sizeIndices) - dbgstats->sizeIndices = ctx->sizeIndices; - if (dbgstats->sizeVBO < ctx->sizeVBO) - dbgstats->sizeVBO = ctx->sizeVBO; - if (dbgstats->sizeIBO < ctx->sizeIBO) - dbgstats->sizeIBO = ctx->sizeIBO; + if (ctx->dev->threadAware) + mtx_lock(&ctx->dev->mutex); - if (ctx->dev->threadAware) - mtx_unlock (&ctx->dev->mutex); + vkvg_debug_stats_t *dbgstats = &ctx->dev->debug_stats; + if (dbgstats->sizePoints < ctx->sizePoints) + dbgstats->sizePoints = ctx->sizePoints; + if (dbgstats->sizePathes < ctx->sizePathes) + dbgstats->sizePathes = ctx->sizePathes; + if (dbgstats->sizeVertices < ctx->sizeVertices) + dbgstats->sizeVertices = ctx->sizeVertices; + if (dbgstats->sizeIndices < ctx->sizeIndices) + dbgstats->sizeIndices = ctx->sizeIndices; + if (dbgstats->sizeVBO < ctx->sizeVBO) + dbgstats->sizeVBO = ctx->sizeVBO; + if (dbgstats->sizeIBO < ctx->sizeIBO) + dbgstats->sizeIBO = ctx->sizeIBO; + + if (ctx->dev->threadAware) + mtx_unlock(&ctx->dev->mutex); #endif - vkvg_surface_destroy(ctx->pSurf); + vkvg_surface_destroy(ctx->pSurf); - if (!ctx->status && ctx->dev->cachedContextCount < VKVG_MAX_CACHED_CONTEXT_COUNT) { - _device_store_context (ctx); - return; - } + if (!ctx->status && ctx->dev->cachedContextCount < VKVG_MAX_CACHED_CONTEXT_COUNT) { + _device_store_context(ctx); + return; + } - _release_context_ressources (ctx); + _release_context_ressources(ctx); } -void vkvg_set_opacity (VkvgContext ctx, float opacity) { - if (ctx->status) - return; +void vkvg_set_opacity(VkvgContext ctx, float opacity) { + if (ctx->status) + return; - if (EQUF(ctx->pushConsts.opacity, opacity)) - return; + if (EQUF(ctx->pushConsts.opacity, opacity)) + return; - _emit_draw_cmd_undrawn_vertices (ctx); - ctx->pushConsts.opacity = opacity; - ctx->pushCstDirty = true; -} -float vkvg_get_opacity (VkvgContext ctx) { - if (ctx->status) - return 0; - return ctx->pushConsts.opacity; + _emit_draw_cmd_undrawn_vertices(ctx); + ctx->pushConsts.opacity = opacity; + ctx->pushCstDirty = true; } -vkvg_status_t vkvg_status (VkvgContext ctx) { - return ctx->status; +float vkvg_get_opacity(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->pushConsts.opacity; } -VkvgContext vkvg_reference (VkvgContext ctx) { - if (!ctx->status) - ctx->references++; - return ctx; +vkvg_status_t vkvg_status(VkvgContext ctx) { return ctx->status; } +VkvgContext vkvg_reference(VkvgContext ctx) { + if (!ctx->status) + ctx->references++; + return ctx; } -uint32_t vkvg_get_reference_count (VkvgContext ctx) { - if (ctx->status) - return 0; - return ctx->references; +uint32_t vkvg_get_reference_count(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->references; } -void vkvg_new_sub_path (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_new_sub_path(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_NEW_SUB_PATH); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_sub_path:\n"); + RECORD(ctx, VKVG_CMD_NEW_SUB_PATH); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_sub_path:\n"); - _finish_path(ctx); + _finish_path(ctx); } -void vkvg_new_path (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_new_path(VkvgContext ctx) { + if (ctx->status) + return; - LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_path:\n"); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: new_path:\n"); - _clear_path(ctx); - RECORD(ctx, VKVG_CMD_NEW_PATH); + _clear_path(ctx); + RECORD(ctx, VKVG_CMD_NEW_PATH); } -void vkvg_close_path (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_close_path(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_CLOSE_PATH); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: close_path:\n"); + RECORD(ctx, VKVG_CMD_CLOSE_PATH); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: close_path:\n"); - if (ctx->pathes[ctx->pathPtr] & PATH_CLOSED_BIT) //already closed - return; - //check if at least 3 points are present - if (ctx->pathes[ctx->pathPtr] < 3) - return; + if (ctx->pathes[ctx->pathPtr] & PATH_CLOSED_BIT) // already closed + return; + // check if at least 3 points are present + if (ctx->pathes[ctx->pathPtr] < 3) + return; - //prevent closing on the same point - if (vec2_equ(ctx->points[ctx->pointCount-1], - ctx->points[ctx->pointCount - ctx->pathes[ctx->pathPtr]])) { - if (ctx->pathes[ctx->pathPtr] < 4)//ensure enough points left for closing - return; - _remove_last_point(ctx); - } + // prevent closing on the same point + if (vec2_equ(ctx->points[ctx->pointCount - 1], ctx->points[ctx->pointCount - ctx->pathes[ctx->pathPtr]])) { + if (ctx->pathes[ctx->pathPtr] < 4) // ensure enough points left for closing + return; + _remove_last_point(ctx); + } - ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; + ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; - _finish_path(ctx); + _finish_path(ctx); } -void vkvg_rel_line_to (VkvgContext ctx, float dx, float dy){ - if (ctx->status) - return; +void vkvg_rel_line_to(VkvgContext ctx, float dx, float dy) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_REL_LINE_TO, dx, dy); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_line_to: %f, %f\n", dx, dy); + RECORD(ctx, VKVG_CMD_REL_LINE_TO, dx, dy); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_line_to: %f, %f\n", dx, dy); - if (_current_path_is_empty(ctx)) - _add_point(ctx, 0, 0); - vec2 cp = _get_current_position(ctx); - _line_to(ctx, cp.x + dx, cp.y + dy); + if (_current_path_is_empty(ctx)) + _add_point(ctx, 0, 0); + vec2 cp = _get_current_position(ctx); + _line_to(ctx, cp.x + dx, cp.y + dy); } -void vkvg_line_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; +void vkvg_line_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_LINE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: line_to: %f, %f\n", x, y); - _line_to(ctx, x, y); + RECORD(ctx, VKVG_CMD_LINE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: line_to: %f, %f\n", x, y); + _line_to(ctx, x, y); } -void vkvg_arc (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2){ - if (ctx->status) - return; +void vkvg_arc(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_ARC, xc, yc, radius, a1, a2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); + RECORD(ctx, VKVG_CMD_ARC, xc, yc, radius, a1, a2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: arc: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); - while (a2 < a1)//positive arc must have a1<a2 - a2 += 2.f*M_PIF; + while (a2 < a1) // positive arc must have a1<a2 + a2 += 2.f * M_PIF; - if (a2 - a1 > 2.f * M_PIF) //limit arc to 2PI - a2 = a1 + 2.f * M_PIF; + if (a2 - a1 > 2.f * M_PIF) // limit arc to 2PI + a2 = a1 + 2.f * M_PIF; - vec2 v = {cosf(a1)*radius + xc, sinf(a1)*radius + yc}; + vec2 v = {cosf(a1) * radius + xc, sinf(a1) * radius + yc}; - float step = _get_arc_step(ctx, radius); - float a = a1; + float step = _get_arc_step(ctx, radius); + float a = a1; - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, v.x, v.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, v.x, v.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, v.x, v.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, v.x, v.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } - a+=step; + a += step; - if (EQUF(a2, a1)) - return; + if (EQUF(a2, a1)) + return; - while(a < a2){ - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - _add_point (ctx, v.x, v.y); - a+=step; - } + while (a < a2) { + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + _add_point(ctx, v.x, v.y); + a += step; + } - if (EQUF(a2-a1,M_PIF*2.f)){//if arc is complete circle, last point is the same as the first one - _set_curve_end(ctx); - vkvg_close_path(ctx); - return; - } - a = a2; - //vec2 lastP = v; - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - //if (!vec2_equ (v,lastP))//this test should not be required - _add_point (ctx, v.x, v.y); - _set_curve_end(ctx); + if (EQUF(a2 - a1, M_PIF * 2.f)) { // if arc is complete circle, last point is the same as the first one + _set_curve_end(ctx); + vkvg_close_path(ctx); + return; + } + a = a2; + // vec2 lastP = v; + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + // if (!vec2_equ (v,lastP))//this test should not be required + _add_point(ctx, v.x, v.y); + _set_curve_end(ctx); } -void vkvg_arc_negative (VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ARC_NEG, xc, yc, radius, a1, a2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); - while (a2 > a1) - a2 -= 2.f*M_PIF; - if (a1 - a2 > a1 + 2.f * M_PIF) //limit arc to 2PI - a2 = a1 - 2.f * M_PIF; +void vkvg_arc_negative(VkvgContext ctx, float xc, float yc, float radius, float a1, float a2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ARC_NEG, xc, yc, radius, a1, a2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: %f,%f %f %f %f\n", xc, yc, radius, a1, a2); + while (a2 > a1) + a2 -= 2.f * M_PIF; + if (a1 - a2 > a1 + 2.f * M_PIF) // limit arc to 2PI + a2 = a1 - 2.f * M_PIF; - vec2 v = {cosf(a1)*radius + xc, sinf(a1)*radius + yc}; + vec2 v = {cosf(a1) * radius + xc, sinf(a1) * radius + yc}; - float step = _get_arc_step(ctx, radius); - float a = a1; + float step = _get_arc_step(ctx, radius); + float a = a1; - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, v.x, v.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, v.x, v.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, v.x, v.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, v.x, v.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } - a-=step; + a -= step; - if (EQUF(a2, a1)) - return; + if (EQUF(a2, a1)) + return; - while(a > a2){ - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - _add_point (ctx,v.x,v.y); - a-=step; - } + while (a > a2) { + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + _add_point(ctx, v.x, v.y); + a -= step; + } - if (EQUF(a1-a2,M_PIF*2.f)){//if arc is complete circle, last point is the same as the first one - _set_curve_end(ctx); - vkvg_close_path(ctx); - return; - } + if (EQUF(a1 - a2, M_PIF * 2.f)) { // if arc is complete circle, last point is the same as the first one + _set_curve_end(ctx); + vkvg_close_path(ctx); + return; + } - a = a2; - //vec2 lastP = v; - v.x = cosf(a)*radius + xc; - v.y = sinf(a)*radius + yc; - //if (!vec2_equ (v,lastP)) - _add_point (ctx, v.x, v.y); - _set_curve_end(ctx); + a = a2; + // vec2 lastP = v; + v.x = cosf(a) * radius + xc; + v.y = sinf(a) * radius + yc; + // if (!vec2_equ (v,lastP)) + _add_point(ctx, v.x, v.y); + _set_curve_end(ctx); } -void vkvg_rel_move_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_MOVE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_mote_to: %f, %f\n", x, y); - if (_current_path_is_empty(ctx)) - _add_point(ctx, 0, 0); - vec2 cp = _get_current_position(ctx); - _finish_path(ctx); - _add_point (ctx, cp.x + x, cp.y + y); +void vkvg_rel_move_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_MOVE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_mote_to: %f, %f\n", x, y); + if (_current_path_is_empty(ctx)) + _add_point(ctx, 0, 0); + vec2 cp = _get_current_position(ctx); + _finish_path(ctx); + _add_point(ctx, cp.x + x, cp.y + y); } -void vkvg_move_to (VkvgContext ctx, float x, float y) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_MOVE_TO, x, y); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: move_to: %f,%f\n", x, y); - _finish_path(ctx); - _add_point (ctx, x, y); +void vkvg_move_to(VkvgContext ctx, float x, float y) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_MOVE_TO, x, y); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: move_to: %f,%f\n", x, y); + _finish_path(ctx); + _add_point(ctx, x, y); } -bool vkvg_has_current_point (VkvgContext ctx) { - if (ctx->status) - return false; - return !_current_path_is_empty(ctx); +bool vkvg_has_current_point(VkvgContext ctx) { + if (ctx->status) + return false; + return !_current_path_is_empty(ctx); } -void vkvg_get_current_point (VkvgContext ctx, float* x, float* y) { - if (ctx->status || _current_path_is_empty(ctx)) { - *x = *y = 0; - return; - } - vec2 cp = _get_current_position(ctx); - *x = cp.x; - *y = cp.y; +void vkvg_get_current_point(VkvgContext ctx, float *x, float *y) { + if (ctx->status || _current_path_is_empty(ctx)) { + *x = *y = 0; + return; + } + vec2 cp = _get_current_position(ctx); + *x = cp.x; + *y = cp.y; } -void _curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - //prevent running _recursive_bezier when all 4 curve points are equal - if (EQUF(x1,x2) && EQUF(x2,x3) && EQUF(y1,y2) && EQUF(y2,y3)) { - if (_current_path_is_empty(ctx) || (EQUF(_get_current_position(ctx).x,x1) && EQUF(_get_current_position(ctx).y,y1))) - return; - } - ctx->simpleConvex = false; - _set_curve_start (ctx); - if (_current_path_is_empty(ctx)) - _add_point(ctx, x1, y1); +void _curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + // prevent running _recursive_bezier when all 4 curve points are equal + if (EQUF(x1, x2) && EQUF(x2, x3) && EQUF(y1, y2) && EQUF(y2, y3)) { + if (_current_path_is_empty(ctx) || + (EQUF(_get_current_position(ctx).x, x1) && EQUF(_get_current_position(ctx).y, y1))) + return; + } + ctx->simpleConvex = false; + _set_curve_start(ctx); + if (_current_path_is_empty(ctx)) + _add_point(ctx, x1, y1); - vec2 cp = _get_current_position(ctx); + vec2 cp = _get_current_position(ctx); - //compute dyn distanceTolerance depending on current scale - float sx = 1, sy = 1; - vkvg_matrix_get_scale (&ctx->pushConsts.mat, &sx, &sy); - float distanceTolerance = fabs(0.25f / fmaxf(sx,sy)); + // compute dyn distanceTolerance depending on current scale + float sx = 1, sy = 1; + vkvg_matrix_get_scale(&ctx->pushConsts.mat, &sx, &sy); + float distanceTolerance = fabs(0.25f / fmaxf(sx, sy)); - _recursive_bezier (ctx, distanceTolerance, cp.x, cp.y, x1, y1, x2, y2, x3, y3, 0); - /*cp.x = x3; - cp.y = y3; - if (!vec2_equ(ctx->points[ctx->pointCount-1],cp))*/ - _add_point(ctx,x3,y3); - _set_curve_end (ctx); + _recursive_bezier(ctx, distanceTolerance, cp.x, cp.y, x1, y1, x2, y2, x3, y3, 0); + /*cp.x = x3; + cp.y = y3; + if (!vec2_equ(ctx->points[ctx->pointCount-1],cp))*/ + _add_point(ctx, x3, y3); + _set_curve_end(ctx); } -const double quadraticFact = 2.0/3.0; -void _quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - float x0, y0; - if (_current_path_is_empty(ctx)) { - x0 = x1; - y0 = y1; - } else - vkvg_get_current_point (ctx, &x0, &y0); - _curve_to (ctx, - x0 + (x1 - x0) * quadraticFact, - y0 + (y1 - y0) * quadraticFact, - x2 + (x1 - x2) * quadraticFact, - y2 + (y1 - y2) * quadraticFact, - x2, y2); +const double quadraticFact = 2.0 / 3.0; +void _quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + float x0, y0; + if (_current_path_is_empty(ctx)) { + x0 = x1; + y0 = y1; + } else + vkvg_get_current_point(ctx, &x0, &y0); + _curve_to(ctx, x0 + (x1 - x0) * quadraticFact, y0 + (y1 - y0) * quadraticFact, x2 + (x1 - x2) * quadraticFact, + y2 + (y1 - y2) * quadraticFact, x2, y2); } -void vkvg_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_QUADRATIC_TO, x1, y1, x2, y2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); - _quadratic_to(ctx, x1, y1, x2, y2); +void vkvg_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_QUADRATIC_TO, x1, y1, x2, y2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); + _quadratic_to(ctx, x1, y1, x2, y2); } -void vkvg_rel_quadratic_to (VkvgContext ctx, float x1, float y1, float x2, float y2) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_QUADRATIC_TO, x1, y1, x2, y2); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); - vec2 cp = _get_current_position(ctx); - _quadratic_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2); +void vkvg_rel_quadratic_to(VkvgContext ctx, float x1, float y1, float x2, float y2) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_QUADRATIC_TO, x1, y1, x2, y2); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_quadratic_to: %f, %f, %f, %f\n", x1, y1, x2, y2); + vec2 cp = _get_current_position(ctx); + _quadratic_to(ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2); } -void vkvg_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CURVE_TO, x1, y1, x2, y2, x3, y3); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); - _curve_to (ctx, x1, y1, x2, y2, x3, y3); +void vkvg_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CURVE_TO, x1, y1, x2, y2, x3, y3); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); + _curve_to(ctx, x1, y1, x2, y2, x3, y3); } -void vkvg_rel_curve_to (VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { - if (ctx->status) - return; - if (_current_path_is_empty(ctx)) { - ctx->status = VKVG_STATUS_NO_CURRENT_POINT; - return; - } - RECORD(ctx, (uint32_t)VKVG_CMD_REL_CURVE_TO, x1, y1, x2, y2, x3, y3); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); - vec2 cp = _get_current_position(ctx); - _curve_to (ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2, cp.x + x3, cp.y + y3); +void vkvg_rel_curve_to(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3) { + if (ctx->status) + return; + if (_current_path_is_empty(ctx)) { + ctx->status = VKVG_STATUS_NO_CURRENT_POINT; + return; + } + RECORD(ctx, (uint32_t)VKVG_CMD_REL_CURVE_TO, x1, y1, x2, y2, x3, y3); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel curve_to %f,%f %f,%f %f,%f:\n", x1, y1, x2, y2, x3, y3); + vec2 cp = _get_current_position(ctx); + _curve_to(ctx, cp.x + x1, cp.y + y1, cp.x + x2, cp.y + y2, cp.x + x3, cp.y + y3); } -void vkvg_fill_rectangle (VkvgContext ctx, float x, float y, float w, float h){ - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "\tCMD: fill_rectangle:\n"); - _vao_add_rectangle (ctx,x,y,w,h); - //_record_draw_cmd(ctx); +void vkvg_fill_rectangle(VkvgContext ctx, float x, float y, float w, float h) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "\tCMD: fill_rectangle:\n"); + _vao_add_rectangle(ctx, x, y, w, h); + //_record_draw_cmd(ctx); } -vkvg_status_t vkvg_rectangle (VkvgContext ctx, float x, float y, float w, float h){ - if (ctx->status) - return ctx->status; - RECORD2(ctx, VKVG_CMD_RECTANGLE, x, y, w, h); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rectangle: %f,%f,%f,%f\n", x, y, w, h); - _finish_path (ctx); +vkvg_status_t vkvg_rectangle(VkvgContext ctx, float x, float y, float w, float h) { + if (ctx->status) + return ctx->status; + RECORD2(ctx, VKVG_CMD_RECTANGLE, x, y, w, h); + LOG(VKVG_LOG_INFO_CMD, "\tCMD: rectangle: %f,%f,%f,%f\n", x, y, w, h); + _finish_path(ctx); - if (w <= 0 || h <= 0) - return VKVG_STATUS_INVALID_RECT; + if (w <= 0 || h <= 0) + return VKVG_STATUS_INVALID_RECT; - _add_point (ctx, x, y); - _add_point (ctx, x + w, y); - _add_point (ctx, x + w, y + h); - _add_point (ctx, x, y + h); + _add_point(ctx, x, y); + _add_point(ctx, x + w, y); + _add_point(ctx, x + w, y + h); + _add_point(ctx, x, y + h); - ctx->pathes[ctx->pathPtr] |= (PATH_CLOSED_BIT|PATH_IS_CONVEX_BIT); + ctx->pathes[ctx->pathPtr] |= (PATH_CLOSED_BIT | PATH_IS_CONVEX_BIT); - _finish_path(ctx); - return VKVG_STATUS_SUCCESS; + _finish_path(ctx); + return VKVG_STATUS_SUCCESS; } -vkvg_status_t vkvg_rounded_rectangle (VkvgContext ctx, float x, float y, float w, float h, float radius){ - if (ctx->status) - return ctx->status; - LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle:\n"); - _finish_path (ctx); +vkvg_status_t vkvg_rounded_rectangle(VkvgContext ctx, float x, float y, float w, float h, float radius) { + if (ctx->status) + return ctx->status; + LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle:\n"); + _finish_path(ctx); - if (w <= 0 || h <= 0) - return VKVG_STATUS_INVALID_RECT; + if (w <= 0 || h <= 0) + return VKVG_STATUS_INVALID_RECT; - if ((radius > w / 2.0f) || (radius > h / 2.0f)) - radius = fmin (w / 2.0f, h / 2.0f); + if ((radius > w / 2.0f) || (radius > h / 2.0f)) + radius = fmin(w / 2.0f, h / 2.0f); - vkvg_move_to(ctx, x, y + radius); - vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, -M_PIF_2); - vkvg_line_to(ctx, x + w - radius, y); - vkvg_arc(ctx, x + w - radius, y + radius, radius, -M_PIF_2, 0); - vkvg_line_to(ctx, x + w, y + h - radius); - vkvg_arc(ctx, x + w - radius, y + h - radius, radius, 0, M_PIF_2); - vkvg_line_to(ctx, x + radius, y + h); - vkvg_arc(ctx, x + radius, y + h - radius, radius, M_PIF_2, M_PIF); - vkvg_line_to(ctx, x, y + radius); - vkvg_close_path(ctx); + vkvg_move_to(ctx, x, y + radius); + vkvg_arc(ctx, x + radius, y + radius, radius, M_PIF, -M_PIF_2); + vkvg_line_to(ctx, x + w - radius, y); + vkvg_arc(ctx, x + w - radius, y + radius, radius, -M_PIF_2, 0); + vkvg_line_to(ctx, x + w, y + h - radius); + vkvg_arc(ctx, x + w - radius, y + h - radius, radius, 0, M_PIF_2); + vkvg_line_to(ctx, x + radius, y + h); + vkvg_arc(ctx, x + radius, y + h - radius, radius, M_PIF_2, M_PIF); + vkvg_line_to(ctx, x, y + radius); + vkvg_close_path(ctx); - return VKVG_STATUS_SUCCESS; + return VKVG_STATUS_SUCCESS; } -void vkvg_rounded_rectangle2 (VkvgContext ctx, float x, float y, float w, float h, float rx, float ry){ - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle2:\n"); - vkvg_move_to (ctx, x+rx, y); - vkvg_line_to (ctx, x+w-rx, y); - vkvg_elliptic_arc_to(ctx, x+w, y+ry, false, true, rx, ry, 0); +void vkvg_rounded_rectangle2(VkvgContext ctx, float x, float y, float w, float h, float rx, float ry) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "CMD: rounded_rectangle2:\n"); + vkvg_move_to(ctx, x + rx, y); + vkvg_line_to(ctx, x + w - rx, y); + vkvg_elliptic_arc_to(ctx, x + w, y + ry, false, true, rx, ry, 0); - vkvg_line_to (ctx, x+w, y+h-ry); - vkvg_elliptic_arc_to(ctx, x+w-rx, y+h, false, true, rx, ry, 0); + vkvg_line_to(ctx, x + w, y + h - ry); + vkvg_elliptic_arc_to(ctx, x + w - rx, y + h, false, true, rx, ry, 0); - vkvg_line_to (ctx, x+rx, y+h); - vkvg_elliptic_arc_to(ctx, x, y+h-ry , false, true, rx, ry, 0); + vkvg_line_to(ctx, x + rx, y + h); + vkvg_elliptic_arc_to(ctx, x, y + h - ry, false, true, rx, ry, 0); - vkvg_line_to (ctx, x, y+ry); - vkvg_elliptic_arc_to(ctx, x+rx, y , false, true, rx, ry, 0); + vkvg_line_to(ctx, x, y + ry); + vkvg_elliptic_arc_to(ctx, x + rx, y, false, true, rx, ry, 0); - vkvg_close_path(ctx); + vkvg_close_path(ctx); } -void vkvg_path_extents (VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) { - if (ctx->status) - return; +void vkvg_path_extents(VkvgContext ctx, float *x1, float *y1, float *x2, float *y2) { + if (ctx->status) + return; - _finish_path(ctx); + _finish_path(ctx); - if (!ctx->pathPtr) {//no path - *x1 = *x2 = *y1 = *y2 = 0; - return; - } + if (!ctx->pathPtr) { // no path + *x1 = *x2 = *y1 = *y2 = 0; + return; + } - _vkvg_path_extents(ctx, false, x1, y1, x2, y2); + _vkvg_path_extents(ctx, false, x1, y1, x2, y2); } -vkvg_clip_state_t _get_previous_clip_state (VkvgContext ctx) { - if (!ctx->pSavedCtxs)//no clip saved => clear - return vkvg_clip_state_clear; - return ctx->pSavedCtxs->clippingState; +vkvg_clip_state_t _get_previous_clip_state(VkvgContext ctx) { + if (!ctx->pSavedCtxs) // no clip saved => clear + return vkvg_clip_state_clear; + return ctx->pSavedCtxs->clippingState; } -static const VkClearAttachment clearStencil = {VK_IMAGE_ASPECT_STENCIL_BIT, 1, {{{0}}}}; -static const VkClearAttachment clearColorAttach = {VK_IMAGE_ASPECT_COLOR_BIT, 0, {{{0}}}}; +static const VkClearAttachment clearStencil = {VK_IMAGE_ASPECT_STENCIL_BIT, 1, {{{0}}}}; +static const VkClearAttachment clearColorAttach = {VK_IMAGE_ASPECT_COLOR_BIT, 0, {{{0}}}}; -void _reset_clip (VkvgContext ctx) { - _emit_draw_cmd_undrawn_vertices(ctx); - if (!ctx->cmdStarted) { - //if command buffer is not already started and in a renderpass, we use the renderpass - //with the loadop clear for stencil - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; - //force run of one renderpass (even empty) to perform clear load op - _start_cmd_for_render_pass(ctx); - return; - } - vkCmdClearAttachments(ctx->cmd, 1, &clearStencil, 1, &ctx->clearRect); +void _reset_clip(VkvgContext ctx) { + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) { + // if command buffer is not already started and in a renderpass, we use the renderpass + // with the loadop clear for stencil + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearStencil; + // force run of one renderpass (even empty) to perform clear load op + _start_cmd_for_render_pass(ctx); + return; + } + vkCmdClearAttachments(ctx->cmd, 1, &clearStencil, 1, &ctx->clearRect); } -void vkvg_reset_clip (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_reset_clip(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_RESET_CLIP); + RECORD(ctx, VKVG_CMD_RESET_CLIP); - if (ctx->curClipState == vkvg_clip_state_clear) - return; - if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) - ctx->curClipState = vkvg_clip_state_none; - else - ctx->curClipState = vkvg_clip_state_clear; + if (ctx->curClipState == vkvg_clip_state_clear) + return; + if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) + ctx->curClipState = vkvg_clip_state_none; + else + ctx->curClipState = vkvg_clip_state_clear; - _reset_clip (ctx); + _reset_clip(ctx); } -void vkvg_clear (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_clear(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_CLEAR); + RECORD(ctx, VKVG_CMD_CLEAR); - if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) - ctx->curClipState = vkvg_clip_state_none; - else - ctx->curClipState = vkvg_clip_state_clear; + if (_get_previous_clip_state(ctx) == vkvg_clip_state_clear) + ctx->curClipState = vkvg_clip_state_none; + else + ctx->curClipState = vkvg_clip_state_clear; - _emit_draw_cmd_undrawn_vertices(ctx); - if (!ctx->cmdStarted) { - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; - _start_cmd_for_render_pass(ctx); - return; - } - VkClearAttachment ca[2] = {clearColorAttach, clearStencil}; - vkCmdClearAttachments(ctx->cmd, 2, ca, 1, &ctx->clearRect); + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) { + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass_ClearAll; + _start_cmd_for_render_pass(ctx); + return; + } + VkClearAttachment ca[2] = {clearColorAttach, clearStencil}; + vkCmdClearAttachments(ctx->cmd, 2, ca, 1, &ctx->clearRect); } -void _clip_preserve (VkvgContext ctx){ - _finish_path(ctx); +void _clip_preserve(VkvgContext ctx) { + _finish_path(ctx); - if (!ctx->pathPtr)//nothing to clip - return; + if (!ctx->pathPtr) // nothing to clip + return; - _emit_draw_cmd_undrawn_vertices(ctx); + _emit_draw_cmd_undrawn_vertices(ctx); - LOG(VKVG_LOG_INFO, "CLIP: ctx = %p; path cpt = %d;\n", ctx, ctx->pathPtr / 2); + LOG(VKVG_LOG_INFO, "CLIP: ctx = %p; path cpt = %d;\n", ctx, ctx->pathPtr / 2); - _ensure_renderpass_is_started(ctx); + _ensure_renderpass_is_started(ctx); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "clip", DBG_LAB_COLOR_CLIP); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "clip", DBG_LAB_COLOR_CLIP); #endif - if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ - _poly_fill (ctx, NULL); - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - }else{ - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - _fill_non_zero(ctx); - _emit_draw_cmd_undrawn_vertices(ctx); - } - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT); + if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD) { + _poly_fill(ctx, NULL); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + } else { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + _fill_non_zero(ctx); + _emit_draw_cmd_undrawn_vertices(ctx); + } + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_ALL_BIT); - _draw_full_screen_quad (ctx, NULL); + _draw_full_screen_quad(ctx, NULL); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - ctx->curClipState = vkvg_clip_state_clip; + ctx->curClipState = vkvg_clip_state_clip; } -void _fill_preserve (VkvgContext ctx){ - _finish_path(ctx); +void _fill_preserve(VkvgContext ctx) { + _finish_path(ctx); - if (!ctx->pathPtr)//nothing to fill - return; + if (!ctx->pathPtr) // nothing to fill + return; - LOG(VKVG_LOG_INFO, "FILL: ctx = %p; path cpt = %d;\n", ctx, ctx->subpathCount); + LOG(VKVG_LOG_INFO, "FILL: ctx = %p; path cpt = %d;\n", ctx, ctx->subpathCount); - if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD){ - _emit_draw_cmd_undrawn_vertices(ctx); - vec4 bounds = {FLT_MAX,FLT_MAX,FLT_MIN,FLT_MIN}; - _poly_fill (ctx, &bounds); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); - _draw_full_screen_quad (ctx, &bounds); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - return; - } + if (ctx->curFillRule == VKVG_FILL_RULE_EVEN_ODD) { + _emit_draw_cmd_undrawn_vertices(ctx); + vec4 bounds = {FLT_MAX, FLT_MAX, FLT_MIN, FLT_MIN}; + _poly_fill(ctx, &bounds); + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_FILL_BIT); + _draw_full_screen_quad(ctx, &bounds); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + return; + } - if (ctx->vertCount - ctx->curVertOffset + ctx->pointCount > VKVG_IBO_MAX) - _emit_draw_cmd_undrawn_vertices(ctx);//limit draw call to addressable vx with choosen index type + if (ctx->vertCount - ctx->curVertOffset + ctx->pointCount > VKVG_IBO_MAX) + _emit_draw_cmd_undrawn_vertices(ctx); // limit draw call to addressable vx with choosen index type - if (ctx->pattern)//if not solid color, source img or gradient has to be bound - _ensure_renderpass_is_started(ctx); - _fill_non_zero(ctx); + if (ctx->pattern) // if not solid color, source img or gradient has to be bound + _ensure_renderpass_is_started(ctx); + _fill_non_zero(ctx); } -void _stroke_preserve (VkvgContext ctx) -{ - _finish_path(ctx); +void _stroke_preserve(VkvgContext ctx) { + _finish_path(ctx); - if (!ctx->pathPtr)//nothing to stroke - return; + if (!ctx->pathPtr) // nothing to stroke + return; - LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); + LOG(VKVG_LOG_INFO, "STROKE: ctx = %p; path ptr = %d;\n", ctx, ctx->pathPtr); - stroke_context_t str = {0}; - str.hw = ctx->lineWidth * 0.5f; - str.lhMax = ctx->miterLimit * ctx->lineWidth; - uint32_t ptrPath = 0; + stroke_context_t str = {0}; + str.hw = ctx->lineWidth * 0.5f; + str.lhMax = ctx->miterLimit * ctx->lineWidth; + uint32_t ptrPath = 0; - while (ptrPath < ctx->pathPtr){ - uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; - uint32_t firstPathPointIdx = str.cp; - uint32_t pathPointCount = ctx->pathes[ptrPath]&PATH_ELT_MASK; - uint32_t lastPathPointIdx = str.cp + pathPointCount - 1; + while (ptrPath < ctx->pathPtr) { + uint32_t ptrSegment = 0, lastSegmentPointIdx = 0; + uint32_t firstPathPointIdx = str.cp; + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + uint32_t lastPathPointIdx = str.cp + pathPointCount - 1; - dash_context_t dc = {0}; + dash_context_t dc = {0}; - if (_path_has_curves (ctx,ptrPath)) { - ptrSegment = 1; - lastSegmentPointIdx = str.cp + (ctx->pathes[ptrPath+ptrSegment]&PATH_ELT_MASK)-1; - } + if (_path_has_curves(ctx, ptrPath)) { + ptrSegment = 1; + lastSegmentPointIdx = str.cp + (ctx->pathes[ptrPath + ptrSegment] & PATH_ELT_MASK) - 1; + } - str.firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + str.firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - //LOG(VKVG_LOG_INFO_PATH, "\tPATH: points count=%10d end point idx=%10d", ctx->pathes[ptrPath]&PATH_ELT_MASK, lastPathPointIdx); + // LOG(VKVG_LOG_INFO_PATH, "\tPATH: points count=%10d end point idx=%10d", ctx->pathes[ptrPath]&PATH_ELT_MASK, + // lastPathPointIdx); - if (ctx->dashCount > 0) { - //init dash stroke - dc.dashOn = true; - dc.curDash = 0; //current dash index - dc.totDashLength = 0;//limit offset to total length of dashes - for (uint32_t i=0;i<ctx->dashCount;i++) - dc.totDashLength += ctx->dashes[i]; - if (dc.totDashLength == 0){ - ctx->status = VKVG_STATUS_INVALID_DASH; - return; - } - dc.curDashOffset = fmodf(ctx->dashOffset, dc.totDashLength); //cur dash offset between defined path point and last dash segment(on/off) start - str.iL = lastPathPointIdx; - } else if (_path_is_closed(ctx,ptrPath)){ - str.iL = lastPathPointIdx; - }else{ - _draw_stoke_cap(ctx, &str, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp], ctx->points[str.cp+1]), true); - str.iL = str.cp++; - } + if (ctx->dashCount > 0) { + // init dash stroke + dc.dashOn = true; + dc.curDash = 0; // current dash index + dc.totDashLength = 0; // limit offset to total length of dashes + for (uint32_t i = 0; i < ctx->dashCount; i++) + dc.totDashLength += ctx->dashes[i]; + if (dc.totDashLength == 0) { + ctx->status = VKVG_STATUS_INVALID_DASH; + return; + } + dc.curDashOffset = fmodf( + ctx->dashOffset, + dc.totDashLength); // cur dash offset between defined path point and last dash segment(on/off) start + str.iL = lastPathPointIdx; + } else if (_path_is_closed(ctx, ptrPath)) { + str.iL = lastPathPointIdx; + } else { + _draw_stoke_cap(ctx, &str, ctx->points[str.cp], + vec2_line_norm(ctx->points[str.cp], ctx->points[str.cp + 1]), true); + str.iL = str.cp++; + } - if (_path_has_curves (ctx,ptrPath)) { - while (str.cp < lastPathPointIdx){ + if (_path_has_curves(ctx, ptrPath)) { + while (str.cp < lastPathPointIdx) { - bool curved = ctx->pathes [ptrPath + ptrSegment] & PATH_HAS_CURVES_BIT; - if (lastSegmentPointIdx == lastPathPointIdx)//last segment of path, dont draw end point here - lastSegmentPointIdx--; - while (str.cp <= lastSegmentPointIdx) - _draw_segment(ctx, &str, &dc, curved); + bool curved = ctx->pathes[ptrPath + ptrSegment] & PATH_HAS_CURVES_BIT; + if (lastSegmentPointIdx == lastPathPointIdx) // last segment of path, dont draw end point here + lastSegmentPointIdx--; + while (str.cp <= lastSegmentPointIdx) + _draw_segment(ctx, &str, &dc, curved); - ptrSegment ++; - uint32_t cptSegPts = ctx->pathes [ptrPath + ptrSegment]&PATH_ELT_MASK; - lastSegmentPointIdx = str.cp + cptSegPts - 1; - if (lastSegmentPointIdx == lastPathPointIdx && cptSegPts == 1) { - //single point last segment - ptrSegment++; - break; - } - } - }else while (str.cp < lastPathPointIdx) - _draw_segment(ctx, &str, &dc, false); + ptrSegment++; + uint32_t cptSegPts = ctx->pathes[ptrPath + ptrSegment] & PATH_ELT_MASK; + lastSegmentPointIdx = str.cp + cptSegPts - 1; + if (lastSegmentPointIdx == lastPathPointIdx && cptSegPts == 1) { + // single point last segment + ptrSegment++; + break; + } + } + } else + while (str.cp < lastPathPointIdx) + _draw_segment(ctx, &str, &dc, false); - if (ctx->dashCount > 0) { - if (_path_is_closed(ctx,ptrPath)){ - str.iR = firstPathPointIdx; + if (ctx->dashCount > 0) { + if (_path_is_closed(ctx, ptrPath)) { + str.iR = firstPathPointIdx; - _draw_dashed_segment(ctx, &str, &dc, false); + _draw_dashed_segment(ctx, &str, &dc, false); - str.iL++; - str.cp++; - } - if (!dc.dashOn){ - //finishing last dash that is already started, draw end caps but not too close to start - //the default gap is the next void - int32_t prevDash = (int32_t)dc.curDash-1; - if (prevDash < 0) - dc.curDash = ctx->dashCount-1; - float m = fminf (ctx->dashes[prevDash] - dc.curDashOffset, ctx->dashes[dc.curDash]); - vec2 p = vec2_sub(ctx->points[str.iR], vec2_mult_s(dc.normal, m)); - _draw_stoke_cap (ctx, &str, p, dc.normal, false); - } - } else if (_path_is_closed(ctx,ptrPath)){ - str.iR = firstPathPointIdx; - bool inverse = _build_vb_step (ctx, &str, false); + str.iL++; + str.cp++; + } + if (!dc.dashOn) { + // finishing last dash that is already started, draw end caps but not too close to start + // the default gap is the next void + int32_t prevDash = (int32_t)dc.curDash - 1; + if (prevDash < 0) + dc.curDash = ctx->dashCount - 1; + float m = fminf(ctx->dashes[prevDash] - dc.curDashOffset, ctx->dashes[dc.curDash]); + vec2 p = vec2_sub(ctx->points[str.iR], vec2_mult_s(dc.normal, m)); + _draw_stoke_cap(ctx, &str, p, dc.normal, false); + } + } else if (_path_is_closed(ctx, ptrPath)) { + str.iR = firstPathPointIdx; + bool inverse = _build_vb_step(ctx, &str, false); - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache [ctx->indCount-6]; - VKVG_IBO_INDEX_TYPE ii = str.firstIdx; - if (inverse){ - inds[1] = ii+1; - inds[4] = ii+1; - inds[5] = ii; - }else{ - inds[1] = ii; - inds[4] = ii; - inds[5] = ii+1; - } - str.cp++; - }else - _draw_stoke_cap (ctx, &str, ctx->points[str.cp], vec2_line_norm(ctx->points[str.cp-1], ctx->points[str.cp]), false); + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount - 6]; + VKVG_IBO_INDEX_TYPE ii = str.firstIdx; + if (inverse) { + inds[1] = ii + 1; + inds[4] = ii + 1; + inds[5] = ii; + } else { + inds[1] = ii; + inds[4] = ii; + inds[5] = ii + 1; + } + str.cp++; + } else + _draw_stoke_cap(ctx, &str, ctx->points[str.cp], + vec2_line_norm(ctx->points[str.cp - 1], ctx->points[str.cp]), false); - str.cp = firstPathPointIdx + pathPointCount; + str.cp = firstPathPointIdx + pathPointCount; - if (ptrSegment > 0) - ptrPath += ptrSegment; - else - ptrPath++; - - //limit batch size here to 1/3 of the ibo index type ability - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - _emit_draw_cmd_undrawn_vertices (ctx); - } + if (ptrSegment > 0) + ptrPath += ptrSegment; + else + ptrPath++; + // limit batch size here to 1/3 of the ibo index type ability + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + _emit_draw_cmd_undrawn_vertices(ctx); + } } -void vkvg_clip (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CLIP); - _clip_preserve(ctx); - _clear_path(ctx); +void vkvg_clip(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CLIP); + _clip_preserve(ctx); + _clear_path(ctx); } -void vkvg_stroke (VkvgContext ctx) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_STROKE); - _stroke_preserve(ctx); - _clear_path(ctx); +void vkvg_stroke(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_STROKE); + _stroke_preserve(ctx); + _clear_path(ctx); } -void vkvg_fill (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_FILL); - _fill_preserve(ctx); - _clear_path(ctx); +void vkvg_fill(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_FILL); + _fill_preserve(ctx); + _clear_path(ctx); } -void vkvg_clip_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_CLIP_PRESERVE); - _clip_preserve (ctx); +void vkvg_clip_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_CLIP_PRESERVE); + _clip_preserve(ctx); } -void vkvg_fill_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_FILL_PRESERVE); - _fill_preserve (ctx); +void vkvg_fill_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_FILL_PRESERVE); + _fill_preserve(ctx); } -void vkvg_stroke_preserve (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_STROKE_PRESERVE); - _stroke_preserve (ctx); +void vkvg_stroke_preserve(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_STROKE_PRESERVE); + _stroke_preserve(ctx); } -void vkvg_paint (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_PAINT); - _finish_path (ctx); +void vkvg_paint(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_PAINT); + _finish_path(ctx); - if (ctx->pathPtr) { - vkvg_fill(ctx); - return; - } + if (ctx->pathPtr) { + vkvg_fill(ctx); + return; + } - _ensure_renderpass_is_started (ctx); - _draw_full_screen_quad (ctx, NULL); + _ensure_renderpass_is_started(ctx); + _draw_full_screen_quad(ctx, NULL); } -void vkvg_set_source_color (VkvgContext ctx, uint32_t c) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_COLOR, c); - ctx->curColor = c; - _update_cur_pattern (ctx, NULL); +void vkvg_set_source_color(VkvgContext ctx, uint32_t c) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_COLOR, c); + ctx->curColor = c; + _update_cur_pattern(ctx, NULL); } -void vkvg_set_source_rgb (VkvgContext ctx, float r, float g, float b) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_RGB, r, g, b); - ctx->curColor = CreateRgbaf(r,g,b,1); - _update_cur_pattern (ctx, NULL); +void vkvg_set_source_rgb(VkvgContext ctx, float r, float g, float b) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_RGB, r, g, b); + ctx->curColor = CreateRgbaf(r, g, b, 1); + _update_cur_pattern(ctx, NULL); } -void vkvg_set_source_rgba (VkvgContext ctx, float r, float g, float b, float a) -{ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_RGBA, r, g, b, a); - ctx->curColor = CreateRgbaf(r,g,b,a); - _update_cur_pattern (ctx, NULL); +void vkvg_set_source_rgba(VkvgContext ctx, float r, float g, float b, float a) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_RGBA, r, g, b, a); + ctx->curColor = CreateRgbaf(r, g, b, a); + _update_cur_pattern(ctx, NULL); } -void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y){ - if (ctx->status || surf->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE_SURFACE, x, y, surf); - ctx->pushConsts.source.x = x; - ctx->pushConsts.source.y = y; - _update_cur_pattern (ctx, vkvg_pattern_create_for_surface(surf)); - ctx->pushCstDirty = true; +void vkvg_set_source_surface(VkvgContext ctx, VkvgSurface surf, float x, float y) { + if (ctx->status || surf->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE_SURFACE, x, y, surf); + ctx->pushConsts.source.x = x; + ctx->pushConsts.source.y = y; + _update_cur_pattern(ctx, vkvg_pattern_create_for_surface(surf)); + ctx->pushCstDirty = true; } -void vkvg_set_source (VkvgContext ctx, VkvgPattern pat){ - if (ctx->status || pat->status) - return; - RECORD(ctx, VKVG_CMD_SET_SOURCE, pat); - _update_cur_pattern (ctx, pat); - vkvg_pattern_reference (pat); +void vkvg_set_source(VkvgContext ctx, VkvgPattern pat) { + if (ctx->status || pat->status) + return; + RECORD(ctx, VKVG_CMD_SET_SOURCE, pat); + _update_cur_pattern(ctx, pat); + vkvg_pattern_reference(pat); } -void vkvg_set_line_width (VkvgContext ctx, float width){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width); - ctx->lineWidth = width; +void vkvg_set_line_width(VkvgContext ctx, float width) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, width); + ctx->lineWidth = width; } -void vkvg_set_miter_limit (VkvgContext ctx, float limit){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, limit); - ctx->miterLimit = limit; +void vkvg_set_miter_limit(VkvgContext ctx, float limit) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_WIDTH, limit); + ctx->miterLimit = limit; } -void vkvg_set_line_cap (VkvgContext ctx, vkvg_line_cap_t cap){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap); - ctx->lineCap = cap; +void vkvg_set_line_cap(VkvgContext ctx, vkvg_line_cap_t cap) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_CAP, cap); + ctx->lineCap = cap; } -void vkvg_set_line_join (VkvgContext ctx, vkvg_line_join_t join){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_LINE_JOIN, join); - ctx->lineJoin = join; +void vkvg_set_line_join(VkvgContext ctx, vkvg_line_join_t join) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_LINE_JOIN, join); + ctx->lineJoin = join; } -void vkvg_set_operator (VkvgContext ctx, vkvg_operator_t op){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_OPERATOR, op); - if (op == ctx->curOperator) - return; +void vkvg_set_operator(VkvgContext ctx, vkvg_operator_t op) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_OPERATOR, op); + if (op == ctx->curOperator) + return; - _emit_draw_cmd_undrawn_vertices(ctx);//draw call with different ops cant be combined, so emit draw cmd for previous vertices. + _emit_draw_cmd_undrawn_vertices( + ctx); // draw call with different ops cant be combined, so emit draw cmd for previous vertices. - ctx->curOperator = op; + ctx->curOperator = op; - if (ctx->cmdStarted) - _bind_draw_pipeline (ctx); + if (ctx->cmdStarted) + _bind_draw_pipeline(ctx); } -void vkvg_set_fill_rule (VkvgContext ctx, vkvg_fill_rule_t fr){ - if (ctx->status) - return; +void vkvg_set_fill_rule(VkvgContext ctx, vkvg_fill_rule_t fr) { + if (ctx->status) + return; #ifndef __APPLE__ - RECORD(ctx, VKVG_CMD_SET_FILL_RULE, fr); - ctx->curFillRule = fr; + RECORD(ctx, VKVG_CMD_SET_FILL_RULE, fr); + ctx->curFillRule = fr; #endif } -vkvg_fill_rule_t vkvg_get_fill_rule (VkvgContext ctx){ - if (ctx->status) - return VKVG_FILL_RULE_NON_ZERO; - return ctx->curFillRule; +vkvg_fill_rule_t vkvg_get_fill_rule(VkvgContext ctx) { + if (ctx->status) + return VKVG_FILL_RULE_NON_ZERO; + return ctx->curFillRule; } -float vkvg_get_line_width (VkvgContext ctx){ - if (ctx->status) - return 0; - return ctx->lineWidth; +float vkvg_get_line_width(VkvgContext ctx) { + if (ctx->status) + return 0; + return ctx->lineWidth; } -void vkvg_set_dash (VkvgContext ctx, const float* dashes, uint32_t num_dashes, float offset){ - if (ctx->status) - return; - if (ctx->dashCount > 0) - free (ctx->dashes); - RECORD(ctx, VKVG_CMD_SET_DASH, num_dashes, offset, dashes); - ctx->dashCount = num_dashes; - ctx->dashOffset = offset; - if (ctx->dashCount == 0) - return; - ctx->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (ctx->dashes, dashes, sizeof(float) * ctx->dashCount); +void vkvg_set_dash(VkvgContext ctx, const float *dashes, uint32_t num_dashes, float offset) { + if (ctx->status) + return; + if (ctx->dashCount > 0) + free(ctx->dashes); + RECORD(ctx, VKVG_CMD_SET_DASH, num_dashes, offset, dashes); + ctx->dashCount = num_dashes; + ctx->dashOffset = offset; + if (ctx->dashCount == 0) + return; + ctx->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(ctx->dashes, dashes, sizeof(float) * ctx->dashCount); } -void vkvg_get_dash (VkvgContext ctx, const float* dashes, uint32_t* num_dashes, float* offset){ - if (ctx->status) - return; - *num_dashes = ctx->dashCount; - *offset = ctx->dashOffset; - if (ctx->dashCount == 0 || dashes == NULL) - return; - memcpy ((float*)dashes, ctx->dashes, sizeof(float) * ctx->dashCount); +void vkvg_get_dash(VkvgContext ctx, const float *dashes, uint32_t *num_dashes, float *offset) { + if (ctx->status) + return; + *num_dashes = ctx->dashCount; + *offset = ctx->dashOffset; + if (ctx->dashCount == 0 || dashes == NULL) + return; + memcpy((float *)dashes, ctx->dashes, sizeof(float) * ctx->dashCount); } - -vkvg_line_cap_t vkvg_get_line_cap (VkvgContext ctx){ - if (ctx->status) - return (vkvg_line_cap_t)0; - return ctx->lineCap; +vkvg_line_cap_t vkvg_get_line_cap(VkvgContext ctx) { + if (ctx->status) + return (vkvg_line_cap_t)0; + return ctx->lineCap; } -vkvg_line_join_t vkvg_get_line_join (VkvgContext ctx){ - if (ctx->status) - return (vkvg_line_join_t)0; - return ctx->lineJoin; +vkvg_line_join_t vkvg_get_line_join(VkvgContext ctx) { + if (ctx->status) + return (vkvg_line_join_t)0; + return ctx->lineJoin; } -vkvg_operator_t vkvg_get_operator (VkvgContext ctx){ - if (ctx->status) - return (vkvg_operator_t)0; - return ctx->curOperator; +vkvg_operator_t vkvg_get_operator(VkvgContext ctx) { + if (ctx->status) + return (vkvg_operator_t)0; + return ctx->curOperator; } -VkvgPattern vkvg_get_source (VkvgContext ctx){ - if (ctx->status) - return NULL; - vkvg_pattern_reference (ctx->pattern); - return ctx->pattern; +VkvgPattern vkvg_get_source(VkvgContext ctx) { + if (ctx->status) + return NULL; + vkvg_pattern_reference(ctx->pattern); + return ctx->pattern; } -void vkvg_select_font_face (VkvgContext ctx, const char* name){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); - _select_font_face (ctx, name); +void vkvg_select_font_face(VkvgContext ctx, const char *name) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_FACE, name); + _select_font_face(ctx, name); } -void vkvg_load_font_from_path (VkvgContext ctx, const char* path, const char* name){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); - _vkvg_font_identity_t* fid = _font_cache_add_font_identity(ctx, path, name); - if (!_font_cache_load_font_file_in_memory (fid)) { - ctx->status = VKVG_STATUS_FILE_NOT_FOUND; - return; - } - _select_font_face (ctx, name); +void vkvg_load_font_from_path(VkvgContext ctx, const char *path, const char *name) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, path, name); + if (!_font_cache_load_font_file_in_memory(fid)) { + ctx->status = VKVG_STATUS_FILE_NOT_FOUND; + return; + } + _select_font_face(ctx, name); } -void vkvg_load_font_from_memory (VkvgContext ctx, unsigned char* fontBuffer, long fontBufferByteSize, const char* name) { - if (ctx->status) - return; - //RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); - _vkvg_font_identity_t* fid = _font_cache_add_font_identity (ctx, NULL, name); - fid->fontBuffer = fontBuffer; - fid->fontBufSize = fontBufferByteSize; +void vkvg_load_font_from_memory(VkvgContext ctx, unsigned char *fontBuffer, long fontBufferByteSize, const char *name) { + if (ctx->status) + return; + // RECORD(ctx, VKVG_CMD_SET_FONT_PATH, name); + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, NULL, name); + fid->fontBuffer = fontBuffer; + fid->fontBufSize = fontBufferByteSize; - _select_font_face (ctx, name); + _select_font_face(ctx, name); } -void vkvg_set_font_size (VkvgContext ctx, uint32_t size){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_FONT_SIZE, size); +void vkvg_set_font_size(VkvgContext ctx, uint32_t size) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_FONT_SIZE, size); #ifdef VKVG_USE_FREETYPE - long newSize = size << 6; + long newSize = size << 6; #else - long newSize = size; + long newSize = size; #endif - if (ctx->selectedCharSize == newSize) - return; - ctx->selectedCharSize = newSize; - ctx->currentFont = NULL; - ctx->currentFontSize = NULL; + if (ctx->selectedCharSize == newSize) + return; + ctx->selectedCharSize = newSize; + ctx->currentFont = NULL; + ctx->currentFontSize = NULL; } -void vkvg_set_text_direction (vkvg_context* ctx, vkvg_direction_t direction){ - -} +void vkvg_set_text_direction(vkvg_context *ctx, vkvg_direction_t direction) {} -void vkvg_show_text (VkvgContext ctx, const char* text){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SHOW_TEXT, text); - LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n"); - //_ensure_renderpass_is_started(ctx); - _font_cache_show_text (ctx, text); - //_flush_undrawn_vertices (ctx); +void vkvg_show_text(VkvgContext ctx, const char *text) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SHOW_TEXT, text); + LOG(VKVG_LOG_INFO_CMD, "CMD: show_text:\n"); + //_ensure_renderpass_is_started(ctx); + _font_cache_show_text(ctx, text); + //_flush_undrawn_vertices (ctx); } -VkvgText vkvg_text_run_create (VkvgContext ctx, const char* text) { - if (ctx->status) - return NULL; - VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - _font_cache_create_text_run(ctx, text, -1, tr); - return tr; +VkvgText vkvg_text_run_create(VkvgContext ctx, const char *text) { + if (ctx->status) + return NULL; + VkvgText tr = (vkvg_text_run_t *)calloc(1, sizeof(vkvg_text_run_t)); + _font_cache_create_text_run(ctx, text, -1, tr); + return tr; } -VkvgText vkvg_text_run_create_with_length (VkvgContext ctx, const char* text, uint32_t length) { - if (ctx->status) - return NULL; - VkvgText tr = (vkvg_text_run_t*)calloc(1, sizeof(vkvg_text_run_t)); - _font_cache_create_text_run(ctx, text, length, tr); - return tr; +VkvgText vkvg_text_run_create_with_length(VkvgContext ctx, const char *text, uint32_t length) { + if (ctx->status) + return NULL; + VkvgText tr = (vkvg_text_run_t *)calloc(1, sizeof(vkvg_text_run_t)); + _font_cache_create_text_run(ctx, text, length, tr); + return tr; } -uint32_t vkvg_text_run_get_glyph_count (VkvgText textRun) { - return textRun->glyph_count; -} -void vkvg_text_run_get_glyph_position (VkvgText textRun, - uint32_t index, - vkvg_glyph_info_t* pGlyphInfo) { - if (index >= textRun->glyph_count) { - *pGlyphInfo = (vkvg_glyph_info_t){0}; - return; - } +uint32_t vkvg_text_run_get_glyph_count(VkvgText textRun) { return textRun->glyph_count; } +void vkvg_text_run_get_glyph_position(VkvgText textRun, uint32_t index, vkvg_glyph_info_t *pGlyphInfo) { + if (index >= textRun->glyph_count) { + *pGlyphInfo = (vkvg_glyph_info_t){0}; + return; + } #if VKVG_USE_HARFBUZZ - memcpy (pGlyphInfo, &textRun->glyphs[index], sizeof(vkvg_glyph_info_t)); + memcpy(pGlyphInfo, &textRun->glyphs[index], sizeof(vkvg_glyph_info_t)); #else - *pGlyphInfo = textRun->glyphs[index]; + *pGlyphInfo = textRun->glyphs[index]; #endif } -void vkvg_text_run_destroy (VkvgText textRun) { - _font_cache_destroy_text_run (textRun); - free (textRun); -} -void vkvg_show_text_run (VkvgContext ctx, VkvgText textRun) { - if (ctx->status) - return; - _font_cache_show_text_run(ctx, textRun); +void vkvg_text_run_destroy(VkvgText textRun) { + _font_cache_destroy_text_run(textRun); + free(textRun); } -void vkvg_text_run_get_extents (VkvgText textRun, vkvg_text_extents_t* extents) { - *extents = textRun->extents; +void vkvg_show_text_run(VkvgContext ctx, VkvgText textRun) { + if (ctx->status) + return; + _font_cache_show_text_run(ctx, textRun); } +void vkvg_text_run_get_extents(VkvgText textRun, vkvg_text_extents_t *extents) { *extents = textRun->extents; } -void vkvg_text_extents (VkvgContext ctx, const char* text, vkvg_text_extents_t* extents) { - if (ctx->status) - return; - _font_cache_text_extents(ctx, text, -1, extents); +void vkvg_text_extents(VkvgContext ctx, const char *text, vkvg_text_extents_t *extents) { + if (ctx->status) + return; + _font_cache_text_extents(ctx, text, -1, extents); } -void vkvg_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents) { - if (ctx->status) - return; - _font_cache_font_extents(ctx, extents); +void vkvg_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents) { + if (ctx->status) + return; + _font_cache_font_extents(ctx, extents); } -void vkvg_save (VkvgContext ctx){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SAVE); - LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx); +void vkvg_save(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SAVE); + LOG(VKVG_LOG_INFO, "SAVE CONTEXT: ctx = %p\n", ctx); - VkvgDevice dev = ctx->dev; - vkvg_context_save_t* sav = (vkvg_context_save_t*)calloc(1,sizeof(vkvg_context_save_t)); + VkvgDevice dev = ctx->dev; + vkvg_context_save_t *sav = (vkvg_context_save_t *)calloc(1, sizeof(vkvg_context_save_t)); - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) { - free (sav); - return; - } + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) { + free(sav); + return; + } - if (ctx->curClipState == vkvg_clip_state_clip) { - sav->clippingState = vkvg_clip_state_clip_saved; + if (ctx->curClipState == vkvg_clip_state_clip) { + sav->clippingState = vkvg_clip_state_clip_saved; - uint8_t curSaveStencil = ctx->curSavBit / 6; + uint8_t curSaveStencil = ctx->curSavBit / 6; - if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0){//new save/restore stencil image have to be created - VkhImage* savedStencilsPtr = NULL; - if (savedStencilsPtr) - savedStencilsPtr = (VkhImage*)realloc(ctx->savedStencils, curSaveStencil * sizeof(VkhImage)); - else - savedStencilsPtr = (VkhImage*)malloc(curSaveStencil * sizeof(VkhImage)); - if (savedStencilsPtr == NULL) { - free(sav); - ctx->status = VKVG_STATUS_NO_MEMORY; - return; - } - ctx->savedStencils = savedStencilsPtr; - VkhImage savStencil = vkh_image_ms_create ((VkhDevice)dev, dev->stencilFormat, dev->samples, ctx->pSurf->width, ctx->pSurf->height, - VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - ctx->savedStencils[curSaveStencil-1] = savStencil; + if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0) { // new save/restore stencil image have to be created + VkhImage *savedStencilsPtr = NULL; + if (savedStencilsPtr) + savedStencilsPtr = (VkhImage *)realloc(ctx->savedStencils, curSaveStencil * sizeof(VkhImage)); + else + savedStencilsPtr = (VkhImage *)malloc(curSaveStencil * sizeof(VkhImage)); + if (savedStencilsPtr == NULL) { + free(sav); + ctx->status = VKVG_STATUS_NO_MEMORY; + return; + } + ctx->savedStencils = savedStencilsPtr; + VkhImage savStencil = vkh_image_ms_create( + (VkhDevice)dev, dev->stencilFormat, dev->samples, ctx->pSurf->width, ctx->pSurf->height, + VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + ctx->savedStencils[curSaveStencil - 1] = savStencil; - vkh_cmd_begin (ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "new save/restore stencil", DBG_LAB_COLOR_SAV); - #endif - - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, savStencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "new save/restore stencil", DBG_LAB_COLOR_SAV); +#endif - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .extent = {ctx->pSurf->width,ctx->pSurf->height,1}}; - vkCmdCopyImage(ctx->cmd, - vkh_image_get_vkimage (ctx->pSurf->stencil),VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (savStencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &cregion); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(ctx->cmd, savStencil, dev->stencilAspectFlag, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .extent = {ctx->pSurf->width, ctx->pSurf->height, 1}}; + vkCmdCopyImage(ctx->cmd, vkh_image_get_vkimage(ctx->pSurf->stencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(savStencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); - #endif + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); - _wait_and_submit_cmd(ctx); - } +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); +#endif - uint8_t curSaveBit = 1 << (ctx->curSavBit % 6 + 2); + VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); + _wait_and_submit_cmd(ctx); + } - _start_cmd_for_render_pass (ctx); + uint8_t curSaveBit = 1 << (ctx->curSavBit % 6 + 2); - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "save rp", DBG_LAB_COLOR_SAV); - #endif + _start_cmd_for_render_pass(ctx); - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "save rp", DBG_LAB_COLOR_SAV); +#endif - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT|curSaveBit); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - _draw_full_screen_quad (ctx, NULL); + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT | curSaveBit); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + _draw_full_screen_quad(ctx, NULL); - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); - #endif - ctx->curSavBit++; - } else if (ctx->curClipState == vkvg_clip_state_none) - sav->clippingState = (_get_previous_clip_state(ctx) & 0x03); - else - sav->clippingState = vkvg_clip_state_clear; + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - sav->dashOffset = ctx->dashOffset; - sav->dashCount = ctx->dashCount; - if (ctx->dashCount > 0) { - sav->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (sav->dashes, ctx->dashes, sizeof(float) * ctx->dashCount); - } - sav->lineWidth = ctx->lineWidth; - sav->miterLimit = ctx->miterLimit; - sav->curOperator= ctx->curOperator; - sav->lineCap = ctx->lineCap; - sav->lineWidth = ctx->lineWidth; - sav->curFillRule= ctx->curFillRule; +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); +#endif + ctx->curSavBit++; + } else if (ctx->curClipState == vkvg_clip_state_none) + sav->clippingState = (_get_previous_clip_state(ctx) & 0x03); + else + sav->clippingState = vkvg_clip_state_clear; - sav->selectedCharSize = ctx->selectedCharSize; - strcpy (sav->selectedFontName, ctx->selectedFontName); + sav->dashOffset = ctx->dashOffset; + sav->dashCount = ctx->dashCount; + if (ctx->dashCount > 0) { + sav->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(sav->dashes, ctx->dashes, sizeof(float) * ctx->dashCount); + } + sav->lineWidth = ctx->lineWidth; + sav->miterLimit = ctx->miterLimit; + sav->curOperator = ctx->curOperator; + sav->lineCap = ctx->lineCap; + sav->lineWidth = ctx->lineWidth; + sav->curFillRule = ctx->curFillRule; - sav->currentFont = ctx->currentFont; - sav->textDirection= ctx->textDirection; - sav->pushConsts = ctx->pushConsts; - if (ctx->pattern) { - sav->pattern = ctx->pattern;//TODO:pattern sav must be imutable (copy?) - vkvg_pattern_reference (ctx->pattern); - } else - sav->curColor = ctx->curColor; + sav->selectedCharSize = ctx->selectedCharSize; + strcpy(sav->selectedFontName, ctx->selectedFontName); - sav->pNext = ctx->pSavedCtxs; - ctx->pSavedCtxs = sav; + sav->currentFont = ctx->currentFont; + sav->textDirection = ctx->textDirection; + sav->pushConsts = ctx->pushConsts; + if (ctx->pattern) { + sav->pattern = ctx->pattern; // TODO:pattern sav must be imutable (copy?) + vkvg_pattern_reference(ctx->pattern); + } else + sav->curColor = ctx->curColor; + sav->pNext = ctx->pSavedCtxs; + ctx->pSavedCtxs = sav; } -void vkvg_restore (VkvgContext ctx){ - if (ctx->status) - return; +void vkvg_restore(VkvgContext ctx) { + if (ctx->status) + return; - RECORD(ctx, VKVG_CMD_RESTORE); + RECORD(ctx, VKVG_CMD_RESTORE); - if (ctx->pSavedCtxs == NULL){ - ctx->status = VKVG_STATUS_INVALID_RESTORE; - return; - } + if (ctx->pSavedCtxs == NULL) { + ctx->status = VKVG_STATUS_INVALID_RESTORE; + return; + } - LOG(VKVG_LOG_INFO, "RESTORE CONTEXT: ctx = %p\n", ctx); + LOG(VKVG_LOG_INFO, "RESTORE CONTEXT: ctx = %p\n", ctx); - vkvg_context_save_t* sav = ctx->pSavedCtxs; - ctx->pSavedCtxs = sav->pNext; + vkvg_context_save_t *sav = ctx->pSavedCtxs; + ctx->pSavedCtxs = sav->pNext; - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; - ctx->pushConsts = sav->pushConsts; - ctx->pushCstDirty = true; + ctx->pushConsts = sav->pushConsts; + ctx->pushCstDirty = true; - if (ctx->curClipState) {//!=none - if (ctx->curClipState == vkvg_clip_state_clip && sav->clippingState == vkvg_clip_state_clear) { - _reset_clip (ctx); - } else { + if (ctx->curClipState) { //!=none + if (ctx->curClipState == vkvg_clip_state_clip && sav->clippingState == vkvg_clip_state_clear) { + _reset_clip(ctx); + } else { - uint8_t curSaveBit = 1 << ((ctx->curSavBit-1) % 6 + 2); + uint8_t curSaveBit = 1 << ((ctx->curSavBit - 1) % 6 + 2); - _start_cmd_for_render_pass (ctx); + _start_cmd_for_render_pass(ctx); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "restore rp", DBG_LAB_COLOR_SAV); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "restore rp", DBG_LAB_COLOR_SAV); #endif - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineClipping); - CmdSetStencilReference (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT|curSaveBit); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); - CmdSetStencilWriteMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + CmdSetStencilReference(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT | curSaveBit); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, curSaveBit); + CmdSetStencilWriteMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - _draw_full_screen_quad (ctx, NULL); + _draw_full_screen_quad(ctx, NULL); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask (ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - } - } - if (sav->clippingState == vkvg_clip_state_clip_saved) { - ctx->curSavBit--; + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + } + } + if (sav->clippingState == vkvg_clip_state_clip_saved) { + ctx->curSavBit--; - uint8_t curSaveStencil = ctx->curSavBit / 6; - if (ctx->curSavBit > 0 && ctx->curSavBit % 6 == 0){//addtional save/restore stencil image have to be copied back to surf stencil first - VkhImage savStencil = ctx->savedStencils[curSaveStencil-1]; + uint8_t curSaveStencil = ctx->curSavBit / 6; + if (ctx->curSavBit > 0 && + ctx->curSavBit % 6 == + 0) { // addtional save/restore stencil image have to be copied back to surf stencil first + VkhImage savStencil = ctx->savedStencils[curSaveStencil - 1]; - vkh_cmd_begin (ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "additional stencil copy while restoring", DBG_LAB_COLOR_SAV); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "additional stencil copy while restoring", DBG_LAB_COLOR_SAV); #endif - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, savStencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(ctx->cmd, savStencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, - .extent = {ctx->pSurf->width,ctx->pSurf->height,1}}; - vkCmdCopyImage(ctx->cmd, - vkh_image_get_vkimage (savStencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (ctx->pSurf->stencil),VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &cregion); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 0, 1}, + .extent = {ctx->pSurf->width, ctx->pSurf->height, 1}}; + vkCmdCopyImage(ctx->cmd, vkh_image_get_vkimage(savStencil), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(ctx->pSurf->stencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &cregion); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); - _wait_and_submit_cmd (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - vkh_image_destroy (savStencil); - } - } + VK_CHECK_RESULT(vkEndCommandBuffer(ctx->cmd)); + _wait_and_submit_cmd(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + vkh_image_destroy(savStencil); + } + } - ctx->curClipState = vkvg_clip_state_none; + ctx->curClipState = vkvg_clip_state_none; - ctx->dashOffset = sav->dashOffset; - if (ctx->dashCount > 0) - free (ctx->dashes); - ctx->dashCount = sav->dashCount; - if (ctx->dashCount > 0) { - ctx->dashes = (float*)malloc (sizeof(float) * ctx->dashCount); - memcpy (ctx->dashes, sav->dashes, sizeof(float) * ctx->dashCount); - } + ctx->dashOffset = sav->dashOffset; + if (ctx->dashCount > 0) + free(ctx->dashes); + ctx->dashCount = sav->dashCount; + if (ctx->dashCount > 0) { + ctx->dashes = (float *)malloc(sizeof(float) * ctx->dashCount); + memcpy(ctx->dashes, sav->dashes, sizeof(float) * ctx->dashCount); + } - ctx->lineWidth = sav->lineWidth; - ctx->miterLimit = sav->miterLimit; - ctx->curOperator= sav->curOperator; - ctx->lineCap = sav->lineCap; - ctx->lineJoin = sav->lineJoint; - ctx->curFillRule= sav->curFillRule; + ctx->lineWidth = sav->lineWidth; + ctx->miterLimit = sav->miterLimit; + ctx->curOperator = sav->curOperator; + ctx->lineCap = sav->lineCap; + ctx->lineJoin = sav->lineJoint; + ctx->curFillRule = sav->curFillRule; - ctx->selectedCharSize = sav->selectedCharSize; - strcpy (ctx->selectedFontName, sav->selectedFontName); + ctx->selectedCharSize = sav->selectedCharSize; + strcpy(ctx->selectedFontName, sav->selectedFontName); - ctx->currentFont = sav->currentFont; - ctx->textDirection= sav->textDirection; + ctx->currentFont = sav->currentFont; + ctx->textDirection = sav->textDirection; - if (sav->pattern) { - if (sav->pattern != ctx->pattern) - _update_cur_pattern (ctx, sav->pattern); - else - vkvg_pattern_destroy(sav->pattern); - } else { - ctx->curColor = sav->curColor; - _update_cur_pattern (ctx, NULL); - } + if (sav->pattern) { + if (sav->pattern != ctx->pattern) + _update_cur_pattern(ctx, sav->pattern); + else + vkvg_pattern_destroy(sav->pattern); + } else { + ctx->curColor = sav->curColor; + _update_cur_pattern(ctx, NULL); + } - _free_ctx_save(sav); + _free_ctx_save(sav); } -void vkvg_translate (VkvgContext ctx, float dx, float dy){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_TRANSLATE, dx, dy); - LOG(VKVG_LOG_INFO_CMD, "CMD: translate: %f, %f\n", dx, dy); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_translate (&ctx->pushConsts.mat, dx, dy); - _set_mat_inv_and_vkCmdPush (ctx); -} -void vkvg_scale (VkvgContext ctx, float sx, float sy){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SCALE, sx, sy); - LOG(VKVG_LOG_INFO_CMD, "CMD: scale: %f, %f\n", sx, sy); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_scale (&ctx->pushConsts.mat, sx, sy); - _set_mat_inv_and_vkCmdPush (ctx); +void vkvg_translate(VkvgContext ctx, float dx, float dy) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_TRANSLATE, dx, dy); + LOG(VKVG_LOG_INFO_CMD, "CMD: translate: %f, %f\n", dx, dy); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_translate(&ctx->pushConsts.mat, dx, dy); + _set_mat_inv_and_vkCmdPush(ctx); } -void vkvg_rotate (VkvgContext ctx, float radians){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ROTATE, radians); - LOG(VKVG_LOG_INFO_CMD, "CMD: rotate: %f\n", radians); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_rotate (&ctx->pushConsts.mat, radians); - _set_mat_inv_and_vkCmdPush (ctx); +void vkvg_scale(VkvgContext ctx, float sx, float sy) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SCALE, sx, sy); + LOG(VKVG_LOG_INFO_CMD, "CMD: scale: %f, %f\n", sx, sy); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_scale(&ctx->pushConsts.mat, sx, sy); + _set_mat_inv_and_vkCmdPush(ctx); } -void vkvg_transform (VkvgContext ctx, const vkvg_matrix_t* matrix) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_TRANSFORM, matrix); - LOG(VKVG_LOG_INFO_CMD, "CMD: transform: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_t res; - vkvg_matrix_multiply (&res, &ctx->pushConsts.mat, matrix); - ctx->pushConsts.mat = res; - _set_mat_inv_and_vkCmdPush (ctx); +void vkvg_rotate(VkvgContext ctx, float radians) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ROTATE, radians); + LOG(VKVG_LOG_INFO_CMD, "CMD: rotate: %f\n", radians); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_rotate(&ctx->pushConsts.mat, radians); + _set_mat_inv_and_vkCmdPush(ctx); } -void vkvg_identity_matrix (VkvgContext ctx) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_IDENTITY_MATRIX); - LOG(VKVG_LOG_INFO_CMD, "CMD: identity_matrix:\n"); - _emit_draw_cmd_undrawn_vertices(ctx); - vkvg_matrix_t im = VKVG_IDENTITY_MATRIX; - ctx->pushConsts.mat = im; - _set_mat_inv_and_vkCmdPush (ctx); +void vkvg_transform(VkvgContext ctx, const vkvg_matrix_t *matrix) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_TRANSFORM, matrix); + LOG(VKVG_LOG_INFO_CMD, "CMD: transform: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_t res; + vkvg_matrix_multiply(&res, &ctx->pushConsts.mat, matrix); + ctx->pushConsts.mat = res; + _set_mat_inv_and_vkCmdPush(ctx); } -void vkvg_set_matrix (VkvgContext ctx, const vkvg_matrix_t* matrix){ - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_SET_MATRIX, matrix); - LOG(VKVG_LOG_INFO_CMD, "CMD: set_matrix: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, matrix->x0, matrix->y0); - _emit_draw_cmd_undrawn_vertices(ctx); - ctx->pushConsts.mat = (*matrix); - _set_mat_inv_and_vkCmdPush (ctx); +void vkvg_identity_matrix(VkvgContext ctx) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_IDENTITY_MATRIX); + LOG(VKVG_LOG_INFO_CMD, "CMD: identity_matrix:\n"); + _emit_draw_cmd_undrawn_vertices(ctx); + vkvg_matrix_t im = VKVG_IDENTITY_MATRIX; + ctx->pushConsts.mat = im; + _set_mat_inv_and_vkCmdPush(ctx); } -void vkvg_get_matrix (VkvgContext ctx, vkvg_matrix_t* const matrix){ - *matrix = ctx->pushConsts.mat; +void vkvg_set_matrix(VkvgContext ctx, const vkvg_matrix_t *matrix) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_SET_MATRIX, matrix); + LOG(VKVG_LOG_INFO_CMD, "CMD: set_matrix: %f, %f, %f, %f, %f, %f\n", matrix->xx, matrix->yx, matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + _emit_draw_cmd_undrawn_vertices(ctx); + ctx->pushConsts.mat = (*matrix); + _set_mat_inv_and_vkCmdPush(ctx); } +void vkvg_get_matrix(VkvgContext ctx, vkvg_matrix_t *const matrix) { *matrix = ctx->pushConsts.mat; } -void vkvg_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,sweepFlag,rx,ry,phi); - float x1, y1; - vkvg_get_current_point(ctx, &x1, &y1); - _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, sweepFlag, rx, ry, phi); +void vkvg_elliptic_arc_to(VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, + float phi) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); + LOG(VKVG_LOG_INFO_CMD, + "\tCMD: elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2, y2, + largeArc, sweepFlag, rx, ry, phi); + float x1, y1; + vkvg_get_current_point(ctx, &x1, &y1); + _elliptic_arc(ctx, x1, y1, x2, y2, largeArc, sweepFlag, rx, ry, phi); } -void vkvg_rel_elliptic_arc_to (VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, float phi) { - if (ctx->status) - return; - RECORD(ctx, VKVG_CMD_REL_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); - LOG(VKVG_LOG_INFO_CMD, "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2,y2,largeArc,sweepFlag,rx,ry,phi); +void vkvg_rel_elliptic_arc_to(VkvgContext ctx, float x2, float y2, bool largeArc, bool sweepFlag, float rx, float ry, + float phi) { + if (ctx->status) + return; + RECORD(ctx, VKVG_CMD_REL_ELLIPTICAL_ARC_TO, x2, y2, rx, ry, phi, largeArc, sweepFlag); + LOG(VKVG_LOG_INFO_CMD, + "\tCMD: rel_elliptic_arc_to: x2:%10.5f y2:%10.5f large:%d sweep:%d rx:%10.5f ry:%10.5f phi:%10.5f \n", x2, y2, + largeArc, sweepFlag, rx, ry, phi); - float x1, y1; - vkvg_get_current_point(ctx, &x1, &y1); - _elliptic_arc(ctx, x1, y1, x2+x1, y2+y1, largeArc, sweepFlag, rx, ry, phi); + float x1, y1; + vkvg_get_current_point(ctx, &x1, &y1); + _elliptic_arc(ctx, x1, y1, x2 + x1, y2 + y1, largeArc, sweepFlag, rx, ry, phi); } -void vkvg_ellipse (VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) { - if (ctx->status) - return; - LOG(VKVG_LOG_INFO_CMD, "CMD: ellipse:\n"); +void vkvg_ellipse(VkvgContext ctx, float radiusX, float radiusY, float x, float y, float rotationAngle) { + if (ctx->status) + return; + LOG(VKVG_LOG_INFO_CMD, "CMD: ellipse:\n"); - float width_two_thirds = radiusX * 4 / 3; + float width_two_thirds = radiusX * 4 / 3; - float dx1 = sinf(rotationAngle) * radiusY; - float dy1 = cosf(rotationAngle) * radiusY; - float dx2 = cosf(rotationAngle) * width_two_thirds; - float dy2 = sinf(rotationAngle) * width_two_thirds; + float dx1 = sinf(rotationAngle) * radiusY; + float dy1 = cosf(rotationAngle) * radiusY; + float dx2 = cosf(rotationAngle) * width_two_thirds; + float dy2 = sinf(rotationAngle) * width_two_thirds; - float topCenterX = x - dx1; - float topCenterY = y + dy1; - float topRightX = topCenterX + dx2; - float topRightY = topCenterY + dy2; - float topLeftX = topCenterX - dx2; - float topLeftY = topCenterY - dy2; + float topCenterX = x - dx1; + float topCenterY = y + dy1; + float topRightX = topCenterX + dx2; + float topRightY = topCenterY + dy2; + float topLeftX = topCenterX - dx2; + float topLeftY = topCenterY - dy2; - float bottomCenterX = x + dx1; - float bottomCenterY = y - dy1; - float bottomRightX = bottomCenterX + dx2; - float bottomRightY = bottomCenterY + dy2; - float bottomLeftX = bottomCenterX - dx2; - float bottomLeftY = bottomCenterY - dy2; + float bottomCenterX = x + dx1; + float bottomCenterY = y - dy1; + float bottomRightX = bottomCenterX + dx2; + float bottomRightY = bottomCenterY + dy2; + float bottomLeftX = bottomCenterX - dx2; + float bottomLeftY = bottomCenterY - dy2; - _finish_path(ctx); - _add_point (ctx, bottomCenterX, bottomCenterY); + _finish_path(ctx); + _add_point(ctx, bottomCenterX, bottomCenterY); - _curve_to (ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY); - _curve_to (ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY); + _curve_to(ctx, bottomRightX, bottomRightY, topRightX, topRightY, topCenterX, topCenterY); + _curve_to(ctx, topLeftX, topLeftY, bottomLeftX, bottomLeftY, bottomCenterX, bottomCenterY); - ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; - _finish_path(ctx); + ctx->pathes[ctx->pathPtr] |= PATH_CLOSED_BIT; + _finish_path(ctx); } -VkvgSurface vkvg_get_target (VkvgContext ctx) { - if (ctx->status) - return NULL; - return ctx->pSurf; +VkvgSurface vkvg_get_target(VkvgContext ctx) { + if (ctx->status) + return NULL; + return ctx->pSurf; } -const char * -vkvg_status_to_string (vkvg_status_t status) { - switch (status) { - case VKVG_STATUS_SUCCESS: - return "no error has occurred"; - case VKVG_STATUS_NO_MEMORY: - return "out of memory"; - case VKVG_STATUS_INVALID_RESTORE: - return "vkvg_restore() without matching vkvg_save()"; - case VKVG_STATUS_NO_CURRENT_POINT: - return "no current point defined"; - case VKVG_STATUS_INVALID_MATRIX: - return "invalid matrix (not invertible)"; - case VKVG_STATUS_INVALID_STATUS: - return "invalid value for an input vkvg_status_t"; - case VKVG_STATUS_INVALID_INDEX: - return "invalid index passed to getter"; - case VKVG_STATUS_NULL_POINTER: - return "NULL pointer"; - case VKVG_STATUS_WRITE_ERROR: - return "error while writing to output stream"; - case VKVG_STATUS_PATTERN_TYPE_MISMATCH: - return "the pattern type is not appropriate for the operation"; - case VKVG_STATUS_PATTERN_INVALID_GRADIENT: - return "the stops count is zero"; - case VKVG_STATUS_INVALID_FORMAT: - return "invalid value for an input vkvg_format_t"; - case VKVG_STATUS_FILE_NOT_FOUND: - return "file not found"; - case VKVG_STATUS_INVALID_DASH: - return "invalid value for a dash setting"; - case VKVG_STATUS_INVALID_RECT: - return "a rectangle has the height or width equal to 0"; - case VKVG_STATUS_TIMEOUT: - return "waiting for a Vulkan operation to finish resulted in a fence timeout (5 seconds)"; - case VKVG_STATUS_DEVICE_ERROR: - return "the initialization of the device resulted in an error"; - case VKVG_STATUS_INVALID_IMAGE: - return "invalid image"; - case VKVG_STATUS_INVALID_SURFACE: - return "invalid surface"; - case VKVG_STATUS_INVALID_FONT: - return "unresolved font name"; - default: - return "<unknown error status>"; - } +const char *vkvg_status_to_string(vkvg_status_t status) { + switch (status) { + case VKVG_STATUS_SUCCESS: + return "no error has occurred"; + case VKVG_STATUS_NO_MEMORY: + return "out of memory"; + case VKVG_STATUS_INVALID_RESTORE: + return "vkvg_restore() without matching vkvg_save()"; + case VKVG_STATUS_NO_CURRENT_POINT: + return "no current point defined"; + case VKVG_STATUS_INVALID_MATRIX: + return "invalid matrix (not invertible)"; + case VKVG_STATUS_INVALID_STATUS: + return "invalid value for an input vkvg_status_t"; + case VKVG_STATUS_INVALID_INDEX: + return "invalid index passed to getter"; + case VKVG_STATUS_NULL_POINTER: + return "NULL pointer"; + case VKVG_STATUS_WRITE_ERROR: + return "error while writing to output stream"; + case VKVG_STATUS_PATTERN_TYPE_MISMATCH: + return "the pattern type is not appropriate for the operation"; + case VKVG_STATUS_PATTERN_INVALID_GRADIENT: + return "the stops count is zero"; + case VKVG_STATUS_INVALID_FORMAT: + return "invalid value for an input vkvg_format_t"; + case VKVG_STATUS_FILE_NOT_FOUND: + return "file not found"; + case VKVG_STATUS_INVALID_DASH: + return "invalid value for a dash setting"; + case VKVG_STATUS_INVALID_RECT: + return "a rectangle has the height or width equal to 0"; + case VKVG_STATUS_TIMEOUT: + return "waiting for a Vulkan operation to finish resulted in a fence timeout (5 seconds)"; + case VKVG_STATUS_DEVICE_ERROR: + return "the initialization of the device resulted in an error"; + case VKVG_STATUS_INVALID_IMAGE: + return "invalid image"; + case VKVG_STATUS_INVALID_SURFACE: + return "invalid surface"; + case VKVG_STATUS_INVALID_FONT: + return "unresolved font name"; + default: + return "<unknown error status>"; + } } diff --git a/src/vkvg_context_internal.c b/src/vkvg_context_internal.c index b6a9068..ce68947 100644 --- a/src/vkvg_context_internal.c +++ b/src/vkvg_context_internal.c @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -//credits for bezier algorithms to: +// credits for bezier algorithms to: // Anti-Grain Geometry (AGG) - Version 2.5 // A high quality rendering engine for C++ // Copyright (C) 2002-2006 Maxim Shemanarev @@ -28,7 +28,6 @@ // mcseemagg@yahoo.com // http://antigrain.com - #include "vkvg_surface_internal.h" #include "vkvg_context_internal.h" #include "vkvg_device_internal.h" @@ -40,1978 +39,1915 @@ #include "glutess.h" #endif -void _resize_vertex_cache (VkvgContext ctx, uint32_t newSize) { - Vertex* tmp = (Vertex*) realloc (ctx->vertexCache, (size_t)newSize * sizeof(Vertex)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize vertex cache (vx count=%u): old size: %u -> new size: %u size(byte): %zu Ptr: %p -> %p\n", - ctx->vertCount, ctx->sizeVertices, newSize, (size_t)newSize * sizeof(Vertex), ctx->vertexCache, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize vertex cache failed: vert count: %u byte size: %zu\n", newSize, newSize * sizeof(Vertex)); - return; - } - ctx->vertexCache = tmp; - ctx->sizeVertices = newSize; -} -void _resize_index_cache (VkvgContext ctx, uint32_t newSize) { - VKVG_IBO_INDEX_TYPE* tmp = (VKVG_IBO_INDEX_TYPE*) realloc (ctx->indexCache, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %lu Ptr: %p -> %p\n", (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE), ctx->indexCache, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize IBO failed: idx count: %u size(byte): %zu\n", newSize, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); - return; - } - ctx->indexCache = tmp; - ctx->sizeIndices = newSize; -} -void _ensure_vertex_cache_size (VkvgContext ctx, uint32_t addedVerticesCount) { - if (ctx->sizeVertices - ctx->vertCount > VKVG_ARRAY_THRESHOLD + addedVerticesCount) - return; - uint32_t newSize = ctx->sizeVertices + addedVerticesCount; - uint32_t modulo = addedVerticesCount % VKVG_VBO_SIZE; - if (modulo > 0) - newSize += VKVG_VBO_SIZE - modulo; - _resize_vertex_cache (ctx, newSize); -} -void _check_vertex_cache_size (VkvgContext ctx) { - assert(ctx->sizeVertices > ctx->vertCount); - if (ctx->sizeVertices - VKVG_ARRAY_THRESHOLD > ctx->vertCount) - return; - _resize_vertex_cache (ctx, ctx->sizeVertices + VKVG_VBO_SIZE); +void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize) { + Vertex *tmp = (Vertex *)realloc(ctx->vertexCache, (size_t)newSize * sizeof(Vertex)); + LOG(VKVG_LOG_DBG_ARRAYS, + "resize vertex cache (vx count=%u): old size: %u -> new size: %u size(byte): %zu Ptr: %p -> %p\n", + ctx->vertCount, ctx->sizeVertices, newSize, (size_t)newSize * sizeof(Vertex), ctx->vertexCache, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize vertex cache failed: vert count: %u byte size: %zu\n", newSize, + newSize * sizeof(Vertex)); + return; + } + ctx->vertexCache = tmp; + ctx->sizeVertices = newSize; } -void _ensure_index_cache_size (VkvgContext ctx, uint32_t addedIndicesCount) { - assert(ctx->sizeIndices > ctx->indCount); - if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount + addedIndicesCount) - return; - uint32_t newSize = ctx->sizeIndices + addedIndicesCount; - uint32_t modulo = addedIndicesCount % VKVG_IBO_SIZE; - if (modulo > 0) - newSize += VKVG_IBO_SIZE - modulo; - _resize_index_cache (ctx, newSize); +void _resize_index_cache(VkvgContext ctx, uint32_t newSize) { + VKVG_IBO_INDEX_TYPE *tmp = + (VKVG_IBO_INDEX_TYPE *)realloc(ctx->indexCache, (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %lu Ptr: %p -> %p\n", (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE), + ctx->indexCache, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize IBO failed: idx count: %u size(byte): %zu\n", newSize, + (size_t)newSize * sizeof(VKVG_IBO_INDEX_TYPE)); + return; + } + ctx->indexCache = tmp; + ctx->sizeIndices = newSize; } -void _check_index_cache_size (VkvgContext ctx) { - if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount) - return; - _resize_index_cache (ctx, ctx->sizeIndices + VKVG_IBO_SIZE); +void _ensure_vertex_cache_size(VkvgContext ctx, uint32_t addedVerticesCount) { + if (ctx->sizeVertices - ctx->vertCount > VKVG_ARRAY_THRESHOLD + addedVerticesCount) + return; + uint32_t newSize = ctx->sizeVertices + addedVerticesCount; + uint32_t modulo = addedVerticesCount % VKVG_VBO_SIZE; + if (modulo > 0) + newSize += VKVG_VBO_SIZE - modulo; + _resize_vertex_cache(ctx, newSize); } -//check host path array size, return true if error. pathPtr is already incremented -bool _check_pathes_array (VkvgContext ctx){ - if (ctx->sizePathes - ctx->pathPtr - ctx->segmentPtr > VKVG_ARRAY_THRESHOLD) - return false; - ctx->sizePathes += VKVG_PATHES_SIZE; - uint32_t* tmp = (uint32_t*) realloc (ctx->pathes, (size_t)ctx->sizePathes * sizeof(uint32_t)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize PATH: new size: %u Ptr: %p -> %p\n", ctx->sizePathes, ctx->pathes, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t)); - _clear_path(ctx); - return true; - } - ctx->pathes = tmp; - return false; +void _check_vertex_cache_size(VkvgContext ctx) { + assert(ctx->sizeVertices > ctx->vertCount); + if (ctx->sizeVertices - VKVG_ARRAY_THRESHOLD > ctx->vertCount) + return; + _resize_vertex_cache(ctx, ctx->sizeVertices + VKVG_VBO_SIZE); } -//check host point array size, return true if error -bool _check_point_array (VkvgContext ctx){ - if (ctx->sizePoints - VKVG_ARRAY_THRESHOLD > ctx->pointCount) - return false; - ctx->sizePoints += VKVG_PTS_SIZE; - vec2* tmp = (vec2*) realloc (ctx->points, (size_t)ctx->sizePoints * sizeof(vec2)); - LOG(VKVG_LOG_DBG_ARRAYS, "resize Points: new size(point): %u Ptr: %p -> %p\n", ctx->sizePoints, ctx->points, tmp); - if (tmp == NULL){ - ctx->status = VKVG_STATUS_NO_MEMORY; - LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2)); - _clear_path (ctx); - return true; - } - ctx->points = tmp; - return false; +void _ensure_index_cache_size(VkvgContext ctx, uint32_t addedIndicesCount) { + assert(ctx->sizeIndices > ctx->indCount); + if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount + addedIndicesCount) + return; + uint32_t newSize = ctx->sizeIndices + addedIndicesCount; + uint32_t modulo = addedIndicesCount % VKVG_IBO_SIZE; + if (modulo > 0) + newSize += VKVG_IBO_SIZE - modulo; + _resize_index_cache(ctx, newSize); } -bool _current_path_is_empty (VkvgContext ctx) { - return ctx->pathes [ctx->pathPtr] == 0; +void _check_index_cache_size(VkvgContext ctx) { + if (ctx->sizeIndices - VKVG_ARRAY_THRESHOLD > ctx->indCount) + return; + _resize_index_cache(ctx, ctx->sizeIndices + VKVG_IBO_SIZE); } -//this function expect that current point exists -vec2 _get_current_position (VkvgContext ctx) { - return ctx->points[ctx->pointCount-1]; +// check host path array size, return true if error. pathPtr is already incremented +bool _check_pathes_array(VkvgContext ctx) { + if (ctx->sizePathes - ctx->pathPtr - ctx->segmentPtr > VKVG_ARRAY_THRESHOLD) + return false; + ctx->sizePathes += VKVG_PATHES_SIZE; + uint32_t *tmp = (uint32_t *)realloc(ctx->pathes, (size_t)ctx->sizePathes * sizeof(uint32_t)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize PATH: new size: %u Ptr: %p -> %p\n", ctx->sizePathes, ctx->pathes, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePathes * sizeof(uint32_t)); + _clear_path(ctx); + return true; + } + ctx->pathes = tmp; + return false; } -//set curve start point and set path has curve bit -void _set_curve_start (VkvgContext ctx) { - if (ctx->segmentPtr > 0) { - //check if current segment has points (straight) - if ((ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_ELT_MASK) > 0) - ctx->segmentPtr++; - }else{ - //not yet segmented path, first segment length is copied - if (ctx->pathes [ctx->pathPtr] > 0){//create first straight segment first - ctx->pathes [ctx->pathPtr + 1] = ctx->pathes [ctx->pathPtr]; - ctx->segmentPtr = 2; - }else - ctx->segmentPtr = 1; - } - _check_pathes_array(ctx); - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0; +// check host point array size, return true if error +bool _check_point_array(VkvgContext ctx) { + if (ctx->sizePoints - VKVG_ARRAY_THRESHOLD > ctx->pointCount) + return false; + ctx->sizePoints += VKVG_PTS_SIZE; + vec2 *tmp = (vec2 *)realloc(ctx->points, (size_t)ctx->sizePoints * sizeof(vec2)); + LOG(VKVG_LOG_DBG_ARRAYS, "resize Points: new size(point): %u Ptr: %p -> %p\n", ctx->sizePoints, ctx->points, tmp); + if (tmp == NULL) { + ctx->status = VKVG_STATUS_NO_MEMORY; + LOG(VKVG_LOG_ERR, "resize PATH failed: new size(byte): %zu\n", ctx->sizePoints * sizeof(vec2)); + _clear_path(ctx); + return true; + } + ctx->points = tmp; + return false; } -//compute segment length and set is curved bit -void _set_curve_end (VkvgContext ctx) { - //ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = ctx->pathes [ctx->pathPtr] - ctx->pathes [ctx->pathPtr + ctx->segmentPtr]; - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] |= PATH_HAS_CURVES_BIT; - ctx->segmentPtr++; - _check_pathes_array(ctx); - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0; +bool _current_path_is_empty(VkvgContext ctx) { return ctx->pathes[ctx->pathPtr] == 0; } +// this function expect that current point exists +vec2 _get_current_position(VkvgContext ctx) { return ctx->points[ctx->pointCount - 1]; } +// set curve start point and set path has curve bit +void _set_curve_start(VkvgContext ctx) { + if (ctx->segmentPtr > 0) { + // check if current segment has points (straight) + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) > 0) + ctx->segmentPtr++; + } else { + // not yet segmented path, first segment length is copied + if (ctx->pathes[ctx->pathPtr] > 0) { // create first straight segment first + ctx->pathes[ctx->pathPtr + 1] = ctx->pathes[ctx->pathPtr]; + ctx->segmentPtr = 2; + } else + ctx->segmentPtr = 1; + } + _check_pathes_array(ctx); + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; } -//path start pointed at ptrPath has curve bit -bool _path_has_curves (VkvgContext ctx, uint32_t ptrPath) { - return ctx->pathes[ptrPath] & PATH_HAS_CURVES_BIT; +// compute segment length and set is curved bit +void _set_curve_end(VkvgContext ctx) { + // ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = ctx->pathes [ctx->pathPtr] - ctx->pathes [ctx->pathPtr + + // ctx->segmentPtr]; + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] |= PATH_HAS_CURVES_BIT; + ctx->segmentPtr++; + _check_pathes_array(ctx); + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; } -void _finish_path (VkvgContext ctx){ - if (ctx->pathes [ctx->pathPtr] == 0)//empty - return; - if ((ctx->pathes [ctx->pathPtr]&PATH_ELT_MASK) < 2){ - //only current pos is in path - ctx->pointCount -= ctx->pathes[ctx->pathPtr];//what about the bounds? - ctx->pathes[ctx->pathPtr] = 0; - ctx->segmentPtr = 0; - return; - } +// path start pointed at ptrPath has curve bit +bool _path_has_curves(VkvgContext ctx, uint32_t ptrPath) { return ctx->pathes[ptrPath] & PATH_HAS_CURVES_BIT; } +void _finish_path(VkvgContext ctx) { + if (ctx->pathes[ctx->pathPtr] == 0) // empty + return; + if ((ctx->pathes[ctx->pathPtr] & PATH_ELT_MASK) < 2) { + // only current pos is in path + ctx->pointCount -= ctx->pathes[ctx->pathPtr]; // what about the bounds? + ctx->pathes[ctx->pathPtr] = 0; + ctx->segmentPtr = 0; + return; + } - LOG(VKVG_LOG_INFO_PATH, "PATH: points count=%10d\n", ctx->pathes[ctx->pathPtr]&PATH_ELT_MASK); + LOG(VKVG_LOG_INFO_PATH, "PATH: points count=%10d\n", ctx->pathes[ctx->pathPtr] & PATH_ELT_MASK); - if (ctx->pathPtr == 0 && ctx->simpleConvex) - ctx->pathes[0] |= PATH_IS_CONVEX_BIT; + if (ctx->pathPtr == 0 && ctx->simpleConvex) + ctx->pathes[0] |= PATH_IS_CONVEX_BIT; - if (ctx->segmentPtr > 0) {//pathes having curves are segmented - ctx->pathes[ctx->pathPtr] |= PATH_HAS_CURVES_BIT; - //curved segment increment segmentPtr on curve end, - //so if last segment is not a curve and point count > 0 - if ((ctx->pathes[ctx->pathPtr+ctx->segmentPtr]&PATH_HAS_CURVES_BIT)==0 && - (ctx->pathes[ctx->pathPtr+ctx->segmentPtr]&PATH_ELT_MASK) > 0) - ctx->segmentPtr++;//current segment has to be included - ctx->pathPtr += ctx->segmentPtr; - }else - ctx->pathPtr ++; + if (ctx->segmentPtr > 0) { // pathes having curves are segmented + ctx->pathes[ctx->pathPtr] |= PATH_HAS_CURVES_BIT; + // curved segment increment segmentPtr on curve end, + // so if last segment is not a curve and point count > 0 + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_HAS_CURVES_BIT) == 0 && + (ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) > 0) + ctx->segmentPtr++; // current segment has to be included + ctx->pathPtr += ctx->segmentPtr; + } else + ctx->pathPtr++; - if (_check_pathes_array(ctx)) - return; + if (_check_pathes_array(ctx)) + return; - ctx->pathes[ctx->pathPtr] = 0; - ctx->segmentPtr = 0; - ctx->subpathCount++; - ctx->simpleConvex = false; + ctx->pathes[ctx->pathPtr] = 0; + ctx->segmentPtr = 0; + ctx->subpathCount++; + ctx->simpleConvex = false; } -//clear path datas in context -void _clear_path (VkvgContext ctx){ - ctx->pathPtr = 0; - ctx->pathes [ctx->pathPtr] = 0; - ctx->pointCount = 0; - ctx->segmentPtr = 0; - ctx->subpathCount = 0; - ctx->simpleConvex = false; +// clear path datas in context +void _clear_path(VkvgContext ctx) { + ctx->pathPtr = 0; + ctx->pathes[ctx->pathPtr] = 0; + ctx->pointCount = 0; + ctx->segmentPtr = 0; + ctx->subpathCount = 0; + ctx->simpleConvex = false; } -void _remove_last_point (VkvgContext ctx){ - ctx->pathes[ctx->pathPtr]--; - ctx->pointCount--; - if (ctx->segmentPtr > 0){//if path is segmented - if (!ctx->pathes [ctx->pathPtr + ctx->segmentPtr])//if current segment is empty - ctx->segmentPtr--; - ctx->pathes [ctx->pathPtr + ctx->segmentPtr]--;//decrement last segment point count - if ((ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_ELT_MASK) == 0)//if no point left (was only one) - ctx->pathes [ctx->pathPtr + ctx->segmentPtr] = 0;//reset current segment - else if (ctx->pathes [ctx->pathPtr + ctx->segmentPtr]&PATH_HAS_CURVES_BIT)//if segment is a curve - ctx->segmentPtr++;//then segPtr has to be forwarded to new segment - } +void _remove_last_point(VkvgContext ctx) { + ctx->pathes[ctx->pathPtr]--; + ctx->pointCount--; + if (ctx->segmentPtr > 0) { // if path is segmented + if (!ctx->pathes[ctx->pathPtr + ctx->segmentPtr]) // if current segment is empty + ctx->segmentPtr--; + ctx->pathes[ctx->pathPtr + ctx->segmentPtr]--; // decrement last segment point count + if ((ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_ELT_MASK) == 0) // if no point left (was only one) + ctx->pathes[ctx->pathPtr + ctx->segmentPtr] = 0; // reset current segment + else if (ctx->pathes[ctx->pathPtr + ctx->segmentPtr] & PATH_HAS_CURVES_BIT) // if segment is a curve + ctx->segmentPtr++; // then segPtr has to be forwarded to new segment + } } -bool _path_is_closed (VkvgContext ctx, uint32_t ptrPath){ - return ctx->pathes[ptrPath] & PATH_CLOSED_BIT; -} -void _add_point (VkvgContext ctx, float x, float y){ - if (_check_point_array(ctx)) - return; - if (isnan(x) || isnan(y)) { - LOG(VKVG_LOG_DEBUG, "_add_point: (%f, %f)\n", x, y); - return; - } - vec2 v = {x,y}; - /*if (!_current_path_is_empty(ctx) && vec2_length(vec2_sub(ctx->points[ctx->pointCount-1], v))<1.f) - return;*/ - LOG(VKVG_LOG_INFO_PTS, "_add_point: (%f, %f)\n", x, y); +bool _path_is_closed(VkvgContext ctx, uint32_t ptrPath) { return ctx->pathes[ptrPath] & PATH_CLOSED_BIT; } +void _add_point(VkvgContext ctx, float x, float y) { + if (_check_point_array(ctx)) + return; + if (isnan(x) || isnan(y)) { + LOG(VKVG_LOG_DEBUG, "_add_point: (%f, %f)\n", x, y); + return; + } + vec2 v = {x, y}; + /*if (!_current_path_is_empty(ctx) && vec2_length(vec2_sub(ctx->points[ctx->pointCount-1], v))<1.f) + return;*/ + LOG(VKVG_LOG_INFO_PTS, "_add_point: (%f, %f)\n", x, y); - ctx->points[ctx->pointCount] = v; - ctx->pointCount++;//total point count of pathes, (for array bounds check) - ctx->pathes[ctx->pathPtr]++;//total point count in path - if (ctx->segmentPtr > 0) - ctx->pathes[ctx->pathPtr + ctx->segmentPtr]++;//total point count in path's segment -} -float _normalizeAngle(float a) -{ - float res = ROUND_DOWN(fmodf(a, 2.0f * M_PIF), 100); - if (res < 0.0f) - res += 2.0f * M_PIF; - return res; + ctx->points[ctx->pointCount] = v; + ctx->pointCount++; // total point count of pathes, (for array bounds check) + ctx->pathes[ctx->pathPtr]++; // total point count in path + if (ctx->segmentPtr > 0) + ctx->pathes[ctx->pathPtr + ctx->segmentPtr]++; // total point count in path's segment } -float _get_arc_step (VkvgContext ctx, float radius) { - float sx, sy; - vkvg_matrix_get_scale (&ctx->pushConsts.mat, &sx, &sy); - float r = radius * fabsf(fmaxf(sx,sy)); - if (r < 30.0f) - return fminf(M_PIF / 3.f, M_PIF / r); - return fminf(M_PIF / 3.f,M_PIF / (r * 0.4f)); +float _normalizeAngle(float a) { + float res = ROUND_DOWN(fmodf(a, 2.0f * M_PIF), 100); + if (res < 0.0f) + res += 2.0f * M_PIF; + return res; } -void _create_gradient_buff (VkvgContext ctx){ - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - sizeof(vkvg_gradient_t), &ctx->uboGrad, true); +float _get_arc_step(VkvgContext ctx, float radius) { + float sx, sy; + vkvg_matrix_get_scale(&ctx->pushConsts.mat, &sx, &sy); + float r = radius * fabsf(fmaxf(sx, sy)); + if (r < 30.0f) + return fminf(M_PIF / 3.f, M_PIF / r); + return fminf(M_PIF / 3.f, M_PIF / (r * 0.4f)); } -void _create_vertices_buff (VkvgContext ctx){ - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeVBO * sizeof(Vertex), &ctx->vertices, true); - vkh_buffer_init ((VkhDevice)ctx->dev, - VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices, true); +void _create_gradient_buff(VkvgContext ctx) { + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + sizeof(vkvg_gradient_t), &ctx->uboGrad, true); } -void _resize_vbo (VkvgContext ctx, uint32_t new_size) { - if (!_wait_ctx_flush_end (ctx))//wait previous cmd if not completed - return; - LOG(VKVG_LOG_DBG_ARRAYS, "resize VBO: %d -> ", ctx->sizeVBO); - ctx->sizeVBO = new_size; - uint32_t mod = ctx->sizeVBO % VKVG_VBO_SIZE; - if (mod > 0) - ctx->sizeVBO += VKVG_VBO_SIZE - mod; - LOG(VKVG_LOG_DBG_ARRAYS, "%d\n", ctx->sizeVBO); - vkh_buffer_resize (&ctx->vertices, ctx->sizeVBO * sizeof(Vertex), true); +void _create_vertices_buff(VkvgContext ctx) { + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + ctx->sizeVBO * sizeof(Vertex), &ctx->vertices, true); + vkh_buffer_init((VkhDevice)ctx->dev, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, + ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), &ctx->indices, true); } -void _resize_ibo (VkvgContext ctx, size_t new_size) { - if (!_wait_ctx_flush_end (ctx))//wait previous cmd if not completed - return; - ctx->sizeIBO = new_size; - uint32_t mod = ctx->sizeIBO % VKVG_IBO_SIZE; - if (mod > 0) - ctx->sizeIBO += VKVG_IBO_SIZE - mod; - LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %d\n", ctx->sizeIBO); - vkh_buffer_resize (&ctx->indices, ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), true); +void _resize_vbo(VkvgContext ctx, uint32_t new_size) { + if (!_wait_ctx_flush_end(ctx)) // wait previous cmd if not completed + return; + LOG(VKVG_LOG_DBG_ARRAYS, "resize VBO: %d -> ", ctx->sizeVBO); + ctx->sizeVBO = new_size; + uint32_t mod = ctx->sizeVBO % VKVG_VBO_SIZE; + if (mod > 0) + ctx->sizeVBO += VKVG_VBO_SIZE - mod; + LOG(VKVG_LOG_DBG_ARRAYS, "%d\n", ctx->sizeVBO); + vkh_buffer_resize(&ctx->vertices, ctx->sizeVBO * sizeof(Vertex), true); } -void _add_vertexf (VkvgContext ctx, float x, float y){ - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - pVert->pos.x = x; - pVert->pos.y = y; - pVert->color = ctx->curColor; - pVert->uv.z = -1; - LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); - ctx->vertCount++; - _check_vertex_cache_size(ctx); +void _resize_ibo(VkvgContext ctx, size_t new_size) { + if (!_wait_ctx_flush_end(ctx)) // wait previous cmd if not completed + return; + ctx->sizeIBO = new_size; + uint32_t mod = ctx->sizeIBO % VKVG_IBO_SIZE; + if (mod > 0) + ctx->sizeIBO += VKVG_IBO_SIZE - mod; + LOG(VKVG_LOG_DBG_ARRAYS, "resize IBO: new size: %d\n", ctx->sizeIBO); + vkh_buffer_resize(&ctx->indices, ctx->sizeIBO * sizeof(VKVG_IBO_INDEX_TYPE), true); } -void _add_vertexf_unchecked (VkvgContext ctx, float x, float y){ - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - pVert->pos.x = x; - pVert->pos.y = y; - pVert->color = ctx->curColor; - pVert->uv.z = -1; - LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); - ctx->vertCount++; +void _add_vertexf(VkvgContext ctx, float x, float y) { + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + pVert->pos.x = x; + pVert->pos.y = y; + pVert->color = ctx->curColor; + pVert->uv.z = -1; + LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); + ctx->vertCount++; + _check_vertex_cache_size(ctx); } -void _add_vertex(VkvgContext ctx, Vertex v){ - ctx->vertexCache[ctx->vertCount] = v; - LOG(VKVG_LOG_INFO_VBO, "Add Vertex %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", ctx->vertCount, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.uv.z, v.color); - ctx->vertCount++; - _check_vertex_cache_size(ctx); +void _add_vertexf_unchecked(VkvgContext ctx, float x, float y) { + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + pVert->pos.x = x; + pVert->pos.y = y; + pVert->color = ctx->curColor; + pVert->uv.z = -1; + LOG(VKVG_LOG_INFO_VBO, "Add Vertexf %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, pVert->pos.x, pVert->pos.y, pVert->uv.x, pVert->uv.y, pVert->uv.z, pVert->color); + ctx->vertCount++; } -void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v){ - ctx->vertexCache[idx] = v; +void _add_vertex(VkvgContext ctx, Vertex v) { + ctx->vertexCache[ctx->vertCount] = v; + LOG(VKVG_LOG_INFO_VBO, "Add Vertex %10d: pos:(%10.4f, %10.4f) uv:(%10.4f,%10.4f,%10.4f) color:0x%.8x \n", + ctx->vertCount, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.uv.z, v.color); + ctx->vertCount++; + _check_vertex_cache_size(ctx); } +void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v) { ctx->vertexCache[idx] = v; } #ifdef VKVG_FILL_NZ_GLUTESS -void _add_indice (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { - ctx->indexCache[ctx->indCount++] = i; - _check_index_cache_size(ctx); +void _add_indice(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + ctx->indexCache[ctx->indCount++] = i; + _check_index_cache_size(ctx); } -void _add_indice_for_fan (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = ctx->tesselator_fan_start; - inds[1] = ctx->indexCache[ctx->indCount-1]; - inds[2] = i; - ctx->indCount+=3; - _check_index_cache_size(ctx); +void _add_indice_for_fan(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = ctx->tesselator_fan_start; + inds[1] = ctx->indexCache[ctx->indCount - 1]; + inds[2] = i; + ctx->indCount += 3; + _check_index_cache_size(ctx); } -void _add_indice_for_strip (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i, bool odd) { - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - if (odd) { - inds[0] = ctx->indexCache[ctx->indCount-2]; - inds[1] = i; - inds[2] = ctx->indexCache[ctx->indCount-1]; - } else { - inds[0] = ctx->indexCache[ctx->indCount-1]; - inds[1] = ctx->indexCache[ctx->indCount-2]; - inds[2] = i; - } - ctx->indCount+=3; - _check_index_cache_size(ctx); +void _add_indice_for_strip(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i, bool odd) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + if (odd) { + inds[0] = ctx->indexCache[ctx->indCount - 2]; + inds[1] = i; + inds[2] = ctx->indexCache[ctx->indCount - 1]; + } else { + inds[0] = ctx->indexCache[ctx->indCount - 1]; + inds[1] = ctx->indexCache[ctx->indCount - 2]; + inds[2] = i; + } + ctx->indCount += 3; + _check_index_cache_size(ctx); } #endif -void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i; - inds[1] = i+2; - inds[2] = i+1; - inds[3] = i+1; - inds[4] = i+2; - inds[5] = i+3; - ctx->indCount+=6; +void _add_tri_indices_for_rect(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i; + inds[1] = i + 2; + inds[2] = i + 1; + inds[3] = i + 1; + inds[4] = i + 2; + inds[5] = i + 3; + ctx->indCount += 6; - _check_index_cache_size(ctx); - LOG(VKVG_LOG_INFO_IBO, "Rectangle IDX: %d %d %d | %d %d %d (count=%d)\n", inds[0], inds[1], inds[2], inds[3], inds[4], inds[5], ctx->indCount); + _check_index_cache_size(ctx); + LOG(VKVG_LOG_INFO_IBO, "Rectangle IDX: %d %d %d | %d %d %d (count=%d)\n", inds[0], inds[1], inds[2], inds[3], + inds[4], inds[5], ctx->indCount); } -void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i0; - inds[1] = i1; - inds[2] = i2; - ctx->indCount+=3; +void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i0; + inds[1] = i1; + inds[2] = i2; + ctx->indCount += 3; - _check_index_cache_size(ctx); - LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0,i1,i2,ctx->indCount); + _check_index_cache_size(ctx); + LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0, i1, i2, ctx->indCount); } -void _add_triangle_indices_unchecked (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2){ - VKVG_IBO_INDEX_TYPE* inds = &ctx->indexCache[ctx->indCount]; - inds[0] = i0; - inds[1] = i1; - inds[2] = i2; - ctx->indCount+=3; +void _add_triangle_indices_unchecked(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, + VKVG_IBO_INDEX_TYPE i2) { + VKVG_IBO_INDEX_TYPE *inds = &ctx->indexCache[ctx->indCount]; + inds[0] = i0; + inds[1] = i1; + inds[2] = i2; + ctx->indCount += 3; - LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0,i1,i2,ctx->indCount); + LOG(VKVG_LOG_INFO_IBO, "Triangle IDX: %d %d %d (indCount=%d)\n", i0, i1, i2, ctx->indCount); } -void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height){ - Vertex v[4] = - { - {{x,y}, ctx->curColor, {0,0,-1}}, - {{x,y+height}, ctx->curColor, {0,0,-1}}, - {{x+width,y}, ctx->curColor, {0,0,-1}}, - {{x+width,y+height},ctx->curColor, {0,0,-1}} - }; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - memcpy (pVert,v,4*sizeof(Vertex)); - ctx->vertCount+=4; +void _vao_add_rectangle(VkvgContext ctx, float x, float y, float width, float height) { + Vertex v[4] = {{{x, y}, ctx->curColor, {0, 0, -1}}, + {{x, y + height}, ctx->curColor, {0, 0, -1}}, + {{x + width, y}, ctx->curColor, {0, 0, -1}}, + {{x + width, y + height}, ctx->curColor, {0, 0, -1}}}; + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + memcpy(pVert, v, 4 * sizeof(Vertex)); + ctx->vertCount += 4; - _check_vertex_cache_size(ctx); + _check_vertex_cache_size(ctx); - _add_tri_indices_for_rect(ctx, firstIdx); + _add_tri_indices_for_rect(ctx, firstIdx); } -//start render pass if not yet started or update push const if requested -void _ensure_renderpass_is_started (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "_ensure_renderpass_is_started\n"); - if (!ctx->cmdStarted) - _start_cmd_for_render_pass(ctx); - else if (ctx->pushCstDirty) - _update_push_constants(ctx); +// start render pass if not yet started or update push const if requested +void _ensure_renderpass_is_started(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "_ensure_renderpass_is_started\n"); + if (!ctx->cmdStarted) + _start_cmd_for_render_pass(ctx); + else if (ctx->pushCstDirty) + _update_push_constants(ctx); } -void _create_cmd_buff (VkvgContext ctx){ - vkh_cmd_buffs_create((VkhDevice)ctx->dev, ctx->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2, ctx->cmdBuffers); +void _create_cmd_buff(VkvgContext ctx) { + vkh_cmd_buffs_create((VkhDevice)ctx->dev, ctx->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 2, ctx->cmdBuffers); #if defined(DEBUG) && defined(ENABLE_VALIDATION) - vkh_device_set_object_name((VkhDevice)ctx->pSurf->dev, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)ctx->cmd, "vkvgCtxCmd"); + vkh_device_set_object_name((VkhDevice)ctx->pSurf->dev, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, + (uint64_t)ctx->cmd, "vkvgCtxCmd"); #endif } -void _clear_attachment (VkvgContext ctx) { - -} +void _clear_attachment(VkvgContext ctx) {} -bool _wait_ctx_flush_end (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); +bool _wait_ctx_flush_end(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "CTX: _wait_flush_fence\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - if (vkh_timeline_wait ((VkhDevice)ctx->dev, ctx->pSurf->timeline, ctx->timelineStep) == VK_SUCCESS) - return true; + if (vkh_timeline_wait((VkhDevice)ctx->dev, ctx->pSurf->timeline, ctx->timelineStep) == VK_SUCCESS) + return true; #else - if (WaitForFences (ctx->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) - return true; + if (WaitForFences(ctx->dev->vkDev, 1, &ctx->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) + return true; #endif - LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); - ctx->status = VKVG_STATUS_TIMEOUT; - return false; + LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); + ctx->status = VKVG_STATUS_TIMEOUT; + return false; } +bool _wait_and_submit_cmd(VkvgContext ctx) { + if (!ctx->cmdStarted) // current cmd buff is empty, be aware that wait is also canceled!! + return true; -bool _wait_and_submit_cmd (VkvgContext ctx){ - if (!ctx->cmdStarted)//current cmd buff is empty, be aware that wait is also canceled!! - return true; - - LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); + LOG(VKVG_LOG_INFO, "CTX: _wait_and_submit_cmd\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - VkvgSurface surf = ctx->pSurf; - VkvgDevice dev = surf->dev; - //vkh_timeline_wait ((VkhDevice)dev, surf->timeline, ct->timelineStep); - if (ctx->pattern && ctx->pattern->type == VKVG_PATTERN_TYPE_SURFACE) { - //add source surface timeline sync. - VkvgSurface source = (VkvgSurface)ctx->pattern->data; - LOCK_SURFACE(surf) - LOCK_SURFACE(source) - LOCK_DEVICE - vkh_cmd_submit_timelined2 (dev->gQueue, &ctx->cmd, - (VkSemaphore[2]){surf->timeline,source->timeline}, - (uint64_t[2]){surf->timelineStep,source->timelineStep}, - (uint64_t[2]){surf->timelineStep+1,source->timelineStep+1}); - surf->timelineStep++; - source->timelineStep++; - ctx->timelineStep = surf->timelineStep; - UNLOCK_DEVICE - UNLOCK_SURFACE(source) - UNLOCK_SURFACE(surf) - } else { - LOCK_SURFACE(surf) - LOCK_DEVICE - vkh_cmd_submit_timelined (dev->gQueue, &ctx->cmd, surf->timeline, surf->timelineStep, surf->timelineStep+1); - surf->timelineStep++; - ctx->timelineStep = surf->timelineStep; - UNLOCK_DEVICE - UNLOCK_SURFACE(surf) - } + VkvgSurface surf = ctx->pSurf; + VkvgDevice dev = surf->dev; + // vkh_timeline_wait ((VkhDevice)dev, surf->timeline, ct->timelineStep); + if (ctx->pattern && ctx->pattern->type == VKVG_PATTERN_TYPE_SURFACE) { + // add source surface timeline sync. + VkvgSurface source = (VkvgSurface)ctx->pattern->data; + LOCK_SURFACE(surf) + LOCK_SURFACE(source) + LOCK_DEVICE + vkh_cmd_submit_timelined2(dev->gQueue, &ctx->cmd, (VkSemaphore[2]){surf->timeline, source->timeline}, + (uint64_t[2]){surf->timelineStep, source->timelineStep}, + (uint64_t[2]){surf->timelineStep + 1, source->timelineStep + 1}); + surf->timelineStep++; + source->timelineStep++; + ctx->timelineStep = surf->timelineStep; + UNLOCK_DEVICE + UNLOCK_SURFACE(source) + UNLOCK_SURFACE(surf) + } else { + LOCK_SURFACE(surf) + LOCK_DEVICE + vkh_cmd_submit_timelined(dev->gQueue, &ctx->cmd, surf->timeline, surf->timelineStep, surf->timelineStep + 1); + surf->timelineStep++; + ctx->timelineStep = surf->timelineStep; + UNLOCK_DEVICE + UNLOCK_SURFACE(surf) + } #else - if (!_wait_ctx_flush_end (ctx)) - return false; - ResetFences (ctx->dev->vkDev, 1, &ctx->flushFence); - _device_submit_cmd (ctx->dev, &ctx->cmd, ctx->flushFence); + if (!_wait_ctx_flush_end(ctx)) + return false; + ResetFences(ctx->dev->vkDev, 1, &ctx->flushFence); + _device_submit_cmd(ctx->dev, &ctx->cmd, ctx->flushFence); #endif - if (ctx->cmd == ctx->cmdBuffers[0]) - ctx->cmd = ctx->cmdBuffers[1]; - else - ctx->cmd = ctx->cmdBuffers[0]; + if (ctx->cmd == ctx->cmdBuffers[0]) + ctx->cmd = ctx->cmdBuffers[1]; + else + ctx->cmd = ctx->cmdBuffers[0]; - ResetCommandBuffer (ctx->cmd, 0); - ctx->cmdStarted = false; - return true; + ResetCommandBuffer(ctx->cmd, 0); + ctx->cmdStarted = false; + return true; } -/*void _explicit_ms_resolve (VkvgContext ctx){//should init cmd before calling this (unused, using automatic resolve by renderpass) - vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); +/*void _explicit_ms_resolve (VkvgContext ctx){//should init cmd before calling this (unused, using automatic resolve by +renderpass) vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout (ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageResolve re = { - .extent = {ctx->pSurf->width, ctx->pSurf->height,1}, - .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} - }; + VkImageResolve re = { + .extent = {ctx->pSurf->width, ctx->pSurf->height,1}, + .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} + }; - vkCmdResolveImage(ctx->cmd, - vkh_image_get_vkimage (ctx->pSurf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (ctx->pSurf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1,&re); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL , - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkCmdResolveImage(ctx->cmd, + vkh_image_get_vkimage (ctx->pSurf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage (ctx->pSurf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1,&re); + vkh_image_set_layout (ctx->cmd, ctx->pSurf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL , + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); }*/ -//pre flush vertices because of vbo or ibo too small, all vertices except last draw call are flushed -//this function expects a vertex offset > 0 -void _flush_vertices_caches_until_vertex_base (VkvgContext ctx) { - _wait_ctx_flush_end (ctx); +// pre flush vertices because of vbo or ibo too small, all vertices except last draw call are flushed +// this function expects a vertex offset > 0 +void _flush_vertices_caches_until_vertex_base(VkvgContext ctx) { + _wait_ctx_flush_end(ctx); - memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->curVertOffset * sizeof (Vertex)); - memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->curIndStart * sizeof (VKVG_IBO_INDEX_TYPE)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->curVertOffset * sizeof(Vertex)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, + ctx->curIndStart * sizeof(VKVG_IBO_INDEX_TYPE)); - //copy remaining vertices and indices to caches starts - //this could be optimized at the cost of additional offsets. - ctx->vertCount -= ctx->curVertOffset; - ctx->indCount -= ctx->curIndStart; - memcpy(ctx->vertexCache, &ctx->vertexCache[ctx->curVertOffset], ctx->vertCount * sizeof (Vertex)); - memcpy(ctx->indexCache, &ctx->indexCache[ctx->curIndStart], ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); + // copy remaining vertices and indices to caches starts + // this could be optimized at the cost of additional offsets. + ctx->vertCount -= ctx->curVertOffset; + ctx->indCount -= ctx->curIndStart; + memcpy(ctx->vertexCache, &ctx->vertexCache[ctx->curVertOffset], ctx->vertCount * sizeof(Vertex)); + memcpy(ctx->indexCache, &ctx->indexCache[ctx->curIndStart], ctx->indCount * sizeof(VKVG_IBO_INDEX_TYPE)); - ctx->curVertOffset = 0; - ctx->curIndStart = 0; + ctx->curVertOffset = 0; + ctx->curIndStart = 0; } -//copy vertex and index caches to the vbo and ibo vkbuffers used by gpu for drawing -//current running cmd has to be completed to free usage of those -void _flush_vertices_caches (VkvgContext ctx) { - if (!_wait_ctx_flush_end (ctx)) - return; +// copy vertex and index caches to the vbo and ibo vkbuffers used by gpu for drawing +// current running cmd has to be completed to free usage of those +void _flush_vertices_caches(VkvgContext ctx) { + if (!_wait_ctx_flush_end(ctx)) + return; - memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->vertCount * sizeof (Vertex)); - memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->indCount * sizeof (VKVG_IBO_INDEX_TYPE)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->vertices), ctx->vertexCache, ctx->vertCount * sizeof(Vertex)); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->indices), ctx->indexCache, ctx->indCount * sizeof(VKVG_IBO_INDEX_TYPE)); - ctx->vertCount = ctx->indCount = ctx->curIndStart = ctx->curVertOffset = 0; + ctx->vertCount = ctx->indCount = ctx->curIndStart = ctx->curVertOffset = 0; } -//this func expect cmdStarted to be true -void _end_render_pass (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "END RENDER PASS: ctx = %p;\n", ctx); - CmdEndRenderPass (ctx->cmd); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +// this func expect cmdStarted to be true +void _end_render_pass(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "END RENDER PASS: ctx = %p;\n", ctx); + CmdEndRenderPass(ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif - ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass; + ctx->renderPassBeginInfo.renderPass = ctx->dev->renderPass; } -void _check_vao_size (VkvgContext ctx) { - if (ctx->vertCount > ctx->sizeVBO || ctx->indCount > ctx->sizeIBO){ - //vbo or ibo buffers too small - if (ctx->cmdStarted) - //if cmd is started buffers, are already bound, so no resize is possible - //instead we flush, and clear vbo and ibo caches - _flush_cmd_until_vx_base (ctx); - if (ctx->vertCount > ctx->sizeVBO) - _resize_vbo(ctx, ctx->sizeVertices); - if (ctx->indCount > ctx->sizeIBO) - _resize_ibo(ctx, ctx->sizeIndices); - } +void _check_vao_size(VkvgContext ctx) { + if (ctx->vertCount > ctx->sizeVBO || ctx->indCount > ctx->sizeIBO) { + // vbo or ibo buffers too small + if (ctx->cmdStarted) + // if cmd is started buffers, are already bound, so no resize is possible + // instead we flush, and clear vbo and ibo caches + _flush_cmd_until_vx_base(ctx); + if (ctx->vertCount > ctx->sizeVBO) + _resize_vbo(ctx, ctx->sizeVertices); + if (ctx->indCount > ctx->sizeIBO) + _resize_ibo(ctx, ctx->sizeIndices); + } } -//stroke and non-zero draw call for solid color flush -void _emit_draw_cmd_undrawn_vertices (VkvgContext ctx){ - if (ctx->indCount == ctx->curIndStart) - return; +// stroke and non-zero draw call for solid color flush +void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx) { + if (ctx->indCount == ctx->curIndStart) + return; - _check_vao_size (ctx); + _check_vao_size(ctx); - _ensure_renderpass_is_started (ctx); + _ensure_renderpass_is_started(ctx); #ifdef VKVG_WIRED_DEBUG - if (vkvg_wired_debug&vkvg_wired_debug_mode_normal) - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - if (vkvg_wired_debug&vkvg_wired_debug_mode_lines) { - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - } - if (vkvg_wired_debug&vkvg_wired_debug_mode_points) { - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); - } - if (vkvg_wired_debug&vkvg_wired_debug_mode_both) - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); + if (vkvg_wired_debug & vkvg_wired_debug_mode_normal) + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + if (vkvg_wired_debug & vkvg_wired_debug_mode_lines) { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineLineList); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + } + if (vkvg_wired_debug & vkvg_wired_debug_mode_points) { + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipelineWired); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + } + if (vkvg_wired_debug & vkvg_wired_debug_mode_both) + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->pSurf->dev->pipe_OVER); #else - CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); + CmdDrawIndexed(ctx->cmd, ctx->indCount - ctx->curIndStart, 1, ctx->curIndStart, (int32_t)ctx->curVertOffset, 0); #endif - LOG(VKVG_LOG_INFO, "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", - ctx, ctx->vertCount - ctx->curVertOffset, - ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, ctx->indCount); + LOG(VKVG_LOG_INFO, + "RECORD DRAW CMD: ctx = %p; vertices = %d; indices = %d (vxOff = %d idxStart = %d idxTot = %d )\n", ctx, + ctx->vertCount - ctx->curVertOffset, ctx->indCount - ctx->curIndStart, ctx->curVertOffset, ctx->curIndStart, + ctx->indCount); - ctx->curIndStart = ctx->indCount; - ctx->curVertOffset = ctx->vertCount; + ctx->curIndStart = ctx->indCount; + ctx->curVertOffset = ctx->vertCount; } -//preflush vertices with drawcommand already emited -void _flush_cmd_until_vx_base (VkvgContext ctx){ - _end_render_pass (ctx); - if (ctx->curVertOffset > 0){ - LOG(VKVG_LOG_INFO, "FLUSH UNTIL VX BASE CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); - _flush_vertices_caches_until_vertex_base (ctx); - } - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); +// preflush vertices with drawcommand already emited +void _flush_cmd_until_vx_base(VkvgContext ctx) { + _end_render_pass(ctx); + if (ctx->curVertOffset > 0) { + LOG(VKVG_LOG_INFO, "FLUSH UNTIL VX BASE CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, + ctx->indCount); + _flush_vertices_caches_until_vertex_base(ctx); + } + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); } -void _flush_cmd_buff (VkvgContext ctx){ - _emit_draw_cmd_undrawn_vertices (ctx); - if (!ctx->cmdStarted) - return; - _end_render_pass (ctx); - LOG(VKVG_LOG_INFO, "FLUSH CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); - _flush_vertices_caches (ctx); - vkh_cmd_end (ctx->cmd); +void _flush_cmd_buff(VkvgContext ctx) { + _emit_draw_cmd_undrawn_vertices(ctx); + if (!ctx->cmdStarted) + return; + _end_render_pass(ctx); + LOG(VKVG_LOG_INFO, "FLUSH CTX: ctx = %p; vertices = %d; indices = %d\n", ctx, ctx->vertCount, ctx->indCount); + _flush_vertices_caches(ctx); + vkh_cmd_end(ctx->cmd); - _wait_and_submit_cmd (ctx); + _wait_and_submit_cmd(ctx); } -//bind correct draw pipeline depending on current OPERATOR -void _bind_draw_pipeline (VkvgContext ctx) { - switch (ctx->curOperator) { - case VKVG_OPERATOR_OVER: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); - break; - case VKVG_OPERATOR_CLEAR: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_CLEAR); - break; - case VKVG_OPERATOR_DIFFERENCE: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_SUB); - break; - default: - CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); - break; - } +// bind correct draw pipeline depending on current OPERATOR +void _bind_draw_pipeline(VkvgContext ctx) { + switch (ctx->curOperator) { + case VKVG_OPERATOR_OVER: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); + break; + case VKVG_OPERATOR_CLEAR: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_CLEAR); + break; + case VKVG_OPERATOR_DIFFERENCE: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_SUB); + break; + default: + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipe_OVER); + break; + } } -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) -const float DBG_LAB_COLOR_RP[4] = {0,0,1,1}; -const float DBG_LAB_COLOR_FSQ[4] = {1,0,0,1}; +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) +const float DBG_LAB_COLOR_RP[4] = {0, 0, 1, 1}; +const float DBG_LAB_COLOR_FSQ[4] = {1, 0, 0, 1}; #endif -void _start_cmd_for_render_pass (VkvgContext ctx) { - LOG(VKVG_LOG_INFO, "START RENDER PASS: ctx = %p\n", ctx); - vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); +void _start_cmd_for_render_pass(VkvgContext ctx) { + LOG(VKVG_LOG_INFO, "START RENDER PASS: ctx = %p\n", ctx); + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || ctx->dev->threadAware){ - VkhImage imgMs = ctx->pSurf->imgMS; - if (imgMs != NULL) - vkh_image_set_layout(ctx->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + if (ctx->pSurf->img->layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL || ctx->dev->threadAware) { + VkhImage imgMs = ctx->pSurf->imgMS; + if (imgMs != NULL) + vkh_image_set_layout(ctx->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout(ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout (ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - } + vkh_image_set_layout(ctx->cmd, ctx->pSurf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_image_set_layout(ctx->cmd, ctx->pSurf->stencil, ctx->dev->stencilAspectFlag, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + } -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "ctx render pass", DBG_LAB_COLOR_RP); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "ctx render pass", DBG_LAB_COLOR_RP); #endif - CmdBeginRenderPass (ctx->cmd, &ctx->renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); - VkViewport viewport = {0,0,(float)ctx->pSurf->width,(float)ctx->pSurf->height,0,1.f}; - CmdSetViewport(ctx->cmd, 0, 1, &viewport); + CmdBeginRenderPass(ctx->cmd, &ctx->renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + VkViewport viewport = {0, 0, (float)ctx->pSurf->width, (float)ctx->pSurf->height, 0, 1.f}; + CmdSetViewport(ctx->cmd, 0, 1, &viewport); - CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); + CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); - VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc,ctx->dsGrad}; - CmdBindDescriptorSets(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineLayout, - 0, 3, dss, 0, NULL); + VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; + CmdBindDescriptorSets(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelineLayout, 0, 3, dss, 0, NULL); - VkDeviceSize offsets[1] = { 0 }; - CmdBindVertexBuffers(ctx->cmd, 0, 1, &ctx->vertices.buffer, offsets); - CmdBindIndexBuffer(ctx->cmd, ctx->indices.buffer, 0, VKVG_VK_INDEX_TYPE); + VkDeviceSize offsets[1] = {0}; + CmdBindVertexBuffers(ctx->cmd, 0, 1, &ctx->vertices.buffer, offsets); + CmdBindIndexBuffer(ctx->cmd, ctx->indices.buffer, 0, VKVG_VK_INDEX_TYPE); - _update_push_constants (ctx); + _update_push_constants(ctx); - _bind_draw_pipeline (ctx); - CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); - ctx->cmdStarted = true; + _bind_draw_pipeline(ctx); + CmdSetStencilCompareMask(ctx->cmd, VK_STENCIL_FRONT_AND_BACK, STENCIL_CLIP_BIT); + ctx->cmdStarted = true; } -//compute inverse mat used in shader when context matrix has changed -//then trigger push constants command -void _set_mat_inv_and_vkCmdPush (VkvgContext ctx) { - ctx->pushConsts.matInv = ctx->pushConsts.mat; - vkvg_matrix_invert (&ctx->pushConsts.matInv); - ctx->pushCstDirty = true; +// compute inverse mat used in shader when context matrix has changed +// then trigger push constants command +void _set_mat_inv_and_vkCmdPush(VkvgContext ctx) { + ctx->pushConsts.matInv = ctx->pushConsts.mat; + vkvg_matrix_invert(&ctx->pushConsts.matInv); + ctx->pushCstDirty = true; } -void _update_push_constants (VkvgContext ctx) { - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants),&ctx->pushConsts); - ctx->pushCstDirty = false; +void _update_push_constants(VkvgContext ctx) { + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants), + &ctx->pushConsts); + ctx->pushCstDirty = false; } -void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat) { - VkvgPattern lastPat = ctx->pattern; - ctx->pattern = pat; - - uint32_t newPatternType = VKVG_PATTERN_TYPE_SOLID; +void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat) { + VkvgPattern lastPat = ctx->pattern; + ctx->pattern = pat; - LOG(VKVG_LOG_INFO, "CTX: _update_cur_pattern: %p -> %p\n", lastPat, pat); + uint32_t newPatternType = VKVG_PATTERN_TYPE_SOLID; - if (pat == NULL) {//solid color - if (lastPat == NULL)//solid - return;//solid to solid transition, no extra action requested - }else - newPatternType = pat->type; + LOG(VKVG_LOG_INFO, "CTX: _update_cur_pattern: %p -> %p\n", lastPat, pat); - switch (newPatternType) { - case VKVG_PATTERN_TYPE_SOLID: - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; - if (lastPat->type == VKVG_PATTERN_TYPE_SURFACE)//unbind current source surface by replacing it with empty texture - _update_descriptor_set (ctx, ctx->dev->emptyImg, ctx->dsSrc); - break; - case VKVG_PATTERN_TYPE_SURFACE: - { - _emit_draw_cmd_undrawn_vertices(ctx); + if (pat == NULL) { // solid color + if (lastPat == NULL) // solid + return; // solid to solid transition, no extra action requested + } else + newPatternType = pat->type; - VkvgSurface surf = (VkvgSurface)pat->data; + switch (newPatternType) { + case VKVG_PATTERN_TYPE_SOLID: + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; + if (lastPat->type == + VKVG_PATTERN_TYPE_SURFACE) // unbind current source surface by replacing it with empty texture + _update_descriptor_set(ctx, ctx->dev->emptyImg, ctx->dsSrc); + break; + case VKVG_PATTERN_TYPE_SURFACE: { + _emit_draw_cmd_undrawn_vertices(ctx); - //flush ctx in two steps to add the src transitioning in the cmd buff - if (ctx->cmdStarted){//transition of img without appropriate dependencies in subpass must be done outside renderpass. - _end_render_pass (ctx); - _flush_vertices_caches (ctx); - } else { - vkh_cmd_begin (ctx->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - ctx->cmdStarted = true; - } + VkvgSurface surf = (VkvgSurface)pat->data; - //transition source surface for sampling - vkh_image_set_layout (ctx->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + // flush ctx in two steps to add the src transitioning in the cmd buff + if (ctx->cmdStarted) { // transition of img without appropriate dependencies in subpass must be done outside + // renderpass. + _end_render_pass(ctx); + _flush_vertices_caches(ctx); + } else { + vkh_cmd_begin(ctx->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + ctx->cmdStarted = true; + } - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; + // transition source surface for sampling + vkh_image_set_layout(ctx->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VkSamplerAddressMode addrMode = 0; - VkFilter filter = VK_FILTER_NEAREST; - switch (pat->extend) { - case VKVG_EXTEND_NONE: - addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; - break; - case VKVG_EXTEND_PAD: - addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - break; - case VKVG_EXTEND_REPEAT: - addrMode = VK_SAMPLER_ADDRESS_MODE_REPEAT; - break; - case VKVG_EXTEND_REFLECT: - addrMode = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; - break; - } - switch (pat->filter) { - case VKVG_FILTER_BILINEAR: - case VKVG_FILTER_BEST: - filter = VK_FILTER_LINEAR; - break; - default: - filter = VK_FILTER_NEAREST; - break; - } - vkh_image_create_sampler (surf->img, filter, filter, - VK_SAMPLER_MIPMAP_MODE_NEAREST, addrMode); + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; - _update_descriptor_set (ctx, surf->img, ctx->dsSrc); + VkSamplerAddressMode addrMode = 0; + VkFilter filter = VK_FILTER_NEAREST; + switch (pat->extend) { + case VKVG_EXTEND_NONE: + addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + break; + case VKVG_EXTEND_PAD: + addrMode = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + break; + case VKVG_EXTEND_REPEAT: + addrMode = VK_SAMPLER_ADDRESS_MODE_REPEAT; + break; + case VKVG_EXTEND_REFLECT: + addrMode = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT; + break; + } + switch (pat->filter) { + case VKVG_FILTER_BILINEAR: + case VKVG_FILTER_BEST: + filter = VK_FILTER_LINEAR; + break; + default: + filter = VK_FILTER_NEAREST; + break; + } + vkh_image_create_sampler(surf->img, filter, filter, VK_SAMPLER_MIPMAP_MODE_NEAREST, addrMode); - if (pat->hasMatrix) { + _update_descriptor_set(ctx, surf->img, ctx->dsSrc); - } + if (pat->hasMatrix) { + } - ctx->pushConsts.source.width = (float)surf->width; - ctx->pushConsts.source.height = (float)surf->height; - break; - } - case VKVG_PATTERN_TYPE_LINEAR: - case VKVG_PATTERN_TYPE_RADIAL: - _flush_cmd_buff (ctx); - if (!_wait_ctx_flush_end (ctx)) - return; + ctx->pushConsts.source.width = (float)surf->width; + ctx->pushConsts.source.height = (float)surf->height; + break; + } + case VKVG_PATTERN_TYPE_LINEAR: + case VKVG_PATTERN_TYPE_RADIAL: + _flush_cmd_buff(ctx); + if (!_wait_ctx_flush_end(ctx)) + return; - if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) - _update_descriptor_set (ctx, ctx->dev->emptyImg, ctx->dsSrc); + if (lastPat && lastPat->type == VKVG_PATTERN_TYPE_SURFACE) + _update_descriptor_set(ctx, ctx->dev->emptyImg, ctx->dsSrc); - vec4 bounds = {{(float)ctx->pSurf->width}, {(float)ctx->pSurf->height}, {0}, {0}};//store img bounds in unused source field - ctx->pushConsts.source = bounds; + vec4 bounds = {{(float)ctx->pSurf->width}, + {(float)ctx->pSurf->height}, + {0}, + {0}}; // store img bounds in unused source field + ctx->pushConsts.source = bounds; - //transform control point with current ctx matrix - vkvg_gradient_t grad = *(vkvg_gradient_t*)pat->data; + // transform control point with current ctx matrix + vkvg_gradient_t grad = *(vkvg_gradient_t *)pat->data; - if (grad.count < 2) { - ctx->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; - return; - } - vkvg_matrix_t mat; - if (pat->hasMatrix) { - vkvg_pattern_get_matrix (pat, &mat); - if (vkvg_matrix_invert (&mat) != VKVG_STATUS_SUCCESS) - mat = VKVG_IDENTITY_MATRIX; - } + if (grad.count < 2) { + ctx->status = VKVG_STATUS_PATTERN_INVALID_GRADIENT; + return; + } + vkvg_matrix_t mat; + if (pat->hasMatrix) { + vkvg_pattern_get_matrix(pat, &mat); + if (vkvg_matrix_invert(&mat) != VKVG_STATUS_SUCCESS) + mat = VKVG_IDENTITY_MATRIX; + } - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[0].x, &grad.cp[0].y); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].x, &grad.cp[0].y); - if (pat->type == VKVG_PATTERN_TYPE_LINEAR) { - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); - } else { - if (pat->hasMatrix) - vkvg_matrix_transform_point (&mat, &grad.cp[1].x, &grad.cp[1].y); - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &grad.cp[1].x, &grad.cp[1].y); + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[0].x, &grad.cp[0].y); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[0].x, &grad.cp[0].y); + if (pat->type == VKVG_PATTERN_TYPE_LINEAR) { + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); + } else { + if (pat->hasMatrix) + vkvg_matrix_transform_point(&mat, &grad.cp[1].x, &grad.cp[1].y); + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &grad.cp[1].x, &grad.cp[1].y); - //radii - if (pat->hasMatrix) { - vkvg_matrix_transform_distance (&mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_distance (&mat, &grad.cp[1].z, &grad.cp[0].w); - } - vkvg_matrix_transform_distance (&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); - vkvg_matrix_transform_distance (&ctx->pushConsts.mat, &grad.cp[1].z, &grad.cp[0].w); - } + // radii + if (pat->hasMatrix) { + vkvg_matrix_transform_distance(&mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_distance(&mat, &grad.cp[1].z, &grad.cp[0].w); + } + vkvg_matrix_transform_distance(&ctx->pushConsts.mat, &grad.cp[0].z, &grad.cp[0].w); + vkvg_matrix_transform_distance(&ctx->pushConsts.mat, &grad.cp[1].z, &grad.cp[0].w); + } - memcpy (vkh_buffer_get_mapped_pointer(&ctx->uboGrad) , &grad, sizeof(vkvg_gradient_t)); - vkh_buffer_flush(&ctx->uboGrad); - break; - } - ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + newPatternType; - ctx->pushCstDirty = true; - if (lastPat) - vkvg_pattern_destroy (lastPat); + memcpy(vkh_buffer_get_mapped_pointer(&ctx->uboGrad), &grad, sizeof(vkvg_gradient_t)); + vkh_buffer_flush(&ctx->uboGrad); + break; + } + ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + newPatternType; + ctx->pushCstDirty = true; + if (lastPat) + vkvg_pattern_destroy(lastPat); } -void _update_descriptor_set (VkvgContext ctx, VkhImage img, VkDescriptorSet ds){ - VkDescriptorImageInfo descSrcTex = vkh_image_get_descriptor (img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - VkWriteDescriptorSet writeDescriptorSet = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ds, - .dstBinding = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &descSrcTex - }; - vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); +void _update_descriptor_set(VkvgContext ctx, VkhImage img, VkDescriptorSet ds) { + VkDescriptorImageInfo descSrcTex = vkh_image_get_descriptor(img, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + VkWriteDescriptorSet writeDescriptorSet = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ds, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &descSrcTex}; + vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); } -void _update_gradient_desc_set (VkvgContext ctx){ - VkDescriptorBufferInfo dbi = {ctx->uboGrad.buffer, 0, VK_WHOLE_SIZE}; - VkWriteDescriptorSet writeDescriptorSet = { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = ctx->dsGrad, - .dstBinding = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .pBufferInfo = &dbi - }; - vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); +void _update_gradient_desc_set(VkvgContext ctx) { + VkDescriptorBufferInfo dbi = {ctx->uboGrad.buffer, 0, VK_WHOLE_SIZE}; + VkWriteDescriptorSet writeDescriptorSet = {.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = ctx->dsGrad, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &dbi}; + vkUpdateDescriptorSets(ctx->dev->vkDev, 1, &writeDescriptorSet, 0, NULL); } /* * Reset currently bound descriptor which image could be destroyed */ /*void _reset_src_descriptor_set (VkvgContext ctx){ - VkvgDevice dev = ctx->pSurf->dev; - //VkDescriptorSet dss[] = {ctx->dsSrc}; - vkFreeDescriptorSets (dev->vkDev, ctx->descriptorPool, 1, &ctx->dsSrc); + VkvgDevice dev = ctx->pSurf->dev; + //VkDescriptorSet dss[] = {ctx->dsSrc}; + vkFreeDescriptorSets (dev->vkDev, ctx->descriptorPool, 1, &ctx->dsSrc); - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = ctx->descriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &dev->dslSrc }; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = ctx->descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &dev->dslSrc }; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); }*/ -void _createDescriptorPool (VkvgContext ctx) { - VkvgDevice dev = ctx->dev; - const VkDescriptorPoolSize descriptorPoolSize[] = { - {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2 }, - {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1 } - }; - VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .maxSets = 3, - .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - .poolSizeCount = 2, - .pPoolSizes = descriptorPoolSize }; - VK_CHECK_RESULT(vkCreateDescriptorPool (dev->vkDev, &descriptorPoolCreateInfo, NULL, &ctx->descriptorPool)); +void _createDescriptorPool(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; + const VkDescriptorPoolSize descriptorPoolSize[] = {{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2}, + {VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1}}; + VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .maxSets = 3, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .poolSizeCount = 2, + .pPoolSizes = descriptorPoolSize}; + VK_CHECK_RESULT(vkCreateDescriptorPool(dev->vkDev, &descriptorPoolCreateInfo, NULL, &ctx->descriptorPool)); } -void _init_descriptor_sets (VkvgContext ctx){ - VkvgDevice dev = ctx->dev; - VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .descriptorPool = ctx->descriptorPool, - .descriptorSetCount = 1, - .pSetLayouts = &dev->dslFont - }; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); - descriptorSetAllocateInfo.pSetLayouts = &dev->dslSrc; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); - descriptorSetAllocateInfo.pSetLayouts = &dev->dslGrad; - VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad)); +void _init_descriptor_sets(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; + VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .descriptorPool = ctx->descriptorPool, + .descriptorSetCount = 1, + .pSetLayouts = &dev->dslFont}; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsFont)); + descriptorSetAllocateInfo.pSetLayouts = &dev->dslSrc; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsSrc)); + descriptorSetAllocateInfo.pSetLayouts = &dev->dslGrad; + VK_CHECK_RESULT(vkAllocateDescriptorSets(dev->vkDev, &descriptorSetAllocateInfo, &ctx->dsGrad)); } -void _release_context_ressources (VkvgContext ctx) { - VkDevice dev = ctx->dev->vkDev; - +void _release_context_ressources(VkvgContext ctx) { + VkDevice dev = ctx->dev->vkDev; + #ifndef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkDestroyFence (dev, ctx->flushFence, NULL); + vkDestroyFence(dev, ctx->flushFence, NULL); #endif - vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); - vkDestroyCommandPool(dev, ctx->cmdPool, NULL); + vkFreeCommandBuffers(dev, ctx->cmdPool, 2, ctx->cmdBuffers); + vkDestroyCommandPool(dev, ctx->cmdPool, NULL); - VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; - vkFreeDescriptorSets (dev, ctx->descriptorPool, 3, dss); + VkDescriptorSet dss[] = {ctx->dsFont, ctx->dsSrc, ctx->dsGrad}; + vkFreeDescriptorSets(dev, ctx->descriptorPool, 3, dss); - vkDestroyDescriptorPool (dev, ctx->descriptorPool,NULL); + vkDestroyDescriptorPool(dev, ctx->descriptorPool, NULL); - vkh_buffer_reset (&ctx->uboGrad); - vkh_buffer_reset (&ctx->indices); - vkh_buffer_reset (&ctx->vertices); + vkh_buffer_reset(&ctx->uboGrad); + vkh_buffer_reset(&ctx->indices); + vkh_buffer_reset(&ctx->vertices); - free(ctx->vertexCache); - free(ctx->indexCache); + free(ctx->vertexCache); + free(ctx->indexCache); - vkh_image_destroy (ctx->fontCacheImg); - //TODO:check this for source counter - //vkh_image_destroy (ctx->source); + vkh_image_destroy(ctx->fontCacheImg); + // TODO:check this for source counter + // vkh_image_destroy (ctx->source); - free(ctx->pathes); - free(ctx->points); + free(ctx->pathes); + free(ctx->points); - free(ctx); + free(ctx); } -//populate vertice buff for stroke -bool _build_vb_step(VkvgContext ctx, stroke_context_t* str, bool isCurve){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; - vec2 p0 = ctx->points[str->cp]; - vec2 v0 = vec2_sub(p0, ctx->points[str->iL]); - vec2 v1 = vec2_sub(ctx->points[str->iR], p0); - float length_v0 = vec2_length(v0); - float length_v1 = vec2_length(v1); - if (length_v0 < FLT_EPSILON || length_v1 < FLT_EPSILON) { - LOG(VKVG_LOG_STROKE, "vb_step discard, length<epsilon: l0:%f l1:%f\n", length_v0, length_v1); - return false; - } - vec2 v0n = vec2_div_s (v0, length_v0); - vec2 v1n = vec2_div_s (v1, length_v1); - float dot = vec2_dot (v0n, v1n); - float det = v0n.x * v1n.y - v0n.y * v1n.x; - if (EQUF(dot,1.0f)) {//colinear - LOG(VKVG_LOG_STROKE, "vb_step discard, dot==1\n"); - return false; - } - - if (EQUF(dot,-1.0f)) {//cusp (could draw line butt?) - vec2 vPerp = vec2_mult_s(vec2_perp (v0n), str->hw); +// populate vertice buff for stroke +bool _build_vb_step(VkvgContext ctx, stroke_context_t *str, bool isCurve) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + vec2 p0 = ctx->points[str->cp]; + vec2 v0 = vec2_sub(p0, ctx->points[str->iL]); + vec2 v1 = vec2_sub(ctx->points[str->iR], p0); + float length_v0 = vec2_length(v0); + float length_v1 = vec2_length(v1); + if (length_v0 < FLT_EPSILON || length_v1 < FLT_EPSILON) { + LOG(VKVG_LOG_STROKE, "vb_step discard, length<epsilon: l0:%f l1:%f\n", length_v0, length_v1); + return false; + } + vec2 v0n = vec2_div_s(v0, length_v0); + vec2 v1n = vec2_div_s(v1, length_v1); + float dot = vec2_dot(v0n, v1n); + float det = v0n.x * v1n.y - v0n.y * v1n.x; + if (EQUF(dot, 1.0f)) { // colinear + LOG(VKVG_LOG_STROKE, "vb_step discard, dot==1\n"); + return false; + } - VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + if (EQUF(dot, -1.0f)) { // cusp (could draw line butt?) + vec2 vPerp = vec2_mult_s(vec2_perp(v0n), str->hw); - v.pos = vec2_add(p0, vPerp); - _add_vertex(ctx, v); - v.pos = vec2_sub(p0, vPerp); - _add_vertex(ctx, v); + VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - _add_triangle_indices(ctx, idx, idx+1, idx+2); - _add_triangle_indices(ctx, idx, idx+2, idx+3); - LOG(VKVG_LOG_STROKE, "vb_step cusp, dot==-1\n"); - return true; - } + v.pos = vec2_add(p0, vPerp); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vPerp); + _add_vertex(ctx, v); - vec2 bisec_n = vec2_norm(vec2_add(v0n,v1n));//bisec/bisec_perp are inverted names - float alpha = acosf(dot); + _add_triangle_indices(ctx, idx, idx + 1, idx + 2); + _add_triangle_indices(ctx, idx, idx + 2, idx + 3); + LOG(VKVG_LOG_STROKE, "vb_step cusp, dot==-1\n"); + return true; + } - if (det<0) - alpha = -alpha; + vec2 bisec_n = vec2_norm(vec2_add(v0n, v1n)); // bisec/bisec_perp are inverted names + float alpha = acosf(dot); - float halfAlpha = alpha / 2.f; - float cosHalfAlpha = cosf(halfAlpha); - float lh = str->hw / cosHalfAlpha; - vec2 bisec_n_perp = vec2_perp(bisec_n); + if (det < 0) + alpha = -alpha; - //limit bisectrice length - float rlh = lh;//rlh is for inside pos tweeks - if (dot < 0.f) - rlh = fminf (rlh, fminf (length_v0, length_v1)); - //--- + float halfAlpha = alpha / 2.f; + float cosHalfAlpha = cosf(halfAlpha); + float lh = str->hw / cosHalfAlpha; + vec2 bisec_n_perp = vec2_perp(bisec_n); - vec2 bisec = vec2_mult_s (bisec_n_perp, rlh); + // limit bisectrice length + float rlh = lh; // rlh is for inside pos tweeks + if (dot < 0.f) + rlh = fminf(rlh, fminf(length_v0, length_v1)); + //--- - VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + vec2 bisec = vec2_mult_s(bisec_n_perp, rlh); - vec2 rlh_inside_pos, rlh_outside_pos; - if (rlh < lh) { - vec2 vnPerp; - if (length_v0 < length_v1) - vnPerp = vec2_perp (v1n); - else - vnPerp = vec2_perp (v0n); - vec2 vHwPerp = vec2_mult_s (vnPerp, str->hw); + VKVG_IBO_INDEX_TYPE idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - double lbc = cosHalfAlpha * rlh; - if (det < 0.f) { - rlh_inside_pos = vec2_add (vec2_add (vec2_mult_s(vnPerp, -lbc), vec2_add(p0, bisec)), vHwPerp); - rlh_outside_pos = vec2_sub (p0, vec2_mult_s (bisec_n_perp, lh)); - } else { - rlh_inside_pos = vec2_sub (vec2_add (vec2_mult_s(vnPerp, lbc), vec2_sub(p0, bisec)), vHwPerp); - rlh_outside_pos = vec2_add (p0, vec2_mult_s (bisec_n_perp, lh)); - } - } else { - if (det < 0.0) { - rlh_inside_pos = vec2_add (p0, bisec); - rlh_outside_pos = vec2_sub (p0, bisec); - } else { - rlh_inside_pos = vec2_sub (p0, bisec); - rlh_outside_pos = vec2_add (p0, bisec); - } - } + vec2 rlh_inside_pos, rlh_outside_pos; + if (rlh < lh) { + vec2 vnPerp; + if (length_v0 < length_v1) + vnPerp = vec2_perp(v1n); + else + vnPerp = vec2_perp(v0n); + vec2 vHwPerp = vec2_mult_s(vnPerp, str->hw); - vkvg_line_join_t join = ctx->lineJoin; + double lbc = cosHalfAlpha * rlh; + if (det < 0.f) { + rlh_inside_pos = vec2_add(vec2_add(vec2_mult_s(vnPerp, -lbc), vec2_add(p0, bisec)), vHwPerp); + rlh_outside_pos = vec2_sub(p0, vec2_mult_s(bisec_n_perp, lh)); + } else { + rlh_inside_pos = vec2_sub(vec2_add(vec2_mult_s(vnPerp, lbc), vec2_sub(p0, bisec)), vHwPerp); + rlh_outside_pos = vec2_add(p0, vec2_mult_s(bisec_n_perp, lh)); + } + } else { + if (det < 0.0) { + rlh_inside_pos = vec2_add(p0, bisec); + rlh_outside_pos = vec2_sub(p0, bisec); + } else { + rlh_inside_pos = vec2_sub(p0, bisec); + rlh_outside_pos = vec2_add(p0, bisec); + } + } - if (isCurve) { - if (dot < 0.8f) - join = VKVG_LINE_JOIN_ROUND; - else - join = VKVG_LINE_JOIN_MITER; - } + vkvg_line_join_t join = ctx->lineJoin; - if (join == VKVG_LINE_JOIN_MITER){ - if (lh > str->lhMax) {//miter limit - double x = (lh - str->lhMax) * cosHalfAlpha; - vec2 bisecPerp = vec2_mult_s (bisec_n, x); - bisec = vec2_mult_s (bisec_n_perp, str->lhMax); - if (det < 0) { - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); + if (isCurve) { + if (dot < 0.8f) + join = VKVG_LINE_JOIN_ROUND; + else + join = VKVG_LINE_JOIN_MITER; + } - vec2 p = vec2_sub(p0, bisec); + if (join == VKVG_LINE_JOIN_MITER) { + if (lh > str->lhMax) { // miter limit + double x = (lh - str->lhMax) * cosHalfAlpha; + vec2 bisecPerp = vec2_mult_s(bisec_n, x); + bisec = vec2_mult_s(bisec_n_perp, str->lhMax); + if (det < 0) { + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); - v.pos = vec2_sub(p, bisecPerp); - _add_vertex(ctx, v); - v.pos = vec2_add(p, bisecPerp); - _add_vertex(ctx, v); + vec2 p = vec2_sub(p0, bisec); - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+4, idx); - _add_triangle_indices(ctx, idx, idx+3, idx+4); - return true; - } else { - vec2 p = vec2_add(p0, bisec); - v.pos = vec2_sub(p, bisecPerp); - _add_vertex(ctx, v); + v.pos = vec2_sub(p, bisecPerp); + _add_vertex(ctx, v); + v.pos = vec2_add(p, bisecPerp); + _add_vertex(ctx, v); - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 4, idx); + _add_triangle_indices(ctx, idx, idx + 3, idx + 4); + return true; + } else { + vec2 p = vec2_add(p0, bisec); + v.pos = vec2_sub(p, bisecPerp); + _add_vertex(ctx, v); - v.pos = vec2_add(p, bisecPerp); - _add_vertex(ctx, v); + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+3, idx+1); - _add_triangle_indices(ctx, idx+1, idx+3, idx+4); - return false; - } + v.pos = vec2_add(p, bisecPerp); + _add_vertex(ctx, v); - } else {//normal miter - if (det < 0) { - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - v.pos = rlh_outside_pos; - _add_vertex(ctx, v); - } else { - v.pos = rlh_outside_pos; - _add_vertex(ctx, v); - v.pos = rlh_inside_pos; - _add_vertex(ctx, v); - } + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 3, idx + 1); + _add_triangle_indices(ctx, idx + 1, idx + 3, idx + 4); + return false; + } - _add_tri_indices_for_rect(ctx, idx); - return false; - } - }else{ - vec2 vp = vec2_perp(v0n); + } else { // normal miter + if (det < 0) { + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + v.pos = rlh_outside_pos; + _add_vertex(ctx, v); + } else { + v.pos = rlh_outside_pos; + _add_vertex(ctx, v); + v.pos = rlh_inside_pos; + _add_vertex(ctx, v); + } - if (det<0){ - if (dot < 0 && rlh < lh) - v.pos = rlh_inside_pos; - else - v.pos = vec2_add (p0, bisec); - _add_vertex(ctx, v); - v.pos = vec2_sub (p0, vec2_mult_s (vp, str->hw)); - }else{ - v.pos = vec2_add (p0, vec2_mult_s (vp, str->hw)); - _add_vertex(ctx, v); - if (dot < 0 && rlh < lh) - v.pos = rlh_inside_pos; - else - v.pos = vec2_sub (p0, bisec); - } - _add_vertex(ctx, v); + _add_tri_indices_for_rect(ctx, idx); + return false; + } + } else { + vec2 vp = vec2_perp(v0n); - if (join == VKVG_LINE_JOIN_BEVEL){ - if (det<0){ - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+4, idx+0); - _add_triangle_indices(ctx, idx, idx+3, idx+4); - }else{ - _add_triangle_indices(ctx, idx, idx+2, idx+1); - _add_triangle_indices(ctx, idx+2, idx+3, idx+1); - _add_triangle_indices(ctx, idx+1, idx+3, idx+4); - } - }else if (join == VKVG_LINE_JOIN_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); - float a = acosf(vp.x); - if (vp.y < 0) - a = -a; + if (det < 0) { + if (dot < 0 && rlh < lh) + v.pos = rlh_inside_pos; + else + v.pos = vec2_add(p0, bisec); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vec2_mult_s(vp, str->hw)); + } else { + v.pos = vec2_add(p0, vec2_mult_s(vp, str->hw)); + _add_vertex(ctx, v); + if (dot < 0 && rlh < lh) + v.pos = rlh_inside_pos; + else + v.pos = vec2_sub(p0, bisec); + } + _add_vertex(ctx, v); - if (det<0){ - a+=M_PIF; - float a1 = a + alpha; - a-=str->arcStep; - while (a > a1){ - _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a-=str->arcStep; - } - }else{ - float a1 = a + alpha; - a+=str->arcStep; - while (a < a1){ - _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a+=str->arcStep; - } - } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - _add_triangle_indices(ctx, idx, idx+2, idx+1); - if (det < 0){ - for (VKVG_IBO_INDEX_TYPE p = idx+2; p < p0Idx; p++) - _add_triangle_indices(ctx, p, p+1, idx); - _add_triangle_indices(ctx, p0Idx, p0Idx+2, idx); - _add_triangle_indices(ctx, idx, p0Idx+1, p0Idx+2); - }else{ - for (VKVG_IBO_INDEX_TYPE p = idx+2; p < p0Idx; p++) - _add_triangle_indices(ctx, p, p+1, idx+1); - _add_triangle_indices(ctx, p0Idx, p0Idx+1, idx+1); - _add_triangle_indices(ctx, idx+1, p0Idx+1, p0Idx+2); - } + if (join == VKVG_LINE_JOIN_BEVEL) { + if (det < 0) { + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 4, idx + 0); + _add_triangle_indices(ctx, idx, idx + 3, idx + 4); + } else { + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + _add_triangle_indices(ctx, idx + 2, idx + 3, idx + 1); + _add_triangle_indices(ctx, idx + 1, idx + 3, idx + 4); + } + } else if (join == VKVG_LINE_JOIN_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); + float a = acosf(vp.x); + if (vp.y < 0) + a = -a; - } + if (det < 0) { + a += M_PIF; + float a1 = a + alpha; + a -= str->arcStep; + while (a > a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a -= str->arcStep; + } + } else { + float a1 = a + alpha; + a += str->arcStep; + while (a < a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a += str->arcStep; + } + } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + _add_triangle_indices(ctx, idx, idx + 2, idx + 1); + if (det < 0) { + for (VKVG_IBO_INDEX_TYPE p = idx + 2; p < p0Idx; p++) + _add_triangle_indices(ctx, p, p + 1, idx); + _add_triangle_indices(ctx, p0Idx, p0Idx + 2, idx); + _add_triangle_indices(ctx, idx, p0Idx + 1, p0Idx + 2); + } else { + for (VKVG_IBO_INDEX_TYPE p = idx + 2; p < p0Idx; p++) + _add_triangle_indices(ctx, p, p + 1, idx + 1); + _add_triangle_indices(ctx, p0Idx, p0Idx + 1, idx + 1); + _add_triangle_indices(ctx, idx + 1, p0Idx + 1, p0Idx + 2); + } + } - vp = vec2_mult_s (vec2_perp(v1n), str->hw); - if (det < 0) - v.pos = vec2_sub (p0, vp); - else - v.pos = vec2_add (p0, vp); - _add_vertex(ctx, v); - } + vp = vec2_mult_s(vec2_perp(v1n), str->hw); + if (det < 0) + v.pos = vec2_sub(p0, vp); + else + v.pos = vec2_add(p0, vp); + _add_vertex(ctx, v); + } -/* -#ifdef DEBUG + /* + #ifdef DEBUG - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v0n,10))); - dlpCount+=2; - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v1n,10))); - dlpCount+=2; - debugLinePoints[dlpCount] = p0; - debugLinePoints[dlpCount+1] = pR; - dlpCount+=2; -#endif*/ - /*if (reducedLH) - return -det; - else*/ - return (det < 0); + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v0n,10))); + dlpCount+=2; + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = _v2add(p0, _vec2dToVec2(_v2Multd(v1n,10))); + dlpCount+=2; + debugLinePoints[dlpCount] = p0; + debugLinePoints[dlpCount+1] = pR; + dlpCount+=2; + #endif*/ + /*if (reducedLH) + return -det; + else*/ + return (det < 0); } -void _draw_stoke_cap (VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart) { - Vertex v = {{0},ctx->curColor,{0,0,-1}}; +void _draw_stoke_cap(VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - if (isStart){ - vec2 vhw = vec2_mult_s (n, str->hw); + if (isStart) { + vec2 vhw = vec2_mult_s(n, str->hw); - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_sub (p0, vhw); + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_sub(p0, vhw); - vhw = vec2_perp (vhw); + vhw = vec2_perp(vhw); - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); + if (ctx->lineCap == VKVG_LINE_CAP_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); - float a = acosf(n.x) + M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a + M_PIF; + float a = acosf(n.x) + M_PIF_2; + if (n.y < 0) + a = M_PIF - a; + float a1 = a + M_PIF; - a += str->arcStep; - while (a < a1){ - _add_vertexf (ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a += str->arcStep; - } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) - _add_triangle_indices (ctx, p0Idx+1, p, p+1); - firstIdx = p0Idx; - } + a += str->arcStep; + while (a < a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a += str->arcStep; + } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + for (VKVG_IBO_INDEX_TYPE p = firstIdx; p < p0Idx; p++) + _add_triangle_indices(ctx, p0Idx + 1, p, p + 1); + firstIdx = p0Idx; + } - v.pos = vec2_add (p0, vhw); - _add_vertex (ctx, v); - v.pos = vec2_sub (p0, vhw); - _add_vertex (ctx, v); + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); - _add_tri_indices_for_rect (ctx, firstIdx); - }else{ - vec2 vhw = vec2_mult_s (n, str->hw); + _add_tri_indices_for_rect(ctx, firstIdx); + } else { + vec2 vhw = vec2_mult_s(n, str->hw); - if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) - p0 = vec2_add (p0, vhw); + if (ctx->lineCap == VKVG_LINE_CAP_SQUARE) + p0 = vec2_add(p0, vhw); - vhw = vec2_perp (vhw); + vhw = vec2_perp(vhw); - v.pos = vec2_add (p0, vhw); - _add_vertex (ctx, v); - v.pos = vec2_sub (p0, vhw); - _add_vertex (ctx, v); + v.pos = vec2_add(p0, vhw); + _add_vertex(ctx, v); + v.pos = vec2_sub(p0, vhw); + _add_vertex(ctx, v); - firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - if (ctx->lineCap == VKVG_LINE_CAP_ROUND){ - if (!str->arcStep) - str->arcStep = _get_arc_step (ctx, str->hw); + if (ctx->lineCap == VKVG_LINE_CAP_ROUND) { + if (!str->arcStep) + str->arcStep = _get_arc_step(ctx, str->hw); - float a = acosf(n.x)+ M_PIF_2; - if (n.y < 0) - a = M_PIF-a; - float a1 = a - M_PIF; + float a = acosf(n.x) + M_PIF_2; + if (n.y < 0) + a = M_PIF - a; + float a1 = a - M_PIF; - a -= str->arcStep; - while ( a > a1){ - _add_vertexf (ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); - a -= str->arcStep; - } + a -= str->arcStep; + while (a > a1) { + _add_vertexf(ctx, cosf(a) * str->hw + p0.x, sinf(a) * str->hw + p0.y); + a -= str->arcStep; + } - VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); - for (VKVG_IBO_INDEX_TYPE p = firstIdx-1 ; p < p0Idx; p++) - _add_triangle_indices (ctx, p+1, p, firstIdx-2); - } - } + VKVG_IBO_INDEX_TYPE p0Idx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset - 1); + for (VKVG_IBO_INDEX_TYPE p = firstIdx - 1; p < p0Idx; p++) + _add_triangle_indices(ctx, p + 1, p, firstIdx - 2); + } + } } -float _draw_dashed_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve) { - //vec2 pL = ctx->points[str->iL]; - vec2 p = ctx->points[str->cp]; - vec2 pR = ctx->points[str->iR]; +float _draw_dashed_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve) { + // vec2 pL = ctx->points[str->iL]; + vec2 p = ctx->points[str->cp]; + vec2 pR = ctx->points[str->iR]; - if (!dc->dashOn)//we test in fact the next dash start, if dashOn = true => next segment is a void. - _build_vb_step (ctx, str, isCurve); + if (!dc->dashOn) // we test in fact the next dash start, if dashOn = true => next segment is a void. + _build_vb_step(ctx, str, isCurve); - vec2 d = vec2_sub (pR, p); - dc->normal = vec2_norm (d); - float segmentLength = vec2_length(d); + vec2 d = vec2_sub(pR, p); + dc->normal = vec2_norm(d); + float segmentLength = vec2_length(d); - while (dc->curDashOffset < segmentLength){ - vec2 p0 = vec2_add (p, vec2_mult_s(dc->normal, dc->curDashOffset)); + while (dc->curDashOffset < segmentLength) { + vec2 p0 = vec2_add(p, vec2_mult_s(dc->normal, dc->curDashOffset)); - _draw_stoke_cap (ctx, str, p0, dc->normal, dc->dashOn); - dc->dashOn ^= true; - dc->curDashOffset += ctx->dashes[dc->curDash]; - if (++dc->curDash == ctx->dashCount) - dc->curDash = 0; - } - dc->curDashOffset -= segmentLength; - dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); - return segmentLength; + _draw_stoke_cap(ctx, str, p0, dc->normal, dc->dashOn); + dc->dashOn ^= true; + dc->curDashOffset += ctx->dashes[dc->curDash]; + if (++dc->curDash == ctx->dashCount) + dc->curDash = 0; + } + dc->curDashOffset -= segmentLength; + dc->curDashOffset = fmodf(dc->curDashOffset, dc->totDashLength); + return segmentLength; } -void _draw_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve) { - str->iR = str->cp + 1; - if (ctx->dashCount > 0) - _draw_dashed_segment(ctx, str, dc, isCurve); - else - _build_vb_step (ctx, str, isCurve); - str->iL = str->cp++; - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) { - Vertex v0 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx]; - Vertex v1 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx + 1]; - _emit_draw_cmd_undrawn_vertices(ctx); - //repeat first 2 vertices for closed pathes - str->firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - _add_vertex(ctx, v0); - _add_vertex(ctx, v1); - ctx->curVertOffset = ctx->vertCount;//prevent redrawing them at the start of the batch - } +void _draw_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve) { + str->iR = str->cp + 1; + if (ctx->dashCount > 0) + _draw_dashed_segment(ctx, str, dc, isCurve); + else + _build_vb_step(ctx, str, isCurve); + str->iL = str->cp++; + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) { + Vertex v0 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx]; + Vertex v1 = ctx->vertexCache[ctx->curVertOffset + str->firstIdx + 1]; + _emit_draw_cmd_undrawn_vertices(ctx); + // repeat first 2 vertices for closed pathes + str->firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + _add_vertex(ctx, v0); + _add_vertex(ctx, v1); + ctx->curVertOffset = ctx->vertCount; // prevent redrawing them at the start of the batch + } } bool ptInTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) { - float dX = p.x-p2.x; - float dY = p.y-p2.y; - float dX21 = p2.x-p1.x; - float dY12 = p1.y-p2.y; - float D = dY12*(p0.x-p2.x) + dX21*(p0.y-p2.y); - float s = dY12*dX + dX21*dY; - float t = (p2.y-p0.y)*dX + (p0.x-p2.x)*dY; - if (D<0) - return (s<=0) && (t<=0) && (s+t>=D); - return (s>=0) && (t>=0) && (s+t<=D); + float dX = p.x - p2.x; + float dY = p.y - p2.y; + float dX21 = p2.x - p1.x; + float dY12 = p1.y - p2.y; + float D = dY12 * (p0.x - p2.x) + dX21 * (p0.y - p2.y); + float s = dY12 * dX + dX21 * dY; + float t = (p2.y - p0.y) * dX + (p0.x - p2.x) * dY; + if (D < 0) + return (s <= 0) && (t <= 0) && (s + t >= D); + return (s >= 0) && (t >= 0) && (s + t <= D); } -void _free_ctx_save (vkvg_context_save_t* sav){ - if (sav->dashCount > 0) - free (sav->dashes); - if (sav->pattern) - vkvg_pattern_destroy(sav->pattern); - free (sav); +void _free_ctx_save(vkvg_context_save_t *sav) { + if (sav->dashCount > 0) + free(sav->dashes); + if (sav->pattern) + vkvg_pattern_destroy(sav->pattern); + free(sav); } - -#define M_APPROXIMATION_SCALE 1.0 -#define M_ANGLE_TOLERANCE 0.01 -#define M_CUSP_LIMIT 0.01 -#define CURVE_RECURSION_LIMIT 100 -#define CURVE_COLLINEARITY_EPSILON 1.7 +#define M_APPROXIMATION_SCALE 1.0 +#define M_ANGLE_TOLERANCE 0.01 +#define M_CUSP_LIMIT 0.01 +#define CURVE_RECURSION_LIMIT 100 +#define CURVE_COLLINEARITY_EPSILON 1.7 #define CURVE_ANGLE_TOLERANCE_EPSILON 0.001 -//no floating point arithmetic operation allowed in macro. -#pragma warning(disable:4127) -void _recursive_bezier (VkvgContext ctx, float distanceTolerance, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - unsigned level) { - if(level > CURVE_RECURSION_LIMIT) - { - return; - } +// no floating point arithmetic operation allowed in macro. +#pragma warning(disable : 4127) +void _recursive_bezier(VkvgContext ctx, float distanceTolerance, float x1, float y1, float x2, float y2, float x3, + float y3, float x4, float y4, unsigned level) { + if (level > CURVE_RECURSION_LIMIT) { + return; + } - // Calculate all the mid-points of the line segments - //---------------------- - float x12 = (x1 + x2) / 2; - float y12 = (y1 + y2) / 2; - float x23 = (x2 + x3) / 2; - float y23 = (y2 + y3) / 2; - float x34 = (x3 + x4) / 2; - float y34 = (y3 + y4) / 2; - float x123 = (x12 + x23) / 2; - float y123 = (y12 + y23) / 2; - float x234 = (x23 + x34) / 2; - float y234 = (y23 + y34) / 2; - float x1234 = (x123 + x234) / 2; - float y1234 = (y123 + y234) / 2; + // Calculate all the mid-points of the line segments + //---------------------- + float x12 = (x1 + x2) / 2; + float y12 = (y1 + y2) / 2; + float x23 = (x2 + x3) / 2; + float y23 = (y2 + y3) / 2; + float x34 = (x3 + x4) / 2; + float y34 = (y3 + y4) / 2; + float x123 = (x12 + x23) / 2; + float y123 = (y12 + y23) / 2; + float x234 = (x23 + x34) / 2; + float y234 = (y23 + y34) / 2; + float x1234 = (x123 + x234) / 2; + float y1234 = (y123 + y234) / 2; - if(level > 0) // Enforce subdivision first time - { - // Try to approximate the full cubic curve by a single straight line - //------------------ - float dx = x4-x1; - float dy = y4-y1; + if (level > 0) // Enforce subdivision first time + { + // Try to approximate the full cubic curve by a single straight line + //------------------ + float dx = x4 - x1; + float dy = y4 - y1; - float d2 = fabsf(((x2 - x4) * dy - (y2 - y4) * dx)); - float d3 = fabsf(((x3 - x4) * dy - (y3 - y4) * dx)); + float d2 = fabsf(((x2 - x4) * dy - (y2 - y4) * dx)); + float d3 = fabsf(((x3 - x4) * dy - (y3 - y4) * dx)); - float da1, da2; + float da1, da2; - if(d2 > CURVE_COLLINEARITY_EPSILON && d3 > CURVE_COLLINEARITY_EPSILON) - { - // Regular care - //----------------- - if((d2 + d3)*(d2 + d3) <= (dx*dx + dy*dy) * distanceTolerance) - { - // If the curvature doesn't exceed the distance_tolerance value - // we tend to finish subdivisions. - //---------------------- - if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { - _add_point(ctx, x1234, y1234); - return; - } + if (d2 > CURVE_COLLINEARITY_EPSILON && d3 > CURVE_COLLINEARITY_EPSILON) { + // Regular care + //----------------- + if ((d2 + d3) * (d2 + d3) <= (dx * dx + dy * dy) * distanceTolerance) { + // If the curvature doesn't exceed the distance_tolerance value + // we tend to finish subdivisions. + //---------------------- + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } - // Angle & Cusp Condition - //---------------------- - float a23 = atan2f(y3 - y2, x3 - x2); - da1 = fabsf(a23 - atan2f(y2 - y1, x2 - x1)); - da2 = fabsf(atan2f(y4 - y3, x4 - x3) - a23); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; - if(da2 >= M_PIF) da2 = M_2_PIF - da2; + // Angle & Cusp Condition + //---------------------- + float a23 = atan2f(y3 - y2, x3 - x2); + da1 = fabsf(a23 - atan2f(y2 - y1, x2 - x1)); + da2 = fabsf(atan2f(y4 - y3, x4 - x3) - a23); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; + if (da2 >= M_PIF) + da2 = M_2_PIF - da2; - if(da1 + da2 < (float)M_ANGLE_TOLERANCE) - { - // Finally we can stop the recursion - //---------------------- - _add_point (ctx, x1234, y1234); - return; - } + if (da1 + da2 < (float)M_ANGLE_TOLERANCE) { + // Finally we can stop the recursion + //---------------------- + _add_point(ctx, x1234, y1234); + return; + } - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x2, y2); - return; - } + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x2, y2); + return; + } - if(da2 > M_CUSP_LIMIT) - { - _add_point (ctx, x3, y3); - return; - } - } - } - } else { - if(d2 > CURVE_COLLINEARITY_EPSILON) - { - // p1,p3,p4 are collinear, p2 is considerable - //---------------------- - if(d2 * d2 <= distanceTolerance * (dx*dx + dy*dy)) - { - if(M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) - { - _add_point (ctx, x1234, y1234); - return; - } + if (da2 > M_CUSP_LIMIT) { + _add_point(ctx, x3, y3); + return; + } + } + } + } else { + if (d2 > CURVE_COLLINEARITY_EPSILON) { + // p1,p3,p4 are collinear, p2 is considerable + //---------------------- + if (d2 * d2 <= distanceTolerance * (dx * dx + dy * dy)) { + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } - // Angle Condition - //---------------------- - da1 = fabsf(atan2f(y3 - y2, x3 - x2) - atan2f(y2 - y1, x2 - x1)); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; + // Angle Condition + //---------------------- + da1 = fabsf(atan2f(y3 - y2, x3 - x2) - atan2f(y2 - y1, x2 - x1)); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; - if(da1 < M_ANGLE_TOLERANCE) - { - _add_point (ctx, x2, y2); - _add_point (ctx, x3, y3); - return; - } + if (da1 < M_ANGLE_TOLERANCE) { + _add_point(ctx, x2, y2); + _add_point(ctx, x3, y3); + return; + } - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x2, y2); - return; - } - } - } - } else if(d3 > CURVE_COLLINEARITY_EPSILON) { - // p1,p2,p4 are collinear, p3 is considerable - //---------------------- - if(d3 * d3 <= distanceTolerance* (dx*dx + dy*dy)) - { - if(M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) - { - _add_point (ctx, x1234, y1234); - return; - } + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x2, y2); + return; + } + } + } + } else if (d3 > CURVE_COLLINEARITY_EPSILON) { + // p1,p2,p4 are collinear, p3 is considerable + //---------------------- + if (d3 * d3 <= distanceTolerance * (dx * dx + dy * dy)) { + if (M_ANGLE_TOLERANCE < CURVE_ANGLE_TOLERANCE_EPSILON) { + _add_point(ctx, x1234, y1234); + return; + } - // Angle Condition - //---------------------- - da1 = fabsf(atan2f(y4 - y3, x4 - x3) - atan2f(y3 - y2, x3 - x2)); - if(da1 >= M_PIF) da1 = M_2_PIF - da1; + // Angle Condition + //---------------------- + da1 = fabsf(atan2f(y4 - y3, x4 - x3) - atan2f(y3 - y2, x3 - x2)); + if (da1 >= M_PIF) + da1 = M_2_PIF - da1; - if(da1 < M_ANGLE_TOLERANCE) - { - _add_point (ctx, x2, y2); - _add_point (ctx, x3, y3); - return; - } + if (da1 < M_ANGLE_TOLERANCE) { + _add_point(ctx, x2, y2); + _add_point(ctx, x3, y3); + return; + } - if(M_CUSP_LIMIT != 0.0) - { - if(da1 > M_CUSP_LIMIT) - { - _add_point (ctx, x3, y3); - return; - } - } - } - } - else - { - // Collinear case - //----------------- - dx = x1234 - (x1 + x4) / 2; - dy = y1234 - (y1 + y4) / 2; - if(dx*dx + dy*dy <= distanceTolerance) - { - _add_point (ctx, x1234, y1234); - return; - } - } - } - } + if (M_CUSP_LIMIT != 0.0) { + if (da1 > M_CUSP_LIMIT) { + _add_point(ctx, x3, y3); + return; + } + } + } + } else { + // Collinear case + //----------------- + dx = x1234 - (x1 + x4) / 2; + dy = y1234 - (y1 + y4) / 2; + if (dx * dx + dy * dy <= distanceTolerance) { + _add_point(ctx, x1234, y1234); + return; + } + } + } + } - // Continue subdivision - //---------------------- - _recursive_bezier (ctx, distanceTolerance, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); - _recursive_bezier (ctx, distanceTolerance,x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); + // Continue subdivision + //---------------------- + _recursive_bezier(ctx, distanceTolerance, x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); + _recursive_bezier(ctx, distanceTolerance, x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); } -#pragma warning(default:4127) -void _line_to (VkvgContext ctx, float x, float y) { - vec2 p = {x,y}; - if (!_current_path_is_empty (ctx)){ - //prevent adding the same point - if (vec2_equ (_get_current_position (ctx), p)) - return; - } - _add_point (ctx, x, y); - ctx->simpleConvex = false; +#pragma warning(default : 4127) +void _line_to(VkvgContext ctx, float x, float y) { + vec2 p = {x, y}; + if (!_current_path_is_empty(ctx)) { + // prevent adding the same point + if (vec2_equ(_get_current_position(ctx), p)) + return; + } + _add_point(ctx, x, y); + ctx->simpleConvex = false; } -void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, float _rx, float _ry, float phi) { - if (ctx->status) - return; +void _elliptic_arc(VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, + float _rx, float _ry, float phi) { + if (ctx->status) + return; - if (_rx==0||_ry==0) { - if (_current_path_is_empty(ctx)) - vkvg_move_to(ctx, x1, y1); - vkvg_line_to(ctx, x2, y2); - return; - } - float rx = fabsf(_rx); - float ry = fabsf(_ry); + if (_rx == 0 || _ry == 0) { + if (_current_path_is_empty(ctx)) + vkvg_move_to(ctx, x1, y1); + vkvg_line_to(ctx, x2, y2); + return; + } + float rx = fabsf(_rx); + float ry = fabsf(_ry); - mat2 m = { - { cosf (phi), sinf (phi)}, - {-sinf (phi), cosf (phi)} - }; - vec2 p = {(x1 - x2)/2, (y1 - y2)/2}; - vec2 p1 = mat2_mult_vec2 (m, p); + mat2 m = {{cosf(phi), sinf(phi)}, {-sinf(phi), cosf(phi)}}; + vec2 p = {(x1 - x2) / 2, (y1 - y2) / 2}; + vec2 p1 = mat2_mult_vec2(m, p); - //radii corrections - double lambda = powf (p1.x, 2) / powf (rx, 2) + powf (p1.y, 2) / powf (ry, 2); - if (lambda > 1) { - lambda = sqrtf (lambda); - rx *= lambda; - ry *= lambda; - } + // radii corrections + double lambda = powf(p1.x, 2) / powf(rx, 2) + powf(p1.y, 2) / powf(ry, 2); + if (lambda > 1) { + lambda = sqrtf(lambda); + rx *= lambda; + ry *= lambda; + } - p = (vec2){rx * p1.y / ry, -ry * p1.x / rx}; + p = (vec2){rx * p1.y / ry, -ry * p1.x / rx}; - vec2 cp = vec2_mult_s (p, sqrtf (fabsf ( - (powf (rx,2) * powf (ry,2) - powf (rx,2) * powf (p1.y, 2) - powf (ry,2) * powf (p1.x, 2)) / - (powf (rx,2) * powf (p1.y, 2) + powf (ry,2) * powf (p1.x, 2)) - ))); + vec2 cp = vec2_mult_s( + p, sqrtf(fabsf((powf(rx, 2) * powf(ry, 2) - powf(rx, 2) * powf(p1.y, 2) - powf(ry, 2) * powf(p1.x, 2)) / + (powf(rx, 2) * powf(p1.y, 2) + powf(ry, 2) * powf(p1.x, 2))))); - if (largeArc == counterClockWise) - vec2_inv(&cp); + if (largeArc == counterClockWise) + vec2_inv(&cp); - m = (mat2) { - {cosf (phi),-sinf (phi)}, - {sinf (phi), cosf (phi)} - }; - p = (vec2){(x1 + x2)/2, (y1 + y2)/2}; - vec2 c = vec2_add (mat2_mult_vec2(m, cp) , p); + m = (mat2){{cosf(phi), -sinf(phi)}, {sinf(phi), cosf(phi)}}; + p = (vec2){(x1 + x2) / 2, (y1 + y2) / 2}; + vec2 c = vec2_add(mat2_mult_vec2(m, cp), p); - vec2 u = vec2_unit_x; - vec2 v = {(p1.x-cp.x)/rx, (p1.y-cp.y)/ry}; - double sa = acosf (vec2_dot (u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); - if (isnan(sa)) - sa=M_PIF; - if (u.x*v.y-u.y*v.x < 0) - sa = -sa; + vec2 u = vec2_unit_x; + vec2 v = {(p1.x - cp.x) / rx, (p1.y - cp.y) / ry}; + double sa = acosf(vec2_dot(u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); + if (isnan(sa)) + sa = M_PIF; + if (u.x * v.y - u.y * v.x < 0) + sa = -sa; - u = v; - v = (vec2) {(-p1.x-cp.x)/rx, (-p1.y-cp.y)/ry}; - double delta_theta = acosf (vec2_dot (u, v) / (fabsf(vec2_length (v)) * fabsf(vec2_length (u)))); - if (isnan(delta_theta)) - delta_theta=M_PIF; - if (u.x*v.y-u.y*v.x < 0) - delta_theta = -delta_theta; + u = v; + v = (vec2){(-p1.x - cp.x) / rx, (-p1.y - cp.y) / ry}; + double delta_theta = acosf(vec2_dot(u, v) / (fabsf(vec2_length(v)) * fabsf(vec2_length(u)))); + if (isnan(delta_theta)) + delta_theta = M_PIF; + if (u.x * v.y - u.y * v.x < 0) + delta_theta = -delta_theta; - if (counterClockWise) { - if (delta_theta < 0) - delta_theta += M_PIF * 2.0; - } else if (delta_theta > 0) - delta_theta -= M_PIF * 2.0; + if (counterClockWise) { + if (delta_theta < 0) + delta_theta += M_PIF * 2.0; + } else if (delta_theta > 0) + delta_theta -= M_PIF * 2.0; - m = (mat2) { - {cosf (phi),-sinf (phi)}, - {sinf (phi), cosf (phi)} - }; + m = (mat2){{cosf(phi), -sinf(phi)}, {sinf(phi), cosf(phi)}}; - double theta = sa; - double ea = sa + delta_theta; + double theta = sa; + double ea = sa + delta_theta; - float step = fmaxf(0.001f, fminf(M_PIF, _get_arc_step(ctx, fminf (rx, ry))*0.1f)); + float step = fmaxf(0.001f, fminf(M_PIF, _get_arc_step(ctx, fminf(rx, ry)) * 0.1f)); - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - vec2 xy = vec2_add (mat2_mult_vec2 (m, p), c); + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + vec2 xy = vec2_add(mat2_mult_vec2(m, p), c); - if (_current_path_is_empty(ctx)){ - _set_curve_start (ctx); - _add_point (ctx, xy.x, xy.y); - if (!ctx->pathPtr) - ctx->simpleConvex = true; - else - ctx->simpleConvex = false; - }else{ - _line_to(ctx, xy.x, xy.y); - _set_curve_start (ctx); - ctx->simpleConvex = false; - } + if (_current_path_is_empty(ctx)) { + _set_curve_start(ctx); + _add_point(ctx, xy.x, xy.y); + if (!ctx->pathPtr) + ctx->simpleConvex = true; + else + ctx->simpleConvex = false; + } else { + _line_to(ctx, xy.x, xy.y); + _set_curve_start(ctx); + ctx->simpleConvex = false; + } - _set_curve_start (ctx); + _set_curve_start(ctx); - if (sa < ea) { - theta += step; - while (theta < ea) { - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - theta += step; - } - } else { - theta -= step; - while (theta > ea) { - p = (vec2) { - rx * cosf (theta), - ry * sinf (theta) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - theta -= step; - } - } - p = (vec2) { - rx * cosf (ea), - ry * sinf (ea) - }; - xy = vec2_add (mat2_mult_vec2 (m, p), c); - _add_point (ctx, xy.x, xy.y); - _set_curve_end(ctx); + if (sa < ea) { + theta += step; + while (theta < ea) { + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + theta += step; + } + } else { + theta -= step; + while (theta > ea) { + p = (vec2){rx * cosf(theta), ry * sinf(theta)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + theta -= step; + } + } + p = (vec2){rx * cosf(ea), ry * sinf(ea)}; + xy = vec2_add(mat2_mult_vec2(m, p), c); + _add_point(ctx, xy.x, xy.y); + _set_curve_end(ctx); } +// Even-Odd inside test with stencil buffer implementation. +void _poly_fill(VkvgContext ctx, vec4 *bounds) { + // we anticipate the check for vbo buffer size, ibo is not used in poly_fill + // the polyfill emit a single vertex for each point in the path. + if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->vertCount + ctx->pointCount) { + if (ctx->cmdStarted) { + _end_render_pass(ctx); + if (ctx->vertCount > 0) + _flush_vertices_caches(ctx); + vkh_cmd_end(ctx->cmd); + _wait_and_submit_cmd(ctx); + _wait_ctx_flush_end(ctx); + if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->pointCount) { + _resize_vbo(ctx, ctx->pointCount + VKVG_ARRAY_THRESHOLD); + _resize_vertex_cache(ctx, ctx->sizeVBO); + } + } else { + _resize_vbo(ctx, ctx->vertCount + ctx->pointCount + VKVG_ARRAY_THRESHOLD); + _resize_vertex_cache(ctx, ctx->sizeVBO); + } -//Even-Odd inside test with stencil buffer implementation. -void _poly_fill (VkvgContext ctx, vec4* bounds){ - //we anticipate the check for vbo buffer size, ibo is not used in poly_fill - //the polyfill emit a single vertex for each point in the path. - if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->vertCount + ctx->pointCount) { - if (ctx->cmdStarted) { - _end_render_pass (ctx); - if (ctx->vertCount > 0) - _flush_vertices_caches (ctx); - vkh_cmd_end (ctx->cmd); - _wait_and_submit_cmd (ctx); - _wait_ctx_flush_end (ctx); - if (ctx->sizeVBO - VKVG_ARRAY_THRESHOLD < ctx->pointCount){ - _resize_vbo (ctx, ctx->pointCount + VKVG_ARRAY_THRESHOLD); - _resize_vertex_cache (ctx, ctx->sizeVBO); - } - }else{ - _resize_vbo (ctx, ctx->vertCount + ctx->pointCount + VKVG_ARRAY_THRESHOLD); - _resize_vertex_cache (ctx, ctx->sizeVBO); - } + _start_cmd_for_render_pass(ctx); + } else { + _ensure_vertex_cache_size(ctx, ctx->pointCount); + _ensure_renderpass_is_started(ctx); + } - _start_cmd_for_render_pass(ctx); - } else { - _ensure_vertex_cache_size (ctx, ctx->pointCount); - _ensure_renderpass_is_started (ctx); - } + CmdBindPipeline(ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelinePolyFill); - CmdBindPipeline (ctx->cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, ctx->dev->pipelinePolyFill); + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; - Vertex v = {{0}, ctx->curColor, {0,0,-1}}; - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)ctx->vertCount; + for (uint32_t i = 0; i < pathPointCount; i++) { + v.pos = ctx->points[i + firstPtIdx]; + ctx->vertexCache[ctx->vertCount++] = v; + if (!bounds) + continue; + // bounds are computed here to scissor the painting operation + // that speed up fill drastically. + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &v.pos.x, &v.pos.y); - for (uint32_t i = 0; i < pathPointCount; i++) { - v.pos = ctx->points [i+firstPtIdx]; - ctx->vertexCache[ctx->vertCount++] = v; - if (!bounds) - continue; - //bounds are computed here to scissor the painting operation - //that speed up fill drastically. - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &v.pos.x, &v.pos.y); + if (v.pos.x < bounds->xMin) + bounds->xMin = v.pos.x; + if (v.pos.x > bounds->xMax) + bounds->xMax = v.pos.x; + if (v.pos.y < bounds->yMin) + bounds->yMin = v.pos.y; + if (v.pos.y > bounds->yMax) + bounds->yMax = v.pos.y; + } - if (v.pos.x < bounds->xMin) - bounds->xMin = v.pos.x; - if (v.pos.x > bounds->xMax) - bounds->xMax = v.pos.x; - if (v.pos.y < bounds->yMin) - bounds->yMin = v.pos.y; - if (v.pos.y > bounds->yMax) - bounds->yMax = v.pos.y; - } + LOG(VKVG_LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, + firstVertIdx, ctx->vertCount - firstVertIdx); + CmdDraw(ctx->cmd, pathPointCount, 1, firstVertIdx, 0); + } + firstPtIdx += pathPointCount; - LOG(VKVG_LOG_INFO_PATH, "\tpoly fill: point count = %d; 1st vert = %d; vert count = %d\n", pathPointCount, firstVertIdx, ctx->vertCount - firstVertIdx); - CmdDraw (ctx->cmd, pathPointCount, 1, firstVertIdx , 0); - } - firstPtIdx += pathPointCount; - - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } - ctx->curVertOffset = ctx->vertCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } + ctx->curVertOffset = ctx->vertCount; } #ifdef VKVG_FILL_NZ_GLUTESS void fan_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - switch (ctx->tesselator_idx_counter) { - case 0: - _add_indice(ctx, i); - ctx->tesselator_fan_start = i; - ctx->tesselator_idx_counter ++; - break; - case 1: - case 2: - _add_indice(ctx, i); - ctx->tesselator_idx_counter ++; - break; - default: - _add_indice_for_fan (ctx, i); - break; - } + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + switch (ctx->tesselator_idx_counter) { + case 0: + _add_indice(ctx, i); + ctx->tesselator_fan_start = i; + ctx->tesselator_idx_counter++; + break; + case 1: + case 2: + _add_indice(ctx, i); + ctx->tesselator_idx_counter++; + break; + default: + _add_indice_for_fan(ctx, i); + break; + } } void strip_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - if (ctx->tesselator_idx_counter < 3) { - _add_indice(ctx, i); - } else - _add_indice_for_strip(ctx, i, ctx->tesselator_idx_counter % 2); - ctx->tesselator_idx_counter ++; + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + if (ctx->tesselator_idx_counter < 3) { + _add_indice(ctx, i); + } else + _add_indice_for_strip(ctx, i, ctx->tesselator_idx_counter % 2); + ctx->tesselator_idx_counter++; } -void triangle_vertex2 (VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; - _add_indice(ctx, i); +void triangle_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) { + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)v; + _add_indice(ctx, i); } -void skip_vertex2 (VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) {} -void begin2(GLenum which, void *poly_data) -{ - VkvgContext ctx = (VkvgContext)poly_data; - switch (which) { - case GL_TRIANGLES: - ctx->vertex_cb = &triangle_vertex2; - break; - case GL_TRIANGLE_STRIP: - ctx->tesselator_idx_counter = 0; - ctx->vertex_cb = &strip_vertex2; - break; - case GL_TRIANGLE_FAN: - ctx->tesselator_idx_counter = ctx->tesselator_fan_start = 0; - ctx->vertex_cb = &fan_vertex2; - break; - default: - fprintf(stderr, "ERROR, can't handle %d\n", (int)which); - ctx->vertex_cb = &skip_vertex2; - } +void skip_vertex2(VKVG_IBO_INDEX_TYPE v, VkvgContext ctx) {} +void begin2(GLenum which, void *poly_data) { + VkvgContext ctx = (VkvgContext)poly_data; + switch (which) { + case GL_TRIANGLES: + ctx->vertex_cb = &triangle_vertex2; + break; + case GL_TRIANGLE_STRIP: + ctx->tesselator_idx_counter = 0; + ctx->vertex_cb = &strip_vertex2; + break; + case GL_TRIANGLE_FAN: + ctx->tesselator_idx_counter = ctx->tesselator_fan_start = 0; + ctx->vertex_cb = &fan_vertex2; + break; + default: + fprintf(stderr, "ERROR, can't handle %d\n", (int)which); + ctx->vertex_cb = &skip_vertex2; + } } -void combine2(const GLdouble newVertex[3], - const void *neighborVertex_s[4], - const GLfloat neighborWeight[4], void **outData, void *poly_data) -{ - VkvgContext ctx = (VkvgContext)poly_data; - Vertex v = {{newVertex[0],newVertex[1]},ctx->curColor, {0,0,-1}}; - *outData = (void*)((unsigned long)(ctx->vertCount - ctx->curVertOffset)); - _add_vertex(ctx, v); +void combine2(const GLdouble newVertex[3], const void *neighborVertex_s[4], const GLfloat neighborWeight[4], + void **outData, void *poly_data) { + VkvgContext ctx = (VkvgContext)poly_data; + Vertex v = {{newVertex[0], newVertex[1]}, ctx->curColor, {0, 0, -1}}; + *outData = (void *)((unsigned long)(ctx->vertCount - ctx->curVertOffset)); + _add_vertex(ctx, v); } -void vertex2(void *vertex_data, void *poly_data) -{ - VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)vertex_data; - VkvgContext ctx = (VkvgContext)poly_data; - ctx->vertex_cb(i, ctx); +void vertex2(void *vertex_data, void *poly_data) { + VKVG_IBO_INDEX_TYPE i = (VKVG_IBO_INDEX_TYPE)vertex_data; + VkvgContext ctx = (VkvgContext)poly_data; + ctx->vertex_cb(i, ctx); } -void _fill_non_zero (VkvgContext ctx){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; - - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; +void _fill_non_zero(VkvgContext ctx) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; - if (ctx->pathPtr == 1 && ctx->pathes[0] & PATH_IS_CONVEX_BIT) { - //simple concave rectangle or circle - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; - _ensure_vertex_cache_size(ctx, pathPointCount); - _ensure_index_cache_size(ctx, (pathPointCount-2)*3); + if (ctx->pathPtr == 1 && ctx->pathes[0] & PATH_IS_CONVEX_BIT) { + // simple concave rectangle or circle + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - VKVG_IBO_INDEX_TYPE i = 0; - while (i < 2){ - v.pos = ctx->points [i++]; - _set_vertex (ctx, ctx->vertCount++, v); - } - while (i < pathPointCount){ - v.pos = ctx->points [i]; - _set_vertex (ctx, ctx->vertCount++, v); - _add_triangle_indices_unchecked(ctx, firstVertIdx, firstVertIdx + i - 1, firstVertIdx + i); - i++; - } - return; - } + _ensure_vertex_cache_size(ctx, pathPointCount); + _ensure_index_cache_size(ctx, (pathPointCount - 2) * 3); + VKVG_IBO_INDEX_TYPE i = 0; + while (i < 2) { + v.pos = ctx->points[i++]; + _set_vertex(ctx, ctx->vertCount++, v); + } + while (i < pathPointCount) { + v.pos = ctx->points[i]; + _set_vertex(ctx, ctx->vertCount++, v); + _add_triangle_indices_unchecked(ctx, firstVertIdx, firstVertIdx + i - 1, firstVertIdx + i); + i++; + } + return; + } - GLUtesselator *tess = gluNewTess(); - gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); - gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid (*) ()) &vertex2); - gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid (*) ()) &begin2); - gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid (*) ()) &combine2); + GLUtesselator *tess = gluNewTess(); + gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); + gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (GLvoid(*)()) & vertex2); + gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (GLvoid(*)()) & begin2); + gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (GLvoid(*)()) & combine2); - gluTessBeginPolygon(tess, ctx); + gluTessBeginPolygon(tess, ctx); - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - gluTessBeginContour(tess); + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + gluTessBeginContour(tess); - VKVG_IBO_INDEX_TYPE i = 0; + VKVG_IBO_INDEX_TYPE i = 0; - while (i < pathPointCount){ - v.pos = ctx->points[i+firstPtIdx]; - double dp[] = {v.pos.x,v.pos.y,0}; - _add_vertex(ctx, v); - gluTessVertex(tess, dp, (void*)((unsigned long)firstVertIdx + i)); - i++; - } - gluTessEndContour(tess); + while (i < pathPointCount) { + v.pos = ctx->points[i + firstPtIdx]; + double dp[] = {v.pos.x, v.pos.y, 0}; + _add_vertex(ctx, v); + gluTessVertex(tess, dp, (void *)((unsigned long)firstVertIdx + i)); + i++; + } + gluTessEndContour(tess); - //limit batch size here to 1/3 of the ibo index type ability - //if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - // _emit_draw_cmd_undrawn_vertices(ctx); - } + // limit batch size here to 1/3 of the ibo index type ability + // if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + // _emit_draw_cmd_undrawn_vertices(ctx); + } - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } - gluTessEndPolygon(tess); + gluTessEndPolygon(tess); - gluDeleteTess(tess); + gluDeleteTess(tess); } #else -//create fill from current path with ear clipping technic -void _fill_non_zero (VkvgContext ctx){ - Vertex v = {{0},ctx->curColor, {0,0,-1}}; +// create fill from current path with ear clipping technic +void _fill_non_zero(VkvgContext ctx) { + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - if (pathPointCount > 2) { - VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - //ear_clip_point* ecps = (ear_clip_point*)malloc(pathPointCount*sizeof(ear_clip_point)); - ear_clip_point ecps[pathPointCount]; - uint32_t ecps_count = pathPointCount; - VKVG_IBO_INDEX_TYPE i = 0; + if (pathPointCount > 2) { + VKVG_IBO_INDEX_TYPE firstVertIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + // ear_clip_point* ecps = (ear_clip_point*)malloc(pathPointCount*sizeof(ear_clip_point)); + ear_clip_point ecps[pathPointCount]; + uint32_t ecps_count = pathPointCount; + VKVG_IBO_INDEX_TYPE i = 0; - //init points link list - while (i < pathPointCount-1){ - v.pos = ctx->points[i+firstPtIdx]; - ear_clip_point ecp = {v.pos, firstVertIdx+i, &ecps[i+1]}; - ecps[i] = ecp; - _add_vertex(ctx, v); - i++; - } + // init points link list + while (i < pathPointCount - 1) { + v.pos = ctx->points[i + firstPtIdx]; + ear_clip_point ecp = {v.pos, firstVertIdx + i, &ecps[i + 1]}; + ecps[i] = ecp; + _add_vertex(ctx, v); + i++; + } - v.pos = ctx->points[i+firstPtIdx]; - ear_clip_point ecp = {v.pos, firstVertIdx+i, ecps}; - ecps[i] = ecp; - _add_vertex(ctx, v); + v.pos = ctx->points[i + firstPtIdx]; + ear_clip_point ecp = {v.pos, firstVertIdx + i, ecps}; + ecps[i] = ecp; + _add_vertex(ctx, v); - ear_clip_point* ecp_current = ecps; - uint32_t tries = 0; + ear_clip_point *ecp_current = ecps; + uint32_t tries = 0; - while (ecps_count > 3) { - if (tries > ecps_count) { - break; - } - ear_clip_point* v0 = ecp_current->next, - *v1 = ecp_current, *v2 = ecp_current->next->next; - if (ecp_zcross (v0, v2, v1)<0){ - ecp_current = ecp_current->next; - tries++; - continue; - } - ear_clip_point* vP = v2->next; - bool isEar = true; - while (vP!=v1){ - if (ptInTriangle (vP->pos, v0->pos, v2->pos, v1->pos)){ - isEar = false; - break; - } - vP = vP->next; - } - if (isEar){ - _add_triangle_indices (ctx, v0->idx, v1->idx, v2->idx); - v1->next = v2; - ecps_count --; - tries = 0; - }else{ - ecp_current = ecp_current->next; - tries++; - } - } - if (ecps_count == 3) - _add_triangle_indices(ctx, ecp_current->next->idx, ecp_current->idx, ecp_current->next->next->idx); + while (ecps_count > 3) { + if (tries > ecps_count) { + break; + } + ear_clip_point *v0 = ecp_current->next, *v1 = ecp_current, *v2 = ecp_current->next->next; + if (ecp_zcross(v0, v2, v1) < 0) { + ecp_current = ecp_current->next; + tries++; + continue; + } + ear_clip_point *vP = v2->next; + bool isEar = true; + while (vP != v1) { + if (ptInTriangle(vP->pos, v0->pos, v2->pos, v1->pos)) { + isEar = false; + break; + } + vP = vP->next; + } + if (isEar) { + _add_triangle_indices(ctx, v0->idx, v1->idx, v2->idx); + v1->next = v2; + ecps_count--; + tries = 0; + } else { + ecp_current = ecp_current->next; + tries++; + } + } + if (ecps_count == 3) + _add_triangle_indices(ctx, ecp_current->next->idx, ecp_current->idx, ecp_current->next->next->idx); - //limit batch size here to 1/3 of the ibo index type ability - if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) - _emit_draw_cmd_undrawn_vertices(ctx); - } + // limit batch size here to 1/3 of the ibo index type ability + if (ctx->vertCount - ctx->curVertOffset > VKVG_IBO_MAX / 3) + _emit_draw_cmd_undrawn_vertices(ctx); + } - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } } #endif -void _vkvg_path_extents (VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2) { - uint32_t ptrPath = 0; - uint32_t firstPtIdx = 0; +void _vkvg_path_extents(VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2) { + uint32_t ptrPath = 0; + uint32_t firstPtIdx = 0; - float xMin = FLT_MAX, yMin = FLT_MAX; - float xMax = FLT_MIN, yMax = FLT_MIN; + float xMin = FLT_MAX, yMin = FLT_MAX; + float xMax = FLT_MIN, yMax = FLT_MIN; - while (ptrPath < ctx->pathPtr){ - uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; + while (ptrPath < ctx->pathPtr) { + uint32_t pathPointCount = ctx->pathes[ptrPath] & PATH_ELT_MASK; - for (uint32_t i = firstPtIdx; i < firstPtIdx + pathPointCount; i++){ - vec2 p = ctx->points[i]; - if (transformed) - vkvg_matrix_transform_point (&ctx->pushConsts.mat, &p.x, &p.y); - if (p.x < xMin) - xMin = p.x; - if (p.x > xMax) - xMax = p.x; - if (p.y < yMin) - yMin = p.y; - if (p.y > yMax) - yMax = p.y; - } + for (uint32_t i = firstPtIdx; i < firstPtIdx + pathPointCount; i++) { + vec2 p = ctx->points[i]; + if (transformed) + vkvg_matrix_transform_point(&ctx->pushConsts.mat, &p.x, &p.y); + if (p.x < xMin) + xMin = p.x; + if (p.x > xMax) + xMax = p.x; + if (p.y < yMin) + yMin = p.y; + if (p.y > yMax) + yMax = p.y; + } - firstPtIdx += pathPointCount; - if (_path_has_curves (ctx, ptrPath)) { - //skip segments lengths used in stroke - ptrPath++; - uint32_t totPts = 0; - while (totPts < pathPointCount) - totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); - }else - ptrPath++; - } - *x1 = xMin; - *x2 = xMax; - *y1 = yMin; - *y2 = yMax; + firstPtIdx += pathPointCount; + if (_path_has_curves(ctx, ptrPath)) { + // skip segments lengths used in stroke + ptrPath++; + uint32_t totPts = 0; + while (totPts < pathPointCount) + totPts += (ctx->pathes[ptrPath++] & PATH_ELT_MASK); + } else + ptrPath++; + } + *x1 = xMin; + *x2 = xMax; + *y1 = yMin; + *y2 = yMax; } -void _draw_full_screen_quad (VkvgContext ctx, vec4* scissor) { -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_start(ctx->cmd, "_draw_full_screen_quad", DBG_LAB_COLOR_FSQ); +void _draw_full_screen_quad(VkvgContext ctx, vec4 *scissor) { +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_start(ctx->cmd, "_draw_full_screen_quad", DBG_LAB_COLOR_FSQ); #endif - if (scissor) { - VkRect2D r = { - {(int32_t)MAX(scissor->xMin, 0), (int32_t)MAX(scissor->yMin, 0)}, - {(int32_t)MAX(scissor->xMax - (int32_t)scissor->xMin + 1, 1), (int32_t)MAX(scissor->yMax - (int32_t)scissor->yMin + 1, 1)} - }; - CmdSetScissor(ctx->cmd, 0, 1, &r); - } + if (scissor) { + VkRect2D r = {{(int32_t)MAX(scissor->xMin, 0), (int32_t)MAX(scissor->yMin, 0)}, + {(int32_t)MAX(scissor->xMax - (int32_t)scissor->xMin + 1, 1), + (int32_t)MAX(scissor->yMax - (int32_t)scissor->yMin + 1, 1)}}; + CmdSetScissor(ctx->cmd, 0, 1, &r); + } - uint32_t firstVertIdx = ctx->vertCount; - _ensure_vertex_cache_size (ctx, 3); + uint32_t firstVertIdx = ctx->vertCount; + _ensure_vertex_cache_size(ctx, 3); - _add_vertexf_unchecked (ctx, -1, -1); - _add_vertexf_unchecked (ctx, 3, -1); - _add_vertexf_unchecked (ctx, -1, 3); + _add_vertexf_unchecked(ctx, -1, -1); + _add_vertexf_unchecked(ctx, 3, -1); + _add_vertexf_unchecked(ctx, -1, 3); - ctx->curVertOffset = ctx->vertCount; + ctx->curVertOffset = ctx->vertCount; - ctx->pushConsts.fsq_patternType |= FULLSCREEN_BIT; - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 24, 4,&ctx->pushConsts.fsq_patternType); - CmdDraw (ctx->cmd,3,1,firstVertIdx,0); - ctx->pushConsts.fsq_patternType &= ~FULLSCREEN_BIT; - CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT, 24, 4,&ctx->pushConsts.fsq_patternType); - if (scissor) - CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); + ctx->pushConsts.fsq_patternType |= FULLSCREEN_BIT; + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 24, 4, + &ctx->pushConsts.fsq_patternType); + CmdDraw(ctx->cmd, 3, 1, firstVertIdx, 0); + ctx->pushConsts.fsq_patternType &= ~FULLSCREEN_BIT; + CmdPushConstants(ctx->cmd, ctx->dev->pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 24, 4, + &ctx->pushConsts.fsq_patternType); + if (scissor) + CmdSetScissor(ctx->cmd, 0, 1, &ctx->bounds); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_cmd_label_end (ctx->cmd); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_cmd_label_end(ctx->cmd); #endif } -void _select_font_face (VkvgContext ctx, const char* name){ - if (strcmp(ctx->selectedFontName, name) == 0) - return; - strcpy (ctx->selectedFontName, name); - ctx->currentFont = NULL; - ctx->currentFontSize = NULL; +void _select_font_face(VkvgContext ctx, const char *name) { + if (strcmp(ctx->selectedFontName, name) == 0) + return; + strcpy(ctx->selectedFontName, name); + ctx->currentFont = NULL; + ctx->currentFontSize = NULL; } diff --git a/src/vkvg_context_internal.h b/src/vkvg_context_internal.h index 3e74ae7..4c598b7 100644 --- a/src/vkvg_context_internal.h +++ b/src/vkvg_context_internal.h @@ -26,56 +26,58 @@ #include "vkvg_fonts.h" #if VKVG_RECORDING - #include "recording/vkvg_record_internal.h" +#include "recording/vkvg_record_internal.h" #else - #define RECORD(ctx,cmd,...) - #define RECORD2(ctx,cmd,...) +#define RECORD(ctx, cmd, ...) +#define RECORD2(ctx, cmd, ...) #endif -#define VKVG_PTS_SIZE 1024 -#define VKVG_VBO_SIZE (VKVG_PTS_SIZE * 4) -#define VKVG_IBO_SIZE (VKVG_VBO_SIZE * 6) -#define VKVG_PATHES_SIZE 16 -#define VKVG_ARRAY_THRESHOLD 8 +#define VKVG_PTS_SIZE 1024 +#define VKVG_VBO_SIZE (VKVG_PTS_SIZE * 4) +#define VKVG_IBO_SIZE (VKVG_VBO_SIZE * 6) +#define VKVG_PATHES_SIZE 16 +#define VKVG_ARRAY_THRESHOLD 8 -#define VKVG_IBO_16 0 -#define VKVG_IBO_32 1 +#define VKVG_IBO_16 0 +#define VKVG_IBO_32 1 -#define VKVG_CUR_IBO_TYPE VKVG_IBO_32//change this only +#define VKVG_CUR_IBO_TYPE VKVG_IBO_32 // change this only #if VKVG_CUR_IBO_TYPE == VKVG_IBO_16 - #define VKVG_IBO_MAX UINT16_MAX - #define VKVG_IBO_INDEX_TYPE uint16_t - #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 +#define VKVG_IBO_MAX UINT16_MAX +#define VKVG_IBO_INDEX_TYPE uint16_t +#define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT16 #else - #define VKVG_IBO_MAX UINT32_MAX - #define VKVG_IBO_INDEX_TYPE uint32_t - #define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 +#define VKVG_IBO_MAX UINT32_MAX +#define VKVG_IBO_INDEX_TYPE uint32_t +#define VKVG_VK_INDEX_TYPE VK_INDEX_TYPE_UINT32 #endif -#define FULLSCREEN_BIT 0x10000000 -#define SRCTYPE_MASK 0x000000FF +#define FULLSCREEN_BIT 0x10000000 +#define SRCTYPE_MASK 0x000000FF #define CreateRgba(r, g, b, a) ((a << 24) | (r << 16) | (g << 8) | b) #ifdef VKVG_PREMULT_ALPHA - #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * a * 255.0f) << 16) | ((int)(g * a * 255.0f) << 8) | (int)(r * a * 255.0f)) +#define CreateRgbaf(r, g, b, a) \ + (((int)(a * 255.0f) << 24) | ((int)(b * a * 255.0f) << 16) | ((int)(g * a * 255.0f) << 8) | (int)(r * a * 255.0f)) #else - #define CreateRgbaf(r, g, b, a) (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) +#define CreateRgbaf(r, g, b, a) \ + (((int)(a * 255.0f) << 24) | ((int)(b * 255.0f) << 16) | ((int)(g * 255.0f) << 8) | (int)(r * 255.0f)) #endif typedef struct { - vec2 pos; - uint32_t color; - vec3 uv; + vec2 pos; + uint32_t color; + vec3 uv; } Vertex; typedef struct { - vec4 source; - vec2 size; - uint32_t fsq_patternType; - float opacity; - vkvg_matrix_t mat; - vkvg_matrix_t matInv; + vec4 source; + vec2 size; + uint32_t fsq_patternType; + float opacity; + vkvg_matrix_t mat; + vkvg_matrix_t matInv; } push_constants; /* context.curClipState may be one of the following, it's set @@ -90,249 +92,244 @@ typedef struct { * - clip_saved: context is clipped and the clip region is saved at that level. */ typedef enum { - vkvg_clip_state_none = 0x00, - vkvg_clip_state_clear = 0x01, - vkvg_clip_state_clip = 0x02, - vkvg_clip_state_clip_saved = 0x06, + vkvg_clip_state_none = 0x00, + vkvg_clip_state_clear = 0x01, + vkvg_clip_state_clip = 0x02, + vkvg_clip_state_clip_saved = 0x06, } vkvg_clip_state_t; typedef struct _vkvg_context_save_t { - struct _vkvg_context_save_t* pNext; + struct _vkvg_context_save_t *pNext; - float lineWidth; - float miterLimit; - uint32_t dashCount; //value count in dash array, 0 if dash not set. - float dashOffset; //an offset for dash - float* dashes; //an array of alternate lengths of on and off stroke. + float lineWidth; + float miterLimit; + uint32_t dashCount; // value count in dash array, 0 if dash not set. + float dashOffset; // an offset for dash + float *dashes; // an array of alternate lengths of on and off stroke. - vkvg_operator_t curOperator; - vkvg_line_cap_t lineCap; - vkvg_line_join_t lineJoint; - vkvg_fill_rule_t curFillRule; + vkvg_operator_t curOperator; + vkvg_line_cap_t lineCap; + vkvg_line_join_t lineJoint; + vkvg_fill_rule_t curFillRule; - long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; - _vkvg_font_identity_t selectedFont; //hold current face and size before cache addition - _vkvg_font_identity_t* currentFont; //font ready for lookup - vkvg_direction_t textDirection; - push_constants pushConsts; - uint32_t curColor; - VkvgPattern pattern; - vkvg_clip_state_t clippingState; + long selectedCharSize; /* Font size*/ + char selectedFontName[FONT_NAME_MAX_SIZE]; + _vkvg_font_identity_t selectedFont; // hold current face and size before cache addition + _vkvg_font_identity_t *currentFont; // font ready for lookup + vkvg_direction_t textDirection; + push_constants pushConsts; + uint32_t curColor; + VkvgPattern pattern; + vkvg_clip_state_t clippingState; } vkvg_context_save_t; typedef struct _vkvg_context_t { - vkvg_status_t status; - uint32_t references; //reference count + vkvg_status_t status; + uint32_t references; // reference count - VkvgDevice dev; - VkvgSurface pSurf; //surface bound to context, set on creation of ctx + VkvgDevice dev; + VkvgSurface pSurf; // surface bound to context, set on creation of ctx #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - uint64_t timelineStep; //context cmd last submission timeline id. + uint64_t timelineStep; // context cmd last submission timeline id. #else - VkFence flushFence; //context fence + VkFence flushFence; // context fence #endif - //VkDescriptorImageInfo sourceDescriptor; //Store view/sampler in context + // VkDescriptorImageInfo sourceDescriptor; //Store view/sampler in context - VkCommandPool cmdPool; //local pools ensure thread safety - VkCommandBuffer cmdBuffers[2]; //double cmd buff for context operations - VkCommandBuffer cmd; //current recording buffer - bool cmdStarted; //prevent flushing empty renderpass - bool pushCstDirty; //prevent pushing to gpu if not requested - VkDescriptorPool descriptorPool; //one pool per thread - VkDescriptorSet dsFont; //fonts glyphs texture atlas descriptor (local for thread safety) - VkDescriptorSet dsSrc; //source ds - VkDescriptorSet dsGrad; //gradient uniform buffer + VkCommandPool cmdPool; // local pools ensure thread safety + VkCommandBuffer cmdBuffers[2]; // double cmd buff for context operations + VkCommandBuffer cmd; // current recording buffer + bool cmdStarted; // prevent flushing empty renderpass + bool pushCstDirty; // prevent pushing to gpu if not requested + VkDescriptorPool descriptorPool; // one pool per thread + VkDescriptorSet dsFont; // fonts glyphs texture atlas descriptor (local for thread safety) + VkDescriptorSet dsSrc; // source ds + VkDescriptorSet dsGrad; // gradient uniform buffer - VkhImage fontCacheImg; //current font cache, may not be the last one, updated only if new glyphs are - //uploaded by the current context + VkhImage fontCacheImg; // current font cache, may not be the last one, updated only if new glyphs are + // uploaded by the current context - VkRect2D bounds; + VkRect2D bounds; - uint32_t curColor; + uint32_t curColor; #if VKVG_FILL_NZ_GLUTESS - void (*vertex_cb)(VKVG_IBO_INDEX_TYPE, VkvgContext);//tesselator vertex callback - VKVG_IBO_INDEX_TYPE tesselator_fan_start; - uint32_t tesselator_idx_counter; + void (*vertex_cb)(VKVG_IBO_INDEX_TYPE, VkvgContext); // tesselator vertex callback + VKVG_IBO_INDEX_TYPE tesselator_fan_start; + uint32_t tesselator_idx_counter; #endif #if VKVG_RECORDING - vkvg_recording_t* recording; + vkvg_recording_t *recording; #endif - vkh_buffer_t uboGrad; //uniform buff obj holdings gradient infos + vkh_buffer_t uboGrad; // uniform buff obj holdings gradient infos - //vk buffers, holds data until flush - vkh_buffer_t indices; //index buffer with persistent map memory - uint32_t sizeIBO; //size of vk ibo - uint32_t sizeIndices; //reserved size - uint32_t indCount; //current indice count + // vk buffers, holds data until flush + vkh_buffer_t indices; // index buffer with persistent map memory + uint32_t sizeIBO; // size of vk ibo + uint32_t sizeIndices; // reserved size + uint32_t indCount; // current indice count - uint32_t curIndStart; //last index recorded in cmd buff - VKVG_IBO_INDEX_TYPE curVertOffset; //vertex offset in draw indexed command + uint32_t curIndStart; // last index recorded in cmd buff + VKVG_IBO_INDEX_TYPE curVertOffset; // vertex offset in draw indexed command - vkh_buffer_t vertices; //vertex buffer with persistent mapped memory - uint32_t sizeVBO; //size of vk vbo size - uint32_t sizeVertices; //reserved size - uint32_t vertCount; //effective vertices count + vkh_buffer_t vertices; // vertex buffer with persistent mapped memory + uint32_t sizeVBO; // size of vk vbo size + uint32_t sizeVertices; // reserved size + uint32_t vertCount; // effective vertices count - Vertex* vertexCache; - VKVG_IBO_INDEX_TYPE* indexCache; + Vertex *vertexCache; + VKVG_IBO_INDEX_TYPE *indexCache; - //pathes, exists until stroke of fill - vec2* points; //points array - uint32_t sizePoints; //reserved size - uint32_t pointCount; //effective points count + // pathes, exists until stroke of fill + vec2 *points; // points array + uint32_t sizePoints; // reserved size + uint32_t pointCount; // effective points count - //pathes array is a list of point count per segment - uint32_t pathPtr; //pointer in the path array - uint32_t* pathes; - uint32_t sizePathes; + // pathes array is a list of point count per segment + uint32_t pathPtr; // pointer in the path array + uint32_t *pathes; + uint32_t sizePathes; - uint32_t segmentPtr; //current segment count in current path having curves - uint32_t subpathCount; //store count of subpath, not straight forward to retrieve from segmented path array - bool simpleConvex; //true if path is single rect or concave closed curve. + uint32_t segmentPtr; // current segment count in current path having curves + uint32_t subpathCount; // store count of subpath, not straight forward to retrieve from segmented path array + bool simpleConvex; // true if path is single rect or concave closed curve. - float lineWidth; - float miterLimit; - uint32_t dashCount; //value count in dash array, 0 if dash not set. - float dashOffset; //an offset for dash - float* dashes; //an array of alternate lengths of on and off stroke. + float lineWidth; + float miterLimit; + uint32_t dashCount; // value count in dash array, 0 if dash not set. + float dashOffset; // an offset for dash + float *dashes; // an array of alternate lengths of on and off stroke. - vkvg_operator_t curOperator; - vkvg_line_cap_t lineCap; - vkvg_line_join_t lineJoin; - vkvg_fill_rule_t curFillRule; + vkvg_operator_t curOperator; + vkvg_line_cap_t lineCap; + vkvg_line_join_t lineJoin; + vkvg_fill_rule_t curFillRule; - long selectedCharSize; /* Font size*/ - char selectedFontName[FONT_NAME_MAX_SIZE]; - //_vkvg_font_t selectedFont; //hold current face and size before cache addition - _vkvg_font_identity_t* currentFont; //font pointing to cached fonts identity - _vkvg_font_t* currentFontSize; //font structure by size ready for lookup - vkvg_direction_t textDirection; + long selectedCharSize; /* Font size*/ + char selectedFontName[FONT_NAME_MAX_SIZE]; + //_vkvg_font_t selectedFont; //hold current face and size before cache addition + _vkvg_font_identity_t *currentFont; // font pointing to cached fonts identity + _vkvg_font_t *currentFontSize; // font structure by size ready for lookup + vkvg_direction_t textDirection; - push_constants pushConsts; - VkvgPattern pattern; + push_constants pushConsts; + VkvgPattern pattern; - vkvg_context_save_t* pSavedCtxs; //last ctx saved ptr - uint8_t curSavBit; //current stencil bit used to save context, 6 bits used by stencil for save/restore - VkhImage* savedStencils; //additional image for saving contexes once more than 6 save/restore are reached - vkvg_clip_state_t curClipState; //current clipping status relative to the previous saved one or clear state if none. + vkvg_context_save_t *pSavedCtxs; // last ctx saved ptr + uint8_t curSavBit; // current stencil bit used to save context, 6 bits used by stencil for save/restore + VkhImage *savedStencils; // additional image for saving contexes once more than 6 save/restore are reached + vkvg_clip_state_t curClipState; // current clipping status relative to the previous saved one or clear state if + // none. - VkClearRect clearRect; - VkRenderPassBeginInfo renderPassBeginInfo; + VkClearRect clearRect; + VkRenderPassBeginInfo renderPassBeginInfo; } vkvg_context; typedef struct _ear_clip_point { - vec2 pos; - VKVG_IBO_INDEX_TYPE idx; - struct _ear_clip_point* next; + vec2 pos; + VKVG_IBO_INDEX_TYPE idx; + struct _ear_clip_point *next; } ear_clip_point; typedef struct { - bool dashOn; - uint32_t curDash; //current dash index - float curDashOffset; //cur dash offset between defined path point and last dash segment(on/off) start - float totDashLength; //total length of dashes - vec2 normal; + bool dashOn; + uint32_t curDash; // current dash index + float curDashOffset; // cur dash offset between defined path point and last dash segment(on/off) start + float totDashLength; // total length of dashes + vec2 normal; } dash_context_t; typedef struct { - uint32_t iL; - uint32_t iR; - uint32_t cp;//current point + uint32_t iL; + uint32_t iR; + uint32_t cp; // current point - VKVG_IBO_INDEX_TYPE firstIdx;//save first point idx for closed path - float hw; //stroke half width, computed once. - float lhMax; //miter limit * line width - float arcStep; //cached arcStep, prevent compute multiple times for same stroke, 0 if not yet computed + VKVG_IBO_INDEX_TYPE firstIdx; // save first point idx for closed path + float hw; // stroke half width, computed once. + float lhMax; // miter limit * line width + float arcStep; // cached arcStep, prevent compute multiple times for same stroke, 0 if not yet computed } stroke_context_t; -void _check_vertex_cache_size (VkvgContext ctx); -void _ensure_vertex_cache_size (VkvgContext ctx, uint32_t addedVerticesCount); -void _resize_vertex_cache (VkvgContext ctx, uint32_t newSize); +void _check_vertex_cache_size(VkvgContext ctx); +void _ensure_vertex_cache_size(VkvgContext ctx, uint32_t addedVerticesCount); +void _resize_vertex_cache(VkvgContext ctx, uint32_t newSize); -void _check_index_cache_size (VkvgContext ctx); -void _ensure_index_cache_size (VkvgContext ctx, uint32_t addedIndicesCount); -void _resize_index_cache (VkvgContext ctx, uint32_t newSize); +void _check_index_cache_size(VkvgContext ctx); +void _ensure_index_cache_size(VkvgContext ctx, uint32_t addedIndicesCount); +void _resize_index_cache(VkvgContext ctx, uint32_t newSize); -bool _check_pathes_array (VkvgContext ctx); +bool _check_pathes_array(VkvgContext ctx); -bool _current_path_is_empty (VkvgContext ctx); -void _finish_path (VkvgContext ctx); -void _clear_path (VkvgContext ctx); -void _remove_last_point (VkvgContext ctx); -bool _path_is_closed (VkvgContext ctx, uint32_t ptrPath); -void _set_curve_start (VkvgContext ctx); -void _set_curve_end (VkvgContext ctx); -bool _path_has_curves (VkvgContext ctx, uint32_t ptrPath); +bool _current_path_is_empty(VkvgContext ctx); +void _finish_path(VkvgContext ctx); +void _clear_path(VkvgContext ctx); +void _remove_last_point(VkvgContext ctx); +bool _path_is_closed(VkvgContext ctx, uint32_t ptrPath); +void _set_curve_start(VkvgContext ctx); +void _set_curve_end(VkvgContext ctx); +bool _path_has_curves(VkvgContext ctx, uint32_t ptrPath); -float _normalizeAngle (float a); -float _get_arc_step (VkvgContext ctx, float radius); +float _normalizeAngle(float a); +float _get_arc_step(VkvgContext ctx, float radius); -vec2 _get_current_position (VkvgContext ctx); -void _add_point (VkvgContext ctx, float x, float y); +vec2 _get_current_position(VkvgContext ctx); +void _add_point(VkvgContext ctx, float x, float y); -void _resetMinMax (VkvgContext ctx); -void _vkvg_path_extents (VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2); -void _draw_stoke_cap (VkvgContext ctx, stroke_context_t* str, vec2 p0, vec2 n, bool isStart); -void _draw_segment (VkvgContext ctx, stroke_context_t* str, dash_context_t* dc, bool isCurve); -float _draw_dashed_segment (VkvgContext ctx, stroke_context_t *str, dash_context_t* dc, bool isCurve); -bool _build_vb_step (VkvgContext ctx, stroke_context_t *str, bool isCurve); +void _resetMinMax(VkvgContext ctx); +void _vkvg_path_extents(VkvgContext ctx, bool transformed, float *x1, float *y1, float *x2, float *y2); +void _draw_stoke_cap(VkvgContext ctx, stroke_context_t *str, vec2 p0, vec2 n, bool isStart); +void _draw_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve); +float _draw_dashed_segment(VkvgContext ctx, stroke_context_t *str, dash_context_t *dc, bool isCurve); +bool _build_vb_step(VkvgContext ctx, stroke_context_t *str, bool isCurve); -void _poly_fill (VkvgContext ctx, vec4 *bounds); -void _fill_non_zero (VkvgContext ctx); -void _draw_full_screen_quad (VkvgContext ctx, vec4 *scissor); +void _poly_fill(VkvgContext ctx, vec4 *bounds); +void _fill_non_zero(VkvgContext ctx); +void _draw_full_screen_quad(VkvgContext ctx, vec4 *scissor); -void _create_gradient_buff (VkvgContext ctx); -void _create_vertices_buff (VkvgContext ctx); -void _add_vertex (VkvgContext ctx, Vertex v); -void _add_vertexf (VkvgContext ctx, float x, float y); -void _set_vertex (VkvgContext ctx, uint32_t idx, Vertex v); -void _add_triangle_indices (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); -void _add_tri_indices_for_rect (VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); +void _create_gradient_buff(VkvgContext ctx); +void _create_vertices_buff(VkvgContext ctx); +void _add_vertex(VkvgContext ctx, Vertex v); +void _add_vertexf(VkvgContext ctx, float x, float y); +void _set_vertex(VkvgContext ctx, uint32_t idx, Vertex v); +void _add_triangle_indices(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i0, VKVG_IBO_INDEX_TYPE i1, VKVG_IBO_INDEX_TYPE i2); +void _add_tri_indices_for_rect(VkvgContext ctx, VKVG_IBO_INDEX_TYPE i); -void _vao_add_rectangle (VkvgContext ctx, float x, float y, float width, float height); +void _vao_add_rectangle(VkvgContext ctx, float x, float y, float width, float height); -void _bind_draw_pipeline (VkvgContext ctx); -void _create_cmd_buff (VkvgContext ctx); -void _check_vao_size (VkvgContext ctx); -void _flush_cmd_buff (VkvgContext ctx); -void _ensure_renderpass_is_started (VkvgContext ctx); -void _emit_draw_cmd_undrawn_vertices (VkvgContext ctx); -void _flush_cmd_until_vx_base (VkvgContext ctx); -bool _wait_ctx_flush_end (VkvgContext ctx); -bool _wait_and_submit_cmd (VkvgContext ctx); -void _update_push_constants (VkvgContext ctx); -void _update_cur_pattern (VkvgContext ctx, VkvgPattern pat); -void _set_mat_inv_and_vkCmdPush (VkvgContext ctx); -void _start_cmd_for_render_pass (VkvgContext ctx); +void _bind_draw_pipeline(VkvgContext ctx); +void _create_cmd_buff(VkvgContext ctx); +void _check_vao_size(VkvgContext ctx); +void _flush_cmd_buff(VkvgContext ctx); +void _ensure_renderpass_is_started(VkvgContext ctx); +void _emit_draw_cmd_undrawn_vertices(VkvgContext ctx); +void _flush_cmd_until_vx_base(VkvgContext ctx); +bool _wait_ctx_flush_end(VkvgContext ctx); +bool _wait_and_submit_cmd(VkvgContext ctx); +void _update_push_constants(VkvgContext ctx); +void _update_cur_pattern(VkvgContext ctx, VkvgPattern pat); +void _set_mat_inv_and_vkCmdPush(VkvgContext ctx); +void _start_cmd_for_render_pass(VkvgContext ctx); -void _createDescriptorPool (VkvgContext ctx); -void _init_descriptor_sets (VkvgContext ctx); -void _update_descriptor_set (VkvgContext ctx, VkhImage img, VkDescriptorSet ds); -void _update_gradient_desc_set (VkvgContext ctx); -void _free_ctx_save (vkvg_context_save_t* sav); +void _createDescriptorPool(VkvgContext ctx); +void _init_descriptor_sets(VkvgContext ctx); +void _update_descriptor_set(VkvgContext ctx, VkhImage img, VkDescriptorSet ds); +void _update_gradient_desc_set(VkvgContext ctx); +void _free_ctx_save(vkvg_context_save_t *sav); void _release_context_ressources(VkvgContext ctx); -static inline float vec2_zcross (vec2 v1, vec2 v2){ - return v1.x*v2.y-v1.y*v2.x; +static inline float vec2_zcross(vec2 v1, vec2 v2) { return v1.x * v2.y - v1.y * v2.x; } +static inline float ecp_zcross(ear_clip_point *p0, ear_clip_point *p1, ear_clip_point *p2) { + return vec2_zcross(vec2_sub(p1->pos, p0->pos), vec2_sub(p2->pos, p0->pos)); } -static inline float ecp_zcross (ear_clip_point* p0, ear_clip_point* p1, ear_clip_point* p2){ - return vec2_zcross (vec2_sub (p1->pos, p0->pos), vec2_sub (p2->pos, p0->pos)); -} -void _recursive_bezier(VkvgContext ctx, float distanceTolerance, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - unsigned level); -void _bezier (VkvgContext ctx, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4); -void _line_to (VkvgContext ctx, float x, float y); -void _elliptic_arc (VkvgContext ctx, float x1, float y1, float x2, float y2, - bool largeArc, bool counterClockWise, float _rx, float _ry, float phi); +void _recursive_bezier(VkvgContext ctx, float distanceTolerance, float x1, float y1, float x2, float y2, float x3, + float y3, float x4, float y4, unsigned level); +void _bezier(VkvgContext ctx, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4); +void _line_to(VkvgContext ctx, float x, float y); +void _elliptic_arc(VkvgContext ctx, float x1, float y1, float x2, float y2, bool largeArc, bool counterClockWise, + float _rx, float _ry, float phi); -void _select_font_face (VkvgContext ctx, const char* name); +void _select_font_face(VkvgContext ctx, const char *name); #endif diff --git a/src/vkvg_device.c b/src/vkvg_device.c index 893d23e..ad54fea 100644 --- a/src/vkvg_device.c +++ b/src/vkvg_device.c @@ -26,295 +26,309 @@ #include "vkh_phyinfo.h" #include "vk_mem_alloc.h" -#define TRY_LOAD_DEVICE_EXT(ext) { \ -if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ - enabledExts[enabledExtsCount++] = #ext; \ -} -void vkvg_device_set_context_cache_size (VkvgDevice dev, uint32_t maxCount) { - if (maxCount == dev->cachedContextMaxCount) - return; +#define TRY_LOAD_DEVICE_EXT(ext) \ + { \ + if (vkh_phyinfo_try_get_extension_properties(pi, #ext, NULL)) \ + enabledExts[enabledExtsCount++] = #ext; \ + } +void vkvg_device_set_context_cache_size(VkvgDevice dev, uint32_t maxCount) { + if (maxCount == dev->cachedContextMaxCount) + return; - dev->cachedContextMaxCount = maxCount; + dev->cachedContextMaxCount = maxCount; - _cached_ctx* cur = dev->cachedContextLast; - while (cur && dev->cachedContextCount > dev->cachedContextMaxCount) { - _release_context_ressources (cur->ctx); - _cached_ctx* prev = cur; - cur = cur->pNext; - free (prev); - dev->cachedContextCount--; - } - dev->cachedContextLast = cur; + _cached_ctx *cur = dev->cachedContextLast; + while (cur && dev->cachedContextCount > dev->cachedContextMaxCount) { + _release_context_ressources(cur->ctx); + _cached_ctx *prev = cur; + cur = cur->pNext; + free(prev); + dev->cachedContextCount--; + } + dev->cachedContextLast = cur; } -void _device_init (VkvgDevice dev, const vkvg_device_create_info_t* info) { - dev->vkDev = info->vkdev; - dev->phy = info->phy; +void _device_init(VkvgDevice dev, const vkvg_device_create_info_t *info) { + dev->vkDev = info->vkdev; + dev->phy = info->phy; dev->instance = info->inst; - dev->hdpi = 72; - dev->vdpi = 72; - dev->samples= info->samples; - if (dev->samples == VK_SAMPLE_COUNT_1_BIT) - dev->deferredResolve = false; + dev->hdpi = 72; + dev->vdpi = 72; + dev->samples = info->samples; + if (dev->samples == VK_SAMPLE_COUNT_1_BIT) + dev->deferredResolve = false; else dev->deferredResolve = info->deferredResolve; - dev->cachedContextMaxCount = VKVG_MAX_CACHED_CONTEXT_COUNT; + dev->cachedContextMaxCount = VKVG_MAX_CACHED_CONTEXT_COUNT; #if VKVG_DBG_STATS - dev->debug_stats = (vkvg_debug_stats_t) {0}; + dev->debug_stats = (vkvg_debug_stats_t){0}; #endif - VkFormat format = FB_COLOR_FORMAT; + VkFormat format = FB_COLOR_FORMAT; - _device_check_best_image_tiling(dev, format); - if (dev->status != VKVG_STATUS_SUCCESS) - return; + _device_check_best_image_tiling(dev, format); + if (dev->status != VKVG_STATUS_SUCCESS) + return; - if (!_device_init_function_pointers (dev)){ - dev->status = VKVG_STATUS_NULL_POINTER; - return; - } + if (!_device_init_function_pointers(dev)) { + dev->status = VKVG_STATUS_NULL_POINTER; + return; + } - VkhPhyInfo phyInfos = vkh_phyinfo_create (dev->phy, NULL); + VkhPhyInfo phyInfos = vkh_phyinfo_create(dev->phy, NULL); dev->phyMemProps = phyInfos->memProps; - dev->gQueue = vkh_queue_create ((VkhDevice)dev, info->qFamIdx, info->qIndex); - //mtx_init (&dev->gQMutex, mtx_plain); + dev->gQueue = vkh_queue_create((VkhDevice)dev, info->qFamIdx, info->qIndex); + // mtx_init (&dev->gQMutex, mtx_plain); - vkh_phyinfo_destroy (phyInfos); + vkh_phyinfo_destroy(phyInfos); #ifdef VKH_USE_VMA - VmaAllocatorCreateInfo allocatorInfo = { - .physicalDevice = info->phy, - .device = info->vkdev - }; - vmaCreateAllocator(&allocatorInfo, (VmaAllocator*)&dev->allocator); + VmaAllocatorCreateInfo allocatorInfo = {.physicalDevice = info->phy, .device = info->vkdev}; + vmaCreateAllocator(&allocatorInfo, (VmaAllocator *)&dev->allocator); #endif - dev->cmdPool= vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - dev->cmd = vkh_cmd_buff_create ((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - dev->fence = vkh_fence_create_signaled ((VkhDevice)dev); + dev->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + dev->cmd = vkh_cmd_buff_create((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); + dev->fence = vkh_fence_create_signaled((VkhDevice)dev); - _device_create_pipeline_cache (dev); - _fonts_cache_create (dev); - if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT){ - dev->renderPass = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); - dev->renderPass_ClearStencil = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); - dev->renderPass_ClearAll = _device_createRenderPassNoResolve (dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); - }else{ - dev->renderPass = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); - dev->renderPass_ClearStencil = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); - dev->renderPass_ClearAll = _device_createRenderPassMS (dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); - } - _device_createDescriptorSetLayout (dev); - _device_setupPipelines (dev); + _device_create_pipeline_cache(dev); + _fonts_cache_create(dev); + if (dev->deferredResolve || dev->samples == VK_SAMPLE_COUNT_1_BIT) { + dev->renderPass = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); + dev->renderPass_ClearStencil = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); + dev->renderPass_ClearAll = + _device_createRenderPassNoResolve(dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); + } else { + dev->renderPass = _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD); + dev->renderPass_ClearStencil = + _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR); + dev->renderPass_ClearAll = + _device_createRenderPassMS(dev, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR); + } + _device_createDescriptorSetLayout(dev); + _device_setupPipelines(dev); - _device_create_empty_texture (dev, format, dev->supportedTiling); + _device_create_empty_texture(dev, format, dev->supportedTiling); #ifdef DEBUG - #if defined(__linux__) && defined(__GLIBC__) - _linux_register_error_handler (); - #endif - #ifdef VKVG_DBG_UTILS - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)dev->cmdPool, "Device Cmd Pool"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)dev->cmd, "Device Cmd Buff"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->fence, "Device Fence"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass, "RP load img/stencil"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearStencil, "RP clear stencil"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, "RP clear all"); +#if defined(__linux__) && defined(__GLIBC__) + _linux_register_error_handler(); +#endif +#ifdef VKVG_DBG_UTILS + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_POOL, (uint64_t)dev->cmdPool, "Device Cmd Pool"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)dev->cmd, "Device Cmd Buff"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_FENCE, (uint64_t)dev->fence, "Device Fence"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass, + "RP load img/stencil"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearStencil, + "RP clear stencil"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_RENDER_PASS, (uint64_t)dev->renderPass_ClearAll, + "RP clear all"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, "DSLayout SOURCE"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, "DSLayout FONT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, "DSLayout GRADIENT"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, "PLLayout dev"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslSrc, + "DSLayout SOURCE"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslFont, + "DSLayout FONT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, (uint64_t)dev->dslGrad, + "DSLayout GRADIENT"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE_LAYOUT, (uint64_t)dev->pipelineLayout, + "PLLayout dev"); - #ifndef __APPLE__ - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, "PL Poly fill"); - #endif - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear"); +#ifndef __APPLE__ + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelinePolyFill, + "PL Poly fill"); +#endif + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipelineClipping, "PL Clipping"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_OVER, "PL draw Over"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_SUB, "PL draw Substract"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_PIPELINE, (uint64_t)dev->pipe_CLEAR, "PL draw Clear"); - vkh_image_set_name(dev->emptyImg, "empty IMG"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), "empty IMG VIEW"); - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), "empty IMG SAMPLER"); - #endif + vkh_image_set_name(dev->emptyImg, "empty IMG"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(dev->emptyImg), + "empty IMG VIEW"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(dev->emptyImg), + "empty IMG SAMPLER"); +#endif #endif - dev->status = VKVG_STATUS_SUCCESS; + dev->status = VKVG_STATUS_SUCCESS; } -#define _CHECK_INST_EXT(ext)\ -if (vkh_instance_extension_supported(#ext)) { \ - if (pExtensions) \ - pExtensions[*pExtCount] = #ext; \ - (*pExtCount)++; \ -} -void vkvg_get_required_instance_extensions (const char** pExtensions, uint32_t* pExtCount) { - *pExtCount = 0; +#define _CHECK_INST_EXT(ext) \ + if (vkh_instance_extension_supported(#ext)) { \ + if (pExtensions) \ + pExtensions[*pExtCount] = #ext; \ + (*pExtCount)++; \ + } +void vkvg_get_required_instance_extensions(const char **pExtensions, uint32_t *pExtCount) { + *pExtCount = 0; - vkh_instance_extensions_check_init (); + vkh_instance_extensions_check_init(); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - _CHECK_INST_EXT(VK_EXT_debug_utils) +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + _CHECK_INST_EXT(VK_EXT_debug_utils) #endif - _CHECK_INST_EXT(VK_KHR_get_physical_device_properties2) + _CHECK_INST_EXT(VK_KHR_get_physical_device_properties2) - vkh_instance_extensions_check_release(); + vkh_instance_extensions_check_release(); } -bool _get_dev_extension_is_supported (VkExtensionProperties* pExtensionProperties, uint32_t extensionCount, const char* name) { - for (uint32_t i=0; i<extensionCount; i++) { - if (strcmp(name, pExtensionProperties[i].extensionName)==0) - return true; - } - return false; -} -#define _CHECK_DEV_EXT(ext) { \ - if (_get_dev_extension_is_supported(pExtensionProperties, extensionCount, #ext)){\ - if (pExtensions) \ - pExtensions[*pExtCount] = #ext; \ - (*pExtCount)++; \ - }\ +bool _get_dev_extension_is_supported(VkExtensionProperties *pExtensionProperties, uint32_t extensionCount, + const char *name) { + for (uint32_t i = 0; i < extensionCount; i++) { + if (strcmp(name, pExtensionProperties[i].extensionName) == 0) + return true; + } + return false; } +#define _CHECK_DEV_EXT(ext) \ + { \ + if (_get_dev_extension_is_supported(pExtensionProperties, extensionCount, #ext)) { \ + if (pExtensions) \ + pExtensions[*pExtCount] = #ext; \ + (*pExtCount)++; \ + } \ + } -vkvg_status_t vkvg_get_required_device_extensions (VkPhysicalDevice phy, const char** pExtensions, uint32_t* pExtCount) { - VkExtensionProperties* pExtensionProperties; - uint32_t extensionCount; +vkvg_status_t vkvg_get_required_device_extensions(VkPhysicalDevice phy, const char **pExtensions, uint32_t *pExtCount) { + VkExtensionProperties *pExtensionProperties; + uint32_t extensionCount; - *pExtCount = 0; + *pExtCount = 0; - VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties(phy, NULL, &extensionCount, NULL)); - pExtensionProperties = (VkExtensionProperties*)malloc(extensionCount * sizeof(VkExtensionProperties)); - VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties(phy, NULL, &extensionCount, pExtensionProperties)); + VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties(phy, NULL, &extensionCount, NULL)); + pExtensionProperties = (VkExtensionProperties *)malloc(extensionCount * sizeof(VkExtensionProperties)); + VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties(phy, NULL, &extensionCount, pExtensionProperties)); - //https://vulkan.lunarg.com/doc/view/1.2.162.0/mac/1.2-extensions/vkspec.html#VK_KHR_portability_subset - _CHECK_DEV_EXT(VK_KHR_portability_subset); - VkPhysicalDeviceFeatures2 phyFeat2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; + // https://vulkan.lunarg.com/doc/view/1.2.162.0/mac/1.2-extensions/vkspec.html#VK_KHR_portability_subset + _CHECK_DEV_EXT(VK_KHR_portability_subset); + VkPhysicalDeviceFeatures2 phyFeat2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2}; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - //ensure feature is implemented by driver. - VkPhysicalDeviceScalarBlockLayoutFeatures scalarBlockLayoutSupport = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES}; - phyFeat2.pNext = &scalarBlockLayoutSupport; + // ensure feature is implemented by driver. + VkPhysicalDeviceScalarBlockLayoutFeatures scalarBlockLayoutSupport = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES}; + phyFeat2.pNext = &scalarBlockLayoutSupport; #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreSupport = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES}; - timelineSemaphoreSupport.pNext = phyFeat2.pNext; - phyFeat2.pNext = &timelineSemaphoreSupport; + VkPhysicalDeviceTimelineSemaphoreFeatures timelineSemaphoreSupport = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES}; + timelineSemaphoreSupport.pNext = phyFeat2.pNext; + phyFeat2.pNext = &timelineSemaphoreSupport; #endif - vkGetPhysicalDeviceFeatures2(phy, &phyFeat2); + vkGetPhysicalDeviceFeatures2(phy, &phyFeat2); #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - if (!scalarBlockLayoutSupport.scalarBlockLayout) { - LOG(VKVG_LOG_ERR, "CREATE Device failed, vkvg compiled with VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT and feature is not implemented for physical device.\n"); - return VKVG_STATUS_DEVICE_ERROR; - } - _CHECK_DEV_EXT(VK_EXT_scalar_block_layout) + if (!scalarBlockLayoutSupport.scalarBlockLayout) { + LOG(VKVG_LOG_ERR, "CREATE Device failed, vkvg compiled with VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT and feature is " + "not implemented for physical device.\n"); + return VKVG_STATUS_DEVICE_ERROR; + } + _CHECK_DEV_EXT(VK_EXT_scalar_block_layout) #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - if (!timelineSemaphoreSupport.timelineSemaphore) { - LOG(VKVG_LOG_ERR, "CREATE Device failed, VK_SEMAPHORE_TYPE_TIMELINE not supported.\n"); - return VKVG_STATUS_DEVICE_ERROR; - } - _CHECK_DEV_EXT(VK_KHR_timeline_semaphore) + if (!timelineSemaphoreSupport.timelineSemaphore) { + LOG(VKVG_LOG_ERR, "CREATE Device failed, VK_SEMAPHORE_TYPE_TIMELINE not supported.\n"); + return VKVG_STATUS_DEVICE_ERROR; + } + _CHECK_DEV_EXT(VK_KHR_timeline_semaphore) #endif - return VKVG_STATUS_SUCCESS; + return VKVG_STATUS_SUCCESS; } -//enabledFeature12 is guarantied to be the first in pNext chain -const void* vkvg_get_device_requirements (VkPhysicalDeviceFeatures* pEnabledFeatures) { +// enabledFeature12 is guarantied to be the first in pNext chain +const void *vkvg_get_device_requirements(VkPhysicalDeviceFeatures *pEnabledFeatures) { - pEnabledFeatures->fillModeNonSolid = VK_TRUE; - pEnabledFeatures->sampleRateShading = VK_TRUE; - pEnabledFeatures->logicOp = VK_TRUE; + pEnabledFeatures->fillModeNonSolid = VK_TRUE; + pEnabledFeatures->sampleRateShading = VK_TRUE; + pEnabledFeatures->logicOp = VK_TRUE; - void* pNext = NULL; + void *pNext = NULL; #ifdef VK_VERSION_1_2 - static VkPhysicalDeviceVulkan12Features enabledFeatures12 = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES + static VkPhysicalDeviceVulkan12Features enabledFeatures12 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - ,.scalarBlockLayout = VK_TRUE + , + .scalarBlockLayout = VK_TRUE #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - ,.timelineSemaphore = VK_TRUE + , + .timelineSemaphore = VK_TRUE #endif - }; - enabledFeatures12.pNext = pNext; - pNext = &enabledFeatures12; + }; + enabledFeatures12.pNext = pNext; + pNext = &enabledFeatures12; #else #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - static VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalarBlockFeat = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT - ,.scalarBlockLayout = VK_TRUE - }; - scalarBlockFeat.pNext = pNext; - pNext = &scalarBlockFeat; + static VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalarBlockFeat = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT, .scalarBlockLayout = VK_TRUE}; + scalarBlockFeat.pNext = pNext; + pNext = &scalarBlockFeat; #endif #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - static VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timelineSemaFeat = { - .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR - ,.timelineSemaphore = VK_TRUE - }; - timelineSemaFeat.pNext = pNext; - pNext = &timelineSemaFeat; + static VkPhysicalDeviceTimelineSemaphoreFeaturesKHR timelineSemaFeat = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR, .timelineSemaphore = VK_TRUE}; + timelineSemaFeat.pNext = pNext; + pNext = &timelineSemaFeat; #endif #endif - return pNext; + return pNext; } +VkvgDevice vkvg_device_create(vkvg_device_create_info_t *info) { + LOG(VKVG_LOG_INFO, "CREATE Device\n"); + VkvgDevice dev = (vkvg_device *)calloc(1, sizeof(vkvg_device)); + if (!dev) { + LOG(VKVG_LOG_ERR, "CREATE Device failed, no memory\n"); + exit(-1); + } -VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info) { - LOG(VKVG_LOG_INFO, "CREATE Device\n"); - VkvgDevice dev = (vkvg_device*)calloc(1,sizeof(vkvg_device)); - if (!dev) { - LOG(VKVG_LOG_ERR, "CREATE Device failed, no memory\n"); - exit(-1); - } - - dev->references = 1; + dev->references = 1; if (!info->vkdev) { - const char* enabledExts [10]; - const char* enabledLayers[10]; - uint32_t enabledExtsCount = 0, enabledLayersCount = 0, phyCount = 0; + const char *enabledExts[10]; + const char *enabledLayers[10]; + uint32_t enabledExtsCount = 0, enabledLayersCount = 0, phyCount = 0; vkh_layers_check_init(); - #ifdef VKVG_USE_VALIDATION +#ifdef VKVG_USE_VALIDATION if (vkh_layer_is_present("VK_LAYER_KHRONOS_validation")) enabledLayers[enabledLayersCount++] = "VK_LAYER_KHRONOS_validation"; - #endif +#endif - #ifdef VKVG_USE_RENDERDOC +#ifdef VKVG_USE_RENDERDOC if (vkh_layer_is_present("VK_LAYER_RENDERDOC_Capture")) enabledLayers[enabledLayersCount++] = "VK_LAYER_RENDERDOC_Capture"; - #endif +#endif vkh_layers_check_release(); - vkvg_get_required_instance_extensions (enabledExts, &enabledExtsCount); + vkvg_get_required_instance_extensions(enabledExts, &enabledExtsCount); - #ifdef VK_VERSION_1_2 +#ifdef VK_VERSION_1_2 VkhApp app = vkh_app_create(1, 2, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); - #else +#else VkhApp app = vkh_app_create(1, 1, "vkvg", enabledLayersCount, enabledLayers, enabledExtsCount, enabledExts); - #endif +#endif - #if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_app_enable_debug_messenger(app - , VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - , VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT - , NULL); - #endif +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_app_enable_debug_messenger(app, VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, NULL); +#endif - VkhPhyInfo* phys = vkh_app_get_phyinfos (app, &phyCount, VK_NULL_HANDLE); + VkhPhyInfo *phys = vkh_app_get_phyinfos(app, &phyCount, VK_NULL_HANDLE); if (phyCount == 0) { dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_destroy (app); + vkh_app_destroy(app); return dev; } @@ -326,170 +340,159 @@ VkvgDevice vkvg_device_create (vkvg_device_create_info_t* info) { if (!(pi->properties.limits.framebufferColorSampleCounts & info->samples)) { LOG(VKVG_LOG_ERR, "CREATE Device failed: sample count not supported: %d\n", info->samples); dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_free_phyinfos (phyCount, phys); - vkh_app_destroy (app); + vkh_app_free_phyinfos(phyCount, phys); + vkh_app_destroy(app); return dev; } - uint32_t qCount = 0; - float qPriorities[] = {0.0}; - VkDeviceQueueCreateInfo pQueueInfos[] = { {0},{0},{0} }; + uint32_t qCount = 0; + float qPriorities[] = {0.0}; + VkDeviceQueueCreateInfo pQueueInfos[] = {{0}, {0}, {0}}; - if (vkh_phyinfo_create_queues (pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) + if (vkh_phyinfo_create_queues(pi, pi->gQueue, 1, qPriorities, &pQueueInfos[qCount])) qCount++; - enabledExtsCount=0; + enabledExtsCount = 0; - if (vkvg_get_required_device_extensions (pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS){ + if (vkvg_get_required_device_extensions(pi->phy, enabledExts, &enabledExtsCount) != VKVG_STATUS_SUCCESS) { dev->status = VKVG_STATUS_DEVICE_ERROR; - vkh_app_free_phyinfos (phyCount, phys); - vkh_app_destroy (app); + vkh_app_free_phyinfos(phyCount, phys); + vkh_app_destroy(app); return dev; } VkPhysicalDeviceFeatures enabledFeatures = {0}; - const void* pNext = vkvg_get_device_requirements (&enabledFeatures); + const void *pNext = vkvg_get_device_requirements(&enabledFeatures); - VkDeviceCreateInfo device_info = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .queueCreateInfoCount = qCount, - .pQueueCreateInfos = (VkDeviceQueueCreateInfo*)&pQueueInfos, - .enabledExtensionCount = enabledExtsCount, - .ppEnabledExtensionNames = enabledExts, - .pEnabledFeatures = &enabledFeatures, - .pNext = pNext}; - dev->vkhDev = vkh_device_create(app, pi, &device_info); + VkDeviceCreateInfo device_info = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .queueCreateInfoCount = qCount, + .pQueueCreateInfos = (VkDeviceQueueCreateInfo *)&pQueueInfos, + .enabledExtensionCount = enabledExtsCount, + .ppEnabledExtensionNames = enabledExts, + .pEnabledFeatures = &enabledFeatures, + .pNext = pNext}; + dev->vkhDev = vkh_device_create(app, pi, &device_info); - vkh_app_free_phyinfos (phyCount, phys); + vkh_app_free_phyinfos(phyCount, phys); - info->inst = vkh_app_get_inst(app); - info->phy = vkh_device_get_phy(dev->vkhDev); - info->vkdev = vkh_device_get_vkdev(dev->vkhDev); - info->qFamIdx = pi->gQueue; - info->qIndex = 0; + info->inst = vkh_app_get_inst(app); + info->phy = vkh_device_get_phy(dev->vkhDev); + info->vkdev = vkh_device_get_vkdev(dev->vkhDev); + info->qFamIdx = pi->gQueue; + info->qIndex = 0; } - _device_init (dev, info); + _device_init(dev, info); - return dev; + return dev; } -void vkvg_device_destroy (VkvgDevice dev) -{ - LOCK_DEVICE - dev->references--; - if (dev->references > 0) { - UNLOCK_DEVICE - return; - } - UNLOCK_DEVICE - - - if (dev->cachedContextCount > 0) { - _cached_ctx* cur = dev->cachedContextLast; - while (cur) { - _release_context_ressources (cur->ctx); - _cached_ctx* prev = cur; - cur = cur->pNext; - free (prev); - } - } +void vkvg_device_destroy(VkvgDevice dev) { + LOCK_DEVICE + dev->references--; + if (dev->references > 0) { + UNLOCK_DEVICE + return; + } + UNLOCK_DEVICE + if (dev->cachedContextCount > 0) { + _cached_ctx *cur = dev->cachedContextLast; + while (cur) { + _release_context_ressources(cur->ctx); + _cached_ctx *prev = cur; + cur = cur->pNext; + free(prev); + } + } - LOG(VKVG_LOG_INFO, "DESTROY Device\n"); + LOG(VKVG_LOG_INFO, "DESTROY Device\n"); - vkDeviceWaitIdle (dev->vkDev); + vkDeviceWaitIdle(dev->vkDev); - vkh_image_destroy (dev->emptyImg); + vkh_image_destroy(dev->emptyImg); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslGrad,NULL); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslFont,NULL); - vkDestroyDescriptorSetLayout (dev->vkDev, dev->dslSrc, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslGrad, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslFont, NULL); + vkDestroyDescriptorSetLayout(dev->vkDev, dev->dslSrc, NULL); #ifndef __APPLE__ - vkDestroyPipeline (dev->vkDev, dev->pipelinePolyFill, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelinePolyFill, NULL); #endif - vkDestroyPipeline (dev->vkDev, dev->pipelineClipping, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineClipping, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_OVER, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_SUB, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipe_CLEAR, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_OVER, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_SUB, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipe_CLEAR, NULL); #ifdef VKVG_WIRED_DEBUG - vkDestroyPipeline (dev->vkDev, dev->pipelineWired, NULL); - vkDestroyPipeline (dev->vkDev, dev->pipelineLineList, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineWired, NULL); + vkDestroyPipeline(dev->vkDev, dev->pipelineLineList, NULL); #endif - vkDestroyPipelineLayout (dev->vkDev, dev->pipelineLayout, NULL); - vkDestroyPipelineCache (dev->vkDev, dev->pipelineCache, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearStencil, NULL); - vkDestroyRenderPass (dev->vkDev, dev->renderPass_ClearAll, NULL); + vkDestroyPipelineLayout(dev->vkDev, dev->pipelineLayout, NULL); + vkDestroyPipelineCache(dev->vkDev, dev->pipelineCache, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass_ClearStencil, NULL); + vkDestroyRenderPass(dev->vkDev, dev->renderPass_ClearAll, NULL); - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - vkDestroyFence (dev->vkDev, dev->fence,NULL); + vkWaitForFences(dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + vkDestroyFence(dev->vkDev, dev->fence, NULL); - vkFreeCommandBuffers (dev->vkDev, dev->cmdPool, 1, &dev->cmd); - vkDestroyCommandPool (dev->vkDev, dev->cmdPool, NULL); + vkFreeCommandBuffers(dev->vkDev, dev->cmdPool, 1, &dev->cmd); + vkDestroyCommandPool(dev->vkDev, dev->cmdPool, NULL); - vkh_queue_destroy(dev->gQueue); + vkh_queue_destroy(dev->gQueue); - _font_cache_destroy(dev); + _font_cache_destroy(dev); #ifdef VKH_USE_VMA - vmaDestroyAllocator (dev->allocator); + vmaDestroyAllocator(dev->allocator); #endif - if (dev->threadAware) - mtx_destroy (&dev->mutex); + if (dev->threadAware) + mtx_destroy(&dev->mutex); - if (dev->vkhDev) { - VkhApp app = vkh_device_get_app (dev->vkhDev); - vkh_device_destroy (dev->vkhDev); - vkh_app_destroy (app); - } + if (dev->vkhDev) { + VkhApp app = vkh_device_get_app(dev->vkhDev); + vkh_device_destroy(dev->vkhDev); + vkh_app_destroy(app); + } - free(dev); + free(dev); } -vkvg_status_t vkvg_device_status (VkvgDevice dev) { - return dev->status; -} -VkvgDevice vkvg_device_reference (VkvgDevice dev) { - LOCK_DEVICE - dev->references++; - UNLOCK_DEVICE - return dev; +vkvg_status_t vkvg_device_status(VkvgDevice dev) { return dev->status; } +VkvgDevice vkvg_device_reference(VkvgDevice dev) { + LOCK_DEVICE + dev->references++; + UNLOCK_DEVICE + return dev; } -uint32_t vkvg_device_get_reference_count (VkvgDevice dev) { - return dev->references; -} -void vkvg_device_set_dpy (VkvgDevice dev, int hdpy, int vdpy) { - dev->hdpi = hdpy; - dev->vdpi = vdpy; +uint32_t vkvg_device_get_reference_count(VkvgDevice dev) { return dev->references; } +void vkvg_device_set_dpy(VkvgDevice dev, int hdpy, int vdpy) { + dev->hdpi = hdpy; + dev->vdpi = vdpy; - //TODO: reset font cache + // TODO: reset font cache } -void vkvg_device_get_dpy (VkvgDevice dev, int* hdpy, int* vdpy) { - *hdpy = dev->hdpi; - *vdpy = dev->vdpi; +void vkvg_device_get_dpy(VkvgDevice dev, int *hdpy, int *vdpy) { + *hdpy = dev->hdpi; + *vdpy = dev->vdpi; } -void vkvg_device_set_thread_aware (VkvgDevice dev, uint32_t thread_aware) { - if (thread_aware) { - if (dev->threadAware) - return; - mtx_init (&dev->mutex, mtx_plain); - mtx_init (&dev->fontCache->mutex, mtx_plain); - dev->threadAware = true; - } else if (dev->threadAware) { - mtx_destroy (&dev->mutex); - mtx_destroy (&dev->fontCache->mutex); - dev->threadAware = false; - } +void vkvg_device_set_thread_aware(VkvgDevice dev, uint32_t thread_aware) { + if (thread_aware) { + if (dev->threadAware) + return; + mtx_init(&dev->mutex, mtx_plain); + mtx_init(&dev->fontCache->mutex, mtx_plain); + dev->threadAware = true; + } else if (dev->threadAware) { + mtx_destroy(&dev->mutex); + mtx_destroy(&dev->fontCache->mutex); + dev->threadAware = false; + } } #if VKVG_DBG_STATS -vkvg_debug_stats_t vkvg_device_get_stats (VkvgDevice dev) { - return dev->debug_stats; -} -vkvg_debug_stats_t vkvg_device_reset_stats (VkvgDevice dev) { - dev->debug_stats = (vkvg_debug_stats_t) {0}; -} +vkvg_debug_stats_t vkvg_device_get_stats(VkvgDevice dev) { return dev->debug_stats; } +vkvg_debug_stats_t vkvg_device_reset_stats(VkvgDevice dev) { dev->debug_stats = (vkvg_debug_stats_t){0}; } #endif diff --git a/src/vkvg_device_internal.c b/src/vkvg_device_internal.c index f9f865c..1264d2f 100644 --- a/src/vkvg_device_internal.c +++ b/src/vkvg_device_internal.c @@ -20,9 +20,11 @@ * THE SOFTWARE. */ -#define GetInstProcAddress(inst, func)(PFN_##func)vkGetInstanceProcAddr(inst, #func); +#define GetInstProcAddress(inst, func) (PFN_##func) vkGetInstanceProcAddr(inst, #func); -#define GetVkProcAddress(dev, inst, func)(vkGetDeviceProcAddr(dev,#func)==NULL)?(PFN_##func)vkGetInstanceProcAddr(inst, #func):(PFN_##func)vkGetDeviceProcAddr(dev, #func) +#define GetVkProcAddress(dev, inst, func) \ + (vkGetDeviceProcAddr(dev, #func) == NULL) ? (PFN_##func)vkGetInstanceProcAddr(inst, #func) \ + : (PFN_##func)vkGetDeviceProcAddr(dev, #func) #include "vkvg_device_internal.h" #include "vkvg_context_internal.h" @@ -33,575 +35,586 @@ uint32_t vkvg_log_level = VKVG_LOG_DEBUG; vkvg_wired_debug_mode vkvg_wired_debug = vkvg_wired_debug_mode_normal; #endif -PFN_vkCmdBindPipeline CmdBindPipeline; -PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; -PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; -PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; +PFN_vkCmdBindPipeline CmdBindPipeline; +PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; +PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; +PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; -PFN_vkCmdDrawIndexed CmdDrawIndexed; -PFN_vkCmdDraw CmdDraw; +PFN_vkCmdDrawIndexed CmdDrawIndexed; +PFN_vkCmdDraw CmdDraw; -PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; -PFN_vkCmdSetStencilReference CmdSetStencilReference; -PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; -PFN_vkCmdBeginRenderPass CmdBeginRenderPass; -PFN_vkCmdEndRenderPass CmdEndRenderPass; -PFN_vkCmdSetViewport CmdSetViewport; -PFN_vkCmdSetScissor CmdSetScissor; +PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; +PFN_vkCmdSetStencilReference CmdSetStencilReference; +PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; +PFN_vkCmdBeginRenderPass CmdBeginRenderPass; +PFN_vkCmdEndRenderPass CmdEndRenderPass; +PFN_vkCmdSetViewport CmdSetViewport; +PFN_vkCmdSetScissor CmdSetScissor; -PFN_vkCmdPushConstants CmdPushConstants; +PFN_vkCmdPushConstants CmdPushConstants; -PFN_vkWaitForFences WaitForFences; -PFN_vkResetFences ResetFences; -PFN_vkResetCommandBuffer ResetCommandBuffer; +PFN_vkWaitForFences WaitForFences; +PFN_vkResetFences ResetFences; +PFN_vkResetCommandBuffer ResetCommandBuffer; -bool _device_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy) { - for (uint32_t i=0; i<phyCount; i++){ - if (vkh_phyinfo_get_properties(phys[i]).deviceType == gpuType) { - *phy = phys[i]; - return true; - } - } - return false; +bool _device_try_get_phyinfo(VkhPhyInfo *phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo *phy) { + for (uint32_t i = 0; i < phyCount; i++) { + if (vkh_phyinfo_get_properties(phys[i]).deviceType == gpuType) { + *phy = phys[i]; + return true; + } + } + return false; } -//TODO:save/reload cache in user temp directory -void _device_create_pipeline_cache(VkvgDevice dev){ +// TODO:save/reload cache in user temp directory +void _device_create_pipeline_cache(VkvgDevice dev) { - VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO}; - VK_CHECK_RESULT(vkCreatePipelineCache(dev->vkDev, &pipelineCacheCreateInfo, NULL, &dev->pipelineCache)); + VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO}; + VK_CHECK_RESULT(vkCreatePipelineCache(dev->vkDev, &pipelineCacheCreateInfo, NULL, &dev->pipelineCache)); } -VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) -{ - VkAttachmentDescription attColor = { - .format = FB_COLOR_FORMAT, - .samples = dev->samples, - .loadOp = loadOp, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attDS = { - .format = dev->stencilFormat, - .samples = dev->samples, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = stencilLoadOp, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; +VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, + VkAttachmentLoadOp stencilLoadOp) { + VkAttachmentDescription attColor = {.format = FB_COLOR_FORMAT, + .samples = dev->samples, + .loadOp = loadOp, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attDS = {.format = dev->stencilFormat, + .samples = dev->samples, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = stencilLoadOp, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkAttachmentDescription attachments[] = {attColor,attDS}; - VkAttachmentReference colorRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attachments[] = {attColor, attDS}; + VkAttachmentReference colorRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkSubpassDescription subpassDescription = { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colorRef, - .pDepthStencilAttachment= &dsRef}; + VkSubpassDescription subpassDescription = {.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &colorRef, + .pDepthStencilAttachment = &dsRef}; - VkSubpassDependency dependencies[] = - { - { VK_SUBPASS_EXTERNAL, 0, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - { 0, VK_SUBPASS_EXTERNAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - }; + VkSubpassDependency dependencies[] = { + {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + }; - VkRenderPassCreateInfo renderPassInfo = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 2, - .pAttachments = attachments, - .subpassCount = 1, - .pSubpasses = &subpassDescription, - .dependencyCount = 2, - .pDependencies = dependencies - }; - VkRenderPass rp; - VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); - return rp; + VkRenderPassCreateInfo renderPassInfo = {.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 2, + .pAttachments = attachments, + .subpassCount = 1, + .pSubpasses = &subpassDescription, + .dependencyCount = 2, + .pDependencies = dependencies}; + VkRenderPass rp; + VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); + return rp; } -VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) -{ - VkAttachmentDescription attColor = { - .format = FB_COLOR_FORMAT, - .samples = dev->samples, - .loadOp = loadOp, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attColorResolve = { - .format = FB_COLOR_FORMAT, - .samples = VK_SAMPLE_COUNT_1_BIT, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentDescription attDS = { - .format = dev->stencilFormat, - .samples = dev->samples, - .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .stencilLoadOp = stencilLoadOp, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, - .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; +VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp) { + VkAttachmentDescription attColor = {.format = FB_COLOR_FORMAT, + .samples = dev->samples, + .loadOp = loadOp, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attColorResolve = {.format = FB_COLOR_FORMAT, + .samples = VK_SAMPLE_COUNT_1_BIT, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attDS = {.format = dev->stencilFormat, + .samples = dev->samples, + .loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, + .storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, + .stencilLoadOp = stencilLoadOp, + .stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE, + .initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + .finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkAttachmentDescription attachments[] = {attColorResolve,attDS,attColor}; - VkAttachmentReference resolveRef= {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; - VkAttachmentReference colorRef = {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentDescription attachments[] = {attColorResolve, attDS, attColor}; + VkAttachmentReference resolveRef = {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; + VkAttachmentReference dsRef = {1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}; + VkAttachmentReference colorRef = {2, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; - VkSubpassDescription subpassDescription = { .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colorRef, - .pResolveAttachments = &resolveRef, - .pDepthStencilAttachment= &dsRef}; + VkSubpassDescription subpassDescription = {.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .colorAttachmentCount = 1, + .pColorAttachments = &colorRef, + .pResolveAttachments = &resolveRef, + .pDepthStencilAttachment = &dsRef}; - VkSubpassDependency dependencies[] = - { - { VK_SUBPASS_EXTERNAL, 0, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - { 0, VK_SUBPASS_EXTERNAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, - VK_DEPENDENCY_BY_REGION_BIT}, - }; + VkSubpassDependency dependencies[] = { + {VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_MEMORY_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + {0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_MEMORY_READ_BIT, + VK_DEPENDENCY_BY_REGION_BIT}, + }; - VkRenderPassCreateInfo renderPassInfo = { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .attachmentCount = 3, - .pAttachments = attachments, - .subpassCount = 1, - .pSubpasses = &subpassDescription, - .dependencyCount = 2, - .pDependencies = dependencies - }; - VkRenderPass rp; - VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); - return rp; + VkRenderPassCreateInfo renderPassInfo = {.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, + .attachmentCount = 3, + .pAttachments = attachments, + .subpassCount = 1, + .pSubpasses = &subpassDescription, + .dependencyCount = 2, + .pDependencies = dependencies}; + VkRenderPass rp; + VK_CHECK_RESULT(vkCreateRenderPass(dev->vkDev, &renderPassInfo, NULL, &rp)); + return rp; } -void _device_setupPipelines(VkvgDevice dev) -{ - VkGraphicsPipelineCreateInfo pipelineCreateInfo = { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .renderPass = dev->renderPass }; +void _device_setupPipelines(VkvgDevice dev) { + VkGraphicsPipelineCreateInfo pipelineCreateInfo = {.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .renderPass = dev->renderPass}; - VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN }; + VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN}; - VkPipelineRasterizationStateCreateInfo rasterizationState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, - .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, - .depthClampEnable = VK_FALSE, - .rasterizerDiscardEnable = VK_FALSE, - .depthBiasEnable = VK_FALSE, - .lineWidth = 1.0f }; + VkPipelineRasterizationStateCreateInfo rasterizationState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .depthBiasEnable = VK_FALSE, + .lineWidth = 1.0f}; - VkPipelineColorBlendAttachmentState blendAttachmentState = - { .colorWriteMask = 0x0, .blendEnable = VK_TRUE, + VkPipelineColorBlendAttachmentState blendAttachmentState = { + .colorWriteMask = 0x0, + .blendEnable = VK_TRUE, #ifdef VKVG_PREMULT_ALPHA - .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .alphaBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_ONE, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .alphaBlendOp = VK_BLEND_OP_ADD, #else - .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, - .alphaBlendOp = VK_BLEND_OP_ADD, + .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD, #endif - }; + }; - VkPipelineColorBlendStateCreateInfo colorBlendState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .attachmentCount = 1, - .pAttachments = &blendAttachmentState }; + VkPipelineColorBlendStateCreateInfo colorBlendState = {.sType = + VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .attachmentCount = 1, + .pAttachments = &blendAttachmentState}; - /*failOp,passOp,depthFailOp,compareOp, compareMask, writeMask, reference;*/ - VkStencilOpState polyFillOpState ={VK_STENCIL_OP_KEEP,VK_STENCIL_OP_INVERT, VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_CLIP_BIT,STENCIL_FILL_BIT,0}; - VkStencilOpState clipingOpState = {VK_STENCIL_OP_ZERO,VK_STENCIL_OP_REPLACE,VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_ALL_BIT, 0x2}; - VkStencilOpState stencilOpState = {VK_STENCIL_OP_KEEP,VK_STENCIL_OP_ZERO, VK_STENCIL_OP_KEEP,VK_COMPARE_OP_EQUAL,STENCIL_FILL_BIT,STENCIL_FILL_BIT,0x1}; + /*failOp,passOp,depthFailOp,compareOp, compareMask, writeMask, reference;*/ + VkStencilOpState polyFillOpState = {VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_CLIP_BIT, + STENCIL_FILL_BIT, + 0}; + VkStencilOpState clipingOpState = {VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_FILL_BIT, + STENCIL_ALL_BIT, + 0x2}; + VkStencilOpState stencilOpState = {VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_KEEP, + VK_COMPARE_OP_EQUAL, + STENCIL_FILL_BIT, + STENCIL_FILL_BIT, + 0x1}; - VkPipelineDepthStencilStateCreateInfo dsStateCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .depthTestEnable = VK_FALSE, - .depthWriteEnable = VK_FALSE, - .depthCompareOp = VK_COMPARE_OP_ALWAYS, - .stencilTestEnable = VK_TRUE, - .front = polyFillOpState, - .back = polyFillOpState }; + VkPipelineDepthStencilStateCreateInfo dsStateCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .depthTestEnable = VK_FALSE, + .depthWriteEnable = VK_FALSE, + .depthCompareOp = VK_COMPARE_OP_ALWAYS, + .stencilTestEnable = VK_TRUE, + .front = polyFillOpState, + .back = polyFillOpState}; - VkDynamicState dynamicStateEnables[] = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR, - VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, - VK_DYNAMIC_STATE_STENCIL_REFERENCE, - VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, - }; - VkPipelineDynamicStateCreateInfo dynamicState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .dynamicStateCount = 2, - .pDynamicStates = dynamicStateEnables }; + VkDynamicState dynamicStateEnables[] = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + }; + VkPipelineDynamicStateCreateInfo dynamicState = {.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .dynamicStateCount = 2, + .pDynamicStates = dynamicStateEnables}; - VkPipelineViewportStateCreateInfo viewportState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .viewportCount = 1, .scissorCount = 1 }; + VkPipelineViewportStateCreateInfo viewportState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, .viewportCount = 1, .scissorCount = 1}; - VkPipelineMultisampleStateCreateInfo multisampleState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .rasterizationSamples = dev->samples }; - /*if (dev->samples != VK_SAMPLE_COUNT_1_BIT){ - multisampleState.sampleShadingEnable = VK_TRUE; - multisampleState.minSampleShading = 0.5f; - }*/ - VkVertexInputBindingDescription vertexInputBinding = { .binding = 0, - .stride = sizeof(Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX }; + VkPipelineMultisampleStateCreateInfo multisampleState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, .rasterizationSamples = dev->samples}; + /*if (dev->samples != VK_SAMPLE_COUNT_1_BIT){ + multisampleState.sampleShadingEnable = VK_TRUE; + multisampleState.minSampleShading = 0.5f; + }*/ + VkVertexInputBindingDescription vertexInputBinding = { + .binding = 0, .stride = sizeof(Vertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX}; - VkVertexInputAttributeDescription vertexInputAttributs[3] = { - {0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, - {1, 0, VK_FORMAT_R8G8B8A8_UNORM, 8}, - {2, 0, VK_FORMAT_R32G32B32_SFLOAT, 12} - }; + VkVertexInputAttributeDescription vertexInputAttributs[3] = {{0, 0, VK_FORMAT_R32G32_SFLOAT, 0}, + {1, 0, VK_FORMAT_R8G8B8A8_UNORM, 8}, + {2, 0, VK_FORMAT_R32G32B32_SFLOAT, 12}}; - VkPipelineVertexInputStateCreateInfo vertexInputState = { .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &vertexInputBinding, - .vertexAttributeDescriptionCount= 3, - .pVertexAttributeDescriptions = vertexInputAttributs }; + VkPipelineVertexInputStateCreateInfo vertexInputState = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = 1, + .pVertexBindingDescriptions = &vertexInputBinding, + .vertexAttributeDescriptionCount = 3, + .pVertexAttributeDescriptions = vertexInputAttributs}; #ifdef VKVG_WIRED_DEBUG - VkShaderModule modVert, modFrag, modFragWired; + VkShaderModule modVert, modFrag, modFragWired; #else - VkShaderModule modVert, modFrag; + VkShaderModule modVert, modFrag; #endif - VkShaderModuleCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pCode = (uint32_t*)vkvg_main_vert_spv, - .codeSize = vkvg_main_vert_spv_len }; - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modVert)); + VkShaderModuleCreateInfo createInfo = {.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pCode = (uint32_t *)vkvg_main_vert_spv, + .codeSize = vkvg_main_vert_spv_len}; + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modVert)); #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - createInfo.pCode = (uint32_t*)vkvg_main_lcd_frag_spv; - createInfo.codeSize = vkvg_main_lcd_frag_spv_len; + createInfo.pCode = (uint32_t *)vkvg_main_lcd_frag_spv; + createInfo.codeSize = vkvg_main_lcd_frag_spv_len; #else - createInfo.pCode = (uint32_t*)vkvg_main_frag_spv; - createInfo.codeSize = vkvg_main_frag_spv_len; + createInfo.pCode = (uint32_t *)vkvg_main_frag_spv; + createInfo.codeSize = vkvg_main_frag_spv_len; #endif - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFrag)); + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFrag)); - VkPipelineShaderStageCreateInfo vertStage = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = modVert, - .pName = "main", - }; - VkPipelineShaderStageCreateInfo fragStage = { .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = modFrag, - .pName = "main", - }; + VkPipelineShaderStageCreateInfo vertStage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = modVert, + .pName = "main", + }; + VkPipelineShaderStageCreateInfo fragStage = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = modFrag, + .pName = "main", + }; - // Use specialization constants to pass number of samples to the shader (used for MSAA resolve) - /*VkSpecializationMapEntry specializationEntry = { - .constantID = 0, - .offset = 0, - .size = sizeof(uint32_t)}; - uint32_t specializationData = VKVG_SAMPLES; - VkSpecializationInfo specializationInfo = { - .mapEntryCount = 1, - .pMapEntries = &specializationEntry, - .dataSize = sizeof(specializationData), - .pData = &specializationData};*/ + // Use specialization constants to pass number of samples to the shader (used for MSAA resolve) + /*VkSpecializationMapEntry specializationEntry = { + .constantID = 0, + .offset = 0, + .size = sizeof(uint32_t)}; + uint32_t specializationData = VKVG_SAMPLES; + VkSpecializationInfo specializationInfo = { + .mapEntryCount = 1, + .pMapEntries = &specializationEntry, + .dataSize = sizeof(specializationData), + .pData = &specializationData};*/ - VkPipelineShaderStageCreateInfo shaderStages[] = {vertStage,fragStage}; + VkPipelineShaderStageCreateInfo shaderStages[] = {vertStage, fragStage}; - pipelineCreateInfo.stageCount = 1; - pipelineCreateInfo.pStages = shaderStages; - pipelineCreateInfo.pVertexInputState = &vertexInputState; - pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; - pipelineCreateInfo.pViewportState = &viewportState; - pipelineCreateInfo.pRasterizationState = &rasterizationState; - pipelineCreateInfo.pMultisampleState = &multisampleState; - pipelineCreateInfo.pColorBlendState = &colorBlendState; - pipelineCreateInfo.pDepthStencilState = &dsStateCreateInfo; - pipelineCreateInfo.pDynamicState = &dynamicState; - pipelineCreateInfo.layout = dev->pipelineLayout; + pipelineCreateInfo.stageCount = 1; + pipelineCreateInfo.pStages = shaderStages; + pipelineCreateInfo.pVertexInputState = &vertexInputState; + pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState; + pipelineCreateInfo.pViewportState = &viewportState; + pipelineCreateInfo.pRasterizationState = &rasterizationState; + pipelineCreateInfo.pMultisampleState = &multisampleState; + pipelineCreateInfo.pColorBlendState = &colorBlendState; + pipelineCreateInfo.pDepthStencilState = &dsStateCreateInfo; + pipelineCreateInfo.pDynamicState = &dynamicState; + pipelineCreateInfo.layout = dev->pipelineLayout; #ifndef __APPLE__ - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelinePolyFill)); + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelinePolyFill)); #endif - inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - dsStateCreateInfo.back = dsStateCreateInfo.front = clipingOpState; - dynamicState.dynamicStateCount = 5; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineClipping)); + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + dsStateCreateInfo.back = dsStateCreateInfo.front = clipingOpState; + dynamicState.dynamicStateCount = 5; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelineClipping)); - dsStateCreateInfo.back = dsStateCreateInfo.front = stencilOpState; - blendAttachmentState.colorWriteMask=0xf; - dynamicState.dynamicStateCount = 3; - pipelineCreateInfo.stageCount = 2; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_OVER)); + dsStateCreateInfo.back = dsStateCreateInfo.front = stencilOpState; + blendAttachmentState.colorWriteMask = 0xf; + dynamicState.dynamicStateCount = 3; + pipelineCreateInfo.stageCount = 2; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_OVER)); - blendAttachmentState.alphaBlendOp = blendAttachmentState.colorBlendOp = VK_BLEND_OP_SUBTRACT; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_SUB)); - - colorBlendState.logicOpEnable = VK_TRUE; - blendAttachmentState.blendEnable = VK_FALSE; - colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_CLEAR)); + blendAttachmentState.alphaBlendOp = blendAttachmentState.colorBlendOp = VK_BLEND_OP_SUBTRACT; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_SUB)); + colorBlendState.logicOpEnable = VK_TRUE; + blendAttachmentState.blendEnable = VK_FALSE; + colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipe_CLEAR)); #ifdef VKVG_WIRED_DEBUG - colorBlendState.logicOpEnable = VK_FALSE; - blendAttachmentState.blendEnable = VK_TRUE; - colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; + colorBlendState.logicOpEnable = VK_FALSE; + blendAttachmentState.blendEnable = VK_TRUE; + colorBlendState.logicOp = VK_LOGIC_OP_CLEAR; - createInfo.pCode = (uint32_t*)wired_frag_spv; + createInfo.pCode = (uint32_t *)wired_frag_spv; - createInfo.codeSize = wired_frag_spv_len; - VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFragWired)); + createInfo.codeSize = wired_frag_spv_len; + VK_CHECK_RESULT(vkCreateShaderModule(dev->vkDev, &createInfo, NULL, &modFragWired)); - shaderStages[1].module = modFragWired; + shaderStages[1].module = modFragWired; - rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineLineList)); + rasterizationState.polygonMode = VK_POLYGON_MODE_LINE; + VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, + &dev->pipelineLineList)); - inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - rasterizationState.polygonMode = VK_POLYGON_MODE_FILL; - VK_CHECK_RESULT(vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineWired)); + inputAssemblyState.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + rasterizationState.polygonMode = VK_POLYGON_MODE_FILL; + VK_CHECK_RESULT( + vkCreateGraphicsPipelines(dev->vkDev, dev->pipelineCache, 1, &pipelineCreateInfo, NULL, &dev->pipelineWired)); - vkDestroyShaderModule(dev->vkDev, modFragWired, NULL); + vkDestroyShaderModule(dev->vkDev, modFragWired, NULL); #endif - vkDestroyShaderModule(dev->vkDev, modVert, NULL); - vkDestroyShaderModule(dev->vkDev, modFrag, NULL); + vkDestroyShaderModule(dev->vkDev, modVert, NULL); + vkDestroyShaderModule(dev->vkDev, modFrag, NULL); } -void _device_createDescriptorSetLayout (VkvgDevice dev) { +void _device_createDescriptorSetLayout(VkvgDevice dev) { - VkDescriptorSetLayoutBinding dsLayoutBinding = - {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1,VK_SHADER_STAGE_FRAGMENT_BIT, NULL}; - VkDescriptorSetLayoutCreateInfo dsLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = 1, - .pBindings = &dsLayoutBinding }; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslSrc)); - dsLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslGrad)); + VkDescriptorSetLayoutBinding dsLayoutBinding = {0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, + VK_SHADER_STAGE_FRAGMENT_BIT, NULL}; + VkDescriptorSetLayoutCreateInfo dsLayoutCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .bindingCount = 1, .pBindings = &dsLayoutBinding}; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslFont)); + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslSrc)); + dsLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + VK_CHECK_RESULT(vkCreateDescriptorSetLayout(dev->vkDev, &dsLayoutCreateInfo, NULL, &dev->dslGrad)); - VkPushConstantRange pushConstantRange[] = { - {VK_SHADER_STAGE_VERTEX_BIT,0,sizeof(push_constants)}, - //{VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push_constants)} - }; - VkDescriptorSetLayout dsls[] = {dev->dslFont,dev->dslSrc,dev->dslGrad}; + VkPushConstantRange pushConstantRange[] = { + {VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(push_constants)}, + //{VK_SHADER_STAGE_FRAGMENT_BIT,0,sizeof(push_constants)} + }; + VkDescriptorSetLayout dsls[] = {dev->dslFont, dev->dslSrc, dev->dslGrad}; - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pushConstantRangeCount = 1, - .pPushConstantRanges = (VkPushConstantRange*)&pushConstantRange, - .setLayoutCount = 3, - .pSetLayouts = dsls }; - VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout)); + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pushConstantRangeCount = 1, + .pPushConstantRanges = + (VkPushConstantRange *)&pushConstantRange, + .setLayoutCount = 3, + .pSetLayouts = dsls}; + VK_CHECK_RESULT(vkCreatePipelineLayout(dev->vkDev, &pipelineLayoutCreateInfo, NULL, &dev->pipelineLayout)); } -void _device_wait_idle (VkvgDevice dev) { - vkDeviceWaitIdle (dev->vkDev); -} -void _device_wait_and_reset_device_fence (VkvgDevice dev) { - vkWaitForFences (dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); - ResetFences (dev->vkDev, 1, &dev->fence); +void _device_wait_idle(VkvgDevice dev) { vkDeviceWaitIdle(dev->vkDev); } +void _device_wait_and_reset_device_fence(VkvgDevice dev) { + vkWaitForFences(dev->vkDev, 1, &dev->fence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &dev->fence); } -bool _device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx) { - LOCK_DEVICE +bool _device_try_get_cached_context(VkvgDevice dev, VkvgContext *pCtx) { + LOCK_DEVICE - if (dev->cachedContextCount) { - thrd_t curThread = thrd_current (); - _cached_ctx* prev = NULL; - _cached_ctx* cur = dev->cachedContextLast; - while (cur) { - if (thrd_equal (cur->thread, curThread)) { - if (prev) - prev->pNext = cur->pNext; - else - dev->cachedContextLast = cur->pNext; + if (dev->cachedContextCount) { + thrd_t curThread = thrd_current(); + _cached_ctx *prev = NULL; + _cached_ctx *cur = dev->cachedContextLast; + while (cur) { + if (thrd_equal(cur->thread, curThread)) { + if (prev) + prev->pNext = cur->pNext; + else + dev->cachedContextLast = cur->pNext; - dev->cachedContextCount--; + dev->cachedContextCount--; - LOG(VKVG_LOG_THREAD,"get cached context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); + LOG(VKVG_LOG_THREAD, "get cached context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, + dev->cachedContextCount); - *pCtx = cur->ctx; - free (cur); - UNLOCK_DEVICE - return true; - } - prev = cur; - cur = cur->pNext; - } - } - *pCtx = NULL; - UNLOCK_DEVICE - return false; + *pCtx = cur->ctx; + free(cur); + UNLOCK_DEVICE + return true; + } + prev = cur; + cur = cur->pNext; + } + } + *pCtx = NULL; + UNLOCK_DEVICE + return false; } -void _device_store_context (VkvgContext ctx) { - VkvgDevice dev = ctx->dev; +void _device_store_context(VkvgContext ctx) { + VkvgDevice dev = ctx->dev; - LOCK_DEVICE + LOCK_DEVICE - _cached_ctx* cur = (_cached_ctx*)calloc(1, sizeof(_cached_ctx)); - cur->ctx = ctx; - cur->thread = thrd_current (); - cur->pNext = dev->cachedContextLast; + _cached_ctx *cur = (_cached_ctx *)calloc(1, sizeof(_cached_ctx)); + cur->ctx = ctx; + cur->thread = thrd_current(); + cur->pNext = dev->cachedContextLast; - dev->cachedContextLast = cur; - dev->cachedContextCount++; + dev->cachedContextLast = cur; + dev->cachedContextCount++; - LOG(VKVG_LOG_THREAD,"store context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); + LOG(VKVG_LOG_THREAD, "store context: %p, thd:%lu cached ctx: %d\n", cur->ctx, cur->thread, dev->cachedContextCount); - ctx->references++; + ctx->references++; - UNLOCK_DEVICE + UNLOCK_DEVICE } -void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence) { - LOCK_DEVICE - vkh_cmd_submit (dev->gQueue, cmd, fence); - UNLOCK_DEVICE +void _device_submit_cmd(VkvgDevice dev, VkCommandBuffer *cmd, VkFence fence) { + LOCK_DEVICE + vkh_cmd_submit(dev->gQueue, cmd, fence); + UNLOCK_DEVICE } -bool _device_init_function_pointers (VkvgDevice dev) { -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - if (vkGetInstanceProcAddr(dev->instance, "vkSetDebugUtilsObjectNameEXT")==VK_NULL_HANDLE){ - LOG(VKVG_LOG_ERR, "vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n"); - return false; - } - vkh_device_init_debug_utils ((VkhDevice)dev); +bool _device_init_function_pointers(VkvgDevice dev) { +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + if (vkGetInstanceProcAddr(dev->instance, "vkSetDebugUtilsObjectNameEXT") == VK_NULL_HANDLE) { + LOG(VKVG_LOG_ERR, "vkvg create device failed: 'VK_EXT_debug_utils' has to be loaded for Debug build\n"); + return false; + } + vkh_device_init_debug_utils((VkhDevice)dev); #endif - CmdBindPipeline = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindPipeline); - CmdBindDescriptorSets = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindDescriptorSets); - CmdBindIndexBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindIndexBuffer); - CmdBindVertexBuffers = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindVertexBuffers); - CmdDrawIndexed = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDrawIndexed); - CmdDraw = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDraw); - CmdSetStencilCompareMask= GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilCompareMask); - CmdSetStencilReference = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilReference); - CmdSetStencilWriteMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilWriteMask); - CmdBeginRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBeginRenderPass); - CmdEndRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdEndRenderPass); - CmdSetViewport = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetViewport); - CmdSetScissor = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetScissor); - CmdPushConstants = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdPushConstants); - WaitForFences = GetVkProcAddress(dev->vkDev, dev->instance, vkWaitForFences); - ResetFences = GetVkProcAddress(dev->vkDev, dev->instance, vkResetFences); - ResetCommandBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkResetCommandBuffer); - return true; + CmdBindPipeline = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindPipeline); + CmdBindDescriptorSets = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindDescriptorSets); + CmdBindIndexBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindIndexBuffer); + CmdBindVertexBuffers = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBindVertexBuffers); + CmdDrawIndexed = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDrawIndexed); + CmdDraw = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdDraw); + CmdSetStencilCompareMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilCompareMask); + CmdSetStencilReference = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilReference); + CmdSetStencilWriteMask = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetStencilWriteMask); + CmdBeginRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdBeginRenderPass); + CmdEndRenderPass = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdEndRenderPass); + CmdSetViewport = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetViewport); + CmdSetScissor = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdSetScissor); + CmdPushConstants = GetVkProcAddress(dev->vkDev, dev->instance, vkCmdPushConstants); + WaitForFences = GetVkProcAddress(dev->vkDev, dev->instance, vkWaitForFences); + ResetFences = GetVkProcAddress(dev->vkDev, dev->instance, vkResetFences); + ResetCommandBuffer = GetVkProcAddress(dev->vkDev, dev->instance, vkResetCommandBuffer); + return true; } -void _device_create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tiling) { - //create empty image to bind to context source descriptor when not in use - dev->emptyImg = vkh_image_create((VkhDevice)dev,format,16,16,tiling,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - vkh_image_create_descriptor(dev->emptyImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +void _device_create_empty_texture(VkvgDevice dev, VkFormat format, VkImageTiling tiling) { + // create empty image to bind to context source descriptor when not in use + dev->emptyImg = vkh_image_create((VkhDevice)dev, format, 16, 16, tiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + vkh_image_create_descriptor(dev->emptyImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - _device_wait_and_reset_device_fence (dev); + _device_wait_and_reset_device_fence(dev); - vkh_cmd_begin (dev->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (dev->cmd, dev->emptyImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - vkh_cmd_end (dev->cmd); - _device_submit_cmd (dev, &dev->cmd, dev->fence); + vkh_cmd_begin(dev->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(dev->cmd, dev->emptyImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + vkh_cmd_end(dev->cmd); + _device_submit_cmd(dev, &dev->cmd, dev->fence); } -void _device_check_best_image_tiling (VkvgDevice dev, VkFormat format) { - VkFlags stencilFormats[] = { VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT }; - VkFormatProperties phyStencilProps = { 0 }, phyImgProps = { 0 }; +void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format) { + VkFlags stencilFormats[] = {VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_D32_SFLOAT_S8_UINT}; + VkFormatProperties phyStencilProps = {0}, phyImgProps = {0}; + + // check png blit format + VkFlags pngBlitFormats[] = {VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM}; + dev->pngStagFormat = VK_FORMAT_UNDEFINED; + for (int i = 0; i < 2; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, pngBlitFormats[i], &phyImgProps); + if ((phyImgProps.linearTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { + dev->pngStagFormat = pngBlitFormats[i]; + dev->pngStagTiling = VK_IMAGE_TILING_LINEAR; + break; + } else if ((phyImgProps.optimalTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == + VKVG_PNG_WRITE_IMG_REQUIREMENTS) { + dev->pngStagFormat = pngBlitFormats[i]; + dev->pngStagTiling = VK_IMAGE_TILING_OPTIMAL; + break; + } + } - //check png blit format - VkFlags pngBlitFormats[] = { VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_R8G8B8A8_UNORM}; - dev->pngStagFormat = VK_FORMAT_UNDEFINED; - for (int i = 0; i < 2; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, pngBlitFormats[i], &phyImgProps); - if ((phyImgProps.linearTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { - dev->pngStagFormat = pngBlitFormats[i]; - dev->pngStagTiling = VK_IMAGE_TILING_LINEAR; - break; - } else if ((phyImgProps.optimalTilingFeatures & VKVG_PNG_WRITE_IMG_REQUIREMENTS) == VKVG_PNG_WRITE_IMG_REQUIREMENTS) { - dev->pngStagFormat = pngBlitFormats[i]; - dev->pngStagTiling = VK_IMAGE_TILING_OPTIMAL; - break; - } - } + if (dev->pngStagFormat == VK_FORMAT_UNDEFINED) + LOG(VKVG_LOG_DEBUG, "vkvg create device failed: no suitable image format for png write\n"); - if (dev->pngStagFormat == VK_FORMAT_UNDEFINED) - LOG(VKVG_LOG_DEBUG, "vkvg create device failed: no suitable image format for png write\n"); + dev->stencilFormat = VK_FORMAT_UNDEFINED; + dev->stencilAspectFlag = VK_IMAGE_ASPECT_STENCIL_BIT; + dev->supportedTiling = 0xff; - dev->stencilFormat = VK_FORMAT_UNDEFINED; - dev->stencilAspectFlag = VK_IMAGE_ASPECT_STENCIL_BIT; - dev->supportedTiling = 0xff; - - vkGetPhysicalDeviceFormatProperties(dev->phy, format, &phyImgProps); - - if ((phyImgProps.optimalTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { - for (int i = 0; i < 4; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); - if (phyStencilProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { - dev->stencilFormat = stencilFormats[i]; - if (i > 0) - dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; - dev->supportedTiling = VK_IMAGE_TILING_OPTIMAL; - return; - } - } - } - if ((phyImgProps.linearTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { - for (int i = 0; i < 4; i++) - { - vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); - if (phyStencilProps.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { - dev->stencilFormat = stencilFormats[i]; - if (i > 0) - dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; - dev->supportedTiling = VK_IMAGE_TILING_LINEAR; - return; - } - } - } - dev->status = VKVG_STATUS_INVALID_FORMAT; - LOG(VKVG_LOG_ERR, "vkvg create device failed: image format not supported: %d\n", format); + vkGetPhysicalDeviceFormatProperties(dev->phy, format, &phyImgProps); + + if ((phyImgProps.optimalTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { + for (int i = 0; i < 4; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); + if (phyStencilProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + dev->stencilFormat = stencilFormats[i]; + if (i > 0) + dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; + dev->supportedTiling = VK_IMAGE_TILING_OPTIMAL; + return; + } + } + } + if ((phyImgProps.linearTilingFeatures & VKVG_SURFACE_IMGS_REQUIREMENTS) == VKVG_SURFACE_IMGS_REQUIREMENTS) { + for (int i = 0; i < 4; i++) { + vkGetPhysicalDeviceFormatProperties(dev->phy, stencilFormats[i], &phyStencilProps); + if (phyStencilProps.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) { + dev->stencilFormat = stencilFormats[i]; + if (i > 0) + dev->stencilAspectFlag |= VK_IMAGE_ASPECT_DEPTH_BIT; + dev->supportedTiling = VK_IMAGE_TILING_LINEAR; + return; + } + } + } + dev->status = VKVG_STATUS_INVALID_FORMAT; + LOG(VKVG_LOG_ERR, "vkvg create device failed: image format not supported: %d\n", format); } -void _dump_image_format_properties (VkvgDevice dev, VkFormat format) { - /*VkImageFormatProperties imgProps; - VK_CHECK_RESULT(vkGetPhysicalDeviceImageFormatProperties(dev->phy, - format, VK_IMAGE_TYPE_2D, VKVG_TILING, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT, - 0, &imgProps)); - printf ("tiling = %d\n", VKVG_TILING); - printf ("max extend = (%d, %d, %d)\n", imgProps.maxExtent.width, imgProps.maxExtent.height, imgProps.maxExtent.depth); - printf ("max mip levels = %d\n", imgProps.maxMipLevels); - printf ("max array layers = %d\n", imgProps.maxArrayLayers); - printf ("sample counts = "); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_1_BIT) - printf ("1,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT) - printf ("2,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_4_BIT) - printf ("4,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_8_BIT) - printf ("8,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_16_BIT) - printf ("16,"); - if (imgProps.sampleCounts & VK_SAMPLE_COUNT_32_BIT) - printf ("32,"); - printf ("\n"); - printf ("max resource size= %lu\n", imgProps.maxResourceSize); +void _dump_image_format_properties(VkvgDevice dev, VkFormat format) { + /*VkImageFormatProperties imgProps; + VK_CHECK_RESULT(vkGetPhysicalDeviceImageFormatProperties(dev->phy, + format, VK_IMAGE_TYPE_2D, VKVG_TILING, + VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT, + 0, &imgProps)); + printf ("tiling = %d\n", VKVG_TILING); + printf ("max extend = (%d, %d, %d)\n", imgProps.maxExtent.width, imgProps.maxExtent.height, + imgProps.maxExtent.depth); printf ("max mip levels = %d\n", imgProps.maxMipLevels); printf ("max array layers = + %d\n", imgProps.maxArrayLayers); printf ("sample counts = "); if (imgProps.sampleCounts & VK_SAMPLE_COUNT_1_BIT) + printf ("1,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_2_BIT) + printf ("2,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_4_BIT) + printf ("4,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_8_BIT) + printf ("8,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_16_BIT) + printf ("16,"); + if (imgProps.sampleCounts & VK_SAMPLE_COUNT_32_BIT) + printf ("32,"); + printf ("\n"); + printf ("max resource size= %lu\n", imgProps.maxResourceSize); */ - } diff --git a/src/vkvg_device_internal.h b/src/vkvg_device_internal.h index ef8c95f..d17eae1 100644 --- a/src/vkvg_device_internal.h +++ b/src/vkvg_device_internal.h @@ -25,128 +25,132 @@ #include "vkvg_internal.h" #include "vkvg_fonts.h" -#define STENCIL_FILL_BIT 0x1 -#define STENCIL_CLIP_BIT 0x2 -#define STENCIL_ALL_BIT 0x3 +#define STENCIL_FILL_BIT 0x1 +#define STENCIL_CLIP_BIT 0x2 +#define STENCIL_ALL_BIT 0x3 #define VKVG_MAX_CACHED_CONTEXT_COUNT 2 -extern PFN_vkCmdBindPipeline CmdBindPipeline; -extern PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; -extern PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; -extern PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; +extern PFN_vkCmdBindPipeline CmdBindPipeline; +extern PFN_vkCmdBindDescriptorSets CmdBindDescriptorSets; +extern PFN_vkCmdBindIndexBuffer CmdBindIndexBuffer; +extern PFN_vkCmdBindVertexBuffers CmdBindVertexBuffers; -extern PFN_vkCmdDrawIndexed CmdDrawIndexed; -extern PFN_vkCmdDraw CmdDraw; +extern PFN_vkCmdDrawIndexed CmdDrawIndexed; +extern PFN_vkCmdDraw CmdDraw; -extern PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; -extern PFN_vkCmdSetStencilReference CmdSetStencilReference; -extern PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; -extern PFN_vkCmdBeginRenderPass CmdBeginRenderPass; -extern PFN_vkCmdEndRenderPass CmdEndRenderPass; -extern PFN_vkCmdSetViewport CmdSetViewport; -extern PFN_vkCmdSetScissor CmdSetScissor; +extern PFN_vkCmdSetStencilCompareMask CmdSetStencilCompareMask; +extern PFN_vkCmdSetStencilReference CmdSetStencilReference; +extern PFN_vkCmdSetStencilWriteMask CmdSetStencilWriteMask; +extern PFN_vkCmdBeginRenderPass CmdBeginRenderPass; +extern PFN_vkCmdEndRenderPass CmdEndRenderPass; +extern PFN_vkCmdSetViewport CmdSetViewport; +extern PFN_vkCmdSetScissor CmdSetScissor; -extern PFN_vkCmdPushConstants CmdPushConstants; -extern PFN_vkWaitForFences WaitForFences; -extern PFN_vkResetFences ResetFences; -extern PFN_vkResetCommandBuffer ResetCommandBuffer; +extern PFN_vkCmdPushConstants CmdPushConstants; +extern PFN_vkWaitForFences WaitForFences; +extern PFN_vkResetFences ResetFences; +extern PFN_vkResetCommandBuffer ResetCommandBuffer; -typedef struct _cached_ctx{ - thrd_t thread; - VkvgContext ctx; - struct _cached_ctx* pNext; +typedef struct _cached_ctx { + thrd_t thread; + VkvgContext ctx; + struct _cached_ctx *pNext; } _cached_ctx; typedef struct _vkvg_device_t { - VkDevice vkDev; /**< Vulkan Logical Device */ - VkPhysicalDeviceMemoryProperties phyMemProps; /**< Vulkan Physical device memory properties */ - VkPhysicalDevice phy; /**< Vulkan Physical device */ - VkInstance instance; /**< Vulkan instance */ + VkDevice vkDev; /**< Vulkan Logical Device */ + VkPhysicalDeviceMemoryProperties phyMemProps; /**< Vulkan Physical device memory properties */ + VkPhysicalDevice phy; /**< Vulkan Physical device */ + VkInstance instance; /**< Vulkan instance */ #ifdef VKH_USE_VMA - void* allocator; /**< Vulkan Memory allocator */ + void *allocator; /**< Vulkan Memory allocator */ #endif - VkImageTiling supportedTiling; /**< Supported image tiling for surface, 0xFF=no support */ - VkFormat stencilFormat; /**< Supported vulkan image format for stencil */ - VkImageAspectFlags stencilAspectFlag; /**< stencil only or depth stencil, could be solved by VK_KHR_separate_depth_stencil_layouts*/ - VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ - VkImageTiling pngStagTiling; /**< tiling for the blit operation */ + VkImageTiling supportedTiling; /**< Supported image tiling for surface, 0xFF=no support */ + VkFormat stencilFormat; /**< Supported vulkan image format for stencil */ + VkImageAspectFlags stencilAspectFlag; /**< stencil only or depth stencil, could be solved by + VK_KHR_separate_depth_stencil_layouts*/ + VkFormat pngStagFormat; /**< Supported vulkan image format png write staging img */ + VkImageTiling pngStagTiling; /**< tiling for the blit operation */ - mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ - bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ - VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ + mtx_t mutex; /**< protect device access (queue, cahes, ...)from ctxs in separate threads */ + bool threadAware; /**< if true, mutex is created and guard device queue and caches access */ + VkhQueue gQueue; /**< Vulkan Queue with Graphic flag */ - VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ - VkRenderPass renderPass_ClearStencil;/**< Vulkan render pass for first draw with context, stencil has to be cleared */ - VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ + VkRenderPass renderPass; /**< Vulkan render pass, common for all surfaces */ + VkRenderPass + renderPass_ClearStencil; /**< Vulkan render pass for first draw with context, stencil has to be cleared */ + VkRenderPass renderPass_ClearAll; /**< Vulkan render pass for new surface, clear all attacments*/ - uint32_t references; /**< Reference count, prevent destroying device if still in use */ - VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ - VkCommandBuffer cmd; /**< Global command buffer */ - VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ + uint32_t references; /**< Reference count, prevent destroying device if still in use */ + VkCommandPool cmdPool; /**< Global command pool for processing on surfaces without context */ + VkCommandBuffer cmd; /**< Global command buffer */ + VkFence fence; /**< this fence is kept signaled when idle, wait and reset are called before each recording. */ - VkPipeline pipe_OVER; /**< default operator */ - VkPipeline pipe_SUB; - VkPipeline pipe_CLEAR; /**< clear operator */ + VkPipeline pipe_OVER; /**< default operator */ + VkPipeline pipe_SUB; + VkPipeline pipe_CLEAR; /**< clear operator */ - VkPipeline pipelinePolyFill; /**< even-odd polygon filling first step */ - VkPipeline pipelineClipping; /**< draw on stencil to update clipping regions */ + VkPipeline pipelinePolyFill; /**< even-odd polygon filling first step */ + VkPipeline pipelineClipping; /**< draw on stencil to update clipping regions */ - VkPipelineCache pipelineCache; /**< speed up startup by caching configured pipelines on disk */ - VkPipelineLayout pipelineLayout; /**< layout common to all pipelines */ - VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ - VkDescriptorSetLayout dslSrc; /**< context source surface descriptors layout */ - VkDescriptorSetLayout dslGrad; /**< context gradient descriptors layout */ + VkPipelineCache pipelineCache; /**< speed up startup by caching configured pipelines on disk */ + VkPipelineLayout pipelineLayout; /**< layout common to all pipelines */ + VkDescriptorSetLayout dslFont; /**< font cache descriptors layout */ + VkDescriptorSetLayout dslSrc; /**< context source surface descriptors layout */ + VkDescriptorSetLayout dslGrad; /**< context gradient descriptors layout */ - int hdpi, /**< only used for FreeType fonts and svg loading */ - vdpi; + int hdpi, /**< only used for FreeType fonts and svg loading */ + vdpi; - VkhDevice vkhDev; /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */ + VkhDevice vkhDev; /**< old VkhDev created during vulkan context creation by @ref vkvg_device_create. */ - VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ - VkSampleCountFlags samples; /**< samples count common to all surfaces */ - bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ - vkvg_status_t status; /**< Current status of device, affected by last operation */ + VkhImage emptyImg; /**< prevent unbound descriptor to trigger Validation error 61 */ + VkSampleCountFlags samples; /**< samples count common to all surfaces */ + bool deferredResolve; /**< if true, resolve only on context destruction and set as source */ + vkvg_status_t status; /**< Current status of device, affected by last operation */ - _font_cache_t* fontCache; /**< Store everything relative to common font caching system */ + _font_cache_t *fontCache; /**< Store everything relative to common font caching system */ - VkvgContext lastCtx; /**< last element of double linked list of context, used to trigger font caching system update on all contexts*/ + VkvgContext lastCtx; /**< last element of double linked list of context, used to trigger font caching system update + on all contexts*/ - int32_t cachedContextMaxCount; /**< Maximum context cache element count.*/ - int32_t cachedContextCount; /**< Current context cache element count.*/ - _cached_ctx* cachedContextLast; /**< Last element of single linked list of saved context for fast reuse.*/ + int32_t cachedContextMaxCount; /**< Maximum context cache element count.*/ + int32_t cachedContextCount; /**< Current context cache element count.*/ + _cached_ctx *cachedContextLast; /**< Last element of single linked list of saved context for fast reuse.*/ #ifdef VKVG_WIRED_DEBUG - VkPipeline pipelineWired; - VkPipeline pipelineLineList; + VkPipeline pipelineWired; + VkPipeline pipelineLineList; #endif #if VKVG_DBG_STATS - vkvg_debug_stats_t debug_stats; /**< debug statistics on memory usage and vulkan ressources */ + vkvg_debug_stats_t debug_stats; /**< debug statistics on memory usage and vulkan ressources */ #endif -}vkvg_device; +} vkvg_device; -#define LOCK_DEVICE \ - if (dev->threadAware)\ - mtx_lock (&dev->mutex); -#define UNLOCK_DEVICE \ - if (dev->threadAware)\ - mtx_unlock (&dev->mutex); +#define LOCK_DEVICE \ + if (dev->threadAware) \ + mtx_lock(&dev->mutex); +#define UNLOCK_DEVICE \ + if (dev->threadAware) \ + mtx_unlock(&dev->mutex); -bool _device_try_get_phyinfo (VkhPhyInfo* phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo* phy); -bool _device_init_function_pointers (VkvgDevice dev); -void _device_create_empty_texture (VkvgDevice dev, VkFormat format, VkImageTiling tiling); -void _device_get_best_image_tiling (VkvgDevice dev, VkFormat format, VkImageTiling* pTiling); -void _device_check_best_image_tiling (VkvgDevice dev, VkFormat format); -void _device_create_pipeline_cache (VkvgDevice dev); -VkRenderPass _device_createRenderPassMS (VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); -VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); -void _device_setupPipelines (VkvgDevice dev); -void _device_createDescriptorSetLayout (VkvgDevice dev); -void _device_wait_idle (VkvgDevice dev); -void _device_wait_and_reset_device_fence(VkvgDevice dev); -void _device_submit_cmd (VkvgDevice dev, VkCommandBuffer* cmd, VkFence fence); +bool _device_try_get_phyinfo(VkhPhyInfo *phys, uint32_t phyCount, VkPhysicalDeviceType gpuType, VkhPhyInfo *phy); +bool _device_init_function_pointers(VkvgDevice dev); +void _device_create_empty_texture(VkvgDevice dev, VkFormat format, VkImageTiling tiling); +void _device_get_best_image_tiling(VkvgDevice dev, VkFormat format, VkImageTiling *pTiling); +void _device_check_best_image_tiling(VkvgDevice dev, VkFormat format); +void _device_create_pipeline_cache(VkvgDevice dev); +VkRenderPass _device_createRenderPassMS(VkvgDevice dev, VkAttachmentLoadOp loadOp, VkAttachmentLoadOp stencilLoadOp); +VkRenderPass _device_createRenderPassNoResolve(VkvgDevice dev, VkAttachmentLoadOp loadOp, + VkAttachmentLoadOp stencilLoadOp); +void _device_setupPipelines(VkvgDevice dev); +void _device_createDescriptorSetLayout(VkvgDevice dev); +void _device_wait_idle(VkvgDevice dev); +void _device_wait_and_reset_device_fence(VkvgDevice dev); +void _device_submit_cmd(VkvgDevice dev, VkCommandBuffer *cmd, VkFence fence); -bool _device_try_get_cached_context (VkvgDevice dev, VkvgContext* pCtx); -void _device_store_context (VkvgContext ctx); +bool _device_try_get_cached_context(VkvgDevice dev, VkvgContext *pCtx); +void _device_store_context(VkvgContext ctx); #endif diff --git a/src/vkvg_experimental.c b/src/vkvg_experimental.c index 3e3e022..31679c0 100644 --- a/src/vkvg_experimental.c +++ b/src/vkvg_experimental.c @@ -23,6 +23,3 @@ #include <string.h> #include "vkvg_experimental.h" #include "vkvg_context_internal.h" - - - diff --git a/src/vkvg_fonts.c b/src/vkvg_fonts.c index 35858f3..868f42b 100644 --- a/src/vkvg_fonts.c +++ b/src/vkvg_fonts.c @@ -32,794 +32,792 @@ #include <wchar.h> #ifndef VKVG_USE_FREETYPE - #define STB_TRUETYPE_IMPLEMENTATION - #include "stb_truetype.h" +#define STB_TRUETYPE_IMPLEMENTATION +#include "stb_truetype.h" #endif -static int defaultFontCharSize = 12<<6; +static int defaultFontCharSize = 12 << 6; -void _fonts_cache_create (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)calloc(1, sizeof(_font_cache_t)); +void _fonts_cache_create(VkvgDevice dev) { + _font_cache_t *cache = (_font_cache_t *)calloc(1, sizeof(_font_cache_t)); - if (dev->threadAware) - mtx_init (&cache->mutex, mtx_plain); + if (dev->threadAware) + mtx_init(&cache->mutex, mtx_plain); #ifdef VKVG_USE_FONTCONFIG - cache->config = FcInitLoadConfigAndFonts (); - if (!cache->config) { - LOG(VKVG_LOG_DEBUG, "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ + cache->config = FcInitLoadConfigAndFonts(); + if (!cache->config) { + LOG(VKVG_LOG_DEBUG, + "Font config initialisation failed, consider using 'FONTCONFIG_PATH' and 'FONTCONFIG_FILE' environmane\ variables to point to 'fonts.conf' needed for FontConfig startup"); - assert(cache->config); - } + assert(cache->config); + } #endif #ifdef VKVG_USE_FREETYPE - FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); + FT_CHECK_RESULT(FT_Init_FreeType(&cache->library)); #endif #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - FT_CHECK_RESULT(FT_Library_SetLcdFilter (cache->library, FT_LCD_FILTER_LIGHT)); - cache->texFormat = FB_COLOR_FORMAT; - cache->texPixelSize = 4; + FT_CHECK_RESULT(FT_Library_SetLcdFilter(cache->library, FT_LCD_FILTER_LIGHT)); + cache->texFormat = FB_COLOR_FORMAT; + cache->texPixelSize = 4; #else - cache->texFormat = VK_FORMAT_R8_UNORM; - cache->texPixelSize = 1; + cache->texFormat = VK_FORMAT_R8_UNORM; + cache->texPixelSize = 1; #endif - cache->texLength = FONT_CACHE_INIT_LAYERS; - cache->texture = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - cache->texLength ,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + cache->texLength = FONT_CACHE_INIT_LAYERS; + cache->texture = vkh_tex2d_array_create( + (VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, cache->texLength, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(cache->texture, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, + VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - cache->uploadFence = vkh_fence_create((VkhDevice)dev); + cache->uploadFence = vkh_fence_create((VkhDevice)dev); - const uint32_t buffLength = FONT_PAGE_SIZE*FONT_PAGE_SIZE*cache->texPixelSize; + const uint32_t buffLength = FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize; - vkh_buffer_init ((VkhDevice)dev, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - buffLength, &cache->buff, true); + vkh_buffer_init((VkhDevice)dev, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, buffLength, + &cache->buff, true); - cache->cmd = vkh_cmd_buff_create((VkhDevice)dev,dev->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY); + cache->cmd = vkh_cmd_buff_create((VkhDevice)dev, dev->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); - //Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill - const VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); + // Set texture cache initial layout to shaderReadOnly to prevent error msg if cache is not fill + const VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, cache->texLength}; + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); - cache->hostBuff = (uint8_t*)malloc(buffLength); - cache->pensY = (int*)calloc(cache->texLength, sizeof(int)); + cache->hostBuff = (uint8_t *)malloc(buffLength); + cache->pensY = (int *)calloc(cache->texLength, sizeof(int)); - dev->fontCache = cache; + dev->fontCache = cache; } -///increase layer count of 2d texture array used as font cache. -void _increase_font_tex_array (VkvgDevice dev){ - LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n"); +/// increase layer count of 2d texture array used as font cache. +void _increase_font_tex_array(VkvgDevice dev) { + LOG(VKVG_LOG_INFO, "_increase_font_tex_array\n"); - _font_cache_t* cache = dev->fontCache; + _font_cache_t *cache = dev->fontCache; - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - ResetFences (dev->vkDev, 1, &cache->uploadFence); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &cache->uploadFence); - vkResetCommandBuffer(cache->cmd, 0); + vkResetCommandBuffer(cache->cmd, 0); - uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; - VkhImage newImg = vkh_tex2d_array_create ((VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, - newSize ,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor (newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + uint8_t newSize = cache->texLength + FONT_CACHE_INIT_LAYERS; + VkhImage newImg = vkh_tex2d_array_create( + (VkhDevice)dev, cache->texFormat, FONT_PAGE_SIZE, FONT_PAGE_SIZE, newSize, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(newImg, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,newSize}; - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,cache->texLength}; + VkImageSubresourceRange subresNew = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, newSize}; + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, cache->texLength}; - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageCopy cregion = { .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, - .extent = {FONT_PAGE_SIZE,FONT_PAGE_SIZE,1}}; + VkImageCopy cregion = {.srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, cache->texLength}, + .extent = {FONT_PAGE_SIZE, FONT_PAGE_SIZE, 1}}; - vkCmdCopyImage (cache->cmd, vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); + vkCmdCopyImage(cache->cmd, vkh_image_get_vkimage(cache->texture), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(newImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cregion); - vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, newImg, subresNew, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); - vkWaitForFences (dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); - cache->pensY = (int*)realloc(cache->pensY, newSize * sizeof(int)); - void* tmp = memset (&cache->pensY[cache->texLength],0,FONT_CACHE_INIT_LAYERS*sizeof(int)); + cache->pensY = (int *)realloc(cache->pensY, newSize * sizeof(int)); + void *tmp = memset(&cache->pensY[cache->texLength], 0, FONT_CACHE_INIT_LAYERS * sizeof(int)); - vkh_image_destroy (cache->texture); + vkh_image_destroy(cache->texture); - cache->texLength = newSize; - cache->texture = newImg; + cache->texLength = newSize; + cache->texture = newImg; - _device_wait_idle(dev); + _device_wait_idle(dev); } -//flush font stagging buffer to cache texture array -//Trigger stagging buffer to be uploaded in font cache. Groupping upload improve performances. -void _flush_chars_to_tex (VkvgDevice dev, _vkvg_font_t* f) { +// flush font stagging buffer to cache texture array +// Trigger stagging buffer to be uploaded in font cache. Groupping upload improve performances. +void _flush_chars_to_tex(VkvgDevice dev, _vkvg_font_t *f) { - _font_cache_t* cache = dev->fontCache; - if (cache->stagingX == 0)//no char in stagging buff to flush - return; + _font_cache_t *cache = dev->fontCache; + if (cache->stagingX == 0) // no char in stagging buff to flush + return; - LOG(VKVG_LOG_INFO, "_flush_chars_to_tex pen(%d, %d)\n",f->curLine.penX, f->curLine.penY); - vkWaitForFences (dev->vkDev,1,&cache->uploadFence,VK_TRUE,UINT64_MAX); - ResetFences (dev->vkDev, 1, &cache->uploadFence); + LOG(VKVG_LOG_INFO, "_flush_chars_to_tex pen(%d, %d)\n", f->curLine.penX, f->curLine.penY); + vkWaitForFences(dev->vkDev, 1, &cache->uploadFence, VK_TRUE, UINT64_MAX); + ResetFences(dev->vkDev, 1, &cache->uploadFence); - vkResetCommandBuffer(cache->cmd,0); + vkResetCommandBuffer(cache->cmd, 0); - memcpy(vkh_buffer_get_mapped_pointer (&cache->buff), cache->hostBuff, (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); + memcpy(vkh_buffer_get_mapped_pointer(&cache->buff), cache->hostBuff, + (uint64_t)f->curLine.height * FONT_PAGE_SIZE * cache->texPixelSize); - vkh_cmd_begin (cache->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cache->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,f->curLine.pageIdx,1}; - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VkImageSubresourceRange subres = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, f->curLine.pageIdx, 1}; + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkBufferImageCopy bufferCopyRegion = { .imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,f->curLine.pageIdx,1}, - .bufferRowLength = FONT_PAGE_SIZE, - .bufferImageHeight = f->curLine.height, - .imageOffset = {f->curLine.penX,f->curLine.penY,0}, - .imageExtent = {FONT_PAGE_SIZE-f->curLine.penX,f->curLine.height,1}}; + VkBufferImageCopy bufferCopyRegion = {.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, f->curLine.pageIdx, 1}, + .bufferRowLength = FONT_PAGE_SIZE, + .bufferImageHeight = f->curLine.height, + .imageOffset = {f->curLine.penX, f->curLine.penY, 0}, + .imageExtent = {FONT_PAGE_SIZE - f->curLine.penX, f->curLine.height, 1}}; - vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, - vkh_image_get_vkimage (cache->texture), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vkCmdCopyBufferToImage(cache->cmd, cache->buff.buffer, vkh_image_get_vkimage(cache->texture), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); - vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_image_set_layout_subres(cache->cmd, cache->texture, subres, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); + VK_CHECK_RESULT(vkEndCommandBuffer(cache->cmd)); - _device_submit_cmd (dev, &cache->cmd, cache->uploadFence); + _device_submit_cmd(dev, &cache->cmd, cache->uploadFence); - f->curLine.penX += cache->stagingX; - cache->stagingX = 0; - memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); + f->curLine.penX += cache->stagingX; + cache->stagingX = 0; + memset(cache->hostBuff, 0, (uint64_t)FONT_PAGE_SIZE * FONT_PAGE_SIZE * cache->texPixelSize); } -///Start a new line in font cache, increase texture layer count if needed. -void _init_next_line_in_tex_cache (VkvgDevice dev, _vkvg_font_t* f){ - _font_cache_t* cache = dev->fontCache; - int i; - for (i = 0; i < cache->texLength; ++i) { - if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) - continue; - f->curLine.pageIdx = (unsigned char)i; - f->curLine.penX = 0; - f->curLine.penY = cache->pensY[i]; - cache->pensY[i] += f->curLine.height; - return; - } - _flush_chars_to_tex (dev, f); - _increase_font_tex_array (dev); - _init_next_line_in_tex_cache(dev, f); +/// Start a new line in font cache, increase texture layer count if needed. +void _init_next_line_in_tex_cache(VkvgDevice dev, _vkvg_font_t *f) { + _font_cache_t *cache = dev->fontCache; + int i; + for (i = 0; i < cache->texLength; ++i) { + if (cache->pensY[i] + f->curLine.height >= FONT_PAGE_SIZE) + continue; + f->curLine.pageIdx = (unsigned char)i; + f->curLine.penX = 0; + f->curLine.penY = cache->pensY[i]; + cache->pensY[i] += f->curLine.height; + return; + } + _flush_chars_to_tex(dev, f); + _increase_font_tex_array(dev); + _init_next_line_in_tex_cache(dev, f); } -void _font_cache_destroy (VkvgDevice dev){ - _font_cache_t* cache = (_font_cache_t*)dev->fontCache; +void _font_cache_destroy(VkvgDevice dev) { + _font_cache_t *cache = (_font_cache_t *)dev->fontCache; - free (cache->hostBuff); + free(cache->hostBuff); - for (int i = 0; i < cache->fontsCount; ++i) { - _vkvg_font_identity_t* f = &cache->fonts[i]; - for (uint32_t j = 0; j < f->sizeCount; j++) { - _vkvg_font_t* s = &f->sizes[j]; + for (int i = 0; i < cache->fontsCount; ++i) { + _vkvg_font_identity_t *f = &cache->fonts[i]; + for (uint32_t j = 0; j < f->sizeCount; j++) { + _vkvg_font_t *s = &f->sizes[j]; #ifdef VKVG_USE_FREETYPE - for (int g = 0; g < s->face->num_glyphs; ++g) { - if (s->charLookup[g]!=NULL) - free(s->charLookup[g]); - } - FT_Done_Face (s->face); + for (int g = 0; g < s->face->num_glyphs; ++g) { + if (s->charLookup[g] != NULL) + free(s->charLookup[g]); + } + FT_Done_Face(s->face); #else - for (int g = 0; g < f->stbInfo.numGlyphs; ++g) { - if (s->charLookup[g]!=NULL) - free(s->charLookup[g]); - } + for (int g = 0; g < f->stbInfo.numGlyphs; ++g) { + if (s->charLookup[g] != NULL) + free(s->charLookup[g]); + } #endif #ifdef VKVG_USE_HARFBUZZ - hb_font_destroy (s->hb_font); + hb_font_destroy(s->hb_font); #endif - free(s->charLookup); - } - free (f->sizes); - free(f->fontFile); - for (uint32_t j = 0; j < f->namesCount; j++) - free (f->names[j]); - if (f->namesCount > 0) - free (f->names); - free (f->fontBuffer); - } + free(s->charLookup); + } + free(f->sizes); + free(f->fontFile); + for (uint32_t j = 0; j < f->namesCount; j++) + free(f->names[j]); + if (f->namesCount > 0) + free(f->names); + free(f->fontBuffer); + } - free(cache->fonts); - free(cache->pensY); + free(cache->fonts); + free(cache->pensY); - vkh_buffer_reset (&cache->buff); - vkh_image_destroy (cache->texture); - //vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); - vkDestroyFence (dev->vkDev,cache->uploadFence,NULL); + vkh_buffer_reset(&cache->buff); + vkh_image_destroy(cache->texture); + // vkFreeCommandBuffers(dev->vkDev,dev->cmdPool, 1, &cache->cmd); + vkDestroyFence(dev->vkDev, cache->uploadFence, NULL); #ifdef VKVG_USE_FREETYPE - FT_Done_FreeType(cache->library); + FT_Done_FreeType(cache->library); #endif #ifdef VKVG_USE_FONTCONFIG - FcConfigDestroy(cache->config); - FcFini(); + FcConfigDestroy(cache->config); + FcFini(); #endif - if (dev->threadAware) - mtx_destroy (&cache->mutex); - - free (dev->fontCache); + if (dev->threadAware) + mtx_destroy(&cache->mutex); + free(dev->fontCache); } -void _font_cache_update_context_descset (VkvgContext ctx) { - if (ctx->fontCacheImg) - vkh_image_destroy (ctx->fontCacheImg); +void _font_cache_update_context_descset(VkvgContext ctx) { + if (ctx->fontCacheImg) + vkh_image_destroy(ctx->fontCacheImg); - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) - ctx->fontCacheImg = ctx->dev->fontCache->texture; - vkh_image_reference (ctx->fontCacheImg); + ctx->fontCacheImg = ctx->dev->fontCache->texture; + vkh_image_reference(ctx->fontCacheImg); - _update_descriptor_set (ctx, ctx->fontCacheImg, ctx->dsFont); + _update_descriptor_set(ctx, ctx->fontCacheImg, ctx->dsFont); - UNLOCK_FONTCACHE (ctx->dev) + UNLOCK_FONTCACHE(ctx->dev) } -//create a new char entry and put glyph in stagging buffer, ready for upload. -_char_ref* _prepare_char (VkvgDevice dev, VkvgText tr, uint32_t gindex){ - _vkvg_font_t* f = tr->font; +// create a new char entry and put glyph in stagging buffer, ready for upload. +_char_ref *_prepare_char(VkvgDevice dev, VkvgText tr, uint32_t gindex) { + _vkvg_font_t *f = tr->font; #ifdef VKVG_USE_FREETYPE - #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); - FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); - #else - FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); - #endif +#if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_TARGET_NORMAL)); + FT_CHECK_RESULT(FT_Render_Glyph(f->face->glyph, FT_RENDER_MODE_LCD)); +#else + FT_CHECK_RESULT(FT_Load_Glyph(f->face, gindex, FT_LOAD_RENDER)); +#endif - FT_GlyphSlot slot = f->face->glyph; - FT_Bitmap bmp = slot->bitmap; - uint32_t bmpByteWidth = bmp.width; - uint32_t bmpPixelWidth = bmp.width; - uint32_t bmpRows = bmp.rows; - unsigned char* buffer = bmp.buffer; + FT_GlyphSlot slot = f->face->glyph; + FT_Bitmap bmp = slot->bitmap; + uint32_t bmpByteWidth = bmp.width; + uint32_t bmpPixelWidth = bmp.width; + uint32_t bmpRows = bmp.rows; + unsigned char *buffer = bmp.buffer; #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - bmpPixelWidth /= 3; + bmpPixelWidth /= 3; #endif #else - stbtt_fontinfo* pStbInfo = &tr->fontId->stbInfo; - int c_x1, c_y1, c_x2, c_y2; - stbtt_GetGlyphBitmapBox (pStbInfo, gindex, f->scale, f->scale, &c_x1, &c_y1, &c_x2, &c_y2); - uint32_t bmpByteWidth = c_x2 - c_x1; - uint32_t bmpPixelWidth = bmpByteWidth; - uint32_t bmpRows = c_y2 - c_y1; + stbtt_fontinfo *pStbInfo = &tr->fontId->stbInfo; + int c_x1, c_y1, c_x2, c_y2; + stbtt_GetGlyphBitmapBox(pStbInfo, gindex, f->scale, f->scale, &c_x1, &c_y1, &c_x2, &c_y2); + uint32_t bmpByteWidth = c_x2 - c_x1; + uint32_t bmpPixelWidth = bmpByteWidth; + uint32_t bmpRows = c_y2 - c_y1; #endif - uint8_t* data = dev->fontCache->hostBuff; + uint8_t *data = dev->fontCache->hostBuff; - if (dev->fontCache->stagingX + f->curLine.penX + bmpPixelWidth > FONT_PAGE_SIZE){ - _flush_chars_to_tex (dev, f); - _init_next_line_in_tex_cache (dev, f); - } + if (dev->fontCache->stagingX + f->curLine.penX + bmpPixelWidth > FONT_PAGE_SIZE) { + _flush_chars_to_tex(dev, f); + _init_next_line_in_tex_cache(dev, f); + } - _char_ref* cr = (_char_ref*)malloc(sizeof(_char_ref)); - int penX = dev->fontCache->stagingX; + _char_ref *cr = (_char_ref *)malloc(sizeof(_char_ref)); + int penX = dev->fontCache->stagingX; #ifdef VKVG_USE_FREETYPE - for(uint32_t y=0; y < bmpRows; y++) { - for(uint32_t x=0; x < bmpPixelWidth; x++) { + for (uint32_t y = 0; y < bmpRows; y++) { + for (uint32_t x = 0; x < bmpPixelWidth; x++) { #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - unsigned char r = buffer[y * bmp.pitch + x * 3]; - unsigned char g = buffer[y * bmp.pitch + x * 3 + 1]; - unsigned char b = buffer[y * bmp.pitch + x * 3 + 2]; + unsigned char r = buffer[y * bmp.pitch + x * 3]; + unsigned char g = buffer[y * bmp.pitch + x * 3 + 1]; + unsigned char b = buffer[y * bmp.pitch + x * 3 + 2]; - data[(penX + x + y * FONT_PAGE_SIZE) * 4] = b; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 1] = g; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 2] = r; - data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 3] = (r+g+b)/3; + data[(penX + x + y * FONT_PAGE_SIZE) * 4] = b; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 1] = g; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 2] = r; + data[(penX + x + y * FONT_PAGE_SIZE) * 4 + 3] = (r + g + b) / 3; #else - data[penX + x + y * FONT_PAGE_SIZE ] = buffer[x + y * bmpPixelWidth]; + data[penX + x + y * FONT_PAGE_SIZE] = buffer[x + y * bmpPixelWidth]; #endif - } - } - cr->bmpDiff.x = (int16_t)slot->bitmap_left; - cr->bmpDiff.y = (int16_t)slot->bitmap_top; - cr->advance = slot->advance; + } + } + cr->bmpDiff.x = (int16_t)slot->bitmap_left; + cr->bmpDiff.y = (int16_t)slot->bitmap_top; + cr->advance = slot->advance; #else - int advance; - int lsb; - stbtt_GetGlyphHMetrics(pStbInfo, gindex, &advance, &lsb); - stbtt_MakeGlyphBitmap (pStbInfo, data + penX, bmpPixelWidth, bmpRows, FONT_PAGE_SIZE, f->scale, f->scale, gindex); - cr->bmpDiff.x = (int16_t)c_x1; - cr->bmpDiff.y = (int16_t)-c_y1; - cr->advance = (vec2) {(uint32_t)roundf (f->scale * advance) << 6, 0}; + int advance; + int lsb; + stbtt_GetGlyphHMetrics(pStbInfo, gindex, &advance, &lsb); + stbtt_MakeGlyphBitmap(pStbInfo, data + penX, bmpPixelWidth, bmpRows, FONT_PAGE_SIZE, f->scale, f->scale, gindex); + cr->bmpDiff.x = (int16_t)c_x1; + cr->bmpDiff.y = (int16_t)-c_y1; + cr->advance = (vec2){(uint32_t)roundf(f->scale * advance) << 6, 0}; #endif - vec4 uvBounds = { - {(float)(penX + f->curLine.penX) / (float)FONT_PAGE_SIZE}, - {(float)f->curLine.penY / (float)FONT_PAGE_SIZE}, - {(float)bmpPixelWidth}, - {(float)bmpRows}}; - cr->bounds = uvBounds; - cr->pageIdx = f->curLine.pageIdx; + vec4 uvBounds = {{(float)(penX + f->curLine.penX) / (float)FONT_PAGE_SIZE}, + {(float)f->curLine.penY / (float)FONT_PAGE_SIZE}, + {(float)bmpPixelWidth}, + {(float)bmpRows}}; + cr->bounds = uvBounds; + cr->pageIdx = f->curLine.pageIdx; - f->charLookup[gindex] = cr; - dev->fontCache->stagingX += bmpPixelWidth; - return cr; + f->charLookup[gindex] = cr; + dev->fontCache->stagingX += bmpPixelWidth; + return cr; } -void _font_add_name (_vkvg_font_identity_t* font, const char* name) { - if (++font->namesCount == 1) - font->names = (char**) malloc (sizeof(char*)); - else - font->names = (char**) realloc (font->names, font->namesCount * sizeof(char*)); - font->names[font->namesCount-1] = (char*)calloc(strlen(name)+1, sizeof (char)); - strcpy (font->names[font->namesCount-1], name); +void _font_add_name(_vkvg_font_identity_t *font, const char *name) { + if (++font->namesCount == 1) + font->names = (char **)malloc(sizeof(char *)); + else + font->names = (char **)realloc(font->names, font->namesCount * sizeof(char *)); + font->names[font->namesCount - 1] = (char *)calloc(strlen(name) + 1, sizeof(char)); + strcpy(font->names[font->namesCount - 1], name); } -bool _font_cache_load_font_file_in_memory (_vkvg_font_identity_t* fontId) { - FILE* fontFile = fopen(fontId->fontFile, "rb"); - if (!fontFile) - return false; - fseek(fontFile, 0, SEEK_END); - fontId->fontBufSize = ftell(fontFile); /* how long is the file ? */ - fseek(fontFile, 0, SEEK_SET); /* reset */ - fontId->fontBuffer = malloc(fontId->fontBufSize); - fread(fontId->fontBuffer, fontId->fontBufSize, 1, fontFile); - fclose(fontFile); - return true; +bool _font_cache_load_font_file_in_memory(_vkvg_font_identity_t *fontId) { + FILE *fontFile = fopen(fontId->fontFile, "rb"); + if (!fontFile) + return false; + fseek(fontFile, 0, SEEK_END); + fontId->fontBufSize = ftell(fontFile); /* how long is the file ? */ + fseek(fontFile, 0, SEEK_SET); /* reset */ + fontId->fontBuffer = malloc(fontId->fontBufSize); + fread(fontId->fontBuffer, fontId->fontBufSize, 1, fontFile); + fclose(fontFile); + return true; } -_vkvg_font_identity_t* _font_cache_add_font_identity (VkvgContext ctx, const char* fontFilePath, const char* name){ - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - if (++cache->fontsCount == 1) - cache->fonts = (_vkvg_font_identity_t*) malloc (cache->fontsCount * sizeof(_vkvg_font_identity_t)); - else - cache->fonts = (_vkvg_font_identity_t*) realloc (cache->fonts, cache->fontsCount * sizeof(_vkvg_font_identity_t)); - _vkvg_font_identity_t nf = {0}; +_vkvg_font_identity_t *_font_cache_add_font_identity(VkvgContext ctx, const char *fontFilePath, const char *name) { + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + if (++cache->fontsCount == 1) + cache->fonts = (_vkvg_font_identity_t *)malloc(cache->fontsCount * sizeof(_vkvg_font_identity_t)); + else + cache->fonts = + (_vkvg_font_identity_t *)realloc(cache->fonts, cache->fontsCount * sizeof(_vkvg_font_identity_t)); + _vkvg_font_identity_t nf = {0}; - if (fontFilePath) { - int fflength = strlen (fontFilePath) + 1; - nf.fontFile = (char*)malloc (fflength * sizeof(char)); - strcpy (nf.fontFile, fontFilePath); - } + if (fontFilePath) { + int fflength = strlen(fontFilePath) + 1; + nf.fontFile = (char *)malloc(fflength * sizeof(char)); + strcpy(nf.fontFile, fontFilePath); + } - _font_add_name (&nf, name); + _font_add_name(&nf, name); - cache->fonts[cache->fontsCount-1] = nf; - return &cache->fonts[cache->fontsCount-1]; + cache->fonts[cache->fontsCount - 1] = nf; + return &cache->fonts[cache->fontsCount - 1]; } -//select current font for context -_vkvg_font_t* _find_or_create_font_size (VkvgContext ctx) { - _vkvg_font_identity_t* font = ctx->currentFont; +// select current font for context +_vkvg_font_t *_find_or_create_font_size(VkvgContext ctx) { + _vkvg_font_identity_t *font = ctx->currentFont; - for (uint32_t i = 0; i < font->sizeCount; ++i) { - if (font->sizes[i].charSize == ctx->selectedCharSize) - return &font->sizes[i]; - } - //if not found, create a new font size structure - if (++font->sizeCount == 1) - font->sizes = (_vkvg_font_t*) malloc (sizeof(_vkvg_font_t)); - else - font->sizes = (_vkvg_font_t*) realloc (font->sizes, font->sizeCount * sizeof(_vkvg_font_t)); - _vkvg_font_t newSize = {.charSize = ctx->selectedCharSize}; + for (uint32_t i = 0; i < font->sizeCount; ++i) { + if (font->sizes[i].charSize == ctx->selectedCharSize) + return &font->sizes[i]; + } + // if not found, create a new font size structure + if (++font->sizeCount == 1) + font->sizes = (_vkvg_font_t *)malloc(sizeof(_vkvg_font_t)); + else + font->sizes = (_vkvg_font_t *)realloc(font->sizes, font->sizeCount * sizeof(_vkvg_font_t)); + _vkvg_font_t newSize = {.charSize = ctx->selectedCharSize}; - VkvgDevice dev = ctx->dev; + VkvgDevice dev = ctx->dev; #ifdef VKVG_USE_FREETYPE - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - FT_CHECK_RESULT(FT_New_Memory_Face (cache->library, font->fontBuffer, font->fontBufSize, 0, &newSize.face)); - FT_CHECK_RESULT(FT_Set_Char_Size(newSize.face, 0, newSize.charSize, dev->hdpi, dev->vdpi )); + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + FT_CHECK_RESULT(FT_New_Memory_Face(cache->library, font->fontBuffer, font->fontBufSize, 0, &newSize.face)); + FT_CHECK_RESULT(FT_Set_Char_Size(newSize.face, 0, newSize.charSize, dev->hdpi, dev->vdpi)); - newSize.charLookup = (_char_ref**)calloc (newSize.face->num_glyphs, sizeof(_char_ref*)); + newSize.charLookup = (_char_ref **)calloc(newSize.face->num_glyphs, sizeof(_char_ref *)); - if (FT_IS_SCALABLE(newSize.face)) - newSize.curLine.height = newSize.face->size->metrics.height >> 6; - else - newSize.curLine.height = newSize.face->height >> 6; + if (FT_IS_SCALABLE(newSize.face)) + newSize.curLine.height = newSize.face->size->metrics.height >> 6; + else + newSize.curLine.height = newSize.face->height >> 6; #else - int result = stbtt_InitFont(&font->stbInfo, font->fontBuffer, 0); - assert(result && "stbtt_initFont failed"); - if (!result) { - ctx->status = VKVG_STATUS_INVALID_FONT; - return NULL; - } - stbtt_GetFontVMetrics(&font->stbInfo, &font->ascent, &font->descent, &font->lineGap); - newSize.charLookup = (_char_ref**)calloc (font->stbInfo.numGlyphs, sizeof(_char_ref*)); - //newSize.scale = stbtt_ScaleForPixelHeight(&font->stbInfo, newSize.charSize); - newSize.scale = stbtt_ScaleForMappingEmToPixels(&font->stbInfo, newSize.charSize); - newSize.curLine.height = roundf (newSize.scale * (font->ascent - font->descent + font->lineGap)); - newSize.ascent = roundf (newSize.scale * font->ascent); - newSize.descent = roundf (newSize.scale * font->descent); - newSize.lineGap = roundf (newSize.scale * font->lineGap); + int result = stbtt_InitFont(&font->stbInfo, font->fontBuffer, 0); + assert(result && "stbtt_initFont failed"); + if (!result) { + ctx->status = VKVG_STATUS_INVALID_FONT; + return NULL; + } + stbtt_GetFontVMetrics(&font->stbInfo, &font->ascent, &font->descent, &font->lineGap); + newSize.charLookup = (_char_ref **)calloc(font->stbInfo.numGlyphs, sizeof(_char_ref *)); + // newSize.scale = stbtt_ScaleForPixelHeight(&font->stbInfo, newSize.charSize); + newSize.scale = stbtt_ScaleForMappingEmToPixels(&font->stbInfo, newSize.charSize); + newSize.curLine.height = roundf(newSize.scale * (font->ascent - font->descent + font->lineGap)); + newSize.ascent = roundf(newSize.scale * font->ascent); + newSize.descent = roundf(newSize.scale * font->descent); + newSize.lineGap = roundf(newSize.scale * font->lineGap); #endif #ifdef VKVG_USE_HARFBUZZ - newSize.hb_font = hb_ft_font_create(newSize.face, NULL); + newSize.hb_font = hb_ft_font_create(newSize.face, NULL); #endif - _init_next_line_in_tex_cache (dev, &newSize); + _init_next_line_in_tex_cache(dev, &newSize); - font->sizes[font->sizeCount-1] = newSize; - return &font->sizes[font->sizeCount-1]; + font->sizes[font->sizeCount - 1] = newSize; + return &font->sizes[font->sizeCount - 1]; } -//try find font already resolved with fontconfig by font name -bool _tryFindFontByName (VkvgContext ctx, _vkvg_font_identity_t** font){ - _font_cache_t* cache = ctx->dev->fontCache; - for (int i = 0; i < cache->fontsCount; ++i) { - for (uint32_t j = 0; j < cache->fonts[i].namesCount; j++) { - if (strcmp (cache->fonts[i].names[j], ctx->selectedFontName) == 0) { - *font = &cache->fonts[i]; - return true; - } - } - } - return false; +// try find font already resolved with fontconfig by font name +bool _tryFindFontByName(VkvgContext ctx, _vkvg_font_identity_t **font) { + _font_cache_t *cache = ctx->dev->fontCache; + for (int i = 0; i < cache->fontsCount; ++i) { + for (uint32_t j = 0; j < cache->fonts[i].namesCount; j++) { + if (strcmp(cache->fonts[i].names[j], ctx->selectedFontName) == 0) { + *font = &cache->fonts[i]; + return true; + } + } + } + return false; } #ifdef VKVG_USE_FONTCONFIG -bool _tryResolveFontNameWithFontConfig (VkvgContext ctx, _vkvg_font_identity_t** resolvedFont) { - _font_cache_t* cache = (_font_cache_t*)ctx->dev->fontCache; - char* fontFile = NULL; +bool _tryResolveFontNameWithFontConfig(VkvgContext ctx, _vkvg_font_identity_t **resolvedFont) { + _font_cache_t *cache = (_font_cache_t *)ctx->dev->fontCache; + char *fontFile = NULL; - FcPattern* pat = FcNameParse((const FcChar8*)ctx->selectedFontName); - FcConfigSubstitute(cache->config, pat, FcMatchPattern); - FcDefaultSubstitute(pat); - FcResult result; - FcPattern* font = FcFontMatch(cache->config, pat, &result); - if (font) - FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile); - *resolvedFont = NULL; - if (fontFile) { - //try find font in cache by path - for (int i = 0; i < cache->fontsCount; ++i) { - if (cache->fonts[i].fontFile && strcmp (cache->fonts[i].fontFile, fontFile) == 0) { - _font_add_name (&cache->fonts[i], ctx->selectedFontName); - *resolvedFont = &cache->fonts[i]; - break; - } - } - if (!*resolvedFont) { - //if not found, create a new vkvg_font - _vkvg_font_identity_t* fid = _font_cache_add_font_identity(ctx, fontFile, ctx->selectedFontName); - _font_cache_load_font_file_in_memory (fid); - *resolvedFont = &cache->fonts[cache->fontsCount-1]; - } - } + FcPattern *pat = FcNameParse((const FcChar8 *)ctx->selectedFontName); + FcConfigSubstitute(cache->config, pat, FcMatchPattern); + FcDefaultSubstitute(pat); + FcResult result; + FcPattern *font = FcFontMatch(cache->config, pat, &result); + if (font) + FcPatternGetString(font, FC_FILE, 0, (FcChar8 **)&fontFile); + *resolvedFont = NULL; + if (fontFile) { + // try find font in cache by path + for (int i = 0; i < cache->fontsCount; ++i) { + if (cache->fonts[i].fontFile && strcmp(cache->fonts[i].fontFile, fontFile) == 0) { + _font_add_name(&cache->fonts[i], ctx->selectedFontName); + *resolvedFont = &cache->fonts[i]; + break; + } + } + if (!*resolvedFont) { + // if not found, create a new vkvg_font + _vkvg_font_identity_t *fid = _font_cache_add_font_identity(ctx, fontFile, ctx->selectedFontName); + _font_cache_load_font_file_in_memory(fid); + *resolvedFont = &cache->fonts[cache->fontsCount - 1]; + } + } - FcPatternDestroy(pat); - FcPatternDestroy(font); + FcPatternDestroy(pat); + FcPatternDestroy(font); - return (fontFile != NULL); + return (fontFile != NULL); } #endif +// try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. +void _update_current_font(VkvgContext ctx) { + if (ctx->currentFont == NULL) { + LOCK_FONTCACHE(ctx->dev) + if (ctx->selectedFontName[0] == 0) + _select_font_face(ctx, "sans"); -//try to find corresponding font in cache (defined by context selectedFont) and create a new font entry if not found. -void _update_current_font (VkvgContext ctx) { - if (ctx->currentFont == NULL){ - LOCK_FONTCACHE(ctx->dev) - if (ctx->selectedFontName[0] == 0) - _select_font_face (ctx, "sans"); - - if (!_tryFindFontByName (ctx, &ctx->currentFont)) { + if (!_tryFindFontByName(ctx, &ctx->currentFont)) { #ifdef VKVG_USE_FONTCONFIG - _tryResolveFontNameWithFontConfig (ctx, &ctx->currentFont); + _tryResolveFontNameWithFontConfig(ctx, &ctx->currentFont); #else - LOG(VKVG_LOG_ERR, "Unresolved font: %s\n", ctx->selectedFontName); - UNLOCK_FONTCACHE(ctx->dev) - ctx->status = VKVG_STATUS_INVALID_FONT; - return; + LOG(VKVG_LOG_ERR, "Unresolved font: %s\n", ctx->selectedFontName); + UNLOCK_FONTCACHE(ctx->dev) + ctx->status = VKVG_STATUS_INVALID_FONT; + return; #endif - } + } - ctx->currentFontSize = _find_or_create_font_size (ctx); - UNLOCK_FONTCACHE(ctx->dev) - } + ctx->currentFontSize = _find_or_create_font_size(ctx); + UNLOCK_FONTCACHE(ctx->dev) + } } #ifdef VKVG_USE_HARFBUZZ -//Get harfBuzz buffer for provided text. -hb_buffer_t * _get_hb_buffer (_vkvg_font_t* font, const char* text, int length) { - hb_buffer_t *buf = hb_buffer_create(); +// Get harfBuzz buffer for provided text. +hb_buffer_t *_get_hb_buffer(_vkvg_font_t *font, const char *text, int length) { + hb_buffer_t *buf = hb_buffer_create(); - hb_script_t script = HB_SCRIPT_LATIN; - hb_unicode_funcs_t* ucfunc = hb_unicode_funcs_get_default (); - wchar_t firstChar = 0; - if (mbstowcs (&firstChar, text, 1)) - script = hb_unicode_script (ucfunc, firstChar); + hb_script_t script = HB_SCRIPT_LATIN; + hb_unicode_funcs_t *ucfunc = hb_unicode_funcs_get_default(); + wchar_t firstChar = 0; + if (mbstowcs(&firstChar, text, 1)) + script = hb_unicode_script(ucfunc, firstChar); - hb_direction_t dir = hb_script_get_horizontal_direction(script); - hb_buffer_set_direction (buf, dir); - hb_buffer_set_script (buf, script); - //hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); - hb_buffer_add_utf8 (buf, text, length, 0, length); + hb_direction_t dir = hb_script_get_horizontal_direction(script); + hb_buffer_set_direction(buf, dir); + hb_buffer_set_script(buf, script); + // hb_buffer_set_language (buf, hb_language_from_string (lng, (int)strlen(lng))); + hb_buffer_add_utf8(buf, text, length, 0, length); - hb_shape (font->hb_font, buf, NULL, 0); + hb_shape(font->hb_font, buf, NULL, 0); - return buf; + return buf; } #endif -//retrieve global font extends of context's current font as defined by FreeType -void _font_cache_font_extents (VkvgContext ctx, vkvg_font_extents_t *extents) { - _update_current_font (ctx); +// retrieve global font extends of context's current font as defined by FreeType +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents) { + _update_current_font(ctx); - if (ctx->status) - return; + if (ctx->status) + return; - //TODO: ensure correct metrics are returned (scalled/unscalled, etc..) - _vkvg_font_t* font = ctx->currentFontSize; + // TODO: ensure correct metrics are returned (scalled/unscalled, etc..) + _vkvg_font_t *font = ctx->currentFontSize; #ifdef VKVG_USE_FREETYPE - FT_BBox* bbox = &font->face->bbox; - FT_Size_Metrics* metrics = &font->face->size->metrics; + FT_BBox *bbox = &font->face->bbox; + FT_Size_Metrics *metrics = &font->face->size->metrics; - extents->ascent = (float)(FT_MulFix(font->face->ascender, metrics->y_scale) >> 6);//metrics->ascender >> 6; - extents->descent =-(float)(FT_MulFix(font->face->descender, metrics->y_scale) >> 6);//metrics->descender >> 6; - extents->height = (float)(FT_MulFix(font->face->height, metrics->y_scale) >> 6);//metrics->height >> 6; - extents->max_x_advance = (float)(bbox->xMax >> 6); - extents->max_y_advance = (float)(bbox->yMax >> 6); + extents->ascent = (float)(FT_MulFix(font->face->ascender, metrics->y_scale) >> 6); // metrics->ascender >> 6; + extents->descent = -(float)(FT_MulFix(font->face->descender, metrics->y_scale) >> 6); // metrics->descender >> 6; + extents->height = (float)(FT_MulFix(font->face->height, metrics->y_scale) >> 6); // metrics->height >> 6; + extents->max_x_advance = (float)(bbox->xMax >> 6); + extents->max_y_advance = (float)(bbox->yMax >> 6); #else - extents->ascent = roundf (font->scale * ctx->currentFont->ascent); - extents->descent =-roundf (font->scale * ctx->currentFont->descent); - extents->height = roundf (font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap)); - extents->max_x_advance = 0;//TODO - extents->max_y_advance = 0; + extents->ascent = roundf(font->scale * ctx->currentFont->ascent); + extents->descent = -roundf(font->scale * ctx->currentFont->descent); + extents->height = + roundf(font->scale * (ctx->currentFont->ascent - ctx->currentFont->descent + ctx->currentFont->lineGap)); + extents->max_x_advance = 0; // TODO + extents->max_y_advance = 0; #endif } -//compute text extends for provided string. -void _font_cache_text_extents (VkvgContext ctx, const char* text, int length, vkvg_text_extents_t *extents) { - if (text == NULL) { - memset(extents, 0, sizeof(vkvg_text_extents_t)); - return; - } +// compute text extends for provided string. +void _font_cache_text_extents(VkvgContext ctx, const char *text, int length, vkvg_text_extents_t *extents) { + if (text == NULL) { + memset(extents, 0, sizeof(vkvg_text_extents_t)); + return; + } - vkvg_text_run_t tr = {0}; - _font_cache_create_text_run (ctx, text, length, &tr); + vkvg_text_run_t tr = {0}; + _font_cache_create_text_run(ctx, text, length, &tr); - if (ctx->status) - return; + if (ctx->status) + return; - *extents = tr.extents; + *extents = tr.extents; - _font_cache_destroy_text_run (&tr); + _font_cache_destroy_text_run(&tr); } -//text is expected as utf8 encoded -//if length is < 0, text must be null terminated, else it contains glyph count -void _font_cache_create_text_run (VkvgContext ctx, const char* text, int length, VkvgText textRun) { +// text is expected as utf8 encoded +// if length is < 0, text must be null terminated, else it contains glyph count +void _font_cache_create_text_run(VkvgContext ctx, const char *text, int length, VkvgText textRun) { - _update_current_font (ctx); + _update_current_font(ctx); - if (ctx->status) - return; + if (ctx->status) + return; - textRun->fontId = ctx->currentFont; - textRun->font = ctx->currentFontSize; - textRun->dev = ctx->dev; + textRun->fontId = ctx->currentFont; + textRun->font = ctx->currentFontSize; + textRun->dev = ctx->dev; - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) #ifdef VKVG_USE_HARFBUZZ - textRun->hbBuf = _get_hb_buffer (ctx->currentFontSize, text, length); - textRun->glyphs = hb_buffer_get_glyph_positions (textRun->hbBuf, &textRun->glyph_count); + textRun->hbBuf = _get_hb_buffer(ctx->currentFontSize, text, length); + textRun->glyphs = hb_buffer_get_glyph_positions(textRun->hbBuf, &textRun->glyph_count); #else - size_t wsize; - if (length < 0) - wsize = mbstowcs(NULL, text, 0); - else - wsize = (size_t)length; - wchar_t *tmp = (wchar_t*)malloc((wsize+1) * sizeof (wchar_t)); - textRun->glyph_count = mbstowcs (tmp, text, wsize); - textRun->glyphs = (vkvg_glyph_info_t*)malloc(textRun->glyph_count * sizeof (vkvg_glyph_info_t)); - for (unsigned int i=0; i<textRun->glyph_count; i++) { + size_t wsize; + if (length < 0) + wsize = mbstowcs(NULL, text, 0); + else + wsize = (size_t)length; + wchar_t *tmp = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t)); + textRun->glyph_count = mbstowcs(tmp, text, wsize); + textRun->glyphs = (vkvg_glyph_info_t *)malloc(textRun->glyph_count * sizeof(vkvg_glyph_info_t)); + for (unsigned int i = 0; i < textRun->glyph_count; i++) { #ifdef VKVG_USE_FREETYPE - uint32_t gindex = FT_Get_Char_Index (textRun->font->face, tmp[i]); + uint32_t gindex = FT_Get_Char_Index(textRun->font->face, tmp[i]); #else - uint32_t gindex = stbtt_FindGlyphIndex (&textRun->fontId->stbInfo, tmp[i]); + uint32_t gindex = stbtt_FindGlyphIndex(&textRun->fontId->stbInfo, tmp[i]); #endif - _char_ref* cr = textRun->font->charLookup[gindex]; - if (cr==NULL) - cr = _prepare_char (textRun->dev, textRun, gindex); - textRun->glyphs[i].codepoint = gindex; - textRun->glyphs[i].x_advance = cr->advance.x; - textRun->glyphs[i].y_advance = cr->advance.y; - textRun->glyphs[i].x_offset = 0; - textRun->glyphs[i].y_offset = 0; - /*textRun->glyphs[i].x_offset = cr->bmpDiff.x; - textRun->glyphs[i].y_offset = cr->bmpDiff.y;*/ - } - free (tmp); + _char_ref *cr = textRun->font->charLookup[gindex]; + if (cr == NULL) + cr = _prepare_char(textRun->dev, textRun, gindex); + textRun->glyphs[i].codepoint = gindex; + textRun->glyphs[i].x_advance = cr->advance.x; + textRun->glyphs[i].y_advance = cr->advance.y; + textRun->glyphs[i].x_offset = 0; + textRun->glyphs[i].y_offset = 0; + /*textRun->glyphs[i].x_offset = cr->bmpDiff.x; + textRun->glyphs[i].y_offset = cr->bmpDiff.y;*/ + } + free(tmp); #endif - - UNLOCK_FONTCACHE (ctx->dev) - unsigned int string_width_in_pixels = 0; - for (uint32_t i=0; i < textRun->glyph_count; ++i) - string_width_in_pixels += textRun->glyphs[i].x_advance >> 6; + UNLOCK_FONTCACHE(ctx->dev) + + unsigned int string_width_in_pixels = 0; + for (uint32_t i = 0; i < textRun->glyph_count; ++i) + string_width_in_pixels += textRun->glyphs[i].x_advance >> 6; #ifdef VKVG_USE_FREETYPE - FT_Size_Metrics* metrics = &ctx->currentFontSize->face->size->metrics; - textRun->extents.height = (float)(FT_MulFix(ctx->currentFontSize->face->height, metrics->y_scale) >> 6);// (metrics->ascender + metrics->descender) >> 6; + FT_Size_Metrics *metrics = &ctx->currentFontSize->face->size->metrics; + textRun->extents.height = (float)(FT_MulFix(ctx->currentFontSize->face->height, metrics->y_scale) >> + 6); // (metrics->ascender + metrics->descender) >> 6; #else - textRun->extents.height = textRun->font->ascent - textRun->font->descent + textRun->font->lineGap; + textRun->extents.height = textRun->font->ascent - textRun->font->descent + textRun->font->lineGap; #endif - textRun->extents.x_advance = (float)string_width_in_pixels; - if (textRun->glyph_count > 0) { - textRun->extents.y_advance = (float)(textRun->glyphs[textRun->glyph_count-1].y_advance >> 6); - textRun->extents.x_bearing = -(float)(textRun->glyphs[0].x_offset >> 6); - textRun->extents.y_bearing = -(float)(textRun->glyphs[0].y_offset >> 6); - } + textRun->extents.x_advance = (float)string_width_in_pixels; + if (textRun->glyph_count > 0) { + textRun->extents.y_advance = (float)(textRun->glyphs[textRun->glyph_count - 1].y_advance >> 6); + textRun->extents.x_bearing = -(float)(textRun->glyphs[0].x_offset >> 6); + textRun->extents.y_bearing = -(float)(textRun->glyphs[0].y_offset >> 6); + } - textRun->extents.width = textRun->extents.x_advance; + textRun->extents.width = textRun->extents.x_advance; } -void _font_cache_destroy_text_run (VkvgText textRun) { +void _font_cache_destroy_text_run(VkvgText textRun) { #ifdef VKVG_USE_HARFBUZZ - hb_buffer_destroy (textRun->hbBuf); + hb_buffer_destroy(textRun->hbBuf); #else - if (textRun->glyph_count > 0) - free (textRun->glyphs); + if (textRun->glyph_count > 0) + free(textRun->glyphs); #endif } #ifdef DEBUG -void _show_texture (vkvg_context* ctx){ - Vertex vs[] = { - {{0,0}, 0, {0,0,0}}, - {{0,FONT_PAGE_SIZE}, 0, {0,1,0}}, - {{FONT_PAGE_SIZE,0}, 0, {1,0,0}}, - {{FONT_PAGE_SIZE,FONT_PAGE_SIZE}, 0, {1,1,0}} - }; +void _show_texture(vkvg_context *ctx) { + Vertex vs[] = {{{0, 0}, 0, {0, 0, 0}}, + {{0, FONT_PAGE_SIZE}, 0, {0, 1, 0}}, + {{FONT_PAGE_SIZE, 0}, 0, {1, 0, 0}}, + {{FONT_PAGE_SIZE, FONT_PAGE_SIZE}, 0, {1, 1, 0}}}; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); - Vertex* pVert = &ctx->vertexCache[ctx->vertCount]; - memcpy (pVert,vs,4*sizeof(Vertex)); - ctx->vertCount+=4; + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + Vertex *pVert = &ctx->vertexCache[ctx->vertCount]; + memcpy(pVert, vs, 4 * sizeof(Vertex)); + ctx->vertCount += 4; - _check_vertex_cache_size(ctx); + _check_vertex_cache_size(ctx); - _add_tri_indices_for_rect(ctx, firstIdx); + _add_tri_indices_for_rect(ctx, firstIdx); } #endif -void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr) { - unsigned int glyph_count; +void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr) { + unsigned int glyph_count; #ifdef VKVG_USE_HARFBUZZ - hb_glyph_info_t* glyph_info = hb_buffer_get_glyph_infos (tr->hbBuf, &glyph_count); + hb_glyph_info_t *glyph_info = hb_buffer_get_glyph_infos(tr->hbBuf, &glyph_count); #else - vkvg_glyph_info_t* glyph_info = tr->glyphs; - glyph_count = tr->glyph_count; + vkvg_glyph_info_t *glyph_info = tr->glyphs; + glyph_count = tr->glyph_count; #endif - Vertex v = {{0},ctx->curColor,{0,0,-1}}; - vec2 pen = {0,0}; + Vertex v = {{0}, ctx->curColor, {0, 0, -1}}; + vec2 pen = {0, 0}; - if (!_current_path_is_empty(ctx)) - pen = _get_current_position(ctx); + if (!_current_path_is_empty(ctx)) + pen = _get_current_position(ctx); - LOCK_FONTCACHE (ctx->dev) + LOCK_FONTCACHE(ctx->dev) - for (uint32_t i=0; i < glyph_count; ++i) { - _char_ref* cr = tr->font->charLookup[glyph_info[i].codepoint]; + for (uint32_t i = 0; i < glyph_count; ++i) { + _char_ref *cr = tr->font->charLookup[glyph_info[i].codepoint]; #ifdef VKVG_USE_HARFBUZZ - if (cr==NULL) - cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); + if (cr == NULL) + cr = _prepare_char(tr->dev, tr, glyph_info[i].codepoint); #endif - float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; - float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; - vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyphs[i].x_offset >> 6), - pen.y - cr->bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; - v.pos = p0; + float uvWidth = cr->bounds.width / (float)FONT_PAGE_SIZE; + float uvHeight = cr->bounds.height / (float)FONT_PAGE_SIZE; + vec2 p0 = {pen.x + cr->bmpDiff.x + (tr->glyphs[i].x_offset >> 6), + pen.y - cr->bmpDiff.y + (tr->glyphs[i].y_offset >> 6)}; + v.pos = p0; - VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + VKVG_IBO_INDEX_TYPE firstIdx = (VKVG_IBO_INDEX_TYPE)(ctx->vertCount - ctx->curVertOffset); + v.uv.x = cr->bounds.x; + v.uv.y = cr->bounds.y; + v.uv.z = cr->pageIdx; + _add_vertex(ctx, v); - v.uv.x = cr->bounds.x; - v.uv.y = cr->bounds.y; - v.uv.z = cr->pageIdx; - _add_vertex(ctx,v); + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx, v); - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); + v.pos.x += cr->bounds.width; + v.pos.y = p0.y; + v.uv.x += uvWidth; + v.uv.y = cr->bounds.y; + _add_vertex(ctx, v); - v.pos.x += cr->bounds.width; - v.pos.y = p0.y; - v.uv.x += uvWidth; - v.uv.y = cr->bounds.y; - _add_vertex(ctx,v); + v.pos.y += cr->bounds.height; + v.uv.y += uvHeight; + _add_vertex(ctx, v); - v.pos.y += cr->bounds.height; - v.uv.y += uvHeight; - _add_vertex(ctx,v); + _add_tri_indices_for_rect(ctx, firstIdx); - _add_tri_indices_for_rect (ctx, firstIdx); + pen.x += (tr->glyphs[i].x_advance >> 6); + pen.y -= (tr->glyphs[i].y_advance >> 6); + } - pen.x += (tr->glyphs[i].x_advance >> 6); - pen.y -= (tr->glyphs[i].y_advance >> 6); - } + // equivalent to a moveto + _finish_path(ctx); + _add_point(ctx, pen.x, pen.y); + _flush_chars_to_tex(tr->dev, tr->font); + UNLOCK_FONTCACHE(ctx->dev) - //equivalent to a moveto - _finish_path(ctx); - _add_point (ctx, pen.x, pen.y); - _flush_chars_to_tex(tr->dev, tr->font); - UNLOCK_FONTCACHE (ctx->dev) - - if (ctx->fontCacheImg != ctx->dev->fontCache->texture) { - vkvg_flush (ctx); - _font_cache_update_context_descset (ctx); - } + if (ctx->fontCacheImg != ctx->dev->fontCache->texture) { + vkvg_flush(ctx); + _font_cache_update_context_descset(ctx); + } } -void _font_cache_show_text (VkvgContext ctx, const char* text){ +void _font_cache_show_text(VkvgContext ctx, const char *text) { - vkvg_text_run_t tr = {0}; - _font_cache_create_text_run (ctx, text, -1, &tr); + vkvg_text_run_t tr = {0}; + _font_cache_create_text_run(ctx, text, -1, &tr); - if (ctx->status) - return; + if (ctx->status) + return; - _font_cache_show_text_run (ctx, &tr); + _font_cache_show_text_run(ctx, &tr); - _font_cache_destroy_text_run (&tr); + _font_cache_destroy_text_run(&tr); - //_show_texture(ctx); return; + //_show_texture(ctx); return; } - /*void testfonts(){ - FT_Library library; - FT_Face face; - FT_GlyphSlot slot; + FT_Library library; + FT_Face face; + FT_GlyphSlot slot; - assert(!FT_Init_FreeType(&library)); - assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); - assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); + assert(!FT_Init_FreeType(&library)); + assert(!FT_New_Face(library, "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 0, &face)); + assert(!FT_Set_Char_Size(face, 0, ptSize, device_hdpi, device_vdpi )); - //_build_face_tex(face); + //_build_face_tex(face); - hb_font_t *hb_font = hb_ft_font_create(face, NULL); - hb_buffer_t *buf = hb_buffer_create(); + hb_font_t *hb_font = hb_ft_font_create(face, NULL); + hb_buffer_t *buf = hb_buffer_create(); - const char *text = "Ленивый рыжий кот"; - const char *lng = "en"; - //"كسول الزنجبيل القط","懶惰的姜貓", + const char *text = "Ленивый рыжий кот"; + const char *lng = "en"; + //"كسول الزنجبيل القط","懶惰的姜貓", - hb_buffer_set_direction (buf, HB_DIRECTION_LTR); - hb_buffer_set_script (buf, HB_SCRIPT_LATIN); - hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); - hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); + hb_buffer_set_direction (buf, HB_DIRECTION_LTR); + hb_buffer_set_script (buf, HB_SCRIPT_LATIN); + hb_buffer_set_language (buf, hb_language_from_string(lng,strlen(lng))); + hb_buffer_add_utf8 (buf, text, strlen(text), 0, strlen(text)); - hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); - hb_script_t sc = hb_buffer_get_script(buf); + hb_unicode_funcs_t * unifc = hb_unicode_funcs_get_default(); + hb_script_t sc = hb_buffer_get_script(buf); - sc = hb_unicode_script(unifc,0x0260); + sc = hb_unicode_script(unifc,0x0260); - FT_CharMap* cm = face->charmap; + FT_CharMap* cm = face->charmap; - //hb_script_to_iso15924_tag() + //hb_script_to_iso15924_tag() - FT_Done_Face ( face ); - FT_Done_FreeType( library ); + FT_Done_Face ( face ); + FT_Done_FreeType( library ); }*/ diff --git a/src/vkvg_fonts.h b/src/vkvg_fonts.h index 959c5c8..5e06344 100644 --- a/src/vkvg_fonts.h +++ b/src/vkvg_fonts.h @@ -22,173 +22,175 @@ #ifndef VKVG_FONTS_H #define VKVG_FONTS_H - //disable warning on iostream functions on windows +// disable warning on iostream functions on windows #define _CRT_SECURE_NO_WARNINGS #ifdef VKVG_USE_FREETYPE - #include <ft2build.h> - #include FT_FREETYPE_H - #if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) - #include <freetype/ftlcdfil.h> - #endif - #define FT_CHECK_RESULT(f) \ - { \ - FT_Error res = (f); \ - if (res != 0) \ - { \ - fprintf(stderr,"Fatal : FreeType error is %d in %s at line %d\n", res, __FILE__, __LINE__); \ - assert(res == 0); \ - } \ - } +#include <ft2build.h> +#include FT_FREETYPE_H +#if defined(VKVG_LCD_FONT_FILTER) && defined(FT_CONFIG_OPTION_SUBPIXEL_RENDERING) +#include <freetype/ftlcdfil.h> +#endif +#define FT_CHECK_RESULT(f) \ + { \ + FT_Error res = (f); \ + if (res != 0) { \ + fprintf(stderr, "Fatal : FreeType error is %d in %s at line %d\n", res, __FILE__, __LINE__); \ + assert(res == 0); \ + } \ + } #else - #include "stb_truetype.h" +#include "stb_truetype.h" #endif #ifdef VKVG_USE_HARFBUZZ - #include <harfbuzz/hb.h> - #include <harfbuzz/hb-ft.h> +#include <harfbuzz/hb.h> +#include <harfbuzz/hb-ft.h> #else #endif #ifdef VKVG_USE_FONTCONFIG - #include <fontconfig/fontconfig.h> +#include <fontconfig/fontconfig.h> #endif -#define FONT_PAGE_SIZE 1024 -#define FONT_CACHE_INIT_LAYERS 1 +#define FONT_PAGE_SIZE 1024 +#define FONT_CACHE_INIT_LAYERS 1 #define FONT_FILE_NAME_MAX_SIZE 1024 -#define FONT_NAME_MAX_SIZE 128 +#define FONT_NAME_MAX_SIZE 128 #include "vkvg_internal.h" #include "vkh_buffer.h" -//texture coordinates of one character in font cache array texture. +// texture coordinates of one character in font cache array texture. typedef struct { - vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ - vec2i16 bmpDiff; /* Difference in pixel between char bitmap top left corner and char glyph*/ - uint8_t pageIdx; /* Page index in font cache texture array */ + vec4 bounds; /* normalized float bounds of character bitmap in font cache texture. */ + vec2i16 bmpDiff; /* Difference in pixel between char bitmap top left corner and char glyph*/ + uint8_t pageIdx; /* Page index in font cache texture array */ #ifdef VKVG_USE_FREETYPE - FT_Vector advance; /* horizontal or vertical advance */ + FT_Vector advance; /* horizontal or vertical advance */ #else - vec2 advance; + vec2 advance; #endif -}_char_ref; +} _char_ref; // Current location in font cache texture array for new character addition. Each font holds such structure to locate // where to upload new chars. typedef struct { - uint8_t pageIdx; /* Current page number in font cache */ - int penX; /* Current X in cache for next char addition */ - int penY; /* Current Y in cache for next char addition */ - int height; /* Height of current line pointed by this structure */ -}_tex_ref_t; + uint8_t pageIdx; /* Current page number in font cache */ + int penX; /* Current X in cache for next char addition */ + int penY; /* Current Y in cache for next char addition */ + int height; /* Height of current line pointed by this structure */ +} _tex_ref_t; -// Loaded font structure, one per size, holds informations for glyphes upload in cache and the lookup table of characters. +// Loaded font structure, one per size, holds informations for glyphes upload in cache and the lookup table of +// characters. typedef struct { #ifdef VKVG_USE_FREETYPE - FT_F26Dot6 charSize; /* Font size*/ - FT_Face face; /* FreeType face*/ + FT_F26Dot6 charSize; /* Font size*/ + FT_Face face; /* FreeType face*/ #else - uint32_t charSize; /* Font size in pixel */ - float scale; /* scale factor for the given size */ - int ascent; /* unscalled stb font metrics */ - int descent; - int lineGap; + uint32_t charSize; /* Font size in pixel */ + float scale; /* scale factor for the given size */ + int ascent; /* unscalled stb font metrics */ + int descent; + int lineGap; #endif #ifdef VKVG_USE_HARFBUZZ - hb_font_t* hb_font; /* HarfBuzz font instance*/ + hb_font_t *hb_font; /* HarfBuzz font instance*/ #endif - _char_ref** charLookup; /* Lookup table of characteres in cache, if not found, upload is queued*/ + _char_ref **charLookup; /* Lookup table of characteres in cache, if not found, upload is queued*/ - _tex_ref_t curLine; /* tex coord where to add new char bmp's */ -}_vkvg_font_t; + _tex_ref_t curLine; /* tex coord where to add new char bmp's */ +} _vkvg_font_t; /* Font identification structure */ typedef struct { - char** names; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path*/ - uint32_t namesCount; /* Count of resolved names by fontConfig */ - unsigned char* fontBuffer; /* stb_truetype in memory buffer */ - long fontBufSize;/* */ - char* fontFile; /* Font file full path*/ + char **names; /* Resolved Input names to this font by fontConfig or custom name set by @ref vkvg_load_from_path*/ + uint32_t namesCount; /* Count of resolved names by fontConfig */ + unsigned char *fontBuffer; /* stb_truetype in memory buffer */ + long fontBufSize; /* */ + char *fontFile; /* Font file full path*/ #ifndef VKVG_USE_FREETYPE - stbtt_fontinfo stbInfo; /* stb_truetype structure */ - int ascent; /* unscalled stb font metrics */ - int descent; - int lineGap; + stbtt_fontinfo stbInfo; /* stb_truetype structure */ + int ascent; /* unscalled stb font metrics */ + int descent; + int lineGap; #endif - uint32_t sizeCount; /* available font size loaded */ - _vkvg_font_t* sizes; /* loaded font size array */ -}_vkvg_font_identity_t; + uint32_t sizeCount; /* available font size loaded */ + _vkvg_font_t *sizes; /* loaded font size array */ +} _vkvg_font_identity_t; // Font cache global structure, entry point for all font related operations. typedef struct { #ifdef VKVG_USE_FREETYPE - FT_Library library; /* FreeType library*/ + FT_Library library; /* FreeType library*/ #else #endif #ifdef VKVG_USE_FONTCONFIG - FcConfig* config; /* Font config, used to find font files by font names*/ + FcConfig *config; /* Font config, used to find font files by font names*/ #endif - int stagingX; /* x pen in host buffer */ - uint8_t* hostBuff; /* host memory where bitmaps are first loaded */ + int stagingX; /* x pen in host buffer */ + uint8_t *hostBuff; /* host memory where bitmaps are first loaded */ - VkCommandBuffer cmd; /* vulkan command buffer for font textures upload */ - vkh_buffer_t buff; /* stagin buffer */ - VkhImage texture; /* 2d array texture used by contexts to draw characteres */ - VkFormat texFormat; /* Format of the fonts texture array */ - uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ - uint8_t texLength; /* layer count of 2d array texture, starts with FONT_CACHE_INIT_LAYERS count and increased when needed */ - int* pensY; /* array of current y pen positions for each texture in cache 2d array */ - VkFence uploadFence; /* Signaled when upload is finished */ - mtx_t mutex; /* font cache global mutex, used only if device is in thread aware mode (see: vkvg_device_set_thread_aware) */ + VkCommandBuffer cmd; /* vulkan command buffer for font textures upload */ + vkh_buffer_t buff; /* stagin buffer */ + VkhImage texture; /* 2d array texture used by contexts to draw characteres */ + VkFormat texFormat; /* Format of the fonts texture array */ + uint8_t texPixelSize; /* Size in byte of a single pixel in a font texture */ + uint8_t texLength; /* layer count of 2d array texture, starts with FONT_CACHE_INIT_LAYERS count and increased when + needed */ + int *pensY; /* array of current y pen positions for each texture in cache 2d array */ + VkFence uploadFence; /* Signaled when upload is finished */ + mtx_t mutex; /* font cache global mutex, used only if device is in thread aware mode (see: + vkvg_device_set_thread_aware) */ - _vkvg_font_identity_t* fonts; /* Loaded fonts structure array */ - int32_t fontsCount; /* Loaded fonts array count*/ -}_font_cache_t; + _vkvg_font_identity_t *fonts; /* Loaded fonts structure array */ + int32_t fontsCount; /* Loaded fonts array count*/ +} _font_cache_t; -#define LOCK_FONTCACHE(dev) \ - if (dev->threadAware)\ - mtx_lock (&dev->fontCache->mutex); -#define UNLOCK_FONTCACHE(dev) \ - if (dev->threadAware)\ - mtx_unlock (&dev->fontCache->mutex); +#define LOCK_FONTCACHE(dev) \ + if (dev->threadAware) \ + mtx_lock(&dev->fontCache->mutex); +#define UNLOCK_FONTCACHE(dev) \ + if (dev->threadAware) \ + mtx_unlock(&dev->fontCache->mutex); // Precompute everything necessary to measure and draw one line of text, usefull to draw the same text multiple times. typedef struct _vkvg_text_run_t { - _vkvg_font_identity_t* fontId; /* vkvg font structure pointer */ - _vkvg_font_t* font; /* vkvg font structure pointer */ - VkvgDevice dev; /* vkvg device associated with this text run */ - vkvg_text_extents_t extents; /* store computed text extends */ - const char* text; /* utf8 char array of text*/ - unsigned int glyph_count;/* Total glyph count */ + _vkvg_font_identity_t *fontId; /* vkvg font structure pointer */ + _vkvg_font_t *font; /* vkvg font structure pointer */ + VkvgDevice dev; /* vkvg device associated with this text run */ + vkvg_text_extents_t extents; /* store computed text extends */ + const char *text; /* utf8 char array of text*/ + unsigned int glyph_count; /* Total glyph count */ #ifdef VKVG_USE_HARFBUZZ - hb_buffer_t* hbBuf; /* HarfBuzz buffer of text */ - hb_glyph_position_t* glyphs; /* HarfBuzz computed glyph positions array */ + hb_buffer_t *hbBuf; /* HarfBuzz buffer of text */ + hb_glyph_position_t *glyphs; /* HarfBuzz computed glyph positions array */ #else - vkvg_glyph_info_t* glyphs; /* computed glyph positions array */ + vkvg_glyph_info_t *glyphs; /* computed glyph positions array */ #endif } vkvg_text_run_t; -//Create font cache. -void _fonts_cache_create (VkvgDevice dev); -//Release all ressources of font cache. -void _font_cache_destroy (VkvgDevice dev); -_vkvg_font_identity_t *_font_cache_add_font_identity (VkvgContext ctx, const char* fontFile, const char *name); -bool _font_cache_load_font_file_in_memory (_vkvg_font_identity_t* fontId); -//Draw text -void _font_cache_show_text (VkvgContext ctx, const char* text); -//Get text dimmensions -void _font_cache_text_extents (VkvgContext ctx, const char* text, int length, vkvg_text_extents_t *extents); -//Get font global dimmensions -void _font_cache_font_extents (VkvgContext ctx, vkvg_font_extents_t* extents); -//Create text object that could be drawn multiple times minimizing harfbuzz and compute processing. -void _font_cache_create_text_run (VkvgContext ctx, const char* text, int length, VkvgText textRun); -//Release ressources held by a text run. -void _font_cache_destroy_text_run (VkvgText textRun); -//Draw text run -void _font_cache_show_text_run (VkvgContext ctx, VkvgText tr); -//update context font cache descriptor set -void _font_cache_update_context_descset (VkvgContext ctx); +// Create font cache. +void _fonts_cache_create(VkvgDevice dev); +// Release all ressources of font cache. +void _font_cache_destroy(VkvgDevice dev); +_vkvg_font_identity_t *_font_cache_add_font_identity(VkvgContext ctx, const char *fontFile, const char *name); +bool _font_cache_load_font_file_in_memory(_vkvg_font_identity_t *fontId); +// Draw text +void _font_cache_show_text(VkvgContext ctx, const char *text); +// Get text dimmensions +void _font_cache_text_extents(VkvgContext ctx, const char *text, int length, vkvg_text_extents_t *extents); +// Get font global dimmensions +void _font_cache_font_extents(VkvgContext ctx, vkvg_font_extents_t *extents); +// Create text object that could be drawn multiple times minimizing harfbuzz and compute processing. +void _font_cache_create_text_run(VkvgContext ctx, const char *text, int length, VkvgText textRun); +// Release ressources held by a text run. +void _font_cache_destroy_text_run(VkvgText textRun); +// Draw text run +void _font_cache_show_text_run(VkvgContext ctx, VkvgText tr); +// update context font cache descriptor set +void _font_cache_update_context_descset(VkvgContext ctx); #endif diff --git a/src/vkvg_internal.h b/src/vkvg_internal.h index 535ca81..3afbe43 100644 --- a/src/vkvg_internal.h +++ b/src/vkvg_internal.h @@ -22,14 +22,14 @@ #ifndef VKVG_INTERNAL_H #define VKVG_INTERNAL_H - //disable warning on iostream functions on windows +// disable warning on iostream functions on windows #define _CRT_SECURE_NO_WARNINGS #include <assert.h> #include <float.h> #include <stdbool.h> #include <stdint.h> -#include <stdio.h> // needed before stdarg.h on Windows +#include <stdio.h> // needed before stdarg.h on Windows #include <stdarg.h> #include <string.h> @@ -37,61 +37,65 @@ #include <math.h> #ifndef M_PIF - #define M_PIF 3.14159265358979323846f /* float pi */ - #define M_PIF_2 1.57079632679489661923f - #define M_2_PIF 0.63661977236758134308f // 2/pi +#define M_PIF 3.14159265358979323846f /* float pi */ +#define M_PIF_2 1.57079632679489661923f +#define M_2_PIF 0.63661977236758134308f // 2/pi #endif /*#ifndef M_2_PI - #define M_2_PI 0.63661977236758134308 // 2/pi + #define M_2_PI 0.63661977236758134308 // 2/pi #endif*/ #ifdef DEBUG -#define LOG(level,...) { \ - if ((vkvg_log_level) & (level)) \ - fprintf (stdout, __VA_ARGS__); \ -} +#define LOG(level, ...) \ + { \ + if ((vkvg_log_level) & (level)) \ + fprintf(stdout, __VA_ARGS__); \ + } #else #define LOG #endif -#define PATH_CLOSED_BIT 0x80000000 /* most significant bit of path elmts is closed/open path state */ -#define PATH_HAS_CURVES_BIT 0x40000000 /* 2rd most significant bit of path elmts is curved status - * for main path, this indicate that curve datas are present. - * For segments, this indicate that the segment is curved or not */ -#define PATH_IS_CONVEX_BIT 0x20000000 /* simple rectangle or circle. */ -#define PATH_ELT_MASK 0x1FFFFFFF /* Bit mask for fetching path element value */ +#define PATH_CLOSED_BIT 0x80000000 /* most significant bit of path elmts is closed/open path state */ +#define PATH_HAS_CURVES_BIT \ + 0x40000000 /* 2rd most significant bit of path elmts is curved status \ + * for main path, this indicate that curve datas are present. \ + * For segments, this indicate that the segment is curved or not */ +#define PATH_IS_CONVEX_BIT 0x20000000 /* simple rectangle or circle. */ +#define PATH_ELT_MASK 0x1FFFFFFF /* Bit mask for fetching path element value */ -#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c))) -#define ROUND_DOWN(v,p) (floorf(v * p) / p) -#define EQUF(a, b) (fabsf(a-(b))<=FLT_EPSILON) +#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c))) +#define ROUND_DOWN(v, p) (floorf(v * p) / p) +#define EQUF(a, b) (fabsf(a - (b)) <= FLT_EPSILON) #ifndef MAX - #define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #ifndef MIN - #define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) #endif #include "deps/tinycthread.h" #include "cross_os.h" -//width of the stencil buffer will determine the number of context saving/restore layers -//the two first bits of the stencil are the FILL and the CLIP bits, all other bits are -//used to store clipping bit on context saving. 8 bit stencil will allow 6 save/restore layer +// width of the stencil buffer will determine the number of context saving/restore layers +// the two first bits of the stencil are the FILL and the CLIP bits, all other bits are +// used to store clipping bit on context saving. 8 bit stencil will allow 6 save/restore layer #define FB_COLOR_FORMAT VK_FORMAT_B8G8R8A8_UNORM -#define VKVG_SURFACE_IMGS_REQUIREMENTS (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT|VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT|\ - VK_FORMAT_FEATURE_TRANSFER_DST_BIT|VK_FORMAT_FEATURE_TRANSFER_SRC_BIT|VK_FORMAT_FEATURE_BLIT_SRC_BIT) -#define VKVG_PNG_WRITE_IMG_REQUIREMENTS (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT|VK_FORMAT_FEATURE_TRANSFER_DST_BIT|VK_FORMAT_FEATURE_BLIT_DST_BIT) -//30 seconds fence timeout +#define VKVG_SURFACE_IMGS_REQUIREMENTS \ + (VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | \ + VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT) +#define VKVG_PNG_WRITE_IMG_REQUIREMENTS \ + (VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | VK_FORMAT_FEATURE_TRANSFER_DST_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT) +// 30 seconds fence timeout #define VKVG_FENCE_TIMEOUT 30000000000 -//#define VKVG_FENCE_TIMEOUT 10000 +// #define VKVG_FENCE_TIMEOUT 10000 #include "vkvg.h" #include "vkh.h" #include "vectors.h" /*typedef struct { - vkvg_status_t status; + vkvg_status_t status; } _vkvg_no_mem_struct;*/ static vkvg_status_t _no_mem_status = VKVG_STATUS_NO_MEMORY; diff --git a/src/vkvg_matrix.c b/src/vkvg_matrix.c index 998ece0..c77f329 100644 --- a/src/vkvg_matrix.c +++ b/src/vkvg_matrix.c @@ -20,8 +20,8 @@ * THE SOFTWARE. */ -//most of the matrix logic is grabbed from cairo, so here is the -//licence: +// most of the matrix logic is grabbed from cairo, so here is the +// licence: /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California @@ -62,206 +62,168 @@ #define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */ -//matrix computations mainly taken from http://cairographics.org -static void _vkvg_matrix_scalar_multiply (vkvg_matrix_t *matrix, float scalar) -{ - matrix->xx *= scalar; - matrix->yx *= scalar; +// matrix computations mainly taken from http://cairographics.org +static void _vkvg_matrix_scalar_multiply(vkvg_matrix_t *matrix, float scalar) { + matrix->xx *= scalar; + matrix->yx *= scalar; - matrix->xy *= scalar; - matrix->yy *= scalar; + matrix->xy *= scalar; + matrix->yy *= scalar; - matrix->x0 *= scalar; - matrix->y0 *= scalar; + matrix->x0 *= scalar; + matrix->y0 *= scalar; } -void _vkvg_matrix_get_affine (const vkvg_matrix_t *matrix, - float *xx, float *yx, - float *xy, float *yy, - float *x0, float *y0) -{ - *xx = matrix->xx; - *yx = matrix->yx; +void _vkvg_matrix_get_affine(const vkvg_matrix_t *matrix, float *xx, float *yx, float *xy, float *yy, float *x0, + float *y0) { + *xx = matrix->xx; + *yx = matrix->yx; - *xy = matrix->xy; - *yy = matrix->yy; + *xy = matrix->xy; + *yy = matrix->yy; - if (x0) - *x0 = matrix->x0; - if (y0) - *y0 = matrix->y0; + if (x0) + *x0 = matrix->x0; + if (y0) + *y0 = matrix->y0; } -static void _vkvg_matrix_compute_adjoint (vkvg_matrix_t *matrix) -{ - /* adj (A) = transpose (C:cofactor (A,i,j)) */ - float a, b, c, d, tx, ty; +static void _vkvg_matrix_compute_adjoint(vkvg_matrix_t *matrix) { + /* adj (A) = transpose (C:cofactor (A,i,j)) */ + float a, b, c, d, tx, ty; - _vkvg_matrix_get_affine (matrix, - &a, &b, - &c, &d, - &tx, &ty); + _vkvg_matrix_get_affine(matrix, &a, &b, &c, &d, &tx, &ty); - vkvg_matrix_init (matrix, - d, -b, - -c, a, - c*ty - d*tx, b*tx - a*ty); + vkvg_matrix_init(matrix, d, -b, -c, a, c * ty - d * tx, b * tx - a * ty); } -float _vkvg_matrix_compute_determinant (const vkvg_matrix_t *matrix) -{ - float a, b, c, d; +float _vkvg_matrix_compute_determinant(const vkvg_matrix_t *matrix) { + float a, b, c, d; - a = matrix->xx; b = matrix->yx; - c = matrix->xy; d = matrix->yy; + a = matrix->xx; + b = matrix->yx; + c = matrix->xy; + d = matrix->yy; - return a*d - b*c; + return a * d - b * c; } -vkvg_status_t vkvg_matrix_invert (vkvg_matrix_t *matrix) -{ - float det; +vkvg_status_t vkvg_matrix_invert(vkvg_matrix_t *matrix) { + float det; - /* Simple scaling|translation matrices are quite common... */ - if (matrix->xy == 0. && matrix->yx == 0.) { - matrix->x0 = -matrix->x0; - matrix->y0 = -matrix->y0; + /* Simple scaling|translation matrices are quite common... */ + if (matrix->xy == 0. && matrix->yx == 0.) { + matrix->x0 = -matrix->x0; + matrix->y0 = -matrix->y0; - if (matrix->xx != 1.f) { - if (matrix->xx == 0.) - return VKVG_STATUS_INVALID_MATRIX; + if (matrix->xx != 1.f) { + if (matrix->xx == 0.) + return VKVG_STATUS_INVALID_MATRIX; - matrix->xx = 1.f / matrix->xx; - matrix->x0 *= matrix->xx; - } + matrix->xx = 1.f / matrix->xx; + matrix->x0 *= matrix->xx; + } - if (matrix->yy != 1.f) { - if (matrix->yy == 0.) - return VKVG_STATUS_INVALID_MATRIX; + if (matrix->yy != 1.f) { + if (matrix->yy == 0.) + return VKVG_STATUS_INVALID_MATRIX; - matrix->yy = 1.f / matrix->yy; - matrix->y0 *= matrix->yy; - } + matrix->yy = 1.f / matrix->yy; + matrix->y0 *= matrix->yy; + } - return VKVG_STATUS_SUCCESS; - } + return VKVG_STATUS_SUCCESS; + } - /* inv (A) = 1/det (A) * adj (A) */ - det = _vkvg_matrix_compute_determinant (matrix); + /* inv (A) = 1/det (A) * adj (A) */ + det = _vkvg_matrix_compute_determinant(matrix); - if (! ISFINITE (det)) - return VKVG_STATUS_INVALID_MATRIX; + if (!ISFINITE(det)) + return VKVG_STATUS_INVALID_MATRIX; - if (det == 0) - return VKVG_STATUS_INVALID_MATRIX; + if (det == 0) + return VKVG_STATUS_INVALID_MATRIX; - _vkvg_matrix_compute_adjoint (matrix); - _vkvg_matrix_scalar_multiply (matrix, 1 / det); + _vkvg_matrix_compute_adjoint(matrix); + _vkvg_matrix_scalar_multiply(matrix, 1 / det); - return VKVG_STATUS_SUCCESS; -} -void vkvg_matrix_init_identity (vkvg_matrix_t *matrix) -{ - vkvg_matrix_init (matrix, - 1, 0, - 0, 1, - 0, 0); + return VKVG_STATUS_SUCCESS; } +void vkvg_matrix_init_identity(vkvg_matrix_t *matrix) { vkvg_matrix_init(matrix, 1, 0, 0, 1, 0, 0); } -void vkvg_matrix_init (vkvg_matrix_t *matrix, - float xx, float yx, - float xy, float yy, - float x0, float y0) -{ - matrix->xx = xx; matrix->yx = yx; - matrix->xy = xy; matrix->yy = yy; - matrix->x0 = x0; matrix->y0 = y0; +void vkvg_matrix_init(vkvg_matrix_t *matrix, float xx, float yx, float xy, float yy, float x0, float y0) { + matrix->xx = xx; + matrix->yx = yx; + matrix->xy = xy; + matrix->yy = yy; + matrix->x0 = x0; + matrix->y0 = y0; } -void vkvg_matrix_init_translate (vkvg_matrix_t *matrix, float tx, float ty) -{ - vkvg_matrix_init (matrix, - 1, 0, - 0, 1, - tx, ty); -} -void vkvg_matrix_init_scale (vkvg_matrix_t *matrix, float sx, float sy) -{ - vkvg_matrix_init (matrix, - sx, 0, - 0, sy, - 0, 0); +void vkvg_matrix_init_translate(vkvg_matrix_t *matrix, float tx, float ty) { + vkvg_matrix_init(matrix, 1, 0, 0, 1, tx, ty); } -void vkvg_matrix_init_rotate (vkvg_matrix_t *matrix, float radians) -{ - float s; - float c; +void vkvg_matrix_init_scale(vkvg_matrix_t *matrix, float sx, float sy) { vkvg_matrix_init(matrix, sx, 0, 0, sy, 0, 0); } +void vkvg_matrix_init_rotate(vkvg_matrix_t *matrix, float radians) { + float s; + float c; - s = sinf (radians); - c = cosf (radians); + s = sinf(radians); + c = cosf(radians); - vkvg_matrix_init (matrix, - c, s, - -s, c, - 0, 0); + vkvg_matrix_init(matrix, c, s, -s, c, 0, 0); } -void vkvg_matrix_translate (vkvg_matrix_t *matrix, float tx, float ty) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_translate(vkvg_matrix_t *matrix, float tx, float ty) { + vkvg_matrix_t tmp; - vkvg_matrix_init_translate (&tmp, tx, ty); + vkvg_matrix_init_translate(&tmp, tx, ty); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_scale (vkvg_matrix_t *matrix, float sx, float sy) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_scale(vkvg_matrix_t *matrix, float sx, float sy) { + vkvg_matrix_t tmp; - vkvg_matrix_init_scale (&tmp, sx, sy); + vkvg_matrix_init_scale(&tmp, sx, sy); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_rotate (vkvg_matrix_t *matrix, float radians) -{ - vkvg_matrix_t tmp; +void vkvg_matrix_rotate(vkvg_matrix_t *matrix, float radians) { + vkvg_matrix_t tmp; - vkvg_matrix_init_rotate (&tmp, radians); + vkvg_matrix_init_rotate(&tmp, radians); - vkvg_matrix_multiply (matrix, &tmp, matrix); + vkvg_matrix_multiply(matrix, &tmp, matrix); } -void vkvg_matrix_multiply (vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b) -{ - vkvg_matrix_t r; +void vkvg_matrix_multiply(vkvg_matrix_t *result, const vkvg_matrix_t *a, const vkvg_matrix_t *b) { + vkvg_matrix_t r; - r.xx = a->xx * b->xx + a->yx * b->xy; - r.yx = a->xx * b->yx + a->yx * b->yy; + r.xx = a->xx * b->xx + a->yx * b->xy; + r.yx = a->xx * b->yx + a->yx * b->yy; - r.xy = a->xy * b->xx + a->yy * b->xy; - r.yy = a->xy * b->yx + a->yy * b->yy; + r.xy = a->xy * b->xx + a->yy * b->xy; + r.yy = a->xy * b->yx + a->yy * b->yy; - r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; - r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; + r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; + r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; - *result = r; + *result = r; } -void vkvg_matrix_transform_distance (const vkvg_matrix_t *matrix, float *dx, float *dy) -{ - float new_x, new_y; +void vkvg_matrix_transform_distance(const vkvg_matrix_t *matrix, float *dx, float *dy) { + float new_x, new_y; - new_x = (matrix->xx * *dx + matrix->xy * *dy); - new_y = (matrix->yx * *dx + matrix->yy * *dy); + new_x = (matrix->xx * *dx + matrix->xy * *dy); + new_y = (matrix->yx * *dx + matrix->yy * *dy); - *dx = new_x; - *dy = new_y; + *dx = new_x; + *dy = new_y; } -void vkvg_matrix_transform_point (const vkvg_matrix_t *matrix, float *x, float *y) -{ - vkvg_matrix_transform_distance (matrix, x, y); +void vkvg_matrix_transform_point(const vkvg_matrix_t *matrix, float *x, float *y) { + vkvg_matrix_transform_distance(matrix, x, y); - *x += matrix->x0; - *y += matrix->y0; + *x += matrix->x0; + *y += matrix->y0; } -void vkvg_matrix_get_scale (const vkvg_matrix_t *matrix, float *sx, float *sy) { - *sx = sqrt (matrix->xx * matrix->xx + matrix->xy * matrix->xy); - /*if (matrix->xx < 0) - *sx = -*sx;*/ - *sy = sqrt (matrix->yx * matrix->yx + matrix->yy * matrix->yy); - /*if (matrix->yy < 0) - *sy = -*sy;*/ +void vkvg_matrix_get_scale(const vkvg_matrix_t *matrix, float *sx, float *sy) { + *sx = sqrt(matrix->xx * matrix->xx + matrix->xy * matrix->xy); + /*if (matrix->xx < 0) + *sx = -*sx;*/ + *sy = sqrt(matrix->yx * matrix->yx + matrix->yy * matrix->yy); + /*if (matrix->yy < 0) + *sy = -*sy;*/ } diff --git a/src/vkvg_matrix.h b/src/vkvg_matrix.h index 7607791..66db350 100644 --- a/src/vkvg_matrix.h +++ b/src/vkvg_matrix.h @@ -27,7 +27,4 @@ #include <stdbool.h> #include "vkvg.h" - - - #endif diff --git a/src/vkvg_pattern.c b/src/vkvg_pattern.c index acefab6..2aad091 100644 --- a/src/vkvg_pattern.c +++ b/src/vkvg_pattern.c @@ -25,225 +25,220 @@ #include "vkvg_device_internal.h" #include "vkvg_pattern.h" -VkvgPattern vkvg_pattern_create_for_surface (VkvgSurface surf){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; +VkvgPattern vkvg_pattern_create_for_surface(VkvgSurface surf) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; - pat->type = VKVG_PATTERN_TYPE_SURFACE; - pat->extend = VKVG_EXTEND_NONE; - pat->data = surf; - pat->references = 1; + pat->type = VKVG_PATTERN_TYPE_SURFACE; + pat->extend = VKVG_EXTEND_NONE; + pat->data = surf; + pat->references = 1; - vkvg_surface_reference (surf); - if (surf->status) - pat->status = surf->status; + vkvg_surface_reference(surf); + if (surf->status) + pat->status = surf->status; - return pat; + return pat; } -vkvg_status_t vkvg_pattern_get_linear_points (VkvgPattern pat, float* x0, float* y0, float* x1, float* y1) { - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_LINEAR) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; +vkvg_status_t vkvg_pattern_get_linear_points(VkvgPattern pat, float *x0, float *y0, float *x1, float *y1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; - *x0 = grad->cp[0].x; - *y0 = grad->cp[0].y; - *x1 = grad->cp[0].z; - *y1 = grad->cp[0].w; - return VKVG_STATUS_SUCCESS; + *x0 = grad->cp[0].x; + *y0 = grad->cp[0].y; + *x1 = grad->cp[0].z; + *y1 = grad->cp[0].w; + return VKVG_STATUS_SUCCESS; } -vkvg_status_t vkvg_pattern_edit_linear (VkvgPattern pat, float x0, float y0, float x1, float y1){ - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_LINEAR) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; +vkvg_status_t vkvg_pattern_edit_linear(VkvgPattern pat, float x0, float y0, float x1, float y1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_LINEAR) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; - grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; - return VKVG_STATUS_SUCCESS; + grad->cp[0] = (vec4){{x0}, {y0}, {x1}, {y1}}; + return VKVG_STATUS_SUCCESS; } -VkvgPattern vkvg_pattern_create_linear (float x0, float y0, float x1, float y1){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; - pat->type = VKVG_PATTERN_TYPE_LINEAR; - pat->extend = VKVG_EXTEND_NONE; +VkvgPattern vkvg_pattern_create_linear(float x0, float y0, float x1, float y1) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; + pat->type = VKVG_PATTERN_TYPE_LINEAR; + pat->extend = VKVG_EXTEND_NONE; - pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); + pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); - if (pat->data) { - vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); - pat->references = 1; - } else - pat->status = VKVG_STATUS_NO_MEMORY; + if (pat->data) { + vkvg_pattern_edit_linear(pat, x0, y0, x1, y1); + pat->references = 1; + } else + pat->status = VKVG_STATUS_NO_MEMORY; - return pat; + return pat; } -vkvg_status_t vkvg_pattern_edit_radial (VkvgPattern pat, - float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1) { - if (pat->status) - return pat->status; - if (pat->type != VKVG_PATTERN_TYPE_RADIAL) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; +vkvg_status_t vkvg_pattern_edit_radial(VkvgPattern pat, float cx0, float cy0, float radius0, float cx1, float cy1, + float radius1) { + if (pat->status) + return pat->status; + if (pat->type != VKVG_PATTERN_TYPE_RADIAL) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; - vec2 c0 = {cx0, cy0}; - vec2 c1 = {cx1, cy1}; + vec2 c0 = {cx0, cy0}; + vec2 c1 = {cx1, cy1}; - if (radius0 > radius1 - 1.0f) - radius0 = radius1 - 1.0f; - vec2 u = vec2_sub (c0, c1); - float l = vec2_length(u); - if (l + radius0 + 1.0f >= radius1) { - vec2 v = vec2_div_s(u, l); - c0 = vec2_add(c1, vec2_mult_s (v, radius1 - radius0 - 1.0f)); - } + if (radius0 > radius1 - 1.0f) + radius0 = radius1 - 1.0f; + vec2 u = vec2_sub(c0, c1); + float l = vec2_length(u); + if (l + radius0 + 1.0f >= radius1) { + vec2 v = vec2_div_s(u, l); + c0 = vec2_add(c1, vec2_mult_s(v, radius1 - radius0 - 1.0f)); + } - grad->cp[0] = (vec4){{c0.x}, {c0.y},{radius0},{0}}; - grad->cp[1] = (vec4){{c1.x}, {c1.y},{radius1},{0}}; - return VKVG_STATUS_SUCCESS; + grad->cp[0] = (vec4){{c0.x}, {c0.y}, {radius0}, {0}}; + grad->cp[1] = (vec4){{c1.x}, {c1.y}, {radius1}, {0}}; + return VKVG_STATUS_SUCCESS; } -VkvgPattern vkvg_pattern_create_radial (float cx0, float cy0, float radius0, - float cx1, float cy1, float radius1){ - VkvgPattern pat = (vkvg_pattern_t*)calloc(1, sizeof(vkvg_pattern_t)); - if (!pat) - return (VkvgPattern)&_no_mem_status; - pat->type = VKVG_PATTERN_TYPE_RADIAL; - pat->extend = VKVG_EXTEND_NONE; +VkvgPattern vkvg_pattern_create_radial(float cx0, float cy0, float radius0, float cx1, float cy1, float radius1) { + VkvgPattern pat = (vkvg_pattern_t *)calloc(1, sizeof(vkvg_pattern_t)); + if (!pat) + return (VkvgPattern)&_no_mem_status; + pat->type = VKVG_PATTERN_TYPE_RADIAL; + pat->extend = VKVG_EXTEND_NONE; - pat->data = (void*)calloc(1,sizeof(vkvg_gradient_t)); + pat->data = (void *)calloc(1, sizeof(vkvg_gradient_t)); - if (pat->data) { - vkvg_pattern_edit_radial (pat, cx0, cy0, radius0, cx1, cy1, radius1); - pat->references = 1; - } else - pat->status = VKVG_STATUS_NO_MEMORY; + if (pat->data) { + vkvg_pattern_edit_radial(pat, cx0, cy0, radius0, cx1, cy1, radius1); + pat->references = 1; + } else + pat->status = VKVG_STATUS_NO_MEMORY; - return pat; + return pat; } -VkvgPattern vkvg_pattern_reference (VkvgPattern pat) { - if (!pat->status) - pat->references++; - return pat; +VkvgPattern vkvg_pattern_reference(VkvgPattern pat) { + if (!pat->status) + pat->references++; + return pat; } -uint32_t vkvg_pattern_get_reference_count (VkvgPattern pat) { - if (pat->status) - return 0; - return pat->references; +uint32_t vkvg_pattern_get_reference_count(VkvgPattern pat) { + if (pat->status) + return 0; + return pat->references; } -vkvg_status_t vkvg_pattern_add_color_stop (VkvgPattern pat, float offset, float r, float g, float b, float a) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; +vkvg_status_t vkvg_pattern_add_color_stop(VkvgPattern pat, float offset, float r, float g, float b, float a) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; #ifdef VKVG_PREMULT_ALPHA - vkvg_color_t c = {a*r,a*g,a*b,a}; + vkvg_color_t c = {a * r, a * g, a * b, a}; #else - vkvg_color_t c = {r,g,b,a}; + vkvg_color_t c = {r, g, b, a}; #endif - grad->colors[grad->count] = c; + grad->colors[grad->count] = c; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - grad->stops[grad->count] = offset; + grad->stops[grad->count] = offset; #else - grad->stops[grad->count].r = offset; + grad->stops[grad->count].r = offset; #endif - grad->count++; + grad->count++; } -void vkvg_pattern_set_extend (VkvgPattern pat, vkvg_extend_t extend){ - if (pat->status) - return; - pat->extend = extend; +void vkvg_pattern_set_extend(VkvgPattern pat, vkvg_extend_t extend) { + if (pat->status) + return; + pat->extend = extend; } -void vkvg_pattern_set_filter (VkvgPattern pat, vkvg_filter_t filter){ - if (pat->status) - return; - pat->filter = filter; +void vkvg_pattern_set_filter(VkvgPattern pat, vkvg_filter_t filter) { + if (pat->status) + return; + pat->filter = filter; } -vkvg_extend_t vkvg_pattern_get_extend (VkvgPattern pat){ - if (pat->status) - return (vkvg_extend_t)0; - return pat->extend; +vkvg_extend_t vkvg_pattern_get_extend(VkvgPattern pat) { + if (pat->status) + return (vkvg_extend_t)0; + return pat->extend; } -vkvg_filter_t vkvg_pattern_get_filter (VkvgPattern pat){ - if (pat->status) - return (vkvg_filter_t)0; - return pat->filter; +vkvg_filter_t vkvg_pattern_get_filter(VkvgPattern pat) { + if (pat->status) + return (vkvg_filter_t)0; + return pat->filter; } -vkvg_pattern_type_t vkvg_pattern_get_type (VkvgPattern pat){ - if (pat->status) - return (vkvg_pattern_type_t)0; - return pat->type; +vkvg_pattern_type_t vkvg_pattern_get_type(VkvgPattern pat) { + if (pat->status) + return (vkvg_pattern_type_t)0; + return pat->type; } -vkvg_status_t vkvg_pattern_get_color_stop_count (VkvgPattern pat, uint32_t* count) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - *count = grad->count; - return VKVG_STATUS_SUCCESS; +vkvg_status_t vkvg_pattern_get_color_stop_count(VkvgPattern pat, uint32_t *count) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + *count = grad->count; + return VKVG_STATUS_SUCCESS; } -vkvg_status_t vkvg_pattern_get_color_stop_rgba (VkvgPattern pat, uint32_t index, - float* offset, float* r, float* g, float* b, float* a) { - if (pat->status) - return pat->status; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) - return VKVG_STATUS_PATTERN_TYPE_MISMATCH; - vkvg_gradient_t* grad = (vkvg_gradient_t*)pat->data; - if (index >= grad->count) - return VKVG_STATUS_INVALID_INDEX; +vkvg_status_t vkvg_pattern_get_color_stop_rgba(VkvgPattern pat, uint32_t index, float *offset, float *r, float *g, + float *b, float *a) { + if (pat->status) + return pat->status; + if (pat->type == VKVG_PATTERN_TYPE_SURFACE || pat->type == VKVG_PATTERN_TYPE_SOLID) + return VKVG_STATUS_PATTERN_TYPE_MISMATCH; + vkvg_gradient_t *grad = (vkvg_gradient_t *)pat->data; + if (index >= grad->count) + return VKVG_STATUS_INVALID_INDEX; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - *offset = grad->stops[index]; + *offset = grad->stops[index]; #else - *offset = grad->stops[index].r; + *offset = grad->stops[index].r; #endif - vkvg_color_t c = grad->colors[index]; - *r = c.r; - *g = c.g; - *b = c.b; - *a = c.a; - return VKVG_STATUS_SUCCESS; + vkvg_color_t c = grad->colors[index]; + *r = c.r; + *g = c.g; + *b = c.b; + *a = c.a; + return VKVG_STATUS_SUCCESS; } -void vkvg_pattern_set_matrix (VkvgPattern pat, const vkvg_matrix_t* matrix) { - if (pat->status) - return; - pat->matrix = *matrix; - pat->hasMatrix = true; +void vkvg_pattern_set_matrix(VkvgPattern pat, const vkvg_matrix_t *matrix) { + if (pat->status) + return; + pat->matrix = *matrix; + pat->hasMatrix = true; } -void vkvg_pattern_get_matrix (VkvgPattern pat, vkvg_matrix_t* matrix) { - if (pat->status) - return; - if (pat->hasMatrix) - *matrix = pat->matrix; - else - *matrix = VKVG_IDENTITY_MATRIX; -} -vkvg_status_t vkvg_pattern_status (VkvgPattern pat) { - return pat->status; +void vkvg_pattern_get_matrix(VkvgPattern pat, vkvg_matrix_t *matrix) { + if (pat->status) + return; + if (pat->hasMatrix) + *matrix = pat->matrix; + else + *matrix = VKVG_IDENTITY_MATRIX; } +vkvg_status_t vkvg_pattern_status(VkvgPattern pat) { return pat->status; } -void vkvg_pattern_destroy(VkvgPattern pat) -{ - if (pat->status) - return; - pat->references--; - if (pat->references > 0) - return; +void vkvg_pattern_destroy(VkvgPattern pat) { + if (pat->status) + return; + pat->references--; + if (pat->references > 0) + return; - if (pat->type == VKVG_PATTERN_TYPE_SURFACE) { - VkvgSurface surf = (VkvgSurface)pat->data; - vkvg_surface_destroy (surf); - }else - free (pat->data); + if (pat->type == VKVG_PATTERN_TYPE_SURFACE) { + VkvgSurface surf = (VkvgSurface)pat->data; + vkvg_surface_destroy(surf); + } else + free(pat->data); - free(pat); + free(pat); } diff --git a/src/vkvg_pattern.h b/src/vkvg_pattern.h index 2ad068d..0ccc7a5 100644 --- a/src/vkvg_pattern.h +++ b/src/vkvg_pattern.h @@ -25,25 +25,25 @@ #include "vkvg_internal.h" typedef struct _vkvg_pattern_t { - vkvg_status_t status; - uint32_t references; - vkvg_pattern_type_t type; - vkvg_extend_t extend; - vkvg_filter_t filter; - vkvg_matrix_t matrix; - bool hasMatrix; - void* data; -}vkvg_pattern_t; + vkvg_status_t status; + uint32_t references; + vkvg_pattern_type_t type; + vkvg_extend_t extend; + vkvg_filter_t filter; + vkvg_matrix_t matrix; + bool hasMatrix; + void *data; +} vkvg_pattern_t; typedef struct _vkvg_gradient_t { - vkvg_color_t colors[16]; + vkvg_color_t colors[16]; #ifdef VKVG_ENABLE_VK_SCALAR_BLOCK_LAYOUT - float stops[16]; + float stops[16]; #else - vec4 stops[16]; + vec4 stops[16]; #endif - vec4 cp[2]; - uint32_t count; -}vkvg_gradient_t; + vec4 cp[2]; + uint32_t count; +} vkvg_gradient_t; #endif diff --git a/src/vkvg_surface.c b/src/vkvg_surface.c index 369adbd..fc28175 100644 --- a/src/vkvg_surface.c +++ b/src/vkvg_surface.c @@ -29,443 +29,430 @@ #include "stb_image_write.h" #include "vkh_image.h" -#define max(x,y) -void _transition_surf_images (VkvgSurface surf) { - LOCK_SURFACE(surf) - VkvgDevice dev = surf->dev; +#define max(x, y) +void _transition_surf_images(VkvgSurface surf) { + LOCK_SURFACE(surf) + VkvgDevice dev = surf->dev; - //_surface_wait_cmd (surf); + //_surface_wait_cmd (surf); - vkh_cmd_begin (surf->cmd,VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - VkhImage imgMs = surf->imgMS; - if (imgMs != NULL) - vkh_image_set_layout(surf->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_cmd_begin(surf->cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + VkhImage imgMs = surf->imgMS; + if (imgMs != NULL) + vkh_image_set_layout(surf->cmd, imgMs, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout(surf->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_image_set_layout (surf->cmd, surf->stencil, dev->stencilAspectFlag, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - vkh_cmd_end (surf->cmd); + vkh_image_set_layout(surf->cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_image_set_layout(surf->cmd, surf->stencil, dev->stencilAspectFlag, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + vkh_cmd_end(surf->cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - UNLOCK_SURFACE(surf) + UNLOCK_SURFACE(surf) } -void vkvg_surface_clear (VkvgSurface surf) { - if (surf->status) - return; - _clear_surface(surf, VK_IMAGE_ASPECT_STENCIL_BIT|VK_IMAGE_ASPECT_COLOR_BIT); +void vkvg_surface_clear(VkvgSurface surf) { + if (surf->status) + return; + _clear_surface(surf, VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_COLOR_BIT); } -VkvgSurface vkvg_surface_create (VkvgDevice dev, uint32_t width, uint32_t height){ - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; +VkvgSurface vkvg_surface_create(VkvgDevice dev, uint32_t width, uint32_t height) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; - surf->width = MAX(1, width); - surf->height = MAX(1, height); - surf->newSurf = true;//used to clear all attacments on first render pass + surf->width = MAX(1, width); + surf->height = MAX(1, height); + surf->newSurf = true; // used to clear all attacments on first render pass - _create_surface_images (surf); + _create_surface_images(surf); - _transition_surf_images (surf); + _transition_surf_images(surf); - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -VkvgSurface vkvg_surface_create_for_VkhImage (VkvgDevice dev, void* vkhImg) { - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; +VkvgSurface vkvg_surface_create_for_VkhImage(VkvgDevice dev, void *vkhImg) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; - if (!vkhImg) { - surf->status = VKVG_STATUS_INVALID_IMAGE; - return surf; - } + if (!vkhImg) { + surf->status = VKVG_STATUS_INVALID_IMAGE; + return surf; + } - VkhImage img = (VkhImage)vkhImg; - surf->width = img->infos.extent.width; - surf->height= img->infos.extent.height; + VkhImage img = (VkhImage)vkhImg; + surf->width = img->infos.extent.width; + surf->height = img->infos.extent.height; - surf->img = img; + surf->img = img; - vkh_image_create_sampler(img, VK_FILTER_NEAREST, VK_FILTER_NEAREST, - VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); + vkh_image_create_sampler(img, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); - _create_surface_secondary_images (surf); - _create_framebuffer (surf); + _create_surface_secondary_images(surf); + _create_framebuffer(surf); - _transition_surf_images (surf); - //_clear_surface (surf, VK_IMAGE_ASPECT_STENCIL_BIT); + _transition_surf_images(surf); + //_clear_surface (surf, VK_IMAGE_ASPECT_STENCIL_BIT); - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -//TODO: it would be better to blit in original size and create ms final image with dest surf dims -VkvgSurface vkvg_surface_create_from_bitmap (VkvgDevice dev, unsigned char* img, uint32_t width, uint32_t height) { - VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); - if (surf->status) - return surf; - if (!img || width <= 0 || height <= 0) { - surf->status = VKVG_STATUS_INVALID_IMAGE; - return surf; - } +// TODO: it would be better to blit in original size and create ms final image with dest surf dims +VkvgSurface vkvg_surface_create_from_bitmap(VkvgDevice dev, unsigned char *img, uint32_t width, uint32_t height) { + VkvgSurface surf = _create_surface(dev, FB_COLOR_FORMAT); + if (surf->status) + return surf; + if (!img || width <= 0 || height <= 0) { + surf->status = VKVG_STATUS_INVALID_IMAGE; + return surf; + } - surf->width = MAX(1, width); - surf->height = MAX(1, height); + surf->width = MAX(1, width); + surf->height = MAX(1, height); - _create_surface_images (surf); + _create_surface_images(surf); - uint32_t imgSize = width * height * 4; - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - //original format image - VkhImage stagImg= vkh_image_create ((VkhDevice)surf->dev,VK_FORMAT_R8G8B8A8_UNORM,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - //bgra bliting target - VkhImage tmpImg = vkh_image_create ((VkhDevice)surf->dev,surf->format,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - vkh_image_create_descriptor (tmpImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, - VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); - //staging buffer - vkh_buffer_t buff = {0}; - vkh_buffer_init((VkhDevice)dev, - VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - VKH_MEMORY_USAGE_CPU_TO_GPU, - imgSize, &buff, true); + uint32_t imgSize = width * height * 4; + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + // original format image + VkhImage stagImg = vkh_image_create((VkhDevice)surf->dev, VK_FORMAT_R8G8B8A8_UNORM, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + // bgra bliting target + VkhImage tmpImg = + vkh_image_create((VkhDevice)surf->dev, surf->format, surf->width, surf->height, VK_IMAGE_TILING_LINEAR, + VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + vkh_image_create_descriptor(tmpImg, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER); + // staging buffer + vkh_buffer_t buff = {0}; + vkh_buffer_init((VkhDevice)dev, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VKH_MEMORY_USAGE_CPU_TO_GPU, imgSize, &buff, + true); - memcpy (vkh_buffer_get_mapped_pointer (&buff), img, imgSize); + memcpy(vkh_buffer_get_mapped_pointer(&buff), img, imgSize); - VkCommandBuffer cmd = surf->cmd; + VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + VkBufferImageCopy bufferCopyRegion = {.imageSubresource = imgSubResLayers, + .imageExtent = {surf->width, surf->height, 1}}; - VkBufferImageCopy bufferCopyRegion = { .imageSubresource = imgSubResLayers, - .imageExtent = {surf->width,surf->height,1}}; + vkCmdCopyBufferToImage(cmd, buff.buffer, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, + &bufferCopyRegion); - vkCmdCopyBufferToImage(cmd, buff.buffer, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(tmpImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (tmpImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); + vkh_image_set_layout(cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - vkh_image_set_layout (cmd, tmpImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + vkh_cmd_end(cmd); - vkh_cmd_end (cmd); + _surface_submit_cmd(surf); // lock surface? - _surface_submit_cmd (surf);//lock surface? + vkh_buffer_reset(&buff); + vkh_image_destroy(stagImg); - vkh_buffer_reset (&buff); - vkh_image_destroy (stagImg); + surf->newSurf = false; - surf->newSurf = false; + // create tmp context with rendering pipeline to create the multisample img + VkvgContext ctx = vkvg_create(surf); - //create tmp context with rendering pipeline to create the multisample img - VkvgContext ctx = vkvg_create (surf); + /* VkClearAttachment ca = {VK_IMAGE_ASPECT_COLOR_BIT,0, { 0.0f, 0.0f, 0.0f, 0.0f }}; + VkClearRect cr = {{{0,0},{surf->width,surf->height}},0,1}; + vkCmdClearAttachments(ctx->cmd, 1, &ca, 1, &cr);*/ -/* VkClearAttachment ca = {VK_IMAGE_ASPECT_COLOR_BIT,0, { 0.0f, 0.0f, 0.0f, 0.0f }}; - VkClearRect cr = {{{0,0},{surf->width,surf->height}},0,1}; - vkCmdClearAttachments(ctx->cmd, 1, &ca, 1, &cr);*/ + vec4 srcRect = {.x = 0, .y = 0, .width = (float)surf->width, .height = (float)surf->height}; + ctx->pushConsts.source = srcRect; + ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + VKVG_PATTERN_TYPE_SURFACE; - vec4 srcRect = {.x=0,.y=0,.width=(float)surf->width,.height=(float)surf->height}; - ctx->pushConsts.source = srcRect; - ctx->pushConsts.fsq_patternType = (ctx->pushConsts.fsq_patternType & FULLSCREEN_BIT) + VKVG_PATTERN_TYPE_SURFACE; + //_update_push_constants (ctx); + _update_descriptor_set(ctx, tmpImg, ctx->dsSrc); + _ensure_renderpass_is_started(ctx); - //_update_push_constants (ctx); - _update_descriptor_set (ctx, tmpImg, ctx->dsSrc); - _ensure_renderpass_is_started (ctx); + vkvg_paint(ctx); + vkvg_destroy(ctx); - vkvg_paint (ctx); - vkvg_destroy (ctx); + vkh_image_destroy(tmpImg); - vkh_image_destroy (tmpImg); - - surf->status = VKVG_STATUS_SUCCESS; - vkvg_device_reference (surf->dev); - return surf; + surf->status = VKVG_STATUS_SUCCESS; + vkvg_device_reference(surf->dev); + return surf; } -VkvgSurface vkvg_surface_create_from_image (VkvgDevice dev, const char* filePath) { - int w = 0, - h = 0, - channels = 0; - unsigned char *img = stbi_load(filePath, &w, &h, &channels, 4);//force 4 components per pixel - if (!img){ - LOG(VKVG_LOG_ERR, "Could not load texture from %s, %s\n", filePath, stbi_failure_reason()); - return (VkvgSurface)&_no_mem_status; - } +VkvgSurface vkvg_surface_create_from_image(VkvgDevice dev, const char *filePath) { + int w = 0, h = 0, channels = 0; + unsigned char *img = stbi_load(filePath, &w, &h, &channels, 4); // force 4 components per pixel + if (!img) { + LOG(VKVG_LOG_ERR, "Could not load texture from %s, %s\n", filePath, stbi_failure_reason()); + return (VkvgSurface)&_no_mem_status; + } - VkvgSurface surf = vkvg_surface_create_from_bitmap(dev, img, (uint32_t)w, (uint32_t)h); + VkvgSurface surf = vkvg_surface_create_from_bitmap(dev, img, (uint32_t)w, (uint32_t)h); - stbi_image_free (img); + stbi_image_free(img); - return surf; + return surf; } -void vkvg_surface_destroy(VkvgSurface surf) -{ - if (surf->status) - return; +void vkvg_surface_destroy(VkvgSurface surf) { + if (surf->status) + return; - LOCK_SURFACE(surf) - surf->references--; - if (surf->references > 0) { - UNLOCK_SURFACE(surf) - return; - } - UNLOCK_SURFACE(surf) + LOCK_SURFACE(surf) + surf->references--; + if (surf->references > 0) { + UNLOCK_SURFACE(surf) + return; + } + UNLOCK_SURFACE(surf) - vkDestroyCommandPool(surf->dev->vkDev, surf->cmdPool, NULL); - vkDestroyFramebuffer(surf->dev->vkDev, surf->fb, NULL); + vkDestroyCommandPool(surf->dev->vkDev, surf->cmdPool, NULL); + vkDestroyFramebuffer(surf->dev->vkDev, surf->fb, NULL); - if (!surf->img->imported) - vkh_image_destroy(surf->img); + if (!surf->img->imported) + vkh_image_destroy(surf->img); - vkh_image_destroy(surf->imgMS); - vkh_image_destroy(surf->stencil); + vkh_image_destroy(surf->imgMS); + vkh_image_destroy(surf->stencil); - if (surf->dev->threadAware) - mtx_destroy (&surf->mutex); + if (surf->dev->threadAware) + mtx_destroy(&surf->mutex); #if VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - vkDestroySemaphore (surf->dev->vkDev, surf->timeline, NULL); + vkDestroySemaphore(surf->dev->vkDev, surf->timeline, NULL); #else - vkDestroyFence (surf->dev->vkDev, surf->flushFence, NULL); + vkDestroyFence(surf->dev->vkDev, surf->flushFence, NULL); #endif - vkvg_device_destroy (surf->dev); - free(surf); + vkvg_device_destroy(surf->dev); + free(surf); } -VkvgSurface vkvg_surface_reference (VkvgSurface surf) { - if (!surf->status) { - LOCK_SURFACE(surf) - surf->references++; - UNLOCK_SURFACE(surf) - } - return surf; +VkvgSurface vkvg_surface_reference(VkvgSurface surf) { + if (!surf->status) { + LOCK_SURFACE(surf) + surf->references++; + UNLOCK_SURFACE(surf) + } + return surf; } -uint32_t vkvg_surface_get_reference_count (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->references; +uint32_t vkvg_surface_get_reference_count(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->references; } -VkImage vkvg_surface_get_vk_image(VkvgSurface surf) -{ - if (surf->status) - return NULL; - if (surf->dev->deferredResolve) - _explicit_ms_resolve(surf); - return vkh_image_get_vkimage (surf->img); +VkImage vkvg_surface_get_vk_image(VkvgSurface surf) { + if (surf->status) + return NULL; + if (surf->dev->deferredResolve) + _explicit_ms_resolve(surf); + return vkh_image_get_vkimage(surf->img); } -void vkvg_surface_resolve (VkvgSurface surf){ - if (surf->status || !surf->dev->deferredResolve) - return; - _explicit_ms_resolve(surf); +void vkvg_surface_resolve(VkvgSurface surf) { + if (surf->status || !surf->dev->deferredResolve) + return; + _explicit_ms_resolve(surf); } -VkFormat vkvg_surface_get_vk_format(VkvgSurface surf) -{ - if (surf->status) - return VK_FORMAT_UNDEFINED; - return surf->format; +VkFormat vkvg_surface_get_vk_format(VkvgSurface surf) { + if (surf->status) + return VK_FORMAT_UNDEFINED; + return surf->format; } -uint32_t vkvg_surface_get_width (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->width; +uint32_t vkvg_surface_get_width(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->width; } -uint32_t vkvg_surface_get_height (VkvgSurface surf) { - if (surf->status) - return 0; - return surf->height; +uint32_t vkvg_surface_get_height(VkvgSurface surf) { + if (surf->status) + return 0; + return surf->height; } -vkvg_status_t vkvg_surface_write_to_png (VkvgSurface surf, const char* path){ - if (surf->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid status: %d\n", surf->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (surf->dev->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid device status: %d\n", surf->dev->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (surf->dev->pngStagFormat == VK_FORMAT_UNDEFINED) { - LOG(VKVG_LOG_ERR, "no suitable image format for png write\n"); - return VKVG_STATUS_INVALID_FORMAT; - } - if (!path) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n"); - return VKVG_STATUS_WRITE_ERROR; - } - LOCK_SURFACE(surf) - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - VkvgDevice dev = surf->dev; +vkvg_status_t vkvg_surface_write_to_png(VkvgSurface surf, const char *path) { + if (surf->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid status: %d\n", surf->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (surf->dev->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, invalid device status: %d\n", surf->dev->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (surf->dev->pngStagFormat == VK_FORMAT_UNDEFINED) { + LOG(VKVG_LOG_ERR, "no suitable image format for png write\n"); + return VKVG_STATUS_INVALID_FORMAT; + } + if (!path) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_png failed, null path\n"); + return VKVG_STATUS_WRITE_ERROR; + } + LOCK_SURFACE(surf) + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + VkvgDevice dev = surf->dev; - //RGBA to blit to, surf img is bgra - VkhImage stagImg; + // RGBA to blit to, surf img is bgra + VkhImage stagImg; - if (dev->pngStagTiling == VK_IMAGE_TILING_LINEAR) - stagImg = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, dev->pngStagTiling, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - else - stagImg = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width,surf->height, dev->pngStagTiling, - VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); + if (dev->pngStagTiling == VK_IMAGE_TILING_LINEAR) + stagImg = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + dev->pngStagTiling, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + else + stagImg = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + dev->pngStagTiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VkCommandBuffer cmd = surf->cmd; + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); - vkh_cmd_end (cmd); + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - VkhImage stagImgLinear = stagImg; + VkhImage stagImgLinear = stagImg; - if (dev->pngStagTiling == VK_IMAGE_TILING_OPTIMAL) { - stagImgLinear = vkh_image_create ((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - VkImageCopy cpy = { - .srcSubresource = imgSubResLayers, - .srcOffset = {0}, - .dstSubresource = imgSubResLayers, - .dstOffset = {0}, - .extent = {(int32_t)surf->width, (int32_t)surf->height, 1} - }; + if (dev->pngStagTiling == VK_IMAGE_TILING_OPTIMAL) { + stagImgLinear = vkh_image_create((VkhDevice)surf->dev, dev->pngStagFormat, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + VkImageCopy cpy = {.srcSubresource = imgSubResLayers, + .srcOffset = {0}, + .dstSubresource = imgSubResLayers, + .dstOffset = {0}, + .extent = {(int32_t)surf->width, (int32_t)surf->height, 1}}; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImgLinear, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdCopyImage(cmd, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImgLinear), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cpy); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImgLinear, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkCmdCopyImage(cmd, vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImgLinear), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &cpy); - vkh_cmd_end (cmd); + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - vkh_image_destroy (stagImg); - } + vkh_image_destroy(stagImg); + } - void* img = vkh_image_map (stagImgLinear); + void *img = vkh_image_map(stagImgLinear); - uint64_t stride = vkh_image_get_stride(stagImgLinear); + uint64_t stride = vkh_image_get_stride(stagImgLinear); - stbi_write_png (path, (int32_t)surf->width, (int32_t)surf->height, 4, img, (int32_t)stride); + stbi_write_png(path, (int32_t)surf->width, (int32_t)surf->height, 4, img, (int32_t)stride); - vkh_image_unmap (stagImgLinear); - vkh_image_destroy (stagImgLinear); + vkh_image_unmap(stagImgLinear); + vkh_image_destroy(stagImgLinear); - UNLOCK_SURFACE(surf) - return VKVG_STATUS_SUCCESS; + UNLOCK_SURFACE(surf) + return VKVG_STATUS_SUCCESS; } -vkvg_status_t vkvg_surface_write_to_memory (VkvgSurface surf, unsigned char* const bitmap){ - if (surf->status) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, invalid status: %d\n", surf->status); - return VKVG_STATUS_INVALID_STATUS; - } - if (!bitmap) { - LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, null path\n"); - return VKVG_STATUS_INVALID_IMAGE; - } +vkvg_status_t vkvg_surface_write_to_memory(VkvgSurface surf, unsigned char *const bitmap) { + if (surf->status) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, invalid status: %d\n", surf->status); + return VKVG_STATUS_INVALID_STATUS; + } + if (!bitmap) { + LOG(VKVG_LOG_ERR, "vkvg_surface_write_to_memory failed, null path\n"); + return VKVG_STATUS_INVALID_IMAGE; + } - LOCK_SURFACE(surf) + LOCK_SURFACE(surf) - VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}; - VkvgDevice dev = surf->dev; + VkImageSubresourceLayers imgSubResLayers = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}; + VkvgDevice dev = surf->dev; - //RGBA to blit to, surf img is bgra - VkhImage stagImg= vkh_image_create ((VkhDevice)surf->dev,VK_FORMAT_B8G8R8A8_UNORM ,surf->width,surf->height,VK_IMAGE_TILING_LINEAR, - VKH_MEMORY_USAGE_GPU_TO_CPU, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); + // RGBA to blit to, surf img is bgra + VkhImage stagImg = vkh_image_create((VkhDevice)surf->dev, VK_FORMAT_B8G8R8A8_UNORM, surf->width, surf->height, + VK_IMAGE_TILING_LINEAR, VKH_MEMORY_USAGE_GPU_TO_CPU, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); - VkCommandBuffer cmd = surf->cmd; + VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, stagImg, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageBlit blit = { - .srcSubresource = imgSubResLayers, - .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - .dstSubresource = imgSubResLayers, - .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, - }; - vkCmdBlitImage (cmd, - vkh_image_get_vkimage (surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); + VkImageBlit blit = { + .srcSubresource = imgSubResLayers, + .srcOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + .dstSubresource = imgSubResLayers, + .dstOffsets[1] = {(int32_t)surf->width, (int32_t)surf->height, 1}, + }; + vkCmdBlitImage(cmd, vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(stagImg), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_NEAREST); - vkh_cmd_end (cmd); + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - uint64_t stride = vkh_image_get_stride(stagImg); - uint32_t dest_stride = surf->width * 4; + uint64_t stride = vkh_image_get_stride(stagImg); + uint32_t dest_stride = surf->width * 4; - char* img = vkh_image_map (stagImg); - char* row = (char*)bitmap; - for (uint32_t y = 0; y < surf->height; y++) { - memcpy(row, img, dest_stride); - row += dest_stride; - img += stride; - } + char *img = vkh_image_map(stagImg); + char *row = (char *)bitmap; + for (uint32_t y = 0; y < surf->height; y++) { + memcpy(row, img, dest_stride); + row += dest_stride; + img += stride; + } - vkh_image_unmap (stagImg); - vkh_image_destroy (stagImg); + vkh_image_unmap(stagImg); + vkh_image_destroy(stagImg); - UNLOCK_SURFACE(surf) + UNLOCK_SURFACE(surf) - return VKVG_STATUS_SUCCESS; + return VKVG_STATUS_SUCCESS; } diff --git a/src/vkvg_surface_internal.c b/src/vkvg_surface_internal.c index ec0cc07..f1bf9dd 100644 --- a/src/vkvg_surface_internal.c +++ b/src/vkvg_surface_internal.c @@ -25,215 +25,227 @@ #include "vkh_image.h" #include "vkh_queue.h" -void _explicit_ms_resolve (VkvgSurface surf){ - LOCK_SURFACE (surf) +void _explicit_ms_resolve(VkvgSurface surf) { + LOCK_SURFACE(surf) - VkCommandBuffer cmd = surf->cmd; + VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - vkh_image_set_layout (cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkh_image_set_layout (cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_image_set_layout(cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - VkImageResolve re = { - .extent = {surf->width, surf->height,1}, - .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1}, - .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT,0,0,1} - }; + VkImageResolve re = {.extent = {surf->width, surf->height, 1}, + .srcSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}, + .dstSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1}}; - vkCmdResolveImage(cmd, - vkh_image_get_vkimage (surf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vkh_image_get_vkimage (surf->img) ,VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1,&re); - vkh_image_set_layout (cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - vkh_cmd_end (cmd); + vkCmdResolveImage(cmd, vkh_image_get_vkimage(surf->imgMS), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vkh_image_get_vkimage(surf->img), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &re); + vkh_image_set_layout(cmd, surf->imgMS, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - UNLOCK_SURFACE (surf) + UNLOCK_SURFACE(surf) } -void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect) -{ - LOCK_SURFACE (surf) +void _clear_surface(VkvgSurface surf, VkImageAspectFlags aspect) { + LOCK_SURFACE(surf) - VkCommandBuffer cmd = surf->cmd; + VkCommandBuffer cmd = surf->cmd; - vkh_cmd_begin (cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); + vkh_cmd_begin(cmd, VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT); - if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { - VkClearColorValue cclr = {{0,0,0,0}}; - VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT,0,1,0,1}; + if (aspect & VK_IMAGE_ASPECT_COLOR_BIT) { + VkClearColorValue cclr = {{0, 0, 0, 0}}; + VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}; - VkhImage img = surf->imgMS; - if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) - img = surf->img; + VkhImage img = surf->imgMS; + if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) + img = surf->img; - vkh_image_set_layout (cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdClearColorImage(cmd, vkh_image_get_vkimage (img), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cclr, 1, &range); + vkCmdClearColorImage(cmd, vkh_image_get_vkimage(img), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &cclr, 1, &range); - vkh_image_set_layout (cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); - } - if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) { - VkClearDepthStencilValue clr = {0,0}; - VkImageSubresourceRange range = {VK_IMAGE_ASPECT_STENCIL_BIT,0,1,0,1}; + vkh_image_set_layout(cmd, img, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT); + } + if (aspect & VK_IMAGE_ASPECT_STENCIL_BIT) { + VkClearDepthStencilValue clr = {0, 0}; + VkImageSubresourceRange range = {VK_IMAGE_ASPECT_STENCIL_BIT, 0, 1, 0, 1}; - vkh_image_set_layout (cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + vkh_image_set_layout(cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - vkCmdClearDepthStencilImage (cmd, vkh_image_get_vkimage (surf->stencil), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,&clr,1,&range); + vkCmdClearDepthStencilImage(cmd, vkh_image_get_vkimage(surf->stencil), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + &clr, 1, &range); - vkh_image_set_layout (cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); - } - vkh_cmd_end (cmd); + vkh_image_set_layout(cmd, surf->stencil, VK_IMAGE_ASPECT_STENCIL_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT); + } + vkh_cmd_end(cmd); - _surface_submit_cmd (surf); + _surface_submit_cmd(surf); - UNLOCK_SURFACE (surf) + UNLOCK_SURFACE(surf) } -void _create_surface_main_image (VkvgSurface surf){ - surf->img = vkh_image_create((VkhDevice)surf->dev,surf->format,surf->width,surf->height,surf->dev->supportedTiling,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT); - vkh_image_create_descriptor(surf->img, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->img, "SURF main color"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->img), "SURF main color VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->img), "SURF main color SAMPLER"); +void _create_surface_main_image(VkvgSurface surf) { + surf->img = vkh_image_create((VkhDevice)surf->dev, surf->format, surf->width, surf->height, + surf->dev->supportedTiling, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); + vkh_image_create_descriptor(surf->img, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->img, "SURF main color"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->img), + "SURF main color VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->img), + "SURF main color SAMPLER"); #endif } -//create multisample color img if sample count > 1 and the stencil buffer multisampled or not -void _create_surface_secondary_images (VkvgSurface surf) { - if (surf->dev->samples > VK_SAMPLE_COUNT_1_BIT){ - surf->imgMS = vkh_image_ms_create((VkhDevice)surf->dev,surf->format,surf->dev->samples,surf->width,surf->height,VKH_MEMORY_USAGE_GPU_ONLY, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor(surf->imgMS, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, - VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->imgMS, "SURF MS color IMG"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->imgMS), "SURF MS color VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->imgMS), "SURF MS color SAMPLER"); +// create multisample color img if sample count > 1 and the stencil buffer multisampled or not +void _create_surface_secondary_images(VkvgSurface surf) { + if (surf->dev->samples > VK_SAMPLE_COUNT_1_BIT) { + surf->imgMS = vkh_image_ms_create((VkhDevice)surf->dev, surf->format, surf->dev->samples, surf->width, + surf->height, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(surf->imgMS, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_COLOR_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->imgMS, "SURF MS color IMG"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, + (uint64_t)vkh_image_get_view(surf->imgMS), "SURF MS color VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, + (uint64_t)vkh_image_get_sampler(surf->imgMS), "SURF MS color SAMPLER"); #endif - } - surf->stencil = vkh_image_ms_create((VkhDevice)surf->dev,surf->dev->stencilFormat,surf->dev->samples,surf->width,surf->height,VKH_MEMORY_USAGE_GPU_ONLY, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_TRANSFER_SRC_BIT); - vkh_image_create_descriptor(surf->stencil, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_STENCIL_BIT, VK_FILTER_NEAREST, - VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST,VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_image_set_name(surf->stencil, "SURF stencil"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, (uint64_t)vkh_image_get_view(surf->stencil), "SURF stencil VIEW"); - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, (uint64_t)vkh_image_get_sampler(surf->stencil), "SURF stencil SAMPLER"); + } + surf->stencil = vkh_image_ms_create((VkhDevice)surf->dev, surf->dev->stencilFormat, surf->dev->samples, surf->width, + surf->height, VKH_MEMORY_USAGE_GPU_ONLY, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT); + vkh_image_create_descriptor(surf->stencil, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_ASPECT_STENCIL_BIT, VK_FILTER_NEAREST, + VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_image_set_name(surf->stencil, "SURF stencil"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_IMAGE_VIEW, + (uint64_t)vkh_image_get_view(surf->stencil), "SURF stencil VIEW"); + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_SAMPLER, + (uint64_t)vkh_image_get_sampler(surf->stencil), "SURF stencil SAMPLER"); #endif } -void _create_framebuffer (VkvgSurface surf) { - VkImageView attachments[] = { - vkh_image_get_view (surf->img), - vkh_image_get_view (surf->stencil), - vkh_image_get_view (surf->imgMS), - }; - VkFramebufferCreateInfo frameBufferCreateInfo = { .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .renderPass = surf->dev->renderPass, - .attachmentCount = 3, - .pAttachments = attachments, - .width = surf->width, - .height = surf->height, - .layers = 1 }; - if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) - frameBufferCreateInfo.attachmentCount = 2; - else if (surf->dev->deferredResolve) { - attachments[0] = attachments[2]; - frameBufferCreateInfo.attachmentCount = 2; - } - VK_CHECK_RESULT(vkCreateFramebuffer(surf->dev->vkDev, &frameBufferCreateInfo, NULL, &surf->fb)); -#if defined(DEBUG) && defined (VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_FRAMEBUFFER, (uint64_t)surf->fb, "SURF FB"); +void _create_framebuffer(VkvgSurface surf) { + VkImageView attachments[] = { + vkh_image_get_view(surf->img), + vkh_image_get_view(surf->stencil), + vkh_image_get_view(surf->imgMS), + }; + VkFramebufferCreateInfo frameBufferCreateInfo = {.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .renderPass = surf->dev->renderPass, + .attachmentCount = 3, + .pAttachments = attachments, + .width = surf->width, + .height = surf->height, + .layers = 1}; + if (surf->dev->samples == VK_SAMPLE_COUNT_1_BIT) + frameBufferCreateInfo.attachmentCount = 2; + else if (surf->dev->deferredResolve) { + attachments[0] = attachments[2]; + frameBufferCreateInfo.attachmentCount = 2; + } + VK_CHECK_RESULT(vkCreateFramebuffer(surf->dev->vkDev, &frameBufferCreateInfo, NULL, &surf->fb)); +#if defined(DEBUG) && defined(VKVG_DBG_UTILS) + vkh_device_set_object_name((VkhDevice)surf->dev, VK_OBJECT_TYPE_FRAMEBUFFER, (uint64_t)surf->fb, "SURF FB"); #endif } -void _create_surface_images (VkvgSurface surf) { +void _create_surface_images(VkvgSurface surf) { - _create_surface_main_image (surf); - _create_surface_secondary_images(surf); - _create_framebuffer (surf); + _create_surface_main_image(surf); + _create_surface_secondary_images(surf); + _create_framebuffer(surf); #if defined(DEBUG) && defined(ENABLE_VALIDATION) - vkh_image_set_name(surf->img, "surfImg"); - vkh_image_set_name(surf->imgMS, "surfImgMS"); - vkh_image_set_name(surf->stencil, "surfStencil"); + vkh_image_set_name(surf->img, "surfImg"); + vkh_image_set_name(surf->imgMS, "surfImgMS"); + vkh_image_set_name(surf->stencil, "surfStencil"); #endif } -VkvgSurface _create_surface (VkvgDevice dev, VkFormat format) { - VkvgSurface surf = (vkvg_surface*)calloc(1,sizeof(vkvg_surface)); - if (!surf) - return (VkvgSurface)&_no_mem_status; +VkvgSurface _create_surface(VkvgDevice dev, VkFormat format) { + VkvgSurface surf = (vkvg_surface *)calloc(1, sizeof(vkvg_surface)); + if (!surf) + return (VkvgSurface)&_no_mem_status; - surf->references = 1; - if (dev->status != VKVG_STATUS_SUCCESS) { - surf->status = VKVG_STATUS_DEVICE_ERROR; - return surf; - } - surf->dev = dev; - surf->format = format; - if (dev->threadAware) - mtx_init (&surf->mutex, mtx_plain); - surf->cmdPool = vkh_cmd_pool_create ((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); - vkh_cmd_buffs_create((VkhDevice)dev, surf->cmdPool,VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1, &surf->cmd); + surf->references = 1; + if (dev->status != VKVG_STATUS_SUCCESS) { + surf->status = VKVG_STATUS_DEVICE_ERROR; + return surf; + } + surf->dev = dev; + surf->format = format; + if (dev->threadAware) + mtx_init(&surf->mutex, mtx_plain); + surf->cmdPool = + vkh_cmd_pool_create((VkhDevice)dev, dev->gQueue->familyIndex, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); + vkh_cmd_buffs_create((VkhDevice)dev, surf->cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1, &surf->cmd); #if VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - surf->timeline = vkh_timeline_create ((VkhDevice)dev, 0); + surf->timeline = vkh_timeline_create((VkhDevice)dev, 0); #else - surf->flushFence = vkh_fence_create ((VkhDevice)dev); + surf->flushFence = vkh_fence_create((VkhDevice)dev); #endif #if defined(DEBUG) && defined(VKVG_DBG_UTILS) - vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)surf->cmd, "vkvgSurfCmd"); + vkh_device_set_object_name((VkhDevice)dev, VK_OBJECT_TYPE_COMMAND_BUFFER, (uint64_t)surf->cmd, "vkvgSurfCmd"); #endif - return surf; + return surf; } -//if fence sync, surf mutex must be locked. +// if fence sync, surf mutex must be locked. /*bool _surface_wait_cmd (VkvgSurface surf) { - LOG(VKVG_LOG_INFO, "SURF: _surface__wait_flush_fence\n"); + LOG(VKVG_LOG_INFO, "SURF: _surface__wait_flush_fence\n"); #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - if (vkh_timeline_wait ((VkhDevice)surf->dev, surf->timeline, surf->timelineStep) == VK_SUCCESS) - return true; + if (vkh_timeline_wait ((VkhDevice)surf->dev, surf->timeline, surf->timelineStep) == VK_SUCCESS) + return true; #else - if (WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) { - ResetFences (surf->dev->vkDev, 1, &surf->flushFence); - return true; - } + if (WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT) == VK_SUCCESS) { + ResetFences (surf->dev->vkDev, 1, &surf->flushFence); + return true; + } #endif - LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); - surf->status = VKVG_STATUS_TIMEOUT; - return false; + LOG(VKVG_LOG_DEBUG, "CTX: _wait_flush_fence timeout\n"); + surf->status = VKVG_STATUS_TIMEOUT; + return false; }*/ -//surface mutex must be locked to call this method, locking to guard also the surf->cmd local buffer usage. -void _surface_submit_cmd (VkvgSurface surf) { - VkvgDevice dev = surf->dev; +// surface mutex must be locked to call this method, locking to guard also the surf->cmd local buffer usage. +void _surface_submit_cmd(VkvgSurface surf) { + VkvgDevice dev = surf->dev; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - LOCK_DEVICE - vkh_cmd_submit_timelined (dev->gQueue, &surf->cmd, surf->timeline, surf->timelineStep, surf->timelineStep+1); - surf->timelineStep++; - UNLOCK_DEVICE - vkh_timeline_wait ((VkhDevice)dev, surf->timeline, surf->timelineStep); + LOCK_DEVICE + vkh_cmd_submit_timelined(dev->gQueue, &surf->cmd, surf->timeline, surf->timelineStep, surf->timelineStep + 1); + surf->timelineStep++; + UNLOCK_DEVICE + vkh_timeline_wait((VkhDevice)dev, surf->timeline, surf->timelineStep); #else - LOCK_DEVICE - vkh_cmd_submit (surf->dev->gQueue, &surf->cmd, surf->flushFence); - UNLOCK_DEVICE - WaitForFences (surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT); - ResetFences (surf->dev->vkDev, 1, &surf->flushFence); + LOCK_DEVICE + vkh_cmd_submit(surf->dev->gQueue, &surf->cmd, surf->flushFence); + UNLOCK_DEVICE + WaitForFences(surf->dev->vkDev, 1, &surf->flushFence, VK_TRUE, VKVG_FENCE_TIMEOUT); + ResetFences(surf->dev->vkDev, 1, &surf->flushFence); #endif } diff --git a/src/vkvg_surface_internal.h b/src/vkvg_surface_internal.h index 5cc47c6..085ce77 100644 --- a/src/vkvg_surface_internal.h +++ b/src/vkvg_surface_internal.h @@ -27,44 +27,44 @@ #include "vkh.h" typedef struct _vkvg_surface_t { - vkvg_status_t status; /**< Current status of surface, affected by last operation */ - uint32_t references; - VkvgDevice dev; - uint32_t width; - uint32_t height; - VkFormat format; - VkFramebuffer fb; - VkhImage img; - VkhImage imgMS; - VkhImage stencil; - VkCommandPool cmdPool; //local pools ensure thread safety - VkCommandBuffer cmd; //surface local command buffer. - bool newSurf; - mtx_t mutex; + vkvg_status_t status; /**< Current status of surface, affected by last operation */ + uint32_t references; + VkvgDevice dev; + uint32_t width; + uint32_t height; + VkFormat format; + VkFramebuffer fb; + VkhImage img; + VkhImage imgMS; + VkhImage stencil; + VkCommandPool cmdPool; // local pools ensure thread safety + VkCommandBuffer cmd; // surface local command buffer. + bool newSurf; + mtx_t mutex; #ifdef VKVG_ENABLE_VK_TIMELINE_SEMAPHORE - VkSemaphore timeline; /**< Timeline semaphore */ - uint64_t timelineStep; + VkSemaphore timeline; /**< Timeline semaphore */ + uint64_t timelineStep; #else - VkFence flushFence; //unsignaled idle. + VkFence flushFence; // unsignaled idle. #endif -}vkvg_surface; +} vkvg_surface; -#define LOCK_SURFACE(surf) \ - if (surf->dev->threadAware)\ - mtx_lock (&surf->mutex); -#define UNLOCK_SURFACE(surf) \ - if (surf->dev->threadAware)\ - mtx_unlock (&surf->mutex); +#define LOCK_SURFACE(surf) \ + if (surf->dev->threadAware) \ + mtx_lock(&surf->mutex); +#define UNLOCK_SURFACE(surf) \ + if (surf->dev->threadAware) \ + mtx_unlock(&surf->mutex); -void _explicit_ms_resolve (VkvgSurface surf); -void _clear_surface (VkvgSurface surf, VkImageAspectFlags aspect); -void _create_surface_main_image (VkvgSurface surf); -void _create_surface_secondary_images (VkvgSurface surf); -void _create_framebuffer (VkvgSurface surf); -void _create_surface_images (VkvgSurface surf); -VkvgSurface _create_surface (VkvgDevice dev, VkFormat format); +void _explicit_ms_resolve(VkvgSurface surf); +void _clear_surface(VkvgSurface surf, VkImageAspectFlags aspect); +void _create_surface_main_image(VkvgSurface surf); +void _create_surface_secondary_images(VkvgSurface surf); +void _create_framebuffer(VkvgSurface surf); +void _create_surface_images(VkvgSurface surf); +VkvgSurface _create_surface(VkvgDevice dev, VkFormat format); -void _surface_submit_cmd (VkvgSurface surf); -//bool _surface_wait_cmd (VkvgSurface surf); +void _surface_submit_cmd(VkvgSurface surf); +// bool _surface_wait_cmd (VkvgSurface surf); #endif |