diff options
Diffstat (limited to 'scene')
66 files changed, 1197 insertions, 627 deletions
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 9eff107827..40013814f8 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -205,7 +205,7 @@ void Navigation2D::_navpoly_unlink(int p_id) { nm.linked = false; } -int Navigation2D::navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) { +int Navigation2D::navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) { int id = last_id++; NavMesh nm; @@ -708,7 +708,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) { void Navigation2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("navpoly_create", "mesh", "xform", "owner"), &Navigation2D::navpoly_create, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform); ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove); diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h index bb97e1a9a9..02dbcb0f96 100644 --- a/scene/2d/navigation2d.h +++ b/scene/2d/navigation2d.h @@ -159,7 +159,7 @@ protected: public: //API should be as dynamic as possible - int navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); + int navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL); void navpoly_set_transform(int p_id, const Transform2D &p_xform); void navpoly_remove(int p_id); diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index c53241e985..5a6a5128e6 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -293,7 +293,7 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) { if (navpoly.is_valid()) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } } } @@ -324,7 +324,7 @@ void NavigationPolygonInstance::_notification(int p_what) { if (enabled && navpoly.is_valid()) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } break; } @@ -419,7 +419,7 @@ void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolyg } if (navigation && navpoly.is_valid() && enabled) { - nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this); + nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this); } //update_gizmo(); _change_notify("navpoly"); diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index 7d53557216..cc3829ad07 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -35,8 +35,7 @@ void Particles2D::set_emitting(bool p_emitting) { - emitting = p_emitting; - VS::get_singleton()->particles_set_emitting(particles, emitting); + VS::get_singleton()->particles_set_emitting(particles, p_emitting); } void Particles2D::set_amount(int p_amount) { @@ -56,7 +55,7 @@ void Particles2D::set_one_shot(bool p_enable) { one_shot = p_enable; VS::get_singleton()->particles_set_one_shot(particles, one_shot); - if (!one_shot && emitting) + if (!one_shot && is_emitting()) VisualServer::get_singleton()->particles_restart(particles); } void Particles2D::set_pre_process_time(float p_time) { @@ -134,7 +133,7 @@ void Particles2D::set_speed_scale(float p_scale) { bool Particles2D::is_emitting() const { - return emitting; + return VS::get_singleton()->particles_get_emitting(particles); } int Particles2D::get_amount() const { diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 6946f2a799..455a663693 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -47,7 +47,6 @@ public: private: RID particles; - bool emitting; bool one_shot; int amount; float lifetime; diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 1e34372d1e..a83c1c1cad 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -486,7 +486,7 @@ void TileMap::_update_dirty_quadrants() { xform.set_origin(offset.floor() + q.pos); _fix_cell_transform(xform, c, npoly_ofs + center_ofs, s); - int pid = navigation->navpoly_create(navpoly, nav_rel * xform); + int pid = navigation->navpoly_add(navpoly, nav_rel * xform); Quadrant::NavPoly np; np.id = pid; @@ -739,6 +739,26 @@ void TileMap::update_bitmask_area(const Vector2 &p_pos) { } } +void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end) { + + if ((p_end.x < p_start.x || p_end.y < p_start.y) || (p_end.x == p_start.x && p_end.y == p_start.y)) { + int i; + Array a = get_used_cells(); + for (i = 0; i < a.size(); i++) { + // update_bitmask_area() in order to update cells adjacent to the + // current cell, since ordering in array may not be reliable + Vector2 vector = (Vector2)a[i]; + update_bitmask_area(Vector2(vector.x, vector.y)); + } + return; + } + for (int x = p_start.x - 1; x <= p_end.x + 1; x++) { + for (int y = p_start.y - 1; y <= p_end.y + 1; y++) { + update_cell_bitmask(x, y); + } + } +} + void TileMap::update_cell_bitmask(int p_x, int p_y) { PosKey p(p_x, p_y); @@ -1507,6 +1527,9 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants); ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants); + ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area); + ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2())); + ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data); ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index e5608884c4..8f0b2e6e4c 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -245,6 +245,7 @@ public: void make_bitmask_area_dirty(const Vector2 &p_pos); void update_bitmask_area(const Vector2 &p_pos); + void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2()); void update_cell_bitmask(int p_x, int p_y); void update_dirty_bitmask(); diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp index e1e0b9b1ce..2bb41bf49e 100644 --- a/scene/3d/arvr_nodes.cpp +++ b/scene/3d/arvr_nodes.cpp @@ -231,7 +231,7 @@ void ARVRController::_notification(int p_what) { void ARVRController::_bind_methods() { ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id); ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id); - ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "1,32,1"), "set_controller_id", "get_controller_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id"); ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name); // passthroughs to information about our related joystick @@ -251,7 +251,8 @@ void ARVRController::_bind_methods() { }; void ARVRController::set_controller_id(int p_controller_id) { - // we don't check any bounds here, this controller may not yet be active and just be a place holder until it is. + // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is. + // Note that setting this to 0 means this node is not bound to a controller yet. controller_id = p_controller_id; }; @@ -420,7 +421,7 @@ void ARVRAnchor::_bind_methods() { ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id); ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id); - ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id"), "set_anchor_id", "get_anchor_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id"); ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name); ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active); @@ -430,7 +431,8 @@ void ARVRAnchor::_bind_methods() { }; void ARVRAnchor::set_anchor_id(int p_anchor_id) { - // we don't check any bounds here, this anchor may not yet be active and just be a place holder until it is. + // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is. + // Note that setting this to 0 means this node is not bound to an anchor yet. anchor_id = p_anchor_id; }; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 8af8c2f7da..8c282a31b8 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -55,12 +55,13 @@ float BakedLightmapData::get_energy() const { return energy; } -void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap) { +void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) { ERR_FAIL_COND(p_lightmap.is_null()); User user; user.path = p_path; user.lightmap = p_lightmap; + user.instance_index = p_instance; users.push_back(user); } @@ -79,16 +80,22 @@ Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const { return users[p_user].lightmap; } +int BakedLightmapData::get_user_instance(int p_user) const { + + ERR_FAIL_INDEX_V(p_user, users.size(), -1); + return users[p_user].instance_index; +} + void BakedLightmapData::clear_users() { users.clear(); } void BakedLightmapData::_set_user_data(const Array &p_data) { - ERR_FAIL_COND(p_data.size() & 1); + ERR_FAIL_COND((p_data.size() % 3) != 0); - for (int i = 0; i < p_data.size(); i += 2) { - add_user(p_data[i], p_data[i + 1]); + for (int i = 0; i < p_data.size(); i += 3) { + add_user(p_data[i], p_data[i + 1], p_data[i + 2]); } } @@ -98,6 +105,7 @@ Array BakedLightmapData::_get_user_data() const { for (int i = 0; i < users.size(); i++) { ret.push_back(users[i].path); ret.push_back(users[i].lightmap); + ret.push_back(users[i].instance_index); } return ret; } @@ -125,7 +133,7 @@ void BakedLightmapData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy); ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy); - ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap"), &BakedLightmapData::add_user); + ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "instance"), &BakedLightmapData::add_user); ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count); ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap); @@ -157,24 +165,25 @@ BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL; BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL; BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL; -void BakedLightmap::set_bake_subdiv(Subdiv p_subdiv) { - bake_subdiv = p_subdiv; +void BakedLightmap::set_bake_cell_size(float p_cell_size) { + bake_cell_size = p_cell_size; } -BakedLightmap::Subdiv BakedLightmap::get_bake_subdiv() const { - return bake_subdiv; +float BakedLightmap::get_bake_cell_size() const { + return bake_cell_size; } -void BakedLightmap::set_capture_subdiv(Subdiv p_subdiv) { - capture_subdiv = p_subdiv; +void BakedLightmap::set_capture_cell_size(float p_cell_size) { + capture_cell_size = p_cell_size; } -BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const { - return capture_subdiv; +float BakedLightmap::get_capture_cell_size() const { + return capture_cell_size; } void BakedLightmap::set_extents(const Vector3 &p_extents) { extents = p_extents; + update_gizmo(); } Vector3 BakedLightmap::get_extents() const { @@ -208,6 +217,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo pm.local_xform = xf; pm.mesh = mesh; pm.path = get_path_to(mi); + pm.instance_idx = -1; for (int i = 0; i < mesh->get_surface_count(); i++) { pm.instance_materials.push_back(mi->get_surface_material(i)); } @@ -218,6 +228,26 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo } } + Spatial *s = Object::cast_to<Spatial>(p_at_node); + + if (!mi && s) { + Array meshes = p_at_node->call("get_bake_meshes"); + if (meshes.size() && (meshes.size() & 1) == 0) { + Transform xf = get_global_transform().affine_inverse() * s->get_global_transform(); + for (int i = 0; i < meshes.size(); i += 2) { + PlotMesh pm; + Transform mesh_xf = meshes[i + 1]; + pm.local_xform = xf * mesh_xf; + pm.mesh = meshes[i]; + pm.instance_idx = i / 2; + if (!pm.mesh.is_valid()) + continue; + pm.path = get_path_to(s); + plot_meshes.push_back(pm); + } + } + } + Light *light = Object::cast_to<Light>(p_at_node); if (light && light->get_bake_mode() != Light::BAKE_DISABLED) { @@ -297,11 +327,29 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi Ref<BakedLightmapData> new_light_data; new_light_data.instance(); - static const int subdiv_value[SUBDIV_MAX] = { 8, 9, 10, 11, 12, 13 }; - VoxelLightBaker baker; - baker.begin_bake(subdiv_value[bake_subdiv], AABB(-extents, extents * 2.0)); + int bake_subdiv; + int capture_subdiv; + AABB bake_bounds; + { + bake_bounds = AABB(-extents, extents * 2.0); + int subdiv = nearest_power_of_2_templated(int(bake_bounds.get_longest_axis_size() / bake_cell_size)); + bake_bounds.size[bake_bounds.get_longest_axis_size()] = subdiv * bake_cell_size; + bake_subdiv = nearest_shift(subdiv) + 1; + + capture_subdiv = bake_subdiv; + float css = bake_cell_size; + while (css < capture_cell_size && capture_subdiv > 2) { + capture_subdiv--; + css *= 2.0; + } + + print_line("bake subdiv: " + itos(bake_subdiv)); + print_line("capture subdiv: " + itos(capture_subdiv)); + } + + baker.begin_bake(bake_subdiv, bake_bounds); List<PlotMesh> mesh_list; List<PlotLight> light_list; @@ -476,23 +524,23 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi if (set_path) { tex->set_path(image_path); } - new_light_data->add_user(E->get().path, tex); + new_light_data->add_user(E->get().path, tex, E->get().instance_idx); } } - int csubdiv = subdiv_value[capture_subdiv]; AABB bounds = AABB(-extents, extents * 2); - new_light_data->set_cell_subdiv(csubdiv); + new_light_data->set_cell_subdiv(capture_subdiv); new_light_data->set_bounds(bounds); - new_light_data->set_octree(baker.create_capture_octree(csubdiv)); + new_light_data->set_octree(baker.create_capture_octree(capture_subdiv)); { + float bake_bound_size = bake_bounds.get_longest_axis_size(); Transform to_bounds; - to_bounds.basis.scale(Vector3(bounds.get_longest_axis_size(), bounds.get_longest_axis_size(), bounds.get_longest_axis_size())); + to_bounds.basis.scale(Vector3(bake_bound_size, bake_bound_size, bake_bound_size)); to_bounds.origin = bounds.position; Transform to_grid; - to_grid.basis.scale(Vector3(1 << (csubdiv - 1), 1 << (csubdiv - 1), 1 << (csubdiv - 1))); + to_grid.basis.scale(Vector3(1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1))); Transform to_cell_space = to_grid * to_bounds.affine_inverse(); new_light_data->set_cell_space_transform(to_cell_space); @@ -546,12 +594,21 @@ void BakedLightmap::_assign_lightmaps() { ERR_FAIL_COND(!light_data.is_valid()); for (int i = 0; i < light_data->get_user_count(); i++) { - Node *node = get_node(light_data->get_user_path(i)); - VisualInstance *vi = Object::cast_to<VisualInstance>(node); - ERR_CONTINUE(!vi); Ref<Texture> lightmap = light_data->get_user_lightmap(i); ERR_CONTINUE(!lightmap.is_valid()); - VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid()); + + Node *node = get_node(light_data->get_user_path(i)); + int instance_idx = light_data->get_user_instance(i); + if (instance_idx >= 0) { + RID instance = node->call("get_bake_mesh_instance", instance_idx); + if (instance.is_valid()) { + VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), lightmap->get_rid()); + } + } else { + VisualInstance *vi = Object::cast_to<VisualInstance>(node); + ERR_CONTINUE(!vi); + VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid()); + } } } @@ -559,9 +616,17 @@ void BakedLightmap::_clear_lightmaps() { ERR_FAIL_COND(!light_data.is_valid()); for (int i = 0; i < light_data->get_user_count(); i++) { Node *node = get_node(light_data->get_user_path(i)); - VisualInstance *vi = Object::cast_to<VisualInstance>(node); - ERR_CONTINUE(!vi); - VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), RID(), RID()); + int instance_idx = light_data->get_user_instance(i); + if (instance_idx >= 0) { + RID instance = node->call("get_bake_mesh_instance", instance_idx); + if (instance.is_valid()) { + VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), RID()); + } + } else { + VisualInstance *vi = Object::cast_to<VisualInstance>(node); + ERR_CONTINUE(!vi); + VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), RID()); + } } } @@ -646,11 +711,11 @@ void BakedLightmap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data); ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data); - ClassDB::bind_method(D_METHOD("set_bake_subdiv", "bake_subdiv"), &BakedLightmap::set_bake_subdiv); - ClassDB::bind_method(D_METHOD("get_bake_subdiv"), &BakedLightmap::get_bake_subdiv); + ClassDB::bind_method(D_METHOD("set_bake_cell_size", "bake_cell_size"), &BakedLightmap::set_bake_cell_size); + ClassDB::bind_method(D_METHOD("get_bake_cell_size"), &BakedLightmap::get_bake_cell_size); - ClassDB::bind_method(D_METHOD("set_capture_subdiv", "capture_subdiv"), &BakedLightmap::set_capture_subdiv); - ClassDB::bind_method(D_METHOD("get_capture_subdiv"), &BakedLightmap::get_capture_subdiv); + ClassDB::bind_method(D_METHOD("set_capture_cell_size", "capture_cell_size"), &BakedLightmap::set_capture_cell_size); + ClassDB::bind_method(D_METHOD("get_capture_cell_size"), &BakedLightmap::get_capture_cell_size); ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality); ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality); @@ -677,37 +742,39 @@ void BakedLightmap::_bind_methods() { ClassDB::bind_method(D_METHOD("debug_bake"), &BakedLightmap::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); - ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_subdiv", PROPERTY_HINT_ENUM, "128,256,512,1024,2048,4096"), "set_bake_subdiv", "get_bake_subdiv"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "capture_subdiv", PROPERTY_HINT_ENUM, "128,256,512"), "set_capture_subdiv", "get_capture_subdiv"); + ADD_GROUP("Bake", "bake_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_bake_cell_size", "get_bake_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality"); ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "is_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_hdr"), "set_hdr", "is_hdr"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "bake_extents"), "set_extents", "get_extents"); + ADD_GROUP("Capture", "capture_"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size"); + ADD_GROUP("Data", ""); ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data"); - BIND_ENUM_CONSTANT(SUBDIV_128); - BIND_ENUM_CONSTANT(SUBDIV_256); - BIND_ENUM_CONSTANT(SUBDIV_512); - BIND_ENUM_CONSTANT(SUBDIV_1024); - BIND_ENUM_CONSTANT(SUBDIV_2048); - BIND_ENUM_CONSTANT(SUBDIV_4096); - BIND_ENUM_CONSTANT(SUBDIV_MAX); - BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW); BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH); BIND_ENUM_CONSTANT(BAKE_MODE_CONE_TRACE); BIND_ENUM_CONSTANT(BAKE_MODE_RAY_TRACE); + + BIND_ENUM_CONSTANT(BAKE_ERROR_OK); + BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH); + BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES); + BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE); + BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED); } BakedLightmap::BakedLightmap() { extents = Vector3(10, 10, 10); - bake_subdiv = SUBDIV_256; - capture_subdiv = SUBDIV_128; + bake_cell_size = 0.25; + capture_cell_size = 0.5; + bake_quality = BAKE_QUALITY_MEDIUM; bake_mode = BAKE_MODE_CONE_TRACE; energy = 1; diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 5595ec1e61..9b53e41d73 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -18,6 +18,7 @@ class BakedLightmapData : public Resource { NodePath path; Ref<Texture> lightmap; + int instance_index; }; Vector<User> users; @@ -44,10 +45,11 @@ public: void set_energy(float p_energy); float get_energy() const; - void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap); + void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance = -1); int get_user_count() const; NodePath get_user_path(int p_user) const; Ref<Texture> get_user_lightmap(int p_user) const; + int get_user_instance(int p_user) const; void clear_users(); virtual RID get_rid() const; @@ -59,17 +61,6 @@ class BakedLightmap : public VisualInstance { GDCLASS(BakedLightmap, VisualInstance); public: - enum Subdiv { - SUBDIV_128, - SUBDIV_256, - SUBDIV_512, - SUBDIV_1024, - SUBDIV_2048, - SUBDIV_4096, - SUBDIV_MAX - - }; - enum BakeQuality { BAKE_QUALITY_LOW, BAKE_QUALITY_MEDIUM, @@ -95,8 +86,8 @@ public: typedef void (*BakeEndFunc)(); private: - Subdiv bake_subdiv; - Subdiv capture_subdiv; + float bake_cell_size; + float capture_cell_size; Vector3 extents; float propagation; float energy; @@ -113,6 +104,7 @@ private: Ref<Mesh> mesh; Transform local_xform; NodePath path; + int instance_idx; }; struct PlotLight { @@ -147,11 +139,11 @@ public: void set_light_data(const Ref<BakedLightmapData> &p_data); Ref<BakedLightmapData> get_light_data() const; - void set_bake_subdiv(Subdiv p_subdiv); - Subdiv get_bake_subdiv() const; + void set_bake_cell_size(float p_cell_size); + float get_bake_cell_size() const; - void set_capture_subdiv(Subdiv p_subdiv); - Subdiv get_capture_subdiv() const; + void set_capture_cell_size(float p_cell_size); + float get_capture_cell_size() const; void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; @@ -181,7 +173,6 @@ public: BakedLightmap(); }; -VARIANT_ENUM_CAST(BakedLightmap::Subdiv); VARIANT_ENUM_CAST(BakedLightmap::BakeQuality); VARIANT_ENUM_CAST(BakedLightmap::BakeMode); VARIANT_ENUM_CAST(BakedLightmap::BakeError); diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index af210fff1c..7143310036 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -56,130 +56,23 @@ void Camera::_update_camera_mode() { } } -bool Camera::_set(const StringName &p_name, const Variant &p_value) { - - bool changed_all = false; - if (p_name == "projection") { - - int proj = p_value; - if (proj == PROJECTION_PERSPECTIVE) - mode = PROJECTION_PERSPECTIVE; - if (proj == PROJECTION_ORTHOGONAL) - mode = PROJECTION_ORTHOGONAL; - - changed_all = true; - } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx") - fov = p_value; - else if (p_name == "size" || p_name == "sizex" || p_name == "sizey") - size = p_value; - else if (p_name == "near") - near = p_value; - else if (p_name == "far") - far = p_value; - else if (p_name == "keep_aspect") - set_keep_aspect_mode(KeepAspect(int(p_value))); - else if (p_name == "vaspect") - set_keep_aspect_mode(p_value ? KEEP_WIDTH : KEEP_HEIGHT); - else if (p_name == "h_offset") - h_offset = p_value; - else if (p_name == "v_offset") - v_offset = p_value; - else if (p_name == "current") { - if (p_value.operator bool()) { - make_current(); - } else { - clear_current(); +void Camera::_validate_property(PropertyInfo &p_property) const { + if (p_property.name == "fov") { + if (mode == PROJECTION_ORTHOGONAL) { + p_property.usage = PROPERTY_USAGE_NOEDITOR; } - } else if (p_name == "cull_mask") { - set_cull_mask(p_value); - } else if (p_name == "environment") { - set_environment(p_value); - } else if (p_name == "doppler/tracking") { - set_doppler_tracking(DopplerTracking(int(p_value))); - } else - return false; - - _update_camera_mode(); - if (changed_all) - _change_notify(); - return true; -} -bool Camera::_get(const StringName &p_name, Variant &r_ret) const { - - if (p_name == "projection") { - r_ret = mode; - } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx") - r_ret = fov; - else if (p_name == "size" || p_name == "sizex" || p_name == "sizey") - r_ret = size; - else if (p_name == "near") - r_ret = near; - else if (p_name == "far") - r_ret = far; - else if (p_name == "keep_aspect") - r_ret = int(keep_aspect); - else if (p_name == "current") { - - if (is_inside_tree() && get_tree()->is_node_being_edited(this)) { - r_ret = current; - } else { - r_ret = is_current(); + } else if (p_property.name == "size") { + if (mode == PROJECTION_PERSPECTIVE) { + p_property.usage = PROPERTY_USAGE_NOEDITOR; } - } else if (p_name == "cull_mask") { - r_ret = get_cull_mask(); - } else if (p_name == "h_offset") { - r_ret = get_h_offset(); - } else if (p_name == "v_offset") { - r_ret = get_v_offset(); - } else if (p_name == "environment") { - r_ret = get_environment(); - } else if (p_name == "doppler/tracking") { - r_ret = get_doppler_tracking(); - } else - return false; - - return true; -} - -void Camera::_get_property_list(List<PropertyInfo> *p_list) const { - - p_list->push_back(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal")); - - switch (mode) { - - case PROJECTION_PERSPECTIVE: { - - p_list->push_back(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_NOEDITOR)); - if (keep_aspect == KEEP_WIDTH) - p_list->push_back(PropertyInfo(Variant::REAL, "fovx", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR)); - else - p_list->push_back(PropertyInfo(Variant::REAL, "fovy", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR)); - - } break; - case PROJECTION_ORTHOGONAL: { - - p_list->push_back(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "1,16384,0.01", PROPERTY_USAGE_NOEDITOR)); - if (keep_aspect == KEEP_WIDTH) - p_list->push_back(PropertyInfo(Variant::REAL, "sizex", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR)); - else - p_list->push_back(PropertyInfo(Variant::REAL, "sizey", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR)); - - } break; } - - p_list->push_back(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01")); - p_list->push_back(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01")); - p_list->push_back(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height")); - p_list->push_back(PropertyInfo(Variant::BOOL, "current")); - p_list->push_back(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER)); - p_list->push_back(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment")); - p_list->push_back(PropertyInfo(Variant::REAL, "h_offset")); - p_list->push_back(PropertyInfo(Variant::REAL, "v_offset")); - p_list->push_back(PropertyInfo(Variant::INT, "doppler/tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics")); } void Camera::_update_camera() { + if (!is_inside_tree()) + return; + Transform tr = get_camera_transform(); tr.origin += tr.basis.get_axis(1) * v_offset; tr.origin += tr.basis.get_axis(0) * h_offset; @@ -191,7 +84,7 @@ void Camera::_update_camera() { get_viewport()->_camera_transform_changed_notify(); */ - if (!is_inside_tree() || get_tree()->is_node_being_edited(this) || !is_current()) + if (get_tree()->is_node_being_edited(this) || !is_current()) return; get_viewport()->_camera_transform_changed_notify(); @@ -282,6 +175,14 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) { update_gizmo(); } +void Camera::set_projection(Camera::Projection p_mode) { + if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) { + mode = p_mode; + _update_camera_mode(); + _change_notify(); + } +} + RID Camera::get_camera() const { return camera; @@ -311,6 +212,14 @@ void Camera::clear_current() { } } +void Camera::set_current(bool p_current) { + if (p_current) { + make_current(); + } else { + clear_current(); + } +} + bool Camera::is_current() const { if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) { @@ -481,6 +390,7 @@ void Camera::set_environment(const Ref<Environment> &p_environment) { VS::get_singleton()->camera_set_environment(camera, environment->get_rid()); else VS::get_singleton()->camera_set_environment(camera, RID()); + _update_camera_mode(); } Ref<Environment> Camera::get_environment() const { @@ -489,10 +399,9 @@ Ref<Environment> Camera::get_environment() const { } void Camera::set_keep_aspect_mode(KeepAspect p_aspect) { - keep_aspect = p_aspect; VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH); - + _update_camera_mode(); _change_notify(); } @@ -511,6 +420,7 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) { velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP); velocity_tracker->reset(get_global_transform().origin); } + _update_camera_mode(); } Camera::DopplerTracking Camera::get_doppler_tracking() const { @@ -529,13 +439,19 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal); ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current); ClassDB::bind_method(D_METHOD("clear_current"), &Camera::clear_current); + ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current); ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform); ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov); ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size); ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar); ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear); + ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov); + ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size); + ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar); + ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear); ClassDB::bind_method(D_METHOD("get_projection"), &Camera::get_projection); + ClassDB::bind_method(D_METHOD("set_projection"), &Camera::set_projection); ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera::set_h_offset); ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera::get_h_offset); ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera::set_v_offset); @@ -550,6 +466,19 @@ void Camera::_bind_methods() { ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking); //ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current ); + ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"), "set_projection", "get_projection"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "near"), "set_znear", "get_znear"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "far"), "set_zfar", "get_zfar"); + BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); @@ -586,10 +515,30 @@ Camera::Projection Camera::get_projection() const { return mode; } -void Camera::set_cull_mask(uint32_t p_layers) { +void Camera::set_fov(float p_fov) { + fov = p_fov; + _update_camera_mode(); +} +void Camera::set_size(float p_size) { + size = p_size; + _update_camera_mode(); +} + +void Camera::set_znear(float p_znear) { + near = p_znear; + _update_camera_mode(); +} + +void Camera::set_zfar(float p_zfar) { + far = p_zfar; + _update_camera_mode(); +} + +void Camera::set_cull_mask(uint32_t p_layers) { layers = p_layers; VisualServer::get_singleton()->camera_set_cull_mask(camera, layers); + _update_camera_mode(); } uint32_t Camera::get_cull_mask() const { diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 73c6844c1a..d69a02afeb 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -95,10 +95,8 @@ protected: virtual void _request_camera_update(); void _update_camera_mode(); - 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; void _notification(int p_what); + virtual void _validate_property(PropertyInfo &property) const; static void _bind_methods(); @@ -111,9 +109,11 @@ public: void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); void set_orthogonal(float p_size, float p_z_near, float p_z_far); + void set_projection(Camera::Projection p_mode); void make_current(); void clear_current(); + void set_current(bool p_current); bool is_current() const; RID get_camera() const; @@ -124,6 +124,11 @@ public: float get_znear() const; Projection get_projection() const; + void set_fov(float p_fov); + void set_size(float p_size); + void set_zfar(float p_zfar); + void set_znear(float p_znear); + virtual Transform get_camera_transform() const; Vector3 project_ray_normal(const Point2 &p_pos) const; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index b6507aedb3..78cf75e3b3 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -202,7 +202,7 @@ void Navigation::_navmesh_unlink(int p_id) { nm.linked = false; } -int Navigation::navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { +int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) { int id = last_id++; NavMesh nm; @@ -686,7 +686,7 @@ Vector3 Navigation::get_up_vector() const { void Navigation::_bind_methods() { - ClassDB::bind_method(D_METHOD("navmesh_create", "mesh", "xform", "owner"), &Navigation::navmesh_create, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform); ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove); diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index d9a38f7b00..134afa2278 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -166,7 +166,7 @@ public: Vector3 get_up_vector() const; //API should be as dynamic as possible - int navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL); + int navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL); void navmesh_set_transform(int p_id, const Transform &p_xform); void navmesh_remove(int p_id); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 40750cdfe8..4fb12b8fac 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -471,7 +471,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { if (navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } } } @@ -508,7 +508,7 @@ void NavigationMeshInstance::_notification(int p_what) { if (enabled && navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } break; } @@ -568,7 +568,7 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na navmesh = p_navmesh; if (navigation && navmesh.is_valid() && enabled) { - nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this); + nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this); } if (debug_view && navmesh.is_valid()) { diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 821f1a5a78..9108973cbf 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -42,8 +42,7 @@ PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const { void Particles::set_emitting(bool p_emitting) { - emitting = p_emitting; - VS::get_singleton()->particles_set_emitting(particles, emitting); + VS::get_singleton()->particles_set_emitting(particles, p_emitting); } void Particles::set_amount(int p_amount) { @@ -63,7 +62,7 @@ void Particles::set_one_shot(bool p_one_shot) { one_shot = p_one_shot; VS::get_singleton()->particles_set_one_shot(particles, one_shot); - if (!one_shot && emitting) + if (!one_shot && is_emitting()) VisualServer::get_singleton()->particles_restart(particles); } @@ -113,7 +112,7 @@ void Particles::set_speed_scale(float p_scale) { bool Particles::is_emitting() const { - return emitting; + return VS::get_singleton()->particles_get_emitting(particles); } int Particles::get_amount() const { @@ -598,6 +597,11 @@ void ParticlesMaterial::_update_shader() { code += "}\n"; code += "\n"; + code += "float rand_from_seed_m1_p1(inout uint seed) {\n"; + code += " return rand_from_seed(seed)*2.0-1.0;\n"; + code += "}\n"; + code += "\n"; + //improve seed quality code += "uint hash(uint x) {\n"; code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n"; @@ -614,6 +618,8 @@ void ParticlesMaterial::_update_shader() { code += " float scale_rand = rand_from_seed(alt_seed);\n"; code += " float hue_rot_rand = rand_from_seed(alt_seed);\n"; code += " float anim_offset_rand = rand_from_seed(alt_seed);\n"; + code += " float pi = 3.14159;\n"; + code += " float degree_to_rad = pi / 180.0;\n"; code += "\n"; if (emission_shape >= EMISSION_SHAPE_POINTS) { @@ -638,23 +644,28 @@ void ParticlesMaterial::_update_shader() { else code += " float tex_anim_offset = 0.0;\n"; + code += " float spread_rad = spread*degree_to_rad;\n"; + if (flags[FLAG_DISABLE_Z]) { - code += " float angle1 = (rand_from_seed(alt_seed)*2.0-1.0)*spread/180.0*3.1416;\n"; - code += " vec3 rot = vec3( cos(angle1), sin(angle1),0.0 );\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n"; + code += " vec3 rot = vec3( cos(angle1_rad), sin(angle1_rad),0.0 );\n"; code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } else { //initiate velocity spread in 3D - code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n"; - code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n"; - code += " vec3 rot_xz = vec3( sin(angle1), 0.0, cos(angle1) );\n"; - code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n"; - code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; + code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n"; + code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad*(1.0-flatness);\n"; + code += " vec3 direction_xz = vec3( sin(angle1_rad), 0, cos(angle1_rad));\n"; + code += " vec3 direction_yz = vec3( 0, sin(angle2_rad), cos(angle2_rad));\n"; + code += " direction_yz.z = direction_yz.z / sqrt(direction_yz.z); //better uniform distribution\n"; + code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " direction = normalize(direction);\n"; + code += " VELOCITY = direction*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; - code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle + code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle code += " CUSTOM.y = 0.0;\n"; //phase code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1) switch (emission_shape) { @@ -777,7 +788,7 @@ void ParticlesMaterial::_update_shader() { code += " float orbit_amount = (orbit_velocity+tex_orbit_velocity)*mix(1.0,rand_from_seed(alt_seed),orbit_velocity_random);\n"; code += " if (orbit_amount!=0.0) {\n"; - code += " float ang = orbit_amount * DELTA * 3.1416 * 2.0;\n"; + code += " float ang = orbit_amount * DELTA * pi * 2.0;\n"; code += " mat2 rot = mat2(vec2(cos(ang),-sin(ang)),vec2(sin(ang),cos(ang)));\n"; code += " TRANSFORM[3].xy-=diff.xy;\n"; code += " TRANSFORM[3].xy+=rot * diff.xy;\n"; @@ -800,7 +811,7 @@ void ParticlesMaterial::_update_shader() { code += " }\n"; code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n"; code += " base_angle += CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n"; - code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle + code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle if (flags[FLAG_ANIM_LOOP]) { code += " CUSTOM.z = mod(CUSTOM.z,1.0);\n"; //loop @@ -821,7 +832,7 @@ void ParticlesMaterial::_update_shader() { else code += " float tex_hue_variation = 0.0;\n"; - code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n"; + code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*pi*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n"; code += " float hue_rot_c = cos(hue_rot_angle);\n"; code += " float hue_rot_s = sin(hue_rot_angle);\n"; code += " mat4 hue_rot_mat = mat4( vec4(0.299, 0.587, 0.114, 0.0),\n"; diff --git a/scene/3d/particles.h b/scene/3d/particles.h index 5b8121e937..24154b5607 100644 --- a/scene/3d/particles.h +++ b/scene/3d/particles.h @@ -57,7 +57,6 @@ public: private: RID particles; - bool emitting; bool one_shot; int amount; float lifetime; diff --git a/scene/3d/portal.h b/scene/3d/portal.h index 4ea208a718..a3a7956286 100644 --- a/scene/3d/portal.h +++ b/scene/3d/portal.h @@ -39,7 +39,8 @@ If a portal is placed next (very close to) a similar, opposing portal, they automatically connect, otherwise, a portal connects to the parent room */ -//this will be redone and replaced by area portals, left for reference since a new class with this name will have to exist and want to reuse the gizmos +// FIXME: This will be redone and replaced by area portals, left for reference +// since a new class with this name will have to exist and want to reuse the gizmos #if 0 class Portal : public VisualInstance { diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h index 3069ea2eba..2b2f80a0c6 100644 --- a/scene/3d/room_instance.h +++ b/scene/3d/room_instance.h @@ -44,7 +44,7 @@ */ -//this will be removed, left for reference +// FIXME: this will be removed, left for reference #if 0 class Room : public VisualInstance { diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index d0e0937eca..3d40bb299a 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -180,6 +180,9 @@ void Skeleton::_notification(int p_what) { rest_global_inverse_dirty = false; } + Transform global_transform = get_global_transform(); + Transform global_transform_inverse = global_transform.affine_inverse(); + for (int i = 0; i < len; i++) { Bone &b = bonesptr[i]; @@ -239,7 +242,9 @@ void Skeleton::_notification(int p_what) { } } - vs->skeleton_bone_set_transform(skeleton, i, b.pose_global * b.rest_global_inverse); + Transform transform = b.pose_global * b.rest_global_inverse; + + vs->skeleton_bone_set_transform(skeleton, i, global_transform * (transform * global_transform_inverse)); for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index d9f88ac693..e890533ab7 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -558,27 +558,27 @@ bool Spatial::is_visible() const { void Spatial::rotate(const Vector3 &p_normal, float p_radians) { Transform t = get_transform(); - t.basis.rotate(p_normal, p_radians); + t.basis.rotate_local(p_normal, p_radians); //use local rotation here, as it makes more sense here in tree hierarchy set_transform(t); } void Spatial::rotate_x(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(1, 0, 0), p_radians); + t.basis.rotate_local(Vector3(1, 0, 0), p_radians); set_transform(t); } void Spatial::rotate_y(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(0, 1, 0), p_radians); + t.basis.rotate_local(Vector3(0, 1, 0), p_radians); set_transform(t); } void Spatial::rotate_z(float p_radians) { Transform t = get_transform(); - t.basis.rotate(Vector3(0, 0, 1), p_radians); + t.basis.rotate_local(Vector3(0, 0, 1), p_radians); set_transform(t); } diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 18ebc22c8b..2ecc445663 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -294,6 +294,7 @@ SpriteBase3D::SpriteBase3D() { for (int i = 0; i < FLAG_MAX; i++) flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; + alpha_cut = ALPHA_CUT_DISABLED; axis = Vector3::AXIS_Z; pixel_size = 0.01; modulate = Color(1, 1, 1, 1); diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp index 98dc1590d8..bd7e52d947 100644 --- a/scene/3d/voxel_light_baker.cpp +++ b/scene/3d/voxel_light_baker.cpp @@ -1,5 +1,39 @@ +/*************************************************************************/ +/* voxel_light_baker.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #include "voxel_light_baker.h" #include "os/os.h" +#include "os/threaded_array_processor.h" + +#include <stdlib.h> + #define FINDMINMAX(x0, x1, x2, min, max) \ min = max = x0; \ if (x1 < min) min = x1; \ @@ -183,14 +217,23 @@ static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalf return true; /* box and triangle overlaps */ } -static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) { +static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) { - if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) - return p_uv[0]; - if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) - return p_uv[1]; - if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) - return p_uv[2]; + if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } + if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) { + r_uv = p_uv[1]; + r_normal = p_normal[1]; + return; + } + if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) { + r_uv = p_uv[2]; + r_normal = p_normal[2]; + return; + } Vector3 v0 = p_vtx[1] - p_vtx[0]; Vector3 v1 = p_vtx[2] - p_vtx[0]; @@ -202,16 +245,20 @@ static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, float d20 = v2.dot(v0); float d21 = v2.dot(v1); float denom = (d00 * d11 - d01 * d01); - if (denom == 0) - return p_uv[0]; + if (denom == 0) { + r_uv = p_uv[0]; + r_normal = p_normal[0]; + return; + } float v = (d11 * d20 - d01 * d21) / denom; float w = (d00 * d21 - d01 * d20) / denom; float u = 1.0f - v - w; - return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; + r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w; + r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized(); } -void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { +void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) { if (p_level == cell_subdiv - 1) { //plot the face by guessing it's albedo and emission value @@ -289,7 +336,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection); - Vector2 uv = get_uv(intersection, p_vtx, p_uv); + Vector2 uv; + Vector3 lnormal; + get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); @@ -304,7 +355,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p emission_accum.g += p_material.emission[ofs].g; emission_accum.b += p_material.emission[ofs].b; - normal_accum += normal; + normal_accum += lnormal; alpha += 1.0; } @@ -316,7 +367,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]); Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5); - Vector2 uv = get_uv(inters, p_vtx, p_uv); + Vector3 lnormal; + Vector2 uv; + get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); + if (lnormal == Vector3()) //just in case normal as nor provided + lnormal = normal; int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1); @@ -334,7 +389,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p emission_accum.g = p_material.emission[ofs].g * alpha; emission_accum.b = p_material.emission[ofs].b * alpha; - normal_accum *= alpha; + normal_accum = lnormal * alpha; } else { @@ -415,7 +470,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p bake_cells[child_idx].level = p_level + 1; } - _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb); + _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb); } } } @@ -539,9 +594,12 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con PoolVector<Vector3>::Read vr = vertices.read(); PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV]; PoolVector<Vector2>::Read uvr; + PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL]; + PoolVector<Vector3>::Read nr; PoolVector<int> index = a[Mesh::ARRAY_INDEX]; bool read_uv = false; + bool read_normals = false; if (uv.size()) { @@ -549,6 +607,11 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con read_uv = true; } + if (normals.size()) { + read_normals = true; + nr = normals.read(); + } + if (index.size()) { int facecount = index.size() / 3; @@ -558,6 +621,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con Vector3 vtxs[3]; Vector2 uvs[3]; + Vector3 normal[3]; for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]); @@ -569,11 +633,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con } } + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[ir[j * 3 + k]]; + } + } + //test against original bounds if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) continue; //plot - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); } } else { @@ -584,6 +654,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con Vector3 vtxs[3]; Vector2 uvs[3]; + Vector3 normal[3]; for (int k = 0; k < 3; k++) { vtxs[k] = p_xform.xform(vr[j * 3 + k]); @@ -595,11 +666,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con } } + if (read_normals) { + for (int k = 0; k < 3; k++) { + normal[k] = nr[j * 3 + k]; + } + } + //test against original bounds if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs)) continue; //plot face - _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds); + _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds); } } } @@ -833,11 +910,13 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C } } - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s; - light->direct_accum[i][1] += light_energy.y * s; - light->direct_accum[i][2] += light_energy.z * s; + if (p_direct) { + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s; + light->direct_accum[i][1] += light_energy.y * s; + light->direct_accum[i][2] += light_energy.z * s; + } } success_count++; } @@ -897,17 +976,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); att *= powf(1.0 - dt, p_attenutation); } -#if 0 - if (light_cache.type == VS::LIGHT_SPOT) { - - float angle = Math::rad2deg(acos(light_axis.dot(spot_axis))); - if (angle > light_cache.spot_angle) - continue; - float d = CLAMP(angle / light_cache.spot_angle, 1, 0); - att *= powf(1.0 - d, light_cache.spot_attenuation); - } -#endif clip_planes = 0; for (int c = 0; c < 3; c++) { @@ -972,11 +1041,13 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color } } - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s * att; - light->direct_accum[i][1] += light_energy.y * s * att; - light->direct_accum[i][2] += light_energy.z * s * att; + if (p_direct) { + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s * att; + light->direct_accum[i][1] += light_energy.y * s * att; + light->direct_accum[i][2] += light_energy.z * s * att; + } } } @@ -1041,17 +1112,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi float dt = CLAMP((d + distance_adv) / local_radius, 0, 1); att *= powf(1.0 - dt, p_attenutation); } -#if 0 - if (light_cache.type == VS::LIGHT_SPOT) { - - float angle = Math::rad2deg(acos(light_axis.dot(spot_axis))); - if (angle > light_cache.spot_angle) - continue; - float d = CLAMP(angle / light_cache.spot_angle, 1, 0); - att *= powf(1.0 - d, light_cache.spot_attenuation); - } -#endif clip_planes = 0; for (int c = 0; c < 3; c++) { @@ -1115,11 +1176,13 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi } } - for (int i = 0; i < 6; i++) { - float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct - light->direct_accum[i][0] += light_energy.x * s * att; - light->direct_accum[i][1] += light_energy.y * s * att; - light->direct_accum[i][2] += light_energy.z * s * att; + if (p_direct) { + for (int i = 0; i < 6; i++) { + float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct + light->direct_accum[i][0] += light_energy.x * s * att; + light->direct_accum[i][1] += light_energy.y * s * att; + light->direct_accum[i][2] += light_energy.z * s * att; + } } } @@ -1614,6 +1677,16 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const return accum; } +_ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) { + /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ + uint32_t x = *state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + *state = x; + return x; +} + Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) { int samples_per_quality[3] = { 48, 128, 512 }; @@ -1636,20 +1709,22 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V const Light *light = bake_light.ptr(); const Cell *cells = bake_cells.ptr(); + uint32_t local_rng_state = rand(); //needs to be fixed again + for (int i = 0; i < samples; i++) { - float random_angle1 = (((Math::rand() % 65535) / 65535.0) * 2.0 - 1.0) * spread; + float random_angle1 = (((xorshift32(&local_rng_state) % 65535) / 65535.0) * 2.0 - 1.0) * spread; Vector3 axis(0, sin(random_angle1), cos(random_angle1)); - float random_angle2 = ((Math::rand() % 65535) / 65535.0) * Math_PI * 2.0; + float random_angle2 = ((xorshift32(&local_rng_state) % 65535) / 65535.0) * Math_PI * 2.0; Basis rot(Vector3(0, 0, 1), random_angle2); axis = rot.xform(axis); Vector3 direction = normal_xform.xform(axis).normalized(); - Vector3 pos = p_pos + Vector3(0.5, 0.5, 0.5) + direction * bias; - Vector3 advance = direction * _get_normal_advance(direction); + Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias; + uint32_t cell = CHILD_EMPTY; while (cell == CHILD_EMPTY) { @@ -1692,7 +1767,7 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V } cell = bc->childs[child]; - if (cell == CHILD_EMPTY) + if (unlikely(cell == CHILD_EMPTY)) break; half >>= 1; @@ -1701,22 +1776,45 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V pos += advance; } - if (cell != CHILD_EMPTY) { + if (unlikely(cell != CHILD_EMPTY)) { for (int i = 0; i < 6; i++) { //anisotropic read light float amount = direction.dot(aniso_normal[i]); - if (amount < 0) - amount = 0; + if (amount <= 0) + continue; accum.x += light[cell].accum[i][0] * amount; accum.y += light[cell].accum[i][1] * amount; accum.z += light[cell].accum[i][2] * amount; } + accum.x += cells[cell].emission[0]; + accum.y += cells[cell].emission[1]; + accum.z += cells[cell].emission[2]; } } + // Make sure we don't reset this thread's RNG state + return accum / samples; } +void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) { + + LightMap *pixel = &p_line[p_x]; + if (pixel->pos == Vector3()) + return; + //print_line("pos: " + pixel->pos + " normal " + pixel->normal); + switch (bake_mode) { + case BAKE_MODE_CONE_TRACE: { + pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; + } break; + case BAKE_MODE_RAY_TRACE: { + pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; + } break; + // pixel->light = Vector3(1, 1, 1); + //} + } +} + Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) { //transfer light information to a lightmap @@ -1760,6 +1858,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh Vector3 vertex[3]; Vector3 normal[3]; Vector2 uv[3]; + for (int j = 0; j < 3; j++) { int idx = ic ? ir[i * 3 + j] : i * 3 + j; vertex[j] = xform.xform(vr[idx]); @@ -1770,39 +1869,18 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh _plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height); } } - //step 3 perform voxel cone trace on lightmap pixels + //step 3 perform voxel cone trace on lightmap pixels { LightMap *lightmap_ptr = lightmap.ptrw(); uint64_t begin_time = OS::get_singleton()->get_ticks_usec(); volatile int lines = 0; + // make sure our OS-level rng is seeded + for (int i = 0; i < height; i++) { - //print_line("bake line " + itos(i) + " / " + itos(height)); -#ifdef _OPENMP -#pragma omp parallel for -#endif - for (int j = 0; j < width; j++) { - - //if (i == 125 && j == 280) { - - LightMap *pixel = &lightmap_ptr[i * width + j]; - if (pixel->pos == Vector3()) - continue; //unused, skipe - - //print_line("pos: " + pixel->pos + " normal " + pixel->normal); - switch (bake_mode) { - case BAKE_MODE_CONE_TRACE: { - pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy; - } break; - case BAKE_MODE_RAY_TRACE: { - pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy; - } break; - // pixel->light = Vector3(1, 1, 1); - //} - } - } + thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]); lines = MAX(lines, i); //for multithread if (p_bake_time_func) { @@ -1878,12 +1956,14 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh LightMap *lightmap_ptr = lightmap.ptrw(); const Cell *cells = bake_cells.ptr(); const Light *light = bake_light.ptr(); - +#ifdef _OPENMP +#pragma omp parallel +#endif for (int i = 0; i < height; i++) { //print_line("bake line " + itos(i) + " / " + itos(height)); #ifdef _OPENMP -#pragma omp parallel for +#pragma omp parallel for schedule(dynamic, 1) #endif for (int j = 0; j < width; j++) { @@ -2002,6 +2082,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh } } +// Enable for debugging #if 0 { PoolVector<uint8_t> img; diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h index 6dee2ee69b..68e11c356b 100644 --- a/scene/3d/voxel_light_baker.h +++ b/scene/3d/voxel_light_baker.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* voxel_light_baker.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + #ifndef VOXEL_LIGHT_BAKER_H #define VOXEL_LIGHT_BAKER_H @@ -99,7 +129,8 @@ private: Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); MaterialCache _get_material_cache(Ref<Material> p_material); - void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); + + void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb); void _fixup_plot(int p_idx, int p_level); void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode); void _check_init_light(); @@ -119,7 +150,10 @@ private: _FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); _FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal); + void _lightmap_bake_point(uint32_t p_x, LightMap *p_line); + public: + void begin_bake(int p_subdiv, const AABB &p_bounds); void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material); void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 32f82fe6b8..a50047e426 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -386,8 +386,6 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const { void AnimationTreePlayer::_get_property_list(List<PropertyInfo> *p_list) const { - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "base_path")); - p_list->push_back(PropertyInfo(Variant::NODE_PATH, "master_player")); p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK)); } @@ -1140,6 +1138,9 @@ void AnimationTreePlayer::transition_node_set_input_count(const StringName &p_no n->inputs.resize(p_inputs); n->input_data.resize(p_inputs); + + _clear_cycle_test(); + last_error = _cycle_test(out_name); } void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringName &p_node, int p_input, bool p_auto_advance) { @@ -1360,6 +1361,8 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) { node_map.erase(p_node); + _clear_cycle_test(); + // compute last error again, just in case last_error = _cycle_test(out_name); dirty_caches = true; @@ -1387,6 +1390,14 @@ AnimationTreePlayer::ConnectError AnimationTreePlayer::_cycle_test(const StringN return CONNECT_OK; } +// Use this function to not alter next complete _cycle_test(). +void AnimationTreePlayer::_clear_cycle_test() { + for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) { + NodeBase *nb = E->get(); + nb->cycletest = false; + } +} + Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const StringName &p_dst_node, int p_dst_input) { ERR_FAIL_COND_V(!node_map.has(p_src_node), ERR_INVALID_PARAMETER); @@ -1411,11 +1422,7 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str dst->inputs[p_dst_input].node = p_src_node; - for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) { - - NodeBase *nb = E->get(); - nb->cycletest = false; - } + _clear_cycle_test(); last_error = _cycle_test(out_name); if (last_error) { diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h index c49b0c4d1b..7213441d6e 100644 --- a/scene/animation/animation_tree_player.h +++ b/scene/animation/animation_tree_player.h @@ -317,6 +317,7 @@ private: bool reset_request; ConnectError _cycle_test(const StringName &p_at_node); + void _clear_cycle_test(); Track *_find_track(const NodePath &p_path); void _recompute_caches(); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 148277f2dd..a67fe2aeeb 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -450,11 +450,11 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const { String tooltip = Control::get_tooltip(p_pos); if (shortcut.is_valid() && shortcut->is_valid()) { - if (tooltip.find("$sc") != -1) { - tooltip = tooltip.replace_first("$sc", "(" + shortcut->get_as_text() + ")"); - } else { - tooltip += " (" + shortcut->get_as_text() + ")"; + String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")"; + if (shortcut->get_name().nocasecmp_to(tooltip) != 0) { + text += "\n" + tooltip; } + tooltip = text; } return tooltip; } diff --git a/scene/gui/button.h b/scene/gui/button.h index 35488582de..5c5a73bae3 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -56,7 +56,6 @@ private: float _internal_margin[4]; protected: - virtual Size2 get_minimum_size() const; void _set_internal_margin(Margin p_margin, float p_value); void _notification(int p_what); static void _bind_methods(); @@ -64,6 +63,8 @@ protected: public: // + virtual Size2 get_minimum_size() const; + void set_text(const String &p_text); String get_text() const; diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index cb6283507e..446676e80d 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -39,33 +39,32 @@ void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { - //sample->set_texture(get_icon("color_sample")); + btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); bt_add_preset->set_icon(get_icon("add_preset")); _update_controls(); } break; - case NOTIFICATION_ENTER_TREE: { + btn_pick->set_icon(get_icon("screen_picker", "ColorPicker")); bt_add_preset->set_icon(get_icon("add_preset")); _update_color(); } break; - case NOTIFICATION_PARENTED: { + for (int i = 0; i < 4; i++) set_margin((Margin)i, get_constant("margin")); } break; - case NOTIFICATION_VISIBILITY_CHANGED: { Popup *p = Object::cast_to<Popup>(get_parent()); if (p) p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2)); } break; - case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: { + if (screen != NULL) { if (screen->is_visible()) { screen->hide(); @@ -523,7 +522,6 @@ ColorPicker::ColorPicker() : add_child(hb_edit); w_edit = memnew(Control); - //w_edit->set_ignore_mouse(false); w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0)); w_edit->set_h_size_flags(SIZE_FILL); w_edit->set_v_size_flags(SIZE_EXPAND_FILL); @@ -589,7 +587,6 @@ ColorPicker::ColorPicker() : c_text->set_h_size_flags(SIZE_EXPAND_FILL); _update_controls(); - //_update_color(); updating = false; set_pick_color(Color(1, 1, 1)); @@ -599,7 +596,6 @@ ColorPicker::ColorPicker() : preset = memnew(TextureRect); bbc->add_child(preset); - //preset->set_ignore_mouse(false); preset->connect("gui_input", this, "_preset_input"); preset->connect("draw", this, "_update_presets"); @@ -660,11 +656,13 @@ bool ColorPickerButton::is_editing_alpha() const { return picker->is_editing_alpha(); } -ColorPicker *ColorPickerButton::get_picker() { +ColorPicker *ColorPickerButton::get_picker() const { + return picker; } -PopupPanel *ColorPickerButton::get_popup() { +PopupPanel *ColorPickerButton::get_popup() const { + return popup; } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index c02cdc8608..2bae279ed5 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -129,8 +129,8 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; - ColorPicker *get_picker(); - PopupPanel *get_popup(); + ColorPicker *get_picker() const; + PopupPanel *get_popup() const; ColorPickerButton(); }; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 81d2b6731f..b34abf5a46 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2835,7 +2835,7 @@ void Control::_bind_methods() { ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale"); ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset"); - ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); ADD_GROUP("Hint", "hint_"); ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip"); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index d4912339da..9a55073bb6 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -289,10 +289,17 @@ bool WindowDialog::get_resizable() const { Size2 WindowDialog::get_minimum_size() const { Ref<Font> font = get_font("title_font", "WindowDialog"); - int msx = close_button->get_combined_minimum_size().x; - msx += font->get_string_size(title).x; - return Size2(msx, 1); + const int button_width = close_button->get_combined_minimum_size().x; + const int title_width = font->get_string_size(title).x; + const int padding = button_width / 2; + const int button_area = button_width + padding; + + // as the title gets centered, title_width + close_button_width is not enough. + // we want a width w, such that w / 2 - title_width / 2 >= button_area, i.e. + // w >= 2 * button_area + title_width + + return Size2(2 * button_area + title_width, 1); } TextureButton *WindowDialog::get_close_button() { diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index e1f77594da..51a25c60a1 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -207,7 +207,7 @@ void Label::_notification(int p_what) { } break; } - int y_ofs = style->get_offset().y; + float y_ofs = style->get_offset().y; y_ofs += (line - lines_skipped) * font_h + font->get_ascent(); y_ofs += vbegin + line * vsep; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 85ae6d6241..cebbb2193d 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -85,7 +85,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) { - selection_clear(); + deselect(); selection.cursor_start = cursor_pos; selection.creating = true; } else if (selection.enabled) { @@ -99,7 +99,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } else { if ((!selection.creating) && (!selection.doubleclick)) { - selection_clear(); + deselect(); } selection.creating = false; selection.doubleclick = false; @@ -175,7 +175,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (editable) { - selection_clear(); + deselect(); text = text.substr(cursor_pos, text.length() - cursor_pos); Ref<Font> font = get_font("font"); @@ -204,7 +204,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (editable) { - selection_clear(); + deselect(); text = text.substr(0, cursor_pos); _text_changed(); } @@ -827,7 +827,7 @@ void LineEdit::shift_selection_check_pre(bool p_shift) { selection.cursor_start = cursor_pos; } if (!p_shift) - selection_clear(); + deselect(); } void LineEdit::shift_selection_check_post(bool p_shift) { @@ -880,13 +880,6 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { } set_cursor_position(ofs); - - /* - int new_cursor_pos=p_x; - int charwidth=draw_area->get_font_char_width(' ',0); - new_cursor_pos=( ( (new_cursor_pos-2)+ (charwidth/2) ) /charwidth ); - if (new_cursor_pos>(int)text.length()) new_cursor_pos=text.length(); - set_cursor_position(window_pos+new_cursor_pos); */ } bool LineEdit::cursor_get_blink_enabled() const { @@ -941,11 +934,6 @@ void LineEdit::delete_char() { set_cursor_position(get_cursor_position() - 1); - if (cursor_pos == window_pos) { - - //set_window_pos(cursor_pos-get_window_length()); - } - _text_changed(); } @@ -1143,7 +1131,7 @@ Size2 LineEdit::get_minimum_size() const { /* selection */ -void LineEdit::selection_clear() { +void LineEdit::deselect() { selection.begin = 0; selection.end = 0; @@ -1159,7 +1147,7 @@ void LineEdit::selection_delete() { if (selection.enabled) delete_text(selection.begin, selection.end); - selection_clear(); + deselect(); } void LineEdit::set_max_length(int p_max_length) { @@ -1224,7 +1212,7 @@ bool LineEdit::is_secret() const { void LineEdit::select(int p_from, int p_to) { if (p_from == 0 && p_to == 0) { - selection_clear(); + deselect(); return; } @@ -1383,7 +1371,9 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &LineEdit::_gui_input); ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear); + ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all); + ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect); ClassDB::bind_method(D_METHOD("set_text", "text"), &LineEdit::set_text); ClassDB::bind_method(D_METHOD("get_text"), &LineEdit::get_text); ClassDB::bind_method(D_METHOD("set_placeholder", "text"), &LineEdit::set_placeholder); @@ -1405,7 +1395,6 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable); ClassDB::bind_method(D_METHOD("set_secret", "enabled"), &LineEdit::set_secret); ClassDB::bind_method(D_METHOD("is_secret"), &LineEdit::is_secret); - ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("menu_option", "option"), &LineEdit::menu_option); ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); @@ -1457,7 +1446,7 @@ LineEdit::LineEdit() { pass = false; placeholder_alpha = 0.6; - selection_clear(); + deselect(); set_focus_mode(FOCUS_ALL); editable = true; set_default_cursor_shape(CURSOR_IBEAM); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index c3a299c2f5..5ca4ca15df 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -119,7 +119,6 @@ private: void shift_selection_check_pre(bool); void shift_selection_check_post(bool); - void selection_clear(); void selection_fill_at_cursor(); void selection_delete(); void set_window_pos(int p_pos); @@ -155,7 +154,9 @@ public: bool is_context_menu_enabled(); PopupMenu *get_menu() const; + void select(int p_from = 0, int p_to = -1); void select_all(); + void deselect(); void delete_char(); void delete_text(int p_from_column, int p_to_column); @@ -190,8 +191,6 @@ public: void set_secret(bool p_secret); bool is_secret() const; - void select(int p_from = 0, int p_to = -1); - virtual Size2 get_minimum_size() const; void set_expand_to_text_length(bool p_enabled); diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index d850553957..c235797bef 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -33,6 +33,9 @@ void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) { + if (disable_shortcuts) + return; + if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event))) { if (!get_parent() || !is_visible_in_tree() || is_disabled()) @@ -60,25 +63,10 @@ void MenuButton::pressed() { void MenuButton::_gui_input(Ref<InputEvent> p_event) { - /*if (p_event.type==InputEvent::MOUSE_BUTTON && p_event->get_button_index()==BUTTON_LEFT) { - clicked=p_event->is_pressed(); - } - if (clicked && p_event.type==InputEvent::MOUSE_MOTION && popup->is_visible_in_tree()) { - - Point2 gt = Point2(p_event.mouse_motion.x,p_event.mouse_motion.y); - gt = get_global_transform().xform(gt); - Point2 lt = popup->get_transform().affine_inverse().xform(gt); - if (popup->has_point(lt)) { - //print_line("HAS POINT!!!"); - popup->call_deferred("grab_click_focus"); - } - - }*/ - BaseButton::_gui_input(p_event); } -PopupMenu *MenuButton::get_popup() { +PopupMenu *MenuButton::get_popup() const { return popup; } @@ -98,14 +86,22 @@ void MenuButton::_bind_methods() { ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &MenuButton::_unhandled_key_input); ClassDB::bind_method(D_METHOD("_set_items"), &MenuButton::_set_items); ClassDB::bind_method(D_METHOD("_get_items"), &MenuButton::_get_items); + ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuButton::set_disable_shortcuts); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items"); ADD_SIGNAL(MethodInfo("about_to_show")); } + +void MenuButton::set_disable_shortcuts(bool p_disabled) { + + disable_shortcuts = p_disabled; +} + MenuButton::MenuButton() { set_flat(true); + set_disable_shortcuts(false); set_enabled_focus_mode(FOCUS_NONE); popup = memnew(PopupMenu); popup->hide(); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index c7f1d976ff..1bd9b155b2 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -40,6 +40,7 @@ class MenuButton : public Button { GDCLASS(MenuButton, Button); bool clicked; + bool disable_shortcuts; PopupMenu *popup; virtual void pressed(); @@ -53,7 +54,9 @@ protected: static void _bind_methods(); public: - PopupMenu *get_popup(); + PopupMenu *get_popup() const; + void set_disable_shortcuts(bool p_disabled); + MenuButton(); ~MenuButton(); }; diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 70f3d9ca83..6f784b56de 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -42,38 +42,35 @@ Size2 OptionButton::get_minimum_size() const { void OptionButton::_notification(int p_what) { - switch (p_what) { - - case NOTIFICATION_DRAW: { - - if (!has_icon("arrow")) - return; - - RID ci = get_canvas_item(); - Ref<Texture> arrow = Control::get_icon("arrow"); - Ref<StyleBox> normal = get_stylebox("normal"); - Color clr = Color(1, 1, 1); - if (get_constant("modulate_arrow")) - switch (get_draw_mode()) { - case DRAW_PRESSED: - clr = get_color("font_color_pressed"); - break; - case DRAW_HOVER: - clr = get_color("font_color_hover"); - break; - case DRAW_DISABLED: - clr = get_color("font_color_disabled"); - break; - default: - clr = get_color("font_color"); - } - - Size2 size = get_size(); - - Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); - arrow->draw(ci, ofs, clr); - - } break; + if (p_what == NOTIFICATION_DRAW) { + + if (!has_icon("arrow")) + return; + + RID ci = get_canvas_item(); + Ref<Texture> arrow = Control::get_icon("arrow"); + Ref<StyleBox> normal = get_stylebox("normal"); + Color clr = Color(1, 1, 1); + if (get_constant("modulate_arrow")) { + switch (get_draw_mode()) { + case DRAW_PRESSED: + clr = get_color("font_color_pressed"); + break; + case DRAW_HOVER: + clr = get_color("font_color_hover"); + break; + case DRAW_DISABLED: + clr = get_color("font_color_disabled"); + break; + default: + clr = get_color("font_color"); + } + } + + Size2 size = get_size(); + + Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2))); + arrow->draw(ci, ofs, clr); } } @@ -244,6 +241,11 @@ void OptionButton::remove_item(int p_idx) { popup->remove_item(p_idx); } +PopupMenu *OptionButton::get_popup() const { + + return popup; +} + Array OptionButton::_get_items() const { Array items; @@ -310,6 +312,8 @@ void OptionButton::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item); ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int); + ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup); + ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items); ClassDB::bind_method(D_METHOD("_get_items"), &OptionButton::_get_items); @@ -320,15 +324,16 @@ void OptionButton::_bind_methods() { OptionButton::OptionButton() { + current = -1; + set_text_align(ALIGN_LEFT); + set_action_mode(ACTION_MODE_BUTTON_PRESS); + popup = memnew(PopupMenu); popup->hide(); + add_child(popup); popup->set_as_toplevel(true); popup->set_pass_on_modal_close_click(false); - add_child(popup); popup->connect("id_pressed", this, "_selected"); - - current = -1; - set_text_align(ALIGN_LEFT); } OptionButton::~OptionButton() { diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index a06c540678..b09942b072 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -85,6 +85,8 @@ public: void remove_item(int p_idx); + PopupMenu *get_popup() const; + virtual void get_translatable_strings(List<String> *p_strings) const; OptionButton(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 32f889e826..d598104cf5 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -42,24 +42,6 @@ String PopupMenu::_get_accel_text(int p_item) const { else if (items[p_item].accel) return keycode_get_string(items[p_item].accel); return String(); - - /* - String atxt; - if (p_accel&KEY_MASK_SHIFT) - atxt+="Shift+"; - if (p_accel&KEY_MASK_ALT) - atxt+="Alt+"; - if (p_accel&KEY_MASK_CTRL) - atxt+="Ctrl+"; - if (p_accel&KEY_MASK_META) - atxt+="Meta+"; - - p_accel&=KEY_CODE_MASK; - - atxt+=String::chr(p_accel).to_upper(); - - return atxt; -*/ } Size2 PopupMenu::get_minimum_size() const { @@ -136,7 +118,6 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { Ref<Font> font = get_font("font"); int vseparation = get_constant("vseparation"); - //int hseparation = get_constant("hseparation"); float font_h = font->get_height(); for (int i = 0; i < items.size(); i++) { @@ -221,7 +202,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { case KEY_DOWN: { - for (int i = mouse_over + 1; i < items.size(); i++) { + int search_from = mouse_over + 1; + if (search_from >= items.size()) + search_from = 0; + + for (int i = search_from; i < items.size(); i++) { if (i < 0 || i >= items.size()) continue; @@ -236,7 +221,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } break; case KEY_UP: { - for (int i = mouse_over - 1; i >= 0; i--) { + int search_from = mouse_over - 1; + if (search_from < 0) + search_from = items.size() - 1; + + for (int i = search_from; i >= 0; i--) { if (i < 0 || i >= items.size()) continue; @@ -249,11 +238,36 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { } } } break; + + case KEY_LEFT: { + + Node *n = get_parent(); + if (!n) + break; + + PopupMenu *pm = Object::cast_to<PopupMenu>(n); + if (!pm) + break; + + hide(); + } break; + + case KEY_RIGHT: { + + if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) + _activate_submenu(mouse_over); + } break; + case KEY_ENTER: case KEY_KP_ENTER: { if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) { + if (items[mouse_over].submenu != "" && submenu_over != mouse_over) { + _activate_submenu(mouse_over); + break; + } + activate_item(mouse_over); } } break; @@ -500,6 +514,13 @@ void PopupMenu::_notification(int p_what) { } break; case NOTIFICATION_MOUSE_EXIT: { + if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) { + mouse_over = -1; + update(); + } + } break; + case NOTIFICATION_POPUP_HIDE: { + if (mouse_over >= 0) { mouse_over = -1; update(); @@ -1217,6 +1238,7 @@ void PopupMenu::set_invalidate_click_until_motion() { PopupMenu::PopupMenu() { mouse_over = -1; + submenu_over = -1; set_focus_mode(FOCUS_ALL); set_as_toplevel(true); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 05c6e9f77e..6fbc58a38a 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -31,6 +31,11 @@ #include "os/keyboard.h" #include "os/os.h" #include "scene/scene_string_names.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) { if (p_free) { @@ -370,7 +375,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & Color uc = color; uc.a *= 0.5; int uy = y + lh - fh + ascent + 2; - VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc); + float underline_width = 1.0; +#ifdef TOOLS_ENABLED + underline_width *= EDSCALE; +#endif + VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc, underline_width); } ofs += cw; } diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 4420a936d2..1c15953517 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -61,7 +61,7 @@ Control *SplitContainer::_getch(int p_idx) const { void SplitContainer::_resort() { - /** First pass, determine minimum size AND amount of stretchable elements */ + /* First pass, determine minimum size AND amount of stretchable elements */ int axis = vertical ? 1 : 0; @@ -114,10 +114,8 @@ void SplitContainer::_resort() { Size2 ms_second = second->get_combined_minimum_size(); if (vertical) { - minimum = ms_first.height + ms_second.height; } else { - minimum = ms_first.width + ms_second.width; } @@ -141,12 +139,10 @@ void SplitContainer::_resort() { } else if (expand_first_mode) { middle_sep = get_size()[axis] - ms_second[axis] - sep; - } else { middle_sep = ms_first[axis]; } - } else if (ratiomode) { int first_ratio = first->get_stretch_ratio(); @@ -160,23 +156,19 @@ void SplitContainer::_resort() { expand_ofs = (available * (1.0 - ratio)); middle_sep = ms_first[axis] + available * ratio + expand_ofs; - } else if (expand_first_mode) { if (expand_ofs > 0) expand_ofs = 0; - - if (expand_ofs < -available) + else if (expand_ofs < -available) expand_ofs = -available; middle_sep = get_size()[axis] - ms_second[axis] - sep + expand_ofs; - } else { if (expand_ofs < 0) expand_ofs = 0; - - if (expand_ofs > available) + else if (expand_ofs > available) expand_ofs = available; middle_sep = ms_first[axis] + expand_ofs; @@ -187,7 +179,6 @@ void SplitContainer::_resort() { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep))); int sofs = middle_sep + sep; fit_child_in_rect(second, Rect2(Point2(0, sofs), Size2(get_size().width, get_size().height - sofs))); - } else { fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(middle_sep, get_size().height))); @@ -246,10 +237,12 @@ void SplitContainer::_notification(int p_what) { _resort(); } break; case NOTIFICATION_MOUSE_ENTER: { + mouse_inside = true; update(); } break; case NOTIFICATION_MOUSE_EXIT: { + mouse_inside = false; update(); } break; @@ -260,22 +253,17 @@ void SplitContainer::_notification(int p_what) { if (collapsed || (!mouse_inside && get_constant("autohide"))) return; + int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0; Ref<Texture> tex = get_icon("grabber"); Size2 size = get_size(); - if (vertical) { + if (dragger_visibility == DRAGGER_VISIBLE) { - //draw_style_box( get_stylebox("bg"), Rect2(0,middle_sep,get_size().width,sep)); - if (dragger_visibility == DRAGGER_VISIBLE) + if (vertical) draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2)); - - } else { - - //draw_style_box( get_stylebox("bg"), Rect2(middle_sep,0,sep,get_size().height)); - if (dragger_visibility == DRAGGER_VISIBLE) + else draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2)); } - } break; } } @@ -292,11 +280,13 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { + int sep = get_constant("separation"); if (vertical) { if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) { + dragging = true; drag_from = mb->get_position().y; drag_ofs = expand_ofs; @@ -304,6 +294,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { } else { if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) { + dragging = true; drag_from = mb->get_position().x; drag_ofs = expand_ofs; @@ -318,36 +309,31 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid()) { - - if (dragging) { + if (mm.is_valid() && dragging) { - expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); - queue_sort(); - emit_signal("dragged", get_split_offset()); - } + expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from); + queue_sort(); + emit_signal("dragged", get_split_offset()); } } Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const { - if (collapsed) - return Control::get_cursor_shape(p_pos); - if (dragging) return (vertical ? CURSOR_VSIZE : CURSOR_HSIZE); - int sep = get_constant("separation"); + if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) { - if (vertical) { + int sep = get_constant("separation"); - if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) { - return CURSOR_VSIZE; - } - } else { + if (vertical) { - if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) { - return CURSOR_HSIZE; + if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) + return CURSOR_VSIZE; + } else { + + if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) + return CURSOR_HSIZE; } } @@ -358,6 +344,7 @@ void SplitContainer::set_split_offset(int p_offset) { if (expand_ofs == p_offset) return; + expand_ofs = p_offset; queue_sort(); } @@ -371,6 +358,7 @@ void SplitContainer::set_collapsed(bool p_collapsed) { if (collapsed == p_collapsed) return; + collapsed = p_collapsed; queue_sort(); } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index c7a484c4c5..40a58d4b32 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -88,7 +88,7 @@ class HSplitContainer : public SplitContainer { public: HSplitContainer() : - SplitContainer(false) { set_default_cursor_shape(CURSOR_HSPLIT); } + SplitContainer(false) {} }; class VSplitContainer : public SplitContainer { @@ -97,7 +97,7 @@ class VSplitContainer : public SplitContainer { public: VSplitContainer() : - SplitContainer(true) { set_default_cursor_shape(CURSOR_VSPLIT); } + SplitContainer(true) {} }; #endif // SPLIT_CONTAINER_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index e5169089f2..0fba4a6f94 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1664,17 +1664,22 @@ void TextEdit::backspace_at_cursor() { cursor_set_column(prev_column); } -void TextEdit::indent_selection_right() { +void TextEdit::indent_right() { - if (!is_selection_active()) { - return; - } + int start_line; + int end_line; begin_complex_operation(); - int start_line = get_selection_from_line(); - int end_line = get_selection_to_line(); + + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + } else { + start_line = cursor.line; + end_line = start_line; + } // ignore if the cursor is not past the first column - if (get_selection_to_column() == 0) { + if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } @@ -1688,23 +1693,31 @@ void TextEdit::indent_selection_right() { set_line(i, line_text); } - // fix selection being off by one on the last line - selection.to_column++; + // fix selection and cursor being off by one on the last line + if (is_selection_active()) { + select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1); + } + cursor_set_column(cursor.column + 1, false); end_complex_operation(); update(); } -void TextEdit::indent_selection_left() { +void TextEdit::indent_left() { - if (!is_selection_active()) { - return; - } + int start_line; + int end_line; begin_complex_operation(); - int start_line = get_selection_from_line(); - int end_line = get_selection_to_line(); + + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + } else { + start_line = cursor.line; + end_line = start_line; + } // ignore if the cursor is not past the first column - if (get_selection_to_column() == 0) { + if (is_selection_active() && get_selection_to_column() == 0) { end_line--; } String last_line_text = get_line(end_line); @@ -1721,10 +1734,11 @@ void TextEdit::indent_selection_left() { } } - // fix selection being off by one on the last line - if (last_line_text != get_line(end_line) && selection.to_column > 0) { - selection.to_column--; + // fix selection and cursor being off by one on the last line + if (is_selection_active() && last_line_text != get_line(end_line)) { + select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1); } + cursor_set_column(cursor.column - 1, false); end_complex_operation(); update(); } @@ -1953,6 +1967,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + _reset_caret_blink_timer(); + + int row, col; + update_line_scroll_pos(); + _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); + + if (is_right_click_moving_caret()) { + if (is_selection_active()) { + + int from_line = get_selection_from_line(); + int to_line = get_selection_to_line(); + int from_column = get_selection_from_column(); + int to_column = get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + deselect(); + } + } + if (!is_selection_active()) { + cursor_set_line(row, true, false); + cursor_set_column(col); + } + } + menu->set_position(get_global_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); menu->popup(); @@ -2216,9 +2255,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { case KEY_TAB: { if (k->get_shift()) { - indent_selection_left(); + indent_left(); } else { - indent_selection_right(); + indent_right(); } dobreak = true; accept_event(); @@ -2389,8 +2428,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (readonly) break; - if (selection.active) { - + if (is_selection_active()) { + if (k->get_shift()) { + indent_left(); + } else { + indent_right(); + } } else { if (k->get_shift()) { @@ -3684,6 +3727,14 @@ bool TextEdit::cursor_is_block_mode() const { return block_caret; } +void TextEdit::set_right_click_moves_caret(bool p_enable) { + right_click_moves_caret = p_enable; +} + +bool TextEdit::is_right_click_moving_caret() const { + return right_click_moves_caret; +} + void TextEdit::_v_scroll_input() { scrolling = false; } @@ -4060,7 +4111,7 @@ void TextEdit::cut() { backspace_at_cursor(); update(); cursor_set_line(cursor.line + 1); - cut_copy_line = true; + cut_copy_line = clipboard; } else { @@ -4074,7 +4125,7 @@ void TextEdit::cut() { selection.active = false; selection.selecting_mode = Selection::MODE_NONE; update(); - cut_copy_line = false; + cut_copy_line = ""; } } @@ -4083,11 +4134,11 @@ void TextEdit::copy() { if (!selection.active) { String clipboard = _base_get_text(cursor.line, 0, cursor.line, text[cursor.line].length()); OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = true; + cut_copy_line = clipboard; } else { String clipboard = _base_get_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = false; + cut_copy_line = ""; } } @@ -4103,7 +4154,7 @@ void TextEdit::paste() { cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - } else if (cut_copy_line) { + } else if (!cut_copy_line.empty() && cut_copy_line == clipboard) { cursor_set_column(0); String ins = "\n"; @@ -4144,11 +4195,15 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t p_from_line = text.size() - 1; if (p_from_column >= text[p_from_line].length()) p_from_column = text[p_from_line].length(); + if (p_from_column < 0) + p_from_column = 0; if (p_to_line >= text.size()) p_to_line = text.size() - 1; if (p_to_column >= text[p_to_line].length()) p_to_column = text[p_to_line].length(); + if (p_to_column < 0) + p_to_column = 0; selection.from_line = p_from_line; selection.from_column = p_from_column; @@ -5433,6 +5488,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode); ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode); + ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret); + ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret); + ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly); ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly); @@ -5444,8 +5502,10 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut); ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy); ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste); - ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all); + ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select); + ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all); + ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect); ClassDB::bind_method(D_METHOD("is_selection_active"), &TextEdit::is_selection_active); ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line); @@ -5466,7 +5526,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); - ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden); + ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden); ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); @@ -5514,6 +5574,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret"); ADD_SIGNAL(MethodInfo("cursor_changed")); ADD_SIGNAL(MethodInfo("text_changed")); @@ -5591,6 +5652,7 @@ TextEdit::TextEdit() { caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", this, "_toggle_draw_caret"); cursor_set_blink_enabled(false); + right_click_moves_caret = true; idle_detect = memnew(Timer); add_child(idle_detect); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index dd305d5822..f18eaa85cb 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -246,6 +246,7 @@ class TextEdit : public Control { bool draw_caret; bool window_has_focus; bool block_caret; + bool right_click_moves_caret; bool setting_row; bool wrap; @@ -270,7 +271,7 @@ class TextEdit : public Control { bool brace_matching_enabled; bool highlight_current_line; bool auto_indent; - bool cut_copy_line; + String cut_copy_line; bool insert_mode; bool select_identifiers_enabled; @@ -443,8 +444,8 @@ public: void set_line(int line, String new_text); void backspace_at_cursor(); - void indent_selection_left(); - void indent_selection_right(); + void indent_left(); + void indent_right(); int get_indent_level(int p_line) const; inline void set_scroll_pass_end_of_file(bool p_enabled) { @@ -481,6 +482,9 @@ public: void cursor_set_block_mode(const bool p_enable); bool cursor_is_block_mode() const; + void set_right_click_moves_caret(bool p_enable); + bool is_right_click_moving_caret() const; + void set_readonly(bool p_readonly); bool is_readonly() const; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index ab12d123ba..51ad22e271 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -30,6 +30,7 @@ #include "tree.h" #include <limits.h> +#include "math_funcs.h" #include "os/input.h" #include "os/keyboard.h" #include "os/os.h" @@ -37,6 +38,10 @@ #include "project_settings.h" #include "scene/main/viewport.h" +#ifdef TOOLS_ENABLED +#include "editor/editor_node.h" +#endif + void TreeItem::move_to_top() { if (!parent || parent->childs == this) @@ -1412,9 +1417,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (c->get_children() != NULL) root_pos -= Point2i(cache.arrow->get_width(), 0); + float line_width = 1.0; +#ifdef TOOLS_ENABLED + line_width *= EDSCALE; +#endif + Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; - VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x, root_pos.y), cache.relationship_line_color); - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color); + VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); } int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); @@ -1765,7 +1775,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool case TreeItem::CELL_MODE_STRING: { //nothing in particular - if (select_mode == SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) { + if (select_mode == SELECT_MULTI && (get_tree()->get_event_count() == focus_in_id || !already_cursor)) { bring_up_editor = false; } @@ -1853,7 +1863,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool } else { editor_text = String::num(p_item->cells[col].val, Math::step_decimals(p_item->cells[col].step)); - if (select_mode == SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id) + if (select_mode == SELECT_MULTI && get_tree()->get_event_count() == focus_in_id) bring_up_editor = false; } } @@ -2776,7 +2786,7 @@ void Tree::_notification(int p_what) { if (p_what == NOTIFICATION_FOCUS_ENTER) { - focus_in_id = get_tree()->get_last_event_id(); + focus_in_id = get_tree()->get_event_count(); } if (p_what == NOTIFICATION_MOUSE_EXIT) { @@ -2940,43 +2950,51 @@ Size2 Tree::get_minimum_size() const { return Size2(1, 1); } -TreeItem *Tree::create_item(TreeItem *p_parent) { +TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { ERR_FAIL_COND_V(blocked > 0, NULL); - TreeItem *ti = memnew(TreeItem(this)); - - ERR_FAIL_COND_V(!ti, NULL); - ti->cells.resize(columns.size()); + TreeItem *ti = NULL; if (p_parent) { - /* Always append at the end */ + // Append or insert a new item to the given parent. + ti = memnew(TreeItem(this)); + ERR_FAIL_COND_V(!ti, NULL); + ti->cells.resize(columns.size()); - TreeItem *last = 0; + TreeItem *prev = NULL; TreeItem *c = p_parent->childs; + int idx = 0; while (c) { - - last = c; + if (idx++ == p_idx) { + ti->next = c; + break; + } + prev = c; c = c->next; } - if (last) { - - last->next = ti; - } else { - + if (prev) + prev->next = ti; + else p_parent->childs = ti; - } ti->parent = p_parent; } else { - if (root) - ti->childs = root; + if (!root) { + // No root exists, make the given item the new root. + ti = memnew(TreeItem(this)); + ERR_FAIL_COND_V(!ti, NULL); + ti->cells.resize(columns.size()); - root = ti; + root = ti; + } else { + // Root exists, append or insert to root. + ti = create_item(root, p_idx); + } } return ti; @@ -3713,7 +3731,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("_scroll_moved"), &Tree::_scroll_moved); ClassDB::bind_method(D_METHOD("clear"), &Tree::clear); - ClassDB::bind_method(D_METHOD("create_item", "parent"), &Tree::_create_item, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); ClassDB::bind_method(D_METHOD("set_column_min_width", "column", "min_width"), &Tree::set_column_min_width); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 112de3165f..b8d94bcffb 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -359,7 +359,7 @@ private: LineEdit *text_editor; HSlider *value_editor; bool updating_value_editor; - uint32_t focus_in_id; + int64_t focus_in_id; PopupMenu *popup_menu; Vector<ColumnInfo> columns; @@ -511,8 +511,8 @@ protected: static void _bind_methods(); //bind helpers - Object *_create_item(Object *p_parent) { - return create_item(Object::cast_to<TreeItem>(p_parent)); + Object *_create_item(Object *p_parent, int p_idx = -1) { + return create_item(Object::cast_to<TreeItem>(p_parent), p_idx); } TreeItem *_get_next_selected(Object *p_item) { @@ -532,7 +532,7 @@ public: void clear(); - TreeItem *create_item(TreeItem *p_parent = 0); + TreeItem *create_item(TreeItem *p_parent = 0, int p_idx = -1); TreeItem *get_root(); TreeItem *get_last_item(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index efc5d269a6..942a6d5428 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -340,7 +340,8 @@ void Node::move_child(Node *p_child, int p_pos) { data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT); } for (const Map<StringName, GroupData>::Element *E = p_child->data.grouped.front(); E; E = E->next()) { - E->get().group->changed = true; + if (E->get().group) + E->get().group->changed = true; } data.blocked--; @@ -2110,6 +2111,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const StringName script_property_name = CoreStringNames::get_singleton()->_script; + List<const Node *> hidden_roots; List<const Node *> node_tree; node_tree.push_front(this); @@ -2120,11 +2122,16 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { for (int i = 0; i < N->get()->get_child_count(); ++i) { + Node *descendant = N->get()->get_child(i); // Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later - if (N->get()->get_child(i)->data.owner != this) + // but remember non-instanced nodes that are hidden below instanced ones + if (descendant->data.owner != this) { + if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this) + hidden_roots.push_back(descendant); continue; + } - node_tree.push_back(N->get()->get_child(i)); + node_tree.push_back(descendant); } } } @@ -2156,7 +2163,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const Variant value = N->get()->get(name); // Duplicate dictionaries and arrays, mainly needed for __meta__ if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).copy(); + value = Dictionary(value).duplicate(); } else if (value.get_type() == Variant::ARRAY) { value = Array(value).duplicate(); } @@ -2201,6 +2208,34 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const } node->add_child(dup); + if (i < node->get_child_count() - 1) { + node->move_child(dup, i); + } + } + + for (List<const Node *>::Element *E = hidden_roots.front(); E; E = E->next()) { + + Node *parent = node->get_node(get_path_to(E->get()->data.parent)); + if (!parent) { + + memdelete(node); + return NULL; + } + + Node *dup = E->get()->_duplicate(p_flags, r_duplimap); + if (!dup) { + + memdelete(node); + return NULL; + } + + parent->add_child(dup); + int pos = E->get()->get_position_in_parent(); + + if (pos < parent->get_child_count() - 1) { + + parent->move_child(dup, pos); + } } return node; @@ -2269,7 +2304,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p Variant value = get(name); // Duplicate dictionaries and arrays, mainly needed for __meta__ if (value.get_type() == Variant::DICTIONARY) { - value = Dictionary(value).copy(); + value = Dictionary(value).duplicate(); } else if (value.get_type() == Variant::ARRAY) { value = Array(value).duplicate(); } diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index deb40800bc..db39b37bd5 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -38,6 +38,7 @@ #include "os/os.h" #include "print_string.h" #include "project_settings.h" +#include "scene/resources/dynamic_font.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/packed_scene.h" @@ -390,13 +391,12 @@ void SceneTree::input_event(const Ref<InputEvent> &p_event) { if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event))) return; //avoid joy input on editor + current_event++; root_lock++; - //last_id=p_event.ID; input_handled = false; Ref<InputEvent> ev = p_event; - ev->set_id(++last_id); //this should work better MainLoop::input_event(ev); @@ -495,6 +495,11 @@ bool SceneTree::idle(float p_time) { Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); if (win_size != last_screen_size) { + if (use_font_oversampling) { + DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width; + DynamicFont::update_oversampling(); + } + last_screen_size = win_size; _update_root_rect(); @@ -935,11 +940,6 @@ void SceneMainLoop::_update_listener_2d() { } */ -uint32_t SceneTree::get_last_event_id() const { - - return last_id; -} - Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { r_error.error = Variant::CallError::CALL_OK; @@ -988,6 +988,10 @@ int64_t SceneTree::get_frame() const { return current_frame; } +int64_t SceneTree::get_event_count() const { + + return current_event; +} Array SceneTree::_get_nodes_in_group(const StringName &p_group) { @@ -2195,6 +2199,9 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("_connection_failed"), &SceneTree::_connection_failed); ClassDB::bind_method(D_METHOD("_server_disconnected"), &SceneTree::_server_disconnected); + ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling); + ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling); + ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node"))); @@ -2244,6 +2251,20 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) { idle_callbacks[idle_callback_count++] = p_callback; } +void SceneTree::set_use_font_oversampling(bool p_oversampling) { + + use_font_oversampling = p_oversampling; + if (use_font_oversampling) { + DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width; + } else { + DynamicFontAtSize::font_oversampling = 1.0; + } +} + +bool SceneTree::is_using_font_oversampling() const { + return use_font_oversampling; +} + SceneTree::SceneTree() { singleton = this; @@ -2264,9 +2285,10 @@ SceneTree::SceneTree() { tree_version = 1; physics_process_time = 1; idle_process_time = 1; - last_id = 1; + root = NULL; current_frame = 0; + current_event = 0; tree_changed_name = "tree_changed"; node_added_name = "node_added"; node_removed_name = "node_removed"; @@ -2327,7 +2349,7 @@ SceneTree::SceneTree() { ProjectSettings::get_singleton()->set("rendering/environment/default_environment", ""); } else { //file was erased, notify user. - ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded.")); + ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Environment -> Default Environment) could not be loaded.")); } } } @@ -2380,6 +2402,8 @@ SceneTree::SceneTree() { last_send_cache_id = 1; #endif + + use_font_oversampling = false; } SceneTree::~SceneTree() { diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 244fc8da62..3e2e74b553 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -109,7 +109,6 @@ private: float idle_process_time; bool accept_quit; bool quit_on_go_back; - uint32_t last_id; #ifdef DEBUG_ENABLED bool debug_collisions_hint; @@ -122,12 +121,15 @@ private: bool _quit; bool initialized; bool input_handled; + Size2 last_screen_size; StringName tree_changed_name; StringName node_added_name; StringName node_removed_name; + bool use_font_oversampling; int64_t current_frame; + int64_t current_event; int node_count; #ifdef TOOLS_ENABLED @@ -323,7 +325,7 @@ public: NOTIFICATION_TRANSFORM_CHANGED = 29 }; - enum CallGroupFlags { + enum GroupCallFlags { GROUP_CALL_DEFAULT = 0, GROUP_CALL_REVERSE = 1, GROUP_CALL_REALTIME = 2, @@ -333,8 +335,6 @@ public: _FORCE_INLINE_ Viewport *get_root() const { return root; } - uint32_t get_last_event_id() const; - void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value); @@ -410,6 +410,7 @@ public: int get_collision_debug_contact_count() { return collision_debug_contacts; } int64_t get_frame() const; + int64_t get_event_count() const; int get_node_count() const; @@ -420,6 +421,9 @@ public: void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize, real_t p_shrink = 1); + void set_use_font_oversampling(bool p_oversampling); + bool is_using_font_oversampling() const; + //void change_scene(const String& p_path); //Node *get_loaded_scene(); @@ -462,6 +466,6 @@ public: VARIANT_ENUM_CAST(SceneTree::StretchMode); VARIANT_ENUM_CAST(SceneTree::StretchAspect); -VARIANT_ENUM_CAST(SceneTree::CallGroupFlags); +VARIANT_ENUM_CAST(SceneTree::GroupCallFlags); #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 4635de81e8..fa6a7832f5 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -184,7 +184,6 @@ Viewport::GUI::GUI() { key_focus = NULL; mouse_over = NULL; - cancelled_input_ID = 0; tooltip = NULL; tooltip_popup = NULL; tooltip_label = NULL; @@ -1421,7 +1420,7 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP)); gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT)); gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM)); - gui.tooltip_label->set_text(tooltip); + gui.tooltip_label->set_text(tooltip.strip_edges()); Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size()); Rect2 vr = gui.tooltip_label->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) @@ -1620,9 +1619,6 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che void Viewport::_gui_input_event(Ref<InputEvent> p_event) { - if (p_event->get_id() == gui.cancelled_input_ID) { - return; - } //? /* if (!is_visible()) { @@ -1640,7 +1636,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (mb->is_pressed()) { Size2 pos = mpos; - if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) { + if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button && mb->get_button_index() == BUTTON_LEFT) { //do not steal mouse focus and stuff @@ -1659,6 +1655,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { //cancel event, sorry, modal exclusive EATS UP ALL //alternative, you can't pop out a window the same frame it was made modal (fixes many issues) get_tree()->set_input_as_handled(); + return; // no one gets the event if exclusive NO ONE } @@ -1751,7 +1748,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_call_input(gui.mouse_focus, mb); } - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id()); get_tree()->set_input_as_handled(); if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { @@ -1807,21 +1803,23 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { pos = gui.focus_inv_xform.xform(pos); mb->set_position(pos); - if (gui.mouse_focus->can_process()) { - _gui_call_input(gui.mouse_focus, mb); - } + Control *mouse_focus = gui.mouse_focus; + //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise if (mb->get_button_index() == gui.mouse_focus_button) { gui.mouse_focus = NULL; gui.mouse_focus_button = -1; } + if (mouse_focus->can_process()) { + _gui_call_input(mouse_focus, mb); + } + /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) { _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); gui.drag_data=Variant(); //always clear }*/ - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id()); get_tree()->set_input_as_handled(); } } @@ -2348,7 +2346,6 @@ void Viewport::_gui_control_grab_focus(Control *p_control) { //no need for change if (gui.key_focus && gui.key_focus == p_control) return; - get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus"); gui.key_focus = p_control; p_control->notification(Control::NOTIFICATION_FOCUS_ENTER); @@ -2370,6 +2367,21 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) { else p_control->_modal_set_prev_focus_owner(0); + if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus)) { + Ref<InputEventMouseButton> mb; + mb.instance(); + mb->set_position(gui.mouse_focus->get_local_mouse_position()); + mb->set_global_position(gui.mouse_focus->get_local_mouse_position()); + mb->set_button_index(gui.mouse_focus_button); + mb->set_pressed(false); + gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb); + + //if (gui.mouse_over == gui.mouse_focus) { + // gui.mouse_focus->notification(Control::NOTIFICATION_MOUSE_EXIT); + //} + gui.mouse_focus = NULL; + } + return gui.modal_stack.back(); } @@ -2886,7 +2898,7 @@ Viewport::Viewport() { gui.canvas_sort_index = 0; msaa = MSAA_DISABLED; - hdr = false; + hdr = true; usage = USAGE_3D; debug_draw = DEBUG_DRAW_DISABLED; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 0835e3f69a..c084e348b5 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -269,7 +269,6 @@ private: float tooltip_timer; float tooltip_delay; List<Control *> modal_stack; - unsigned int cancelled_input_ID; Transform2D focus_inv_xform; bool subwindow_order_dirty; List<Control *> subwindows; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 9715e1d6a0..0c8837ee1a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -200,6 +200,9 @@ static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL; static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL; +static ResourceFormatSaverShader *resource_saver_shader = NULL; +static ResourceFormatLoaderShader *resource_loader_shader = NULL; + void register_scene_types() { SceneStringNames::create(); @@ -268,11 +271,11 @@ void register_scene_types() { ClassDB::register_class<Control>(); ClassDB::register_class<Button>(); ClassDB::register_class<Label>(); - ClassDB::register_class<ScrollBar>(); + ClassDB::register_virtual_class<ScrollBar>(); ClassDB::register_class<HScrollBar>(); ClassDB::register_class<VScrollBar>(); ClassDB::register_class<ProgressBar>(); - ClassDB::register_class<Slider>(); + ClassDB::register_virtual_class<Slider>(); ClassDB::register_class<HSlider>(); ClassDB::register_class<VSlider>(); ClassDB::register_class<Popup>(); @@ -283,7 +286,7 @@ void register_scene_types() { ClassDB::register_class<ToolButton>(); ClassDB::register_class<LinkButton>(); ClassDB::register_class<Panel>(); - ClassDB::register_class<Range>(); + ClassDB::register_virtual_class<Range>(); OS::get_singleton()->yield(); //may take time to init @@ -542,6 +545,8 @@ void register_scene_types() { ClassDB::register_class<DynamicFontData>(); ClassDB::register_class<DynamicFont>(); + DynamicFont::initialize_dynamic_fonts(); + ClassDB::register_virtual_class<StyleBox>(); ClassDB::register_class<StyleBoxEmpty>(); ClassDB::register_class<StyleBoxTexture>(); @@ -605,6 +610,12 @@ void register_scene_types() { resource_loader_text = memnew(ResourceFormatLoaderText); ResourceLoader::add_resource_format_loader(resource_loader_text, true); + resource_saver_shader = memnew(ResourceFormatSaverShader); + ResourceSaver::add_resource_format_saver(resource_saver_shader, true); + + resource_loader_shader = memnew(ResourceFormatLoaderShader); + ResourceLoader::add_resource_format_loader(resource_loader_shader, true); + for (int i = 0; i < 20; i++) { GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), ""); GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); @@ -621,6 +632,8 @@ void unregister_scene_types() { memdelete(resource_loader_stream_texture); memdelete(resource_loader_theme); + DynamicFont::finish_dynamic_fonts(); + if (resource_saver_text) { memdelete(resource_saver_text); } @@ -628,6 +641,13 @@ void unregister_scene_types() { memdelete(resource_loader_text); } + if (resource_saver_shader) { + memdelete(resource_saver_shader); + } + if (resource_loader_shader) { + memdelete(resource_loader_shader); + } + SpatialMaterial::finish_shaders(); ParticlesMaterial::finish_shaders(); CanvasItemMaterial::finish_shaders(); diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp index a40417f24d..66b1e49d13 100644 --- a/scene/resources/dynamic_font.cpp +++ b/scene/resources/dynamic_font.cpp @@ -191,10 +191,10 @@ Error DynamicFontAtSize::_load() { ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER ); }*/ - error = FT_Set_Pixel_Sizes(face, 0, id.size); + error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling); - ascent = face->size->metrics.ascender >> 6; - descent = -face->size->metrics.descender >> 6; + ascent = (face->size->metrics.ascender >> 6) / oversampling; + descent = (-face->size->metrics.descender >> 6) / oversampling; linegap = 0; texture_flags = 0; if (id.mipmaps) @@ -208,6 +208,8 @@ Error DynamicFontAtSize::_load() { return OK; } +float DynamicFontAtSize::font_oversampling = 1.0; + float DynamicFontAtSize::get_height() const { return ascent + descent; @@ -282,11 +284,11 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V if (delta.x == 0) continue; - ret.x += delta.x >> 6; + ret.x += (delta.x >> 6) / oversampling; break; } } else { - ret.x += delta.x >> 6; + ret.x += (delta.x >> 6) / oversampling; } } @@ -338,7 +340,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT cpos.y += ch->v_align; ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0); if (ch->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect, p_modulate, false, RID(), false); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect_uv, p_modulate, false, RID(), false); advance = ch->advance; used_fallback = true; break; @@ -360,7 +362,7 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT cpos.y += c->v_align; ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0); if (c->texture_idx != -1) - VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate, false, RID(), false); + VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect_uv, p_modulate, false, RID(), false); advance = c->advance; //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2()); } @@ -382,11 +384,11 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT if (delta.x == 0) continue; - advance += delta.x >> 6; + advance += (delta.x >> 6) / oversampling; break; } } else { - advance += delta.x >> 6; + advance += (delta.x >> 6) / oversampling; } } @@ -602,19 +604,37 @@ void DynamicFontAtSize::_update_char(CharType p_char) { } Character chr; - chr.h_align = xofs; - chr.v_align = ascent - yofs; // + ascent - descent; - chr.advance = advance; + chr.h_align = xofs / oversampling; + chr.v_align = ascent - (yofs / oversampling); // + ascent - descent; + chr.advance = advance / oversampling; chr.texture_idx = tex_index; chr.found = true; - chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h); + chr.rect_uv = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h); + chr.rect = chr.rect_uv; + chr.rect.position /= oversampling; + chr.rect.size /= oversampling; //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs)); char_map[p_char] = chr; } +bool DynamicFontAtSize::update_oversampling() { + if (oversampling == font_oversampling) + return false; + if (!valid) + return false; + + FT_Done_FreeType(library); + textures.clear(); + char_map.clear(); + oversampling = font_oversampling; + _load(); + + return true; +} + DynamicFontAtSize::DynamicFontAtSize() { valid = false; @@ -623,6 +643,7 @@ DynamicFontAtSize::DynamicFontAtSize() { descent = 1; linegap = 1; texture_flags = 0; + oversampling = font_oversampling; } DynamicFontAtSize::~DynamicFontAtSize() { @@ -913,15 +934,52 @@ void DynamicFont::_bind_methods() { BIND_ENUM_CONSTANT(SPACING_SPACE); } -DynamicFont::DynamicFont() { +Mutex *DynamicFont::dynamic_font_mutex = NULL; + +SelfList<DynamicFont>::List DynamicFont::dynamic_fonts; + +DynamicFont::DynamicFont() : + font_list(this) { spacing_top = 0; spacing_bottom = 0; spacing_char = 0; spacing_space = 0; + if (dynamic_font_mutex) + dynamic_font_mutex->lock(); + dynamic_fonts.add(&font_list); + if (dynamic_font_mutex) + dynamic_font_mutex->unlock(); } DynamicFont::~DynamicFont() { + + if (dynamic_font_mutex) + dynamic_font_mutex->lock(); + dynamic_fonts.remove(&font_list); + if (dynamic_font_mutex) + dynamic_font_mutex->unlock(); +} + +void DynamicFont::initialize_dynamic_fonts() { + dynamic_font_mutex = Mutex::create(); +} + +void DynamicFont::finish_dynamic_fonts() { + memdelete(dynamic_font_mutex); + dynamic_font_mutex = NULL; +} + +void DynamicFont::update_oversampling() { + + SelfList<DynamicFont> *E = dynamic_fonts.first(); + while (E) { + + if (E->self()->data_at_size.is_valid() && E->self()->data_at_size->update_oversampling()) { + E->self()->emit_changed(); + } + E = E->next(); + } } ///////////////////////// diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h index 52c3f30590..b2452a6a0a 100644 --- a/scene/resources/dynamic_font.h +++ b/scene/resources/dynamic_font.h @@ -32,6 +32,7 @@ #ifdef FREETYPE_ENABLED #include "io/resource_loader.h" +#include "os/mutex.h" #include "os/thread_safe.h" #include "scene/resources/font.h" @@ -97,10 +98,11 @@ class DynamicFontAtSize : public Reference { FT_Face face; /* handle to face object */ FT_StreamRec stream; - int ascent; - int descent; - int linegap; - int rect_margin; + float ascent; + float descent; + float linegap; + float rect_margin; + float oversampling; uint32_t texture_flags; @@ -121,6 +123,7 @@ class DynamicFontAtSize : public Reference { bool found; int texture_idx; Rect2 rect; + Rect2 rect_uv; float v_align; float h_align; float advance; @@ -145,8 +148,9 @@ class DynamicFontAtSize : public Reference { static HashMap<String, Vector<uint8_t> > _fontdata; Error _load(); -protected: public: + static float font_oversampling; + float get_height() const; float get_ascent() const; @@ -157,6 +161,7 @@ public: float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const; void set_texture_flags(uint32_t p_flags); + bool update_oversampling(); DynamicFontAtSize(); ~DynamicFontAtSize(); @@ -232,6 +237,15 @@ public: virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const; + SelfList<DynamicFont> font_list; + + static Mutex *dynamic_font_mutex; + static SelfList<DynamicFont>::List dynamic_fonts; + + static void initialize_dynamic_fonts(); + static void finish_dynamic_fonts(); + static void update_oversampling(); + DynamicFont(); ~DynamicFont(); }; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 2b44ea4554..8510669d6c 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -257,8 +257,8 @@ Error BitmapFont::create_from_fnt(const String &p_file) { if (keys.has("file")) { - String file = keys["file"]; - file = p_file.get_base_dir() + "/" + file; + String base_dir = p_file.get_base_dir(); + String file = base_dir.plus_file(keys["file"]); Ref<Texture> tex = ResourceLoader::load(file); if (tex.is_null()) { ERR_PRINT("Can't load font texture!"); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 326320c60f..cc9fde58e2 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -753,7 +753,7 @@ void SpatialMaterial::_update_shader() { if (features[FEATURE_REFRACTION] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //refraction not supported with triplanar if (features[FEATURE_NORMAL_MAPPING]) { - code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) ) * SIDE;\n"; + code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n"; } else { code += "\tvec3 ref_normal = NORMAL;\n"; } diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index bb33962be6..bf5f7bf039 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1111,13 +1111,14 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe for (int j = 0; j < vc; j++) { Vector3 v = p_base_transform.xform(r[j]); + Vector3 n = p_base_transform.basis.xform(rn[j]).normalized(); vertices[(j + vertex_ofs) * 3 + 0] = v.x; vertices[(j + vertex_ofs) * 3 + 1] = v.y; vertices[(j + vertex_ofs) * 3 + 2] = v.z; - normals[(j + vertex_ofs) * 3 + 0] = rn[j].x; - normals[(j + vertex_ofs) * 3 + 1] = rn[j].y; - normals[(j + vertex_ofs) * 3 + 2] = rn[j].z; + normals[(j + vertex_ofs) * 3 + 0] = n.x; + normals[(j + vertex_ofs) * 3 + 1] = n.y; + normals[(j + vertex_ofs) * 3 + 2] = n.z; uv_index[j + vertex_ofs] = Pair<int, int>(i, j); } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 3a5cb7da2e..879f76e6d8 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -270,6 +270,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const { if (i > 0) { if (parent) { parent->_add_child_nocheck(node, snames[n.name]); + if (n.index >= 0 && n.index < parent->get_child_count() - 1) + parent->move_child(node, n.index); } else { //it may be possible that an instanced scene has changed //and the node has nowhere to go anymore @@ -386,6 +388,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map nd.name = _nm_get_string(p_node->get_name(), name_map); nd.instance = -1; //not instanced by default + nd.index = p_node->get_index(); // if this node is part of an instanced scene or sub-instanced scene // we need to get the corresponding instance states. @@ -1114,7 +1117,10 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) { nd.parent = r[idx++]; nd.owner = r[idx++]; nd.type = r[idx++]; - nd.name = r[idx++]; + uint32_t name_index = r[idx++]; + nd.name = name_index & ((1 << NAME_INDEX_BITS) - 1); + nd.index = (name_index >> NAME_INDEX_BITS); + nd.index--; //0 is invaild, stored as 1 nd.instance = r[idx++]; nd.properties.resize(r[idx++]); for (int j = 0; j < nd.properties.size(); j++) { @@ -1206,7 +1212,11 @@ Dictionary SceneState::get_bundled_scene() const { rnodes.push_back(nd.parent); rnodes.push_back(nd.owner); rnodes.push_back(nd.type); - rnodes.push_back(nd.name); + uint32_t name_index = nd.name; + if (nd.index < (1 << (32 - NAME_INDEX_BITS)) - 1) { //save if less than 16k childs + name_index |= uint32_t(nd.index + 1) << NAME_INDEX_BITS; //for backwards compatibility, index 0 is no index + } + rnodes.push_back(name_index); rnodes.push_back(nd.instance); rnodes.push_back(nd.properties.size()); for (int j = 0; j < nd.properties.size(); j++) { @@ -1284,6 +1294,11 @@ StringName SceneState::get_node_name(int p_idx) const { return names[nodes[p_idx].name]; } +int SceneState::get_node_index(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, nodes.size(), -1); + return nodes[p_idx].index; +} + bool SceneState::is_node_instance_placeholder(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, nodes.size(), false); @@ -1524,7 +1539,7 @@ int SceneState::add_node_path(const NodePath &p_path) { node_paths.push_back(p_path); return (node_paths.size() - 1) | FLAG_ID_IS_PATH; } -int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance) { +int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index) { NodeData nd; nd.parent = p_parent; @@ -1532,6 +1547,7 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int nd.type = p_type; nd.name = p_name; nd.instance = p_instance; + nd.index = p_index; nodes.push_back(nd); @@ -1605,6 +1621,7 @@ void SceneState::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node_instance_placeholder", "idx"), &SceneState::get_node_instance_placeholder); ClassDB::bind_method(D_METHOD("get_node_instance", "idx"), &SceneState::get_node_instance); ClassDB::bind_method(D_METHOD("get_node_groups", "idx"), &SceneState::_get_node_groups); + ClassDB::bind_method(D_METHOD("get_node_index", "idx"), &SceneState::get_node_index); ClassDB::bind_method(D_METHOD("get_node_property_count", "idx"), &SceneState::get_node_property_count); ClassDB::bind_method(D_METHOD("get_node_property_name", "idx", "prop_idx"), &SceneState::get_node_property_name); ClassDB::bind_method(D_METHOD("get_node_property_value", "idx", "prop_idx"), &SceneState::get_node_property_value); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 20bfb19b1f..70deea24ff 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -48,6 +48,8 @@ class SceneState : public Reference { enum { NO_PARENT_SAVED = 0x7FFFFFFF, + NAME_INDEX_BITS = 18, + NAME_MASK = (1 << NAME_INDEX_BITS) - 1, }; struct NodeData { @@ -57,6 +59,7 @@ class SceneState : public Reference { int type; int name; int instance; + int index; struct Property { @@ -151,6 +154,7 @@ public: String get_node_instance_placeholder(int p_idx) const; bool is_node_instance_placeholder(int p_idx) const; Vector<StringName> get_node_groups(int p_idx) const; + int get_node_index(int p_idx) const; int get_node_property_count(int p_idx) const; StringName get_node_property_name(int p_idx, int p_prop) const; @@ -174,7 +178,7 @@ public: int find_name(const StringName &p_name) const; int add_value(const Variant &p_value); int add_node_path(const NodePath &p_path); - int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance); + int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index); void add_node_property(int p_node, int p_name, int p_value); void add_node_group(int p_node, int p_group); void set_base_scene(int p_idx); diff --git a/scene/resources/room.h b/scene/resources/room.h index aadee858c2..0e021cfcf7 100644 --- a/scene/resources/room.h +++ b/scene/resources/room.h @@ -36,7 +36,7 @@ @author Juan Linietsky <reduzio@gmail.com> */ -//left for reference but will be removed when portals are reimplemented using Area +// FIXME: left for reference but will be removed when portals are reimplemented using Area #if 0 class RoomBounds : public Resource { diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp index aebbb5b562..7bf5f24269 100644 --- a/scene/resources/scene_format_text.cpp +++ b/scene/resources/scene_format_text.cpp @@ -198,6 +198,7 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R int type = -1; int name = -1; int instance = -1; + int index = -1; //int base_scene=-1; if (next_tag.fields.has("name")) { @@ -249,7 +250,11 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R owner = 0; //if no owner, owner is root } - int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance); + if (next_tag.fields.has("index")) { + index = next_tag.fields["index"]; + } + + int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index); if (next_tag.fields.has("groups")) { @@ -1609,6 +1614,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r StringName type = state->get_node_type(i); StringName name = state->get_node_name(i); + int index = state->get_node_index(i); NodePath path = state->get_node_path(i, true); NodePath owner = state->get_node_owner_path(i); Ref<PackedScene> instance = state->get_node_instance(i); @@ -1626,6 +1632,9 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r if (owner != NodePath() && owner != NodePath(".")) { header += " owner=\"" + String(owner.simplified()) + "\""; } + if (index >= 0) { + header += " index=\"" + itos(index) + "\""; + } if (groups.size()) { String sgroups = " groups=[\n"; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 66df7dfda8..207c50f673 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -151,3 +151,80 @@ Shader::~Shader() { VisualServer::get_singleton()->free(shader); } +//////////// + +RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error) { + + if (r_error) + *r_error = ERR_FILE_CANT_OPEN; + + Ref<Shader> shader; + shader.instance(); + + Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path); + + String str; + str.parse_utf8((const char *)buffer.ptr(), buffer.size()); + + shader->set_code(str); + + if (r_error) + *r_error = OK; + + return shader; +} + +void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const { + + p_extensions->push_back("shader"); +} + +bool ResourceFormatLoaderShader::handles_type(const String &p_type) const { + + return (p_type == "Shader"); +} + +String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const { + + String el = p_path.get_extension().to_lower(); + if (el == "shader") + return "Shader"; + return ""; +} + +Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + + Ref<Shader> shader = p_resource; + ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER); + + String source = shader->get_code(); + + Error err; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + if (err) { + + ERR_FAIL_COND_V(err, err); + } + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } + file->close(); + memdelete(file); + + return OK; +} + +void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { + + if (Object::cast_to<Shader>(*p_resource)) { + p_extensions->push_back("shader"); + } +} +bool ResourceFormatSaverShader::recognize(const RES &p_resource) const { + + return Object::cast_to<Shader>(*p_resource) != NULL; +} diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 5cc70629c7..78d73a33e2 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -31,6 +31,7 @@ #define SHADER_H #include "io/resource_loader.h" +#include "io/resource_saver.h" #include "resource.h" #include "scene/resources/texture.h" @@ -38,7 +39,6 @@ class Shader : public Resource { GDCLASS(Shader, Resource); OBJ_SAVE_TYPE(Shader); - RES_BASE_EXTENSION("shd"); public: enum Mode { @@ -95,4 +95,19 @@ public: VARIANT_ENUM_CAST(Shader::Mode); +class ResourceFormatLoaderShader : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +class ResourceFormatSaverShader : public ResourceFormatSaver { +public: + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const RES &p_resource) const; +}; + #endif // SHADER_H diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 987d6c5f6a..35d0d55d85 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -707,6 +707,8 @@ Ref<Image> StreamTexture::get_data() const { } void StreamTexture::set_flags(uint32_t p_flags) { + flags = p_flags; + VS::get_singleton()->texture_set_flags(texture, flags); } void StreamTexture::reload_from_file() { diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index bd6b917d4e..144c208c07 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -893,8 +893,8 @@ void TileSet::clear() { void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile); - ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "mode"), &TileSet::autotile_set_bitmask_mode); - ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode"), &TileSet::autotile_get_bitmask_mode); + ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode); + ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode); ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name); ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name); ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture); |