rRES raylib resources custom file format support

First version of custom raylib resources file format -IN DEVELOPMENT-
This commit is contained in:
raysan5 2016-12-27 17:42:22 +01:00
parent bf3a213e44
commit 202f45415c
2 changed files with 464 additions and 0 deletions

View File

@ -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
View 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;
*/