From ec5c9686b3afef5fb2c147fc9786b6890c025dd9 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 17 Sep 2018 16:56:02 +0200 Subject: [PATCH] Improved data export capabilities! REVIEWED: ExportImage() REVIEWED: ExportMesh() ADDED: ExportWave() REMOVED: Internal funcs: SavePNG(), SaveBMP() NOTE: These changes break the API (parameters order) --- src/CMakeOptions.txt | 3 +- src/audio.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ src/config.h | 6 ++-- src/core.c | 4 ++- src/models.c | 77 ++++++++++++++++++++++------------------ src/raylib.h | 5 +-- src/text.c | 3 -- src/textures.c | 28 ++++++++++++--- src/utils.c | 35 ------------------- src/utils.h | 11 ------ 10 files changed, 158 insertions(+), 97 deletions(-) diff --git a/src/CMakeOptions.txt b/src/CMakeOptions.txt index c8af55a0..84643b28 100644 --- a/src/CMakeOptions.txt +++ b/src/CMakeOptions.txt @@ -45,6 +45,7 @@ option(SUPPORT_FONT_TEXTURE "Draw rectangle shapes using font texture white char option(SUPPORT_QUADS_DRAW_MODE "Use QUADS instead of TRIANGLES for drawing when possible. Some lines-based shapes could still use lines" ON) # textures.c +option(SUPPORT_IMAGE_EXPORT "Support image exporting to file" ON) option(SUPPORT_IMAGE_GENERATION "Support procedural image generation functionality (gradient, spot, perlin-noise, cellular)" ON) option(SUPPORT_FILEFORMAT_PNG "Support loading PNG as textures" ON) option(SUPPORT_FILEFORMAT_DDS "Support loading DDS as textures" ON) @@ -72,8 +73,6 @@ option(SUPPORT_FILEFORMAT_MOD "Support loading MOD for sound" ON) option(SUPPORT_FILEFORMAT_FLAC "Support loading FLAC for sound" ${OFF}) # utils.c -option(SUPPORT_SAVE_PNG "Support saving image data in PNG file format" ON) -option(SUPPORT_SAVE_BMP "Support saving image data in BMP file format" ${OFF}) option(SUPPORT_TRACELOG "Show TraceLog() output messages. NOTE: By default LOG_DEBUG traces not shown" ON) option(SUPPORT_FILEFORMAT_FNT "Support loading fonts in FNT format" ON) diff --git a/src/audio.c b/src/audio.c index 274134b2..f03b35f4 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1049,6 +1049,89 @@ void UpdateSound(Sound sound, const void *data, int samplesCount) #endif } +// Export wave data to file +void ExportWave(Wave wave, const char *fileName) +{ + bool success = false; + + if (IsFileExtension(fileName, ".wav")) + { + // Basic WAV headers structs + typedef struct { + char chunkID[4]; + int chunkSize; + char format[4]; + } RiffHeader; + + typedef struct { + char subChunkID[4]; + int subChunkSize; + short audioFormat; + short numChannels; + int sampleRate; + int byteRate; + short blockAlign; + short bitsPerSample; + } WaveFormat; + + typedef struct { + char subChunkID[4]; + int subChunkSize; + } WaveData; + + RiffHeader riffHeader; + WaveFormat waveFormat; + WaveData waveData; + + // Fill structs with data + riffHeader.chunkID[0] = 'R'; + riffHeader.chunkID[1] = 'I'; + riffHeader.chunkID[2] = 'F'; + riffHeader.chunkID[3] = 'F'; + riffHeader.chunkSize = 44 - 4 + wave.sampleCount*wave.sampleSize/8; + riffHeader.format[0] = 'W'; + riffHeader.format[1] = 'A'; + riffHeader.format[2] = 'V'; + riffHeader.format[3] = 'E'; + + waveFormat.subChunkID[0] = 'f'; + waveFormat.subChunkID[1] = 'm'; + waveFormat.subChunkID[2] = 't'; + waveFormat.subChunkID[3] = ' '; + waveFormat.subChunkSize = 16; + waveFormat.audioFormat = 1; + waveFormat.numChannels = wave.channels; + waveFormat.sampleRate = wave.sampleRate; + waveFormat.byteRate = wave.sampleRate*wave.sampleSize/8; + waveFormat.blockAlign = wave.sampleSize/8; + waveFormat.bitsPerSample = wave.sampleSize; + + waveData.subChunkID[0] = 'd'; + waveData.subChunkID[1] = 'a'; + waveData.subChunkID[2] = 't'; + waveData.subChunkID[3] = 'a'; + waveData.subChunkSize = wave.sampleCount*wave.channels*wave.sampleSize/8; + + FILE *wavFile = fopen(fileName, "wb"); + + if (wavFile == NULL) return; + + fwrite(&riffHeader, 1, sizeof(RiffHeader), wavFile); + fwrite(&waveFormat, 1, sizeof(WaveFormat), wavFile); + fwrite(&waveData, 1, sizeof(WaveData), wavFile); + + fwrite(wave.data, 1, wave.sampleCount*wave.channels*wave.sampleSize/8, wavFile); + + fclose(wavFile); + + success = true; + } + else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export wave sample data + + if (success) TraceLog(LOG_INFO, "Wave exported successfully: %s", fileName); + else TraceLog(LOG_WARNING, "Wave could not be exported."); +} + // Play a sound void PlaySound(Sound sound) { diff --git a/src/config.h b/src/config.h index 317df46b..9bb5ab22 100644 --- a/src/config.h +++ b/src/config.h @@ -86,6 +86,8 @@ //#define SUPPORT_FILEFORMAT_PKM 1 //#define SUPPORT_FILEFORMAT_PVR 1 +// Support image export functionality (.png, .bmp, .tga, .jpg) +#define SUPPORT_IMAGE_EXPORT // Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... // If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT() #define SUPPORT_IMAGE_MANIPULATION 1 @@ -133,10 +135,6 @@ // Show TraceLog() output messages // NOTE: By default LOG_DEBUG traces not shown #define SUPPORT_TRACELOG 1 -// Support saving image data fileformats -// NOTE: Requires stb_image_write library -#define SUPPORT_SAVE_PNG 1 -//#define SUPPORT_SAVE_BMP 1 #endif //defined(RAYLIB_CMAKE) diff --git a/src/core.c b/src/core.c index 92d966e7..fc1a5a09 100644 --- a/src/core.c +++ b/src/core.c @@ -1297,7 +1297,9 @@ void TakeScreenshot(const char *fileName) { #if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) unsigned char *imgData = rlReadScreenPixels(renderWidth, renderHeight); - SavePNG(fileName, imgData, renderWidth, renderHeight, 4); // Save image as PNG + + Image image = { imgData, renderWidth, renderHeight, 1, UNCOMPRESSED_R8G8B8A8 }; + ExportImage(image, fileName); free(imgData); TraceLog(LOG_INFO, "Screenshot taken: %s", fileName); diff --git a/src/models.c b/src/models.c index d6b93511..8a498139 100644 --- a/src/models.c +++ b/src/models.c @@ -664,45 +664,54 @@ void UnloadMesh(Mesh *mesh) rlUnloadMesh(mesh); } -// Export mesh as an OBJ file -void ExportMesh(const char *fileName, Mesh mesh) +// Export mesh data to file +void ExportMesh(Mesh mesh, const char *fileName) { - FILE *objFile = fopen(fileName, "wt"); + bool success = false; - fprintf(objFile, "# raylib Mesh OBJ exporter v1.0\n\n"); - fprintf(objFile, "# Mesh exported as triangle faces and not optimized.\n"); - fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount); - fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount); - fprintf(objFile, "# LICENSE: zlib/libpng\n"); - fprintf(objFile, "# Copyright (c) 2018 Ramon Santamaria (@raysan5)\n\n"); - - fprintf(objFile, "g mesh\n"); - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) + if (IsFileExtension(fileName, ".obj")) { - fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); + FILE *objFile = fopen(fileName, "wt"); + + fprintf(objFile, "# raylib Mesh OBJ exporter v1.0\n\n"); + fprintf(objFile, "# Mesh exported as triangle faces and not optimized.\n"); + fprintf(objFile, "# Vertex Count: %i\n", mesh.vertexCount); + fprintf(objFile, "# Triangle Count: %i\n\n", mesh.triangleCount); + fprintf(objFile, "# LICENSE: zlib/libpng\n"); + fprintf(objFile, "# Copyright (c) 2018 Ramon Santamaria (@raysan5)\n\n"); + + fprintf(objFile, "g mesh\n"); + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) + { + fprintf(objFile, "v %.2f %.2f %.2f\n", mesh.vertices[v], mesh.vertices[v + 1], mesh.vertices[v + 2]); + } + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) + { + fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); + } + + for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) + { + fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); + } + + for (int i = 0; i < mesh.triangleCount; i += 3) + { + fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2); + } + + fprintf(objFile, "\n"); + + fclose(objFile); + + success = true; } - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 2) - { - fprintf(objFile, "vt %.2f %.2f\n", mesh.texcoords[v], mesh.texcoords[v + 1]); - } - - for (int i = 0, v = 0; i < mesh.vertexCount; i++, v += 3) - { - fprintf(objFile, "vn %.2f %.2f %.2f\n", mesh.normals[v], mesh.normals[v + 1], mesh.normals[v + 2]); - } - - for (int i = 0; i < mesh.triangleCount; i += 3) - { - fprintf(objFile, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", i, i, i, i + 1, i + 1, i + 1, i + 2, i + 2, i + 2); - } - - fprintf(objFile, "\n"); - - fclose(objFile); + else if (IsFileExtension(fileName, ".raw")) { } // TODO: Support additional file formats to export mesh vertex data - TraceLog(LOG_INFO, "Mesh saved: %s", fileName); + if (success) TraceLog(LOG_INFO, "Mesh exported successfully: %s", fileName); + else TraceLog(LOG_WARNING, "Mesh could not be exported."); } #if defined(SUPPORT_MESH_GENERATION) diff --git a/src/raylib.h b/src/raylib.h index 5be60836..11b11a54 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -988,7 +988,7 @@ RLAPI Image LoadImage(const char *fileName); RLAPI Image LoadImageEx(Color *pixels, int width, int height); // Load image from Color array data (RGBA - 32bit) RLAPI Image LoadImagePro(void *data, int width, int height, int format); // Load image from raw data with parameters RLAPI Image LoadImageRaw(const char *fileName, int width, int height, int format, int headerSize); // Load image from RAW file data -RLAPI void ExportImage(const char *fileName, Image image); // Export image as a PNG file +RLAPI void ExportImage(Image image, const char *fileName); // Export image data to file RLAPI Texture2D LoadTexture(const char *fileName); // Load texture from file into GPU memory (VRAM) RLAPI Texture2D LoadTextureFromImage(Image image); // Load texture from image data RLAPI RenderTexture2D LoadRenderTexture(int width, int height); // Load texture for rendering (framebuffer) @@ -1113,7 +1113,7 @@ RLAPI void UnloadModel(Model model); // Mesh loading/unloading functions RLAPI Mesh LoadMesh(const char *fileName); // Load mesh from file RLAPI void UnloadMesh(Mesh *mesh); // Unload mesh from memory (RAM and/or VRAM) -RLAPI void ExportMesh(const char *fileName, Mesh mesh); // Export mesh as an OBJ file +RLAPI void ExportMesh(Mesh mesh, const char *fileName); // Export mesh data to file // Mesh manipulation functions RLAPI BoundingBox MeshBoundingBox(Mesh mesh); // Compute mesh bounding box limits @@ -1221,6 +1221,7 @@ RLAPI Sound LoadSoundFromWave(Wave wave); // Load so RLAPI void UpdateSound(Sound sound, const void *data, int samplesCount);// Update sound buffer with new data RLAPI void UnloadWave(Wave wave); // Unload wave data RLAPI void UnloadSound(Sound sound); // Unload sound +RLAPI void ExportWave(Wave wave, const char *fileName); // Export wave data to file // Wave/Sound management functions RLAPI void PlaySound(Sound sound); // Play a sound diff --git a/src/text.c b/src/text.c index bc21e4fe..3dbb261b 100644 --- a/src/text.c +++ b/src/text.c @@ -86,9 +86,6 @@ static Font LoadImageFont(Image image, Color key, int firstChar); // Load a Imag #if defined(SUPPORT_FILEFORMAT_FNT) static Font LoadBMFont(const char *fileName); // Load a BMFont file (AngelCode font file) #endif -#if defined(SUPPORT_FILEFORMAT_TTF) -//static Font LoadTTF(const char *fileName, int fontSize, int charsCount, int *fontChars); // Load spritefont from TTF data -#endif #if defined(SUPPORT_DEFAULT_FONT) extern void LoadDefaultFont(void); diff --git a/src/textures.c b/src/textures.c index 9e86af92..7abbaf53 100644 --- a/src/textures.c +++ b/src/textures.c @@ -19,6 +19,9 @@ * Selecte desired fileformats to be supported for image data loading. Some of those formats are * supported by default, to remove support, just comment unrequired #define in this module * +* #define SUPPORT_IMAGE_EXPORT +* Support image export in multiple file formats +* * #define SUPPORT_IMAGE_MANIPULATION * Support multiple image editing functions to scale, adjust colors, flip, draw on images, crop... * If not defined only three image editing functions supported: ImageFormat(), ImageAlphaMask(), ImageToPOT() @@ -103,6 +106,11 @@ // NOTE: Used to read image data (multiple formats support) #endif +#if defined(SUPPORT_IMAGE_EXPORT) + #define STB_IMAGE_WRITE_IMPLEMENTATION + #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() +#endif + #if defined(SUPPORT_IMAGE_MANIPULATION) #define STB_IMAGE_RESIZE_IMPLEMENTATION #include "external/stb_image_resize.h" // Required for: stbir_resize_uint8() @@ -706,15 +714,25 @@ void UpdateTexture(Texture2D texture, const void *pixels) rlUpdateTexture(texture.id, texture.width, texture.height, texture.format, pixels); } -// Export image as a PNG file -void ExportImage(const char *fileName, Image image) +// Export image data to file +// NOTE: File format depends on fileName extension +void ExportImage(Image image, const char *fileName) { + int success = 0; + // NOTE: Getting Color array as RGBA unsigned char values unsigned char *imgData = (unsigned char *)GetImageData(image); - // NOTE: SavePNG() not supported by some platforms: PLATFORM_WEB, PLATFORM_ANDROID - SavePNG(fileName, imgData, image.width, image.height, 4); - + if (IsFileExtension(fileName, ".png")) success = stbi_write_png(fileName, image.width, image.height, 4, imgData, image.width*4); + else if (IsFileExtension(fileName, ".bmp")) success = stbi_write_bmp(fileName, image.width, image.height, 4, imgData); + else if (IsFileExtension(fileName, ".tga")) success = stbi_write_tga(fileName, image.width, image.height, 4, imgData); + else if (IsFileExtension(fileName, ".jpg")) success = stbi_write_jpg(fileName, image.width, image.height, 4, imgData, 80); // Between 1 and 100 + else if (IsFileExtension(fileName, ".raw")) { } // TODO: Export raw pixel data + else if (IsFileExtension(fileName, ".h")) { } // TODO: Export pixel data as an array of bytes + + if (success != 0) TraceLog(LOG_INFO, "Image exported successfully: %s", fileName); + else TraceLog(LOG_WARNING, "Image could not be exported."); + free(imgData); } diff --git a/src/utils.c b/src/utils.c index f7c19afb..b2951040 100644 --- a/src/utils.c +++ b/src/utils.c @@ -4,21 +4,10 @@ * * CONFIGURATION: * -* #define SUPPORT_SAVE_PNG (defined by default) -* Support saving image data as PNG fileformat -* NOTE: Requires stb_image_write library -* -* #define SUPPORT_SAVE_BMP -* Support saving image data as BMP fileformat -* NOTE: Requires stb_image_write library -* * #define SUPPORT_TRACELOG * Show TraceLog() output messages * NOTE: By default LOG_DEBUG traces not shown * -* DEPENDENCIES: -* stb_image_write - BMP/PNG writting functions -* * * LICENSE: zlib/libpng * @@ -62,12 +51,6 @@ FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)); - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) - #define STB_IMAGE_WRITE_IMPLEMENTATION - #include "external/stb_image_write.h" // Required for: stbi_write_bmp(), stbi_write_png() -#endif - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -160,24 +143,6 @@ void TraceLog(int msgType, const char *text, ...) #endif // SUPPORT_TRACELOG } -// Creates a BMP image file from an array of pixel data -void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize) -{ -#if defined(SUPPORT_SAVE_BMP) && (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) - stbi_write_bmp(fileName, width, height, compSize, imgData); - TraceLog(LOG_INFO, "BMP Image saved: %s", fileName); -#endif -} - -// Creates a PNG image file from an array of pixel data -void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize) -{ -#if defined(SUPPORT_SAVE_PNG) && (defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI)) - stbi_write_png(fileName, width, height, compSize, imgData, width*compSize); - TraceLog(LOG_INFO, "PNG Image saved: %s", fileName); -#endif -} - // Keep track of memory allocated // NOTE: mallocType defines the type of data allocated /* diff --git a/src/utils.h b/src/utils.h index dfdb0c2a..08b33962 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,10 +32,6 @@ #include // Required for: AAssetManager #endif -#ifndef SUPPORT_SAVE_PNG -#define SUPPORT_SAVE_PNG 1 -#endif - //---------------------------------------------------------------------------------- // Some basic Defines //---------------------------------------------------------------------------------- @@ -58,13 +54,6 @@ extern "C" { // Prevents name mangling of functions //---------------------------------------------------------------------------------- // Module Functions Declaration //---------------------------------------------------------------------------------- -#if defined(SUPPORT_SAVE_BMP) -void SaveBMP(const char *fileName, unsigned char *imgData, int width, int height, int compSize); -#endif -#if defined(SUPPORT_SAVE_PNG) -void SavePNG(const char *fileName, unsigned char *imgData, int width, int height, int compSize); -#endif - #if defined(PLATFORM_ANDROID) void InitAssetManager(AAssetManager *manager); // Initialize asset manager from android app FILE *android_fopen(const char *fileName, const char *mode); // Replacement for fopen()