diff --git a/Engine/source/gfx/bitmap/gBitmap.cpp b/Engine/source/gfx/bitmap/gBitmap.cpp index 2a7054008..bde7a4a25 100644 --- a/Engine/source/gfx/bitmap/gBitmap.cpp +++ b/Engine/source/gfx/bitmap/gBitmap.cpp @@ -1206,6 +1206,20 @@ bool GBitmap::readBitmap(const String& bmType, const Torque::Path& path) return regInfo->readFunc(path, this); } +bool GBitmap::readBitmapStream(const String& bmType, Stream& ioStream, U32 len) +{ + PROFILE_SCOPE(ResourceGBitmap_readBitmapStream); + const GBitmap::Registration* regInfo = GBitmap::sFindRegInfo(bmType); + + if (regInfo == NULL) + { + Con::errorf("[GBitmap::readBitmap] unable to find registration for extension [%s]", bmType.c_str()); + return false; + } + + return regInfo->readStreamFunc(ioStream, this, len); +} + bool GBitmap::writeBitmap( const String &bmType, const Torque::Path& path, U32 compressionLevel ) { FileStream stream; @@ -1230,6 +1244,19 @@ bool GBitmap::writeBitmap( const String &bmType, const Torque::Path& path, U32 return regInfo->writeFunc(path, this, (compressionLevel == U32_MAX) ? regInfo->defaultCompression : compressionLevel ); } +bool GBitmap::writeBitmapStream(const String& bmType, Stream& ioStream, U32 compressionLevel) +{ + const GBitmap::Registration* regInfo = GBitmap::sFindRegInfo(bmType); + + if (regInfo == NULL) + { + Con::errorf("[GBitmap::writeBitmap] unable to find registration for extension [%s]", bmType.c_str()); + return false; + } + + return regInfo->writeStreamFunc(ioStream, this, (compressionLevel == U32_MAX) ? regInfo->defaultCompression : compressionLevel); +} + template<> void *Resource::create(const Torque::Path &path) { PROFILE_SCOPE( ResourceGBitmap_create ); diff --git a/Engine/source/gfx/bitmap/gBitmap.h b/Engine/source/gfx/bitmap/gBitmap.h index e0577dd55..c170349f7 100644 --- a/Engine/source/gfx/bitmap/gBitmap.h +++ b/Engine/source/gfx/bitmap/gBitmap.h @@ -70,26 +70,31 @@ public: struct Registration { - /// The read function prototype. + /// The read functions prototype. typedef bool(*ReadFunc)(const Torque::Path& path, GBitmap* bitmap); - - /// The write function prototype. Compression levels are image-specific - see their registration declaration for details. + typedef bool(*ReadStreamFunc)(Stream& stream, GBitmap* bitmap, U32 len); + /// The write functions prototype. Compression levels are image-specific - see their registration declaration for details. typedef bool(*WriteFunc)(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel); - + typedef bool(*WriteStreamFunc)(Stream& stream, GBitmap* bitmap, U32 compressionLevel); + /// Used to sort the registrations so that /// lookups occur in a fixed order. U32 priority; - Vector extensions; ///< the list of file extensions for this bitmap type [these should be lower case] - ReadFunc readFunc; ///< the read function to call for this bitmap type - WriteFunc writeFunc; ///< the write function to call for this bitmap type - U32 defaultCompression; ///< the default compression level [levels are image-specific - see their registration declaration for details] + ReadFunc readFunc; ///< the read function to read from a file. + WriteFunc writeFunc; ///< the write function to write to a file. + ReadStreamFunc readStreamFunc; ///< the read function to read from a stream. + WriteStreamFunc writeStreamFunc; ///< the write function to write to a stream. + + U32 defaultCompression; ///< the default compression level [levels are image-specific - see their registration declaration for details] Registration() { readFunc = NULL; writeFunc = NULL; + readStreamFunc = NULL; + writeStreamFunc = NULL; defaultCompression = 0; priority = 0; VECTOR_SET_ASSOCIATION( extensions ); @@ -238,19 +243,24 @@ public: //-------------------------------------- Input/Output interface - /// Read a bitmap from a stream + /// Read a bitmap from a file /// @param bmType This is a file extension to describe the type of the data [i.e. "png" for PNG file, etc] /// @param ioStream The stream to read from - bool readBitmap(const String& bmType, const Torque::Path& path); + bool readBitmap(const String& bmType, const Torque::Path& path); - /// Write a bitmap to a stream + /// Sane as above but reads from a stream. + bool readBitmapStream(const String& bmType, Stream& ioStream, U32 len); + + /// Write a bitmap to a file /// @param bmType This is a file extension to describe the type of the data [i.e. "png" for PNG file, etc] /// @param ioStream The stream to read from /// @param compressionLevel Image format specific compression level. For JPEG sets the quality level percentage, range 0 to 100. /// For PNG compression level is 0 - 10 /// Not used for other image formats. - - bool writeBitmap( const String &bmType, const Torque::Path& path, U32 compressionLevel = U32_MAX ); + bool writeBitmap( const String &bmType, const Torque::Path& path, U32 compressionLevel = U32_MAX ); + + /// Sane as above but writes to a stream. + bool writeBitmapStream(const String& bmType, Stream& ioStream, U32 compressionLevel = U32_MAX); bool readMNG(Stream& io_rStream); // located in bitmapMng.cc bool writeMNG(Stream& io_rStream) const; diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index a0eaef6d6..ce022073b 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -21,6 +21,7 @@ //----------------------------------------------------------------------------- #include "platform/platform.h" +#include "console/console.h" #include "core/stream/fileStream.h" #include "core/stream/memStream.h" @@ -40,7 +41,10 @@ #include "stb_image_write.h" static bool sReadSTB(const Torque::Path& path, GBitmap* bitmap); +static bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len); + static bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel); +static bool sWriteStreamSTB(Stream& stream, GBitmap* bitmap, U32 compressionLevel); static struct _privateRegisterSTB { @@ -58,8 +62,10 @@ static struct _privateRegisterSTB reg.extensions.push_back("tga"); reg.readFunc = sReadSTB; + reg.readStreamFunc = sReadStreamSTB; reg.writeFunc = sWriteSTB; + reg.writeStreamFunc = sWriteStreamSTB; // for png only. reg.defaultCompression = 6; @@ -194,6 +200,41 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) return true; } +bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len) +{ + PROFILE_SCOPE(sReadStreamSTB); + // only used for font at the moment. + + U8* data = new U8[len]; + stream.read(len, data); + + S32 width, height, comp = 0; + + unsigned char* pixelData = stbi_load_from_memory((const U8*)data, (int)len, &width, &height, &comp, 1); + if (!pixelData) + { + const char* stbErr = stbi_failure_reason(); + + if (!stbErr) + stbErr = "Unknown Error!"; + + Con::printf("sReadStreamSTB Error: %s", stbErr); + return false; + } + bitmap->deleteImage(); + + bitmap->allocateBitmap(256, 256, false, GFXFormatA8); + + U8* pBase = bitmap->getWritableBits(0); + U32 rowBytes = bitmap->getByteSize(); + dMemcpy(pBase, pixelData, rowBytes); + + dFree(data); + dFree(pixelData); + + return true; +} + /** * Write bitmap to an image file. * @@ -269,3 +310,28 @@ bool sWriteSTB(const Torque::Path& path, GBitmap* bitmap, U32 compressionLevel) return false; } + +bool sWriteStreamSTB(Stream& stream, GBitmap* bitmap, U32 compressionLevel) +{ + S32 len; + const U8* pData = bitmap->getBits(); + + unsigned char* png = stbi_write_png_to_mem(pData, 0, bitmap->getWidth(), bitmap->getHeight(), 1, &len); + + if (!png) + { + const char* stbErr = stbi_failure_reason(); + + if (!stbErr) + stbErr = "Unknown Error!"; + + Con::printf("sReadStreamSTB Error: %s", stbErr); + return false; + } + + stream.write(len); + stream.write(len, png); + + dFree(png); + return true; +} diff --git a/Engine/source/gfx/gFont.cpp b/Engine/source/gfx/gFont.cpp index af291c9b4..de7a87b5a 100644 --- a/Engine/source/gfx/gFont.cpp +++ b/Engine/source/gfx/gFont.cpp @@ -699,12 +699,21 @@ bool GFont::read(Stream& io_rStream) for(i = 0; i < numSheets; i++) { GBitmap *bmp = new GBitmap; - String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); + /*String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); if(!bmp->readBitmap("png", path)) { delete bmp; return false; + }*/ + U32 len; + io_rStream.read(&len); + + if (!bmp->readBitmapStream("png", io_rStream, len)) + { + delete bmp; + return false; } + GFXTexHandle handle = GFXTexHandle(bmp, &GFXFontTextureProfile, true, avar("%s() - Read Font Sheet for %s %d (line %d)", __FUNCTION__, mFaceName.c_str(), mSize, __LINE__)); //handle.setFilterNearest(); mTextureSheets.push_back(handle); @@ -779,7 +788,9 @@ bool GFont::write(Stream& stream) for (i = 0; i < mTextureSheets.size(); i++) { String path = String::ToString("%s/%s %d %d (%s).png", Con::getVariable("$GUI::fontCacheDirectory"), mFaceName.c_str(), mSize, i, getCharSetName(mCharSet)); - mTextureSheets[i].getBitmap()->writeBitmap("png", path); + //mTextureSheets[i].getBitmap()->writeBitmap("png", path); + + mTextureSheets[i].getBitmap()->writeBitmapStream("png", stream); } stream.write(mCurX);