From 304b511d1a21194944b88ce739cd6a14755c2d3d Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 8 Nov 2022 12:25:53 +0000 Subject: [PATCH] assorted --- dep/cxong/tinydir.h | 838 +++++++++++++++++++++++++++++++++++++ dep/randygaul/cute_files.h | 520 +++++++++++++++++++++++ dep/stb/stb_vorbis.h | 18 +- src/vg/vg.h | 26 +- src/vg/vg_audio.h | 9 +- src/vg/vg_input.h | 215 +++++++--- src/vg/vg_m.h | 9 +- src/vg/vg_steam_utils.h | 41 ++ 8 files changed, 1592 insertions(+), 84 deletions(-) create mode 100644 dep/cxong/tinydir.h create mode 100644 dep/randygaul/cute_files.h diff --git a/dep/cxong/tinydir.h b/dep/cxong/tinydir.h new file mode 100644 index 0000000..ba20c3e --- /dev/null +++ b/dep/cxong/tinydir.h @@ -0,0 +1,838 @@ +/* +Copyright (c) 2013-2021, 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__ +#elif defined(__cplusplus) +# define _TINYDIR_FUNC static inline +#elif defined(__GNUC__) +/* Suppress unused function warning */ +# define _TINYDIR_FUNC __attribute__((unused)) static +#else +# define _TINYDIR_FUNC static +#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)) \ + || ((defined __APPLE__) && (defined __MACH__)) \ + || (defined BSD) + 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/dep/randygaul/cute_files.h b/dep/randygaul/cute_files.h new file mode 100644 index 0000000..fcd585e --- /dev/null +++ b/dep/randygaul/cute_files.h @@ -0,0 +1,520 @@ +/* + ------------------------------------------------------------------------------ + Licensing information can be found at the end of the file. + ------------------------------------------------------------------------------ + + cute_files.h - v1.0 + + To create implementation (the function definitions) + #define CUTE_FILES_IMPLEMENTATION + in *one* C/CPP file (translation unit) that includes this file + + Summary: + Utility header for traversing directories to apply a function on each found file. + Recursively finds sub-directories. Can also be used to iterate over files in a + folder manually. All operations done in a cross-platform manner (thx posix!). + + This header does no dynamic memory allocation, and performs internally safe string + copies as necessary. Strings for paths, file names and file extensions are all + capped, and intended to use primarily the C run-time stack memory. Feel free to + modify the defines in this file to adjust string size limitations. + + Read the header for specifics on each function. + + Here's an example to print all files in a folder: + cf_dir_t dir; + cf_dir_open(&dir, "a"); + + while (dir.has_next) + { + cf_file_t file; + cf_read_file(&dir, &file); + printf("%s\n", file.name); + cf_dir_next(&dir); + } + + cf_dir_close(&dir); +*/ + +#if !defined(CUTE_FILES_H) + +#define CUTE_FILES_WINDOWS 1 +#define CUTE_FILES_MAC 2 +#define CUTE_FILES_UNIX 3 + +#if defined(_WIN32) + #define CUTE_FILES_PLATFORM CUTE_FILES_WINDOWS + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS + #endif +#elif defined(__APPLE__) + #define CUTE_FILES_PLATFORM CUTE_FILES_MAC +#else + #define CUTE_FILES_PLATFORM CUTE_FILES_UNIX +#endif + +#include // strerror, strncpy + +// change to 0 to compile out any debug checks +#define CUTE_FILES_DEBUG_CHECKS 1 + +#if CUTE_FILES_DEBUG_CHECKS + + #include // printf + #include // assert + #include + #define CUTE_FILES_ASSERT assert + +#else + + #define CUTE_FILES_ASSERT(...) + +#endif // CUTE_FILES_DEBUG_CHECKS + +#define CUTE_FILES_MAX_PATH 1024 +#define CUTE_FILES_MAX_FILENAME 256 +#define CUTE_FILES_MAX_EXT 32 + +struct cf_file_t; +struct cf_dir_t; +struct cf_time_t; +typedef struct cf_file_t cf_file_t; +typedef struct cf_dir_t cf_dir_t; +typedef struct cf_time_t cf_time_t; +typedef void (cf_callback_t)(cf_file_t* file, void* udata); + +// Stores the file extension in cf_file_t::ext, and returns a pointer to +// cf_file_t::ext +const char* cf_get_ext(cf_file_t* file); + +// Applies a function (cb) to all files in a directory. Will recursively visit +// all subdirectories. Useful for asset management, file searching, indexing, etc. +void cf_traverse(const char* path, cf_callback_t* cb, void* udata); + +// Fills out a cf_file_t struct with file information. Does not actually open the +// file contents, and instead performs more lightweight OS-specific calls. +int cf_read_file(cf_dir_t* dir, cf_file_t* file); + +// Once a cf_dir_t is opened, this function can be used to grab another file +// from the operating system. +void cf_dir_next(cf_dir_t* dir); + +// Performs lightweight OS-specific call to close internal handle. +void cf_dir_close(cf_dir_t* dir); + +// Performs lightweight OS-specific call to open a file handle on a directory. +int cf_dir_open(cf_dir_t* dir, const char* path); + +// Compares file last write times. -1 if file at path_a was modified earlier than path_b. +// 0 if they are equal. 1 if file at path_b was modified earlier than path_a. +int cf_compare_file_times_by_path(const char* path_a, const char* path_b); + +// Retrieves time file was last modified, returns 0 upon failure +int cf_get_file_time(const char* path, cf_time_t* time); + +// Compares file last write times. -1 if time_a was modified earlier than path_b. +// 0 if they are equal. 1 if time_b was modified earlier than path_a. +int cf_compare_file_times(cf_time_t* time_a, cf_time_t* time_b); + +// Returns 1 of file exists, otherwise returns 0. +int cf_file_exists(const char* path); + +// Returns 1 if the file's extension matches the string in ext +// Returns 0 otherwise +int cf_match_ext(cf_file_t* file, const char* ext); + +// Prints detected errors to stdout +void cf_do_unit_tests(); + +#if CUTE_FILES_PLATFORM == CUTE_FILES_WINDOWS + +#if !defined _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#endif +#include + + struct cf_file_t + { + char path[CUTE_FILES_MAX_PATH]; + char name[CUTE_FILES_MAX_FILENAME]; + char ext[CUTE_FILES_MAX_EXT]; + int is_dir; + int is_reg; + size_t size; + }; + + struct cf_dir_t + { + char path[CUTE_FILES_MAX_PATH]; + int has_next; + HANDLE handle; + WIN32_FIND_DATAA fdata; + }; + + struct cf_time_t + { + FILETIME time; + }; + +#elif CUTE_FILES_PLATFORM == CUTE_FILES_MAC || CUTE_FILES_PLATFORM == CUTE_FILES_UNIX + + #include + #include + #include + #include + + struct cf_file_t + { + char path[CUTE_FILES_MAX_PATH]; + char name[CUTE_FILES_MAX_FILENAME]; + char ext[CUTE_FILES_MAX_EXT]; + int is_dir; + int is_reg; + int size; + struct stat info; + }; + + struct cf_dir_t + { + char path[CUTE_FILES_MAX_PATH]; + int has_next; + DIR* dir; + struct dirent* entry; + }; + + struct cf_time_t + { + time_t time; + }; + +#endif + +#define CUTE_FILES_H +#endif + +#ifdef CUTE_FILES_IMPLEMENTATION +#ifndef CUTE_FILES_IMPLEMENTATION_ONCE +#define CUTE_FILES_IMPLEMENTATION_ONCE + +#define cf_safe_strcpy(dst, src, n, max) cf_safe_strcpy_internal(dst, src, n, max, __FILE__, __LINE__) +static int cf_safe_strcpy_internal(char* dst, const char* src, int n, int max, const char* file, int line) +{ + int c; + const char* original = src; + + do + { + if (n >= max) + { + if (!CUTE_FILES_DEBUG_CHECKS) break; + printf("ERROR: String \"%s\" too long to copy on line %d in file %s (max length of %d).\n" + , original + , line + , file + , max); + CUTE_FILES_ASSERT(0); + } + + c = *src++; + dst[n] = c; + ++n; + } while (c); + + return n; +} + +const char* cf_get_ext(cf_file_t* file) +{ + char* name = file->name; + char* period = NULL; + while (*name++) if (*name == '.') period = name; + if (period) cf_safe_strcpy(file->ext, period, 0, CUTE_FILES_MAX_EXT); + else file->ext[0] = 0; + return file->ext; +} + +void cf_traverse(const char* path, cf_callback_t* cb, void* udata) +{ + cf_dir_t dir; + cf_dir_open(&dir, path); + + while (dir.has_next) + { + cf_file_t file; + int res = cf_read_file(&dir, &file); + + if (res == 0) { + cf_dir_next(&dir); + continue; + } + + if (file.is_dir && file.name[0] != '.') + { + char path2[CUTE_FILES_MAX_PATH]; + int n = cf_safe_strcpy(path2, path, 0, CUTE_FILES_MAX_PATH); + n = cf_safe_strcpy(path2, "/", n - 1, CUTE_FILES_MAX_PATH); + cf_safe_strcpy(path2, file.name, n -1, CUTE_FILES_MAX_PATH); + cf_traverse(path2, cb, udata); + } + + if (file.is_reg) cb(&file, udata); + cf_dir_next(&dir); + } + + cf_dir_close(&dir); +} + +int cf_match_ext(cf_file_t* file, const char* ext) +{ + return !strcmp(file->ext, ext); +} + +#if CUTE_FILES_PLATFORM == CUTE_FILES_WINDOWS + + int cf_read_file(cf_dir_t* dir, cf_file_t* file) + { + CUTE_FILES_ASSERT(dir->handle != INVALID_HANDLE_VALUE); + + int n = 0; + char* fpath = file->path; + char* dpath = dir->path; + + n = cf_safe_strcpy(fpath, dpath, 0, CUTE_FILES_MAX_PATH); + n = cf_safe_strcpy(fpath, "/", n - 1, CUTE_FILES_MAX_PATH); + + char* dname = dir->fdata.cFileName; + char* fname = file->name; + + cf_safe_strcpy(fname, dname, 0, CUTE_FILES_MAX_FILENAME); + cf_safe_strcpy(fpath, fname, n - 1, CUTE_FILES_MAX_PATH); + + size_t max_dword = MAXDWORD; + file->size = ((size_t)dir->fdata.nFileSizeHigh * (max_dword + 1)) + (size_t)dir->fdata.nFileSizeLow; + cf_get_ext(file); + + file->is_dir = !!(dir->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + file->is_reg = !!(dir->fdata.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) || + !(dir->fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); + + return 1; + } + + void cf_dir_next(cf_dir_t* dir) + { + CUTE_FILES_ASSERT(dir->has_next); + + if (!FindNextFileA(dir->handle, &dir->fdata)) + { + dir->has_next = 0; + DWORD err = GetLastError(); + CUTE_FILES_ASSERT(err == ERROR_SUCCESS || err == ERROR_NO_MORE_FILES); + } + } + + void cf_dir_close(cf_dir_t* dir) + { + dir->path[0] = 0; + dir->has_next = 0; + if (dir->handle != INVALID_HANDLE_VALUE) FindClose(dir->handle); + } + + int cf_dir_open(cf_dir_t* dir, const char* path) + { + int n = cf_safe_strcpy(dir->path, path, 0, CUTE_FILES_MAX_PATH); + n = cf_safe_strcpy(dir->path, "\\*", n - 1, CUTE_FILES_MAX_PATH); + dir->handle = FindFirstFileA(dir->path, &dir->fdata); + dir->path[n - 3] = 0; + + if (dir->handle == INVALID_HANDLE_VALUE) + { + printf("ERROR: Failed to open directory (%s): %s.\n", path, strerror(errno)); + cf_dir_close(dir); + CUTE_FILES_ASSERT(0); + return 0; + } + + dir->has_next = 1; + + return 1; + } + + int cf_compare_file_times_by_path(const char* path_a, const char* path_b) + { + FILETIME time_a = { 0 }; + FILETIME time_b = { 0 }; + WIN32_FILE_ATTRIBUTE_DATA data; + + if (GetFileAttributesExA(path_a, GetFileExInfoStandard, &data)) time_a = data.ftLastWriteTime; + if (GetFileAttributesExA(path_b, GetFileExInfoStandard, &data)) time_b = data.ftLastWriteTime; + return CompareFileTime(&time_a, &time_b); + } + + int cf_get_file_time(const char* path, cf_time_t* time) + { + FILETIME initialized_to_zero = { 0 }; + time->time = initialized_to_zero; + WIN32_FILE_ATTRIBUTE_DATA data; + if (GetFileAttributesExA(path, GetFileExInfoStandard, &data)) + { + time->time = data.ftLastWriteTime; + return 1; + } + return 0; + } + + int cf_compare_file_times(cf_time_t* time_a, cf_time_t* time_b) + { + return CompareFileTime(&time_a->time, &time_b->time); + } + + int cf_file_exists(const char* path) + { + WIN32_FILE_ATTRIBUTE_DATA unused; + return GetFileAttributesExA(path, GetFileExInfoStandard, &unused); + } + +#elif CUTE_FILES_PLATFORM == CUTE_FILES_MAC || CUTE_FILES_PLATFORM == CUTE_FILES_UNIX + + int cf_read_file(cf_dir_t* dir, cf_file_t* file) + { + CUTE_FILES_ASSERT(dir->entry); + + int n = 0; + char* fpath = file->path; + char* dpath = dir->path; + + n = cf_safe_strcpy(fpath, dpath, 0, CUTE_FILES_MAX_PATH); + n = cf_safe_strcpy(fpath, "/", n - 1, CUTE_FILES_MAX_PATH); + + char* dname = dir->entry->d_name; + char* fname = file->name; + + cf_safe_strcpy(fname, dname, 0, CUTE_FILES_MAX_FILENAME); + cf_safe_strcpy(fpath, fname, n - 1, CUTE_FILES_MAX_PATH); + + if (stat(file->path, &file->info)) + return 0; + + file->size = file->info.st_size; + cf_get_ext(file); + + file->is_dir = S_ISDIR(file->info.st_mode); + file->is_reg = S_ISREG(file->info.st_mode); + + return 1; + } + + void cf_dir_next(cf_dir_t* dir) + { + CUTE_FILES_ASSERT(dir->has_next); + dir->entry = readdir(dir->dir); + dir->has_next = dir->entry ? 1 : 0; + } + + void cf_dir_close(cf_dir_t* dir) + { + dir->path[0] = 0; + if (dir->dir) closedir(dir->dir); + dir->dir = 0; + dir->has_next = 0; + dir->entry = 0; + } + + int cf_dir_open(cf_dir_t* dir, const char* path) + { + cf_safe_strcpy(dir->path, path, 0, CUTE_FILES_MAX_PATH); + dir->dir = opendir(path); + + if (!dir->dir) + { + printf("ERROR: Failed to open directory (%s): %s.\n", path, strerror(errno)); + cf_dir_close(dir); + CUTE_FILES_ASSERT(0); + return 0; + } + + dir->has_next = 1; + dir->entry = readdir(dir->dir); + if (!dir->dir) dir->has_next = 0; + + return 1; + } + + // Warning : untested code! (let me know if it breaks) + int cf_compare_file_times_by_path(const char* path_a, const char* path_b) + { + time_t time_a; + time_t time_b; + struct stat info; + if (stat(path_a, &info)) return 0; + time_a = info.st_mtime; + if (stat(path_b, &info)) return 0; + time_b = info.st_mtime; + return (int)difftime(time_a, time_b); + } + + // Warning : untested code! (let me know if it breaks) + int cf_get_file_time(const char* path, cf_time_t* time) + { + struct stat info; + if (stat(path, &info)) return 0; + time->time = info.st_mtime; + return 1; + } + + // Warning : untested code! (let me know if it breaks) + int cf_compare_file_times(cf_time_t* time_a, cf_time_t* time_b) + { + return (int)difftime(time_a->time, time_b->time); + } + + // Warning : untested code! (let me know if it breaks) + int cf_file_exists(const char* path) + { + return access(path, F_OK) != -1; + } + +#endif // CUTE_FILES_PLATFORM + +#endif // CUTE_FILES_IMPLEMENTATION_ONCE +#endif // CUTE_FILES_IMPLEMENTATION + +/* + ------------------------------------------------------------------------------ + This software is available under 2 licenses - you may choose the one you like. + ------------------------------------------------------------------------------ + ALTERNATIVE A - zlib license + Copyright (c) 2017 Randy Gaul http://www.randygaul.net + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from + the use of this software. + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + ------------------------------------------------------------------------------ + ALTERNATIVE B - Public Domain (www.unlicense.org) + This is free and unencumbered software released into the public domain. + Anyone is free to copy, modify, publish, use, compile, sell, or distribute this + software, either in source code form or as a compiled binary, for any purpose, + commercial or non-commercial, and by any means. + In jurisdictions that recognize copyright laws, the author or authors of this + software dedicate any and all copyright interest in the software to the public + domain. We make this dedication for the benefit of the public at large and to + the detriment of our heirs and successors. We intend this dedication to be an + overt act of relinquishment in perpetuity of all present and future rights to + this software under copyright law. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ------------------------------------------------------------------------------ +*/ diff --git a/dep/stb/stb_vorbis.h b/dep/stb/stb_vorbis.h index 3e5c250..3279c96 100644 --- a/dep/stb/stb_vorbis.h +++ b/dep/stb/stb_vorbis.h @@ -5128,19 +5128,19 @@ stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *err #define PLAYBACK_LEFT 2 #define PLAYBACK_RIGHT 4 -#define L (PLAYBACK_LEFT | PLAYBACK_MONO) -#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) -#define R (PLAYBACK_RIGHT | PLAYBACK_MONO) +#define SBVL (PLAYBACK_LEFT | PLAYBACK_MONO) +#define SBVC (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) +#define SBVR (PLAYBACK_RIGHT | PLAYBACK_MONO) static int8 channel_position[7][6] = { { 0 }, - { C }, - { L, R }, - { L, C, R }, - { L, R, L, R }, - { L, C, R, L, R }, - { L, C, R, L, R, C }, + { SBVC }, + { SBVL, SBVR }, + { SBVL, SBVC, SBVR }, + { SBVL, SBVR, SBVL, SBVR }, + { SBVL, SBVC, SBVR, SBVL, SBVR }, + { SBVL, SBVC, SBVR, SBVL, SBVR, SBVC }, }; diff --git a/src/vg/vg.h b/src/vg/vg.h index 61db7d6..77d27e2 100644 --- a/src/vg/vg.h +++ b/src/vg/vg.h @@ -84,7 +84,9 @@ struct vg samples; float refresh_rate; - v2f mouse, + double mouse_pos[2]; + v2f + mouse_delta, mouse_wheel; /* Runtime */ @@ -122,6 +124,7 @@ struct vg int gamepad_ready; const char *gamepad_name; int gamepad_id; + int gamepad_use_trackpad_look; } VG_STATIC vg = { .time_rate = 1.0 }; @@ -332,8 +335,11 @@ VG_STATIC void vg_checkgl( const char *src_info ) void vg_mouse_callback( GLFWwindow* ptrW, double xpos, double ypos ) { - vg.mouse[0] = xpos; - vg.mouse[1] = ypos; + vg.mouse_delta[0] += xpos - vg.mouse_pos[0]; + vg.mouse_delta[1] += ypos - vg.mouse_pos[1]; + + vg.mouse_pos[0] = xpos; + vg.mouse_pos[1] = ypos; } void vg_scroll_callback( GLFWwindow* ptrW, double xoffset, double yoffset ) @@ -498,7 +504,10 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name ) glfwSetCharCallback( vg.window, console_proc_wchar ); glfwSetKeyCallback( vg.window, console_proc_key ); - glfwSetInputMode( vg.window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN ); + glfwSetInputMode( vg.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED ); + + if( glfwRawMouseMotionSupported() ) + glfwSetInputMode( vg.window, GLFW_RAW_MOUSE_MOTION, GLFW_TRUE ); if( !gladLoadGLLoader((GLADloadproc)glfwGetProcAddress) ) { @@ -529,7 +538,9 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name ) if( glfwWindowShouldClose( vg.window ) ) break; - v2_copy( (v2f){ 0.0f, 0.0f }, vg.mouse_wheel ); + v2_zero( vg.mouse_wheel ); + v2_zero( vg.mouse_delta ); + glfwPollEvents(); vg.time_real_last = vg.time_real; @@ -605,8 +616,9 @@ VG_STATIC void vg_enter( int argc, char *argv[], const char *window_name ) vg.engine_stage = k_engine_stage_ui; { ui_begin( vg.window_x, vg.window_y ); - ui_set_mouse( vg.mouse[0], vg.mouse[1], - vg_get_button_state( "primary" ) ); + + /* TODO */ + ui_set_mouse( vg.mouse_pos[0], vg.mouse_pos[1], 0 ); vg_profile_drawn( (struct vg_profile *[]){&vg_prof_update,&vg_prof_render}, 2, diff --git a/src/vg/vg_audio.h b/src/vg/vg_audio.h index 9d4f023..80307b8 100644 --- a/src/vg/vg_audio.h +++ b/src/vg/vg_audio.h @@ -15,7 +15,6 @@ #include "dr_soft/miniaudio.h" - #include "vg/vg.h" #include "vg/vg_stdint.h" #include "vg/vg_platform.h" @@ -31,20 +30,18 @@ #ifndef __clang__ #pragma GCC push_options #pragma GCC optimize ("O3") + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif #endif -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - #define STB_VORBIS_MAX_CHANNELS 2 #include "stb/stb_vorbis.h" -#pragma GCC diagnostic pop - #ifdef __GNUC__ #ifndef __clang__ #pragma GCC pop_options + #pragma GCC diagnostic pop #endif #endif diff --git a/src/vg/vg_input.h b/src/vg/vg_input.h index 19e1f36..5b16287 100644 --- a/src/vg/vg_input.h +++ b/src/vg/vg_input.h @@ -34,6 +34,7 @@ VG_STATIC struct input_binding k_input_type_unknown, k_input_type_keyboard_key, + k_input_type_mouse_button, /* ? TODO */ k_input_type_gamepad_axis, k_input_type_gamepad_button } @@ -47,6 +48,7 @@ VG_STATIC struct input_binding keyboard_positive, keyboard_negative; + int gamepad_inverted; float value; } axis; @@ -64,6 +66,22 @@ VG_STATIC struct input_binding vg_named_inputs[ 32 ]; VG_STATIC u32 vg_named_input_count = 0; +VG_STATIC void vg_create_unnamed_input( struct input_binding *bind, + enum input_type type ) +{ + memset( bind, 0, sizeof(struct input_binding) ); + + bind->name = "API DEFINED"; + bind->save_this = 0; + bind->type = type; + + bind->axis.gamepad_axis = -1; + bind->axis.keyboard_positive = -1; + bind->axis.keyboard_negative = -1; + bind->button.gamepad_id = -1; + bind->button.keyboard_id = -1; +} + VG_STATIC struct input_binding *vg_create_named_input( const char *name, enum input_type type ) { @@ -74,11 +92,20 @@ VG_STATIC struct input_binding *vg_create_named_input( const char *name, bind->save_this = 0; bind->type = type; + bind->axis.gamepad_axis = -1; + bind->axis.keyboard_positive = -1; + bind->axis.keyboard_negative = -1; + bind->button.gamepad_id = -1; + bind->button.keyboard_id = -1; + return bind; } VG_STATIC struct input_binding *vg_get_named_input( const char *name ) { + if( name[0] == '+' || name[0] == '-' ) + name ++; + for( u32 i=0; iname ); - vg_info( " type: %s\n", (const char *[]){"button","axis"}[ bind->type ] ); + vg_info( " type: %s\n", (const char *[]){"button","axis","axis[0-1]"} + [ bind->type ] ); vg_info( " save this? %d\n", bind->save_this ); if( (bind->type == k_input_type_axis) || @@ -243,10 +274,98 @@ VG_STATIC void vg_print_binding_info( struct input_binding *bind ) } } +VG_STATIC void vg_apply_bind_str( struct input_binding *bind, + const char *mod, + const char *str ) +{ + int axis_mod = 0; + char modch = ' '; + if( (mod[0] == '-') || (mod[0] == '+') ) + { + axis_mod = 1; + modch = mod[0]; + mod ++; + } + + int invert = 0; + if( (str[0] == '-' ) ) + { + invert = 1; + str ++; + } + + u32 id; + enum input_type type = vg_str_to_input( str, &id ); + + if( bind->type == k_input_type_button ) + { + if( axis_mod ) + { + vg_error( "Cannot use axis modifiers on button input!\n" ); + return; + } + + if( invert ) + { + vg_error( "Cannot invert button input!\n" ); + return; + } + + if( type == k_input_type_keyboard_key ) + bind->button.keyboard_id = id; + else if( type == k_input_type_gamepad_button ) + bind->button.gamepad_id = id; + else + { + vg_error( "Unknown button or key '%s'\n", str ); + return; + } + } + else if( (bind->type == k_input_type_axis ) || + (bind->type == k_input_type_axis_norm)) + { + if( axis_mod ) + { + if( type == k_input_type_keyboard_key ) + { + if( invert ) + { + vg_error( "Cannot invert a keyboard key!\n" ); + return; + } + + if( modch == '+' ) + bind->axis.keyboard_positive = id; + else + bind->axis.keyboard_negative = id; + } + else + { + vg_error( "You can only bind keyboard keys to +- axises\n" ); + return; + } + } + else + { + if( type == k_input_type_gamepad_axis ) + { + bind->axis.gamepad_inverted = invert; + bind->axis.gamepad_axis = id; + } + else + { + vg_error( "You can only bind gamepad axises to this\n" ); + return; + } + } + } +} + /* * bind x jump * bind a -horizontal * bind d +horizontal + * bind -gp-ls-h horizontal */ VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] ) @@ -259,18 +378,12 @@ VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] ) return 0; } - if( strlen(argv[0]) == 0 ) - return 0; - - int axis_mod = 0; - if( (argv[0][0] == '-') || (argv[0][0] == '+') ) - axis_mod = 1; - - struct input_binding *bind = vg_get_named_input( argv[0]+axis_mod ); + const char *str_bind_name = argv[0]; + struct input_binding *bind = vg_get_named_input( str_bind_name ); if( !bind ) { - vg_error( "There is no named input called %s\n", argv[0]+axis_mod ); + vg_error( "There is no bind with that name '%s'\n", str_bind_name ); return 0; } @@ -282,56 +395,10 @@ VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] ) if( argc == 2 ) { - u32 id; - enum input_type type = vg_str_to_input( argv[1], &id ); - - if( bind->type == k_input_type_button ) - { - if( axis_mod ) - { - vg_error( "Cannot use axis modifiers on button input!\n" ); - return 0; - } + const char *str_input_id = argv[1]; - if( type == k_input_type_keyboard_key ) - bind->button.keyboard_id = id; - else if( type == k_input_type_gamepad_button ) - bind->button.gamepad_id = id; - else - { - vg_error( "Unknown button or key '%s'\n", argv[1] ); - return 0; - } - } - else if( (bind->type == k_input_type_axis ) || - (bind->type == k_input_type_axis_norm)) - { - if( axis_mod ) - { - if( type == k_input_type_keyboard_key ) - { - if( argv[0][0] == '+' ) - bind->axis.keyboard_positive = id; - else - bind->axis.keyboard_negative = id; - } - else - { - vg_error( "You can only bind keyboard keys to +- axises\n" ); - return 0; - } - } - else - { - if( type == k_input_type_gamepad_axis ) - bind->axis.gamepad_axis = id; - else - { - vg_error( "You can only bind gamepad axises to this\n" ); - return 0; - } - } - } + vg_apply_bind_str( bind, str_bind_name, str_input_id ); + return 0; } return 0; @@ -339,6 +406,22 @@ VG_STATIC int vg_rebind_input_cmd( int argc, const char *argv[] ) VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) { + if( vg_console.enabled ) + { + for( i32 i=0; itype == k_input_type_button ) + { + bind->button.prev = bind->button.value; + bind->button.value = 0; + } + } + + return; + } + for( i32 i=0; iaxis.gamepad_axis != -1 ) + { gamepad_value = vg.gamepad.axes[ bind->axis.gamepad_axis ]; + if( bind->axis.gamepad_inverted ) + gamepad_value *= -1.0f; + } if( fabsf(gamepad_value) <= 0.01f ) gamepad_value = 0.0f; @@ -394,19 +481,20 @@ VG_STATIC void vg_input_update( u32 num, struct input_binding *binds ) } } +VG_STATIC int vg_console_enabled(void); VG_STATIC int vg_input_button_down( struct input_binding *bind ) { if( bind->button.value && !bind->button.prev ) return 1; return 0; } +#if 0 VG_STATIC float vg_get_axis( const char *axis ) { return 0.0f; } -VG_STATIC int vg_console_enabled(void); VG_STATIC void vg_get_button_states( const char *name, int *cur, int *prev ) { @@ -434,6 +522,7 @@ VG_STATIC enum vg_button_state vg_get_button_state( const char *button ) if(vg_get_button( button )) return k_button_state_pressed; return k_button_state_none; } +#endif void vg_update_inputs(void) { @@ -470,6 +559,10 @@ VG_STATIC void vg_gamepad_init(void) vg.gamepad_name = glfwGetGamepadName( id ); vg_success( "Gamepad mapping registered: %s\n", vg.gamepad_name ); + /* This path usually only gets chosen when starting outside of steam */ + if( !strcmp(vg.gamepad_name, "Steam Controller") ) + vg.gamepad_use_trackpad_look = 1; + vg.gamepad_ready = 1; vg.gamepad_id = id; break; diff --git a/src/vg/vg_m.h b/src/vg/vg_m.h index 0736752..8e49fe5 100644 --- a/src/vg/vg_m.h +++ b/src/vg/vg_m.h @@ -188,7 +188,14 @@ static inline void v2_lerp( v2f a, v2f b, float t, v2f d ) static inline void v2_normalize( v2f a ) { - v2_muls( a, 1.f / v2_length( a ), a ); + v2_muls( a, 1.0f / v2_length( a ), a ); +} + +static void v2_normalize_clamp( v2f a ) +{ + float l2 = v2_length2( a ); + if( l2 > 1.0f ) + v2_muls( a, 1.0f/sqrtf(l2), a ); } static inline void v2_floor( v2f a, v2f b ) diff --git a/src/vg/vg_steam_utils.h b/src/vg/vg_steam_utils.h index 282fe74..e20c340 100644 --- a/src/vg/vg_steam_utils.h +++ b/src/vg/vg_steam_utils.h @@ -14,6 +14,8 @@ #pragma pack(pop) typedef void ISteamUtils; +typedef void ISteamInput; + ISteamUtils *SteamAPI_SteamUtils_v010(void); ISteamUtils *SteamAPI_SteamUtils(void) { @@ -24,4 +26,43 @@ int SteamAPI_ISteamUtils_SetWarningMessageHook( ISteamUtils *self, void( *fn_print )(int, const char *) ); +ISteamInput *SteamAPI_SteamInput_v006(void); +ISteamInput *SteamAPI_SteamInput(void) +{ + return SteamAPI_SteamInput_v006(); +} + +typedef u64 InputHandle_t; + +typedef enum ESteamInputType ESteamInputType; +enum ESteamInputType +{ + k_ESteamInputType_Unknown, + k_ESteamInputType_SteamController, + k_ESteamInputType_XBox360Controller, + k_ESteamInputType_XBoxOneController, + k_ESteamInputType_GenericGamepad, + k_ESteamInputType_PS4Controller, + k_ESteamInputType_AppleMFiController, + k_ESteamInputType_AndroidController, + k_ESteamInputType_SwitchJoyConPair, + k_ESteamInputType_SwitchJoyConSingle, + k_ESteamInputType_SwitchProController, + k_ESteamInputType_MobileTouch, + k_ESteamInputType_PS3Controller, + k_ESteamInputType_PS5Controller, + k_ESteamInputType_SteamDeckController, // Added in SDK 153 + k_ESteamInputType_Count, + k_ESteamInputType_MaximumPossibleValue = 255, +}; + +int SteamAPI_ISteamInput_Init( ISteamInput* self, int bExplicitlyCallRunFrame ); +int SteamAPI_ISteamInput_Shutdown( ISteamInput* self ); +InputHandle_t SteamAPI_ISteamInput_GetControllerForGamepadIndex( + ISteamInput* self, int nIndex ); +ESteamInputType SteamAPI_ISteamInput_GetInputTypeForHandle( + ISteamInput* self, InputHandle_t inputHandle ); +void SteamAPI_ISteamInput_RunFrame( ISteamInput* self, int bReservedValue ); + + #endif /* VG_STEAM_UTILS_H */ -- 2.25.1