pre-git state
This commit is contained in:
		
						commit
						d8e4480819
					
				
							
								
								
									
										18
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
IndentWidth: 4
 | 
			
		||||
AlignAfterOpenBracket: Align
 | 
			
		||||
AlignArrayOfStructures: Right
 | 
			
		||||
AlignConsecutiveAssignments: true
 | 
			
		||||
AlignConsecutiveMacros: true
 | 
			
		||||
AllowAllArgumentsOnNextLine: false
 | 
			
		||||
AllowAllParametersOfDeclarationOnNextLine: false
 | 
			
		||||
AllowShortBlocksOnASingleLine: Never
 | 
			
		||||
AllowShortCaseLabelsOnASingleLine: false
 | 
			
		||||
AllowShortEnumsOnASingleLine: false
 | 
			
		||||
AllowShortFunctionsOnASingleLine: None
 | 
			
		||||
AllowShortIfStatementsOnASingleLine: Never
 | 
			
		||||
AlwaysBreakAfterReturnType: None
 | 
			
		||||
BinPackArguments: false
 | 
			
		||||
BinPackParameters: false
 | 
			
		||||
BreakBeforeBraces: Attach
 | 
			
		||||
IndentPPDirectives: BeforeHash
 | 
			
		||||
PointerAlignment: Right 
 | 
			
		||||
							
								
								
									
										1819
									
								
								contrib/glad/glad.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1819
									
								
								contrib/glad/glad.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3656
									
								
								contrib/glad/glad.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3656
									
								
								contrib/glad/glad.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										311
									
								
								contrib/glad/khrplatform.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								contrib/glad/khrplatform.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,311 @@
 | 
			
		||||
#ifndef __khrplatform_h_
 | 
			
		||||
#define __khrplatform_h_
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
 | 
			
		||||
**
 | 
			
		||||
** Permission is hereby granted, free of charge, to any person obtaining a
 | 
			
		||||
** copy of this software and/or associated documentation files (the
 | 
			
		||||
** "Materials"), to deal in the Materials without restriction, including
 | 
			
		||||
** without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
** distribute, sublicense, and/or sell copies of the Materials, and to
 | 
			
		||||
** permit persons to whom the Materials are furnished to do so, subject to
 | 
			
		||||
** the following conditions:
 | 
			
		||||
**
 | 
			
		||||
** The above copyright notice and this permission notice shall be included
 | 
			
		||||
** in all copies or substantial portions of the Materials.
 | 
			
		||||
**
 | 
			
		||||
** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
			
		||||
** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 | 
			
		||||
** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 | 
			
		||||
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 | 
			
		||||
** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* Khronos platform-specific types and definitions.
 | 
			
		||||
 *
 | 
			
		||||
 * The master copy of khrplatform.h is maintained in the Khronos EGL
 | 
			
		||||
 * Registry repository at https://github.com/KhronosGroup/EGL-Registry
 | 
			
		||||
 * The last semantic modification to khrplatform.h was at commit ID:
 | 
			
		||||
 *      67a3e0864c2d75ea5287b9f3d2eb74a745936692
 | 
			
		||||
 *
 | 
			
		||||
 * Adopters may modify this file to suit their platform. Adopters are
 | 
			
		||||
 * encouraged to submit platform specific modifications to the Khronos
 | 
			
		||||
 * group so that they can be included in future versions of this file.
 | 
			
		||||
 * Please submit changes by filing pull requests or issues on
 | 
			
		||||
 * the EGL Registry repository linked above.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * See the Implementer's Guidelines for information about where this file
 | 
			
		||||
 * should be located on your system and for more details of its use:
 | 
			
		||||
 *    http://www.khronos.org/registry/implementers_guide.pdf
 | 
			
		||||
 *
 | 
			
		||||
 * This file should be included as
 | 
			
		||||
 *        #include <KHR/khrplatform.h>
 | 
			
		||||
 * by Khronos client API header files that use its types and defines.
 | 
			
		||||
 *
 | 
			
		||||
 * The types in khrplatform.h should only be used to define API-specific types.
 | 
			
		||||
 *
 | 
			
		||||
 * Types defined in khrplatform.h:
 | 
			
		||||
 *    khronos_int8_t              signed   8  bit
 | 
			
		||||
 *    khronos_uint8_t             unsigned 8  bit
 | 
			
		||||
 *    khronos_int16_t             signed   16 bit
 | 
			
		||||
 *    khronos_uint16_t            unsigned 16 bit
 | 
			
		||||
 *    khronos_int32_t             signed   32 bit
 | 
			
		||||
 *    khronos_uint32_t            unsigned 32 bit
 | 
			
		||||
 *    khronos_int64_t             signed   64 bit
 | 
			
		||||
 *    khronos_uint64_t            unsigned 64 bit
 | 
			
		||||
 *    khronos_intptr_t            signed   same number of bits as a pointer
 | 
			
		||||
 *    khronos_uintptr_t           unsigned same number of bits as a pointer
 | 
			
		||||
 *    khronos_ssize_t             signed   size
 | 
			
		||||
 *    khronos_usize_t             unsigned size
 | 
			
		||||
 *    khronos_float_t             signed   32 bit floating point
 | 
			
		||||
 *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
 | 
			
		||||
 *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
 | 
			
		||||
 *                                         nanoseconds
 | 
			
		||||
 *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
 | 
			
		||||
 *    khronos_boolean_enum_t      enumerated boolean type. This should
 | 
			
		||||
 *      only be used as a base type when a client API's boolean type is
 | 
			
		||||
 *      an enum. Client APIs which use an integer or other type for
 | 
			
		||||
 *      booleans cannot use this as the base type for their boolean.
 | 
			
		||||
 *
 | 
			
		||||
 * Tokens defined in khrplatform.h:
 | 
			
		||||
 *
 | 
			
		||||
 *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
 | 
			
		||||
 *
 | 
			
		||||
 *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
 | 
			
		||||
 *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
 | 
			
		||||
 *
 | 
			
		||||
 * Calling convention macros defined in this file:
 | 
			
		||||
 *    KHRONOS_APICALL
 | 
			
		||||
 *    KHRONOS_APIENTRY
 | 
			
		||||
 *    KHRONOS_APIATTRIBUTES
 | 
			
		||||
 *
 | 
			
		||||
 * These may be used in function prototypes as:
 | 
			
		||||
 *
 | 
			
		||||
 *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
 | 
			
		||||
 *                                  int arg1,
 | 
			
		||||
 *                                  int arg2) KHRONOS_APIATTRIBUTES;
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
 | 
			
		||||
#   define KHRONOS_STATIC 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 * Definition of KHRONOS_APICALL
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 * This precedes the return type of the function in the function prototype.
 | 
			
		||||
 */
 | 
			
		||||
#if defined(KHRONOS_STATIC)
 | 
			
		||||
    /* If the preprocessor constant KHRONOS_STATIC is defined, make the
 | 
			
		||||
     * header compatible with static linking. */
 | 
			
		||||
#   define KHRONOS_APICALL
 | 
			
		||||
#elif defined(_WIN32)
 | 
			
		||||
#   define KHRONOS_APICALL __declspec(dllimport)
 | 
			
		||||
#elif defined (__SYMBIAN32__)
 | 
			
		||||
#   define KHRONOS_APICALL IMPORT_C
 | 
			
		||||
#elif defined(__ANDROID__)
 | 
			
		||||
#   define KHRONOS_APICALL __attribute__((visibility("default")))
 | 
			
		||||
#else
 | 
			
		||||
#   define KHRONOS_APICALL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 * Definition of KHRONOS_APIENTRY
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 * This follows the return type of the function  and precedes the function
 | 
			
		||||
 * name in the function prototype.
 | 
			
		||||
 */
 | 
			
		||||
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
 | 
			
		||||
    /* Win32 but not WinCE */
 | 
			
		||||
#   define KHRONOS_APIENTRY __stdcall
 | 
			
		||||
#else
 | 
			
		||||
#   define KHRONOS_APIENTRY
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 * Definition of KHRONOS_APIATTRIBUTES
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 * This follows the closing parenthesis of the function prototype arguments.
 | 
			
		||||
 */
 | 
			
		||||
#if defined (__ARMCC_2__)
 | 
			
		||||
#define KHRONOS_APIATTRIBUTES __softfp
 | 
			
		||||
#else
 | 
			
		||||
#define KHRONOS_APIATTRIBUTES
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 * basic type definitions
 | 
			
		||||
 *-----------------------------------------------------------------------*/
 | 
			
		||||
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Using <stdint.h>
 | 
			
		||||
 */
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
typedef int32_t                 khronos_int32_t;
 | 
			
		||||
typedef uint32_t                khronos_uint32_t;
 | 
			
		||||
typedef int64_t                 khronos_int64_t;
 | 
			
		||||
typedef uint64_t                khronos_uint64_t;
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   1
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   1
 | 
			
		||||
/*
 | 
			
		||||
 * To support platform where unsigned long cannot be used interchangeably with
 | 
			
		||||
 * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t.
 | 
			
		||||
 * Ideally, we could just use (u)intptr_t everywhere, but this could result in
 | 
			
		||||
 * ABI breakage if khronos_uintptr_t is changed from unsigned long to
 | 
			
		||||
 * unsigned long long or similar (this results in different C++ name mangling).
 | 
			
		||||
 * To avoid changes for existing platforms, we restrict usage of intptr_t to
 | 
			
		||||
 * platforms where the size of a pointer is larger than the size of long.
 | 
			
		||||
 */
 | 
			
		||||
