diff --git a/CMakeLists.txt b/CMakeLists.txt index 4898be8..1a3b43b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,18 @@ add_definitions(-DUNICODE -D_UNICODE) include_directories("DevIL Windows SDK/include") link_directories("DevIL Windows SDK/lib/x64/unicode/Release") -set(SOURCE_FILE main.cpp pixel_format.cpp) -set(HEADER_FILE pixel_format.h) +set(SOURCE_FILE main.cpp pixel_format.cpp + ILImage.h + ILImageSupport.cpp + ConvertImage.cpp + TextureFileCreater.h + TextureFileCreater.cpp + TextureFileCreaterR.cpp + TextureFileCreaterRG.cpp + TextureFileCreaterRGB.cpp + TextureFileCreaterRGBA.cpp) + +set(HEADER_FILE pixel_format.h ConvertImage.h) SOURCE_GROUP("Header Files" FILES ${HEADER_FILE}) SOURCE_GROUP("Source Files" FILES ${SOURCE_FILE}) diff --git a/ConvertImage.cpp b/ConvertImage.cpp new file mode 100644 index 0000000..dd9ed49 --- /dev/null +++ b/ConvertImage.cpp @@ -0,0 +1,71 @@ +#include"ConvertImage.h" +#include"ILImage.h" +#include"TextureFileCreater.h" + +TextureFileCreater *CreateTextureFileCreaterR(const PixelFormat *,ILImage *); +TextureFileCreater *CreateTextureFileCreaterRG(const PixelFormat *,ILImage *); +TextureFileCreater *CreateTextureFileCreaterRGB(const PixelFormat *,ILImage *); +TextureFileCreater *CreateTextureFileCreaterRGBA(const PixelFormat *,ILImage *); + +ConvertImage::ConvertImage() +{ + image=nullptr; +} + +ConvertImage::~ConvertImage() +{ + SAFE_CLEAR(image); +} + +bool ConvertImage::Load(const OSString &fn) +{ + LOG_INFO(OS_TEXT("File: ")+fn); + + image=new ILImage(); + + if(!image->LoadFile(fn)) + { + delete image; + return(false); + } + + filename=fn; + + return(true); +} + +bool ConvertImage::Convert(const PixelFormat **pf) +{ + image->Bind(); + + const uint channels=image->channels(); + + TextureFileCreater *tex_file_creater; + + if(channels==1)tex_file_creater=CreateTextureFileCreaterR(pf[0],image);else + if(channels==2)tex_file_creater=CreateTextureFileCreaterRG(pf[1],image);else + if(channels==3)tex_file_creater=CreateTextureFileCreaterRGB(pf[2],image);else + if(channels==4)tex_file_creater=CreateTextureFileCreaterRGBA(pf[3],image);else + { + LOG_ERROR(OS_TEXT("image format don't support ")); + return(false); + } + + if(!tex_file_creater->WriteFileHeader(filename)) + { + tex_file_creater->Delete(); + LOG_ERROR(OS_TEXT("Write file header failed.")); + return(false); + } + + if(!tex_file_creater->Write()) + { + tex_file_creater->Delete(); + return(false); + } + + tex_file_creater->Close(); + + delete tex_file_creater; + return(true); +} diff --git a/ConvertImage.h b/ConvertImage.h new file mode 100644 index 0000000..923fc2c --- /dev/null +++ b/ConvertImage.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include +#include"pixel_format.h" + +using namespace hgl; + +class ILImage; + +class ConvertImage +{ + OSString filename; + + ILImage *image; + +private: + + bool CreateTextureFile(const PixelFormat *); + +private: + +public: + + ConvertImage(); + ~ConvertImage(); + + bool Load(const OSString &fn); + bool Convert(const PixelFormat **); +};//class ConvertImage \ No newline at end of file diff --git a/ILImage.h b/ILImage.h new file mode 100644 index 0000000..f1e4483 --- /dev/null +++ b/ILImage.h @@ -0,0 +1,51 @@ +#pragma once +#include +#include + +using namespace hgl; + +class ILImage +{ + ILuint il_index; + ILuint il_width,il_height; + ILuint il_bit,il_format,il_type; + + uint channel_count; + +private: + + bool Convert(ILuint,ILuint); + + void *GetData(ILuint,ILuint); + +public: + + const ILuint width ()const{return il_width;} + const ILuint height ()const{return il_height;} + const ILuint bit ()const{return il_bit;} + const ILuint format ()const{return il_format;} + const ILuint type ()const{return il_type;} + + const ILuint pixel_total()const{return il_width*il_height;} + +public: + + const uint channels()const{return channel_count;} //通道数量 + +public: + + ILImage(); + ~ILImage(); + + bool LoadFile(const OSString &); + + void Bind(); + + void *GetR(ILuint type); + + void *GetRG(ILuint type){return GetData(IL_LUMINANCE_ALPHA,type);} + void *GetRGB(ILuint type){return GetData(IL_RGB,type);} + void *GetBGR(ILuint type){return GetData(IL_BGR,type);} + void *GetRGBA(ILuint type){return GetData(IL_RGBA,type);} + void *GetBGRA(ILuint type){return GetData(IL_BGRA,type);} +};//class ILImage diff --git a/ILImageSupport.cpp b/ILImageSupport.cpp new file mode 100644 index 0000000..7d6f4fb --- /dev/null +++ b/ILImageSupport.cpp @@ -0,0 +1,133 @@ +//注:起名为ILImageSupport是为了避免与IL中现有的ilimage冲突 + +#include"ILImage.h" +#include +#include + +using namespace hgl; + +ILImage::ILImage() +{ + ilGenImages(1,&il_index); +} + +ILImage::~ILImage() +{ + ilDeleteImages(1,&il_index); +} + +void ILImage::Bind() +{ + ilBindImage(il_index); +} + +bool ILImage::Convert(ILuint format,ILuint type) +{ + if(il_format==format + &&il_type==type)return(true); + + Bind(); + if(!ilConvertImage(format,type)) + return(false); + + il_format=format; + il_type=type; + return(true); +} + +bool ILImage::LoadFile(const OSString &filename) +{ + Bind(); + + if(!ilLoadImage(filename.c_str())) + { + LOG_ERROR(OS_TEXT("LoadImage failed.")); + return(false); + } + + il_width =ilGetInteger(IL_IMAGE_WIDTH); + il_height =ilGetInteger(IL_IMAGE_HEIGHT); + il_bit =ilGetInteger(IL_IMAGE_BITS_PER_PIXEL); + il_format =ilGetInteger(IL_IMAGE_FORMAT); + il_type =ilGetInteger(IL_IMAGE_TYPE); + + if(ilGetInteger(IL_IMAGE_ORIGIN)==IL_ORIGIN_LOWER_LEFT) + iluFlipImage(); + + LOG_INFO(OS_TEXT("\t width: ")+OSString(il_width)); + LOG_INFO(OS_TEXT("\theight: ")+OSString(il_height)); + LOG_INFO(OS_TEXT("\t bit: ")+OSString(il_bit)); + LOG_INFO(OS_TEXT("\tformat: ")+OSString(il_format)); + LOG_INFO(OS_TEXT("\t type: ")+OSString(il_type)); + + if(il_format==IL_COLOR_INDEX) + { + uint il_pattle=ilGetInteger(IL_PALETTE_TYPE); + + if(il_pattle==IL_PAL_RGB24||il_pattle==IL_PAL_BGR24) + { + il_bit =24; + il_format =IL_BGR; + il_type =IL_UNSIGNED_BYTE; + } + else + if(il_pattle==IL_PAL_RGB32||il_pattle==IL_PAL_BGR32) + { + il_bit =48; + il_format =IL_BGR; + il_type =IL_UNSIGNED_SHORT; + } + else + if(il_pattle==IL_PAL_RGBA32||il_pattle==IL_PAL_BGRA32) + { + il_bit =32; + il_format =IL_BGRA; + il_type =IL_UNSIGNED_BYTE; + } + else + { + LOG_ERROR("Don't support the pattle format."); + return(false); + } + + Convert(il_format,il_type); + } + + if(il_format==IL_LUMINANCE||il_format==IL_ALPHA)channel_count=1;else + if(il_format==IL_LUMINANCE_ALPHA) channel_count=2;else + if(il_format==IL_RGB||il_format==IL_BGR) channel_count=3;else + if(il_format==IL_RGBA||il_format==IL_BGRA) channel_count=4;else + channel_count=0; + + return(true); +} + +void *ILImage::GetR(ILuint type) +{ + Bind(); + + if(il_format==IL_ALPHA)return ilGetAlpha(type); + if(il_format==IL_LUMINANCE) + { + if(il_type!=type) + { + if(!Convert(il_format,type)) + return(nullptr); + + return ilGetData(); + } + } + + return(nullptr); +} + +void *ILImage::GetData(ILuint format,ILuint type) +{ + Bind(); + + if(il_format!=format||il_type!=type) + if(!Convert(format,type)) + return nullptr; + + return ilGetData(); +} diff --git a/TextureFileCreater.cpp b/TextureFileCreater.cpp new file mode 100644 index 0000000..b3b4fc9 --- /dev/null +++ b/TextureFileCreater.cpp @@ -0,0 +1,122 @@ +#include"TextureFileCreater.h" +#include + +namespace +{ + /** + * 截取完整路径中的路径名和文件名 + * @param pathname 拆分后的路径名 + * @param filename 拆分后的文件名 + * @param fullname 拆分前的完整路径文件名 + */ + template + inline bool SplitFilename(BaseString &pathname,BaseString &filename,const BaseString &fullname) + { + if(fullname.Length()<=1) + return false; + + const T spear_char[] = { '/','\\' }; + + const int pos=fullname.FindRightChar(spear_char); + + if(pos==-1) + return(false); + + pathname.Strcpy(fullname,pos); + filename.Strcpy(fullname.c_str()+pos+1); + + return(true); + } + + template + inline BaseString ReplaceExtName(const BaseString &old_name,const BaseString &new_extname,const T split_char='.') + { + if(old_name.Length()<=1) + return(BaseString::charOf(split_char)+new_extname); + + const int pos=old_name.FindRightChar(split_char); + + if(pos==-1) + return old_name.SubString(0,pos+1)+new_extname; + else + return old_name+BaseString(split_char)+new_extname; + } +}//namespace + +bool ToILType(ILuint &type,const uint8 bits,const ColorDataType cdt) +{ + constexpr ILuint target_type[3][(uint)ColorDataType::END-1]= + { + //UNORM SNORM UINT SINT, USCALE,SSCALE, UFLOAT SFLOAT + {IL_UNSIGNED_BYTE, IL_BYTE, IL_UNSIGNED_BYTE, IL_BYTE, 0,0, 0, 0}, + {IL_UNSIGNED_SHORT, IL_SHORT, IL_UNSIGNED_SHORT, IL_SHORT, 0,0, IL_HALF, IL_HALF}, + {IL_UNSIGNED_INT, IL_INT, IL_UNSIGNED_INT, IL_INT, 0,0, IL_FLOAT, IL_FLOAT} + }; + + if(bits<=8 )type=target_type[0][(uint)cdt-1];else + if(bits<=16 )type=target_type[1][(uint)cdt-1];else + if(bits<=32 )type=target_type[2][(uint)cdt-1];else + return(false); + + return(type); +} + +TextureFileCreater::TextureFileCreater(const PixelFormat *pf,ILImage *img) +{ + fmt=pf; + image=img; + + pixel_total=image->pixel_total(); + pixel_bytes=pf->GetPixelBytes(); + total_bytes=pixel_total*pixel_bytes; + + dos=nullptr; +} +TextureFileCreater::~TextureFileCreater() +{ + SAFE_CLEAR(dos); +} + +bool TextureFileCreater::WriteFileHeader(const OSString &old_filename) +{ + OSString pn,fn; + + SplitFilename(pn,fn,old_filename); + + filename=ReplaceExtName(old_filename,OS_TEXT(".Tex2D")); + + if(!fos.CreateTrunc(filename)) + return(false); + + dos=new io::LEDataOutputStream(&fos); + + dos->Write("Tex2D\x1A",6); + dos->WriteUint8(2); //版本 + dos->WriteBool(false); //是否有mipmaps + dos->WriteUint32(image->width()); + dos->WriteUint32(image->height()); + dos->WriteUint8(fmt->channels); //颜色通道数 + dos->WriteUint8((uint8 *)fmt->color,fmt->channels); //颜色标记 + dos->WriteUint8(fmt->bits,fmt->channels); //颜色位数 + dos->WriteUint8((uint8)fmt->type); //数据类型 + + return(true); +} + +bool TextureFileCreater::Write(void *data) +{ + return(dos->Write(data,total_bytes)==total_bytes); +} + +void TextureFileCreater::Close() +{ + SAFE_CLEAR(dos); + fos.Close(); +} + +void TextureFileCreater::Delete() +{ + Close(); + + filesystem::FileDelete(filename); +} \ No newline at end of file diff --git a/TextureFileCreater.h b/TextureFileCreater.h new file mode 100644 index 0000000..5d53a4d --- /dev/null +++ b/TextureFileCreater.h @@ -0,0 +1,44 @@ +#pragma once + +#include"ILImage.h" +#include"pixel_format.h" +#include +#include + +using namespace hgl; + +bool ToILType(ILuint &type,const uint8 bits,const ColorDataType cdt); + +class TextureFileCreater +{ +protected: + + const PixelFormat *fmt; + + ILImage *image; + + uint pixel_bytes; //单像素字节数 + uint pixel_total; //象素总量=width*height + uint total_bytes; //总字节数 + +protected: + + OSString filename; + + io::FileOutputStream fos; + io::DataOutputStream *dos; + + bool Write(void *); + +public: + + TextureFileCreater(const PixelFormat *pf,ILImage *); + virtual ~TextureFileCreater(); + + virtual bool WriteFileHeader(const OSString &); + + virtual bool Write()=0; + + virtual void Close(); + virtual void Delete(); +};//class TextureFileCreater \ No newline at end of file diff --git a/TextureFileCreaterR.cpp b/TextureFileCreaterR.cpp new file mode 100644 index 0000000..aacff9d --- /dev/null +++ b/TextureFileCreaterR.cpp @@ -0,0 +1,32 @@ +#include"TextureFileCreater.h" +#include"ILImage.h" + +class TextureFileCreaterR:public TextureFileCreater +{ +public: + + using TextureFileCreater::TextureFileCreater; + +public: + + bool Write() override + { + ILuint type; + + if(!ToILType(type,fmt->bits[0],fmt->type)) + return(nullptr); + + void *data=image->GetR(type); + + if(!data) + return(nullptr); + + //目前仅有R8UN,R16UN,R16F,R32U,R32I,R32F几种,都是8的整倍数,所以直接写 + return TextureFileCreater::Write(data); + } +};//class TextureFileCreaterR:public TextureFileCreater + +TextureFileCreater *CreateTextureFileCreaterR(const PixelFormat *pf,ILImage *image) +{ + return(new TextureFileCreaterR(pf,image)); +} \ No newline at end of file diff --git a/TextureFileCreaterRG.cpp b/TextureFileCreaterRG.cpp new file mode 100644 index 0000000..5e10f9e --- /dev/null +++ b/TextureFileCreaterRG.cpp @@ -0,0 +1,30 @@ +#include"TextureFileCreater.h" +#include"ILImage.h" + +class TextureFileCreaterRG:public TextureFileCreater +{ +public: + + using TextureFileCreater::TextureFileCreater; + +public: + + bool Write() override + { + ILuint type; + + if(!ToILType(type,fmt->bits[0],fmt->type)) + return(nullptr); + + void *data=image->GetRG(type); + + //目前仅有R8UN,R16UN,R16F,R32U,R32I,R32F几种,都是8的整倍数,所以直接写 + + return TextureFileCreater::Write(data); + } +};//class TextureFileCreaterRG:public TextureFileCreater + +TextureFileCreater *CreateTextureFileCreaterRG(const PixelFormat *pf,ILImage *image) +{ + return(new TextureFileCreaterRG(pf,image)); +} diff --git a/TextureFileCreaterRGB.cpp b/TextureFileCreaterRGB.cpp new file mode 100644 index 0000000..4594069 --- /dev/null +++ b/TextureFileCreaterRGB.cpp @@ -0,0 +1,62 @@ +#include"TextureFileCreater.h" +#include"ILImage.h" +#include + +class TextureFileCreaterRGB:public TextureFileCreater +{ +public: + + using TextureFileCreater::TextureFileCreater; + + void RGB8toRGB565(uint16 *target,uint8 *src,uint size) + { + for(uint i=0;i>3); + + ++target; + src+=3; + } + } + +public: + + bool Write() override + { + if(fmt->format==ColorFormat::RGB32U + ||fmt->format==ColorFormat::RGB32I + ||fmt->format==ColorFormat::RGB32F) + { + ILuint type; + + if(!ToILType(type,fmt->bits[0],fmt->type)) + return(nullptr); + + void *origin_rgb=image->GetRGB(type); + + return TextureFileCreater::Write(origin_rgb); + } + else if(fmt->format==ColorFormat::RGB565) + { + void *origin_rgb=image->GetRGB(IL_UNSIGNED_BYTE); + + AutoDelete rgb565=new uint16[image->pixel_total()]; + + RGB8toRGB565(rgb565,(uint8 *)origin_rgb,image->pixel_total()); + + return TextureFileCreater::Write(rgb565); + } + else + { + LOG_ERROR(OS_TEXT("Don't support this RGB format")); + return(false); + } + } +};//class TextureFileCreaterRGB:public TextureFileCreater + +TextureFileCreater *CreateTextureFileCreaterRGB(const PixelFormat *pf,ILImage *image) +{ + return(new TextureFileCreaterRGB(pf,image)); +} diff --git a/TextureFileCreaterRGBA.cpp b/TextureFileCreaterRGBA.cpp new file mode 100644 index 0000000..88d014a --- /dev/null +++ b/TextureFileCreaterRGBA.cpp @@ -0,0 +1,114 @@ +#include"TextureFileCreater.h" +#include"ILImage.h" +#include + +class TextureFileCreaterRGBA:public TextureFileCreater +{ +public: + + using TextureFileCreater::TextureFileCreater; + + void RGBA8toRGBA4(uint16 *target,uint8 *src,uint size) + { + for(uint i=0;i>4); + + ++target; + src+=4; + } + } + + void RGBA8toA1RGB5(uint16 *target,uint8 *src,uint size) + { + for(uint i=0;i>3); + + ++target; + src+=4; + } + } + + void RGBA16toA2BGR10(uint32 *target,uint16 *src,uint size) + { + for(uint i=0;i> 6); + + ++target; + src+=4; + } + } + +public: + + bool Write() override + { + if(fmt->format==ColorFormat::RGBA8UN + ||fmt->format==ColorFormat::RGBA16UN + ||fmt->format==ColorFormat::RGBA16F + ||fmt->format==ColorFormat::RGBA32U + ||fmt->format==ColorFormat::RGBA32I + ||fmt->format==ColorFormat::RGBA32F) + { + ILuint type; + + if(!ToILType(type,fmt->bits[0],fmt->type)) + return(nullptr); + + void *origin_rgba=image->GetRGBA(type); + + return TextureFileCreater::Write(origin_rgba); + } + else if(fmt->format==ColorFormat::BGRA4) + { + void *origin_rgba=image->GetRGBA(IL_UNSIGNED_BYTE); + + AutoDelete bgra4=new uint16[image->pixel_total()]; + + RGBA8toRGBA4(bgra4,(uint8 *)origin_rgba,image->pixel_total()); + + return TextureFileCreater::Write(bgra4); + } + else if(fmt->format==ColorFormat::A1RGB5) + { + void *origin_rgba=image->GetRGBA(IL_UNSIGNED_BYTE); + + AutoDelete a1_rgb5=new uint16[image->pixel_total()]; + + RGBA8toA1RGB5(a1_rgb5,(uint8 *)origin_rgba,image->pixel_total()); + + return TextureFileCreater::Write(a1_rgb5); + } + else if(fmt->format==ColorFormat::A2BGR10UN) + { + void *origin_rgba=image->GetRGBA(IL_UNSIGNED_SHORT); + + AutoDelete a2_bgr10=new uint32[image->pixel_total()]; + + RGBA16toA2BGR10(a2_bgr10,(uint16 *)origin_rgba,image->pixel_total()); + + return TextureFileCreater::Write(a2_bgr10); + } + else + { + LOG_ERROR(OS_TEXT("Don't support this RGBA format")); + return(false); + } + } +};//class TextureFileCreaterRGB:public TextureFileCreater + +TextureFileCreater *CreateTextureFileCreaterRGBA(const PixelFormat *pf,ILImage *image) +{ + return(new TextureFileCreaterRGBA(pf,image)); +} diff --git a/main.cpp b/main.cpp index 70d171f..ab08d3e 100644 --- a/main.cpp +++ b/main.cpp @@ -1,13 +1,11 @@ -#include -#include -#include +#include #include -#include"pixel_format.h" #include #include #include #include #include +#include"ConvertImage.h" using namespace hgl; using namespace hgl::filesystem; @@ -48,7 +46,7 @@ void ParseParamFormat(const CmdParse &cmd) std::cout<name<name<<" "<GetPixelBytes()<<" bits "<type)]<channels<<": "<name<<" "<GetPixelBytes()<<" bits "<type)]<>3;} ///<获取单个象素所需字节数 };// const PixelFormat *GetPixelFormat(ColorFormat); ///<根据获取获取象素格式类型