Skip to content

Commit

Permalink
Add support for exporting ImageTexture, AtlasTexture
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitalita committed Nov 5, 2024
1 parent edb7d8c commit c789196
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 25 deletions.
9 changes: 9 additions & 0 deletions compat/image_enum_compat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,15 @@ String ImageEnumCompat::get_v3_format_name(V3Image::Format p_format) {
return v3_format_names[p_format];
}

V3Image::Format ImageEnumCompat::get_v3_format_enum_from_name(String p_format) {
for (int i = 0; i < V3Image::FORMAT_MAX; i++) {
if (v3_format_names[i] == p_format) {
return V3Image::Format(i);
}
}
return V3Image::FORMAT_MAX;
}

String ImageEnumCompat::get_v3_format_identifier(V3Image::Format p_format) {
ERR_FAIL_INDEX_V(p_format, V3Image::FORMAT_MAX, String());
return v3_format_identifiers[p_format];
Expand Down
3 changes: 3 additions & 0 deletions compat/image_enum_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ class ImageEnumCompat {
static String get_v2_format_name(V2Image::Format p_format);
static String get_v2_format_identifier(V2Image::Format p_format);
static String get_v2_format_identifier_pcfg(V2Image::Format p_format, int p_img_size);

static String get_v3_format_name(V3Image::Format p_format);
static String get_v3_format_identifier(V3Image::Format p_format);
static V3Image::Format get_v3_format_enum_from_name(String p_format);

static String get_v4_format_identifier(Image::Format p_format);

static Image::Format convert_image_format_enum_v3_to_v4(V3Image::Format fmt);
Expand Down
167 changes: 154 additions & 13 deletions compat/texture_loader_compat.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "texture_loader_compat.h"
#include "compat/resource_compat_binary.h"
#include "compat/resource_loader_compat.h"
#include "core/error/error_list.h"
#include "core/error/error_macros.h"
#include "core/io/missing_resource.h"
#include "core/variant/dictionary.h"
Expand Down Expand Up @@ -100,7 +101,15 @@ TextureLoaderCompat::TextureVersionType TextureLoaderCompat::recognize(const Str
}
return FORMAT_V4_IMAGE_TEXTURE;
} else if (type == "AtlasTexture") {
return FORMAT_V2_ATLAS_TEXTURE;
switch (i_info.ver_major) {
case 1:
case 2:
return FORMAT_V2_ATLAS_TEXTURE;
case 3:
return FORMAT_V3_ATLAS_TEXTURE;
default:
return FORMAT_V4_ATLAS_TEXTURE;
}
} else if (type == "LargeTexture") {
return FORMAT_V2_LARGE_TEXTURE;
} else if (type == "CubeMap") {
Expand All @@ -119,11 +128,13 @@ int TextureLoaderCompat::get_ver_major_from_textype(TextureVersionType type) {
case FORMAT_V2_LARGE_TEXTURE:
case FORMAT_V2_CUBEMAP:
return 2;
case FORMAT_V3_ATLAS_TEXTURE:
case FORMAT_V3_IMAGE_TEXTURE:
case FORMAT_V3_STREAM_TEXTURE2D:
case FORMAT_V3_STREAM_TEXTURE3D:
case FORMAT_V3_STREAM_TEXTUREARRAY:
return 3;
case FORMAT_V4_ATLAS_TEXTURE:
case FORMAT_V4_IMAGE_TEXTURE:
case FORMAT_V4_COMPRESSED_TEXTURE2D:
case FORMAT_V4_COMPRESSED_TEXTURE3D:
Expand Down Expand Up @@ -155,12 +166,31 @@ TextureLoaderCompat::TextureType TextureLoaderCompat::get_type_enum_from_version
case FORMAT_V4_IMAGE_TEXTURE:
return TEXTURE_TYPE_2D;
case FORMAT_V2_ATLAS_TEXTURE:
case FORMAT_V3_ATLAS_TEXTURE:
case FORMAT_V4_ATLAS_TEXTURE:
return TEXTURE_TYPE_ATLAS;
default:
return TEXTURE_TYPE_UNKNOWN;
}
}

bool TextureLoaderCompat::is_binary_resource(TextureVersionType t) {
switch (t) {
case FORMAT_V2_TEXTURE:
case FORMAT_V2_IMAGE_TEXTURE:
case FORMAT_V2_ATLAS_TEXTURE:
case FORMAT_V2_LARGE_TEXTURE:
case FORMAT_V2_CUBEMAP:
case FORMAT_V3_IMAGE_TEXTURE:
case FORMAT_V4_IMAGE_TEXTURE:
case FORMAT_V3_ATLAS_TEXTURE:
case FORMAT_V4_ATLAS_TEXTURE:
return true;
default:
return false;
}
}

String TextureLoaderCompat::get_type_name_from_textype(TextureVersionType type) {
switch (type) {
case FORMAT_V2_TEXTURE:
Expand All @@ -170,6 +200,8 @@ String TextureLoaderCompat::get_type_name_from_textype(TextureVersionType type)
case FORMAT_V4_IMAGE_TEXTURE:
return "ImageTexture";
case FORMAT_V2_ATLAS_TEXTURE:
case FORMAT_V3_ATLAS_TEXTURE:
case FORMAT_V4_ATLAS_TEXTURE:
return "AtlasTexture";
case FORMAT_V2_LARGE_TEXTURE:
return "LargeTexture";
Expand Down Expand Up @@ -685,28 +717,42 @@ Ref<Resource> ResourceConverterTexture2D::convert(const Ref<MissingResource> &re
int th = 0;
int tw_custom = 0;
int th_custom = 0;
int flags;
int flags = 0;
Ref<Image> image;
Ref<Resource> image_res;
Ref<Resource> texture;
Dictionary compat_dict = (res->get_meta("compat", Dictionary()));
String type = res->get_original_class();
if (type == "Texture" || type == "ImageTexture") {
name = ver_major == 2 ? res->get("resource/name") : res->get("resource_name");
image = res->get("image");

auto convert_image = [&](const Ref<Resource> &image_res) -> Ref<Image> {
Ref<Image> image = image_res;
if (image.is_null() && image_res->get_class() == "MissingResource") {
ImageConverterCompat ic;
if (ic.handles_type("Image", ver_major)) {
image = ic.convert(image_res, p_type, ver_major, r_error);
}
}
return image;
};
if ((type == "Texture" && ver_major == 2) || type == "ImageTexture") {
name = get_resource_name(res, ver_major);
image = convert_image(res->get("image"));
ERR_FAIL_COND_V_MSG(image.is_null(), res, "Cannot load resource '" + name + "'.");

size = res->get("size");
flags = res->get("flags");
bool mipmaps = flags & 1 || image->has_mipmaps();

ERR_FAIL_COND_V_MSG(image.is_null(), Ref<Resource>(), "Cannot load resource '" + name + "'.");
image->set_name(name);
tw = image->get_width();
th = image->get_height();
if (tw != size.width) {
if (size.width && tw != size.width) {
tw_custom = size.width;
}
if (th != size.height) {
if (size.height && th != size.height) {
th_custom = size.height;
}
texture = ResourceFormatLoaderCompatTexture2D::_set_tex(res->get_path(), p_type, tw, th, tw_custom, th_custom, flags, image);
texture = TextureLoaderCompat::create_image_texture(res->get_path(), p_type, tw, th, tw_custom, th_custom, mipmaps, image);
} else if (ver_major >= 3) {
if (p_type == ResourceInfo::LoadType::NON_GLOBAL_LOAD) {
return res;
Expand All @@ -715,8 +761,12 @@ Ref<Resource> ResourceConverterTexture2D::convert(const Ref<MissingResource> &re
String load_path = res->get("load_path");
ResourceFormatLoaderCompatTexture2D tlc;
texture = tlc.custom_load(load_path, p_type, r_error);
} else {
ERR_FAIL_V_MSG(res, "Unsupported type: " + type);
}
if (compat_dict.size() > 0) {
texture->set_meta("compat", compat_dict);
}
texture->set_meta("compat", compat_dict);
return texture;
}

Expand Down Expand Up @@ -787,7 +837,7 @@ ResourceInfo TextureLoaderCompat::get_resource_info(const String &p_path, Error
return ResourceInfo();
}
int ver_major = TextureLoaderCompat::get_ver_major_from_textype(t);
if (ver_major == 2 || t == TextureLoaderCompat::FORMAT_V3_IMAGE_TEXTURE || t == TextureLoaderCompat::FORMAT_V4_IMAGE_TEXTURE) {
if (TextureLoaderCompat::is_binary_resource(t)) {
ResourceFormatLoaderCompatBinary rlcb;
return rlcb.get_resource_info(p_path, r_error);
}
Expand All @@ -813,7 +863,7 @@ Ref<Resource> ResourceFormatLoaderCompatTexture2D::custom_load(const String &p_p
Ref<Resource> texture;
Ref<Image> image;
bool convert = false;
if (t == TextureLoaderCompat::FORMAT_V2_IMAGE_TEXTURE || t == TextureLoaderCompat::FORMAT_V2_TEXTURE || t == TextureLoaderCompat::FORMAT_V3_IMAGE_TEXTURE || t == TextureLoaderCompat::FORMAT_V4_IMAGE_TEXTURE) {
if (TextureLoaderCompat::is_binary_resource(t)) {
convert = true;
} else if (t == TextureLoaderCompat::FORMAT_V3_STREAM_TEXTURE2D) {
err = TextureLoaderCompat::_load_data_stex2d_v3(p_path, lw, lh, lwc, lhc, lflags, image);
Expand Down Expand Up @@ -1011,4 +1061,95 @@ Ref<Resource> ResourceFormatLoaderCompatTextureLayered::custom_load(const String
set_res_path(texture, res->get_path(), p_type);

return texture;
}
}

bool ImageConverterCompat::handles_type(const String &p_type, int ver_major) const {
return (p_type == "Image") && ver_major == 3;
}

Ref<Resource> ImageConverterCompat::convert(const Ref<MissingResource> &res, ResourceInfo::LoadType p_type, int ver_major, Error *r_error) {
String name;
Vector2 size;
Ref<Image> image;
Dictionary compat_dict = (res->get_meta("compat", Dictionary()));
String type = res->get_original_class();
if (type != "Image") {
WARN_PRINT("ImageConverterCompat: Unsupported type: " + type);
return res;
}
name = get_resource_name(res, ver_major);
Dictionary data = res->get("data");
int tw = data.get("width", 0);
int th = data.get("height", 0);
String format = data.get("format", "");
auto fmt_enum = ImageEnumCompat::convert_image_format_enum_v3_to_v4(ImageEnumCompat::get_v3_format_enum_from_name(format));
if (fmt_enum == Image::FORMAT_MAX) {
*r_error = ERR_UNAVAILABLE;
ERR_FAIL_V_MSG(res, "Deprecated v3 image format: " + format);
}
bool mipmaps = data.get("mipmaps", false);
Vector<uint8_t> img_data = data.get("data", Vector<uint8_t>());
image = Image::create_from_data(tw, th, mipmaps, fmt_enum, img_data);
image->set_name(name);
if (compat_dict.size() > 0) {
image->set_meta("compat", compat_dict);
}
return image;
}

class OverrideImageTexture : public ImageTexture {
public:
Ref<Image> image;
virtual Ref<Image> get_image() const override {
// otherwise, call the parent
return image;
}
virtual String get_save_class() const override {
return "ImageTexture";
}
};

class fakeimagetex : Texture2D {
GDCLASS(fakeimagetex, Texture2D);

public:
mutable RID texture;
Image::Format format = Image::FORMAT_L8;
bool mipmaps = false;
int w = 0;
int h = 0;
Size2 size_override;
mutable Ref<BitMap> alpha_cache;
bool image_stored = false;
};
static_assert(sizeof(fakeimagetex) == sizeof(ImageTexture), "fakeimagetex must be the same size as ImageTexture");

Ref<ImageTexture> TextureLoaderCompat::create_image_texture(const String &p_path, ResourceInfo::LoadType p_type, int tw, int th, int tw_custom, int th_custom, bool mipmaps, Ref<Image> image) {
Ref<ImageTexture> texture;
Ref<OverrideImageTexture> override_texture;
if (p_type != ResourceInfo::LoadType::REAL_LOAD) {
override_texture.instantiate();
override_texture->image = image;
texture = override_texture;
} else {
texture.instantiate();
}
fakeimagetex *fake = reinterpret_cast<fakeimagetex *>(texture.ptr());
fake->image_stored = true;
fake->w = tw;
fake->h = th;
fake->format = image->get_format();
if (tw_custom || th_custom) {
fake->size_override = Size2(tw_custom, th_custom);
}
fake->mipmaps = mipmaps;
bool size_override = tw_custom || th_custom;
if (p_type == ResourceInfo::LoadType::REAL_LOAD) {
RID texture_rid = RS::get_singleton()->texture_2d_create(image);
fake->texture = texture_rid;
if (size_override) {
RS::get_singleton()->texture_set_size_override(texture_rid, fake->w, fake->h);
}
}
return texture;
}
16 changes: 15 additions & 1 deletion compat/texture_loader_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "core/object/ref_counted.h"
#include "core/templates/vector.h"
#include "scene/resources/compressed_texture.h"
#include "scene/resources/image_texture.h"
class TextureLoaderCompat {
public:
enum TextureVersionType {
Expand All @@ -18,10 +19,12 @@ class TextureLoaderCompat {
FORMAT_V2_ATLAS_TEXTURE, //atex
FORMAT_V2_LARGE_TEXTURE, //ltex
FORMAT_V2_CUBEMAP, //cbm
FORMAT_V3_ATLAS_TEXTURE, //res
FORMAT_V3_IMAGE_TEXTURE, //tex
FORMAT_V3_STREAM_TEXTURE2D, //stex
FORMAT_V3_STREAM_TEXTURE3D, //tex3d
FORMAT_V3_STREAM_TEXTUREARRAY, //texarr
FORMAT_V4_ATLAS_TEXTURE, //res
FORMAT_V4_IMAGE_TEXTURE, //tex
FORMAT_V4_COMPRESSED_TEXTURE2D, //ctex
FORMAT_V4_COMPRESSED_TEXTURE3D, //ctex3d
Expand All @@ -34,7 +37,6 @@ class TextureLoaderCompat {
TEXTURE_TYPE_LAYERED,
TEXTURE_TYPE_ATLAS
};

static Error _load_data_ctexlayered_v4(const String &p_path, Vector<Ref<Image>> &r_data, Image::Format &r_format, int &r_width, int &r_height, int &r_depth, int &r_type, bool &r_mipmaps);
static Error _load_layered_texture_v3(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);
static ResourceInfo _get_resource_info(TextureLoaderCompat::TextureVersionType t);
Expand All @@ -43,6 +45,8 @@ class TextureLoaderCompat {
static Error _load_data_ctex2d_v4(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, int p_size_limit = 0);
static Error _load_data_stex2d_v3(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, int &flags, Ref<Image> &image, int p_size_limit = 0);

static Ref<ImageTexture> create_image_texture(const String &p_path, ResourceInfo::LoadType p_type, int tw, int th, int tw_custom, int th_custom, bool mipmaps, Ref<Image> image);
static bool is_binary_resource(TextureVersionType t);
static TextureVersionType recognize(const String &p_path, Error *r_err);
static int get_ver_major_from_textype(TextureVersionType type);
static TextureType get_type_enum_from_version_type(TextureVersionType type);
Expand All @@ -60,6 +64,16 @@ class ResourceConverterTexture2D : public ResourceCompatConverter {
// static Ref<CompressedTexture2D> _load_texture2d(const String &p_path, Ref<Image> &image, bool &size_override, int ver_major, Error *r_err) const;
};

class ImageConverterCompat : public ResourceCompatConverter {
GDCLASS(ImageConverterCompat, ResourceCompatConverter);

public:
virtual Ref<Resource> convert(const Ref<MissingResource> &res, ResourceInfo::LoadType p_type, int ver_major, Error *r_error = nullptr) override;
virtual bool handles_type(const String &p_type, int ver_major) const override;

// static Ref<CompressedTexture2D> _load_texture2d(const String &p_path, Ref<Image> &image, bool &size_override, int ver_major, Error *r_err) const;
};

class ResourceFormatLoaderCompatTexture2D : public CompatFormatLoader {
GDCLASS(ResourceFormatLoaderCompatTexture2D, CompatFormatLoader);

Expand Down
Loading

0 comments on commit c789196

Please sign in to comment.