#if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__)
 | 
			
		||||
#if __SIZEOF_POINTER__ > __SIZEOF_LONG__
 | 
			
		||||
#define KHRONOS_USE_INTPTR_T
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#elif defined(__VMS ) || defined(__sgi)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Using <inttypes.h>
 | 
			
		||||
 */
 | 
			
		||||
#include <inttypes.h>
 | 
			
		||||
typedef int32_t                 khronos_int32_t;
 | 
			
		||||
typedef uint32_t                khronos_uint32_t;
 | 
			
		||||
typedef int64_t                 khronos_int64_t;
 | 
			
		||||
typedef uint64_t                khronos_uint64_t;
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   1
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   1
 | 
			
		||||
 | 
			
		||||
#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Win32
 | 
			
		||||
 */
 | 
			
		||||
typedef __int32                 khronos_int32_t;
 | 
			
		||||
typedef unsigned __int32        khronos_uint32_t;
 | 
			
		||||
typedef __int64                 khronos_int64_t;
 | 
			
		||||
typedef unsigned __int64        khronos_uint64_t;
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   1
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   1
 | 
			
		||||
 | 
			
		||||
#elif defined(__sun__) || defined(__digital__)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Sun or Digital
 | 
			
		||||
 */
 | 
			
		||||
typedef int                     khronos_int32_t;
 | 
			
		||||
typedef unsigned int            khronos_uint32_t;
 | 
			
		||||
#if defined(__arch64__) || defined(_LP64)
 | 
			
		||||
typedef long int                khronos_int64_t;
 | 
			
		||||
typedef unsigned long int       khronos_uint64_t;
 | 
			
		||||
#else
 | 
			
		||||
typedef long long int           khronos_int64_t;
 | 
			
		||||
typedef unsigned long long int  khronos_uint64_t;
 | 
			
		||||
#endif /* __arch64__ */
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   1
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   1
 | 
			
		||||
 | 
			
		||||
#elif 0
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Hypothetical platform with no float or int64 support
 | 
			
		||||
 */
 | 
			
		||||
typedef int                     khronos_int32_t;
 | 
			
		||||
typedef unsigned int            khronos_uint32_t;
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   0
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   0
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Generic fallback
 | 
			
		||||
 */
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
typedef int32_t                 khronos_int32_t;
 | 
			
		||||
typedef uint32_t                khronos_uint32_t;
 | 
			
		||||
typedef int64_t                 khronos_int64_t;
 | 
			
		||||
typedef uint64_t                khronos_uint64_t;
 | 
			
		||||
#define KHRONOS_SUPPORT_INT64   1
 | 
			
		||||
#define KHRONOS_SUPPORT_FLOAT   1
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Types that are (so far) the same on all platforms
 | 
			
		||||
 */
 | 
			
		||||
typedef signed   char          khronos_int8_t;
 | 
			
		||||
typedef unsigned char          khronos_uint8_t;
 | 
			
		||||
typedef signed   short int     khronos_int16_t;
 | 
			
		||||
typedef unsigned short int     khronos_uint16_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Types that differ between LLP64 and LP64 architectures - in LLP64,
 | 
			
		||||
 * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
 | 
			
		||||
 * to be the only LLP64 architecture in current use.
 | 
			
		||||
 */
 | 
			
		||||
#ifdef KHRONOS_USE_INTPTR_T
 | 
			
		||||
typedef intptr_t               khronos_intptr_t;
 | 
			
		||||
typedef uintptr_t              khronos_uintptr_t;
 | 
			
		||||
#elif defined(_WIN64)
 | 
			
		||||
typedef signed   long long int khronos_intptr_t;
 | 
			
		||||
typedef unsigned long long int khronos_uintptr_t;
 | 
			
		||||
#else
 | 
			
		||||
typedef signed   long  int     khronos_intptr_t;
 | 
			
		||||
typedef unsigned long  int     khronos_uintptr_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_WIN64)
 | 
			
		||||
typedef signed   long long int khronos_ssize_t;
 | 
			
		||||
typedef unsigned long long int khronos_usize_t;
 | 
			
		||||
#else
 | 
			
		||||
typedef signed   long  int     khronos_ssize_t;
 | 
			
		||||
typedef unsigned long  int     khronos_usize_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if KHRONOS_SUPPORT_FLOAT
 | 
			
		||||
/*
 | 
			
		||||
 * Float type
 | 
			
		||||
 */
 | 
			
		||||
typedef          float         khronos_float_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if KHRONOS_SUPPORT_INT64
 | 
			
		||||
/* Time types
 | 
			
		||||
 *
 | 
			
		||||
 * These types can be used to represent a time interval in nanoseconds or
 | 
			
		||||
 * an absolute Unadjusted System Time.  Unadjusted System Time is the number
 | 
			
		||||
 * of nanoseconds since some arbitrary system event (e.g. since the last
 | 
			
		||||
 * time the system booted).  The Unadjusted System Time is an unsigned
 | 
			
		||||
 * 64 bit value that wraps back to 0 every 584 years.  Time intervals
 | 
			
		||||
 * may be either signed or unsigned.
 | 
			
		||||
 */
 | 
			
		||||
typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
 | 
			
		||||
typedef khronos_int64_t        khronos_stime_nanoseconds_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Dummy value used to pad enum types to 32 bits.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef KHRONOS_MAX_ENUM
 | 
			
		||||
#define KHRONOS_MAX_ENUM 0x7FFFFFFF
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Enumerated boolean type
 | 
			
		||||
 *
 | 
			
		||||
 * Values other than zero should be considered to be true.  Therefore
 | 
			
		||||
 * comparisons should not be made against KHRONOS_TRUE.
 | 
			
		||||
 */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    KHRONOS_FALSE = 0,
 | 
			
		||||
    KHRONOS_TRUE  = 1,
 | 
			
		||||
    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
 | 
			
		||||
} khronos_boolean_enum_t;
 | 
			
		||||
 | 
			
		||||
#endif /* __khrplatform_h_ */
 | 
			
		||||
							
								
								
									
										26
									
								
								contrib/xxhash/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								contrib/xxhash/LICENSE
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
			
		||||
xxHash Library
 | 
			
		||||
Copyright (c) 2012-2021 Yann Collet
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
* Redistributions of source code must retain the above copyright notice, this
 | 
			
		||||
  list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
* 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 HOLDER 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.
 | 
			
		||||
							
								
								
									
										43
									
								
								contrib/xxhash/xxhash.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								contrib/xxhash/xxhash.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
 * xxHash - Extremely Fast Hash algorithm
 | 
			
		||||
 * Copyright (C) 2012-2021 Yann Collet
 | 
			
		||||
 *
 | 
			
		||||
 * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions are
 | 
			
		||||
 * met:
 | 
			
		||||
 *
 | 
			
		||||
 *    * Redistributions of source code must retain the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *    * 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.
 | 
			
		||||
 *
 | 
			
		||||
 * You can contact the author at:
 | 
			
		||||
 *   - xxHash homepage: https://www.xxhash.com
 | 
			
		||||
 *   - xxHash source repository: https://github.com/Cyan4973/xxHash
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * xxhash.c instantiates functions defined in xxhash.h
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define XXH_STATIC_LINKING_ONLY   /* access advanced declarations */
 | 
			
		||||
#define XXH_IMPLEMENTATION   /* access definitions */
 | 
			
		||||
 | 
			
		||||
#include "xxhash.h"
 | 
			
		||||
							
								
								
									
										6773
									
								
								contrib/xxhash/xxhash.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6773
									
								
								contrib/xxhash/xxhash.h
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										49
									
								
								include/fio.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								include/fio.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
			
		||||
#ifndef VY_FIO_H
 | 
			
		||||
#define VY_FIO_H
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "voyage.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    void *data;
 | 
			
		||||
    size_t size;
 | 
			
		||||
} vy_file_buffer;
 | 
			
		||||
 | 
			
		||||
/* used to identify a file (XXH3 hash of the path) */
 | 
			
		||||
typedef uint64_t vy_file_id;
 | 
			
		||||
 | 
			
		||||
typedef unsigned int vy_fio_handle;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    unsigned int queue_size;
 | 
			
		||||
    unsigned int max_file_count;
 | 
			
		||||
} vy_fio_config;
 | 
			
		||||
 | 
			
		||||
bool vyInitFIO(const vy_fio_config *config);
 | 
			
		||||
 | 
			
		||||
void vyShutdownFIO(void);
 | 
			
		||||
 | 
			
		||||
vy_file_id vyGetFileId(const char *path);
 | 
			
		||||
 | 
			
		||||
vy_file_id vyGetFileIdFromSpan(vy_text_span path);
 | 
			
		||||
 | 
			
		||||
vy_file_id vyAddFile(const char *path);
 | 
			
		||||
 | 
			
		||||
vy_file_id vyAddFileFromSpan(vy_text_span path);
 | 
			
		||||
 | 
			
		||||
const char *vyGetFilePath(vy_file_id fid);
 | 
			
		||||
 | 
			
		||||
vy_fio_handle vyEnqueueRead(vy_file_id fid);
 | 
			
		||||
 | 
			
		||||
void vyAbortFIO(vy_fio_handle fio);
 | 
			
		||||
 | 
			
		||||
