diff --git a/sfwl/core/3rd_tinydir.h b/sfwl/core/3rd_tinydir.h deleted file mode 100644 index e08eb84..0000000 --- a/sfwl/core/3rd_tinydir.h +++ /dev/null @@ -1,831 +0,0 @@ -/* -Copyright (c) 2013-2019, tinydir authors: -- Cong Xu -- Lautis Sun -- Baudouin Feildel -- Andargor -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -#ifndef TINYDIR_H -#define TINYDIR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#if ((defined _UNICODE) && !(defined UNICODE)) -#define UNICODE -#endif - -#if ((defined UNICODE) && !(defined _UNICODE)) -#define _UNICODE -#endif - -#include -#include -#include -#ifdef _MSC_VER -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include -# pragma warning(push) -# pragma warning (disable : 4996) -#else -# include -# include -# include -# include -#endif -#ifdef __MINGW32__ -# include -#endif - - -/* types */ - -/* Windows UNICODE wide character support */ -#if defined _MSC_VER || defined __MINGW32__ -# define _tinydir_char_t TCHAR -# define TINYDIR_STRING(s) _TEXT(s) -# define _tinydir_strlen _tcslen -# define _tinydir_strcpy _tcscpy -# define _tinydir_strcat _tcscat -# define _tinydir_strcmp _tcscmp -# define _tinydir_strrchr _tcsrchr -# define _tinydir_strncmp _tcsncmp -#else -# define _tinydir_char_t char -# define TINYDIR_STRING(s) s -# define _tinydir_strlen strlen -# define _tinydir_strcpy strcpy -# define _tinydir_strcat strcat -# define _tinydir_strcmp strcmp -# define _tinydir_strrchr strrchr -# define _tinydir_strncmp strncmp -#endif - -#if (defined _MSC_VER || defined __MINGW32__) -# include -# define _TINYDIR_PATH_MAX MAX_PATH -#elif defined __linux__ -# include -# ifdef PATH_MAX -# define _TINYDIR_PATH_MAX PATH_MAX -# endif -#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -# include -# if defined(BSD) -# include -# ifdef PATH_MAX -# define _TINYDIR_PATH_MAX PATH_MAX -# endif -# endif -#endif - -#ifndef _TINYDIR_PATH_MAX -#define _TINYDIR_PATH_MAX 4096 -#endif - -#ifdef _MSC_VER -/* extra chars for the "\\*" mask */ -# define _TINYDIR_PATH_EXTRA 2 -#else -# define _TINYDIR_PATH_EXTRA 0 -#endif - -#define _TINYDIR_FILENAME_MAX 256 - -#if (defined _MSC_VER || defined __MINGW32__) -#define _TINYDIR_DRIVE_MAX 3 -#endif - -#ifdef _MSC_VER -# define _TINYDIR_FUNC static __inline -#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L -# define _TINYDIR_FUNC static __inline__ -#else -# define _TINYDIR_FUNC static inline -#endif - -/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */ -#ifdef TINYDIR_USE_READDIR_R - -/* readdir_r is a POSIX-only function, and may not be available under various - * environments/settings, e.g. MinGW. Use readdir fallback */ -#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\ - _POSIX_SOURCE -# define _TINYDIR_HAS_READDIR_R -#endif -#if _POSIX_C_SOURCE >= 200112L -# define _TINYDIR_HAS_FPATHCONF -# include -#endif -#if _BSD_SOURCE || _SVID_SOURCE || \ - (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700) -# define _TINYDIR_HAS_DIRFD -# include -#endif -#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\ - defined _PC_NAME_MAX -# define _TINYDIR_USE_FPATHCONF -#endif -#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\ - !(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX) -# define _TINYDIR_USE_READDIR -#endif - -/* Use readdir by default */ -#else -# define _TINYDIR_USE_READDIR -#endif - -/* MINGW32 has two versions of dirent, ASCII and UNICODE*/ -#ifndef _MSC_VER -#if (defined __MINGW32__) && (defined _UNICODE) -#define _TINYDIR_DIR _WDIR -#define _tinydir_dirent _wdirent -#define _tinydir_opendir _wopendir -#define _tinydir_readdir _wreaddir -#define _tinydir_closedir _wclosedir -#else -#define _TINYDIR_DIR DIR -#define _tinydir_dirent dirent -#define _tinydir_opendir opendir -#define _tinydir_readdir readdir -#define _tinydir_closedir closedir -#endif -#endif - -/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */ -#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE) -#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE) -#else -#error "Either define both alloc and free or none of them!" -#endif - -#if !defined(_TINYDIR_MALLOC) - #define _TINYDIR_MALLOC(_size) malloc(_size) - #define _TINYDIR_FREE(_ptr) free(_ptr) -#endif /* !defined(_TINYDIR_MALLOC) */ - -typedef struct tinydir_file -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - _tinydir_char_t name[_TINYDIR_FILENAME_MAX]; - _tinydir_char_t *extension; - int is_dir; - int is_reg; - -#ifndef _MSC_VER -#ifdef __MINGW32__ - struct _stat _s; -#else - struct stat _s; -#endif -#endif -} tinydir_file; - -typedef struct tinydir_dir -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - int has_next; - size_t n_files; - - tinydir_file *_files; -#ifdef _MSC_VER - HANDLE _h; - WIN32_FIND_DATA _f; -#else - _TINYDIR_DIR *_d; - struct _tinydir_dirent *_e; -#ifndef _TINYDIR_USE_READDIR - struct _tinydir_dirent *_ep; -#endif -#endif -} tinydir_dir; - - -/* declarations */ - -_TINYDIR_FUNC -int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path); -_TINYDIR_FUNC -int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path); -_TINYDIR_FUNC -void tinydir_close(tinydir_dir *dir); - -_TINYDIR_FUNC -int tinydir_next(tinydir_dir *dir); -_TINYDIR_FUNC -int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file); -_TINYDIR_FUNC -int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i); -_TINYDIR_FUNC -int tinydir_open_subdir_n(tinydir_dir *dir, size_t i); - -_TINYDIR_FUNC -int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path); -_TINYDIR_FUNC -void _tinydir_get_ext(tinydir_file *file); -_TINYDIR_FUNC -int _tinydir_file_cmp(const void *a, const void *b); -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR -_TINYDIR_FUNC -size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp); -#endif -#endif - - -/* definitions*/ - -_TINYDIR_FUNC -int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path) -{ -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR - int error; - int size; /* using int size */ -#endif -#else - _tinydir_char_t path_buf[_TINYDIR_PATH_MAX]; -#endif - _tinydir_char_t *pathp; - - if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0) - { - errno = EINVAL; - return -1; - } - if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - /* initialise dir */ - dir->_files = NULL; -#ifdef _MSC_VER - dir->_h = INVALID_HANDLE_VALUE; -#else - dir->_d = NULL; -#ifndef _TINYDIR_USE_READDIR - dir->_ep = NULL; -#endif -#endif - tinydir_close(dir); - - _tinydir_strcpy(dir->path, path); - /* Remove trailing slashes */ - pathp = &dir->path[_tinydir_strlen(dir->path) - 1]; - while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/'))) - { - *pathp = TINYDIR_STRING('\0'); - pathp++; - } -#ifdef _MSC_VER - _tinydir_strcpy(path_buf, dir->path); - _tinydir_strcat(path_buf, TINYDIR_STRING("\\*")); -#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) - dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0); -#else - dir->_h = FindFirstFile(path_buf, &dir->_f); -#endif - if (dir->_h == INVALID_HANDLE_VALUE) - { - errno = ENOENT; -#else - dir->_d = _tinydir_opendir(path); - if (dir->_d == NULL) - { -#endif - goto bail; - } - - /* read first file */ - dir->has_next = 1; -#ifndef _MSC_VER -#ifdef _TINYDIR_USE_READDIR - dir->_e = _tinydir_readdir(dir->_d); -#else - /* allocate dirent buffer for readdir_r */ - size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */ - if (size == -1) return -1; - dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size); - if (dir->_ep == NULL) return -1; - - error = readdir_r(dir->_d, dir->_ep, &dir->_e); - if (error != 0) return -1; -#endif - if (dir->_e == NULL) - { - dir->has_next = 0; - } -#endif - - return 0; - -bail: - tinydir_close(dir); - return -1; -} - -_TINYDIR_FUNC -int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path) -{ - /* Count the number of files first, to pre-allocate the files array */ - size_t n_files = 0; - if (tinydir_open(dir, path) == -1) - { - return -1; - } - while (dir->has_next) - { - n_files++; - if (tinydir_next(dir) == -1) - { - goto bail; - } - } - tinydir_close(dir); - - if (n_files == 0 || tinydir_open(dir, path) == -1) - { - return -1; - } - - dir->n_files = 0; - dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files); - if (dir->_files == NULL) - { - goto bail; - } - while (dir->has_next) - { - tinydir_file *p_file; - dir->n_files++; - - p_file = &dir->_files[dir->n_files - 1]; - if (tinydir_readfile(dir, p_file) == -1) - { - goto bail; - } - - if (tinydir_next(dir) == -1) - { - goto bail; - } - - /* Just in case the number of files has changed between the first and - second reads, terminate without writing into unallocated memory */ - if (dir->n_files == n_files) - { - break; - } - } - - qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp); - - return 0; - -bail: - tinydir_close(dir); - return -1; -} - -_TINYDIR_FUNC -void tinydir_close(tinydir_dir *dir) -{ - if (dir == NULL) - { - return; - } - - memset(dir->path, 0, sizeof(dir->path)); - dir->has_next = 0; - dir->n_files = 0; - _TINYDIR_FREE(dir->_files); - dir->_files = NULL; -#ifdef _MSC_VER - if (dir->_h != INVALID_HANDLE_VALUE) - { - FindClose(dir->_h); - } - dir->_h = INVALID_HANDLE_VALUE; -#else - if (dir->_d) - { - _tinydir_closedir(dir->_d); - } - dir->_d = NULL; - dir->_e = NULL; -#ifndef _TINYDIR_USE_READDIR - _TINYDIR_FREE(dir->_ep); - dir->_ep = NULL; -#endif -#endif -} - -_TINYDIR_FUNC -int tinydir_next(tinydir_dir *dir) -{ - if (dir == NULL) - { - errno = EINVAL; - return -1; - } - if (!dir->has_next) - { - errno = ENOENT; - return -1; - } - -#ifdef _MSC_VER - if (FindNextFile(dir->_h, &dir->_f) == 0) -#else -#ifdef _TINYDIR_USE_READDIR - dir->_e = _tinydir_readdir(dir->_d); -#else - if (dir->_ep == NULL) - { - return -1; - } - if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0) - { - return -1; - } -#endif - if (dir->_e == NULL) -#endif - { - dir->has_next = 0; -#ifdef _MSC_VER - if (GetLastError() != ERROR_SUCCESS && - GetLastError() != ERROR_NO_MORE_FILES) - { - tinydir_close(dir); - errno = EIO; - return -1; - } -#endif - } - - return 0; -} - -_TINYDIR_FUNC -int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file) -{ - const _tinydir_char_t *filename; - if (dir == NULL || file == NULL) - { - errno = EINVAL; - return -1; - } -#ifdef _MSC_VER - if (dir->_h == INVALID_HANDLE_VALUE) -#else - if (dir->_e == NULL) -#endif - { - errno = ENOENT; - return -1; - } - filename = -#ifdef _MSC_VER - dir->_f.cFileName; -#else - dir->_e->d_name; -#endif - if (_tinydir_strlen(dir->path) + - _tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >= - _TINYDIR_PATH_MAX) - { - /* the path for the file will be too long */ - errno = ENAMETOOLONG; - return -1; - } - if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - _tinydir_strcpy(file->path, dir->path); - if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0) - _tinydir_strcat(file->path, TINYDIR_STRING("/")); - _tinydir_strcpy(file->name, filename); - _tinydir_strcat(file->path, filename); -#ifndef _MSC_VER -#ifdef __MINGW32__ - if (_tstat( -#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \ - || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \ - || ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) - if (lstat( -#else - if (stat( -#endif - file->path, &file->_s) == -1) - { - return -1; - } -#endif - _tinydir_get_ext(file); - - file->is_dir = -#ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); -#else - S_ISDIR(file->_s.st_mode); -#endif - file->is_reg = -#ifdef _MSC_VER - !!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || - ( - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) && -#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) && -#endif -#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) && -#endif - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) && - !(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY)); -#else - S_ISREG(file->_s.st_mode); -#endif - - return 0; -} - -_TINYDIR_FUNC -int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i) -{ - if (dir == NULL || file == NULL) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files) - { - errno = ENOENT; - return -1; - } - - memcpy(file, &dir->_files[i], sizeof(tinydir_file)); - _tinydir_get_ext(file); - - return 0; -} - -_TINYDIR_FUNC -int tinydir_open_subdir_n(tinydir_dir *dir, size_t i) -{ - _tinydir_char_t path[_TINYDIR_PATH_MAX]; - if (dir == NULL) - { - errno = EINVAL; - return -1; - } - if (i >= dir->n_files || !dir->_files[i].is_dir) - { - errno = ENOENT; - return -1; - } - - _tinydir_strcpy(path, dir->_files[i].path); - tinydir_close(dir); - if (tinydir_open_sorted(dir, path) == -1) - { - return -1; - } - - return 0; -} - -/* Open a single file given its path */ -_TINYDIR_FUNC -int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path) -{ - tinydir_dir dir; - int result = 0; - int found = 0; - _tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX]; - _tinydir_char_t *dir_name; - _tinydir_char_t *base_name; -#if (defined _MSC_VER || defined __MINGW32__) - _tinydir_char_t drive_buf[_TINYDIR_PATH_MAX]; - _tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX]; -#endif - - if (file == NULL || path == NULL || _tinydir_strlen(path) == 0) - { - errno = EINVAL; - return -1; - } - if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX) - { - errno = ENAMETOOLONG; - return -1; - } - - /* Get the parent path */ -#if (defined _MSC_VER || defined __MINGW32__) -#if ((defined _MSC_VER) && (_MSC_VER >= 1400)) - errno = _tsplitpath_s( - path, - drive_buf, _TINYDIR_DRIVE_MAX, - dir_name_buf, _TINYDIR_FILENAME_MAX, - file_name_buf, _TINYDIR_FILENAME_MAX, - ext_buf, _TINYDIR_FILENAME_MAX); -#else - _tsplitpath( - path, - drive_buf, - dir_name_buf, - file_name_buf, - ext_buf); -#endif - - if (errno) - { - return -1; - } - -/* _splitpath_s not work fine with only filename and widechar support */ -#ifdef _UNICODE - if (drive_buf[0] == L'\xFEFE') - drive_buf[0] = '\0'; - if (dir_name_buf[0] == L'\xFEFE') - dir_name_buf[0] = '\0'; -#endif - - /* Emulate the behavior of dirname by returning "." for dir name if it's - empty */ - if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0') - { - _tinydir_strcpy(dir_name_buf, TINYDIR_STRING(".")); - } - /* Concatenate the drive letter and dir name to form full dir name */ - _tinydir_strcat(drive_buf, dir_name_buf); - dir_name = drive_buf; - /* Concatenate the file name and extension to form base name */ - _tinydir_strcat(file_name_buf, ext_buf); - base_name = file_name_buf; -#else - _tinydir_strcpy(dir_name_buf, path); - dir_name = dirname(dir_name_buf); - _tinydir_strcpy(file_name_buf, path); - base_name = basename(file_name_buf); -#endif - - /* Special case: if the path is a root dir, open the parent dir as the file */ -#if (defined _MSC_VER || defined __MINGW32__) - if (_tinydir_strlen(base_name) == 0) -#else - if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0) -#endif - { - memset(file, 0, sizeof * file); - file->is_dir = 1; - file->is_reg = 0; - _tinydir_strcpy(file->path, dir_name); - file->extension = file->path + _tinydir_strlen(file->path); - return 0; - } - - /* Open the parent directory */ - if (tinydir_open(&dir, dir_name) == -1) - { - return -1; - } - - /* Read through the parent directory and look for the file */ - while (dir.has_next) - { - if (tinydir_readfile(&dir, file) == -1) - { - result = -1; - goto bail; - } - if (_tinydir_strcmp(file->name, base_name) == 0) - { - /* File found */ - found = 1; - break; - } - tinydir_next(&dir); - } - if (!found) - { - result = -1; - errno = ENOENT; - } - -bail: - tinydir_close(&dir); - return result; -} - -_TINYDIR_FUNC -void _tinydir_get_ext(tinydir_file *file) -{ - _tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.')); - if (period == NULL) - { - file->extension = &(file->name[_tinydir_strlen(file->name)]); - } - else - { - file->extension = period + 1; - } -} - -_TINYDIR_FUNC -int _tinydir_file_cmp(const void *a, const void *b) -{ - const tinydir_file *fa = (const tinydir_file *)a; - const tinydir_file *fb = (const tinydir_file *)b; - if (fa->is_dir != fb->is_dir) - { - return -(fa->is_dir - fb->is_dir); - } - return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX); -} - -#ifndef _MSC_VER -#ifndef _TINYDIR_USE_READDIR -/* -The following authored by Ben Hutchings -from https://womble.decadent.org.uk/readdir_r-advisory.html -*/ -/* Calculate the required buffer size (in bytes) for directory * -* entries read from the given directory handle. Return -1 if this * -* this cannot be done. * -* * -* This code does not trust values of NAME_MAX that are less than * -* 255, since some systems (including at least HP-UX) incorrectly * -* define it to be a smaller value. */ -_TINYDIR_FUNC -size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp) -{ - long name_max; - size_t name_end; - /* parameter may be unused */ - (void)dirp; - -#if defined _TINYDIR_USE_FPATHCONF - name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX); - if (name_max == -1) -#if defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -#else - return (size_t)(-1); -#endif -#elif defined(NAME_MAX) - name_max = (NAME_MAX > 255) ? NAME_MAX : 255; -#else -#error "buffer size for readdir_r cannot be determined" -#endif - name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1; - return (name_end > sizeof(struct _tinydir_dirent) ? - name_end : sizeof(struct _tinydir_dirent)); -} -#endif -#endif - -#ifdef __cplusplus -} -#endif - -# if defined (_MSC_VER) -# pragma warning(pop) -# endif - -#endif diff --git a/sfwl/core/char_range.inc b/sfwl/core/char_range.inc index da9a9ee..3fe945f 100644 --- a/sfwl/core/char_range.inc +++ b/sfwl/core/char_range.inc @@ -3,8 +3,10 @@ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ /*************************************************************************/ +//--STRIP #ifndef CHAR_RANGE_INC #define CHAR_RANGE_INC +//--STRIP //--STRIP #include "core/typedefs.h" @@ -1430,4 +1432,6 @@ static CharRange xid_continue[] = { { 0x0, 0x0 }, }; +//--STRIP #endif // CHAR_RANGE_INC +//--STRIP diff --git a/sfwl/core/char_utils.h b/sfwl/core/char_utils.h index 3e8912f..4714c11 100644 --- a/sfwl/core/char_utils.h +++ b/sfwl/core/char_utils.h @@ -3,8 +3,10 @@ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ /*************************************************************************/ +//--STRIP #ifndef CHAR_UTILS_H #define CHAR_UTILS_H +//--STRIP //--STRIP #include "core/typedefs.h" @@ -86,4 +88,6 @@ static _FORCE_INLINE_ bool is_underscore(char32_t p_char) { return (p_char == '_'); } +//--STRIP #endif // CHAR_UTILS_H +//--STRIP diff --git a/sfwl/core/color.cpp b/sfwl/core/color.cpp new file mode 100644 index 0000000..bfc71de --- /dev/null +++ b/sfwl/core/color.cpp @@ -0,0 +1,522 @@ +/*************************************************************************/ +/* color.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "core/color.h" + +#include "core/math_funcs.h" +//--STRIP + +uint32_t Color::to_argb32() const { + uint32_t c = (uint8_t)Math::round(a * 255); + c <<= 8; + c |= (uint8_t)Math::round(r * 255); + c <<= 8; + c |= (uint8_t)Math::round(g * 255); + c <<= 8; + c |= (uint8_t)Math::round(b * 255); + + return c; +} + +uint32_t Color::to_abgr32() const { + uint32_t c = (uint8_t)Math::round(a * 255); + c <<= 8; + c |= (uint8_t)Math::round(b * 255); + c <<= 8; + c |= (uint8_t)Math::round(g * 255); + c <<= 8; + c |= (uint8_t)Math::round(r * 255); + + return c; +} + +uint32_t Color::to_rgba32() const { + uint32_t c = (uint8_t)Math::round(r * 255); + c <<= 8; + c |= (uint8_t)Math::round(g * 255); + c <<= 8; + c |= (uint8_t)Math::round(b * 255); + c <<= 8; + c |= (uint8_t)Math::round(a * 255); + + return c; +} + +uint64_t Color::to_abgr64() const { + uint64_t c = (uint16_t)Math::round(a * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(r * 65535); + + return c; +} + +uint64_t Color::to_argb64() const { + uint64_t c = (uint16_t)Math::round(a * 65535); + c <<= 16; + c |= (uint16_t)Math::round(r * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + + return c; +} + +uint64_t Color::to_rgba64() const { + uint64_t c = (uint16_t)Math::round(r * 65535); + c <<= 16; + c |= (uint16_t)Math::round(g * 65535); + c <<= 16; + c |= (uint16_t)Math::round(b * 65535); + c <<= 16; + c |= (uint16_t)Math::round(a * 65535); + + return c; +} + +float Color::get_h() const { + float min = MIN(r, g); + min = MIN(min, b); + float max = MAX(r, g); + max = MAX(max, b); + + float delta = max - min; + + if (delta == 0) { + return 0; + } + + float h; + if (r == max) { + h = (g - b) / delta; // between yellow & magenta + } else if (g == max) { + h = 2 + (b - r) / delta; // between cyan & yellow + } else { + h = 4 + (r - g) / delta; // between magenta & cyan + } + + h /= 6.0; + if (h < 0) { + h += 1.0; + } + + return h; +} + +float Color::get_s() const { + float min = MIN(r, g); + min = MIN(min, b); + float max = MAX(r, g); + max = MAX(max, b); + + float delta = max - min; + + return (max != 0) ? (delta / max) : 0; +} + +float Color::get_v() const { + float max = MAX(r, g); + max = MAX(max, b); + return max; +} + +void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) { + int i; + float f, p, q, t; + a = p_alpha; + + if (p_s == 0) { + // acp_hromatic (grey) + r = g = b = p_v; + return; + } + + p_h *= 6.0; + p_h = Math::fmod(p_h, 6); + i = Math::floor(p_h); + + f = p_h - i; + p = p_v * (1 - p_s); + q = p_v * (1 - p_s * f); + t = p_v * (1 - p_s * (1 - f)); + + switch (i) { + case 0: // Red is the dominant color + r = p_v; + g = t; + b = p; + break; + case 1: // Green is the dominant color + r = q; + g = p_v; + b = p; + break; + case 2: + r = p; + g = p_v; + b = t; + break; + case 3: // Blue is the dominant color + r = p; + g = q; + b = p_v; + break; + case 4: + r = t; + g = p; + b = p_v; + break; + default: // (5) Red is the dominant color + r = p_v; + g = p; + b = q; + break; + } +} + +bool Color::is_equal_approx(const Color &p_color) const { + return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a); +} + +Color Color::clamp(const Color &p_min, const Color &p_max) const { + return Color( + CLAMP(r, p_min.r, p_max.r), + CLAMP(g, p_min.g, p_max.g), + CLAMP(b, p_min.b, p_max.b), + CLAMP(a, p_min.a, p_max.a)); +} + +void Color::invert() { + r = 1.0 - r; + g = 1.0 - g; + b = 1.0 - b; +} +void Color::contrast() { + r = Math::fmod(r + 0.5, 1.0); + g = Math::fmod(g + 0.5, 1.0); + b = Math::fmod(b + 0.5, 1.0); +} + +Color Color::hex(uint32_t p_hex) { + float a = (p_hex & 0xFF) / 255.0; + p_hex >>= 8; + float b = (p_hex & 0xFF) / 255.0; + p_hex >>= 8; + float g = (p_hex & 0xFF) / 255.0; + p_hex >>= 8; + float r = (p_hex & 0xFF) / 255.0; + + return Color(r, g, b, a); +} + +Color Color::hex64(uint64_t p_hex) { + float a = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float b = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float g = (p_hex & 0xFFFF) / 65535.0; + p_hex >>= 16; + float r = (p_hex & 0xFFFF) / 65535.0; + + return Color(r, g, b, a); +} + +Color Color::from_rgbe9995(uint32_t p_rgbe) { + float r = p_rgbe & 0x1ff; + float g = (p_rgbe >> 9) & 0x1ff; + float b = (p_rgbe >> 18) & 0x1ff; + float e = (p_rgbe >> 27); + float m = Math::pow(2, e - 15.0 - 9.0); + + float rd = r * m; + float gd = g * m; + float bd = b * m; + + return Color(rd, gd, bd, 1.0f); +} + +static float _parse_col(const String &p_str, int p_ofs) { + int ig = 0; + + for (int i = 0; i < 2; i++) { + int c = p_str[i + p_ofs]; + int v = 0; + + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a'; + v += 10; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A'; + v += 10; + } else { + return -1; + } + + if (i == 0) { + ig += v * 16; + } else { + ig += v; + } + } + + return ig; +} + +Color Color::inverted() const { + Color c = *this; + c.invert(); + return c; +} + +Color Color::contrasted() const { + Color c = *this; + c.contrast(); + return c; +} + +Color Color::html(const String &p_color) { + String color = p_color; + if (color.length() == 0) { + return Color(); + } + if (color[0] == '#') { + color = color.substr(1, color.length() - 1); + } + if (color.length() == 3 || color.length() == 4) { + String exp_color; + for (int i = 0; i < color.length(); i++) { + exp_color += color[i]; + exp_color += color[i]; + } + color = exp_color; + } + + bool alpha = false; + + if (color.length() == 8) { + alpha = true; + } else if (color.length() == 6) { + alpha = false; + } else { + ERR_FAIL_V_MSG(Color(), "Invalid color code: " + p_color + "."); + } + + int a = 255; + if (alpha) { + a = _parse_col(color, 0); + ERR_FAIL_COND_V_MSG(a < 0, Color(), "Invalid color code: " + p_color + "."); + } + + int from = alpha ? 2 : 0; + + int r = _parse_col(color, from + 0); + ERR_FAIL_COND_V_MSG(r < 0, Color(), "Invalid color code: " + p_color + "."); + int g = _parse_col(color, from + 2); + ERR_FAIL_COND_V_MSG(g < 0, Color(), "Invalid color code: " + p_color + "."); + int b = _parse_col(color, from + 4); + ERR_FAIL_COND_V_MSG(b < 0, Color(), "Invalid color code: " + p_color + "."); + + return Color(r / 255.0, g / 255.0, b / 255.0, a / 255.0); +} + +bool Color::html_is_valid(const String &p_color) { + String color = p_color; + + if (color.length() == 0) { + return false; + } + if (color[0] == '#') { + color = color.substr(1, color.length() - 1); + } + + bool alpha = false; + + if (color.length() == 8) { + alpha = true; + } else if (color.length() == 6) { + alpha = false; + } else { + return false; + } + + if (alpha) { + int a = _parse_col(color, 0); + if (a < 0) { + return false; + } + } + + int from = alpha ? 2 : 0; + + int r = _parse_col(color, from + 0); + if (r < 0) { + return false; + } + int g = _parse_col(color, from + 2); + if (g < 0) { + return false; + } + int b = _parse_col(color, from + 4); + if (b < 0) { + return false; + } + + return true; +} + +String _to_hex(float p_val) { + int v = Math::round(p_val * 255); + v = CLAMP(v, 0, 255); + String ret; + + for (int i = 0; i < 2; i++) { + CharType c[2] = { 0, 0 }; + int lv = v & 0xF; + if (lv < 10) { + c[0] = '0' + lv; + } else { + c[0] = 'a' + lv - 10; + } + + v >>= 4; + String cs = (const CharType *)c; + ret = cs + ret; + } + + return ret; +} + +String Color::to_html(bool p_alpha) const { + String txt; + txt += _to_hex(r); + txt += _to_hex(g); + txt += _to_hex(b); + if (p_alpha) { + txt = _to_hex(a) + txt; + } + return txt; +} + +Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { + Color c; + c.set_hsv(p_h, p_s, p_v, p_a); + return c; +} + +Color::operator String() const { + return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; +} + +Color Color::operator+(const Color &p_color) const { + return Color( + r + p_color.r, + g + p_color.g, + b + p_color.b, + a + p_color.a); +} + +void Color::operator+=(const Color &p_color) { + r = r + p_color.r; + g = g + p_color.g; + b = b + p_color.b; + a = a + p_color.a; +} + +Color Color::operator-(const Color &p_color) const { + return Color( + r - p_color.r, + g - p_color.g, + b - p_color.b, + a - p_color.a); +} + +void Color::operator-=(const Color &p_color) { + r = r - p_color.r; + g = g - p_color.g; + b = b - p_color.b; + a = a - p_color.a; +} + +Color Color::operator*(const Color &p_color) const { + return Color( + r * p_color.r, + g * p_color.g, + b * p_color.b, + a * p_color.a); +} + +Color Color::operator*(const real_t &rvalue) const { + return Color( + r * rvalue, + g * rvalue, + b * rvalue, + a * rvalue); +} + +void Color::operator*=(const Color &p_color) { + r = r * p_color.r; + g = g * p_color.g; + b = b * p_color.b; + a = a * p_color.a; +} + +void Color::operator*=(const real_t &rvalue) { + r = r * rvalue; + g = g * rvalue; + b = b * rvalue; + a = a * rvalue; +} + +Color Color::operator/(const Color &p_color) const { + return Color( + r / p_color.r, + g / p_color.g, + b / p_color.b, + a / p_color.a); +} + +Color Color::operator/(const real_t &rvalue) const { + return Color( + r / rvalue, + g / rvalue, + b / rvalue, + a / rvalue); +} + +void Color::operator/=(const Color &p_color) { + r = r / p_color.r; + g = g / p_color.g; + b = b / p_color.b; + a = a / p_color.a; +} + +void Color::operator/=(const real_t &rvalue) { + if (rvalue == 0) { + r = 1.0; + g = 1.0; + b = 1.0; + a = 1.0; + } else { + r = r / rvalue; + g = g / rvalue; + b = b / rvalue; + a = a / rvalue; + } +}; + +Color Color::operator-() const { + return Color( + 1.0 - r, + 1.0 - g, + 1.0 - b, + 1.0 - a); +} diff --git a/sfwl/core/color.h b/sfwl/core/color.h new file mode 100644 index 0000000..b4d6096 --- /dev/null +++ b/sfwl/core/color.h @@ -0,0 +1,247 @@ +//--STRIP +#ifndef COLOR_H +#define COLOR_H +//--STRIP + +/*************************************************************************/ +/* color.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "core/math_funcs.h" +#include "core/ustring.h" +//--STRIP + +struct _NO_DISCARD_CLASS_ Color { + union { + struct { + float r; + float g; + float b; + float a; + }; + float components[4]; + }; + + bool operator==(const Color &p_color) const { return (r == p_color.r && g == p_color.g && b == p_color.b && a == p_color.a); } + bool operator!=(const Color &p_color) const { return (r != p_color.r || g != p_color.g || b != p_color.b || a != p_color.a); } + + uint32_t to_rgba32() const; + uint32_t to_argb32() const; + uint32_t to_abgr32() const; + uint64_t to_rgba64() const; + uint64_t to_argb64() const; + uint64_t to_abgr64() const; + float get_h() const; + float get_s() const; + float get_v() const; + void set_hsv(float p_h, float p_s, float p_v, float p_alpha = 1.0); + + _FORCE_INLINE_ float &operator[](int idx) { + return components[idx]; + } + _FORCE_INLINE_ const float &operator[](int idx) const { + return components[idx]; + } + + Color operator+(const Color &p_color) const; + void operator+=(const Color &p_color); + + Color operator-() const; + Color operator-(const Color &p_color) const; + void operator-=(const Color &p_color); + + Color operator*(const Color &p_color) const; + Color operator*(const real_t &rvalue) const; + void operator*=(const Color &p_color); + void operator*=(const real_t &rvalue); + + Color operator/(const Color &p_color) const; + Color operator/(const real_t &rvalue) const; + void operator/=(const Color &p_color); + void operator/=(const real_t &rvalue); + + bool is_equal_approx(const Color &p_color) const; + + Color clamp(const Color &p_min = Color(0, 0, 0, 0), const Color &p_max = Color(1, 1, 1, 1)) const; + + void invert(); + void contrast(); + Color inverted() const; + Color contrasted() const; + + _FORCE_INLINE_ float get_luminance() const { + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + _FORCE_INLINE_ Color linear_interpolate(const Color &p_to, float p_weight) const { + Color res = *this; + + res.r += (p_weight * (p_to.r - r)); + res.g += (p_weight * (p_to.g - g)); + res.b += (p_weight * (p_to.b - b)); + res.a += (p_weight * (p_to.a - a)); + + return res; + } + + _FORCE_INLINE_ Color darkened(float p_amount) const { + Color res = *this; + res.r = res.r * (1.0f - p_amount); + res.g = res.g * (1.0f - p_amount); + res.b = res.b * (1.0f - p_amount); + return res; + } + + _FORCE_INLINE_ Color lightened(float p_amount) const { + Color res = *this; + res.r = res.r + (1.0f - res.r) * p_amount; + res.g = res.g + (1.0f - res.g) * p_amount; + res.b = res.b + (1.0f - res.b) * p_amount; + return res; + } + + _FORCE_INLINE_ uint32_t to_rgbe9995() const { + const float pow2to9 = 512.0f; + const float B = 15.0f; + //const float Emax = 31.0f; + const float N = 9.0f; + + float sharedexp = 65408.000f; //(( pow2to9 - 1.0f)/ pow2to9)*powf( 2.0f, 31.0f - 15.0f); + + float cRed = MAX(0.0f, MIN(sharedexp, r)); + float cGreen = MAX(0.0f, MIN(sharedexp, g)); + float cBlue = MAX(0.0f, MIN(sharedexp, b)); + + float cMax = MAX(cRed, MAX(cGreen, cBlue)); + + // expp = MAX(-B - 1, log2(maxc)) + 1 + B + + float expp = MAX(-B - 1.0f, floor(Math::log(cMax) / Math_LN2)) + 1.0f + B; + + float sMax = (float)floor((cMax / Math::pow(2.0f, expp - B - N)) + 0.5f); + + float exps = expp + 1.0f; + + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } + + float sRed = Math::floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = Math::floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = Math::floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + + return (uint32_t(Math::fast_ftoi(sRed)) & 0x1FF) | ((uint32_t(Math::fast_ftoi(sGreen)) & 0x1FF) << 9) | ((uint32_t(Math::fast_ftoi(sBlue)) & 0x1FF) << 18) | ((uint32_t(Math::fast_ftoi(exps)) & 0x1F) << 27); + } + + _FORCE_INLINE_ Color blend(const Color &p_over) const { + Color res; + float sa = 1.0 - p_over.a; + res.a = a * sa + p_over.a; + if (res.a == 0) { + return Color(0, 0, 0, 0); + } else { + res.r = (r * a * sa + p_over.r * p_over.a) / res.a; + res.g = (g * a * sa + p_over.g * p_over.a) / res.a; + res.b = (b * a * sa + p_over.b * p_over.a) / res.a; + } + return res; + } + + _FORCE_INLINE_ Color to_linear() const { + return Color( + r < 0.04045 ? r * (1.0 / 12.92) : Math::pow((r + 0.055) * (1.0 / (1 + 0.055)), 2.4), + g < 0.04045 ? g * (1.0 / 12.92) : Math::pow((g + 0.055) * (1.0 / (1 + 0.055)), 2.4), + b < 0.04045 ? b * (1.0 / 12.92) : Math::pow((b + 0.055) * (1.0 / (1 + 0.055)), 2.4), + a); + } + _FORCE_INLINE_ Color to_srgb() const { + return Color( + r < 0.0031308 ? 12.92 * r : (1.0 + 0.055) * Math::pow(r, 1.0f / 2.4f) - 0.055, + g < 0.0031308 ? 12.92 * g : (1.0 + 0.055) * Math::pow(g, 1.0f / 2.4f) - 0.055, + b < 0.0031308 ? 12.92 * b : (1.0 + 0.055) * Math::pow(b, 1.0f / 2.4f) - 0.055, a); + } + + static Color hex(uint32_t p_hex); + static Color hex64(uint64_t p_hex); + static Color html(const String &p_color); + static bool html_is_valid(const String &p_color); + String to_html(bool p_alpha = true) const; + Color from_hsv(float p_h, float p_s, float p_v, float p_a) const; + static Color from_rgbe9995(uint32_t p_rgbe); + + _FORCE_INLINE_ bool operator<(const Color &p_color) const; //used in set keys + operator String() const; + + static _FORCE_INLINE_ Color color8(int r, int g, int b) { + return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f); + } + + static _FORCE_INLINE_ Color color8(int r, int g, int b, int a) { + return Color(static_cast(r) / 255.0f, static_cast(g) / 255.0f, static_cast(b) / 255.0f, static_cast(a) / 255.0f); + } + + _FORCE_INLINE_ void set_r8(int32_t r8) { r = (CLAMP(r8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_r8() const { return int32_t(CLAMP(Math::round(r * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_g8(int32_t g8) { g = (CLAMP(g8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_g8() const { return int32_t(CLAMP(Math::round(g * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_b8(int32_t b8) { b = (CLAMP(b8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_b8() const { return int32_t(CLAMP(Math::round(b * 255.0f), 0.0f, 255.0f)); } + _FORCE_INLINE_ void set_a8(int32_t a8) { a = (CLAMP(a8, 0, 255) / 255.0f); } + _FORCE_INLINE_ int32_t get_a8() const { return int32_t(CLAMP(Math::round(a * 255.0f), 0.0f, 255.0f)); } + + _FORCE_INLINE_ void set_h(float p_h) { set_hsv(p_h, get_s(), get_v(), a); } + _FORCE_INLINE_ void set_s(float p_s) { set_hsv(get_h(), p_s, get_v(), a); } + _FORCE_INLINE_ void set_v(float p_v) { set_hsv(get_h(), get_s(), p_v, a); } + + /** + * No construct parameters, r=0, g=0, b=0. a=255 + */ + _FORCE_INLINE_ Color() { + r = 0; + g = 0; + b = 0; + a = 1.0; + } + + /** + * RGB / RGBA construct parameters. Alpha is optional, but defaults to 1.0 + */ + _FORCE_INLINE_ Color(float p_r, float p_g, float p_b, float p_a = 1.0) { + r = p_r; + g = p_g; + b = p_b; + a = p_a; + } + + /** + * Construct a Color from another Color, but with the specified alpha value. + */ + _FORCE_INLINE_ Color(const Color &p_c, float p_a) { + r = p_c.r; + g = p_c.g; + b = p_c.b; + a = p_a; + } +}; + +bool Color::operator<(const Color &p_color) const { + if (r == p_color.r) { + if (g == p_color.g) { + if (b == p_color.b) { + return (a < p_color.a); + } else { + return (b < p_color.b); + } + } else { + return g < p_color.g; + } + } else { + return r < p_color.r; + } +} + +//--STRIP +#endif +//--STRIP diff --git a/sfwl/core/cowdata.h b/sfwl/core/cowdata.h index b9ac1aa..416a4ac 100644 --- a/sfwl/core/cowdata.h +++ b/sfwl/core/cowdata.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef COWDATA_H_ #define COWDATA_H_ +//--STRIP /*************************************************************************/ /* cowdata.h */ @@ -368,4 +370,6 @@ CowData::~CowData() { _unref(_ptr); } +//--STRIP #endif /* COW_H_ */ +//--STRIP diff --git a/sfwl/core/dir_access.cpp b/sfwl/core/dir_access.cpp index d1085f1..7584b0b 100644 --- a/sfwl/core/dir_access.cpp +++ b/sfwl/core/dir_access.cpp @@ -2,144 +2,1195 @@ //--STRIP #include "dir_access.h" -#include "3rd_tinydir.h" #include //--STRIP -Error DirAccess::open_dir(const String &path, bool skip_specials) { - if (_dir_open) { - return ERR_CANT_ACQUIRE_RESOURCE; - } +/*************************************************************************/ +/* dir_access.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ +//--STRIP +#include "dir_access.h" + +#include "core/list.h" + +#include "core/file_access.h" +#include "core/local_vector.h" +#include "core/memory.h" +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) + +#include +#include +#define WIN32_LEAN_AND_MEAN +#include + +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_MNTENT +#include +#endif + +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "Shlwapi") +#endif + +#if defined(_WIN64) || defined(_WIN32) + +bool DirAccess::is_link(String p_file) { + return false; +}; +String DirAccess::read_link(String p_file) { + return p_file; +}; +Error DirAccess::create_link(String p_source, String p_target) { + return FAILED; +}; + +/* + +[03:57] yessopie, so i don't havemak to rely on unicows +[03:58] reduz- yeah, all of the functions fail, and then you can call GetLastError () which will return 120 +[03:58] CategoryApl, hehe, what? :) +[03:59] didn't Verona lead to some trouble +[03:59] 120 = ERROR_CALL_NOT_IMPLEMENTED +[03:59] (you can use that constant if you include winerr.h) +[03:59] well answer with winning a compo + +[04:02] if ( SetCurrentDirectoryW ( L"." ) == FALSE && GetLastError () == ERROR_CALL_NOT_IMPLEMENTED ) { use ANSI } +*/ + +struct DirAccessWindowsPrivate { + HANDLE h; //handle for findfirstfile + WIN32_FIND_DATA f; + WIN32_FIND_DATAW fu; //unicode version +}; + +// CreateFolderAsync + +Error DirAccess::list_dir_begin(bool skip_specials) { + _cisdir = false; + _cishidden = false; _skip_specials = skip_specials; - if (tinydir_open(_dir, path.utf8().get_data()) == -1) { + list_dir_end(); + p->h = FindFirstFileExW((LPCWSTR)(String(current_dir + "\\*").utf16().get_data()), FindExInfoStandard, &p->fu, FindExSearchNameMatch, NULL, 0); + + return (p->h == INVALID_HANDLE_VALUE) ? ERR_CANT_OPEN : OK; +} + +String DirAccess::get_next() { + if (p->h == INVALID_HANDLE_VALUE) { + return ""; + } + + _cisdir = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + _cishidden = (p->fu.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN); + + String name = String::utf16((const char16_t *)(p->fu.cFileName)); + + if (FindNextFileW(p->h, &p->fu) == 0) { + FindClose(p->h); + p->h = INVALID_HANDLE_VALUE; + } + + return name; +} + +bool DirAccess::current_is_dir() const { + return _cisdir; +} + +bool DirAccess::current_is_hidden() const { + return _cishidden; +} + +bool DirAccess::current_is_file() const { + return !_cisdir; +} + +bool DirAccess::current_is_special_dir() const { + return _cisspecial; +} + +void DirAccess::list_dir_end() { + if (p->h != INVALID_HANDLE_VALUE) { + FindClose(p->h); + p->h = INVALID_HANDLE_VALUE; + } +} +int DirAccess::get_drive_count() { + return drive_count; +} +String DirAccess::get_drive(int p_drive) { + if (p_drive < 0 || p_drive >= drive_count) { + return ""; + } + + return String::chr(drives[p_drive]) + ":"; +} + +Error DirAccess::change_dir(String p_dir) { + GLOBAL_LOCK_FUNCTION + + WCHAR real_current_dir_name[2048]; + GetCurrentDirectoryW(2048, real_current_dir_name); + String prev_dir = String::utf16((const char16_t *)real_current_dir_name); + + SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data())); + bool worked = (SetCurrentDirectoryW((LPCWSTR)(p_dir.utf16().get_data())) != 0); + + String base; + if (base != "") { + GetCurrentDirectoryW(2048, real_current_dir_name); + String new_dir = String::utf16((const char16_t *)real_current_dir_name).replace("\\", "/"); + if (!new_dir.begins_with(base)) { + worked = false; + } + } + + if (worked) { + GetCurrentDirectoryW(2048, real_current_dir_name); + current_dir = String::utf16((const char16_t *)real_current_dir_name); + current_dir = current_dir.replace("\\", "/"); + } + + SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data())); + + return worked ? OK : ERR_INVALID_PARAMETER; +} + +Error DirAccess::make_dir(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = current_dir.plus_file(p_dir); + } + + p_dir = p_dir.simplify_path().replace("/", "\\"); + + bool success; + int err; + + if (!p_dir.is_network_share_path()) { + p_dir = "\\\\?\\" + p_dir; + // Add "\\?\" to the path to extend max. path length past 248, if it's not a network share UNC path. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx + } + + success = CreateDirectoryW((LPCWSTR)(p_dir.utf16().get_data()), NULL); + err = GetLastError(); + + if (success) { + return OK; + } + + if (err == ERROR_ALREADY_EXISTS || err == ERROR_ACCESS_DENIED) { + return ERR_ALREADY_EXISTS; + } + + return ERR_CANT_CREATE; +} + +String DirAccess::get_current_dir() { + String base; + if (base != "") { + String bd = current_dir.replace("\\", "/").replace_first(base, ""); + if (bd.begins_with("/")) { + return bd.substr(1, bd.length()); + } else { + return bd; + } + } + + return current_dir; +} + +String DirAccess::get_current_dir_without_drive() { + String dir = get_current_dir(); + + int p = current_dir.find(":"); + if (p != -1) { + dir = dir.right(p + 1); + } + + return dir; +} + +bool DirAccess::file_exists(String p_file) { + GLOBAL_LOCK_FUNCTION + + if (!p_file.is_abs_path()) { + p_file = get_current_dir().plus_file(p_file); + } + + DWORD fileAttr; + + fileAttr = GetFileAttributesW((LPCWSTR)(p_file.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { + return false; + } + + return !(fileAttr & FILE_ATTRIBUTE_DIRECTORY); +} + +bool DirAccess::dir_exists(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = get_current_dir().plus_file(p_dir); + } + + DWORD fileAttr; + + fileAttr = GetFileAttributesW((LPCWSTR)(p_dir.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { + return false; + } + + return (fileAttr & FILE_ATTRIBUTE_DIRECTORY); +} + +Error DirAccess::rename(String p_path, String p_new_path) { + if (p_path.is_rel_path()) { + p_path = get_current_dir().plus_file(p_path); + } + + if (p_new_path.is_rel_path()) { + p_new_path = get_current_dir().plus_file(p_new_path); + } + + // If we're only changing file name case we need to do a little juggling + if (p_path.to_lower() == p_new_path.to_lower()) { + if (dir_exists(p_path)) { + // The path is a dir; just rename + return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + } + + // The path is a file; juggle + WCHAR tmpfile[MAX_PATH]; + + if (!GetTempFileNameW((LPCWSTR)(get_current_dir().utf16().get_data()), NULL, 0, tmpfile)) { + return FAILED; + } + + if (!::ReplaceFileW(tmpfile, (LPCWSTR)(p_path.utf16().get_data()), NULL, 0, NULL, NULL)) { + DeleteFileW(tmpfile); + return FAILED; + } + + return ::_wrename(tmpfile, (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + + } else { + if (file_exists(p_new_path)) { + if (remove(p_new_path) != OK) { + return FAILED; + } + } + + return ::_wrename((LPCWSTR)(p_path.utf16().get_data()), (LPCWSTR)(p_new_path.utf16().get_data())) == 0 ? OK : FAILED; + } +} + +Error DirAccess::remove(String p_path) { + if (p_path.is_rel_path()) { + p_path = get_current_dir().plus_file(p_path); + } + + DWORD fileAttr; + + fileAttr = GetFileAttributesW((LPCWSTR)(p_path.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { return FAILED; } - _dir_open = true; - - return OK; + if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY)) { + return ::_wrmdir((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + } else { + return ::_wunlink((LPCWSTR)(p_path.utf16().get_data())) == 0 ? OK : FAILED; + } } +/* -Error DirAccess::open_dir(const char *path, bool skip_specials) { - if (_dir_open) { - return ERR_CANT_ACQUIRE_RESOURCE; +FileType DirAccess::get_file_type(const String& p_file) const { + WCHAR real_current_dir_name[2048]; + GetCurrentDirectoryW(2048, real_current_dir_name); + String prev_dir = Strong::utf16((const char16_t *)real_current_dir_name); + + bool worked = SetCurrentDirectoryW((LPCWSTR)(current_dir.utf16().get_data())); + + DWORD attr; + if (worked) { + WIN32_FILE_ATTRIBUTE_DATA fileInfo; + attr = GetFileAttributesExW((LPCWSTR)(p_file.utf16().get_data()), GetFileExInfoStandard, &fileInfo); } - _skip_specials = skip_specials; + SetCurrentDirectoryW((LPCWSTR)(prev_dir.utf16().get_data())); - if (tinydir_open(_dir, path) == -1) { - return FAILED; + if (!worked) { + return FILE_TYPE_NONE; } - _dir_open = true; - - return OK; + return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FILE_TYPE_ } +*/ -void DirAccess::close_dir() { - if (!_dir_open) { - return; +uint64_t DirAccess::get_space_left() { + uint64_t bytes = 0; + + if (!GetDiskFreeSpaceEx(NULL, (PULARGE_INTEGER)&bytes, NULL, NULL)) { + return 0; } - tinydir_close(_dir); - - _dir_open = false; + //this is either 0 or a value in bytes. + return bytes; } -bool DirAccess::has_next() { - if (!_dir) { - return false; +String DirAccess::get_filesystem_type() const { + String path = const_cast(this)->get_current_dir(); + + if (path.is_network_share_path()) { + return "Network Share"; } - return _dir->has_next; -} -bool DirAccess::read() { - _read_file_result = tinydir_readfile(_dir, _file); + int unit_end = path.find(":"); + ERR_FAIL_COND_V(unit_end == -1, String()); + String unit = path.substr(0, unit_end + 1) + "\\"; - return _read_file_result != -1; -} -bool DirAccess::next() { - if (!_dir->has_next) { - return false; + WCHAR szVolumeName[100]; + WCHAR szFileSystemName[10]; + DWORD dwSerialNumber = 0; + DWORD dwMaxFileNameLength = 0; + DWORD dwFileSystemFlags = 0; + + if (::GetVolumeInformationW((LPCWSTR)(unit.utf16().get_data()), + szVolumeName, + sizeof(szVolumeName), + &dwSerialNumber, + &dwMaxFileNameLength, + &dwFileSystemFlags, + szFileSystemName, + sizeof(szFileSystemName)) == TRUE) { + return String::utf16((const char16_t *)szFileSystemName); } - bool rres = read(); - while (!rres && _dir->has_next) { - tinydir_next(_dir); - rres = read(); + ERR_FAIL_V(""); +} + +int DirAccess::get_current_drive() { + String path = get_current_dir().to_lower(); + for (int i = 0; i < get_drive_count(); i++) { + String d = get_drive(i).to_lower(); + if (path.begins_with(d)) { + return i; + } } - if (!rres) { - return false; - } - - if (_dir->has_next) { - tinydir_next(_dir); - } - - if (_skip_specials && current_is_dir() && current_is_special_dir()) { - return next(); - } - - return true; + return 0; } -bool DirAccess::current_is_ok() { - return _read_file_result == 01; -} -String DirAccess::current_get_name() { - return String(_file->name); -} -String DirAccess::current_get_path() { - return String(_file->path); -} -String DirAccess::current_get_extension() { - return String(_file->extension); -} -const char *DirAccess::current_get_name_cstr() { - return _file->name; -} -const char *DirAccess::current_get_path_cstr() { - return _file->path; -} -const char *DirAccess::current_get_extension_cstr() { - return _file->extension; -} -bool DirAccess::current_is_file() { - return !_file->is_dir; -} -bool DirAccess::current_is_dir() { - return _file->is_dir; -} -bool DirAccess::current_is_special_dir() { - if ((_file->name[0] == '.' && _file->name[1] == '\0') || (_file->name[0] == '.' && _file->name[1] == '.')) { - return true; - } - +bool DirAccess::drives_are_shortcuts() { return false; } -bool DirAccess::is_dir_open() { - return _dir_open; +uint64_t DirAccess::get_modified_time(String p_file) { + return 0; +}; + +DirAccess::DirAccess() { + p = memnew(DirAccessWindowsPrivate); + p->h = INVALID_HANDLE_VALUE; + current_dir = "."; + + drive_count = 0; + +#ifdef UWP_ENABLED + Windows::Storage::StorageFolder ^ install_folder = Windows::ApplicationModel::Package::Current->InstalledLocation; + change_dir(install_folder->Path->Data()); + +#else + + DWORD mask = GetLogicalDrives(); + + for (int i = 0; i < MAX_DRIVES; i++) { + if (mask & (1 << i)) { //DRIVE EXISTS + + drives[drive_count] = 'A' + i; + drive_count++; + } + } + + change_dir("."); +#endif } -bool DirAccess::is_dir_closed() { - return !_dir_open; + +DirAccess::~DirAccess() { + list_dir_end(); + + memdelete(p); +} + +#else + +Error DirAccess::list_dir_begin(bool skip_specials) { + list_dir_end(); //close any previous dir opening! + + _skip_specials = skip_specials; + + //char real_current_dir_name[2048]; //is this enough?! + //getcwd(real_current_dir_name,2048); + //chdir(current_path.utf8().get_data()); + dir_stream = opendir(current_dir.utf8().get_data()); + //chdir(real_current_dir_name); + if (!dir_stream) { + return ERR_CANT_OPEN; //error! + } + + return OK; +} + +bool DirAccess::file_exists(String p_file) { + GLOBAL_LOCK_FUNCTION + + if (p_file.is_rel_path()) { + p_file = current_dir.plus_file(p_file); + } + + struct stat flags; + bool success = (stat(p_file.utf8().get_data(), &flags) == 0); + + if (success && S_ISDIR(flags.st_mode)) { + success = false; + } + + return success; +} + +bool DirAccess::dir_exists(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = get_current_dir().plus_file(p_dir); + } + + struct stat flags; + bool success = (stat(p_dir.utf8().get_data(), &flags) == 0); + + return (success && S_ISDIR(flags.st_mode)); +} + +uint64_t DirAccess::get_modified_time(String p_file) { + if (p_file.is_rel_path()) { + p_file = current_dir.plus_file(p_file); + } + + struct stat flags; + bool success = (stat(p_file.utf8().get_data(), &flags) == 0); + + if (success) { + return flags.st_mtime; + } else { + ERR_FAIL_V(0); + }; + return 0; +}; + +String DirAccess::get_next() { + if (!dir_stream) { + return ""; + } + + dirent *entry = readdir(dir_stream); + + if (entry == nullptr) { + list_dir_end(); + return ""; + } + + String fname = fix_unicode_name(entry->d_name); + + // Look at d_type to determine if the entry is a directory, unless + // its type is unknown (the file system does not support it) or if + // the type is a link, in that case we want to resolve the link to + // known if it points to a directory. stat() will resolve the link + // for us. + if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) { + String f = current_dir.plus_file(fname); + + struct stat flags; + if (stat(f.utf8().get_data(), &flags) == 0) { + _cisdir = S_ISDIR(flags.st_mode); + } else { + _cisdir = false; + } + } else { + _cisdir = (entry->d_type == DT_DIR); + } + + _cishidden = is_hidden(fname); + + _cisspecial = is_special(fname); + + if (_skip_specials && _cisspecial) { + // Should only happen 2 times max + return get_next(); + } + + return fname; +} + +bool DirAccess::current_is_dir() const { + return _cisdir; +} + +bool DirAccess::current_is_file() const { + return !_cisdir; +} + +bool DirAccess::current_is_special_dir() const { + return _cisspecial; +} + +bool DirAccess::current_is_hidden() const { + return _cishidden; +} + +void DirAccess::list_dir_end() { + if (dir_stream) { + closedir(dir_stream); + } + dir_stream = nullptr; + _cisdir = false; +} + +#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +static bool _filter_drive(struct mntent *mnt) { + // Ignore devices that don't point to /dev + if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) { + return false; + } + + // Accept devices mounted at common locations + if (strncmp(mnt->mnt_dir, "/media", 6) == 0 || + strncmp(mnt->mnt_dir, "/mnt", 4) == 0 || + strncmp(mnt->mnt_dir, "/home", 5) == 0 || + strncmp(mnt->mnt_dir, "/run/media", 10) == 0) { + return true; + } + + // Ignore everything else + return false; +} +#endif + +static void _get_drives(List *list) { + list->push_back("/"); + +#if defined(HAVE_MNTENT) && defined(X11_ENABLED) + // Check /etc/mtab for the list of mounted partitions + FILE *mtab = setmntent("/etc/mtab", "r"); + if (mtab) { + struct mntent mnt; + char strings[4096]; + + while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) { + if (mnt.mnt_dir != nullptr && _filter_drive(&mnt)) { + // Avoid duplicates + if (!list->find(mnt.mnt_dir)) { + list->push_back(mnt.mnt_dir); + } + } + } + + endmntent(mtab); + } +#endif + + // Add $HOME + const char *home = getenv("HOME"); + if (home) { + // Only add if it's not a duplicate + if (!list->find(home)) { + list->push_back(home); + } + + // Check $HOME/.config/gtk-3.0/bookmarks + char path[1024]; + snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home); + FILE *fd = fopen(path, "r"); + if (fd) { + char string[1024]; + while (fgets(string, 1024, fd)) { + // Parse only file:// links + if (strncmp(string, "file://", 7) == 0) { + // Strip any unwanted edges on the strings and push_back if it's not a duplicate + String fpath = String(string + 7).strip_edges().split_spaces()[0].percent_decode(); + if (!list->find(fpath)) { + list->push_back(fpath); + } + } + } + + fclose(fd); + } + } + + list->sort(); +} + +int DirAccess::get_drive_count() { + List list; + _get_drives(&list); + + return list.size(); +} + +String DirAccess::get_drive(int p_drive) { + List list; + _get_drives(&list); + + ERR_FAIL_INDEX_V(p_drive, list.size(), ""); + + return list[p_drive]; +} + +int DirAccess::get_current_drive() { + int drive = 0; + int max_length = -1; + const String path = get_current_dir().to_lower(); + for (int i = 0; i < get_drive_count(); i++) { + const String d = get_drive(i).to_lower(); + if (max_length < d.length() && path.begins_with(d)) { + max_length = d.length(); + drive = i; + } + } + return drive; +} + +bool DirAccess::drives_are_shortcuts() { + return true; +} + +Error DirAccess::make_dir(String p_dir) { + GLOBAL_LOCK_FUNCTION + + if (p_dir.is_rel_path()) { + p_dir = get_current_dir().plus_file(p_dir); + } + + bool success = (mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0); + int err = errno; + + if (success) { + return OK; + }; + + if (err == EEXIST) { + return ERR_ALREADY_EXISTS; + }; + + return ERR_CANT_CREATE; +} + +Error DirAccess::change_dir(String p_dir) { + GLOBAL_LOCK_FUNCTION + + // prev_dir is the directory we are changing out of + String prev_dir; + char real_current_dir_name[2048]; + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); + if (prev_dir.parse_utf8(real_current_dir_name)) { + prev_dir = real_current_dir_name; //no utf8, maybe latin? + } + + // try_dir is the directory we are trying to change into + String try_dir = ""; + if (p_dir.is_rel_path()) { + String next_dir = current_dir.plus_file(p_dir); + next_dir = next_dir.simplify_path(); + try_dir = next_dir; + } else { + try_dir = p_dir; + } + + bool worked = (chdir(try_dir.utf8().get_data()) == 0); // we can only give this utf8 + if (!worked) { + return ERR_INVALID_PARAMETER; + } + + String base; + if (base != String() && !try_dir.begins_with(base)) { + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == nullptr, ERR_BUG); + String new_dir; + new_dir.parse_utf8(real_current_dir_name); + + if (!new_dir.begins_with(base)) { + try_dir = current_dir; //revert + } + } + + // the directory exists, so set current_dir to try_dir + current_dir = try_dir; + ERR_FAIL_COND_V(chdir(prev_dir.utf8().get_data()) != 0, ERR_BUG); + return OK; +} + +String DirAccess::get_current_dir() { + String base; + if (base != "") { + String bd = current_dir.replace_first(base, ""); + if (bd.begins_with("/")) { + return bd.substr(1, bd.length()); + } else { + return bd; + } + } + return current_dir; +} + +Error DirAccess::rename(String p_path, String p_new_path) { + if (p_path.is_rel_path()) { + p_path = get_current_dir().plus_file(p_path); + } + + if (p_new_path.is_rel_path()) { + p_new_path = get_current_dir().plus_file(p_new_path); + } + + return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED; +} + +Error DirAccess::remove(String p_path) { + if (p_path.is_rel_path()) { + p_path = get_current_dir().plus_file(p_path); + } + + struct stat flags; + if ((stat(p_path.utf8().get_data(), &flags) != 0)) { + return FAILED; + } + + if (S_ISDIR(flags.st_mode)) { + return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED; + } else { + return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED; + } +} + +bool DirAccess::is_link(String p_file) { + if (p_file.is_rel_path()) { + p_file = get_current_dir().plus_file(p_file); + } + + struct stat flags; + if ((lstat(p_file.utf8().get_data(), &flags) != 0)) { + return FAILED; + } + + return S_ISLNK(flags.st_mode); +} + +String DirAccess::read_link(String p_file) { + if (p_file.is_rel_path()) { + p_file = get_current_dir().plus_file(p_file); + } + + char buf[256]; + memset(buf, 0, 256); + ssize_t len = readlink(p_file.utf8().get_data(), buf, sizeof(buf)); + String link; + if (len > 0) { + link.parse_utf8(buf, len); + } + return link; +} + +Error DirAccess::create_link(String p_source, String p_target) { + if (p_target.is_rel_path()) { + p_target = get_current_dir().plus_file(p_target); + } + + if (symlink(p_source.utf8().get_data(), p_target.utf8().get_data()) == 0) { + return OK; + } else { + return FAILED; + } +} + +uint64_t DirAccess::get_space_left() { +#ifndef NO_STATVFS + struct statvfs vfs; + if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) { + return 0; + }; + + return (uint64_t)vfs.f_bavail * (uint64_t)vfs.f_frsize; +#else + // FIXME: Implement this. + return 0; +#endif +}; + +String DirAccess::get_filesystem_type() const { + return ""; //TODO this should be implemented +} + +bool DirAccess::is_hidden(const String &p_name) { + return p_name != "." && p_name != ".." && p_name.begins_with("."); +} + +String DirAccess::get_current_dir_without_drive() { + return get_current_dir(); } DirAccess::DirAccess() { - _skip_specials = true; - _read_file_result = 0; - _dir_open = false; - _dir = memnew(tinydir_dir); - _file = memnew(tinydir_file); -} -DirAccess::~DirAccess() { - if (is_dir_open()) { - close_dir(); + dir_stream = NULL; + _cisdir = false; + + next_is_dir = false; + _skip_specials = false; + + _cishidden = false; + _cisspecial = false; + + /* determine drive count */ + + // set current directory to an absolute path of the current directory + char real_current_dir_name[2048]; + ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == nullptr); + if (current_dir.parse_utf8(real_current_dir_name)) { + current_dir = real_current_dir_name; } - memdelete(_dir); - memdelete(_file); + change_dir(current_dir); +} + +DirAccess::~DirAccess() { + list_dir_end(); +} + +#endif + +static Error _erase_recursive(DirAccess *da) { + List dirs; + List files; + + da->list_dir_begin(); + String n = da->get_next(); + while (n != String()) { + if (n != "." && n != "..") { + if (da->current_is_dir()) { + dirs.push_back(n); + } else { + files.push_back(n); + } + } + + n = da->get_next(); + } + + da->list_dir_end(); + + for (List::Element *E = dirs.front(); E; E = E->next()) { + Error err = da->change_dir(E->get()); + if (err == OK) { + err = _erase_recursive(da); + if (err) { + da->change_dir(".."); + return err; + } + err = da->change_dir(".."); + if (err) { + return err; + } + err = da->remove(da->get_current_dir().plus_file(E->get())); + if (err) { + return err; + } + } else { + return err; + } + } + + for (List::Element *E = files.front(); E; E = E->next()) { + Error err = da->remove(da->get_current_dir().plus_file(E->get())); + if (err) { + return err; + } + } + + return OK; +} + +Error DirAccess::erase_contents_recursive() { + return _erase_recursive(this); +} + +Error DirAccess::make_dir_recursive(String p_dir) { + if (p_dir.length() < 1) { + return OK; + }; + + String full_dir; + + if (p_dir.is_rel_path()) { + //append current + full_dir = get_current_dir().plus_file(p_dir); + + } else { + full_dir = p_dir; + } + + full_dir = full_dir.replace("\\", "/"); + + String base; + + if (full_dir.is_network_share_path()) { + int pos = full_dir.find("/", 2); + ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); + pos = full_dir.find("/", pos + 1); + ERR_FAIL_COND_V(pos < 0, ERR_INVALID_PARAMETER); + base = full_dir.substr(0, pos + 1); + } else if (full_dir.begins_with("/")) { + base = "/"; + } else if (full_dir.find(":/") != -1) { + base = full_dir.substr(0, full_dir.find(":/") + 2); + } else { + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } + + full_dir = full_dir.replace_first(base, "").simplify_path(); + + Vector subdirs = full_dir.split("/"); + + String curpath = base; + for (int i = 0; i < subdirs.size(); i++) { + curpath = curpath.plus_file(subdirs[i]); + Error err = make_dir(curpath); + if (err != OK && err != ERR_ALREADY_EXISTS) { + ERR_FAIL_V_MSG(err, "Could not create directory: " + curpath); + } + } + + return OK; +} + +DirAccess *DirAccess::create_for_path(const String &p_path) { + DirAccess *d = memnew(DirAccess()); + d->open(p_path); + return d; +} +DirAccess *DirAccess::create() { + return memnew(DirAccess()); +} + +Error DirAccess::open(const String &p_path) { + return change_dir(p_path); +} + +String DirAccess::get_full_path(const String &p_path) { + DirAccess d; + + d.change_dir(p_path); + String full = d.get_current_dir(); + + return full; +} + +Error DirAccess::copy(String p_from, String p_to, int p_chmod_flags) { + //printf("copy %s -> %s\n",p_from.ascii().get_data(),p_to.ascii().get_data()); + Error err; + FileAccess *fsrc = FileAccess::create_and_open(p_from, FileAccess::READ, &err); + + if (err) { + ERR_PRINT("Failed to open " + p_from); + return err; + } + + FileAccess *fdst = FileAccess::create_and_open(p_to, FileAccess::WRITE, &err); + if (err) { + fsrc->close(); + memdelete(fsrc); + ERR_PRINT("Failed to open " + p_to); + return err; + } + + const size_t copy_buffer_limit = 65536; // 64 KB + + fsrc->seek_end(0); + uint64_t size = fsrc->get_position(); + fsrc->seek(0); + err = OK; + size_t buffer_size = MIN(size * sizeof(uint8_t), copy_buffer_limit); + LocalVector buffer; + buffer.resize(buffer_size); + while (size > 0) { + if (fsrc->get_error() != OK) { + err = fsrc->get_error(); + break; + } + if (fdst->get_error() != OK) { + err = fdst->get_error(); + break; + } + + int bytes_read = fsrc->get_buffer(buffer.ptr(), buffer_size); + if (bytes_read <= 0) { + err = FAILED; + break; + } + fdst->store_buffer(buffer.ptr(), bytes_read); + + size -= bytes_read; + } + + if (err == OK && p_chmod_flags != -1) { + fdst->close(); + err = FileAccess::set_unix_permissions(p_to, p_chmod_flags); + // If running on a platform with no chmod support (i.e., Windows), don't fail + if (err == ERR_UNAVAILABLE) { + err = OK; + } + } + + memdelete(fsrc); + memdelete(fdst); + + return err; +} + +// Changes dir for the current scope, returning back to the original dir +// when scope exits +class DirChanger { + DirAccess *da; + String original_dir; + +public: + DirChanger(DirAccess *p_da, String p_dir) : + da(p_da), + original_dir(p_da->get_current_dir()) { + p_da->change_dir(p_dir); + } + + ~DirChanger() { + da->change_dir(original_dir); + } +}; + +Error DirAccess::_copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links) { + List dirs; + + String curdir = get_current_dir(); + list_dir_begin(); + String n = get_next(); + while (n != String()) { + if (n != "." && n != "..") { + if (p_copy_links && is_link(get_current_dir().plus_file(n))) { + create_link(read_link(get_current_dir().plus_file(n)), p_to + n); + } else if (current_is_dir()) { + dirs.push_back(n); + } else { + const String &rel_path = n; + if (!n.is_rel_path()) { + list_dir_end(); + return ERR_BUG; + } + Error err = copy(get_current_dir().plus_file(n), p_to + rel_path, p_chmod_flags); + if (err) { + list_dir_end(); + return err; + } + } + } + + n = get_next(); + } + + list_dir_end(); + + for (List::Element *E = dirs.front(); E; E = E->next()) { + String rel_path = E->get(); + String target_dir = p_to + rel_path; + if (!p_target_da->dir_exists(target_dir)) { + Error err = p_target_da->make_dir(target_dir); + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + target_dir + "'."); + } + + Error err = change_dir(E->get()); + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot change current directory to '" + E->get() + "'."); + + err = _copy_dir(p_target_da, p_to + rel_path + "/", p_chmod_flags, p_copy_links); + if (err) { + change_dir(".."); + ERR_FAIL_V_MSG(err, "Failed to copy recursively."); + } + err = change_dir(".."); + ERR_FAIL_COND_V_MSG(err != OK, err, "Failed to go back."); + } + + return OK; +} + +Error DirAccess::copy_dir(String p_from, String p_to, int p_chmod_flags, bool p_copy_links) { + ERR_FAIL_COND_V_MSG(!dir_exists(p_from), ERR_FILE_NOT_FOUND, "Source directory doesn't exist."); + + DirAccess *target_da = DirAccess::create_for_path(p_to); + ERR_FAIL_COND_V_MSG(!target_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_to + "'."); + + if (!target_da->dir_exists(p_to)) { + Error err = target_da->make_dir_recursive(p_to); + if (err) { + memdelete(target_da); + } + ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot create directory '" + p_to + "'."); + } + + if (!p_to.ends_with("/")) { + p_to = p_to + "/"; + } + + DirChanger dir_changer(this, p_from); + Error err = _copy_dir(target_da, p_to, p_chmod_flags, p_copy_links); + memdelete(target_da); + + return err; +} + +bool DirAccess::exists(String p_dir) { + DirAccess *da = DirAccess::create_for_path(p_dir); + bool valid = da->change_dir(p_dir) == OK; + memdelete(da); + return valid; +} + +String DirAccess::get_filesystem_abspath_for(String p_path) { + DirAccess d; + + d.change_dir(p_path); + String full = d.get_current_dir(); + + return full; +} + +bool DirAccess::is_special(const String &p_path) { + if (p_path.size() > 2) { + return false; + } + + return p_path == "." || p_path == ".."; } diff --git a/sfwl/core/dir_access.h b/sfwl/core/dir_access.h index f747c0c..36bc93d 100644 --- a/sfwl/core/dir_access.h +++ b/sfwl/core/dir_access.h @@ -1,49 +1,147 @@ - +//--STRIP #ifndef DIR_ACCESS_H #define DIR_ACCESS_H +//--STRIP + +/*************************************************************************/ +/* dir_access.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ //--STRIP #include "core/error_list.h" #include "core/ustring.h" //--STRIP -struct tinydir_file; -struct tinydir_dir; +#if defined(_WIN64) || defined(_WIN32) +struct DirAccessWindowsPrivate; + +#elif defined(__APPLE__) + +#include + +#else +struct __dirstream; +typedef struct __dirstream DIR; +#endif class DirAccess { + Error _copy_dir(DirAccess *p_target_da, String p_to, int p_chmod_flags, bool p_copy_links); + public: - Error open_dir(const String &path, bool skip_specials = true); - Error open_dir(const char *path, bool skip_specials = true); - void close_dir(); + virtual Error list_dir_begin(bool skip_specials = false); ///< This starts dir listing + virtual String get_next(); + virtual bool current_is_dir() const; + virtual bool current_is_hidden() const; + virtual bool current_is_file() const; + virtual bool current_is_special_dir() const; - bool has_next(); - bool read(); - bool next(); + virtual void list_dir_end(); ///< - bool current_is_ok(); - String current_get_name(); - String current_get_path(); - String current_get_extension(); - const char *current_get_name_cstr(); - const char *current_get_path_cstr(); - const char *current_get_extension_cstr(); - bool current_is_file(); - bool current_is_dir(); - bool current_is_special_dir(); + virtual int get_drive_count(); + virtual String get_drive(int p_drive); + virtual int get_current_drive(); + virtual bool drives_are_shortcuts(); - bool is_dir_open(); - bool is_dir_closed(); + virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success + virtual String get_current_dir(); ///< return current dir location + virtual String get_current_dir_without_drive(); + virtual Error make_dir(String p_dir); + virtual Error make_dir_recursive(String p_dir); + virtual Error erase_contents_recursive(); //super dangerous, use with care! + + virtual bool file_exists(String p_file); + virtual bool dir_exists(String p_dir); + static bool exists(String p_dir); + virtual uint64_t get_space_left(); + + Error copy_dir(String p_from, String p_to, int p_chmod_flags = -1, bool p_copy_links = false); + virtual Error copy(String p_from, String p_to, int p_chmod_flags = -1); + virtual Error rename(String p_from, String p_to); + virtual Error remove(String p_name); + + virtual bool is_link(String p_file); + virtual String read_link(String p_file); + virtual Error create_link(String p_source, String p_target); + + virtual uint64_t get_modified_time(String p_file); + + virtual String get_filesystem_type() const; + static String get_full_path(const String &p_path); + + static DirAccess *create_for_path(const String &p_path); + static DirAccess *create(); + + Error open(const String &p_path); + + static String get_filesystem_abspath_for(String p_path); + + static bool is_special(const String &p_path); DirAccess(); virtual ~DirAccess(); -private: - bool _skip_specials; - int _read_file_result; - tinydir_dir *_dir; - tinydir_file *_file; +protected: +#if defined(_WIN64) || defined(_WIN32) +#else + virtual String fix_unicode_name(const char *p_name) const { return String::utf8(p_name); } + virtual bool is_hidden(const String &p_name); +#endif - bool _dir_open; + bool next_is_dir; + bool _skip_specials; + +#if defined(_WIN64) || defined(_WIN32) + enum { + MAX_DRIVES = 26 + }; + + DirAccessWindowsPrivate *p; + /* Windows stuff */ + + char drives[MAX_DRIVES]; // a-z: + int drive_count; + + String current_dir; + + bool _cisdir; + bool _cishidden; + bool _cisspecial; +#else + String current_dir; + DIR *dir_stream; + + bool _cisdir; + bool _cishidden; + bool _cisspecial; +#endif }; +struct DirAccessRef { + DirAccess *f; + + _FORCE_INLINE_ bool is_null() const { return f == nullptr; } + _FORCE_INLINE_ bool is_valid() const { return f != nullptr; } + + _FORCE_INLINE_ operator bool() const { return f != nullptr; } + _FORCE_INLINE_ operator DirAccess *() { return f; } + + _FORCE_INLINE_ DirAccess *operator->() { + return f; + } + + DirAccessRef(DirAccess *fa) { f = fa; } + DirAccessRef(DirAccessRef &&other) { + f = other.f; + other.f = nullptr; + } + ~DirAccessRef() { + if (f) { + memdelete(f); + } + } +}; + +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/error_list.h b/sfwl/core/error_list.h index 521e534..848c268 100644 --- a/sfwl/core/error_list.h +++ b/sfwl/core/error_list.h @@ -3,8 +3,10 @@ /* From https://github.com/Relintai/pandemonium_engine (MIT) */ /*************************************************************************/ +//--STRIP #ifndef ERROR_LIST_H #define ERROR_LIST_H +//--STRIP /** Error List. Please never compare an error against FAILED * Either do result != OK , or !result. This way, Error fail @@ -65,4 +67,6 @@ enum Error { ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/error_macros.h b/sfwl/core/error_macros.h index 4733076..141adf4 100644 --- a/sfwl/core/error_macros.h +++ b/sfwl/core/error_macros.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef ERROR_MACROS_H #define ERROR_MACROS_H +//--STRIP //--STRIP #include "core/logger.h" @@ -247,7 +249,7 @@ _FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \ GENERATE_TRAP -#define CRASH_NOW(msg) \ +#define CRASH_NOW() \ RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "CRASH!"); \ GENERATE_TRAP @@ -291,4 +293,6 @@ _FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E #define DEV_CHECK_ONCE(m_cond) #endif +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/file_access.cpp b/sfwl/core/file_access.cpp index 454846b..aedb68e 100644 --- a/sfwl/core/file_access.cpp +++ b/sfwl/core/file_access.cpp @@ -1,98 +1,1160 @@ +/*************************************************************************/ +/* file_access.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + //--STRIP #include "file_access.h" +#include "core/marshalls.h" + #include //--STRIP +#if defined(_WIN64) || defined(_WIN32) -String FileAccess::read_file(const String &path) { - FILE *f = fopen(path.utf8().get_data(), "r"); +#include // _SH_DENYNO +#include +#define WIN32_LEAN_AND_MEAN +#include - ERR_FAIL_COND_V_MSG(!f, String(), "Error opening file! " + path); +#include +#include +#include +#include +#include - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); /* same as rewind(f); */ +#ifdef _MSC_VER +#define S_ISREG(m) ((m)&_S_IFREG) +#endif - CharString cs; - cs.resize(fsize + 1); // +1 for the null terminator +//--STRIP +#include "core/sfw_time.h" +//--STRIP - fread(cs.ptrw(), 1, fsize, f); - fclose(f); +#else - return String::utf8(cs.ptr()); +#include +#include +#include + +#include + +#include + +#ifdef MSVC +#define S_ISREG(m) ((m)&_S_IFREG) +#include +#endif +#ifndef S_ISREG +#define S_ISREG(m) ((m)&S_IFREG) +#endif + +#ifndef NO_FCNTL +#include +#else +#include +#endif + +#endif + +#if defined(_WIN64) || defined(_WIN32) + +void FileAccess::check_errors() const { + ERR_FAIL_COND(!f); + + if (feof(f)) { + last_error = ERR_FILE_EOF; + } } -Vector FileAccess::read_file_bin(const String &path) { - FILE *f = fopen(path.utf8().get_data(), "rb"); +Error FileAccess::_open(const String &p_path, int p_mode_flags) { + path_src = p_path; + path = fix_path(p_path); - Vector fd; - - ERR_FAIL_COND_V_MSG(!f, fd, "Error opening file! " + path); - - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); /* same as rewind(f); */ - - fd.resize(fsize); - - fread(fd.ptrw(), 1, fsize, f); - fclose(f); - - return fd; -} - -Error FileAccess::read_file_into_bin(const String &path, Vector *data) { - if (!data) { - return ERR_PARAMETER_RANGE_ERROR; + if (f) { + close(); } - FILE *f = fopen(path.utf8().get_data(), "rb"); + const WCHAR *mode_string; + if (p_mode_flags == READ) { + mode_string = L"rb"; + } else if (p_mode_flags == WRITE) { + mode_string = L"wb"; + } else if (p_mode_flags == READ_WRITE) { + mode_string = L"rb+"; + } else if (p_mode_flags == WRITE_READ) { + mode_string = L"wb+"; + } else { + return ERR_INVALID_PARAMETER; + } + + /* pretty much every implementation that uses fopen as primary + backend supports utf8 encoding */ + + struct _stat st; + if (_wstat((LPCWSTR)(path.utf16().get_data()), &st) == 0) { + if (!S_ISREG(st.st_mode)) { + return ERR_FILE_CANT_OPEN; + } + }; + +#ifdef TOOLS_ENABLED + // Windows is case insensitive, but all other platforms are sensitive to it + // To ease cross-platform development, we issue a warning if users try to access + // a file using the wrong case (which *works* on Windows, but won't on other + // platforms). + if (p_mode_flags == READ) { + WIN32_FIND_DATAW d; + HANDLE f = FindFirstFileW((LPCWSTR)(path.utf16().get_data()), &d); + + if (f != INVALID_HANDLE_VALUE) { + String fname = String::utf16((const char16_t *)(d.cFileName)); + + if (fname != String()) { + String base_file = path.get_file(); + if (base_file != fname && base_file.findn(fname) == 0) { + WARN_PRINT("Case mismatch opening requested file '" + base_file + "', stored as '" + fname + "' in the filesystem. This file will not open when exported to other case-sensitive platforms."); + } + } + + FindClose(f); + } + } +#endif + + if (is_backup_save_enabled() && p_mode_flags & WRITE && !(p_mode_flags & READ)) { + save_path = path; + path = path + ".tmp"; + } + + f = _wfsopen((LPCWSTR)(path.utf16().get_data()), mode_string, _SH_DENYNO); + + if (f == nullptr) { + switch (errno) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; + } else { + last_error = OK; + flags = p_mode_flags; + return OK; + } +} + +void FileAccess::close() { if (!f) { - return ERR_FILE_CANT_OPEN; + return; } - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); /* same as rewind(f); */ - - data->resize(fsize); - - fread(data->ptrw(), 1, fsize, f); fclose(f); + f = NULL; - return OK; + if (save_path != "") { + bool rename_error = true; + int attempts = 4; + while (rename_error && attempts) { + // This workaround of trying multiple times is added to deal with paranoid Windows + // antiviruses that love reading just written files even if they are not executable, thus + // locking the file and preventing renaming from happening. + +#ifdef UWP_ENABLED + // UWP has no PathFileExists, so we check attributes instead + DWORD fileAttr; + + fileAttr = GetFileAttributesW((LPCWSTR)(save_path.utf16().get_data())); + if (INVALID_FILE_ATTRIBUTES == fileAttr) { +#else + if (!PathFileExistsW((LPCWSTR)(save_path.utf16().get_data()))) { +#endif + //creating new file + rename_error = _wrename((LPCWSTR)((save_path + ".tmp").utf16().get_data()), (LPCWSTR)(save_path.utf16().get_data())) != 0; + } else { + //atomic replace for existing file + rename_error = !ReplaceFileW((LPCWSTR)(save_path.utf16().get_data()), (LPCWSTR)((save_path + ".tmp").utf16().get_data()), NULL, 2 | 4, NULL, NULL); + } + if (rename_error) { + attempts--; + SFWTime::sleep_us(100000); // wait 100msec and try again + } + } + + if (rename_error) { + if (close_fail_notify) { + close_fail_notify(save_path); + } + } + + save_path = ""; + + ERR_FAIL_COND_MSG(rename_error, "Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); + } } -Error FileAccess::write_file(const String &path, const String &str) { - FILE *f = fopen(path.utf8().get_data(), "w"); +String FileAccess::get_path() const { + return path_src; +} - if (!f) { - return ERR_FILE_CANT_OPEN; +String FileAccess::get_path_absolute() const { + return path; +} + +bool FileAccess::is_open() const { + return (f != NULL); +} + +void FileAccess::seek(uint64_t p_position) { + ERR_FAIL_COND(!f); + + last_error = OK; + + if (_fseeki64(f, p_position, SEEK_SET)) { + check_errors(); } - fwrite(str.utf8().ptr(), sizeof(char), str.size(), f); - fclose(f); - - return OK; + prev_op = 0; } -Error FileAccess::write_file_bin(const String &path, const Vector &data) { - FILE *f = fopen(path.utf8().get_data(), "wb"); +void FileAccess::seek_end(int64_t p_position) { + ERR_FAIL_COND(!f); - if (!f) { - return ERR_FILE_CANT_OPEN; + if (_fseeki64(f, p_position, SEEK_END)) { + check_errors(); } - fwrite(data.ptr(), sizeof(uint8_t), data.size(), f); - fclose(f); - - return OK; + prev_op = 0; } -FileAccess::FileAccess() { +uint64_t FileAccess::get_position() const { + int64_t aux_position = _ftelli64(f); + + if (aux_position < 0) { + check_errors(); + } + + return aux_position; +} + +uint64_t FileAccess::get_len() const { + ERR_FAIL_COND_V(!f, 0); + + uint64_t pos = get_position(); + _fseeki64(f, 0, SEEK_END); + uint64_t size = get_position(); + _fseeki64(f, pos, SEEK_SET); + + return size; +} + +bool FileAccess::eof_reached() const { + check_errors(); + return last_error == ERR_FILE_EOF; +} + +uint8_t FileAccess::get_8() const { + ERR_FAIL_COND_V(!f, 0); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } + uint8_t b; + if (fread(&b, 1, 1, f) == 0) { + check_errors(); + b = '\0'; + }; + + return b; +} + +uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + ERR_FAIL_COND_V(!f, -1); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } + uint64_t read = fread(p_dst, 1, p_length, f); + check_errors(); + return read; +}; + +Error FileAccess::get_error() const { + return last_error; +} + +void FileAccess::flush() { + ERR_FAIL_COND(!f); + fflush(f); + + if (prev_op == WRITE) { + prev_op = 0; + } +} + +void FileAccess::store_8(uint8_t p_dest) { + ERR_FAIL_COND(!f); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + fwrite(&p_dest, 1, 1, f); +} + +void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!f); + ERR_FAIL_COND(!p_src && p_length > 0); + + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != (size_t)p_length); +} + +bool FileAccess::file_exists(const String &p_name) { + String filename = fix_path(p_name); + + FILE *g = _wfsopen((LPCWSTR)(filename.utf16().get_data()), L"rb", _SH_DENYNO); + + if (g == nullptr) { + return false; + } else { + fclose(g); + return true; + } +} + +uint64_t FileAccess::_get_modified_time(const String &p_file) { + String file = fix_path(p_file); + if (file.ends_with("/") && file != "/") + file = file.substr(0, file.length() - 1); + + struct _stat st; + int rv = _wstat((LPCWSTR)(file.utf16().get_data()), &st); + + if (rv == 0) { + return st.st_mtime; + } else { + LOG_TRACE("Failed to get modified time for: " + p_file + ""); + return 0; + } +} + +uint32_t FileAccess::_get_unix_permissions(const String &p_file) { + return 0; +} + +Error FileAccess::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + return ERR_UNAVAILABLE; +} + +FileAccess::FileAccess() : + f(NULL), + flags(0), + prev_op(0), + last_error(OK) { } FileAccess::~FileAccess() { + close(); } + +#else + +void FileAccess::check_errors() const { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + + if (feof(f)) { + last_error = ERR_FILE_EOF; + } +} + +Error FileAccess::_open(const String &p_path, int p_mode_flags) { + if (f) { + fclose(f); + } + f = nullptr; + + path_src = p_path; + path = fix_path(p_path); + //printf("opening %s, %i\n", path.utf8().get_data(), Memory::get_static_mem_usage()); + + ERR_FAIL_COND_V_MSG(f, ERR_ALREADY_IN_USE, "File is already in use."); + const char *mode_string; + + if (p_mode_flags == READ) { + mode_string = "rb"; + } else if (p_mode_flags == WRITE) { + mode_string = "wb"; + } else if (p_mode_flags == READ_WRITE) { + mode_string = "rb+"; + } else if (p_mode_flags == WRITE_READ) { + mode_string = "wb+"; + } else { + return ERR_INVALID_PARAMETER; + } + + /* pretty much every implementation that uses fopen as primary + backend (unix-compatible mostly) supports utf8 encoding */ + + //printf("opening %s as %s\n", p_path.utf8().get_data(), path.utf8().get_data()); + struct stat st; + int err = stat(path.utf8().get_data(), &st); + if (!err) { + switch (st.st_mode & S_IFMT) { + case S_IFLNK: + case S_IFREG: + break; + default: + return ERR_FILE_CANT_OPEN; + } + } + + if (is_backup_save_enabled() && (p_mode_flags & WRITE) && !(p_mode_flags & READ)) { + save_path = path; + path = path + ".tmp"; + } + + f = fopen(path.utf8().get_data(), mode_string); + + if (f == nullptr) { + switch (errno) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; + } + + // Set close on exec to avoid leaking it to subprocesses. + int fd = fileno(f); + + if (fd != -1) { +#if defined(NO_FCNTL) + unsigned long par = 0; + ioctl(fd, FIOCLEX, &par); +#else + int opts = fcntl(fd, F_GETFD); + fcntl(fd, F_SETFD, opts | FD_CLOEXEC); +#endif + } + + last_error = OK; + flags = p_mode_flags; + return OK; +} + +void FileAccess::close() { + if (!f) { + return; + } + + fclose(f); + f = nullptr; + + if (close_notification_func) { + close_notification_func(path, flags); + } + + if (save_path != "") { + int rename_error = rename((save_path + ".tmp").utf8().get_data(), save_path.utf8().get_data()); + + if (rename_error && close_fail_notify) { + close_fail_notify(save_path); + } + + save_path = ""; + ERR_FAIL_COND(rename_error != 0); + } +} + +bool FileAccess::is_open() const { + return (f != nullptr); +} + +String FileAccess::get_path() const { + return path_src; +} + +String FileAccess::get_path_absolute() const { + return path; +} + +void FileAccess::seek(uint64_t p_position) { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + + last_error = OK; + if (fseeko(f, p_position, SEEK_SET)) { + check_errors(); + } +} + +void FileAccess::seek_end(int64_t p_position) { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + + if (fseeko(f, p_position, SEEK_END)) { + check_errors(); + } +} + +uint64_t FileAccess::get_position() const { + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + + int64_t pos = ftello(f); + if (pos < 0) { + check_errors(); + ERR_FAIL_V(0); + } + return pos; +} + +uint64_t FileAccess::get_len() const { + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + + int64_t pos = ftello(f); + ERR_FAIL_COND_V(pos < 0, 0); + ERR_FAIL_COND_V(fseeko(f, 0, SEEK_END), 0); + int64_t size = ftello(f); + ERR_FAIL_COND_V(size < 0, 0); + ERR_FAIL_COND_V(fseeko(f, pos, SEEK_SET), 0); + + return size; +} + +bool FileAccess::eof_reached() const { + return last_error == ERR_FILE_EOF; +} + +uint8_t FileAccess::get_8() const { + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); + uint8_t b; + if (fread(&b, 1, 1, f) == 0) { + check_errors(); + b = '\0'; + } + return b; +} + +uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use."); + + uint64_t read = fread(p_dst, 1, p_length, f); + check_errors(); + return read; +}; + +Error FileAccess::get_error() const { + return last_error; +} + +void FileAccess::flush() { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + fflush(f); +} + +void FileAccess::store_8(uint8_t p_dest) { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); +} + +void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND(!p_src && p_length > 0); + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); +} + +bool FileAccess::file_exists(const String &p_path) { + int err; + struct stat st; + String filename = fix_path(p_path); + + // Does the name exist at all? + err = stat(filename.utf8().get_data(), &st); + if (err) { + return false; + } + +#if defined(_WIN64) || defined(_WIN32) + if (_access(filename.utf8().get_data(), 4) == -1) { + return false; + } +#else + // See if we have access to the file + if (access(filename.utf8().get_data(), F_OK)) { + return false; + } +#endif + + // See if this is a regular file + switch (st.st_mode & S_IFMT) { + case S_IFLNK: + case S_IFREG: + return true; + default: + return false; + } +} + +uint64_t FileAccess::_get_modified_time(const String &p_file) { + String file = fix_path(p_file); + struct stat flags; + int err = stat(file.utf8().get_data(), &flags); + + if (!err) { + return flags.st_mtime; + } else { + LOG_TRACE("Failed to get modified time for: " + p_file + ""); + return 0; + }; +} + +uint32_t FileAccess::_get_unix_permissions(const String &p_file) { + String file = fix_path(p_file); + struct stat flags; + int err = stat(file.utf8().get_data(), &flags); + + if (!err) { + return flags.st_mode & 0x7FF; //only permissions + } else { + ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + "."); + }; +} + +Error FileAccess::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + String file = fix_path(p_file); + + int err = chmod(file.utf8().get_data(), p_permissions); + if (!err) { + return OK; + } + + return FAILED; +} + +FileCloseNotificationFunc FileAccess::close_notification_func = nullptr; + +FileAccess::FileAccess() : + f(nullptr), + flags(0), + last_error(OK) { + endian_swap = false; + real_is_double = false; +} + +FileAccess::~FileAccess() { + close(); +} + +#endif + +FileAccess::FileCloseFailNotify FileAccess::close_fail_notify = nullptr; + +bool FileAccess::backup_save = false; + +FileAccess *FileAccess::create() { + return memnew(FileAccess()); +} + +bool FileAccess::exists(const String &p_name) { + FileAccess *f = create_and_open(p_name, READ); + if (!f) { + return false; + } + memdelete(f); + return true; +} + +Error FileAccess::reopen(const String &p_path, int p_mode_flags) { + return _open(p_path, p_mode_flags); +}; + +Error FileAccess::open(const String &p_path, int p_mode_flags) { + return _open(p_path, p_mode_flags); +} + +FileAccess *FileAccess::create_and_open(const String &p_path, int p_mode_flags, Error *r_error) { + //try packed data first + + FileAccess *ret = nullptr; + + ret = create(); + Error err = ret->_open(p_path, p_mode_flags); + + if (r_error) { + *r_error = err; + } + if (err != OK) { + memdelete(ret); + ret = nullptr; + } + + return ret; +} + +String FileAccess::fix_path(const String &p_path) const { + //helper used by file accesses that use a single filesystem + + String r_path = p_path.replace("\\", "/"); + + return r_path; +} + +/* these are all implemented for ease of porting, then can later be optimized */ + +uint16_t FileAccess::get_16() const { + uint16_t res; + uint8_t a, b; + + a = get_8(); + b = get_8(); + + if (endian_swap) { + SWAP(a, b); + } + + res = b; + res <<= 8; + res |= a; + + return res; +} +uint32_t FileAccess::get_32() const { + uint32_t res; + uint16_t a, b; + + a = get_16(); + b = get_16(); + + if (endian_swap) { + SWAP(a, b); + } + + res = b; + res <<= 16; + res |= a; + + return res; +} +uint64_t FileAccess::get_64() const { + uint64_t res; + uint32_t a, b; + + a = get_32(); + b = get_32(); + + if (endian_swap) { + SWAP(a, b); + } + + res = b; + res <<= 32; + res |= a; + + return res; +} + +float FileAccess::get_float() const { + MarshallFloat m; + m.i = get_32(); + return m.f; +}; + +real_t FileAccess::get_real() const { + if (real_is_double) { + return get_double(); + } else { + return get_float(); + } +} + +double FileAccess::get_double() const { + MarshallDouble m; + m.l = get_64(); + return m.d; +}; + +String FileAccess::get_token() const { + CharString token; + + CharType c = get_8(); + + while (!eof_reached()) { + if (c <= ' ') { + if (token.length()) { + break; + } + } else { + token += c; + } + c = get_8(); + } + + return String::utf8(token.get_data()); +} + +class CharBuffer { + Vector vector; + char stack_buffer[256]; + + char *buffer; + int capacity; + int written; + + bool grow() { + if (vector.resize(next_power_of_2(1 + written)) != OK) { + return false; + } + + if (buffer == stack_buffer) { // first chunk? + + for (int i = 0; i < written; i++) { + vector.write[i] = stack_buffer[i]; + } + } + + buffer = vector.ptrw(); + capacity = vector.size(); + ERR_FAIL_COND_V(written >= capacity, false); + + return true; + } + +public: + _FORCE_INLINE_ CharBuffer() : + buffer(stack_buffer), + capacity(sizeof(stack_buffer) / sizeof(char)), + written(0) { + } + + _FORCE_INLINE_ void push_back(char c) { + if (written >= capacity) { + ERR_FAIL_COND(!grow()); + } + + buffer[written++] = c; + } + + _FORCE_INLINE_ const char *get_data() const { + return buffer; + } +}; + +String FileAccess::get_line() const { + CharBuffer line; + + CharType c = get_8(); + + while (!eof_reached()) { + if (c == '\n' || c == '\0') { + line.push_back(0); + return String::utf8(line.get_data()); + } else if (c != '\r') { + line.push_back(c); + } + + c = get_8(); + } + line.push_back(0); + return String::utf8(line.get_data()); +} + +Vector FileAccess::get_csv_line(const String &p_delim) const { + ERR_FAIL_COND_V_MSG(p_delim.length() != 1, Vector(), "Only single character delimiters are supported to parse CSV lines."); + ERR_FAIL_COND_V_MSG(p_delim[0] == '"', Vector(), "The double quotation mark character (\") is not supported as a delimiter for CSV lines."); + + String line; + + // CSV can support entries with line breaks as long as they are enclosed + // in double quotes. So our "line" might be more than a single line in the + // text file. + int qc = 0; + do { + if (eof_reached()) { + break; + } + line += get_line() + "\n"; + qc = 0; + for (int i = 0; i < line.length(); i++) { + if (line[i] == '"') { + qc++; + } + } + } while (qc % 2); + + // Remove the extraneous newline we've added above. + line = line.substr(0, line.length() - 1); + + Vector strings; + + bool in_quote = false; + String current; + for (int i = 0; i < line.length(); i++) { + CharType c = line[i]; + // A delimiter ends the current entry, unless it's in a quoted string. + if (!in_quote && c == p_delim[0]) { + strings.push_back(current); + current = String(); + } else if (c == '"') { + // Doubled quotes are escapes for intentional quotes in the string. + if (line[i + 1] == '"' && in_quote) { + current += '"'; + i++; + } else { + in_quote = !in_quote; + } + } else { + current += c; + } + } + strings.push_back(current); + + return strings; +} + +/* +uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + + uint64_t i = 0; + for (i = 0; i < p_length && !eof_reached(); i++) { + p_dst[i] = get_8(); + } + + return i; +} +*/ + +String FileAccess::get_as_utf8_string(bool p_skip_cr) const { + Vector sourcef; + uint64_t len = get_len(); + sourcef.resize(len + 1); + + uint8_t *w = sourcef.ptrw(); + uint64_t r = get_buffer(w, len); + ERR_FAIL_COND_V(r != len, String()); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w, -1, p_skip_cr)) { + return String(); + } + + return s; +} + +void FileAccess::store_16(uint16_t p_dest) { + uint8_t a, b; + + a = p_dest & 0xFF; + b = p_dest >> 8; + + if (endian_swap) { + SWAP(a, b); + } + + store_8(a); + store_8(b); +} +void FileAccess::store_32(uint32_t p_dest) { + uint16_t a, b; + + a = p_dest & 0xFFFF; + b = p_dest >> 16; + + if (endian_swap) { + SWAP(a, b); + } + + store_16(a); + store_16(b); +} +void FileAccess::store_64(uint64_t p_dest) { + uint32_t a, b; + + a = p_dest & 0xFFFFFFFF; + b = p_dest >> 32; + + if (endian_swap) { + SWAP(a, b); + } + + store_32(a); + store_32(b); +} + +void FileAccess::store_real(real_t p_real) { + if (sizeof(real_t) == 4) { + store_float(p_real); + } else { + store_double(p_real); + } +} + +void FileAccess::store_float(float p_dest) { + MarshallFloat m; + m.f = p_dest; + store_32(m.i); +}; + +void FileAccess::store_double(double p_dest) { + MarshallDouble m; + m.d = p_dest; + store_64(m.l); +}; + +uint64_t FileAccess::get_modified_time(const String &p_file) { + FileAccess *fa = create(); + ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); + + uint64_t mt = fa->_get_modified_time(p_file); + memdelete(fa); + return mt; +} + +uint32_t FileAccess::get_unix_permissions(const String &p_file) { + FileAccess *fa = create(); + ERR_FAIL_COND_V_MSG(!fa, 0, "Cannot create FileAccess for path '" + p_file + "'."); + + uint32_t mt = fa->_get_unix_permissions(p_file); + memdelete(fa); + return mt; +} + +Error FileAccess::set_unix_permissions(const String &p_file, uint32_t p_permissions) { + FileAccess *fa = create(); + ERR_FAIL_COND_V_MSG(!fa, ERR_CANT_CREATE, "Cannot create FileAccess for path '" + p_file + "'."); + + Error err = fa->_set_unix_permissions(p_file, p_permissions); + memdelete(fa); + return err; +} + +void FileAccess::store_string(const String &p_string) { + if (p_string.length() == 0) { + return; + } + + CharString cs = p_string.utf8(); + store_buffer((uint8_t *)&cs[0], cs.length()); +} + +void FileAccess::store_pascal_string(const String &p_string) { + CharString cs = p_string.utf8(); + store_32(cs.length()); + store_buffer((uint8_t *)&cs[0], cs.length()); +}; + +String FileAccess::get_pascal_string() { + uint32_t sl = get_32(); + CharString cs; + cs.resize(sl + 1); + get_buffer((uint8_t *)cs.ptr(), sl); + cs[sl] = 0; + + String ret; + ret.parse_utf8(cs.ptr()); + + return ret; +}; + +void FileAccess::store_line(const String &p_line) { + store_string(p_line); + store_8('\n'); +} + +void FileAccess::store_csv_line(const Vector &p_values, const String &p_delim) { + ERR_FAIL_COND(p_delim.length() != 1); + + String line = ""; + int size = p_values.size(); + for (int i = 0; i < size; ++i) { + String value = p_values[i]; + + if (value.find("\"") != -1 || value.find(p_delim) != -1 || value.find("\n") != -1) { + value = "\"" + value.replace("\"", "\"\"") + "\""; + } + if (i < size - 1) { + value += p_delim; + } + + line += value; + } + + store_line(line); +} + +void FileAccess::store_buffer_vec(const Vector &data) { + store_buffer(data.ptr(), data.size()); +} + +/* +void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); + for (uint64_t i = 0; i < p_length; i++) { + store_8(p_src[i]); + } +} +*/ + +Vector FileAccess::get_file_as_array(const String &p_path, Error *r_error) { + FileAccess *f = FileAccess::create_and_open(p_path, READ, r_error); + if (!f) { + if (r_error) { // if error requested, do not throw error + return Vector(); + } + ERR_FAIL_V_MSG(Vector(), "Can't open file from path '" + String(p_path) + "'."); + } + Vector data; + data.resize(f->get_len()); + f->get_buffer(data.ptrw(), data.size()); + memdelete(f); + return data; +} + +String FileAccess::get_file_as_string(const String &p_path, Error *r_error) { + Error err; + Vector array = get_file_as_array(p_path, &err); + if (r_error) { + *r_error = err; + } + if (err != OK) { + if (r_error) { + return String(); + } + ERR_FAIL_V_MSG(String(), "Can't get file as string from path '" + String(p_path) + "'."); + } + + String ret; + ret.parse_utf8((const char *)array.ptr(), array.size()); + return ret; +} + +/* +FileAccess::FileAccess() { + endian_swap = false; + real_is_double = false; +}; +*/ diff --git a/sfwl/core/file_access.h b/sfwl/core/file_access.h index 83d0377..80649fc 100644 --- a/sfwl/core/file_access.h +++ b/sfwl/core/file_access.h @@ -1,28 +1,203 @@ - +//--STRIP #ifndef FILE_ACCESS_H #define FILE_ACCESS_H +//--STRIP + +/*************************************************************************/ +/* file_access.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ //--STRIP #include "core/error_list.h" +#include "core/math_defs.h" #include "core/ustring.h" //--STRIP +#if defined(_WIN64) || defined(_WIN32) + +// Mingw +struct _iobuf; +typedef struct _iobuf FILE; + +#elif defined(__APPLE__) + +struct __sFILE; +typedef struct __sFILE FILE; + +typedef void (*FileCloseNotificationFunc)(const String &p_file, int p_flags); + +#else +struct _IO_FILE; +typedef struct _IO_FILE FILE; + +typedef void (*FileCloseNotificationFunc)(const String &p_file, int p_flags); +#endif + class FileAccess { public: - //TODO should probably have some simple buffered open / close / write / read api. + typedef void (*FileCloseFailNotify)(const String &); - String read_file(const String &path); + bool endian_swap; + bool real_is_double; - Vector read_file_bin(const String &path); - Error read_file_into_bin(const String &path, Vector *data); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); - Error write_file(const String &path, const String &str); - Error write_file_bin(const String &path, const Vector &data); +protected: + String fix_path(const String &p_path) const; + virtual Error _open(const String &p_path, int p_mode_flags); ///< open a file + virtual uint64_t _get_modified_time(const String &p_file); + + static FileCloseFailNotify close_fail_notify; + +private: + static bool backup_save; + +public: + static void set_file_close_fail_notify_callback(FileCloseFailNotify p_cbk) { close_fail_notify = p_cbk; } + + enum ModeFlags { + READ = 1, + WRITE = 2, + READ_WRITE = 3, + WRITE_READ = 7, + }; + + virtual void close(); ///< close a file + virtual bool is_open() const; ///< true when file is open + + virtual String get_path() const; /// returns the path for the current open file + virtual String get_path_absolute() const; /// returns the absolute path for the current open file + + virtual void seek(uint64_t p_position); ///< seek to a given position + virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file with negative offset + virtual uint64_t get_position() const; ///< get position in the file + virtual uint64_t get_len() const; ///< get size of the file + + virtual bool eof_reached() const; ///< reading passed EOF + + virtual uint8_t get_8() const; ///< get a byte + virtual uint16_t get_16() const; ///< get 16 bits uint + virtual uint32_t get_32() const; ///< get 32 bits uint + virtual uint64_t get_64() const; ///< get 64 bits uint + + virtual float get_float() const; + virtual double get_double() const; + virtual real_t get_real() const; + + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes + virtual String get_line() const; + virtual String get_token() const; + virtual Vector get_csv_line(const String &p_delim = ",") const; + virtual String get_as_utf8_string(bool p_skip_cr = true) const; // Skip CR by default for compat. + + /**< use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) + * It's not about the current CPU type but file formats. + * this flags get reset to false (little endian) on each open + */ + + virtual void set_endian_swap(bool p_swap) { endian_swap = p_swap; } + inline bool get_endian_swap() const { return endian_swap; } + + virtual Error get_error() const; ///< get last error + + virtual void flush(); + virtual void store_8(uint8_t p_dest); ///< store a byte + virtual void store_16(uint16_t p_dest); ///< store 16 bits uint + virtual void store_32(uint32_t p_dest); ///< store 32 bits uint + virtual void store_64(uint64_t p_dest); ///< store 64 bits uint + + virtual void store_float(float p_dest); + virtual void store_double(double p_dest); + virtual void store_real(real_t p_real); + + virtual void store_string(const String &p_string); + virtual void store_line(const String &p_line); + virtual void store_csv_line(const Vector &p_values, const String &p_delim = ","); + + virtual void store_pascal_string(const String &p_string); + virtual String get_pascal_string(); + + void store_buffer_vec(const Vector &data); ///< store an array of bytes + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes + + virtual bool file_exists(const String &p_name); ///< return true if a file exists + + virtual Error reopen(const String &p_path, int p_mode_flags); ///< does not change the AccessType + + Error open(const String &p_path, int p_mode_flags); + + static FileAccess *create(); /// Helper that Creates a file access + static FileAccess *create_and_open(const String &p_path, int p_mode_flags, Error *r_error = nullptr); + static bool exists(const String &p_name); ///< return true if a file exists + static uint64_t get_modified_time(const String &p_file); + static uint32_t get_unix_permissions(const String &p_file); + static Error set_unix_permissions(const String &p_file, uint32_t p_permissions); + + static void set_backup_save(bool p_enable) { backup_save = p_enable; }; + static bool is_backup_save_enabled() { return backup_save; }; + + static Vector get_file_as_array(const String &p_path, Error *r_error = nullptr); + static String get_file_as_string(const String &p_path, Error *r_error = nullptr); FileAccess(); virtual ~FileAccess(); -private: +#if defined(_WIN64) || defined(_WIN32) +#else + static FileCloseNotificationFunc close_notification_func; +#endif + +protected: +#if defined(_WIN64) || defined(_WIN32) + void check_errors() const; + + FILE *f; + int flags; + mutable int prev_op; + mutable Error last_error; + String path; + String path_src; + String save_path; +#else + void check_errors() const; + + FILE *f; + int flags; + + mutable Error last_error; + String save_path; + String path; + String path_src; +#endif }; +struct FileAccessRef { + FileAccess *f; + + _FORCE_INLINE_ bool is_null() const { return f == nullptr; } + _FORCE_INLINE_ bool is_valid() const { return f != nullptr; } + + _FORCE_INLINE_ operator bool() const { return f != nullptr; } + _FORCE_INLINE_ operator FileAccess *() { return f; } + + _FORCE_INLINE_ FileAccess *operator->() { + return f; + } + + FileAccessRef(FileAccess *fa) { f = fa; } + FileAccessRef(FileAccessRef &&other) { + f = other.f; + other.f = nullptr; + } + ~FileAccessRef() { + if (f) { + memdelete(f); + } + } +}; + +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/hash_map.h b/sfwl/core/hash_map.h index 0a2e863..181965b 100644 --- a/sfwl/core/hash_map.h +++ b/sfwl/core/hash_map.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef HASH_MAP_H #define HASH_MAP_H +//--STRIP /*************************************************************************/ /* hash_map.h */ @@ -640,4 +642,6 @@ private: } }; +//--STRIP #endif // HASH_MAP_H +//--STRIP diff --git a/sfwl/core/hash_set.h b/sfwl/core/hash_set.h index 82a7c7d..dcb24b4 100644 --- a/sfwl/core/hash_set.h +++ b/sfwl/core/hash_set.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef HASH_SET_H #define HASH_SET_H +//--STRIP /*************************************************************************/ /* hash_set.h */ @@ -479,4 +481,6 @@ public: } }; +//--STRIP #endif // HASH_SET_H +//--STRIP diff --git a/sfwl/core/hashfuncs.h b/sfwl/core/hashfuncs.h index 6dc09f0..fd1fba7 100644 --- a/sfwl/core/hashfuncs.h +++ b/sfwl/core/hashfuncs.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef HASHFUNCS_H #define HASHFUNCS_H +//--STRIP /*************************************************************************/ /* hashfuncs.h */ @@ -7,8 +9,17 @@ /*************************************************************************/ //--STRIP +#include "core/aabb.h" #include "core/math_defs.h" #include "core/math_funcs.h" +#include "core/rect2.h" +#include "core/rect2i.h" +#include "core/vector2.h" +#include "core/vector2i.h" +#include "core/vector3.h" +#include "core/vector3i.h" +#include "core/vector4.h" +#include "core/vector4i.h" #include "core/string_name.h" #include "core/ustring.h" #include "core/typedefs.h" @@ -297,6 +308,66 @@ struct HashMapHasherDefault { static _FORCE_INLINE_ uint32_t hash(const int16_t p_int) { return hash_fmix32(p_int); } static _FORCE_INLINE_ uint32_t hash(const uint8_t p_int) { return hash_fmix32(p_int); } static _FORCE_INLINE_ uint32_t hash(const int8_t p_int) { return hash_fmix32(p_int); } + + static _FORCE_INLINE_ uint32_t hash(const Vector2i &p_vec) { + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector3i &p_vec) { + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + h = hash_murmur3_one_32(p_vec.z, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector4i &p_vec) { + uint32_t h = hash_murmur3_one_32(p_vec.x); + h = hash_murmur3_one_32(p_vec.y, h); + h = hash_murmur3_one_32(p_vec.z, h); + h = hash_murmur3_one_32(p_vec.w, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector2 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector3 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + h = hash_murmur3_one_real(p_vec.z, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Vector4 &p_vec) { + uint32_t h = hash_murmur3_one_real(p_vec.x); + h = hash_murmur3_one_real(p_vec.y, h); + h = hash_murmur3_one_real(p_vec.z, h); + h = hash_murmur3_one_real(p_vec.w, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Rect2i &p_rect) { + uint32_t h = hash_murmur3_one_32(p_rect.position.x); + h = hash_murmur3_one_32(p_rect.position.y, h); + h = hash_murmur3_one_32(p_rect.size.x, h); + h = hash_murmur3_one_32(p_rect.size.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const Rect2 &p_rect) { + uint32_t h = hash_murmur3_one_real(p_rect.position.x); + h = hash_murmur3_one_real(p_rect.position.y, h); + h = hash_murmur3_one_real(p_rect.size.x, h); + h = hash_murmur3_one_real(p_rect.size.y, h); + return hash_fmix32(h); + } + static _FORCE_INLINE_ uint32_t hash(const AABB &p_aabb) { + uint32_t h = hash_murmur3_one_real(p_aabb.position.x); + h = hash_murmur3_one_real(p_aabb.position.y, h); + h = hash_murmur3_one_real(p_aabb.position.z, h); + h = hash_murmur3_one_real(p_aabb.size.x, h); + h = hash_murmur3_one_real(p_aabb.size.y, h); + h = hash_murmur3_one_real(p_aabb.size.z, h); + return hash_fmix32(h); + } }; template @@ -320,6 +391,20 @@ struct HashMapComparatorDefault { } }; +template <> +struct HashMapComparatorDefault { + static bool compare(const Vector2 &p_lhs, const Vector2 &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))); + } +}; + +template <> +struct HashMapComparatorDefault { + static bool compare(const Vector3 &p_lhs, const Vector3 &p_rhs) { + return ((p_lhs.x == p_rhs.x) || (Math::is_nan(p_lhs.x) && Math::is_nan(p_rhs.x))) && ((p_lhs.y == p_rhs.y) || (Math::is_nan(p_lhs.y) && Math::is_nan(p_rhs.y))) && ((p_lhs.z == p_rhs.z) || (Math::is_nan(p_lhs.z) && Math::is_nan(p_rhs.z))); + } +}; + constexpr uint32_t HASH_TABLE_SIZE_MAX = 29; const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { @@ -416,4 +501,6 @@ static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const #endif // _MSC_VER } +//--STRIP #endif // HASHFUNCS_H +//--STRIP diff --git a/sfwl/core/inet_address.cpp b/sfwl/core/inet_address.cpp new file mode 100644 index 0000000..679dbf1 --- /dev/null +++ b/sfwl/core/inet_address.cpp @@ -0,0 +1,331 @@ +//Based on: + +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +//--STRIP +#include "inet_address.h" +//--STRIP + +#include +#include + +#if defined(_WIN64) || defined(_WIN32) + +#ifdef __GNUC__ +#define GCCWIN +// Mingw / gcc on windows +// #define _WIN32_WINNT 0x0501 +#include +#include + +extern "C" { +WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, PCSTR pszAddrString, PVOID pAddrBuf); + +#ifdef __MINGW64_VERSION_MAJOR +#if __MINGW64_VERSION_MAJOR >= 7 +WINSOCK_API_LINKAGE PCSTR WSAAPI inet_ntop(INT Family, const VOID * pAddr, PSTR pStringBuf, size_t StringBufSize); +#else +WINSOCK_API_LINKAGE PCSTR WSAAPI inet_ntop(INT Family, VOID * pAddr, PSTR pStringBuf, size_t StringBufSize); +#endif + +#else +WINSOCK_API_LINKAGE PCSTR WSAAPI inet_ntop(INT Family, VOID * pAddr, PSTR pStringBuf, size_t StringBufSize); +#endif + +} +#else +// Windows... + +#define WIN32_LEAN_AND_MEAN +#include + +#include +#include +#include + +extern "C" { + +PCSTR WSAAPI inet_ntop( _In_ INT Family,_In_ const VOID * pAddr,_Out_writes_(StringBufSize) PSTR pStringBuf, _In_ size_t StringBufSize); + +WINSOCK_API_LINKAGE INT WSAAPI inet_pton(_In_ INT Family,_In_ PCSTR pszAddrString, _When_(Family == AF_INET, _Out_writes_bytes_(sizeof(IN_ADDR)))_When_(Family == AF_INET6, _Out_writes_bytes_(sizeof(IN6_ADDR)))PVOID pAddrBuf); + +} + +#endif + +struct in6__addruint { + union { + u_char Byte[16]; + u_short Word[8]; + uint32_t __s6_addr32[4]; + } uext; +}; +#else +#include +#include +#include // memset +#endif + +#ifdef _MSC_VER +#pragma comment(lib, "ws2_32") +#endif + +// INADDR_ANY use (type)value casting. +static const in_addr_t kInaddrAny = INADDR_ANY; +static const in_addr_t kInaddrLoopback = INADDR_ANY; + +// /* Structure describing an Internet socket address. */ +// struct sock_addrin { +// sa_family_t sin_family; /* address family: AF_INET */ +// uint16_t sin_port; /* port in network byte order */ +// struct in_addr sin_addr; /* internet address */ +// }; + +// /* Internet address. */ +// typedef uint32_t in_addr_t; +// struct in_addr { +// in_addr_t s_addr; /* address in network byte order */ +// }; + +// struct sockaddr_in6 { +// sa_family_t sin6_family; /* address family: AF_INET6 */ +// uint16_t sin6_port; /* port in network byte order */ +// uint32_t sin6_flowinfo; /* IPv6 flow information */ +// struct in6_addr sin6_addr; /* IPv6 address */ +// uint32_t sin6_scope_id; /* IPv6 scope-id */ +// }; + +/* +#ifdef __linux__ +#if !(__GNUC_PREREQ(4, 6)) +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +#endif +*/ + +// Defined here so we don't need to include in the header +struct InetAddress::InetAddressData { + union { + struct sockaddr_in _addr; + struct sockaddr_in6 _addr6; + }; +}; + +String InetAddress::to_ip_port() const { + char buf[64] = ""; + uint16_t port = ntohs(_data->_addr.sin_port); + snprintf(buf, sizeof(buf), ":%u", port); + + return to_ip() + String(buf); +} + +bool InetAddress::is_intranet_ip() const { + if (_data->_addr.sin_family == AF_INET) { + uint32_t ip_addr = ntohl(_data->_addr.sin_addr.s_addr); + if ((ip_addr >= 0x0A000000 && ip_addr <= 0x0AFFFFFF) || + (ip_addr >= 0xAC100000 && ip_addr <= 0xAC1FFFFF) || + (ip_addr >= 0xC0A80000 && ip_addr <= 0xC0A8FFFF) || + ip_addr == 0x7f000001) + + { + return true; + } + } else { + auto addrP = ip6_net_endian(); + // Loopback ip + if (*addrP == 0 && *(addrP + 1) == 0 && *(addrP + 2) == 0 && + ntohl(*(addrP + 3)) == 1) { + return true; + } + + // Privated ip is prefixed by FEC0::/10 or FE80::/10, need testing + auto i32 = (ntohl(*addrP) & 0xffc00000); + if (i32 == 0xfec00000 || i32 == 0xfe800000) { + return true; + } + + if (*addrP == 0 && *(addrP + 1) == 0 && ntohl(*(addrP + 2)) == 0xffff) { + // the IPv6 version of an IPv4 IP address + uint32_t ip_addr = ntohl(*(addrP + 3)); + if ((ip_addr >= 0x0A000000 && ip_addr <= 0x0AFFFFFF) || + (ip_addr >= 0xAC100000 && ip_addr <= 0xAC1FFFFF) || + (ip_addr >= 0xC0A80000 && ip_addr <= 0xC0A8FFFF) || + ip_addr == 0x7f000001) + + { + return true; + } + } + } + return false; +} + +bool InetAddress::is_loopback_ip() const { + if (!is_ip_v6()) { + uint32_t ip_addr = ntohl(_data->_addr.sin_addr.s_addr); + if (ip_addr == 0x7f000001) { + return true; + } + } else { + auto addrP = ip6_net_endian(); + if (*addrP == 0 && *(addrP + 1) == 0 && *(addrP + 2) == 0 && + ntohl(*(addrP + 3)) == 1) { + return true; + } + // the IPv6 version of an IPv4 loopback address + if (*addrP == 0 && *(addrP + 1) == 0 && ntohl(*(addrP + 2)) == 0xffff && + ntohl(*(addrP + 3)) == 0x7f000001) { + return true; + } + } + return false; +} + +const struct sockaddr *InetAddress::get_sock_addr() const { + return static_cast((void *)(&_data->_addr6)); +} + +void InetAddress::set_sock_addr_inet6(const struct sockaddr_in6 &addr6) { + _data->_addr6 = addr6; + _is_ip_v6 = (_data->_addr6.sin6_family == AF_INET6); + _is_unspecified = false; +} + +sa_family_t InetAddress::family() const { + return _data->_addr.sin_family; +} + +String InetAddress::to_ip() const { + char buf[64]; + if (_data->_addr.sin_family == AF_INET) { +#if defined GCCWIN || (_MSC_VER && _MSC_VER >= 1900) + ::inet_ntop(AF_INET, (PVOID)&_data->_addr.sin_addr, buf, sizeof(buf)); +#else + ::inet_ntop(AF_INET, &_data->_addr.sin_addr, buf, sizeof(buf)); +#endif + } else if (_data->_addr.sin_family == AF_INET6) { +#if defined GCCWIN || (_MSC_VER && _MSC_VER >= 1900) + ::inet_ntop(AF_INET6, (PVOID)&_data->_addr6.sin6_addr, buf, sizeof(buf)); +#else + ::inet_ntop(AF_INET6, &_data->_addr6.sin6_addr, buf, sizeof(buf)); +#endif + } + + return buf; +} + +uint32_t InetAddress::ip_net_endian() const { + // assert(family() == AF_INET); + return _data->_addr.sin_addr.s_addr; +} + +const uint32_t *InetAddress::ip6_net_endian() const { +// assert(family() == AF_INET6); +#if defined __linux__ || defined __HAIKU__ + return _data->_addr6.sin6_addr.s6_addr32; +#elif defined(_WIN64) || defined(_WIN32) + // TODO is this OK ? + const struct in6__addruint *_addrtemp = + reinterpret_cast(&_data->_addr6.sin6_addr); + return (*_addrtemp).uext.__s6_addr32; +#else + return _data->_addr6.sin6_addr.__u6_addr.__u6_addr32; +#endif +} + +uint16_t InetAddress::port_net_endian() const { + return _data->_addr.sin_port; +} + +void InetAddress::set_port_net_endian(uint16_t port) { + _data->_addr.sin_port = port; +} + +inline bool InetAddress::is_unspecified() const { + return _is_unspecified; +} + +uint16_t InetAddress::to_port() const { + return ntohs(port_net_endian()); +} + +bool InetAddress::is_ip_v6() const { + return _is_ip_v6; +} + +InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) { + _data = memnew(InetAddressData); + + _is_ip_v6 = ipv6; + + if (ipv6) { + memset(&_data->_addr6, 0, sizeof(_data->_addr6)); + _data->_addr6.sin6_family = AF_INET6; + + in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; + + _data->_addr6.sin6_addr = ip; + _data->_addr6.sin6_port = htons(port); + } else { + memset(&_data->_addr, 0, sizeof(_data->_addr)); + _data->_addr.sin_family = AF_INET; + + in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; + + _data->_addr.sin_addr.s_addr = htonl(ip); + _data->_addr.sin_port = htons(port); + } + + _is_unspecified = false; +} + +InetAddress::InetAddress(const String &ip, uint16_t port, bool ipv6) { + _data = memnew(InetAddressData); + + _is_ip_v6 = ipv6; + + if (ipv6) { + memset(&_data->_addr6, 0, sizeof(_data->_addr6)); + _data->_addr6.sin6_family = AF_INET6; + _data->_addr6.sin6_port = htons(port); + + if (::inet_pton(AF_INET6, ip.utf8().get_data(), &_data->_addr6.sin6_addr) <= 0) { + return; + } + } else { + memset(&_data->_addr, 0, sizeof(_data->_addr)); + _data->_addr.sin_family = AF_INET; + _data->_addr.sin_port = htons(port); + + if (::inet_pton(AF_INET, ip.utf8().get_data(), &_data->_addr.sin_addr) <= 0) { + return; + } + } + + _is_unspecified = false; +} + +InetAddress::InetAddress(const struct sockaddr_in &addr) { + _data = memnew(InetAddressData); + + _data->_addr = addr; + _is_unspecified = false; +} + +InetAddress::InetAddress(const struct sockaddr_in6 &addr) { + _data = memnew(InetAddressData); + + _data->_addr6 = addr; + _is_ip_v6 = true; + _is_unspecified = false; +} + +InetAddress::~InetAddress() { + memdelete(_data); +} diff --git a/sfwl/core/inet_address.h b/sfwl/core/inet_address.h new file mode 100644 index 0000000..20a83ac --- /dev/null +++ b/sfwl/core/inet_address.h @@ -0,0 +1,96 @@ +//Based on: + +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +// Taken from Muduo and modified +// Copyright 2016, Tao An. All rights reserved. +// https://github.com/an-tao/trantor +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Tao An + +//--STRIP +#ifndef INET_ADDRESS_H +#define INET_ADDRESS_H +//--STRIP + +//On windows link to ws2_32 + +//--STRIP +#include "int_types.h" +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) +using sa_family_t = unsigned short; +using in_addr_t = uint32_t; +using uint16_t = unsigned short; +#else +#include +#include +#include +#endif + +//--STRIP +#include "core/ustring.h" +#include "int_types.h" +//--STRIP + +struct sockaddr_in; +struct sockaddr_in6; + +class InetAddress { +public: + struct InetAddressData; + + sa_family_t family() const; + + String to_ip() const; + String to_ip_port() const; + + uint16_t to_port() const; + + bool is_ip_v6() const; + bool is_intranet_ip() const; + bool is_loopback_ip() const; + + const struct sockaddr *get_sock_addr() const; + + void set_sock_addr_inet6(const struct sockaddr_in6 &addr6); + + uint32_t ip_net_endian() const; + const uint32_t *ip6_net_endian() const; + + uint16_t port_net_endian() const; + + void set_port_net_endian(uint16_t port); + + inline bool is_unspecified() const; + + InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); + InetAddress(const String &ip, uint16_t port, bool ipv6 = false); + + explicit InetAddress(const struct sockaddr_in &addr); + explicit InetAddress(const struct sockaddr_in6 &addr); + + ~InetAddress(); + +private: + InetAddressData *_data; + + bool _is_ip_v6; + bool _is_unspecified; +}; + +//--STRIP +#endif +//--STRIP diff --git a/sfwl/core/list.h b/sfwl/core/list.h index fe1bc05..eee64ed 100644 --- a/sfwl/core/list.h +++ b/sfwl/core/list.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef GLOBALS_LIST_H #define GLOBALS_LIST_H +//--STRIP /*************************************************************************/ /* list.h */ @@ -674,4 +676,6 @@ public: }; }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/local_vector.h b/sfwl/core/local_vector.h index dd712df..1f43016 100644 --- a/sfwl/core/local_vector.h +++ b/sfwl/core/local_vector.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef LOCAL_VECTOR_H #define LOCAL_VECTOR_H +//--STRIP /*************************************************************************/ /* local_vector.h */ @@ -296,4 +298,6 @@ template class LocalVectori : public LocalVector { }; +//--STRIP #endif // LOCAL_VECTOR_H +//--STRIP diff --git a/sfwl/core/logger.h b/sfwl/core/logger.h index 7fba994..ff73d62 100644 --- a/sfwl/core/logger.h +++ b/sfwl/core/logger.h @@ -1,7 +1,7 @@ - +//--STRIP #ifndef LOGGER_H #define LOGGER_H - +//--STRIP class String; @@ -71,4 +71,6 @@ public: static void log_ret_ptr(String *str); }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/marshalls.h b/sfwl/core/marshalls.h new file mode 100644 index 0000000..f34c113 --- /dev/null +++ b/sfwl/core/marshalls.h @@ -0,0 +1,148 @@ +//--STRIP +#ifndef MARSHALLS_H +#define MARSHALLS_H +//--STRIP + +/*************************************************************************/ +/* marshalls.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "core/int_types.h" +#include "core/math_defs.h" +//--STRIP + +/** + * Miscellaneous helpers for marshalling data types, and encoding + * in an endian independent way + */ + +union MarshallFloat { + uint32_t i; ///< int + float f; ///< float +}; + +union MarshallDouble { + uint64_t l; ///< long long + double d; ///< double +}; + +static inline unsigned int encode_uint16(uint16_t p_uint, uint8_t *p_arr) { + for (int i = 0; i < 2; i++) { + *p_arr = p_uint & 0xFF; + p_arr++; + p_uint >>= 8; + } + + return sizeof(uint16_t); +} + +static inline unsigned int encode_uint32(uint32_t p_uint, uint8_t *p_arr) { + for (int i = 0; i < 4; i++) { + *p_arr = p_uint & 0xFF; + p_arr++; + p_uint >>= 8; + } + + return sizeof(uint32_t); +} + +static inline unsigned int encode_float(float p_float, uint8_t *p_arr) { + MarshallFloat mf; + mf.f = p_float; + encode_uint32(mf.i, p_arr); + + return sizeof(uint32_t); +} + +static inline unsigned int encode_uint64(uint64_t p_uint, uint8_t *p_arr) { + for (int i = 0; i < 8; i++) { + *p_arr = p_uint & 0xFF; + p_arr++; + p_uint >>= 8; + } + + return sizeof(uint64_t); +} + +static inline unsigned int encode_double(double p_double, uint8_t *p_arr) { + MarshallDouble md; + md.d = p_double; + encode_uint64(md.l, p_arr); + + return sizeof(uint64_t); +} + +static inline int encode_cstring(const char *p_string, uint8_t *p_data) { + int len = 0; + + while (*p_string) { + if (p_data) { + *p_data = (uint8_t)*p_string; + p_data++; + } + p_string++; + len++; + }; + + if (p_data) { + *p_data = 0; + } + return len + 1; +} + +static inline uint16_t decode_uint16(const uint8_t *p_arr) { + uint16_t u = 0; + + for (int i = 0; i < 2; i++) { + uint16_t b = *p_arr; + b <<= (i * 8); + u |= b; + p_arr++; + } + + return u; +} + +static inline uint32_t decode_uint32(const uint8_t *p_arr) { + uint32_t u = 0; + + for (int i = 0; i < 4; i++) { + uint32_t b = *p_arr; + b <<= (i * 8); + u |= b; + p_arr++; + } + + return u; +} + +static inline float decode_float(const uint8_t *p_arr) { + MarshallFloat mf; + mf.i = decode_uint32(p_arr); + return mf.f; +} + +static inline uint64_t decode_uint64(const uint8_t *p_arr) { + uint64_t u = 0; + + for (int i = 0; i < 8; i++) { + uint64_t b = (*p_arr) & 0xFF; + b <<= (i * 8); + u |= b; + p_arr++; + } + + return u; +} + +static inline double decode_double(const uint8_t *p_arr) { + MarshallDouble md; + md.l = decode_uint64(p_arr); + return md.d; +} + +//--STRIP +#endif +//--STRIP diff --git a/sfwl/core/math_defs.h b/sfwl/core/math_defs.h index 192b375..d28ddc8 100644 --- a/sfwl/core/math_defs.h +++ b/sfwl/core/math_defs.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef MATH_DEFS_H #define MATH_DEFS_H +//--STRIP /*************************************************************************/ /* math_defs.h */ @@ -95,4 +97,6 @@ typedef double real_t; typedef float real_t; #endif +//--STRIP #endif // MATH_DEFS_H +//--STRIP diff --git a/sfwl/core/math_funcs.h b/sfwl/core/math_funcs.h index b2bd32c..7fb67ac 100644 --- a/sfwl/core/math_funcs.h +++ b/sfwl/core/math_funcs.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef MATH_FUNCS_H #define MATH_FUNCS_H +//--STRIP /*************************************************************************/ /* math_funcs.h */ @@ -641,4 +643,6 @@ public: } }; +//--STRIP #endif // MATH_FUNCS_H +//--STRIP diff --git a/sfwl/core/memory.cpp b/sfwl/core/memory.cpp index 56c69c0..9b90dd8 100644 --- a/sfwl/core/memory.cpp +++ b/sfwl/core/memory.cpp @@ -23,15 +23,15 @@ void *operator new(size_t p_size, void *(*p_allocfunc)(size_t p_size)) { #ifdef _MSC_VER void operator delete(void *p_mem, const char *p_description) { - CRASH_NOW_MSG("Call to placement delete should not happen."); + CRASH_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *(*p_allocfunc)(size_t p_size)) { - CRASH_NOW_MSG("Call to placement delete should not happen."); + CRASH_MSG("Call to placement delete should not happen."); } void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_description) { - CRASH_NOW_MSG("Call to placement delete should not happen."); + CRASH_MSG("Call to placement delete should not happen."); } #endif diff --git a/sfwl/core/memory.h b/sfwl/core/memory.h index a23debf..58fd6e3 100644 --- a/sfwl/core/memory.h +++ b/sfwl/core/memory.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef MEMORY_H #define MEMORY_H +//--STRIP /*************************************************************************/ /* memory.h */ @@ -179,4 +181,6 @@ struct _GlobalNilClass { static _GlobalNil _nil; }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/mutex.h b/sfwl/core/mutex.h index 86c3ade..865de85 100644 --- a/sfwl/core/mutex.h +++ b/sfwl/core/mutex.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef MUTEX_H #define MUTEX_H +//--STRIP /*************************************************************************/ /* mutex.h */ @@ -94,4 +96,6 @@ using BinaryMutex = MutexImpl; // Non-recursive, handle with care #endif // !NO_THREADS +//--STRIP #endif // MUTEX_H +//--STRIP diff --git a/sfwl/core/og_hash_map.h b/sfwl/core/og_hash_map.h index cc80345..7470ed8 100644 --- a/sfwl/core/og_hash_map.h +++ b/sfwl/core/og_hash_map.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef GHASH_MAP_H #define GHASH_MAP_H +//--STRIP /*************************************************************************/ /* og_hash_map.h */ @@ -578,4 +580,6 @@ public: } }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/ordered_hash_map.h b/sfwl/core/ordered_hash_map.h index be7e23d..07bd369 100644 --- a/sfwl/core/ordered_hash_map.h +++ b/sfwl/core/ordered_hash_map.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef ORDERED_HASH_MAP_H #define ORDERED_HASH_MAP_H +//--STRIP /*************************************************************************/ /* ordered_hash_map.h */ @@ -284,4 +286,6 @@ public: } }; +//--STRIP #endif // ORDERED_HASH_MAP_H +//--STRIP diff --git a/sfwl/core/paged_allocator.h b/sfwl/core/paged_allocator.h index 3317f22..0aa11da 100644 --- a/sfwl/core/paged_allocator.h +++ b/sfwl/core/paged_allocator.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef PAGED_ALLOCATOR_H #define PAGED_ALLOCATOR_H +//--STRIP /*************************************************************************/ /* paged_allocator.h */ @@ -107,4 +109,6 @@ public: } }; +//--STRIP #endif // PAGED_ALLOCATOR_H +//--STRIP diff --git a/sfwl/core/pair.h b/sfwl/core/pair.h index 812bc40..5b1983b 100644 --- a/sfwl/core/pair.h +++ b/sfwl/core/pair.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef PAIR_H #define PAIR_H +//--STRIP /*************************************************************************/ /* pair.h */ @@ -89,4 +91,6 @@ struct KeyValueSort { } }; +//--STRIP #endif // PAIR_H +//--STRIP diff --git a/sfwl/core/pcg.h b/sfwl/core/pcg.h index 082e446..6c3b630 100644 --- a/sfwl/core/pcg.h +++ b/sfwl/core/pcg.h @@ -1,8 +1,10 @@ // *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website) +//--STRIP #ifndef RANDOM_H #define RANDOM_H +//--STRIP //--STRIP #include "core/typedefs.h" @@ -15,4 +17,6 @@ uint32_t pcg32_random_r(pcg32_random_t* rng); void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initstate, uint64_t initseq); uint32_t pcg32_boundedrand_r(pcg32_random_t* rng, uint32_t bound); +//--STRIP #endif // RANDOM_H +//--STRIP diff --git a/sfwl/core/pool_allocator.h b/sfwl/core/pool_allocator.h index 7ed6a5d..daa3729 100644 --- a/sfwl/core/pool_allocator.h +++ b/sfwl/core/pool_allocator.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef POOL_ALLOCATOR_H #define POOL_ALLOCATOR_H +//--STRIP /*************************************************************************/ /* pool_allocator.h */ @@ -124,4 +126,6 @@ public: virtual ~PoolAllocator(); }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/pool_vector.h b/sfwl/core/pool_vector.h index 5ffc6f5..456a2d6 100644 --- a/sfwl/core/pool_vector.h +++ b/sfwl/core/pool_vector.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef POOL_VECTOR_H #define POOL_VECTOR_H +//--STRIP /*************************************************************************/ /* pool_vector.h */ @@ -709,4 +711,6 @@ void PoolVector::sort() { sorter.sort(w.ptr(), len); } +//--STRIP #endif // POOL_VECTOR_H +//--STRIP diff --git a/sfwl/core/random_pcg.h b/sfwl/core/random_pcg.h index 088f3a5..9541ada 100644 --- a/sfwl/core/random_pcg.h +++ b/sfwl/core/random_pcg.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RANDOM_PCG_H #define RANDOM_PCG_H +//--STRIP /*************************************************************************/ /* random_pcg.h */ @@ -115,4 +117,6 @@ public: int random(int p_from, int p_to); }; +//--STRIP #endif // RANDOM_PCG_H +//--STRIP diff --git a/sfwl/core/rb_map.h b/sfwl/core/rb_map.h index 67de2a0..7c71ab1 100644 --- a/sfwl/core/rb_map.h +++ b/sfwl/core/rb_map.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RB_MAP_H #define RB_MAP_H +//--STRIP /*************************************************************************/ /* rb_map.h */ @@ -652,4 +654,6 @@ public: } }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/rb_set.h b/sfwl/core/rb_set.h index 43f254f..3e9c34f 100644 --- a/sfwl/core/rb_set.h +++ b/sfwl/core/rb_set.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RB_SET_H #define RB_SET_H +//--STRIP /*************************************************************************/ /* rb_set.h */ @@ -606,4 +608,6 @@ public: } }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/ring_buffer.h b/sfwl/core/ring_buffer.h index d8c3146..a10d7f2 100644 --- a/sfwl/core/ring_buffer.h +++ b/sfwl/core/ring_buffer.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RINGBUFFER_H #define RINGBUFFER_H +//--STRIP /*************************************************************************/ /* ring_buffer.h */ @@ -196,4 +198,6 @@ public: ~RingBuffer(){}; }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/rw_lock.h b/sfwl/core/rw_lock.h index 93d9e95..9c9a754 100644 --- a/sfwl/core/rw_lock.h +++ b/sfwl/core/rw_lock.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RWLOCK_H #define RWLOCK_H +//--STRIP /*************************************************************************/ /* rw_lock.h */ @@ -90,4 +92,6 @@ public: } }; +//--STRIP #endif // RWLOCK_H +//--STRIP diff --git a/sfwl/core/safe_refcount.h b/sfwl/core/safe_refcount.h index d8d9b79..e1129d2 100644 --- a/sfwl/core/safe_refcount.h +++ b/sfwl/core/safe_refcount.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef SAFE_REFCOUNT_H #define SAFE_REFCOUNT_H +//--STRIP /*************************************************************************/ /* safe_refcount.h */ @@ -307,4 +309,6 @@ public: #endif +//--STRIP #endif // SAFE_REFCOUNT_H +//--STRIP diff --git a/sfwl/core/sfw_core.h b/sfwl/core/sfw_core.h index 92585a4..106a9bb 100644 --- a/sfwl/core/sfw_core.h +++ b/sfwl/core/sfw_core.h @@ -1,6 +1,7 @@ - +//--STRIP #ifndef SFW_CORE_H #define SFW_CORE_H +//--STRIP class SFWCore { public: @@ -11,4 +12,6 @@ protected: static bool _initialized; }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/sfw_time.cpp b/sfwl/core/sfw_time.cpp index 5b28f9d..e5d12af 100644 --- a/sfwl/core/sfw_time.cpp +++ b/sfwl/core/sfw_time.cpp @@ -4,12 +4,19 @@ //--STRIP #include "core/sfw_time.h" -#include #include -#include #include //--STRIP +#if defined(_WIN64) || defined(_WIN32) +#define WIN32_LEAN_AND_MEAN +#include +#include +#else +#include +#include +#endif + #if 0 uint64_t SFWTime::time_gpu() { GLint64 t = 123456789; @@ -114,8 +121,8 @@ static uint64_t nanotimer(uint64_t *out_freq) { } uint64_t SFWTime::time_ns() { - static __thread uint64_t epoch = 0; - static __thread uint64_t freq = 0; + static thread_local uint64_t epoch = 0; + static thread_local uint64_t freq = 0; if (!freq) { epoch = nanotimer(&freq); } diff --git a/sfwl/core/sfw_time.h b/sfwl/core/sfw_time.h index 0916014..b97a503 100644 --- a/sfwl/core/sfw_time.h +++ b/sfwl/core/sfw_time.h @@ -1,5 +1,7 @@ -#ifndef SFWTime_H -#define SFWTime_H +//--STRIP +#ifndef SFW_TIME_H +#define SFW_TIME_H +//--STRIP // ----------------------------------------------------------------------------- // time framework utils @@ -26,4 +28,6 @@ public: static void sleep_ns(double us); }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/socket.cpp b/sfwl/core/socket.cpp new file mode 100644 index 0000000..93c48ca --- /dev/null +++ b/sfwl/core/socket.cpp @@ -0,0 +1,356 @@ +//--STRIP +#include "socket.h" +//--STRIP + +//Based on: + +/** + * + * Socket.cc + * An Tao + * + * Public header file in trantor lib. + * + * Copyright 2018, An Tao. All rights reserved. + * Use of this source code is governed by a BSD-style license + * that can be found in the License file. + * + * + */ + +#if !defined(_WIN64) && !defined(_WIN32) +#include +#endif +#include + +///usr/include/asm-generic/errno-base.h +//http://www.virtsync.com/c-error-codes-include-errno +#include + +#if defined(_WIN64) || defined(_WIN32) +#include +#else +#include +#include +#endif + +//--STRIP +#include "core/error_macros.h" +#include "core/ustring.h" +//--STRIP + +void Socket::create_net_socket() { + create(AF_INET); +} + +void Socket::create(int family) { +#ifdef __linux__ + _socket = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); +#else + _socket = static_cast(::socket(family, SOCK_STREAM, IPPROTO_TCP)); +#endif +} + +void Socket::close_socket() { + if (!_socket) { + return; + } + +#if !defined(_WIN64) && !defined(_WIN32) + close(_socket); +#else + closesocket(_socket); +#endif + + _socket = 0; +} + +// taken from muduo +int Socket::set_non_block() { + ERR_FAIL_COND_V(_socket == 0, -1); + +#if defined(_WIN64) || defined(_WIN32) + // TODO how to set FD_CLOEXEC on windows? is it necessary? + u_long arg = 1; + auto ret = ioctlsocket(_socket, (long)FIONBIO, &arg); + + if (ret) { + //LOG_ERR("ioctlsocket error"); + return -1; + } + + return 0; +#else + // non-block + int flags = ::fcntl(_socket, F_GETFL, 0); + flags |= O_NONBLOCK; + int ret = ::fcntl(_socket, F_SETFL, flags); + // TODO check + + return ret; +#endif +} + +// taken from muduo +int Socket::set_close_on_exit() { + ERR_FAIL_COND_V(_socket == 0, -1); + +#if defined(_WIN64) || defined(_WIN32) + // TODO how to set FD_CLOEXEC on windows? is it necessary? + return 0; +#else + // close-on-exec + int flags = ::fcntl(_socket, F_GETFD, 0); + flags |= FD_CLOEXEC; + int ret = ::fcntl(_socket, F_SETFD, flags); + // TODO check + + return ret; +#endif +} + +int Socket::get_error() { + ERR_FAIL_COND_V(_socket == 0, -1); + + int optval; + + socklen_t optlen = static_cast(sizeof optval); + +#if defined(_WIN64) || defined(_WIN32) + if (::getsockopt(_socket, SOL_SOCKET, SO_ERROR, (char *)&optval, &optlen) < 0) +#else + if (::getsockopt(_socket, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) +#endif + { + return errno; + } else { + return optval; + } +} + +int Socket::connect(const InetAddress &addr) { + ERR_FAIL_COND_V(_socket == 0, -1); + + if (addr.is_ip_v6()) { + return ::connect(_socket, addr.get_sock_addr(), static_cast(sizeof(struct sockaddr_in6))); + } else { + return ::connect(_socket, addr.get_sock_addr(), static_cast(sizeof(struct sockaddr_in))); + } +} + +bool Socket::is_self_connect() { + ERR_FAIL_COND_V(_socket == 0, false); + + struct sockaddr_in6 localaddr = get_local_addr(); + struct sockaddr_in6 peeraddr = get_peer_addr(); + + if (localaddr.sin6_family == AF_INET) { + const struct sockaddr_in *laddr4 = reinterpret_cast(&localaddr); + const struct sockaddr_in *raddr4 = reinterpret_cast(&peeraddr); + return laddr4->sin_port == raddr4->sin_port && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; + } else if (localaddr.sin6_family == AF_INET6) { + return localaddr.sin6_port == peeraddr.sin6_port && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; + } else { + return false; + } +} + +int Socket::bind_address(const InetAddress &address) { + ERR_FAIL_COND_V(_socket == 0, -1); + + int ret; + if (address.is_ip_v6()) { + ret = ::bind(_socket, address.get_sock_addr(), sizeof(sockaddr_in6)); + } else { + ret = ::bind(_socket, address.get_sock_addr(), sizeof(sockaddr_in)); + } + + if (ret != 0) { +#if defined(_WIN64) || defined(_WIN32) + return WSAGetLastError(); +#else + return errno; +#endif + } + + return ret; +} + +int Socket::listen() { + ERR_FAIL_COND_V(_socket == 0, -1); + + return ::listen(_socket, SOMAXCONN); +} + +int Socket::accept(Socket *sock) { + ERR_FAIL_COND_V(!sock, -1); + + struct sockaddr_in6 addr6; + memset(&addr6, 0, sizeof(addr6)); + socklen_t size = sizeof(addr6); + +#ifdef __linux__ + int connfd = ::accept4(_socket, (struct sockaddr *)&addr6, &size, SOCK_NONBLOCK | SOCK_CLOEXEC); +#else + int connfd = static_cast(::accept(_socket, (struct sockaddr *)&addr6, &size)); +#endif + + if (connfd >= 0) { + sock->_socket = connfd; + sock->_address.set_sock_addr_inet6(addr6); +#ifndef __linux__ + sock->set_non_block(); + sock->set_close_on_exit(); +#endif + } + + return connfd; +} + +int Socket::close_write() { + ERR_FAIL_COND_V(_socket == 0, -1); + +#if !defined(_WIN64) && !defined(_WIN32) + return ::shutdown(_socket, SHUT_WR); +#else + return ::shutdown(_socket, SD_SEND); +#endif +} + +int Socket::read(char *buffer, uint64_t len) { + //ERR_FAIL_COND_V(_socket == 0, -1); + +#if !defined(_WIN64) && !defined(_WIN32) + return ::read(_socket, buffer, len); +#else + return recv(_socket, buffer, static_cast(len), 0); +#endif +} + +int Socket::send(const char *buffer, uint64_t len) { + //ERR_FAIL_COND_V(_socket == 0, -1); + +#if !defined(_WIN64) && !defined(_WIN32) + return write(_socket, buffer, len); +#else + errno = 0; + return ::send(_socket, buffer, static_cast(len), 0); +#endif +} + +void Socket::set_tcp_nodelay(bool on) { + ERR_FAIL_COND(_socket == 0); + +#if defined(_WIN64) || defined(_WIN32) + char optval = on ? 1 : 0; +#else + int optval = on ? 1 : 0; +#endif + ::setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, &optval, static_cast(sizeof optval)); +} + +void Socket::set_reuse_addr(bool on) { + ERR_FAIL_COND(_socket == 0); + +#if defined(_WIN64) || defined(_WIN32) + char optval = on ? 1 : 0; +#else + int optval = on ? 1 : 0; +#endif + ::setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, &optval, static_cast(sizeof optval)); +} + +int Socket::set_reuse_port(bool on) { + ERR_FAIL_COND_V(_socket == 0, -1); + +#ifdef SO_REUSEPORT +#if defined(_WIN64) || defined(_WIN32) + char optval = on ? 1 : 0; +#else + int optval = on ? 1 : 0; +#endif + int ret = ::setsockopt(_socket, SOL_SOCKET, SO_REUSEPORT, &optval, static_cast(sizeof optval)); + + return ret; +#else + if (on) { + //LOG_ERR("SO_REUSEPORT is not supported."); + return -1; + } + + return 0; +#endif +} + +void Socket::set_keep_alive(bool on) { + ERR_FAIL_COND(_socket == 0); + +#if defined(_WIN64) || defined(_WIN32) + char optval = on ? 1 : 0; +#else + int optval = on ? 1 : 0; +#endif + ::setsockopt(_socket, SOL_SOCKET, SO_KEEPALIVE, &optval, static_cast(sizeof optval)); +} + +struct sockaddr_in6 Socket::get_local_addr(int *r_err) { + struct sockaddr_in6 localaddr = { 0 }; + + ERR_FAIL_COND_V(_socket == 0, localaddr); + + memset(&localaddr, 0, sizeof(localaddr)); + socklen_t addrlen = static_cast(sizeof localaddr); + + int err = ::getsockname(_socket, static_cast((void *)(&localaddr)), &addrlen); + + if (r_err) { + *r_err = err; + } + + return localaddr; +} + +struct sockaddr_in6 Socket::get_peer_addr(int *r_err) { + struct sockaddr_in6 peeraddr = { 0 }; + + ERR_FAIL_COND_V(_socket == 0, peeraddr); + + memset(&peeraddr, 0, sizeof(peeraddr)); + socklen_t addrlen = static_cast(sizeof peeraddr); + + int err = ::getpeername(_socket, static_cast((void *)(&peeraddr)), &addrlen); + + if (r_err) { + *r_err = err; + } + + return peeraddr; +} + +int Socket::global_init() { +#if defined(_WIN64) || defined(_WIN32) + int r; + WSADATA wsa_data; + + r = WSAStartup(MAKEWORD(2, 2), &wsa_data); + + return r; +#else + return 0; +#endif +} + +Socket::Socket() { + _socket = 0; +} + +Socket::Socket(int socketFD, const InetAddress &address) { + _socket = socketFD; + _address = address; +} + +Socket::~Socket() { + if (_socket >= 0) { + close_socket(); + } +} diff --git a/sfwl/core/socket.h b/sfwl/core/socket.h new file mode 100644 index 0000000..a0afa0f --- /dev/null +++ b/sfwl/core/socket.h @@ -0,0 +1,69 @@ +//--STRIP +#ifndef SOCKET_H +#define SOCKET_H +//--STRIP + +//Based on: + +/** + * + * Socket.h + * An Tao + * + * Public header file in trantor lib. + * + * Copyright 2018, An Tao. All rights reserved. + * Use of this source code is governed by a BSD-style license + * that can be found in the License file. + * + * + */ + +//--STRIP +#include "inet_address.h" +//--STRIP + +class Socket { +public: + void create_net_socket(); + void create(int family); + void close_socket(); + + int connect(const InetAddress &address); + int bind_address(const InetAddress &address); + int listen(); + int accept(Socket *sock); + + int close_write(); + + int read(char *buffer, uint64_t len); + int send(const char *buffer, uint64_t len); + + bool is_self_connect(); + + void set_tcp_nodelay(bool on); + void set_reuse_addr(bool on); + int set_reuse_port(bool on); + void set_keep_alive(bool on); + + int set_non_block(); + int set_close_on_exit(); + + int get_error(); + + struct sockaddr_in6 get_local_addr(int *r_err = NULL); + struct sockaddr_in6 get_peer_addr(int *r_err = NULL); + + static int global_init(); + + Socket(); + Socket(int socketFD, const InetAddress &address); + ~Socket(); + + int _socket; + InetAddress _address; +}; + +//--STRIP +#endif // SOCKET_H +//--STRIP diff --git a/sfwl/core/sort_array.h b/sfwl/core/sort_array.h index 379149d..73fb83d 100644 --- a/sfwl/core/sort_array.h +++ b/sfwl/core/sort_array.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef SORT_ARRAY_H #define SORT_ARRAY_H +//--STRIP /*************************************************************************/ /* sort_array.h */ @@ -297,4 +299,6 @@ public: #undef ERR_BAD_COMPARE +//--STRIP #endif // SORT_ARRAY_H +//--STRIP diff --git a/sfwl/core/spin_lock.h b/sfwl/core/spin_lock.h index b993f73..396bf40 100644 --- a/sfwl/core/spin_lock.h +++ b/sfwl/core/spin_lock.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef SPIN_LOCK_H #define SPIN_LOCK_H +//--STRIP /*************************************************************************/ /* spin_lock.h */ @@ -25,4 +27,7 @@ public: locked.clear(std::memory_order_release); } }; + +//--STRIP #endif // SPIN_LOCK_H +//--STRIP diff --git a/sfwl/core/string_name.h b/sfwl/core/string_name.h index 6a97ff6..33b1a0a 100644 --- a/sfwl/core/string_name.h +++ b/sfwl/core/string_name.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef STRING_NAME_H #define STRING_NAME_H +//--STRIP /*************************************************************************/ /* string_name.h */ @@ -205,4 +207,6 @@ StringName _scs_create(const char *p_chr, bool p_static = false); //#define SNAME(m_arg) ([]() -> const StringName & { static StringName sname = _scs_create(m_arg, true); return sname; })() +//--STRIP #endif // STRING_NAME_H +//--STRIP diff --git a/sfwl/core/sub_process.cpp b/sfwl/core/sub_process.cpp new file mode 100644 index 0000000..662dcce --- /dev/null +++ b/sfwl/core/sub_process.cpp @@ -0,0 +1,761 @@ +/*************************************************************************/ +/* sub_process.cpp */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "sub_process.h" +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include + +typedef struct tagLOGCONTEXTW { + WCHAR lcName[40]; + UINT lcOptions; + UINT lcStatus; + UINT lcLocks; + UINT lcMsgBase; + UINT lcDevice; + UINT lcPktRate; + DWORD lcPktData; + DWORD lcPktMode; + DWORD lcMoveMask; + DWORD lcBtnDnMask; + DWORD lcBtnUpMask; + LONG lcInOrgX; + LONG lcInOrgY; + LONG lcInOrgZ; + LONG lcInExtX; + LONG lcInExtY; + LONG lcInExtZ; + LONG lcOutOrgX; + LONG lcOutOrgY; + LONG lcOutOrgZ; + LONG lcOutExtX; + LONG lcOutExtY; + LONG lcOutExtZ; + DWORD lcSensX; + DWORD lcSensY; + DWORD lcSensZ; + BOOL lcSysMode; + int lcSysOrgX; + int lcSysOrgY; + int lcSysExtX; + int lcSysExtY; + DWORD lcSysSensX; + DWORD lcSysSensY; +} LOGCONTEXTW; + +typedef HANDLE(WINAPI *WTOpenPtr)(HWND p_window, LOGCONTEXTW *p_ctx, BOOL p_enable); + +// TODO clean these up +#include +#include +#include +#include +#include +#include +#include + +struct SubProcess::SubProcessWindowsData { + struct ProcessInfo { + STARTUPINFO si; + PROCESS_INFORMATION pi; + }; + + HANDLE _pipe_handles[2]; + ProcessInfo _process_info; +}; + +Error SubProcess::start() { + if (_executable_path.empty()) { + return ERR_FILE_BAD_PATH; + } + + if (is_process_running()) { + return ERR_BUSY; + } + + String path = _executable_path.replace("/", "\\"); + + String cmdline = _quote_command_line_argument(path); + for (int i = 0; i < _arguments.size(); ++i) { + cmdline += " " + _quote_command_line_argument(_arguments[i]); + } + + ZeroMemory(&_data->_process_info.si, sizeof(_data->_process_info.si)); + _data->_process_info.si.cb = sizeof(_data->_process_info.si); + ZeroMemory(&_data->_process_info.pi, sizeof(_data->_process_info.pi)); + LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&_data->_process_info.si; + + Char16String modstr = cmdline.utf16(); // Windows wants to change this no idea why. + + bool inherit_handles = false; + + if (_read_output) { + // Create pipe for StdOut and StdErr. + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = NULL; + + ERR_FAIL_COND_V(!CreatePipe(&_data->_pipe_handles[0], &_data->_pipe_handles[1], &sa, 0), ERR_CANT_FORK); + ERR_FAIL_COND_V(!SetHandleInformation(_data->_pipe_handles[0], HANDLE_FLAG_INHERIT, 0), ERR_CANT_FORK); // Read handle is for host process only and should not be inherited. + + _data->_process_info.si.dwFlags |= STARTF_USESTDHANDLES; + _data->_process_info.si.hStdOutput = _data->_pipe_handles[1]; + if (_read_std_err) { + _data->_process_info.si.hStdError = _data->_pipe_handles[1]; + } + inherit_handles = true; + } + + DWORD creaton_flags = NORMAL_PRIORITY_CLASS; + if (_open_console) { + creaton_flags |= CREATE_NEW_CONSOLE; + } else { + creaton_flags |= CREATE_NO_WINDOW; + } + + int ret = CreateProcessW(nullptr, (LPWSTR)(modstr.ptrw()), nullptr, nullptr, inherit_handles, creaton_flags, nullptr, nullptr, si_w, &_data->_process_info.pi); + if (!ret && _read_output) { + CloseHandle(_data->_pipe_handles[0]); // Cleanup pipe handles. + CloseHandle(_data->_pipe_handles[1]); + + _data->_pipe_handles[0] = NULL; + _data->_pipe_handles[1] = NULL; + } + + ERR_FAIL_COND_V(ret == 0, ERR_CANT_FORK); + + if (_blocking) { + if (_read_output) { + CloseHandle(_data->_pipe_handles[1]); // Close pipe write handle (only child process is writing). + + int bytes_in_buffer = 0; + + const int CHUNK_SIZE = 4096; + DWORD read = 0; + for (;;) { // Read StdOut and StdErr from pipe. + _bytes.resize(bytes_in_buffer + CHUNK_SIZE); + const bool success = ReadFile(_data->_pipe_handles[0], _bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL); + if (!success || read == 0) { + break; + } + // Assume that all possible encodings are ASCII-compatible. + // Break at newline to allow receiving long output in portions. + int newline_index = -1; + for (int i = read - 1; i >= 0; i--) { + if (_bytes[bytes_in_buffer + i] == '\n') { + newline_index = i; + break; + } + } + + if (newline_index == -1) { + bytes_in_buffer += read; + continue; + } + + const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); + _append_to_pipe(_bytes.ptr(), bytes_to_convert); + + bytes_in_buffer = read - (newline_index + 1); + memmove(_bytes.ptr(), _bytes.ptr() + bytes_to_convert, bytes_in_buffer); + } + + if (bytes_in_buffer > 0) { + _append_to_pipe(_bytes.ptr(), bytes_in_buffer); + } + + CloseHandle(_data->_pipe_handles[0]); // Close pipe read handle. + } + + WaitForSingleObject(_data->_process_info.pi.hProcess, INFINITE); + + DWORD ret2; + GetExitCodeProcess(_data->_process_info.pi.hProcess, &ret2); + _exitcode = ret2; + + CloseHandle(_data->_process_info.pi.hProcess); + CloseHandle(_data->_process_info.pi.hThread); + } else { + if (_read_output) { + //eventually we will need to keep this + CloseHandle(_data->_pipe_handles[1]); // Close pipe write handle (only child process is writing). + _data->_pipe_handles[1] = NULL; + } + + _process_started = true; + + ProcessID pid = _data->_process_info.pi.dwProcessId; + _process_id = pid; + } + + return OK; +} + +Error SubProcess::stop() { + if (!_process_started) { + return OK; + } + + if (_data->_pipe_handles[0]) { + CloseHandle(_data->_pipe_handles[0]); // Cleanup pipe handles. + _data->_pipe_handles[0] = NULL; + } + + if (_data->_pipe_handles[1]) { + CloseHandle(_data->_pipe_handles[1]); + _data->_pipe_handles[1] = NULL; + } + + const int ret = TerminateProcess(_data->_process_info.pi.hProcess, 0); + + CloseHandle(_data->_process_info.pi.hProcess); + CloseHandle(_data->_process_info.pi.hThread); + + ZeroMemory(&_data->_process_info.si, sizeof(_data->_process_info.si)); + _data->_process_info.si.cb = sizeof(_data->_process_info.si); + ZeroMemory(&_data->_process_info.pi, sizeof(_data->_process_info.pi)); + + _process_started = false; + + return ret != 0 ? OK : FAILED; +} + +Error SubProcess::poll() { + if (!_process_started) { + return FAILED; + } + + if (!_data->_pipe_handles[0]) { + return FAILED; + } + + _pipe.clear(); + + int bytes_in_buffer = 0; + + const int CHUNK_SIZE = 4096; + DWORD read = 0; + + _bytes.resize(bytes_in_buffer + CHUNK_SIZE); + const bool success = ReadFile(_data->_pipe_handles[0], _bytes.ptr() + bytes_in_buffer, CHUNK_SIZE, &read, NULL); + + if (!success) { + stop(); + return ERR_FILE_EOF; + } + + if (read == 0) { + return OK; + } + + // Assume that all possible encodings are ASCII-compatible. + // Break at newline to allow receiving long output in portions. + int newline_index = -1; + for (int i = read - 1; i >= 0; i--) { + if (_bytes[bytes_in_buffer + i] == '\n') { + newline_index = i; + break; + } + } + + if (newline_index == -1) { + bytes_in_buffer += read; + return OK; + } + + const int bytes_to_convert = bytes_in_buffer + (newline_index + 1); + _append_to_pipe(_bytes.ptr(), bytes_to_convert); + + bytes_in_buffer = read - (newline_index + 1); + memmove(_bytes.ptr(), _bytes.ptr() + bytes_to_convert, bytes_in_buffer); + + if (bytes_in_buffer > 0) { + _append_to_pipe(_bytes.ptr(), bytes_in_buffer); + } + + return OK; +} + +Error SubProcess::send_signal(const int p_signal) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +Error SubProcess::send_data(const String &p_data) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +bool SubProcess::is_process_running() const { + if (_process_id == 0) { + return false; + } + + if (!_process_started) { + return false; + } + + DWORD dw_exit_code = 0; + if (!GetExitCodeProcess(_data->_process_info.pi.hProcess, &dw_exit_code)) { + return false; + } + + if (dw_exit_code != STILL_ACTIVE) { + return false; + } + + return true; +} + +String SubProcess::_quote_command_line_argument(const String &p_text) const { + for (int i = 0; i < p_text.size(); i++) { + CharType c = p_text[i]; + if (c == ' ' || c == '&' || c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}' || c == '^' || c == '=' || c == ';' || c == '!' || c == '\'' || c == '+' || c == ',' || c == '`' || c == '~') { + return "\"" + p_text + "\""; + } + } + return p_text; +} + +void SubProcess::_append_to_pipe(char *p_bytes, int p_size) { + // Try to convert from default ANSI code page to Unicode. + LocalVector wchars; + int total_wchars = MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, nullptr, 0); + if (total_wchars > 0) { + wchars.resize(total_wchars); + if (MultiByteToWideChar(CP_ACP, 0, p_bytes, p_size, wchars.ptr(), total_wchars) == 0) { + wchars.clear(); + } + } + + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + if (wchars.empty()) { + // Let's hope it's compatible with UTF-8. + _pipe += String::utf8(p_bytes, p_size); + } else { + _pipe += String(wchars.ptr(), total_wchars); + } + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } +} + +SubProcess::SubProcess() { + _data = memnew(SubProcessWindowsData); + + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; + + _data->_pipe_handles[0] = NULL; + _data->_pipe_handles[1] = NULL; + + _process_started = false; + + ZeroMemory(&_data->_process_info.si, sizeof(_data->_process_info.si)); + _data->_process_info.si.cb = sizeof(_data->_process_info.si); + ZeroMemory(&_data->_process_info.pi, sizeof(_data->_process_info.pi)); +} +SubProcess::~SubProcess() { + stop(); + + memdelete(_data); +} + +#else + +#include +#include +#include +#include +#include +#include +#include + +Error SubProcess::start() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + if (_executable_path.empty()) { + return ERR_FILE_BAD_PATH; + } + + if (is_process_running()) { + return ERR_BUSY; + } + + if (_blocking && _read_output) { + String argss; + argss = "\"" + _executable_path + "\""; + + for (int i = 0; i < _arguments.size(); i++) { + argss += String(" \"") + _arguments[i] + "\""; + } + + if (_read_std_err) { + argss += " 2>&1"; // Read stderr too + } else { + argss += " 2>/dev/null"; //silence stderr + } + FILE *f = popen(argss.utf8().get_data(), "r"); + + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + + char buf[65535]; + + while (fgets(buf, 65535, f)) { + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + _pipe += String::utf8(buf); + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } + } + int rv = pclose(f); + + _exitcode = WEXITSTATUS(rv); + + return OK; + } + + if (!_blocking && _read_output) { + String argss; + argss = "\"" + _executable_path + "\""; + + for (int i = 0; i < _arguments.size(); i++) { + argss += String(" \"") + _arguments[i] + "\""; + } + + if (_read_std_err) { + argss += " 2>&1"; // Read stderr too + } else { + argss += " 2>/dev/null"; //silence stderr + } + + _process_fp = popen(argss.utf8().get_data(), "r"); + + ERR_FAIL_COND_V_MSG(!_process_fp, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); + + return OK; + } + + // We just run it, no need to worry about output + + pid_t pid = fork(); + ERR_FAIL_COND_V(pid < 0, ERR_CANT_FORK); + + if (pid == 0) { + // is child + + if (!_blocking) { + // For non blocking calls, create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at end. + setsid(); + } + + Vector cs; + cs.push_back(_executable_path.utf8()); + for (int i = 0; i < _arguments.size(); i++) { + cs.push_back(_arguments[i].utf8()); + } + + Vector args; + for (int i = 0; i < cs.size(); i++) { + args.push_back((char *)cs[i].get_data()); + } + args.push_back(0); + + execvp(_executable_path.utf8().get_data(), &args[0]); + // still alive? something failed.. + fprintf(stderr, "**ERROR** SubProcess::execute - Could not create child process while executing: %s\n", _executable_path.utf8().get_data()); + raise(SIGKILL); + } + + if (_blocking) { + int status; + waitpid(pid, &status, 0); + + _exitcode = WIFEXITED(status) ? WEXITSTATUS(status) : status; + } else { + _process_id = pid; + } + + return OK; +#endif +} + +Error SubProcess::stop() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + if (_process_fp) { + int rv = pclose(_process_fp); + _process_fp = NULL; + _exitcode = WEXITSTATUS(rv); + _process_id = 0; + return OK; + } + + if (_process_id) { + int ret = ::kill(_process_id, SIGKILL); + + if (!ret) { + //avoid zombie process + int st; + ::waitpid(_process_id, &st, 0); + } + + _process_id = 0; + + return ret ? ERR_INVALID_PARAMETER : OK; + } + + return OK; +#endif +} + +Error SubProcess::poll() { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else + + if (_process_fp) { + if (fgets(_process_buf, 65535, _process_fp)) { + if (_pipe_mutex) { + _pipe_mutex->lock(); + } + _pipe = String::utf8(_process_buf); + if (_pipe_mutex) { + _pipe_mutex->unlock(); + } + } else { + // The process finished + // Cleanup: + stop(); + return ERR_FILE_EOF; + } + } + + return OK; +#endif +} + +Error SubProcess::send_signal(const int p_signal) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +Error SubProcess::send_data(const String &p_data) { + //Not Yet Impl + ERR_FAIL_V(ERR_BUG); +} + +bool SubProcess::is_process_running() const { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(false); +#else + + if (_process_fp) { + return !feof(_process_fp); + } + + if (_process_id == 0) { + return false; + } + + int status = 0; + if (waitpid(_process_id, &status, WNOHANG) != 0) { + return false; + } + + return true; +#endif +} + +SubProcess::SubProcess() { + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; + + _process_fp = NULL; +} +SubProcess::~SubProcess() { + stop(); +} + +#endif + +SubProcess *SubProcess::create() { + return memnew(SubProcess()); +} + +String SubProcess::get_executable_path() const { + return _executable_path; +} +void SubProcess::set_executable_path(const String &p_executable_path) { + ERR_FAIL_COND(is_process_running()); + + _executable_path = p_executable_path; +} + +Vector SubProcess::get_arguments() const { + return _arguments; +} +void SubProcess::set_arguments(const Vector &p_arguments) { + ERR_FAIL_COND(is_process_running()); + + _arguments = p_arguments; +} + +bool SubProcess::get_blocking() const { + return _blocking; +} +void SubProcess::set_blocking(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _blocking = p_value; +} + +bool SubProcess::get_read_output() const { + return _read_output; +} +void SubProcess::set_read_output(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_output = p_value; +} + +bool SubProcess::get_read_std() const { + return _read_std; +} +void SubProcess::set_read_std(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_std = p_value; +} + +bool SubProcess::get_read_std_err() const { + return _read_std_err; +} +void SubProcess::set_read_std_err(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _read_std_err = p_value; +} + +bool SubProcess::get_use_pipe_mutex() const { + return _use_pipe_mutex; +} +void SubProcess::set_use_pipe_mutex(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _use_pipe_mutex = p_value; +} + +bool SubProcess::get_open_console() const { + return _open_console; +} +void SubProcess::set_open_console(const bool p_value) { + ERR_FAIL_COND(is_process_running()); + + _open_console = p_value; +} + +Error SubProcess::run(const String &p_executable_path, const Vector &p_arguments, bool p_output, bool p_blocking, bool p_read_std_err, bool p_use_pipe_mutex, bool p_open_console) { + if (is_process_running()) { + return ERR_ALREADY_IN_USE; + } + + _executable_path = p_executable_path; + _arguments = p_arguments; + + _blocking = p_blocking; + + _read_output = p_output; + + _read_std = true; + _read_std_err = p_read_std_err; + + _use_pipe_mutex = p_use_pipe_mutex; + + _open_console = p_open_console; + + _setup_pipe_mutex(); + + return start(); +} + +/* +SubProcess::SubProcess() { + _blocking = false; + + _read_output = true; + + _read_std = true; + _read_std_err = false; + + _use_pipe_mutex = false; + + _pipe_mutex = NULL; + + _open_console = false; + + _process_id = ProcessID(); + _exitcode = 0; +}; +*/ + +void SubProcess::_setup_pipe_mutex() { + if (_use_pipe_mutex) { + if (!_pipe_mutex) { + _pipe_mutex = memnew(Mutex); + } + } else { + if (_pipe_mutex) { + memdelete(_pipe_mutex); + _pipe_mutex = NULL; + } + } +} diff --git a/sfwl/core/sub_process.h b/sfwl/core/sub_process.h new file mode 100644 index 0000000..8aa2833 --- /dev/null +++ b/sfwl/core/sub_process.h @@ -0,0 +1,160 @@ +//--STRIP +#ifndef SUB_PROCESS_H +#define SUB_PROCESS_H +//--STRIP + +/*************************************************************************/ +/* sub_process.h */ +/* From https://github.com/Relintai/pandemonium_engine (MIT) */ +/*************************************************************************/ + +//--STRIP +#include "core/list.h" +#include "core/math_defs.h" +#include "core/memory.h" +#include "core/mutex.h" +#include "core/typedefs.h" +#include "core/ustring.h" +#include "core/error_list.h" + +#include +//--STRIP + +#if defined(_WIN64) || defined(_WIN32) + +//--STRIP +#include "core/local_vector.h" +//--STRIP + +#endif + +/** + * Multi-Platform abstraction for running and communicating with sub processes + */ + +class SubProcess { +public: + typedef int64_t ProcessID; + + #if defined(_WIN64) || defined(_WIN32) + struct SubProcessWindowsData; + #endif + + static SubProcess *create(); + + String get_executable_path() const; + void set_executable_path(const String &p_executable_path); + + Vector get_arguments() const; + void set_arguments(const Vector &p_arguments); + + bool get_blocking() const; + void set_blocking(const bool p_value); + + bool get_read_output() const; + void set_read_output(const bool p_value); + + bool get_read_std() const; + void set_read_std(const bool p_value); + + bool get_read_std_err() const; + void set_read_std_err(const bool p_value); + + bool get_use_pipe_mutex() const; + void set_use_pipe_mutex(const bool p_value); + + bool get_open_console() const; + void set_open_console(const bool p_value); + + String get_data() const { + return _pipe; + } + + int get_process_id() const { + return _process_id; + } + + int get_exitcode() const { + return _exitcode; + } + + virtual Error start(); + virtual Error stop(); + virtual Error poll(); + virtual Error send_signal(const int p_signal); + virtual Error send_data(const String &p_data); + virtual bool is_process_running() const; + + Error run(const String &p_executable_path, const Vector &p_arguments = Vector(), bool p_output = true, bool p_blocking = true, bool p_read_std_err = false, bool p_use_pipe_mutex = false, bool p_open_console = false); + + SubProcess(); + virtual ~SubProcess(); + +protected: + void _setup_pipe_mutex(); + + String _executable_path; + Vector _arguments; + + bool _blocking; + + bool _read_output; + + bool _read_std; + bool _read_std_err; + + String _pipe; + + bool _use_pipe_mutex; + + Mutex *_pipe_mutex; + + bool _open_console; + + ProcessID _process_id; + int _exitcode; + +#if defined(_WIN64) || defined(_WIN32) + + String _quote_command_line_argument(const String &p_text) const; + void _append_to_pipe(char *p_bytes, int p_size); + + bool _process_started; + LocalVector _bytes; + + SubProcessWindowsData *_data; + +#else + FILE *_process_fp; + char _process_buf[65535]; +#endif +}; + +struct SubProcessRef { + SubProcess *f; + + _FORCE_INLINE_ bool is_null() const { return f == nullptr; } + _FORCE_INLINE_ bool is_valid() const { return f != nullptr; } + + _FORCE_INLINE_ operator bool() const { return f != nullptr; } + _FORCE_INLINE_ operator SubProcess *() { return f; } + + _FORCE_INLINE_ SubProcess *operator->() { + return f; + } + + SubProcessRef(SubProcess *fa) { f = fa; } + SubProcessRef(SubProcessRef &&other) { + f = other.f; + other.f = nullptr; + } + ~SubProcessRef() { + if (f) { + memdelete(f); + } + } +}; + +//--STRIP +#endif +//--STRIP diff --git a/sfwl/core/thread.cpp b/sfwl/core/thread.cpp index fc06c6b..0b5c26a 100644 --- a/sfwl/core/thread.cpp +++ b/sfwl/core/thread.cpp @@ -111,7 +111,4 @@ Thread::ID Thread::get_caller_id() { return caller_id; } } - -//--STRIP -#endif // THREAD_H -//--STRIP +#endif diff --git a/sfwl/core/thread_safe.h b/sfwl/core/thread_safe.h index 4c58395..51365d7 100644 --- a/sfwl/core/thread_safe.h +++ b/sfwl/core/thread_safe.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef THREAD_SAFE_H #define THREAD_SAFE_H +//--STRIP /*************************************************************************/ /* thread_safe.h */ @@ -15,4 +17,6 @@ #define _THREAD_SAFE_LOCK_ _thread_safe_.lock(); #define _THREAD_SAFE_UNLOCK_ _thread_safe_.unlock(); +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/tight_local_vector.h b/sfwl/core/tight_local_vector.h index 3e404e8..f21a97d 100644 --- a/sfwl/core/tight_local_vector.h +++ b/sfwl/core/tight_local_vector.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef TIGHT_LOCAL_VECTOR_H #define TIGHT_LOCAL_VECTOR_H +//--STRIP /*************************************************************************/ /* tight_local_vector.h */ @@ -292,4 +294,6 @@ template class TightLocalVectori : public TightLocalVector { }; +//--STRIP #endif // TIGHT_LOCAL_VECTOR_H +//--STRIP diff --git a/sfwl/core/typedefs.h b/sfwl/core/typedefs.h index 198b3b0..f13c6f2 100644 --- a/sfwl/core/typedefs.h +++ b/sfwl/core/typedefs.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef TYPEDEFS_H #define TYPEDEFS_H +//--STRIP /*************************************************************************/ /* typedefs.h */ @@ -403,4 +405,6 @@ struct _GlobalLock { #define HAS_TRIVIAL_COPY(T) __has_trivial_copy(T) #endif +//--STRIP #endif // TYPEDEFS_H +//--STRIP diff --git a/sfwl/core/ucaps.h b/sfwl/core/ucaps.h index 0c7a051..a70b0d3 100644 --- a/sfwl/core/ucaps.h +++ b/sfwl/core/ucaps.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef UCAPS_H #define UCAPS_H +//--STRIP /*************************************************************************/ /* ucaps.h */ @@ -1386,4 +1388,7 @@ static int _find_lower(int ch) { return ch; } + +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/ustring.cpp b/sfwl/core/ustring.cpp index 9530d93..e54da02 100644 --- a/sfwl/core/ustring.cpp +++ b/sfwl/core/ustring.cpp @@ -10,6 +10,7 @@ //--STRIP #include "core/ustring.h" +#include "core/color.h" #include "core/math_funcs.h" #include "core/memory.h" #include "ucaps.h" @@ -4563,6 +4564,10 @@ bool String::is_valid_unsigned_integer() const { return true; } +bool String::is_valid_html_color() const { + return Color::html_is_valid(*this); +} + bool String::is_valid_filename() const { String stripped = strip_edges(); if (*this != stripped) { diff --git a/sfwl/core/ustring.h b/sfwl/core/ustring.h index e7364ed..f5318b9 100644 --- a/sfwl/core/ustring.h +++ b/sfwl/core/ustring.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef USTRING_H #define USTRING_H +//--STRIP /*************************************************************************/ /* ustring.h */ @@ -480,6 +482,7 @@ public: bool is_valid_integer() const; bool is_valid_float() const; bool is_valid_hex_number(bool p_with_prefix) const; + bool is_valid_html_color() const; bool is_valid_ip_address() const; bool is_valid_filename() const; bool is_valid_bool() const; @@ -603,4 +606,6 @@ String RTR(const String &); bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); +//--STRIP #endif // USTRING_H +//--STRIP diff --git a/sfwl/core/vector.h b/sfwl/core/vector.h index 3d8e16b..c66176c 100644 --- a/sfwl/core/vector.h +++ b/sfwl/core/vector.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef VECTOR_H #define VECTOR_H +//--STRIP /*************************************************************************/ /* vector.h */ @@ -171,4 +173,6 @@ bool Vector::push_back(T p_elem) { return false; } +//--STRIP #endif +//--STRIP diff --git a/sfwl/core/version.h b/sfwl/core/version.h new file mode 100644 index 0000000..e1881dd --- /dev/null +++ b/sfwl/core/version.h @@ -0,0 +1,10 @@ +//--STRIP +#ifndef SFW_VERSION_H +#define SFW_VERSION_H +//--STRIP + +#define SFW_VERSION 1 + +//--STRIP +#endif +//--STRIP diff --git a/sfwl/core/vmap.h b/sfwl/core/vmap.h index 8045625..e974590 100644 --- a/sfwl/core/vmap.h +++ b/sfwl/core/vmap.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef VMAP_H #define VMAP_H +//--STRIP /*************************************************************************/ /* vmap.h */ @@ -176,4 +178,7 @@ public: return *this; } }; + +//--STRIP #endif // VMAP_H +//--STRIP diff --git a/sfwl/core/vset.h b/sfwl/core/vset.h index d67690b..a8921ca 100644 --- a/sfwl/core/vset.h +++ b/sfwl/core/vset.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef VSET_H #define VSET_H +//--STRIP /*************************************************************************/ /* vset.h */ @@ -115,4 +117,6 @@ public: } }; +//--STRIP #endif // VSET_H +//--STRIP diff --git a/sfwl/object/array.h b/sfwl/object/array.h index aaaaddd..09b8978 100644 --- a/sfwl/object/array.h +++ b/sfwl/object/array.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef ARRAY_H #define ARRAY_H +//--STRIP /*************************************************************************/ /* array.h */ @@ -89,4 +91,6 @@ public: ~Array(); }; +//--STRIP #endif // ARRAY_H +//--STRIP diff --git a/sfwl/object/core_string_names.h b/sfwl/object/core_string_names.h index 29acf05..80abf2e 100644 --- a/sfwl/object/core_string_names.h +++ b/sfwl/object/core_string_names.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef CORE_STRING_NAMES_H #define CORE_STRING_NAMES_H +//--STRIP /*************************************************************************/ /* core_string_names.h */ @@ -65,4 +67,6 @@ public: StringName a8; }; +//--STRIP #endif // SCENE_STRING_NAMES_H +//--STRIP diff --git a/sfwl/object/dictionary.h b/sfwl/object/dictionary.h index d14a251..9526fea 100644 --- a/sfwl/object/dictionary.h +++ b/sfwl/object/dictionary.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef DICTIONARY_H #define DICTIONARY_H +//--STRIP /*************************************************************************/ /* dictionary.h */ @@ -69,4 +71,6 @@ public: ~Dictionary(); }; +//--STRIP #endif // DICTIONARY_H +//--STRIP diff --git a/sfwl/object/object.h b/sfwl/object/object.h index bd0444a..28aa567 100644 --- a/sfwl/object/object.h +++ b/sfwl/object/object.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef OBJECT_H #define OBJECT_H +//--STRIP //--STRIP #include "core/hash_map.h" @@ -25,7 +27,7 @@ private: void operator=(const m_class &p_rval) {} \ \ public: \ - virtual String get_class() const { \ + virtual String get_class() const { \ return String(#m_class); \ } \ virtual const StringName *_get_class_namev() const { \ @@ -50,10 +52,10 @@ public: static String inherits_static() { \ return String(#m_inherits); \ } \ - virtual bool is_class(const String &p_class) const { \ + virtual bool is_class(const String &p_class) const { \ return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \ } \ - virtual bool is_class_ptr(void *p_ptr) const { \ + virtual bool is_class_ptr(void *p_ptr) const { \ return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); \ } \ static void get_valid_parents_static(Vector *p_parents) { \ @@ -280,4 +282,6 @@ public: } }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/object_id.h b/sfwl/object/object_id.h index 3cba6fe..e887cdf 100644 --- a/sfwl/object/object_id.h +++ b/sfwl/object/object_id.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef OBJECTID_H #define OBJECTID_H +//--STRIP /*************************************************************************/ /* object_id.h */ @@ -12,4 +14,6 @@ typedef uint64_t ObjectID; +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/object_rc.h b/sfwl/object/object_rc.h index eae71c9..e59aa7a 100644 --- a/sfwl/object/object_rc.h +++ b/sfwl/object/object_rc.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef OBJECTRC_H #define OBJECTRC_H +//--STRIP /*************************************************************************/ /* object_rc.h */ @@ -51,4 +53,6 @@ public: } }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/psignal.h b/sfwl/object/psignal.h index 2d6d435..11a817b 100644 --- a/sfwl/object/psignal.h +++ b/sfwl/object/psignal.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef SIGNAL_H #define SIGNAL_H +//--STRIP //--STRIP #include "core/vector.h" @@ -171,4 +173,6 @@ bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) { return false; } +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/ref_ptr.h b/sfwl/object/ref_ptr.h index 0f1c9c4..9da7002 100644 --- a/sfwl/object/ref_ptr.h +++ b/sfwl/object/ref_ptr.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef REF_PTR_H #define REF_PTR_H +//--STRIP /*************************************************************************/ /* ref_ptr.h */ @@ -35,4 +37,6 @@ public: ~RefPtr(); }; +//--STRIP #endif // REF_PTR_H +//--STRIP diff --git a/sfwl/object/reference.h b/sfwl/object/reference.h index 948ef52..ee7e7ca 100644 --- a/sfwl/object/reference.h +++ b/sfwl/object/reference.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef REFERENCE_H #define REFERENCE_H +//--STRIP /*************************************************************************/ /* reference.h */ @@ -267,4 +269,6 @@ public: }; */ +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/resource.h b/sfwl/object/resource.h index 6ed1fb2..8f839a4 100644 --- a/sfwl/object/resource.h +++ b/sfwl/object/resource.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef RESOURCE_H #define RESOURCE_H +//--STRIP //--STRIP #include "object/reference.h" @@ -22,4 +24,6 @@ public: virtual ~Resource(); }; +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/variant.cpp b/sfwl/object/variant.cpp index 7076813..6a9c8a0 100644 --- a/sfwl/object/variant.cpp +++ b/sfwl/object/variant.cpp @@ -36,6 +36,58 @@ String Variant::get_type_name(Variant::Type p_type) { return "String"; } break; + // math types + case RECT2: { + return "Rect2"; + } break; + case RECT2I: { + return "Rect2i"; + } break; + case VECTOR2: { + return "Vector2"; + } break; + case VECTOR2I: { + return "Vector2i"; + } break; + case VECTOR3: { + return "Vector3"; + } break; + case VECTOR3I: { + return "Vector3i"; + } break; + case VECTOR4: { + return "Vector4"; + } break; + case VECTOR4I: { + return "Vector4i"; + } break; + + case PLANE: { + return "Plane"; + } break; + case QUATERNION: { + return "Quaternion"; + } break; + case AABB: { + return "AABB"; + } break; + case BASIS: { + return "Basis"; + } break; + case TRANSFORM: { + return "Transform"; + } break; + case TRANSFORM2D: { + return "Transform2D"; + } break; + case PROJECTION: { + return "Projection"; + } break; + + // misc types + case COLOR: { + return "Color"; + } break; case OBJECT: { return "Object"; } break; @@ -62,6 +114,27 @@ String Variant::get_type_name(Variant::Type p_type) { case POOL_STRING_ARRAY: { return "PoolStringArray"; } break; + case POOL_VECTOR2_ARRAY: { + return "PoolVector2Array"; + } break; + case POOL_VECTOR2I_ARRAY: { + return "PoolVector2iArray"; + } break; + case POOL_VECTOR3_ARRAY: { + return "PoolVector3Array"; + } break; + case POOL_VECTOR3I_ARRAY: { + return "PoolVector3iArray"; + } break; + case POOL_VECTOR4_ARRAY: { + return "PoolVector4Array"; + } break; + case POOL_VECTOR4I_ARRAY: { + return "PoolVector4iArray"; + } break; + case POOL_COLOR_ARRAY: { + return "PoolColorArray"; + } break; default: { } } @@ -126,6 +199,129 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { invalid_types = invalid; } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; + case RECT2I: { + static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2I: { + static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + // misc types + case COLOR: { + static const Type valid[] = { + STRING, + INT, + NIL, + }; + + valid_types = valid; + } break; case OBJECT: { static const Type valid[] = { NIL @@ -150,6 +346,11 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { POOL_INT_ARRAY, POOL_STRING_ARRAY, POOL_REAL_ARRAY, + POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, + POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, NIL }; @@ -186,6 +387,56 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { }; valid_types = valid; } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR2I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + valid_types = valid; + } break; + case POOL_COLOR_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; default: { } } @@ -272,6 +523,128 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case RECT2: { + static const Type valid[] = { + RECT2I, + NIL + }; + + valid_types = valid; + } break; + case RECT2I: { + static const Type valid[] = { + RECT2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2: { + static const Type valid[] = { + VECTOR2I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR2I: { + static const Type valid[] = { + VECTOR2, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3: { + static const Type valid[] = { + VECTOR3I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR3I: { + static const Type valid[] = { + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4: { + static const Type valid[] = { + VECTOR4I, + NIL + }; + + valid_types = valid; + } break; + case VECTOR4I: { + static const Type valid[] = { + VECTOR4, + NIL + }; + + valid_types = valid; + } break; + case PLANE: { + //Can't + } break; + case QUATERNION: { + static const Type valid[] = { + BASIS, + NIL + }; + + valid_types = valid; + } break; + case AABB: { + //Can't + } break; + case BASIS: { + static const Type valid[] = { + QUATERNION, + VECTOR3, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM: { + static const Type valid[] = { + TRANSFORM2D, + QUATERNION, + BASIS, + NIL + }; + + valid_types = valid; + } break; + case TRANSFORM2D: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case PROJECTION: { + static const Type valid[] = { + TRANSFORM, + NIL + }; + + valid_types = valid; + } break; + case COLOR: { + static const Type valid[] = { + STRING, + INT, + NIL, + }; + + valid_types = valid; + } break; case OBJECT: { static const Type valid[] = { NIL @@ -296,6 +669,13 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type POOL_INT_ARRAY, POOL_STRING_ARRAY, POOL_REAL_ARRAY, + POOL_COLOR_ARRAY, + POOL_VECTOR2_ARRAY, + POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + POOL_VECTOR4_ARRAY, + POOL_VECTOR4I_ARRAY, NIL }; @@ -333,6 +713,62 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; + case POOL_VECTOR2_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR2I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR3_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR3I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_VECTOR4I_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; + case POOL_COLOR_ARRAY: { + static const Type valid[] = { + ARRAY, + NIL + }; + + valid_types = valid; + } break; default: { } } @@ -431,6 +867,58 @@ bool Variant::is_zero() const { return *reinterpret_cast(_data._mem) == String(); } break; + // math types + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(); + } break; + case RECT2I: { + return *reinterpret_cast(_data._mem) == Rect2i(); + } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(); + } break; + case VECTOR2I: { + return *reinterpret_cast(_data._mem) == Vector2i(); + } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(); + } break; + + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(); + } break; + case QUATERNION: { + return *reinterpret_cast(_data._mem) == Quaternion(); + } break; + case AABB: { + return *_data._aabb == ::AABB(); + } break; + case BASIS: { + return *_data._basis == Basis(); + } break; + case TRANSFORM: { + return *_data._transform == Transform(); + } break; + case TRANSFORM2D: { + return *_data._transform2d == Transform2D(); + } break; + case PROJECTION: { + return *_data._projection == Projection(); + } break; + + // misc types + case COLOR: { + return *reinterpret_cast(_data._mem) == Color(); + } break; case OBJECT: { return _UNSAFE_OBJ_PROXY_PTR(*this) == nullptr; } break; @@ -457,6 +945,27 @@ bool Variant::is_zero() const { case POOL_STRING_ARRAY: { return reinterpret_cast *>(_data._mem)->size() == 0; } break; + case POOL_VECTOR2_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR2I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR3_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR3I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_VECTOR4I_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; + case POOL_COLOR_ARRAY: { + return reinterpret_cast *>(_data._mem)->size() == 0; + } break; default: { } } @@ -480,6 +989,36 @@ bool Variant::is_one() const { case REAL: { return _data._real == 1; } break; + case RECT2: { + return *reinterpret_cast(_data._mem) == Rect2(1, 1, 1, 1); + } break; + case RECT2I: { + return *reinterpret_cast(_data._mem) == Rect2i(1, 1, 1, 1); + } break; + case VECTOR2: { + return *reinterpret_cast(_data._mem) == Vector2(1, 1); + } break; + case VECTOR2I: { + return *reinterpret_cast(_data._mem) == Vector2i(1, 1); + } break; + case VECTOR3: { + return *reinterpret_cast(_data._mem) == Vector3(1, 1, 1); + } break; + case VECTOR3I: { + return *reinterpret_cast(_data._mem) == Vector3i(1, 1, 1); + } break; + case VECTOR4: { + return *reinterpret_cast(_data._mem) == Vector4(1, 1, 1, 1); + } break; + case VECTOR4I: { + return *reinterpret_cast(_data._mem) == Vector4i(1, 1, 1, 1); + } break; + case PLANE: { + return *reinterpret_cast(_data._mem) == Plane(1, 1, 1, 1); + } break; + case COLOR: { + return *reinterpret_cast(_data._mem) == Color(1, 1, 1, 1); + } break; default: { return !is_zero(); @@ -537,6 +1076,58 @@ void Variant::reference(const Variant &p_variant) { memnew_placement(_data._mem, String(*reinterpret_cast(p_variant._data._mem))); } break; + // math types + case RECT2: { + memnew_placement(_data._mem, Rect2(*reinterpret_cast(p_variant._data._mem))); + } break; + case RECT2I: { + memnew_placement(_data._mem, Rect2i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR2: { + memnew_placement(_data._mem, Vector2(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR2I: { + memnew_placement(_data._mem, Vector2i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR3: { + memnew_placement(_data._mem, Vector3(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR3I: { + memnew_placement(_data._mem, Vector3i(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4: { + memnew_placement(_data._mem, Vector4(*reinterpret_cast(p_variant._data._mem))); + } break; + case VECTOR4I: { + memnew_placement(_data._mem, Vector4i(*reinterpret_cast(p_variant._data._mem))); + } break; + + case PLANE: { + memnew_placement(_data._mem, Plane(*reinterpret_cast(p_variant._data._mem))); + } break; + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast(p_variant._data._mem))); + } break; + case AABB: { + _data._aabb = memnew(::AABB(*p_variant._data._aabb)); + } break; + case BASIS: { + _data._basis = memnew(Basis(*p_variant._data._basis)); + } break; + case TRANSFORM: { + _data._transform = memnew(Transform(*p_variant._data._transform)); + } break; + case TRANSFORM2D: { + _data._transform2d = memnew(Transform2D(*p_variant._data._transform2d)); + } break; + case PROJECTION: { + _data._projection = memnew(Projection(*p_variant._data._projection)); + } break; + + // misc types + case COLOR: { + memnew_placement(_data._mem, Color(*reinterpret_cast(p_variant._data._mem))); + } break; case OBJECT: { memnew_placement(_data._mem, ObjData(p_variant._get_obj())); if (likely(_get_obj().rc)) { @@ -566,6 +1157,27 @@ void Variant::reference(const Variant &p_variant) { case POOL_STRING_ARRAY: { memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); } break; + case POOL_VECTOR2_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR2I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR3_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR3I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_VECTOR4I_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; + case POOL_COLOR_ARRAY: { + memnew_placement(_data._mem, PoolVector(*reinterpret_cast *>(p_variant._data._mem))); + } break; default: { } } @@ -584,6 +1196,45 @@ void Variant::zero() { case REAL: this->_data._real = 0; break; + case RECT2: + *reinterpret_cast(this->_data._mem) = Rect2(); + break; + case RECT2I: + *reinterpret_cast(this->_data._mem) = Rect2i(); + break; + case VECTOR2: + *reinterpret_cast(this->_data._mem) = Vector2(); + break; + case VECTOR2I: + *reinterpret_cast(this->_data._mem) = Vector2i(); + break; + case VECTOR3: + *reinterpret_cast(this->_data._mem) = Vector3(); + break; + case VECTOR3I: + *reinterpret_cast(this->_data._mem) = Vector3i(); + break; + case VECTOR4: + *reinterpret_cast(this->_data._mem) = Vector4(); + break; + case VECTOR4I: + *reinterpret_cast(this->_data._mem) = Vector4i(); + break; + case PLANE: + *reinterpret_cast(this->_data._mem) = Plane(); + break; + case QUATERNION: + *reinterpret_cast(this->_data._mem) = Quaternion(); + break; + case AABB: + *reinterpret_cast<::AABB *>(this->_data._mem) = ::AABB(); + break; + case COLOR: + *reinterpret_cast(this->_data._mem) = Color(); + break; + case PROJECTION: + *reinterpret_cast(this->_data._mem) = Projection(); + break; default: this->clear(); break; @@ -601,6 +1252,35 @@ void Variant::clear() { case STRING: { reinterpret_cast(_data._mem)->~String(); } break; + /* + RECT2, + RECT2I + VECTOR2, + VECTOR2I, + VECTOR3, + VECTOR3i, + VECTOR4, + VECTOR4i, + + PLANE, + QUATERNION, + */ + case AABB: { + memdelete(_data._aabb); + } break; + case BASIS: { + memdelete(_data._basis); + } break; + case TRANSFORM: { + memdelete(_data._transform); + } break; + case TRANSFORM2D: { + memdelete(_data._transform2d); + } break; + case PROJECTION: { + memdelete(_data._projection); + } break; + //COLOR // misc types case OBJECT: { @@ -635,6 +1315,27 @@ void Variant::clear() { case POOL_STRING_ARRAY: { reinterpret_cast *>(_data._mem)->~PoolVector(); } break; + case POOL_VECTOR2_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR2I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR3_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR3I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_VECTOR4I_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; + case POOL_COLOR_ARRAY: { + reinterpret_cast *>(_data._mem)->~PoolVector(); + } break; default: { } /* not needed */ } @@ -931,6 +1632,40 @@ String Variant::stringify(List &stack) const { return rtos(_data._real); case STRING: return *reinterpret_cast(_data._mem); + case RECT2: + return operator Rect2(); + case RECT2I: + return operator Rect2i(); + case VECTOR2: + return operator Vector2(); + case VECTOR2I: + return operator Vector2i(); + case VECTOR3: + return operator Vector3(); + case VECTOR3I: + return operator Vector3i(); + case VECTOR4: + return operator Vector4(); + case VECTOR4I: + return operator Vector4i(); + case PLANE: + return operator Plane(); + case QUATERNION: + return operator Quaternion(); + case AABB: + return operator ::AABB(); + case BASIS: { + return operator Basis(); + } break; + case TRANSFORM: + return operator Transform(); + case TRANSFORM2D: { + return operator Transform2D(); + } break; + case PROJECTION: + return operator Projection(); + case COLOR: + return operator Color(); case OBJECT: { Object *obj = _OBJ_PTR(*this); if (likely(obj)) { @@ -1004,6 +1739,27 @@ String Variant::stringify(List &stack) const { case POOL_STRING_ARRAY: { return stringify_vector(operator PoolVector(), stack); } break; + case POOL_VECTOR2_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR2I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR3_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR3I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_VECTOR4I_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; + case POOL_COLOR_ARRAY: { + return stringify_vector(operator PoolVector(), stack); + } break; default: { return "[" + get_type_name(type) + "]"; @@ -1013,6 +1769,251 @@ String Variant::stringify(List &stack) const { return ""; } +Variant::operator Rect2() const { + if (type == RECT2) { + return *reinterpret_cast(_data._mem); + } else if (type == RECT2I) { + return Rect2(*reinterpret_cast(_data._mem)); + } else { + return Rect2(); + } +} +Variant::operator Rect2i() const { + if (type == RECT2I) { + return *reinterpret_cast(_data._mem); + } else if (type == RECT2) { + return Rect2i(*reinterpret_cast(_data._mem)); + } else { + return Rect2i(); + } +} + +Variant::operator Vector2() const { + if (type == VECTOR2) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else { + return Vector2(); + } +} +Variant::operator Vector2i() const { + if (type == VECTOR2I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR3I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else if (type == VECTOR4I) { + return Vector2i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y); + } else { + return Vector2i(); + } +} + +Variant::operator Vector3() const { + if (type == VECTOR3) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3I) { + return Vector3(*reinterpret_cast(_data._mem)); + } else if (type == VECTOR2) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3(); + } +} +Variant::operator Vector3i() const { + if (type == VECTOR3I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR2) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR2I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0); + } else if (type == VECTOR4) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else if (type == VECTOR4I) { + return Vector3i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z); + } else { + return Vector3i(); + } +} + +Variant::operator Vector4() const { + if (type == VECTOR4) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR2) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4(); + } +} + +Variant::operator Vector4i() const { + if (type == VECTOR4I) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR4) { + const Vector4 &v4 = *reinterpret_cast(_data._mem); + return Vector4i(v4.x, v4.y, v4.z, v4.w); + } else if (type == VECTOR2) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR2I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, 0.0, 0.0); + } else if (type == VECTOR3) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else if (type == VECTOR3I) { + return Vector4i(reinterpret_cast(_data._mem)->x, reinterpret_cast(_data._mem)->y, reinterpret_cast(_data._mem)->z, 0.0); + } else { + return Vector4i(); + } +} + +Variant::operator Plane() const { + if (type == PLANE) { + return *reinterpret_cast(_data._mem); + } else { + return Plane(); + } +} +Variant::operator ::AABB() const { + if (type == AABB) { + return *_data._aabb; + } else { + return ::AABB(); + } +} + +Variant::operator Basis() const { + if (type == BASIS) { + return *_data._basis; + } else if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == VECTOR3) { + return Basis(*reinterpret_cast(_data._mem)); + } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? + return _data._transform->basis; + } else { + return Basis(); + } +} + +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast(_data._mem); + } else if (type == BASIS) { + return *_data._basis; + } else if (type == TRANSFORM) { + return _data._transform->basis; + } else { + return Quaternion(); + } +} + +Variant::operator Transform2D() const { + if (type == TRANSFORM2D) { + return *_data._transform2d; + } else if (type == TRANSFORM) { + const Transform &t = *_data._transform; + Transform2D m; + m.columns[0][0] = t.basis.rows[0][0]; + m.columns[0][1] = t.basis.rows[1][0]; + m.columns[1][0] = t.basis.rows[0][1]; + m.columns[1][1] = t.basis.rows[1][1]; + m.columns[2][0] = t.origin[0]; + m.columns[2][1] = t.origin[1]; + return m; + } else { + return Transform2D(); + } +} + +Variant::operator Transform() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Transform(); + } +} + +Variant::operator Projection() const { + if (type == TRANSFORM) { + return *_data._transform; + } else if (type == BASIS) { + return Transform(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform(Basis(*reinterpret_cast(_data._mem)), Vector3()); + } else if (type == TRANSFORM2D) { + const Transform2D &t = *_data._transform2d; + Transform m; + m.basis.rows[0][0] = t.columns[0][0]; + m.basis.rows[1][0] = t.columns[0][1]; + m.basis.rows[0][1] = t.columns[1][0]; + m.basis.rows[1][1] = t.columns[1][1]; + m.origin[0] = t.columns[2][0]; + m.origin[1] = t.columns[2][1]; + return m; + } else if (type == PROJECTION) { + return *_data._projection; + } else { + return Projection(); + } +} + +Variant::operator Color() const { + if (type == COLOR) { + return *reinterpret_cast(_data._mem); + } else if (type == STRING) { + return Color::html(operator String()); + } else if (type == INT) { + return Color::hex(operator int()); + } else { + return Color(); + } +} + Variant::operator RefPtr() const { if (type == OBJECT) { return _get_obj().ref; @@ -1059,6 +2060,27 @@ inline DA _convert_array_from_variant(const Variant &p_variant) { case Variant::POOL_STRING_ARRAY: { return _convert_array>(p_variant.operator PoolVector()); } + case Variant::POOL_VECTOR2_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR2I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR3_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR3I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_VECTOR4I_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } + case Variant::POOL_COLOR_ARRAY: { + return _convert_array>(p_variant.operator PoolVector()); + } default: { return DA(); } @@ -1073,6 +2095,7 @@ Variant::operator Dictionary() const { } } + Variant::operator Array() const { if (type == ARRAY) { return *reinterpret_cast(_data._mem); @@ -1110,9 +2133,112 @@ Variant::operator PoolVector() const { return _convert_array_from_variant>(*this); } } +Variant::operator PoolVector() const { + if (type == POOL_VECTOR2_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR2I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR3I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_VECTOR4I_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} +Variant::operator PoolVector() const { + if (type == POOL_COLOR_ARRAY) { + return *reinterpret_cast *>(_data._mem); + } else { + return _convert_array_from_variant>(*this); + } +} /* helpers */ +Variant::operator PoolVector() const { + Array va = operator Array(); + PoolVector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + PoolVector::Write w = planes.write(); + + for (int i = 0; i < va_size; i++) { + w[i] = va[i]; + } + + return planes; +} + +Variant::operator PoolVector() const { + PoolVector va = operator PoolVector(); + PoolVector faces; + int va_size = va.size(); + if (va_size == 0) { + return faces; + } + + faces.resize(va_size / 3); + PoolVector::Write w = faces.write(); + PoolVector::Read r = va.read(); + + for (int i = 0; i < va_size; i++) { + w[i / 3].vertex[i % 3] = r[i]; + } + + return faces; +} + +Variant::operator Vector() const { + Array va = operator Array(); + Vector planes; + int va_size = va.size(); + if (va_size == 0) { + return planes; + } + + planes.resize(va_size); + + for (int i = 0; i < va_size; i++) { + planes.write[i] = va[i]; + } + + return planes; +} + Variant::operator Vector() const { Array from = operator Array(); Vector to; @@ -1176,6 +2302,115 @@ Variant::operator Vector() const { return to; } +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector2 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector2i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector3i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4 *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Vector4i *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + +Variant::operator Vector() const { + PoolVector from = operator PoolVector(); + Vector to; + int len = from.size(); + if (len == 0) { + return Vector(); + } + to.resize(len); + PoolVector::Read r = from.read(); + Color *w = to.ptrw(); + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + return to; +} + Variant::operator Margin() const { return (Margin) operator int(); } @@ -1274,6 +2509,80 @@ Variant::Variant(const CharType *p_wstring) { memnew_placement(_data._mem, String(p_wstring)); } +Variant::Variant(const Rect2 &p_rect2) { + type = RECT2; + memnew_placement(_data._mem, Rect2(p_rect2)); +} +Variant::Variant(const Rect2i &p_rect2) { + type = RECT2I; + memnew_placement(_data._mem, Rect2i(p_rect2)); +} + +Variant::Variant(const Vector2 &p_vector2) { + type = VECTOR2; + memnew_placement(_data._mem, Vector2(p_vector2)); +} +Variant::Variant(const Vector2i &p_vector2) { + type = VECTOR2I; + memnew_placement(_data._mem, Vector2i(p_vector2)); +} + +Variant::Variant(const Vector3 &p_vector3) { + type = VECTOR3; + memnew_placement(_data._mem, Vector3(p_vector3)); +} +Variant::Variant(const Vector3i &p_vector3) { + type = VECTOR3I; + memnew_placement(_data._mem, Vector3i(p_vector3)); +} + +Variant::Variant(const Vector4 &p_vector4) { + type = VECTOR4; + memnew_placement(_data._mem, Vector4(p_vector4)); +} +Variant::Variant(const Vector4i &p_vector4) { + type = VECTOR4I; + memnew_placement(_data._mem, Vector4i(p_vector4)); +} + +Variant::Variant(const Plane &p_plane) { + type = PLANE; + memnew_placement(_data._mem, Plane(p_plane)); +} +Variant::Variant(const ::AABB &p_aabb) { + type = AABB; + _data._aabb = memnew(::AABB(p_aabb)); +} + +Variant::Variant(const Basis &p_matrix) { + type = BASIS; + _data._basis = memnew(Basis(p_matrix)); +} + +Variant::Variant(const Quaternion &p_quat) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quat)); +} +Variant::Variant(const Transform &p_transform) { + type = TRANSFORM; + _data._transform = memnew(Transform(p_transform)); +} + +Variant::Variant(const Transform2D &p_transform) { + type = TRANSFORM2D; + _data._transform2d = memnew(Transform2D(p_transform)); +} + +Variant::Variant(const Projection &p_projection) { + type = PROJECTION; + _data._projection = memnew(Projection(p_projection)); +} + +Variant::Variant(const Color &p_color) { + type = COLOR; + memnew_placement(_data._mem, Color(p_color)); +} + Variant::Variant(const RefPtr &p_resource) { type = OBJECT; memnew_placement(_data._mem, ObjData); @@ -1305,6 +2614,30 @@ Variant::Variant(const Array &p_array) { memnew_placement(_data._mem, Array(p_array)); } +Variant::Variant(const PoolVector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + +Variant::Variant(const Vector &p_array) { + type = ARRAY; + + Array *plane_array = memnew_placement(_data._mem, Array); + + plane_array->resize(p_array.size()); + + for (int i = 0; i < p_array.size(); i++) { + plane_array->operator[](i) = Variant(p_array[i]); + } +} + Variant::Variant(const PoolVector &p_raw_array) { type = POOL_BYTE_ARRAY; memnew_placement(_data._mem, PoolVector(p_raw_array)); @@ -1321,6 +2654,57 @@ Variant::Variant(const PoolVector &p_string_array) { type = POOL_STRING_ARRAY; memnew_placement(_data._mem, PoolVector(p_string_array)); } +Variant::Variant(const PoolVector &p_vector2_array) { + type = POOL_VECTOR2_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector2_array)); +} +Variant::Variant(const PoolVector &p_vector2_array) { + type = POOL_VECTOR2I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector2_array)); +} +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} +Variant::Variant(const PoolVector &p_vector3_array) { + type = POOL_VECTOR3I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector3_array)); +} + +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} +Variant::Variant(const PoolVector &p_vector4_array) { + type = POOL_VECTOR4I_ARRAY; + memnew_placement(_data._mem, PoolVector(p_vector4_array)); +} + +Variant::Variant(const PoolVector &p_color_array) { + type = POOL_COLOR_ARRAY; + memnew_placement(_data._mem, PoolVector(p_color_array)); +} + +Variant::Variant(const PoolVector &p_face_array) { + PoolVector vertices; + int face_count = p_face_array.size(); + vertices.resize(face_count * 3); + + if (face_count) { + PoolVector::Read r = p_face_array.read(); + PoolVector::Write w = vertices.write(); + + for (int i = 0; i < face_count; i++) { + for (int j = 0; j < 3; j++) { + w[i * 3 + j] = r[i].vertex[j]; + } + } + } + + type = NIL; + + *this = vertices; +} /* helpers */ @@ -1390,6 +2774,110 @@ Variant::Variant(const Vector &p_array) { *this = v; } +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector2 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector2i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector3i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4 *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + if (len > 0) { + v.resize(len); + PoolVector::Write w = v.write(); + const Vector4i *r = p_array.ptr(); + + for (int i = 0; i < len; i++) { + w[i] = r[i]; + } + } + *this = v; +} + +Variant::Variant(const Vector &p_array) { + type = NIL; + PoolVector v; + int len = p_array.size(); + v.resize(len); + for (int i = 0; i < len; i++) { + v.set(i, p_array[i]); + } + *this = v; +} + void Variant::operator=(const Variant &p_variant) { if (unlikely(this == &p_variant)) { return; @@ -1418,6 +2906,59 @@ void Variant::operator=(const Variant &p_variant) { case STRING: { *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); } break; + + // math types + case RECT2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case RECT2I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR2: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR2I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR3: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR3I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case VECTOR4I: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + + case PLANE: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case QUATERNION: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; + case AABB: { + *_data._aabb = *(p_variant._data._aabb); + } break; + case BASIS: { + *_data._basis = *(p_variant._data._basis); + } break; + case TRANSFORM: { + *_data._transform = *(p_variant._data._transform); + } break; + case TRANSFORM2D: { + *_data._transform2d = *(p_variant._data._transform2d); + } break; + case PROJECTION: { + *_data._projection = *(p_variant._data._projection); + } break; + + // misc types + case COLOR: { + *reinterpret_cast(_data._mem) = *reinterpret_cast(p_variant._data._mem); + } break; case OBJECT: { if (likely(_get_obj().rc)) { if (unlikely(_get_obj().rc->decrement())) { @@ -1452,6 +2993,27 @@ void Variant::operator=(const Variant &p_variant) { case POOL_STRING_ARRAY: { *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); } break; + case POOL_VECTOR2_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR2I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR3I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_VECTOR4I_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; + case POOL_COLOR_ARRAY: { + *reinterpret_cast *>(_data._mem) = *reinterpret_cast *>(p_variant._data._mem); + } break; default: { } } @@ -1490,6 +3052,128 @@ uint32_t Variant::recursive_hash(int p_recursion_count) const { case STRING: { return reinterpret_cast(_data._mem)->hash(); } break; + + // math types + case RECT2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case RECT2I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR2: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR2I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR3: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR3I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case VECTOR4I: { + return HashMapHasherDefault::hash(*reinterpret_cast(_data._mem)); + } break; + case PLANE: { + uint32_t h = HASH_MURMUR3_SEED; + const Plane &p = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(p.normal.x, h); + h = hash_murmur3_one_real(p.normal.y, h); + h = hash_murmur3_one_real(p.normal.z, h); + h = hash_murmur3_one_real(p.d, h); + return hash_fmix32(h); + } break; + case QUATERNION: { + uint32_t h = HASH_MURMUR3_SEED; + const Quaternion &q = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_real(q.x, h); + h = hash_murmur3_one_real(q.y, h); + h = hash_murmur3_one_real(q.z, h); + h = hash_murmur3_one_real(q.w, h); + return hash_fmix32(h); + } break; + case AABB: { + return HashMapHasherDefault::hash(*_data._aabb); + } break; + case BASIS: { + uint32_t h = HASH_MURMUR3_SEED; + const Basis &b = *_data._basis; + h = hash_murmur3_one_real(b[0].x, h); + h = hash_murmur3_one_real(b[0].y, h); + h = hash_murmur3_one_real(b[0].z, h); + h = hash_murmur3_one_real(b[1].x, h); + h = hash_murmur3_one_real(b[1].y, h); + h = hash_murmur3_one_real(b[1].z, h); + h = hash_murmur3_one_real(b[2].x, h); + h = hash_murmur3_one_real(b[2].y, h); + h = hash_murmur3_one_real(b[2].z, h); + return hash_fmix32(h); + } break; + case TRANSFORM: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform &t = *_data._transform; + h = hash_murmur3_one_real(t.basis[0].x, h); + h = hash_murmur3_one_real(t.basis[0].y, h); + h = hash_murmur3_one_real(t.basis[0].z, h); + h = hash_murmur3_one_real(t.basis[1].x, h); + h = hash_murmur3_one_real(t.basis[1].y, h); + h = hash_murmur3_one_real(t.basis[1].z, h); + h = hash_murmur3_one_real(t.basis[2].x, h); + h = hash_murmur3_one_real(t.basis[2].y, h); + h = hash_murmur3_one_real(t.basis[2].z, h); + h = hash_murmur3_one_real(t.origin.x, h); + h = hash_murmur3_one_real(t.origin.y, h); + h = hash_murmur3_one_real(t.origin.z, h); + return hash_fmix32(h); + } break; + case TRANSFORM2D: { + uint32_t h = HASH_MURMUR3_SEED; + const Transform2D &t = *_data._transform2d; + h = hash_murmur3_one_real(t[0].x, h); + h = hash_murmur3_one_real(t[0].y, h); + h = hash_murmur3_one_real(t[1].x, h); + h = hash_murmur3_one_real(t[1].y, h); + h = hash_murmur3_one_real(t[2].x, h); + h = hash_murmur3_one_real(t[2].y, h); + + return hash_fmix32(h); + } break; + case PROJECTION: { + uint32_t h = HASH_MURMUR3_SEED; + const Projection &t = *_data._projection; + h = hash_murmur3_one_real(t.matrix[0].x, h); + h = hash_murmur3_one_real(t.matrix[0].y, h); + h = hash_murmur3_one_real(t.matrix[0].z, h); + h = hash_murmur3_one_real(t.matrix[0].w, h); + h = hash_murmur3_one_real(t.matrix[1].x, h); + h = hash_murmur3_one_real(t.matrix[1].y, h); + h = hash_murmur3_one_real(t.matrix[1].z, h); + h = hash_murmur3_one_real(t.matrix[1].w, h); + h = hash_murmur3_one_real(t.matrix[2].x, h); + h = hash_murmur3_one_real(t.matrix[2].y, h); + h = hash_murmur3_one_real(t.matrix[2].z, h); + h = hash_murmur3_one_real(t.matrix[2].w, h); + h = hash_murmur3_one_real(t.matrix[3].x, h); + h = hash_murmur3_one_real(t.matrix[3].y, h); + h = hash_murmur3_one_real(t.matrix[3].z, h); + h = hash_murmur3_one_real(t.matrix[3].w, h); + return hash_fmix32(h); + } break; + + // misc types + case COLOR: { + uint32_t h = HASH_MURMUR3_SEED; + const Color &c = *reinterpret_cast(_data._mem); + h = hash_murmur3_one_float(c.r, h); + h = hash_murmur3_one_float(c.g, h); + h = hash_murmur3_one_float(c.b, h); + h = hash_murmur3_one_float(c.a, h); + return hash_fmix32(h); + } break; case OBJECT: { return hash_one_uint64(hash_make_uint64_t(_UNSAFE_OBJ_PROXY_PTR(*this))); } break; @@ -1561,6 +3245,140 @@ uint32_t Variant::recursive_hash(int p_recursion_count) const { return hash; } break; + case POOL_VECTOR2_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR2I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR3_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR3I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].x, hash); + hash = hash_murmur3_one_real(r[i].y, hash); + hash = hash_murmur3_one_real(r[i].z, hash); + hash = hash_murmur3_one_real(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_VECTOR4I_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_32(r[i].x, hash); + hash = hash_murmur3_one_32(r[i].y, hash); + hash = hash_murmur3_one_32(r[i].z, hash); + hash = hash_murmur3_one_32(r[i].w, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; + case POOL_COLOR_ARRAY: { + uint32_t hash = HASH_MURMUR3_SEED; + const PoolVector &arr = *reinterpret_cast *>(_data._mem); + int len = arr.size(); + + if (likely(len)) { + PoolVector::Read r = arr.read(); + + for (int i = 0; i < len; i++) { + hash = hash_murmur3_one_real(r[i].r, hash); + hash = hash_murmur3_one_real(r[i].g, hash); + hash = hash_murmur3_one_real(r[i].b, hash); + hash = hash_murmur3_one_real(r[i].a, hash); + } + + hash = hash_fmix32(hash); + } + + return hash; + } break; default: { } } @@ -1646,6 +3464,134 @@ bool Variant::hash_compare(const Variant &p_variant) const { case STRING: { return *reinterpret_cast(_data._mem) == *reinterpret_cast(p_variant._data._mem); } break; + + case RECT2: { + const Rect2 *l = reinterpret_cast(_data._mem); + const Rect2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(l->position, r->position) && + hash_compare_vector2(l->size, r->size); + } break; + case RECT2I: { + const Rect2i *l = reinterpret_cast(_data._mem); + const Rect2i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2i(l->position, r->position) && + hash_compare_vector2i(l->size, r->size); + } break; + case VECTOR2: { + const Vector2 *l = reinterpret_cast(_data._mem); + const Vector2 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2(*l, *r); + } break; + case VECTOR2I: { + const Vector2i *l = reinterpret_cast(_data._mem); + const Vector2i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector2i(*l, *r); + } break; + case VECTOR3: { + const Vector3 *l = reinterpret_cast(_data._mem); + const Vector3 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(*l, *r); + } break; + case VECTOR3I: { + const Vector3i *l = reinterpret_cast(_data._mem); + const Vector3i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3i(*l, *r); + } break; + case VECTOR4: { + const Vector4 *l = reinterpret_cast(_data._mem); + const Vector4 *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4(*l, *r); + } break; + case VECTOR4I: { + const Vector4i *l = reinterpret_cast(_data._mem); + const Vector4i *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector4i(*l, *r); + } break; + + case PLANE: { + const Plane *l = reinterpret_cast(_data._mem); + const Plane *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_vector3(l->normal, r->normal) && + hash_compare_scalar(l->d, r->d); + } break; + case QUATERNION: { + const Quaternion *l = reinterpret_cast(_data._mem); + const Quaternion *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_quat(*l, *r); + } break; + case AABB: { + const ::AABB *l = _data._aabb; + const ::AABB *r = p_variant._data._aabb; + + return hash_compare_vector3(l->position, r->position) && + hash_compare_vector3(l->size, r->size); + + } break; + case BASIS: { + const Basis *l = _data._basis; + const Basis *r = p_variant._data._basis; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->rows[i], r->rows[i])) { + return false; + } + } + + return true; + } break; + case TRANSFORM: { + const Transform *l = _data._transform; + const Transform *r = p_variant._data._transform; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector3(l->basis.rows[i], r->basis.rows[i])) { + return false; + } + } + + return hash_compare_vector3(l->origin, r->origin); + } break; + case TRANSFORM2D: { + Transform2D *l = _data._transform2d; + Transform2D *r = p_variant._data._transform2d; + + for (int i = 0; i < 3; i++) { + if (!hash_compare_vector2(l->columns[i], r->columns[i])) { + return false; + } + } + + return true; + } break; + case PROJECTION: { + const Projection *l = _data._projection; + const Projection *r = p_variant._data._projection; + + for (int i = 0; i < 4; i++) { + if (!hash_compare_vector4(l->matrix[i], r->matrix[i])) { + return false; + } + } + + return true; + } break; + + case COLOR: { + const Color *l = reinterpret_cast(_data._mem); + const Color *r = reinterpret_cast(p_variant._data._mem); + + return hash_compare_color(*l, *r); + } break; case ARRAY: { const Array &l = *(reinterpret_cast(_data._mem)); const Array &r = *(reinterpret_cast(p_variant._data._mem)); @@ -1666,6 +3612,28 @@ bool Variant::hash_compare(const Variant &p_variant) const { case POOL_REAL_ARRAY: { hash_compare_pool_array(_data._mem, p_variant._data._mem, real_t, hash_compare_scalar); } break; + case POOL_VECTOR2_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2, hash_compare_vector2); + } break; + case POOL_VECTOR2I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector2i, hash_compare_vector2i); + } break; + case POOL_VECTOR3_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3, hash_compare_vector3); + } break; + case POOL_VECTOR3I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector3i, hash_compare_vector3i); + } break; + case POOL_VECTOR4_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4, hash_compare_vector4); + } break; + case POOL_VECTOR4I_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Vector4i, hash_compare_vector4i); + } break; + case POOL_COLOR_ARRAY: { + hash_compare_pool_array(_data._mem, p_variant._data._mem, Color, hash_compare_color); + } break; + default: bool v; Variant r; diff --git a/sfwl/object/variant.h b/sfwl/object/variant.h index d152065..d17c205 100644 --- a/sfwl/object/variant.h +++ b/sfwl/object/variant.h @@ -1,5 +1,7 @@ +//--STRIP #ifndef VARIANT_H #define VARIANT_H +//--STRIP /*************************************************************************/ /* variant.h */ @@ -7,9 +9,21 @@ /*************************************************************************/ //--STRIP -#include "core/math_defs.h" +#include "core/aabb.h" +#include "core/basis.h" +#include "core/color.h" +#include "core/face3.h" +#include "core/plane.h" #include "core/pool_vector.h" +#include "core/projection.h" +#include "core/quaternion.h" +#include "core/transform.h" +#include "core/transform_2d.h" #include "core/ustring.h" +#include "core/vector3.h" +#include "core/vector3i.h" +#include "core/vector4.h" +#include "core/vector4i.h" #include "object/array.h" #include "object/dictionary.h" #include "object/ref_ptr.h" @@ -23,6 +37,13 @@ typedef PoolVector PoolByteArray; typedef PoolVector PoolIntArray; typedef PoolVector PoolRealArray; typedef PoolVector PoolStringArray; +typedef PoolVector PoolVector2Array; +typedef PoolVector PoolVector2iArray; +typedef PoolVector PoolVector3Array; +typedef PoolVector PoolVector3iArray; +typedef PoolVector PoolVector4Array; +typedef PoolVector PoolVector4iArray; +typedef PoolVector PoolColorArray; // Temporary workaround until c++11 alignas() #ifdef __GNUC__ @@ -51,7 +72,26 @@ public: REAL, STRING, + // math types + RECT2, + RECT2I, + VECTOR2, + VECTOR2I, + VECTOR3, + VECTOR3I, + VECTOR4, + VECTOR4I, + + PLANE, + QUATERNION, + AABB, + BASIS, + TRANSFORM, + TRANSFORM2D, + PROJECTION, + // misc types + COLOR, OBJECT, STRING_NAME, DICTIONARY, @@ -62,6 +102,13 @@ public: POOL_INT_ARRAY, POOL_REAL_ARRAY, POOL_STRING_ARRAY, + POOL_VECTOR2_ARRAY, + POOL_VECTOR2I_ARRAY, + POOL_VECTOR3_ARRAY, + POOL_VECTOR3I_ARRAY, + POOL_VECTOR4_ARRAY, + POOL_VECTOR4I_ARRAY, + POOL_COLOR_ARRAY, VARIANT_MAX // 38 @@ -94,6 +141,11 @@ private: bool _bool; int64_t _int; double _real; + Transform2D *_transform2d; + ::AABB *_aabb; + Basis *_basis; + Transform *_transform; + Projection *_projection; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; } _data GCC_ALIGNED_8; @@ -138,7 +190,23 @@ public: operator double() const; operator String() const; operator StringName() const; + operator Rect2() const; + operator Rect2i() const; + operator Vector2() const; + operator Vector2i() const; + operator Vector3() const; + operator Vector3i() const; + operator Vector4() const; + operator Vector4i() const; + operator Plane() const; + operator ::AABB() const; + operator Quaternion() const; + operator Basis() const; + operator Transform() const; + operator Transform2D() const; + operator Projection() const; + operator Color() const; operator RefPtr() const; operator Object *() const; @@ -150,6 +218,15 @@ public: operator PoolVector() const; operator PoolVector() const; operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; + operator PoolVector() const; operator Vector() const; operator Vector() const; @@ -157,6 +234,15 @@ public: operator Vector() const; operator Vector() const; operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + operator Vector() const; + + operator Vector() const; // some core type enums to convert to operator Margin() const; @@ -183,16 +269,40 @@ public: Variant(const StringName &p_string); Variant(const char *const p_cstring); Variant(const CharType *p_wstring); - + Variant(const Vector2 &p_vector2); + Variant(const Vector2i &p_vector2); + Variant(const Rect2 &p_rect2); + Variant(const Rect2i &p_rect2); + Variant(const Vector3 &p_vector3); + Variant(const Vector3i &p_vector3); + Variant(const Vector4 &p_vector4); + Variant(const Vector4i &p_vector4); + Variant(const Projection &p_projection); + Variant(const Plane &p_plane); + Variant(const ::AABB &p_aabb); + Variant(const Quaternion &p_quat); + Variant(const Basis &p_matrix); + Variant(const Transform2D &p_transform); + Variant(const Transform &p_transform); + Variant(const Color &p_color); Variant(const RefPtr &p_resource); Variant(const Object *p_object); Variant(const Dictionary &p_dictionary); Variant(const Array &p_array); + Variant(const PoolVector &p_array); Variant(const PoolVector &p_raw_array); Variant(const PoolVector &p_int_array); Variant(const PoolVector &p_real_array); Variant(const PoolVector &p_string_array); + Variant(const PoolVector &p_vector3_array); + Variant(const PoolVector &p_vector3_array); + Variant(const PoolVector &p_color_array); + Variant(const PoolVector &p_face_array); + Variant(const PoolVector &p_vector2_array); + Variant(const PoolVector &p_vector2_array); + Variant(const PoolVector &p_vector4_array); + Variant(const PoolVector &p_vector4_array); Variant(const Vector &p_array); Variant(const Vector &p_array); @@ -200,6 +310,14 @@ public: Variant(const Vector &p_array); Variant(const Vector &p_array); Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); + Variant(const Vector &p_array); // If this changes the table in variant_op must be updated enum Operator { @@ -321,4 +439,7 @@ const Variant::ObjData &Variant::_get_obj() const { } String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant()); + +//--STRIP #endif +//--STRIP diff --git a/sfwl/object/variant_op.cpp b/sfwl/object/variant_op.cpp index c5b77ea..a079c40 100644 --- a/sfwl/object/variant_op.cpp +++ b/sfwl/object/variant_op.cpp @@ -21,6 +21,22 @@ CASE_TYPE(PREFIX, OP, BOOL) \ CASE_TYPE(PREFIX, OP, REAL) \ CASE_TYPE(PREFIX, OP, STRING) \ + CASE_TYPE(PREFIX, OP, RECT2) \ + CASE_TYPE(PREFIX, OP, RECT2I) \ + CASE_TYPE(PREFIX, OP, VECTOR2) \ + CASE_TYPE(PREFIX, OP, VECTOR2I) \ + CASE_TYPE(PREFIX, OP, VECTOR3) \ + CASE_TYPE(PREFIX, OP, VECTOR3I) \ + CASE_TYPE(PREFIX, OP, VECTOR4) \ + CASE_TYPE(PREFIX, OP, VECTOR4I) \ + CASE_TYPE(PREFIX, OP, PLANE) \ + CASE_TYPE(PREFIX, OP, QUATERNION) \ + CASE_TYPE(PREFIX, OP, AABB) \ + CASE_TYPE(PREFIX, OP, BASIS) \ + CASE_TYPE(PREFIX, OP, TRANSFORM) \ + CASE_TYPE(PREFIX, OP, TRANSFORM2D) \ + CASE_TYPE(PREFIX, OP, PROJECTION) \ + CASE_TYPE(PREFIX, OP, COLOR) \ CASE_TYPE(PREFIX, OP, OBJECT) \ CASE_TYPE(PREFIX, OP, STRING_NAME) \ CASE_TYPE(PREFIX, OP, DICTIONARY) \ @@ -28,7 +44,14 @@ CASE_TYPE(PREFIX, OP, POOL_BYTE_ARRAY) \ CASE_TYPE(PREFIX, OP, POOL_INT_ARRAY) \ CASE_TYPE(PREFIX, OP, POOL_REAL_ARRAY) \ - CASE_TYPE(PREFIX, OP, POOL_STRING_ARRAY) + CASE_TYPE(PREFIX, OP, POOL_STRING_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR2_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR2I_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR3I_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR4_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_VECTOR4I_ARRAY) \ + CASE_TYPE(PREFIX, OP, POOL_COLOR_ARRAY) #ifdef __GNUC__ #define TYPE(PREFIX, OP, TYPE) &&PREFIX##_##OP##_##TYPE @@ -41,6 +64,22 @@ TYPE(PREFIX, OP, INT), \ TYPE(PREFIX, OP, REAL), \ TYPE(PREFIX, OP, STRING), \ + TYPE(PREFIX, OP, RECT2), \ + TYPE(PREFIX, OP, RECT2I), \ + TYPE(PREFIX, OP, VECTOR2), \ + TYPE(PREFIX, OP, VECTOR2I), \ + TYPE(PREFIX, OP, VECTOR3), \ + TYPE(PREFIX, OP, VECTOR3I), \ + TYPE(PREFIX, OP, VECTOR4), \ + TYPE(PREFIX, OP, VECTOR4I), \ + TYPE(PREFIX, OP, PLANE), \ + TYPE(PREFIX, OP, QUATERNION), \ + TYPE(PREFIX, OP, AABB), \ + TYPE(PREFIX, OP, BASIS), \ + TYPE(PREFIX, OP, TRANSFORM), \ + TYPE(PREFIX, OP, TRANSFORM2D), \ + TYPE(PREFIX, OP, PROJECTION), \ + TYPE(PREFIX, OP, COLOR), \ TYPE(PREFIX, OP, OBJECT), \ TYPE(PREFIX, OP, STRING_NAME), \ TYPE(PREFIX, OP, DICTIONARY), \ @@ -49,6 +88,13 @@ TYPE(PREFIX, OP, POOL_INT_ARRAY), \ TYPE(PREFIX, OP, POOL_REAL_ARRAY), \ TYPE(PREFIX, OP, POOL_STRING_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR2_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR2I_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR3_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR3I_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR4_ARRAY), \ + TYPE(PREFIX, OP, POOL_VECTOR4I_ARRAY), \ + TYPE(PREFIX, OP, POOL_COLOR_ARRAY), \ } /* clang-format on */ @@ -186,6 +232,18 @@ bool Variant::booleanize() const { _RETURN(p_a._data.m_type m_op p_b._data._int); \ if (p_b.type == REAL) \ _RETURN(p_a._data.m_type m_op p_b._data._real); \ + if (p_b.type == VECTOR2) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR2I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR3) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR3I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR4) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ + if (p_b.type == VECTOR4I) \ + _RETURN(p_a._data.m_type m_op *reinterpret_cast(p_b._data._mem)); \ \ _RETURN_FAIL \ }; @@ -449,12 +507,35 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_EQUAL, INT, ==, _int); DEFAULT_OP_NUM_NULL(math, OP_EQUAL, REAL, ==, _real); DEFAULT_OP_STR_NULL(math, OP_EQUAL, STRING, ==, String); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2, ==, Rect2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, RECT2I, ==, Rect2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2, ==, Vector2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR2I, ==, Vector2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3, ==, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR3I, ==, Vector3i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR4, ==, Vector4); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, VECTOR4I, ==, Vector4i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, PLANE, ==, Plane); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, QUATERNION, ==, Quaternion); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, AABB, ==, _aabb); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, BASIS, ==, _basis); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM, ==, _transform); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, TRANSFORM2D, ==, _transform2d); + DEFAULT_OP_PTRREF_NULL(math, OP_EQUAL, PROJECTION, ==, _projection); + DEFAULT_OP_LOCALMEM_NULL(math, OP_EQUAL, COLOR, ==, Color); DEFAULT_OP_STR_NULL_SN(math, OP_EQUAL, STRING_NAME, ==, StringName); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_VECTOR4I_ARRAY, Vector4i); + DEFAULT_OP_ARRAY_EQ(math, OP_EQUAL, POOL_COLOR_ARRAY, Color); } SWITCH_OP(math, OP_NOT_EQUAL, p_a.type) { @@ -526,12 +607,35 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, INT, !=, _int); DEFAULT_OP_NUM_NULL(math, OP_NOT_EQUAL, REAL, !=, _real); DEFAULT_OP_STR_NULL(math, OP_NOT_EQUAL, STRING, !=, String); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2, !=, Rect2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, RECT2I, !=, Rect2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2, !=, Vector2); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR2I, !=, Vector2i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3, !=, Vector3); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR3I, !=, Vector3i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR4, !=, Vector4); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, VECTOR4I, !=, Vector4i); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, PLANE, !=, Plane); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, QUATERNION, !=, Quaternion); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, AABB, !=, _aabb); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, BASIS, !=, _basis); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM, !=, _transform); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, TRANSFORM2D, !=, _transform2d); + DEFAULT_OP_PTRREF_NULL(math, OP_NOT_EQUAL, PROJECTION, !=, _projection); + DEFAULT_OP_LOCALMEM_NULL(math, OP_NOT_EQUAL, COLOR, !=, Color); DEFAULT_OP_STR_NULL_SN(math, OP_NOT_EQUAL, STRING_NAME, !=, StringName); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_VECTOR4I_ARRAY, Vector4i); + DEFAULT_OP_ARRAY_NEQ(math, OP_NOT_EQUAL, POOL_COLOR_ARRAY, Color); } SWITCH_OP(math, OP_LESS, p_a.type) { @@ -576,14 +680,37 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_LESS, INT, <, _int); DEFAULT_OP_NUM(math, OP_LESS, REAL, <, _real); DEFAULT_OP_STR(math, OP_LESS, STRING, <, String); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR2I, <, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR3I, <, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR4, <, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_LESS, VECTOR4I, <, Vector4i); DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_VECTOR4I_ARRAY, Vector4i); + DEFAULT_OP_ARRAY_LT(math, OP_LESS, POOL_COLOR_ARRAY, Color); CASE_TYPE(math, OP_LESS, NIL) + CASE_TYPE(math, OP_LESS, RECT2) + CASE_TYPE(math, OP_LESS, RECT2I) + CASE_TYPE(math, OP_LESS, PLANE) + CASE_TYPE(math, OP_LESS, QUATERNION) + CASE_TYPE(math, OP_LESS, AABB) + CASE_TYPE(math, OP_LESS, BASIS) + CASE_TYPE(math, OP_LESS, TRANSFORM) + CASE_TYPE(math, OP_LESS, TRANSFORM2D) + CASE_TYPE(math, OP_LESS, PROJECTION) CASE_TYPE(math, OP_LESS, STRING_NAME) + CASE_TYPE(math, OP_LESS, COLOR) CASE_TYPE(math, OP_LESS, DICTIONARY) _RETURN_FAIL; } @@ -598,9 +725,25 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_LESS_EQUAL, INT, <=, _int); DEFAULT_OP_NUM(math, OP_LESS_EQUAL, REAL, <=, _real); DEFAULT_OP_STR(math, OP_LESS_EQUAL, STRING, <=, String); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR2I, <=, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR3I, <=, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR4, <=, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_LESS_EQUAL, VECTOR4I, <=, Vector4i); CASE_TYPE(math, OP_LESS_EQUAL, NIL) CASE_TYPE(math, OP_LESS_EQUAL, BOOL) + CASE_TYPE(math, OP_LESS_EQUAL, RECT2) + CASE_TYPE(math, OP_LESS_EQUAL, RECT2I) + CASE_TYPE(math, OP_LESS_EQUAL, PLANE) + CASE_TYPE(math, OP_LESS_EQUAL, QUATERNION) + CASE_TYPE(math, OP_LESS_EQUAL, AABB) + CASE_TYPE(math, OP_LESS_EQUAL, BASIS) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_LESS_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_LESS_EQUAL, PROJECTION) + CASE_TYPE(math, OP_LESS_EQUAL, COLOR) CASE_TYPE(math, OP_LESS_EQUAL, STRING_NAME) CASE_TYPE(math, OP_LESS_EQUAL, DICTIONARY) CASE_TYPE(math, OP_LESS_EQUAL, ARRAY) @@ -608,6 +751,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_LESS_EQUAL, POOL_INT_ARRAY); CASE_TYPE(math, OP_LESS_EQUAL, POOL_REAL_ARRAY); CASE_TYPE(math, OP_LESS_EQUAL, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_VECTOR4I_ARRAY); + CASE_TYPE(math, OP_LESS_EQUAL, POOL_COLOR_ARRAY); _RETURN_FAIL; } @@ -653,13 +803,36 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_GREATER, INT, >, _int); DEFAULT_OP_NUM(math, OP_GREATER, REAL, >, _real); DEFAULT_OP_STR_REV(math, OP_GREATER, STRING, <, String); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2, <, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR2I, <, Vector2i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3, <, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR3I, <, Vector3i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR4, <, Vector4); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER, VECTOR4I, <, Vector4i); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_VECTOR4I_ARRAY, Vector4i); + DEFAULT_OP_ARRAY_GT(math, OP_GREATER, POOL_COLOR_ARRAY, Color); CASE_TYPE(math, OP_GREATER, NIL) + CASE_TYPE(math, OP_GREATER, RECT2) + CASE_TYPE(math, OP_GREATER, RECT2I) + CASE_TYPE(math, OP_GREATER, PLANE) + CASE_TYPE(math, OP_GREATER, QUATERNION) + CASE_TYPE(math, OP_GREATER, AABB) + CASE_TYPE(math, OP_GREATER, BASIS) CASE_TYPE(math, OP_GREATER, STRING_NAME) + CASE_TYPE(math, OP_GREATER, TRANSFORM) + CASE_TYPE(math, OP_GREATER, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER, PROJECTION) + CASE_TYPE(math, OP_GREATER, COLOR) CASE_TYPE(math, OP_GREATER, DICTIONARY) _RETURN_FAIL; } @@ -674,9 +847,25 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, INT, >=, _int); DEFAULT_OP_NUM(math, OP_GREATER_EQUAL, REAL, >=, _real); DEFAULT_OP_STR_REV(math, OP_GREATER_EQUAL, STRING, <=, String); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2, <=, Vector2); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR2I, <=, Vector2i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3, <=, Vector3); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR3I, <=, Vector3i); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR4, <=, Vector4); + DEFAULT_OP_LOCALMEM_REV(math, OP_GREATER_EQUAL, VECTOR4I, <=, Vector4i); CASE_TYPE(math, OP_GREATER_EQUAL, NIL) CASE_TYPE(math, OP_GREATER_EQUAL, BOOL) + CASE_TYPE(math, OP_GREATER_EQUAL, RECT2) + CASE_TYPE(math, OP_GREATER_EQUAL, RECT2I) + CASE_TYPE(math, OP_GREATER_EQUAL, PLANE) + CASE_TYPE(math, OP_GREATER_EQUAL, QUATERNION) + CASE_TYPE(math, OP_GREATER_EQUAL, AABB) + CASE_TYPE(math, OP_GREATER_EQUAL, BASIS) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM) + CASE_TYPE(math, OP_GREATER_EQUAL, TRANSFORM2D) + CASE_TYPE(math, OP_GREATER_EQUAL, PROJECTION) + CASE_TYPE(math, OP_GREATER_EQUAL, COLOR) CASE_TYPE(math, OP_GREATER_EQUAL, DICTIONARY) CASE_TYPE(math, OP_GREATER_EQUAL, STRING_NAME) CASE_TYPE(math, OP_GREATER_EQUAL, ARRAY) @@ -684,6 +873,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_GREATER_EQUAL, POOL_INT_ARRAY); CASE_TYPE(math, OP_GREATER_EQUAL, POOL_REAL_ARRAY); CASE_TYPE(math, OP_GREATER_EQUAL, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_VECTOR4I_ARRAY); + CASE_TYPE(math, OP_GREATER_EQUAL, POOL_COLOR_ARRAY); _RETURN_FAIL; } @@ -710,14 +906,37 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM(math, OP_ADD, INT, +, _int); DEFAULT_OP_NUM(math, OP_ADD, REAL, +, _real); DEFAULT_OP_STR(math, OP_ADD, STRING, +, String); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2, +, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR2I, +, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3, +, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR3I, +, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR4, +, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_ADD, VECTOR4I, +, Vector4i); + DEFAULT_OP_LOCALMEM(math, OP_ADD, QUATERNION, +, Quaternion); + DEFAULT_OP_LOCALMEM(math, OP_ADD, COLOR, +, Color); DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_BYTE_ARRAY, uint8_t); DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_INT_ARRAY, int); DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_REAL_ARRAY, real_t); DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_STRING_ARRAY, String); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR2_ARRAY, Vector2); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR2I_ARRAY, Vector2i); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR3_ARRAY, Vector3); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR3I_ARRAY, Vector3i); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR4_ARRAY, Vector4); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_VECTOR4I_ARRAY, Vector4i); + DEFAULT_OP_ARRAY_ADD(math, OP_ADD, POOL_COLOR_ARRAY, Color); CASE_TYPE(math, OP_ADD, NIL) CASE_TYPE(math, OP_ADD, BOOL) + CASE_TYPE(math, OP_ADD, RECT2) + CASE_TYPE(math, OP_ADD, RECT2I) + CASE_TYPE(math, OP_ADD, PLANE) + CASE_TYPE(math, OP_ADD, AABB) + CASE_TYPE(math, OP_ADD, BASIS) + CASE_TYPE(math, OP_ADD, TRANSFORM) + CASE_TYPE(math, OP_ADD, TRANSFORM2D) + CASE_TYPE(math, OP_ADD, PROJECTION) CASE_TYPE(math, OP_ADD, OBJECT) CASE_TYPE(math, OP_ADD, DICTIONARY) CASE_TYPE(math, OP_ADD, STRING_NAME) @@ -727,10 +946,26 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, SWITCH_OP(math, OP_SUBTRACT, p_a.type) { DEFAULT_OP_NUM(math, OP_SUBTRACT, INT, -, _int); DEFAULT_OP_NUM(math, OP_SUBTRACT, REAL, -, _real); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2, -, Vector2); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR2I, -, Vector2i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3, -, Vector3); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR3I, -, Vector3i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR4, -, Vector4); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, VECTOR4I, -, Vector4i); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, QUATERNION, -, Quaternion); + DEFAULT_OP_LOCALMEM(math, OP_SUBTRACT, COLOR, -, Color); CASE_TYPE(math, OP_SUBTRACT, NIL) CASE_TYPE(math, OP_SUBTRACT, BOOL) CASE_TYPE(math, OP_SUBTRACT, STRING) + CASE_TYPE(math, OP_SUBTRACT, RECT2) + CASE_TYPE(math, OP_SUBTRACT, RECT2I) + CASE_TYPE(math, OP_SUBTRACT, PLANE) + CASE_TYPE(math, OP_SUBTRACT, AABB) + CASE_TYPE(math, OP_SUBTRACT, BASIS) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM) + CASE_TYPE(math, OP_SUBTRACT, TRANSFORM2D) + CASE_TYPE(math, OP_SUBTRACT, PROJECTION) CASE_TYPE(math, OP_SUBTRACT, OBJECT) CASE_TYPE(math, OP_SUBTRACT, STRING_NAME) CASE_TYPE(math, OP_SUBTRACT, DICTIONARY) @@ -739,16 +974,120 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_SUBTRACT, POOL_INT_ARRAY); CASE_TYPE(math, OP_SUBTRACT, POOL_REAL_ARRAY); CASE_TYPE(math, OP_SUBTRACT, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_VECTOR4I_ARRAY); + CASE_TYPE(math, OP_SUBTRACT, POOL_COLOR_ARRAY); _RETURN_FAIL; } SWITCH_OP(math, OP_MULTIPLY, p_a.type) { + CASE_TYPE(math, OP_MULTIPLY, QUATERNION) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(reinterpret_cast(p_a._data._mem)->xform(*(const Vector3 *)p_b._data._mem)); + } + case VECTOR3I: { + _RETURN(reinterpret_cast(p_a._data._mem)->xform(*(const Vector3i *)p_b._data._mem)); + } + case QUATERNION: { + _RETURN(*reinterpret_cast(p_a._data._mem) * *reinterpret_cast(p_b._data._mem)); + } + case REAL: { + _RETURN(*reinterpret_cast(p_a._data._mem) * p_b._data._real); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, BASIS) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(p_a._data._basis->xform(*(const Vector3 *)p_b._data._mem)); + } + case VECTOR3I: { + _RETURN(p_a._data._basis->xform(*(const Vector3i *)p_b._data._mem)); + } + case BASIS: { + _RETURN(*p_a._data._basis * *p_b._data._basis); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, TRANSFORM) { + switch (p_b.type) { + case VECTOR3: { + _RETURN(p_a._data._transform->xform(*(const Vector3 *)p_b._data._mem)); + } + case VECTOR3I: { + _RETURN(p_a._data._transform->xform(*(const Vector3i *)p_b._data._mem)); + } + case TRANSFORM: { + _RETURN(*p_a._data._transform * *p_b._data._transform); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, TRANSFORM2D) { + switch (p_b.type) { + case TRANSFORM2D: { + _RETURN(*p_a._data._transform2d * *p_b._data._transform2d); + } + case VECTOR2: { + _RETURN(p_a._data._transform2d->xform(*(const Vector2 *)p_b._data._mem)); + } + case VECTOR2I: { + _RETURN(p_a._data._transform2d->xform(*(const Vector2i *)p_b._data._mem)); + } + default: + _RETURN_FAIL; + } + } + + CASE_TYPE(math, OP_MULTIPLY, PROJECTION) { + switch (p_b.type) { + case VECTOR4: { + _RETURN(p_a._data._projection->xform(*(const Vector4 *)p_b._data._mem)); + } + case VECTOR3: { + _RETURN(p_a._data._projection->xform(*(const Vector3 *)p_b._data._mem)); + } + case PLANE: { + _RETURN(p_a._data._projection->xform(*(const Plane *)p_b._data._mem)); + } + case PROJECTION: { + _RETURN(p_a._data._projection->operator*(*(const Projection *)p_b._data._mem)); + } + default: + _RETURN_FAIL; + } + } + DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, INT, *, _int); DEFAULT_OP_NUM_VEC(math, OP_MULTIPLY, REAL, *, _real); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2, *, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR2I, *, Vector2i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3, *, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR3I, *, Vector3i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR4, *, Vector4); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, VECTOR4I, *, Vector4i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_MULTIPLY, COLOR, *, Color); CASE_TYPE(math, OP_MULTIPLY, NIL) CASE_TYPE(math, OP_MULTIPLY, BOOL) CASE_TYPE(math, OP_MULTIPLY, STRING) + CASE_TYPE(math, OP_MULTIPLY, RECT2) + CASE_TYPE(math, OP_MULTIPLY, RECT2I) + CASE_TYPE(math, OP_MULTIPLY, PLANE) + CASE_TYPE(math, OP_MULTIPLY, AABB) CASE_TYPE(math, OP_MULTIPLY, OBJECT) CASE_TYPE(math, OP_MULTIPLY, STRING_NAME) CASE_TYPE(math, OP_MULTIPLY, DICTIONARY) @@ -757,16 +1096,50 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MULTIPLY, POOL_INT_ARRAY); CASE_TYPE(math, OP_MULTIPLY, POOL_REAL_ARRAY); CASE_TYPE(math, OP_MULTIPLY, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_VECTOR4I_ARRAY); + CASE_TYPE(math, OP_MULTIPLY, POOL_COLOR_ARRAY); _RETURN_FAIL; } SWITCH_OP(math, OP_DIVIDE, p_a.type) { + CASE_TYPE(math, OP_DIVIDE, QUATERNION) { + if (p_b.type != REAL) + _RETURN_FAIL; +#ifdef DEBUG_ENABLED + if (p_b._data._real == 0) { + r_valid = false; + _RETURN("Division By Zero"); + } +#endif + _RETURN(*reinterpret_cast(p_a._data._mem) / p_b._data._real); + } + DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, INT, _int); DEFAULT_OP_NUM_DIV(math, OP_DIVIDE, REAL, _real); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2, /, Vector2); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR2I, /, Vector2i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3, /, Vector3); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR3I, /, Vector3i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR4, /, Vector4); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, VECTOR4I, /, Vector4i); + DEFAULT_OP_LOCALMEM_NUM(math, OP_DIVIDE, COLOR, /, Color); CASE_TYPE(math, OP_DIVIDE, NIL) CASE_TYPE(math, OP_DIVIDE, BOOL) CASE_TYPE(math, OP_DIVIDE, STRING) + CASE_TYPE(math, OP_DIVIDE, RECT2) + CASE_TYPE(math, OP_DIVIDE, RECT2I) + CASE_TYPE(math, OP_DIVIDE, PLANE) + CASE_TYPE(math, OP_DIVIDE, AABB) + CASE_TYPE(math, OP_DIVIDE, BASIS) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM) + CASE_TYPE(math, OP_DIVIDE, TRANSFORM2D) + CASE_TYPE(math, OP_DIVIDE, PROJECTION) CASE_TYPE(math, OP_DIVIDE, OBJECT) CASE_TYPE(math, OP_DIVIDE, STRING_NAME) CASE_TYPE(math, OP_DIVIDE, DICTIONARY) @@ -775,16 +1148,39 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_DIVIDE, POOL_INT_ARRAY); CASE_TYPE(math, OP_DIVIDE, POOL_REAL_ARRAY); CASE_TYPE(math, OP_DIVIDE, POOL_STRING_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR2_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR2I_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR3_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR3I_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR4_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_VECTOR4I_ARRAY); + CASE_TYPE(math, OP_DIVIDE, POOL_COLOR_ARRAY); _RETURN_FAIL; } SWITCH_OP(math, OP_POSITIVE, p_a.type) { DEFAULT_OP_NUM_POS(math, OP_POSITIVE, INT, _int); DEFAULT_OP_NUM_POS(math, OP_POSITIVE, REAL, _real); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2, Vector2); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR2I, Vector2i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR3I, Vector3i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR4, Vector4); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, VECTOR4I, Vector4i); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_POS(math, OP_POSITIVE, QUATERNION, Quaternion); CASE_TYPE(math, OP_POSITIVE, NIL) CASE_TYPE(math, OP_POSITIVE, BOOL) CASE_TYPE(math, OP_POSITIVE, STRING) + CASE_TYPE(math, OP_POSITIVE, RECT2) + CASE_TYPE(math, OP_POSITIVE, RECT2I) + CASE_TYPE(math, OP_POSITIVE, AABB) + CASE_TYPE(math, OP_POSITIVE, BASIS) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM) + CASE_TYPE(math, OP_POSITIVE, TRANSFORM2D) + CASE_TYPE(math, OP_POSITIVE, PROJECTION) + CASE_TYPE(math, OP_POSITIVE, COLOR) CASE_TYPE(math, OP_POSITIVE, OBJECT) CASE_TYPE(math, OP_POSITIVE, STRING_NAME) CASE_TYPE(math, OP_POSITIVE, DICTIONARY) @@ -793,6 +1189,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_POSITIVE, POOL_INT_ARRAY) CASE_TYPE(math, OP_POSITIVE, POOL_REAL_ARRAY) CASE_TYPE(math, OP_POSITIVE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_VECTOR4I_ARRAY) + CASE_TYPE(math, OP_POSITIVE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -800,9 +1203,26 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, DEFAULT_OP_NUM_NEG(math, OP_NEGATE, INT, _int); DEFAULT_OP_NUM_NEG(math, OP_NEGATE, REAL, _real); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2, Vector2); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR2I, Vector2i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3, Vector3); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR3I, Vector3i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR4, Vector4); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, VECTOR4I, Vector4i); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, PLANE, Plane); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, QUATERNION, Quaternion); + DEFAULT_OP_LOCALMEM_NEG(math, OP_NEGATE, COLOR, Color); + CASE_TYPE(math, OP_NEGATE, NIL) CASE_TYPE(math, OP_NEGATE, BOOL) CASE_TYPE(math, OP_NEGATE, STRING) + CASE_TYPE(math, OP_NEGATE, RECT2) + CASE_TYPE(math, OP_NEGATE, RECT2I) + CASE_TYPE(math, OP_NEGATE, AABB) + CASE_TYPE(math, OP_NEGATE, BASIS) + CASE_TYPE(math, OP_NEGATE, TRANSFORM) + CASE_TYPE(math, OP_NEGATE, TRANSFORM2D) + CASE_TYPE(math, OP_NEGATE, PROJECTION) CASE_TYPE(math, OP_NEGATE, OBJECT) CASE_TYPE(math, OP_NEGATE, STRING_NAME) CASE_TYPE(math, OP_NEGATE, DICTIONARY) @@ -811,6 +1231,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_NEGATE, POOL_INT_ARRAY) CASE_TYPE(math, OP_NEGATE, POOL_REAL_ARRAY) CASE_TYPE(math, OP_NEGATE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_VECTOR4I_ARRAY) + CASE_TYPE(math, OP_NEGATE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -849,6 +1276,22 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, NIL) CASE_TYPE(math, OP_MODULE, BOOL) CASE_TYPE(math, OP_MODULE, REAL) + CASE_TYPE(math, OP_MODULE, RECT2) + CASE_TYPE(math, OP_MODULE, RECT2I) + CASE_TYPE(math, OP_MODULE, VECTOR2) + CASE_TYPE(math, OP_MODULE, VECTOR2I) + CASE_TYPE(math, OP_MODULE, VECTOR3) + CASE_TYPE(math, OP_MODULE, VECTOR3I) + CASE_TYPE(math, OP_MODULE, VECTOR4) + CASE_TYPE(math, OP_MODULE, VECTOR4I) + CASE_TYPE(math, OP_MODULE, PLANE) + CASE_TYPE(math, OP_MODULE, QUATERNION) + CASE_TYPE(math, OP_MODULE, AABB) + CASE_TYPE(math, OP_MODULE, BASIS) + CASE_TYPE(math, OP_MODULE, TRANSFORM) + CASE_TYPE(math, OP_MODULE, TRANSFORM2D) + CASE_TYPE(math, OP_MODULE, PROJECTION) + CASE_TYPE(math, OP_MODULE, COLOR) CASE_TYPE(math, OP_MODULE, OBJECT) CASE_TYPE(math, OP_MODULE, STRING_NAME) CASE_TYPE(math, OP_MODULE, DICTIONARY) @@ -857,6 +1300,13 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, CASE_TYPE(math, OP_MODULE, POOL_INT_ARRAY) CASE_TYPE(math, OP_MODULE, POOL_REAL_ARRAY) CASE_TYPE(math, OP_MODULE, POOL_STRING_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR2_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR2I_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR3_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR3I_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR4_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_VECTOR4I_ARRAY) + CASE_TYPE(math, OP_MODULE, POOL_COLOR_ARRAY) _RETURN_FAIL; } @@ -978,6 +1428,500 @@ void Variant::evaluate(const Operator &p_op, const Variant &p_a, void Variant::set_named(const StringName &p_index, const Variant &p_value, bool *r_valid) { bool valid = false; switch (type) { + case RECT2: { + if (p_value.type == Variant::VECTOR2) { + Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { + Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } + } break; + case RECT2I: { + if (p_value.type == Variant::VECTOR2) { + Rect2i *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { + Rect2i *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } + } break; + case VECTOR2: { + if (p_value.type == Variant::INT) { + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR2I: { + if (p_value.type == Variant::INT) { + Vector2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = static_cast(p_value._data._real); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = static_cast(p_value._data._real); + valid = true; + } + } + + } break; + case VECTOR3: { + if (p_value.type == Variant::INT) { + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR3I: { + if (p_value.type == Variant::INT) { + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR4: { + if (p_value.type == Variant::INT) { + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; + case VECTOR4I: { + if (p_value.type == Variant::INT) { + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; + case PLANE: { + if (p_value.type == Variant::INT) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->normal.x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->normal.y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->normal.z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->d) { + v->d = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->normal.x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->normal.y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->normal.z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->d) { + v->d = p_value._data._real; + valid = true; + } + + } else if (p_value.type == Variant::VECTOR3) { + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->normal) { + v->normal = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + + } break; + case QUATERNION: { + if (p_value.type == Variant::INT) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._int; + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + v->x = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->y = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->z = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->w = p_value._data._real; + valid = true; + } + } + + } break; // 10 + case AABB: { + if (p_value.type == Variant::VECTOR3) { + ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = *reinterpret_cast(p_value._data._mem) - v->position; + valid = true; + } + } else if (p_value.type == Variant::VECTOR3I) { + ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + v->position = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->size) { + v->size = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->end) { + v->size = Vector3(*reinterpret_cast(p_value._data._mem)) - v->position; + valid = true; + } + } + } break; + case BASIS: { + if (p_value.type == Variant::VECTOR3) { + Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + v->set_axis(0, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->set_axis(1, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->set_axis(2, *reinterpret_cast(p_value._data._mem)); + valid = true; + } + } else if (p_value.type == Variant::VECTOR3I) { + Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + v->set_axis(0, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->set_axis(1, *reinterpret_cast(p_value._data._mem)); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->set_axis(2, *reinterpret_cast(p_value._data._mem)); + valid = true; + } + } + } break; + case TRANSFORM: { + if (p_value.type == Variant::BASIS && p_index == CoreStringNames::singleton->basis) { + _data._transform->basis = *p_value._data._basis; + valid = true; + } else if (p_value.type == Variant::VECTOR3 && p_index == CoreStringNames::singleton->origin) { + _data._transform->origin = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_value.type == Variant::VECTOR3I && p_index == CoreStringNames::singleton->origin) { + _data._transform->origin = *reinterpret_cast(p_value._data._mem); + valid = true; + } + + } break; + case TRANSFORM2D: { + if (p_value.type == Variant::VECTOR2) { + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + v->columns[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->columns[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->origin) { + v->columns[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } else if (p_value.type == Variant::VECTOR2I) { + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + v->columns[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->columns[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->origin) { + v->columns[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + + } break; + case PROJECTION: { + if (p_value.type == Variant::VECTOR4) { + Projection *v = _data._projection; + if (p_index == CoreStringNames::singleton->x) { + v->matrix[0] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->y) { + v->matrix[1] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->z) { + v->matrix[2] = *reinterpret_cast(p_value._data._mem); + valid = true; + } else if (p_index == CoreStringNames::singleton->w) { + v->matrix[3] = *reinterpret_cast(p_value._data._mem); + valid = true; + } + } + + } break; + case COLOR: { + if (p_value.type == Variant::INT) { + Color *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->r) { + v->r = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->g) { + v->g = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->b) { + v->b = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->a) { + v->a = p_value._data._int; + valid = true; + } else if (p_index == CoreStringNames::singleton->r8) { + v->r = p_value._data._int / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->g8) { + v->g = p_value._data._int / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->b8) { + v->b = p_value._data._int / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->a8) { + v->a = p_value._data._int / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->h) { + v->set_hsv(p_value._data._int, v->get_s(), v->get_v(), v->a); + valid = true; + } else if (p_index == CoreStringNames::singleton->s) { + v->set_hsv(v->get_h(), p_value._data._int, v->get_v(), v->a); + valid = true; + } else if (p_index == CoreStringNames::singleton->v) { + v->set_hsv(v->get_h(), v->get_s(), p_value._data._int, v->a); + valid = true; + } + } else if (p_value.type == Variant::REAL) { + Color *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->r) { + v->r = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->g) { + v->g = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->b) { + v->b = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->a) { + v->a = p_value._data._real; + valid = true; + } else if (p_index == CoreStringNames::singleton->r8) { + v->r = p_value._data._real / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->g8) { + v->g = p_value._data._real / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->b8) { + v->b = p_value._data._real / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->a8) { + v->a = p_value._data._real / 255.0; + valid = true; + } else if (p_index == CoreStringNames::singleton->h) { + v->set_hsv(p_value._data._real, v->get_s(), v->get_v(), v->a); + valid = true; + } else if (p_index == CoreStringNames::singleton->s) { + v->set_hsv(v->get_h(), p_value._data._real, v->get_v(), v->a); + valid = true; + } else if (p_index == CoreStringNames::singleton->v) { + v->set_hsv(v->get_h(), v->get_s(), p_value._data._real, v->a); + valid = true; + } + } + } break; case OBJECT: { Object *obj = _OBJ_PTR(*this); if (unlikely(!obj)) { @@ -1006,6 +1950,203 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { *r_valid = true; } switch (type) { + case RECT2: { + const Rect2 *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; + case RECT2I: { + const Rect2i *v = reinterpret_cast(_data._mem); + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; + case VECTOR2: { + const Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } + + } break; + case VECTOR2I: { + const Vector2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } + + } break; + case VECTOR3: { + const Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } + + } break; + case VECTOR3I: { + const Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } + + } break; + case VECTOR4: { + const Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; + case VECTOR4I: { + const Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; + case PLANE: { + const Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->normal.x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->normal.y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->normal.z; + } else if (p_index == CoreStringNames::singleton->d) { + return v->d; + } else if (p_index == CoreStringNames::singleton->normal) { + return v->normal; + } + + } break; + case QUATERNION: { + const Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + return v->w; + } + + } break; // 10 + case AABB: { + const ::AABB *v = _data._aabb; + //scalar name + if (p_index == CoreStringNames::singleton->position) { + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + return v->size + v->position; + } + } break; + case BASIS: { + const Basis *v = _data._basis; + //scalar name + if (p_index == CoreStringNames::singleton->x) { + return v->get_axis(0); + } else if (p_index == CoreStringNames::singleton->y) { + return v->get_axis(1); + } else if (p_index == CoreStringNames::singleton->z) { + return v->get_axis(2); + } + + } break; + case TRANSFORM: { + if (p_index == CoreStringNames::singleton->basis) { + return _data._transform->basis; + } else if (p_index == CoreStringNames::singleton->origin) { + return _data._transform->origin; + } + + } break; + case TRANSFORM2D: { + const Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + return v->columns[0]; + } else if (p_index == CoreStringNames::singleton->y) { + return v->columns[1]; + } else if (p_index == CoreStringNames::singleton->origin) { + return v->columns[2]; + } + + } break; + case PROJECTION: { + const Projection *v = _data._projection; + if (p_index == CoreStringNames::singleton->x) { + return v->matrix[0]; + } else if (p_index == CoreStringNames::singleton->y) { + return v->matrix[1]; + } else if (p_index == CoreStringNames::singleton->z) { + return v->matrix[2]; + } else if (p_index == CoreStringNames::singleton->w) { + return v->matrix[3]; + } + + } break; + case COLOR: { + const Color *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->r) { + return v->r; + } else if (p_index == CoreStringNames::singleton->g) { + return v->g; + } else if (p_index == CoreStringNames::singleton->b) { + return v->b; + } else if (p_index == CoreStringNames::singleton->a) { + return v->a; + } else if (p_index == CoreStringNames::singleton->r8) { + return int(Math::round(v->r * 255.0)); + } else if (p_index == CoreStringNames::singleton->g8) { + return int(Math::round(v->g * 255.0)); + } else if (p_index == CoreStringNames::singleton->b8) { + return int(Math::round(v->b * 255.0)); + } else if (p_index == CoreStringNames::singleton->a8) { + return int(Math::round(v->a * 255.0)); + } else if (p_index == CoreStringNames::singleton->h) { + return v->get_h(); + } else if (p_index == CoreStringNames::singleton->s) { + return v->get_s(); + } else if (p_index == CoreStringNames::singleton->v) { + return v->get_v(); + } + } break; case OBJECT: { Object *obj = _OBJ_PTR(*this); if (unlikely(!obj)) { @@ -1129,7 +2270,947 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) return; } break; + case RECT2: { + if (p_value.type == Variant::VECTOR2 || p_value.type == Variant::VECTOR2I) { + if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Rect2 *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + v->size = Vector2(p_value) - v->position; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Rect2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + v->position = p_value; + return; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + v->size = p_value; + return; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + v->size = Vector2(p_value) - v->position; + return; + } + } + } else { + return; + } + } break; //7 + case RECT2I: { + if (p_value.type == Variant::VECTOR2 || p_value.type == Variant::VECTOR2I) { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + Rect2i *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + //TODO fix + v->size = Vector2i(Vector2(p_value)) - v->position; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Rect2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + v->position = p_value; + return; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + v->size = p_value; + return; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + v->size = Vector2(p_value) - v->position; + return; + } + } + } else { + return; + } + } break; + case VECTOR2: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + Vector2 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + Vector2 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } + } + } break; // 5 + case VECTOR2I: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + Vector2i *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + Vector2i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } + } + + } break; //6 + + case VECTOR3: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + Vector3 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } + } + + } break; + case VECTOR3I: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + Vector3i *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } + } + + } break; + case VECTOR4: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + Vector4 *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + } break; + case VECTOR4I: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + Vector4i *v = reinterpret_cast(_data._mem); + valid = true; + (*v)[idx] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + + } break; + case PLANE: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Plane *v = reinterpret_cast(_data._mem); + if (*str == "x") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.x = p_value; + return; + } else if (*str == "y") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.y = p_value; + return; + } else if (*str == "z") { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.z = p_value; + return; + } else if (*str == "normal") { + if (p_value.type != Variant::VECTOR3) { + return; + } + + valid = true; + v->normal = p_value; + return; + } else if (*str == "d") { + valid = true; + v->d = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + valid = true; + v->normal.z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->normal) { + if (p_value.type != Variant::VECTOR3) { + return; + } + + valid = true; + v->normal = p_value; + return; + } else if (p_index == CoreStringNames::singleton->d) { + valid = true; + v->d = p_value; + return; + } + } + + } break; + case QUATERNION: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + Quaternion *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + v->x = p_value; + return; + } else if (*str == "y") { + valid = true; + v->y = p_value; + return; + } else if (*str == "z") { + valid = true; + v->z = p_value; + return; + } else if (*str == "w") { + valid = true; + v->w = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->x = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->y = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->z = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->w = p_value; + return; + } + } + + } break; // 10 + case AABB: { + if (p_value.type != Variant::VECTOR3) { + return; + } + + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + ::AABB *v = _data._aabb; + if (*str == "position") { + valid = true; + v->position = p_value; + return; + } else if (*str == "size") { + valid = true; + v->size = p_value; + return; + } else if (*str == "end") { + valid = true; + v->size = Vector3(p_value) - v->position; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + ::AABB *v = _data._aabb; + if (p_index == CoreStringNames::singleton->position) { + valid = true; + v->position = p_value; + return; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + v->size = p_value; + return; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + v->size = Vector3(p_value) - v->position; + return; + } + } + } break; + case BASIS: { + if (p_value.type != Variant::VECTOR3) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + Basis *v = _data._basis; + + valid = true; + v->set_axis(index, p_value); + return; + } + } else if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + Basis *v = _data._basis; + + if (*str == "x") { + valid = true; + v->set_axis(0, p_value); + return; + } else if (*str == "y") { + valid = true; + v->set_axis(1, p_value); + return; + } else if (*str == "z") { + valid = true; + v->set_axis(2, p_value); + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Basis *v = _data._basis; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->set_axis(0, p_value); + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->set_axis(1, p_value); + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->set_axis(2, p_value); + return; + } + } + + } break; + case TRANSFORM: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + if (p_value.type != Variant::VECTOR3) { + return; + } + + int index = p_index; + + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + Transform *v = _data._transform; + valid = true; + if (index == 3) { + v->origin = p_value; + } else { + v->basis.set_axis(index, p_value); + } + return; + } + } else if (p_index.get_type() == Variant::STRING) { + Transform *v = _data._transform; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "basis") { + if (p_value.type != Variant::BASIS) { + return; + } + valid = true; + v->basis = p_value; + return; + } + if (*str == "origin") { + if (p_value.type != Variant::VECTOR3) { + return; + } + valid = true; + v->origin = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Transform *v = _data._transform; + + if (p_index == CoreStringNames::singleton->basis) { + if (p_value.type != Variant::BASIS) { + return; + } + valid = true; + v->basis = p_value; + return; + } + if (p_index == CoreStringNames::singleton->origin) { + if (p_value.type != Variant::VECTOR3) { + return; + } + valid = true; + v->origin = p_value; + return; + } + } + + } break; + case TRANSFORM2D: { + if (p_value.type != Variant::VECTOR2 || p_value.get_type() != Variant::VECTOR2I) { + return; + } + + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + Transform2D *v = _data._transform2d; + + valid = true; + v->columns[index] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + Transform2D *v = _data._transform2d; + if (*str == "x") { + valid = true; + v->columns[0] = p_value; + return; + } else if (*str == "y") { + valid = true; + v->columns[1] = p_value; + return; + } else if (*str == "origin") { + valid = true; + v->columns[2] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->columns[0] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->columns[1] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->origin) { + valid = true; + v->columns[2] = p_value; + return; + } + } + + } break; + case PROJECTION: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + if (p_value.type != Variant::VECTOR4) { + return; + } + + int index = p_index; + + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + Projection *v = _data._projection; + valid = true; + v->matrix[index] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING) { + Projection *v = _data._projection; + const String *str = reinterpret_cast(p_index._data._mem); + + if (p_value.type != Variant::VECTOR4) { + return; + } + + if (*str == "x") { + valid = true; + v->matrix[0] = p_value; + return; + } else if (*str == "y") { + valid = true; + v->matrix[1] = p_value; + return; + } else if (*str == "z") { + valid = true; + v->matrix[2] = p_value; + return; + } else if (*str == "w") { + valid = true; + v->matrix[3] = p_value; + return; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Projection *v = _data._projection; + + if (p_value.type != Variant::VECTOR4) { + return; + } + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + v->matrix[0] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + v->matrix[1] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + v->matrix[2] = p_value; + return; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + v->matrix[3] = p_value; + return; + } + } + + } break; + case COLOR: { + if (p_value.type != Variant::INT && p_value.type != Variant::REAL) { + return; + } + + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + Color *v = reinterpret_cast(_data._mem); + if (*str == "r") { + valid = true; + v->r = p_value; + return; + } else if (*str == "g") { + valid = true; + v->g = p_value; + return; + } else if (*str == "b") { + valid = true; + v->b = p_value; + return; + } else if (*str == "a") { + valid = true; + v->a = p_value; + return; + } else if (*str == "h") { + valid = true; + v->set_hsv(p_value, v->get_s(), v->get_v(), v->a); + return; + } else if (*str == "s") { + valid = true; + v->set_hsv(v->get_h(), p_value, v->get_v(), v->a); + return; + } else if (*str == "v") { + valid = true; + v->set_hsv(v->get_h(), v->get_s(), p_value, v->a); + return; + } else if (*str == "r8") { + valid = true; + v->r = float(p_value) / 255.0; + return; + } else if (*str == "g8") { + valid = true; + v->g = float(p_value) / 255.0; + return; + } else if (*str == "b8") { + valid = true; + v->b = float(p_value) / 255.0; + return; + } else if (*str == "a8") { + valid = true; + v->a = float(p_value) / 255.0; + return; + } + } else if (p_index.get_type() == Variant::INT) { + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + Color *v = reinterpret_cast(_data._mem); + (*v)[idx] = p_value; + valid = true; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + Color *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->r) { + valid = true; + v->r = p_value; + return; + } else if (p_index == CoreStringNames::singleton->g) { + valid = true; + v->g = p_value; + return; + } else if (p_index == CoreStringNames::singleton->b) { + valid = true; + v->b = p_value; + return; + } else if (p_index == CoreStringNames::singleton->a) { + valid = true; + v->a = p_value; + return; + } else if (p_index == CoreStringNames::singleton->h) { + valid = true; + v->set_hsv(p_value, v->get_s(), v->get_v(), v->a); + return; + } else if (p_index == CoreStringNames::singleton->s) { + valid = true; + v->set_hsv(v->get_h(), p_value, v->get_v(), v->a); + return; + } else if (p_index == CoreStringNames::singleton->v) { + valid = true; + v->set_hsv(v->get_h(), v->get_s(), p_value, v->a); + return; + } else if (p_index == CoreStringNames::singleton->r8) { + valid = true; + v->r = float(p_value) / 255.0; + return; + } else if (p_index == CoreStringNames::singleton->g8) { + valid = true; + v->g = float(p_value) / 255.0; + return; + } else if (p_index == CoreStringNames::singleton->b8) { + valid = true; + v->b = float(p_value) / 255.0; + return; + } else if (p_index == CoreStringNames::singleton->a8) { + valid = true; + v->a = float(p_value) / 255.0; + return; + } + } + + } break; case OBJECT: { Object *obj = _OBJ_PTR(*this); if (unlikely(!obj)) { @@ -1162,6 +3243,9 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) DEFAULT_OP_DVECTOR_SET(POOL_INT_ARRAY, int, p_value.type != Variant::REAL && p_value.type != Variant::INT) DEFAULT_OP_DVECTOR_SET(POOL_REAL_ARRAY, real_t, p_value.type != Variant::REAL && p_value.type != Variant::INT) DEFAULT_OP_DVECTOR_SET(POOL_STRING_ARRAY, String, p_value.type != Variant::STRING) + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR2_ARRAY, Vector2, p_value.type != Variant::VECTOR2) // 25 + DEFAULT_OP_DVECTOR_SET(POOL_VECTOR3_ARRAY, Vector3, p_value.type != Variant::VECTOR3) + DEFAULT_OP_DVECTOR_SET(POOL_COLOR_ARRAY, Color, p_value.type != Variant::COLOR) default: return; } @@ -1203,7 +3287,697 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { } } break; - + case RECT2: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Rect2 *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Rect2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + return v->size + v->position; + } + } + } break; + case RECT2I: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Rect2i *v = reinterpret_cast(_data._mem); + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Rect2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->position) { + valid = true; + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + return v->size + v->position; + } + } + } break; + case VECTOR2: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + const Vector2 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Vector2 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector2 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } + } + + } break; // 5 + case VECTOR2I: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + // scalar index + int idx = p_index; + if (idx < 0) { + idx += 2; + } + if (idx >= 0 && idx < 2) { + const Vector2i *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const Vector2i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector2i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } + } + + } break; // 6 + case VECTOR3: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + const Vector3 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector3 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector3 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } + } + + } break; + case VECTOR3I: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 3; + } + if (idx >= 0 && idx < 3) { + const Vector3i *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector3i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector3i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } + } + + } break; + case VECTOR4: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + const Vector4 *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector4 *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Vector4 *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; + case VECTOR4I: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + //scalar index + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + const Vector4i *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Vector4i *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + const Vector4i *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; + case PLANE: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Plane *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->normal.x; + } else if (*str == "y") { + valid = true; + return v->normal.y; + } else if (*str == "z") { + valid = true; + return v->normal.z; + } else if (*str == "normal") { + valid = true; + return v->normal; + } else if (*str == "d") { + valid = true; + return v->d; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Plane *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->normal.x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->normal.y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->normal.z; + } else if (p_index == CoreStringNames::singleton->normal) { + valid = true; + return v->normal; + } else if (p_index == CoreStringNames::singleton->d) { + valid = true; + return v->d; + } + } + + } break; + case QUATERNION: { + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + const Quaternion *v = reinterpret_cast(_data._mem); + if (*str == "x") { + valid = true; + return v->x; + } else if (*str == "y") { + valid = true; + return v->y; + } else if (*str == "z") { + valid = true; + return v->z; + } else if (*str == "w") { + valid = true; + return v->w; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Quaternion *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->x; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->y; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->z; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->w; + } + } + + } break; // 10 + case AABB: { + if (p_index.get_type() == Variant::STRING) { + //scalar name + + const String *str = reinterpret_cast(p_index._data._mem); + const ::AABB *v = _data._aabb; + if (*str == "position") { + valid = true; + return v->position; + } else if (*str == "size") { + valid = true; + return v->size; + } else if (*str == "end") { + valid = true; + return v->size + v->position; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const ::AABB *v = _data._aabb; + if (p_index == CoreStringNames::singleton->position) { + valid = true; + return v->position; + } else if (p_index == CoreStringNames::singleton->size) { + valid = true; + return v->size; + } else if (p_index == CoreStringNames::singleton->end) { + valid = true; + return v->size + v->position; + } + } + } break; + case BASIS: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + const Basis *v = _data._basis; + + valid = true; + return v->get_axis(index); + } + } else if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + const Basis *v = _data._basis; + + if (*str == "x") { + valid = true; + return v->get_axis(0); + } else if (*str == "y") { + valid = true; + return v->get_axis(1); + } else if (*str == "z") { + valid = true; + return v->get_axis(2); + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Basis *v = _data._basis; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->get_axis(0); + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->get_axis(1); + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->get_axis(2); + } + } + + } break; + case TRANSFORM: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + const Transform *v = _data._transform; + valid = true; + return index == 3 ? v->origin : v->basis.get_axis(index); + } + } else if (p_index.get_type() == Variant::STRING) { + const Transform *v = _data._transform; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "basis") { + valid = true; + return v->basis; + } + if (*str == "origin") { + valid = true; + return v->origin; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Transform *v = _data._transform; + + if (p_index == CoreStringNames::singleton->basis) { + valid = true; + return v->basis; + } + if (p_index == CoreStringNames::singleton->origin) { + valid = true; + return v->origin; + } + } + + } break; + case TRANSFORM2D: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + + if (index < 0) { + index += 3; + } + if (index >= 0 && index < 3) { + const Transform2D *v = _data._transform2d; + + valid = true; + return v->columns[index]; + } + } else if (p_index.get_type() == Variant::STRING) { + //scalar name + const String *str = reinterpret_cast(p_index._data._mem); + const Transform2D *v = _data._transform2d; + if (*str == "x") { + valid = true; + return v->columns[0]; + } else if (*str == "y") { + valid = true; + return v->columns[1]; + } else if (*str == "origin") { + valid = true; + return v->columns[2]; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + //scalar name + + const Transform2D *v = _data._transform2d; + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->columns[0]; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->columns[1]; + } else if (p_index == CoreStringNames::singleton->origin) { + valid = true; + return v->columns[2]; + } + } + + } break; + case PROJECTION: { + if (p_index.get_type() == Variant::INT || p_index.get_type() == Variant::REAL) { + int index = p_index; + if (index < 0) { + index += 4; + } + if (index >= 0 && index < 4) { + const Projection *v = _data._projection; + valid = true; + return v->matrix[index]; + } + } else if (p_index.get_type() == Variant::STRING) { + const Projection *v = _data._projection; + const String *str = reinterpret_cast(p_index._data._mem); + + if (*str == "x") { + valid = true; + return v->matrix[0]; + } else if (*str == "y") { + valid = true; + return v->matrix[1]; + } else if (*str == "z") { + valid = true; + return v->matrix[2]; + } else if (*str == "w") { + valid = true; + return v->matrix[3]; + } + } else if (p_index.get_type() == Variant::STRING_NAME) { + const Projection *v = _data._projection; + + if (p_index == CoreStringNames::singleton->x) { + valid = true; + return v->matrix[0]; + } else if (p_index == CoreStringNames::singleton->y) { + valid = true; + return v->matrix[1]; + } else if (p_index == CoreStringNames::singleton->z) { + valid = true; + return v->matrix[2]; + } else if (p_index == CoreStringNames::singleton->w) { + valid = true; + return v->matrix[3]; + } + } + + } break; + case COLOR: { + if (p_index.get_type() == Variant::STRING) { + const String *str = reinterpret_cast(p_index._data._mem); + const Color *v = reinterpret_cast(_data._mem); + if (*str == "r") { + valid = true; + return v->r; + } else if (*str == "g") { + valid = true; + return v->g; + } else if (*str == "b") { + valid = true; + return v->b; + } else if (*str == "a") { + valid = true; + return v->a; + } else if (*str == "h") { + valid = true; + return v->get_h(); + } else if (*str == "s") { + valid = true; + return v->get_s(); + } else if (*str == "v") { + valid = true; + return v->get_v(); + } else if (*str == "r8") { + valid = true; + return (int)Math::round(v->r * 255.0); + } else if (*str == "g8") { + valid = true; + return (int)Math::round(v->g * 255.0); + } else if (*str == "b8") { + valid = true; + return (int)Math::round(v->b * 255.0); + } else if (*str == "a8") { + valid = true; + return (int)Math::round(v->a * 255.0); + } + } else if (p_index.get_type() == Variant::INT) { + int idx = p_index; + if (idx < 0) { + idx += 4; + } + if (idx >= 0 && idx < 4) { + const Color *v = reinterpret_cast(_data._mem); + valid = true; + return (*v)[idx]; + } + } else if (p_index.get_type() == Variant::STRING) { + const Color *v = reinterpret_cast(_data._mem); + if (p_index == CoreStringNames::singleton->r) { + valid = true; + return v->r; + } else if (p_index == CoreStringNames::singleton->g) { + valid = true; + return v->g; + } else if (p_index == CoreStringNames::singleton->b) { + valid = true; + return v->b; + } else if (p_index == CoreStringNames::singleton->a) { + valid = true; + return v->a; + } else if (p_index == CoreStringNames::singleton->h) { + valid = true; + return v->get_h(); + } else if (p_index == CoreStringNames::singleton->s) { + valid = true; + return v->get_s(); + } else if (p_index == CoreStringNames::singleton->v) { + valid = true; + return v->get_v(); + } else if (p_index == CoreStringNames::singleton->r8) { + valid = true; + return (int)Math::round(v->r * 255.0); + } else if (p_index == CoreStringNames::singleton->g8) { + valid = true; + return (int)Math::round(v->g * 255.0); + } else if (p_index == CoreStringNames::singleton->b8) { + valid = true; + return (int)Math::round(v->b * 255.0); + } else if (p_index == CoreStringNames::singleton->a8) { + valid = true; + return (int)Math::round(v->a * 255.0); + } + } + + } break; case OBJECT: { Object *obj = _OBJ_PTR(*this); if (unlikely(!obj)) { @@ -1234,6 +4008,13 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { DEFAULT_OP_DVECTOR_GET(POOL_INT_ARRAY, int) DEFAULT_OP_DVECTOR_GET(POOL_REAL_ARRAY, real_t) DEFAULT_OP_DVECTOR_GET(POOL_STRING_ARRAY, String) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR2_ARRAY, Vector2) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR2I_ARRAY, Vector2i) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR3_ARRAY, Vector3) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR3I_ARRAY, Vector3i) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR4_ARRAY, Vector4) + DEFAULT_OP_DVECTOR_GET(POOL_VECTOR4I_ARRAY, Vector4i) + DEFAULT_OP_DVECTOR_GET(POOL_COLOR_ARRAY, Color) default: return Variant(); } @@ -1366,7 +4147,138 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const { } } break; //25 - + case POOL_VECTOR2_ARRAY: { + if (p_index.get_type() == Variant::VECTOR2) { + Vector2 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR2I_ARRAY: { + if (p_index.get_type() == Variant::VECTOR2I) { + Vector2i index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR3_ARRAY: { + if (p_index.get_type() == Variant::VECTOR3) { + Vector3 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR3I_ARRAY: { + if (p_index.get_type() == Variant::VECTOR3I) { + Vector3i index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR4_ARRAY: { + if (p_index.get_type() == Variant::VECTOR4) { + Vector4 index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_VECTOR4I_ARRAY: { + if (p_index.get_type() == Variant::VECTOR4I) { + Vector4i index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + + } break; + case POOL_COLOR_ARRAY: { + if (p_index.get_type() == Variant::COLOR) { + Color index = p_index; + const PoolVector *arr = reinterpret_cast *>(_data._mem); + + int l = arr->size(); + if (l) { + PoolVector::Read r = arr->read(); + for (int i = 0; i < l; i++) { + if (r[i] == index) { + return true; + } + } + } + + return false; + } + } break; default: { } } @@ -1388,6 +4300,54 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { r_iter = 0; return _data._real > 0.0; } break; + case VECTOR2: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + + r_iter = from; + + return from < to; + } break; + case VECTOR2I: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + + r_iter = from; + + return from < to; + } break; + case VECTOR3: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + r_iter = from; + + if (from == to) { + return false; + } else if (from < to) { + return step > 0; + } else { + return step < 0; + } + //return true; + } break; + case VECTOR3I: { + int64_t from = reinterpret_cast(_data._mem)->x; + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + r_iter = from; + + if (from == to) { + return false; + } else if (from < to) { + return step > 0; + } else { + return step < 0; + } + //return true; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); if (str->empty()) { @@ -1450,6 +4410,63 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { r_iter = 0; return true; } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR2I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + } break; + case POOL_COLOR_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + if (arr->size() == 0) { + return false; + } + r_iter = 0; + return true; + + } break; default: { } } @@ -1478,6 +4495,68 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case VECTOR2: { + int64_t to = reinterpret_cast(_data._mem)->y; + + int64_t idx = r_iter; + idx++; + + if (idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; + case VECTOR2I: { + int64_t to = reinterpret_cast(_data._mem)->y; + + int64_t idx = r_iter; + idx++; + + if (idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; + case VECTOR3: { + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + int64_t idx = r_iter; + idx += step; + + if (step < 0 && idx <= to) { + return false; + } + + if (step > 0 && idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; + case VECTOR3I: { + int64_t to = reinterpret_cast(_data._mem)->y; + int64_t step = reinterpret_cast(_data._mem)->z; + + int64_t idx = r_iter; + idx += step; + + if (step < 0 && idx <= to) { + return false; + } + + if (step > 0 && idx >= to) { + return false; + } + + r_iter = idx; + return true; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); int idx = r_iter; @@ -1552,6 +4631,76 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { r_iter = idx; return true; } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR2I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; + case POOL_COLOR_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; + idx++; + if (idx >= arr->size()) { + return false; + } + r_iter = idx; + return true; + } break; default: { } } @@ -1569,6 +4718,18 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { case REAL: { return r_iter; } break; + case VECTOR2: { + return r_iter; + } break; + case VECTOR2I: { + return r_iter; + } break; + case VECTOR3: { + return r_iter; + } break; + case VECTOR3I: { + return r_iter; + } break; case STRING: { const String *str = reinterpret_cast(_data._mem); return str->substr(r_iter, 1); @@ -1629,6 +4790,83 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { r_valid = false; return Variant(); } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR2I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_VECTOR4I_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } +#endif + return arr->get(idx); + } break; + case POOL_COLOR_ARRAY: { + const PoolVector *arr = reinterpret_cast *>(_data._mem); + int idx = r_iter; +#ifdef DEBUG_ENABLED + if (idx < 0 || idx >= arr->size()) { + r_valid = false; + return Variant(); + } #endif return arr->get(idx); } break; @@ -1684,6 +4922,97 @@ void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) { r_dst = ra - rb; } return; + case RECT2: { + const Rect2 *ra = reinterpret_cast(a._data._mem); + const Rect2 *rb = reinterpret_cast(b._data._mem); + r_dst = Rect2(ra->position - rb->position, ra->size - rb->size); + } + return; + case RECT2I: { + const Rect2i *ra = reinterpret_cast(a._data._mem); + const Rect2i *rb = reinterpret_cast(b._data._mem); + + int32_t vax = ra->position.x; + int32_t vay = ra->position.y; + int32_t vbx = ra->size.x; + int32_t vby = ra->size.y; + int32_t vcx = rb->position.x; + int32_t vcy = rb->position.y; + int32_t vdx = rb->size.x; + int32_t vdy = rb->size.y; + + r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy)); + } + return; + case VECTOR2: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; + case VECTOR2I: { + int32_t vax = reinterpret_cast(a._data._mem)->x; + int32_t vbx = reinterpret_cast(b._data._mem)->x; + int32_t vay = reinterpret_cast(a._data._mem)->y; + int32_t vby = reinterpret_cast(b._data._mem)->y; + r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby)); + } + return; + case VECTOR3: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; + case VECTOR3I: { + int32_t vax = reinterpret_cast(a._data._mem)->x; + int32_t vbx = reinterpret_cast(b._data._mem)->x; + int32_t vay = reinterpret_cast(a._data._mem)->y; + int32_t vby = reinterpret_cast(b._data._mem)->y; + int32_t vaz = reinterpret_cast(a._data._mem)->z; + int32_t vbz = reinterpret_cast(b._data._mem)->z; + r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz)); + } + return; + case VECTOR4: { + r_dst = *reinterpret_cast(a._data._mem) - *reinterpret_cast(b._data._mem); + } + return; + case VECTOR4I: { + int32_t vax = reinterpret_cast(a._data._mem)->x; + int32_t vbx = reinterpret_cast(b._data._mem)->x; + int32_t vay = reinterpret_cast(a._data._mem)->y; + int32_t vaw = reinterpret_cast(a._data._mem)->w; + int32_t vby = reinterpret_cast(b._data._mem)->y; + int32_t vaz = reinterpret_cast(a._data._mem)->z; + int32_t vbz = reinterpret_cast(b._data._mem)->z; + int32_t vbw = reinterpret_cast(b._data._mem)->w; + r_dst = Vector4i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz), int32_t(vaw - vbw)); + } + return; + case AABB: { + const ::AABB *ra = reinterpret_cast(a._data._mem); + const ::AABB *rb = reinterpret_cast(b._data._mem); + r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size); + } + return; + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast(a._data._mem); + const Quaternion *qb = reinterpret_cast(b._data._mem); + r_dst = (*qb).inverse() * *qa; + } + return; + case COLOR: { + const Color *ca = reinterpret_cast(a._data._mem); + const Color *cb = reinterpret_cast(b._data._mem); + float new_r = ca->r - cb->r; + float new_g = ca->g - cb->g; + float new_b = ca->b - cb->b; + float new_a = ca->a - cb->a; + new_r = new_r > 1.0 ? 1.0 : new_r; + new_g = new_g > 1.0 ? 1.0 : new_g; + new_b = new_b > 1.0 ? 1.0 : new_b; + new_a = new_a > 1.0 ? 1.0 : new_a; + r_dst = Color(new_r, new_g, new_b, new_a); + } + return; default: { r_dst = a; } @@ -1720,6 +5049,69 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = ra + rb * c; } return; + case RECT2: { + const Rect2 *ra = reinterpret_cast(a._data._mem); + const Rect2 *rb = reinterpret_cast(b._data._mem); + r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c); + } + return; + case RECT2I: { + const Rect2i *ra = reinterpret_cast(a._data._mem); + const Rect2i *rb = reinterpret_cast(b._data._mem); + r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c); + } + return; + case VECTOR2: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR2I: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR3: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR3I: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR4: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case VECTOR4I: { + r_dst = *reinterpret_cast(a._data._mem) + *reinterpret_cast(b._data._mem) * c; + } + return; + case AABB: { + const ::AABB *ra = reinterpret_cast(a._data._mem); + const ::AABB *rb = reinterpret_cast(b._data._mem); + r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); + } + return; + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast(a._data._mem); + const Quaternion *qb = reinterpret_cast(b._data._mem); + r_dst = *qa * empty_rot.slerp(*qb, c); + } + return; + case COLOR: { + const Color *ca = reinterpret_cast(a._data._mem); + const Color *cb = reinterpret_cast(b._data._mem); + float new_r = ca->r + cb->r * c; + float new_g = ca->g + cb->g * c; + float new_b = ca->b + cb->b * c; + float new_a = ca->a + cb->a * c; + new_r = new_r > 1.0 ? 1.0 : new_r; + new_g = new_g > 1.0 ? 1.0 : new_g; + new_b = new_b > 1.0 ? 1.0 : new_b; + new_a = new_a > 1.0 ? 1.0 : new_a; + r_dst = Color(new_r, new_g, new_b, new_a); + } + return; default: { r_dst = c < 0.5 ? a : b; } @@ -1802,6 +5194,66 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = dst; } return; + case RECT2: { + r_dst = Rect2(reinterpret_cast(a._data._mem)->position.linear_interpolate(reinterpret_cast(b._data._mem)->position, c), reinterpret_cast(a._data._mem)->size.linear_interpolate(reinterpret_cast(b._data._mem)->size, c)); + } + return; + case RECT2I: { + r_dst = Rect2(reinterpret_cast(a._data._mem)->position.linear_interpolate(reinterpret_cast(b._data._mem)->position, c), reinterpret_cast(a._data._mem)->size.linear_interpolate(reinterpret_cast(b._data._mem)->size, c)); + } + return; + case VECTOR2: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR2I: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR3: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR3I: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR4: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case VECTOR4I: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; + case PLANE: { + r_dst = a; + } + return; + case QUATERNION: { + r_dst = reinterpret_cast(a._data._mem)->slerp(*reinterpret_cast(b._data._mem), c); + } + return; + case AABB: { + r_dst = ::AABB(a._data._aabb->position.linear_interpolate(b._data._aabb->position, c), a._data._aabb->size.linear_interpolate(b._data._aabb->size, c)); + } + return; + case BASIS: { + r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis; + } + return; + case TRANSFORM: { + r_dst = a._data._transform->interpolate_with(*b._data._transform, c); + } + return; + case TRANSFORM2D: { + r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c); + } + return; + case COLOR: { + r_dst = reinterpret_cast(a._data._mem)->linear_interpolate(*reinterpret_cast(b._data._mem), c); + } + return; case OBJECT: { r_dst = a; } @@ -1873,6 +5325,163 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = a; } return; + case POOL_VECTOR2_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR2I_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR3_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR3I_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR4_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; + case POOL_VECTOR4I_ARRAY: { + /* + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].lerp(br[i], c); + } + } + r_dst = v; + } + */ + r_dst = a; + } + return; + case POOL_COLOR_ARRAY: { + const PoolVector *arr_a = reinterpret_cast *>(a._data._mem); + const PoolVector *arr_b = reinterpret_cast *>(b._data._mem); + int sz = arr_a->size(); + if (sz == 0 || arr_b->size() != sz) { + r_dst = a; + } else { + PoolVector v; + v.resize(sz); + { + PoolVector::Write vw = v.write(); + PoolVector::Read ar = arr_a->read(); + PoolVector::Read br = arr_b->read(); + + for (int i = 0; i < sz; i++) { + vw[i] = ar[i].linear_interpolate(br[i], c); + } + } + r_dst = v; + } + } + return; default: { r_dst = a; } diff --git a/tools/merger/sfwl/sfwl_core.cpp.inl b/tools/merger/sfwl/sfwl_core.cpp.inl index 71fbe5a..b28c49a 100644 --- a/tools/merger/sfwl/sfwl_core.cpp.inl +++ b/tools/merger/sfwl/sfwl_core.cpp.inl @@ -91,6 +91,11 @@ //--STRIP {{FILE:sfwl/core/string_name.cpp}} +//--STRIP +//#include "core/math_funcs.h" +//--STRIP +{{FILE:sfwl/core/color.cpp}} + //--STRIP //#include "core/pcg.h" //--STRIP @@ -101,14 +106,34 @@ //--STRIP {{FILE:sfwl/core/file_access.cpp}} -{{FILE:sfwl/core/3rd_tinydir.h}} - //--STRIP //#include "dir_access.h" //#include "3rd_tinydir.h" //--STRIP {{FILE:sfwl/core/dir_access.cpp}} +//--STRIP +//System includes +//--STRIP +{{FILE:sfwl/core/inet_address.cpp}} +//--STRIP +//#include "core/error_macros.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/socket.cpp}} + +//--STRIP +//Win Only +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//--STRIP +{{FILE:sfwl/core/sub_process.cpp}} + //--STRIP //#include "core/pool_vector.h" //#include "core/string_name.h" diff --git a/tools/merger/sfwl/sfwl_core.h.inl b/tools/merger/sfwl/sfwl_core.h.inl index 4aafa84..a397b66 100644 --- a/tools/merger/sfwl/sfwl_core.h.inl +++ b/tools/merger/sfwl/sfwl_core.h.inl @@ -1,6 +1,8 @@ #ifndef SFWL_H #define SFWL_H +{{FILEINLINE:sfwl/core/version.h}} + {{FILEINLINE:tools/merger/sfw_readme.inl.h}} {{FILEINLINE:tools/merger/sfw_linceses_core.inl.h}} @@ -38,6 +40,11 @@ //--STRIP {{FILE:sfwl/core/typedefs.h}} +//--STRIP +//#include "core/int_types.h" +//#include "core/math_defs.h" +//--STRIP +{{FILE:sfwl/core/marshalls.h}} //--STRIP //#include "core/int_types.h" @@ -199,6 +206,12 @@ //--STRIP {{FILE:sfwl/core/string_name.h}} +//--STRIP +//#include "core/math_funcs.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/color.h}} + //--STRIP //Needs ustring.h //--STRIP @@ -309,6 +322,29 @@ //--STRIP {{FILE:sfwl/core/dir_access.h}} +//--STRIP +//#include "int_types.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/inet_address.h}} +//--STRIP +//#include "inet_address.h" +//--STRIP +{{FILE:sfwl/core/socket.h}} + +//--STRIP +//#include "core/list.h" +//#include "core/math_defs.h" +//#include "core/memory.h" +//#include "core/mutex.h" +//#include "core/typedefs.h" +//#include "core/ustring.h" +//#include +//Win Only +//#include "core/local_vector.h" +//--STRIP +{{FILE:sfwl/core/sub_process.h}} + //--STRIP //no includes //--STRIP diff --git a/tools/merger/sfwl/sfwl_full.cpp.inl b/tools/merger/sfwl/sfwl_full.cpp.inl index a9e8b45..c4ab33f 100644 --- a/tools/merger/sfwl/sfwl_full.cpp.inl +++ b/tools/merger/sfwl/sfwl_full.cpp.inl @@ -91,6 +91,11 @@ //--STRIP {{FILE:sfwl/core/string_name.cpp}} +//--STRIP +//#include "core/math_funcs.h" +//--STRIP +{{FILE:sfwl/core/color.cpp}} + //--STRIP //#include "core/pcg.h" //--STRIP @@ -101,14 +106,34 @@ //--STRIP {{FILE:sfwl/core/file_access.cpp}} -{{FILE:sfwl/core/3rd_tinydir.h}} - //--STRIP //#include "dir_access.h" //#include "3rd_tinydir.h" //--STRIP {{FILE:sfwl/core/dir_access.cpp}} +//--STRIP +//System includes +//--STRIP +{{FILE:sfwl/core/inet_address.cpp}} +//--STRIP +//#include "core/error_macros.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/socket.cpp}} + +//--STRIP +//Win Only +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//--STRIP +{{FILE:sfwl/core/sub_process.cpp}} + //--STRIP //#include "core/pool_vector.h" //#include "core/string_name.h" diff --git a/tools/merger/sfwl/sfwl_full.h.inl b/tools/merger/sfwl/sfwl_full.h.inl index 317ff25..b617750 100644 --- a/tools/merger/sfwl/sfwl_full.h.inl +++ b/tools/merger/sfwl/sfwl_full.h.inl @@ -1,6 +1,8 @@ #ifndef SFWL_H #define SFWL_H +{{FILEINLINE:sfwl/core/version.h}} + {{FILEINLINE:tools/merger/sfw_readme.inl.h}} {{FILEINLINE:tools/merger/sfw_linceses_core.inl.h}} @@ -38,6 +40,11 @@ //--STRIP {{FILE:sfwl/core/typedefs.h}} +//--STRIP +//#include "core/int_types.h" +//#include "core/math_defs.h" +//--STRIP +{{FILE:sfwl/core/marshalls.h}} //--STRIP //#include "core/int_types.h" @@ -199,6 +206,12 @@ //--STRIP {{FILE:sfwl/core/string_name.h}} +//--STRIP +//#include "core/math_funcs.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/color.h}} + //--STRIP //Needs ustring.h //--STRIP @@ -309,6 +322,29 @@ //--STRIP {{FILE:sfwl/core/dir_access.h}} +//--STRIP +//#include "int_types.h" +//#include "core/ustring.h" +//--STRIP +{{FILE:sfwl/core/inet_address.h}} +//--STRIP +//#include "inet_address.h" +//--STRIP +{{FILE:sfwl/core/socket.h}} + +//--STRIP +//#include "core/list.h" +//#include "core/math_defs.h" +//#include "core/memory.h" +//#include "core/mutex.h" +//#include "core/typedefs.h" +//#include "core/ustring.h" +//#include +//Win Only +//#include "core/local_vector.h" +//--STRIP +{{FILE:sfwl/core/sub_process.h}} + //--STRIP //no includes //--STRIP