diff options
Diffstat (limited to 'scene')
42 files changed, 1746 insertions, 1297 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 3d9e64ae79..cef473dcdf 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -61,7 +61,7 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { - target[j] = buffer[j] * vol; + target[j] += buffer[j] * vol; vol += vol_inc; } @@ -76,8 +76,8 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { AudioFrame frame = buffer[j] * vol; - targets[0][j] = frame; - targets[1][j] = frame; + targets[0][j] += frame; + targets[1][j] += frame; vol += vol_inc; } @@ -93,9 +93,9 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { AudioFrame frame = buffer[j] * vol; - targets[0][j] = frame; - targets[1][j] = frame; - targets[2][j] = frame; + targets[0][j] += frame; + targets[1][j] += frame; + targets[2][j] += frame; vol += vol_inc; } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 89b89a50d8..4a80aba355 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "canvas_item.h" -#include "core/method_bind_ext.inc" +#include "core/method_bind_ext.gen.inc" #include "message_queue.h" #include "os/input.h" #include "scene/main/canvas_layer.h" @@ -39,6 +39,196 @@ #include "scene/scene_string_names.h" #include "servers/visual_server.h" +Mutex *CanvasItemMaterial::material_mutex = NULL; +SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials; +Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map; + +void CanvasItemMaterial::init_shaders() { + +#ifndef NO_THREADS + material_mutex = Mutex::create(); +#endif +} + +void CanvasItemMaterial::finish_shaders() { + +#ifndef NO_THREADS + memdelete(material_mutex); +#endif +} + +void CanvasItemMaterial::_update_shader() { + + dirty_materials.remove(&element); + + MaterialKey mk = _compute_key(); + if (mk.key == current_key.key) + return; //no update required in the end + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + } + + current_key = mk; + + if (shader_map.has(mk)) { + + VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader); + shader_map[mk].users++; + return; + } + + //must create a shader! + + String code = "shader_type canvas_item;\nrender_mode "; + switch (blend_mode) { + case BLEND_MODE_MIX: code += "blend_mix"; break; + case BLEND_MODE_ADD: code += "blend_add"; break; + case BLEND_MODE_SUB: code += "blend_sub"; break; + case BLEND_MODE_MUL: code += "blend_mul"; break; + case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break; + } + + switch (light_mode) { + case LIGHT_MODE_NORMAL: break; + case LIGHT_MODE_UNSHADED: code += ",unshaded"; break; + case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break; + } + code += ";\n"; //thats it. + + ShaderData shader_data; + shader_data.shader = VS::get_singleton()->shader_create(); + shader_data.users = 1; + + VS::get_singleton()->shader_set_code(shader_data.shader, code); + + shader_map[mk] = shader_data; + + VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader); +} + +void CanvasItemMaterial::flush_changes() { + + if (material_mutex) + material_mutex->lock(); + + while (dirty_materials.first()) { + + dirty_materials.first()->self()->_update_shader(); + } + + if (material_mutex) + material_mutex->unlock(); +} + +void CanvasItemMaterial::_queue_shader_change() { + + if (material_mutex) + material_mutex->lock(); + + if (!element.in_list()) { + dirty_materials.add(&element); + } + + if (material_mutex) + material_mutex->unlock(); +} + +bool CanvasItemMaterial::_is_shader_dirty() const { + + bool dirty = false; + + if (material_mutex) + material_mutex->lock(); + + dirty = element.in_list(); + + if (material_mutex) + material_mutex->unlock(); + + return dirty; +} +void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) { + + blend_mode = p_blend_mode; + _queue_shader_change(); +} + +CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const { + return blend_mode; +} + +void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) { + + light_mode = p_light_mode; + _queue_shader_change(); +} + +CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const { + + return light_mode; +} + +void CanvasItemMaterial::_validate_property(PropertyInfo &property) const { +} + +void CanvasItemMaterial::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode); + ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode); + + ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode); + ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode"); + + BIND_CONSTANT(BLEND_MODE_MIX); + BIND_CONSTANT(BLEND_MODE_ADD); + BIND_CONSTANT(BLEND_MODE_SUB); + BIND_CONSTANT(BLEND_MODE_MUL); + BIND_CONSTANT(BLEND_MODE_PREMULT_ALPHA); + BIND_CONSTANT(LIGHT_MODE_NORMAL); + BIND_CONSTANT(LIGHT_MODE_UNSHADED); + BIND_CONSTANT(LIGHT_MODE_LIGHT_ONLY); +} + +CanvasItemMaterial::CanvasItemMaterial() + : element(this) { + + blend_mode = BLEND_MODE_MIX; + light_mode = LIGHT_MODE_NORMAL; + + current_key.key = 0; + current_key.invalid_key = 1; + _queue_shader_change(); +} + +CanvasItemMaterial::~CanvasItemMaterial() { + + if (material_mutex) + material_mutex->lock(); + + if (shader_map.has(current_key)) { + shader_map[current_key].users--; + if (shader_map[current_key].users == 0) { + //deallocate shader, as it's no longer in use + VS::get_singleton()->free(shader_map[current_key].shader); + shader_map.erase(current_key); + } + + VS::get_singleton()->material_set_shader(_get_material(), RID()); + } + + if (material_mutex) + material_mutex->unlock(); +} + /////////////////////////////////////////////////////////////////// bool CanvasItem::is_visible_in_tree() const { @@ -177,7 +367,9 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const { } Transform2D CanvasItem::get_global_transform() const { - +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_V(!is_inside_tree(), get_transform()); +#endif if (global_invalid) { const CanvasItem *pi = get_parent_item(); @@ -575,8 +767,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const void CanvasItem::_notify_transform(CanvasItem *p_node) { - if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) + if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) { return; //nothing to do + } p_node->global_invalid = true; @@ -665,7 +858,7 @@ bool CanvasItem::is_draw_behind_parent_enabled() const { return behind; } -void CanvasItem::set_material(const Ref<ShaderMaterial> &p_material) { +void CanvasItem::set_material(const Ref<Material> &p_material) { material = p_material; RID rid; @@ -686,7 +879,7 @@ bool CanvasItem::get_use_parent_material() const { return use_parent_material; } -Ref<ShaderMaterial> CanvasItem::get_material() const { +Ref<Material> CanvasItem::get_material() const { return material; } @@ -788,8 +981,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d); //ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport); - ClassDB::bind_method(D_METHOD("set_material", "material:ShaderMaterial"), &CanvasItem::set_material); - ClassDB::bind_method(D_METHOD("get_material:ShaderMaterial"), &CanvasItem::get_material); + ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &CanvasItem::set_material); + ClassDB::bind_method(D_METHOD("get_material:Material"), &CanvasItem::get_material); ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material); ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material); @@ -815,7 +1008,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); ADD_GROUP("Material", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material"); //exporting these two things doesn't really make much sense i think //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ; @@ -877,7 +1070,15 @@ bool CanvasItem::is_local_transform_notification_enabled() const { } void CanvasItem::set_notify_transform(bool p_enable) { + if (notify_transform == p_enable) + return; + notify_transform = p_enable; + + if (notify_transform && is_inside_tree()) { + //this ensures that invalid globals get resolved, so notifications can be received + get_global_transform(); + } } bool CanvasItem::is_transform_notification_enabled() const { diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 906a08d219..bffc171fc1 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -42,6 +42,92 @@ class Font; class StyleBox; +class CanvasItemMaterial : public Material { + + GDCLASS(CanvasItemMaterial, Material) + +public: + enum BlendMode { + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_PREMULT_ALPHA + }; + + enum LightMode { + LIGHT_MODE_NORMAL, + LIGHT_MODE_UNSHADED, + LIGHT_MODE_LIGHT_ONLY + }; + +private: + union MaterialKey { + + struct { + uint32_t blend_mode : 4; + uint32_t light_mode : 4; + uint32_t invalid_key : 1; + }; + + uint32_t key; + + bool operator<(const MaterialKey &p_key) const { + return key < p_key.key; + } + }; + + struct ShaderData { + RID shader; + int users; + }; + + static Map<MaterialKey, ShaderData> shader_map; + + MaterialKey current_key; + + _FORCE_INLINE_ MaterialKey _compute_key() const { + + MaterialKey mk; + mk.key = 0; + mk.blend_mode = blend_mode; + mk.light_mode = light_mode; + return mk; + } + + static Mutex *material_mutex; + static SelfList<CanvasItemMaterial>::List dirty_materials; + SelfList<CanvasItemMaterial> element; + + void _update_shader(); + _FORCE_INLINE_ void _queue_shader_change(); + _FORCE_INLINE_ bool _is_shader_dirty() const; + + BlendMode blend_mode; + LightMode light_mode; + +protected: + static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; + +public: + void set_blend_mode(BlendMode p_blend_mode); + BlendMode get_blend_mode() const; + + void set_light_mode(LightMode p_light_mode); + LightMode get_light_mode() const; + + static void init_shaders(); + static void finish_shaders(); + static void flush_changes(); + + CanvasItemMaterial(); + virtual ~CanvasItemMaterial(); +}; + +VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode) +VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode) + class CanvasItem : public Node { GDCLASS(CanvasItem, Node); @@ -83,7 +169,7 @@ private: bool notify_local_transform; bool notify_transform; - Ref<ShaderMaterial> material; + Ref<Material> material; mutable Transform2D global_transform; mutable bool global_invalid; @@ -203,8 +289,8 @@ public: RID get_canvas() const; Ref<World2D> get_world_2d() const; - void set_material(const Ref<ShaderMaterial> &p_material); - Ref<ShaderMaterial> get_material() const; + void set_material(const Ref<Material> &p_material); + Ref<Material> get_material() const; void set_use_parent_material(bool p_use_parent_material); bool get_use_parent_material() const; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index caf9cf201a..c5c274e225 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -31,18 +31,6 @@ #include "scene/scene_string_names.h" #include "servers/physics_2d_server.h" -void CollisionObject2D::_update_shapes_from_children() { - - shapes.clear(); - for (int i = 0; i < get_child_count(); i++) { - - Node *n = get_child(i); - n->call("_add_to_collision_object", this); - } - - _update_shapes(); -} - void CollisionObject2D::_notification(int p_what) { switch (p_what) { @@ -88,82 +76,197 @@ void CollisionObject2D::_notification(int p_what) { } } -void CollisionObject2D::_update_shapes() { +uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { - if (!rid.is_valid()) - return; + ShapeData sd; + uint32_t id; + + if (shapes.size() == 0) { + id = 1; + } else { + id = shapes.back()->key() + 1; + } + + sd.owner = p_owner; + + shapes[id] = sd; + + return id; +} + +void CollisionObject2D::remove_shape_owner(uint32_t owner) { + + ERR_FAIL_COND(!shapes.has(owner)); + + shape_owner_clear_shapes(owner); + + shapes.erase(owner); +} + +void CollisionObject2D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) { + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.disabled = p_disabled; + for (int i = 0; i < sd.shapes.size(); i++) { + if (area) { + Physics2DServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); + } else { + Physics2DServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); + } + } +} + +bool CollisionObject2D::is_shape_owner_disabled(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), false); + + return shapes[p_owner].disabled; +} + +void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable) { if (area) - Physics2DServer::get_singleton()->area_clear_shapes(rid); - else - Physics2DServer::get_singleton()->body_clear_shapes(rid); - - for (int i = 0; i < shapes.size(); i++) { - - if (shapes[i].shape.is_null()) - continue; - if (area) - Physics2DServer::get_singleton()->area_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform); - else { - Physics2DServer::get_singleton()->body_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform); - if (shapes[i].trigger) - Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, i, shapes[i].trigger); + return; //not for areas + + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.one_way_collision = p_enable; + for (int i = 0; i < sd.shapes.size(); i++) { + Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, p_enable); + } +} + +bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), false); + + return shapes[p_owner].one_way_collision; +} + +void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) { + + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + r_owners->push_back(E->key()); + } +} + +void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + + ShapeData &sd = shapes[p_owner]; + sd.xform = p_transform; + for (int i = 0; i < sd.shapes.size(); i++) { + if (area) { + Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform); + } else { + Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform); } } } +Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const { -bool CollisionObject2D::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name; + ERR_FAIL_COND_V(!shapes.has(p_owner), Transform2D()); - if (name.begins_with("shapes/")) { + return shapes[p_owner].xform; +} - int idx = name.get_slicec('/', 1).to_int(); - String what = name.get_slicec('/', 2); - if (what == "shape") { - if (idx >= shapes.size()) - add_shape(RefPtr(p_value)); - else - set_shape(idx, RefPtr(p_value)); - } else if (what == "transform") - set_shape_transform(idx, p_value); - else if (what == "trigger") - set_shape_as_trigger(idx, p_value); - } else - return false; - - return true; +Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), NULL); + + return shapes[p_owner].owner; +} + +void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + ERR_FAIL_COND(p_shape.is_null()); + + ShapeData &sd = shapes[p_owner]; + ShapeData::Shape s; + s.index = total_subshapes; + s.shape = p_shape; + if (area) { + Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform); + } else { + Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform); + } + sd.shapes.push_back(s); + + total_subshapes++; +} +int CollisionObject2D::shape_owner_get_shape_count(uint32_t p_owner) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), 0); + + return shapes[p_owner].shapes.size(); +} +Ref<Shape> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>()); + ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>()); + + return shapes[p_owner].shapes[p_shape].shape; +} +int CollisionObject2D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const { + + ERR_FAIL_COND_V(!shapes.has(p_owner), -1); + ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1); + + return shapes[p_owner].shapes[p_shape].index; } -bool CollisionObject2D::_get(const StringName &p_name, Variant &r_ret) const { +void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) { + + ERR_FAIL_COND(!shapes.has(p_owner)); + ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); + + int index_to_remove = shapes[p_owner].shapes[p_shape].index; + if (area) { + Physics2DServer::get_singleton()->area_remove_shape(rid, index_to_remove); + } else { + Physics2DServer::get_singleton()->body_remove_shape(rid, index_to_remove); + } + + shapes[p_owner].shapes.remove(p_shape); + + for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + for (int i = 0; i < E->get().shapes.size(); i++) { + if (E->get().shapes[i].index > index_to_remove) { + E->get().shapes[i].index -= 1; + } + } + } - String name = p_name; + total_subshapes--; +} - if (name.begins_with("shapes/")) { +void CollisionObject2D::shape_owner_clear_shapes(uint32_t p_owner) { - int idx = name.get_slicec('/', 1).to_int(); - String what = name.get_slicec('/', 2); - if (what == "shape") - r_ret = get_shape(idx); - else if (what == "transform") - r_ret = get_shape_transform(idx); - else if (what == "trigger") - r_ret = is_shape_set_as_trigger(idx); - } else - return false; + ERR_FAIL_COND(!shapes.has(p_owner)); - return true; + while (shape_owner_get_shape_count(p_owner) > 0) { + shape_owner_remove_shape(p_owner, 0); + } } -void CollisionObject2D::_get_property_list(List<PropertyInfo> *p_list) const { +uint32_t CollisionObject2D::shape_find_owner(int p_shape_index) const { - //p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0); - for (int i = 0; i < shapes.size(); i++) { - String path = "shapes/" + itos(i) + "/"; - p_list->push_back(PropertyInfo(Variant::OBJECT, path + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, path + "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); - p_list->push_back(PropertyInfo(Variant::BOOL, path + "trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE)); + for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { + for (int i = 0; i < E->get().shapes.size(); i++) { + if (E->get().shapes[i].index == p_shape_index) { + return E->key(); + } + } } + + //in theory it should be unreachable + return 0; } void CollisionObject2D::set_pickable(bool p_enabled) { @@ -216,16 +319,6 @@ void CollisionObject2D::_update_pickable() { void CollisionObject2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_shape", "shape:Shape2D", "transform"), &CollisionObject2D::add_shape, DEFVAL(Transform2D())); - ClassDB::bind_method(D_METHOD("get_shape_count"), &CollisionObject2D::get_shape_count); - ClassDB::bind_method(D_METHOD("set_shape", "shape_idx", "shape:Shape"), &CollisionObject2D::set_shape); - ClassDB::bind_method(D_METHOD("set_shape_transform", "shape_idx", "transform"), &CollisionObject2D::set_shape_transform); - ClassDB::bind_method(D_METHOD("set_shape_as_trigger", "shape_idx", "enable"), &CollisionObject2D::set_shape_as_trigger); - ClassDB::bind_method(D_METHOD("get_shape:Shape2D", "shape_idx"), &CollisionObject2D::get_shape); - ClassDB::bind_method(D_METHOD("get_shape_transform", "shape_idx"), &CollisionObject2D::get_shape_transform); - ClassDB::bind_method(D_METHOD("is_shape_set_as_trigger", "shape_idx"), &CollisionObject2D::is_shape_set_as_trigger); - ClassDB::bind_method(D_METHOD("remove_shape", "shape_idx"), &CollisionObject2D::remove_shape); - ClassDB::bind_method(D_METHOD("clear_shapes"), &CollisionObject2D::clear_shapes); ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); @@ -242,100 +335,13 @@ void CollisionObject2D::_bind_methods() { ADD_GROUP("", ""); } -void CollisionObject2D::add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform) { - - ERR_FAIL_COND(p_shape.is_null()); - - ShapeData sdata; - sdata.shape = p_shape; - sdata.xform = p_transform; - sdata.trigger = false; - - if (area) - Physics2DServer::get_singleton()->area_add_shape(get_rid(), p_shape->get_rid(), p_transform); - else - Physics2DServer::get_singleton()->body_add_shape(get_rid(), p_shape->get_rid(), p_transform); - - shapes.push_back(sdata); -} -int CollisionObject2D::get_shape_count() const { - - return shapes.size(); -} -void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - ERR_FAIL_COND(p_shape.is_null()); - - shapes[p_shape_idx].shape = p_shape; - if (area) - Physics2DServer::get_singleton()->area_set_shape(get_rid(), p_shape_idx, p_shape->get_rid()); - else - Physics2DServer::get_singleton()->body_set_shape(get_rid(), p_shape_idx, p_shape->get_rid()); - - //_update_shapes(); -} - -void CollisionObject2D::set_shape_transform(int p_shape_idx, const Transform2D &p_transform) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes[p_shape_idx].xform = p_transform; - - if (area) - Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(), p_shape_idx, p_transform); - else - Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(), p_shape_idx, p_transform); - - //_update_shapes(); -} - -Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Ref<Shape2D>()); - return shapes[p_shape_idx].shape; -} -Transform2D CollisionObject2D::get_shape_transform(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Transform2D()); - return shapes[p_shape_idx].xform; -} -void CollisionObject2D::remove_shape(int p_shape_idx) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes.remove(p_shape_idx); - - _update_shapes(); -} - -void CollisionObject2D::set_shape_as_trigger(int p_shape_idx, bool p_trigger) { - - ERR_FAIL_INDEX(p_shape_idx, shapes.size()); - shapes[p_shape_idx].trigger = p_trigger; - if (!area && rid.is_valid()) { - - Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, p_shape_idx, p_trigger); - } -} - -bool CollisionObject2D::is_shape_set_as_trigger(int p_shape_idx) const { - - ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), false); - return shapes[p_shape_idx].trigger; -} - -void CollisionObject2D::clear_shapes() { - - shapes.clear(); - - _update_shapes(); -} - CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { rid = p_rid; area = p_area; pickable = true; set_notify_transform(true); + total_subshapes = 0; if (p_area) { @@ -348,6 +354,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { CollisionObject2D::CollisionObject2D() { //owner= + set_notify_transform(true); } diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 4d4611afd1..deffe8a002 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -35,37 +35,40 @@ class CollisionObject2D : public Node2D { - GDCLASS(CollisionObject2D, Node2D); + GDCLASS(CollisionObject2D, Node2D) bool area; RID rid; bool pickable; struct ShapeData { + + Object *owner; Transform2D xform; - Ref<Shape2D> shape; - bool trigger; + struct Shape { + Ref<Shape2D> shape; + int index; + }; + + Vector<Shape> shapes; + bool disabled; + bool one_way_collision; ShapeData() { - trigger = false; + disabled = false; + one_way_collision = false; + owner = NULL; } }; - Vector<ShapeData> shapes; - - void _update_shapes(); + int total_subshapes; - friend class CollisionShape2D; - friend class CollisionPolygon2D; - void _update_shapes_from_children(); + Map<uint32_t, ShapeData> shapes; protected: CollisionObject2D(RID p_rid, bool p_area); void _notification(int p_what); - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; static void _bind_methods(); void _update_pickable(); @@ -75,16 +78,29 @@ protected: void _mouse_exit(); public: - void add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform = Transform2D()); - int get_shape_count() const; - void set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape); - void set_shape_transform(int p_shape_idx, const Transform2D &p_transform); - Ref<Shape2D> get_shape(int p_shape_idx) const; - Transform2D get_shape_transform(int p_shape_idx) const; - void set_shape_as_trigger(int p_shape_idx, bool p_trigger); - bool is_shape_set_as_trigger(int p_shape_idx) const; - void remove_shape(int p_shape_idx); - void clear_shapes(); + uint32_t create_shape_owner(Object *p_owner); + void remove_shape_owner(uint32_t owner); + void get_shape_owners(List<uint32_t> *r_owners); + + void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform); + Transform2D shape_owner_get_transform(uint32_t p_owner) const; + Object *shape_owner_get_owner(uint32_t p_owner) const; + + void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled); + bool is_shape_owner_disabled(uint32_t p_owner) const; + + void shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable); + bool is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const; + + void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape); + int shape_owner_get_shape_count(uint32_t p_owner) const; + Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const; + int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const; + + void shape_owner_remove_shape(uint32_t p_owner, int p_shape); + void shape_owner_clear_shapes(uint32_t p_owner); + + uint32_t shape_find_owner(int p_shape_index) const; void set_pickable(bool p_enabled); bool is_pickable() const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 6b603c6473..bd669eb4c8 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -35,13 +35,9 @@ #include "thirdparty/misc/triangulator.h" -void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { +void CollisionPolygon2D::_build_polygon() { - if (unparenting || !can_update_body) - return; - - CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); - ERR_FAIL_COND(!co); + parent->shape_owner_clear_shapes(owner_id); if (polygon.size() == 0) return; @@ -53,18 +49,10 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them Vector<Vector<Vector2> > decomp = _decompose_in_convex(); - shape_from = co->get_shape_count(); for (int i = 0; i < decomp.size(); i++) { Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D); convex->set_points(decomp[i]); - co->add_shape(convex, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); - } - shape_to = co->get_shape_count() - 1; - if (shape_to < shape_from) { - shape_from = -1; - shape_to = -1; + parent->shape_owner_add_shape(owner_id, convex); } } else { @@ -83,28 +71,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { w = PoolVector<Vector2>::Write(); concave->set_segments(segments); - co->add_shape(concave, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); - - shape_from = co->get_shape_count() - 1; - shape_to = co->get_shape_count() - 1; + parent->shape_owner_add_shape(owner_id, concave); } - - //co->add_shape(shape,get_transform()); -} - -void CollisionPolygon2D::_update_parent() { - - if (!can_update_body) - return; - Node *parent = get_parent(); - if (!parent) - return; - CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); - if (!co) - return; - co->_update_shapes_from_children(); } Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { @@ -155,33 +123,38 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() { void CollisionPolygon2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - unparenting = false; - can_update_body = get_tree()->is_editor_hint(); - if (!get_tree()->is_editor_hint()) { + case NOTIFICATION_PARENTED: { + + parent = get_parent()->cast_to<CollisionObject2D>(); + if (parent) { + owner_id = parent->create_shape_owner(this); + _build_polygon(); + parent->shape_owner_set_transform(owner_id, get_transform()); + parent->shape_owner_set_disabled(owner_id, disabled); + parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + } + + /*if (get_tree()->is_editor_hint()) { //display above all else set_z_as_relative(false); set_z(VS::CANVAS_ITEM_Z_MAX - 1); - } + }*/ } break; - case NOTIFICATION_EXIT_TREE: { - can_update_body = false; - } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_tree()) - break; - if (can_update_body) { - _update_parent(); - } else if (shape_from >= 0 && shape_to >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - for (int i = shape_from; i <= shape_to; i++) { - co->set_shape_transform(i, get_transform()); - } + if (parent) { + parent->shape_owner_set_transform(owner_id, get_transform()); } } break; + case NOTIFICATION_UNPARENTED: { + if (parent) { + parent->remove_shape_owner(owner_id); + } + owner_id = 0; + parent = NULL; + } break; case NOTIFICATION_DRAW: { @@ -210,10 +183,22 @@ void CollisionPolygon2D::_notification(int p_what) { draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); #endif - } break; - case NOTIFICATION_UNPARENTED: { - unparenting = true; - _update_parent(); + if (one_way_collision) { + Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4); + dcol.a = 1.0; + Vector2 line_to(0, 20); + draw_line(Vector2(), line_to, dcol, 3); + Vector<Vector2> pts; + float tsize = 8; + pts.push_back(line_to + (Vector2(0, tsize))); + pts.push_back(line_to + (Vector2(0.707 * tsize, 0))); + pts.push_back(line_to + (Vector2(-0.707 * tsize, 0))); + Vector<Color> cols; + for (int i = 0; i < 3; i++) + cols.push_back(dcol); + + draw_primitive(pts, cols, Vector<Vector2>()); //small arrow + } } break; } } @@ -222,7 +207,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { polygon = p_polygon; - if (can_update_body) { + { for (int i = 0; i < polygon.size(); i++) { if (i == 0) aabb = Rect2(polygon[i], Size2()); @@ -236,7 +221,10 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { aabb.position -= aabb.size * 0.3; aabb.size += aabb.size * 0.6; } - _update_parent(); + } + + if (parent) { + _build_polygon(); } update(); update_configuration_warning(); @@ -251,7 +239,9 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { ERR_FAIL_INDEX(p_mode, 2); build_mode = p_mode; - _update_parent(); + if (parent) { + _build_polygon(); + } } CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { @@ -264,79 +254,69 @@ Rect2 CollisionPolygon2D::get_item_rect() const { return aabb; } -void CollisionPolygon2D::set_trigger(bool p_trigger) { +String CollisionPolygon2D::get_configuration_warning() const { - trigger = p_trigger; - _update_parent(); - if (!can_update_body && is_inside_tree() && shape_from >= 0 && shape_to >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - for (int i = shape_from; i <= shape_to; i++) { - co->set_shape_as_trigger(i, p_trigger); - } + if (!get_parent()->cast_to<CollisionObject2D>()) { + return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); } -} -bool CollisionPolygon2D::is_trigger() const { + if (polygon.empty()) { + return TTR("An empty CollisionPolygon2D has no effect on collision."); + } - return trigger; + return String(); } -void CollisionPolygon2D::_set_shape_range(const Vector2 &p_range) { - - shape_from = p_range.x; - shape_to = p_range.y; +void CollisionPolygon2D::set_disabled(bool p_disabled) { + disabled = p_disabled; + update(); + if (parent) { + parent->shape_owner_set_disabled(owner_id, p_disabled); + } } -Vector2 CollisionPolygon2D::_get_shape_range() const { - - return Vector2(shape_from, shape_to); +bool CollisionPolygon2D::is_disabled() const { + return disabled; } -String CollisionPolygon2D::get_configuration_warning() const { - - if (!get_parent()->cast_to<CollisionObject2D>()) { - return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +void CollisionPolygon2D::set_one_way_collision(bool p_enable) { + one_way_collision = p_enable; + update(); + if (parent) { + parent->shape_owner_set_one_way_collision(owner_id, p_enable); } +} - if (polygon.empty()) { - return TTR("An empty CollisionPolygon2D has no effect on collision."); - } +bool CollisionPolygon2D::is_one_way_collision_enabled() const { - return String(); + return one_way_collision; } void CollisionPolygon2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionPolygon2D::_add_to_collision_object); ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon); ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon2D::get_polygon); ClassDB::bind_method(D_METHOD("set_build_mode", "build_mode"), &CollisionPolygon2D::set_build_mode); ClassDB::bind_method(D_METHOD("get_build_mode"), &CollisionPolygon2D::get_build_mode); - - ClassDB::bind_method(D_METHOD("set_trigger", "trigger"), &CollisionPolygon2D::set_trigger); - ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionPolygon2D::is_trigger); - - ClassDB::bind_method(D_METHOD("_set_shape_range", "shape_range"), &CollisionPolygon2D::_set_shape_range); - ClassDB::bind_method(D_METHOD("_get_shape_range"), &CollisionPolygon2D::_get_shape_range); - - ClassDB::bind_method(D_METHOD("get_collision_object_first_shape"), &CollisionPolygon2D::get_collision_object_first_shape); - ClassDB::bind_method(D_METHOD("get_collision_object_last_shape"), &CollisionPolygon2D::get_collision_object_last_shape); + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon2D::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon2D::is_disabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionPolygon2D::set_one_way_collision); + ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionPolygon2D::is_one_way_collision_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode"); ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shape_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_shape_range", "_get_shape_range"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); } CollisionPolygon2D::CollisionPolygon2D() { aabb = Rect2(-10, -10, 20, 20); build_mode = BUILD_SOLIDS; - trigger = false; - unparenting = false; - shape_from = -1; - shape_to = -1; - can_update_body = false; set_notify_local_transform(true); + parent = NULL; + owner_id = 0; + disabled = false; + one_way_collision = false; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index b1a4a4822d..f0666ba9de 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -33,6 +33,8 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +class CollisionObject2D; + class CollisionPolygon2D : public Node2D { GDCLASS(CollisionPolygon2D, Node2D); @@ -47,29 +49,20 @@ protected: Rect2 aabb; BuildMode build_mode; Vector<Point2> polygon; - bool trigger; - bool unparenting; - - void _add_to_collision_object(Object *p_obj); - void _update_parent(); - - bool can_update_body; - int shape_from; - int shape_to; - - void _set_shape_range(const Vector2 &p_range); - Vector2 _get_shape_range() const; + uint32_t owner_id; + CollisionObject2D *parent; + bool disabled; + bool one_way_collision; Vector<Vector<Vector2> > _decompose_in_convex(); + void _build_polygon(); + protected: void _notification(int p_what); static void _bind_methods(); public: - void set_trigger(bool p_trigger); - bool is_trigger() const; - void set_build_mode(BuildMode p_mode); BuildMode get_build_mode() const; @@ -78,11 +71,14 @@ public: virtual Rect2 get_item_rect() const; - int get_collision_object_first_shape() const { return shape_from; } - int get_collision_object_last_shape() const { return shape_to; } - virtual String get_configuration_warning() const; + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_one_way_collision(bool p_enable); + bool is_one_way_collision_enabled() const; + CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 1687a898db..ff4aa245ec 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -37,68 +37,48 @@ #include "scene/resources/segment_shape_2d.h" #include "scene/resources/shape_line_2d.h" -void CollisionShape2D::_add_to_collision_object(Object *p_obj) { - - if (unparenting) - return; - - CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); - ERR_FAIL_COND(!co); - update_shape_index = co->get_shape_count(); - co->add_shape(shape, get_transform()); - if (trigger) - co->set_shape_as_trigger(co->get_shape_count() - 1, true); -} - void CollisionShape2D::_shape_changed() { update(); - _update_parent(); -} - -void CollisionShape2D::_update_parent() { - - Node *parent = get_parent(); - if (!parent) - return; - CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); - if (!co) - return; - co->_update_shapes_from_children(); } void CollisionShape2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - unparenting = false; - can_update_body = get_tree()->is_editor_hint(); - if (!get_tree()->is_editor_hint()) { + case NOTIFICATION_PARENTED: { + + parent = get_parent()->cast_to<CollisionObject2D>(); + if (parent) { + owner_id = parent->create_shape_owner(this); + if (shape.is_valid()) { + parent->shape_owner_add_shape(owner_id, shape); + } + parent->shape_owner_set_transform(owner_id, get_transform()); + parent->shape_owner_set_disabled(owner_id, disabled); + parent->shape_owner_set_one_way_collision(owner_id, one_way_collision); + } + + /*if (get_tree()->is_editor_hint()) { //display above all else set_z_as_relative(false); set_z(VS::CANVAS_ITEM_Z_MAX - 1); - } + }*/ } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_tree()) - break; - if (can_update_body) { - _update_parent(); - } else if (update_shape_index >= 0) { - - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape_transform(update_shape_index, get_transform()); - } + if (parent) { + parent->shape_owner_set_transform(owner_id, get_transform()); } } break; - case NOTIFICATION_EXIT_TREE: { - can_update_body = false; - + case NOTIFICATION_UNPARENTED: { + if (parent) { + parent->remove_shape_owner(owner_id); + } + owner_id = 0; + parent = NULL; } break; /* case NOTIFICATION_TRANSFORM_CHANGED: { @@ -121,15 +101,33 @@ void CollisionShape2D::_notification(int p_what) { rect = Rect2(); Color draw_col = get_tree()->get_debug_collisions_color(); + if (disabled) { + float g = draw_col.gray(); + draw_col.r = g; + draw_col.g = g; + draw_col.b = g; + } shape->draw(get_canvas_item(), draw_col); rect = shape->get_rect(); rect = rect.grow(3); - } break; - case NOTIFICATION_UNPARENTED: { - unparenting = true; - _update_parent(); + if (one_way_collision) { + Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4); + dcol.a = 1.0; + Vector2 line_to(0, 20); + draw_line(Vector2(), line_to, dcol, 3); + Vector<Vector2> pts; + float tsize = 8; + pts.push_back(line_to + (Vector2(0, tsize))); + pts.push_back(line_to + (Vector2(0.707 * tsize, 0))); + pts.push_back(line_to + (Vector2(-0.707 * tsize, 0))); + Vector<Color> cols; + for (int i = 0; i < 3; i++) + cols.push_back(dcol); + + draw_primitive(pts, cols, Vector<Vector2>()); //small arrow + } } break; } } @@ -140,14 +138,13 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) { shape->disconnect("changed", this, "_shape_changed"); shape = p_shape; update(); - if (is_inside_tree() && can_update_body) - _update_parent(); - if (is_inside_tree() && !can_update_body && update_shape_index >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape(update_shape_index, p_shape); + if (parent) { + parent->shape_owner_clear_shapes(owner_id); + if (shape.is_valid()) { + parent->shape_owner_add_shape(owner_id, shape); } } + if (shape.is_valid()) shape->connect("changed", this, "_shape_changed"); @@ -164,72 +161,65 @@ Rect2 CollisionShape2D::get_item_rect() const { return rect; } -void CollisionShape2D::set_trigger(bool p_trigger) { +String CollisionShape2D::get_configuration_warning() const { - trigger = p_trigger; - if (can_update_body) { - _update_parent(); - } else if (is_inside_tree() && update_shape_index >= 0) { - CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); - if (co) { - co->set_shape_as_trigger(update_shape_index, p_trigger); - } + if (!get_parent()->cast_to<CollisionObject2D>()) { + return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); } -} -bool CollisionShape2D::is_trigger() const { + if (!shape.is_valid()) { + return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"); + } - return trigger; + return String(); } -void CollisionShape2D::_set_update_shape_index(int p_index) { - - update_shape_index = p_index; +void CollisionShape2D::set_disabled(bool p_disabled) { + disabled = p_disabled; + update(); + if (parent) { + parent->shape_owner_set_disabled(owner_id, p_disabled); + } } -int CollisionShape2D::_get_update_shape_index() const { - - return update_shape_index; +bool CollisionShape2D::is_disabled() const { + return disabled; } -String CollisionShape2D::get_configuration_warning() const { - - if (!get_parent()->cast_to<CollisionObject2D>()) { - return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); +void CollisionShape2D::set_one_way_collision(bool p_enable) { + one_way_collision = p_enable; + update(); + if (parent) { + parent->shape_owner_set_one_way_collision(owner_id, p_enable); } +} - if (!shape.is_valid()) { - return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!"); - } +bool CollisionShape2D::is_one_way_collision_enabled() const { - return String(); + return one_way_collision; } void CollisionShape2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape); ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape2D::get_shape); + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionShape2D::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape2D::is_disabled); + ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionShape2D::set_one_way_collision); + ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled); ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape2D::_shape_changed); - ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionShape2D::_add_to_collision_object); - ClassDB::bind_method(D_METHOD("set_trigger", "enable"), &CollisionShape2D::set_trigger); - ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionShape2D::is_trigger); - - ClassDB::bind_method(D_METHOD("_set_update_shape_index", "index"), &CollisionShape2D::_set_update_shape_index); - ClassDB::bind_method(D_METHOD("_get_update_shape_index"), &CollisionShape2D::_get_update_shape_index); - - ClassDB::bind_method(D_METHOD("get_collision_object_shape_index"), &CollisionShape2D::get_collision_object_shape_index); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_update_shape_index", "_get_update_shape_index"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled"); } CollisionShape2D::CollisionShape2D() { rect = Rect2(-Point2(10, 10), Point2(20, 20)); set_notify_local_transform(true); - trigger = false; - unparenting = false; - can_update_body = false; - update_shape_index = -1; + owner_id = 0; + parent = NULL; + disabled = false; + one_way_collision = false; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 3e63981010..1f2b96b91f 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -33,35 +33,33 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +class CollisionObject2D; + class CollisionShape2D : public Node2D { - GDCLASS(CollisionShape2D, Node2D); + GDCLASS(CollisionShape2D, Node2D) Ref<Shape2D> shape; Rect2 rect; - bool trigger; - bool unparenting; - bool can_update_body; + uint32_t owner_id; + CollisionObject2D *parent; void _shape_changed(); - int update_shape_index; - - void _set_update_shape_index(int p_index); - int _get_update_shape_index() const; + bool disabled; + bool one_way_collision; protected: - void _update_parent(); void _notification(int p_what); static void _bind_methods(); - void _add_to_collision_object(Object *p_obj); - public: void set_shape(const Ref<Shape2D> &p_shape); Ref<Shape2D> get_shape() const; virtual Rect2 get_item_rect() const; - void set_trigger(bool p_trigger); - bool is_trigger() const; - int get_collision_object_shape_index() const { return _get_update_shape_index(); } + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_one_way_collision(bool p_enable); + bool is_one_way_collision_enabled() const; virtual String get_configuration_warning() const; diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 1a57d24342..5438557d0b 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -310,12 +310,15 @@ void Line2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color"); + ADD_GROUP("Fill", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode"); + ADD_GROUP("Capping", ""); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode"); + ADD_GROUP("Border", ""); ADD_PROPERTY(PropertyInfo(Variant::REAL, "sharp_limit"), "set_sharp_limit", "get_sharp_limit"); ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision"); diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 7c864c3430..aa9258c7b4 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "particles_2d.h" + #include "scene/3d/particles.h" #include "scene/scene_string_names.h" @@ -49,6 +50,12 @@ void Particles2D::set_lifetime(float p_lifetime) { lifetime = p_lifetime; VS::get_singleton()->particles_set_lifetime(particles, lifetime); } + +void Particles2D::set_one_shot(bool p_enable) { + + one_shot = p_enable; + VS::get_singleton()->particles_set_one_shot(particles, one_shot); +} void Particles2D::set_pre_process_time(float p_time) { pre_process_time = p_time; @@ -83,7 +90,7 @@ void Particles2D::set_use_local_coordinates(bool p_enable) { local_coords = p_enable; VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords); set_notify_transform(!p_enable); - if (!p_enable) { + if (!p_enable && is_inside_tree()) { _update_particle_emission_transform(); } } @@ -134,6 +141,11 @@ float Particles2D::get_lifetime() const { return lifetime; } + +bool Particles2D::get_one_shot() const { + + return one_shot; +} float Particles2D::get_pre_process_time() const { return pre_process_time; @@ -263,6 +275,10 @@ int Particles2D::get_h_frames() const { return h_frames; } +void Particles2D::restart() { + VS::get_singleton()->particles_restart(particles); +} + void Particles2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { @@ -276,10 +292,12 @@ void Particles2D::_notification(int p_what) { VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames); +#ifdef TOOLS_ENABLED if (get_tree()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); } +#endif } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { @@ -292,6 +310,7 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount); ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime); + ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot); ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time); ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio); @@ -305,6 +324,7 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount); ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime); + ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time); ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio); ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio); @@ -332,21 +352,25 @@ void Particles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames); ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames); - ADD_GROUP("Parameters", ""); + ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); + ADD_GROUP("Drawing", ""); + ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order"); ADD_GROUP("Process Material", "process_"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Textures", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); @@ -362,6 +386,7 @@ Particles2D::Particles2D() { particles = VS::get_singleton()->particles_create(); set_emitting(true); + set_one_shot(false); set_amount(8); set_lifetime(1); set_fixed_fps(0); diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index ab7dcb1464..23278ce746 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -48,6 +48,7 @@ private: RID particles; bool emitting; + bool one_shot; int amount; float lifetime; float pre_process_time; @@ -79,6 +80,7 @@ public: void set_emitting(bool p_emitting); void set_amount(int p_amount); void set_lifetime(float p_lifetime); + void set_one_shot(bool p_enabled); void set_pre_process_time(float p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); @@ -90,6 +92,7 @@ public: bool is_emitting() const; int get_amount() const; float get_lifetime() const; + bool get_one_shot() const; float get_pre_process_time() const; float get_explosiveness_ratio() const; float get_randomness_ratio() const; @@ -121,6 +124,7 @@ public: void set_h_frames(int p_count); int get_h_frames() const; + void restart(); Rect2 capture_rect() const; Particles2D(); ~Particles2D(); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 68270ed771..fd261117e1 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -44,28 +44,6 @@ void PhysicsBody2D::_notification(int p_what) { */ } -void PhysicsBody2D::set_one_way_collision_direction(const Vector2 &p_dir) { - - one_way_collision_direction = p_dir; - Physics2DServer::get_singleton()->body_set_one_way_collision_direction(get_rid(), p_dir); -} - -Vector2 PhysicsBody2D::get_one_way_collision_direction() const { - - return one_way_collision_direction; -} - -void PhysicsBody2D::set_one_way_collision_max_depth(float p_depth) { - - one_way_collision_max_depth = p_depth; - Physics2DServer::get_singleton()->body_set_one_way_collision_max_depth(get_rid(), p_depth); -} - -float PhysicsBody2D::get_one_way_collision_max_depth() const { - - return one_way_collision_max_depth; -} - void PhysicsBody2D::_set_layers(uint32_t p_mask) { set_collision_layer(p_mask); @@ -92,10 +70,6 @@ void PhysicsBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody2D::_set_layers); ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_layers); - ClassDB::bind_method(D_METHOD("set_one_way_collision_direction", "dir"), &PhysicsBody2D::set_one_way_collision_direction); - ClassDB::bind_method(D_METHOD("get_one_way_collision_direction"), &PhysicsBody2D::get_one_way_collision_direction); - ClassDB::bind_method(D_METHOD("set_one_way_collision_max_depth", "depth"), &PhysicsBody2D::set_one_way_collision_max_depth); - ClassDB::bind_method(D_METHOD("get_one_way_collision_max_depth"), &PhysicsBody2D::get_one_way_collision_max_depth); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::remove_collision_exception_with); ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", 0), "_set_layers", "_get_layers"); //for backwards compat @@ -103,9 +77,6 @@ void PhysicsBody2D::_bind_methods() { ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); - ADD_GROUP("", ""); - ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "one_way_collision/direction"), "set_one_way_collision_direction", "get_one_way_collision_direction"); - ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "one_way_collision/max_depth"), "set_one_way_collision_max_depth", "get_one_way_collision_max_depth"); } void PhysicsBody2D::set_collision_layer(uint32_t p_layer) { @@ -164,7 +135,6 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) collision_layer = 1; collision_mask = 1; - set_one_way_collision_max_depth(0); set_pickable(false); } @@ -971,248 +941,105 @@ RigidBody2D::~RigidBody2D() { ////////////////////////// -Variant KinematicBody2D::_get_collider() const { - - ObjectID oid = get_collider(); - if (oid == 0) - return Variant(); - Object *obj = ObjectDB::get_instance(oid); - if (!obj) - return Variant(); - - Reference *ref = obj->cast_to<Reference>(); - if (ref) { - return Ref<Reference>(ref); - } - - return obj; -} - -void KinematicBody2D::revert_motion() { +Dictionary KinematicBody2D::_move(const Vector2 &p_motion) { + + Collision col; + if (move(p_motion, col)) { + Dictionary d; + d["position"] = col.collision; + d["normal"] = col.collision; + d["local_shape"] = col.local_shape; + d["travel"] = col.travel; + d["remainder"] = col.remainder; + d["collider_id"] = col.collider; + if (col.collider) { + d["collider"] = ObjectDB::get_instance(col.collider); + } else { + d["collider"] = Variant(); + } - Transform2D gt = get_global_transform(); - gt.elements[2] -= travel; - travel = Vector2(); - set_global_transform(gt); -} + d["collider_shape_index"] = col.collider_shape; + d["collider_metadata"] = col.collider_metadata; -Vector2 KinematicBody2D::get_travel() const { + return d; - return travel; + } else { + return Dictionary(); + } } -Vector2 KinematicBody2D::move(const Vector2 &p_motion) { - -#if 1 +bool KinematicBody2D::move(const Vector2 &p_motion, Collision &r_collision) { Transform2D gt = get_global_transform(); Physics2DServer::MotionResult result; - colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result); - - collider_metadata = result.collider_metadata; - collider_shape = result.collider_shape; - collider_vel = result.collider_velocity; - collision = result.collision_point; - normal = result.collision_normal; - collider = result.collider_id; - - gt.elements[2] += result.motion; - set_global_transform(gt); - travel = result.motion; - - return result.remainder; - -#else - //give me back regular physics engine logic - //this is madness - //and most people using this function will think - //what it does is simpler than using physics - //this took about a week to get right.. - //but is it right? who knows at this point.. - - colliding = false; - ERR_FAIL_COND_V(!is_inside_tree(), Vector2()); - Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); - ERR_FAIL_COND_V(!dss, Vector2()); - const int max_shapes = 32; - Vector2 sr[max_shapes * 2]; - int res_shapes; - - Set<RID> exclude; - exclude.insert(get_rid()); - - //recover first - int recover_attempts = 4; - - bool collided = false; - uint32_t mask = 0; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY; - if (true) - mask |= Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY; - - //print_line("margin: "+rtos(margin)); - do { - - //motion recover - for (int i = 0; i < get_shape_count(); i++) { - - if (is_shape_set_as_trigger(i)) - continue; - if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), Vector2(), margin, sr, max_shapes, res_shapes, exclude, get_layer_mask(), mask)) - collided = true; - } - - if (!collided) - break; - - Vector2 recover_motion; - - for (int i = 0; i < res_shapes; i++) { - - Vector2 a = sr[i * 2 + 0]; - Vector2 b = sr[i * 2 + 1]; - - float d = a.distance_to(b); - - /* - if (d<margin) - continue; - */ - recover_motion += (b - a) * 0.4; - } - - if (recover_motion == Vector2()) { - collided = false; - break; - } - - Transform2D gt = get_global_transform(); - gt.elements[2] += recover_motion; - set_global_transform(gt); - - recover_attempts--; - - } while (recover_attempts); - - //move second - float safe = 1.0; - float unsafe = 1.0; - int best_shape = -1; - - for (int i = 0; i < get_shape_count(); i++) { - - if (is_shape_set_as_trigger(i)) - continue; - - float lsafe, lunsafe; - bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0, lsafe, lunsafe, exclude, get_layer_mask(), mask); - //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); - if (!valid) { - - safe = 0; - unsafe = 0; - best_shape = i; //sadly it's the best - break; - } - if (lsafe == 1.0) { - continue; - } - if (lsafe < safe) { - - safe = lsafe; - unsafe = lunsafe; - best_shape = i; - } + bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result); + + if (colliding) { + r_collision.collider_metadata = result.collider_metadata; + r_collision.collider_shape = result.collider_shape; + r_collision.collider_vel = result.collider_velocity; + r_collision.collision = result.collision_point; + r_collision.normal = result.collision_normal; + r_collision.collider = result.collider_id; + r_collision.travel = result.motion; + r_collision.remainder = result.remainder; + r_collision.local_shape = result.collision_local_shape; } - //print_line("best shape: "+itos(best_shape)+" motion "+p_motion); - - if (safe >= 1) { - //not collided - colliding = false; - - } else { - - //it collided, let's get the rest info in unsafe advance - Transform2D ugt = get_global_transform(); - ugt.elements[2] += p_motion * unsafe; - Physics2DDirectSpaceState::ShapeRestInfo rest_info; - bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt * get_shape_transform(best_shape), Vector2(), margin, &rest_info, exclude, get_layer_mask(), mask); - if (!c2) { - //should not happen, but floating point precision is so weird.. - - colliding = false; - } else { - - //print_line("Travel: "+rtos(travel)); - colliding = true; - collision = rest_info.point; - normal = rest_info.normal; - collider = rest_info.collider_id; - collider_vel = rest_info.linear_velocity; - collider_shape = rest_info.shape; - collider_metadata = rest_info.metadata; - } - } - - Vector2 motion = p_motion * safe; - Transform2D gt = get_global_transform(); - gt.elements[2] += motion; + gt.elements[2] += result.motion; set_global_transform(gt); - return p_motion - motion; -#endif + return colliding; } Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_bounces, float p_floor_max_angle) { - Vector2 motion = (move_and_slide_floor_velocity + p_linear_velocity) * get_fixed_process_delta_time(); + Vector2 motion = (floor_velocity + p_linear_velocity) * get_fixed_process_delta_time(); Vector2 lv = p_linear_velocity; - move_and_slide_on_floor = false; - move_and_slide_on_ceiling = false; - move_and_slide_on_wall = false; - move_and_slide_colliders.clear(); - move_and_slide_floor_velocity = Vector2(); + on_floor = false; + on_ceiling = false; + on_wall = false; + colliders.clear(); + floor_velocity = Vector2(); while (p_max_bounces) { - motion = move(motion); + Collision collision; + + bool collided = move(motion, collision); - if (is_colliding()) { + if (collided) { + + motion = collision.remainder; if (p_floor_direction == Vector2()) { //all is a wall - move_and_slide_on_wall = true; + on_wall = true; } else { - if (get_collision_normal().dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor + if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor - move_and_slide_on_floor = true; - move_and_slide_floor_velocity = get_collider_velocity(); + on_floor = true; + floor_velocity = collision.collider_vel; - if (get_travel().length() < 1 && ABS((lv.x - move_and_slide_floor_velocity.x)) < p_slope_stop_min_velocity) { - revert_motion(); + if (collision.travel.length() < 1 && ABS((lv.x - floor_velocity.x)) < p_slope_stop_min_velocity) { + Transform2D gt = get_global_transform(); + gt.elements[2] -= collision.travel; + set_global_transform(gt); return Vector2(); } - } else if (get_collision_normal().dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling - move_and_slide_on_ceiling = true; + } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling + on_ceiling = true; } else { - move_and_slide_on_wall = true; + on_wall = true; } } - Vector2 n = get_collision_normal(); + Vector2 n = collision.normal; motion = motion.slide(n); lv = lv.slide(n); - Variant collider = _get_collider(); - if (collider.get_type() != Variant::NIL) { - move_and_slide_colliders.push_back(collider); - } + + colliders.push_back(collision); } else { break; @@ -1226,26 +1053,22 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const return lv; } -bool KinematicBody2D::is_move_and_slide_on_floor() const { +bool KinematicBody2D::is_on_floor() const { - return move_and_slide_on_floor; + return on_floor; } -bool KinematicBody2D::is_move_and_slide_on_wall() const { +bool KinematicBody2D::is_on_wall() const { - return move_and_slide_on_wall; + return on_wall; } -bool KinematicBody2D::is_move_and_slide_on_ceiling() const { +bool KinematicBody2D::is_on_ceiling() const { - return move_and_slide_on_ceiling; + return on_ceiling; } -Array KinematicBody2D::get_move_and_slide_colliders() const { - return move_and_slide_colliders; -} +Vector2 KinematicBody2D::get_floor_velocity() const { -Vector2 KinematicBody2D::move_to(const Vector2 &p_position) { - - return move(p_position - get_global_position()); + return floor_velocity; } bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion) { @@ -1255,98 +1078,123 @@ bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_moti return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, margin); } -Vector2 KinematicBody2D::get_collision_pos() const { +void KinematicBody2D::set_safe_margin(float p_margin) { - ERR_FAIL_COND_V(!colliding, Vector2()); - return collision; + margin = p_margin; } -Vector2 KinematicBody2D::get_collision_normal() const { +float KinematicBody2D::get_safe_margin() const { - ERR_FAIL_COND_V(!colliding, Vector2()); - return normal; + return margin; } -Vector2 KinematicBody2D::get_collider_velocity() const { +int KinematicBody2D::get_collision_count() const { - return collider_vel; + return colliders.size(); } +Vector2 KinematicBody2D::get_collision_position(int p_collision) const { -ObjectID KinematicBody2D::get_collider() const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); - ERR_FAIL_COND_V(!colliding, 0); - return collider; + return colliders[p_collision].collision; } - -int KinematicBody2D::get_collider_shape() const { - - ERR_FAIL_COND_V(!colliding, 0); - return collider_shape; +Vector2 KinematicBody2D::get_collision_normal(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].normal; } -Variant KinematicBody2D::get_collider_metadata() const { - - ERR_FAIL_COND_V(!colliding, 0); - return collider_metadata; +Vector2 KinematicBody2D::get_collision_travel(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].travel; } - -bool KinematicBody2D::is_colliding() const { - - return colliding; +Vector2 KinematicBody2D::get_collision_remainder(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].remainder; } +Object *KinematicBody2D::get_collision_local_shape(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); + uint32_t owner = shape_find_owner(colliders[p_collision].local_shape); + return shape_owner_get_owner(owner); +} +Object *KinematicBody2D::get_collision_collider(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); -void KinematicBody2D::set_collision_margin(float p_margin) { + if (colliders[p_collision].collider) { + return ObjectDB::get_instance(colliders[p_collision].collider); + } - margin = p_margin; + return NULL; } +ObjectID KinematicBody2D::get_collision_collider_id(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), 0); -float KinematicBody2D::get_collision_margin() const { + return colliders[p_collision].collider; +} +Object *KinematicBody2D::get_collision_collider_shape(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL); + Object *collider = get_collision_collider(p_collision); + if (collider) { + CollisionObject2D *obj2d = collider->cast_to<CollisionObject2D>(); + if (obj2d) { + uint32_t owner = shape_find_owner(colliders[p_collision].collider_shape); + return obj2d->shape_owner_get_owner(owner); + } + } - return margin; + return NULL; +} +int KinematicBody2D::get_collision_collider_shape_index(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), -1); + return colliders[p_collision].collider_shape; +} +Vector2 KinematicBody2D::get_collision_collider_velocity(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2()); + return colliders[p_collision].collider_vel; +} +Variant KinematicBody2D::get_collision_collider_metadata(int p_collision) const { + ERR_FAIL_INDEX_V(p_collision, colliders.size(), Variant()); + return colliders[p_collision].collider_metadata; } void KinematicBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::move); - ClassDB::bind_method(D_METHOD("move_to", "position"), &KinematicBody2D::move_to); + ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::_move); ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45))); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody2D::test_move); - ClassDB::bind_method(D_METHOD("get_travel"), &KinematicBody2D::get_travel); - ClassDB::bind_method(D_METHOD("revert_motion"), &KinematicBody2D::revert_motion); - ClassDB::bind_method(D_METHOD("is_colliding"), &KinematicBody2D::is_colliding); + ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity); - ClassDB::bind_method(D_METHOD("get_collision_pos"), &KinematicBody2D::get_collision_pos); - ClassDB::bind_method(D_METHOD("get_collision_normal"), &KinematicBody2D::get_collision_normal); - ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicBody2D::get_collider_velocity); - ClassDB::bind_method(D_METHOD("get_collider:Variant"), &KinematicBody2D::_get_collider); - ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicBody2D::get_collider_shape); - ClassDB::bind_method(D_METHOD("get_collider_metadata:Variant"), &KinematicBody2D::get_collider_metadata); - ClassDB::bind_method(D_METHOD("get_move_and_slide_colliders"), &KinematicBody2D::get_move_and_slide_colliders); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_floor"), &KinematicBody2D::is_move_and_slide_on_floor); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_ceiling"), &KinematicBody2D::is_move_and_slide_on_ceiling); - ClassDB::bind_method(D_METHOD("is_move_and_slide_on_wall"), &KinematicBody2D::is_move_and_slide_on_wall); + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin", "pixels"), &KinematicBody2D::get_safe_margin); - ClassDB::bind_method(D_METHOD("set_collision_margin", "pixels"), &KinematicBody2D::set_collision_margin); - ClassDB::bind_method(D_METHOD("get_collision_margin", "pixels"), &KinematicBody2D::get_collision_margin); + ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicBody2D::get_collision_count); + ClassDB::bind_method(D_METHOD("get_collision_position", "collision"), &KinematicBody2D::get_collision_position); + ClassDB::bind_method(D_METHOD("get_collision_normal", "collision"), &KinematicBody2D::get_collision_normal); + ClassDB::bind_method(D_METHOD("get_collision_travel", "collision"), &KinematicBody2D::get_collision_travel); + ClassDB::bind_method(D_METHOD("get_collision_remainder", "collision"), &KinematicBody2D::get_collision_remainder); + ClassDB::bind_method(D_METHOD("get_collision_local_shape", "collision"), &KinematicBody2D::get_collision_local_shape); + ClassDB::bind_method(D_METHOD("get_collision_collider", "collision"), &KinematicBody2D::get_collision_collider); + ClassDB::bind_method(D_METHOD("get_collision_collider_id", "collision"), &KinematicBody2D::get_collision_collider_id); + ClassDB::bind_method(D_METHOD("get_collision_collider_shape", "collision"), &KinematicBody2D::get_collision_collider_shape); + ClassDB::bind_method(D_METHOD("get_collision_collider_shape_index", "collision"), &KinematicBody2D::get_collision_collider_shape_index); + ClassDB::bind_method(D_METHOD("get_collision_collider_velocity", "collision"), &KinematicBody2D::get_collision_collider_velocity); + ClassDB::bind_method(D_METHOD("get_collision_collider_metadata", "collision"), &KinematicBody2D::get_collision_collider_metadata); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_collision_margin", "get_collision_margin"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); } KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC) { - colliding = false; - collider = 0; - - collider_shape = 0; - margin = 0.08; - move_and_slide_on_floor = false; - move_and_slide_on_ceiling = false; - move_and_slide_on_wall = false; + on_floor = false; + on_ceiling = false; + on_wall = false; } KinematicBody2D::~KinematicBody2D() { } diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 50c9865f18..8c8e4ebc77 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -40,8 +40,6 @@ class PhysicsBody2D : public CollisionObject2D { uint32_t collision_layer; uint32_t collision_mask; - Vector2 one_way_collision_direction; - float one_way_collision_max_depth; void _set_layers(uint32_t p_mask); uint32_t _get_layers() const; @@ -68,12 +66,6 @@ public: void add_collision_exception_with(Node *p_node); //must be physicsbody void remove_collision_exception_with(Node *p_node); - void set_one_way_collision_direction(const Vector2 &p_dir); - Vector2 get_one_way_collision_direction() const; - - void set_one_way_collision_max_depth(float p_dir); - float get_one_way_collision_max_depth() const; - PhysicsBody2D(); }; @@ -272,54 +264,60 @@ class KinematicBody2D : public PhysicsBody2D { GDCLASS(KinematicBody2D, PhysicsBody2D); +public: + struct Collision { + Vector2 collision; + Vector2 normal; + Vector2 collider_vel; + ObjectID collider; + int collider_shape; + Variant collider_metadata; + Vector2 remainder; + Vector2 travel; + int local_shape; + }; + +private: float margin; - bool colliding; - Vector2 collision; - Vector2 normal; - Vector2 collider_vel; - ObjectID collider; - int collider_shape; - Variant collider_metadata; - Vector2 travel; - - Vector2 move_and_slide_floor_velocity; - bool move_and_slide_on_floor; - bool move_and_slide_on_ceiling; - bool move_and_slide_on_wall; - Array move_and_slide_colliders; - - Variant _get_collider() const; + + Vector2 floor_velocity; + bool on_floor; + bool on_ceiling; + bool on_wall; + Vector<Collision> colliders; _FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const; + Dictionary _move(const Vector2 &p_motion); + protected: static void _bind_methods(); public: - Vector2 move(const Vector2 &p_motion); - Vector2 move_to(const Vector2 &p_position); - + bool move(const Vector2 &p_motion, Collision &r_collision); bool test_move(const Transform2D &p_from, const Vector2 &p_motion); - bool is_colliding() const; - - Vector2 get_travel() const; - void revert_motion(); - - Vector2 get_collision_pos() const; - Vector2 get_collision_normal() const; - Vector2 get_collider_velocity() const; - ObjectID get_collider() const; - int get_collider_shape() const; - Variant get_collider_metadata() const; - void set_collision_margin(float p_margin); - float get_collision_margin() const; + void set_safe_margin(float p_margin); + float get_safe_margin() const; Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), float p_slope_stop_min_velocity = 5, int p_max_bounces = 4, float p_floor_max_angle = Math::deg2rad((float)45)); - bool is_move_and_slide_on_floor() const; - bool is_move_and_slide_on_wall() const; - bool is_move_and_slide_on_ceiling() const; - Array get_move_and_slide_colliders() const; + bool is_on_floor() const; + bool is_on_wall() const; + bool is_on_ceiling() const; + Vector2 get_floor_velocity() const; + + int get_collision_count() const; + Vector2 get_collision_position(int p_collision) const; + Vector2 get_collision_normal(int p_collision) const; + Vector2 get_collision_travel(int p_collision) const; + Vector2 get_collision_remainder(int p_collision) const; + Object *get_collision_local_shape(int p_collision) const; + Object *get_collision_collider(int p_collision) const; + ObjectID get_collision_collider_id(int p_collision) const; + Object *get_collision_collider_shape(int p_collision) const; + int get_collision_collider_shape_index(int p_collision) const; + Vector2 get_collision_collider_velocity(int p_collision) const; + Variant get_collision_collider_metadata(int p_collision) const; KinematicBody2D(); ~KinematicBody2D(); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index ff574a6bd6..450f8e2474 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -351,10 +351,12 @@ void Sprite::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map"); + ADD_GROUP("Offset", ""); ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v"); + ADD_GROUP("Animation", ""); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame"); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 4676f2c4c1..098bdf93de 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "tile_map.h" #include "io/marshalls.h" -#include "method_bind_ext.inc" +#include "method_bind_ext.gen.inc" #include "os/os.h" #include "servers/physics_2d_server.h" diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 5b5bce342d..e755b1480b 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -98,7 +98,7 @@ void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const { if (mesh.is_valid()) { for (int i = 0; i < mesh->get_surface_count(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "Material")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial")); } } } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 3394c1e204..c291aa33ed 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -58,6 +58,13 @@ void Particles::set_lifetime(float p_lifetime) { lifetime = p_lifetime; VS::get_singleton()->particles_set_lifetime(particles, lifetime); } + +void Particles::set_one_shot(bool p_one_shot) { + + one_shot = p_one_shot; + VS::get_singleton()->particles_set_one_shot(particles, one_shot); +} + void Particles::set_pre_process_time(float p_time) { pre_process_time = p_time; @@ -114,6 +121,11 @@ float Particles::get_lifetime() const { return lifetime; } +bool Particles::get_one_shot() const { + + return one_shot; +} + float Particles::get_pre_process_time() const { return pre_process_time; @@ -233,6 +245,11 @@ String Particles::get_configuration_warning() const { return warnings; } +void Particles::restart() { + + VisualServer::get_singleton()->particles_restart(particles); +} + Rect3 Particles::capture_aabb() const { return VS::get_singleton()->particles_get_current_aabb(particles); @@ -254,6 +271,7 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles::set_emitting); ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles::set_amount); ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles::set_lifetime); + ClassDB::bind_method(D_METHOD("set_one_shot", "enable"), &Particles::set_one_shot); ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles::set_pre_process_time); ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles::set_explosiveness_ratio); ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles::set_randomness_ratio); @@ -267,6 +285,7 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("is_emitting"), &Particles::is_emitting); ClassDB::bind_method(D_METHOD("get_amount"), &Particles::get_amount); ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles::get_lifetime); + ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles::get_one_shot); ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles::get_pre_process_time); ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles::get_explosiveness_ratio); ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles::get_randomness_ratio); @@ -287,23 +306,26 @@ void Particles::_bind_methods() { ClassDB::bind_method(D_METHOD("get_draw_passes"), &Particles::get_draw_passes); ClassDB::bind_method(D_METHOD("get_draw_pass_mesh:Mesh", "pass"), &Particles::get_draw_pass_mesh); + ClassDB::bind_method(D_METHOD("restart"), &Particles::restart); ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb); - ADD_GROUP("Parameters", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount"); + ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); - ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); + ADD_GROUP("Drawing", ""); + ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_aabb"), "set_visibility_aabb", "get_visibility_aabb"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); ADD_GROUP("Process Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes"); for (int i = 0; i < MAX_DRAW_PASSES; i++) { @@ -322,6 +344,7 @@ Particles::Particles() { particles = VS::get_singleton()->particles_create(); set_base(particles); set_emitting(true); + set_one_shot(false); set_amount(8); set_lifetime(1); set_fixed_fps(0); @@ -571,7 +594,7 @@ void ParticlesMaterial::_update_shader() { code += "\n"; code += " uint base_number=NUMBER/uint(trail_divisor);\n"; - code += " uint alt_seed=hash(base_number+uint(1));\n"; + code += " uint alt_seed=hash(base_number+uint(1)+RANDOM_SEED);\n"; code += " float angle_rand=rand_from_seed(alt_seed);\n"; code += " float scale_rand=rand_from_seed(alt_seed);\n"; code += " float hue_rot_rand=rand_from_seed(alt_seed);\n"; @@ -1082,16 +1105,9 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> case PARAM_SCALE: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); - Ref<CurveTexture> curve = p_texture; - if (curve.is_valid()) { - if (curve->get_min() == 0 && curve->get_max() == 1) { - - curve->set_max(32); - PoolVector<Vector2> points; - points.push_back(Vector2(0, 1)); - points.push_back(Vector2(1, 1)); - curve->set_points(points); - } + Ref<CurveTexture> curve_tex = p_texture; + if (curve_tex.is_valid()) { + curve_tex->ensure_default_setup(); } } break; @@ -1257,14 +1273,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail Ref<CurveTexture> curve = trail_size_modifier; if (curve.is_valid()) { - if (curve->get_min() == 0 && curve->get_max() == 1) { - - curve->set_max(32); - PoolVector<Vector2> points; - points.push_back(Vector2(0, 1)); - points.push_back(Vector2(1, 1)); - curve->set_points(points); - } + curve->ensure_default_setup(); } RID texture; diff --git a/scene/3d/particles.h b/scene/3d/particles.h index dad8ed4585..0549eb4c09 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -58,6 +58,7 @@ private: RID particles; bool emitting; + bool one_shot; int amount; float lifetime; float pre_process_time; @@ -86,6 +87,7 @@ public: void set_emitting(bool p_emitting); void set_amount(int p_amount); void set_lifetime(float p_lifetime); + void set_one_shot(bool p_enabled); void set_pre_process_time(float p_time); void set_explosiveness_ratio(float p_ratio); void set_randomness_ratio(float p_ratio); @@ -97,6 +99,7 @@ public: bool is_emitting() const; int get_amount() const; float get_lifetime() const; + bool get_one_shot() const; float get_pre_process_time() const; float get_explosiveness_ratio() const; float get_randomness_ratio() const; @@ -122,6 +125,8 @@ public: virtual String get_configuration_warning() const; + void restart(); + Rect3 capture_aabb() const; Particles(); ~Particles(); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 3a55a2bc32..2a7a804470 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "physics_body.h" -#include "method_bind_ext.inc" +#include "method_bind_ext.gen.inc" #include "scene/scene_string_names.h" void PhysicsBody::_notification(int p_what) { diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp index 874c21546d..abc7766ecb 100644 --- a/scene/3d/scenario_fx.cpp +++ b/scene/3d/scenario_fx.cpp @@ -28,43 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "scenario_fx.h" +#include "scene/main/viewport.h" void WorldEnvironment::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_WORLD) { + if (p_what == Spatial::NOTIFICATION_ENTER_WORLD || p_what == Spatial::NOTIFICATION_ENTER_TREE) { if (environment.is_valid()) { - if (get_world()->get_environment().is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); } - get_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } - } else if (p_what == NOTIFICATION_EXIT_WORLD) { + } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) { - if (environment.is_valid() && get_world()->get_environment() == environment) { - get_world()->set_environment(Ref<Environment>()); - remove_from_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref<Environment>()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } } } void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { - if (is_inside_world() && environment.is_valid() && get_world()->get_environment() == environment) { - get_world()->set_environment(Ref<Environment>()); - remove_from_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref<Environment>()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); //clean up } environment = p_environment; - if (is_inside_world() && environment.is_valid()) { - if (get_world()->get_environment().is_valid()) { + if (is_inside_tree() && environment.is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); } - get_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } update_configuration_warning(); @@ -77,11 +78,11 @@ Ref<Environment> WorldEnvironment::get_environment() const { String WorldEnvironment::get_configuration_warning() const { - if (!is_visible_in_tree() || !is_inside_tree() || !environment.is_valid()) + if (/*!is_visible_in_tree() ||*/ !is_inside_tree() || !environment.is_valid()) return String(); List<Node *> nodes; - get_tree()->get_nodes_in_group("_world_environment_" + itos(get_world()->get_scenario().get_id()), &nodes); + get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id()), &nodes); if (nodes.size() > 1) { return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h index b2a4bc5472..d1e0a63130 100644 --- a/scene/3d/scenario_fx.h +++ b/scene/3d/scenario_fx.h @@ -36,9 +36,9 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class WorldEnvironment : public Spatial { +class WorldEnvironment : public Node { - GDCLASS(WorldEnvironment, Spatial); + GDCLASS(WorldEnvironment, Node); Ref<Environment> environment; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index b6c59ba277..78e8e92afc 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -581,10 +581,12 @@ void Sprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); + ADD_GROUP("Animation", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region"), "set_region", "is_region"); + ADD_GROUP("Region", "region_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_SIGNAL(MethodInfo("frame_changed")); diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 104fa0f70f..6f8c38eddd 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -316,7 +316,7 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material_override", "get_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial"), "set_material_override", "get_material_override"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "visible_in_all_rooms"), "set_flag", "get_flag", FLAG_VISIBLE_IN_ALL_ROOMS); diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 67920d177e..ad0b0fbfb2 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "tween.h" -#include "method_bind_ext.inc" +#include "method_bind_ext.gen.inc" void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8, const Variant &p_arg9, const Variant &p_arg10) { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index ee6af21dbd..9ef340edbc 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -122,9 +122,6 @@ void ColorPicker::_value_changed(double) { } set_pick_color(color); - - _update_text_value(); - emit_signal("color_changed", color); } @@ -257,7 +254,7 @@ void ColorPicker::_update_text_value() { } void ColorPicker::_sample_draw() { - sample->draw_rect(Rect2(Point2(), Size2(256, 20)), color); + sample->draw_rect(Rect2(Point2(), Size2(uv_edit->get_size().width, 20)), color); } void ColorPicker::_hsv_draw(int p_wich, Control *c) { @@ -277,12 +274,12 @@ void ColorPicker::_hsv_draw(int p_wich, Control *c) { c->draw_polygon(points, colors); Vector<Color> colors2; Color col = color; - col.set_hsv(color.get_h(), 1, 1); + col.set_hsv(h, 1, 1); col.a = 0; colors2.push_back(col); col.a = 1; colors2.push_back(col); - col.set_hsv(color.get_h(), 1, 0); + col.set_hsv(h, 1, 0); colors2.push_back(col); col.a = 0; colors2.push_back(col); @@ -311,10 +308,10 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &ev) { if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { changing_color = true; - float x = CLAMP((float)bev->get_position().x, 0, 256); - float y = CLAMP((float)bev->get_position().y, 0, 256); - s = x / 256; - v = 1.0 - y / 256.0; + float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width); + float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height); + s = x / uv_edit->get_size().width; + v = 1.0 - y / uv_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -330,10 +327,10 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &ev) { if (mev.is_valid()) { if (!changing_color) return; - float x = CLAMP((float)mev->get_position().x, 0, 256); - float y = CLAMP((float)mev->get_position().y, 0, 256); - s = x / 256; - v = 1.0 - y / 256.0; + float x = CLAMP((float)mev->get_position().x, 0, uv_edit->get_size().width); + float y = CLAMP((float)mev->get_position().y, 0, uv_edit->get_size().height); + s = x / uv_edit->get_size().width; + v = 1.0 - y / uv_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -350,8 +347,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { changing_color = true; - h = 1 - (256.0 - (float)bev->get_position().y) / 256.0; - + float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); + h = y / w_edit->get_size().height; } else { changing_color = false; } @@ -368,9 +365,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (!changing_color) return; - float y = CLAMP((float)mev->get_position().y, 0, 256); - //h = 1.0 - y / 256.0; - h = y / 256.0; + float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); + h = y / w_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -508,12 +504,14 @@ ColorPicker::ColorPicker() add_child(hb_smpl); HBoxContainer *hb_edit = memnew(HBoxContainer); + hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); uv_edit = memnew(Control); uv_edit->connect("gui_input", this, "_uv_input"); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); - uv_edit->set_custom_minimum_size(Size2(256, 256)); + uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); + uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); Vector<Variant> args = Vector<Variant>(); args.push_back(0); args.push_back(uv_edit); @@ -523,7 +521,9 @@ ColorPicker::ColorPicker() w_edit = memnew(Control); //w_edit->set_ignore_mouse(false); - w_edit->set_custom_minimum_size(Size2(30, 256)); + w_edit->set_custom_minimum_size(Size2(30, 0)); + w_edit->set_h_size_flags(SIZE_FILL); + w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", this, "_w_input"); args.clear(); args.push_back(1); @@ -549,6 +549,7 @@ ColorPicker::ColorPicker() HBoxContainer *hbc = memnew(HBoxContainer); labels[i] = memnew(Label(lt[i])); + labels[i]->set_custom_minimum_size(Size2(10, 0)); hbc->add_child(labels[i]); scroll[i] = memnew(HSlider); @@ -570,7 +571,7 @@ ColorPicker::ColorPicker() HBoxContainer *hhb = memnew(HBoxContainer); btn_mode = memnew(CheckButton); - btn_mode->set_text("RAW Mode"); + btn_mode->set_text(TTR("RAW Mode")); btn_mode->connect("toggled", this, "set_raw_mode"); hhb->add_child(btn_mode); vbr->add_child(hhb); @@ -601,7 +602,7 @@ ColorPicker::ColorPicker() bt_add_preset = memnew(Button); bt_add_preset->set_icon(get_icon("add_preset")); - bt_add_preset->set_tooltip("Add current color as a preset"); + bt_add_preset->set_tooltip(TTR("Add current color as a preset")); bt_add_preset->connect("pressed", this, "_add_preset_pressed"); bbc->add_child(bt_add_preset); } diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 95f65f31d6..538dd846e4 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "graph_node.h" -#include "method_bind_ext.inc" +#include "method_bind_ext.gen.inc" bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { diff --git a/scene/gui/input_action.cpp b/scene/gui/input_action.cpp index 311cb4ab13..3f80c31c8b 100644 --- a/scene/gui/input_action.cpp +++ b/scene/gui/input_action.cpp @@ -43,7 +43,7 @@ Ref<InputEvent> ShortCut::get_shortcut() const { bool ShortCut::is_shortcut(const Ref<InputEvent> &p_event) const { - return shortcut.is_valid() && shortcut->action_match(p_event); + return shortcut.is_valid() && shortcut->shortcut_match(p_event); } String ShortCut::get_as_text() const { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 0b8595de42..78ede6e494 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1831,7 +1831,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("add_image", "image:Texture"), &RichTextLabel::add_image); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); ClassDB::bind_method(D_METHOD("remove_line"), &RichTextLabel::remove_line); - ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font); + ClassDB::bind_method(D_METHOD("push_font", "font:Font"), &RichTextLabel::push_font); ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color); ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align); ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent); @@ -1854,7 +1854,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scroll_follow", "follow"), &RichTextLabel::set_scroll_follow); ClassDB::bind_method(D_METHOD("is_scroll_following"), &RichTextLabel::is_scroll_following); - ClassDB::bind_method(D_METHOD("get_v_scroll"), &RichTextLabel::get_v_scroll); + ClassDB::bind_method(D_METHOD("get_v_scroll:VScrollBar"), &RichTextLabel::get_v_scroll); ClassDB::bind_method(D_METHOD("scroll_to_line", "line"), &RichTextLabel::scroll_to_line); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index d864d9fce7..d8788b4eca 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -622,6 +622,40 @@ bool TreeItem::is_custom_set_as_button(int p_column) const { return cells[p_column].custom_button; } +void TreeItem::set_text_align(int p_column, TextAlign p_align) { + ERR_FAIL_INDEX(p_column, cells.size()); + cells[p_column].text_align = p_align; + _changed_notify(p_column); +} + +TreeItem::TextAlign TreeItem::get_text_align(int p_column) const { + ERR_FAIL_INDEX_V(p_column, cells.size(), ALIGN_LEFT); + return cells[p_column].text_align; +} + +void TreeItem::set_expand_right(int p_column, bool p_enable) { + + ERR_FAIL_INDEX(p_column, cells.size()); + cells[p_column].expand_right = p_enable; + _changed_notify(p_column); +} + +bool TreeItem::get_expand_right(int p_column) const { + + ERR_FAIL_INDEX_V(p_column, cells.size(), false); + return cells[p_column].expand_right; +} + +void TreeItem::set_disable_folding(bool p_disable) { + + disable_folding = p_disable; + _changed_notify(0); +} + +bool TreeItem::is_folding_disabled() const { + return disable_folding; +} + void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_mode", "column", "mode"), &TreeItem::set_cell_mode); @@ -692,12 +726,19 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button); ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled); + ClassDB::bind_method(D_METHOD("set_expand_right", "column", "enable"), &TreeItem::set_expand_right); + ClassDB::bind_method(D_METHOD("get_expand_right", "column"), &TreeItem::get_expand_right); + ClassDB::bind_method(D_METHOD("set_tooltip", "column", "tooltip"), &TreeItem::set_tooltip); ClassDB::bind_method(D_METHOD("get_tooltip", "column"), &TreeItem::get_tooltip); - + ClassDB::bind_method(D_METHOD("set_text_align", "column", "text_align"), &TreeItem::set_text_align); + ClassDB::bind_method(D_METHOD("get_text_align", "column"), &TreeItem::get_text_align); ClassDB::bind_method(D_METHOD("move_to_top"), &TreeItem::move_to_top); ClassDB::bind_method(D_METHOD("move_to_bottom"), &TreeItem::move_to_bottom); + ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding); + ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled); + BIND_CONSTANT(CELL_MODE_STRING); BIND_CONSTANT(CELL_MODE_CHECK); BIND_CONSTANT(CELL_MODE_RANGE); @@ -724,6 +765,7 @@ TreeItem::TreeItem(Tree *p_tree) { tree = p_tree; collapsed = false; + disable_folding = false; parent = 0; // parent item next = 0; // next in list @@ -894,6 +936,32 @@ int Tree::get_item_height(TreeItem *p_item) const { void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color) { Rect2i rect = p_rect; + Ref<Font> font = cache.font; + String text = p_cell.text; + if (p_cell.suffix != String()) + text += " " + p_cell.suffix; + + int w = 0; + if (!p_cell.icon.is_null()) { + Size2i bmsize = p_cell.get_icon_size(); + + if (p_cell.icon_max_w > 0 && bmsize.width > p_cell.icon_max_w) { + bmsize.width = p_cell.icon_max_w; + } + w += bmsize.width + cache.hseparation; + } + w += font->get_string_size(text).width; + + switch (p_cell.text_align) { + case TreeItem::ALIGN_LEFT: + break; //do none + case TreeItem::ALIGN_CENTER: + rect.position.x = MAX(0, (rect.size.width - w) / 2); + break; //do none + case TreeItem::ALIGN_RIGHT: + rect.position.x = MAX(0, (rect.size.width - w)); + break; //do none + } RID ci = get_canvas_item(); if (!p_cell.icon.is_null()) { @@ -914,12 +982,6 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co rect.size.x-=Math::floor(rect.size.y/2); */ - Ref<Font> font = cache.font; - - String text = p_cell.text; - if (p_cell.suffix != String()) - text += " " + p_cell.suffix; - rect.position.y += Math::floor((rect.size.y - font->get_height()) / 2.0) + font->get_ascent(); font->draw(ci, rect.position, text, p_color, rect.size.x); } @@ -970,20 +1032,6 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (!skip && (p_pos.y + label_h - cache.offset.y) > 0) { - if (!hide_folding && p_item->childs) { //has childs, draw the guide box - - Ref<Texture> arrow; - - if (p_item->collapsed) { - - arrow = cache.arrow_collapsed; - } else { - arrow = cache.arrow; - } - - arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset); - } - //draw separation. //if (p_item->get_parent()!=root || !hide_root) @@ -991,9 +1039,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int font_ascent = font->get_ascent(); - int ofs = p_pos.x + (hide_folding ? cache.hseparation : cache.item_margin); + int ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); + int skip = 0; for (int i = 0; i < columns.size(); i++) { + if (skip) { + skip--; + continue; + } + int w = get_column_width(i); if (i == 0) { @@ -1011,6 +1065,16 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 w -= cache.hseparation; } + if (p_item->cells[i].expand_right) { + + int plus = 1; + while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) { + w += get_column_width(i + plus); + plus++; + skip++; + } + } + int bw = 0; for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { Ref<Texture> b = p_item->cells[i].buttons[j].texture; @@ -1076,8 +1140,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].custom_bg_color) { Rect2 r = cell_rect; - r.position.x -= cache.hseparation; - r.size.x += cache.hseparation; + if (i == 0) { + r.position.x = p_draw_ofs.x; + r.size.x = w + ofs; + } else { + r.position.x -= cache.hseparation; + r.size.x += cache.hseparation; + } if (p_item->cells[i].custom_bg_outline) { VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y, r.size.x, 1), p_item->cells[i].bg_color); VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(r.position.x, r.position.y + r.size.y - 1, r.size.x, 1), p_item->cells[i].bg_color); @@ -1274,6 +1343,19 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } + if (!p_item->disable_folding && !hide_folding && p_item->childs) { //has childs, draw the guide box + + Ref<Texture> arrow; + + if (p_item->collapsed) { + + arrow = cache.arrow_collapsed; + } else { + arrow = cache.arrow; + } + + arrow->draw(ci, p_pos + p_draw_ofs + Point2i(0, (label_h - arrow->get_height()) / 2) - cache.offset); + } //separator //get_painter()->draw_fill_rect( Point2i(0,pos.y),Size2i(get_size().width,1),color( COLOR_TREE_GRID) ); @@ -1295,8 +1377,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 while (c) { if (cache.draw_relationship_lines == 1) { - int root_ofs = children_pos.x + (hide_folding ? cache.hseparation : cache.item_margin); - int parent_ofs = p_pos.x + (hide_folding ? cache.hseparation : cache.item_margin); + int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); + int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; if (c->get_children() != NULL) root_pos -= Point2i(cache.arrow->get_width(), 0); @@ -1488,7 +1570,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool return -1; } - if (!hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) { + if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) { if (p_item->childs) p_item->set_collapsed(!p_item->is_collapsed()); @@ -1504,6 +1586,18 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool for (int i = 0; i < columns.size(); i++) { col_width = get_column_width(i); + + if (p_item->cells[i].expand_right) { + + int plus = 1; + while (i + plus < columns.size() && !p_item->cells[i + plus].editable && p_item->cells[i + plus].mode == TreeItem::CELL_MODE_STRING && p_item->cells[i + plus].text == "" && p_item->cells[i + plus].icon.is_null()) { + plus++; + col_width += cache.hseparation; + col_width += get_column_width(i + plus); + plus++; + } + } + if (x > col_width) { col_ofs += col_width; x -= col_width; @@ -1528,6 +1622,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool x -= cache.hseparation; } + if (!p_item->disable_folding && !hide_folding && !p_item->cells[col].editable && !p_item->cells[col].selectable && p_item->get_children()) { + p_item->set_collapsed(!p_item->is_collapsed()); + return -1; //collapse/uncollapse because nothing can be done with item + } + TreeItem::Cell &c = p_item->cells[col]; bool already_selected = c.selected; diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 097e0110e8..59e35bb230 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -58,6 +58,12 @@ public: CELL_MODE_CUSTOM, ///< Contains a custom value, show a string, and an edit button }; + enum TextAlign { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT + }; + private: friend class Tree; @@ -82,6 +88,9 @@ private: bool custom_bg_outline; Color bg_color; bool custom_button; + bool expand_right; + + TextAlign text_align; Variant meta; String tooltip; @@ -122,6 +131,8 @@ private: custom_bg_color = false; expr = false; icon_max_w = 0; + text_align = ALIGN_LEFT; + expand_right = false; } Size2 get_icon_size() const; @@ -131,6 +142,7 @@ private: Vector<Cell> cells; bool collapsed; // wont show childs + bool disable_folding; TreeItem *parent; // parent item TreeItem *next; // next in list @@ -248,13 +260,23 @@ public: void clear_children(); + void set_text_align(int p_column, TextAlign p_align); + TextAlign get_text_align(int p_column) const; + + void set_expand_right(int p_column, bool p_enable); + bool get_expand_right(int p_column) const; + void move_to_top(); void move_to_bottom(); + void set_disable_folding(bool p_disable); + bool is_folding_disabled() const; + ~TreeItem(); }; VARIANT_ENUM_CAST(TreeItem::TreeCellMode); +VARIANT_ENUM_CAST(TreeItem::TextAlign); class Tree : public Control { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 714327c5b7..a87c83f17c 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -49,6 +49,7 @@ #include "scene/scene_string_names.h" #include "global_config.h" +#include "scene/3d/scenario_fx.h" void ViewportTexture::setup_local_to_scene() { @@ -1017,10 +1018,9 @@ void Viewport::_propagate_enter_world(Node *p_node) { if (!p_node->is_inside_tree()) //may not have entered scene yet return; - Spatial *s = p_node->cast_to<Spatial>(); - if (s) { + if (p_node->cast_to<Spatial>() || p_node->cast_to<WorldEnvironment>()) { - s->notification(Spatial::NOTIFICATION_ENTER_WORLD); + p_node->notification(Spatial::NOTIFICATION_ENTER_WORLD); } else { Viewport *v = p_node->cast_to<Viewport>(); if (v) { @@ -1055,10 +1055,9 @@ void Viewport::_propagate_exit_world(Node *p_node) { if (!p_node->is_inside_tree()) //may have exited scene already return; - Spatial *s = p_node->cast_to<Spatial>(); - if (s) { + if (p_node->cast_to<Spatial>() || p_node->cast_to<WorldEnvironment>()) { - s->notification(Spatial::NOTIFICATION_EXIT_WORLD, true); + p_node->notification(Spatial::NOTIFICATION_EXIT_WORLD); } else { Viewport *v = p_node->cast_to<Viewport>(); if (v) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d4ca55346a..151bc80321 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -469,6 +469,9 @@ void register_scene_types() { ClassDB::register_class<Shader>(); ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); + ClassDB::register_class<CanvasItemMaterial>(); + SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes); + CanvasItemMaterial::init_shaders(); ClassDB::register_class<Node2D>(); ClassDB::register_class<Particles2D>(); //ClassDB::register_class<ParticleAttractor2D>(); @@ -577,6 +580,7 @@ void register_scene_types() { ClassDB::register_class<Animation>(); ClassDB::register_virtual_class<Font>(); ClassDB::register_class<BitmapFont>(); + ClassDB::register_class<Curve>(); ClassDB::register_class<DynamicFontData>(); ClassDB::register_class<DynamicFont>(); @@ -663,5 +667,6 @@ void unregister_scene_types() { SpatialMaterial::finish_shaders(); ParticlesMaterial::finish_shaders(); + CanvasItemMaterial::finish_shaders(); SceneStringNames::free(); } diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 10c12c9411..3957923c6a 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -380,6 +380,365 @@ Curve2D::Curve2D() #endif +Curve::Curve() { + _bake_resolution = 100; + _baked_cache_dirty = false; +#ifdef TOOLS_ENABLED + _disable_set_data = false; +#endif +} + +int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { + // Add a point and preserve order + + // Curve bounds is in 0..1 + if (p_pos.x > MAX_X) + p_pos.x = MAX_X; + else if (p_pos.x < MIN_X) + p_pos.x = MIN_X; + + int ret = -1; + + if (_points.size() == 0) { + _points.push_back(Point(p_pos, left_tangent, right_tangent)); + ret = 0; + + } else if (_points.size() == 1) { + // TODO Is the `else` able to handle this block already? + + real_t diff = p_pos.x - _points[0].pos.x; + + if (diff > 0) { + _points.push_back(Point(p_pos, left_tangent, right_tangent)); + ret = 1; + } else { + _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + ret = 0; + } + + } else { + + int i = get_index(p_pos.x); + + int nearest_index = i; + if (i + 1 < _points.size()) { + real_t diff0 = p_pos.x - _points[i].pos.x; + real_t diff1 = _points[i + 1].pos.x - p_pos.x; + + if (diff1 < diff0) + nearest_index = i + 1; + } + + if (i == 0 && p_pos.x < _points[0].pos.x) { + // Insert before anything else + _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + ret = 0; + } else { + // Insert between i and i+1 + ++i; + _points.insert(i, Point(p_pos, left_tangent, right_tangent)); + ret = i; + } + } + + mark_dirty(); + + return ret; +} + +int Curve::get_index(real_t offset) const { + + // Lower-bound float binary search + + int imin = 0; + int imax = _points.size() - 1; + + while (imax - imin > 1) { + int m = (imin + imax) / 2; + + real_t a = _points[m].pos.x; + real_t b = _points[m + 1].pos.x; + + if (a < offset && b < offset) { + imin = m; + + } else if (a > offset) { + imax = m; + + } else { + return m; + } + } + + // Will happen if the offset is out of bounds + if (offset > _points[imax].pos.x) + return imax; + return imin; +} + +void Curve::clean_dupes() { + + bool dirty = false; + + for (int i = 1; i < _points.size(); ++i) { + real_t diff = _points[i - 1].pos.x - _points[i].pos.x; + if (diff <= CMP_EPSILON) { + _points.remove(i); + --i; + dirty = true; + } + } + + if (dirty) + mark_dirty(); +} + +void Curve::set_point_left_tangent(int i, real_t tangent) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].left_tangent = tangent; + mark_dirty(); +} + +void Curve::set_point_right_tangent(int i, real_t tangent) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].right_tangent = tangent; + mark_dirty(); +} + +real_t Curve::get_point_left_tangent(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), 0); + return _points[i].left_tangent; +} + +real_t Curve::get_point_right_tangent(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), 0); + return _points[i].right_tangent; +} + +void Curve::remove_point(int p_index) { + ERR_FAIL_INDEX(p_index, _points.size()); + _points.remove(p_index); + mark_dirty(); +} + +void Curve::clear_points() { + _points.clear(); + mark_dirty(); +} + +void Curve::set_point_value(int p_index, real_t pos) { + ERR_FAIL_INDEX(p_index, _points.size()); + _points[p_index].pos.y = pos; + mark_dirty(); +} + +int Curve::set_point_offset(int p_index, float offset) { + ERR_FAIL_INDEX_V(p_index, _points.size(), -1); + Point p = _points[p_index]; + remove_point(p_index); + int i = add_point(Vector2(offset, p.pos.y)); + _points[i].left_tangent = p.left_tangent; + _points[i].right_tangent = p.right_tangent; + return i; +} + +Vector2 Curve::get_point_pos(int p_index) const { + ERR_FAIL_INDEX_V(p_index, _points.size(), Vector2(0, 0)); + return _points[p_index].pos; +} + +real_t Curve::interpolate(real_t offset) const { + if (_points.size() == 0) + return 0; + if (_points.size() == 1) + return _points[0].pos.y; + + int i = get_index(offset); + + if (i == _points.size() - 1) + return _points[i].pos.y; + + real_t local = offset - _points[i].pos.x; + + if (i == 0 && local <= 0) + return _points[0].pos.y; + + return interpolate_local_nocheck(i, local); +} + +real_t Curve::interpolate_local_nocheck(int index, real_t local_offset) const { + + const Point a = _points[index]; + const Point b = _points[index + 1]; + + // Cubic bezier + + // ac-----bc + // / \ + // / \ Here with a.right_tangent > 0 + // / \ and b.left_tangent < 0 + // / \ + // a b + // + // |-d1--|-d2--|-d3--| + // + // d1 == d2 == d3 == d / 3 + + // Control points are chosen at equal distances + real_t d = b.pos.x - a.pos.x; + if (Math::abs(d) <= CMP_EPSILON) + return b.pos.y; + local_offset /= d; + d /= 3.0; + real_t yac = a.pos.y + d * a.right_tangent; + real_t ybc = b.pos.y - d * b.left_tangent; + + real_t y = _bezier_interp(local_offset, a.pos.y, yac, ybc, b.pos.y); + + return y; +} + +void Curve::mark_dirty() { + _baked_cache_dirty = true; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +Array Curve::get_data() const { + + Array output; + output.resize(_points.size() * 3); + + for (int j = 0; j < _points.size(); ++j) { + + const Point p = _points[j]; + int i = j * 3; + + output[i] = p.pos; + output[i + 1] = p.left_tangent; + output[i + 2] = p.right_tangent; + } + + return output; +} + +void Curve::set_data(Array input) { + ERR_FAIL_COND(input.size() % 3 != 0); + +#ifdef TOOLS_ENABLED + if (_disable_set_data) + return; +#endif + + _points.clear(); + + // Validate input + for (int i = 0; i < input.size(); i += 3) { + ERR_FAIL_COND(input[i].get_type() != Variant::VECTOR2); + ERR_FAIL_COND(input[i + 1].get_type() != Variant::REAL); + ERR_FAIL_COND(input[i + 2].get_type() != Variant::REAL); + } + + _points.resize(input.size() / 3); + + for (int j = 0; j < _points.size(); ++j) { + + Point &p = _points[j]; + int i = j * 3; + + p.pos = input[i]; + p.left_tangent = input[i + 1]; + p.right_tangent = input[i + 2]; + } + + mark_dirty(); +} + +void Curve::bake() { + _baked_cache.clear(); + + _baked_cache.resize(_bake_resolution); + + for (int i = 1; i < _bake_resolution - 1; ++i) { + real_t x = i / static_cast<real_t>(_bake_resolution); + real_t y = interpolate(x); + _baked_cache[i] = y; + } + + if (_points.size() != 0) { + _baked_cache[0] = _points[0].pos.y; + _baked_cache[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y; + } + + _baked_cache_dirty = false; +} + +void Curve::set_bake_resolution(int p_resolution) { + ERR_FAIL_COND(p_resolution < 1); + ERR_FAIL_COND(p_resolution > 1000); + _bake_resolution = p_resolution; + _baked_cache_dirty = true; +} + +real_t Curve::interpolate_baked(real_t offset) { + if (_baked_cache_dirty) { + // Last-second bake if not done already + bake(); + } + + // Special cases if the cache is too small + if (_baked_cache.size() == 0) { + if (_points.size() == 0) + return 0; + return _points[0].pos.y; + } else if (_baked_cache.size() == 1) { + return _baked_cache[0]; + } + + // Get interpolation index + real_t fi = offset * _baked_cache.size(); + int i = Math::floor(fi); + if (i < 0) { + i = 0; + fi = 0; + } else if (i >= _baked_cache.size()) { + i = _baked_cache.size() - 1; + fi = 0; + } + + // Interpolate + if (i + 1 < _baked_cache.size()) { + real_t t = fi - i; + return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t); + } else { + return _baked_cache[_baked_cache.size() - 1]; + } +} + +void Curve::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_point", "pos", "left_tangent", "right_tangent"), &Curve::add_point, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point); + ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points); + ClassDB::bind_method(D_METHOD("get_point_pos", "index"), &Curve::get_point_pos); + ClassDB::bind_method(D_METHOD("set_point_value", "index", "y"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("set_point_offset", "index", "offset"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate); + ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked); + ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent); + ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_left_tangent); + ClassDB::bind_method(D_METHOD("set_point_left_tangent", "index", "tangent"), &Curve::set_point_left_tangent); + ClassDB::bind_method(D_METHOD("set_point_right_tangent", "index", "tangent"), &Curve::set_point_left_tangent); + ClassDB::bind_method(D_METHOD("clean_dupes"), &Curve::clean_dupes); + ClassDB::bind_method(D_METHOD("bake"), &Curve::bake); + ClassDB::bind_method(D_METHOD("get_bake_resolution"), &Curve::get_bake_resolution); + ClassDB::bind_method(D_METHOD("set_bake_resolution", "resolution"), &Curve::set_bake_resolution); + ClassDB::bind_method(D_METHOD("_get_data"), &Curve::get_data); + ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve::set_data); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); +} + int Curve2D::get_point_count() const { return points.size(); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 17c0ac9f5e..63b9a07f07 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -82,6 +82,78 @@ public: #endif +// y(x) curve +class Curve : public Resource { + GDCLASS(Curve, Resource) +public: + static const int MIN_X = 0.f; + static const int MAX_X = 1.f; + +#ifdef TOOLS_ENABLED + bool _disable_set_data; +#endif + + struct Point { + Vector2 pos; + real_t left_tangent; + real_t right_tangent; + + Point() { + left_tangent = 0; + right_tangent = 0; + } + + Point(Vector2 p, real_t left = 0, real_t right = 0) { + pos = p; + left_tangent = left; + right_tangent = right; + } + }; + + Curve(); + + int get_point_count() const { return _points.size(); } + + int add_point(Vector2 p_pos, real_t left_tangent = 0, real_t right_tangent = 0); + void remove_point(int p_index); + void clear_points(); + + int get_index(real_t offset) const; + + void set_point_value(int p_index, real_t pos); + int set_point_offset(int p_index, float offset); + Vector2 get_point_pos(int p_index) const; + + real_t interpolate(real_t offset) const; + real_t interpolate_local_nocheck(int index, real_t local_offset) const; + + void clean_dupes(); + + void set_point_left_tangent(int i, real_t tangent); + void set_point_right_tangent(int i, real_t tangent); + real_t get_point_left_tangent(int i) const; + real_t get_point_right_tangent(int i) const; + + Array get_data() const; + void set_data(Array input); + + void bake(); + int get_bake_resolution() const { return _bake_resolution; } + void set_bake_resolution(int p_interval); + real_t interpolate_baked(real_t offset); + +protected: + static void _bind_methods(); + +private: + void mark_dirty(); + + Vector<Point> _points; + bool _baked_cache_dirty; + Vector<real_t> _baked_cache; + int _bake_resolution; +}; + class Curve2D : public Resource { GDCLASS(Curve2D, Resource); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index a435ba06cc..24e3977de8 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -959,7 +959,6 @@ void Environment::_bind_methods() { ADD_GROUP("SS Reflections", "ss_reflections_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_enabled"), "set_ssr_enabled", "is_ssr_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ss_reflections_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_accel", PROPERTY_HINT_RANGE, "0,4,0.01"), "set_ssr_accel", "get_ssr_accel"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance"); @@ -1040,7 +1039,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_far_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_far_amount", "get_dof_blur_far_amount"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dof_blur_far_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_dof_blur_far_quality", "get_dof_blur_far_quality"); - ADD_GROUP("DOF Far Near", "dof_blur_near_"); + ADD_GROUP("DOF Near Blur", "dof_blur_near_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index ce88325539..0912c70144 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1232,17 +1232,17 @@ void SpatialMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "albedo_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ALBEDO); ADD_GROUP("Metallic", "metallic_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_metallic", "get_metallic"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_metallic", "get_metallic"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "metallic_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_specular", "get_specular"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "metallic_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_METALLIC); ADD_GROUP("Roughness", "roughness_"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "roughness_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_roughness", "get_roughness"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "roughness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_roughness", "get_roughness"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "roughness_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_ROUGHNESS); ADD_GROUP("Emission", "emission_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_enabled"), "set_feature", "get_feature", FEATURE_EMISSION); - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION); @@ -1253,19 +1253,19 @@ void SpatialMaterial::_bind_methods() { ADD_GROUP("Rim", "rim_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "rim_enabled"), "set_feature", "get_feature", FEATURE_RIM); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim", "get_rim"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim", "get_rim"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rim_tint", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_rim_tint", "get_rim_tint"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "rim_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_RIM); ADD_GROUP("Clearcoat", "clearcoat_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "clearcoat_enabled"), "set_feature", "get_feature", FEATURE_CLEARCOAT); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat", "get_clearcoat"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "clearcoat_gloss", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_clearcoat_gloss", "get_clearcoat_gloss"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "clearcoat_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_CLEARCOAT); ADD_GROUP("Anisotropy", "anisotropy_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "anisotropy_enabled"), "set_feature", "get_feature", FEATURE_ANISOTROPY); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy_anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "anisotropy", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy", "get_anisotropy"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anisotropy_flowmap", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_FLOWMAP); ADD_GROUP("Ambient Occlusion", "ao_"); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index a3180ee1df..ef7011b2af 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -668,7 +668,11 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::DICTIONARY, "surfaces/" + itos(i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "Material", PROPERTY_USAGE_EDITOR)); + if (surfaces[i].is_2d) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR)); + } else { + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial", PROPERTY_USAGE_EDITOR)); + } } p_list->push_back(PropertyInfo(Variant::RECT3, "custom_aabb/custom_aabb")); @@ -692,6 +696,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Surface s; s.aabb = p_aabb; + s.is_2d = p_format & ARRAY_FLAG_USE_2D_VERTICES; surfaces.push_back(s); _recompute_aabb(); @@ -709,7 +714,8 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & /* make aABB? */ { - PoolVector<Vector3> vertices = p_arrays[ARRAY_VERTEX]; + Variant arr = p_arrays[ARRAY_VERTEX]; + PoolVector<Vector3> vertices = arr; int len = vertices.size(); ERR_FAIL_COND(len == 0); PoolVector<Vector3>::Read r = vertices.read(); @@ -726,6 +732,7 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & } surfaces[surfaces.size() - 1].aabb = aabb; + surfaces[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; _recompute_aabb(); } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 37fddf3aa6..f716b59fe9 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -147,6 +147,7 @@ private: String name; Rect3 aabb; Ref<Material> material; + bool is_2d; }; Vector<Surface> surfaces; RID mesh; diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 60fb97c792..b2822ca0c4 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "surface_tool.h" -#include "method_bind_ext.inc" +#include "method_bind_ext.gen.inc" #define _VERTEX_SNAP 0.0001 #define EQ_VERTEX_DIST 0.00001 diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 2120b37497..0bd8c41228 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -28,9 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "texture.h" -#include "core/method_bind_ext.inc" +#include "core/method_bind_ext.gen.inc" #include "core/os/os.h" +#include "core_string_names.h" #include "io/image_loader.h" + Size2 Texture::get_size() const { return Size2(get_width(), get_height()); @@ -1376,254 +1378,126 @@ void CurveTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width); - ClassDB::bind_method(D_METHOD("set_points", "points"), &CurveTexture::set_points); - ClassDB::bind_method(D_METHOD("get_points"), &CurveTexture::get_points); + ClassDB::bind_method(D_METHOD("set_curve", "curve:Curve"), &CurveTexture::set_curve); + ClassDB::bind_method(D_METHOD("get_curve:Curve"), &CurveTexture::get_curve); + + ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update); ADD_PROPERTY(PropertyInfo(Variant::REAL, "min", PROPERTY_HINT_RANGE, "-1024,1024"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max", PROPERTY_HINT_RANGE, "-1024,1024"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); } void CurveTexture::set_max(float p_max) { - max = p_max; + _max = p_max; emit_changed(); } float CurveTexture::get_max() const { - return max; + return _max; } void CurveTexture::set_min(float p_min) { - min = p_min; + _min = p_min; emit_changed(); } float CurveTexture::get_min() const { - return min; + return _min; } void CurveTexture::set_width(int p_width) { ERR_FAIL_COND(p_width < 32 || p_width > 4096); - width = p_width; - if (points.size()) - set_points(points); + _width = p_width; + _update(); } int CurveTexture::get_width() const { - return width; + return _width; } -static void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, float *p_heights, bool *p_useds, int p_width, float p_min, float p_max) { - - float geometry[4][4]; - float tmp1[4][4]; - float tmp2[4][4]; - float deltas[4][4]; - double x, dx, dx2, dx3; - double y, dy, dy2, dy3; - double d, d2, d3; - int lastx; - int newx; - float lasty; - float newy; - int ntimes; - int i, j; - - int xmax = p_width; - - /* construct the geometry matrix from the segment */ - for (i = 0; i < 4; i++) { - geometry[i][2] = 0; - geometry[i][3] = 0; - } +void CurveTexture::ensure_default_setup() { - geometry[0][0] = (p_a[0] * xmax); - geometry[1][0] = (p_b[0] * xmax); - geometry[2][0] = (p_c[0] * xmax); - geometry[3][0] = (p_d[0] * xmax); - - geometry[0][1] = (p_a[1]); - geometry[1][1] = (p_b[1]); - geometry[2][1] = (p_c[1]); - geometry[3][1] = (p_d[1]); - - /* subdivide the curve ntimes (1000) times */ - ntimes = 4 * xmax; - /* ntimes can be adjusted to give a finer or coarser curve */ - d = 1.0 / ntimes; - d2 = d * d; - d3 = d * d * d; - - /* construct a temporary matrix for determining the forward differencing deltas */ - tmp2[0][0] = 0; - tmp2[0][1] = 0; - tmp2[0][2] = 0; - tmp2[0][3] = 1; - tmp2[1][0] = d3; - tmp2[1][1] = d2; - tmp2[1][2] = d; - tmp2[1][3] = 0; - tmp2[2][0] = 6 * d3; - tmp2[2][1] = 2 * d2; - tmp2[2][2] = 0; - tmp2[2][3] = 0; - tmp2[3][0] = 6 * d3; - tmp2[3][1] = 0; - tmp2[3][2] = 0; - tmp2[3][3] = 0; - - /* compose the basis and geometry matrices */ - - static const float CR_basis[4][4] = { - { -0.5, 1.5, -1.5, 0.5 }, - { 1.0, -2.5, 2.0, -0.5 }, - { -0.5, 0.0, 0.5, 0.0 }, - { 0.0, 1.0, 0.0, 0.0 }, - }; - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] + - CR_basis[i][1] * geometry[1][j] + - CR_basis[i][2] * geometry[2][j] + - CR_basis[i][3] * geometry[3][j]); - } + if (_curve.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + set_curve(curve); } - /* compose the above results to get the deltas matrix */ - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - deltas[i][j] = (tmp2[i][0] * tmp1[0][j] + - tmp2[i][1] * tmp1[1][j] + - tmp2[i][2] * tmp1[2][j] + - tmp2[i][3] * tmp1[3][j]); - } + + if (get_min() == 0 && get_max() == 1) { + set_max(32); } +} - /* extract the x deltas */ - x = deltas[0][0]; - dx = deltas[1][0]; - dx2 = deltas[2][0]; - dx3 = deltas[3][0]; - - /* extract the y deltas */ - y = deltas[0][1]; - dy = deltas[1][1]; - dy2 = deltas[2][1]; - dy3 = deltas[3][1]; - - lastx = CLAMP(x, 0, xmax); - lasty = y; - - p_heights[lastx] = lasty; - p_useds[lastx] = true; - - /* loop over the curve */ - for (i = 0; i < ntimes; i++) { - /* increment the x values */ - x += dx; - dx += dx2; - dx2 += dx3; - - /* increment the y values */ - y += dy; - dy += dy2; - dy2 += dy3; - - newx = CLAMP((Math::round(x)), 0, xmax); - newy = CLAMP(y, p_min, p_max); - - /* if this point is different than the last one...then draw it */ - if ((lastx != newx) || (lasty != newy)) { - p_useds[newx] = true; - p_heights[newx] = newy; +void CurveTexture::set_curve(Ref<Curve> p_curve) { + if (_curve != p_curve) { + if (_curve.is_valid()) { + _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_update"); } - - lastx = newx; - lasty = newy; + _curve = p_curve; + if (_curve.is_valid()) { + _curve->connect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + _update(); } } -void CurveTexture::set_points(const PoolVector<Vector2> &p_points) { - - points = p_points; +void CurveTexture::_update() { PoolVector<uint8_t> data; - PoolVector<bool> used; - data.resize(width * sizeof(float)); - used.resize(width); + data.resize(_width * sizeof(float)); + + // The array is locked in that scope { PoolVector<uint8_t>::Write wd8 = data.write(); float *wd = (float *)wd8.ptr(); - PoolVector<bool>::Write wu = used.write(); - int pc = p_points.size(); - PoolVector<Vector2>::Read pr = p_points.read(); - - for (int i = 0; i < width; i++) { - wd[i] = 0.0; - wu[i] = false; - } - - Vector2 prev = Vector2(0, 0); - Vector2 prev2 = Vector2(0, 0); - - for (int i = -1; i < pc; i++) { - Vector2 next; - Vector2 next2; - if (i + 1 >= pc) { - next = Vector2(1, 0); - } else { - next = Vector2(pr[i + 1].x, pr[i + 1].y); + if (_curve.is_valid()) { + Curve &curve = **_curve; + float height = _max - _min; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + float v = curve.interpolate_baked(t); + wd[i] = CLAMP(_min + v * height, _min, _max); } - if (i + 2 >= pc) { - next2 = Vector2(1, 0); - } else { - next2 = Vector2(pr[i + 2].x, pr[i + 2].y); + } else { + for (int i = 0; i < _width; ++i) { + wd[i] = 0; } - - /*if (i==-1 && prev.offset==next.offset) { - prev=next; - continue; - }*/ - - _plot_curve(prev2, prev, next, next2, wd, wu.ptr(), width, min, max); - - prev2 = prev; - prev = next; } } - Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RF, data)); + Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data)); - VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER); - VS::get_singleton()->texture_set_data(texture, image); + VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER); + VS::get_singleton()->texture_set_data(_texture, image); emit_changed(); } -PoolVector<Vector2> CurveTexture::get_points() const { +Ref<Curve> CurveTexture::get_curve() const { - return points; + return _curve; } RID CurveTexture::get_rid() const { - return texture; + return _texture; } CurveTexture::CurveTexture() { - max = 1; - min = 0; - width = 2048; - texture = VS::get_singleton()->texture_create(); + _max = 1; + _min = 0; + _width = 2048; + _texture = VS::get_singleton()->texture_create(); } CurveTexture::~CurveTexture() { - VS::get_singleton()->free(texture); + VS::get_singleton()->free(_texture); } ////////////////// @@ -1634,13 +1508,6 @@ CurveTexture::~CurveTexture() { #define COLOR_RAMP_SET_COLORS "set_colors" GradientTexture::GradientTexture() { - //Set initial color ramp transition from black to white - points.resize(2); - points[0].color = Color(0, 0, 0, 1); - points[0].offset = 0; - points[1].color = Color(1, 1, 1, 1); - points[1].offset = 1; - is_sorted = true; update_pending = false; width = 2048; @@ -1654,32 +1521,33 @@ GradientTexture::~GradientTexture() { void GradientTexture::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &GradientTexture::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &GradientTexture::remove_point); - - ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &GradientTexture::set_offset); - ClassDB::bind_method(D_METHOD("get_offset", "point"), &GradientTexture::get_offset); - - ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &GradientTexture::set_color); - ClassDB::bind_method(D_METHOD("get_color", "point"), &GradientTexture::get_color); + ClassDB::bind_method(D_METHOD("set_gradient", "gradient:Gradient"), &GradientTexture::set_gradient); + ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &GradientTexture::get_gradient); ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width); - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &GradientTexture::get_color_at_offset); - - ClassDB::bind_method(D_METHOD("get_point_count"), &GradientTexture::get_points_count); - ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &GradientTexture::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &GradientTexture::get_offsets); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width"); +} - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &GradientTexture::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &GradientTexture::get_colors); +void GradientTexture::set_gradient(Ref<Gradient> p_gradient) { + if (p_gradient == gradient) + return; + if (gradient.is_valid()) { + gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + gradient = p_gradient; + if (gradient.is_valid()) { + gradient->connect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + _update(); + emit_changed(); +} - ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); +Ref<Gradient> GradientTexture::get_gradient() const { + return gradient; } void GradientTexture::_queue_update() { @@ -1692,16 +1560,22 @@ void GradientTexture::_queue_update() { void GradientTexture::_update() { + if (gradient.is_null()) + return; + update_pending = false; PoolVector<uint8_t> data; data.resize(width * 4); { PoolVector<uint8_t>::Write wd8 = data.write(); + Gradient &g = **gradient; + for (int i = 0; i < width; i++) { + float ofs = float(i) / (width - 1); + Color color = g.get_color_at_offset(ofs); - Color color = get_color_at_offset(ofs); wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255)); wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255)); wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255)); @@ -1727,112 +1601,6 @@ int GradientTexture::get_width() const { return width; } -Vector<float> GradientTexture::get_offsets() const { - Vector<float> offsets; - offsets.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - offsets[i] = points[i].offset; - } - return offsets; -} - -Vector<Color> GradientTexture::get_colors() const { - Vector<Color> colors; - colors.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - colors[i] = points[i].color; - } - return colors; -} - -void GradientTexture::set_offsets(const Vector<float> &p_offsets) { - points.resize(p_offsets.size()); - for (int i = 0; i < points.size(); i++) { - points[i].offset = p_offsets[i]; - } - is_sorted = false; - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_colors(const Vector<Color> &p_colors) { - if (points.size() < p_colors.size()) - is_sorted = false; - points.resize(p_colors.size()); - for (int i = 0; i < points.size(); i++) { - points[i].color = p_colors[i]; - } - emit_changed(); - _queue_update(); -} - -Vector<GradientTexture::Point> &GradientTexture::get_points() { - return points; -} - -void GradientTexture::add_point(float p_offset, const Color &p_color) { - - Point p; - p.offset = p_offset; - p.color = p_color; - is_sorted = false; - points.push_back(p); - - emit_changed(); - _queue_update(); -} - -void GradientTexture::remove_point(int p_index) { - - ERR_FAIL_INDEX(p_index, points.size()); - ERR_FAIL_COND(points.size() <= 2); - points.remove(p_index); - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_points(Vector<GradientTexture::Point> &p_points) { - points = p_points; - is_sorted = false; - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_offset(int pos, const float offset) { - if (points.size() <= pos) - points.resize(pos + 1); - points[pos].offset = offset; - is_sorted = false; - emit_changed(); - _queue_update(); -} - -float GradientTexture::get_offset(int pos) const { - if (points.size() > pos) - return points[pos].offset; - return 0; //TODO: Maybe throw some error instead? -} - Ref<Image> GradientTexture::get_data() const { return VisualServer::get_singleton()->texture_get_data(texture); } - -void GradientTexture::set_color(int pos, const Color &color) { - if (points.size() <= pos) { - points.resize(pos + 1); - is_sorted = false; - } - points[pos].color = color; - emit_changed(); - _queue_update(); -} - -Color GradientTexture::get_color(int pos) const { - if (points.size() > pos) - return points[pos].color; - return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? -} - -int GradientTexture::get_points_count() const { - return points.size(); -} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 2b82dbd21f..ff5a58c221 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -30,9 +30,11 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include "curve.h" #include "io/resource_loader.h" #include "math_2d.h" #include "resource.h" +#include "scene/resources/color_ramp.h" #include "servers/visual_server.h" /** @@ -389,20 +391,22 @@ public: ~CubeMap(); }; -VARIANT_ENUM_CAST(CubeMap::Flags); -VARIANT_ENUM_CAST(CubeMap::Side); -VARIANT_ENUM_CAST(CubeMap::Storage); +VARIANT_ENUM_CAST(CubeMap::Flags) +VARIANT_ENUM_CAST(CubeMap::Side) +VARIANT_ENUM_CAST(CubeMap::Storage) class CurveTexture : public Texture { - GDCLASS(CurveTexture, Texture); - RES_BASE_EXTENSION("curvetex"); + GDCLASS(CurveTexture, Texture) + RES_BASE_EXTENSION("curvetex") private: - RID texture; - PoolVector<Vector2> points; - float min, max; - int width; + RID _texture; + Ref<Curve> _curve; + float _min, _max; + int _width; + + void _update(); protected: static void _bind_methods(); @@ -417,8 +421,10 @@ public: void set_width(int p_width); int get_width() const; - void set_points(const PoolVector<Vector2> &p_points); - PoolVector<Vector2> get_points() const; + void ensure_default_setup(); + + void set_curve(Ref<Curve> p_curve); + Ref<Curve> get_curve() const; virtual RID get_rid() const; @@ -446,7 +452,7 @@ public: //VARIANT_ENUM_CAST( Texture::CubeMapSide ); class GradientTexture : public Texture { - GDCLASS(GradientTexture, Texture); + GDCLASS(GradientTexture, Texture) public: struct Point { @@ -459,8 +465,7 @@ public: }; private: - Vector<Point> points; - bool is_sorted; + Ref<Gradient> gradient; bool update_pending; RID texture; int width; @@ -472,23 +477,8 @@ protected: static void _bind_methods(); public: - void add_point(float p_offset, const Color &p_color); - void remove_point(int p_index); - - void set_points(Vector<Point> &points); - Vector<Point> &get_points(); - - void set_offset(int pos, const float offset); - float get_offset(int pos) const; - - void set_color(int pos, const Color &color); - Color get_color(int pos) const; - - void set_offsets(const Vector<float> &offsets); - Vector<float> get_offsets() const; - - void set_colors(const Vector<Color> &colors); - Vector<Color> get_colors() const; + void set_gradient(Ref<Gradient> p_gradient); + Ref<Gradient> get_gradient() const; void set_width(int p_width); int get_width() const; @@ -500,52 +490,8 @@ public: virtual void set_flags(uint32_t p_flags) {} virtual uint32_t get_flags() const { return FLAG_FILTER; } - _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { - - if (points.empty()) - return Color(0, 0, 0, 1); - - if (!is_sorted) { - points.sort(); - is_sorted = true; - } - - //binary search - int low = 0; - int high = points.size() - 1; - int middle; - - while (low <= high) { - middle = (low + high) / 2; - Point &point = points[middle]; - if (point.offset > p_offset) { - high = middle - 1; //search low end of array - } else if (point.offset < p_offset) { - low = middle + 1; //search high end of array - } else { - return point.color; - } - } - - //return interpolated value - if (points[middle].offset > p_offset) { - middle--; - } - int first = middle; - int second = middle + 1; - if (second >= points.size()) - return points[points.size() - 1].color; - if (first < 0) - return points[0].color; - Point &pointFirst = points[first]; - Point &pointSecond = points[second]; - return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); - } - virtual Ref<Image> get_data() const; - int get_points_count() const; - GradientTexture(); virtual ~GradientTexture(); }; |