Merge pull request #120917 from Repiteo/4.7-cherry-picks-3
[4.7] Cherry-picks for the 4.7 branch (future 4.7.1) - 3rd batch
This commit is contained in:
32 files changed
+379
-285
No files matched your search
@@ -1115,10 +1115,10 @@
|
||||
The node's global position, relative to the world (usually to the [CanvasLayer]).
|
||||
</member>
|
||||
<member name="grow_horizontal" type="int" setter="set_h_grow_direction" getter="get_h_grow_direction" enum="Control.GrowDirection" default="1">
|
||||
Controls the direction on the horizontal axis in which the control should grow or shrink if its horizontal size is changed.
|
||||
Controls the direction on the horizontal axis in which the control should grow if its horizontal minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size.
|
||||
</member>
|
||||
<member name="grow_vertical" type="int" setter="set_v_grow_direction" getter="get_v_grow_direction" enum="Control.GrowDirection" default="1">
|
||||
Controls the direction on the vertical axis in which the control should grow or shrink if its vertical size is changed.
|
||||
Controls the direction on the vertical axis in which the control should grow if its vertical minimum size is changed to be greater than its current size, as the control always has to be at least the minimum size.
|
||||
</member>
|
||||
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" enum="Control.LayoutDirection" default="0">
|
||||
Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew). See also [method is_layout_rtl].
|
||||
@@ -1568,13 +1568,13 @@
|
||||
[b]Note:[/b] If the control has received [signal mouse_entered] but not [signal mouse_exited], changing the [member mouse_filter] to [constant MOUSE_FILTER_IGNORE] will cause [signal mouse_exited] to be emitted.
|
||||
</constant>
|
||||
<constant name="GROW_DIRECTION_BEGIN" value="0" enum="GrowDirection">
|
||||
The control will grow/shrink to the left or top if its size is changed to be larger/smaller than its current size on the respective axis.
|
||||
The control will grow to the left or top to make up if its minimum size is changed to be greater than its current size on the respective axis.
|
||||
</constant>
|
||||
<constant name="GROW_DIRECTION_END" value="1" enum="GrowDirection">
|
||||
The control will grow/shrink to the right or bottom if its size is changed to be larger/smaller than its current size on the respective axis.
|
||||
The control will grow to the right or bottom to make up if its minimum size is changed to be greater than its current size on the respective axis.
|
||||
</constant>
|
||||
<constant name="GROW_DIRECTION_BOTH" value="2" enum="GrowDirection">
|
||||
The control will grow/shrink in both directions equally if its size is changed to be larger/smaller than its current size.
|
||||
The control will grow in both directions equally to make up if its minimum size is changed to be greater than its current size.
|
||||
</constant>
|
||||
<constant name="ANCHOR_BEGIN" value="0" enum="Anchor">
|
||||
Snaps one of the 4 anchor's sides to the origin of the node's [code]Rect[/code], in the top left. Use it with one of the [code]anchor_*[/code] member variables, like [member anchor_left]. To change all 4 anchors at once, use [method set_anchors_preset].
|
||||
|
||||
@@ -446,7 +446,13 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_off
|
||||
v = Object::cast_to<EncodedObjectAsID>(v)->get_object_id();
|
||||
h = PROPERTY_HINT_OBJECT_ID;
|
||||
hs = var.type_hint;
|
||||
|
||||
// Makes the call stack select the node in the remote tree. See https://github.com/godotengine/godot/issues/79477
|
||||
if (n == "self") {
|
||||
_object_selected(v);
|
||||
}
|
||||
}
|
||||
|
||||
String type;
|
||||
switch (var.type) {
|
||||
case 0:
|
||||
|
||||
@@ -691,7 +691,7 @@ void ImportDock::_reimport() {
|
||||
}
|
||||
|
||||
EditorFileSystem::get_singleton()->reimport_files(params->paths);
|
||||
EditorFileSystem::get_singleton()->emit_signal(SNAME("filesystem_changed")); //it changed, so force emitting the signal
|
||||
EditorFileSystem::get_singleton()->filesystem_changed(); // It changed, so force emitting the signal.
|
||||
|
||||
_set_dirty(false);
|
||||
}
|
||||
|
||||
@@ -1398,14 +1398,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
||||
break;
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
|
||||
placeholder = !placeholder;
|
||||
|
||||
undo_redo->create_action(TTR("Toggle Load as Placeholder"));
|
||||
undo_redo->add_undo_method(node, "set_scene_instance_load_placeholder", !placeholder);
|
||||
undo_redo->add_do_method(node, "set_scene_instance_load_placeholder", placeholder);
|
||||
|
||||
if (placeholder) {
|
||||
EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node, false);
|
||||
}
|
||||
|
||||
node->set_scene_instance_load_placeholder(placeholder);
|
||||
scene_tree->update_tree();
|
||||
undo_redo->commit_action();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
@@ -1955,6 +1960,21 @@ void SceneTreeDock::_node_renamed() {
|
||||
_node_selected();
|
||||
}
|
||||
|
||||
void SceneTreeDock::_make_owners_map(Node *p_node, Dictionary &r_owners) {
|
||||
r_owners[p_node] = p_node->get_owner();
|
||||
for (Node *child : p_node->iterate_children()) {
|
||||
_make_owners_map(child, r_owners);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTreeDock::_apply_owners_map(Node *p_node, const Dictionary &p_owners) {
|
||||
Node *owner = Object::cast_to<Node>(p_owners[p_node]);
|
||||
p_node->set_owner(owner);
|
||||
for (Node *child : p_node->iterate_children()) {
|
||||
_apply_owners_map(child, p_owners);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTreeDock::_set_owners(Node *p_owner, const Array &p_nodes) {
|
||||
for (int i = 0; i < p_nodes.size(); i++) {
|
||||
Node *n = Object::cast_to<Node>(p_nodes[i]);
|
||||
@@ -4498,7 +4518,7 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
|
||||
// When copying, all nodes that should have an owner assigned here were given nullptr as an owner
|
||||
// and added to the node_clipboard_edited_scene_owned list.
|
||||
if (d != dup && E2.key->get_owner() == nullptr) {
|
||||
if (node_clipboard_edited_scene_owned.find(const_cast<Node *>(E2.key))) {
|
||||
if (node_clipboard_edited_scene_owned.has(const_cast<Node *>(E2.key))) {
|
||||
ur->add_do_method(d, "set_owner", owner);
|
||||
}
|
||||
}
|
||||
@@ -4536,14 +4556,20 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
|
||||
|
||||
void SceneTreeDock::paste_node_as_replacement() {
|
||||
List<Node *> selected_node_list = editor_selection->get_top_selected_node_list();
|
||||
Node *clipboard_node = node_clipboard.front()->get();
|
||||
|
||||
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||
ur->create_action(TTR("Paste Node(s) as Replacement"), UndoRedo::MERGE_DISABLE, edited_scene);
|
||||
|
||||
for (Node *selected : selected_node_list) {
|
||||
Node *clipboard_node = node_clipboard.front()->get();
|
||||
HashMap<const Node *, Node *> duplimap;
|
||||
Node *new_node = clipboard_node->duplicate_from_editor(duplimap);
|
||||
if (!new_node) {
|
||||
continue;
|
||||
}
|
||||
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||
ur->add_do_reference(new_node);
|
||||
ur->add_undo_reference(selected);
|
||||
|
||||
String old_scene_file_path = selected->get_scene_file_path();
|
||||
String new_scene_file_path = clipboard_node->get_scene_file_path();
|
||||
|
||||
@@ -4551,34 +4577,16 @@ void SceneTreeDock::paste_node_as_replacement() {
|
||||
bool new_is_scene = !new_scene_file_path.is_empty();
|
||||
|
||||
LocalVector<Node *> old_children;
|
||||
Dictionary owners_map;
|
||||
|
||||
ur->create_action(TTR("Paste Node(s) as Replacement"), UndoRedo::MERGE_ALL, selected);
|
||||
int child_count = selected->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
Node *child = selected->get_child(0);
|
||||
_make_owners_map(child, owners_map);
|
||||
old_children.push_back(child);
|
||||
|
||||
if (old_is_scene) {
|
||||
for (int i = 0; i < selected->get_child_count(); i++) {
|
||||
Node *child = selected->get_child(i);
|
||||
if (child->get_owner() == selected) {
|
||||
ur->add_do_method(selected, "remove_child", child);
|
||||
|
||||
selected->remove_child(child);
|
||||
old_children.push_back(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ur->add_do_method(this, "replace_node", selected, new_node, false);
|
||||
ur->add_do_method(new_node, "set_scene_file_path", new_scene_file_path);
|
||||
ur->add_do_reference(new_node);
|
||||
|
||||
if (new_is_scene) {
|
||||
for (int i = 0; i < new_node->get_child_count(); i++) {
|
||||
Node *child = new_node->get_child(i);
|
||||
if (child->get_owner() == new_node) {
|
||||
ur->add_undo_method(new_node, "add_child", child, true);
|
||||
ur->add_undo_method(child, "set_owner", new_node);
|
||||
ur->add_undo_reference(child);
|
||||
}
|
||||
}
|
||||
ur->add_do_method(selected, "remove_child", child);
|
||||
selected->remove_child(child);
|
||||
}
|
||||
|
||||
const bool is_missing_node_selected = Object::cast_to<MissingNode>(selected) != nullptr;
|
||||
@@ -4592,9 +4600,6 @@ void SceneTreeDock::paste_node_as_replacement() {
|
||||
selected_transform_3d = selected_node_3d->get_transform();
|
||||
}
|
||||
|
||||
_replace_node(selected, new_node, is_missing_node_selected);
|
||||
new_node->set_scene_file_path(new_scene_file_path);
|
||||
|
||||
if (selected_canvas_item) {
|
||||
Node2D *new_node_2d = Object::cast_to<Node2D>(new_node);
|
||||
Control *new_control = Object::cast_to<Control>(new_node);
|
||||
@@ -4612,29 +4617,47 @@ void SceneTreeDock::paste_node_as_replacement() {
|
||||
}
|
||||
}
|
||||
|
||||
if (new_is_scene) {
|
||||
for (int i = 0; i < new_node->get_child_count(); i++) {
|
||||
Node *child = new_node->get_child(i);
|
||||
if (child->get_owner() == new_node) {
|
||||
ur->add_undo_method(new_node, "remove_child", child);
|
||||
for (Node *child : new_node->iterate_children()) {
|
||||
ur->add_do_reference(child);
|
||||
ur->add_do_method(new_node, "add_child", child);
|
||||
ur->add_undo_method(new_node, "remove_child", child);
|
||||
}
|
||||
|
||||
// Note that due to the new node possibly having child nodes, it's not possible to unify the operations to use only do methods.
|
||||
_replace_node(selected, new_node, is_missing_node_selected);
|
||||
ur->add_do_method(this, "replace_node", selected, new_node, false);
|
||||
if (old_is_scene || new_is_scene) {
|
||||
new_node->set_scene_file_path(new_scene_file_path);
|
||||
ur->add_do_method(new_node, "set_scene_file_path", new_scene_file_path);
|
||||
}
|
||||
|
||||
for (KeyValue<const Node *, Node *> &E2 : duplimap) {
|
||||
Node *d = E2.value;
|
||||
// When copying, all nodes that should have an owner assigned here were given nullptr as an owner
|
||||
// and added to the node_clipboard_edited_scene_owned list.
|
||||
if (d != new_node && E2.key->get_owner() == nullptr) {
|
||||
if (node_clipboard_edited_scene_owned.has(const_cast<Node *>(E2.key))) {
|
||||
d->set_owner(edited_scene);
|
||||
ur->add_do_method(d, "set_owner", edited_scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ur->add_undo_method(this, "replace_node", new_node, selected, false);
|
||||
ur->add_undo_method(selected, "set_scene_file_path", old_scene_file_path);
|
||||
ur->add_undo_reference(selected);
|
||||
|
||||
if (old_is_scene) {
|
||||
for (Node *child : old_children) {
|
||||
ur->add_undo_method(selected, "add_child", child, true);
|
||||
ur->add_undo_method(child, "set_owner", selected);
|
||||
ur->add_undo_reference(child);
|
||||
}
|
||||
if (old_is_scene || new_is_scene) {
|
||||
ur->add_undo_method(selected, "set_scene_file_path", old_scene_file_path);
|
||||
}
|
||||
|
||||
ur->commit_action(false);
|
||||
for (Node *child : old_children) {
|
||||
ur->add_undo_method(selected, "add_child", child);
|
||||
ur->add_undo_method(this, "_apply_owners_map", child, owners_map);
|
||||
ur->add_undo_reference(child);
|
||||
}
|
||||
}
|
||||
ur->commit_action(false);
|
||||
// FIXME: This shouldn't be needed, but children of the pasted node do not appear immediately for some reason.
|
||||
scene_tree->clear_cache();
|
||||
scene_tree->update_tree();
|
||||
}
|
||||
|
||||
List<Node *> SceneTreeDock::get_node_clipboard() const {
|
||||
@@ -4945,6 +4968,7 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
|
||||
|
||||
void SceneTreeDock::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("_post_do_create"), &SceneTreeDock::_post_do_create);
|
||||
ClassDB::bind_method(D_METHOD("_apply_owners_map"), &SceneTreeDock::_apply_owners_map);
|
||||
ClassDB::bind_method(D_METHOD("_set_owners"), &SceneTreeDock::_set_owners);
|
||||
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_root"), &SceneTreeDock::_reparent_nodes_to_root);
|
||||
ClassDB::bind_method(D_METHOD("_reparent_nodes_to_paths_with_transform_and_name"), &SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name);
|
||||
|
||||
@@ -195,6 +195,8 @@ class SceneTreeDock : public EditorDock {
|
||||
void _node_reparent(NodePath p_path, bool p_keep_global_xform);
|
||||
void _do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform);
|
||||
|
||||
void _make_owners_map(Node *p_node, Dictionary &r_owners);
|
||||
void _apply_owners_map(Node *p_node, const Dictionary &p_owners);
|
||||
void _set_owners(Node *p_owner, const Array &p_nodes);
|
||||
|
||||
enum ReplaceOwnerMode {
|
||||
|
||||
@@ -368,7 +368,7 @@ void EditorInterface::make_scene_preview(const String &p_path, Node *p_scene, in
|
||||
}
|
||||
|
||||
EditorResourcePreview::get_singleton()->check_for_invalidation(p_path);
|
||||
EditorFileSystem::get_singleton()->emit_signal(SNAME("filesystem_changed"));
|
||||
EditorFileSystem::get_singleton()->filesystem_changed();
|
||||
}
|
||||
|
||||
void EditorInterface::add_root_node(Node *p_node) {
|
||||
|
||||
@@ -4720,7 +4720,6 @@ void EditorNode::_set_current_scene_nocheck(int p_idx, bool p_ignore_state) {
|
||||
|
||||
Node *old_scene = get_editor_data().get_edited_scene_root();
|
||||
|
||||
resource_count.clear();
|
||||
editor_selection->clear();
|
||||
SceneTreeDock::get_singleton()->clear_previous_node_selection();
|
||||
editor_data.set_edited_scene(p_idx);
|
||||
@@ -4752,6 +4751,7 @@ void EditorNode::_set_current_scene_nocheck(int p_idx, bool p_ignore_state) {
|
||||
|
||||
EditorUndoRedoManager::get_singleton()->clear_history(editor_data.get_scene_history_id(p_idx), false);
|
||||
}
|
||||
resource_count.clear();
|
||||
SceneTreeDock::get_singleton()->get_tree_editor()->update_tree();
|
||||
|
||||
_update_title();
|
||||
|
||||
@@ -2552,16 +2552,16 @@ void EditorFileSystem::update_files(const Vector<String> &p_script_paths) {
|
||||
if (!is_scanning()) {
|
||||
_process_update_pending();
|
||||
}
|
||||
if (!filesystem_changed_queued) {
|
||||
filesystem_changed_queued = true;
|
||||
if (!filesystem_changed_queued.is_set()) {
|
||||
filesystem_changed_queued.set();
|
||||
callable_mp(this, &EditorFileSystem::_notify_filesystem_changed).call_deferred();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileSystem::_notify_filesystem_changed() {
|
||||
emit_signal("filesystem_changed");
|
||||
filesystem_changed_queued = false;
|
||||
emit_signal(SNAME("filesystem_changed"));
|
||||
filesystem_changed_queued.clear();
|
||||
}
|
||||
|
||||
HashSet<String> EditorFileSystem::get_valid_extensions() const {
|
||||
@@ -2602,6 +2602,18 @@ void EditorFileSystem::register_global_class_script(const String &p_search_path,
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileSystem::filesystem_changed() {
|
||||
if (Thread::is_main_thread()) {
|
||||
_notify_filesystem_changed();
|
||||
return;
|
||||
}
|
||||
// If not already queued, queue a deferred call to notify about filesystem changes.
|
||||
if (!filesystem_changed_queued.is_set()) {
|
||||
filesystem_changed_queued.set();
|
||||
callable_mp(this, &EditorFileSystem::_notify_filesystem_changed).call_deferred();
|
||||
}
|
||||
}
|
||||
|
||||
Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector<String> &p_files) {
|
||||
String importer_name;
|
||||
|
||||
@@ -3720,7 +3732,7 @@ void EditorFileSystem::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_file_type", "path"), &EditorFileSystem::get_file_type);
|
||||
ClassDB::bind_method(D_METHOD("reimport_files", "files"), &EditorFileSystem::reimport_files);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("filesystem_changed"));
|
||||
ADD_SIGNAL(MethodInfo("filesystem_changed")); // May only be emitted on the main thread.
|
||||
ADD_SIGNAL(MethodInfo("script_classes_updated"));
|
||||
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
|
||||
ADD_SIGNAL(MethodInfo("resources_reimporting", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources")));
|
||||
|
||||
@@ -182,7 +182,7 @@ class EditorFileSystem : public Node {
|
||||
EditorFileSystemDirectory *new_filesystem = nullptr;
|
||||
static ScannedDirectory *first_scan_root_dir;
|
||||
|
||||
bool filesystem_changed_queued = false;
|
||||
SafeFlag filesystem_changed_queued;
|
||||
bool scanning = false;
|
||||
bool importing = false;
|
||||
bool first_scan = true;
|
||||
@@ -392,6 +392,8 @@ public:
|
||||
HashSet<String> get_valid_extensions() const;
|
||||
void register_global_class_script(const String &p_search_path, const String &p_target_path);
|
||||
|
||||
void filesystem_changed();
|
||||
|
||||
EditorFileSystemDirectory *get_filesystem_path(const String &p_path);
|
||||
String get_file_type(const String &p_file) const;
|
||||
EditorFileSystemDirectory *find_file(const String &p_file, int *r_index) const;
|
||||
|
||||
@@ -209,15 +209,14 @@ bool EditorQuickOpenDialog::_is_instant_preview_active() const {
|
||||
}
|
||||
|
||||
void EditorQuickOpenDialog::selection_changed() {
|
||||
if (!_is_instant_preview_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This prevents the property from being changed the first time the Quick Open
|
||||
// window is opened.
|
||||
if (!initial_selection_performed) {
|
||||
initial_selection_performed = true;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_is_instant_preview_active()) {
|
||||
preview_property();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1613,12 +1613,35 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
||||
continue;
|
||||
}
|
||||
const String mat_id = mat->get_meta("import_id", mat->get_name());
|
||||
if (mat_id.is_empty() || !p_material_data.has(mat_id)) {
|
||||
if (mat_id.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
Dictionary matdata = p_material_data[mat_id];
|
||||
// Start with per-material import settings, if any. This is populated by the
|
||||
// Advanced Import Settings dialog, but may be empty when using only the Import dock.
|
||||
Dictionary matdata;
|
||||
if (p_material_data.has(mat_id)) {
|
||||
matdata = p_material_data[mat_id];
|
||||
}
|
||||
String file_path;
|
||||
// Read any existing "use_external" settings to get the enabled status and file path.
|
||||
if (matdata.has("use_external/enabled")) {
|
||||
const bool enabled = bool(matdata["use_external/enabled"]);
|
||||
// If the user has explicitly overwrote this material to not be external, skip it.
|
||||
if (!enabled) {
|
||||
continue;
|
||||
}
|
||||
// Read any existing file path from this material's import settings, if present.
|
||||
if (matdata.has("use_external/fallback_path")) {
|
||||
file_path = matdata["use_external/fallback_path"];
|
||||
} else if (matdata.has("use_external/path")) {
|
||||
file_path = matdata["use_external/path"];
|
||||
if (file_path.begins_with("uid://")) {
|
||||
file_path = ResourceUID::get_singleton()->uid_to_path(file_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
// For any material settings that are missing, fill them with default values.
|
||||
{
|
||||
//fill node settings for this node with default values
|
||||
List<ImportOption> iopts;
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MATERIAL, &iopts);
|
||||
for (const ImportOption &E : iopts) {
|
||||
@@ -1631,18 +1654,21 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
||||
post_importer_plugins.write[j]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MATERIAL, p_root, p_node, mat, matdata);
|
||||
}
|
||||
if (extract_mat != 0) {
|
||||
const String ext = material_extension[p_options.has("materials/extract_format") ? (int)p_options["materials/extract_format"] : 0];
|
||||
const String path = spath.path_join(mat_id.validate_filename() + ext);
|
||||
const String uid_path = ResourceUID::path_to_uid(path);
|
||||
|
||||
matdata["use_external/enabled"] = true;
|
||||
matdata["use_external/path"] = uid_path;
|
||||
matdata["use_external/fallback_path"] = path;
|
||||
if (!FileAccess::exists(path) || extract_mat == 2 /*overwrite*/) {
|
||||
ResourceSaver::save(mat, path);
|
||||
// If no file path was specified, generate one based on the material name and the selected format.
|
||||
if (file_path.is_empty()) {
|
||||
const String ext = material_extension[p_options.has("materials/extract_format") ? (int)p_options["materials/extract_format"] : 0];
|
||||
file_path = spath.path_join(mat_id.validate_filename() + ext);
|
||||
const String uid_path = ResourceUID::path_to_uid(file_path);
|
||||
matdata["use_external/enabled"] = true;
|
||||
matdata["use_external/path"] = uid_path;
|
||||
matdata["use_external/fallback_path"] = file_path;
|
||||
}
|
||||
// Write the file if it doesn't exist, or if the user has selected to overwrite existing files.
|
||||
if (!FileAccess::exists(file_path) || extract_mat == 2 /*overwrite*/) {
|
||||
ResourceSaver::save(mat, file_path);
|
||||
}
|
||||
|
||||
Ref<Material> external_mat = ResourceLoader::load(path, "", ResourceFormatLoader::CACHE_MODE_REPLACE);
|
||||
Ref<Material> external_mat = ResourceLoader::load(file_path, "", ResourceFormatLoader::CACHE_MODE_REPLACE);
|
||||
if (external_mat.is_valid()) {
|
||||
m->set_surface_material(i, external_mat);
|
||||
}
|
||||
|
||||
@@ -1771,7 +1771,7 @@ void EditorAudioStreamPicker::_preview_draw() {
|
||||
|
||||
float text_width = size.width - 4 * EDSCALE - icon->get_width();
|
||||
if (text_width > 0) {
|
||||
stream_preview_rect->draw_string(font, Point2i(EDSCALE * 4 + icon->get_width(), rect.position.y + font->get_ascent(font_size) + (rect.size.height - font->get_height(font_size)) / 2), text, HORIZONTAL_ALIGNMENT_CENTER, text_width, font_size, get_theme_color(SceneStringName(font_color), EditorStringName(Editor)));
|
||||
stream_preview_rect->draw_string(font, Point2i(size.width - text_width, rect.position.y + font->get_ascent(font_size) + (rect.size.height - font->get_height(font_size)) / 2), text, HORIZONTAL_ALIGNMENT_CENTER, text_width, font_size, get_theme_color(SceneStringName(font_color), EditorStringName(Editor)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "editor/run/editor_run_bar.h"
|
||||
#include "editor/run/embedded_process.h"
|
||||
#include "editor/run/run_instances_dialog.h"
|
||||
#include "editor/script/script_editor_plugin.h"
|
||||
#include "editor/settings/editor_feature_profile.h"
|
||||
#include "editor/settings/editor_settings.h"
|
||||
#include "editor/themes/editor_scale.h"
|
||||
@@ -1769,7 +1770,7 @@ void GameViewPluginBase::_save_last_editor(const String &p_editor) {
|
||||
|
||||
void GameViewPluginBase::_focus_another_editor() {
|
||||
if (_is_window_wrapper_enabled()) {
|
||||
if (last_editor.is_empty()) {
|
||||
if (last_editor.is_empty() || (last_editor == "Script" && ScriptEditor::get_singleton()->is_editor_floating())) {
|
||||
EditorNode::get_singleton()->get_editor_main_screen()->select(EditorMainScreen::EDITOR_2D);
|
||||
} else {
|
||||
EditorInterface::get_singleton()->set_main_screen_editor(last_editor);
|
||||
|
||||
@@ -6290,42 +6290,59 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe
|
||||
return false;
|
||||
}
|
||||
|
||||
void CanvasItemEditorViewport::_add_node_to_scene(Node *p_parent, Node *p_child, const Vector2 &p_target_position) {
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
if (p_parent) {
|
||||
undo_redo->add_do_method(p_parent, "add_child", p_child, true);
|
||||
undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
||||
undo_redo->add_do_reference(p_child);
|
||||
undo_redo->add_undo_method(p_parent, "remove_child", p_child);
|
||||
|
||||
const String new_name = p_parent->validate_child_name(p_child);
|
||||
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
||||
undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_child->get_class(), new_name);
|
||||
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
|
||||
} else { // If no parent is selected, set as root node of the scene.
|
||||
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_child);
|
||||
undo_redo->add_do_reference(p_child);
|
||||
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
||||
}
|
||||
// There's nothing to be used as source position, so snapping will work as absolute if enabled.
|
||||
Vector2 target_position = canvas_item_editor->snap_point(p_target_position);
|
||||
CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
||||
// Set position via undo_redo for proper live editing support.
|
||||
undo_redo->add_do_method(p_child, "set_position", parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position);
|
||||
|
||||
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
|
||||
undo_redo->add_do_method(editor_selection, "add_node", p_child);
|
||||
}
|
||||
|
||||
void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point) {
|
||||
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
|
||||
const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
|
||||
if (!node_name.is_empty()) {
|
||||
p_child->set_name(node_name);
|
||||
}
|
||||
// Compute the global position.
|
||||
Transform2D xform = canvas_item_editor->get_canvas_transform();
|
||||
Point2 target_position = xform.affine_inverse().xform(p_point);
|
||||
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
// Adjust position for Control and TouchScreenButton.
|
||||
Ref<Texture2D> texture = ResourceCache::get_ref(p_path);
|
||||
|
||||
if (p_parent) {
|
||||
undo_redo->add_do_method(p_parent, "add_child", p_child, true);
|
||||
undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
||||
undo_redo->add_do_reference(p_child);
|
||||
undo_redo->add_undo_method(p_parent, "remove_child", p_child);
|
||||
} else { // If no parent is selected, set as root node of the scene.
|
||||
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_child);
|
||||
undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
||||
undo_redo->add_do_reference(p_child);
|
||||
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
||||
}
|
||||
|
||||
if (p_parent) {
|
||||
String new_name = p_parent->validate_child_name(p_child);
|
||||
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
||||
undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_child->get_class(), new_name);
|
||||
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
|
||||
if (Object::cast_to<Control>(p_child) || Object::cast_to<TouchScreenButton>(p_child) || Object::cast_to<Polygon2D>(p_child)) {
|
||||
target_position -= texture->get_size() / 2;
|
||||
}
|
||||
_add_node_to_scene(p_parent, p_child, target_position);
|
||||
|
||||
// Use undo_redo for properties to support live editing.
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
if (Object::cast_to<TouchScreenButton>(p_child) || Object::cast_to<TextureButton>(p_child)) {
|
||||
undo_redo->add_do_property(p_child, "texture_normal", texture);
|
||||
} else {
|
||||
undo_redo->add_do_property(p_child, "texture", texture);
|
||||
}
|
||||
|
||||
// make visible for certain node type
|
||||
// Make visible for certain node type.
|
||||
if (Object::cast_to<Control>(p_child)) {
|
||||
Size2 texture_size = texture->get_size();
|
||||
undo_redo->add_do_property(p_child, "size", texture_size);
|
||||
@@ -6339,28 +6356,10 @@ void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_chil
|
||||
};
|
||||
undo_redo->add_do_property(p_child, "polygon", list);
|
||||
}
|
||||
|
||||
// Compute the global position
|
||||
Transform2D xform = canvas_item_editor->get_canvas_transform();
|
||||
Point2 target_position = xform.affine_inverse().xform(p_point);
|
||||
|
||||
// Adjust position for Control and TouchScreenButton
|
||||
if (Object::cast_to<Control>(p_child) || Object::cast_to<TouchScreenButton>(p_child)) {
|
||||
target_position -= texture->get_size() / 2;
|
||||
}
|
||||
|
||||
// There's nothing to be used as source position, so snapping will work as absolute if enabled.
|
||||
target_position = canvas_item_editor->snap_point(target_position);
|
||||
|
||||
CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
||||
Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
|
||||
|
||||
undo_redo->add_do_method(p_child, "set_position", local_target_pos);
|
||||
}
|
||||
|
||||
void CanvasItemEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) {
|
||||
AudioStreamPlayer2D *child = memnew(AudioStreamPlayer2D);
|
||||
child->set_stream(ResourceCache::get_ref(p_path));
|
||||
|
||||
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
|
||||
const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
|
||||
@@ -6368,41 +6367,14 @@ void CanvasItemEditorViewport::_create_audio_node(Node *p_parent, const String &
|
||||
child->set_name(node_name);
|
||||
}
|
||||
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
|
||||
if (p_parent) {
|
||||
undo_redo->add_do_method(p_parent, "add_child", child, true);
|
||||
undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
||||
undo_redo->add_do_reference(child);
|
||||
undo_redo->add_undo_method(p_parent, "remove_child", child);
|
||||
} else { // If no parent is selected, set as root node of the scene.
|
||||
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
|
||||
undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
|
||||
undo_redo->add_do_reference(child);
|
||||
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
|
||||
}
|
||||
|
||||
if (p_parent) {
|
||||
String new_name = p_parent->validate_child_name(child);
|
||||
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
|
||||
undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), child->get_class(), new_name);
|
||||
undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
|
||||
}
|
||||
|
||||
// Compute the global position
|
||||
Transform2D xform = canvas_item_editor->get_canvas_transform();
|
||||
Point2 target_position = xform.affine_inverse().xform(p_point);
|
||||
|
||||
// There's nothing to be used as source position, so snapping will work as absolute if enabled.
|
||||
target_position = canvas_item_editor->snap_point(target_position);
|
||||
_add_node_to_scene(p_parent, child, target_position);
|
||||
|
||||
CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
|
||||
Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
|
||||
|
||||
undo_redo->add_do_method(child, "set_position", local_target_pos);
|
||||
|
||||
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
|
||||
undo_redo->add_do_method(editor_selection, "add_node", child);
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->add_do_property(child, "stream", ResourceCache::get_ref(p_path));
|
||||
}
|
||||
|
||||
bool CanvasItemEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) {
|
||||
@@ -6512,7 +6484,6 @@ void CanvasItemEditorViewport::_perform_drop_data() {
|
||||
if (texture.is_valid()) {
|
||||
Node *child = Object::cast_to<Node>(ClassDB::instantiate(default_texture_node_type));
|
||||
_create_texture_node(target_node, child, path, drop_pos);
|
||||
undo_redo->add_do_method(editor_selection, "add_node", child);
|
||||
}
|
||||
|
||||
Ref<AudioStream> audio = res;
|
||||
@@ -6567,9 +6538,9 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
|
||||
|
||||
String error_message;
|
||||
for (const String &path : files) {
|
||||
const String &res_type = ResourceLoader::get_resource_type(path);
|
||||
const StringName res_type = ResourceLoader::get_resource_type(path);
|
||||
|
||||
if (ClassDB::is_parent_class(res_type, "PackedScene")) {
|
||||
if (ClassDB::is_parent_class(res_type, SNAME("PackedScene"))) {
|
||||
Ref<PackedScene> scn = ResourceLoader::load(path);
|
||||
ERR_CONTINUE(scn.is_null());
|
||||
|
||||
@@ -6583,11 +6554,9 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
|
||||
}
|
||||
memdelete(instantiated_scene);
|
||||
instantiate_type |= SCENE;
|
||||
}
|
||||
if (ClassDB::is_parent_class(res_type, "Texture2D")) {
|
||||
} else if (ClassDB::is_parent_class(res_type, SNAME("Texture2D"))) {
|
||||
instantiate_type |= TEXTURE;
|
||||
}
|
||||
if (ClassDB::is_parent_class(res_type, "AudioStream")) {
|
||||
} else if (ClassDB::is_parent_class(res_type, SNAME("AudioStream"))) {
|
||||
instantiate_type |= AUDIO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -685,6 +685,7 @@ class CanvasItemEditorViewport : public Control {
|
||||
|
||||
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;
|
||||
bool _is_any_texture_selected() const;
|
||||
void _add_node_to_scene(Node *p_parent, Node *p_child, const Vector2 &p_target_position);
|
||||
void _create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point);
|
||||
void _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);
|
||||
bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);
|
||||
|
||||
@@ -78,7 +78,7 @@ void EditorSceneTabs::_notification(int p_what) {
|
||||
|
||||
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
|
||||
case NOTIFICATION_TRANSLATION_CHANGED: {
|
||||
_scene_tabs_resized();
|
||||
_update_tab_titles();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +502,7 @@ void EditorAutoloadSettings::update_autoload() {
|
||||
if (old_info.path == info.path) {
|
||||
// Still the same resource, check status
|
||||
info.node = old_info.node;
|
||||
if (info.node) {
|
||||
if (info.node && info.node->is_instance()) {
|
||||
Ref<Script> scr = info.node->get_script();
|
||||
info.in_editor = scr.is_valid() && scr->is_tool();
|
||||
if (info.is_singleton == old_info.is_singleton && info.in_editor == old_info.in_editor) {
|
||||
|
||||
@@ -110,6 +110,7 @@ void editor_register_icons(const Ref<Theme> &p_theme, bool p_dark_theme, float p
|
||||
HashSet<StringName> saturation_exceptions;
|
||||
saturation_exceptions.insert("DefaultProjectIcon");
|
||||
saturation_exceptions.insert("Godot");
|
||||
saturation_exceptions.insert("GodotFile");
|
||||
saturation_exceptions.insert("Logo");
|
||||
saturation_exceptions.insert("TitleBarLogo");
|
||||
|
||||
|
||||
@@ -7188,27 +7188,25 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_se
|
||||
}
|
||||
|
||||
PackedByteArray GLTFDocument::generate_buffer(Ref<GLTFState> p_state) {
|
||||
Ref<GLTFState> state = p_state;
|
||||
ERR_FAIL_COND_V(state.is_null(), PackedByteArray());
|
||||
ERR_FAIL_COND_V(p_state.is_null(), PackedByteArray());
|
||||
// For buffers, set the state filename to an empty string, but
|
||||
// don't touch the base path, in case the user set it manually.
|
||||
state->filename = "";
|
||||
Error err = _serialize(state);
|
||||
p_state->filename = "";
|
||||
Error err = _serialize(p_state);
|
||||
ERR_FAIL_COND_V(err != OK, PackedByteArray());
|
||||
PackedByteArray bytes = _serialize_glb_buffer(state, &err);
|
||||
PackedByteArray bytes = _serialize_glb_buffer(p_state, &err);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) {
|
||||
Ref<GLTFState> state = p_state;
|
||||
ERR_FAIL_COND_V(state.is_null(), ERR_INVALID_PARAMETER);
|
||||
state->set_base_path(p_path.get_base_dir());
|
||||
state->filename = p_path.get_file();
|
||||
Error err = _serialize(state);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
p_state->set_base_path(p_path.get_base_dir());
|
||||
p_state->filename = p_path.get_file();
|
||||
Error err = _serialize(p_state);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
err = _serialize_file(state, p_path);
|
||||
err = _serialize_file(p_state, p_path);
|
||||
if (err != OK) {
|
||||
return Error::FAILED;
|
||||
}
|
||||
@@ -7266,15 +7264,14 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, boo
|
||||
}
|
||||
|
||||
Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags) {
|
||||
ERR_FAIL_NULL_V(p_node, FAILED);
|
||||
Ref<GLTFState> state = p_state;
|
||||
ERR_FAIL_COND_V(state.is_null(), FAILED);
|
||||
state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
if (!state->buffers.size()) {
|
||||
state->buffers.push_back(Vector<uint8_t>());
|
||||
ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
p_state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
p_state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
p_state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
p_state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
if (!p_state->buffers.size()) {
|
||||
p_state->buffers.push_back(Vector<uint8_t>());
|
||||
}
|
||||
// Perform export preflight for document extensions. Only extensions that
|
||||
// return OK will be used for the rest of the export steps.
|
||||
@@ -7285,7 +7282,7 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint
|
||||
if (ClassDB::is_class_exposed(ext->get_class_name())) {
|
||||
ext_dup = ext->duplicate();
|
||||
}
|
||||
Error err = ext_dup->export_preflight(state, p_node);
|
||||
Error err = ext_dup->export_preflight(p_state, p_node);
|
||||
if (err == OK) {
|
||||
document_extensions.push_back(ext_dup);
|
||||
}
|
||||
@@ -7294,14 +7291,14 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint
|
||||
if (_root_node_mode == RootNodeMode::ROOT_NODE_MODE_MULTI_ROOT) {
|
||||
const int child_count = p_node->get_child_count();
|
||||
for (int i = 0; i < child_count; i++) {
|
||||
_convert_scene_node(state, p_node->get_child(i), -1, -1);
|
||||
_convert_scene_node(p_state, p_node->get_child(i), -1, -1);
|
||||
}
|
||||
state->scene_name = p_node->get_name();
|
||||
p_state->scene_name = p_node->get_name();
|
||||
} else {
|
||||
if (_root_node_mode == RootNodeMode::ROOT_NODE_MODE_SINGLE_ROOT) {
|
||||
state->extensions_used.append("GODOT_single_root");
|
||||
p_state->extensions_used.append("GODOT_single_root");
|
||||
}
|
||||
_convert_scene_node(state, p_node, -1, -1);
|
||||
_convert_scene_node(p_state, p_node, -1, -1);
|
||||
}
|
||||
// Run post-convert for each extension, in case an extension needs to do something after converting the scene.
|
||||
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
|
||||
@@ -7313,40 +7310,36 @@ Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint
|
||||
}
|
||||
|
||||
Error GLTFDocument::append_from_buffer(const PackedByteArray &p_bytes, const String &p_base_path, Ref<GLTFState> p_state, uint32_t p_flags) {
|
||||
Ref<GLTFState> state = p_state;
|
||||
ERR_FAIL_COND_V(state.is_null(), FAILED);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
|
||||
Error err = FAILED;
|
||||
state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
p_state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
p_state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
p_state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
p_state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
|
||||
Ref<FileAccessMemory> file_access;
|
||||
file_access.instantiate();
|
||||
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
|
||||
state->set_base_path(p_base_path.get_base_dir());
|
||||
err = _parse(p_state, state->base_path, file_access);
|
||||
p_state->set_base_path(p_base_path.get_base_dir());
|
||||
err = _parse(p_state, p_state->base_path, file_access);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
|
||||
ERR_CONTINUE(ext.is_null());
|
||||
err = ext->import_post_parse(state);
|
||||
err = ext->import_post_parse(p_state);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error GLTFDocument::append_from_file(const String &p_path, Ref<GLTFState> p_state, uint32_t p_flags, const String &p_base_path) {
|
||||
Ref<GLTFState> state = p_state;
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
|
||||
if (state == Ref<GLTFState>()) {
|
||||
state.instantiate();
|
||||
}
|
||||
state->set_filename(p_path.get_file().get_basename());
|
||||
state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
p_state->set_filename(p_path.get_file().get_basename());
|
||||
p_state->use_named_skin_binds = p_flags & ImportFlags::IMPORT_FLAG_USE_NAMED_SKIN_BINDS;
|
||||
p_state->discard_meshes_and_materials = p_flags & ImportFlags::IMPORT_FLAG_DISCARD_MESHES_AND_MATERIALS;
|
||||
p_state->force_generate_tangents = p_flags & ImportFlags::IMPORT_FLAG_GENERATE_TANGENT_ARRAYS;
|
||||
p_state->force_disable_compression = p_flags & ImportFlags::IMPORT_FLAG_FORCE_DISABLE_MESH_COMPRESSION;
|
||||
|
||||
Error err;
|
||||
Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ, &err);
|
||||
@@ -7356,7 +7349,7 @@ Error GLTFDocument::append_from_file(const String &p_path, Ref<GLTFState> p_stat
|
||||
if (base_path.is_empty()) {
|
||||
base_path = p_path.get_base_dir();
|
||||
}
|
||||
state->set_base_path(base_path);
|
||||
p_state->set_base_path(base_path);
|
||||
err = _parse(p_state, base_path, file);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
for (Ref<GLTFDocumentExtension> ext : document_extensions) {
|
||||
@@ -7368,7 +7361,7 @@ Error GLTFDocument::append_from_file(const String &p_path, Ref<GLTFState> p_stat
|
||||
}
|
||||
|
||||
Error GLTFDocument::_parse_gltf_extensions(Ref<GLTFState> p_state) {
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_PARSE_ERROR);
|
||||
ERR_FAIL_COND_V(p_state.is_null(), ERR_INVALID_PARAMETER);
|
||||
if (p_state->json.has("extensionsUsed")) {
|
||||
Vector<String> ext_array = p_state->json["extensionsUsed"];
|
||||
p_state->extensions_used = ext_array;
|
||||
|
||||
@@ -1227,6 +1227,9 @@ void GridMapEditor::edit(GridMap *p_gridmap) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent the cursor from being at an incorrect position before any inputs happen.
|
||||
cursor_origin = (Vector3(cursor_gridpos) + Vector3(0.5 * node->get_center_x(), 0.5 * node->get_center_y(), 0.5 * node->get_center_z())) * node->get_cell_size();
|
||||
|
||||
update_palette();
|
||||
_update_cursor_instance();
|
||||
|
||||
@@ -1411,27 +1414,29 @@ void GridMapEditor::_update_cursor_instance() {
|
||||
|
||||
const RID scenario = get_tree()->get_root()->get_world_3d()->get_scenario();
|
||||
|
||||
if (mode_buttons_group->get_pressed_button() == paint_mode_button) {
|
||||
if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {
|
||||
Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);
|
||||
if (mesh.is_valid() && mesh->get_rid().is_valid()) {
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);
|
||||
RSE::ShadowCastingSetting cast_shadows = (RSE::ShadowCastingSetting)node->get_mesh_library()->get_item_mesh_cast_shadow(selected_palette);
|
||||
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, cast_shadows);
|
||||
if (mesh_library.is_valid()) {
|
||||
if (mode_buttons_group->get_pressed_button() == paint_mode_button) {
|
||||
if (selected_palette >= 0 && node && node->get_mesh_library().is_valid()) {
|
||||
Ref<Mesh> mesh = node->get_mesh_library()->get_item_mesh(selected_palette);
|
||||
if (mesh.is_valid() && mesh->get_rid().is_valid()) {
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(mesh->get_rid(), scenario);
|
||||
RSE::ShadowCastingSetting cast_shadows = (RSE::ShadowCastingSetting)node->get_mesh_library()->get_item_mesh_cast_shadow(selected_palette);
|
||||
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(cursor_instance, cast_shadows);
|
||||
}
|
||||
}
|
||||
} else if (mode_buttons_group->get_pressed_button() == select_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(default_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(default_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
} else if (mode_buttons_group->get_pressed_button() == erase_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(erase_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(erase_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
} else if (mode_buttons_group->get_pressed_button() == pick_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(pick_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(pick_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
}
|
||||
} else if (mode_buttons_group->get_pressed_button() == select_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(default_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(default_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
} else if (mode_buttons_group->get_pressed_button() == erase_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(erase_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(erase_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
} else if (mode_buttons_group->get_pressed_button() == pick_mode_button) {
|
||||
cursor_inner_mat->set_albedo(Color(pick_color, 0.2));
|
||||
cursor_outer_mat->set_albedo(Color(pick_color, 0.8));
|
||||
cursor_instance = RenderingServer::get_singleton()->instance_create2(cursor_mesh, scenario);
|
||||
}
|
||||
|
||||
bool was_visible = cursor_visible;
|
||||
|
||||
@@ -112,7 +112,7 @@ void JoltProjectSettings::read_settings() {
|
||||
joint_world_node = (JoltJointWorldNode)(int)GLOBAL_GET("physics/jolt_physics_3d/joints/world_node");
|
||||
|
||||
temp_memory_mib = GLOBAL_GET("physics/jolt_physics_3d/limits/temporary_memory_buffer_size");
|
||||
temp_memory_b = temp_memory_mib * 1024 * 1024;
|
||||
temp_memory_b = (int64_t)temp_memory_mib * 1024 * 1024;
|
||||
world_boundary_shape_size = GLOBAL_GET("physics/jolt_physics_3d/limits/world_boundary_shape_size");
|
||||
max_linear_velocity = GLOBAL_GET("physics/jolt_physics_3d/limits/max_linear_velocity");
|
||||
max_angular_velocity = GLOBAL_GET("physics/jolt_physics_3d/limits/max_angular_velocity");
|
||||
|
||||
@@ -600,15 +600,15 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(ProcessState &p_proce
|
||||
bool p_is_external_seeking = p_playback_info.is_external_seeking;
|
||||
|
||||
bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;
|
||||
|
||||
bool is_reset = Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking;
|
||||
if (is_reset && cur_internal_active) {
|
||||
do_start = true;
|
||||
}
|
||||
|
||||
bool is_abort = cur_request == ONE_SHOT_REQUEST_ABORT;
|
||||
if (is_reset && !do_start && (is_fading_out || (abort_on_reset && cur_active))) {
|
||||
is_abort = true;
|
||||
bool is_reset = Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking;
|
||||
if (is_reset) {
|
||||
if (!do_start && (is_fading_out || (abort_on_reset && cur_active))) {
|
||||
is_abort = true;
|
||||
}
|
||||
if (cur_internal_active) {
|
||||
do_start = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_abort) {
|
||||
|
||||
@@ -1363,6 +1363,10 @@ void RuntimeNodeSelect::_find_3d_items_at_rect(const Rect2 &p_rect, Vector<Selec
|
||||
const int num_hits = ss->intersect_shape(shape_params, results, 32);
|
||||
for (int i = 0; i < num_hits; i++) {
|
||||
const PhysicsDirectSpaceState3D::ShapeResult &result = results[i];
|
||||
if (!result.collider) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SelectResult res;
|
||||
res.item = Object::cast_to<Node>(result.collider);
|
||||
res.order = -dist_pos.distance_to(Object::cast_to<Node3D>(res.item)->get_global_transform().origin);
|
||||
|
||||
+29
-38
@@ -918,49 +918,32 @@ Control::GrowDirection Control::get_v_grow_direction() const {
|
||||
return data.v_grow;
|
||||
}
|
||||
|
||||
void Control::_compute_layout_rect(Rect2 p_rect, bool p_keep_offsets) {
|
||||
void Control::_compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]) {
|
||||
Size2 parent_rect_size = get_parent_anchorable_rect().size;
|
||||
|
||||
if (p_keep_offsets) {
|
||||
// If computing anchors, we need to ensure the parent rect size is valid to avoid division by zero.
|
||||
ERR_FAIL_COND(parent_rect_size.x == 0.0);
|
||||
ERR_FAIL_COND(parent_rect_size.y == 0.0);
|
||||
}
|
||||
ERR_FAIL_COND(parent_rect_size.x == 0.0);
|
||||
ERR_FAIL_COND(parent_rect_size.y == 0.0);
|
||||
|
||||
real_t x = p_rect.position.x;
|
||||
real_t y = p_rect.position.y;
|
||||
|
||||
if (_get_layout_mode() != LayoutMode::LAYOUT_MODE_CONTAINER) {
|
||||
float left_grow_factor =
|
||||
(data.h_grow == GROW_DIRECTION_BEGIN) ? 1.0f
|
||||
: (data.h_grow == GROW_DIRECTION_END) ? 0.0f
|
||||
: 0.5f;
|
||||
float top_grow_factor =
|
||||
(data.v_grow == GROW_DIRECTION_BEGIN) ? 1.0f
|
||||
: (data.v_grow == GROW_DIRECTION_END) ? 0.0f
|
||||
: 0.5f;
|
||||
|
||||
Size2 size_diff = p_rect.size - data.size_cache;
|
||||
|
||||
x -= size_diff.x * (is_layout_rtl() ? (1.0f - left_grow_factor) : left_grow_factor);
|
||||
y -= size_diff.y * top_grow_factor;
|
||||
}
|
||||
|
||||
if (is_layout_rtl()) {
|
||||
x = parent_rect_size.x - x - p_rect.size.x;
|
||||
}
|
||||
r_anchors[0] = (x - p_offsets[0]) / parent_rect_size.x;
|
||||
r_anchors[1] = (p_rect.position.y - p_offsets[1]) / parent_rect_size.y;
|
||||
r_anchors[2] = (x + p_rect.size.x - p_offsets[2]) / parent_rect_size.x;
|
||||
r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_offsets[3]) / parent_rect_size.y;
|
||||
}
|
||||
|
||||
if (p_keep_offsets) {
|
||||
data.anchor[0] = (x - data.offset[0]) / parent_rect_size.x;
|
||||
data.anchor[1] = (y - data.offset[1]) / parent_rect_size.y;
|
||||
data.anchor[2] = (x + p_rect.size.x - data.offset[2]) / parent_rect_size.x;
|
||||
data.anchor[3] = (y + p_rect.size.y - data.offset[3]) / parent_rect_size.y;
|
||||
} else {
|
||||
data.offset[0] = x - (data.anchor[0] * parent_rect_size.x);
|
||||
data.offset[1] = y - (data.anchor[1] * parent_rect_size.y);
|
||||
data.offset[2] = x + p_rect.size.x - (data.anchor[2] * parent_rect_size.x);
|
||||
data.offset[3] = y + p_rect.size.y - (data.anchor[3] * parent_rect_size.y);
|
||||
void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]) {
|
||||
Size2 parent_rect_size = get_parent_anchorable_rect().size;
|
||||
|
||||
real_t x = p_rect.position.x;
|
||||
if (is_layout_rtl()) {
|
||||
x = parent_rect_size.x - x - p_rect.size.x;
|
||||
}
|
||||
r_offsets[0] = x - (p_anchors[0] * parent_rect_size.x);
|
||||
r_offsets[1] = p_rect.position.y - (p_anchors[1] * parent_rect_size.y);
|
||||
r_offsets[2] = x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x);
|
||||
r_offsets[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y);
|
||||
}
|
||||
|
||||
/// Presets and layout modes.
|
||||
@@ -1493,7 +1476,11 @@ void Control::set_position(const Point2 &p_point, bool p_keep_offsets) {
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
_compute_layout_rect(Rect2(p_point, data.size_cache), p_keep_offsets);
|
||||
if (p_keep_offsets) {
|
||||
_compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor);
|
||||
} else {
|
||||
_compute_offsets(Rect2(p_point, data.size_cache), data.anchor, data.offset);
|
||||
}
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
@@ -1565,7 +1552,11 @@ void Control::set_size(const Size2 &p_size, bool p_keep_offsets) {
|
||||
|
||||
data.expanded_by_desired_size = false;
|
||||
|
||||
_compute_layout_rect(Rect2(data.pos_cache, new_size), p_keep_offsets);
|
||||
if (p_keep_offsets) {
|
||||
_compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor);
|
||||
} else {
|
||||
_compute_offsets(Rect2(data.pos_cache, new_size), data.anchor, data.offset);
|
||||
}
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
@@ -1585,7 +1576,7 @@ void Control::set_rect(const Rect2 &p_rect) {
|
||||
data.anchor[i] = ANCHOR_BEGIN;
|
||||
}
|
||||
|
||||
_compute_layout_rect(p_rect);
|
||||
_compute_offsets(p_rect, data.anchor, data.offset);
|
||||
if (is_inside_tree()) {
|
||||
_size_changed();
|
||||
}
|
||||
|
||||
+2
-1
@@ -365,7 +365,8 @@ private:
|
||||
void _set_global_position(const Point2 &p_point);
|
||||
void _set_size(const Size2 &p_size);
|
||||
|
||||
void _compute_layout_rect(Rect2 p_rect, bool p_keep_offsets = false);
|
||||
void _compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]);
|
||||
void _compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]);
|
||||
|
||||
void _set_layout_mode(LayoutMode p_mode);
|
||||
void _update_layout_mode();
|
||||
|
||||
@@ -3795,6 +3795,7 @@ PopupMenu::PopupMenu() {
|
||||
search_bar->set_clear_button_enabled(true);
|
||||
search_bar->set_placeholder(ETR("Search"));
|
||||
search_bar->set_keep_editing_on_text_submit(true);
|
||||
search_bar->set_virtual_keyboard_show_on_focus(false);
|
||||
search_bar->connect(SceneStringName(text_changed), callable_mp(this, &PopupMenu::_search_bar_text_changed));
|
||||
search_bar->connect(SceneStringName(focus_entered), callable_mp(this, &PopupMenu::_search_bar_focus_entered));
|
||||
vbox_container->add_child(search_bar, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
+7
-2
@@ -189,8 +189,13 @@ double Range::_calc_value(double p_val, double p_step) const {
|
||||
}
|
||||
|
||||
if (p_step > 0) {
|
||||
// Subtract min to support cases like min = 0.1, step = 0.2, snaps to 0.1, 0.3, 0.5, etc.
|
||||
p_val = _snapped_r128(p_val - shared->min, p_step) + shared->min;
|
||||
if (Math::abs(shared->min) > p_step * 1e14) {
|
||||
// Min is too big to use for snapping offset, so snap without it.
|
||||
p_val = _snapped_r128(p_val, p_step);
|
||||
} else {
|
||||
// Subtract min to support cases like min = 0.1, step = 0.2, snaps to 0.1, 0.3, 0.5, etc.
|
||||
p_val = _snapped_r128(p_val - shared->min, p_step) + shared->min;
|
||||
}
|
||||
}
|
||||
|
||||
if (_rounded_values) {
|
||||
|
||||
@@ -735,6 +735,7 @@ void SpinBox::_bind_methods() {
|
||||
SpinBox::SpinBox() {
|
||||
line_edit = memnew(SpinBoxLineEdit);
|
||||
line_edit->set_emoji_menu_enabled(false);
|
||||
line_edit->set_use_parent_material(true);
|
||||
add_child(line_edit, false, INTERNAL_MODE_FRONT);
|
||||
|
||||
line_edit->set_theme_type_variation("SpinBoxInnerLineEdit");
|
||||
|
||||
@@ -729,6 +729,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
||||
|
||||
theme->set_icon("file_thumbnail", "FileDialog", icons["file_thumbnail"]);
|
||||
theme->set_icon("folder_thumbnail", "FileDialog", icons["folder_thumbnail"]);
|
||||
theme->set_icon("menu_copy_path", "FileDialog", empty_icon);
|
||||
theme->set_icon("menu_delete", "FileDialog", empty_icon);
|
||||
theme->set_icon("menu_new_folder", "FileDialog", empty_icon);
|
||||
theme->set_icon("menu_refresh", "FileDialog", empty_icon);
|
||||
theme->set_icon("menu_show_in_file_manager", "FileDialog", empty_icon);
|
||||
theme->set_icon("menu_open_bundle", "FileDialog", empty_icon);
|
||||
theme->set_color("folder_icon_color", "FileDialog", Color(1, 1, 1));
|
||||
theme->set_color("file_icon_color", "FileDialog", Color(1, 1, 1));
|
||||
theme->set_color("file_disabled_color", "FileDialog", Color(1, 1, 1, 0.25));
|
||||
|
||||
@@ -122,8 +122,21 @@ public:
|
||||
virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
|
||||
virtual void mesh_surface_update_index_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {}
|
||||
|
||||
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {}
|
||||
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); }
|
||||
virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {
|
||||
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL(m);
|
||||
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, m->surfaces.size());
|
||||
RenderingServerTypes::SurfaceData s = m->surfaces.get(p_surface);
|
||||
s.material = p_material;
|
||||
m->surfaces.set(p_surface, s);
|
||||
m->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MATERIAL);
|
||||
}
|
||||
virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const override {
|
||||
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
||||
ERR_FAIL_NULL_V(m, RID());
|
||||
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, m->surfaces.size(), RID());
|
||||
return m->surfaces[p_surface].material;
|
||||
}
|
||||
|
||||
virtual RenderingServerTypes::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override {
|
||||
DummyMesh *m = mesh_owner.get_or_null(p_mesh);
|
||||
|
||||
@@ -418,7 +418,7 @@ TextureStorage::TextureStorage() {
|
||||
}
|
||||
}
|
||||
|
||||
{ //create default array white
|
||||
{ // Creates a default 2D texture array filled with a white color.
|
||||
|
||||
RD::TextureFormat tformat;
|
||||
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -444,7 +444,33 @@ TextureStorage::TextureStorage() {
|
||||
}
|
||||
}
|
||||
|
||||
{ //create default array black
|
||||
{ // Сreates a default 2D texture array filled with a black color.
|
||||
|
||||
RD::TextureFormat tformat;
|
||||
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
tformat.width = 4;
|
||||
tformat.height = 4;
|
||||
tformat.array_layers = 1;
|
||||
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
|
||||
tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
|
||||
|
||||
Vector<uint8_t> pv;
|
||||
pv.resize(16 * 4);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
pv.set(i * 4 + 0, 0);
|
||||
pv.set(i * 4 + 1, 0);
|
||||
pv.set(i * 4 + 2, 0);
|
||||
pv.set(i * 4 + 3, 255);
|
||||
}
|
||||
|
||||
{
|
||||
Vector<Vector<uint8_t>> vpv;
|
||||
vpv.push_back(pv);
|
||||
default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
|
||||
}
|
||||
}
|
||||
|
||||
{ // Creates a default 2D texture array filled with a transparent color.
|
||||
|
||||
RD::TextureFormat tformat;
|
||||
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
|
||||
@@ -466,7 +492,7 @@ TextureStorage::TextureStorage() {
|
||||
{
|
||||
Vector<Vector<uint8_t>> vpv;
|
||||
vpv.push_back(pv);
|
||||
default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
|
||||
default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_TRANSPARENT] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -147,15 +147,20 @@ bool RenderingLightCuller::_prepare_light(const RendererSceneCull::Instance &p_i
|
||||
Plane boundary_planes[5];
|
||||
{
|
||||
constexpr const int MAX_PLANES = 5;
|
||||
// Orthogonal cameras have fixed max shadow distance, determined by the camera far plane.
|
||||
// That must be accounted for, or else GH-120457 happens.
|
||||
// For perspective cameras, shadow far must also never be further than the camera far plane (otherwise things break).
|
||||
float camera_far = data.camera_projection.get_z_far();
|
||||
float shadow_far = data.camera_projection.is_orthogonal() ? camera_far : MIN(lsource.range, camera_far);
|
||||
real_t plane_distances[MAX_PLANES] = {
|
||||
data.camera_projection.get_z_near(),
|
||||
lsource.cascade_splits[0] * lsource.range,
|
||||
lsource.cascade_splits[1] * lsource.range,
|
||||
lsource.cascade_splits[2] * lsource.range,
|
||||
lsource.range,
|
||||
lsource.cascade_splits[0] * shadow_far,
|
||||
lsource.cascade_splits[1] * shadow_far,
|
||||
lsource.cascade_splits[2] * shadow_far,
|
||||
shadow_far,
|
||||
};
|
||||
//If not 4 cascades, replace last used cascade plane distance with max shadow range (shadow far plane distance).
|
||||
plane_distances[used_planes - 1] = lsource.range;
|
||||
// If not 4 cascades, replace last used cascade plane distance with max shadow range (shadow far plane distance).
|
||||
plane_distances[used_planes - 1] = shadow_far;
|
||||
#ifdef LIGHT_CULLER_DEBUG_LOGGING
|
||||
if (is_logging()) {
|
||||
print_line("cascade split planes (first " + itos(used_planes) + " used): " +
|
||||
|
||||
Reference in new issue
Block a user