diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2020-05-11 13:45:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-05-11 13:45:48 +0200 |
commit | 32133a11b56761df99579ad96ee29a47d2aed6b4 (patch) | |
tree | ab68992cfe6b1f59a618f713545fdcb3b6488b07 /scene/resources | |
parent | bbdfc7353c3af72fcdf037ff10b8571aa2afc230 (diff) | |
parent | 1bea8e1eacc68bcedbd3f207395bccf11011dae2 (diff) |
Merge pull request #38386 from reduz/new-lightmapper
New GPU lightmapper
Diffstat (limited to 'scene/resources')
-rw-r--r-- | scene/resources/mesh.cpp | 6 | ||||
-rw-r--r-- | scene/resources/mesh.h | 6 | ||||
-rw-r--r-- | scene/resources/texture.cpp | 481 | ||||
-rw-r--r-- | scene/resources/texture.h | 166 |
4 files changed, 414 insertions, 245 deletions
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 401b689145..6548c65cd7 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -472,11 +472,11 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const { return newmesh; } -void Mesh::set_lightmap_size_hint(const Vector2 &p_size) { +void Mesh::set_lightmap_size_hint(const Size2i &p_size) { lightmap_size_hint = p_size; } -Size2 Mesh::get_lightmap_size_hint() const { +Size2i Mesh::get_lightmap_size_hint() const { return lightmap_size_hint; } @@ -486,7 +486,7 @@ void Mesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint); ClassDB::bind_method(D_METHOD("get_aabb"), &Mesh::get_aabb); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint"); ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count); ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index a65cf0a928..80cd57846b 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -43,7 +43,7 @@ class Mesh : public Resource { mutable Ref<TriangleMesh> triangle_mesh; //cached mutable Vector<Vector3> debug_lines; - Size2 lightmap_size_hint; + Size2i lightmap_size_hint; protected: static void _bind_methods(); @@ -138,8 +138,8 @@ public: virtual AABB get_aabb() const = 0; - void set_lightmap_size_hint(const Vector2 &p_size); - Size2 get_lightmap_size_hint() const; + void set_lightmap_size_hint(const Size2i &p_size); + Size2i get_lightmap_size_hint() const; void clear_cache() const; typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 91c40d871d..6e155ddf91 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -355,7 +355,7 @@ ImageTexture::~ImageTexture() { ////////////////////////////////////////// -Ref<Image> StreamTexture::load_image_from_file(FileAccess *f, int p_size_limit) { +Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit) { uint32_t data_format = f->get_32(); uint32_t w = f->get_16(); @@ -492,7 +492,7 @@ Ref<Image> StreamTexture::load_image_from_file(FileAccess *f, int p_size_limit) return Ref<Image>(); } -void StreamTexture::set_path(const String &p_path, bool p_take_over) { +void StreamTexture2D::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); @@ -501,40 +501,40 @@ void StreamTexture::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } -void StreamTexture::_requested_3d(void *p_ud) { +void StreamTexture2D::_requested_3d(void *p_ud) { - StreamTexture *st = (StreamTexture *)p_ud; - Ref<StreamTexture> stex(st); + StreamTexture2D *st = (StreamTexture2D *)p_ud; + Ref<StreamTexture2D> stex(st); ERR_FAIL_COND(!request_3d_callback); request_3d_callback(stex); } -void StreamTexture::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) { +void StreamTexture2D::_requested_roughness(void *p_ud, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel) { - StreamTexture *st = (StreamTexture *)p_ud; - Ref<StreamTexture> stex(st); + StreamTexture2D *st = (StreamTexture2D *)p_ud; + Ref<StreamTexture2D> stex(st); ERR_FAIL_COND(!request_roughness_callback); request_roughness_callback(stex, p_normal_path, p_roughness_channel); } -void StreamTexture::_requested_normal(void *p_ud) { +void StreamTexture2D::_requested_normal(void *p_ud) { - StreamTexture *st = (StreamTexture *)p_ud; - Ref<StreamTexture> stex(st); + StreamTexture2D *st = (StreamTexture2D *)p_ud; + Ref<StreamTexture2D> stex(st); ERR_FAIL_COND(!request_normal_callback); request_normal_callback(stex); } -StreamTexture::TextureFormatRequestCallback StreamTexture::request_3d_callback = nullptr; -StreamTexture::TextureFormatRoughnessRequestCallback StreamTexture::request_roughness_callback = nullptr; -StreamTexture::TextureFormatRequestCallback StreamTexture::request_normal_callback = nullptr; +StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_3d_callback = nullptr; +StreamTexture2D::TextureFormatRoughnessRequestCallback StreamTexture2D::request_roughness_callback = nullptr; +StreamTexture2D::TextureFormatRequestCallback StreamTexture2D::request_normal_callback = nullptr; -Image::Format StreamTexture::get_format() const { +Image::Format StreamTexture2D::get_format() const { return format; } -Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) { +Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit) { alpha_cache.unref(); @@ -595,7 +595,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_ return OK; } -Error StreamTexture::load(const String &p_path) { +Error StreamTexture2D::load(const String &p_path) { int lw, lh, lwc, lhc; Ref<Image> image; @@ -661,20 +661,20 @@ Error StreamTexture::load(const String &p_path) { emit_changed(); return OK; } -String StreamTexture::get_load_path() const { +String StreamTexture2D::get_load_path() const { return path_to_file; } -int StreamTexture::get_width() const { +int StreamTexture2D::get_width() const { return w; } -int StreamTexture::get_height() const { +int StreamTexture2D::get_height() const { return h; } -RID StreamTexture::get_rid() const { +RID StreamTexture2D::get_rid() const { if (!texture.is_valid()) { texture = RS::get_singleton()->texture_2d_placeholder_create(); @@ -682,7 +682,7 @@ RID StreamTexture::get_rid() const { return texture; } -void StreamTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { if ((w | h) == 0) return; @@ -690,7 +690,7 @@ void StreamTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_ RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); } -void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { +void StreamTexture2D::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat) const { if ((w | h) == 0) return; @@ -698,7 +698,7 @@ void StreamTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_til RID specular_rid = p_specular_map.is_valid() ? p_specular_map->get_rid() : RID(); RenderingServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_texture_filter, p_texture_repeat); } -void StreamTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { +void StreamTexture2D::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture2D> &p_normal_map, const Ref<Texture2D> &p_specular_map, const Color &p_specular_color_shininess, RS::CanvasItemTextureFilter p_texture_filter, RS::CanvasItemTextureRepeat p_texture_repeat, bool p_clip_uv) const { if ((w | h) == 0) return; @@ -707,12 +707,12 @@ void StreamTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, con RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose, normal_rid, specular_rid, p_specular_color_shininess, p_clip_uv, p_texture_filter, p_texture_repeat); } -bool StreamTexture::has_alpha() const { +bool StreamTexture2D::has_alpha() const { return false; } -Ref<Image> StreamTexture::get_data() const { +Ref<Image> StreamTexture2D::get_data() const { if (texture.is_valid()) { return RS::get_singleton()->texture_2d_get(texture); @@ -721,7 +721,7 @@ Ref<Image> StreamTexture::get_data() const { } } -bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { +bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const { if (!alpha_cache.is_valid()) { Ref<Image> img = get_data(); @@ -757,7 +757,7 @@ bool StreamTexture::is_pixel_opaque(int p_x, int p_y) const { return true; } -void StreamTexture::reload_from_file() { +void StreamTexture2D::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) @@ -771,34 +771,34 @@ void StreamTexture::reload_from_file() { load(path); } -void StreamTexture::_validate_property(PropertyInfo &property) const { +void StreamTexture2D::_validate_property(PropertyInfo &property) const { } -void StreamTexture::_bind_methods() { +void StreamTexture2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture::load); - ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture::get_load_path); + ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture2D::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTexture2D::get_load_path); ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); } -StreamTexture::StreamTexture() { +StreamTexture2D::StreamTexture2D() { format = Image::FORMAT_MAX; w = 0; h = 0; } -StreamTexture::~StreamTexture() { +StreamTexture2D::~StreamTexture2D() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } } -RES ResourceFormatLoaderStreamTexture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { - Ref<StreamTexture> st; + Ref<StreamTexture2D> st; st.instance(); Error err = st->load(p_path); if (r_error) @@ -809,17 +809,17 @@ RES ResourceFormatLoaderStreamTexture::load(const String &p_path, const String & return st; } -void ResourceFormatLoaderStreamTexture::get_recognized_extensions(List<String> *p_extensions) const { +void ResourceFormatLoaderStreamTexture2D::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("stex"); } -bool ResourceFormatLoaderStreamTexture::handles_type(const String &p_type) const { - return p_type == "StreamTexture"; +bool ResourceFormatLoaderStreamTexture2D::handles_type(const String &p_type) const { + return p_type == "StreamTexture2D"; } -String ResourceFormatLoaderStreamTexture::get_resource_type(const String &p_path) const { +String ResourceFormatLoaderStreamTexture2D::get_resource_type(const String &p_path) const { if (p_path.get_extension().to_lower() == "stex") - return "StreamTexture"; + return "StreamTexture2D"; return ""; } @@ -1930,23 +1930,47 @@ AnimatedTexture::~AnimatedTexture() { } /////////////////////////////// -Image::Format TextureLayered::get_format() const { +void TextureLayered::_bind_methods() { + + ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format); + ClassDB::bind_method(D_METHOD("get_layered_type"), &TextureLayered::get_layered_type); + ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width); + ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height); + ClassDB::bind_method(D_METHOD("get_layers"), &TextureLayered::get_layers); + ClassDB::bind_method(D_METHOD("has_mipmaps"), &TextureLayered::has_mipmaps); + ClassDB::bind_method(D_METHOD("get_layer_data"), &TextureLayered::get_layer_data); + + BIND_ENUM_CONSTANT(LAYERED_TYPE_2D_ARRAY); + BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP); + BIND_ENUM_CONSTANT(LAYERED_TYPE_CUBEMAP_ARRAY); +} + +/////////////////////////////// +Image::Format ImageTextureLayered::get_format() const { return format; } -uint32_t TextureLayered::get_width() const { +int ImageTextureLayered::get_width() const { return width; } -uint32_t TextureLayered::get_height() const { +int ImageTextureLayered::get_height() const { return height; } -uint32_t TextureLayered::get_layers() const { +int ImageTextureLayered::get_layers() const { return layers; } -Error TextureLayered::_create_from_images(const Array &p_images) { +bool ImageTextureLayered::has_mipmaps() const { + return mipmaps; +} + +ImageTextureLayered::LayeredType ImageTextureLayered::get_layered_type() const { + return layered_type; +} + +Error ImageTextureLayered::_create_from_images(const Array &p_images) { Vector<Ref<Image>> images; for (int i = 0; i < p_images.size(); i++) { Ref<Image> img = p_images[i]; @@ -1957,7 +1981,7 @@ Error TextureLayered::_create_from_images(const Array &p_images) { return create_from_images(images); } -Array TextureLayered::_get_images() const { +Array ImageTextureLayered::_get_images() const { Array images; for (int i = 0; i < layers; i++) { images.push_back(get_layer_data(i)); @@ -1965,14 +1989,14 @@ Array TextureLayered::_get_images() const { return images; } -Error TextureLayered::create_from_images(Vector<Ref<Image>> p_images) { +Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) { int new_layers = p_images.size(); ERR_FAIL_COND_V(new_layers == 0, ERR_INVALID_PARAMETER); - if (layered_type == RS::TEXTURE_LAYERED_CUBEMAP) { + if (layered_type == LAYERED_TYPE_CUBEMAP) { ERR_FAIL_COND_V_MSG(new_layers != 6, ERR_INVALID_PARAMETER, "Cubemaps require exactly 6 layers"); - } else if (layered_type == RS::TEXTURE_LAYERED_CUBEMAP_ARRAY) { + } else if (layered_type == LAYERED_TYPE_CUBEMAP_ARRAY) { ERR_FAIL_COND_V_MSG((new_layers % 6) != 0, ERR_INVALID_PARAMETER, "Cubemap array layers must be a multiple of 6"); } @@ -1994,11 +2018,11 @@ Error TextureLayered::create_from_images(Vector<Ref<Image>> p_images) { } if (texture.is_valid()) { - RID new_texture = RS::get_singleton()->texture_2d_layered_create(p_images, layered_type); + RID new_texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type)); ERR_FAIL_COND_V(!new_texture.is_valid(), ERR_CANT_CREATE); RS::get_singleton()->texture_replace(texture, new_texture); } else { - texture = RS::get_singleton()->texture_2d_layered_create(p_images, layered_type); + texture = RS::get_singleton()->texture_2d_layered_create(p_images, RS::TextureLayeredType(layered_type)); ERR_FAIL_COND_V(!texture.is_valid(), ERR_CANT_CREATE); } @@ -2010,7 +2034,7 @@ Error TextureLayered::create_from_images(Vector<Ref<Image>> p_images) { return OK; } -void TextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) { +void ImageTextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) { ERR_FAIL_COND(texture.is_valid()); ERR_FAIL_COND(p_image.is_null()); ERR_FAIL_COND(p_image->get_format() != format); @@ -2020,19 +2044,19 @@ void TextureLayered::update_layer(const Ref<Image> &p_image, int p_layer) { RS::get_singleton()->texture_2d_update(texture, p_image, p_layer); } -Ref<Image> TextureLayered::get_layer_data(int p_layer) const { +Ref<Image> ImageTextureLayered::get_layer_data(int p_layer) const { ERR_FAIL_INDEX_V(p_layer, layers, Ref<Image>()); return RS::get_singleton()->texture_2d_layer_get(texture, p_layer); } -RID TextureLayered::get_rid() const { +RID ImageTextureLayered::get_rid() const { if (texture.is_null()) { - texture = RS::get_singleton()->texture_2d_layered_placeholder_create(); + texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type)); } return texture; } -void TextureLayered::set_path(const String &p_path, bool p_take_over) { +void ImageTextureLayered::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { RS::get_singleton()->texture_set_path(texture, p_path); } @@ -2040,24 +2064,17 @@ void TextureLayered::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } -void TextureLayered::_bind_methods() { - - ClassDB::bind_method(D_METHOD("get_format"), &TextureLayered::get_format); - - ClassDB::bind_method(D_METHOD("get_width"), &TextureLayered::get_width); - ClassDB::bind_method(D_METHOD("get_height"), &TextureLayered::get_height); - ClassDB::bind_method(D_METHOD("get_layers"), &TextureLayered::get_layers); +void ImageTextureLayered::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_from_images", "images"), &TextureLayered::_create_from_images); - ClassDB::bind_method(D_METHOD("update_layer", "image", "layer"), &TextureLayered::update_layer); - ClassDB::bind_method(D_METHOD("get_layer_data", "layer"), &TextureLayered::get_layer_data); + ClassDB::bind_method(D_METHOD("create_from_images", "images"), &ImageTextureLayered::_create_from_images); + ClassDB::bind_method(D_METHOD("update_layer", "image", "layer"), &ImageTextureLayered::update_layer); - ClassDB::bind_method(D_METHOD("_get_images"), &TextureLayered::_get_images); + ClassDB::bind_method(D_METHOD("_get_images"), &ImageTextureLayered::_get_images); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_images", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_INTERNAL), "create_from_images", "_get_images"); } -TextureLayered::TextureLayered(RenderingServer::TextureLayeredType p_layered_type) { +ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) { layered_type = p_layered_type; format = Image::FORMAT_MAX; @@ -2066,193 +2083,241 @@ TextureLayered::TextureLayered(RenderingServer::TextureLayeredType p_layered_typ layers = 0; } -TextureLayered::~TextureLayered() { +ImageTextureLayered::~ImageTextureLayered() { if (texture.is_valid()) { RS::get_singleton()->free(texture); } } -RES ResourceFormatLoaderTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +/////////////////////////////////////////// + +void StreamTextureLayered::set_path(const String &p_path, bool p_take_over) { - if (r_error) { - *r_error = ERR_CANT_OPEN; + if (texture.is_valid()) { + RenderingServer::get_singleton()->texture_set_path(texture, p_path); } - Ref<TextureLayered> lt; + Resource::set_path(p_path, p_take_over); +} + +Image::Format StreamTextureLayered::get_format() const { - if (p_path.ends_with("cube")) { - Ref<Cubemap> cube; - cube.instance(); - lt = cube; - } else if (p_path.ends_with("cubearr")) { - Ref<CubemapArray> cubearr; - cubearr.instance(); - lt = cubearr; - } else if (p_path.ends_with("tex2darr")) { - Ref<Texture2DArray> t2darr; - t2darr.instance(); - lt = t2darr; - } else { - ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture extension."); + return format; +} + +Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit) { + + ERR_FAIL_COND_V(images.size() != 0, ERR_INVALID_PARAMETER); + + FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + + uint8_t header[4]; + f->get_buffer(header, 4); + if (header[0] != 'G' || header[1] != 'S' || header[2] != 'T' || header[3] != 'L') { + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture layered file is corrupt (Bad header)."); } - FileAccess *f = FileAccess::open(p_path, FileAccess::READ); - ERR_FAIL_COND_V_MSG(!f, RES(), "Cannot open file '" + p_path + "'."); + uint32_t version = f->get_32(); + + if (version > FORMAT_VERSION) { + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Stream texture file is too new."); + } - char header[5] = { 0, 0, 0, 0, 0 }; - f->get_buffer((uint8_t *)header, 4); + uint32_t layer_count = f->get_32(); //layer count + uint32_t type = f->get_32(); //layer count + ERR_FAIL_COND_V(type != layered_type, ERR_INVALID_DATA); - if (String(header) != "GDLT") { - f->close(); - memdelete(f); - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - // FIXME: It's bogus that we fail in both branches. Seen while rebasing - // vulkan branch on master branch. - ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture."); - } else { + uint32_t df = f->get_32(); //data format + mipmap_limit = int(f->get_32()); + //reserverd + f->get_32(); + f->get_32(); + f->get_32(); - f->close(); - memdelete(f); - ERR_FAIL_V_MSG(RES(), "Unrecognized layered texture file format '" + String((const char *)header) + "'."); + if (!(df & FORMAT_BIT_STREAM)) { + p_size_limit = 0; } - int tw = f->get_32(); - int th = f->get_32(); - int td = f->get_32(); - bool use_mipmaps = f->get_32() != 0; //texture flags (deprecated) - Image::Format format = Image::Format(f->get_32()); - uint32_t compression = f->get_32(); // 0 - lossless (PNG), 1 - vram, 2 - uncompressed + images.resize(layer_count); - Vector<Ref<Image>> images; - for (int layer = 0; layer < td; layer++) { + for (uint32_t i = 0; i < layer_count; i++) { + Ref<Image> image = StreamTexture2D::load_image_from_file(f, p_size_limit); + ERR_FAIL_COND_V(image.is_null() || image->empty(), ERR_CANT_OPEN); + images.write[i] = image; + } - Ref<Image> image; - image.instance(); + return OK; +} - if (compression == COMPRESSION_LOSSLESS) { - //look for a PNG file inside +Error StreamTextureLayered::load(const String &p_path) { - int mipmaps = f->get_32(); - Vector<Ref<Image>> mipmap_images; + Vector<Ref<Image>> images; - for (int i = 0; i < mipmaps; i++) { - uint32_t size = f->get_32(); + int mipmap_limit; - Vector<uint8_t> pv; - pv.resize(size); - { - uint8_t *w = pv.ptrw(); - f->get_buffer(w, size); - } + Error err = _load_data(p_path, images, mipmap_limit); + if (err) + return err; - Ref<Image> img = Image::lossless_unpacker(pv); + if (texture.is_valid()) { + RID new_texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type)); + RS::get_singleton()->texture_replace(texture, new_texture); + } else { + texture = RS::get_singleton()->texture_2d_layered_create(images, RS::TextureLayeredType(layered_type)); + } - if (img.is_null() || img->empty() || format != img->get_format()) { - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - f->close(); - memdelete(f); - ERR_FAIL_V(RES()); - } + w = images[0]->get_width(); + h = images[0]->get_height(); + mipmaps = images[0]->has_mipmaps(); + format = images[0]->get_format(); + layers = images.size(); - mipmap_images.push_back(img); - } + path_to_file = p_path; - if (mipmap_images.size() == 1) { + if (get_path() == String()) { + //temporarily set path if no path set for resource, helps find errors + RenderingServer::get_singleton()->texture_set_path(texture, p_path); + } - image = mipmap_images[0]; + _change_notify(); + emit_changed(); + return OK; +} +String StreamTextureLayered::get_load_path() const { - } else { - int total_size = Image::get_image_data_size(tw, th, format, true); - Vector<uint8_t> img_data; - img_data.resize(total_size); - - { - uint8_t *w = img_data.ptrw(); - - int ofs = 0; - for (int i = 0; i < mipmap_images.size(); i++) { - - Vector<uint8_t> id = mipmap_images[i]->get_data(); - int len = id.size(); - const uint8_t *r = id.ptr(); - copymem(&w[ofs], r, len); - ofs += len; - } - } + return path_to_file; +} - image->create(tw, th, true, format, img_data); - if (image->empty()) { - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - f->close(); - memdelete(f); - ERR_FAIL_V(RES()); - } - } +int StreamTextureLayered::get_width() const { - } else { + return w; +} +int StreamTextureLayered::get_height() const { - //look for regular format + return h; +} +int StreamTextureLayered::get_layers() const { - int total_size = Image::get_image_data_size(tw, th, format, use_mipmaps); + return layers; +} +bool StreamTextureLayered::has_mipmaps() const { + return mipmaps; +} - Vector<uint8_t> img_data; - img_data.resize(total_size); +TextureLayered::LayeredType StreamTextureLayered::get_layered_type() const { - { - uint8_t *w = img_data.ptrw(); - int bytes = f->get_buffer(w, total_size); - if (bytes != total_size) { - if (r_error) { - *r_error = ERR_FILE_CORRUPT; - } - f->close(); - memdelete(f); - ERR_FAIL_V(RES()); - } - } + return layered_type; +} - image->create(tw, th, use_mipmaps, format, img_data); - } +RID StreamTextureLayered::get_rid() const { - images.push_back(image); + if (!texture.is_valid()) { + texture = RS::get_singleton()->texture_2d_layered_placeholder_create(RS::TextureLayeredType(layered_type)); } + return texture; +} - Error err = lt->create_from_images(images); - if (err != OK) { - *r_error = err; - return RES(); +Ref<Image> StreamTextureLayered::get_layer_data(int p_layer) const { + + if (texture.is_valid()) { + return RS::get_singleton()->texture_2d_layer_get(texture, p_layer); } else { + return Ref<Image>(); + } +} + +void StreamTextureLayered::reload_from_file() { + + String path = get_path(); + if (!path.is_resource_file()) + return; - if (r_error) - *r_error = OK; + path = ResourceLoader::path_remap(path); //remap for translation + path = ResourceLoader::import_remap(path); //remap for import + if (!path.is_resource_file()) + return; + + load(path); +} + +void StreamTextureLayered::_validate_property(PropertyInfo &property) const { +} + +void StreamTextureLayered::_bind_methods() { + + ClassDB::bind_method(D_METHOD("load", "path"), &StreamTextureLayered::load); + ClassDB::bind_method(D_METHOD("get_load_path"), &StreamTextureLayered::get_load_path); + + ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); +} + +StreamTextureLayered::StreamTextureLayered(LayeredType p_type) { + + layered_type = p_type; + format = Image::FORMAT_MAX; + w = 0; + h = 0; + layers = 0; + mipmaps = false; +} + +StreamTextureLayered::~StreamTextureLayered() { + + if (texture.is_valid()) { + RS::get_singleton()->free(texture); } +} - return lt; +///////////////////////////////////////////////// + +RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { + + Ref<StreamTextureLayered> st; + if (p_path.get_extension().to_lower() == "stexarray") { + Ref<StreamTexture2DArray> s; + s.instance(); + st = s; + } else if (p_path.get_extension().to_lower() == "scube") { + Ref<StreamCubemap> s; + s.instance(); + st = s; + } else if (p_path.get_extension().to_lower() == "scubearray") { + Ref<StreamCubemapArray> s; + s.instance(); + st = s; + } else { + if (r_error) { + *r_error = ERR_FILE_UNRECOGNIZED; + } + return RES(); + } + Error err = st->load(p_path); + if (r_error) + *r_error = err; + if (err != OK) + return RES(); + + return st; } -void ResourceFormatLoaderTextureLayered::get_recognized_extensions(List<String> *p_extensions) const { +void ResourceFormatLoaderStreamTextureLayered::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("cube"); - p_extensions->push_back("cubearr"); - p_extensions->push_back("tex2darr"); + p_extensions->push_back("stexarray"); + p_extensions->push_back("scube"); + p_extensions->push_back("scubearray"); } -bool ResourceFormatLoaderTextureLayered::handles_type(const String &p_type) const { - return p_type == "Texture2DArray" || p_type == "Cubemap" || p_type == "CubemapArray"; +bool ResourceFormatLoaderStreamTextureLayered::handles_type(const String &p_type) const { + return p_type == "StreamTexture2DArray" || p_type == "StreamCubemap" || p_type == "StreamCubemapArray"; } -String ResourceFormatLoaderTextureLayered::get_resource_type(const String &p_path) const { +String ResourceFormatLoaderStreamTextureLayered::get_resource_type(const String &p_path) const { - if (p_path.get_extension().to_lower() == "cube") - return "Cubemap"; - if (p_path.get_extension().to_lower() == "cubearr") - return "CubemapArray"; - if (p_path.get_extension().to_lower() == "tex2darr") - return "Texture2DArray"; + if (p_path.get_extension().to_lower() == "stexarray") + return "StreamTexture2DArray"; + if (p_path.get_extension().to_lower() == "scube") + return "StreamCubemap"; + if (p_path.get_extension().to_lower() == "scubearray") + return "StreamCubemapArray"; return ""; } diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 5d5f438eba..5d4131ec4c 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -132,9 +132,9 @@ public: ~ImageTexture(); }; -class StreamTexture : public Texture2D { +class StreamTexture2D : public Texture2D { - GDCLASS(StreamTexture, Texture2D); + GDCLASS(StreamTexture2D, Texture2D); public: enum DataFormat { @@ -181,8 +181,8 @@ protected: public: static Ref<Image> load_image_from_file(FileAccess *p_file, int p_size_limit); - typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture> &); - typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); + typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture2D> &); + typedef void (*TextureFormatRoughnessRequestCallback)(const Ref<StreamTexture2D> &, const String &p_normal_path, RS::TextureDetectRoughnessChannel p_roughness_channel); static TextureFormatRequestCallback request_3d_callback; static TextureFormatRoughnessRequestCallback request_roughness_callback; @@ -207,11 +207,11 @@ public: virtual Ref<Image> get_data() const; - StreamTexture(); - ~StreamTexture(); + StreamTexture2D(); + ~StreamTexture2D(); }; -class ResourceFormatLoaderStreamTexture : public ResourceFormatLoader { +class ResourceFormatLoaderStreamTexture2D : public ResourceFormatLoader { public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); virtual void get_recognized_extensions(List<String> *p_extensions) const; @@ -349,10 +349,34 @@ public: }; class TextureLayered : public Texture { - GDCLASS(TextureLayered, Texture); - RS::TextureLayeredType layered_type; +protected: + static void _bind_methods(); + +public: + enum LayeredType { + LAYERED_TYPE_2D_ARRAY, + LAYERED_TYPE_CUBEMAP, + LAYERED_TYPE_CUBEMAP_ARRAY + }; + + virtual Image::Format get_format() const = 0; + virtual LayeredType get_layered_type() const = 0; + virtual int get_width() const = 0; + virtual int get_height() const = 0; + virtual int get_layers() const = 0; + virtual bool has_mipmaps() const = 0; + virtual Ref<Image> get_layer_data(int p_layer) const = 0; +}; + +VARIANT_ENUM_CAST(TextureLayered::LayeredType) + +class ImageTextureLayered : public TextureLayered { + + GDCLASS(ImageTextureLayered, TextureLayered); + + LayeredType layered_type; mutable RID texture; Image::Format format; @@ -370,57 +394,137 @@ protected: static void _bind_methods(); public: - Image::Format get_format() const; - uint32_t get_width() const; - uint32_t get_height() const; - uint32_t get_layers() const; - bool has_mipmaps() const; + virtual Image::Format get_format() const; + virtual int get_width() const; + virtual int get_height() const; + virtual int get_layers() const; + virtual bool has_mipmaps() const; + virtual LayeredType get_layered_type() const; Error create_from_images(Vector<Ref<Image>> p_images); void update_layer(const Ref<Image> &p_image, int p_layer); - Ref<Image> get_layer_data(int p_layer) const; + virtual Ref<Image> get_layer_data(int p_layer) const; virtual RID get_rid() const; virtual void set_path(const String &p_path, bool p_take_over = false); - TextureLayered(RS::TextureLayeredType p_layered_type); - ~TextureLayered(); + ImageTextureLayered(LayeredType p_layered_type); + ~ImageTextureLayered(); }; -class Texture2DArray : public TextureLayered { +class Texture2DArray : public ImageTextureLayered { - GDCLASS(Texture2DArray, TextureLayered) + GDCLASS(Texture2DArray, ImageTextureLayered) public: Texture2DArray() : - TextureLayered(RS::TEXTURE_LAYERED_2D_ARRAY) {} + ImageTextureLayered(LAYERED_TYPE_2D_ARRAY) {} }; -class Cubemap : public TextureLayered { +class Cubemap : public ImageTextureLayered { - GDCLASS(Cubemap, TextureLayered); + GDCLASS(Cubemap, ImageTextureLayered); public: Cubemap() : - TextureLayered(RS::TEXTURE_LAYERED_CUBEMAP) {} + ImageTextureLayered(LAYERED_TYPE_CUBEMAP) {} }; -class CubemapArray : public TextureLayered { +class CubemapArray : public ImageTextureLayered { - GDCLASS(CubemapArray, TextureLayered); + GDCLASS(CubemapArray, ImageTextureLayered); public: CubemapArray() : - TextureLayered(RS::TEXTURE_LAYERED_CUBEMAP_ARRAY) {} + ImageTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} }; -class ResourceFormatLoaderTextureLayered : public ResourceFormatLoader { +class StreamTextureLayered : public TextureLayered { + + GDCLASS(StreamTextureLayered, TextureLayered); + public: - enum Compression { - COMPRESSION_LOSSLESS, - COMPRESSION_VRAM, - COMPRESSION_UNCOMPRESSED + enum DataFormat { + DATA_FORMAT_IMAGE, + DATA_FORMAT_LOSSLESS, + DATA_FORMAT_LOSSY, + DATA_FORMAT_BASIS_UNIVERSAL, + }; + + enum { + FORMAT_VERSION = 1 }; + enum FormatBits { + FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, + FORMAT_BIT_LOSSLESS = 1 << 20, + FORMAT_BIT_LOSSY = 1 << 21, + FORMAT_BIT_STREAM = 1 << 22, + FORMAT_BIT_HAS_MIPMAPS = 1 << 23, + }; + +private: + Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0); + String path_to_file; + mutable RID texture; + Image::Format format; + int w, h, layers; + bool mipmaps; + LayeredType layered_type; + + virtual void reload_from_file(); + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + Image::Format get_format() const; + Error load(const String &p_path); + String get_load_path() const; + virtual LayeredType get_layered_type() const; + + int get_width() const; + int get_height() const; + int get_layers() const; + virtual bool has_mipmaps() const; + virtual RID get_rid() const; + + virtual void set_path(const String &p_path, bool p_take_over); + + virtual Ref<Image> get_layer_data(int p_layer) const; + + StreamTextureLayered(LayeredType p_layered_type); + ~StreamTextureLayered(); +}; + +class StreamTexture2DArray : public StreamTextureLayered { + + GDCLASS(StreamTexture2DArray, StreamTextureLayered) +public: + StreamTexture2DArray() : + StreamTextureLayered(LAYERED_TYPE_2D_ARRAY) {} +}; + +class StreamCubemap : public StreamTextureLayered { + + GDCLASS(StreamCubemap, StreamTextureLayered); + +public: + StreamCubemap() : + StreamTextureLayered(LAYERED_TYPE_CUBEMAP) {} +}; + +class StreamCubemapArray : public StreamTextureLayered { + + GDCLASS(StreamCubemapArray, StreamTextureLayered); + +public: + StreamCubemapArray() : + StreamTextureLayered(LAYERED_TYPE_CUBEMAP_ARRAY) {} +}; + +class ResourceFormatLoaderStreamTextureLayered : public ResourceFormatLoader { +public: virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; |