From 23645cc407a04034bef457a9a3ab62dc62b94a94 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 13 Dec 2016 21:00:11 +0100 Subject: [PATCH] Fix DDS load crash with certain formats; support R16, RG16, R32, RG32 --- panda/src/gobj/texture.cxx | 98 ++++++++++++++++++++++++++++++++++++-- panda/src/gobj/texture.h | 2 + 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 76530db95b..115d9529bf 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -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. diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index cd05019416..e40ca6f8e5 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -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);