Path: blob/master/scene/resources/compressed_texture.cpp
20873 views
/**************************************************************************/1/* compressed_texture.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 "compressed_texture.h"3132#include "core/io/file_access.h"33#include "scene/resources/bit_map.h"3435Error CompressedTexture2D::_load_data(const String &p_path, int &r_width, int &r_height, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) {36alpha_cache.unref();3738ERR_FAIL_COND_V(image.is_null(), ERR_INVALID_PARAMETER);3940Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);41ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));4243uint8_t header[4];44f->get_buffer(header, 4);45if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != '2') {46ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is corrupt (Bad header).");47}4849uint32_t version = f->get_32();5051if (version > FORMAT_VERSION) {52ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");53}54r_width = f->get_32();55r_height = f->get_32();56uint32_t df = f->get_32(); //data format5758//skip reserved59mipmap_limit = int(f->get_32());60//reserved61f->get_32();62f->get_32();63f->get_32();6465#ifdef TOOLS_ENABLED6667r_request_3d = request_3d_callback && df & FORMAT_BIT_DETECT_3D;68r_request_roughness = request_roughness_callback && df & FORMAT_BIT_DETECT_ROUGNESS;69r_request_normal = request_normal_callback && df & FORMAT_BIT_DETECT_NORMAL;7071#else7273r_request_3d = false;74r_request_roughness = false;75r_request_normal = false;7677#endif78if (!(df & FORMAT_BIT_STREAM)) {79p_size_limit = 0;80}8182image = load_image_from_file(f, p_size_limit);8384if (image.is_null() || image->is_empty()) {85return ERR_CANT_OPEN;86}8788return OK;89}9091void CompressedTexture2D::set_path(const String &p_path, bool p_take_over) {92if (texture.is_valid()) {93RenderingServer::get_singleton()->texture_set_path(texture, p_path);94}9596Resource::set_path(p_path, p_take_over);97}9899void CompressedTexture2D::_requested_3d(void *p_ud) {100CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;101Ref<CompressedTexture2D> ctex(ct);102ERR_FAIL_NULL(request_3d_callback);103request_3d_callback(ctex);104}105106void CompressedTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) {107CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;108Ref<CompressedTexture2D> ctex(ct);109ERR_FAIL_NULL(request_roughness_callback);110request_roughness_callback(ctex, p_normal_path, p_roughness_channel);111}112113void CompressedTexture2D::_requested_normal(void *p_ud) {114CompressedTexture2D *ct = (CompressedTexture2D *)p_ud;115Ref<CompressedTexture2D> ctex(ct);116ERR_FAIL_NULL(request_normal_callback);117request_normal_callback(ctex);118}119120CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_3d_callback = nullptr;121CompressedTexture2D::TextureFormatRoughnessRequestCallback CompressedTexture2D::request_roughness_callback = nullptr;122CompressedTexture2D::TextureFormatRequestCallback CompressedTexture2D::request_normal_callback = nullptr;123124Image::Format CompressedTexture2D::get_format() const {125return format;126}127128Error CompressedTexture2D::load(const String &p_path) {129int lw, lh;130Ref<Image> image;131image.instantiate();132133bool request_3d;134bool request_normal;135bool request_roughness;136int mipmap_limit;137138Error err = _load_data(p_path, lw, lh, image, request_3d, request_normal, request_roughness, mipmap_limit);139if (err) {140return err;141}142143if (texture.is_valid()) {144RID new_texture = RS::get_singleton()->texture_2d_create(image);145RS::get_singleton()->texture_replace(texture, new_texture);146} else {147texture = RS::get_singleton()->texture_2d_create(image);148}149if (lw || lh) {150RS::get_singleton()->texture_set_size_override(texture, lw, lh);151}152153w = lw;154h = lh;155path_to_file = p_path;156format = image->get_format();157158if (get_path().is_empty()) {159//temporarily set path if no path set for resource, helps find errors160RenderingServer::get_singleton()->texture_set_path(texture, p_path);161}162163#ifdef TOOLS_ENABLED164165if (request_3d) {166//print_line("request detect 3D at " + p_path);167RS::get_singleton()->texture_set_detect_3d_callback(texture, _requested_3d, this);168} else {169//print_line("not requesting detect 3D at " + p_path);170RS::get_singleton()->texture_set_detect_3d_callback(texture, nullptr, nullptr);171}172173if (request_roughness) {174//print_line("request detect srgb at " + p_path);175RS::get_singleton()->texture_set_detect_roughness_callback(texture, _requested_roughness, this);176} else {177//print_line("not requesting detect srgb at " + p_path);178RS::get_singleton()->texture_set_detect_roughness_callback(texture, nullptr, nullptr);179}180181if (request_normal) {182//print_line("request detect srgb at " + p_path);183RS::get_singleton()->texture_set_detect_normal_callback(texture, _requested_normal, this);184} else {185//print_line("not requesting detect normal at " + p_path);186RS::get_singleton()->texture_set_detect_normal_callback(texture, nullptr, nullptr);187}188189#endif190notify_property_list_changed();191emit_changed();192return OK;193}194195String CompressedTexture2D::get_load_path() const {196return path_to_file;197}198199int CompressedTexture2D::get_width() const {200return w;201}202203int CompressedTexture2D::get_height() const {204return h;205}206207RID CompressedTexture2D::get_rid() const {208if (!texture.is_valid()) {209texture = RS::get_singleton()->texture_2d_placeholder_create();210}211return texture;212}213214void CompressedTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const {215if ((w | h) == 0) {216return;217}218RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose);219}220221void CompressedTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const {222if ((w | h) == 0) {223return;224}225RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose);226}227228void CompressedTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) const {229if ((w | h) == 0) {230return;231}232RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, p_clip_uv);233}234235bool CompressedTexture2D::has_alpha() const {236return false;237}238239Ref<Image> CompressedTexture2D::get_image() const {240if (texture.is_valid()) {241return RS::get_singleton()->texture_2d_get(texture);242} else {243return Ref<Image>();244}245}246247bool CompressedTexture2D::is_pixel_opaque(int p_x, int p_y) const {248if (alpha_cache.is_null()) {249Ref<Image> img = get_image();250if (img.is_valid()) {251if (img->is_compressed()) { //must decompress, if compressed252Ref<Image> decom = img->duplicate();253decom->decompress();254img = decom;255}256257alpha_cache.instantiate();258alpha_cache->create_from_image_alpha(img);259}260}261262if (alpha_cache.is_valid()) {263int aw = int(alpha_cache->get_size().width);264int ah = int(alpha_cache->get_size().height);265if (aw == 0 || ah == 0) {266return true;267}268269int x = p_x * aw / w;270int y = p_y * ah / h;271272x = CLAMP(x, 0, aw - 1);273y = CLAMP(y, 0, ah - 1);274275return alpha_cache->get_bit(x, y);276}277278return true;279}280281void CompressedTexture2D::reload_from_file() {282String path = get_path();283if (!path.is_resource_file()) {284return;285}286287path = ResourceLoader::path_remap(path); //remap for translation288path = ResourceLoader::import_remap(path); //remap for import289if (!path.is_resource_file()) {290return;291}292293load(path);294}295296Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_size_limit) {297uint32_t data_format = f->get_32();298uint32_t w = f->get_16();299uint32_t h = f->get_16();300uint32_t mipmaps = f->get_32();301Image::Format format = Image::Format(f->get_32());302303if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP) {304//look for a PNG or WebP file inside305306int sw = w;307int sh = h;308309//mipmaps need to be read independently, they will be later combined310Vector<Ref<Image>> mipmap_images;311uint64_t total_size = 0;312313for (uint32_t i = 0; i < mipmaps + 1; i++) {314uint32_t size = f->get_32();315316if (p_size_limit > 0 && i < (mipmaps - 1) && (sw > p_size_limit || sh > p_size_limit)) {317//can't load this due to size limit318sw = MAX(sw >> 1, 1);319sh = MAX(sh >> 1, 1);320f->seek(f->get_position() + size);321continue;322}323324Vector<uint8_t> pv;325pv.resize(size);326{327uint8_t *wr = pv.ptrw();328f->get_buffer(wr, size);329}330331Ref<Image> img;332if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) {333img = Image::png_unpacker(pv);334} else if (data_format == DATA_FORMAT_WEBP && Image::webp_unpacker) {335img = Image::webp_unpacker(pv);336}337338if (img.is_null() || img->is_empty()) {339ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());340}341// If the image is compressed and its format doesn't match the desired format, return an empty reference.342// This is done to avoid recompressing the image on load.343ERR_FAIL_COND_V(img->is_compressed() && format != img->get_format(), Ref<Image>());344345// The format will actually be the format of the header,346// as it may have changed on compression.347if (format != img->get_format()) {348// Convert the image to the desired format.349// Note: We are not decompressing the image here, just changing its format.350// It's important that all images in the texture array share the same format for correct rendering.351img->convert(format);352}353354total_size += img->get_data().size();355356mipmap_images.push_back(img);357358sw = MAX(sw >> 1, 1);359sh = MAX(sh >> 1, 1);360}361362//print_line("mipmap read total: " + itos(mipmap_images.size()));363364Ref<Image> image;365image.instantiate();366367if (mipmap_images.size() == 1) {368//only one image (which will most likely be the case anyway for this format)369image = mipmap_images[0];370return image;371372} else {373//rarer use case, but needs to be supported374Vector<uint8_t> img_data;375img_data.resize(total_size);376377{378uint8_t *wr = img_data.ptrw();379380int ofs = 0;381for (int i = 0; i < mipmap_images.size(); i++) {382Vector<uint8_t> id = mipmap_images[i]->get_data();383int len = id.size();384const uint8_t *r = id.ptr();385memcpy(&wr[ofs], r, len);386ofs += len;387}388}389390image->set_data(w, h, true, mipmap_images[0]->get_format(), img_data);391return image;392}393394} else if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) {395int sw = w;396int sh = h;397uint32_t size = f->get_32();398if (p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {399//can't load this due to size limit400sw = MAX(sw >> 1, 1);401sh = MAX(sh >> 1, 1);402f->seek(f->get_position() + size);403return Ref<Image>();404}405Vector<uint8_t> pv;406pv.resize(size);407{408uint8_t *wr = pv.ptrw();409f->get_buffer(wr, size);410}411Ref<Image> img;412img = Image::basis_universal_unpacker(pv);413if (img.is_null() || img->is_empty()) {414ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>());415}416format = img->get_format();417sw = MAX(sw >> 1, 1);418sh = MAX(sh >> 1, 1);419return img;420} else if (data_format == DATA_FORMAT_IMAGE) {421int size = Image::get_image_data_size(w, h, format, mipmaps ? true : false);422423for (uint32_t i = 0; i < mipmaps + 1; i++) {424int tw, th;425int ofs = Image::get_image_mipmap_offset_and_dimensions(w, h, format, i, tw, th);426427if (p_size_limit > 0 && i < mipmaps && (p_size_limit > tw || p_size_limit > th)) {428if (ofs) {429f->seek(f->get_position() + ofs);430}431continue; //oops, size limit enforced, go to next432}433434Vector<uint8_t> data;435data.resize(size - ofs);436437{438uint8_t *wr = data.ptrw();439f->get_buffer(wr, data.size());440}441442Ref<Image> image = Image::create_from_data(tw, th, mipmaps - i ? true : false, format, data);443444return image;445}446}447448return Ref<Image>();449}450451void CompressedTexture2D::_bind_methods() {452ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture2D::load);453ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture2D::get_load_path);454455ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");456}457458CompressedTexture2D::~CompressedTexture2D() {459if (texture.is_valid()) {460ERR_FAIL_NULL(RenderingServer::get_singleton());461RS::get_singleton()->free_rid(texture);462}463}464465Ref<Resource> ResourceFormatLoaderCompressedTexture2D::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) {466Ref<CompressedTexture2D> st;467st.instantiate();468Error err = st->load(p_path);469if (r_error) {470*r_error = err;471}472if (err != OK) {473return Ref<Resource>();474}475476return st;477}478479void ResourceFormatLoaderCompressedTexture2D::get_recognized_extensions(List<String> *p_extensions) const {480p_extensions->push_back("ctex");481}482483bool ResourceFormatLoaderCompressedTexture2D::handles_type(const String &p_type) const {484return p_type == "CompressedTexture2D";485}486487String ResourceFormatLoaderCompressedTexture2D::get_resource_type(const String &p_path) const {488if (p_path.has_extension("ctex")) {489return "CompressedTexture2D";490}491return "";492}493494void CompressedTexture3D::set_path(const String &p_path, bool p_take_over) {495if (texture.is_valid()) {496RenderingServer::get_singleton()->texture_set_path(texture, p_path);497}498499Resource::set_path(p_path, p_take_over);500}501502Image::Format CompressedTexture3D::get_format() const {503return format;504}505506Error CompressedTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, bool &r_mipmaps) {507Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);508ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));509510uint8_t header[4];511f->get_buffer(header, 4);512ERR_FAIL_COND_V(header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L', ERR_FILE_UNRECOGNIZED);513514//stored as compressed textures (used for lossless and lossy compression)515uint32_t version = f->get_32();516517if (version > FORMAT_VERSION) {518ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");519}520521r_depth = f->get_32(); //depth522f->get_32(); //ignored (mode)523f->get_32(); // ignored (data format)524525f->get_32(); //ignored526int mipmap_count = f->get_32();527f->get_32(); //ignored528f->get_32(); //ignored529530r_mipmaps = mipmap_count != 0;531532r_data.clear();533534for (int i = 0; i < (r_depth + mipmap_count); i++) {535Ref<Image> image = CompressedTexture2D::load_image_from_file(f, 0);536ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);537if (i == 0) {538r_format = image->get_format();539r_width = image->get_width();540r_height = image->get_height();541}542r_data.push_back(image);543}544545return OK;546}547548Error CompressedTexture3D::load(const String &p_path) {549Vector<Ref<Image>> data;550551int tw, th, td;552Image::Format tfmt;553bool tmm;554555Error err = _load_data(p_path, data, tfmt, tw, th, td, tmm);556if (err) {557return err;558}559560if (texture.is_valid()) {561RID new_texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);562RS::get_singleton()->texture_replace(texture, new_texture);563} else {564texture = RS::get_singleton()->texture_3d_create(tfmt, tw, th, td, tmm, data);565}566567w = tw;568h = th;569d = td;570mipmaps = tmm;571format = tfmt;572573path_to_file = p_path;574575if (get_path().is_empty()) {576//temporarily set path if no path set for resource, helps find errors577RenderingServer::get_singleton()->texture_set_path(texture, p_path);578}579580notify_property_list_changed();581emit_changed();582return OK;583}584585String CompressedTexture3D::get_load_path() const {586return path_to_file;587}588589int CompressedTexture3D::get_width() const {590return w;591}592593int CompressedTexture3D::get_height() const {594return h;595}596597int CompressedTexture3D::get_depth() const {598return d;599}600601bool CompressedTexture3D::has_mipmaps() const {602return mipmaps;603}604605RID CompressedTexture3D::get_rid() const {606if (!texture.is_valid()) {607texture = RS::get_singleton()->texture_3d_placeholder_create();608}609return texture;610}611612Vector<Ref<Image>> CompressedTexture3D::get_data() const {613if (texture.is_valid()) {614return RS::get_singleton()->texture_3d_get(texture);615} else {616return Vector<Ref<Image>>();617}618}619620void CompressedTexture3D::reload_from_file() {621String path = get_path();622if (!path.is_resource_file()) {623return;624}625626path = ResourceLoader::path_remap(path); //remap for translation627path = ResourceLoader::import_remap(path); //remap for import628if (!path.is_resource_file()) {629return;630}631632load(path);633}634635void CompressedTexture3D::_bind_methods() {636ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTexture3D::load);637ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTexture3D::get_load_path);638639ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");640}641642CompressedTexture3D::~CompressedTexture3D() {643if (texture.is_valid()) {644ERR_FAIL_NULL(RenderingServer::get_singleton());645RS::get_singleton()->free_rid(texture);646}647}648649Ref<Resource> ResourceFormatLoaderCompressedTexture3D::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) {650Ref<CompressedTexture3D> st;651st.instantiate();652Error err = st->load(p_path);653if (r_error) {654*r_error = err;655}656if (err != OK) {657return Ref<Resource>();658}659660return st;661}662663void ResourceFormatLoaderCompressedTexture3D::get_recognized_extensions(List<String> *p_extensions) const {664p_extensions->push_back("ctex3d");665}666667bool ResourceFormatLoaderCompressedTexture3D::handles_type(const String &p_type) const {668return p_type == "CompressedTexture3D";669}670671String ResourceFormatLoaderCompressedTexture3D::get_resource_type(const String &p_path) const {672if (p_path.has_extension("ctex3d")) {673return "CompressedTexture3D";674}675return "";676}677678void CompressedTextureLayered::set_path(const String &p_path, bool p_take_over) {679if (texture.is_valid()) {680RenderingServer::get_singleton()->texture_set_path(texture, p_path);681}682683Resource::set_path(p_path, p_take_over);684}685686Image::Format CompressedTextureLayered::get_format() const {687return format;688}689690Error CompressedTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) {691ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER);692693Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);694ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Unable to open file: %s.", p_path));695696uint8_t header[4];697f->get_buffer(header, 4);698if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L') {699ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture layered file is corrupt (Bad header).");700}701702uint32_t version = f->get_32();703704if (version > FORMAT_VERSION) {705ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Compressed texture file is too new.");706}707708uint32_t layer_count = f->get_32(); //layer count709uint32_t type = f->get_32(); //layer count710ERR_FAIL_COND_V((int)type != layered_type, ERR_INVALID_DATA);711712uint32_t df = f->get_32(); //data format713mipmap_limit = int(f->get_32());714//reserved715f->get_32();716f->get_32();717f->get_32();718719if (!(df & FORMAT_BIT_STREAM)) {720p_size_limit = 0;721}722723images.resize(layer_count);724725for (uint32_t i = 0; i < layer_count; i++) {726Ref<Image> image = CompressedTexture2D::load_image_from_file(f, p_size_limit);727ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN);728images.write[i] = image;729}730731return OK;732}733734Error CompressedTextureLayered::load(const String &p_path) {735Vector<Ref<Image>> images;736737int mipmap_limit;738739Error err = _load_data(p_path, images, mipmap_limit);740if (err) {741return err;742}743744if (texture.is_valid()) {745RID new_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));746RS::get_singleton()->texture_replace(texture, new_texture);747} else {748texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type));749}750751w = images[0]->get_width();752h = images[0]->get_height();753mipmaps = images[0]->has_mipmaps();754format = images[0]->get_format();755layers = images.size();756757path_to_file = p_path;758759if (get_path().is_empty()) {760//temporarily set path if no path set for resource, helps find errors761RenderingServer::get_singleton()->texture_set_path(texture, p_path);762}763764notify_property_list_changed();765emit_changed();766return OK;767}768769String CompressedTextureLayered::get_load_path() const {770return path_to_file;771}772773int CompressedTextureLayered::get_width() const {774return w;775}776777int CompressedTextureLayered::get_height() const {778return h;779}780781int CompressedTextureLayered::get_layers() const {782return layers;783}784785bool CompressedTextureLayered::has_mipmaps() const {786return mipmaps;787}788789TextureLayered::LayeredType CompressedTextureLayered::get_layered_type() const {790return layered_type;791}792793RID CompressedTextureLayered::get_rid() const {794if (!texture.is_valid()) {795texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type));796}797return texture;798}799800Ref<Image> CompressedTextureLayered::get_layer_data(int p_layer) const {801if (texture.is_valid()) {802ERR_FAIL_INDEX_V(p_layer, get_layers(), Ref<Image>());803return RS::get_singleton()->texture_2d_layer_get(texture, p_layer);804} else {805return Ref<Image>();806}807}808809void CompressedTextureLayered::reload_from_file() {810String path = get_path();811if (!path.is_resource_file()) {812return;813}814815path = ResourceLoader::path_remap(path); //remap for translation816path = ResourceLoader::import_remap(path); //remap for import817if (!path.is_resource_file()) {818return;819}820821load(path);822}823824void CompressedTextureLayered::_bind_methods() {825ClassDB::bind_method(D_METHOD("load", "path"), &CompressedTextureLayered::load);826ClassDB::bind_method(D_METHOD("get_load_path"), &CompressedTextureLayered::get_load_path);827828ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.ctex"), "load", "get_load_path");829}830831CompressedTextureLayered::CompressedTextureLayered(LayeredType p_type) {832layered_type = p_type;833}834835CompressedTextureLayered::~CompressedTextureLayered() {836if (texture.is_valid()) {837ERR_FAIL_NULL(RenderingServer::get_singleton());838RS::get_singleton()->free_rid(texture);839}840}841842/////////////////////////////////////////////////843844Ref<Resource> ResourceFormatLoaderCompressedTextureLayered::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) {845Ref<CompressedTextureLayered> ct;846if (p_path.has_extension("ctexarray")) {847Ref<CompressedTexture2DArray> c;848c.instantiate();849ct = c;850} else if (p_path.has_extension("ccube")) {851Ref<CompressedCubemap> c;852c.instantiate();853ct = c;854} else if (p_path.has_extension("ccubearray")) {855Ref<CompressedCubemapArray> c;856c.instantiate();857ct = c;858} else {859if (r_error) {860*r_error = ERR_FILE_UNRECOGNIZED;861}862return Ref<Resource>();863}864Error err = ct->load(p_path);865if (r_error) {866*r_error = err;867}868if (err != OK) {869return Ref<Resource>();870}871872return ct;873}874875void ResourceFormatLoaderCompressedTextureLayered::get_recognized_extensions(List<String> *p_extensions) const {876p_extensions->push_back("ctexarray");877p_extensions->push_back("ccube");878p_extensions->push_back("ccubearray");879}880881bool ResourceFormatLoaderCompressedTextureLayered::handles_type(const String &p_type) const {882return p_type == "CompressedTexture2DArray" || p_type == "CompressedCubemap" || p_type == "CompressedCubemapArray";883}884885String ResourceFormatLoaderCompressedTextureLayered::get_resource_type(const String &p_path) const {886if (p_path.has_extension("ctexarray")) {887return "CompressedTexture2DArray";888}889if (p_path.has_extension("ccube")) {890return "CompressedCubemap";891}892if (p_path.has_extension("ccubearray")) {893return "CompressedCubemapArray";894}895return "";896}897898899