iuno
This commit is contained in:
		
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -88,4 +88,7 @@ assets/borrowed | |||||||
|  |  | ||||||
| *~ | *~ | ||||||
|  |  | ||||||
| /dist | /dist | ||||||
|  |  | ||||||
|  | /archive0 | ||||||
|  | /archive1 | ||||||
| @@ -5,45 +5,10 @@ | |||||||
|  |  | ||||||
| include(FetchContent) | include(FetchContent) | ||||||
|  |  | ||||||
| # GLFW | # RayLib | ||||||
| FetchContent_Declare( | FetchContent_Declare( | ||||||
|   glfw |   raylib | ||||||
|   GIT_REPOSITORY  https://github.com/glfw/glfw |   GIT_REPOSITORY  https://github.com/raysan5/raylib | ||||||
|   GIT_TAG         3.4 |   GIT_TAG         5.5 | ||||||
| ) | ) | ||||||
| FetchContent_MakeAvailable(glfw) | FetchContent_MakeAvailable(raylib) | ||||||
|  |  | ||||||
| # GLAD (For GLFW) |  | ||||||
| add_subdirectory(glad) |  | ||||||
|  |  | ||||||
| # CGLM |  | ||||||
| FetchContent_Declare( |  | ||||||
|   cglm |  | ||||||
|   GIT_REPOSITORY  https://github.com/recp/cglm |  | ||||||
|   GIT_TAG         v0.9.4 |  | ||||||
| ) |  | ||||||
| FetchContent_MakeAvailable(cglm) |  | ||||||
|  |  | ||||||
| #LibArchive |  | ||||||
| FetchContent_Declare( |  | ||||||
|   libarchive |  | ||||||
|   GIT_REPOSITORY https://github.com/libarchive/libarchive |  | ||||||
|   GIT_TAG        v3.7.6 |  | ||||||
| ) |  | ||||||
| FetchContent_MakeAvailable(libarchive) |  | ||||||
|  |  | ||||||
| #libspng |  | ||||||
| FetchContent_Declare( |  | ||||||
|   libspng |  | ||||||
|   GIT_REPOSITORY https://github.com/randy408/libspng |  | ||||||
|   GIT_TAG        v0.7.4 |  | ||||||
| ) |  | ||||||
| FetchContent_MakeAvailable(libspng) |  | ||||||
|  |  | ||||||
| # SDL2 |  | ||||||
| # FetchContent_Declare( |  | ||||||
| #   SDL2 |  | ||||||
| #   GIT_REPOSITORY https://github.com/libsdl-org/SDL |  | ||||||
| #   GIT_TAG        release-2.0.14 |  | ||||||
| # ) |  | ||||||
| # FetchContent_MakeAvailable(SDL2) |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| cmake_minimum_required(VERSION 3.11) |  | ||||||
| project(glad) |  | ||||||
| set(CMAKE_C_STANDARD 99) |  | ||||||
| set(CMAKE_C_STANDARD_REQUIRED ON) |  | ||||||
|  |  | ||||||
| add_library(${PROJECT_NAME} |  | ||||||
|   src/glad.c |  | ||||||
| ) |  | ||||||
| target_include_directories(${PROJECT_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     ${CMAKE_CURRENT_SOURCE_DIR}/include |  | ||||||
| ) |  | ||||||
| @@ -1,311 +0,0 @@ | |||||||
| #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_ */ |  | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1833
									
								
								lib/glad/src/glad.c
									
									
									
									
									
								
							
							
						
						
									
										1833
									
								
								lib/glad/src/glad.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,7 +1,30 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters | # Copyright (c) 2025 Dominic Masters | ||||||
| #  | # | ||||||
| # This software is released under the MIT License. | # This software is released under the MIT License. | ||||||
| # https://opensource.org/licenses/MIT | # https://opensource.org/licenses/MIT | ||||||
|  |  | ||||||
| add_subdirectory(dusktest) | # Libs | ||||||
| add_subdirectory(dusk) | target_link_libraries(${DUSK_TARGET_NAME} | ||||||
|  |   PUBLIC | ||||||
|  |     m | ||||||
|  |     raylib | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # Includes | ||||||
|  | target_include_directories(${DUSK_TARGET_NAME} | ||||||
|  |   PUBLIC | ||||||
|  |     ${CMAKE_CURRENT_LIST_DIR} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # Sources | ||||||
|  | target_sources(${DUSK_TARGET_NAME} | ||||||
|  |   PRIVATE | ||||||
|  |     main.c | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | # Subdirs | ||||||
|  | add_subdirectory(assert) | ||||||
|  | add_subdirectory(console) | ||||||
|  | add_subdirectory(error) | ||||||
|  | add_subdirectory(server) | ||||||
|  | add_subdirectory(util) | ||||||
| @@ -303,15 +303,17 @@ void cmdGet(const consolecmdexec_t *exec) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void cmdSet(const consolecmdexec_t *exec) { | void cmdSet(const consolecmdexec_t *exec) { | ||||||
|   assertTrue( |   assertTrue(exec->argc >= 2, "set command requires 2 arguments."); | ||||||
|     exec->argc >= 2, |  | ||||||
|     "set command requires 2 arguments." |  | ||||||
|   ); |  | ||||||
| 
 | 
 | ||||||
|   for(uint32_t i = 0; i < CONSOLE.variableCount; i++) { |   for(uint32_t i = 0; i < CONSOLE.variableCount; i++) { | ||||||
|     consolevar_t *var = &CONSOLE.variables[i]; |     consolevar_t *var = &CONSOLE.variables[i]; | ||||||
|     if(stringCompare(var->name, exec->argv[0]) != 0) continue; |     if(stringCompare(var->name, exec->argv[0]) != 0) continue; | ||||||
|     consoleVarSetValue(var, exec->argv[1]); |     consoleVarSetValue(var, exec->argv[1]); | ||||||
|  |     consolePrint("%s %s", var->name, var->value); | ||||||
|  |     for(i = 0; i < var->eventCount; i++) { | ||||||
|  |       assertNotNull(var->events[i], "Event is NULL"); | ||||||
|  |       var->events[i](var); | ||||||
|  |     } | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @@ -325,4 +327,58 @@ void cmdEcho(const consolecmdexec_t *exec) { | |||||||
|   ); |   ); | ||||||
| 
 | 
 | ||||||
|   consolePrint("%s", exec->argv[0]); |   consolePrint("%s", exec->argv[0]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // May move these later
 | ||||||
|  | void consoleUpdate() { | ||||||
|  |   int32_t key = GetKeyPressed(); | ||||||
|  | 
 | ||||||
|  |   switch(key) { | ||||||
|  |     case 0: | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     case KEY_ENTER: | ||||||
|  |       consoleExec(CONSOLE.inputBuffer); | ||||||
|  |       CONSOLE.inputIndex = 0; | ||||||
|  |       CONSOLE.inputBuffer[0] = '\0'; | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     case KEY_BACKSPACE: | ||||||
|  |       if(CONSOLE.inputIndex > 0) { | ||||||
|  |         CONSOLE.inputIndex--; | ||||||
|  |         CONSOLE.inputBuffer[CONSOLE.inputIndex] = '\0'; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  | 
 | ||||||
|  |     default: | ||||||
|  |       if(key >= 32 && key <= 126 && CONSOLE.inputIndex < CONSOLE_LINE_MAX - 1) { | ||||||
|  |         CONSOLE.inputBuffer[CONSOLE.inputIndex++] = (char_t)GetCharPressed(); | ||||||
|  |         CONSOLE.inputBuffer[CONSOLE.inputIndex] = '\0'; | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   consoleProcess(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void consoleDraw() { | ||||||
|  |   size_t i = 0; | ||||||
|  |   char_t *line; | ||||||
|  |   int32_t fontSize = 10; | ||||||
|  |   do { | ||||||
|  |     line = CONSOLE.line[i]; | ||||||
|  |     if(line[0] == '\0') { | ||||||
|  |       i++; | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     DrawText(line, 0, i*fontSize, fontSize, BLACK); | ||||||
|  |     i++; | ||||||
|  |   } while(i < CONSOLE_HISTORY_MAX); | ||||||
|  | 
 | ||||||
|  |   DrawText( | ||||||
|  |     CONSOLE.inputBuffer, 0, | ||||||
|  |     (CONSOLE_HISTORY_MAX + 1) * fontSize, | ||||||
|  |     fontSize, | ||||||
|  |     BLACK | ||||||
|  |   ); | ||||||
| } | } | ||||||
| @@ -38,6 +38,10 @@ typedef struct { | |||||||
|   consolecmd_t *cmdGet; |   consolecmd_t *cmdGet; | ||||||
|   consolecmd_t *cmdSet; |   consolecmd_t *cmdSet; | ||||||
|   pthread_mutex_t lock; // Mutex for thread safety
 |   pthread_mutex_t lock; // Mutex for thread safety
 | ||||||
|  | 
 | ||||||
|  |   // May move these later
 | ||||||
|  |   char_t inputBuffer[CONSOLE_LINE_MAX]; | ||||||
|  |   int32_t inputIndex; | ||||||
| } console_t; | } console_t; | ||||||
| 
 | 
 | ||||||
| extern console_t CONSOLE; | extern console_t CONSOLE; | ||||||
| @@ -93,6 +97,16 @@ void consoleExec(const char_t *line); | |||||||
|  */ |  */ | ||||||
| void consoleProcess(); | void consoleProcess(); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Updates the console's input buffer and handles user input. | ||||||
|  |  */ | ||||||
|  | void consoleUpdate(); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Draws the console's output. | ||||||
|  |  */ | ||||||
|  | void consoleDraw(); | ||||||
|  | 
 | ||||||
| void cmdGet(const consolecmdexec_t *exec); | void cmdGet(const consolecmdexec_t *exec); | ||||||
| void cmdSet(const consolecmdexec_t *exec); | void cmdSet(const consolecmdexec_t *exec); | ||||||
| void cmdEcho(const consolecmdexec_t *exec); | void cmdEcho(const consolecmdexec_t *exec); | ||||||
| @@ -16,7 +16,12 @@ | |||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| #include <pthread.h> | #include <pthread.h> | ||||||
|  | #include <raylib.h> | ||||||
|  | #include <errno.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | 
 | ||||||
| typedef bool bool_t; | typedef bool bool_t; | ||||||
| typedef char char_t; | typedef char char_t; | ||||||
| 
 | 
 | ||||||
|  | #define DUSK_NAME "Dusk" | ||||||
| #define DUSK_VERSION "1.0.0" | #define DUSK_VERSION "1.0.0" | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Libs |  | ||||||
| target_link_libraries(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Includes |  | ||||||
| target_include_directories(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     ${CMAKE_CURRENT_LIST_DIR} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| add_subdirectory(assert) |  | ||||||
| add_subdirectory(console) |  | ||||||
| add_subdirectory(error) |  | ||||||
| add_subdirectory(util) |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "dusk.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|  |  | ||||||
| } server_t; |  | ||||||
|  |  | ||||||
| extern server_t SERVER; |  | ||||||
|  |  | ||||||
| void serverInit(); |  | ||||||
| void serverStart(); |  | ||||||
| void serverDispose(); |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| # |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Libs |  | ||||||
| target_link_libraries(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     archive_static |  | ||||||
|     m |  | ||||||
|     spng_static |  | ||||||
|     cglm |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Includes |  | ||||||
| target_include_directories(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|   ${CMAKE_CURRENT_LIST_DIR} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     asset.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| add_subdirectory(assert) |  | ||||||
| add_subdirectory(display) |  | ||||||
| add_subdirectory(overworld) |  | ||||||
|  |  | ||||||
| # Assets |  | ||||||
| copytool("textures/8x8.png") |  | ||||||
| @@ -1,69 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2023 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
|  |  | ||||||
| void assertNotGLErrorCheck(const char_t *file, const int32_t line) { |  | ||||||
|   assertNotNull(file, "File is an invlaid string"); |  | ||||||
|   assertTrue(line > 0, "assertNotGLErrorCheck: line is invalid"); |  | ||||||
|  |  | ||||||
|   char_t *buffer; |  | ||||||
|   GLenum errorCode; |  | ||||||
|   int32_t errorCount = 0; |  | ||||||
|  |  | ||||||
|   while((errorCode = glGetError()) != GL_NO_ERROR) { |  | ||||||
|     if(errorCount == 0) { |  | ||||||
|       buffer = memoryAllocate(sizeof(char_t) * 4096); |  | ||||||
|       sprintf(buffer, "assertNotGLErrorCheck: %s:%d\n", file, line); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     errorCount++; |  | ||||||
|      |  | ||||||
|     switch (errorCode) { |  | ||||||
|       case GL_INVALID_ENUM: |  | ||||||
|         sprintf(buffer, "%s\nINVALID_ENUM", buffer); |  | ||||||
|         break; |  | ||||||
|  |  | ||||||
|       case GL_INVALID_VALUE: |  | ||||||
|         sprintf(buffer, "%s\nINVALID_ENUM", buffer); |  | ||||||
|         break; |  | ||||||
|        |  | ||||||
|       case GL_INVALID_OPERATION: |  | ||||||
|         sprintf(buffer, "%s\nINVALID_OPERATION", buffer); |  | ||||||
|         break; |  | ||||||
|  |  | ||||||
|       // case GL_INVALID_FRAMEBUFFER_OPERATION: |  | ||||||
|       //   sprintf(buffer, "%s\nINVALID_FRAMEBUFFER_OPERATION", buffer); |  | ||||||
|       //   break; |  | ||||||
|        |  | ||||||
|       case GL_OUT_OF_MEMORY: |  | ||||||
|         sprintf(buffer, "%s\nOUT_OF_MEMORY", buffer); |  | ||||||
|         break; |  | ||||||
|        |  | ||||||
|       case GL_STACK_UNDERFLOW: |  | ||||||
|         sprintf(buffer, "%s\nSTACK_UNDERFLOW", buffer); |  | ||||||
|         break; |  | ||||||
|        |  | ||||||
|       case GL_STACK_OVERFLOW: |  | ||||||
|         sprintf(buffer, "%s\nSTACK_OVERFLOW", buffer); |  | ||||||
|         break; |  | ||||||
|  |  | ||||||
|       default: |  | ||||||
|         sprintf(buffer, "%s\nUNKNOWN_ERROR", buffer); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     sprintf(buffer, "%s (%i)\n", buffer, errorCode); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if(errorCount > 0) { |  | ||||||
|     assertUnreachable(buffer); |  | ||||||
|     free(buffer); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Asserts that there are no OpenGL errors. |  | ||||||
|  *  |  | ||||||
|  * @param file The file the assertion is being made in. |  | ||||||
|  * @param line The line the assertion is being made in. |  | ||||||
|  */ |  | ||||||
| void assertNotGLErrorCheck(const char_t *file, const int32_t line); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Asserts that there are no OpenGL errors. |  | ||||||
|  */ |  | ||||||
| #define assertNoGLError() assertNotGLErrorCheck(__FILE__, __LINE__) |  | ||||||
| @@ -1,223 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2024 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "asset.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "util/math.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
|  |  | ||||||
| asset_t ASSET; |  | ||||||
|  |  | ||||||
| void assetInit() { |  | ||||||
|   const char_t *assetFilename = "dusk.tar"; |  | ||||||
|   char_t assetPath[FILENAME_MAX]; |  | ||||||
|   const char_t* scanLocations[] = { |  | ||||||
|     EXECUTABLE_DIRECTORY |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   memoryZero(&ASSET, sizeof(asset_t)); |  | ||||||
|  |  | ||||||
|   // Try and find the asset file. |  | ||||||
|   for(int32_t i = 0; i < sizeof(scanLocations) / sizeof(char_t*); i++) { |  | ||||||
|     sprintf(assetPath, "%s/%s", scanLocations[i], assetFilename); |  | ||||||
|  |  | ||||||
|     FILE *file = fopen(assetPath, "rb"); |  | ||||||
|     if(file == NULL) continue; |  | ||||||
|  |  | ||||||
|     // File found. |  | ||||||
|     ASSET.file = file; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Ensure we found it. |  | ||||||
|   assertNotNull(ASSET.file, "Failed to find asset file!"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void assetOpen(const char_t *path) { |  | ||||||
|   assertNotNull(path, "Path is not valid!"); |  | ||||||
|   assertStrLen(path, FILENAME_MAX, "Path is too long!"); |  | ||||||
|   assertStrLenMin(path, 1, "Path is empty!"); |  | ||||||
|  |  | ||||||
|   // Make sure things are clean |  | ||||||
|   assertNull(ASSET.archive, "Archive is not NULL!"); |  | ||||||
|   assertNull(ASSET.entry, "Entry is not NULL!"); |  | ||||||
|   assertNotNull(ASSET.file, "File is NULL!"); |  | ||||||
|  |  | ||||||
|   // Store path |  | ||||||
|   strcpy(ASSET.path, path); |  | ||||||
|  |  | ||||||
|   // Prepare data |  | ||||||
|   ASSET.archive = archive_read_new(); |  | ||||||
|   assertNotNull(ASSET.archive, "Failed to init archive reader"); |  | ||||||
|  |  | ||||||
|   // Set up the reader |  | ||||||
|   // archive_read_support_filter_bzip2(ASSET_ARCHIVE); |  | ||||||
|   archive_read_support_format_tar(ASSET.archive); |  | ||||||
|  |  | ||||||
|   // Set the archive reader callbacks |  | ||||||
|   archive_read_set_open_callback(ASSET.archive, &assetArchiveOpen); |  | ||||||
|   archive_read_set_read_callback(ASSET.archive, &assetArchiveRead); |  | ||||||
|   archive_read_set_seek_callback(ASSET.archive, &assetArchiveSeek); |  | ||||||
|   archive_read_set_close_callback(ASSET.archive, &assetArchiveClose); |  | ||||||
|   archive_read_set_callback_data(ASSET.archive, ASSET.buffer);// TODO: Not needed? |  | ||||||
|  |  | ||||||
|   // Open the archive |  | ||||||
|   int32_t ret =  archive_read_open1(ASSET.archive); |  | ||||||
|   assertTrue(ret == ARCHIVE_OK, "Failed to open archive!"); |  | ||||||
|  |  | ||||||
|   // Iterate over each file. |  | ||||||
|   while(archive_read_next_header(ASSET.archive, &ASSET.entry) == ARCHIVE_OK) { |  | ||||||
|     // What file is at this position? |  | ||||||
|     const char_t *headerFile = (char_t*)archive_entry_pathname(ASSET.entry); |  | ||||||
|  |  | ||||||
|     // Compare if this is the file we are looking for, if it is just exit the |  | ||||||
|     // function |  | ||||||
|     if(strcmp(headerFile, ASSET.path) == 0) return; |  | ||||||
|  |  | ||||||
|     // It is not, skip it. |  | ||||||
|     int32_t ret = archive_read_data_skip(ASSET.archive); |  | ||||||
|     assertTrue(ret == ARCHIVE_OK, "Failed to skip data!"); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // If we get here we did not find the find in the archive. |  | ||||||
|   assertUnreachable("Failed to find file!"); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| size_t assetGetSize() { |  | ||||||
|   assertNotNull(ASSET.archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(ASSET.entry, "Entry is NULL!"); |  | ||||||
|   assertTrue(archive_entry_size_is_set(ASSET.entry), "Entry size is not set!"); |  | ||||||
|   return archive_entry_size(ASSET.entry); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| size_t assetRead( |  | ||||||
|   uint8_t *buffer, |  | ||||||
|   const size_t bufferSize |  | ||||||
| ) { |  | ||||||
|   assertNotNull(ASSET.archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(ASSET.entry, "Entry is NULL!"); |  | ||||||
|   assertNotNull(buffer, "Buffer is NULL!"); |  | ||||||
|   assertTrue(bufferSize > 0, "Buffer size must be greater than 0!"); |  | ||||||
|  |  | ||||||
|   ssize_t read = archive_read_data(ASSET.archive, buffer, bufferSize); |  | ||||||
|   if(read == ARCHIVE_FATAL) { |  | ||||||
|     assertUnreachable(archive_error_string(ASSET.archive)); |  | ||||||
|     return -1; |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   assertTrue(read != ARCHIVE_RETRY, "Failed to read data (RETRY)!"); |  | ||||||
|   assertTrue(read != ARCHIVE_WARN, "Failed to read data (WARN)!"); |  | ||||||
|  |  | ||||||
|   return read; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| size_t assetReadUntil( |  | ||||||
|   uint8_t *buffer, |  | ||||||
|   const char_t c, |  | ||||||
|   const size_t maxLength |  | ||||||
| ) { |  | ||||||
|   if(buffer == NULL) { |  | ||||||
|     assertTrue( |  | ||||||
|       maxLength == -1, "If no buffer is provided, maxLength must be -1." |  | ||||||
|     ); |  | ||||||
|     uint8_t tBuffer[1]; |  | ||||||
|     size_t read = 0; |  | ||||||
|     while(assetRead(tBuffer, 1) == 1 && (char_t)tBuffer[0] != c) read++; |  | ||||||
|     return read; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   size_t read = 0; |  | ||||||
|   while(read < maxLength) { |  | ||||||
|     // TODO: Read more than 1 char at a time. |  | ||||||
|     read += assetRead(buffer + read, 1); |  | ||||||
|     if((char_t)buffer[read-1] == c) return read - 1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   return -1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void assetSkip(const size_t length) { |  | ||||||
|   assertNotNull(ASSET.archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(ASSET.entry, "Entry is NULL!"); |  | ||||||
|    |  | ||||||
|   // Asset archive does not support skipping, so we have to read and discard. |  | ||||||
|   uint8_t buffer[ASSET_BUFFER_SIZE]; |  | ||||||
|   size_t remaining = length; |  | ||||||
|   do { |  | ||||||
|     size_t toRead = mathMin(remaining, ASSET_BUFFER_SIZE); |  | ||||||
|     size_t read = assetRead(buffer, toRead); |  | ||||||
|     assertTrue(read == toRead, "Failed to skip data! (overskip?)"); |  | ||||||
|     remaining -= read; |  | ||||||
|   } while(remaining > 0); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void assetClose() { |  | ||||||
|   if(ASSET.archive == NULL) return; |  | ||||||
|  |  | ||||||
|   assertNotNull(ASSET.archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(ASSET.entry, "Entry is NULL!"); |  | ||||||
|    |  | ||||||
|   int32_t ret = archive_read_free(ASSET.archive); |  | ||||||
|   assertTrue(ret == ARCHIVE_OK, "Failed to close archive!"); |  | ||||||
|  |  | ||||||
|   assertNull(ASSET.archive, "Archive is not NULL? Cleanup incorrect."); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void assetDispose() { |  | ||||||
|   assertNull(ASSET.archive, "Asset disposing but asset is currently open?"); |  | ||||||
|   assertNull(ASSET.entry, "Asset disposing but entry is currently open?"); |  | ||||||
|   assertNotNull(ASSET.file, "Asset disposing but file is NULL?"); |  | ||||||
|    |  | ||||||
|   fclose(ASSET.file); |  | ||||||
|   memoryZero(&ASSET, sizeof(asset_t)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Libarchive callbacks |  | ||||||
|  |  | ||||||
| ssize_t assetArchiveRead( |  | ||||||
|   struct archive *archive, |  | ||||||
|   void *data, |  | ||||||
|   const void **buffer |  | ||||||
| ) { |  | ||||||
|   assertNotNull(archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(data, "Data is NULL!"); |  | ||||||
|   assertNotNull(buffer, "Buffer is NULL!"); |  | ||||||
|  |  | ||||||
|   *buffer = data; |  | ||||||
|   size_t read = fread(data, 1, ASSET_BUFFER_SIZE, ASSET.file); |  | ||||||
|   if(ferror(ASSET.file)) return ARCHIVE_FATAL; |  | ||||||
|   return read; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int64_t assetArchiveSeek( |  | ||||||
|   struct archive *archive, |  | ||||||
|   void *data, |  | ||||||
|   int64_t offset, |  | ||||||
|   int32_t whence |  | ||||||
| ) { |  | ||||||
|   assertNotNull(archive, "Archive is NULL!"); |  | ||||||
|   assertNotNull(data, "Data is NULL!"); |  | ||||||
|   assertTrue(offset > 0, "Offset must be greater than 0!"); |  | ||||||
|   assertNotNull(ASSET.file, "File is NULL!"); |  | ||||||
|   int32_t ret = fseek(ASSET.file, offset, whence); |  | ||||||
|   assertTrue(ret == 0, "Failed to seek!"); |  | ||||||
|   return ftell(ASSET.file); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int32_t assetArchiveOpen(struct archive *a, void *data) { |  | ||||||
|   int32_t ret = fseek(ASSET.file, 0, SEEK_SET); |  | ||||||
|   assertTrue(ret == 0, "Failed to seek to start of file!"); |  | ||||||
|   return ARCHIVE_OK; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int32_t assetArchiveClose(struct archive *a, void *data) { |  | ||||||
|   assertNotNull(ASSET.file, "File is NULL!"); |  | ||||||
|    |  | ||||||
|   ASSET.archive = NULL; |  | ||||||
|   ASSET.entry = NULL; |  | ||||||
|  |  | ||||||
|   return ARCHIVE_OK; |  | ||||||
| } |  | ||||||
| @@ -1,137 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
| #include <archive.h> |  | ||||||
| #include <archive_entry.h> |  | ||||||
|  |  | ||||||
| #define ASSET_BUFFER_SIZE 32768 |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   FILE *file; |  | ||||||
|   struct archive *archive; |  | ||||||
|   struct archive_entry *entry; |  | ||||||
|   uint8_t buffer[ASSET_BUFFER_SIZE]; |  | ||||||
|  |  | ||||||
|   // ? |  | ||||||
|   char_t path[FILENAME_MAX]; |  | ||||||
| } asset_t; |  | ||||||
|  |  | ||||||
| extern asset_t ASSET; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the asset manager. |  | ||||||
|  */ |  | ||||||
| void assetInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Opens an asset by its filename (within the asset archive). Asset paths should |  | ||||||
|  * always use the unix forward slash '/' as a path separator. |  | ||||||
|  *  |  | ||||||
|  * @param path The path to the asset within the archive. |  | ||||||
|  */ |  | ||||||
| void assetOpen(const char *path); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Returns the size of the asset. |  | ||||||
|  *  |  | ||||||
|  * @return The size of the asset. |  | ||||||
|  */ |  | ||||||
| size_t assetGetSize(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Reads the asset into the buffer. |  | ||||||
|  *  |  | ||||||
|  * @param buffer The buffer to read the asset into. |  | ||||||
|  * @param bufferSize The size of the buffer. |  | ||||||
|  * @return The amount of data read. |  | ||||||
|  */ |  | ||||||
| size_t assetRead(uint8_t *buffer, const size_t bufferSize); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Reads ahead in the buffer until either the end of the buffer, or the |  | ||||||
|  * specified character is found. Return value will be -1 if the character was |  | ||||||
|  * not found. |  | ||||||
|  *  |  | ||||||
|  * Buffer can be NULL if you just want to skip ahead. |  | ||||||
|  *  |  | ||||||
|  * Returned value will be either the amount of data read into the buffer, which |  | ||||||
|  * excludes the extra 1 character that was read from the asset. If the character |  | ||||||
|  * was not found, -1 will be returned. |  | ||||||
|  *  |  | ||||||
|  * @param buffer Buffer to read into. |  | ||||||
|  * @param c Character to read until. |  | ||||||
|  * @param maxLength Maximum length to read. |  | ||||||
|  * @return -1 if the character was not found, otherwise the amount of data read. |  | ||||||
|  */ |  | ||||||
| size_t assetReadUntil(uint8_t *buffer, const char c, const size_t maxLength); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Skips ahead in the buffer by the specified length. |  | ||||||
|  *  |  | ||||||
|  * @param length The length to skip ahead by. |  | ||||||
|  */ |  | ||||||
| void assetSkip(const size_t length); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Closes the asset. |  | ||||||
|  */ |  | ||||||
| void assetClose(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys and cleans up the asset manager. |  | ||||||
|  */ |  | ||||||
| void assetDispose(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Internal read method provided to libarchive api. |  | ||||||
|  *  |  | ||||||
|  * @param archive The archive to read from. |  | ||||||
|  * @param data The data to read into. |  | ||||||
|  * @param buffer The buffer to read from. |  | ||||||
|  * @return The amount of data read. |  | ||||||
|  */ |  | ||||||
| ssize_t assetArchiveRead( |  | ||||||
|   struct archive *archive, |  | ||||||
|   void *data, |  | ||||||
|   const void **buffer |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Internal seek method provided to libarchive api. |  | ||||||
|  *  |  | ||||||
|  * @param archive The archive to seek in. |  | ||||||
|  * @param data The data to seek in. |  | ||||||
|  * @param offset Offset bytes to seek. |  | ||||||
|  * @param whence Relative to whence to seek. |  | ||||||
|  * @return The new position. |  | ||||||
|  */ |  | ||||||
| int64_t assetArchiveSeek( |  | ||||||
|   struct archive *archive, |  | ||||||
|   void *data, |  | ||||||
|   int64_t offset, |  | ||||||
|   int32_t whence |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Internal open method provided to libarchive api. |  | ||||||
|  *  |  | ||||||
|  * @param archive The archive to open. |  | ||||||
|  * @param data The data to open. |  | ||||||
|  * @return The result of the open. |  | ||||||
|  */ |  | ||||||
| int32_t assetArchiveOpen(struct archive *a, void *data); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Internal close method provided to libarchive api. |  | ||||||
|  *  |  | ||||||
|  * @param archive The archive to close. |  | ||||||
|  * @param data The data to close. |  | ||||||
|  * @return The result of the close. |  | ||||||
|  */ |  | ||||||
| int32_t assetArchiveClose(struct archive *a, void *data); |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     render.c |  | ||||||
|     quad.c |  | ||||||
|     texture.c |  | ||||||
|     tilesetgl.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| add_subdirectory(shader) |  | ||||||
| @@ -1,130 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "framebuffer.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "display/window.h" |  | ||||||
|  |  | ||||||
| framebuffer_t FRAMEBUFFER; |  | ||||||
|  |  | ||||||
| void frameBufferInit(const int32_t width, const int32_t height) { |  | ||||||
|   assertTrue(width > 0, "Width must be greater than 0"); |  | ||||||
|   assertTrue(height > 0, "Height must be greater than 0"); |  | ||||||
|  |  | ||||||
|   FRAMEBUFFER.id = -1; |  | ||||||
|   FRAMEBUFFER.width = -1; |  | ||||||
|   FRAMEBUFFER.height = -1; |  | ||||||
|   FRAMEBUFFER.texture = -1; |  | ||||||
|  |  | ||||||
|   frameBufferSetSize(width, height); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void frameBufferSetSize(const int32_t width, const int32_t height) { |  | ||||||
|   assertTrue(width > 0, "Width must be greater than 0"); |  | ||||||
|   assertTrue(height > 0, "Height must be greater than 0"); |  | ||||||
|  |  | ||||||
|   if(FRAMEBUFFER.width == width && FRAMEBUFFER.height == height) return; |  | ||||||
|  |  | ||||||
|   FRAMEBUFFER.width = width; |  | ||||||
|   FRAMEBUFFER.height = height; |  | ||||||
|  |  | ||||||
|   frameBufferUnbind(); |  | ||||||
|  |  | ||||||
|   // Delete old texture and depth buffer |  | ||||||
|   if(FRAMEBUFFER.texture != -1) { |  | ||||||
|     glDeleteTextures(1, &FRAMEBUFFER.texture); |  | ||||||
|     assertNoGLError(); |  | ||||||
|     FRAMEBUFFER.texture = -1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if(FRAMEBUFFER.id != -1) { |  | ||||||
|     glDeleteFramebuffers(1, &FRAMEBUFFER.id); |  | ||||||
|     assertNoGLError(); |  | ||||||
|     FRAMEBUFFER.id = -1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Generate framebuffer |  | ||||||
|   glGenFramebuffers(1, &FRAMEBUFFER.id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glBindFramebuffer(GL_FRAMEBUFFER, FRAMEBUFFER.id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Create new texture |  | ||||||
|   glGenTextures(1, &FRAMEBUFFER.texture); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glBindTexture(GL_TEXTURE_2D, FRAMEBUFFER.texture); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FRAMEBUFFER.texture, 0); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Check framebuffer completeness |  | ||||||
|   GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   assertTrue(status == GL_FRAMEBUFFER_COMPLETE, "Framebuffer is not complete"); |  | ||||||
|  |  | ||||||
|   glBindFramebuffer(GL_FRAMEBUFFER, 0); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void frameBufferBind() { |  | ||||||
|   if(FRAMEBUFFER.id == -1) return; |  | ||||||
|  |  | ||||||
|   glBindFramebuffer(GL_FRAMEBUFFER, FRAMEBUFFER.id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glViewport(0, 0, FRAMEBUFFER.width, FRAMEBUFFER.height); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void frameBufferTextureBind(const GLuint slot) { |  | ||||||
|   if(FRAMEBUFFER.texture == -1) return; |  | ||||||
|  |  | ||||||
|   glActiveTexture(GL_TEXTURE0 + slot); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindTexture(GL_TEXTURE_2D, FRAMEBUFFER.texture); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void frameBufferUnbind() { |  | ||||||
|   glBindFramebuffer(GL_FRAMEBUFFER, 0); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glClearColor(0.05f, 0.05f, 0.05f, 1.0f); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void frameBufferDispose() { |  | ||||||
|   glDeleteFramebuffers(1, &FRAMEBUFFER.id); |  | ||||||
|   glDeleteTextures(1, &FRAMEBUFFER.texture); |  | ||||||
|  |  | ||||||
|   FRAMEBUFFER.id = -1; |  | ||||||
|   FRAMEBUFFER.texture = -1; |  | ||||||
| } |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   GLuint id; |  | ||||||
|   GLuint texture; |  | ||||||
|   int width; |  | ||||||
|   int height; |  | ||||||
| } framebuffer_t; |  | ||||||
|  |  | ||||||
| extern framebuffer_t FRAMEBUFFER; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the framebuffer. |  | ||||||
|  *  |  | ||||||
|  * @param width The width of the framebuffer. |  | ||||||
|  * @param height The height of the framebuffer. |  | ||||||
|  */ |  | ||||||
| void frameBufferInit(const int32_t width, const int32_t height); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Sets the size of the framebuffer. |  | ||||||
|  *  |  | ||||||
|  * @param width The width of the framebuffer. |  | ||||||
|  * @param height The height of the framebuffer. |  | ||||||
|  */ |  | ||||||
| void frameBufferSetSize(const int32_t width, const int32_t height); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds the framebuffer. |  | ||||||
|  */ |  | ||||||
| void frameBufferBind(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Unbinds the framebuffer. |  | ||||||
|  */ |  | ||||||
| void frameBufferUnbind(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds the framebuffer texture to a slot. |  | ||||||
|  *  |  | ||||||
|  * @param slot The slot to bind the texture to. |  | ||||||
|  */ |  | ||||||
| void frameBufferTextureBind(const GLuint slot); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Unbinds the framebuffer. |  | ||||||
|  */ |  | ||||||
| void frameBufferDispose(); |  | ||||||
| @@ -1,108 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "quad.h" |  | ||||||
|  |  | ||||||
| duskquad_t QUAD; |  | ||||||
|  |  | ||||||
| void quadInit() { |  | ||||||
|   // Create the single quad. |  | ||||||
|   const float quadPositions[] = { |  | ||||||
|     0.0f, 0.0f, 0.0f,  // Bottom-left corner |  | ||||||
|     1.0f, 0.0f, 0.0f,  // Bottom-right corner |  | ||||||
|     1.0f, 1.0f, 0.0f,  // Top-right corner |  | ||||||
|     0.0f, 1.0f, 0.0f   // Top-left corner |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const float quadUVs[] = { |  | ||||||
|     0.0f, 0.0f, |  | ||||||
|     1.0f, 0.0f, |  | ||||||
|     1.0f, 1.0f, |  | ||||||
|     0.0f, 1.0f |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   const uint32_t quadIndices[] = { |  | ||||||
|     0, 1, 2, |  | ||||||
|     2, 3, 0, |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   glGenVertexArrays(1, &QUAD.quadVAO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindVertexArray(QUAD.quadVAO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Positions |  | ||||||
|   glGenBuffers(1, &QUAD.quadVBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|    |  | ||||||
|   glBindBuffer(GL_ARRAY_BUFFER, QUAD.quadVBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|      |  | ||||||
|   glBufferData( |  | ||||||
|     GL_ARRAY_BUFFER, sizeof(quadPositions), quadPositions, GL_STATIC_DRAW |  | ||||||
|   ); |  | ||||||
|   assertNoGLError(); |  | ||||||
|    |  | ||||||
|   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glEnableVertexAttribArray(0); |  | ||||||
|   assertNoGLError(); |  | ||||||
|    |  | ||||||
|   // UVs |  | ||||||
|   glGenBuffers(1, &QUAD.quadUVVBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindBuffer(GL_ARRAY_BUFFER, QUAD.quadUVVBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBufferData(GL_ARRAY_BUFFER, sizeof(quadUVs), quadUVs, GL_STATIC_DRAW); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glEnableVertexAttribArray(1); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Indices |  | ||||||
|   glGenBuffers(1, &QUAD.quadEBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, QUAD.quadEBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBufferData( |  | ||||||
|     GL_ELEMENT_ARRAY_BUFFER, sizeof(quadIndices), quadIndices, GL_STATIC_DRAW |  | ||||||
|   ); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void quadRender(const int32_t count) { |  | ||||||
|   glBindVertexArray(QUAD.quadVAO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glDrawElementsInstanced( |  | ||||||
|     GL_TRIANGLES, 6, |  | ||||||
|     GL_UNSIGNED_INT, 0, |  | ||||||
|     count |  | ||||||
|   ); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void quadDispose() { |  | ||||||
|   glDeleteBuffers(1, &QUAD.quadVBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glDeleteBuffers(1, &QUAD.quadEBO); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glDeleteVertexArrays(1, &QUAD.quadVAO); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   GLuint quadVBO; |  | ||||||
|   GLuint quadUVVBO; |  | ||||||
|   GLuint quadVAO; |  | ||||||
|   GLuint quadEBO; |  | ||||||
| } duskquad_t; |  | ||||||
|  |  | ||||||
| extern duskquad_t QUAD; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the quad. |  | ||||||
|  */ |  | ||||||
| void quadInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Renders quads. |  | ||||||
|  *  |  | ||||||
|  * @param count The number of quads to render. |  | ||||||
|  */ |  | ||||||
| void quadRender(const int32_t count); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of the quad. |  | ||||||
|  */ |  | ||||||
| void quadDispose(); |  | ||||||
| @@ -1,52 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
| #include "render.h" |  | ||||||
| #include "display/scene.h" |  | ||||||
| #include "display/shader/shadermanager.h" |  | ||||||
| #include "display/quad.h" |  | ||||||
| #include "display/window.h" |  | ||||||
| #include "display/tilesetgl.h" |  | ||||||
|  |  | ||||||
| render_t RENDER; |  | ||||||
|  |  | ||||||
| void renderInit() { |  | ||||||
|   memoryZero(&RENDER, sizeof(render_t)); |  | ||||||
|    |  | ||||||
|   glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glEnable(GL_BLEND); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   shaderManagerInit(); |  | ||||||
|   quadInit(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void renderUpdate() { |  | ||||||
|   glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Update rendering data |  | ||||||
|   shaderManagerUpdate(); |  | ||||||
|   tilesetGLBind(); |  | ||||||
|    |  | ||||||
|   // Hand off to the scene to do its rendering. |  | ||||||
|   sceneRender(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void renderDispose() { |  | ||||||
|   quadDispose(); |  | ||||||
|   shaderManagerDispose(); |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   int32_t nothing; |  | ||||||
| } render_t; |  | ||||||
|  |  | ||||||
| extern render_t RENDER; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the render system. |  | ||||||
|  */ |  | ||||||
| void renderInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the render system. |  | ||||||
|  */ |  | ||||||
| void renderUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Renders the overworld scene. |  | ||||||
|  */ |  | ||||||
| void renderOverworld(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of the render system. |  | ||||||
|  */ |  | ||||||
| void renderDispose(); |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     shadermanager.c |  | ||||||
|     shader.c |  | ||||||
|     shaderbuffer.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| add_subdirectory(data) |  | ||||||
| add_subdirectory(entityshader) |  | ||||||
| add_subdirectory(mapshader) |  | ||||||
| add_subdirectory(fragments) |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     transforms.c |  | ||||||
|     entities.c |  | ||||||
|     mapshaderdata.c |  | ||||||
|     tilesetshaderdata.c |  | ||||||
| ) |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "entities.h" |  | ||||||
| #include "overworld/overworld.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
|  |  | ||||||
| shaderbuffer_t ENTITIES_BUFFER; |  | ||||||
| entitiesdata_t ENTITIES_DATA; |  | ||||||
|  |  | ||||||
| void entitiesInit() { |  | ||||||
|   memoryZero(&ENTITIES_DATA, sizeof(entitiesdata_t)); |  | ||||||
|   shaderBufferInit(&ENTITIES_BUFFER, sizeof(entitiesdata_t)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void entitiesUpdate() { |  | ||||||
|   for(uint8_t i = 0; i < OVERWORLD.entityCount; i++) { |  | ||||||
|     // Pack the entity data into the buffer |  | ||||||
|     entity_t *src = &OVERWORLD.entities[i]; |  | ||||||
|     entitiesdataent_t *dst = &ENTITIES_DATA.entities[i]; |  | ||||||
|  |  | ||||||
|     // Copy position data. |  | ||||||
|     memoryCopyRangeSafe( |  | ||||||
|       &dst->position, |  | ||||||
|       &src->x, |  | ||||||
|       &src->frame + sizeof(uint8_t), |  | ||||||
|       sizeof(uint8_t) * 5 |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   shaderBufferBind(&ENTITIES_BUFFER); |  | ||||||
|   shaderBufferSetData(&ENTITIES_BUFFER, &ENTITIES_DATA); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void entitiesDispose() { |  | ||||||
|   shaderBufferDispose(&ENTITIES_BUFFER); |  | ||||||
| } |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../../../../dusk/overworld/overworlddefs.h" |  | ||||||
| #include "../fragments/packed.glsl" |  | ||||||
| #include "../fragments/quad.glsl" |  | ||||||
| #include "../data/tilesets.glsl" |  | ||||||
|  |  | ||||||
| struct Entity { |  | ||||||
|   uvec4 position; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| layout(std140) uniform b_Entities { |  | ||||||
|   Entity entities[OVERWORLD_ENTITY_COUNT_MAX]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| vec2 entityGetSize() { |  | ||||||
|   return vec2(float(OVERWORLD_ENTITY_WIDTH), float(OVERWORLD_ENTITY_HEIGHT)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 entityGetVertice(uint instanceIndex, uint indiceIndex) { |  | ||||||
|   // Get base quad vertice |  | ||||||
|   vec2 vert = quadGetVertice(indiceIndex); |  | ||||||
|  |  | ||||||
|   uint x = packedGetU8(0u, entities[instanceIndex].position); |  | ||||||
|   uint y = packedGetU8(1u, entities[instanceIndex].position); |  | ||||||
|   int subX = packedGetI8(2u, entities[instanceIndex].position); |  | ||||||
|   int subY = packedGetI8(3u, entities[instanceIndex].position); |  | ||||||
|  |  | ||||||
|   vert.x += float(x); |  | ||||||
|   vert.y += float(y); |  | ||||||
|  |  | ||||||
|   vert *= entityGetSize(); |  | ||||||
|  |  | ||||||
|   vert.x += float(subX); |  | ||||||
|   vert.y += float(subY); |  | ||||||
|  |  | ||||||
|   return vert; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 entityGetUV(uint instanceIndex, uint indiceIndex) { |  | ||||||
|   uint frame = packedGetU8(4u, entities[instanceIndex].position); |  | ||||||
|   vec4 tilesetUVs = tilesetGetUVsByIndex(uint(TILESET_SLOT_ENTITIES), frame); |  | ||||||
|   vec2 uv = quadGetTextureCoordinate(indiceIndex, tilesetUVs); |  | ||||||
|   return uv; |  | ||||||
| } |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "display/shader/shaderbuffer.h" |  | ||||||
| #include "overworld/overworld.h" |  | ||||||
|  |  | ||||||
| #define ENTITIES_BLOCK_NAME "b_Entities" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   uvec4_t position; |  | ||||||
| } entitiesdataent_t; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   entitiesdataent_t entities[OVERWORLD_ENTITY_COUNT_MAX]; |  | ||||||
| } entitiesdata_t; |  | ||||||
|  |  | ||||||
| extern shaderbuffer_t ENTITIES_BUFFER; |  | ||||||
| extern entitiesdata_t ENTITIES_DATA; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the entities buffer and data. |  | ||||||
|  */ |  | ||||||
| void entitiesInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the entities buffer with the current data. |  | ||||||
|  */ |  | ||||||
| void entitiesUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys the entities buffer. |  | ||||||
|  */ |  | ||||||
| void entitiesDispose(); |  | ||||||
| @@ -1,48 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../../../../dusk/overworld/overworlddefs.h" |  | ||||||
| #include "../fragments/packed.glsl" |  | ||||||
| #include "../fragments/quad.glsl" |  | ||||||
|  |  | ||||||
| #define MAP_TILE_PACKED_SIZE 16 |  | ||||||
|  |  | ||||||
| layout(std140) uniform b_Map { |  | ||||||
|   uvec4 mapTileIds[OVERWORLD_TILE_COUNT_MAX / MAP_TILE_PACKED_SIZE]; |  | ||||||
|   uvec4 mapSize; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| vec2 mapTileGetSize() { |  | ||||||
|   return vec2(float(OVERWORLD_TILE_WIDTH), float(OVERWORLD_TILE_HEIGHT)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 mapGetVertice(uint instanceIndex, uint indiceIndex) { |  | ||||||
|   vec2 quad = quadGetVertice(indiceIndex); |  | ||||||
|  |  | ||||||
|   uint mapWidth = packedGetU8(0u, mapSize); |  | ||||||
|   uint mapHeight = packedGetU8(1u, mapSize); |  | ||||||
|   uint mapLayerCount = packedGetU8(2u, mapSize); |  | ||||||
|  |  | ||||||
|   // Get x and y within layer |  | ||||||
|   uint x = instanceIndex % mapWidth; |  | ||||||
|   uint y = (instanceIndex / mapWidth) % mapHeight; |  | ||||||
|  |  | ||||||
|   // Get quad position, consider layer count |  | ||||||
|   quad += vec2(x, y); |  | ||||||
|   quad *= mapTileGetSize(); |  | ||||||
|  |  | ||||||
|   return quad; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint mapGetLayer(uint instanceIndex) { |  | ||||||
|   uint mapWidth = packedGetU8(0u, mapSize); |  | ||||||
|   uint mapHeight = packedGetU8(1u, mapSize); |  | ||||||
|   return instanceIndex / (mapWidth * mapHeight); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint mapGetTileId(uint instanceIndex) { |  | ||||||
|   uvec4 v4 = mapTileIds[packedArrayGetU8IndexFromUVEC4Array(instanceIndex)]; |  | ||||||
|   return packedArrayGetU8FromUVEC4ArrayValue(instanceIndex, v4); |  | ||||||
| } |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "mapshaderdata.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
|  |  | ||||||
| shaderbuffer_t MAP_SHADER_DATA_BUFFER; |  | ||||||
| mapshaderdata_t MAP_SHADER_DATA_DATA; |  | ||||||
|  |  | ||||||
| void mapShaderDataInit() { |  | ||||||
|   memoryZero(&MAP_SHADER_DATA_DATA, sizeof(mapshaderdata_t)); |  | ||||||
|   shaderBufferInit(&MAP_SHADER_DATA_BUFFER, sizeof(mapshaderdata_t)); |  | ||||||
|  |  | ||||||
|   assertTrue( |  | ||||||
|     sizeof(MAP_SHADER_DATA_DATA.tileIds) == sizeof(OVERWORLD.map.tileIds), |  | ||||||
|     "Map shader tile data and Overworld tile data are not the same size." |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void mapShaderDataUpdate() { |  | ||||||
|   // Copy tile ids. |  | ||||||
|   memoryCopyRangeSafe( |  | ||||||
|     MAP_SHADER_DATA_DATA.tileIds, |  | ||||||
|     OVERWORLD.map.tileIds, |  | ||||||
|     &OVERWORLD.map.tileIds[ |  | ||||||
|       OVERWORLD.map.width * OVERWORLD.map.height * OVERWORLD.map.layerCount |  | ||||||
|     ], |  | ||||||
|     sizeof(MAP_SHADER_DATA_DATA.tileIds) |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Copy map size. |  | ||||||
|   memoryCopyRangeSafe( |  | ||||||
|     &MAP_SHADER_DATA_DATA.mapSize, |  | ||||||
|     &OVERWORLD.map.width, |  | ||||||
|     &OVERWORLD.map.layerCount + sizeof(uint8_t), |  | ||||||
|     sizeof(uint8_t) * 3 |  | ||||||
|   ); |  | ||||||
|    |  | ||||||
|   shaderBufferBind(&MAP_SHADER_DATA_BUFFER); |  | ||||||
|   shaderBufferSetData(&MAP_SHADER_DATA_BUFFER, &MAP_SHADER_DATA_DATA); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void mapShaderDataDispose() { |  | ||||||
|   shaderBufferDispose(&MAP_SHADER_DATA_BUFFER); |  | ||||||
| } |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma ocne |  | ||||||
| #include "display/shader/shaderbuffer.h" |  | ||||||
| #include "overworld/overworld.h" |  | ||||||
|  |  | ||||||
| #define MAP_BLOCK_NAME "b_Map" |  | ||||||
| #define MAP_TILE_PACK_SIZE sizeof(uvec4_t) / sizeof(tileid_t) |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   uvec4_t tileIds[OVERWORLD_TILE_COUNT_MAX / MAP_TILE_PACK_SIZE]; |  | ||||||
|   uvec4_t mapSize; |  | ||||||
| } mapshaderdata_t; |  | ||||||
|  |  | ||||||
| extern shaderbuffer_t MAP_SHADER_DATA_BUFFER; |  | ||||||
| extern mapshaderdata_t MAP_SHADER_DATA_DATA; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the map buffer and data. |  | ||||||
|  */ |  | ||||||
| void mapShaderDataInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the map buffer with the current data. |  | ||||||
|  */ |  | ||||||
| void mapShaderDataUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys the map buffer. |  | ||||||
|  */ |  | ||||||
| void mapShaderDataDispose(); |  | ||||||
| @@ -1,64 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../../../../dusk/display/tilesetdefs.h" |  | ||||||
| #include "../fragments/packed.glsl" |  | ||||||
|  |  | ||||||
| struct Tileset { |  | ||||||
|   uvec4 tileset; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| layout(std140) uniform b_Tilesets { |  | ||||||
|   Tileset tilesets[TILESET_SLOT_COUNT]; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| uniform sampler2D u_TilesetTextures[TILESET_SLOT_COUNT]; |  | ||||||
|  |  | ||||||
| uint tilesetGetColumns(uint tilesetIndex) { |  | ||||||
|   return packedGetU32(0u, tilesets[tilesetIndex].tileset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint tilesetGetRows(uint tilesetIndex) { |  | ||||||
|   return packedGetU32(1u, tilesets[tilesetIndex].tileset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint tilesetGetWidth(uint tilesetIndex) { |  | ||||||
|   return packedGetU32(2u, tilesets[tilesetIndex].tileset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint tilesetGetHeight(uint tilesetIndex) { |  | ||||||
|   return packedGetU32(3u, tilesets[tilesetIndex].tileset); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec4 tilesetGetUVs(uint tilesetIndex, uint col, uint row) { |  | ||||||
|   Tileset tileset = tilesets[tilesetIndex]; |  | ||||||
|   float segWidth = 1.0 / float(tilesetGetColumns(tilesetIndex)); |  | ||||||
|   float segHeight = 1.0 / float(tilesetGetRows(tilesetIndex)); |  | ||||||
|   float x = float(col) * segWidth; |  | ||||||
|   float y = float(row) * segHeight; |  | ||||||
|   return vec4(x, y, x + segWidth, y + segHeight); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec4 tilesetGetUVsByIndex(uint tilesetIndex, uint index) { |  | ||||||
|   Tileset tileset = tilesets[tilesetIndex]; |  | ||||||
|   uint col = index % tilesetGetColumns(tilesetIndex); |  | ||||||
|   uint row = index / tilesetGetColumns(tilesetIndex); |  | ||||||
|   return tilesetGetUVs(tilesetIndex, col, row); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec4 tilesetGetColor(uint tilesetIndex, vec2 coord) { |  | ||||||
|   switch(tilesetIndex) { |  | ||||||
|     case 0u: |  | ||||||
|       return texture(u_TilesetTextures[0], coord); |  | ||||||
|     case 1u: |  | ||||||
|       return texture(u_TilesetTextures[1], coord); |  | ||||||
|     case 2u: |  | ||||||
|       return texture(u_TilesetTextures[2], coord); |  | ||||||
|     case 3u: |  | ||||||
|       return texture(u_TilesetTextures[3], coord); |  | ||||||
|     default: |  | ||||||
|       return vec4(1, 1, 1, 1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "tilesetshaderdata.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
| #include "display/shader/shader.h" |  | ||||||
|  |  | ||||||
| shaderbuffer_t TILESET_SHADER_DATA_BUFFER; |  | ||||||
| tilesetshaderdata_t TILESET_SHADER_DATA_DATA; |  | ||||||
| GLuint TILESET_SHADER_DATA_TEXTURES[TILESET_SLOT_COUNT]; |  | ||||||
|  |  | ||||||
| void tilesetShaderDataInit() { |  | ||||||
|   memoryZero(&TILESET_SHADER_DATA_DATA, sizeof(tilesetshaderdata_t)); |  | ||||||
|   shaderBufferInit(&TILESET_SHADER_DATA_BUFFER, sizeof(tilesetshaderdata_t)); |  | ||||||
|  |  | ||||||
|   assertTrue( |  | ||||||
|     sizeof(tilesetshaderdata_t) == sizeof(uvec4_t) * TILESET_SLOT_COUNT, |  | ||||||
|     "Tileset Shader Data size mismatch" |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   uint8_t i = 0; |  | ||||||
|   do { |  | ||||||
|     TILESET_SHADER_DATA_TEXTURES[i] = i; |  | ||||||
|   } while(++i < TILESET_SLOT_COUNT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void tilesetShaderDataUpdate() { |  | ||||||
|   uint8_t i = 0; |  | ||||||
|   do { |  | ||||||
|     tilesetid_t id = TILESET_SLOTS[i]; |  | ||||||
|     if(id == TILESET_NULL) continue; |  | ||||||
|     tileset_t *tileset = &TILESETS[id]; |  | ||||||
|     texture_t *texture = &TILESET_GL_TEXTURES[i]; |  | ||||||
|     tilesetshaderdatatileset_t *dest = &TILESET_SHADER_DATA_DATA.tilesets[i]; |  | ||||||
|  |  | ||||||
|     dest->columns = tileset->columns; |  | ||||||
|     dest->rows = tileset->rows; |  | ||||||
|     dest->width = texture->width; |  | ||||||
|     dest->height = texture->height; |  | ||||||
|   } while(++i < TILESET_SLOT_COUNT); |  | ||||||
|  |  | ||||||
|   shaderBufferBind(&TILESET_SHADER_DATA_BUFFER); |  | ||||||
|   shaderBufferSetData(&TILESET_SHADER_DATA_BUFFER, &TILESET_SHADER_DATA_DATA); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void tilesetShaderTexturesBind(const GLuint uniform) { |  | ||||||
|   shaderSetTextures(uniform, TILESET_SHADER_DATA_TEXTURES, TILESET_SLOT_COUNT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void tilesetShaderDataDispose() { |  | ||||||
|   shaderBufferDispose(&TILESET_SHADER_DATA_BUFFER); |  | ||||||
| } |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "display/shader/shaderbuffer.h" |  | ||||||
| #include "display/tilesetgl.h" |  | ||||||
|  |  | ||||||
| #define TILESET_SHADER_DATA_BLOCK_NAME "b_Tilesets" |  | ||||||
| #define TILESET_UNIFORM_TEXTURES_NAME "u_TilesetTextures" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   uint32_t columns; |  | ||||||
|   uint32_t rows; |  | ||||||
|   uint32_t width; |  | ||||||
|   uint32_t height; |  | ||||||
| } tilesetshaderdatatileset_t; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   tilesetshaderdatatileset_t tilesets[TILESET_SLOT_COUNT]; |  | ||||||
| } tilesetshaderdata_t; |  | ||||||
|  |  | ||||||
| extern shaderbuffer_t TILESET_SHADER_DATA_BUFFER; |  | ||||||
| extern tilesetshaderdata_t TILESET_SHADER_DATA_DATA; |  | ||||||
| extern GLuint TILESET_SHADER_DATA_TEXTURES[]; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the tileset buffer and data. |  | ||||||
|  */ |  | ||||||
| void tilesetShaderDataInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the tileset buffer with the current data. |  | ||||||
|  */ |  | ||||||
| void tilesetShaderDataUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds the tileset textures to the given uniform. |  | ||||||
|  *  |  | ||||||
|  * @param uniform The uniform to bind the textures to. |  | ||||||
|  */ |  | ||||||
| void tilesetShaderTexturesBind(const GLuint uniform); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys the tileset buffer. |  | ||||||
|  */ |  | ||||||
| void tilesetShaderDataDispose(); |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "transforms.h" |  | ||||||
| #include "display/window.h" |  | ||||||
|  |  | ||||||
| shaderbuffer_t TRANSFORMS_BUFFER; |  | ||||||
| transformsdata_t TRANSFORMS_DATA; |  | ||||||
|  |  | ||||||
| void transformsInit() { |  | ||||||
|   memset(&TRANSFORMS_DATA, 0, sizeof(transformsdata_t)); |  | ||||||
|   shaderBufferInit(&TRANSFORMS_BUFFER, sizeof(transformsdata_t)); |  | ||||||
|  |  | ||||||
|   glm_mat4_identity(TRANSFORMS_DATA.projection); |  | ||||||
|   glm_mat4_identity(TRANSFORMS_DATA.view); |  | ||||||
|  |  | ||||||
|   TRANSFORMS_DATA.resolution[0] = WINDOW_WIDTH; |  | ||||||
|   TRANSFORMS_DATA.resolution[1] = WINDOW_HEIGHT; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void transformsUpdate() { |  | ||||||
|   TRANSFORMS_DATA.resolution[0] = WINDOW_WIDTH; |  | ||||||
|   TRANSFORMS_DATA.resolution[1] = WINDOW_HEIGHT; |  | ||||||
|  |  | ||||||
|   glm_perspective( |  | ||||||
|     glm_rad(45.0f), |  | ||||||
|     TRANSFORMS_DATA.resolution[0] / TRANSFORMS_DATA.resolution[1], |  | ||||||
|     0.5f, |  | ||||||
|     1000.0f, |  | ||||||
|     TRANSFORMS_DATA.projection |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   glm_lookat( |  | ||||||
|     (vec3){ 0, 0, 300 }, |  | ||||||
|     (vec3){ 0, 32, 0 }, |  | ||||||
|     (vec3){ 0, 1, 0 }, |  | ||||||
|     TRANSFORMS_DATA.view |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   shaderBufferBind(&TRANSFORMS_BUFFER); |  | ||||||
|   shaderBufferSetData(&TRANSFORMS_BUFFER, &TRANSFORMS_DATA); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void transformsDispose() { |  | ||||||
|   shaderBufferDispose(&TRANSFORMS_BUFFER); |  | ||||||
| } |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../../../../dusk/display/displaydefs.h" |  | ||||||
|  |  | ||||||
| struct Transform { |  | ||||||
|   mat4 projection; |  | ||||||
|   mat4 view; |  | ||||||
|   vec2 resolution; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| layout(std140) uniform b_Transforms { |  | ||||||
|   Transform transforms; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| vec2 transformDisplayGetSize() { |  | ||||||
|   return vec2(SCREEN_WIDTH, SCREEN_HEIGHT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float transformDisplayGetAspectRatio() { |  | ||||||
|   return (float(SCREEN_WIDTH) / float(SCREEN_HEIGHT)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 transformResolutionGetSize() { |  | ||||||
|   return transforms.resolution; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| float transformResolutionGetAspectRatio() { |  | ||||||
|   return (transforms.resolution.x / transforms.resolution.y); |  | ||||||
| } |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "display/shader/shaderbuffer.h" |  | ||||||
|  |  | ||||||
| #define TRANSFORMS_BLOCK_NAME "b_Transforms" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   mat4 projection; |  | ||||||
|   mat4 view; |  | ||||||
|   vec2 resolution; |  | ||||||
| } transformsdata_t; |  | ||||||
|  |  | ||||||
| extern shaderbuffer_t TRANSFORMS_BUFFER; |  | ||||||
| extern transformsdata_t TRANSFORMS_DATA; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the transforms buffer and data. |  | ||||||
|  */ |  | ||||||
| void transformsInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the transforms buffer with the current data. |  | ||||||
|  */ |  | ||||||
| void transformsUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys the transforms buffer. |  | ||||||
|  */ |  | ||||||
| void transformsDispose(); |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Shaders |  | ||||||
| glsltool(entity_vert.glsl) |  | ||||||
| glsltool(entity_frag.glsl) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     entityshader.c |  | ||||||
| ) |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../fragments/header.glsl" |  | ||||||
| #include "../data/entities.glsl" |  | ||||||
| #include "../data/tilesets.glsl" |  | ||||||
|  |  | ||||||
| // Inputs from vertex shader |  | ||||||
| in vec2 v_TextureCoord; |  | ||||||
|  |  | ||||||
| // Frag pixel color |  | ||||||
| out vec4 FragColor; |  | ||||||
|  |  | ||||||
| void main() { |  | ||||||
|   vec4 tColor = tilesetGetColor(uint(TILESET_SLOT_ENTITIES), v_TextureCoord); |  | ||||||
|   if(tColor.a == 0.0) discard; |  | ||||||
|   if(tColor.r == 0.0) discard; |  | ||||||
|   FragColor = vec4(1, 1, 1, 1) * tColor; |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../fragments/header.glsl" |  | ||||||
| #include "../data/transforms.glsl" |  | ||||||
| #include "../data/entities.glsl" |  | ||||||
|  |  | ||||||
| // Outputs to fragment shader |  | ||||||
| out vec2 v_TextureCoord; |  | ||||||
|  |  | ||||||
| void main() { |  | ||||||
|   uint instanceIndex = uint(gl_InstanceID); |  | ||||||
|   uint indiceIndex = quadGetIndiceIndex(gl_VertexID); |  | ||||||
|  |  | ||||||
|   vec2 vert = entityGetVertice(instanceIndex, indiceIndex); |  | ||||||
|   vec2 uv = entityGetUV(instanceIndex, indiceIndex); |  | ||||||
|  |  | ||||||
|   gl_Position = transforms.projection * transforms.view * vec4(vert, 0.0, 1.0); |  | ||||||
|   v_TextureCoord = uv; |  | ||||||
| } |  | ||||||
| @@ -1,64 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
| #include "entityshader.h" |  | ||||||
| #include "entity_vert.glsl.h" |  | ||||||
| #include "entity_frag.glsl.h" |  | ||||||
| #include "display/shader/data/transforms.h" |  | ||||||
| #include "display/shader/data/entities.h" |  | ||||||
| #include "display/shader/data/tilesetshaderdata.h" |  | ||||||
|  |  | ||||||
| entityshader_t ENTITY_SHADER; |  | ||||||
|  |  | ||||||
| void entityShaderInit() { |  | ||||||
|   memoryZero(&ENTITY_SHADER, sizeof(entityshader_t)); |  | ||||||
|  |  | ||||||
|   shaderInit( |  | ||||||
|     &ENTITY_SHADER.shader, |  | ||||||
|     entity_vertShaderSource, |  | ||||||
|     entity_fragShaderSource |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Uniform buffers |  | ||||||
|   ENTITY_SHADER.transformsBlock = shaderGetBlock( |  | ||||||
|     &ENTITY_SHADER.shader, |  | ||||||
|     TRANSFORMS_BLOCK_NAME |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   ENTITY_SHADER.entitiesBlock = shaderGetBlock( |  | ||||||
|     &ENTITY_SHADER.shader, |  | ||||||
|     ENTITIES_BLOCK_NAME |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   ENTITY_SHADER.tilesetsBlock = shaderGetBlock( |  | ||||||
|     &ENTITY_SHADER.shader, |  | ||||||
|     TILESET_SHADER_DATA_BLOCK_NAME |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Uniforms |  | ||||||
|   ENTITY_SHADER.tilesetTexturesUniform = shaderGetUniform( |  | ||||||
|     &ENTITY_SHADER.shader, |  | ||||||
|     TILESET_UNIFORM_TEXTURES_NAME |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void entityShaderUse() { |  | ||||||
|   shaderUse(&ENTITY_SHADER.shader); |  | ||||||
|   shaderBufferBindToBlock(&TRANSFORMS_BUFFER, ENTITY_SHADER.transformsBlock); |  | ||||||
|   shaderBufferBindToBlock(&ENTITIES_BUFFER, ENTITY_SHADER.entitiesBlock); |  | ||||||
|   shaderBufferBindToBlock( |  | ||||||
|     &TILESET_SHADER_DATA_BUFFER, ENTITY_SHADER.tilesetsBlock |  | ||||||
|   ); |  | ||||||
|   tilesetShaderTexturesBind(ENTITY_SHADER.tilesetTexturesUniform); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void entityShaderDispose() { |  | ||||||
|   shaderDispose(&ENTITY_SHADER.shader); |  | ||||||
| } |  | ||||||
| @@ -1,36 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "display/shader/shader.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   shader_t shader; |  | ||||||
|  |  | ||||||
|   GLuint entitiesBlock; |  | ||||||
|   GLuint transformsBlock; |  | ||||||
|   GLuint tilesetsBlock; |  | ||||||
|    |  | ||||||
|   GLuint tilesetTexturesUniform; |  | ||||||
| } entityshader_t; |  | ||||||
|  |  | ||||||
| extern entityshader_t ENTITY_SHADER; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the entity shader. |  | ||||||
|  */ |  | ||||||
| void entityShaderInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Uses the entity shader. |  | ||||||
|  */ |  | ||||||
| void entityShaderUse(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of the entity shader. |  | ||||||
|  */ |  | ||||||
| void entityShaderDispose(); |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
| ) |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #version 330 core |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #define PACKED_U8_PER_UI 4 |  | ||||||
| #define PACKED_U8_PER_UVEC4 PACKED_U8_PER_UI * 4 |  | ||||||
|  |  | ||||||
| uint packedGetU8(uint position, uvec4 data) { |  | ||||||
|   uint subData = data[position / 4u]; |  | ||||||
|   return (subData >> (position * 8u)) & 0xFFu; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint packedGetU32(uint position, uvec4 data) { |  | ||||||
|   return data[position]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int packedGetI8(uint position, uvec4 data) { |  | ||||||
|   uint subData = data[position / 4u]; |  | ||||||
|  |  | ||||||
|   int shift = int(position * 8u); |  | ||||||
|   return int(subData << (24 - shift)) >> 24; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint packedArrayGetU8IndexFromUVEC4Array(uint u8ArrayIndex) { |  | ||||||
|   // Given a uint8_t array is uploaded, this will return the index to get the |  | ||||||
|   // appropriate uvec4 from a uvec4 array that will be at the right index. |  | ||||||
|   return u8ArrayIndex / uint(PACKED_U8_PER_UVEC4); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint packedArrayGetU8FromUVEC4ArrayValue(uint u8ArrayIndex, uvec4 data) { |  | ||||||
|   // Given a value from a uint8_t array, this will return the value at the |  | ||||||
|   // appropriate index. You must first get the uvec4 from the array using |  | ||||||
|   // packedArrayGetU8IndexFromUVEC4Array. |  | ||||||
|   uint subIndex = (u8ArrayIndex % uint(PACKED_U8_PER_UVEC4)) / uint(PACKED_U8_PER_UI); |  | ||||||
|   uint shiftAmount = (u8ArrayIndex % uint(PACKED_U8_PER_UI)) * 8u; |  | ||||||
|   uint value = (data[subIndex] >> shiftAmount) & 0xFFu; |  | ||||||
|   return value; |  | ||||||
| } |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| uint quadGetIndiceIndex(uint vertexId) { |  | ||||||
|   return vertexId % 6u; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| uint quadGetIndiceIndex(int vertexId) { |  | ||||||
|   return quadGetIndiceIndex(uint(vertexId)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 quadGetVertice(uint indiceIndex) { |  | ||||||
|   vec2 vert = vec2(0, 0); |  | ||||||
|  |  | ||||||
|   /*if(indiceIndex == 0u || indiceIndex == 4u) { |  | ||||||
|     // vert = vec2(0, 0); |  | ||||||
|   } else*/ if(indiceIndex == 1u) { |  | ||||||
|     vert = vec2(1, 0); |  | ||||||
|   } else if(indiceIndex == 2u || indiceIndex == 5u) { |  | ||||||
|     vert = vec2(1, 1); |  | ||||||
|   } else if(indiceIndex == 3u) { |  | ||||||
|     vert = vec2(0, 1); |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   return vert; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 quadGetTextureCoordinate(uint indiceIndex) { |  | ||||||
|   vec2 vert = quadGetVertice(indiceIndex); |  | ||||||
|   return vert; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| vec2 quadGetTextureCoordinate(uint indiceIndex, vec4 uv) { |  | ||||||
|   vec2 vert = quadGetVertice(indiceIndex); |  | ||||||
|   vert.y = 1.0 - vert.y; |  | ||||||
|   return vec2(uv.x + (uv.z - uv.x) * vert.x, uv.y + (uv.w - uv.y) * vert.y); |  | ||||||
| } |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Shaders |  | ||||||
| glsltool(map_vert.glsl) |  | ||||||
| glsltool(map_frag.glsl) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     mapshader.c |  | ||||||
| ) |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../fragments/header.glsl" |  | ||||||
| #include "../data/map.glsl" |  | ||||||
|  |  | ||||||
| // Inputs from vertex shader |  | ||||||
| in vec2 v_TextureCoord; |  | ||||||
| flat in uint v_InstanceIndex; |  | ||||||
| flat in uint v_IndiceIndex; |  | ||||||
|  |  | ||||||
| // Frag pixel color |  | ||||||
| out vec4 FragColor; |  | ||||||
|  |  | ||||||
| void main() { |  | ||||||
|   uint layer = mapGetLayer(v_InstanceIndex); |  | ||||||
|   uint tileId = mapGetTileId(v_InstanceIndex); |  | ||||||
|  |  | ||||||
|   if(tileId == 0u) { |  | ||||||
|     FragColor = vec4(1, 0, 0, 1); |  | ||||||
|   } else if(tileId == 1u) { |  | ||||||
|     FragColor = vec4(0, 1, 0, 1); |  | ||||||
|   } else { |  | ||||||
|     FragColor = vec4(0, 0, 1, 1); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| // Copyright (c) 2025 Dominic Masters |  | ||||||
| //  |  | ||||||
| // This software is released under the MIT License. |  | ||||||
| // https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| #include "../fragments/header.glsl" |  | ||||||
| #include "../data/transforms.glsl" |  | ||||||
| #include "../data/map.glsl" |  | ||||||
|  |  | ||||||
| // Outputs to fragment shader |  | ||||||
| out vec2 v_TextureCoord; |  | ||||||
| flat out uint v_InstanceIndex; |  | ||||||
| flat out uint v_IndiceIndex; |  | ||||||
|  |  | ||||||
| void main() { |  | ||||||
|   uint instanceIndex = uint(gl_InstanceID); |  | ||||||
|   uint indiceIndex = quadGetIndiceIndex(gl_VertexID); |  | ||||||
|  |  | ||||||
|   uint layer = mapGetLayer(instanceIndex); |  | ||||||
|   vec2 vert = mapGetVertice(instanceIndex, indiceIndex); |  | ||||||
|   vec2 uv = quadGetTextureCoordinate(indiceIndex); |  | ||||||
|  |  | ||||||
|   gl_Position = transforms.projection * transforms.view * vec4(vert, float(layer) * 64.0, 1.0); |  | ||||||
|  |  | ||||||
|   v_TextureCoord = uv; |  | ||||||
|   v_InstanceIndex = instanceIndex; |  | ||||||
|   v_IndiceIndex = indiceIndex; |  | ||||||
| } |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "mapshader.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
| #include "display/shader/data/mapshaderdata.h" |  | ||||||
| #include "display/shader/data/transforms.h" |  | ||||||
| #include "map_vert.glsl.h" |  | ||||||
| #include "map_frag.glsl.h" |  | ||||||
|  |  | ||||||
| mapshader_t MAP_SHADER; |  | ||||||
|  |  | ||||||
| void mapShaderInit() { |  | ||||||
|   memoryZero(&MAP_SHADER, sizeof(mapshader_t)); |  | ||||||
|  |  | ||||||
|   shaderInit( |  | ||||||
|     &MAP_SHADER.shader, |  | ||||||
|     map_vertShaderSource, |  | ||||||
|     map_fragShaderSource |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Uniform blocks |  | ||||||
|   MAP_SHADER.mapBlock = shaderGetBlock( |  | ||||||
|     &MAP_SHADER.shader, |  | ||||||
|     MAP_BLOCK_NAME |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   MAP_SHADER.transformsBlock = shaderGetBlock( |  | ||||||
|     &MAP_SHADER.shader, |  | ||||||
|     TRANSFORMS_BLOCK_NAME |  | ||||||
|   ); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void mapShaderUse() { |  | ||||||
|   shaderUse(&MAP_SHADER.shader); |  | ||||||
|   shaderBufferBindToBlock(&MAP_SHADER_DATA_BUFFER, MAP_SHADER.mapBlock); |  | ||||||
|   shaderBufferBindToBlock(&TRANSFORMS_BUFFER, MAP_SHADER.transformsBlock); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void mapShaderDispose() { |  | ||||||
|   shaderDispose(&MAP_SHADER.shader); |  | ||||||
| } |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "display/shader/shader.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   shader_t shader; |  | ||||||
|   GLuint mapBlock; |  | ||||||
|   GLuint transformsBlock; |  | ||||||
| } mapshader_t; |  | ||||||
|  |  | ||||||
| extern mapshader_t MAP_SHADER; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the map shader. |  | ||||||
|  */ |  | ||||||
| void mapShaderInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Uses the map shader. |  | ||||||
|  */ |  | ||||||
| void mapShaderUse(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Destroys the map shader. |  | ||||||
|  */ |  | ||||||
| void mapShaderDispose(); |  | ||||||
| @@ -1,146 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "shader.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
|  |  | ||||||
| void shaderInit( |  | ||||||
|   shader_t *shader, |  | ||||||
|   const char *vertexSource, |  | ||||||
|   const char *fragmentSource |  | ||||||
| ) { |  | ||||||
|   assertNotNull(shader, "shader must not be NULL"); |  | ||||||
|   assertNotNull(vertexSource, "vertexSource must not be NULL"); |  | ||||||
|   assertNotNull(fragmentSource, "fragmentSource must not be NULL"); |  | ||||||
|  |  | ||||||
|   int32_t success; |  | ||||||
|   char infoLog[SHADER_LOG_LENGTH]; |  | ||||||
|  |  | ||||||
|   // Create vertex shader |  | ||||||
|   shader->vertexShader = glCreateShader(GL_VERTEX_SHADER); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glShaderSource(shader->vertexShader, 1, &vertexSource, NULL); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glCompileShader(shader->vertexShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glGetShaderiv(shader->vertexShader, GL_COMPILE_STATUS, &success); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   if(!success) { |  | ||||||
|     glGetShaderInfoLog( |  | ||||||
|       shader->vertexShader, SHADER_LOG_LENGTH, NULL, infoLog |  | ||||||
|     ); |  | ||||||
|     assertNoGLError(); |  | ||||||
|     assertUnreachable(infoLog); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Create fragment shader |  | ||||||
|   shader->fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glShaderSource(shader->fragmentShader, 1, &fragmentSource, NULL); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glCompileShader(shader->fragmentShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glGetShaderiv(shader->fragmentShader, GL_COMPILE_STATUS, &success); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   if(!success) { |  | ||||||
|     glGetShaderInfoLog( |  | ||||||
|       shader->fragmentShader, SHADER_LOG_LENGTH, NULL, infoLog |  | ||||||
|     ); |  | ||||||
|     assertNoGLError(); |  | ||||||
|     assertUnreachable(infoLog); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Create shader program |  | ||||||
|   shader->shaderProgram = glCreateProgram(); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glAttachShader(shader->shaderProgram, shader->vertexShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glAttachShader(shader->shaderProgram, shader->fragmentShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glLinkProgram(shader->shaderProgram); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glGetProgramiv(shader->shaderProgram, GL_LINK_STATUS, &success); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   if(!success) { |  | ||||||
|     glGetProgramInfoLog(shader->shaderProgram, SHADER_LOG_LENGTH, NULL, infoLog); |  | ||||||
|     assertNoGLError(); |  | ||||||
|     assertUnreachable(infoLog); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderUse(const shader_t *shader) { |  | ||||||
|   assertNotNull(shader, "shader must not be NULL"); |  | ||||||
|  |  | ||||||
|   glUseProgram(shader->shaderProgram); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| GLuint shaderGetUniform(const shader_t *shader, const char_t *name) { |  | ||||||
|   assertNotNull(shader, "shader must not be NULL"); |  | ||||||
|   assertNotNull(name, "name must not be NULL"); |  | ||||||
|  |  | ||||||
|   GLuint uniform = glGetUniformLocation(shader->shaderProgram, name); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   return uniform; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| GLuint shaderGetBlock(const shader_t *shader, const char *name) { |  | ||||||
|   assertNotNull(shader, "shader must not be NULL"); |  | ||||||
|   assertNotNull(name, "name must not be NULL"); |  | ||||||
|  |  | ||||||
|   GLuint blockIndex = glGetUniformBlockIndex(shader->shaderProgram, name); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // TODO: I really don't think this should be here at all. |  | ||||||
|   glUniformBlockBinding(shader->shaderProgram, blockIndex, blockIndex); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   return blockIndex; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderSetTextures( |  | ||||||
|   const GLuint uniform, |  | ||||||
|   const GLuint *textures, |  | ||||||
|   const uint8_t count |  | ||||||
| ) { |  | ||||||
|   assertNotNull(textures, "textures must not be NULL"); |  | ||||||
|   assertTrue(count > 0, "count must be greater than 0"); |  | ||||||
|  |  | ||||||
|   glUniform1iv(uniform, count, textures); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderDispose(shader_t *shader) { |  | ||||||
|   assertNotNull(shader, "shader must not be NULL"); |  | ||||||
|  |  | ||||||
|   glDeleteProgram(shader->shaderProgram); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glDeleteShader(shader->vertexShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glDeleteShader(shader->fragmentShader); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| #define SHADER_LOG_LENGTH 512 |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   GLuint shaderProgram; |  | ||||||
|   GLuint vertexShader; |  | ||||||
|   GLuint fragmentShader; |  | ||||||
| } shader_t; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes a shader. |  | ||||||
|  *  |  | ||||||
|  * @param shader The shader to initialize. |  | ||||||
|  * @param vertexSource The vertex shader source. |  | ||||||
|  * @param fragmentSource The fragment shader source. |  | ||||||
|  */ |  | ||||||
| void shaderInit( |  | ||||||
|   shader_t *shader, |  | ||||||
|   const char_t *vertexSource, |  | ||||||
|   const char_t *fragmentSource |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Uses a shader. |  | ||||||
|  *  |  | ||||||
|  * @param shader The shader to use. |  | ||||||
|  */ |  | ||||||
| void shaderUse(const shader_t *shader); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Gets a uniform from a shader. |  | ||||||
|  *  |  | ||||||
|  * @param shader The shader to get the uniform from. |  | ||||||
|  * @param name The name of the uniform. |  | ||||||
|  * @return The uniform. |  | ||||||
|  */ |  | ||||||
| GLuint shaderGetUniform(const shader_t *shader, const char_t *name); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Gets a block id from a shader. |  | ||||||
|  *  |  | ||||||
|  * @param shader The shader to get the block from. |  | ||||||
|  * @param name The name of the block. |  | ||||||
|  * @return The block index/identifier. |  | ||||||
|  */ |  | ||||||
| GLuint shaderGetBlock(const shader_t *shader, const char_t *name); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Sets texture uniforms to a shader. |  | ||||||
|  *  |  | ||||||
|  * @param uniform The uniform to set. |  | ||||||
|  * @param textures The textures to set. |  | ||||||
|  * @param count The number of textures to set. |  | ||||||
|  */ |  | ||||||
| void shaderSetTextures( |  | ||||||
|   const GLuint uniform, |  | ||||||
|   const GLuint *textures, |  | ||||||
|   const uint8_t count |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of a shader. |  | ||||||
|  *  |  | ||||||
|  * @param shader The shader to dispose of. |  | ||||||
|  */ |  | ||||||
| void shaderDispose(shader_t *shader); |  | ||||||
| @@ -1,55 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "shaderbuffer.h" |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
|  |  | ||||||
| void shaderBufferInit(shaderbuffer_t *shaderBuffer, const size_t size) { |  | ||||||
|   assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL."); |  | ||||||
|   assertTrue(size > 0, "size must be greater than 0."); |  | ||||||
|  |  | ||||||
|   shaderBuffer->size = size; |  | ||||||
|  |  | ||||||
|   glGenBuffers(1, &shaderBuffer->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   shaderBufferBind(shaderBuffer); |  | ||||||
|  |  | ||||||
|   glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_STATIC_DRAW); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderBufferBind(shaderbuffer_t *shaderBuffer) { |  | ||||||
|   assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL."); |  | ||||||
|  |  | ||||||
|   glBindBuffer(GL_UNIFORM_BUFFER, shaderBuffer->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderBufferSetData(shaderbuffer_t *shaderBuffer, const void *data) { |  | ||||||
|   assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL."); |  | ||||||
|   assertNotNull(data, "data cannot be NULL."); |  | ||||||
|  |  | ||||||
|   glBufferData(GL_UNIFORM_BUFFER, shaderBuffer->size, data, GL_STATIC_DRAW); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderBufferBindToBlock( |  | ||||||
|   shaderbuffer_t *shaderBuffer, |  | ||||||
|   const GLuint blockIndex |  | ||||||
| ) { |  | ||||||
|   assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL."); |  | ||||||
|  |  | ||||||
|   glBindBufferBase(GL_UNIFORM_BUFFER, blockIndex, shaderBuffer->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderBufferDispose(shaderbuffer_t *shaderBuffer) { |  | ||||||
|   assertNotNull(shaderBuffer, "shaderBuffer cannot be NULL."); |  | ||||||
|   glDeleteBuffers(1, &shaderBuffer->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
| @@ -1,61 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   GLuint id; |  | ||||||
|   size_t size; |  | ||||||
| } shaderbuffer_t; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes a shader buffer. |  | ||||||
|  *  |  | ||||||
|  * @param shaderBuffer The shader buffer to initialize. |  | ||||||
|  * @param size The size of the buffer. |  | ||||||
|  */ |  | ||||||
| void shaderBufferInit( |  | ||||||
|   shaderbuffer_t *shaderBuffer, |  | ||||||
|   const size_t size |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds a shader buffer. |  | ||||||
|  *  |  | ||||||
|  * @param shaderBuffer The shader buffer to bind. |  | ||||||
|  */ |  | ||||||
| void shaderBufferBind(shaderbuffer_t *shaderBuffer); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Sets the data of a shader buffer. |  | ||||||
|  *  |  | ||||||
|  * @param shaderBuffer The shader buffer to set the data of. |  | ||||||
|  * @param data The data to set. |  | ||||||
|  */ |  | ||||||
| void shaderBufferSetData( |  | ||||||
|   shaderbuffer_t *shaderBuffer, |  | ||||||
|   const void *data |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds a shader buffer to a block. |  | ||||||
|  *  |  | ||||||
|  * @param shaderBuffer The shader buffer to bind. |  | ||||||
|  * @param blockIndex The block index to bind to. |  | ||||||
|  */ |  | ||||||
| void shaderBufferBindToBlock( |  | ||||||
|   shaderbuffer_t *shaderBuffer, |  | ||||||
|   const GLuint blockIndex |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of a shader buffer. |  | ||||||
|  *  |  | ||||||
|  * @param shaderBuffer The shader buffer to dispose of. |  | ||||||
|  */ |  | ||||||
| void shaderBufferDispose(shaderbuffer_t *shaderBuffer); |  | ||||||
| @@ -1,109 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "shadermanager.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "display/shader/data/transforms.h" |  | ||||||
| #include "display/shader/data/entities.h" |  | ||||||
| #include "display/shader/data/mapshaderdata.h" |  | ||||||
| #include "display/shader/data/tilesetshaderdata.h" |  | ||||||
| #include "display/shader/entityshader/entityshader.h" |  | ||||||
| #include "display/shader/mapshader/mapshader.h" |  | ||||||
|  |  | ||||||
| shadermanagerdatacallback_t SHADER_MANAGER_DATA_CALLBACKS[] = { |  | ||||||
|   { transformsInit, transformsUpdate, transformsDispose }, |  | ||||||
|   { entitiesInit, entitiesUpdate, entitiesDispose }, |  | ||||||
|   { mapShaderDataInit, mapShaderDataUpdate, mapShaderDataDispose }, |  | ||||||
|   { tilesetShaderDataInit, tilesetShaderDataUpdate, tilesetShaderDataDispose } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| shadermanagershadercallback_t SHADER_MANAGER_SHADER_CALLBACKS[] = { |  | ||||||
|   { entityShaderInit, entityShaderDispose }, |  | ||||||
|   { mapShaderInit, mapShaderDispose } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| void shaderManagerInit() { |  | ||||||
|   size_t i; |  | ||||||
|   assertTrue( |  | ||||||
|     SHADER_MANAGER_SHADER_CALLBACKS_SIZE > 0, |  | ||||||
|     "No Shader Callbacks Defined" |  | ||||||
|   ); |  | ||||||
|   assertTrue( |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS_SIZE > 0, |  | ||||||
|     "No Data Callbacks Defined" |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Init Shader Datas (before the shaders) |  | ||||||
|   i = 0; |  | ||||||
|   do { |  | ||||||
|     assertNotNull( |  | ||||||
|       SHADER_MANAGER_DATA_CALLBACKS[i].init, |  | ||||||
|       "Data Callback is NULL" |  | ||||||
|     ); |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS[i++].init(); |  | ||||||
|   } while(i < SHADER_MANAGER_DATA_CALLBACKS_SIZE); |  | ||||||
|  |  | ||||||
|   // Init the shaders |  | ||||||
|   i = 0; |  | ||||||
|   do { |  | ||||||
|     assertNotNull( |  | ||||||
|       SHADER_MANAGER_SHADER_CALLBACKS[i].init, |  | ||||||
|       "Shader Callback is NULL" |  | ||||||
|     ); |  | ||||||
|     SHADER_MANAGER_SHADER_CALLBACKS[i++].init(); |  | ||||||
|   } while(i < SHADER_MANAGER_SHADER_CALLBACKS_SIZE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderManagerUpdate() { |  | ||||||
|   assertTrue( |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS_SIZE > 0, |  | ||||||
|     "No Data Callbacks Defined" |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   // Update all the data |  | ||||||
|   size_t i = 0; |  | ||||||
|   do { |  | ||||||
|     assertNotNull( |  | ||||||
|       SHADER_MANAGER_DATA_CALLBACKS[i].update, |  | ||||||
|       "Data Callback is NULL" |  | ||||||
|     ); |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS[i++].update(); |  | ||||||
|   } while(i < SHADER_MANAGER_DATA_CALLBACKS_SIZE); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void shaderManagerDispose() { |  | ||||||
|   assertTrue( |  | ||||||
|     SHADER_MANAGER_SHADER_CALLBACKS_SIZE > 0, |  | ||||||
|     "No Shader Callbacks Defined" |  | ||||||
|   ); |  | ||||||
|   assertTrue( |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS_SIZE > 0, |  | ||||||
|     "No Data Callbacks Defined" |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   // Cleanup the shaders |  | ||||||
|   size_t i = 0; |  | ||||||
|   do { |  | ||||||
|     assertNotNull( |  | ||||||
|       SHADER_MANAGER_SHADER_CALLBACKS[i].dispose, |  | ||||||
|       "Shader Callback is NULL" |  | ||||||
|     ); |  | ||||||
|     SHADER_MANAGER_SHADER_CALLBACKS[i++].dispose(); |  | ||||||
|   } while(i < SHADER_MANAGER_SHADER_CALLBACKS_SIZE); |  | ||||||
|  |  | ||||||
|   // Cleanup the data |  | ||||||
|   i = 0; |  | ||||||
|   do { |  | ||||||
|     assertNotNull( |  | ||||||
|       SHADER_MANAGER_DATA_CALLBACKS[i].dispose, |  | ||||||
|       "Data Callback is NULL" |  | ||||||
|     ); |  | ||||||
|     SHADER_MANAGER_DATA_CALLBACKS[i++].dispose(); |  | ||||||
|   } while(i < SHADER_MANAGER_DATA_CALLBACKS_SIZE); |  | ||||||
| } |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "dusk.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   void (*init)(); |  | ||||||
|   void (*update)(); |  | ||||||
|   void (*dispose)(); |  | ||||||
| } shadermanagerdatacallback_t; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   void (*init)(); |  | ||||||
|   void (*dispose)(); |  | ||||||
| } shadermanagershadercallback_t; |  | ||||||
|  |  | ||||||
| extern shadermanagerdatacallback_t SHADER_MANAGER_DATA_CALLBACKS[]; |  | ||||||
| extern shadermanagershadercallback_t SHADER_MANAGER_SHADER_CALLBACKS[]; |  | ||||||
|  |  | ||||||
| #define SHADER_MANAGER_DATA_CALLBACKS_SIZE ( \ |  | ||||||
|   sizeof(SHADER_MANAGER_DATA_CALLBACKS) / sizeof(shadermanagerdatacallback_t) \ |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| #define SHADER_MANAGER_SHADER_CALLBACKS_SIZE ( \ |  | ||||||
|   sizeof(SHADER_MANAGER_SHADER_CALLBACKS) / \ |  | ||||||
|   sizeof(shadermanagershadercallback_t) \ |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the Shader Manager |  | ||||||
|  */ |  | ||||||
| void shaderManagerInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the Shader Manager |  | ||||||
|  */ |  | ||||||
| void shaderManagerUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of the Shader Manager |  | ||||||
|  */ |  | ||||||
| void shaderManagerDispose(); |  | ||||||
| @@ -1,103 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2023 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "texture.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "assert/assertgl.h" |  | ||||||
| #include "asset.h" |  | ||||||
| #include "util/math.h" |  | ||||||
| #include "util/memory.h" |  | ||||||
|  |  | ||||||
| #define TEXTURE_BUFFER_SIZE 32768 |  | ||||||
|  |  | ||||||
| int32_t TEXTURE_ACTIVE_COUNT; |  | ||||||
|  |  | ||||||
| void textureLoad( |  | ||||||
|   texture_t *texture, |  | ||||||
|   const char_t *path |  | ||||||
| ) { |  | ||||||
|   assertNotNull(texture, "Texture is null."); |  | ||||||
|   assertNotNull(path, "Path is null."); |  | ||||||
|  |  | ||||||
|   // Open asset |  | ||||||
|   assetOpen(path); |  | ||||||
|  |  | ||||||
|   // Setup spng |  | ||||||
|   spng_ctx *ctx = spng_ctx_new(0); |  | ||||||
|   spng_set_png_stream(ctx, &textureSPNGBuffer, NULL); |  | ||||||
|  |  | ||||||
|   // Get image info |  | ||||||
|   struct spng_ihdr ihdr; |  | ||||||
|   spng_get_ihdr(ctx, &ihdr); |  | ||||||
|   texture->width = ihdr.width; |  | ||||||
|   texture->height = ihdr.height; |  | ||||||
|  |  | ||||||
|   // Decode the image. I can probably stream this in the future. |  | ||||||
|   size_t dataSize = ihdr.width * ihdr.height * 4;// 4 for RGBA |  | ||||||
|   uint8_t *data = (uint8_t *)memoryAllocate(dataSize); |  | ||||||
|   assertNotNull(data, "Failed to allocate memory for texture data."); |  | ||||||
|   spng_decode_image(ctx, data, dataSize, SPNG_FMT_RGBA8, 0); |  | ||||||
|  |  | ||||||
|   // Finish decoding |  | ||||||
|   spng_ctx_free(ctx); |  | ||||||
|   assetClose(); |  | ||||||
|  |  | ||||||
|   // Create texture |  | ||||||
|   glGenTextures(1, &texture->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindTexture(GL_TEXTURE_2D, texture->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   // Buffer then cleanup |  | ||||||
|   glTexImage2D( |  | ||||||
|     GL_TEXTURE_2D, 0, GL_RGBA, |  | ||||||
|     texture->width, texture->height, |  | ||||||
|     0, GL_RGBA, GL_UNSIGNED_BYTE, data |  | ||||||
|   ); |  | ||||||
|   assertNoGLError(); |  | ||||||
|   memoryFree(data); |  | ||||||
|  |  | ||||||
|   // Setup texture parameters |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindTexture(GL_TEXTURE_2D, 0); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void textureBind( |  | ||||||
|   const texture_t *texture, |  | ||||||
|   const GLuint slot |  | ||||||
| ) { |  | ||||||
|   assertNotNull(texture, "Texture is null."); |  | ||||||
|    |  | ||||||
|   glActiveTexture(GL_TEXTURE0 + slot); |  | ||||||
|   assertNoGLError(); |  | ||||||
|  |  | ||||||
|   glBindTexture(GL_TEXTURE_2D, texture->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void textureDispose(texture_t *texture) { |  | ||||||
|   glDeleteTextures(1, &texture->id); |  | ||||||
|   assertNoGLError(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int32_t textureSPNGBuffer( |  | ||||||
|   spng_ctx *ctx, |  | ||||||
|   void *user, |  | ||||||
|   void *destination, |  | ||||||
|   size_t length |  | ||||||
| ) { |  | ||||||
|   size_t read = assetRead(destination, length); |  | ||||||
|   if(read == 0) return SPNG_IO_EOF; |  | ||||||
|   return SPNG_OK; |  | ||||||
| } |  | ||||||
| @@ -1,63 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2023 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
| #include <spng.h> |  | ||||||
|  |  | ||||||
| extern int32_t TEXTURE_ACTIVE_COUNT; |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   uint32_t width; |  | ||||||
|   uint32_t height; |  | ||||||
|   GLuint id; |  | ||||||
| } texture_t; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes a texture to be read to be used. |  | ||||||
|  *  |  | ||||||
|  * @param texture Texture to initialize. |  | ||||||
|  * @param path Path of the file to load. |  | ||||||
|  */ |  | ||||||
| void textureLoad( |  | ||||||
|   texture_t *texture, |  | ||||||
|   const char_t *path |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds the texture to the given slot (for use by the shaders). |  | ||||||
|  *  |  | ||||||
|  * @param texture Texture to bind. |  | ||||||
|  * @param slot Slot to bind to. |  | ||||||
|  */ |  | ||||||
| void textureBind( |  | ||||||
|   const texture_t *texture, |  | ||||||
|   const GLuint slot |  | ||||||
| ); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Unloads a previously initialized texture. |  | ||||||
|  *  |  | ||||||
|  * @param texture Texture to destroy. |  | ||||||
|  */ |  | ||||||
| void textureDispose(texture_t *texture); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Callback function for libspng to read from the asset. |  | ||||||
|  *  |  | ||||||
|  * @param ctx The spng context. |  | ||||||
|  * @param user User data. |  | ||||||
|  * @param destination Destination buffer. |  | ||||||
|  * @param length Length of the buffer. |  | ||||||
|  * @return The amount of data read. |  | ||||||
|  */ |  | ||||||
| int32_t textureSPNGBuffer( |  | ||||||
|   spng_ctx *ctx, |  | ||||||
|   void *user, |  | ||||||
|   void *destination, |  | ||||||
|   size_t length |  | ||||||
| ); |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "tilesetgl.h" |  | ||||||
| #include "assert/assert.h" |  | ||||||
|  |  | ||||||
| const char* TILESET_GL_TEXTURES_PATHS[TILESET_COUNT] = { |  | ||||||
|   NULL, |  | ||||||
|   "textures/8x8.png" |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| texture_t TILESET_GL_TEXTURES[TILESET_SLOT_COUNT]; |  | ||||||
|  |  | ||||||
| void tilesetGLBind() { |  | ||||||
|   uint8_t i; |  | ||||||
|   do { |  | ||||||
|     if(TILESET_SLOTS[i] == TILESET_NULL) continue; |  | ||||||
|     textureBind(TILESET_GL_TEXTURES + i, i); |  | ||||||
|   } while(++i < TILESET_SLOT_COUNT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void tilesetBind(const tilesetid_t id, const uint8_t slot) { |  | ||||||
|   assertTrue(slot < TILESET_SLOT_COUNT, "Invalid slot"); |  | ||||||
|   assertTrue(id < TILESET_COUNT, "Invalid tileset id"); |  | ||||||
|  |  | ||||||
|   TILESET_SLOTS[slot] = id; |  | ||||||
|   textureLoad(TILESET_GL_TEXTURES + slot, TILESET_GL_TEXTURES_PATHS[id]); |  | ||||||
| } |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "texture.h" |  | ||||||
| #include "display/tileset.h" |  | ||||||
|  |  | ||||||
| extern const char* TILESET_GL_TEXTURES_PATHS[]; |  | ||||||
| extern texture_t TILESET_GL_TEXTURES[]; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Binds the tileset to the OpenGL context. |  | ||||||
|  */ |  | ||||||
| void tilesetGLBind(); |  | ||||||
| @@ -1,24 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "dusk.h" |  | ||||||
| #include "duskglimpl.h" |  | ||||||
|  |  | ||||||
| #include <libgen.h> |  | ||||||
| #include <cglm/cglm.h> |  | ||||||
| #include <float.h> |  | ||||||
| #include <pthread.h> |  | ||||||
| #include <unistd.h> |  | ||||||
|  |  | ||||||
| typedef float float_t; |  | ||||||
| typedef double double_t; |  | ||||||
|  |  | ||||||
| extern char_t EXECUTABLE_PATH[]; |  | ||||||
| extern char_t EXECUTABLE_DIRECTORY[]; |  | ||||||
|  |  | ||||||
| typedef uint32_t uvec4_t[4]; |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     overworld.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "overworld/overworld.h" |  | ||||||
| #include "display/quad.h" |  | ||||||
| #include "display/shader/entityshader/entityshader.h" |  | ||||||
| #include "display/shader/mapshader/mapshader.h" |  | ||||||
|  |  | ||||||
| void overworldRender() { |  | ||||||
|   mapShaderUse(); |  | ||||||
|   quadRender( |  | ||||||
|     OVERWORLD.map.width * OVERWORLD.map.height * OVERWORLD.map.layerCount |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   entityShaderUse(); |  | ||||||
|   quadRender(OVERWORLD.entityCount); |  | ||||||
| } |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| # |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Libs |  | ||||||
| target_link_libraries(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     glfw |  | ||||||
|     glad |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Includes |  | ||||||
| target_include_directories(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     ${CMAKE_CURRENT_LIST_DIR} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     main.c |  | ||||||
|     input.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| add_subdirectory(display) |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| #  |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     window.c |  | ||||||
| ) |  | ||||||
| @@ -1,79 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "window.h" |  | ||||||
|  |  | ||||||
| GLFWwindow* window; |  | ||||||
| uint32_t WINDOW_WIDTH; |  | ||||||
| uint32_t WINDOW_HEIGHT; |  | ||||||
|  |  | ||||||
| int32_t windowInit() { |  | ||||||
|   // Initialize GLFW |  | ||||||
|   if(!glfwInit()) { |  | ||||||
|     const char* description; |  | ||||||
|     int code = glfwGetError(&description); |  | ||||||
|     if (description) { |  | ||||||
|       printf("GLFW Error %d: %s\n", code, description); |  | ||||||
|     } else { |  | ||||||
|       printf("GLFW Error: Unknown error\n"); |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     return -1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Create a windowed mode window and its OpenGL contex |  | ||||||
|   glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); |  | ||||||
|   glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); |  | ||||||
|   glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); |  | ||||||
|   glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); |  | ||||||
|   glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); |  | ||||||
|   glfwWindowHint(GLFW_MAXIMIZED, GLFW_FALSE); |  | ||||||
|   glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); |  | ||||||
|   glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); |  | ||||||
|  |  | ||||||
|   window = glfwCreateWindow( |  | ||||||
|     WINDOW_WIDTH_DEFAULT, WINDOW_HEIGHT_DEFAULT, |  | ||||||
|     "Dusk", |  | ||||||
|     NULL, NULL |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|   WINDOW_WIDTH = WINDOW_WIDTH_DEFAULT; |  | ||||||
|   WINDOW_HEIGHT = WINDOW_HEIGHT_DEFAULT; |  | ||||||
|  |  | ||||||
|   if(!window) { |  | ||||||
|     glfwTerminate(); |  | ||||||
|     return -2; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   // Make the window's context current |  | ||||||
|   glfwMakeContextCurrent(window); |  | ||||||
|   glfwSwapInterval(1); |  | ||||||
|  |  | ||||||
|   // Get initial framebuffer sizeglfwCreateWindow |  | ||||||
|   glfwGetFramebufferSize(window, &WINDOW_WIDTH, &WINDOW_HEIGHT); |  | ||||||
|  |  | ||||||
|   // Load OpenGL functions using glad or another loader here if necessary |  | ||||||
|   if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) return -3; |  | ||||||
|    |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool_t windowShouldClose() { |  | ||||||
|   return glfwWindowShouldClose(window); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void windowUpdate() { |  | ||||||
|   glfwSwapBuffers(window); |  | ||||||
|   glfwPollEvents(); |  | ||||||
|    |  | ||||||
|   glfwGetFramebufferSize(window, &WINDOW_WIDTH, &WINDOW_HEIGHT); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void windowDispose() { |  | ||||||
|   glfwDestroyWindow(window); |  | ||||||
|   glfwTerminate(); |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskglfw.h" |  | ||||||
| #include "display/displaydefs.h" |  | ||||||
|  |  | ||||||
| #define WINDOW_WIDTH_DEFAULT SCREEN_WIDTH*3 |  | ||||||
| #define WINDOW_HEIGHT_DEFAULT SCREEN_HEIGHT*3 |  | ||||||
|  |  | ||||||
| extern GLFWwindow* window; |  | ||||||
| extern uint32_t WINDOW_WIDTH; |  | ||||||
| extern uint32_t WINDOW_HEIGHT; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Initializes the game render window. |  | ||||||
|  *  |  | ||||||
|  * @return 0 on success, any other value on failure. |  | ||||||
|  */ |  | ||||||
| int32_t windowInit(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Returns whether the window should close. |  | ||||||
|  *  |  | ||||||
|  * @return true if the window should close, false otherwise. |  | ||||||
|  */ |  | ||||||
| bool_t windowShouldClose(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Updates the window subsystem. |  | ||||||
|  */ |  | ||||||
| void windowUpdate(); |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Disposes of the window. |  | ||||||
|  */ |  | ||||||
| void windowDispose(); |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "duskgl.h" |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
| #include "dusk.h" |  | ||||||
| #include <glad/glad.h> |  | ||||||
| #include <GLFW/glfw3.h> |  | ||||||
| @@ -1,56 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "input.h" |  | ||||||
| #include "display/window.h" |  | ||||||
|  |  | ||||||
| typedef struct { |  | ||||||
|   uint16_t glfw; |  | ||||||
|   inputstate_t bind; |  | ||||||
| } glfwkeybindmap_t; |  | ||||||
|  |  | ||||||
| glfwkeybindmap_t GLFW_KEY_BIND_MAP[] = { |  | ||||||
|   {GLFW_KEY_W, INPUT_UP}, |  | ||||||
|   {GLFW_KEY_UP, INPUT_UP}, |  | ||||||
|    |  | ||||||
|   {GLFW_KEY_S, INPUT_DOWN}, |  | ||||||
|   {GLFW_KEY_DOWN, INPUT_DOWN}, |  | ||||||
|    |  | ||||||
|   {GLFW_KEY_A, INPUT_LEFT}, |  | ||||||
|   {GLFW_KEY_LEFT, INPUT_LEFT}, |  | ||||||
|    |  | ||||||
|   {GLFW_KEY_D, INPUT_RIGHT}, |  | ||||||
|   {GLFW_KEY_RIGHT, INPUT_RIGHT}, |  | ||||||
|    |  | ||||||
|   {GLFW_KEY_ENTER, INPUT_ACCEPT}, |  | ||||||
|   {GLFW_KEY_E, INPUT_ACCEPT}, |  | ||||||
|   {GLFW_KEY_SPACE, INPUT_ACCEPT}, |  | ||||||
|  |  | ||||||
|   {GLFW_KEY_BACKSPACE, INPUT_BACK}, |  | ||||||
|   {GLFW_KEY_Q, INPUT_BACK}, |  | ||||||
|    |  | ||||||
|   {GLFW_KEY_ESCAPE, INPUT_MENU}, |  | ||||||
|  |  | ||||||
|   {0, 0} |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| inputstate_t inputPlatformState() { |  | ||||||
|   inputstate_t state = 0; |  | ||||||
|  |  | ||||||
|   // Handle keybinds |  | ||||||
|   glfwkeybindmap_t *map = GLFW_KEY_BIND_MAP; |  | ||||||
|   do { |  | ||||||
|     if(glfwGetKey(window, map->glfw) != GLFW_PRESS) { |  | ||||||
|       map++; |  | ||||||
|       continue; |  | ||||||
|     } |  | ||||||
|     state |= map->bind; |  | ||||||
|     map++; |  | ||||||
|   } while(map->glfw != 0); |  | ||||||
|  |  | ||||||
|   return state; |  | ||||||
| } |  | ||||||
| @@ -1,70 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "assert/assert.h" |  | ||||||
| #include "display/window.h" |  | ||||||
| #include "display/render.h" |  | ||||||
| #include "game.h" |  | ||||||
| #include "asset.h" |  | ||||||
|  |  | ||||||
| char_t EXECUTABLE_PATH[FILENAME_MAX]; |  | ||||||
| char_t EXECUTABLE_DIRECTORY[FILENAME_MAX]; |  | ||||||
|  |  | ||||||
| int32_t main(int32_t argc, char_t **argv) { |  | ||||||
|   // Get launch args |  | ||||||
|   assertTrue(argc > 0, "argc is not valid!"); |  | ||||||
|   assertNotNull(argv, "argv is not valid!"); |  | ||||||
|   assertNotNull(argv[0], "argv[0] is not valid!"); |  | ||||||
|   assertStrLen(argv[0], FILENAME_MAX, "argv[0] is too long!"); |  | ||||||
|   assertStrLenMin(argv[0], 1, "argv[0] is empty!"); |  | ||||||
|  |  | ||||||
|   // Store the executable path and directory. |  | ||||||
|   strcpy(EXECUTABLE_PATH, argv[0]); |  | ||||||
|   strcpy(EXECUTABLE_DIRECTORY, dirname(EXECUTABLE_PATH)); |  | ||||||
|  |  | ||||||
|   // Init systems |  | ||||||
|   int32_t ret; |  | ||||||
|   if((ret = windowInit()) != 0) { |  | ||||||
|     return -1; |  | ||||||
|   } |  | ||||||
|   gameInit(); |  | ||||||
|  |  | ||||||
|   // Init asset and render systems. |  | ||||||
|   assetInit(); |  | ||||||
|   renderInit(); |  | ||||||
|  |  | ||||||
|   // Prepare for time tracking |  | ||||||
|   double_t time, newTime; |  | ||||||
|   float_t fDelta, fTimeSinceLastFrame = 1.0f; |  | ||||||
|   int32_t updateResult; |  | ||||||
|  |  | ||||||
|   // Main loop |  | ||||||
|   while(!windowShouldClose()) { |  | ||||||
|     // Determine the delta. |  | ||||||
|     newTime = glfwGetTime(); |  | ||||||
|     fDelta = (float_t)(newTime - time); |  | ||||||
|     time = newTime; |  | ||||||
|     fTimeSinceLastFrame += fDelta; |  | ||||||
|  |  | ||||||
|     // Tick according to the game tick rate. |  | ||||||
|     if(fTimeSinceLastFrame >= (1.0f / GAME_TICK_RATE)) { |  | ||||||
|       gameUpdate(); |  | ||||||
|       fTimeSinceLastFrame = 0.0f; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Draw. In future may be tick based. |  | ||||||
|     renderUpdate(); |  | ||||||
|     windowUpdate(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   renderDispose(); |  | ||||||
|   windowDispose(); |  | ||||||
|   assetDispose(); |  | ||||||
|   gameDispose(); |  | ||||||
|  |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| # Copyright (c) 2025 Dominic Masters |  | ||||||
| # |  | ||||||
| # This software is released under the MIT License. |  | ||||||
| # https://opensource.org/licenses/MIT |  | ||||||
|  |  | ||||||
| # Libs |  | ||||||
| target_link_libraries(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Includes |  | ||||||
| target_include_directories(${DUSK_TARGET_NAME} |  | ||||||
|   PUBLIC |  | ||||||
|     ${CMAKE_CURRENT_LIST_DIR} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Sources |  | ||||||
| target_sources(${DUSK_TARGET_NAME} |  | ||||||
|   PRIVATE |  | ||||||
|     main.c |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # Subdirs |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| /** |  | ||||||
|  * Copyright (c) 2025 Dominic Masters |  | ||||||
|  *  |  | ||||||
|  * This software is released under the MIT License. |  | ||||||
|  * https://opensource.org/licenses/MIT |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| #include "dusk.h" |  | ||||||
| #include "error/error.h" |  | ||||||
| #include "console/console.h" |  | ||||||
| #include "util/string.h" |  | ||||||
|  |  | ||||||
| bool_t exitRequested = false; |  | ||||||
|  |  | ||||||
| void cmdExit(const consolecmdexec_t *exec) { |  | ||||||
|   exitRequested = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void testChange(const consolevar_t *var) { |  | ||||||
|   consolePrint("Variable '%s' changed to '%s'.", var->name, var->value); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int main() { |  | ||||||
|   consoleInit(); |  | ||||||
|  |  | ||||||
|   consoleRegCmd("exit", cmdExit); |  | ||||||
|   consoleRegVar("test", "Hello", testChange); |  | ||||||
|   consolePrint(" = Dusk Console = "); |  | ||||||
|  |  | ||||||
|   char_t buffer[CONSOLE_LINE_MAX * 10]; |  | ||||||
|   while(fgets(buffer, sizeof(buffer), stdin)) { |  | ||||||
|     consoleExec(buffer); |  | ||||||
|     consoleProcess(); |  | ||||||
|     if(exitRequested) break; |  | ||||||
|   } |  | ||||||
|   printf("Goodbye!\n"); |  | ||||||
|  |  | ||||||
|   return 0;   |  | ||||||
| } |  | ||||||
| @@ -35,11 +35,21 @@ bool_t errorCheck() { | |||||||
|   return ERROR_STACK.code != ERROR_OK; |   return ERROR_STACK.code != ERROR_OK; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| errorret_t errorPrint() { | const char_t * errorString() { | ||||||
|   if(ERROR_STACK.code == ERROR_OK) return ERROR_OK; |   if(!errorCheck()) return NULL; | ||||||
|  |   return ERROR_STACK.message; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|   printf("Error: %s\n", ERROR_STACK.message); | void errorFlush() { | ||||||
|   errorret_t code = ERROR_STACK.code; |   if(!errorCheck()) return; | ||||||
|   ERROR_STACK.code = ERROR_OK; |   ERROR_STACK.code = ERROR_OK; | ||||||
|  |   ERROR_STACK.message[0] = '\0'; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | errorret_t errorPrint() { | ||||||
|  |   if(!errorCheck()) return ERROR_OK; | ||||||
|  |   printf("Error: %s\n", errorString()); | ||||||
|  |   errorret_t code = ERROR_STACK.code; | ||||||
|  |   errorFlush(); | ||||||
|   return code; |   return code; | ||||||
| } | } | ||||||
| @@ -44,6 +44,16 @@ errorret_t errorCode(const errorret_t code, const char_t *message, ...); | |||||||
|  */ |  */ | ||||||
| bool_t errorCheck(); | bool_t errorCheck(); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * Retrieves the error message from the error stack. | ||||||
|  |  */ | ||||||
|  | const char_t * errorString(); | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Clears the error stack. | ||||||
|  |  */ | ||||||
|  | void errorFlush(); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Prints the error stack to the console. This also clears the error stack. |  * Prints the error stack to the console. This also clears the error stack. | ||||||
|  */ |  */ | ||||||
							
								
								
									
										48
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright (c) 2025 Dominic Masters | ||||||
|  |  *  | ||||||
|  |  * This software is released under the MIT License. | ||||||
|  |  * https://opensource.org/licenses/MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "console/console.h" | ||||||
|  | #include "server/server.h" | ||||||
|  |  | ||||||
|  | void cmdExit(const consolecmdexec_t *exec) { | ||||||
|  |   CloseWindow(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmdServe(const consolecmdexec_t *exec) { | ||||||
|  |   serverStart(3030); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cmdClose(const consolecmdexec_t *exec) { | ||||||
|  |   serverStop(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(void) { | ||||||
|  |   consoleInit(); | ||||||
|  |   serverInit(); | ||||||
|  |  | ||||||
|  |   consoleRegCmd("exit", cmdExit); | ||||||
|  |   consoleRegCmd("serve", cmdServe); | ||||||
|  |   consoleRegCmd("close", cmdClose); | ||||||
|  |  | ||||||
|  |   InitWindow(1280, 720, DUSK_NAME); | ||||||
|  |  | ||||||
|  |   while(!WindowShouldClose()) { | ||||||
|  |     consoleUpdate(); | ||||||
|  |  | ||||||
|  |     BeginDrawing(); | ||||||
|  |     ClearBackground(RAYWHITE); | ||||||
|  |  | ||||||
|  |     consoleDraw(); | ||||||
|  |  | ||||||
|  |     EndDrawing(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   CloseWindow(); | ||||||
|  |   serverDispose(); | ||||||
|  |    | ||||||
|  |   return EXIT_SUCCESS; | ||||||
|  | } | ||||||
| @@ -6,5 +6,6 @@ | |||||||
| # Sources | # Sources | ||||||
| target_sources(${DUSK_TARGET_NAME} | target_sources(${DUSK_TARGET_NAME} | ||||||
|   PRIVATE |   PRIVATE | ||||||
|     assertgl.c |     server.c | ||||||
|  |     serverclient.c | ||||||
| ) | ) | ||||||
							
								
								
									
										192
									
								
								src/server/server.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								src/server/server.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright (c) 2025 Dominic Masters | ||||||
|  |  *  | ||||||
|  |  * This software is released under the MIT License. | ||||||
|  |  * https://opensource.org/licenses/MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "server.h" | ||||||
|  | #include "util/memory.h" | ||||||
|  | #include "assert/assert.h" | ||||||
|  | #include "console/console.h" | ||||||
|  |  | ||||||
|  | server_t SERVER; | ||||||
|  |  | ||||||
|  | void serverInit() { | ||||||
|  |   memoryZero(&SERVER, sizeof(server_t)); | ||||||
|  |   pthread_mutex_init(&SERVER.startMutex, NULL); | ||||||
|  |   pthread_cond_init(&SERVER.startCond, NULL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | errorret_t serverStart(uint16_t port) { | ||||||
|  |   assertFalse(SERVER.isRunning, "Server is already running?"); | ||||||
|  |   consolePrint("Starting server on port %d...\n", port); | ||||||
|  |  | ||||||
|  |   pthread_mutex_lock(&SERVER.startMutex); | ||||||
|  |   SERVER.threadReady = false; | ||||||
|  |  | ||||||
|  |   // Initialize the server socket | ||||||
|  |   SERVER.serverSocket = socket(AF_INET, SOCK_STREAM, 0); | ||||||
|  |   if(SERVER.serverSocket < 0) { | ||||||
|  |     pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |     return error("Failed to create socket"); | ||||||
|  |   } | ||||||
|  |   SERVER.serverAddress.sin_family = AF_INET; | ||||||
|  |   SERVER.serverAddress.sin_addr.s_addr = INADDR_ANY; | ||||||
|  |   SERVER.serverAddress.sin_port = htons(port); | ||||||
|  |  | ||||||
|  |   // Bind the socket to the address and port | ||||||
|  |   int32_t res = bind( | ||||||
|  |     SERVER.serverSocket, | ||||||
|  |     (struct sockaddr *)&SERVER.serverAddress, | ||||||
|  |     sizeof(SERVER.serverAddress) | ||||||
|  |   ); | ||||||
|  |   if(res < 0) { | ||||||
|  |     close(SERVER.serverSocket); | ||||||
|  |     pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |     return error("Failed to bind socket"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Set the socket to listen for incoming connections | ||||||
|  |   res = listen(SERVER.serverSocket, SERVER_MAX_CLIENTS); | ||||||
|  |   if(res < 0) { | ||||||
|  |     close(SERVER.serverSocket); | ||||||
|  |     pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |     return error("Failed to listen on socket"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Start the server thread | ||||||
|  |   SERVER.isRunning = true; | ||||||
|  |   if(pthread_create(&SERVER.thread, NULL, serverThread, NULL) != 0) { | ||||||
|  |     perror("Failed to create server thread"); | ||||||
|  |     serverStop(); | ||||||
|  |     pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |     return error("Failed to create server thread"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Wait for the server thread to be ready | ||||||
|  |   while(!SERVER.threadReady) { | ||||||
|  |     pthread_cond_wait(&SERVER.startCond, &SERVER.startMutex); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |   consolePrint("Server started."); | ||||||
|  |   return ERROR_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void * serverThread(void *arg) { | ||||||
|  |   struct timeval timeout; | ||||||
|  |   fd_set readfds; | ||||||
|  |  | ||||||
|  |   pthread_mutex_lock(&SERVER.startMutex); | ||||||
|  |   SERVER.threadReady = true; | ||||||
|  |   pthread_cond_signal(&SERVER.startCond); | ||||||
|  |   pthread_mutex_unlock(&SERVER.startMutex); | ||||||
|  |  | ||||||
|  |   while(SERVER.isRunning) { | ||||||
|  |     usleep(SERVER_TIMEOUT * 1000); | ||||||
|  |  | ||||||
|  |     FD_ZERO(&readfds); | ||||||
|  |     FD_SET(SERVER.serverSocket, &readfds); | ||||||
|  |  | ||||||
|  |     timeout.tv_usec = SERVER_TIMEOUT * 1000; | ||||||
|  |  | ||||||
|  |     // Wait for  | ||||||
|  |     int32_t activity = select( | ||||||
|  |       SERVER.serverSocket + 1, | ||||||
|  |       &readfds, | ||||||
|  |       NULL, | ||||||
|  |       NULL, | ||||||
|  |       &timeout | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     // Check for errors | ||||||
|  |     if(activity < 0) { | ||||||
|  |       consolePrint("Error in select"); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Timeout | ||||||
|  |     if(activity == 0) continue; | ||||||
|  |  | ||||||
|  |     // Check if there is a new connection | ||||||
|  |     if(!FD_ISSET(SERVER.serverSocket, &readfds)) continue; | ||||||
|  |  | ||||||
|  |     // Accept new connection | ||||||
|  |     int32_t clientSocket = accept(SERVER.serverSocket, NULL, NULL); | ||||||
|  |     if(clientSocket < 0) { | ||||||
|  |       consolePrint("Failed to accept connection"); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     // Initialize the client | ||||||
|  |     serverclient_t *client = NULL; | ||||||
|  |     uint8_t i = 0; | ||||||
|  |     do { | ||||||
|  |       if(SERVER.clients[i].state != SERVER_CLIENT_STATE_DISCONNECTED) { | ||||||
|  |         i++; | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       client = &SERVER.clients[i]; | ||||||
|  |       break; | ||||||
|  |     } while(i < SERVER_MAX_CLIENTS); | ||||||
|  |  | ||||||
|  |     // Can we receive this client? | ||||||
|  |     if(!client) { | ||||||
|  |       const char_t *errMsg = "ERR|Server full"; | ||||||
|  |       send(clientSocket, errMsg, strlen(errMsg), 0); | ||||||
|  |       consolePrint("Server full, closing connection."); | ||||||
|  |       close(clientSocket); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     errorret_t ret = serverClientAccept(client, clientSocket); | ||||||
|  |     if(ret != ERROR_OK) { | ||||||
|  |       consolePrint("Failed to accept client connection", errorString()); | ||||||
|  |       errorFlush(); | ||||||
|  |       close(clientSocket); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     usleep(1000); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   printf("Server thread exiting.\n"); | ||||||
|  |   assertFalse( | ||||||
|  |     SERVER.isRunning, "Server thread exiting while server is running?" | ||||||
|  |   ); | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t serverGetClientCount() { | ||||||
|  |   uint8_t i = 0, clientCount = 0; | ||||||
|  |   do { | ||||||
|  |     if(SERVER.clients[i].state == SERVER_CLIENT_STATE_DISCONNECTED) continue; | ||||||
|  |     clientCount++; | ||||||
|  |   } while(i < SERVER_MAX_CLIENTS); | ||||||
|  |   return clientCount; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void serverStop() { | ||||||
|  |   consolePrint("Stopping server..."); | ||||||
|  |  | ||||||
|  |   SERVER.isRunning = false; | ||||||
|  |   if(SERVER.serverSocket >= 0) { | ||||||
|  |     close(SERVER.serverSocket); | ||||||
|  |     SERVER.serverSocket = -1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(SERVER.thread) { | ||||||
|  |     pthread_join(SERVER.thread, NULL); | ||||||
|  |     SERVER.thread = 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   pthread_mutex_destroy(&SERVER.startMutex); | ||||||
|  |   pthread_cond_destroy(&SERVER.startCond); | ||||||
|  |  | ||||||
|  |   consolePrint("Server stopped."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void serverDispose() { | ||||||
|  |   serverStop(); | ||||||
|  | } | ||||||
							
								
								
									
										81
									
								
								src/server/server.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								src/server/server.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright (c) 2025 Dominic Masters | ||||||
|  |  *  | ||||||
|  |  * This software is released under the MIT License. | ||||||
|  |  * https://opensource.org/licenses/MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include "serverclient.h" | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <arpa/inet.h> | ||||||
|  |  | ||||||
|  | #define SERVER_MAX_CLIENTS 32 | ||||||
|  | #define SERVER_MAX_CHANNELS 2 | ||||||
|  | #define SERVER_TIMEOUT 200 | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   bool_t isRunning; | ||||||
|  |   pthread_t thread; | ||||||
|  |   int serverSocket; | ||||||
|  |   struct sockaddr_in serverAddress; | ||||||
|  |   pthread_mutex_t startMutex; | ||||||
|  |   pthread_cond_t startCond; | ||||||
|  |   bool_t threadReady; | ||||||
|  |   serverclient_t clients[SERVER_MAX_CLIENTS]; | ||||||
|  | } server_t; | ||||||
|  |  | ||||||
|  | extern server_t SERVER; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Initialize the server | ||||||
|  |  *  | ||||||
|  |  * This function initializes the server by setting up the ENet library and | ||||||
|  |  * creating a server host. | ||||||
|  |  */ | ||||||
|  | void serverInit(); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Start the server | ||||||
|  |  *  | ||||||
|  |  * This function starts the server by creating a host, binding it to the | ||||||
|  |  * specified address and port, and starting the server thread. | ||||||
|  |  *  | ||||||
|  |  * @param port The port number to bind the server to. | ||||||
|  |  * @return Returns an error code if the server fails to start. | ||||||
|  |  */ | ||||||
|  | errorret_t serverStart(uint16_t port); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Server thread function | ||||||
|  |  *  | ||||||
|  |  * This function runs in a separate thread and handles incoming connections, | ||||||
|  |  * messages, and disconnections. | ||||||
|  |  *  | ||||||
|  |  * @param arg Pointer to the argument passed to the thread. | ||||||
|  |  */ | ||||||
|  | void * serverThread(void *arg); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Get the client count | ||||||
|  |  *  | ||||||
|  |  * This function returns the number of connected clients to the server. | ||||||
|  |  *  | ||||||
|  |  * @return The number of connected clients. | ||||||
|  |  */ | ||||||
|  | uint8_t serverGetClientCount(); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Stop the server | ||||||
|  |  *  | ||||||
|  |  * This function stops the server by destroying the host and cleaning up | ||||||
|  |  * resources. | ||||||
|  |  */ | ||||||
|  | void serverStop(); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Dispose of the server | ||||||
|  |  *  | ||||||
|  |  * This function disposes of the server by deinitializing the ENet library. | ||||||
|  |  */ | ||||||
|  | void serverDispose(); | ||||||
							
								
								
									
										109
									
								
								src/server/serverclient.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								src/server/serverclient.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright (c) 2025 Dominic Masters | ||||||
|  |  *  | ||||||
|  |  * This software is released under the MIT License. | ||||||
|  |  * https://opensource.org/licenses/MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #include "serverclient.h" | ||||||
|  | #include "util/memory.h" | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include "console/console.h" | ||||||
|  |  | ||||||
|  | errorret_t serverClientAccept( | ||||||
|  |   serverclient_t *client, | ||||||
|  |   const int32_t socket | ||||||
|  | ) { | ||||||
|  |   memoryZero(client, sizeof(serverclient_t)); | ||||||
|  |   client->socket = socket; | ||||||
|  |   client->state = SERVER_CLIENT_STATE_ACCEPTING; | ||||||
|  |  | ||||||
|  |   // Set timeout to 20 seconds | ||||||
|  |   client->timeout.tv_usec = SERVER_CLIENT_TIMEOUT * 1000; | ||||||
|  |  | ||||||
|  |   // Create a thread for the client | ||||||
|  |   if(pthread_create(&client->thread, NULL, serverClientThread, client) != 0) { | ||||||
|  |     client->state = SERVER_CLIENT_STATE_DISCONNECTED; | ||||||
|  |     return error("Failed to create client thread"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | errorret_t serverClientSend( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   const uint8_t *data, | ||||||
|  |   const size_t len | ||||||
|  | ) { | ||||||
|  |   if(client->state != SERVER_CLIENT_STATE_ACCEPTING) { | ||||||
|  |     return error("Client is not accepting"); | ||||||
|  |   } | ||||||
|  |   ssize_t sent = send(client->socket, data, len, 0); | ||||||
|  |   if(sent < 0) return error("Failed to send data"); | ||||||
|  |   return ERROR_OK; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | errorret_t serverClientSendString( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   const char_t *data | ||||||
|  | ) { | ||||||
|  |   return serverClientSend(client, (const uint8_t *)data, strlen(data)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ssize_t serverClientReceive( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   uint8_t *buffer, | ||||||
|  |   const size_t len | ||||||
|  | ) { | ||||||
|  |   if(client->state != SERVER_CLIENT_STATE_ACCEPTING) return -1; | ||||||
|  |   ssize_t received = recv(client->socket, buffer, len, 0); | ||||||
|  |   if(received < 0) return received; | ||||||
|  |   return received; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void serverClientClose(serverclient_t *client) { | ||||||
|  |   client->state = SERVER_CLIENT_STATE_DISCONNECTED; | ||||||
|  |   close(client->socket); | ||||||
|  |   pthread_join(client->thread, NULL); | ||||||
|  |   client->thread = 0; | ||||||
|  |   client->socket = -1; | ||||||
|  |   consolePrint("Client disconnected."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void *serverClientThread(void *arg) { | ||||||
|  |   serverclient_t *client = (serverclient_t *)arg; | ||||||
|  |   char_t buffer[1024]; | ||||||
|  |   ssize_t read; | ||||||
|  |  | ||||||
|  |   printf("Client thread started for socket %d.\n", client->socket); | ||||||
|  |  | ||||||
|  |   // Set socket timeout | ||||||
|  |   setsockopt( | ||||||
|  |     client->socket, | ||||||
|  |     SOL_SOCKET, | ||||||
|  |     SO_RCVTIMEO, | ||||||
|  |     &client->timeout, | ||||||
|  |     sizeof(client->timeout) | ||||||
|  |   ); | ||||||
|  |  | ||||||
|  |   // Send welcome message | ||||||
|  |   serverClientSendString(client, "DUSK|"DUSK_VERSION); | ||||||
|  |  | ||||||
|  |   // Receive version from client | ||||||
|  |   read = serverClientReceive(client, buffer, sizeof(buffer)); | ||||||
|  |  | ||||||
|  |   // First 5 bytes should be "DUSK|" | ||||||
|  |   if(read < 5 || strncmp(buffer, "DUSK|", 5) != 0) { | ||||||
|  |     serverClientSendString(client, "ERR|Invalid version (0)"); | ||||||
|  |     serverClientClose(client); | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Next (up to X bytes where X is the length of the version string) | ||||||
|  |   // should be the version string | ||||||
|  |   buffer[read] = '\0'; // Null-terminate the string | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   printf("Received version: %s\n", buffer); | ||||||
|  |    | ||||||
|  |   serverClientClose(client); | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
							
								
								
									
										85
									
								
								src/server/serverclient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								src/server/serverclient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | |||||||
|  | /** | ||||||
|  |  * Copyright (c) 2025 Dominic Masters | ||||||
|  |  *  | ||||||
|  |  * This software is released under the MIT License. | ||||||
|  |  * https://opensource.org/licenses/MIT | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  | #include "error/error.h" | ||||||
|  |  | ||||||
|  | #define SERVER_CLIENT_TIMEOUT 20000 // 20 seconds | ||||||
|  |  | ||||||
|  | typedef enum { | ||||||
|  |   SERVER_CLIENT_STATE_DISCONNECTED, | ||||||
|  |   SERVER_CLIENT_STATE_ACCEPTING, | ||||||
|  | } serverclientstate_t; | ||||||
|  |  | ||||||
|  | typedef struct { | ||||||
|  |   int32_t socket; | ||||||
|  |   serverclientstate_t state; | ||||||
|  |   pthread_t thread; // Add thread field | ||||||
|  |   struct timeval timeout; // Add timeout field | ||||||
|  | } serverclient_t; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Accepts an incoming connection from a server client. | ||||||
|  |  */ | ||||||
|  | errorret_t serverClientAccept( | ||||||
|  |   serverclient_t *client, | ||||||
|  |   const int32_t socket | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Sends data to a server client. | ||||||
|  |  *  | ||||||
|  |  * @param client Pointer to the server client structure. | ||||||
|  |  * @param data Pointer to the data to send. | ||||||
|  |  * @param len Length of the data to send. | ||||||
|  |  * @return Error code indicating success or failure. | ||||||
|  |  */ | ||||||
|  | errorret_t serverClientSend( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   const uint8_t *data, | ||||||
|  |   const size_t len | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Sends a string to a server client. | ||||||
|  |  *  | ||||||
|  |  * @param client Pointer to the server client structure. | ||||||
|  |  * @param data Pointer to the string to send. | ||||||
|  |  * @return Error code indicating success or failure. | ||||||
|  |  */ | ||||||
|  | errorret_t serverClientSendString( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   const char_t *data | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Receives data from a server client. | ||||||
|  |  *  | ||||||
|  |  * @param client Pointer to the server client structure. | ||||||
|  |  * @param buffer Pointer to the buffer to store received data. | ||||||
|  |  * @param len Max length of the buffer. | ||||||
|  |  * @return Number of bytes received. 0 or less indicates an error. | ||||||
|  |  */ | ||||||
|  | ssize_t serverClientReceive( | ||||||
|  |   serverclient_t * client, | ||||||
|  |   uint8_t *buffer, | ||||||
|  |   const size_t len | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Closes the connection to a server client. | ||||||
|  |  */ | ||||||
|  | void serverClientClose( | ||||||
|  |   serverclient_t *client | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Thread function for handling a server client. | ||||||
|  |  *  | ||||||
|  |  * @param arg Pointer to the server client structure. | ||||||
|  |  */ | ||||||
|  | void *serverClientThread(void *arg); | ||||||
		Reference in New Issue
	
	Block a user