PNG loading and major refactoring.

PNG loading is not working properly yet.
This commit is contained in:
King_DuckZ 2014-02-21 21:51:56 +01:00
parent d0893cba3a
commit 28bd73a1f7
17 changed files with 254 additions and 43 deletions

View file

@ -8,12 +8,31 @@
#include <ciso646>
#include <png.h>
#define lengthof(a) (static_cast<int32_t>(sizeof(a)) / static_cast<int32_t>(sizeof(a[0])))
namespace cloonel {
namespace {
enum GraphicFormat {
GraphicFormat_Unknown,
GraphicFormat_Png
};
enum ColorChannelMask {
#if SDL_BYTE_ORDER == SDL_BIGENDIAN
ColorChannelMask_Red = 0xff000000,
ColorChannelMask_Green = 0xff0000,
ColorChannelMask_Blue = 0xff00,
ColorChannelMask_Alpha = 0xff
#elif SDL_BYTE_ORDER == SDL_LITTLEENDIAN
ColorChannelMask_Red = 0xff,
ColorChannelMask_Green = 0xff00,
ColorChannelMask_Blue = 0xff0000,
ColorChannelMask_Alpha = 0xff000000
#else
# error "Unknonwn endianness"
#endif
};
struct GraphicFormatItem {
const char* extension;
size_t length;
@ -26,8 +45,34 @@ namespace cloonel {
GraphicFormat GuessGraphicFormatFromName (const std::string& parPath) __attribute__((pure));
///--------------------------------------------------------------------
///--------------------------------------------------------------------
///----------------------------------------------------------------------
///----------------------------------------------------------------------
SDL_Surface* SurfaceFromPngRGBA (ushort2 parSize, int parBpp, const png_structp& parPngPtr, const png_infop& parInfoPtr) {
const png_size_t stride = png_get_rowbytes(parPngPtr, parInfoPtr);
assert(stride > 0);
std::unique_ptr<uint8_t[]> image(new uint8_t[stride * parSize.y()]);
uint8_t* const imagePtr = image.get();
for (uint16_t y = 0; y < parSize.y(); ++y) {
png_read_row(parPngPtr, imagePtr + stride * y, nullptr);
}
SDL_Surface* const retSurf = SDL_CreateRGBSurfaceFrom(
imagePtr,
parSize.x(),
parSize.y(),
parBpp,
static_cast<int>(stride),
ColorChannelMask_Red,
ColorChannelMask_Green,
ColorChannelMask_Blue,
ColorChannelMask_Alpha
);
return retSurf;
}
///----------------------------------------------------------------------
///----------------------------------------------------------------------
GraphicFormat GuessGraphicFormatFromName (const std::string& parPath) {
const size_t dotPos = parPath.find_last_of('.');
if (parPath.npos == dotPos) {
@ -44,27 +89,82 @@ namespace cloonel {
return GraphicFormat_Unknown;
}
///--------------------------------------------------------------------
///--------------------------------------------------------------------
///----------------------------------------------------------------------
///----------------------------------------------------------------------
void ReadDataFromInputStream (png_structp parPngPtr, png_bytep parOutBytes, png_size_t parByteCountToRead) {
if (not png_get_io_ptr(parPngPtr))
return;
PhysicsFSFile& rawfile = *static_cast<PhysicsFSFile*>(png_get_io_ptr(parPngPtr));
const int64_t read = rawfile.Read(static_cast<void*>(parOutBytes), static_cast<uint32_t>(parByteCountToRead), 1);
if (read != static_cast<int64_t>(parByteCountToRead))
return;
return;
}
///----------------------------------------------------------------------
///http://blog.hammerian.net/2009/reading-png-images-from-memory/
///----------------------------------------------------------------------
SDL_Surface* LoadNewPngSurface (const std::string& parPath) {
PhysicsFSFile rawfile(parPath.c_str(), PhysicsFSFile::OpenMode_Read, "graphics");
unsigned char header[8];
assert(rawfile.IsOpen());
rawfile.Read(header, 8, 1);
if (png_sig_cmp(header, 0, 8))
//Read the signature from the input stream
rawfile.Read(header, lengthof(header), 1);
if (png_sig_cmp(header, 0, lengthof(header)))
return nullptr;
png_structp pngptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (not pngptr)
return nullptr;
//Get the file info struct
png_structp pngptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (not pngptr)
return nullptr;
return nullptr;
//Get the data info struct
png_infop infoptr = png_create_info_struct(pngptr);
if (not infoptr) {
png_destroy_read_struct(&pngptr, nullptr, nullptr);
return nullptr;
}
//Set the function that will be called to read data from the stream
png_set_read_fn(pngptr, &rawfile, ReadDataFromInputStream);
//Tell the lib we already verified the signature
png_set_sig_bytes(pngptr, lengthof(header));
//Read the header
png_uint_32 width, height;
int bitDepth, colorType;
png_read_info(pngptr, infoptr);
const png_uint_32 headerGetInfoRetVal = png_get_IHDR(pngptr, infoptr, &width, &height, &bitDepth, &colorType, nullptr, nullptr, nullptr);
if (static_cast<png_uint_32>(-1) == headerGetInfoRetVal) {
png_destroy_read_struct(&pngptr, &infoptr, nullptr);
return nullptr;
}
SDL_Surface* retSurf;
switch (colorType) {
case PNG_COLOR_TYPE_RGB:
retSurf = nullptr; //SurfaceFromPngRGB();
assert(false); //not implemented
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
retSurf = SurfaceFromPngRGBA(ushort2(static_cast<uint8_t>(width), static_cast<uint8_t>(height)), bitDepth * 4, pngptr, infoptr);
break;
default:
png_destroy_read_struct(&pngptr, &infoptr, nullptr);
retSurf = nullptr;
}
return retSurf;
}
} //unnamed namespace
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
Texture::Texture (const std::string& parPath, SDLMain* parMain, bool parLoadNow) :
m_path(parPath),
m_texture(nullptr),
@ -74,14 +174,14 @@ namespace cloonel {
Reload();
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
Texture::~Texture() noexcept {
Destroy();
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Destroy() noexcept {
if (m_texture) {
SDL_DestroyTexture(m_texture);
@ -89,8 +189,8 @@ namespace cloonel {
}
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Reload() {
const GraphicFormat fmt = GuessGraphicFormatFromName(m_path);
Destroy();
@ -99,6 +199,7 @@ namespace cloonel {
switch (fmt) {
case GraphicFormat_Png:
surf = LoadNewPngSurface(m_path.c_str());
break;
default:
throw std::runtime_error(std::string("Unsupported file format for \"") + m_path + "\"");
@ -116,9 +217,9 @@ namespace cloonel {
}
}
///------------------------------------------------------------------------
///------------------------------------------------------------------------
void Texture::Render (const int2& parPos) {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
void Texture::Render (int2 parPos) const {
assert(IsLoaded());
const SDL_Rect dest = { parPos.x(), parPos.y(), m_size.x(), m_size.y() };
SDL_RenderCopy(m_sdlmain->GetRenderer(), m_texture, nullptr, &dest);