bool vyIsFIOFinished(vy_fio_handle fio);
 | 
			
		||||
 | 
			
		||||
bool vyRetrieveReadBuffer(vy_fio_handle fio, vy_file_buffer *buffer);
 | 
			
		||||
 | 
			
		||||
void vyFreeFileBuffer(vy_file_buffer buffer);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										56
									
								
								include/gfx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								include/gfx.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
#ifndef VY_GFX_H
 | 
			
		||||
#define VY_GFX_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/* graphics system. this is the interface of the rendering code.
 | 
			
		||||
 *
 | 
			
		||||
 * we need (at least) three different renderers:
 | 
			
		||||
 * - world cell renderer (for world & dungeon environments)
 | 
			
		||||
 * - character renderer (for animated models)
 | 
			
		||||
 * - object renderer (for static models)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
bool vyInitRenderer(void);
 | 
			
		||||
 | 
			
		||||
void vyShutdownRenderer(void);
 | 
			
		||||
 | 
			
		||||
/* Generational indices for backend objects */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
} vy_gfx_pipeline_id;
 | 
			
		||||
 | 
			
		||||
#define VY_IS_GFX_ID_VALID(id) ((id).index != 0)
 | 
			
		||||
 | 
			
		||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
			
		||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
			
		||||
 * replaced with the (at the time of the invoke) grid buffer of the current
 | 
			
		||||
 * world cell.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_ATTRIBUTE_VALUE_UNDEFINED,
 | 
			
		||||
 | 
			
		||||
    VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO,
 | 
			
		||||
} vy_attribute_value;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
    vy_attribute_value value;
 | 
			
		||||
} vy_attribute_binding;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_attribute_binding *uniform_bindings;
 | 
			
		||||
    vy_attribute_binding *storage_bindings;
 | 
			
		||||
    vy_attribute_binding *texture_bindings;
 | 
			
		||||
 | 
			
		||||
    vy_gfx_pipeline_id pipeline;
 | 
			
		||||
 | 
			
		||||
    unsigned int uniform_binding_count;
 | 
			
		||||
    unsigned int storage_binding_count;
 | 
			
		||||
    unsigned int texture_binding_count;
 | 
			
		||||
} vy_shader;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										29
									
								
								include/gfx_backend.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								include/gfx_backend.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
#ifndef VY_GFX_BACKEND_H
 | 
			
		||||
#define VY_GFX_BACKEND_H
 | 
			
		||||
 | 
			
		||||
/* Backend functions and types. */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *compute_source;
 | 
			
		||||
    size_t compute_source_length;
 | 
			
		||||
} vy_compute_pipeline_info;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *vertex_source;
 | 
			
		||||
    size_t vertex_source_length;
 | 
			
		||||
 | 
			
		||||
    const char *fragment_source;
 | 
			
		||||
    size_t fragment_source_length;
 | 
			
		||||
} vy_graphics_pipeline_info;
 | 
			
		||||
 | 
			
		||||
vy_gfx_pipeline_id
 | 
			
		||||
vyCompileComputePipeline(const vy_compute_pipeline_info *info);
 | 
			
		||||
 | 
			
		||||
vy_gfx_pipeline_id
 | 
			
		||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										17
									
								
								include/voyage.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								include/voyage.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#ifndef VY_VOYAGE_H
 | 
			
		||||
#define VY_VOYAGE_H
 | 
			
		||||
 | 
			
		||||
/* basic types and macros */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
#define VY_UNUSED(x) ((void)sizeof((x)))
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *start;
 | 
			
		||||
    unsigned int length;
 | 
			
		||||
} vy_text_span;
 | 
			
		||||
 | 
			
		||||
void vyReportError(const char *subsystem, const char *fmt, ...);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										51
									
								
								meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								meson.build
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,51 @@
 | 
			
		||||
project('voyage', 'c',
 | 
			
		||||
  default_options: ['buildtype=debug', 'b_sanitize=address', 'c_std=c17', 'warning_level=3'])
 | 
			
		||||
 | 
			
		||||
compiler = meson.get_compiler('c')
 | 
			
		||||
buildtype = get_option('buildtype')
 | 
			
		||||
 | 
			
		||||
# Build options
 | 
			
		||||
if compiler.get_argument_syntax() == 'gcc'
 | 
			
		||||
  add_project_arguments(
 | 
			
		||||
    ['-Wconversion', '-Wno-sign-conversion',
 | 
			
		||||
      '-Wdouble-promotion', '-Wno-unused-function', '-Wno-unused-parameter'],
 | 
			
		||||
    language : 'c'
 | 
			
		||||
    )
 | 
			
		||||
elif compiler.get_argument_syntax() == 'msvc'
 | 
			
		||||
  add_project_arguments(
 | 
			
		||||
    ['/wd4146', '/wd4245', '/wd4100', '/D_CRT_SECURE_NO_WARNINGS', '/RTcsu'],
 | 
			
		||||
    language:  'c'
 | 
			
		||||
    )
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Debug specific flags
 | 
			
		||||
if buildtype == 'debug'
 | 
			
		||||
  add_project_arguments([ '-DDEBUG'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# "Select" renderer backend
 | 
			
		||||
# Currently only OpenGL is supported
 | 
			
		||||
add_project_arguments([ '-DRENDERER_GL'], language : 'c')
 | 
			
		||||
 | 
			
		||||
# Gather dependencies
 | 
			
		||||
thread_dep = dependency('threads')
 | 
			
		||||
m_dep = compiler.find_library('m', required : false)
 | 
			
		||||
glfw_proj = subproject('glfw')
 | 
			
		||||
glfw_dep = glfw_proj.get_variable('glfw_dep')
 | 
			
		||||
 | 
			
		||||
incdir = include_directories(['contrib', 'include'])
 | 
			
		||||
 | 
			
		||||
executable('voyage',
 | 
			
		||||
  # Project Sources
 | 
			
		||||
  'src/voyage.c',
 | 
			
		||||
  'src/fio.c',
 | 
			
		||||
  'src/error_report.c',
 | 
			
		||||
  'src/gfx_main.c',
 | 
			
		||||
  'src/gfx_shader_loading.c',
 | 
			
		||||
  'src/gfx_pipelines.c',
 | 
			
		||||
 | 
			
		||||
  # Contrib Sources
 | 
			
		||||
  'contrib/glad/glad.c',
 | 
			
		||||
  'contrib/xxhash/xxhash.c',
 | 
			
		||||
  dependencies : [thread_dep, m_dep, glfw_dep],
 | 
			
		||||
  include_directories: incdir)
 | 
			
		||||
							
								
								
									
										7
									
								
								shader/cell.shader
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								shader/cell.shader
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
vertex shader/cell_vert.glsl;
 | 
			
		||||
fragment shader/cell_frag.glsl;
 | 
			
		||||
 | 
			
		||||
texture_bindings {
 | 
			
		||||
    0 MATERIAL_ALBEDO;
 | 
			
		||||
    1 MATERIAL_NORMAL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/error_report.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/error_report.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
#include "voyage.h"
 | 
			
		||||
 | 
			
		||||
/* TODO(Kevin): Log to file, show error message box, ... */
 | 
			
		||||
 | 
			
		||||
void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    va_start(ap, fmt);
 | 
			
		||||
    fprintf(stderr, "[%s] ", subsystem);
 | 
			
		||||
    vfprintf(stderr, fmt, ap);
 | 
			
		||||
    fprintf(stderr, "\n");
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										358
									
								
								src/fio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										358
									
								
								src/fio.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,358 @@
 | 
			
		||||
#include "fio.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <xxhash/xxhash.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    #include <pthread.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define FLAGS_FINISHED  0x001
 | 
			
		||||
#define FLAGS_RETRIEVED 0x002
 | 
			
		||||
#define FLAGS_IN_USE    0x004
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id fid;
 | 
			
		||||
    vy_file_buffer buffer;
 | 
			
		||||
    unsigned int flags;
 | 
			
		||||
} vy_file_op;
 | 
			
		||||
 | 
			
		||||
/* Ringbuffer of file io operations */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_op *ops;
 | 
			
		||||
    unsigned int size;
 | 
			
		||||
    unsigned int write_pos;
 | 
			
		||||
    unsigned int read_pos;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_t mutex;
 | 
			
		||||
    pthread_cond_t pending_cond;
 | 
			
		||||
#endif
 | 
			
		||||
} vy_fio_queue;
 | 
			
		||||
 | 
			
		||||
#define NAME_CAP(cap) ((cap)*128)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id *ids;
 | 
			
		||||
    unsigned int *name_offsets;
 | 
			
		||||
    char *names;
 | 
			
		||||
    unsigned int capacity;
 | 
			
		||||
    unsigned int name_head;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_t mutex;
 | 
			
		||||
#endif
 | 
			
		||||
} vy_file_tab;
 | 
			
		||||
 | 
			
		||||
static vy_fio_queue _queue;
 | 
			
		||||
