ULRE/src/SceneGraph/TextureLoader.cpp

243 lines
8.9 KiB
C++

#include<hgl/graph/TextureLoader.h>
#include<hgl/io/FileInputStream.h>
#include<hgl/log/LogInfo.h>
namespace hgl
{
namespace graph
{
namespace
{
constexpr VkFormat CompressFormatList[]=
{
PF_BC1_RGBUN,
PF_BC1_RGBAUN,
PF_BC2UN,
PF_BC3UN,
PF_BC4UN,
PF_BC5UN,
PF_BC6UF,
PF_BC6SF,
PF_BC7UN
};
constexpr uint32 CompressFormatBits[]={4,4,8,8,4,8,8,8,8};
constexpr uint32 CompressFormatCount=sizeof(CompressFormatList)/sizeof(VkFormat);
}
const uint TexPixelFormat::pixel_bits()const
{
return channels ?bits[0]+bits[1]+bits[2]+bits[3]
:CompressFormatBits[compress_format];
}
const uint32 ComputeMipmapBytes(uint32 length,uint32 bytes)
{
uint32 total=0;
while(length>=1)
{
if(bytes<8)
total+=8;
else
total+=bytes;
if(length==1)break;
if(length>1){length>>=1;bytes>>=1;}
}
return total;
}
const uint32 ComputeMipmapBytes(uint32 width,uint32 height,uint32 bytes)
{
uint32 total=0;
while(width>=1&&height>=1)
{
if(bytes<8)
total+=8;
else
total+=bytes;
if(width==1&&height==1)break;
if(width >1){width >>=1;bytes>>=1;}
if(height>1){height>>=1;bytes>>=1;}
}
return total;
}
const uint32 ComputeMipmapBytes(uint32 width,uint32 height,uint32 depth,uint32 bytes)
{
uint32 total=0;
while(width>=1&&height>=1&&depth>=1)
{
if(bytes<8)
total+=8;
else
total+=bytes;
if(width==1&&height==1&&depth==1)break;
if(depth >1){depth >>=1;bytes>>=1;}
if(width >1){width >>=1;bytes>>=1;}
if(height>1){height>>=1;bytes>>=1;}
}
return total;
}
struct VulkanTexturePixelFormat
{
VkFormat format;
uint8 channels; //颜色通道数
char colors[4];
uint8 bits[4];
VulkanNumberType type;
};//
constexpr VulkanTexturePixelFormat pf_list[]=
{
{ PF_RGBA4, 4,{'R','G','B','A'},{ 4, 4, 4, 4},VulkanNumberType::UNORM}, //Android 部分不支持
{ PF_BGRA4, 4,{'B','G','R','A'},{ 4, 4, 4, 4},VulkanNumberType::UNORM}, //ios不支持这个
{UPF_RGB565, 3,{'R','G','B', 0 },{ 5, 6, 5, 0},VulkanNumberType::UNORM},
{UPF_A1RGB5, 4,{'A','R','G','B'},{ 1, 5, 5, 5},VulkanNumberType::UNORM},
{UPF_R8, 1,{'R', 0 , 0 , 0 },{ 8, 0, 0, 0},VulkanNumberType::UNORM},
{UPF_RG8, 2,{'R','G', 0 , 0 },{ 8, 8, 0, 0},VulkanNumberType::UNORM},
{UPF_RGBA8, 4,{'R','G','B','A'},{ 8, 8, 8, 8},VulkanNumberType::UNORM},
{UPF_RGBA8S, 4,{'R','G','B','A'},{ 8, 8, 8, 8},VulkanNumberType::SNORM},
{UPF_RGBA8U, 4,{'R','G','B','A'},{ 8, 8, 8, 8},VulkanNumberType::UINT},
{UPF_RGBA8I, 4,{'R','G','B','A'},{ 8, 8, 8, 8},VulkanNumberType::SINT},
{UPF_ABGR8, 4,{'A','B','G','R'},{ 8, 8, 8, 8},VulkanNumberType::UNORM},
{UPF_A2BGR10, 4,{'A','B','G','R'},{ 2,10,10,10},VulkanNumberType::UNORM},
{UPF_R16, 1,{'R', 0 , 0 , 0 },{16, 0, 0, 0},VulkanNumberType::UNORM},
{UPF_R16U, 1,{'R', 0 , 0 , 0 },{16, 0, 0, 0},VulkanNumberType::UINT},
{UPF_R16I, 1,{'R', 0 , 0 , 0 },{16, 0, 0, 0},VulkanNumberType::SINT},
{UPF_R16F, 1,{'R', 0 , 0 , 0 },{16, 0, 0, 0},VulkanNumberType::SFLOAT},
{UPF_RG16, 2,{'R','G', 0 , 0 },{16,16, 0, 0},VulkanNumberType::UNORM},
{UPF_RG16U, 2,{'R','G', 0 , 0 },{16,16, 0, 0},VulkanNumberType::UINT},
{UPF_RG16I, 2,{'R','G', 0 , 0 },{16,16, 0, 0},VulkanNumberType::SINT},
{UPF_RG16F, 2,{'R','G', 0 , 0 },{16,16, 0, 0},VulkanNumberType::SFLOAT},
{ PF_RGBA16UN, 4,{'R','G','B','A'},{16,16,16,16},VulkanNumberType::UNORM},
{ PF_RGBA16SN, 4,{'R','G','B','A'},{16,16,16,16},VulkanNumberType::SNORM},
{UPF_RGBA16U, 4,{'R','G','B','A'},{16,16,16,16},VulkanNumberType::UINT},
{UPF_RGBA16I, 4,{'R','G','B','A'},{16,16,16,16},VulkanNumberType::SINT},
{UPF_RGBA16F, 4,{'R','G','B','A'},{16,16,16,16},VulkanNumberType::SFLOAT},
{UPF_R32U, 1,{'R', 0 , 0 , 0 },{32, 0, 0, 0},VulkanNumberType::UINT},
{UPF_R32I, 1,{'R', 0 , 0 , 0 },{32, 0, 0, 0},VulkanNumberType::SINT},
{UPF_R32F, 1,{'R', 0 , 0 , 0 },{32, 0, 0, 0},VulkanNumberType::SFLOAT},
{UPF_RG32U, 2,{'R','G', 0 , 0 },{32,32, 0, 0},VulkanNumberType::UINT},
{UPF_RG32I, 2,{'R','G', 0 , 0 },{32,32, 0, 0},VulkanNumberType::SINT},
{UPF_RG32F, 2,{'R','G', 0 , 0 },{32,32, 0, 0},VulkanNumberType::SFLOAT},
{ PF_RGB32U, 3,{'R','G','B', 0 },{32,32,32, 0},VulkanNumberType::UINT},
{ PF_RGB32I, 3,{'R','G','B', 0 },{32,32,32, 0},VulkanNumberType::SINT},
{ PF_RGB32F, 3,{'R','G','B', 0 },{32,32,32, 0},VulkanNumberType::SFLOAT},
{UPF_RGBA32U, 4,{'R','G','B','A'},{32,32,32,32},VulkanNumberType::UINT},
{UPF_RGBA32I, 4,{'R','G','B','A'},{32,32,32,32},VulkanNumberType::SINT},
{UPF_RGBA32F, 4,{'R','G','B','A'},{32,32,32,32},VulkanNumberType::SFLOAT},
{UPF_B10GR11UF, 3,{'B','G','R', 0 },{10,11,11, 0},VulkanNumberType::UFLOAT}
};
constexpr uint VulkanTexturePixelFormatCount=sizeof(pf_list)/sizeof(VulkanTexturePixelFormat);
const VkFormat GetVulkanFormat(const TexPixelFormat &tpf)
{
const VulkanTexturePixelFormat *pf=pf_list;
for(uint i=0;i<VulkanTexturePixelFormatCount;i++,++pf)
{
if(tpf.channels!=pf->channels)continue;
if(tpf.datatype!=(uint8)pf->type)continue;
if(tpf.colors[0]!=pf->colors[0])continue;
if(tpf.colors[1]!=pf->colors[1])continue;
if(tpf.colors[2]!=pf->colors[2])continue;
if(tpf.colors[3]!=pf->colors[3])continue;
if(tpf.bits[0]!=pf->bits[0])continue;
if(tpf.bits[1]!=pf->bits[1])continue;
if(tpf.bits[2]!=pf->bits[2])continue;
if(tpf.bits[3]!=pf->bits[3])continue;
return pf->format;
}
return VK_FORMAT_UNDEFINED;
}
bool TextureLoader::Load(io::InputStream *is)
{
if(!is)return(false);
if(is->Read(&file_header,sizeof(TextureFileHeader))!=sizeof(TextureFileHeader))
return(false);
constexpr char TEXTURE_FILE_HEADER[]="Texture";
constexpr uint TEXTURE_FILE_HEADER_LENGTH=sizeof(TEXTURE_FILE_HEADER)-1;
if(memcmp(&file_header.id_str,TEXTURE_FILE_HEADER,TEXTURE_FILE_HEADER_LENGTH))
return(false);
if(file_header.version!=0)
return(false);
// if(file_header.type!=type)
// return(false);
if(file_header.pixel_format.channels==0)
{
if(file_header.pixel_format.compress_format<0
||file_header.pixel_format.compress_format>=CompressFormatCount)
return(nullptr);
format=CompressFormatList[file_header.pixel_format.compress_format];
}
else
{
format=GetVulkanFormat(file_header.pixel_format);
}
//计算0级mipmap图像的字节数
mipmap_zero_total_bytes=(GetPixelsCount()*file_header.pixel_format.pixel_bits())>>3;
total_bytes=GetTotalBytes();
const uint32 file_left_bytes=is->Available();
if(file_left_bytes<total_bytes)
return(false);
void *ptr=OnBegin(total_bytes);
if(!ptr)
return(false);
if(is->Read(ptr,total_bytes)!=total_bytes)
OnError();
OnEnd();
return(true);
}
bool TextureLoader::Load(const OSString &filename)
{
io::OpenFileInputStream fis(filename);
if(!fis)
{
LOG_ERROR(OS_TEXT("[ERROR] open texture file<")+filename+OS_TEXT("> failed."));
return(false);
}
return this->Load(&fis);
}
}//namespace graph
}//namespace hgl