mirror of
				https://github.com/raysan5/raylib.git
				synced 2025-10-26 12:27:01 +00:00 
			
		
		
		
	rRES raylib resources custom file format support
First version of custom raylib resources file format -IN DEVELOPMENT-
This commit is contained in:
		
							
								
								
									
										20
									
								
								src/raylib.h
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/raylib.h
									
									
									
									
									
								
							| @@ -602,6 +602,26 @@ typedef enum { | ||||
|     HMD_FOVE_VR, | ||||
| } VrDevice; | ||||
|  | ||||
| // rRES data returned when reading a resource, it contains all required data for user (24 byte) | ||||
| typedef struct { | ||||
|     unsigned int type;          // Resource type (4 byte) | ||||
|      | ||||
|     unsigned int param1;        // Resouce parameter 1 (4 byte) | ||||
|     unsigned int param2;        // Resouce parameter 2 (4 byte) | ||||
|     unsigned int param3;        // Resouce parameter 3 (4 byte) | ||||
|     unsigned int param4;        // Resouce parameter 4 (4 byte) | ||||
|      | ||||
|     void *data;                 // Resource data pointer (4 byte) | ||||
| } RRESData; | ||||
|  | ||||
| typedef enum {  | ||||
|     RRES_RAW = 0,  | ||||
|     RRES_IMAGE,  | ||||
|     RRES_WAVE,  | ||||
|     RRES_VERTEX,  | ||||
|     RRES_TEXT  | ||||
| } RRESDataType; | ||||
|  | ||||
| #ifdef __cplusplus | ||||
| extern "C" {            // Prevents name mangling of functions | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										444
									
								
								src/rres.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										444
									
								
								src/rres.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,444 @@ | ||||
| /********************************************************************************************** | ||||
| * | ||||
| *   rres - raylib Resource custom format management functions | ||||
| * | ||||
| *   Basic functions to load/save rRES resource files | ||||
| * | ||||
| *   External libs: | ||||
| *       tinfl   -  DEFLATE decompression functions | ||||
| * | ||||
| *   Module Configuration Flags: | ||||
| * | ||||
| *       #define RREM_IMPLEMENTATION | ||||
| *           Generates the implementation of the library into the included file. | ||||
| * | ||||
| * | ||||
| *   Copyright (c) 2016-2017 Ramon Santamaria (@raysan5) | ||||
| * | ||||
| *   This software is provided "as-is", without any express or implied warranty. In no event | ||||
| *   will the authors be held liable for any damages arising from the use of this software. | ||||
| * | ||||
| *   Permission is granted to anyone to use this software for any purpose, including commercial | ||||
| *   applications, and to alter it and redistribute it freely, subject to the following restrictions: | ||||
| * | ||||
| *     1. The origin of this software must not be misrepresented; you must not claim that you | ||||
| *     wrote the original software. If you use this software in a product, an acknowledgment | ||||
| *     in the product documentation would be appreciated but is not required. | ||||
| * | ||||
| *     2. Altered source versions must be plainly marked as such, and must not be misrepresented | ||||
| *     as being the original software. | ||||
| * | ||||
| *     3. This notice may not be removed or altered from any source distribution. | ||||
| * | ||||
| **********************************************************************************************/ | ||||
|  | ||||
| #ifndef RRES_H | ||||
| #define RRES_H | ||||
|  | ||||
| #if !defined(RRES_STANDALONE) | ||||
|     #include "raylib.h" | ||||
| #endif | ||||
|  | ||||
| //#define RRES_STATIC | ||||
| #ifdef RRES_STATIC | ||||
|     #define RRESDEF static              // Functions just visible to module including this file | ||||
| #else | ||||
|     #ifdef __cplusplus | ||||
|         #define RRESDEF extern "C"      // Functions visible from other files (no name mangling of functions in C++) | ||||
|     #else | ||||
|         #define RRESDEF extern          // Functions visible from other files | ||||
|     #endif | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| #define MAX_RESOURCES_SUPPORTED   256 | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| // NOTE: Some types are required for RAYGUI_STANDALONE usage | ||||
| //---------------------------------------------------------------------------------- | ||||
| #if defined(RRES_STANDALONE) | ||||
|     // rRES data returned when reading a resource, it contains all required data for user (24 byte) | ||||
|     typedef struct { | ||||
|         unsigned int type;          // Resource type (4 byte) | ||||
|          | ||||
|         unsigned int param1;        // Resouce parameter 1 (4 byte) | ||||
|         unsigned int param2;        // Resouce parameter 2 (4 byte) | ||||
|         unsigned int param3;        // Resouce parameter 3 (4 byte) | ||||
|         unsigned int param4;        // Resouce parameter 4 (4 byte) | ||||
|          | ||||
|         void *data;                 // Resource data pointer (4 byte) | ||||
|     } RRESData; | ||||
|      | ||||
|     typedef enum {  | ||||
|         RRES_RAW = 0,  | ||||
|         RRES_IMAGE,  | ||||
|         RRES_WAVE,  | ||||
|         RRES_VERTEX,  | ||||
|         RRES_TEXT  | ||||
|     } RRESDataType; | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global variables | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| RRESDEF RRESData LoadResource(const char *rresFileName); | ||||
| RRESDEF RRESData LoadResourceById(const char *rresFileName, int rresId); | ||||
| RRESDEF void UnloadResource(RRESData rres); | ||||
|  | ||||
| #endif // RRES_H | ||||
|  | ||||
|  | ||||
| /*********************************************************************************** | ||||
| * | ||||
| *   RRES IMPLEMENTATION | ||||
| * | ||||
| ************************************************************************************/ | ||||
|  | ||||
| #if defined(RRES_IMPLEMENTATION) | ||||
|  | ||||
| #include <stdio.h>          // Required for: FILE, fopen(), fclose() | ||||
|  | ||||
| // Check if custom malloc/free functions defined, if not, using standard ones | ||||
| #if !defined(RRES_MALLOC) | ||||
|     #include <stdlib.h>     // Required for: malloc(), free() | ||||
|  | ||||
|     #define RRES_MALLOC(size)  malloc(size) | ||||
|     #define RRES_FREE(ptr)     free(ptr) | ||||
| #endif | ||||
|  | ||||
| #include "external/tinfl.c" // Required for: tinfl_decompress_mem_to_mem() | ||||
|                             // NOTE: DEFLATE algorythm data decompression | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Defines and Macros | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Types and Structures Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // rRES file header (8 byte) | ||||
| typedef struct { | ||||
|     char id[4];                 // File identifier: rRES (4 byte) | ||||
|     unsigned short version;     // File version and subversion (2 byte) | ||||
|     unsigned short count;       // Number of resources in this file (2 byte) | ||||
| } RRESFileHeader; | ||||
|  | ||||
| // rRES info header, every resource includes this header (12 byte + 16 byte) | ||||
| typedef struct { | ||||
|     unsigned short id;          // Resource unique identifier (2 byte) | ||||
|     unsigned char dataType;     // Resource data type (1 byte) | ||||
|     unsigned char compType;     // Resource data compression type (1 byte) | ||||
|     unsigned int dataSize;      // Resource data size (compressed or not, only DATA) (4 byte) | ||||
|     unsigned int uncompSize;    // Resource data size (uncompressed, only DATA) (4 byte) | ||||
|  | ||||
|     unsigned int param1;        // Resouce parameter 1 (4 byte) | ||||
|     unsigned int param2;        // Resouce parameter 2 (4 byte) | ||||
|     unsigned int param3;        // Resouce parameter 3 (4 byte) | ||||
|     unsigned int param4;        // Resouce parameter 4 (4 byte) | ||||
| } RRESInfoHeader; | ||||
|  | ||||
| // Compression types | ||||
| typedef enum {  | ||||
|     RRES_COMP_NONE = 0,         // No data compression | ||||
|     RRES_COMP_DEFLATE,          // DEFLATE compression | ||||
|     RRES_COMP_LZ4,              // LZ4 compression | ||||
|     RRES_COMP_LZMA,             // LZMA compression | ||||
|     // brotli, zopfli, gzip     // Other compression algorythms... | ||||
| } RRESCompressionType; | ||||
|  | ||||
| #if defined(RRES_STANDALONE) | ||||
| typedef enum { INFO = 0, ERROR, WARNING, DEBUG, OTHER } TraceLogType; | ||||
| #endif | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Global Variables Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
| //... | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Declaration | ||||
| //---------------------------------------------------------------------------------- | ||||
| static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize); | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module Functions Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // Load resource from file (only one) | ||||
| // NOTE: Returns uncompressed data with parameters, only first resource found | ||||
| RRESDEF RRESData LoadResource(const char *fileName) | ||||
| { | ||||
|     RRESData rres = { 0 }; | ||||
|      | ||||
|     RRESFileHeader fileHeader; | ||||
|     RRESInfoHeader infoHeader; | ||||
|      | ||||
|     FILE *rresFile = fopen(fileName, "rb"); | ||||
|  | ||||
|     if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName); | ||||
|     else | ||||
|     { | ||||
|         // Read rres file info header | ||||
|         fread(&fileHeader.id[0], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[1], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[2], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[3], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.version, sizeof(short), 1, rresFile); | ||||
|         fread(&fileHeader.count, sizeof(short), 1, rresFile); | ||||
|  | ||||
|         // Verify "rRES" identifier | ||||
|         if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) | ||||
|         { | ||||
|             TraceLog(WARNING, "[%s] This is not a valid raylib resource file", fileName); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Read first resource info and parameters | ||||
|             fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); | ||||
|              | ||||
|             // Register data type and parameters | ||||
|             rres.type = infoHeader.dataType; | ||||
|             rres.param1 = infoHeader.param1; | ||||
|             rres.param2 = infoHeader.param2; | ||||
|             rres.param3 = infoHeader.param3; | ||||
|             rres.param4 = infoHeader.param4; | ||||
|  | ||||
|             // Read resource data block | ||||
|             void *data = RRES_MALLOC(infoHeader.dataSize); | ||||
|             fread(data, infoHeader.dataSize, 1, rresFile); | ||||
|  | ||||
|             if (infoHeader.compType == RRES_COMP_DEFLATE) | ||||
|             { | ||||
|                 void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); | ||||
|                  | ||||
|                 rres.data = uncompData; | ||||
|                  | ||||
|                 RRES_FREE(data); | ||||
|             } | ||||
|             else rres.data = data; | ||||
|  | ||||
|             if (rres.data != NULL) TraceLog(INFO, "[%s] Resource data loaded successfully", fileName); | ||||
|         } | ||||
|  | ||||
|         fclose(rresFile); | ||||
|     } | ||||
|  | ||||
|     return rres; | ||||
| } | ||||
|  | ||||
| // Load resource from file by id | ||||
| // NOTE: Returns uncompressed data with parameters, search resource by id | ||||
| RRESDEF RRESData LoadResourceById(const char *fileName, int rresId) | ||||
| { | ||||
|     RRESData rres = { 0 }; | ||||
|      | ||||
|     RRESFileHeader fileHeader; | ||||
|     RRESInfoHeader infoHeader; | ||||
|      | ||||
|     FILE *rresFile = fopen(fileName, "rb"); | ||||
|  | ||||
|     if (rresFile == NULL) TraceLog(WARNING, "[%s] rRES raylib resource file could not be opened", fileName); | ||||
|     else | ||||
|     { | ||||
|         // Read rres file info header | ||||
|         fread(&fileHeader.id[0], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[1], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[2], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.id[3], sizeof(char), 1, rresFile); | ||||
|         fread(&fileHeader.version, sizeof(short), 1, rresFile); | ||||
|         fread(&fileHeader.count, sizeof(short), 1, rresFile); | ||||
|  | ||||
|         // Verify "rRES" identifier | ||||
|         if ((fileHeader.id[0] != 'r') && (fileHeader.id[1] != 'R') && (fileHeader.id[2] != 'E') && (fileHeader.id[3] != 'S')) | ||||
|         { | ||||
|             TraceLog(WARNING, "[%s] This is not a valid raylib resource file", fileName); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             for (int i = 0; i < fileHeader.count; i++) | ||||
|             { | ||||
|                 // Read resource info and parameters | ||||
|                 fread(&infoHeader, sizeof(RRESInfoHeader), 1, rresFile); | ||||
|  | ||||
|                 if (infoHeader.id == rresId) | ||||
|                 { | ||||
|                     // Register data type and parameters | ||||
|                     rres.type = infoHeader.dataType; | ||||
|                     rres.param1 = infoHeader.param1; | ||||
|                     rres.param2 = infoHeader.param2; | ||||
|                     rres.param3 = infoHeader.param3; | ||||
|                     rres.param4 = infoHeader.param4; | ||||
|  | ||||
|                     // Read resource data block | ||||
|                     void *data = RRES_MALLOC(infoHeader.dataSize); | ||||
|                     fread(data, infoHeader.dataSize, 1, rresFile); | ||||
|  | ||||
|                     if (infoHeader.compType == RRES_COMP_DEFLATE) | ||||
|                     { | ||||
|                         void *uncompData = DecompressData(data, infoHeader.dataSize, infoHeader.uncompSize); | ||||
|                          | ||||
|                         rres.data = uncompData; | ||||
|                          | ||||
|                         RRES_FREE(data); | ||||
|                     } | ||||
|                     else rres.data = data; | ||||
|  | ||||
|                     if (rres.data != NULL) TraceLog(INFO, "[%s][ID %i] Resource data loaded successfully", fileName, (int)rresId); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // Skip required data to read next resource infoHeader | ||||
|                     fseek(rresFile, infoHeader.dataSize, SEEK_CUR); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (rres.data == NULL) TraceLog(WARNING, "[%s][ID %i] Requested resource could not be found, wrong id?", fileName, (int)rresId); | ||||
|         } | ||||
|  | ||||
|         fclose(rresFile); | ||||
|     } | ||||
|  | ||||
|     return rres; | ||||
| } | ||||
|  | ||||
| RRESDEF void UnloadResource(RRESData rres) | ||||
| { | ||||
|     if (rres.data != NULL) free(rres.data); | ||||
| } | ||||
|  | ||||
| //---------------------------------------------------------------------------------- | ||||
| // Module specific Functions Definition | ||||
| //---------------------------------------------------------------------------------- | ||||
|  | ||||
| // Data decompression function | ||||
| // NOTE: Allocated data MUST be freed by user | ||||
| static void *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) | ||||
| { | ||||
|     int tempUncompSize; | ||||
|     void *uncompData; | ||||
|  | ||||
|     // Allocate buffer to hold decompressed data | ||||
|     uncompData = (mz_uint8 *)RRES_MALLOC((size_t)uncompSize); | ||||
|  | ||||
|     // Check correct memory allocation | ||||
|     if (uncompData == NULL) | ||||
|     { | ||||
|         TraceLog(WARNING, "Out of memory while decompressing data"); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // Decompress data | ||||
|         tempUncompSize = tinfl_decompress_mem_to_mem(uncompData, (size_t)uncompSize, data, compSize, 1); | ||||
|  | ||||
|         if (tempUncompSize == -1) | ||||
|         { | ||||
|             TraceLog(WARNING, "Data decompression failed"); | ||||
|             RRES_FREE(uncompData); | ||||
|         } | ||||
|  | ||||
|         if (uncompSize != (int)tempUncompSize) | ||||
|         { | ||||
|             TraceLog(WARNING, "Expected uncompressed size do not match, data may be corrupted"); | ||||
|             TraceLog(WARNING, " -- Expected uncompressed size: %i", uncompSize); | ||||
|             TraceLog(WARNING, " -- Returned uncompressed size: %i", tempUncompSize); | ||||
|         } | ||||
|  | ||||
|         TraceLog(INFO, "Data decompressed successfully from %u bytes to %u bytes", (mz_uint32)compSize, (mz_uint32)tempUncompSize); | ||||
|     } | ||||
|  | ||||
|     return uncompData; | ||||
| } | ||||
|  | ||||
|  | ||||
| // Some required functions for rres standalone module version | ||||
| #if defined(RRES_STANDALONE) | ||||
| // Outputs a trace log message (INFO, ERROR, WARNING) | ||||
| // NOTE: If a file has been init, output log is written there | ||||
| void TraceLog(int msgType, const char *text, ...) | ||||
| { | ||||
|     va_list args; | ||||
|     int traceDebugMsgs = 0; | ||||
|  | ||||
| #ifdef DO_NOT_TRACE_DEBUG_MSGS | ||||
|     traceDebugMsgs = 0; | ||||
| #endif | ||||
|  | ||||
|     switch (msgType) | ||||
|     { | ||||
|         case INFO: fprintf(stdout, "INFO: "); break; | ||||
|         case ERROR: fprintf(stdout, "ERROR: "); break; | ||||
|         case WARNING: fprintf(stdout, "WARNING: "); break; | ||||
|         case DEBUG: if (traceDebugMsgs) fprintf(stdout, "DEBUG: "); break; | ||||
|         default: break; | ||||
|     } | ||||
|  | ||||
|     if ((msgType != DEBUG) || ((msgType == DEBUG) && (traceDebugMsgs))) | ||||
|     { | ||||
|         va_start(args, text); | ||||
|         vfprintf(stdout, text, args); | ||||
|         va_end(args); | ||||
|  | ||||
|         fprintf(stdout, "\n"); | ||||
|     } | ||||
|  | ||||
|     if (msgType == ERROR) exit(1);      // If ERROR message, exit program | ||||
| } | ||||
| #endif | ||||
|  | ||||
| #endif // RAYGUI_IMPLEMENTATION | ||||
|  | ||||
|  | ||||
| /* | ||||
| //T LoadResource(const char *rresFileName, int resId); | ||||
|  | ||||
| // ASSUMPTION: rRES files only contain one resource (solution to id requirement...) | ||||
|  | ||||
| // Now, rres file check and data loading can be managed inside each function: | ||||
| Image LoadImage();          // -> Texture2D | ||||
| Wave LoadWave()             // -> Sound, Music | ||||
| const char *LoadText();     // -> Shader, Material | ||||
|  | ||||
| // NOTE: RRESData uses void* data pointer, so we can load to image.data, wave.data, mesh.*, (unsigned char *) | ||||
|  | ||||
| Image LoadImagePro(void *data, int width, int height, int format); | ||||
| Image LoadImagePro(rres.data, rres.param1, rres.param2, rres.param3); | ||||
|  | ||||
| Mesh LoadMeshEx(int numVertex, float *vData, float *vtData, float *vnData, Color *cData); | ||||
| Mesh LoadMeshEx(rres.param1, rres.data, rres.data + offset, rres.data + offset*2, rres.data + offset*3); | ||||
|  | ||||
| Shader LoadShaderV(const char *vsText, int vsLength); | ||||
| Shader LoadShaderV(rres.data, rres.param1); | ||||
|  | ||||
| Wave LoadWaveEx(void *data, int sampleCount, int sampleRate, int sampleSize, int channels); | ||||
| Wave LoadWaveEx(rres.data, rres.param1, (int)rres.param2, (int)rres.param3, (int)rres.param4); | ||||
|  | ||||
| // Max value for an unsigned short: 65535 | ||||
|  | ||||
| // Parameters information depending on resource type (IMAGE, WAVE, MESH, TEXT) | ||||
|  | ||||
| // Image data params | ||||
| int imgWidth, imgHeight; | ||||
| char colorFormat, mipmaps; | ||||
|  | ||||
| // Wave data params | ||||
| short sampleRate, bps; | ||||
| char channels, reserved; | ||||
|  | ||||
| // Mesh data params | ||||
| int vertexCount, reserved; | ||||
| short vertexTypesMask, vertexFormatsMask; | ||||
|  | ||||
| // Text data params | ||||
| int numChars; | ||||
| char textFormat, language, charsetCode; | ||||
| */ | ||||
		Reference in New Issue
	
	Block a user
	 raysan5
					raysan5