summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/camera/camera_osx.mm2
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp7
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h5
-rw-r--r--modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd41
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp38
-rw-r--r--modules/gdscript/gdscript_editor.cpp9
-rw-r--r--modules/gdscript/gdscript_parser.cpp62
-rw-r--r--modules/gdscript/gdscript_parser.h2
-rw-r--r--modules/gdscript/gdscript_warning.cpp2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out4
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp4
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h4
-rw-r--r--modules/gltf/gltf_document.cpp59
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml3
-rw-r--r--modules/gridmap/grid_map.cpp18
-rw-r--r--modules/gridmap/grid_map.h6
-rw-r--r--modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs67
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp8
20 files changed, 314 insertions, 50 deletions
diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm
index 626cc3f285..391006bfc2 100644
--- a/modules/camera/camera_osx.mm
+++ b/modules/camera/camera_osx.mm
@@ -231,7 +231,7 @@ void CameraFeedOSX::set_device(AVCaptureDevice *p_device) {
// get some info
NSString *device_name = p_device.localizedName;
- name = device_name.UTF8String;
+ name = String::utf8(device_name.UTF8String);
position = CameraFeed::FEED_UNSPECIFIED;
if ([p_device position] == AVCaptureDevicePositionBack) {
position = CameraFeed::FEED_BACK;
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index e03680010b..4cca907bf2 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -83,7 +83,7 @@ uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
return IMPORT_SCENE;
}
-Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps,
+Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err) {
// done for performance when re-importing lots of files when testing importer in verbose only!
if (OS::get_singleton()->is_stdout_verbose()) {
@@ -1468,3 +1468,8 @@ void EditorSceneFormatImporterFBX::BuildDocumentNodes(
}
}
}
+Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path,
+ uint32_t p_flags, const Map<StringName, Variant> &p_options,
+ int p_bake_fps) {
+ return Ref<Animation>();
+}
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index a6ea8058a7..eebcb86409 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -127,7 +127,10 @@ public:
virtual void get_extensions(List<String> *r_extensions) const override;
virtual uint32_t get_import_flags() const override;
- virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
+ virtual Node3D *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
+ virtual Ref<Animation> import_animation(const String &p_path,
+ uint32_t p_flags, const Map<StringName, Variant> &p_options,
+ int p_bake_fps) override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd
new file mode 100644
index 0000000000..27383b878d
--- /dev/null
+++ b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd
@@ -0,0 +1,41 @@
+# meta-description: Visual shader's node plugin template
+
+@tool
+extends _BASE_
+class_name VisualShaderNode_CLASS_
+
+func _get_name() -> String:
+ return "_CLASS_"
+
+func _get_category() -> String:
+ return ""
+
+func _get_description() -> String:
+ return ""
+
+func _get_return_icon_type() -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_input_port_count() -> int:
+ return 0
+
+func _get_input_port_name(port: int) -> String:
+ return ""
+
+func _get_input_port_type(port: int) -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_output_port_count() -> int:
+ return 1
+
+func _get_output_port_name(port: int) -> String:
+ return "result"
+
+func _get_output_port_type(port: int) -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_global_code(mode: Shader.Mode) -> String:
+ return ""
+
+func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String:
+ return output_vars[0] + " = 0.0;"
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index ffd34080e3..0bf4f5e1f1 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -881,12 +881,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
- resolve_function_body(member.function);
-
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
E->apply(parser, member.function);
}
+
+#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : member.function->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
+#endif // DEBUG_ENABLED
+
+ resolve_function_body(member.function);
+
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
} else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {
if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
if (member.variable->getter != nullptr) {
@@ -925,6 +936,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : member.function->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
}
@@ -992,6 +1007,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable);
}
}
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
}
}
}
@@ -1186,7 +1204,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
for (int i = 0; i < p_suite->statements.size(); i++) {
GDScriptParser::Node *stmt = p_suite->statements[i];
+ for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) {
+ annotation->apply(parser, stmt);
+ }
+
+#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : stmt->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
+#endif // DEBUG_ENABLED
+
resolve_node(stmt);
+
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
+
decide_suite_type(p_suite, stmt);
}
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 7e5780a6b8..9db76861ff 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -646,6 +646,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);
r_result.insert(option.display, option);
}
+ } else if (p_annotation->name == "@warning_ignore") {
+ for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
+ ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ r_result.insert(warning.display, warning);
+ }
}
}
@@ -1159,6 +1164,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) {
bool found = false;
+ if (p_expression == nullptr) {
+ return false;
+ }
+
if (p_expression->is_constant) {
// Already has a value, so just use that.
r_type = _type_from_variant(p_expression->reduced_value);
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d12795d320..2faf0febca 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -39,6 +39,7 @@
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#include "core/string/string_builder.h"
+#include "gdscript_warning.h"
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
+ register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true);
// Networking.
register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true);
- // TODO: Warning annotations.
}
GDScriptParser::~GDScriptParser() {
@@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
return;
}
+ if (ignored_warning_codes.has(p_code)) {
+ return;
+ }
+
String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();
if (ignored_warnings.has(warn_name)) {
return;
@@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() {
template <class T>
void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) {
advance();
- T *member = (this->*p_parse_function)();
- if (member == nullptr) {
- return;
- }
+
#ifdef TOOLS_ENABLED
- int doc_comment_line = member->start_line - 1;
+ int doc_comment_line = previous.start_line - 1;
#endif // TOOLS_ENABLED
// Consume annotations.
+ List<AnnotationNode *> annotations;
while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
- member->annotations.push_front(last_annotation);
+ annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind));
clear_unused_annotations();
- return;
}
#ifdef TOOLS_ENABLED
if (last_annotation->start_line == doc_comment_line) {
@@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
#endif // TOOLS_ENABLED
}
+ T *member = (this->*p_parse_function)();
+ if (member == nullptr) {
+ return;
+ }
+
+ // Apply annotations.
+ for (AnnotationNode *&annotation : annotations) {
+ member->annotations.push_back(annotation);
+ }
+
#ifdef TOOLS_ENABLED
// Consume doc comments.
class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
@@ -1507,6 +1519,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code;
#endif
+ bool is_annotation = false;
+
switch (current.type) {
case GDScriptTokenizer::Token::PASS:
advance();
@@ -1576,6 +1590,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
break;
case GDScriptTokenizer::Token::ANNOTATION: {
advance();
+ is_annotation = true;
AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);
if (annotation != nullptr) {
annotation_stack.push_back(annotation);
@@ -1616,6 +1631,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
}
+ // Apply annotations to statement.
+ while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) {
+ AnnotationNode *last_annotation = annotation_stack.back()->get();
+ if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) {
+ result->annotations.push_front(last_annotation);
+ annotation_stack.pop_back();
+ } else {
+ push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name));
+ clear_unused_annotations();
+ }
+ }
+
#ifdef DEBUG_ENABLED
if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
@@ -3552,7 +3579,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) {
- ERR_FAIL_V_MSG(false, "Not implemented.");
+#ifdef DEBUG_ENABLED
+ bool has_error = false;
+ for (const Variant &warning_name : p_annotation->resolved_arguments) {
+ GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());
+ if (warning == GDScriptWarning::WARNING_MAX) {
+ push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation);
+ has_error = true;
+ } else {
+ p_node->ignored_warnings.push_back(warning);
+ }
+ }
+
+ return !has_error;
+
+#else // ! DEBUG_ENABLED
+ // Only available in debug builds.
+ return true;
+#endif // DEBUG_ENABLED
}
template <Multiplayer::RPCMode t_mode>
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index b5ff0538eb..bf0f670905 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -297,6 +297,7 @@ public:
int leftmost_column = 0, rightmost_column = 0;
Node *next = nullptr;
List<AnnotationNode *> annotations;
+ Vector<uint32_t> ignored_warnings;
DataType datatype;
@@ -1204,6 +1205,7 @@ private:
#ifdef DEBUG_ENABLED
List<GDScriptWarning> warnings;
Set<String> ignored_warnings;
+ Set<uint32_t> ignored_warning_codes;
Set<int> unsafe_lines;
#endif
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index fd251b8444..73536f5f8e 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -213,7 +213,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name)
}
}
- ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name);
+ return WARNING_MAX;
}
#endif // DEBUG_ENABLED
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 5845f84605..47772b8039 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -362,16 +362,16 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha
}
builder.append("\n>> on function: ");
- builder.append(p_function);
+ builder.append(String::utf8(p_function));
builder.append("()\n>> ");
- builder.append(String(p_file).trim_prefix(self->base_dir));
+ builder.append(String::utf8(p_file).trim_prefix(self->base_dir));
builder.append("\n>> ");
builder.append(itos(p_line));
builder.append("\n>> ");
- builder.append(p_error);
+ builder.append(String::utf8(p_error));
if (strlen(p_explanation) > 0) {
builder.append("\n>> ");
- builder.append(p_explanation);
+ builder.append(String::utf8(p_explanation));
}
builder.append("\n");
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
new file mode 100644
index 0000000000..877a4ea221
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
@@ -0,0 +1,15 @@
+@warning_ignore(unused_private_class_variable)
+var _unused = 2
+
+@warning_ignore(unused_variable)
+func test():
+ print("test")
+ var unused = 3
+
+ @warning_ignore(redundant_await)
+ print(await regular_func())
+
+ print("done")
+
+func regular_func():
+ return 0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
new file mode 100644
index 0000000000..42292774a0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+test
+0
+done
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index b4d39041da..f063cc1e2b 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -48,7 +48,7 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c
}
Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path,
- uint32_t p_flags, int p_bake_fps,
+ uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps,
Error *r_err) {
Ref<GLTFDocument> doc;
@@ -65,7 +65,7 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path,
}
Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path,
- uint32_t p_flags,
+ uint32_t p_flags, const Map<StringName, Variant> &p_options,
int p_bake_fps) {
return Ref<Animation>();
}
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index dafd278f24..4410559b3d 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -47,9 +47,9 @@ class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter {
public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path,
- uint32_t p_flags, int p_bake_fps) override;
+ uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) override;
};
#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 2f8320d7c9..833bcb00e6 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -2523,14 +2523,16 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (p.has("mode")) {
const int mode = p["mode"];
ERR_FAIL_INDEX_V(mode, 7, ERR_FILE_CORRUPT);
+ // Convert mesh.primitive.mode to Godot Mesh enum. See:
+ // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_mesh_primitive_mode
static const Mesh::PrimitiveType primitives2[7] = {
- Mesh::PRIMITIVE_POINTS,
- Mesh::PRIMITIVE_LINES,
- Mesh::PRIMITIVE_LINES, //loop not supported, should ce converted
- Mesh::PRIMITIVE_LINES,
- Mesh::PRIMITIVE_TRIANGLES,
- Mesh::PRIMITIVE_TRIANGLE_STRIP,
- Mesh::PRIMITIVE_TRIANGLES, //fan not supported, should be converted
+ Mesh::PRIMITIVE_POINTS, // 0 POINTS
+ Mesh::PRIMITIVE_LINES, // 1 LINES
+ Mesh::PRIMITIVE_LINES, // 2 LINE_LOOP; loop not supported, should be converted
+ Mesh::PRIMITIVE_LINE_STRIP, // 3 LINE_STRIP
+ Mesh::PRIMITIVE_TRIANGLES, // 4 TRIANGLES
+ Mesh::PRIMITIVE_TRIANGLE_STRIP, // 5 TRIANGLE_STRIP
+ Mesh::PRIMITIVE_TRIANGLES, // 6 TRIANGLE_FAN fan not supported, should be converted
#ifndef _MSC_VER
#warning line loop and triangle fan are not supported and need to be converted to lines and triangles
#endif
@@ -3390,29 +3392,32 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
tex.instantiate();
{
Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
- // Code for uncompressing RG normal maps
- Ref<Image> img = normal_texture->get_image();
- Ref<ImageTexture> img_tex = img;
- if (img_tex.is_valid()) {
- img = img_tex->get_image();
- }
- img->decompress();
- img->convert(Image::FORMAT_RGBA8);
- img->convert_ra_rgba8_to_rg();
- for (int32_t y = 0; y < img->get_height(); y++) {
- for (int32_t x = 0; x < img->get_width(); x++) {
- Color c = img->get_pixel(x, y);
- Vector2 red_green = Vector2(c.r, c.g);
- red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f);
- float blue = 1.0f - red_green.dot(red_green);
- blue = MAX(0.0f, blue);
- c.b = Math::sqrt(blue);
- img->set_pixel(x, y, c);
+ if (normal_texture.is_valid()) {
+ // Code for uncompressing RG normal maps
+ Ref<Image> img = normal_texture->get_image();
+ if (img.is_valid()) {
+ Ref<ImageTexture> img_tex = img;
+ if (img_tex.is_valid()) {
+ img = img_tex->get_image();
+ }
+ img->decompress();
+ img->convert(Image::FORMAT_RGBA8);
+ img->convert_ra_rgba8_to_rg();
+ for (int32_t y = 0; y < img->get_height(); y++) {
+ for (int32_t x = 0; x < img->get_width(); x++) {
+ Color c = img->get_pixel(x, y);
+ Vector2 red_green = Vector2(c.r, c.g);
+ red_green = red_green * Vector2(2.0f, 2.0f) - Vector2(1.0f, 1.0f);
+ float blue = 1.0f - red_green.dot(red_green);
+ blue = MAX(0.0f, blue);
+ c.b = Math::sqrt(blue);
+ img->set_pixel(x, y, c);
+ }
+ }
+ tex->create_from_image(img);
}
}
- tex->create_from_image(img);
}
- Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL);
GLTFTextureIndex gltf_texture_index = -1;
if (tex.is_valid() && tex->get_image().is_valid()) {
tex->set_name(material->get_name() + "_normal");
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 73315350ff..885817caf1 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -181,6 +181,9 @@
<member name="navigation_layers" type="int" setter="set_navigation_layers" getter="get_navigation_layers" default="1">
The navigation layers the GridMap generates its navigable regions in.
</member>
+ <member name="physics_material" type="PhysicsMaterial" setter="set_physics_material" getter="get_physics_material">
+ Overrides the default friction and bounce physics properties for the whole [GridMap].
+ </member>
</members>
<signals>
<signal name="cell_size_changed">
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 3383daefea..a861efcbf4 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -34,6 +34,7 @@
#include "core/object/message_queue.h"
#include "scene/3d/light_3d.h"
#include "scene/resources/mesh_library.h"
+#include "scene/resources/physics_material.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
#include "servers/navigation_server_3d.h"
@@ -181,6 +182,15 @@ void GridMap::set_collision_mask_value(int p_layer_number, bool p_value) {
set_collision_mask(mask);
}
+void GridMap::set_physics_material(Ref<PhysicsMaterial> p_material) {
+ physics_material = p_material;
+ _recreate_octant_data();
+}
+
+Ref<PhysicsMaterial> GridMap::get_physics_material() const {
+ return physics_material;
+}
+
bool GridMap::get_collision_mask_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
@@ -316,6 +326,10 @@ void GridMap::set_cell_item(const Vector3i &p_position, int p_item, int p_rot) {
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(g->static_body, get_instance_id());
PhysicsServer3D::get_singleton()->body_set_collision_layer(g->static_body, collision_layer);
PhysicsServer3D::get_singleton()->body_set_collision_mask(g->static_body, collision_mask);
+ if (physics_material.is_valid()) {
+ PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_FRICTION, physics_material->get_friction());
+ PhysicsServer3D::get_singleton()->body_set_param(g->static_body, PhysicsServer3D::BODY_PARAM_BOUNCE, physics_material->get_bounce());
+ }
SceneTree *st = SceneTree::get_singleton();
if (st && st->is_debugging_collisions_hint()) {
@@ -801,6 +815,9 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &GridMap::set_collision_layer_value);
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &GridMap::get_collision_layer_value);
+ ClassDB::bind_method(D_METHOD("set_physics_material", "material"), &GridMap::set_physics_material);
+ ClassDB::bind_method(D_METHOD("get_physics_material"), &GridMap::get_physics_material);
+
ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &GridMap::set_bake_navigation);
ClassDB::bind_method(D_METHOD("is_baking_navigation"), &GridMap::is_baking_navigation);
@@ -850,6 +867,7 @@ void GridMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_baked_meshes", "gen_lightmap_uv", "lightmap_uv_texel_size"), &GridMap::make_baked_meshes, DEFVAL(false), DEFVAL(0.1));
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_library", PROPERTY_HINT_RESOURCE_TYPE, "MeshLibrary"), "set_mesh_library", "get_mesh_library");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material", "get_physics_material");
ADD_GROUP("Cell", "cell_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "cell_size"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_octant_size", PROPERTY_HINT_RANGE, "1,1024,1"), "set_octant_size", "get_octant_size");
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index db3395b6fe..546b530148 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -38,6 +38,8 @@
//heh heh, godotsphir!! this shares no code and the design is completely different with previous projects i've done..
//should scale better with hardware that supports instancing
+class PhysicsMaterial;
+
class GridMap : public Node3D {
GDCLASS(GridMap, Node3D);
@@ -134,6 +136,7 @@ class GridMap : public Node3D {
uint32_t collision_layer = 1;
uint32_t collision_mask = 1;
+ Ref<PhysicsMaterial> physics_material;
bool bake_navigation = false;
uint32_t navigation_layers = 1;
@@ -223,6 +226,9 @@ public:
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
+ void set_physics_material(Ref<PhysicsMaterial> p_material);
+ Ref<PhysicsMaterial> get_physics_material() const;
+
void set_bake_navigation(bool p_bake_navigation);
bool is_baking_navigation();
diff --git a/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs b/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs
new file mode 100644
index 0000000000..00fdc9968e
--- /dev/null
+++ b/modules/mono/editor_templates/VisualShaderNodeCustom/basic.cs
@@ -0,0 +1,67 @@
+// meta-description: Visual shader's node plugin template
+
+using _BINDINGS_NAMESPACE_;
+using System;
+
+public partial class VisualShaderNode_CLASS_ : _BASE_
+{
+ public override string _GetName()
+ {
+ return "_CLASS_";
+ }
+
+ public override string _GetCategory()
+ {
+ return "";
+ }
+
+ public override string _GetDescription()
+ {
+ return "";
+ }
+
+ public override int _GetReturnIconType()
+ {
+ return 0;
+ }
+
+ public override int _GetInputPortCount()
+ {
+ return 0;
+ }
+
+ public override string _GetInputPortName(int port)
+ {
+ return "";
+ }
+
+ public override int _GetInputPortType(int port)
+ {
+ return 0;
+ }
+
+ public override int _GetOutputPortCount()
+ {
+ return 1;
+ }
+
+ public override string _GetOutputPortName(int port)
+ {
+ return "result";
+ }
+
+ public override int _GetOutputPortType(int port)
+ {
+ return 0;
+ }
+
+ public override string _GetGlobalCode(Shader.Mode mode)
+ {
+ return "";
+ }
+
+ public override string _GetCode(Godot.Collections.Array inputVars, Godot.Collections.Array outputVars, Shader.Mode mode, VisualShader.Type type)
+ {
+ return "";
+ }
+}
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 27d23a142e..056e1eb6a3 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -2316,10 +2316,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const {
property.hint = PROPERTY_HINT_ENUM;
List<StringName> sigs;
+ List<MethodInfo> base_sigs;
Ref<VisualScript> vs = get_visual_script();
if (vs.is_valid()) {
vs->get_custom_signal_list(&sigs);
+ ClassDB::get_signal_list(vs->get_instance_base_type(), &base_sigs);
}
String ml;
@@ -2329,6 +2331,12 @@ void VisualScriptEmitSignal::_validate_property(PropertyInfo &property) const {
}
ml += E;
}
+ for (const MethodInfo &E : base_sigs) {
+ if (!ml.is_empty()) {
+ ml += ",";
+ }
+ ml += E.name;
+ }
property.hint_string = ml;
}