Path: blob/master/modules/dds/texture_loader_dds.cpp
11352 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_R16G16B16A16_UNORM: {50return DDS_RGBA16;51}52case DXGI_R16G16B16A16_UINT: {53return DDS_RGBA16I;54}55case DXGI_R32G32_FLOAT: {56return DDS_RG32F;57}58case DXGI_R10G10B10A2_UNORM: {59return DDS_RGB10A2;60}61case DXGI_R8G8B8A8_UNORM:62case DXGI_R8G8B8A8_UNORM_SRGB: {63return DDS_RGBA8;64}65case DXGI_R16G16_FLOAT: {66return DDS_RG16F;67}68case DXGI_R16G16_UNORM: {69return DDS_RG16;70}71case DXGI_R16G16_UINT: {72return DDS_RG16I;73}74case DXGI_R32_FLOAT: {75return DDS_R32F;76}77case DXGI_R8_UNORM:78case DXGI_A8_UNORM: {79return DDS_LUMINANCE;80}81case DXGI_R16_FLOAT: {82return DDS_R16F;83}84case DXGI_R16_UNORM: {85return DDS_R16;86}87case DXGI_R16_UINT: {88return DDS_R16I;89}90case DXGI_R8G8_UNORM: {91return DDS_LUMINANCE_ALPHA;92}93case DXGI_R9G9B9E5: {94return DDS_RGB9E5;95}96case DXGI_BC1_UNORM:97case DXGI_BC1_UNORM_SRGB: {98return DDS_DXT1;99}100case DXGI_BC2_UNORM:101case DXGI_BC2_UNORM_SRGB: {102return DDS_DXT3;103}104case DXGI_BC3_UNORM:105case DXGI_BC3_UNORM_SRGB: {106return DDS_DXT5;107}108case DXGI_BC4_UNORM: {109return DDS_ATI1;110}111case DXGI_BC5_UNORM: {112return DDS_ATI2;113}114case DXGI_B5G6R5_UNORM: {115return DDS_BGR565;116}117case DXGI_B5G5R5A1_UNORM: {118return DDS_BGR5A1;119}120case DXGI_B8G8R8A8_UNORM: {121return DDS_BGRA8;122}123case DXGI_BC6H_UF16: {124return DDS_BC6U;125}126case DXGI_BC6H_SF16: {127return DDS_BC6S;128}129case DXGI_BC7_UNORM:130case DXGI_BC7_UNORM_SRGB: {131return DDS_BC7;132}133case DXGI_B4G4R4A4_UNORM: {134return DDS_BGRA4;135}136137default: {138return DDS_MAX;139}140}141}142143static 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) {144const DDSFormatInfo &info = dds_format_info[p_dds_format];145146uint32_t w = p_width;147uint32_t h = p_height;148149if (info.compressed) {150// BC compressed.151w += w % info.divisor;152h += h % info.divisor;153if (w != p_width) {154WARN_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));155}156if (h != p_height) {157WARN_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));158}159160uint32_t size = MAX(1u, (w + 3) / 4) * MAX(1u, (h + 3) / 4) * info.block_size;161162if (p_flags & DDSD_LINEARSIZE) {163ERR_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.");164} else {165ERR_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.");166}167168for (uint32_t i = 1; i < p_mipmaps; i++) {169w = MAX(1u, w >> 1);170h = MAX(1u, h >> 1);171172uint32_t bsize = MAX(1u, (w + 3) / 4) * MAX(1u, (h + 3) / 4) * info.block_size;173size += bsize;174}175176r_src_data.resize(size);177uint8_t *wb = r_src_data.ptrw();178p_file->get_buffer(wb, size);179180} else {181// Generic uncompressed.182uint32_t size = p_width * p_height * info.block_size;183184for (uint32_t i = 1; i < p_mipmaps; i++) {185w = MAX(1u, w >> 1);186h = MAX(1u, h >> 1);187size += w * h * info.block_size;188}189190// Calculate the space these formats will take up after decoding.191switch (p_dds_format) {192case DDS_BGR5A1:193case DDS_B2GR3A8:194case DDS_LUMINANCE_ALPHA_4:195size = size * 2;196break;197198case DDS_B2GR3:199size = size * 3;200break;201202default:203break;204}205206r_src_data.resize(size);207uint8_t *wb = r_src_data.ptrw();208p_file->get_buffer(wb, size);209210switch (p_dds_format) {211case DDS_BGR5A1: {212// To RGBA8.213int colcount = size / 4;214215for (int i = colcount - 1; i >= 0; i--) {216int src_ofs = i * 2;217int dst_ofs = i * 4;218219uint8_t a = wb[src_ofs + 1] & 0x80;220uint8_t b = wb[src_ofs] & 0x1F;221uint8_t g = (wb[src_ofs] >> 5) | ((wb[src_ofs + 1] & 0x3) << 3);222uint8_t r = (wb[src_ofs + 1] >> 2) & 0x1F;223224wb[dst_ofs + 0] = r << 3;225wb[dst_ofs + 1] = g << 3;226wb[dst_ofs + 2] = b << 3;227wb[dst_ofs + 3] = a ? 255 : 0;228}229230} break;231case DDS_BGRA4: {232// To RGBA4.233for (uint32_t i = 0; i < size; i += 2) {234uint8_t ar = wb[i + 0];235uint8_t gb = wb[i + 1];236237wb[i + 0] = ((ar & 0x0F) << 4) | ((gb & 0xF0) >> 4);238wb[i + 1] = ((ar & 0xF0) >> 4) | ((gb & 0x0F) << 4);239}240241} break;242case DDS_B2GR3: {243// To RGB8.244int colcount = size / 3;245246for (int i = colcount - 1; i >= 0; i--) {247int src_ofs = i;248int dst_ofs = i * 3;249250uint8_t b = (wb[src_ofs] & 0x3) << 6;251uint8_t g = (wb[src_ofs] & 0x1C) << 3;252uint8_t r = (wb[src_ofs] & 0xE0);253254wb[dst_ofs] = r;255wb[dst_ofs + 1] = g;256wb[dst_ofs + 2] = b;257}258259} break;260case DDS_B2GR3A8: {261// To RGBA8.262int colcount = size / 4;263264for (int i = colcount - 1; i >= 0; i--) {265int src_ofs = i * 2;266int dst_ofs = i * 4;267268uint8_t b = (wb[src_ofs] & 0x3) << 6;269uint8_t g = (wb[src_ofs] & 0x1C) << 3;270uint8_t r = (wb[src_ofs] & 0xE0);271uint8_t a = wb[src_ofs + 1];272273wb[dst_ofs] = r;274wb[dst_ofs + 1] = g;275wb[dst_ofs + 2] = b;276wb[dst_ofs + 3] = a;277}278279} break;280case DDS_RGB10A2: {281// To RGBA8.282int colcount = size / 4;283284for (int i = 0; i < colcount; i++) {285int ofs = i * 4;286287uint32_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);288289// This method follows the 'standard' way of decoding 10-bit dds files,290// which means the ones created with DirectXTex will be loaded incorrectly.291uint8_t a = (w32 & 0xc0000000) >> 24;292uint8_t r = (w32 & 0x3ff) >> 2;293uint8_t g = (w32 & 0xffc00) >> 12;294uint8_t b = (w32 & 0x3ff00000) >> 22;295296wb[ofs + 0] = r;297wb[ofs + 1] = g;298wb[ofs + 2] = b;299wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque.300}301302} break;303case DDS_BGR10A2: {304// To RGBA8.305int colcount = size / 4;306307for (int i = 0; i < colcount; i++) {308int ofs = i * 4;309310uint32_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);311312// This method follows the 'standard' way of decoding 10-bit dds files,313// which means the ones created with DirectXTex will be loaded incorrectly.314uint8_t a = (w32 & 0xc0000000) >> 24;315uint8_t r = (w32 & 0x3ff00000) >> 22;316uint8_t g = (w32 & 0xffc00) >> 12;317uint8_t b = (w32 & 0x3ff) >> 2;318319wb[ofs + 0] = r;320wb[ofs + 1] = g;321wb[ofs + 2] = b;322wb[ofs + 3] = a == 0xc0 ? 255 : a; // 0xc0 should be opaque.323}324325} break;326327// Channel-swapped.328case DDS_BGRA8: {329// To RGBA8.330int colcount = size / 4;331332for (int i = 0; i < colcount; i++) {333SWAP(wb[i * 4 + 0], wb[i * 4 + 2]);334}335336} break;337case DDS_BGR8: {338// To RGB8.339int colcount = size / 3;340341for (int i = 0; i < colcount; i++) {342SWAP(wb[i * 3 + 0], wb[i * 3 + 2]);343}344345} break;346347case DDS_RGBX8: {348// To RGB8.349int colcount = size / 4;350351for (int i = 0; i < colcount; i++) {352int src_ofs = i * 4;353int dst_ofs = i * 3;354355wb[dst_ofs + 0] = wb[src_ofs + 0];356wb[dst_ofs + 1] = wb[src_ofs + 1];357wb[dst_ofs + 2] = wb[src_ofs + 2];358}359360r_src_data.resize(size * 3 / 4);361362} break;363case DDS_BGRX8: {364// To RGB8.365int colcount = size / 4;366367for (int i = 0; i < colcount; i++) {368int src_ofs = i * 4;369int dst_ofs = i * 3;370371wb[dst_ofs + 0] = wb[src_ofs + 2];372wb[dst_ofs + 1] = wb[src_ofs + 1];373wb[dst_ofs + 2] = wb[src_ofs + 0];374}375376r_src_data.resize(size * 3 / 4);377378} break;379380// Grayscale.381case DDS_LUMINANCE_ALPHA_4: {382// To LA8.383int colcount = size / 2;384385for (int i = colcount - 1; i >= 0; i--) {386int src_ofs = i;387int dst_ofs = i * 2;388389uint8_t l = wb[src_ofs] & 0x0F;390uint8_t a = wb[src_ofs] & 0xF0;391392wb[dst_ofs] = (l << 4) | l;393wb[dst_ofs + 1] = a | (a >> 4);394}395396} break;397398default: {399}400}401}402403return memnew(Image(p_width, p_height, p_mipmaps > 1, info.format, r_src_data));404}405406static 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) {407Vector<uint8_t> src_data;408Vector<Ref<Image>> images;409images.resize(p_layer_count);410411for (uint32_t i = 0; i < p_layer_count; i++) {412images.write[i] = _dds_load_layer(p_f, p_dds_format, p_width, p_height, p_mipmaps, p_pitch, p_flags, src_data);413ERR_FAIL_COND_V(images.write[i].is_null(), Vector<Ref<Image>>());414}415416return images;417}418419static 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) {420ERR_FAIL_COND_V(p_images.is_empty(), Ref<Resource>());421422if ((p_dds_type & DDST_TYPE_MASK) == DDST_2D) {423if (p_dds_type & DDST_ARRAY) {424Ref<Texture2DArray> texture;425texture.instantiate();426texture->create_from_images(p_images);427428if (r_error) {429*r_error = OK;430}431432return texture;433434} else {435if (r_error) {436*r_error = OK;437}438439return ImageTexture::create_from_image(p_images[0]);440}441442} else if ((p_dds_type & DDST_TYPE_MASK) == DDST_CUBEMAP) {443ERR_FAIL_COND_V(p_layer_count % 6 != 0, Ref<Resource>());444445if (p_dds_type & DDST_ARRAY) {446Ref<CubemapArray> texture;447texture.instantiate();448texture->create_from_images(p_images);449450if (r_error) {451*r_error = OK;452}453454return texture;455456} else {457Ref<Cubemap> texture;458texture.instantiate();459texture->create_from_images(p_images);460461if (r_error) {462*r_error = OK;463}464465return texture;466}467468} else if ((p_dds_type & DDST_TYPE_MASK) == DDST_3D) {469Ref<ImageTexture3D> texture;470texture.instantiate();471texture->create(p_images[0]->get_format(), p_width, p_height, p_layer_count, p_mipmaps > 1, p_images);472473if (r_error) {474*r_error = OK;475}476477return texture;478}479480return Ref<Resource>();481}482483static 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) {484return _dds_create_texture(p_images, p_dds_type, p_width, p_height, p_layer_count, p_mipmaps, r_error);485}486487static 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 = "") {488ERR_FAIL_COND_V_MSG(p_f.is_null(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));489ERR_FAIL_COND_V_MSG(!p_f->get_length(), Vector<Ref<Image>>(), vformat("Empty DDS texture file."));490491uint32_t magic = p_f->get_32();492uint32_t hsize = p_f->get_32();493r_flags = p_f->get_32();494r_height = p_f->get_32();495r_width = p_f->get_32();496r_pitch = p_f->get_32();497uint32_t depth = p_f->get_32();498r_mipmaps = p_f->get_32();499500// Skip reserved.501for (int i = 0; i < 11; i++) {502p_f->get_32();503}504505// Validate.506// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,507// but non-mandatory when reading (as some writers don't set them).508if (magic != DDS_MAGIC || hsize != 124) {509ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Invalid or unsupported DDS texture file '%s'.", p_path));510}511512/* uint32_t format_size = */ p_f->get_32();513uint32_t format_flags = p_f->get_32();514uint32_t format_fourcc = p_f->get_32();515uint32_t format_rgb_bits = p_f->get_32();516uint32_t format_red_mask = p_f->get_32();517uint32_t format_green_mask = p_f->get_32();518uint32_t format_blue_mask = p_f->get_32();519uint32_t format_alpha_mask = p_f->get_32();520521/* uint32_t caps_1 = */ p_f->get_32();522uint32_t caps_2 = p_f->get_32();523/* uint32_t caps_3 = */ p_f->get_32();524/* uint32_t caps_4 = */ p_f->get_32();525526// Skip reserved.527p_f->get_32();528529if (p_f->get_position() < 128) {530p_f->seek(128);531}532533r_layer_count = 1;534r_dds_type = DDST_2D;535536if (caps_2 & DDSC2_CUBEMAP) {537r_dds_type = DDST_CUBEMAP;538r_layer_count *= 6;539540} else if (caps_2 & DDSC2_VOLUME) {541r_dds_type = DDST_3D;542r_layer_count = depth;543}544545r_dds_format = DDS_MAX;546547if (format_flags & DDPF_FOURCC) {548// FourCC formats.549switch (format_fourcc) {550case DDFCC_DXT1: {551r_dds_format = DDS_DXT1;552} break;553case DDFCC_DXT2:554case DDFCC_DXT3: {555r_dds_format = DDS_DXT3;556} break;557case DDFCC_DXT4:558case DDFCC_DXT5: {559r_dds_format = DDS_DXT5;560} break;561case DDFCC_ATI1:562case DDFCC_BC4U: {563r_dds_format = DDS_ATI1;564} break;565case DDFCC_ATI2:566case DDFCC_BC5U:567case DDFCC_A2XY: {568r_dds_format = DDS_ATI2;569} break;570case DDFCC_RGBA16: {571r_dds_format = DDS_RGBA16;572} break;573case DDFCC_R16F: {574r_dds_format = DDS_R16F;575} break;576case DDFCC_RG16F: {577r_dds_format = DDS_RG16F;578} break;579case DDFCC_RGBA16F: {580r_dds_format = DDS_RGBA16F;581} break;582case DDFCC_R32F: {583r_dds_format = DDS_R32F;584} break;585case DDFCC_RG32F: {586r_dds_format = DDS_RG32F;587} break;588case DDFCC_RGBA32F: {589r_dds_format = DDS_RGBA32F;590} break;591case DDFCC_DX10: {592uint32_t dxgi_format = p_f->get_32();593uint32_t dimension = p_f->get_32();594/* uint32_t misc_flags_1 = */ p_f->get_32();595uint32_t array_size = p_f->get_32();596/* uint32_t misc_flags_2 = */ p_f->get_32();597598if (dimension == DX10D_3D) {599r_dds_type = DDST_3D;600r_layer_count = depth;601}602603if (array_size > 1) {604r_layer_count *= array_size;605r_dds_type |= DDST_ARRAY;606}607608r_dds_format = _dxgi_to_dds_format(dxgi_format);609} break;610611default: {612ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported FourCC in DDS '%s'.", p_path));613}614}615616} else if (format_flags & DDPF_RGB) {617// Channel-bitmasked formats.618if (format_flags & DDPF_ALPHAPIXELS) {619// With alpha.620if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff && format_alpha_mask == 0xff000000) {621r_dds_format = DDS_BGRA8;622} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000 && format_alpha_mask == 0xff000000) {623r_dds_format = DDS_RGBA8;624} else if (format_rgb_bits == 16 && format_red_mask == 0x00007c00 && format_green_mask == 0x000003e0 && format_blue_mask == 0x0000001f && format_alpha_mask == 0x00008000) {625r_dds_format = DDS_BGR5A1;626} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff00000 && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff && format_alpha_mask == 0xc0000000) {627r_dds_format = DDS_BGR10A2;628} else if (format_rgb_bits == 32 && format_red_mask == 0x3ff && format_green_mask == 0xffc00 && format_blue_mask == 0x3ff00000 && format_alpha_mask == 0xc0000000) {629r_dds_format = DDS_RGB10A2;630} else if (format_rgb_bits == 16 && format_red_mask == 0xf00 && format_green_mask == 0xf0 && format_blue_mask == 0xf && format_alpha_mask == 0xf000) {631r_dds_format = DDS_BGRA4;632} else if (format_rgb_bits == 16 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3 && format_alpha_mask == 0xff00) {633r_dds_format = DDS_B2GR3A8;634}635636} else {637// Without alpha.638if (format_rgb_bits == 24 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {639r_dds_format = DDS_BGR8;640} else if (format_rgb_bits == 24 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {641r_dds_format = DDS_RGB8;642} else if (format_rgb_bits == 16 && format_red_mask == 0x0000f800 && format_green_mask == 0x000007e0 && format_blue_mask == 0x0000001f) {643r_dds_format = DDS_BGR565;644} else if (format_rgb_bits == 8 && format_red_mask == 0xe0 && format_green_mask == 0x1c && format_blue_mask == 0x3) {645r_dds_format = DDS_B2GR3;646} else if (format_rgb_bits == 32 && format_red_mask == 0xff0000 && format_green_mask == 0xff00 && format_blue_mask == 0xff) {647r_dds_format = DDS_BGRX8;648} else if (format_rgb_bits == 32 && format_red_mask == 0xff && format_green_mask == 0xff00 && format_blue_mask == 0xff0000) {649r_dds_format = DDS_RGBX8;650}651}652653if (format_rgb_bits == 32 && format_red_mask == 0xffff && format_green_mask == 0xffff0000) {654r_dds_format = DDS_RG16;655}656657} else {658// Other formats.659if (format_flags & DDPF_ALPHAONLY && format_rgb_bits == 8 && format_alpha_mask == 0xff) {660// Alpha only.661r_dds_format = DDS_LUMINANCE;662}663}664665// Depending on the writer, luminance formats may or may not have the DDPF_RGB or DDPF_LUMINANCE flags defined,666// so we check for these formats after everything else failed.667if (r_dds_format == DDS_MAX) {668if (format_flags & DDPF_ALPHAPIXELS) {669// With alpha.670if (format_rgb_bits == 16 && format_red_mask == 0xff && format_alpha_mask == 0xff00) {671r_dds_format = DDS_LUMINANCE_ALPHA;672} else if (format_rgb_bits == 8 && format_red_mask == 0xf && format_alpha_mask == 0xf0) {673r_dds_format = DDS_LUMINANCE_ALPHA_4;674}675676} else {677// Without alpha.678if (format_rgb_bits == 8 && format_red_mask == 0xff) {679r_dds_format = DDS_LUMINANCE;680} else if (format_rgb_bits == 16 && format_red_mask == 0xffff) {681r_dds_format = DDS_R16;682}683}684}685686// No format detected, error.687if (r_dds_format == DDS_MAX) {688ERR_FAIL_V_MSG(Vector<Ref<Image>>(), vformat("Unrecognized or unsupported color layout in DDS '%s'.", p_path));689}690691if (!(r_flags & DDSD_MIPMAPCOUNT)) {692r_mipmaps = 1;693}694695return _dds_load_images(p_f, r_dds_format, r_width, r_height, r_mipmaps, r_pitch, r_flags, r_layer_count);696}697698static Ref<Resource> _dds_load_from_buffer(Ref<FileAccess> p_f, Error *r_error, const String &p_path = "") {699if (r_error) {700*r_error = ERR_FILE_CORRUPT;701}702703DDSFormat dds_format;704uint32_t width = 0, height = 0, mipmaps = 0, pitch = 0, flags = 0, layer_count = 0, dds_type = 0;705706Vector<Ref<Image>> images = _dds_load_images_from_buffer(p_f, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, p_path);707return _dds_create_texture_from_images(images, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type, r_error);708}709710static Ref<Resource> _dds_load_from_file(const String &p_path, Error *r_error) {711if (r_error) {712*r_error = ERR_CANT_OPEN;713}714715Error err;716Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);717if (f.is_null()) {718return Ref<Resource>();719}720721return _dds_load_from_buffer(f, r_error, p_path);722}723724Ref<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) {725return _dds_load_from_file(p_path, r_error);726}727728void ResourceFormatDDS::get_recognized_extensions(List<String> *p_extensions) const {729p_extensions->push_back("dds");730}731732bool ResourceFormatDDS::handles_type(const String &p_type) const {733return ClassDB::is_parent_class(p_type, "Texture");734}735736String ResourceFormatDDS::get_resource_type(const String &p_path) const {737if (p_path.get_extension().to_lower() == "dds") {738return "Texture";739}740return "";741}742743Ref<Image> load_mem_dds(const uint8_t *p_dds, int p_size) {744ERR_FAIL_NULL_V(p_dds, Ref<Image>());745ERR_FAIL_COND_V(!p_size, Ref<Image>());746Ref<FileAccessMemory> memfile;747memfile.instantiate();748Error open_memfile_error = memfile->open_custom(p_dds, p_size);749ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for DDS image buffer.");750751DDSFormat dds_format;752uint32_t width, height, mipmaps, pitch, flags, layer_count, dds_type;753754Vector<Ref<Image>> images = _dds_load_images_from_buffer(memfile, dds_format, width, height, mipmaps, pitch, flags, layer_count, dds_type);755ERR_FAIL_COND_V_MSG(images.is_empty(), Ref<Image>(), "Failed to load DDS image.");756757return images[0];758}759760ResourceFormatDDS::ResourceFormatDDS() {761Image::_dds_mem_loader_func = load_mem_dds;762}763764765