aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorraysan5 <raysan5@gmail.com>2016-12-27 17:42:22 +0100
committerraysan5 <raysan5@gmail.com>2016-12-27 17:42:22 +0100
commit202f45415c98df2201202ba8edb10b6496cbeb62 (patch)
treeb151489e922b188b408f8b45aaf94b280a29b012 /src
parentbf3a213e44e8de1f61aeadc692c50290d3852a98 (diff)
downloadraylib-202f45415c98df2201202ba8edb10b6496cbeb62.tar.gz
raylib-202f45415c98df2201202ba8edb10b6496cbeb62.zip
rRES raylib resources custom file format support
First version of custom raylib resources file format -IN DEVELOPMENT-
Diffstat (limited to 'src')
-rw-r--r--src/raylib.h20
-rw-r--r--src/rres.h444
2 files changed, 464 insertions, 0 deletions
diff --git a/src/raylib.h b/src/raylib.h
index 6fd960dc..e2e4ee13 100644
--- a/src/raylib.h
+++ b/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
diff --git a/src/rres.h b/src/rres.h
new file mode 100644
index 00000000..dcf7be3f
--- /dev/null
+++ b/src/rres.h
@@ -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;
+*/ \ No newline at end of file