From 2cf5fa77658af7f5e72245e798db6b3a3f256371 Mon Sep 17 00:00:00 2001 From: raysan5 Date: Thu, 23 Jan 2014 12:36:18 +0100 Subject: [PATCH] Updated raylib to version 1.0.4 Lots of changes added, check CHANGELOG for detailed description --- CHANGELOG | 23 +- README.md | 5 +- ROADMAP.md | 2 +- release/win32-mingw/include/raylib.h | 66 +-- release/win32-mingw/lib/libraylib.a | Bin 140226 -> 170068 bytes src/audio.c | 190 ++++++++- src/core.c | 38 +- src/raylib.h | 66 +-- src/textures.c | 179 +++++--- src/tinfl.c | 592 +++++++++++++++++++++++++++ src/utils.c | 127 ++++++ src/utils.h | 71 ++++ src/vector3.h | 2 +- tools/README.txt | 36 ++ tools/rrem.exe | Bin 0 -> 241166 bytes 15 files changed, 1283 insertions(+), 114 deletions(-) create mode 100644 src/tinfl.c create mode 100644 src/utils.c create mode 100644 src/utils.h create mode 100644 tools/README.txt create mode 100644 tools/rrem.exe diff --git a/CHANGELOG b/CHANGELOG index 6c8b2657c..cce8ada50 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,32 @@ changelog --------- -Current Release: raylib 1.0.3 (December 2013) +Current Release: raylib 1.0.4 (January 2014) NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source. NOTE: Current Release includes all previous updates. +----------------------------------------------- +Release: raylib 1.0.4 (23 January 2014) +----------------------------------------------- +[tool] Published a first alpha version of rREM tool (raylib Resource Embedder) +[core] GetRandomValue() - Bug corrected, now works right +[core] Fade() - Added, fades a color to an alpha percentadge +[core] WriteBitmap() - Moved to new module: utils.c, not used anymore +[core] TakeScreenshot() - Now uses WritePNG() (utils.c) +[utils] New module created with utility functions +[utils] WritePNG() - Write a PNG file (used by TakeScreenshot() on core) +[utils] DecompressData() - Added, used for rRES resource data decompresion +[textures] LoadImageFromRES() - Added, load an image from a rRES resource file +[textures] LoadTextureFromRES() - Added, load a texture from a rRES resource file +[audio] LoadSoundFromRES() - Added, load a sound from a rRES resource file +[audio] IsPlaying() - Added, check if a sound is currently playing +[audio] SetVolume() - Added, set the volume for a sound +[audio] SetPitch() - Added, set the pitch for a sound +[examples] ex06a_color_select completed +[examples] ex06b_logo_anim completed +[examples] ex06c_font select completed + ----------------------------------------------- Release: raylib 1.0.3 (19 December 2013) ----------------------------------------------- diff --git a/README.md b/README.md index 50a2d0d10..9dcb2a66b 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ about ----- -raylib is a simple and easy-to-use library to learn C videogames programming. +raylib is a simple and easy-to-use library to learn videogames programming. raylib is highly inspired by Borland BGI graphics lib (more specifically WinBGI) and by XNA framework. Allegro and SDL have also been analyzed for reference. @@ -80,7 +80,8 @@ raylib could be build with the following command lines (Using GCC compiler): gcc -c models.c -std=c99 -Wall gcc -c vector3.c -std=c99 -Wall gcc -c audio.c -std=c99 -Wall - ar rcs raylib.a core.o shapes.o textures.o stb_image.o text.o models.o vector3.o audio.o + gcc -c utils.c -std=c99 -Wall + ar rcs raylib.a core.o shapes.o textures.o stb_image.o text.o models.o vector3.o utils.o audio.o To compile examples, make sure raylib.h is placed in include path and libraries raylib (libraylib.a) and glfw3 (libglfw3.a) are placed in the libraries path. It's also recommended to link with file icon.o for fancy raylib icon usage. diff --git a/ROADMAP.md b/ROADMAP.md index cb0e03043..cd2603b9e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ Around the source code there are some TODO points with pending revisions/bugs an raylib v1.x - Review Billboard Drawing functions - - Review Heightmap Loading and Drawing functions + - Review Heightmap Loading and Drawing functions - Load Heightmap directly as a Model - Lighting support (only 3d mode) - CreateLight() - [DONE] Simple Collision Detection functions - Default scene Camera controls (zoom, pan, rotate) diff --git a/release/win32-mingw/include/raylib.h b/release/win32-mingw/include/raylib.h index da6451147..dff65ae6e 100644 --- a/release/win32-mingw/include/raylib.h +++ b/release/win32-mingw/include/raylib.h @@ -1,8 +1,8 @@ /********************************************************************************************* * -* raylib 1.0.3 (www.raylib.com) +* raylib 1.0.4 (www.raylib.com) * -* A simple and easy-to-use library to learn C videogames programming +* A simple and easy-to-use library to learn videogames programming * * Features: * Library written in plain C code (C99) @@ -16,13 +16,14 @@ * GLFW3 (www.glfw.org) for window/context management and input * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * OpenAL Soft for audio device/context management +* tinfl for data decompression (DEFLATE algorithm) * * Some design decisions: * 32bit Colors - All defined color are always RGBA * 32bit Textures - All loaded images are converted automatically to RGBA textures * SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures * One custom default font is loaded automatically when InitWindow() -* +* * -- LICENSE (raylib v1.0, November 2013) -- * * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, @@ -236,29 +237,31 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ -void InitWindow(int width, int height, const char *title); // Initialize Window and Graphics Context (OpenGL) -void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage); -void CloseWindow(); // Close Window and Terminate Context -bool WindowShouldClose(); // Detect if KEY_ESCAPE pressed or Close icon pressed -void ToggleFullscreen(); // Fullscreen toggle (by default F11) -void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image -void SetExitKey(int key); // Set a custom key to exit program (default is ESC) +void InitWindow(int width, int height, const char *title); // Initialize Window and Graphics Context (OpenGL) +void InitWindowEx(int width, int height, const char* title, // Initialize Window and Graphics Context (OpenGL),... + bool resizable, const char *cursorImage); // ...define if windows-resizable and custom cursor +void CloseWindow(); // Close Window and Terminate Context +bool WindowShouldClose(); // Detect if KEY_ESCAPE pressed or Close icon pressed +void ToggleFullscreen(); // Fullscreen toggle (by default F11) +void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image +void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -void ClearBackground(Color color); // Sets Background Color -void BeginDrawing(); // Setup drawing canvas to start drawing -void EndDrawing(); // End canvas drawing and Swap Buffers (Double Buffering) +void ClearBackground(Color color); // Sets Background Color +void BeginDrawing(); // Setup drawing canvas to start drawing +void EndDrawing(); // End canvas drawing and Swap Buffers (Double Buffering) -void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) -void End3dMode(); // Ends 3D mode and returns to default 2D orthographic mode +void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) +void End3dMode(); // Ends 3D mode and returns to default 2D orthographic mode -void SetTargetFPS(int fps); // Set target FPS (maximum) -float GetFPS(); // Returns current FPS -float GetFrameTime(); // Returns time in seconds for one frame +void SetTargetFPS(int fps); // Set target FPS (maximum) +float GetFPS(); // Returns current FPS +float GetFrameTime(); // Returns time in seconds for one frame -Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -int GetHexValue(Color color); // Returns hexadecimal value for a Color +Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +int GetHexValue(Color color); // Returns hexadecimal value for a Color -int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) +int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) +Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0 to 1.0 //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) @@ -317,15 +320,18 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 // Texture Loading and Drawing Functions (Module: textures) //------------------------------------------------------------------------------------ Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) -void UnloadImage(Image image); // Unload image from CPU memory (RAM) +Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory -//Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps); // Load an image as texture (and convert to POT with mipmaps) (raylib 1.x) +Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) +Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data +void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadTexture(Texture2D texture); // Unload texture from GPU memory + void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters -Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data +void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters + float rotation, Color tint); //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) @@ -334,7 +340,8 @@ SpriteFont GetDefaultFont(); SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int fontSize, int spacing, Color tint); // Draw text using SpriteFont +void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters + int fontSize, int spacing, Color tint); int MeasureText(const char *text, int fontSize); // Measure string width for default font Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont int GetFontBaseSize(SpriteFont spriteFont); // Returns the base size for a SpriteFont (chars height) @@ -362,6 +369,7 @@ void DrawGizmo(Vector3 position, bool orbits); // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) +//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) void UnloadModel(Model model); // Unload 3d model from memory void DrawModel(Model model, Vector3 position, float scale, Color color); // Draw a model void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a textured model @@ -380,11 +388,15 @@ void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vect void InitAudioDevice(); // Initialize audio device and context void CloseAudioDevice(); // Close the audio device and context Sound LoadSound(char *fileName); // Load sound to memory +Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) void UnloadSound(Sound sound); // Unload sound + void PlaySound(Sound sound); // Play a sound -void PlaySoundEx(Sound sound, float timePosition, bool loop); // Play a sound with extended parameters void PauseSound(Sound sound); // Pause a sound void StopSound(Sound sound); // Stop playing a sound +bool IsPlaying(Sound sound); // Check if a sound is currently playing +void SetVolume(Sound sound, float volume); // Set volume for a sound (1.0 is base level) +void SetPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) #ifdef __cplusplus } diff --git a/release/win32-mingw/lib/libraylib.a b/release/win32-mingw/lib/libraylib.a index dc6edb6dcd0afb432eced4775abee3e4031e77de..e0a1dd4dc7f8f00368ca17231d03865504064a3f 100644 GIT binary patch delta 40178 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 delta 11393 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 // To use exit() function #include // Used for .WAV loading +#include "utils.h" // rRES data decompression utility function + //#include "stb_vorbis.h" // TODO: OGG loading functions //---------------------------------------------------------------------------------- @@ -52,8 +54,7 @@ typedef struct Wave { unsigned int sampleRate; unsigned int dataSize; short bitsPerSample; - short channels; - short format; + short channels; } Wave; //---------------------------------------------------------------------------------- @@ -179,6 +180,159 @@ Sound LoadSound(char *fileName) return sound; } +// Load sound to memory from rRES file (raylib Resource) +Sound LoadSoundFromRES(const char *rresName, int resId) +{ + // NOTE: rresName could be directly a char array with all the data!!! --> TODO + Sound sound; + bool found = false; + + char id[4]; // rRES file identifier + unsigned char version; // rRES file version and subversion + char useless; // rRES header reserved data + short numRes; + + ResInfoHeader infoHeader; + + FILE *rresFile = fopen(rresName, "rb"); + + if (!rresFile) printf("Error opening raylib Resource file\n"); + + // Read rres file (basic file check - id) + fread(&id[0], sizeof(char), 1, rresFile); + fread(&id[1], sizeof(char), 1, rresFile); + fread(&id[2], sizeof(char), 1, rresFile); + fread(&id[3], sizeof(char), 1, rresFile); + fread(&version, sizeof(char), 1, rresFile); + fread(&useless, sizeof(char), 1, rresFile); + + if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) + { + printf("This is not a valid raylib Resource file!\n"); + exit(1); + } + + // Read number of resources embedded + fread(&numRes, sizeof(short), 1, rresFile); + + for (int i = 0; i < numRes; i++) + { + fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); + + if (infoHeader.id == resId) + { + found = true; + + // Check data is of valid SOUND type + if (infoHeader.type == 1) // SOUND data type + { + // TODO: Check data compression type + // NOTE: We suppose compression type 2 (DEFLATE - default) + + // Reading SOUND parameters + Wave wave; + short sampleRate, bps; + char channels, reserved; + + fread(&sampleRate, sizeof(short), 1, rresFile); // Sample rate (frequency) + fread(&bps, sizeof(short), 1, rresFile); // Bits per sample + fread(&channels, 1, 1, rresFile); // Channels (1 - mono, 2 - stereo) + fread(&reserved, 1, 1, rresFile); // + + printf("Sample rate: %i\n", (int)sampleRate); + printf("Bits per sample: %i\n", (int)bps); + printf("Channels: %i\n", (int)channels); + + wave.sampleRate = sampleRate; + wave.dataSize = infoHeader.srcSize; + wave.bitsPerSample = bps; + wave.channels = (short)channels; + + unsigned char *data = malloc(infoHeader.size); + + fread(data, infoHeader.size, 1, rresFile); + + wave.data = DecompressData(data, infoHeader.size, infoHeader.srcSize); + + free(data); + + // Convert wave to Sound (OpenAL) + ALenum format; + + // The OpenAL format is worked out by looking at the number of channels and the bits per sample + if (wave.channels == 1) + { + if (wave.bitsPerSample == 8 ) format = AL_FORMAT_MONO8; + else if (wave.bitsPerSample == 16) format = AL_FORMAT_MONO16; + } + else if (wave.channels == 2) + { + if (wave.bitsPerSample == 8 ) format = AL_FORMAT_STEREO8; + else if (wave.bitsPerSample == 16) format = AL_FORMAT_STEREO16; + } + + + // Create an audio source + ALuint source; + alGenSources(1, &source); // Generate pointer to audio source + + alSourcef(source, AL_PITCH, 1); + alSourcef(source, AL_GAIN, 1); + alSource3f(source, AL_POSITION, 0, 0, 0); + alSource3f(source, AL_VELOCITY, 0, 0, 0); + alSourcei(source, AL_LOOPING, AL_FALSE); + + // Convert loaded data to OpenAL buffer + //---------------------------------------- + ALuint buffer; + alGenBuffers(1, &buffer); // Generate pointer to buffer + + // Upload sound data to buffer + alBufferData(buffer, format, (void*)wave.data, wave.dataSize, wave.sampleRate); + + // Attach sound buffer to source + alSourcei(source, AL_BUFFER, buffer); + + // Unallocate WAV data + UnloadWAV(wave); + + printf("Audio file loaded...!\n"); + + sound.source = source; + sound.buffer = buffer; + } + else + { + + printf("Required resource do not seem to be a valid IMAGE resource\n"); + exit(2); + } + } + else + { + // Depending on type, skip the right amount of parameters + switch (infoHeader.type) + { + case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters + case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters + case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) + case 3: break; // TEXT: No parameters + case 4: break; // RAW: No parameters + default: break; + } + + // Jump DATA to read next infoHeader + fseek(rresFile, infoHeader.size, SEEK_CUR); + } + } + + fclose(rresFile); + + if (!found) printf("Required resource id could not be found in the raylib Resource file!\n"); + + return sound; +} + // Unload sound void UnloadSound(Sound sound) { @@ -197,10 +351,18 @@ void PlaySound(Sound sound) // NOTE: Only work when the entire file is in a single buffer //int byteOffset; //alGetSourcei(sound.source, AL_BYTE_OFFSET, &byteOffset); + // + //int sampleRate; + //alGetBufferi(sound.buffer, AL_FREQUENCY, &sampleRate); // AL_CHANNELS, AL_BITS (bps) + //float seconds = (float)byteOffset / sampleRate; // Number of seconds since the beginning of the sound + //or + //float result; + //alGetSourcef(sound.source, AL_SEC_OFFSET, &result); // AL_SAMPLE_OFFSET } // Play a sound with extended options +// TODO: This function should be reviewed... void PlaySoundEx(Sound sound, float timePosition, bool loop) { // TODO: Review @@ -227,6 +389,30 @@ void StopSound(Sound sound) alSourceStop(sound.source); } +// Check if a sound is playing +bool IsPlaying(Sound sound) +{ + bool playing = false; + ALint state; + + alGetSourcei(sound.source, AL_SOURCE_STATE, &state); + if (state == AL_PLAYING) playing = true; + + return playing; +} + +// Set volume for a sound +void SetVolume(Sound sound, float volume) +{ + alSourcef(sound.source, AL_GAIN, volume); +} + +// Set pitch for a sound +void SetPitch(Sound sound, float pitch) +{ + alSourcef(sound.source, AL_PITCH, pitch); +} + // Load WAV file into Wave structure static Wave LoadWAV(char *fileName) { diff --git a/src/core.c b/src/core.c index 920f34a30..78525483c 100644 --- a/src/core.c +++ b/src/core.c @@ -35,6 +35,7 @@ #include // Useful to initialize random seed #include // Math related functions, tan() on SetPerspective #include "vector3.h" // Basic Vector3 functions +#include "utils.h" // WritePNG() function //#define GLFW_DLL // Using GLFW DLL on Windows -> No, we use static version! @@ -81,7 +82,6 @@ static char currentGamepadState[32] = {0}; // Required to check if gamepad btn //---------------------------------------------------------------------------------- extern void LoadDefaultFont(); // [Module: text] Loads default font on InitWindow() extern void UnloadDefaultFont(); // [Module: text] Unloads default font from GPU memory -extern void WriteBitmap(const char *fileName, const pixel *imgDataPixel, int width, int height); // [Module: textures] Writes a bitmap (BMP) file //---------------------------------------------------------------------------------- // Module specific Functions Declaration @@ -354,6 +354,15 @@ int GetRandomValue(int min, int max) return (rand()%(abs(max-min)+1) + min); } +// Fades color by a percentadge +Color Fade(Color color, float alpha) +{ + if (alpha < 0.0) alpha = 0.0; + else if (alpha > 1.0) alpha = 1.0; + + return (Color){color.r, color.g, color.b, color.a*alpha}; +} + //---------------------------------------------------------------------------------- // Module Functions Definition - Input (Keyboard, Mouse, Gamepad) Functions //---------------------------------------------------------------------------------- @@ -737,21 +746,36 @@ static void TakeScreenshot() char buffer[20]; // Buffer to store file name int fbWidth, fbHeight; - Color *imgDataPixel; // Pixel image data array + unsigned char *imgData; // Pixel image data array glfwGetFramebufferSize(window, &fbWidth, &fbHeight); // Get framebuffer size of current window - imgDataPixel = (Color *)malloc(fbWidth * fbHeight * sizeof(Color)); + imgData = (unsigned char *)malloc(fbWidth * fbHeight * sizeof(unsigned char) * 4); // NOTE: glReadPixels returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer - glReadPixels(0, 0, fbWidth, fbHeight, GL_RGBA, GL_UNSIGNED_BYTE, imgDataPixel); + glReadPixels(0, 0, fbWidth, fbHeight, GL_RGBA, GL_UNSIGNED_BYTE, imgData); - sprintf(buffer, "screenshot%03i.bmp", shotNum); + // TODO: Flip image vertically! + + unsigned char *imgDataFlip = (unsigned char *)malloc(fbWidth * fbHeight * sizeof(unsigned char) * 4); + + for (int y = fbHeight-1; y >= 0; y--) + { + for (int x = 0; x < (fbWidth*4); x++) + { + imgDataFlip[x + (fbHeight - y - 1)*fbWidth*4] = imgData[x + (y*fbWidth*4)]; + } + } + + free(imgData); + + sprintf(buffer, "screenshot%03i.png", shotNum); // NOTE: BMP directly stores data flipped vertically - WriteBitmap(buffer, imgDataPixel, fbWidth, fbHeight); // Writes pixel data array into a bitmap (BMP) file + //WriteBitmap(buffer, imgDataPixel, fbWidth, fbHeight); // Writes pixel data array into a bitmap (BMP) file + WritePNG(buffer, imgDataFlip, fbWidth, fbHeight); - free(imgDataPixel); + free(imgDataFlip); shotNum++; } \ No newline at end of file diff --git a/src/raylib.h b/src/raylib.h index da6451147..dff65ae6e 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1,8 +1,8 @@ /********************************************************************************************* * -* raylib 1.0.3 (www.raylib.com) +* raylib 1.0.4 (www.raylib.com) * -* A simple and easy-to-use library to learn C videogames programming +* A simple and easy-to-use library to learn videogames programming * * Features: * Library written in plain C code (C99) @@ -16,13 +16,14 @@ * GLFW3 (www.glfw.org) for window/context management and input * stb_image (Sean Barret) for images loading (JPEG, PNG, BMP, TGA, PSD, GIF, HDR, PIC) * OpenAL Soft for audio device/context management +* tinfl for data decompression (DEFLATE algorithm) * * Some design decisions: * 32bit Colors - All defined color are always RGBA * 32bit Textures - All loaded images are converted automatically to RGBA textures * SpriteFonts - All loaded sprite-font images are converted to RGBA and POT textures * One custom default font is loaded automatically when InitWindow() -* +* * -- LICENSE (raylib v1.0, November 2013) -- * * raylib is licensed under an unmodified zlib/libpng license, which is an OSI-certified, @@ -236,29 +237,31 @@ extern "C" { // Prevents name mangling of functions //------------------------------------------------------------------------------------ // Window and Graphics Device Functions (Module: core) //------------------------------------------------------------------------------------ -void InitWindow(int width, int height, const char *title); // Initialize Window and Graphics Context (OpenGL) -void InitWindowEx(int width, int height, const char* title, bool resizable, const char *cursorImage); -void CloseWindow(); // Close Window and Terminate Context -bool WindowShouldClose(); // Detect if KEY_ESCAPE pressed or Close icon pressed -void ToggleFullscreen(); // Fullscreen toggle (by default F11) -void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image -void SetExitKey(int key); // Set a custom key to exit program (default is ESC) +void InitWindow(int width, int height, const char *title); // Initialize Window and Graphics Context (OpenGL) +void InitWindowEx(int width, int height, const char* title, // Initialize Window and Graphics Context (OpenGL),... + bool resizable, const char *cursorImage); // ...define if windows-resizable and custom cursor +void CloseWindow(); // Close Window and Terminate Context +bool WindowShouldClose(); // Detect if KEY_ESCAPE pressed or Close icon pressed +void ToggleFullscreen(); // Fullscreen toggle (by default F11) +void SetCustomCursor(const char *cursorImage); // Set a custom cursor icon/image +void SetExitKey(int key); // Set a custom key to exit program (default is ESC) -void ClearBackground(Color color); // Sets Background Color -void BeginDrawing(); // Setup drawing canvas to start drawing -void EndDrawing(); // End canvas drawing and Swap Buffers (Double Buffering) +void ClearBackground(Color color); // Sets Background Color +void BeginDrawing(); // Setup drawing canvas to start drawing +void EndDrawing(); // End canvas drawing and Swap Buffers (Double Buffering) -void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) -void End3dMode(); // Ends 3D mode and returns to default 2D orthographic mode +void Begin3dMode(Camera cam); // Initializes 3D mode for drawing (Camera setup) +void End3dMode(); // Ends 3D mode and returns to default 2D orthographic mode -void SetTargetFPS(int fps); // Set target FPS (maximum) -float GetFPS(); // Returns current FPS -float GetFrameTime(); // Returns time in seconds for one frame +void SetTargetFPS(int fps); // Set target FPS (maximum) +float GetFPS(); // Returns current FPS +float GetFrameTime(); // Returns time in seconds for one frame -Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value -int GetHexValue(Color color); // Returns hexadecimal value for a Color +Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +int GetHexValue(Color color); // Returns hexadecimal value for a Color -int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) +int GetRandomValue(int min, int max); // Returns a random value between min and max (both included) +Color Fade(Color color, float alpha); // Color fade-in or fade-out, alpha goes from 0.0 to 1.0 //------------------------------------------------------------------------------------ // Input Handling Functions (Module: core) @@ -317,15 +320,18 @@ bool CheckCollisionPointTriangle(Vector2 point, Vector2 p1, Vector2 p2, Vector2 // Texture Loading and Drawing Functions (Module: textures) //------------------------------------------------------------------------------------ Image LoadImage(const char *fileName); // Load an image into CPU memory (RAM) -void UnloadImage(Image image); // Unload image from CPU memory (RAM) +Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource) Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory -//Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps); // Load an image as texture (and convert to POT with mipmaps) (raylib 1.x) +Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource) +Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data +void UnloadImage(Image image); // Unload image from CPU memory (RAM) void UnloadTexture(Texture2D texture); // Unload texture from GPU memory + void DrawTexture(Texture2D texture, int posX, int posY, Color tint); // Draw a Texture2D void DrawTextureEx(Texture2D texture, Vector2 position, float rotation, float scale, Color tint); // Draw a Texture2D with extended parameters void DrawTextureRec(Texture2D texture, Rectangle sourceRec, Vector2 position, Color tint); // Draw a part of a texture defined by a rectangle -void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, float rotation, Color tint); // Draw a part of a texture defined by a rectangle with 'pro' parameters -Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data +void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, Vector2 origin, // Draw a part of a texture defined by a rectangle with 'pro' parameters + float rotation, Color tint); //------------------------------------------------------------------------------------ // Font Loading and Text Drawing Functions (Module: text) @@ -334,7 +340,8 @@ SpriteFont GetDefaultFont(); SpriteFont LoadSpriteFont(const char *fileName); // Load a SpriteFont image into GPU memory void UnloadSpriteFont(SpriteFont spriteFont); // Unload SpriteFont from GPU memory void DrawText(const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) -void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, int fontSize, int spacing, Color tint); // Draw text using SpriteFont +void DrawTextEx(SpriteFont spriteFont, const char* text, Vector2 position, // Draw text using SpriteFont and additional parameters + int fontSize, int spacing, Color tint); int MeasureText(const char *text, int fontSize); // Measure string width for default font Vector2 MeasureTextEx(SpriteFont spriteFont, const char *text, int fontSize, int spacing); // Measure string size for SpriteFont int GetFontBaseSize(SpriteFont spriteFont); // Returns the base size for a SpriteFont (chars height) @@ -362,6 +369,7 @@ void DrawGizmo(Vector3 position, bool orbits); // Model 3d Loading and Drawing Functions (Module: models) //------------------------------------------------------------------------------------ Model LoadModel(const char *fileName); // Load a 3d model (.OBJ) +//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource) void UnloadModel(Model model); // Unload 3d model from memory void DrawModel(Model model, Vector3 position, float scale, Color color); // Draw a model void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a textured model @@ -380,11 +388,15 @@ void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vect void InitAudioDevice(); // Initialize audio device and context void CloseAudioDevice(); // Close the audio device and context Sound LoadSound(char *fileName); // Load sound to memory +Sound LoadSoundFromRES(const char *rresName, int resId); // Load sound to memory from rRES file (raylib Resource) void UnloadSound(Sound sound); // Unload sound + void PlaySound(Sound sound); // Play a sound -void PlaySoundEx(Sound sound, float timePosition, bool loop); // Play a sound with extended parameters void PauseSound(Sound sound); // Pause a sound void StopSound(Sound sound); // Stop playing a sound +bool IsPlaying(Sound sound); // Check if a sound is currently playing +void SetVolume(Sound sound, float volume); // Set volume for a sound (1.0 is base level) +void SetPitch(Sound sound, float pitch); // Set pitch for a sound (1.0 is base level) #ifdef __cplusplus } diff --git a/src/textures.c b/src/textures.c index 19eb09b42..ee073e9ab 100644 --- a/src/textures.c +++ b/src/textures.c @@ -32,6 +32,8 @@ #include // Declares malloc() and free() for memory management #include "stb_image.h" // Used to read image data (multiple formats support) +#include "utils.h" // rRES data decompression utility function + //---------------------------------------------------------------------------------- // Defines and Macros //---------------------------------------------------------------------------------- @@ -95,10 +97,121 @@ Image LoadImage(const char *fileName) return image; } -// Unload image from CPU memory (RAM) -void UnloadImage(Image image) +// Load an image from rRES file (raylib Resource) +Image LoadImageFromRES(const char *rresName, int resId) { - free(image.pixels); + // NOTE: rresName could be directly a char array with all the data!!! ---> TODO! + Image image; + bool found = false; + + char id[4]; // rRES file identifier + unsigned char version; // rRES file version and subversion + char useless; // rRES header reserved data + short numRes; + + ResInfoHeader infoHeader; + + FILE *rresFile = fopen(rresName, "rb"); + + if (!rresFile) printf("Error opening raylib Resource file\n"); + + // Read rres file (basic file check - id) + fread(&id[0], sizeof(char), 1, rresFile); + fread(&id[1], sizeof(char), 1, rresFile); + fread(&id[2], sizeof(char), 1, rresFile); + fread(&id[3], sizeof(char), 1, rresFile); + fread(&version, sizeof(char), 1, rresFile); + fread(&useless, sizeof(char), 1, rresFile); + + if ((id[0] != 'r') && (id[1] != 'R') && (id[2] != 'E') &&(id[3] != 'S')) + { + printf("This is not a valid raylib Resource file!\n"); + exit(1); + } + + // Read number of resources embedded + fread(&numRes, sizeof(short), 1, rresFile); + + for (int i = 0; i < numRes; i++) + { + fread(&infoHeader, sizeof(ResInfoHeader), 1, rresFile); + + if (infoHeader.id == resId) + { + found = true; + + // Check data is of valid IMAGE type + if (infoHeader.type == 0) // IMAGE data type + { + // TODO: Check data compression type + + // NOTE: We suppose compression type 2 (DEFLATE - default) + short imgWidth, imgHeight; + char colorFormat, mipmaps; + + fread(&imgWidth, sizeof(short), 1, rresFile); // Image width + fread(&imgHeight, sizeof(short), 1, rresFile); // Image height + fread(&colorFormat, 1, 1, rresFile); // Image data color format (default: RGBA 32 bit) + fread(&mipmaps, 1, 1, rresFile); // Mipmap images included (default: 0) + + printf("Image width: %i\n", (int)imgWidth); + printf("Image height: %i\n", (int)imgHeight); + + image.width = (int)imgWidth; + image.height = (int)imgHeight; + + unsigned char *data = malloc(infoHeader.size); + + fread(data, infoHeader.size, 1, rresFile); + + unsigned char *imgData = DecompressData(data, infoHeader.size, infoHeader.srcSize); + + image.pixels = (Color *)malloc(sizeof(Color)*imgWidth*imgHeight); + + int pix = 0; + + for (int i = 0; i < (imgWidth*imgHeight*4); i += 4) + { + image.pixels[pix].r = imgData[i]; + image.pixels[pix].g = imgData[i+1]; + image.pixels[pix].b = imgData[i+2]; + image.pixels[pix].a = imgData[i+3]; + pix++; + } + + free(imgData); + + free(data); + } + else + { + printf("Required resource do not seem to be a valid IMAGE resource\n"); + exit(2); + } + } + else + { + // Depending on type, skip the right amount of parameters + switch (infoHeader.type) + { + case 0: fseek(rresFile, 6, SEEK_CUR); break; // IMAGE: Jump 6 bytes of parameters + case 1: fseek(rresFile, 6, SEEK_CUR); break; // SOUND: Jump 6 bytes of parameters + case 2: fseek(rresFile, 5, SEEK_CUR); break; // MODEL: Jump 5 bytes of parameters (TODO: Review) + case 3: break; // TEXT: No parameters + case 4: break; // RAW: No parameters + default: break; + } + + // Jump DATA to read next infoHeader + fseek(rresFile, infoHeader.size, SEEK_CUR); + } + } + + fclose(rresFile); + + if (!found) printf("Required resource id could not be found in the raylib Resource file!\n"); + + return image; } // Load an image as texture into GPU memory @@ -140,6 +253,17 @@ Texture2D LoadTexture(const char *fileName) return texture; } +// Load an image as texture from rRES file (raylib Resource) +Texture2D LoadTextureFromRES(const char *rresName, int resId) +{ + Texture2D texture; + + Image image = LoadImageFromRES(rresName, resId); + texture = CreateTexture2D(image); + + return texture; +} + // Load an image as texture (and convert to POT with mipmaps) Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps) { @@ -187,6 +311,12 @@ Texture2D CreateTexture2D(Image image) return texture; } +// Unload image from CPU memory (RAM) +void UnloadImage(Image image) +{ + free(image.pixels); +} + // Unload texture from GPU memory void UnloadTexture(Texture2D texture) { @@ -299,47 +429,4 @@ void DrawTexturePro(Texture2D texture, Rectangle sourceRec, Rectangle destRec, V glPopMatrix(); glDisable(GL_TEXTURE_2D); // Disable textures usage -} - -// Creates a bitmap (BMP) file from an array of pixel data -// NOTE: This function is only used by module [core], not explicitly available to raylib users -extern void WriteBitmap(const char *fileName, const Color *imgDataPixel, int width, int height) -{ - int filesize = 54 + 3*width*height; - - unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header - unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header - - bmpFileHeader[2] = (unsigned char)(filesize); - bmpFileHeader[3] = (unsigned char)(filesize>>8); - bmpFileHeader[4] = (unsigned char)(filesize>>16); - bmpFileHeader[5] = (unsigned char)(filesize>>24); - - bmpInfoHeader[4] = (unsigned char)(width); - bmpInfoHeader[5] = (unsigned char)(width>>8); - bmpInfoHeader[6] = (unsigned char)(width>>16); - bmpInfoHeader[7] = (unsigned char)(width>>24); - bmpInfoHeader[8] = (unsigned char)(height); - bmpInfoHeader[9] = (unsigned char)(height>>8); - bmpInfoHeader[10] = (unsigned char)(height>>16); - bmpInfoHeader[11] = (unsigned char)(height>>24); - - FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode - - // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer - fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data - fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data - - // Write pixel data to file - for (int y = 0; y < height ; y++) - { - for (int x = 0; x < width; x++) - { - fputc(imgDataPixel[x + y*width].b, bmpFile); - fputc(imgDataPixel[x + y*width].g, bmpFile); - fputc(imgDataPixel[x + y*width].r, bmpFile); - } - } - - fclose(bmpFile); // Close bitmap file } \ No newline at end of file diff --git a/src/tinfl.c b/src/tinfl.c new file mode 100644 index 000000000..a17a156b6 --- /dev/null +++ b/src/tinfl.c @@ -0,0 +1,592 @@ +/* tinfl.c v1.11 - public domain inflate with zlib header parsing/adler32 checking (inflate-only subset of miniz.c) + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated May 20, 2011 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + + The entire decompressor coroutine is implemented in tinfl_decompress(). The other functions are optional high-level helpers. +*/ +#ifndef TINFL_HEADER_INCLUDED +#define TINFL_HEADER_INCLUDED + +#include + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef unsigned long long mz_uint64; + +#if defined(_M_IX86) || defined(_M_X64) +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 if integer loads and stores to unaligned addresses are acceptable on the target platform (slightly faster). +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif + +#if defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if the processor has 64-bit general purpose registers (enables 64-bit bitbuffer in inflator) +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +// Works around MSVC's spammy "warning C4127: conditional expression is constant" message. +#ifdef _MSC_VER + #define MZ_MACRO_END while (0, 0) +#else + #define MZ_MACRO_END while (0) +#endif + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. +enum +{ + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum +{ + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum +{ + TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct +{ + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS + #define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF + typedef mz_uint64 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (64) +#else + typedef mz_uint32 tinfl_bit_buf_t; + #define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag +{ + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +#endif // #ifdef TINFL_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef TINFL_HEADER_FILE_ONLY + +#include + +// MZ_MALLOC, etc. are only used by the optional high-level helper functions. +#ifdef MINIZ_NO_MALLOC + #define MZ_MALLOC(x) NULL + #define MZ_FREE(x) x, ((void)0) + #define MZ_REALLOC(p, x) NULL +#else + #define MZ_MALLOC(x) malloc(x) + #define MZ_FREE(x) free(x) + #define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) +#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) + #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else + #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) + #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN switch(r->m_state) { case 0: +#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for ( ; ; ) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else c = *pIn_buf_cur++; } MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a +// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ + } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read +// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully +// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ + int temp; mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ + } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) +{ + static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; + static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + static const int s_min_table_sizes[3] = { 257, 1, 4 }; + + tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } + + num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + } + + do + { + TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; + if (r->m_type == 0) + { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } + while ((counter) && (num_bits)) + { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) + { + size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pIn_buf_cur >= pIn_buf_end) + { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) + { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } + else + { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + } + } + else if (r->m_type == 3) + { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } + else + { + if (r->m_type == 1) + { + mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; + r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; + } + else + { + for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + r->m_table_sizes[2] = 19; + } + for ( ; (int)r->m_type >= 0; r->m_type--) + { + int tree_next, tree_cur; tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } + if ((65536 != total) && (used_syms > 1)) + { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) + { + mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; + cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } + if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) + { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) + { + for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) + { + mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } + if ((dist == 16) && (!counter)) + { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) + { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + } + } + for ( ; ; ) + { + mz_uint8 *pSrc; + for ( ; ; ) + { + if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) + { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) + break; + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = (mz_uint8)counter; + } + else + { + int sym2; mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } +#else + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + if (counter & 256) + break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } +#endif + if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) + code_len = sym2 >> 9; + else + { + code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + } + bit_buf >>= code_len; num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) + { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; + if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) + { + while (counter--) + { + while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } + *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) + { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do + { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) + { + if (counter) + { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do + { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) + { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) + { + TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) + { + const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; + while (buf_len) + { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) + { + s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + } + for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) +{ + tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) + { + MZ_FREE(pBuf); *pOut_len = 0; return NULL; + } + pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) +{ + tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); + status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) +{ + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) + return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for ( ; ; ) + { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) + { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +#endif // #ifndef TINFL_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS 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 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 SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 000000000..8c5d72405 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,127 @@ +/********************************************************************************************* +* +* raylib.utils +* +* Utils Functions Definitions +* +* Uses external lib: +* tinfl - zlib DEFLATE algorithm decompression lib +* +* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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. +* +**********************************************************************************************/ + +#include "utils.h" + +#include // malloc(), free() +#include // printf() +//#include // String management functions: strlen(), strrchr(), strcmp() + +#define STB_IMAGE_WRITE_IMPLEMENTATION + +#include "stb_image_write.h" // Create PNG file +#include "tinfl.c" + +// Data decompression function +// NOTE: Allocated data MUST be freed! +unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize) +{ + int tempUncompSize; + unsigned char *pUncomp; + + // Allocate buffer to hold decompressed data + pUncomp = (mz_uint8 *)malloc((size_t)uncompSize); + + // Check correct memory allocation + if (!pUncomp) + { + printf("Out of memory!\n"); + return NULL; + } + + // Decompress data + tempUncompSize = tinfl_decompress_mem_to_mem(pUncomp, (size_t)uncompSize, data, compSize, 1); + + if (tempUncompSize == -1) + { + printf("Decompression failed!\n"); + free(pUncomp); + return NULL; + } + + if (uncompSize != (int)tempUncompSize) + { + printf("WARNING! Expected uncompressed size do not match! Data may be corrupted!\n"); + printf(" -- Expected uncompressed size: %i\n", uncompSize); + printf(" -- Returned uncompressed size: %i\n", tempUncompSize); + } + + printf("Decompressed from %u bytes to %u bytes\n", (mz_uint32)compSize, (mz_uint32)tempUncompSize); + + return pUncomp; +} + +// Creates a bitmap (BMP) file from an array of pixel data +// NOTE: This function is not explicitly available to raylib users +void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height) +{ + int filesize = 54 + 3*width*height; + + unsigned char bmpFileHeader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; // Standard BMP file header + unsigned char bmpInfoHeader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; // Standard BMP info header + + bmpFileHeader[2] = (unsigned char)(filesize); + bmpFileHeader[3] = (unsigned char)(filesize>>8); + bmpFileHeader[4] = (unsigned char)(filesize>>16); + bmpFileHeader[5] = (unsigned char)(filesize>>24); + + bmpInfoHeader[4] = (unsigned char)(width); + bmpInfoHeader[5] = (unsigned char)(width>>8); + bmpInfoHeader[6] = (unsigned char)(width>>16); + bmpInfoHeader[7] = (unsigned char)(width>>24); + bmpInfoHeader[8] = (unsigned char)(height); + bmpInfoHeader[9] = (unsigned char)(height>>8); + bmpInfoHeader[10] = (unsigned char)(height>>16); + bmpInfoHeader[11] = (unsigned char)(height>>24); + + FILE *bmpFile = fopen(fileName, "wb"); // Define a pointer to bitmap file and open it in write-binary mode + + // NOTE: fwrite parameters are: data pointer, size in bytes of each element to be written, number of elements, file-to-write pointer + fwrite(bmpFileHeader, sizeof(unsigned char), 14, bmpFile); // Write BMP file header data + fwrite(bmpInfoHeader, sizeof(unsigned char), 40, bmpFile); // Write BMP info header data + + // Write pixel data to file + for (int y = 0; y < height ; y++) + { + for (int x = 0; x < width; x++) + { + fputc(imgData[(x*4)+2 + (y*width*4)], bmpFile); + fputc(imgData[(x*4)+1 + (y*width*4)], bmpFile); + fputc(imgData[(x*4) + (y*width*4)], bmpFile); + } + } + + fclose(bmpFile); // Close bitmap file +} + +// Creates a PNG image file from an array of pixel data +// NOTE: Uses stb_image_write +void WritePNG(const char *fileName, unsigned char *imgData, int width, int height) +{ + stbi_write_png(fileName, width, height, 4, imgData, width*4); // It WORKS!!! +} \ No newline at end of file diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 000000000..53241aff6 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,71 @@ +/********************************************************************************************* +* +* raylib.utils +* +* Some utility functions: rRES files data decompression +* +* Uses external lib: +* tinfl - zlib DEFLATE algorithm decompression lib +* +* Copyright (c) 2013 Ramon Santamaria (Ray San - raysan@raysanweb.com) +* +* 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 UTILS_H +#define UTILS_H + +//---------------------------------------------------------------------------------- +// Some basic Defines +//---------------------------------------------------------------------------------- +//... + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +//---------------------------------------------------------------------------------- +typedef enum { IMAGE, SOUND, MODEL, TEXT, RAW } DataType; + +// One resource info header, every resource includes this header (8 byte) +typedef struct { + unsigned short id; // Resource unique identifier (2 byte) + unsigned char type; // Resource type (1 byte) + unsigned char comp; // Data Compression and Coding (1 byte) + unsigned int size; // Data size in .rres file (compressed or not, only DATA) (4 byte) + unsigned int srcSize; // Source data size (uncompressed, only DATA) +} ResInfoHeader; + +#ifdef __cplusplus +extern "C" { // Prevents name mangling of functions +#endif + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// Nop... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- +unsigned char *DecompressData(const unsigned char *data, unsigned long compSize, int uncompSize); +void WriteBitmap(const char *fileName, unsigned char *imgData, int width, int height); +void WritePNG(const char *fileName, unsigned char *imgData, int width, int height); + +#ifdef __cplusplus +} +#endif + +#endif // UTILS_H \ No newline at end of file diff --git a/src/vector3.h b/src/vector3.h index a42b26789..6c0ead6da 100644 --- a/src/vector3.h +++ b/src/vector3.h @@ -26,7 +26,7 @@ #ifndef VECTOR3_H #define VECTOR3_H -#include "raylib.h" // Defines Vector3 structure +#include "raylib.h" // Defines Vector3 structure #ifdef __cplusplus extern "C" { // Prevents name mangling of functions diff --git a/tools/README.txt b/tools/README.txt new file mode 100644 index 000000000..4c9f66140 --- /dev/null +++ b/tools/README.txt @@ -0,0 +1,36 @@ +/********************************************************************************************** +* +* rREM - raylib Resource Embedder 1.0.0 (alpha) +* +* Tool to embed resources (images, text, sounds, models...) into a rRES file. +* +* Copyright 2014 Ramon Santamaria. All rights reserved. +* +***********************************************************************************************/ + + +rrem creates a .rres resource with embedded files and a .h header to access embedded data + + +Usage example: + +1) Create 'resources.rres' and 'resources.h' including 3 files: + + rrem image01.png image02.jpg sound03.wav + + +2) In your raylib program, just add at top: + + #include "resources.h" + + +3) When a resource is required, just load it using: + + Texture2D mytex = LoadTextureFromRES("resources.rres", RES_image01); + Sound mysound = LoadSoundFromRES("resources.rres", RES_sound03); + + +Note that you can check resources id names in resources.h file + + +Have fun! :) diff --git a/tools/rrem.exe b/tools/rrem.exe new file mode 100644 index 0000000000000000000000000000000000000000..1d058bf4dd04a56a36c42a00c185e52eac9d01bb GIT binary patch literal 241166 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 literal 0 HcmV?d00001