assorted
authorhgn <hgodden00@gmail.com>
Tue, 8 Nov 2022 12:25:53 +0000 (12:25 +0000)
committerhgn <hgodden00@gmail.com>
Tue, 8 Nov 2022 12:25:53 +0000 (12:25 +0000)
dep/cxong/tinydir.h [new file with mode: 0644]
dep/randygaul/cute_files.h [new file with mode: 0644]
dep/stb/stb_vorbis.h
src/vg/vg.h
src/vg/vg_audio.h
src/vg/vg_input.h
src/vg/vg_m.h
src/vg/vg_steam_utils.h

diff --git a/dep/cxong/tinydir.h b/dep/cxong/tinydir.h
new file mode 100644 (file)
index 0000000..ba20c3e
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+Copyright (c) 2013-2021, tinydir authors:
+- Cong Xu
+- Lautis Sun
+- Baudouin Feildel
+- Andargor <andargor@yahoo.com>
+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 <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+# ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# include <tchar.h>
+# pragma warning(push)
+# pragma warning (disable : 4996)
+#else
+# include <dirent.h>
+# include <libgen.h>
+# include <sys/stat.h>
+# include <stddef.h>
+#endif
+#ifdef __MINGW32__
+# include <tchar.h>
+#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 <windows.h>
+# define _TINYDIR_PATH_MAX MAX_PATH
+#elif defined  __linux__
+# include <limits.h>
+# ifdef PATH_MAX
+#  define _TINYDIR_PATH_MAX PATH_MAX
+# endif
+#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
+# include <sys/param.h>
+# if defined(BSD)
+#  include <limits.h>
+#  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 <unistd.h>
+#endif
+#if _BSD_SOURCE || _SVID_SOURCE || \
+       (_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
+# define _TINYDIR_HAS_DIRFD
+# include <sys/types.h>
+#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 <ben@decadent.org.uk>
+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 (file)
index 0000000..fcd585e
--- /dev/null
@@ -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 <string.h> // strerror, strncpy
+
+// change to 0 to compile out any debug checks
+#define CUTE_FILES_DEBUG_CHECKS 1
+
+#if CUTE_FILES_DEBUG_CHECKS
+
+       #include <stdio.h>  // printf
+       #include <assert.h> // assert
+       #include <errno.h>
+       #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 <windows.h>
+
+       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 <sys/stat.h>
+       #include <dirent.h>
+       #include <unistd.h>
+    #include <time.h>
+
+       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.
+       ------------------------------------------------------------------------------
+*/
index 3e5c2504c08f76b9d04e4adfbce80818631e835e..3279c969d8ebda7a1d7ce3db2e19653367a0ee61 100644 (file)
@@ -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 },
 };
 
 
index 61db7d6e0f83e802ee85f943f5932e84501de00b..77d27e2fb9f80553cacad4469608b79f82a4678d 100644 (file)
@@ -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,
index 9d4f023346dd2a8710fec66043b15840687fce2d..80307b85951810fc49c6d2d929d5515c94120dbc 100644 (file)
@@ -15,7 +15,6 @@
 
 #include "dr_soft/miniaudio.h"
 
-
 #include "vg/vg.h"
 #include "vg/vg_stdint.h"
 #include "vg/vg_platform.h"
   #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
 
index 19e1f36ce796725fe15a718f6e167df24e9b4732..5b16287fbce20ca63238037d95a1b5712dad067b 100644 (file)
@@ -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; i<vg_named_input_count; i++ )
    {
       struct input_binding *bind = &vg_named_inputs[i];
@@ -112,6 +139,8 @@ vg_all_bindable_inputs[] =
  {k_input_type_keyboard_key, "down", GLFW_KEY_DOWN},
  {k_input_type_keyboard_key, "shift", GLFW_KEY_LEFT_SHIFT},
  {k_input_type_keyboard_key, "control", GLFW_KEY_LEFT_CONTROL},
+ {k_input_type_keyboard_key, "\2enter", GLFW_KEY_ENTER},
+ {k_input_type_keyboard_key, "\2escape", GLFW_KEY_ESCAPE },
  
  {k_input_type_gamepad_axis, "gp-lt", GLFW_GAMEPAD_AXIS_LEFT_TRIGGER},
  {k_input_type_gamepad_axis, "gp-rt", GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER},
@@ -131,7 +160,8 @@ vg_all_bindable_inputs[] =
  {k_input_type_gamepad_button, "gp-dpad-down", GLFW_GAMEPAD_BUTTON_DPAD_DOWN},
  {k_input_type_gamepad_button, "gp-dpad-left", GLFW_GAMEPAD_BUTTON_DPAD_LEFT},
  {k_input_type_gamepad_button, "gp-dpad-right", GLFW_GAMEPAD_BUTTON_DPAD_RIGHT},
- {k_input_type_gamepad_button, "gp-dpad-up", GLFW_GAMEPAD_BUTTON_DPAD_UP}
+ {k_input_type_gamepad_button, "gp-dpad-up", GLFW_GAMEPAD_BUTTON_DPAD_UP},
+ {k_input_type_gamepad_button, "\2gp-menu", GLFW_GAMEPAD_BUTTON_BACK}
 };
 
 VG_STATIC const char *vg_input_to_str( u32 input, enum input_type input_type )
@@ -216,7 +246,8 @@ VG_STATIC enum input_type vg_str_to_input( const char *str, u32 *input )
 VG_STATIC void vg_print_binding_info( struct input_binding *bind )
 {
    vg_info( "    name: %s\n", bind->name );
-   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; i<num; i++ )
+      {
+         struct input_binding *bind = &binds[i];
+
+         if( bind->type == k_input_type_button )
+         {
+            bind->button.prev = bind->button.value;
+            bind->button.value = 0;
+         }
+      }
+
+      return;
+   }
+
    for( i32 i=0; i<num; i++ )
    {
       struct input_binding *bind = &binds[i];
@@ -369,7 +452,11 @@ VG_STATIC void vg_input_update( u32 num, struct input_binding *binds )
                keyboard_value -= 1.0f;
 
          if( bind->axis.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;
index 0736752364113b85a711349926d3df5208e22f2a..8e49fe55e330f4adb99d2291ae552c56fbf55274 100644 (file)
@@ -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 )
index 282fe74815fbe6cdadd3eea0de89d935e870c4d4..e20c340cc9f89983a6da3e6e5277a547958fe595 100644 (file)
@@ -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 */