ULRE/example/Vulkan/TGATexture.cpp

187 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include<hgl/graph/vulkan/VK.h>
#include<hgl/graph/vulkan/VKDevice.h>
#include<hgl/graph/vulkan/VKBuffer.h>
#include<hgl/io/FileInputStream.h>
#include<hgl/LogInfo.h>
VK_NAMESPACE_BEGIN
namespace
{
#pragma pack(push,1)
struct TGAHeader
{
uint8 id;
uint8 color_map_type;
uint8 image_type; // 1 colormap image ,2 true-color,3 grayscale
uint16 color_map_first;
uint16 color_map_length;
uint8 color_map_size;
uint16 x_origin;
uint16 y_origin;
uint16 width;
uint16 height;
uint8 bit;
uint8 image_desc;
};
union TGAImageDesc
{
//不要把此union放到上面的struct中否则Visual C++会将此union编译成4字节。GCC无此问题
uint8 image_desc;
struct
{
uint alpha_depth:4;
uint reserved:1;
uint direction:1; //0 lower-left,1 upper left
};
};
#pragma pack(pop)
void RGB8to565(uint16 *target,uint8 *src,uint size)
{
for(uint i=0;i<size;i++)
{
*target=((src[2]<<8)&0xF800)
|((src[1]<<3)&0x7E0)
| (src[0]>>3);
++target;
src+=3;
}
}
void RGBtoRGBA(uint8 *tar,uint8 *src,uint size)
{
for(uint i=0;i<size;i++)
{
*tar++=*src++;
*tar++=*src++;
*tar++=*src++;
*tar++=255;
}
}
void SwapRow(uint8 *data,uint line_size,uint height)
{
uint8 *top=data;
uint8 *bottom=data+(height-1)*line_size;
uint8 *tmp=new uint8[line_size];
while(top<bottom)
{
memcpy(tmp,bottom,line_size);
memcpy(bottom,top,line_size);
memcpy(top,tmp,line_size);
top+=line_size;
bottom-=line_size;
}
delete[] tmp;
}
}//namespace
Texture2D *LoadTGATexture(const OSString &filename,Device *device)
{
io::OpenFileInputStream fis(filename);
if(!fis)
{
LOG_ERROR(OS_TEXT("[ERROR] open file<")+filename+OS_TEXT("> failed."));
return(nullptr);
}
const int64 file_length=fis->GetSize();
if(file_length<=sizeof(TGAHeader))
{
LOG_ERROR(OS_TEXT("[ERROR] file<")+filename+OS_TEXT("> length < sizeof(TGAHeader)."));
return(nullptr);
}
TGAHeader header;
TGAImageDesc image_desc;
if(fis->Read(&header,sizeof(TGAHeader))!=sizeof(TGAHeader))
return(false);
const uint total_bytes=header.width*header.height*header.bit>>3;
if(file_length<sizeof(TGAHeader)+total_bytes)
{
LOG_ERROR(OS_TEXT("[ERROR] file<")+filename+OS_TEXT("> length error."));
return(nullptr);
}
image_desc.image_desc=header.image_desc;
VkFormat format=FMT_UNDEFINED;
if(header.image_type==2)
{
if(header.bit==24)format=FMT_BGRA8UN;else
if(header.bit==32)format=FMT_BGRA8UN;
}
else if(header.image_type==3&&header.bit==8)
format=FMT_R8UN;
if(format==FMT_UNDEFINED)
{
LOG_ERROR(OS_TEXT("[ERROR] Image format error,filename: ")+filename);
return(nullptr);
}
vulkan::Buffer *buf;
if(header.bit==24)
{
uint8 *pixel_data=new uint8[total_bytes];
fis->Read(pixel_data,total_bytes);
if(image_desc.direction==0)
SwapRow((uint8 *)pixel_data,header.width*header.bit/8,header.height);
buf=device->CreateBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT,header.width*header.height*4);
RGBtoRGBA((uint8 *)buf->Map(),pixel_data,header.width*header.height);
buf->Unmap();
format=FMT_BGRA8UN;
}
else
{
vulkan::Buffer *buf=device->CreateBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT,total_bytes);
uint8 *pixel_data=(uint8 *)buf->Map();
fis->Read(pixel_data,total_bytes);
if(image_desc.direction==0)
SwapRow((uint8 *)pixel_data,header.width*header.bit/8,header.height);
buf->Unmap();
}
Texture2D *tex=device->CreateTexture2D(format,buf,header.width,header.height);
delete buf;
if(tex)
{
LOG_INFO(OS_TEXT("load image file<")+filename+OS_TEXT(">:<")+OSString(header.width)+OS_TEXT("x")+OSString(header.height)+OS_TEXT("> to texture ok"));
//下面代码用于测试修改纹理
//device->ChangeTexture2D(tex,pixel_data,header->width/4,header->height/4,header->width/2,header->height/2,line_size*header->height/4);
}
else
{
LOG_ERROR(OS_TEXT("load image file<")+filename+OS_TEXT(">:<")+OSString(header.width)+OS_TEXT("x")+OSString(header.height)+OS_TEXT("> to texture failed."));
}
return(tex);
}
VK_NAMESPACE_END