static vy_file_tab _file_tab;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
static pthread_t _thread;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool InitFIOQueue(unsigned int size) {
 | 
			
		||||
    _queue.ops = calloc(size, sizeof(vy_file_op));
 | 
			
		||||
    if (!_queue.ops)
 | 
			
		||||
        return false;
 | 
			
		||||
    _queue.write_pos = 0;
 | 
			
		||||
    _queue.read_pos  = 0;
 | 
			
		||||
    _queue.size      = size;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ShutdownFIOQueue(void) {
 | 
			
		||||
    for (unsigned int i = 0; i < _queue.size; ++i) {
 | 
			
		||||
        free(_queue.ops[i].buffer.data);
 | 
			
		||||
    }
 | 
			
		||||
    free(_queue.ops);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool InitFileTab(unsigned int max_files) {
 | 
			
		||||
    _file_tab.ids = calloc(max_files, sizeof(vy_file_id));
 | 
			
		||||
    if (!_file_tab.ids)
 | 
			
		||||
        return false;
 | 
			
		||||
    _file_tab.name_offsets = calloc(max_files, sizeof(unsigned int));
 | 
			
		||||
    if (!_file_tab.name_offsets)
 | 
			
		||||
        return false;
 | 
			
		||||
    _file_tab.names = malloc(NAME_CAP(max_files));
 | 
			
		||||
    if (!_file_tab.names)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    _file_tab.capacity  = max_files;
 | 
			
		||||
    _file_tab.name_head = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    if (pthread_mutex_init(&_file_tab.mutex, NULL) != 0)
 | 
			
		||||
        return false;
 | 
			
		||||
#endif
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ShutdownFileTab(void) {
 | 
			
		||||
    free(_file_tab.ids);
 | 
			
		||||
    free(_file_tab.names);
 | 
			
		||||
    free(_file_tab.name_offsets);
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_destroy(&_file_tab.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *FIOThreadProc(void *);
 | 
			
		||||
 | 
			
		||||
bool vyInitFIO(const vy_fio_config *config) {
 | 
			
		||||
    unsigned int queue_size = (config->queue_size) ? config->queue_size : 512;
 | 
			
		||||
    unsigned int max_file_count =
 | 
			
		||||
        (config->max_file_count) ? config->max_file_count : 512;
 | 
			
		||||
 | 
			
		||||
    if (!InitFIOQueue(queue_size))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    if (!InitFileTab(max_file_count))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    if (pthread_create(&_thread, NULL, FIOThreadProc, NULL) != 0)
 | 
			
		||||
        return false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyShutdownFIO(void) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_cancel(_thread);
 | 
			
		||||
    pthread_join(_thread, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
    ShutdownFIOQueue();
 | 
			
		||||
    ShutdownFileTab();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_file_id vyGetFileId(const char *path) {
 | 
			
		||||
    vy_text_span span;
 | 
			
		||||
    span.start  = path;
 | 
			
		||||
    span.length = (unsigned int)strlen(path);
 | 
			
		||||
    return vyGetFileIdFromSpan(span);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_file_id vyGetFileIdFromSpan(vy_text_span path) {
 | 
			
		||||
    /* Randomly choosen, aka finger smash keyboard */
 | 
			
		||||
    XXH64_hash_t seed = 15340978;
 | 
			
		||||
    vy_file_id fid    = (vy_file_id)XXH64(path.start, path.length, seed);
 | 
			
		||||
    if (fid == 0)
 | 
			
		||||
        fid = ~fid;
 | 
			
		||||
    return fid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_file_id vyAddFileFromSpan(vy_text_span path) {
 | 
			
		||||
    vy_file_id fid = vyGetFileIdFromSpan(path);
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_lock(&_file_tab.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    /* Hash Insert */
 | 
			
		||||
    unsigned int i    = 0;
 | 
			
		||||
    unsigned int base = (unsigned int)(fid % _file_tab.capacity);
 | 
			
		||||
    while (i < _file_tab.capacity) {
 | 
			
		||||
        unsigned int at = (base + i) % _file_tab.capacity;
 | 
			
		||||
        if (_file_tab.ids[at] == 0) {
 | 
			
		||||
            /* Insert */
 | 
			
		||||
            unsigned int slen = (unsigned int)path.length + 1;
 | 
			
		||||
            if ((_file_tab.name_head + slen) >= NAME_CAP(_file_tab.capacity)) {
 | 
			
		||||
                /* Out of name storage */
 | 
			
		||||
                fid = 0;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(_file_tab.names + _file_tab.name_head, path.start, slen);
 | 
			
		||||
            _file_tab.name_offsets[at] = _file_tab.name_head;
 | 
			
		||||
            _file_tab.ids[at]          = fid;
 | 
			
		||||
            _file_tab.name_head += slen;
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (_file_tab.ids[at] == fid) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Out of space */
 | 
			
		||||
    if (i == _file_tab.capacity)
 | 
			
		||||
        fid = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_unlock(&_file_tab.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    return fid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_file_id vyAddFile(const char *path) {
 | 
			
		||||
    vy_text_span span;
 | 
			
		||||
    span.start  = path;
 | 
			
		||||
    span.length = (unsigned int)strlen(path);
 | 
			
		||||
    return vyAddFileFromSpan(span);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *vyGetFilePath(vy_file_id fid) {
 | 
			
		||||
    /* Hash Lookup */
 | 
			
		||||
    if (fid == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_lock(&_file_tab.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    const char *result = NULL;
 | 
			
		||||
    unsigned int i     = 0;
 | 
			
		||||
    unsigned int base  = (unsigned int)(fid % _file_tab.capacity);
 | 
			
		||||
    while (i < _file_tab.capacity) {
 | 
			
		||||
        unsigned int at = (base + i) % _file_tab.capacity;
 | 
			
		||||
        if (_file_tab.ids[at] == fid) {
 | 
			
		||||
            result = _file_tab.names + _file_tab.name_offsets[at];
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (_file_tab.ids[at] == 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_unlock(&_file_tab.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_fio_handle vyEnqueueRead(vy_file_id fid) {
 | 
			
		||||
    vy_fio_handle handle = 0;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
        pthread_mutex_lock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (_queue.ops[_queue.write_pos].flags == 0 ||
 | 
			
		||||
            ((_queue.ops[_queue.write_pos].flags & FLAGS_FINISHED) != 0 &&
 | 
			
		||||
             (_queue.ops[_queue.write_pos].flags & FLAGS_RETRIEVED) != 0)) {
 | 
			
		||||
 | 
			
		||||
            _queue.ops[_queue.write_pos].fid   = fid;
 | 
			
		||||
            _queue.ops[_queue.write_pos].flags = FLAGS_IN_USE;
 | 
			
		||||
 | 
			
		||||
            handle           = _queue.write_pos + 1;
 | 
			
		||||
            _queue.write_pos = (_queue.write_pos + 1) % _queue.size;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
            pthread_cond_signal(&_queue.pending_cond);
 | 
			
		||||
            pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
        pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    } while (1);
 | 
			
		||||
 | 
			
		||||
    return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyAbortFIO(vy_fio_handle fio) {
 | 
			
		||||
    if (fio == 0)
 | 
			
		||||
        return;
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_lock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    _queue.ops[fio - 1].flags = 0;
 | 
			
		||||
    if (_queue.ops[fio - 1].buffer.data) {
 | 
			
		||||
        free(_queue.ops[fio - 1].buffer.data);
 | 
			
		||||
        _queue.ops[fio - 1].buffer.size = 0;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool vyIsFIOFinished(vy_fio_handle fio) {
 | 
			
		||||
    if (fio == 0)
 | 
			
		||||
        return false;
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_lock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    bool result = (_queue.ops[fio - 1].flags & FLAGS_FINISHED) != 0;
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool vyRetrieveReadBuffer(vy_fio_handle fio, vy_file_buffer *buffer) {
 | 
			
		||||
    if (fio == 0)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_lock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    bool is_finished = (_queue.ops[fio - 1].flags & FLAGS_FINISHED) != 0;
 | 
			
		||||
    if (is_finished) {
 | 
			
		||||
        size_t sz    = _queue.ops[fio - 1].buffer.size;
 | 
			
		||||
        buffer->data = malloc(sz);
 | 
			
		||||
        if (!buffer->data)
 | 
			
		||||
            return false;
 | 
			
		||||
        buffer->size = sz;
 | 
			
		||||
        memcpy(buffer->data, _queue.ops[fio - 1].buffer.data, sz);
 | 
			
		||||
        _queue.ops[fio - 1].flags |= FLAGS_RETRIEVED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return is_finished;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyFreeFileBuffer(vy_file_buffer buffer) {
 | 
			
		||||
    free(buffer.data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ProcessRead(vy_file_op *op) {
 | 
			
		||||
    const char *path = vyGetFilePath(op->fid);
 | 
			
		||||
    if (!path) {
 | 
			
		||||
        op->flags |= FLAGS_FINISHED;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    op->buffer.data = NULL;
 | 
			
		||||
    op->buffer.size = 0;
 | 
			
		||||
 | 
			
		||||
    FILE *file = fopen(path, "rb");
 | 
			
		||||
    if (!file) {
 | 
			
		||||
        op->flags |= FLAGS_FINISHED;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    fseek(file, 0, SEEK_END);
 | 
			
		||||
    long fsz = ftell(file);
 | 
			
		||||
    fseek(file, 0, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
    op->buffer.data = malloc(fsz);
 | 
			
		||||
    op->buffer.size = (size_t)fsz;
 | 
			
		||||
    if (fread(op->buffer.data, fsz, 1, file) != 1) {
 | 
			
		||||
        free(op->buffer.data);
 | 
			
		||||
        op->buffer.data = NULL;
 | 
			
		||||
        op->buffer.size = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fclose(file);
 | 
			
		||||
    op->flags |= FLAGS_FINISHED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void *FIOThreadProc(void *_param) {
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
    while (true) {
 | 
			
		||||
        pthread_mutex_lock(&_queue.mutex);
 | 
			
		||||
        while (_queue.write_pos == _queue.read_pos) {
 | 
			
		||||
            pthread_cond_wait(&_queue.pending_cond, &_queue.mutex);
 | 
			
		||||
        }
 | 
			
		||||
        ProcessRead(&_queue.ops[_queue.read_pos]);
 | 
			
		||||
        _queue.read_pos = (_queue.read_pos + 1) % _queue.size;
 | 
			
		||||
        pthread_mutex_unlock(&_queue.mutex);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/gfx_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/gfx_main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
 | 
			
		||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
			
		||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
			
		||||
 * replaced with the (at the time of the invoke) grid buffer of the current
 | 
			
		||||
 * world cell.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
bool vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count);
 | 
			
		||||
 | 
			
		||||
bool vyInitRenderer(void) {
 | 
			
		||||
    /* Init shader programs */
 | 
			
		||||
    const char *shader_files[] = {"shader/cell.shader"};
 | 
			
		||||
    vy_shader shaders[1];
 | 
			
		||||
    if (!vyLoadShaders(shader_files, shaders, 1))
 | 
			
		||||
        return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyShutdownRenderer(void) {
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										155
									
								
								src/gfx_pipelines.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/gfx_pipelines.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,155 @@
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "gfx_backend.h"
 | 
			
		||||
#include "voyage.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    GLuint prog;
 | 
			
		||||
} vy_gl_pipeline;
 | 
			
		||||
 | 
			
		||||
#define NUM_SLOTS 256
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t generation_in_use[NUM_SLOTS];
 | 
			
		||||
    vy_gl_pipeline pipelines[NUM_SLOTS];
 | 
			
		||||
} vy_pipeline_storage;
 | 
			
		||||
 | 
			
		||||
static vy_pipeline_storage _storage;
 | 
			
		||||
 | 
			
		||||
static vy_gfx_pipeline_id StorePipeline(vy_gl_pipeline pipeline) {
 | 
			
		||||
    /* Search for free slot */
 | 
			
		||||
    uint32_t slot = NUM_SLOTS;
 | 
			
		||||
    for (uint32_t i = 0; i < NUM_SLOTS; ++i) {
 | 
			
		||||
        if ((_storage.generation_in_use[i] & 0x1) == 0) {
 | 
			
		||||
            slot = i;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (slot == NUM_SLOTS) {
 | 
			
		||||
        vyReportError("GL_GFX", "Ran out of pipeline storage slots");
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t generation = _storage.generation_in_use[slot] >> 1;
 | 
			
		||||
    generation          = (generation + 1) & 0x1;
 | 
			
		||||
 | 
			
		||||
    _storage.pipelines[slot]         = pipeline;
 | 
			
		||||
    _storage.generation_in_use[slot] = (generation << 1) | 0x1;
 | 
			
		||||
 | 
			
		||||
    vy_gfx_pipeline_id id;
 | 
			
		||||
    id.index = (generation << 27) | slot;
 | 
			
		||||
    return id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ReleasePipelineSlot(vy_gfx_pipeline_id id) {
 | 
			
		||||
    uint32_t slot = id.index & 0x08ffffff;
 | 
			
		||||
    uint32_t gen  = (id.index >> 27) & 0x1f;
 | 
			
		||||
    if (slot >= NUM_SLOTS)
 | 
			
		||||
        return;
 | 
			
		||||
    gen = gen << 1 | 0x1;
 | 
			
		||||
    if (_storage.generation_in_use[slot] == gen)
 | 
			
		||||
        _storage.generation_in_use[slot] &= ~0x1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_gfx_pipeline_id
 | 
			
		||||
vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
 | 
			
		||||
    char info_log[512];
 | 
			
		||||
 | 
			
		||||
    GLuint prog   = glCreateProgram();
 | 
			
		||||
    GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
 | 
			
		||||
 | 
			
		||||
    GLchar *code   = (GLchar *)info->compute_source;
 | 
			
		||||
    GLint code_len = (GLint)info->compute_source_length;
 | 
			
		||||
    glShaderSource(shader, 1, (const GLchar **)&code, &code_len);
 | 
			
		||||
    glCompileShader(shader);
 | 
			
		||||
 | 
			
		||||
    GLint success;
 | 
			
		||||
    glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        glGetShaderInfoLog(shader, 512, NULL, info_log);
 | 
			
		||||
        vyReportError("GL_GFX",
 | 
			
		||||
                      "Failed to compile compute shader\n%s",
 | 
			
		||||
                      info_log);
 | 
			
		||||
        glDeleteProgram(prog);
 | 
			
		||||
        glDeleteShader(shader);
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
    glAttachShader(prog, shader);
 | 
			
		||||
    glLinkProgram(prog);
 | 
			
		||||
    glGetProgramiv(prog, GL_LINK_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        glGetProgramInfoLog(prog, 512, NULL, info_log);
 | 
			
		||||
        vyReportError("GL_GFX", "Failed to link compute shader\n%s", info_log);
 | 
			
		||||
        glDeleteShader(shader);
 | 
			
		||||
        glDeleteProgram(prog);
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
    glDeleteShader(shader);
 | 
			
		||||
 | 
			
		||||
    vy_gl_pipeline pipeline;
 | 
			
		||||
    pipeline.prog = prog;
 | 
			
		||||
    return StorePipeline(pipeline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_gfx_pipeline_id
 | 
			
		||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
			
		||||
    char info_log[512];
 | 
			
		||||
 | 
			
		||||
    GLuint prog            = glCreateProgram();
 | 
			
		||||
    GLuint vertex_shader   = glCreateShader(GL_VERTEX_SHADER);
 | 
			
		||||
    GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
 | 
			
		||||
 | 
			
		||||
    GLchar *code   = (GLchar *)info->vertex_source;
 | 
			
		||||
    GLint code_len = (GLint)info->vertex_source_length;
 | 
			
		||||
    glShaderSource(vertex_shader, 1, (const GLchar **)&code, &code_len);
 | 
			
		||||
    glCompileShader(vertex_shader);
 | 
			
		||||
 | 
			
		||||
    GLint success;
 | 
			
		||||
    glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        glGetShaderInfoLog(vertex_shader, 512, NULL, info_log);
 | 
			
		||||
        vyReportError("GL_GFX",
 | 
			
		||||
                      "Failed to compile vertex shader\n%s",
 | 
			
		||||
                      info_log);
 | 
			
		||||
        glDeleteShader(vertex_shader);
 | 
			
		||||
        glDeleteShader(fragment_shader);
 | 
			
		||||
        glDeleteProgram(prog);
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
    glAttachShader(prog, vertex_shader);
 | 
			
		||||
 | 
			
		||||
    code     = (GLchar *)info->fragment_source;
 | 
			
		||||
    code_len = (GLint)info->fragment_source_length;
 | 
			
		||||
    glShaderSource(fragment_shader, 1, (const GLchar **)&code, &code_len);
 | 
			
		||||
    glCompileShader(fragment_shader);
 | 
			
		||||
 | 
			
		||||
    glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        glGetShaderInfoLog(fragment_shader, 512, NULL, info_log);
 | 
			
		||||
        vyReportError("GFX", "Failed to compile fragment shader\n%s", info_log);
 | 
			
		||||
        glDeleteShader(fragment_shader);
 | 
			
		||||
        glDeleteShader(fragment_shader);
 | 
			
		||||
        glDeleteProgram(prog);
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
    glAttachShader(prog, fragment_shader);
 | 
			
		||||
 | 
			
		||||
    glLinkProgram(prog);
 | 
			
		||||
    glGetProgramiv(prog, GL_LINK_STATUS, &success);
 | 
			
		||||
    if (!success) {
 | 
			
		||||
        glGetProgramInfoLog(prog, 512, NULL, info_log);
 | 
			
		||||
        vyReportError("GFX", "Failed to link graphics shader\n%s", info_log);
 | 
			
		||||
        glDeleteShader(vertex_shader);
 | 
			
		||||
        glDeleteShader(fragment_shader);
 | 
			
		||||
        glDeleteProgram(prog);
 | 
			
		||||
        return (vy_gfx_pipeline_id){0};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glDeleteShader(vertex_shader);
 | 
			
		||||
    glDeleteShader(fragment_shader);
 | 
			
		||||
 | 
			
		||||
    vy_gl_pipeline pipeline;
 | 
			
		||||
    pipeline.prog = prog;
 | 
			
		||||
    return StorePipeline(pipeline);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										563
									
								
								src/gfx_shader_loading.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										563
									
								
								src/gfx_shader_loading.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,563 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "fio.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "gfx_backend.h"
 | 
			
		||||
#include "voyage.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_STMT_FORM_VALUE,
 | 
			
		||||
    VY_STMT_FORM_LIST,
 | 
			
		||||
} vy_stmt_form;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    unsigned int first;
 | 
			
		||||
    unsigned int count;
 | 
			
		||||
} vy_parsed_stmt_list;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_stmt_form form;
 | 
			
		||||
    vy_text_span attribute;
 | 
			
		||||
    union {
 | 
			
		||||
        vy_text_span value;
 | 
			
		||||
        unsigned int list_index;
 | 
			
		||||
    };
 | 
			
		||||
    /* For lists */
 | 
			
		||||
    unsigned int next;
 | 
			
		||||
} vy_parsed_stmt;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *file;
 | 
			
		||||
    const char *text;
 | 
			
		||||
    size_t at;
 | 
			
		||||
    size_t length;
 | 
			
		||||
    int line;
 | 
			
		||||
 | 
			
		||||
    vy_parsed_stmt *statements;
 | 
			
		||||
    unsigned int statement_count;
 | 
			
		||||
    unsigned int statement_capacity;
 | 
			
		||||
 | 
			
		||||
    vy_parsed_stmt_list *statement_lists;
 | 
			
		||||
    unsigned int statement_list_count;
 | 
			
		||||
    unsigned int statement_list_capacity;
 | 
			
		||||
} vy_parse_state;
 | 
			
		||||
 | 
			
		||||
static bool IsAllowedChar(char c) {
 | 
			
		||||
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
 | 
			
		||||
           (c >= 'A' && c <= 'Z') || (c == '.') || (c == '_') || (c == '/');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool IsWhitespace(char c) {
 | 
			
		||||
    return c == ' ' || c == '\t' || c == '\n';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SkipWhitespace(vy_parse_state *state) {
 | 
			
		||||
    while (state->at < state->length && IsWhitespace(state->text[state->at])) {
 | 
			
		||||
        if (state->text[state->at] == '\n')
 | 
			
		||||
            ++state->line;
 | 
			
		||||
        ++state->at;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
			
		||||
    vy_text_span name;
 | 
			
		||||
    name.start  = &state->text[state->at];
 | 
			
		||||
    name.length = 0;
 | 
			
		||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at])) {
 | 
			
		||||
        if (IsAllowedChar(state->text[state->at])) {
 | 
			
		||||
            ++state->at;
 | 
			
		||||
            ++name.length;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "%s:%d Unexpected character %c",
 | 
			
		||||
                          state->file,
 | 
			
		||||
                          state->line,
 | 
			
		||||
                          state->text[state->at]);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    *_name = name;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
			
		||||
    vy_text_span value;
 | 
			
		||||
    value.start  = &state->text[state->at];
 | 
			
		||||
    value.length = 0;
 | 
			
		||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at]) &&
 | 
			
		||||
           state->text[state->at] != ';') {
 | 
			
		||||
        if (IsAllowedChar(state->text[state->at])) {
 | 
			
		||||
            ++state->at;
 | 
			
		||||
            ++value.length;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "%s:%d Unexpected character %c",
 | 
			
		||||
                          state->file,
 | 
			
		||||
                          state->line,
 | 
			
		||||
                          state->text[state->at]);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    *_value = value;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index);
 | 
			
		||||
 | 
			
		||||
static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    vy_parsed_stmt stmt;
 | 
			
		||||
    stmt.next = UINT_MAX; /* end of list */
 | 
			
		||||
 | 
			
		||||
    SkipWhitespace(state);
 | 
			
		||||
    if (!ParseAttribute(state, &stmt.attribute))
 | 
			
		||||
        return false;
 | 
			
		||||
    SkipWhitespace(state);
 | 
			
		||||
 | 
			
		||||
    if (state->at == state->length) {
 | 
			
		||||
        vyReportError("GFX",
 | 
			
		||||
                      "%s:%d Expected either a value or '{'",
 | 
			
		||||
                      state->file,
 | 
			
		||||
                      state->line);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (state->text[state->at] == '{') {
 | 
			
		||||
        /* Consume '{' */
 | 
			
		||||
        ++state->at;
 | 
			
		||||
 | 
			
		||||
        stmt.form = VY_STMT_FORM_LIST;
 | 
			
		||||
        if (!ParseStmtList(state, &stmt.list_index))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        /* Consume '}' */
 | 
			
		||||
        if (state->at < state->length && state->text[state->at] == '}')
 | 
			
		||||
            ++state->at;
 | 
			
		||||
    } else {
 | 
			
		||||
        stmt.form = VY_STMT_FORM_VALUE;
 | 
			
		||||
        if (!ParseValue(state, &stmt.value))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        /* Consume ';' */
 | 
			
		||||
        if (state->at < state->length && state->text[state->at] == ';')
 | 
			
		||||
            ++state->at;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SkipWhitespace(state);
 | 
			
		||||
 | 
			
		||||
    /* Add statement to array */
 | 
			
		||||
    if (state->statement_count == state->statement_capacity) {
 | 
			
		||||
        unsigned int cap = (state->statement_capacity > 0)
 | 
			
		||||
                               ? state->statement_capacity * 2
 | 
			
		||||
                               : 64;
 | 
			
		||||
        vy_parsed_stmt *temp =
 | 
			
		||||
            realloc(state->statements, sizeof(vy_parsed_stmt) * cap);
 | 
			
		||||
        if (!temp) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "While parsing %s: Out of memory\n",
 | 
			
		||||
                          state->file);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        state->statements         = temp;
 | 
			
		||||
        state->statement_capacity = cap;
 | 
			
		||||
    }
 | 
			
		||||
    state->statements[state->statement_count] = stmt;
 | 
			
		||||
    *stmt_index                               = state->statement_count++;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
			
		||||
    vy_parsed_stmt_list list;
 | 
			
		||||
    list.first = state->statement_count;
 | 
			
		||||
    list.count = 0;
 | 
			
		||||
 | 
			
		||||
    unsigned int last = UINT_MAX;
 | 
			
		||||
 | 
			
		||||
    while (state->at < state->length && state->text[state->at] != '}') {
 | 
			
		||||
        unsigned int stmt;
 | 
			
		||||
        if (!ParseStmt(state, &stmt))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (last != UINT_MAX)
 | 
			
		||||
            state->statements[last].next = stmt;
 | 
			
		||||
        last = stmt;
 | 
			
		||||
 | 
			
		||||
        ++list.count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Add list to array */
 | 
			
		||||
    if (state->statement_list_count == state->statement_list_capacity) {
 | 
			
		||||
        unsigned int cap = (state->statement_list_capacity > 0)
 | 
			
		||||
                               ? state->statement_list_capacity * 2
 | 
			
		||||
                               : 64;
 | 
			
		||||
        vy_parsed_stmt_list *temp =
 | 
			
		||||
            realloc(state->statement_lists, sizeof(vy_parsed_stmt_list) * cap);
 | 
			
		||||
        if (!temp) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "While parsing %s: Out of memory\n",
 | 
			
		||||
                          state->file);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        state->statement_lists         = temp;
 | 
			
		||||
        state->statement_list_capacity = cap;
 | 
			
		||||
    }
 | 
			
		||||
    state->statement_lists[state->statement_list_count] = list;
 | 
			
		||||
    *list_index = state->statement_list_count++;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DbgPrintShaderFile(const vy_parse_state *state,
 | 
			
		||||
                               unsigned int list_index,
 | 
			
		||||
                               unsigned int indent) {
 | 
			
		||||
    assert(list_index < state->statement_list_count);
 | 
			
		||||
    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
 | 
			
		||||
    unsigned int stmt_index = list->first;
 | 
			
		||||
    for (unsigned int i = 0; i < list->count; ++i) {
 | 
			
		||||
        const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        for (unsigned int j = 0; j < indent; ++j)
 | 
			
		||||
            printf(" ");
 | 
			
		||||
        printf("%.*s: ", stmt->attribute.length, stmt->attribute.start);
 | 
			
		||||
        if (stmt->form == VY_STMT_FORM_VALUE) {
 | 
			
		||||
            printf("%.*s\n", stmt->value.length, stmt->value.start);
 | 
			
		||||
        } else {
 | 
			
		||||
            printf("{\n");
 | 
			
		||||
            DbgPrintShaderFile(state, stmt->list_index, indent + 2);
 | 
			
		||||
            printf("}\n");
 | 
			
		||||
        }
 | 
			
		||||
        stmt_index = stmt->next;
 | 
			
		||||
    }
 | 
			
		||||
    assert(stmt_index = UINT_MAX);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool CompareSpanToString(vy_text_span span, const char *cmp) {
 | 
			
		||||
    size_t cmp_len = strlen(cmp);
 | 
			
		||||
    if (cmp_len != (size_t)span.length)
 | 
			
		||||
        return false;
 | 
			
		||||
    for (size_t i = 0; i < cmp_len; ++i) {
 | 
			
		||||
        if (span.start[i] != cmp[i])
 | 
			
		||||
            return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const vy_parsed_stmt *FindStatement(const vy_parse_state *state,
 | 
			
		||||
                                           unsigned int list_index,
 | 
			
		||||
                                           const char *attribute) {
 | 
			
		||||
    if (list_index >= state->statement_list_count)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
    unsigned int stmt_index         = list->first;
 | 
			
		||||
    for (unsigned int i = 0; i < list->count; ++i) {
 | 
			
		||||
        const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        if (CompareSpanToString(stmt->attribute, attribute))
 | 
			
		||||
            return stmt;
 | 
			
		||||
        stmt_index = stmt->next;
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_fio_handle DispatchFileRead(vy_text_span path) {
 | 
			
		||||
    vy_file_id fid = vyAddFileFromSpan(path);
 | 
			
		||||
    if (fid == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
    vy_fio_handle fio = vyEnqueueRead(fid);
 | 
			
		||||
    return fio;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_fio_handle DispatchShaderRead(const char *shader,
 | 
			
		||||
                                        const vy_parse_state *state,
 | 
			
		||||
                                        unsigned int root_list,
 | 
			
		||||
                                        const char *file_path) {
 | 
			
		||||
    const vy_parsed_stmt *path = FindStatement(state, root_list, shader);
 | 
			
		||||
    if (!path) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (path->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
        vyReportError("GFX",
 | 
			
		||||
                      "Expected simple value for attribute \"%s\" in %s\n",
 | 
			
		||||
                      shader,
 | 
			
		||||
                      file_path);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return DispatchFileRead(path->value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_gfx_pipeline_id LinkProgram(vy_parse_state *state,
 | 
			
		||||
                                      const char *file_path,
 | 
			
		||||
                                      unsigned int root_list) {
 | 
			
		||||
    /* Process the data */
 | 
			
		||||
    vy_fio_handle vertex_read =
 | 
			
		||||
        DispatchShaderRead("vertex", state, root_list, file_path);
 | 
			
		||||
    vy_fio_handle fragment_read =
 | 
			
		||||
        DispatchShaderRead("fragment", state, root_list, file_path);
 | 
			
		||||
    vy_fio_handle compute_read =
 | 
			
		||||
        DispatchShaderRead("compute", state, root_list, file_path);
 | 
			
		||||
 | 
			
		||||
    if (compute_read) {
 | 
			
		||||
        if (vertex_read || fragment_read) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "A shader program can not contain a compute "
 | 
			
		||||
                          "shader and graphics shaders: %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            vyAbortFIO(vertex_read);
 | 
			
		||||
            vyAbortFIO(fragment_read);
 | 
			
		||||
            vyAbortFIO(compute_read);
 | 
			
		||||
            return (vy_gfx_pipeline_id){0};
 | 
			
		||||
        }
 | 
			
		||||
        while (!vyIsFIOFinished(compute_read)) {
 | 
			
		||||
            /* wait */
 | 
			
		||||
        }
 | 
			
		||||
        vy_file_buffer compute_code;
 | 
			
		||||
        if (!vyRetrieveReadBuffer(compute_read, &compute_code)) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "Failed to load compute shader required by: %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            return (vy_gfx_pipeline_id){0};
 | 
			
		||||
        }
 | 
			
		||||
        vy_compute_pipeline_info info;
 | 
			
		||||
        info.compute_source         = compute_code.data;
 | 
			
		||||
        info.compute_source_length  = compute_code.size;
 | 
			
		||||
        vy_gfx_pipeline_id pipeline = vyCompileComputePipeline(&info);
 | 
			
		||||
        vyFreeFileBuffer(compute_code);
 | 
			
		||||
        return pipeline;
 | 
			
		||||
    } else if (vertex_read || fragment_read) {
 | 
			
		||||
        if (compute_read) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "A shader program can not contain a compute "
 | 
			
		||||
                          "shader and graphics shaders: %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            vyAbortFIO(vertex_read);
 | 
			
		||||
            vyAbortFIO(fragment_read);
 | 
			
		||||
            vyAbortFIO(compute_read);
 | 
			
		||||
            return (vy_gfx_pipeline_id){0};
 | 
			
		||||
        }
 | 
			
		||||
        if (!vertex_read || !fragment_read) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "A shader program must contain at least a vertex and "
 | 
			
		||||
                          "a fragment shader: %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            vyAbortFIO(vertex_read);
 | 
			
		||||
            vyAbortFIO(fragment_read);
 | 
			
		||||
            vyAbortFIO(compute_read);
 | 
			
		||||
            return (vy_gfx_pipeline_id){0};
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vy_graphics_pipeline_info info;
 | 
			
		||||
        vy_file_buffer vertex_code   = {NULL, 0};
 | 
			
		||||
        vy_file_buffer fragment_code = {NULL, 0};
 | 
			
		||||
 | 
			
		||||
        int remaining = 2;
 | 
			
		||||
        while (remaining > 0) {
 | 
			
		||||
            if (vyIsFIOFinished(vertex_read)) {
 | 
			
		||||
                if (!vyRetrieveReadBuffer(vertex_read, &vertex_code)) {
 | 
			
		||||
                    vyReportError(
 | 
			
		||||
                        "GFX",
 | 
			
		||||
                        "Failed to load vertex shader required by: %s",
 | 
			
		||||
                        file_path);
 | 
			
		||||
                    vyFreeFileBuffer(fragment_code);
 | 
			
		||||
                    return (vy_gfx_pipeline_id){0};
 | 
			
		||||
                }
 | 
			
		||||
                info.vertex_source        = vertex_code.data;
 | 
			
		||||
                info.vertex_source_length = vertex_code.size;
 | 
			
		||||
                --remaining;
 | 
			
		||||
                vertex_read = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (vyIsFIOFinished(fragment_read)) {
 | 
			
		||||
                if (!vyRetrieveReadBuffer(fragment_read, &fragment_code)) {
 | 
			
		||||
                    vyReportError(
 | 
			
		||||
                        "GFX",
 | 
			
		||||
                        "Failed to load fragment shader required by: %s",
 | 
			
		||||
                        file_path);
 | 
			
		||||
                    vyFreeFileBuffer(vertex_code);
 | 
			
		||||
                    return (vy_gfx_pipeline_id){0};
 | 
			
		||||
                }
 | 
			
		||||
                info.fragment_source        = fragment_code.data;
 | 
			
		||||
                info.fragment_source_length = fragment_code.size;
 | 
			
		||||
                --remaining;
 | 
			
		||||
                fragment_read = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vy_gfx_pipeline_id pipeline = vyCompileGraphicsPipeline(&info);
 | 
			
		||||
        vyFreeFileBuffer(vertex_code);
 | 
			
		||||
        vyFreeFileBuffer(fragment_code);
 | 
			
		||||
        return pipeline;
 | 
			
		||||
    } else if (!compute_read && !vertex_read && !fragment_read) {
 | 
			
		||||
        vyReportError("GFX",
 | 
			
		||||
                      "Either \"compute\" or \"vertex\" and \"fragment\" "
 | 
			
		||||
                      "are required in %s",
 | 
			
		||||
                      file_path);
 | 
			
		||||
        vyAbortFIO(vertex_read);
 | 
			
		||||
        vyAbortFIO(fragment_read);
 | 
			
		||||
        vyAbortFIO(compute_read);
 | 
			
		||||
    }
 | 
			
		||||
    return (vy_gfx_pipeline_id){0};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
			
		||||
    if (span.length == 0)
 | 
			
		||||
        return false;
 | 
			
		||||
    int at           = (int)span.length - 1;
 | 
			
		||||
    unsigned int exp = 1;
 | 
			
		||||
    unsigned int n   = 0;
 | 
			
		||||
    while (at >= 0) {
 | 
			
		||||
        if (span.start[at] >= '0' && span.start[at] <= '9') {
 | 
			
		||||
            unsigned int digit = (unsigned int)(span.start[at] - '0');
 | 
			
		||||
            n += digit * exp;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "Unexpected non-digit character in binding index");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        --at;
 | 
			
		||||
        exp *= 10;
 | 
			
		||||
    }
 | 
			
		||||
    *index = n;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_attribute_value ParseBindingValue(vy_text_span span) {
 | 
			
		||||
    if (CompareSpanToString(span, "MATERIAL_ALBEDO")) {
 | 
			
		||||
        return VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("GFX",
 | 
			
		||||
                  "Unsupported binding value %*.s",
 | 
			
		||||
                  span.length,
 | 
			
		||||
                  span.start);
 | 
			
		||||
    return VY_ATTRIBUTE_VALUE_UNDEFINED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
ParseShaderFile(vy_file_id fid, vy_file_buffer fbuf, vy_shader *shader) {
 | 
			
		||||
    /* This is the grammar for shader files:
 | 
			
		||||
     * <stmt-list> ::= <stmt>*
 | 
			
		||||
     * <stmt> ::= <attribute> ( ( <value> ';' ) | ( '{' <stmt-list> '}' ) )
 | 
			
		||||
     * <attribute> ::= [:alnum:]*
 | 
			
		||||
     * <value>:: = [:alnum:]* */
 | 
			
		||||
    const char *file_path = vyGetFilePath(fid);
 | 
			
		||||
    vy_parse_state state  = {.text                    = (const char *)fbuf.data,
 | 
			
		||||
                             .at                      = 0,
 | 
			
		||||
                             .length                  = fbuf.size,
 | 
			
		||||
                             .line                    = 1,
 | 
			
		||||
                             .file                    = file_path,
 | 
			
		||||
                             .statements              = NULL,
 | 
			
		||||
                             .statement_lists         = NULL,
 | 
			
		||||
                             .statement_capacity      = 0,
 | 
			
		||||
                             .statement_list_capacity = 0};
 | 
			
		||||
 | 
			
		||||
    bool result            = true;
 | 
			
		||||
    unsigned int root_list = 0;
 | 
			
		||||
    if (!ParseStmtList(&state, &root_list)) {
 | 
			
		||||
        result = false;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    DbgPrintShaderFile(&state, root_list, 0);
 | 
			
		||||
 | 
			
		||||
    shader->pipeline = LinkProgram(&state, file_path, root_list);
 | 
			
		||||
    if (!VY_IS_GFX_ID_VALID(shader->pipeline)) {
 | 
			
		||||
        result = false;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Process bindings */
 | 
			
		||||
    shader->texture_bindings      = NULL;
 | 
			
		||||
    shader->texture_binding_count = 0;
 | 
			
		||||
    shader->uniform_bindings      = NULL;
 | 
			
		||||
    shader->uniform_binding_count = 0;
 | 
			
		||||
    shader->storage_bindings      = NULL;
 | 
			
		||||
    shader->storage_binding_count = 0;
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *texture_bindings =
 | 
			
		||||
        FindStatement(&state, root_list, "texture_bindings");
 | 
			
		||||
    if (texture_bindings) {
 | 
			
		||||
        if (texture_bindings->form != VY_STMT_FORM_LIST) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
                          "Expected list of bindings as the value of "
 | 
			
		||||
                          "\"texture_bindings\" in %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        const vy_parsed_stmt_list *binding_list =
 | 
			
		||||
            &state.statement_lists[texture_bindings->list_index];
 | 
			
		||||
        shader->texture_bindings =
 | 
			
		||||
            malloc(sizeof(vy_attribute_binding) * binding_list->count);
 | 
			
		||||
        if (!shader->texture_bindings) {
 | 
			
		||||
            vyReportError("GFX", "Out of memory");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        shader->texture_binding_count = binding_list->count;
 | 
			
		||||
 | 
			
		||||
        unsigned int stmt_index = binding_list->first;
 | 
			
		||||
        for (unsigned int i = 0; i < binding_list->count; ++i) {
 | 
			
		||||
            const vy_parsed_stmt *stmt = &state.statements[stmt_index];
 | 
			
		||||
            if (!ParseBindingIndex(stmt->attribute,
 | 
			
		||||
                                   &shader->texture_bindings[i].index)) {
 | 
			
		||||
                free(shader->texture_bindings);
 | 
			
		||||
                result = false;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            shader->texture_bindings[i].value = ParseBindingValue(stmt->value);
 | 
			
		||||
            if (shader->texture_bindings[i].value ==
 | 
			
		||||
                VY_ATTRIBUTE_VALUE_UNDEFINED) {
 | 
			
		||||
                free(shader->texture_bindings);
 | 
			
		||||
                result = false;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            stmt_index = stmt->next;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *uniform_bindings =
 | 
			
		||||
        FindStatement(&state, root_list, "uniform_bindings");
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *storage_bindings =
 | 
			
		||||
        FindStatement(&state, root_list, "storage_bindings");
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    free(state.statements);
 | 
			
		||||
    free(state.statement_lists);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count) {
 | 
			
		||||
    vy_fio_handle fios[64];
 | 
			
		||||
    vy_file_id fids[64];
 | 
			
		||||
    for (unsigned int i = 0; i < count; i += 64) {
 | 
			
		||||
        unsigned int chunk_size = count - i;
 | 
			
		||||
        if (chunk_size > 64)
 | 
			
		||||
            chunk_size = 64;
 | 
			
		||||
        for (unsigned int j = 0; j < chunk_size; ++j) {
 | 
			
		||||
            vy_file_id fid = vyAddFile(paths[i + j]);
 | 
			
		||||
            if (!fid)
 | 
			
		||||
                return false;
 | 
			
		||||
            fids[j] = fid;
 | 
			
		||||
            fios[j] = vyEnqueueRead(fid);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        unsigned int remaining = chunk_size;
 | 
			
		||||
        while (remaining > 0) {
 | 
			
		||||
            for (unsigned int j = 0; j < chunk_size; ++j) {
 | 
			
		||||
                if (vyIsFIOFinished(fios[j])) {
 | 
			
		||||
                    vy_file_buffer fbuf;
 | 
			
		||||
                    if (!vyRetrieveReadBuffer(fios[j], &fbuf)) {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
                    ParseShaderFile(fids[j], fbuf, &shaders[i + j]);
 | 
			
		||||
                    vyFreeFileBuffer(fbuf);
 | 
			
		||||
                    --remaining;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								src/voyage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/voyage.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <GLFW/glfw3.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "fio.h"
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
 | 
			
		||||
static void glfw_error_cb(int err, const char *description) {
 | 
			
		||||
    fprintf(stderr, "[GLFW] %u: %s\n", err, description);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void make_window_windowed_fullscreen(GLFWwindow *window,
 | 
			
		||||
                                            GLFWmonitor *monitor) {
 | 
			
		||||
    const GLFWvidmode *mode = glfwGetVideoMode(monitor);
 | 
			
		||||
    glfwSetWindowMonitor(window,
 | 
			
		||||
                         monitor,
 | 
			
		||||
                         0,
 | 
			
		||||
                         0,
 | 
			
		||||
                         mode->width,
 | 
			
		||||
                         mode->height,
 | 
			
		||||
                         mode->refreshRate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void make_window_windowed(GLFWwindow *window, int w, int h) {
 | 
			
		||||
    glfwSetWindowMonitor(window, NULL, 0, 0, w, h, GLFW_DONT_CARE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int f1;
 | 
			
		||||
    int esc;
 | 
			
		||||
} key_states;
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
    glfwSetErrorCallback(glfw_error_cb);
 | 
			
		||||
    if (!glfwInit()) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    printf("[GFLW] Version: %s\n", glfwGetVersionString());
 | 
			
		||||
 | 
			
		||||
    /* Create a windowed full screen window */
 | 
			
		||||
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
 | 
			
		||||
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
 | 
			
		||||
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
 | 
			
		||||
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
 | 
			
		||||
    GLFWwindow *window = glfwCreateWindow(640, 480, "Voyage", NULL, NULL);
 | 
			
		||||
    if (!window) {
 | 
			
		||||
        fprintf(stderr, "[GFX] Window creation failed.\n");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    glfwMakeContextCurrent(window);
 | 
			
		||||
    glfwSwapInterval(1);
 | 
			
		||||
 | 
			
		||||
    if (!gladLoadGL()) {
 | 
			
		||||
        fprintf(stderr, "[GFX] OpenGL load failed.\n");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_fio_config fio_config = {0};
 | 
			
		||||
    if (!vyInitFIO(&fio_config)) {
 | 
			
		||||
        fprintf(stderr, "[FIO] Init failed.\n");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!vyInitRenderer()) {
 | 
			
		||||
        fprintf(stderr, "[GFX] Init failed.\n");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    printf("GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS: %u\n",
 | 
			
		||||
           GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS);
 | 
			
		||||
    printf("GL_MAX_UNIFORM_BUFFER_BINDINGS: %u\n",
 | 
			
		||||
           GL_MAX_UNIFORM_BUFFER_BINDINGS);
 | 
			
		||||
 | 
			
		||||
    key_states prev_keys = {0};
 | 
			
		||||
    int window_state     = 0;
 | 
			
		||||
 | 
			
		||||
    while (!glfwWindowShouldClose(window)) {
 | 
			
		||||
        /* Gather input */
 | 
			
		||||
        key_states keys;
 | 
			
		||||
        keys.f1  = glfwGetKey(window, GLFW_KEY_F1);
 | 
			
		||||
        keys.esc = glfwGetKey(window, GLFW_KEY_ESCAPE);
 | 
			
		||||
 | 
			
		||||
        if (keys.f1 && !prev_keys.f1) {
 | 
			
		||||
            if (window_state)
 | 
			
		||||
                make_window_windowed(window, 640, 480);
 | 
			
		||||
            else
 | 
			
		||||
                make_window_windowed_fullscreen(window,
 | 
			
		||||
                                                glfwGetPrimaryMonitor());
 | 
			
		||||
            window_state = !window_state;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (keys.esc)
 | 
			
		||||
            glfwSetWindowShouldClose(window, GLFW_TRUE);
 | 
			
		||||
 | 
			
		||||
        int fbw, fbh;
 | 
			
		||||
        glfwGetFramebufferSize(window, &fbw, &fbh);
 | 
			
		||||
        glViewport(0, 0, fbw, fbh);
 | 
			
		||||
        glClearColor(0, 0, 0, 0);
 | 
			
		||||
        glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
        glfwSwapBuffers(window);
 | 
			
		||||
        glfwPollEvents();
 | 
			
		||||
        prev_keys = keys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyShutdownRenderer();
 | 
			
		||||
    vyShutdownFIO();
 | 
			
		||||
 | 
			
		||||
    glfwDestroyWindow(window);
 | 
			
		||||
    glfwTerminate();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								subprojects/glfw.wrap
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								subprojects/glfw.wrap
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
[wrap-file]
 | 
			
		||||
directory = glfw-3.3.8
 | 
			
		||||
source_url = https://github.com/glfw/glfw/archive/refs/tags/3.3.8.tar.gz
 | 
			
		||||
source_filename = glfw-3.3.8.tar.gz
 | 
			
		||||
source_hash = f30f42e05f11e5fc62483e513b0488d5bceeab7d9c5da0ffe2252ad81816c713
 | 
			
		||||
patch_filename = glfw_3.3.8-2_patch.zip
 | 
			
		||||
patch_url = https://wrapdb.mesonbuild.com/v2/glfw_3.3.8-2/get_patch
 | 
			
		||||
patch_hash = eca865a15ff49d29d1a710fda3cfb9ca82057dda7f15ed617a1677cc5992c503
 | 
			
		||||
wrapdb_version = 3.3.8-2
 | 
			
		||||
 | 
			
		||||
[provide]
 | 
			
		||||
glfw3 = glfw_dep
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user