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 }