diff --git a/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/Apps/plClient/plClient.vcproj b/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/Apps/plClient/plClient.vcproj
index ab9e84e7..e43e54f6 100644
--- a/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/Apps/plClient/plClient.vcproj
+++ b/MOULOpenSourceClientPlugin/Plasma20/MsDevProjects/Plasma/Apps/plClient/plClient.vcproj
@@ -39,11 +39,11 @@
Name="VCCustomBuildTool"/>
+#define PNGSIGSIZE 8
+// Custom functions to read and write data from or to an hsStream
+// used by libPNG's respective functions
+void pngReadDelegate(png_structp png_ptr, png_bytep png_data, png_size_t length)
+{
+ hsStream *inStream = (hsStream *)png_get_io_ptr(png_ptr);
+ inStream->Read(length, (UInt8 *)png_data);
+}
+
+void pngWriteDelegate(png_structp png_ptr, png_bytep png_data, png_size_t length)
+{
+}
+
+void pngFlushDelegate(png_structp png_ptr)
+{
+}
+
+//// Singleton Instance ///////////////////////////////////////////////////////
+
+plPNG &plPNG::Instance( void )
+{
+ static plPNG theInstance;
+ return theInstance;
+}
-plMipmap *plPNG::IRead( hsStream *inStream )
+//// IRead ////////////////////////////////////////////////////////////////////
+// Given an open hsStream, reads the PNG data off of the
+// stream and decodes it into a new plMipmap. The mipmap's buffer ends up
+// being a packed RGBA buffer.
+// Returns a pointer to the new mipmap if successful, NULL otherwise.
+
+plMipmap* plPNG::IRead( hsStream *inStream )
{
plMipmap *newMipmap = NULL;
png_structp png_ptr;
@@ -44,12 +74,10 @@ plMipmap *plPNG::IRead( hsStream *inStream )
try
{
// Check PNG Signature
- png_byte sig[8];
+ png_byte sig[PNGSIGSIZE];
inStream->Read8Bytes((char *) sig);
- if (!png_sig_cmp(sig, 0, 8))
+ if (!png_sig_cmp(sig, 0, PNGSIGSIZE))
{
- inStream->Rewind();
-
// Allocate required structs
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
@@ -69,10 +97,57 @@ plMipmap *plPNG::IRead( hsStream *inStream )
throw( false );
}
+ // Assign delegate function for reading from hsStream
+ png_set_read_fn(png_ptr, (png_voidp)inStream, pngReadDelegate);
+
+ // Get PNG Header information
+ png_set_sig_bytes(png_ptr, PNGSIGSIZE);
+ png_read_info(png_ptr, info_ptr);
+ png_uint_32 imgWidth = png_get_image_width(png_ptr, info_ptr);
+ png_uint_32 imgHeight = png_get_image_height(png_ptr, info_ptr);
+ png_uint_32 bitdepth = png_get_bit_depth(png_ptr, info_ptr);
+ png_uint_32 channels = png_get_channels(png_ptr, info_ptr);
+ png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);
+
+ // Convert images to RGB color space
+ switch (color_type) {
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(png_ptr);
+ channels = 3;
+ break;
+ case PNG_COLOR_TYPE_GRAY:
+ if (bitdepth < 8)
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ bitdepth = 8;
+ break;
+ }
+
+ // Convert transparency (if needed) to a full alpha channel
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ {
+ png_set_tRNS_to_alpha(png_ptr);
+ channels+=1;
+ }
+
+ png_set_bgr(png_ptr);
+
+ /// Construct a new mipmap to hold everything
+ newMipmap = TRACKED_NEW plMipmap(imgWidth, imgHeight, plMipmap::kARGB32Config, 1, plMipmap::kUncompressed);
+
+ char *destp = (char *)newMipmap->GetImage();
+ png_bytep *row_ptrs = new png_bytep[imgHeight];
+ const unsigned int stride = imgWidth * bitdepth * channels / 8;
+ // Assign row pointers to the appropriate locations in the newly-created Mipmap
+ for (size_t i = 0; i < imgHeight; i++)
+ {
+ row_ptrs[i] = (png_bytep)destp + (i * stride);
+ }
+ png_read_image(png_ptr, row_ptrs);
// Clean up allocated structs
png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ delete [] row_ptrs;
}
}
catch( ... )
@@ -105,12 +180,13 @@ plMipmap* plPNG::ReadFromFile( const wchar *fileName )
return ret;
}
-hsBool plPNG::IWrite( plMipmap *source, hsStream *outStream )
+hsBool plPNG::IWrite( plMipmap *source, hsStream *outStream )
{
hsBool result = true;
try
{
+ //png_set_write_fn(png_ptr, (png_voidp)&outStream, pngWriteDelegate, pngFlushDelegate);
}
catch( ... )
{
@@ -120,7 +196,7 @@ hsBool plPNG::IWrite( plMipmap *source, hsStream *outStream )
return result;
}
-hsBool plPNG::WriteToFile( const char *fileName, plMipmap *sourceData )
+hsBool plPNG::WriteToFile( const char *fileName, plMipmap *sourceData )
{
wchar* wFilename = hsStringToWString(fileName);
hsBool retVal = WriteToFile(wFilename, sourceData);
@@ -128,7 +204,7 @@ hsBool plPNG::WriteToFile( const char *fileName, plMipmap *sourceData )
return retVal;
}
-hsBool plPNG::WriteToFile( const wchar *fileName, plMipmap *sourceData )
+hsBool plPNG::WriteToFile( const wchar *fileName, plMipmap *sourceData )
{
hsUNIXStream out;
if (!out.Open(fileName, L"wb"))
@@ -136,4 +212,4 @@ hsBool plPNG::WriteToFile( const wchar *fileName, plMipmap *sourceData )
hsBool ret = IWrite(sourceData, &out);
out.Close();
return ret;
-}
\ No newline at end of file
+}
diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plPNG.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plPNG.h
index 22ac28fc..2f6eb0f9 100644
--- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plPNG.h
+++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plPNG.h
@@ -49,6 +49,8 @@ class plPNG
hsBool WriteToStream( hsStream *outStream, plMipmap *sourceData ) { return IWrite( sourceData, outStream ); }
hsBool WriteToFile( const char *fileName, plMipmap *sourceData );
hsBool WriteToFile( const wchar *fileName, plMipmap *sourceData );
+
+ static plPNG &Instance( void );
};
-#endif // _plPNG_h
\ No newline at end of file
+#endif // _plPNG_h