00001 #include "gui_gl_manager.hpp"
00002 #include "gui_gl_material.hpp"
00003 #include <gui_out.hpp>
00004
00005 #include <png.h>
00006 #include <fstream>
00007 #include <iostream>
00008
00009 namespace gui {
00010 namespace gl
00011 {
00012 void raise_error(png_struct* png, char const* message)
00013 {
00014 throw utils::exception(message);
00015 }
00016
00017 void read_data(png_structp pReadStruct, png_bytep pData, png_size_t uiLength)
00018 {
00019 png_voidp p = png_get_io_ptr(pReadStruct);
00020 ((std::ifstream*)p)->read((char*)pData, uiLength);
00021 }
00022
00023 utils::refptr<gui::material> manager::create_material_png(const std::string& sFileName) const
00024 {
00025 std::ifstream mFile(sFileName, std::ios::binary);
00026 if (!mFile.is_open())
00027 {
00028 gui::out << gui::warning << "gui::gl::manager : Cannot find file '" << sFileName << "'." << std::endl;
00029 return nullptr;
00030 }
00031
00032 const uint PNGSIGSIZE = 8;
00033 png_byte lSignature[PNGSIGSIZE];
00034 mFile.read((char*)lSignature, PNGSIGSIZE);
00035 if (!mFile.good() || png_sig_cmp(lSignature, 0, PNGSIGSIZE) != 0)
00036 {
00037 gui::out << gui::warning << "gui::gl::manager : '" << sFileName <<
00038 "' is not a valid PNG image : '" << lSignature << "'." << std::endl;
00039 return nullptr;
00040 }
00041
00042 png_structp pReadStruct = nullptr;
00043 png_infop pInfoStruct = nullptr;
00044
00045 try
00046 {
00047 pReadStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, raise_error, nullptr);
00048 if (!pReadStruct)
00049 {
00050 gui::out << gui::error << "gui::gl::manager : 'png_create_read_struct' failed." << std::endl;
00051 return nullptr;
00052 }
00053
00054 pInfoStruct = png_create_info_struct(pReadStruct);
00055 if (!pInfoStruct)
00056 throw utils::exception("'png_create_info_struct' failed.");
00057
00058 png_set_read_fn(pReadStruct, (png_voidp)(&mFile), read_data);
00059
00060 png_set_sig_bytes(pReadStruct, PNGSIGSIZE);
00061 png_read_info(pReadStruct, pInfoStruct);
00062
00063 png_uint_32 uiDepth = png_get_bit_depth(pReadStruct, pInfoStruct);
00064
00065 if (uiDepth != 8)
00066 throw utils::exception("only 8 bit color chanels are supported for PNG images.");
00067
00068 png_uint_32 uiChannels = png_get_channels(pReadStruct, pInfoStruct);
00069
00070 if (uiChannels != 4 && uiChannels != 3)
00071 throw utils::exception("only RGB or RGBA is supported for PNG images.");
00072
00073 png_uint_32 uiColorType = png_get_color_type(pReadStruct, pInfoStruct);
00074
00075 if (uiColorType == PNG_COLOR_TYPE_RGB)
00076 {
00077 png_set_filler(pReadStruct, 0xff, PNG_FILLER_AFTER);
00078 uiChannels = 4;
00079 }
00080 else if (uiColorType != PNG_COLOR_TYPE_RGBA)
00081 throw utils::exception("only RGB or RGBA is supported for PNG images.");
00082
00083 png_uint_32 uiWidth = png_get_image_width(pReadStruct, pInfoStruct);
00084 png_uint_32 uiHeight = png_get_image_height(pReadStruct, pInfoStruct);
00085
00086 utils::refptr<png_bytep> pRows(new png_bytep[uiHeight]);
00087 utils::refptr<material> pTex(new gui::gl::material(uiWidth, uiHeight));
00088
00089 png_bytep* pTempRows = pRows.get();
00090 ub32color* pTempData = pTex->get_data().data();
00091 for (uint i = 0; i < uiHeight; ++i)
00092 pTempRows[i] = (png_bytep)(pTempData + i*uiWidth);
00093
00094 png_read_image(pReadStruct, pTempRows);
00095
00096 png_destroy_read_struct(&pReadStruct, &pInfoStruct, nullptr);
00097
00098 pTex->premultiply_alpha();
00099 pTex->update_texture();
00100 pTex->clear_cache_data_();
00101 lTextureList_[sFileName] = pTex;
00102
00103 return pTex;
00104 }
00105 catch (utils::exception& e)
00106 {
00107 gui::out << gui::error << "gui::gl::manager : Parsing " << sFileName << " :\n"
00108 << e.get_description() << std::endl;
00109
00110 if (pReadStruct && pInfoStruct)
00111 png_destroy_read_struct(&pReadStruct, &pInfoStruct, nullptr);
00112 else if (pReadStruct)
00113 png_destroy_read_struct(&pReadStruct, nullptr, nullptr);
00114
00115 return nullptr;
00116 }
00117 }
00118 }
00119 }