/*************************************************************************/ /* texture.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "texture.h" #include "core/os/os.h" #include "io/image_loader.h" Size2 Texture::get_size() const { return Size2(get_width(), get_height()); } void Texture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, get_size()), get_rid(), false, p_modulate, p_transpose); } void Texture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, get_rid(), p_tile, p_modulate, p_transpose); } void Texture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) const { VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, get_rid(), p_src_rect, p_modulate, p_transpose); } bool Texture::get_rect_region_uv_rect(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_uv_rect) const { Size2 size = get_size(); if (size.width == 0 || size.height == 0) return false; r_rect = p_rect; r_uv_rect = Rect2(p_src_rect.get_pos() / size, p_src_rect.get_size() / size); return true; } void Texture::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_width"), &Texture::get_width); ObjectTypeDB::bind_method(_MD("get_height"), &Texture::get_height); ObjectTypeDB::bind_method(_MD("get_size"), &Texture::get_size); ObjectTypeDB::bind_method(_MD("get_rid"), &Texture::get_rid); ObjectTypeDB::bind_method(_MD("has_alpha"), &Texture::has_alpha); ObjectTypeDB::bind_method(_MD("set_flags", "flags"), &Texture::set_flags); ObjectTypeDB::bind_method(_MD("get_flags"), &Texture::get_flags); ObjectTypeDB::bind_method(_MD("draw", "canvas_item", "pos", "modulate", "transpose"), &Texture::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); ObjectTypeDB::bind_method(_MD("draw_rect", "canvas_item", "rect", "tile", "modulate", "transpose"), &Texture::draw_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); ObjectTypeDB::bind_method(_MD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false)); BIND_CONSTANT(FLAG_MIPMAPS); BIND_CONSTANT(FLAG_REPEAT); BIND_CONSTANT(FLAG_FILTER); BIND_CONSTANT(FLAG_VIDEO_SURFACE); BIND_CONSTANT(FLAGS_DEFAULT); BIND_CONSTANT(FLAG_ANISOTROPIC_FILTER); BIND_CONSTANT(FLAG_CONVERT_TO_LINEAR); BIND_CONSTANT(FLAG_MIRRORED_REPEAT); } Texture::Texture() { } ///////////////////// void ImageTexture::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) return; uint32_t flags = get_flags(); Image img; Error err = ImageLoader::load_image(path, &img); ERR_FAIL_COND(err != OK); create_from_image(img, flags); } bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "image" && p_value.get_type() == Variant::IMAGE) create_from_image(p_value, flags); else if (p_name == "flags") if (w * h == 0) flags = p_value; else set_flags(p_value); else if (p_name == "size") { Size2 s = p_value; w = s.width; h = s.height; VisualServer::get_singleton()->texture_set_size_override(texture, w, h); } else if (p_name == "storage") { storage = Storage(p_value.operator int()); } else if (p_name == "lossy_quality") { lossy_storage_quality = p_value; } else if (p_name == "_data") { _set_data(p_value); } else return false; return true; } bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "image_data") { } else if (p_name == "image") r_ret = get_data(); else if (p_name == "flags") r_ret = flags; else if (p_name == "size") r_ret = Size2(w, h); else if (p_name == "storage") r_ret = storage; else if (p_name == "lossy_quality") r_ret = lossy_storage_quality; else return false; return true; } void ImageTexture::_get_property_list(List *p_list) const { PropertyHint img_hint = PROPERTY_HINT_NONE; if (storage == STORAGE_COMPRESS_LOSSY) { img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY; } else if (storage == STORAGE_COMPRESS_LOSSLESS) { img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS; } p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat")); p_list->push_back(PropertyInfo(Variant::IMAGE, "image", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless")); p_list->push_back(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); } void ImageTexture::_reload_hook(const RID &p_hook) { String path = get_path(); if (!path.is_resource_file()) return; Image img; Error err = ImageLoader::load_image(path, &img); ERR_FAIL_COND(err != OK); VisualServer::get_singleton()->texture_set_data(texture, img); _change_notify(); } void ImageTexture::create(int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { flags = p_flags; VisualServer::get_singleton()->texture_allocate(texture, p_width, p_height, p_format, p_flags); format = p_format; w = p_width; h = p_height; } void ImageTexture::create_from_image(const Image &p_image, uint32_t p_flags) { ERR_FAIL_COND(p_image.empty()); flags = p_flags; w = p_image.get_width(); h = p_image.get_height(); format = p_image.get_format(); VisualServer::get_singleton()->texture_allocate(texture, p_image.get_width(), p_image.get_height(), p_image.get_format(), p_flags); VisualServer::get_singleton()->texture_set_data(texture, p_image); _change_notify(); } void ImageTexture::set_flags(uint32_t p_flags) { /* uint32_t cube = flags & FLAG_CUBEMAP; if (flags == p_flags&cube) return; flags=p_flags|cube; */ flags = p_flags; VisualServer::get_singleton()->texture_set_flags(texture, p_flags); } uint32_t ImageTexture::get_flags() const { return ImageTexture::flags; } Image::Format ImageTexture::get_format() const { return format; } void ImageTexture::load(const String &p_path) { Image img; img.load(p_path); create_from_image(img); } void ImageTexture::set_data(const Image &p_image) { VisualServer::get_singleton()->texture_set_data(texture, p_image); VisualServer::get_singleton()->texture_set_reload_hook(texture, 0, StringName()); //hook is erased if data is changed _change_notify(); } void ImageTexture::_resource_path_changed() { String path = get_path(); if (VS::get_singleton()->has_feature(VS::FEATURE_NEEDS_RELOAD_HOOK)) { //this needs to be done much better, but probably will end up being deprecated as technology advances if (path.is_resource_file() && ImageLoader::recognize(path.extension())) { //hook is set only if path is hookable VisualServer::get_singleton()->texture_set_reload_hook(texture, get_instance_ID(), "_reload_hook"); } else { VisualServer::get_singleton()->texture_set_reload_hook(texture, 0, StringName()); } } } Image ImageTexture::get_data() const { return VisualServer::get_singleton()->texture_get_data(texture); } int ImageTexture::get_width() const { return w; } int ImageTexture::get_height() const { return h; } RID ImageTexture::get_rid() const { return texture; } void ImageTexture::fix_alpha_edges() { if (format == Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) { Image img = get_data(); img.fix_alpha_edges(); set_data(img); } } void ImageTexture::premultiply_alpha() { if (format == Image::FORMAT_RGBA /*&& !(flags&FLAG_CUBEMAP)*/) { Image img = get_data(); img.premultiply_alpha(); set_data(img); } } void ImageTexture::normal_to_xy() { Image img = get_data(); img.normalmap_to_xy(); create_from_image(img, flags); } void ImageTexture::shrink_x2_and_keep_size() { Size2 sizeov = get_size(); Image img = get_data(); img.resize(img.get_width() / 2, img.get_height() / 2, Image::INTERPOLATE_BILINEAR); create_from_image(img, flags); set_size_override(sizeov); } bool ImageTexture::has_alpha() const { return (format == Image::FORMAT_GRAYSCALE_ALPHA || format == Image::FORMAT_INDEXED_ALPHA || format == Image::FORMAT_RGBA); } void ImageTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) return; VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, Rect2(p_pos, Size2(w, h)), texture, false, p_modulate, p_transpose); } void ImageTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) return; VisualServer::get_singleton()->canvas_item_add_texture_rect(p_canvas_item, p_rect, texture, p_tile, p_modulate, p_transpose); } void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) const { if ((w | h) == 0) return; VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, p_rect, texture, p_src_rect, p_modulate, p_transpose); } void ImageTexture::set_size_override(const Size2 &p_size) { Size2 s = p_size; if (s.x != 0) w = s.x; if (s.y != 0) h = s.y; VisualServer::get_singleton()->texture_set_size_override(texture, w, h); } void ImageTexture::set_path(const String &p_path, bool p_take_over) { if (texture.is_valid()) { VisualServer::get_singleton()->texture_set_path(texture, p_path); } Resource::set_path(p_path, p_take_over); } void ImageTexture::set_storage(Storage p_storage) { storage = p_storage; } ImageTexture::Storage ImageTexture::get_storage() const { return storage; } void ImageTexture::set_lossy_storage_quality(float p_lossy_storage_quality) { lossy_storage_quality = p_lossy_storage_quality; } float ImageTexture::get_lossy_storage_quality() const { return lossy_storage_quality; } void ImageTexture::_set_data(Dictionary p_data) { Image img = p_data["image"]; uint32_t flags = p_data["flags"]; create_from_image(img, flags); set_storage(Storage(p_data["storage"].operator int())); set_lossy_storage_quality(p_data["lossy_quality"]); set_size_override(p_data["size"]); }; void ImageTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("create", "width", "height", "format", "flags"), &ImageTexture::create, DEFVAL(FLAGS_DEFAULT)); ObjectTypeDB::bind_method(_MD("create_from_image", "image", "flags"), &ImageTexture::create_from_image, DEFVAL(FLAGS_DEFAULT)); ObjectTypeDB::bind_method(_MD("get_format"), &ImageTexture::get_format); ObjectTypeDB::bind_method(_MD("load", "path"), &ImageTexture::load); ObjectTypeDB::bind_method(_MD("set_data", "image"), &ImageTexture::set_data); ObjectTypeDB::bind_method(_MD("get_data", "cube_side"), &ImageTexture::get_data); ObjectTypeDB::bind_method(_MD("set_storage", "mode"), &ImageTexture::set_storage); ObjectTypeDB::bind_method(_MD("get_storage"), &ImageTexture::get_storage); ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality", "quality"), &ImageTexture::set_lossy_storage_quality); ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"), &ImageTexture::get_lossy_storage_quality); ObjectTypeDB::bind_method(_MD("fix_alpha_edges"), &ImageTexture::fix_alpha_edges); ObjectTypeDB::bind_method(_MD("premultiply_alpha"), &ImageTexture::premultiply_alpha); ObjectTypeDB::bind_method(_MD("normal_to_xy"), &ImageTexture::normal_to_xy); ObjectTypeDB::bind_method(_MD("shrink_x2_and_keep_size"), &ImageTexture::shrink_x2_and_keep_size); ObjectTypeDB::bind_method(_MD("set_size_override", "size"), &ImageTexture::set_size_override); ObjectTypeDB::set_method_flags(get_type_static(), _SCS("fix_alpha_edges"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ObjectTypeDB::set_method_flags(get_type_static(), _SCS("premultiply_alpha"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ObjectTypeDB::set_method_flags(get_type_static(), _SCS("normal_to_xy"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ObjectTypeDB::set_method_flags(get_type_static(), _SCS("shrink_x2_and_keep_size"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ObjectTypeDB::bind_method(_MD("_reload_hook", "rid"), &ImageTexture::_reload_hook); BIND_CONSTANT(STORAGE_RAW); BIND_CONSTANT(STORAGE_COMPRESS_LOSSY); BIND_CONSTANT(STORAGE_COMPRESS_LOSSLESS); } ImageTexture::ImageTexture() { w = h = 0; flags = FLAGS_DEFAULT; texture = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; } ImageTexture::~ImageTexture() { VisualServer::get_singleton()->free(texture); } ////////////////////////////////////////// int AtlasTexture::get_width() const { if (region.size.width == 0) { if (atlas.is_valid()) return atlas->get_width(); return 1; } else { return region.size.width + margin.size.width; } } int AtlasTexture::get_height() const { if (region.size.height == 0) { if (atlas.is_valid()) return atlas->get_height(); return 1; } else { return region.size.height + margin.size.height; } } RID AtlasTexture::get_rid() const { if (atlas.is_valid()) return atlas->get_rid(); return RID(); } bool AtlasTexture::has_alpha() const { if (atlas.is_valid()) return atlas->has_alpha(); return false; } void AtlasTexture::set_flags(uint32_t p_flags) { if (atlas.is_valid()) atlas->set_flags(p_flags); } uint32_t AtlasTexture::get_flags() const { if (atlas.is_valid()) return atlas->get_flags(); return 0; } void AtlasTexture::set_atlas(const Ref &p_atlas) { if (atlas == p_atlas) return; atlas = p_atlas; emit_changed(); emit_signal("atlas_changed"); } Ref AtlasTexture::get_atlas() const { return atlas; } void AtlasTexture::set_region(const Rect2 &p_region) { region = p_region; emit_changed(); } Rect2 AtlasTexture::get_region() const { return region; } void AtlasTexture::set_margin(const Rect2 &p_margin) { margin = p_margin; emit_changed(); } Rect2 AtlasTexture::get_margin() const { return margin; } void AtlasTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_atlas", "atlas:Texture"), &AtlasTexture::set_atlas); ObjectTypeDB::bind_method(_MD("get_atlas:Texture"), &AtlasTexture::get_atlas); ObjectTypeDB::bind_method(_MD("set_region", "region"), &AtlasTexture::set_region); ObjectTypeDB::bind_method(_MD("get_region"), &AtlasTexture::get_region); ObjectTypeDB::bind_method(_MD("set_margin", "margin"), &AtlasTexture::set_margin); ObjectTypeDB::bind_method(_MD("get_margin"), &AtlasTexture::get_margin); ADD_SIGNAL(MethodInfo("atlas_changed")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_atlas"), _SCS("get_atlas")); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), _SCS("set_region"), _SCS("get_region")); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), _SCS("set_margin"), _SCS("get_margin")); } void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { Rect2 rc = region; if (!atlas.is_valid()) return; if (rc.size.width == 0) { rc.size.width = atlas->get_width(); } if (rc.size.height == 0) { rc.size.height = atlas->get_height(); } VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.pos, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose); } void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { Rect2 rc = region; if (!atlas.is_valid()) return; if (rc.size.width == 0) { rc.size.width = atlas->get_width(); } if (rc.size.height == 0) { rc.size.height = atlas->get_height(); } Vector2 scale = p_rect.size / (region.size + margin.size); Rect2 dr(p_rect.pos + margin.pos * scale, rc.size * scale); VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose); } void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) const { //this might not necesarily work well if using a rect, needs to be fixed properly Rect2 rc = region; if (!atlas.is_valid()) return; Rect2 src = p_src_rect; src.pos += (rc.pos - margin.pos); Rect2 src_c = rc.clip(src); if (src_c.size == Size2()) return; Vector2 ofs = (src_c.pos - src.pos); Vector2 scale = p_rect.size / p_src_rect.size; if (scale.x < 0) { float mx = (margin.size.width - margin.pos.x); mx -= margin.pos.x; ofs.x = -(ofs.x + mx); } if (scale.y < 0) { float my = margin.size.height - margin.pos.y; my -= margin.pos.y; ofs.y = -(ofs.y + my); } Rect2 dr(p_rect.pos + ofs * scale, src_c.size * scale); VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose); } bool AtlasTexture::get_rect_region_uv_rect(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_uv_rect) const { Rect2 rc = region; if (!atlas.is_valid()) return false; Size2 atlas_size = atlas->get_size(); if (atlas_size.width == 0 || atlas_size.height == 0) return false; Rect2 src = p_src_rect; src.pos += (rc.pos - margin.pos); Rect2 src_c = rc.clip(src); if (src_c.size == Size2()) return false; Vector2 ofs = (src_c.pos - src.pos); Vector2 scale = p_rect.size / p_src_rect.size; if (scale.x < 0) { float mx = (margin.size.width - margin.pos.x); mx -= margin.pos.x; ofs.x = -(ofs.x + mx); } if (scale.y < 0) { float my = margin.size.height - margin.pos.y; my -= margin.pos.y; ofs.y = -(ofs.y + my); } Rect2 dr(p_rect.pos + ofs * scale, src_c.size * scale); r_rect = dr; r_uv_rect = Rect2(src_c.get_pos() / atlas_size, src_c.get_size() / atlas_size); return true; } AtlasTexture::AtlasTexture() { } ////////////////////////////////////////// int LargeTexture::get_width() const { return size.width; } int LargeTexture::get_height() const { return size.height; } RID LargeTexture::get_rid() const { return RID(); } bool LargeTexture::has_alpha() const { for (int i = 0; i < pieces.size(); i++) { if (pieces[i].texture->has_alpha()) return true; } return false; } void LargeTexture::set_flags(uint32_t p_flags) { for (int i = 0; i < pieces.size(); i++) { pieces[i].texture->set_flags(p_flags); } } uint32_t LargeTexture::get_flags() const { if (pieces.size()) return pieces[0].texture->get_flags(); return 0; } int LargeTexture::add_piece(const Point2 &p_offset, const Ref &p_texture) { ERR_FAIL_COND_V(p_texture.is_null(), -1); Piece p; p.offset = p_offset; p.texture = p_texture; pieces.push_back(p); return pieces.size() - 1; } void LargeTexture::set_piece_offset(int p_idx, const Point2 &p_offset) { ERR_FAIL_INDEX(p_idx, pieces.size()); pieces[p_idx].offset = p_offset; }; void LargeTexture::set_piece_texture(int p_idx, const Ref &p_texture) { ERR_FAIL_INDEX(p_idx, pieces.size()); pieces[p_idx].texture = p_texture; }; void LargeTexture::set_size(const Size2 &p_size) { size = p_size; } void LargeTexture::clear() { pieces.clear(); size = Size2i(); } Array LargeTexture::_get_data() const { Array arr; for (int i = 0; i < pieces.size(); i++) { arr.push_back(pieces[i].offset); arr.push_back(pieces[i].texture); } arr.push_back(Size2(size)); return arr; } void LargeTexture::_set_data(const Array &p_array) { ERR_FAIL_COND(p_array.size() < 1); ERR_FAIL_COND(!(p_array.size() & 1)); clear(); for (int i = 0; i < p_array.size() - 1; i += 2) { add_piece(p_array[i], p_array[i + 1]); } size = Size2(p_array[p_array.size() - 1]); } int LargeTexture::get_piece_count() const { return pieces.size(); } Vector2 LargeTexture::get_piece_offset(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, pieces.size(), Vector2()); return pieces[p_idx].offset; } Ref LargeTexture::get_piece_texture(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, pieces.size(), Ref()); return pieces[p_idx].texture; } void LargeTexture::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_piece", "ofs", "texture:Texture"), &LargeTexture::add_piece); ObjectTypeDB::bind_method(_MD("set_piece_offset", "idx", "ofs"), &LargeTexture::set_piece_offset); ObjectTypeDB::bind_method(_MD("set_piece_texture", "idx", "texture:Texture"), &LargeTexture::set_piece_texture); ObjectTypeDB::bind_method(_MD("set_size", "size"), &LargeTexture::set_size); ObjectTypeDB::bind_method(_MD("clear"), &LargeTexture::clear); ObjectTypeDB::bind_method(_MD("get_piece_count"), &LargeTexture::get_piece_count); ObjectTypeDB::bind_method(_MD("get_piece_offset", "idx"), &LargeTexture::get_piece_offset); ObjectTypeDB::bind_method(_MD("get_piece_texture:Texture", "idx"), &LargeTexture::get_piece_texture); ObjectTypeDB::bind_method(_MD("_set_data", "data"), &LargeTexture::_set_data); ObjectTypeDB::bind_method(_MD("_get_data"), &LargeTexture::_get_data); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"), _SCS("_get_data")); } void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose) const { for (int i = 0; i < pieces.size(); i++) { // TODO pieces[i].texture->draw(p_canvas_item, pieces[i].offset + p_pos, p_modulate, p_transpose); } } void LargeTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) const { //tiling not supported for this if (size.x == 0 || size.y == 0) return; Size2 scale = p_rect.size / size; for (int i = 0; i < pieces.size(); i++) { // TODO pieces[i].texture->draw_rect(p_canvas_item, Rect2(pieces[i].offset * scale + p_rect.pos, pieces[i].texture->get_size() * scale), false, p_modulate, p_transpose); } } void LargeTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) const { //tiling not supported for this if (p_src_rect.size.x == 0 || p_src_rect.size.y == 0) return; Size2 scale = p_rect.size / p_src_rect.size; for (int i = 0; i < pieces.size(); i++) { // TODO Rect2 rect(pieces[i].offset, pieces[i].texture->get_size()); if (!p_src_rect.intersects(rect)) continue; Rect2 local = p_src_rect.clip(rect); Rect2 target = local; target.size *= scale; target.pos = p_rect.pos + (p_src_rect.pos + rect.pos) * scale; local.pos -= rect.pos; pieces[i].texture->draw_rect_region(p_canvas_item, target, local, p_modulate, p_transpose); } } LargeTexture::LargeTexture() { } /////////////////////////////////////////////// void CubeMap::set_flags(uint32_t p_flags) { flags = p_flags; if (_is_valid()) VS::get_singleton()->texture_set_flags(cubemap, flags | VS::TEXTURE_FLAG_CUBEMAP); } uint32_t CubeMap::get_flags() const { return flags; } void CubeMap::set_side(Side p_side, const Image &p_image) { ERR_FAIL_COND(p_image.empty()); ERR_FAIL_INDEX(p_side, 6); if (!_is_valid()) { format = p_image.get_format(); w = p_image.get_width(); h = p_image.get_height(); VS::get_singleton()->texture_allocate(cubemap, w, h, p_image.get_format(), flags | VS::TEXTURE_FLAG_CUBEMAP); } VS::get_singleton()->texture_set_data(cubemap, p_image, VS::CubeMapSide(p_side)); valid[p_side] = true; } Image CubeMap::get_side(Side p_side) const { if (!valid[p_side]) return Image(); return VS::get_singleton()->texture_get_data(cubemap, VS::CubeMapSide(p_side)); } Image::Format CubeMap::get_format() const { return format; } int CubeMap::get_width() const { return w; } int CubeMap::get_height() const { return h; } RID CubeMap::get_rid() const { return cubemap; } void CubeMap::set_storage(Storage p_storage) { storage = p_storage; } CubeMap::Storage CubeMap::get_storage() const { return storage; } void CubeMap::set_lossy_storage_quality(float p_lossy_storage_quality) { lossy_storage_quality = p_lossy_storage_quality; } float CubeMap::get_lossy_storage_quality() const { return lossy_storage_quality; } void CubeMap::set_path(const String &p_path, bool p_take_over) { if (cubemap.is_valid()) { VisualServer::get_singleton()->texture_set_path(cubemap, p_path); } Resource::set_path(p_path, p_take_over); } bool CubeMap::_set(const StringName &p_name, const Variant &p_value) { if (p_name == "side/left") { set_side(SIDE_LEFT, p_value); } else if (p_name == "side/right") { set_side(SIDE_RIGHT, p_value); } else if (p_name == "side/bottom") { set_side(SIDE_BOTTOM, p_value); } else if (p_name == "side/top") { set_side(SIDE_TOP, p_value); } else if (p_name == "side/front") { set_side(SIDE_FRONT, p_value); } else if (p_name == "side/back") { set_side(SIDE_BACK, p_value); } else if (p_name == "flags") { set_flags(p_value); } else if (p_name == "storage") { storage = Storage(p_value.operator int()); } else if (p_name == "lossy_quality") { lossy_storage_quality = p_value; } else return false; return true; } bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "side/left") { r_ret = get_side(SIDE_LEFT); } else if (p_name == "side/right") { r_ret = get_side(SIDE_RIGHT); } else if (p_name == "side/bottom") { r_ret = get_side(SIDE_BOTTOM); } else if (p_name == "side/top") { r_ret = get_side(SIDE_TOP); } else if (p_name == "side/front") { r_ret = get_side(SIDE_FRONT); } else if (p_name == "side/back") { r_ret = get_side(SIDE_BACK); } else if (p_name == "flags") { r_ret = flags; } else if (p_name == "storage") { r_ret = storage; } else if (p_name == "lossy_quality") { r_ret = lossy_storage_quality; } else return false; return true; } void CubeMap::_get_property_list(List *p_list) const { PropertyHint img_hint = PROPERTY_HINT_NONE; if (storage == STORAGE_COMPRESS_LOSSY) { img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSY; } else if (storage == STORAGE_COMPRESS_LOSSLESS) { img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS; } p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter")); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/left", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/right", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/bottom", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/top", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/front", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::IMAGE, "side/back", img_hint, String::num(lossy_storage_quality))); p_list->push_back(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless", PROPERTY_USAGE_EDITOR)); p_list->push_back(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); } void CubeMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_width"), &CubeMap::get_width); ObjectTypeDB::bind_method(_MD("get_height"), &CubeMap::get_height); ObjectTypeDB::bind_method(_MD("get_rid"), &CubeMap::get_rid); ObjectTypeDB::bind_method(_MD("set_flags", "flags"), &CubeMap::set_flags); ObjectTypeDB::bind_method(_MD("get_flags"), &CubeMap::get_flags); ObjectTypeDB::bind_method(_MD("set_side", "side", "image"), &CubeMap::set_side); ObjectTypeDB::bind_method(_MD("get_side", "side"), &CubeMap::get_side); ObjectTypeDB::bind_method(_MD("set_storage", "mode"), &CubeMap::set_storage); ObjectTypeDB::bind_method(_MD("get_storage"), &CubeMap::get_storage); ObjectTypeDB::bind_method(_MD("set_lossy_storage_quality", "quality"), &CubeMap::set_lossy_storage_quality); ObjectTypeDB::bind_method(_MD("get_lossy_storage_quality"), &CubeMap::get_lossy_storage_quality); BIND_CONSTANT(STORAGE_RAW); BIND_CONSTANT(STORAGE_COMPRESS_LOSSY); BIND_CONSTANT(STORAGE_COMPRESS_LOSSLESS); BIND_CONSTANT(SIDE_LEFT); BIND_CONSTANT(SIDE_RIGHT); BIND_CONSTANT(SIDE_BOTTOM); BIND_CONSTANT(SIDE_TOP); BIND_CONSTANT(SIDE_FRONT); BIND_CONSTANT(SIDE_BACK); BIND_CONSTANT(FLAG_MIPMAPS); BIND_CONSTANT(FLAG_REPEAT); BIND_CONSTANT(FLAG_FILTER); BIND_CONSTANT(FLAGS_DEFAULT); } CubeMap::CubeMap() { w = h = 0; flags = FLAGS_DEFAULT; for (int i = 0; i < 6; i++) valid[i] = false; cubemap = VisualServer::get_singleton()->texture_create(); storage = STORAGE_RAW; lossy_storage_quality = 0.7; } CubeMap::~CubeMap() { VisualServer::get_singleton()->free(cubemap); } /* BIND_CONSTANT( FLAG_CUBEMAP ); BIND_CONSTANT( CUBEMAP_LEFT ); BIND_CONSTANT( CUBEMAP_RIGHT ); BIND_CONSTANT( CUBEMAP_BOTTOM ); BIND_CONSTANT( CUBEMAP_TOP ); BIND_CONSTANT( CUBEMAP_FRONT ); BIND_CONSTANT( CUBEMAP_BACK ); */