Path: blob/master/modules/dds/texture_loader_dds.cpp
10277 views
/**************************************************************************/1/* texture_loader_dds.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "texture_loader_dds.h"3132#include "dds_enums.h"3334#include "core/io/file_access.h"35#include "core/io/file_access_memory.h"36#include "scene/resources/image_texture.h"3738DDSFormat _dxgi_to_dds_format(uint32_t p_dxgi_format) {39switch (p_dxgi_format) {40case DXGI_R32G32B32A32_FLOAT: {41return DDS_RGBA32F;42}43case DXGI_R32G32B32_FLOAT: {44return DDS_RGB32F;45}46case DXGI_R16G16B16A16_FLOAT: {47return DDS_RGBA16F;48}49case DXGI_R32G32_FLOAT: {50return DDS_RG32F;51}52case DXGI_R10G10B10A2_UNORM: {53return DDS_RGB10A2;54}55case DXGI_R8G8B8A8_UNORM:56case DXGI_R8G8B8A8_UNORM_SRGB: {57return DDS_RGBA8;58}59case DXGI_R16G16_FLOAT: {60return DDS_RG16F;61}62case DXGI_R32_FLOAT: {63return DDS_R32F;64}65case DXGI_R8_UNORM:66case DXGI_A8_UNORM: {67return DDS_LUMINANCE;68}69case DXGI_R16_FLOAT: {70return DDS_R16F;71}72case DXGI_R8G8_UNORM: {73return DDS_LUMINANCE_ALPHA;74}75case DXGI_R9G9B9E5: {76return DDS_RGB9E5;77}78case DXGI_BC1_UNORM:79case DXGI_BC1_UNORM_SRGB: {80return DDS_DXT1;81}82case DXGI_BC2_UNORM:83case DXGI_BC2_UNORM_SRGB: {84return DDS_DXT3;85}86case DXGI_BC3_UNORM:87case DXGI_BC3_UNORM_SRGB: {88return DDS_DXT5;89}90case DXGI_BC4_UNORM: {91return DDS_ATI1;92}93case DXGI_BC5_UNORM: {94return DDS_ATI2;95}96case DXGI_B5G6R5_UNORM: {97return DDS_BGR565;98}99case DXGI_B5G5R5A1_UNORM: {100return DDS_BGR5A1;101}102case DXGI_B8G8R8A8_UNORM: {103return DDS_BGRA8;104}105case DXGI_BC6H_UF16: {106return DDS_BC6U;107}108case DXGI_BC6H_SF16: {109return DDS_BC6S;110}111case DXGI_BC7_UNORM:112case DXGI_BC7_UNORM_SRGB: {113return DDS_BC7;114}115case DXGI_B4G4R4A4_UNORM: {116return DDS_BGRA4;117}118119default: {120return DDS_MAX;121}122}123}124125static Ref<Image> _dds_load_layer(Ref<FileAccess> p_file, DDSFormat p_dds_format, uint32_t p_width, uint32_t p_height, uint32_t p_mipmaps, uint32_t p_pitch, uint32_t p_flags, Vector<uint8_t> &r_src_data) {126const DDSFormatInfo &info = dds_format_info[p_dds_format];127128uint32_t w = p_width;129uint32_t h = p_height;130131if (info.compressed) {132// BC compressed.133w += w % info.divisor;134h += h % info.divisor;135if (w != p_width) {136WARN_PRINT(vformat("%s: DDS width '%d' is not divisible by %d. This is not allowed as per the DDS specification, attempting to load anyway.", p_file->get_path(), p_width, info.divisor));137}138if (h != p_height) {139WARN_PRINT(vformat("%s: DDS height '%d' is not divisible by %d. This is not allowed as per the DDS specification, attempting to load anyway.", p_file->get_path(), p_height, info.divisor));140}141142uint32_t size = MAX(1u, (w + 3) / 4) * MAX(1u, (h + 3) / 4) * info.block_size;143144if (p_flags & DDSD_LINEARSIZE) {145ERR_FAIL_COND_V_MSG(size != p_pitch, Ref<Resource>(), "DDS header flags specify that a linear size of the top-level image is present, but the specified size does not match the expected value.");146} else {147ERR_FAIL_COND_V_MSG(p_pitch != 0, Ref<Resource>(), "DDS header flags specify that no linear size will given for the top-level image, but a non-zero linear size value is present in the header.");148}149150for (uint32_t i = 1; i < p_mipmaps; i++) {151w = MAX(1u, w >> 1);152h = MAX(1u, h >> 1);153154uint32_t bsize = MAX(1u, (w + 3) / 4) * MAX(1u, (h + 3) / 4) * info.block_size;155size += bsize;156}157158r_src_data.resize(size);159uint8_t *wb = r_src_data.ptrw();160p_file->get_buffer(wb, size);161162} else {163// Generic uncompressed.164uint32_t size = p_width * p_height * info.block_size;165166for (uint32_t i = 1; i < p_mipmaps; i++) {167w = MAX(1u, w >> 1);168h = MAX(1u, h >> 1);169size += w * h * info.block_size;170}171172// Calculate the space these formats will take up after decoding.173switch (p_dds_format) {174case DDS_BGR5A1:175case DDS_B2GR3A8:176case DDS_LUMINANCE_ALPHA_4:177size = size * 2;178break;179180case DDS_B2GR3:181size = size * 3;182break;183184default:185break;186}187188r_src_data.resize(size);189uint8_t *wb = r_src_data.ptrw();190p_file->get_buffer(wb, size);191192switch (p_dds_format) {193case DDS_BGR5A1: {194// To RGBA8.195int colcount = size / 4;196197for (int i = colcount - 1; i >= 0; i--) {198int src_ofs = i * 2;199int dst_ofs = i * 4;200201uint8_t a = wb[src_ofs + 1] & 0x80;202uint8_t b = wb[src_ofs] & 0x1F;203uint8_t g = (wb[src_ofs] >> 5) | ((wb[src_ofs + 1] & 0x3) << 3);204uint8_t r = (wb[src_ofs + 1] >> 2) & 0x1F;205206wb[dst_ofs + 0] = r << 3;207wb[dst_ofs + 1] = g << 3;208wb[dst_ofs + 2] = b << 3;209wb[dst_ofs + 3] = a ? 255 : 0;210}211212} break;213case DDS_BGRA4: {214// To RGBA4.215for (uint32_t i = 0; i < size; i += 2) {216uint8_t ar = wb[i + 0];217uint8_t gb = wb[i + 1];218219wb[i + 0] = ((ar & 0x0F) << 4) | ((gb & 0xF0) >> 4);220wb[i + 1] = ((ar & 0xF0) >> 4) | ((gb & 0x0F) << 4);221}222223} break;224case DDS_B2GR3: {225// To RGB8.226int colcount = size / 3;227228for (int i = colcount - 1; i >= 0; i--) {229int src_ofs = i;230int dst_ofs = i * 3;231232uint8_t b = (wb[src_ofs] & 0x3) << 6;233uint8_t g = (wb[src_ofs] & 0x1C) << 3;234uint8_t r = (wb[src_ofs] & 0xE0);235236wb[dst_ofs] = r;237wb[dst_ofs + 1] = g;238wb[dst_ofs + 2] = b;239}240241} break;242case DDS_B2GR3A8: {243// To RGBA8.244int colcount = size / 4;245246for (int i = colcount - 1; i >= 0; i--) {247int src_ofs = i * 2;248int dst_ofs = i * 4;249250uint8_t b = (wb[src_ofs] & 0x3) << 6;251uint8_t g = (wb[src_ofs] & 0x1C) << 3;252uint8_t r = (wb[src_ofs] & 0xE0);253uint8_t a = wb[src_ofs + 1];254255wb[dst_ofs] = r;256wb[dst_ofs + 1] = g;257wb[dst_ofs + 2] = b;258wb[dst_ofs + 3] = a;259}260261} break;262case DDS_RGB10A2: {263// To RGBA8.264int colcount = size / 4;265266for (int i = 0; i < colcount; i++) {267int ofs = i * 4;268269uint32_t w32 = uint32_t(wb[ofs + 0]) | (uint32_t(wb[ofs + 1]) << 8) | (uint32_t(wb[ofs + 2]) << 16) | (uint32_t(wb[ofs + 3]) << 24);270271// This method follows the 'standard' way of decoding 10-bit dds files,272// which means the ones created with DirectXTex will be loaded incorrectly.273uint8_t a = (w32 & 0xc0000000) >> 24;274uint8_t r = (w32 & 0x3ff) >> 2;275uint8_t g = (w32 & 0xffc00) >> 12;276uint8_t b = (w32 & 0x3ff00000) >> 22;277278wb[ofs + 0] = r;279wb[ofs + 1] = g;280wb[ofs + 2] = b;281wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque.282}283284} break;285case DDS_BGR10A2: {286// To RGBA8.287int colcount = size / 4;288289for (int i = 0; i < colcount; i++) {290int ofs = i * 4;291292uint32_t w32 = uint32_t(wb[ofs + 0]) | (uint32_t(wb[ofs + 1]) << 8) | (uint32_t(wb[ofs + 2]) << 16) | (uint32_t(wb[ofs + 3]) << 24);293294// This method follows the 'standard' way of decoding 10-bit dds files,295// which means the ones created with DirectXTex will be loaded incorrectly.296uint8_t a = (w32 & 0xc0000000) >> 24;297uint8_t r = (w32 & 0x3ff00000) >> 22;298uint8_t g = (w32 & 0xffc00) >> 12;299uint8_t b = (w32 & 0x3ff) >> 2;300301wb[ofs + 0] = r;302wb[ofs + 1] = g;303wb[ofs + 2] = b;304wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque.305}306307} break;308309// Channel-swapped.310case DDS_BGRA8: {311// To RGBA8.312int colcount = size / 4;313314for (int i = 0; i < colcount; i++) {315SWAP(wb[i * 4 + 0], wb[i * 4 + 2]);316}317318} break;319case DDS_BGR8: {320// To RGB8.321int colcount = size / 3;322323for (int i = 0; i < colcount; i++) {324SWAP(wb[i * 3 + 0], wb[i * 3 + 2]);325}326327} break;328329case DDS_RGBX8: {330// To RGB8.331int colcount = size / 4;332333for (int i = 0; i < colcount; i++) {334int src_ofs = i * 4;335int dst_ofs = i * 3;336337wb[dst_ofs + 0] = wb[src_ofs + 0];338wb[dst_ofs + 1] = wb[src_ofs + 1];339wb[dst_ofs + 2] = wb[src_ofs + 2];340}341342r_src_data.resize(size * 3 / 4);343344} break;345case DDS_BGRX8: {346// To RGB8.347int colcount = size / 4;348349for (int i = 0; i < colcount; i++) {350int src_ofs = i * 4;351int dst_ofs = i * 3;352353wb[dst_ofs + 0] = wb[src_ofs + 2];354wb[dst_ofs + 1] = wb[src_ofs + 1];355wb[dst_ofs + 2] = wb[src_ofs + 0];356}357358r_src_data.resize(size * 3 / 4);359360} break;361362// Grayscale.363case DDS_LUMINANCE_ALPHA_4: {364// To LA8.365int colcount = size / 2;366367for (int i = colcount - 1; i >= 0; i--) {368int src_ofs = i;369int dst_ofs = i * 2;370371uint8_t l = wb[src_ofs] & 0x0F;372uint8_t a = wb[src_ofs] & 0xF0;373374wb[dst_ofs] = (l << 4) | l;375wb[dst_ofs + 1] = a | (a >> 4);376}377378} break;379380default: {381}382}383}384385return memnew(Image(p_width, p_height, p_mipmaps > 1, info.format, r_src_data));386}387388static Vector<Ref<Image>> _dds_load_images(Ref<FileAccess> p_f, DDSFormat p_dds_format, uint32_t p_width, uint32_t p_height, uint32_t p_mipmaps, uint32_t p_pitch, uint32_t p_flags, uint32_t p_layer_count) {389Vector<uint8_t> src_data;390Vector<Ref<Image>> images;391images.resize(p_layer_count);392393for (uint32_t i = 0; i < p_layer_count; i++) {394images.write[i] = _dds_load_layer(p_f, p_dds_format, p_width, p_height, p_mipmaps, p_pitch, p_flags, src_data);395ERR_FAIL_COND_V(images.write[i].is_null(), Vector<Ref<Image>>());396}397398return images;399}400401static Ref<Resource> _dds_create_texture(const Vector<Ref<Image>> &p_images, uint32_t p_dds_type, uint32_t p_width, uint32_t p_height, uint32_t p_layer_count, uint32_t p_mipmaps, Error *r_error) {402ERR_FAIL_COND_V(p_images.is_empty(), Ref<Resource>());403404if ((p_dds_type & DDST_TYPE_MASK) == DDST_2D) {405if (p_dds_type & DDST_ARRAY) {406Ref<Texture2DArray> texture;407texture.instantiate();408texture->create_from_images(p_images);409410if (r_error) {411*r_error = OK;412}413414return texture;415416} else {417if (r_error) {418*r_error = OK;419}420421return ImageTexture::create_from_image(p_images[0]);422}423424} else if ((p_dds_type & DDST_TYPE_MASK) == DDST_CUBEMAP) {425ERR_FAIL_COND_V(p_layer_count % 6 != 0, Ref<Resource>());426427if (p_dds_type & DDST_ARRAY) {428Ref<CubemapArray> texture;429texture.instantiate();430texture->create_from_images(p_images);431432if (r_error) {433*r_error = OK;434}435436return texture;437438} else {439Ref<Cubemap> texture;440texture.instantiate();441texture->create_from_images(p_images);442443if (r_error) {444*r_error = OK;445}446447return texture;448}449450} else if ((p_dds_type & DDST_TYPE_MASK) == DDST_3D) {451Ref<ImageTexture3D> texture;452texture.instantiate();453texture->create(p_images[0]->get_format(), p_width, p_height, p_layer_count, p_mipmaps > 1, p_images);454455if (r_error) {456*r_error = OK;457}458459return texture;460}461462return Ref<Resource>();463}464465static Ref<Resource> _dds_create_texture_from_images(const Vector<Ref<Image>> &p_images, DDSFormat p_dds_format, uint32_t p_width, uint32_t p_height, uint32_t p_mipmaps, uint32_t p_pitch, uint32_t p_flags, uint32_t p_layer_count, uint32_t p_dds_type, Error *r_error) {466return _dds_create_texture(p_images, p_dds_type, p_width, p_height, p_layer_count, p_mipmaps, r_error);467}468469static Vector<Ref<Image>> _dds_load_images_from_buffer(Ref<FileAccess> p_f, DDSFormat &r_dds_format, uint32_t &r_width, uint32_t &r_height, uint32_t &r_mipmaps, uint32_t &r_pitch, uint32_t &r_flags, uint32_t &r_layer_count, uint32_t &r_dds_type, const String &p_path = "") {470ERR_FAIL_COND_V_MSG(p_f.is_null(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));471ERR_FAIL_COND_V_MSG(!p_f->get_length(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));472473uint32_t magic = p_f->get_32();474uint32_t hsize = p_f->get_32();475r_flags = p_f->get_32();476r_height = p_f->get_32();477r_width = p_f->get_32();478r_pitch = p_f->get_32();479uint32_t depth = p_f->get_32();480r_mipmaps = p_f->get_32();481482// Skip reserved.483for (int i = 0; i < 11; i++) {484p_f->get_32();485}486487// Validate.488// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,489// but non-mandatory when reading (as some writers don't set them).490if (magic != DDS_MAGIC || hsize != 124) {491ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Invalid or unsupported DDS texture file '%s'.", p_path));492}493494/* uint32_t format_size = */ p_f->get_32();495uint32_t format_flags = p_f->get_32();496uint32_t format_fourcc = p_f->get_32();497uint32_t format_rgb_bits = p_f->get_32();498uint32_t format_red_mask = p_f->get_32();499uint32_t format_green_mask = p_f->get_32();500uint32_t format_blue_mask = p_f->get_32();501uint32_t format_alpha_mask = p_f->get_32();502503/* uint32_t caps_1 = */ p_f->get_32();504uint32_t caps_2 = p_f->get_32();505/* uint32_t caps_3 = */ p_f->get_32();506/* uint32_t caps_4 = */ p_f->get_32();507508// Skip reserved.509p_f->get_32();510511if (p_f->get_position() < 128) {512p_f->seek(128);513}514515r_layer_count = 1;516r_dds_type = DDST_2D;517518if (caps_2 & DDSC2_CUBEMAP) {519r_dds_type = DDST_CUBEMAP;520r_layer_count *= 6;521522} else if (caps_2 & DDSC2_VOLUME) {523r_dds_type = DDST_3D;524r_layer_count = depth;525}526527r_dds_format = DDS_MAX;528529if (format_flags & DDPF_FOURCC) {530// FourCC formats.531switch (format_fourcc) {532case DDFCC_DXT1: {533r_dds_format = DDS_DXT1;534} break;535case DDFCC_DXT2:536case DDFCC_DXT3: {537r_dds_format = DDS_DXT3;538} break;539case DDFCC_DXT4:540case DDFCC_DXT5: {541r_dds_format = DDS_DXT5;542} break;543case DDFCC_ATI1:544case DDFCC_BC4U: {545r_dds_format = DDS_ATI1;546} break;547case DDFCC_ATI2:548case DDFCC_BC5U:549case DDFCC_A2XY: {550r_dds_format = DDS_ATI2;551} break;552case DDFCC_R16F: {553r_dds_format = DDS_R16F;554} break;555case DDFCC_RG16F: {556r_dds_format = DDS_RG16F;557} break;558case DDFCC_RGBA16F: {559r_dds_format = DDS_RGBA16F;560} break;561case DDFCC_R32F: {562r_dds_format = DDS_R32F;563} break;564case DDFCC_RG32F: {565r_dds_format = DDS_RG32F;566} break;567case DDFCC_RGBA32F: {568r_dds_format = DDS_RGBA32F;569} break;570case DDFCC_DX10: {571uint32_t dxgi_format = p_f->get_32();572uint32_t dimension = p_f->get_32();573/* uint32_t misc_flags_1 = */ p_f->get_32();574uint32_t array_size = p_f->get_32();575/* uint32_t misc_flags_2 = */ p_f->get_32();576577if (dimension == DX10D_3D) {578r_dds_type = DDST_3D;579r_layer_count = depth;580}581582if (array_size > 1) {583r_layer_count *= array_size;584r_dds_type |= DDST_ARRAY;585}586587r_dds_format = _dxgi_to_dds_format(dxgi_format);588} break;589590default: {591ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported FourCC in DDS '%s'.", p_path));592}593}594595} else if (format_flags & DDPF_RGB) {596// Channel-bitmasked formats.597if (format_flags & DDPF_ALPHAPIXELS) {598// With alpha.599if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) {600r_dds_format = DDS_BGRA8;601} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) {602r_dds_format = DDS_RGBA8;603} else if (format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) {604r_dds_format = DDS_BGR5A1;605} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) {606r_dds_format = DDS_BGR10A2;607} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) {608r_dds_format = DDS_RGB10A2;609} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {610r_dds_format = DDS_BGRA4;611} else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) {612r_dds_format = DDS_B2GR3A8;613}614615} else {616// Without alpha.617if (format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {618r_dds_format = DDS_BGR8;619} else if (format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {620r_dds_format = DDS_RGB8;621} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {622r_dds_format = DDS_BGR565;623} else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) {624r_dds_format = DDS_B2GR3;625} else if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {626r_dds_format = DDS_BGRX8;627} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {628r_dds_format = DDS_RGBX8;629}630}631632} else {633// Other formats.634if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {635// Alpha only.636r_dds_format = DDS_LUMINANCE;637}638}639640// Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined,641// so we check for these formats after everything else failed.642if (r_dds_format == DDS_MAX) {643if (format_flags & DDPF_ALPHAPIXELS) {644// With alpha.645if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {646r_dds_format = DDS_LUMINANCE_ALPHA;647} else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) {648r_dds_format = DDS_LUMINANCE_ALPHA_4;649}650651} else {652// Without alpha.653if (format_rgb_bits == 8 && format_red_mask == 0xff) {654r_dds_format = DDS_LUMINANCE;655}656}657}658659// No format detected, error.660if (r_dds_format == DDS_MAX) {661ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported color layout in DDS '%s'.", p_path));662}663664if (!(r_flags & DDSD_MIPMAPCOUNT)) {665r_mipmaps = 1;666}667668return _dds_load_images(p_f, r_dds_format, r_width, r_height, r_mipmaps, r_pitch, r_flags, r_layer_count);669}670671static Ref<Resource> _dds_load_from_buffer(Ref<FileAccess> p_f, Error *r_error, const String &p_path = "") {672if (r_error) {673*r_error = ERR_FILE_CORRUPT;674}675676DDSFormat dds_format;677uint32_t width = 0, height = 0, mipmaps = 0, pitch = 0, flags = 0, layer_count = 0, dds_type = 0;678679Vector<Ref<Image>> images = _dds_load_images_from_buffer(p_f, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, p_path);680return _dds_create_texture_from_images(images, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, r_error);681}682683static Ref<Resource> _dds_load_from_file(const String &p_path, Error *r_error) {684if (r_error) {685*r_error = ERR_CANT_OPEN;686}687688Error err;689Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);690if (f.is_null()) {691return Ref<Resource>();692}693694return _dds_load_from_buffer(f, r_error, p_path);695}696697Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {698return _dds_load_from_file(p_path, r_error);699}700701void ResourceFormatDDS::get_recognized_extensions(List<String> *p_extensions) const {702p_extensions->push_back("dds");703}704705bool ResourceFormatDDS::handles_type(const String &p_type) const {706return ClassDB::is_parent_class(p_type, "Texture");707}708709String ResourceFormatDDS::get_resource_type(const String &p_path) const {710if (p_path.get_extension().to_lower() == "dds") {711return "Texture";712}713return "";714}715716Ref<Image> load_mem_dds(const uint8_t *p_dds, int p_size) {717ERR_FAIL_NULL_V(p_dds, Ref<Image>());718ERR_FAIL_COND_V(!p_size, Ref<Image>());719Ref<FileAccessMemory> memfile;720memfile.instantiate();721Error open_memfile_error = memfile->open_custom(p_dds, p_size);722ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for DDS image buffer.");723724DDSFormat dds_format;725uint32_t width, height, mipmaps, pitch, flags, layer_count, dds_type;726727Vector<Ref<Image>> images = _dds_load_images_from_buffer(memfile, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type);728ERR_FAIL_COND_V_MSG(images.is_empty(), Ref<Image>(), "Failed to load DDS image.");729730return images[0];731}732733ResourceFormatDDS::ResourceFormatDDS() {734Image::_dds_mem_loader_func = load_mem_dds;735}736737738