Fix DDS load crash with certain formats; support R16, RG16, R32, RG32

This commit is contained in:
rdb 2016-12-13 21:00:11 +01:00
parent b21e8fdf32
commit 23645cc407
2 changed files with 96 additions and 4 deletions

View File

@ -3643,13 +3643,13 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
header.pf.four_cc == 0x30315844) { // 'DX10'
// A DirectX 10 style texture, which has an additional header.
func = read_dds_level_generic_uncompressed;
unsigned int format = dds.get_uint32();
unsigned int dxgi_format = dds.get_uint32();
unsigned int dimension = dds.get_uint32();
unsigned int misc_flag = dds.get_uint32();
unsigned int array_size = dds.get_uint32();
/*unsigned int alpha_mode = */dds.get_uint32();
switch (format) {
switch (dxgi_format) {
case 2: // DXGI_FORMAT_R32G32B32A32_FLOAT
format = F_rgba32;
component_type = T_float;
@ -3665,6 +3665,11 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
component_type = T_unsigned_short;
func = read_dds_level_abgr16;
break;
case 16: // DXGI_FORMAT_R32G32_FLOAT
format = F_rg32;
component_type = T_float;
func = read_dds_level_raw;
break;
case 27: // DXGI_FORMAT_R8G8B8A8_TYPELESS
case 28: // DXGI_FORMAT_R8G8B8A8_UNORM
format = F_rgba8;
@ -3688,6 +3693,41 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
component_type = T_byte;
func = read_dds_level_abgr8;
break;
case 34: // DXGI_FORMAT_R16G16_FLOAT:
format = F_rg16;
component_type = T_half_float;
func = read_dds_level_raw;
break;
case 35: // DXGI_FORMAT_R16G16_UNORM:
format = F_rg16;
component_type = T_unsigned_short;
func = read_dds_level_raw;
break;
case 37: // DXGI_FORMAT_R16G16_SNORM:
format = F_rg16;
component_type = T_short;
func = read_dds_level_raw;
break;
case 40: // DXGI_FORMAT_D32_FLOAT
format = F_depth_component32;
component_type = T_float;
func = read_dds_level_raw;
break;
case 41: // DXGI_FORMAT_R32_FLOAT
format = F_r32;
component_type = T_float;
func = read_dds_level_raw;
break;
case 42: // DXGI_FORMAT_R32_UINT
format = F_r32i;
component_type = T_unsigned_int;
func = read_dds_level_raw;
break;
case 43: // DXGI_FORMAT_R32_SINT
format = F_r32i;
component_type = T_int;
func = read_dds_level_raw;
break;
case 48: // DXGI_FORMAT_R8G8_TYPELESS
case 49: // DXGI_FORMAT_R8G8_UNORM
format = F_rg;
@ -3703,6 +3743,36 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
format = F_rg8i;
component_type = T_byte;
break;
case 54: // DXGI_FORMAT_R16_FLOAT:
format = F_r16;
component_type = T_half_float;
func = read_dds_level_raw;
break;
case 55: // DXGI_FORMAT_D16_UNORM:
format = F_depth_component16;
component_type = T_unsigned_short;
func = read_dds_level_raw;
break;
case 56: // DXGI_FORMAT_R16_UNORM:
format = F_r16;
component_type = T_unsigned_short;
func = read_dds_level_raw;
break;
case 57: // DXGI_FORMAT_R16_UINT:
format = F_r16i;
component_type = T_unsigned_short;
func = read_dds_level_raw;
break;
case 58: // DXGI_FORMAT_R16_SNORM:
format = F_r16;
component_type = T_short;
func = read_dds_level_raw;
break;
case 59: // DXGI_FORMAT_R16_SINT:
format = F_r16i;
component_type = T_short;
func = read_dds_level_raw;
break;
case 60: // DXGI_FORMAT_R8_TYPELESS
case 61: // DXGI_FORMAT_R8_UNORM
format = F_red;
@ -3760,7 +3830,6 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
compression = CM_rgtc;
func = read_dds_level_bc4;
break;
break;
case 82: // DXGI_FORMAT_BC5_TYPELESS
case 83: // DXGI_FORMAT_BC5_UNORM
format = F_rg;
@ -3786,7 +3855,7 @@ do_read_dds(CData *cdata, istream &in, const string &filename, bool header_only)
break;
default:
gobj_cat.error()
<< filename << ": unsupported DXGI format " << format << ".\n";
<< filename << ": unsupported DXGI format " << dxgi_format << ".\n";
return false;
}
@ -8264,6 +8333,7 @@ read_dds_level_abgr32(Texture *tex, CData *cdata, const DDSHeader &header, int n
size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
size_t row_bytes = x_size * 16;
nassertr(row_bytes * y_size == size, PTA_uchar());
PTA_uchar image = PTA_uchar::empty_array(size);
for (int y = y_size - 1; y >= 0; --y) {
unsigned char *p = image.p() + y * row_bytes;
@ -8280,6 +8350,26 @@ read_dds_level_abgr32(Texture *tex, CData *cdata, const DDSHeader &header, int n
return image;
}
/**
* Called by read_dds for a DDS file that needs no transformations applied.
*/
PTA_uchar Texture::
read_dds_level_raw(Texture *tex, CData *cdata, const DDSHeader &header, int n, istream &in) {
int x_size = tex->do_get_expected_mipmap_x_size(cdata, n);
int y_size = tex->do_get_expected_mipmap_y_size(cdata, n);
size_t size = tex->do_get_expected_ram_mipmap_page_size(cdata, n);
size_t row_bytes = x_size * cdata->_num_components * cdata->_component_width;
nassertr(row_bytes * y_size == size, PTA_uchar());
PTA_uchar image = PTA_uchar::empty_array(size);
for (int y = y_size - 1; y >= 0; --y) {
unsigned char *p = image.p() + y * row_bytes;
in.read((char *)p, row_bytes);
}
return image;
}
/**
* Called by read_dds for a DDS file whose format isn't one we've specifically
* optimized.

View File

@ -817,6 +817,8 @@ private:
int n, istream &in);
static PTA_uchar read_dds_level_abgr32(Texture *tex, CData *cdata, const DDSHeader &header,
int n, istream &in);
static PTA_uchar read_dds_level_raw(Texture *tex, CData *cdata, const DDSHeader &header,
int n, istream &in);
static PTA_uchar read_dds_level_generic_uncompressed(Texture *tex, CData *cdata,
const DDSHeader &header,
int n, istream &in);