diff options
23 files changed, 373 insertions, 145 deletions
diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index 806a95398f..8d75581342 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -47,13 +47,14 @@ static int _get_pad(int p_alignment, int p_n) { } void PCKPacker::_bind_methods() { - ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment", "key", "encrypt_directory"), &PCKPacker::pck_start, DEFVAL(0), DEFVAL(String()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("pck_start", "pck_name", "alignment", "key", "encrypt_directory"), &PCKPacker::pck_start, DEFVAL(32), DEFVAL("0000000000000000000000000000000000000000000000000000000000000000"), DEFVAL(false)); ClassDB::bind_method(D_METHOD("add_file", "pck_path", "source_path", "encrypt"), &PCKPacker::add_file, DEFVAL(false)); ClassDB::bind_method(D_METHOD("flush", "verbose"), &PCKPacker::flush, DEFVAL(false)); } Error PCKPacker::pck_start(const String &p_file, int p_alignment, const String &p_key, bool p_encrypt_directory) { ERR_FAIL_COND_V_MSG((p_key.is_empty() || !p_key.is_valid_hex_number(false) || p_key.length() != 64), ERR_CANT_CREATE, "Invalid Encryption Key (must be 64 characters long)."); + ERR_FAIL_COND_V_MSG(p_alignment <= 0, ERR_CANT_CREATE, "Invalid alignment, must be greater then 0."); String _key = p_key.to_lower(); key.resize(32); diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index 3d2ce8f240..bd8902a01d 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -58,7 +58,7 @@ class PCKPacker : public RefCounted { Vector<File> files; public: - Error pck_start(const String &p_file, int p_alignment = 0, const String &p_key = String(), bool p_encrypt_directory = false); + Error pck_start(const String &p_file, int p_alignment = 32, const String &p_key = "0000000000000000000000000000000000000000000000000000000000000000", bool p_encrypt_directory = false); Error add_file(const String &p_file, const String &p_src, bool p_encrypt = false); Error flush(bool p_verbose = false); diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml index 28508c85e0..b5e7b32225 100644 --- a/doc/classes/PCKPacker.xml +++ b/doc/classes/PCKPacker.xml @@ -43,8 +43,8 @@ <method name="pck_start"> <return type="int" enum="Error" /> <argument index="0" name="pck_name" type="String" /> - <argument index="1" name="alignment" type="int" default="0" /> - <argument index="2" name="key" type="String" default="""" /> + <argument index="1" name="alignment" type="int" default="32" /> + <argument index="2" name="key" type="String" default=""0000000000000000000000000000000000000000000000000000000000000000"" /> <argument index="3" name="encrypt_directory" type="bool" default="false" /> <description> Creates a new PCK file with the name [code]pck_name[/code]. The [code].pck[/code] file extension isn't added automatically, so it should be part of [code]pck_name[/code] (even though it's not required). diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 1bc88a86f7..1ebc8cca5e 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -473,7 +473,7 @@ String OS_Unix::get_user_data_dir() const { } } - return ProjectSettings::get_singleton()->get_resource_path(); + return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]"); } String OS_Unix::get_executable_path() const { diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 20deb35089..aaaa50e729 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -206,6 +206,8 @@ def configure_msvc(env, manual_msvc_config): elif env["target"] == "debug": env.AppendUnique(CCFLAGS=["/Zi", "/FS", "/Od", "/EHsc"]) + # Allow big objects. Only needed for debug, see MinGW branch for rationale. + env.AppendUnique(CCFLAGS=["/bigobj"]) env.Append(LINKFLAGS=["/DEBUG"]) if env["debug_symbols"]: @@ -227,7 +229,6 @@ def configure_msvc(env, manual_msvc_config): env.AppendUnique(CCFLAGS=["/Gd", "/GR", "/nologo"]) env.AppendUnique(CCFLAGS=["/utf-8"]) # Force to use Unicode encoding. - env.AppendUnique(CCFLAGS=["/bigobj"]) # Allow big objects, no drawbacks. env.AppendUnique(CXXFLAGS=["/TP"]) # assume all sources are C++ if manual_msvc_config: # should be automatic if SCons found it @@ -359,6 +360,10 @@ def configure_mingw(env): elif env["target"] == "debug": env.Append(CCFLAGS=["-g3"]) + # Allow big objects. It's supposed not to have drawbacks but seems to break + # GCC LTO, so enabling for debug builds only (which are not built with LTO + # and are the only ones with too big objects). + env.Append(CCFLAGS=["-Wa,-mbig-obj"]) if env["windows_subsystem"] == "gui": env.Append(LINKFLAGS=["-Wl,--subsystem,windows"]) @@ -422,7 +427,6 @@ def configure_mingw(env): ## Compile flags env.Append(CCFLAGS=["-mwindows"]) - env.Append(CCFLAGS=["-Wa,-mbig-obj"]) # Allow big objects, no drawbacks. env.Append(CPPDEFINES=["WINDOWS_ENABLED", "WASAPI_ENABLED", "WINMIDI_ENABLED"]) env.Append(CPPDEFINES=[("WINVER", env["target_win_version"]), ("_WIN32_WINNT", env["target_win_version"])]) diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 2c21390d73..d8d4e92d9d 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -760,7 +760,7 @@ String OS_Windows::get_user_data_dir() const { } } - return ProjectSettings::get_singleton()->get_resource_path(); + return get_data_path().plus_file(get_godot_dir_name()).plus_file("app_userdata").plus_file("[unnamed project]"); } String OS_Windows::get_unique_id() const { diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index bdb6cda5af..204ed72878 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -464,7 +464,7 @@ void NavigationRegion2D::_notification(int p_what) { draw_line(a, b, doors_color); // Draw a circle to illustrate the margins. - real_t angle = b.angle_to_point(a); + real_t angle = a.angle_to_point(b); draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color); draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); } diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 049cdb5bef..5a378554c9 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -833,7 +833,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { real_t dist = center.distance_to(bev->get_position()); if (dist <= center.x) { - real_t rad = bev->get_position().angle_to_point(center); + real_t rad = center.angle_to_point(bev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; s = CLAMP(dist / center.x, 0, 1); } else { @@ -850,7 +850,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { real_t dist = center.distance_to(bev->get_position()); if (dist >= center.x * 0.84 && dist <= center.x) { - real_t rad = bev->get_position().angle_to_point(center); + real_t rad = center.angle_to_point(bev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; spinning = true; } else { @@ -895,12 +895,12 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event, Control *c) { Vector2 center = c->get_size() / 2.0; if (picker_type == SHAPE_VHS_CIRCLE) { real_t dist = center.distance_to(mev->get_position()); - real_t rad = mev->get_position().angle_to_point(center); + real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; s = CLAMP(dist / center.x, 0, 1); } else { if (spinning) { - real_t rad = mev->get_position().angle_to_point(center); + real_t rad = center.angle_to_point(mev->get_position()); h = ((rad >= 0) ? rad : (Math_TAU + rad)) / Math_TAU; } else { real_t corner_x = (c == wheel_uv) ? center.x - Math_SQRT12 * c->get_size().width * 0.42 : 0; diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index 92d4261d8d..c4f05a7975 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -61,6 +61,11 @@ void Range::_changed_notify(const char *p_what) { update(); } +void Range::_validate_values() { + shared->max = MAX(shared->max, shared->min); + shared->page = CLAMP(shared->page, 0, shared->max - shared->min); +} + void Range::Shared::emit_changed(const char *p_what) { for (Set<Range *>::Element *E = owners.front(); E; E = E->next()) { Range *r = E->get(); @@ -100,6 +105,7 @@ void Range::set_value(double p_val) { void Range::set_min(double p_min) { shared->min = p_min; set_value(shared->val); + _validate_values(); shared->emit_changed("min"); @@ -109,6 +115,7 @@ void Range::set_min(double p_min) { void Range::set_max(double p_max) { shared->max = p_max; set_value(shared->val); + _validate_values(); shared->emit_changed("max"); } @@ -121,6 +128,7 @@ void Range::set_step(double p_step) { void Range::set_page(double p_page) { shared->page = p_page; set_value(shared->val); + _validate_values(); shared->emit_changed("page"); } @@ -270,6 +278,12 @@ void Range::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed"); + + ADD_LINKED_PROPERTY("min_value", "value"); + ADD_LINKED_PROPERTY("min_value", "max_value"); + ADD_LINKED_PROPERTY("min_value", "page"); + ADD_LINKED_PROPERTY("max_value", "value"); + ADD_LINKED_PROPERTY("max_value", "page"); } void Range::set_use_rounded_values(bool p_enable) { diff --git a/scene/gui/range.h b/scene/gui/range.h index 7a129e88d6..0dc702b19c 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -59,6 +59,7 @@ class Range : public Control { void _value_changed_notify(); void _changed_notify(const char *p_what = ""); + void _validate_values(); protected: virtual void _value_changed(double) {} diff --git a/scene/resources/skeleton_modification_2d_ccdik.cpp b/scene/resources/skeleton_modification_2d_ccdik.cpp index 6eab8d4afe..bea42109cb 100644 --- a/scene/resources/skeleton_modification_2d_ccdik.cpp +++ b/scene/resources/skeleton_modification_2d_ccdik.cpp @@ -205,8 +205,8 @@ void SkeletonModification2DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node2D * } else { // How to rotate from the tip: get the difference of rotation needed from the tip to the target, from the perspective of the joint. // Because we are only using the offset, we do not need to account for the bone angle of the Bone2D node. - float joint_to_tip = operation_transform.get_origin().angle_to_point(p_tip->get_global_position()); - float joint_to_target = operation_transform.get_origin().angle_to_point(p_target->get_global_position()); + float joint_to_tip = p_tip->get_global_position().angle_to_point(operation_transform.get_origin()); + float joint_to_target = p_target->get_global_position().angle_to_point(operation_transform.get_origin()); operation_transform.set_rotation( operation_transform.get_rotation() + (joint_to_target - joint_to_tip)); } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 0bdc81330e..87ff225de9 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -1835,6 +1835,7 @@ void VisualShader::_update_shader() const { code += " float __scalar_buff1;\n"; code += " float __scalar_buff2;\n"; code += " int __scalar_ibuff;\n"; + code += " vec4 __vec4_buff;\n"; code += " vec3 __ndiff = normalize(__diff);\n\n"; } if (has_start) { diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp index 7dd4eed15b..1a829968e3 100644 --- a/scene/resources/visual_shader_particle_nodes.cpp +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -264,7 +264,7 @@ String VisualShaderNodeParticleMeshEmitter::get_caption() const { } int VisualShaderNodeParticleMeshEmitter::get_output_port_count() const { - return 2; + return 6; } VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter::get_output_port_type(int p_port) const { @@ -273,6 +273,14 @@ VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter return PORT_TYPE_VECTOR; // position case 1: return PORT_TYPE_VECTOR; // normal + case 2: + return PORT_TYPE_VECTOR; // color + case 3: + return PORT_TYPE_SCALAR; // alpha + case 4: + return PORT_TYPE_VECTOR; // uv + case 5: + return PORT_TYPE_VECTOR; // uv2 } return PORT_TYPE_SCALAR; } @@ -283,6 +291,14 @@ String VisualShaderNodeParticleMeshEmitter::get_output_port_name(int p_port) con return "position"; case 1: return "normal"; + case 2: + return "color"; + case 3: + return "alpha"; + case 4: + return "uv"; + case 5: + return "uv2"; } return String(); } @@ -299,135 +315,263 @@ String VisualShaderNodeParticleMeshEmitter::get_input_port_name(int p_port) cons return String(); } -String VisualShaderNodeParticleMeshEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { +String VisualShaderNodeParticleMeshEmitter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { String code; if (mesh.is_valid()) { - code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n"; - code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n"; + if (is_output_port_connected(0)) { // position + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n"; + } + + if (is_output_port_connected(1)) { // normal + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n"; + } + + if (is_output_port_connected(2) || is_output_port_connected(3)) { // color & alpha + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_col") + ";\n"; + } + + if (is_output_port_connected(4)) { // uv + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv") + ";\n"; + } + + if (is_output_port_connected(5)) { // uv2 + code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv2") + ";\n"; + } } return code; } -String VisualShaderNodeParticleMeshEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { +String VisualShaderNodeParticleMeshEmitter::_generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d) const { String code; - - code += " __scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n"; - - if (position_texture->get_width() == 0) { - code += " " + p_output_vars[0] + " = vec3(0.0);\n"; - } else { - if (mode_2d) { - code += " " + p_output_vars[0] + " = vec3("; + if (is_output_port_connected(p_index)) { + if (mode_2d && !p_ignore_mode2d) { + code += " " + p_output_vars[p_index] + " = vec3("; code += "texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_vx") + ", "; + code += make_unique_id(p_type, p_id, p_texture_name) + ", "; code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n"; } else { - code += " " + p_output_vars[0] + " = texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_vx") + ", "; + code += " " + p_output_vars[p_index] + " = texelFetch("; + code += make_unique_id(p_type, p_id, p_texture_name) + ", "; code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n"; } } + return code; +} - if (normal_texture->get_width() == 0) { - code += " " + p_output_vars[1] + " = vec3(0.0);\n"; - } else { - if (mode_2d) { - code += " " + p_output_vars[1] + " = vec3("; - code += "texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_nm") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n"; +String VisualShaderNodeParticleMeshEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + code += " __scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n"; + + code += _generate_code(p_type, p_id, p_output_vars, 0, "mesh_vx"); + code += _generate_code(p_type, p_id, p_output_vars, 1, "mesh_nm"); + + if (is_output_port_connected(2) || is_output_port_connected(3)) { + code += " __vec4_buff = texelFetch("; + code += make_unique_id(p_type, p_id, "mesh_col") + ", "; + code += "ivec2(__scalar_ibuff, 0), 0);\n"; + if (is_output_port_connected(2)) { + code += " " + p_output_vars[2] + " = __vec4_buff.rgb;\n"; } else { - code += " " + p_output_vars[1] + " = texelFetch("; - code += make_unique_id(p_type, p_id, "mesh_nm") + ", "; - code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n"; + code += " " + p_output_vars[2] + " = vec3(0.0);\n"; + } + if (is_output_port_connected(3)) { + code += " " + p_output_vars[3] + " = __vec4_buff.a;\n"; + } else { + code += " " + p_output_vars[3] + " = 0.0;\n"; } } + code += _generate_code(p_type, p_id, p_output_vars, 4, "mesh_uv", true); + code += _generate_code(p_type, p_id, p_output_vars, 5, "mesh_uv2", true); + return code; } Vector<VisualShader::DefaultTextureParam> VisualShaderNodeParticleMeshEmitter::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { - VisualShader::DefaultTextureParam dtp_vx; - dtp_vx.name = make_unique_id(p_type, p_id, "mesh_vx"); - dtp_vx.params.push_back(position_texture); + Vector<VisualShader::DefaultTextureParam> ret; - VisualShader::DefaultTextureParam dtp_nm; - dtp_nm.name = make_unique_id(p_type, p_id, "mesh_nm"); - dtp_nm.params.push_back(normal_texture); + if (is_output_port_connected(0)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_vx"); + dtp.params.push_back(position_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(1)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_nm"); + dtp.params.push_back(normal_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(2) || is_output_port_connected(3)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_col"); + dtp.params.push_back(color_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(4)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_uv"); + dtp.params.push_back(uv_texture); + ret.push_back(dtp); + } + + if (is_output_port_connected(5)) { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "mesh_uv2"); + dtp.params.push_back(uv2_texture); + ret.push_back(dtp); + } - Vector<VisualShader::DefaultTextureParam> ret; - ret.push_back(dtp_vx); - ret.push_back(dtp_nm); return ret; } -void VisualShaderNodeParticleMeshEmitter::update_texture() { +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2> &p_array, Ref<ImageTexture> &r_texture) { + Ref<Image> image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBF); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + } + + for (int i = 0; i < p_array.size(); i++) { + Vector2 v = p_array[i]; + image->set_pixel(i, 0, Color(v.x, v.y, 0)); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3> &p_array, Ref<ImageTexture> &r_texture) { + Ref<Image> image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBF); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF); + } + + for (int i = 0; i < p_array.size(); i++) { + Vector3 v = p_array[i]; + image->set_pixel(i, 0, Color(v.x, v.y, v.z)); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p_array, Ref<ImageTexture> &r_texture) { + Ref<Image> image; + image.instantiate(); + + if (p_array.size() == 0) { + image->create(1, 1, false, Image::Format::FORMAT_RGBA8); + } else { + image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8); + } + + for (int i = 0; i < p_array.size(); i++) { + image->set_pixel(i, 0, p_array[i]); + } + if (r_texture->get_width() != p_array.size() || p_array.size() == 0) { + r_texture->create_from_image(image); + } else { + r_texture->update(image); + } +} + +void VisualShaderNodeParticleMeshEmitter::_update_textures() { if (!mesh.is_valid()) { return; } Vector<Vector3> vertices; Vector<Vector3> normals; + Vector<Color> colors; + Vector<Vector2> uvs; + Vector<Vector2> uvs2; if (use_all_surfaces) { for (int i = 0; i < max_surface_index; i++) { + // position Array vertex_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_VERTEX]; for (int j = 0; j < vertex_array.size(); j++) { vertices.push_back((Vector3)vertex_array[j]); } + // normal Array normal_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_NORMAL]; - for (int j = 0; j < vertex_array.size(); j++) { - normals.push_back((Vector3)vertex_array[j]); + for (int j = 0; j < normal_array.size(); j++) { + normals.push_back((Vector3)normal_array[j]); + } + + // color + Array color_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_COLOR]; + for (int j = 0; j < color_array.size(); j++) { + colors.push_back((Color)color_array[j]); + } + + // uv + Array uv_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV]; + for (int j = 0; j < uv_array.size(); j++) { + uvs.push_back((Vector2)uv_array[j]); + } + + // uv2 + Array uv2_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV2]; + for (int j = 0; j < uv2_array.size(); j++) { + uvs2.push_back((Vector2)uv2_array[j]); } } } else { + // position Array vertex_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_VERTEX]; for (int i = 0; i < vertex_array.size(); i++) { vertices.push_back((Vector3)vertex_array[i]); } + // normal Array normal_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_NORMAL]; for (int i = 0; i < normal_array.size(); i++) { normals.push_back((Vector3)normal_array[i]); } - } - // vertices - { - Ref<Image> image; - image.instantiate(); - image->create(vertices.size(), 1, false, Image::Format::FORMAT_RGBF); - - for (int i = 0; i < vertices.size(); i++) { - Vector3 v = vertices[i]; - image->set_pixel(i, 0, Color(v.x, v.y, v.z)); - } - if (position_texture->get_width() != vertices.size()) { - position_texture->create_from_image(image); - } else { - position_texture->update(image); + // color + Array color_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_COLOR]; + for (int i = 0; i < color_array.size(); i++) { + colors.push_back((Color)color_array[i]); } - } - - // normals - { - Ref<Image> image; - image.instantiate(); - image->create(normals.size(), 1, false, Image::Format::FORMAT_RGBF); - for (int i = 0; i < normals.size(); i++) { - Vector3 v = normals[i]; - image->set_pixel(i, 0, Color(v.x, v.y, v.z)); + // uv + Array uv_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV]; + for (int j = 0; j < uv_array.size(); j++) { + uvs.push_back((Vector2)uv_array[j]); } - if (normal_texture->get_width() != normals.size()) { - normal_texture->create_from_image(image); - } else { - normal_texture->update(image); + + // uv2 + Array uv2_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV2]; + for (int j = 0; j < uv2_array.size(); j++) { + uvs2.push_back((Vector2)uv2_array[j]); } } + + _update_texture(vertices, position_texture); + _update_texture(normals, normal_texture); + _update_texture(colors, color_texture); + _update_texture(uvs, uv_texture); + _update_texture(uvs2, uv2_texture); } void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) { @@ -442,7 +586,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) { } if (mesh.is_valid()) { - Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture); + Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures); if (mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) { mesh->disconnect(CoreStringNames::get_singleton()->changed, callable); @@ -452,7 +596,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) { mesh = p_mesh; if (mesh.is_valid()) { - Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture); + Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures); if (!mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) { mesh->connect(CoreStringNames::get_singleton()->changed, callable); @@ -528,10 +672,13 @@ void VisualShaderNodeParticleMeshEmitter::_bind_methods() { } VisualShaderNodeParticleMeshEmitter::VisualShaderNodeParticleMeshEmitter() { - connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture)); + connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures)); position_texture.instantiate(); normal_texture.instantiate(); + color_texture.instantiate(); + uv_texture.instantiate(); + uv2_texture.instantiate(); } // VisualShaderNodeParticleMultiplyByAxisAngle diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h index 0d0f21e4bf..79459432f1 100644 --- a/scene/resources/visual_shader_particle_nodes.h +++ b/scene/resources/visual_shader_particle_nodes.h @@ -115,6 +115,16 @@ class VisualShaderNodeParticleMeshEmitter : public VisualShaderNodeParticleEmitt Ref<ImageTexture> position_texture; Ref<ImageTexture> normal_texture; + Ref<ImageTexture> color_texture; + Ref<ImageTexture> uv_texture; + Ref<ImageTexture> uv2_texture; + + String _generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d = false) const; + + void _update_texture(const Vector<Vector2> &p_array, Ref<ImageTexture> &r_texture); + void _update_texture(const Vector<Vector3> &p_array, Ref<ImageTexture> &r_texture); + void _update_texture(const Vector<Color> &p_array, Ref<ImageTexture> &r_texture); + void _update_textures(); protected: static void _bind_methods(); @@ -130,11 +140,9 @@ public: virtual PortType get_input_port_type(int p_port) const override; virtual String get_input_port_name(int p_port) const override; - virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; - void update_texture(); - void set_mesh(Ref<Mesh> p_mesh); Ref<Mesh> get_mesh() const; diff --git a/servers/physics_2d/godot_space_2d.cpp b/servers/physics_2d/godot_space_2d.cpp index 6465a5542c..7a5eb26bb3 100644 --- a/servers/physics_2d/godot_space_2d.cpp +++ b/servers/physics_2d/godot_space_2d.cpp @@ -439,8 +439,6 @@ bool GodotPhysicsDirectSpaceState2D::rest_info(const ShapeParameters &p_paramete GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; - Rect2 aabb = p_parameters.transform.xform(shape->get_aabb()); aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion aabb = aabb.grow(p_parameters.margin); @@ -448,10 +446,11 @@ bool GodotPhysicsDirectSpaceState2D::rest_info(const ShapeParameters &p_paramete int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); _RestCallbackData2D rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; - rcd.min_allowed_depth = min_contact_depth; + + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + real_t motion_length = p_parameters.motion.length(); + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); for (int i = 0; i < amount; i++) { if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { @@ -879,9 +878,6 @@ bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D:: ugt.elements[2] += p_parameters.motion * unsafe; _RestCallbackData2D rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index 686f3e4d59..540b16c6e3 100644 --- a/servers/physics_3d/godot_collision_solver_3d.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -264,7 +264,7 @@ bool GodotCollisionSolver3D::solve_soft_body(const GodotShape3D *p_shape_A, cons local_aabb.size[i] = smax - smin; } - concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo); + concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo, true); } else { AABB shape_aabb = p_transform_A.xform(p_shape_A->get_aabb()); shape_aabb.grow_by(collision_margin); @@ -346,7 +346,7 @@ bool GodotCollisionSolver3D::solve_concave(const GodotShape3D *p_shape_A, const local_aabb.size[i] = smax - smin; } - concave_B->cull(local_aabb, concave_callback, &cinfo); + concave_B->cull(local_aabb, concave_callback, &cinfo, false); return cinfo.collided; } @@ -559,7 +559,7 @@ bool GodotCollisionSolver3D::solve_distance(const GodotShape3D *p_shape_A, const local_aabb.size[i] = smax - smin; } - concave_B->cull(local_aabb, concave_distance_callback, &cinfo); + concave_B->cull(local_aabb, concave_distance_callback, &cinfo, false); if (!cinfo.collided) { r_point_A = cinfo.close_A; r_point_B = cinfo.close_B; diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index 0790333f65..4faa07b6c9 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -36,6 +36,8 @@ #define fallback_collision_solver gjk_epa_calculate_penetration +#define _BACKFACE_NORMAL_THRESHOLD -0.0002 + // Cylinder SAT analytic methods and face-circle contact points for cylinder-trimesh and cylinder-box collision are based on ODE colliders. /* @@ -612,13 +614,14 @@ class SeparatorAxisTest { const Transform3D *transform_A = nullptr; const Transform3D *transform_B = nullptr; real_t best_depth = 1e15; - Vector3 best_axis; _CollectorCallback *callback = nullptr; real_t margin_A = 0.0; real_t margin_B = 0.0; Vector3 separator_axis; public: + Vector3 best_axis; + _FORCE_INLINE_ bool test_previous_axis() { if (callback && callback->prev_axis && *callback->prev_axis != Vector3()) { return test_axis(*callback->prev_axis); @@ -627,7 +630,7 @@ public: } } - _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) { + _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) { Vector3 axis = p_axis; if (axis.is_equal_approx(Vector3())) { @@ -661,12 +664,7 @@ public: //use the smallest depth if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0 - if (p_directional) { - min_B = max_B; - axis = -axis; - } else { - min_B = -min_B; - } + min_B = -min_B; } if (max_B < min_B) { @@ -1014,7 +1012,7 @@ static void _collision_sphere_face(const GodotShape3D *p_a, const Transform3D &p Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1041,6 +1039,17 @@ static void _collision_sphere_face(const GodotShape3D *p_a, const Transform3D &p } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } @@ -1486,7 +1495,7 @@ static void _collision_box_face(const GodotShape3D *p_a, const Transform3D &p_tr Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1591,6 +1600,17 @@ static void _collision_box_face(const GodotShape3D *p_a, const Transform3D &p_tr } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } @@ -1802,7 +1822,7 @@ static void _collision_capsule_face(const GodotShape3D *p_a, const Transform3D & Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1858,6 +1878,17 @@ static void _collision_capsule_face(const GodotShape3D *p_a, const Transform3D & } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } @@ -1952,7 +1983,7 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); // Face B normal. - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -2034,6 +2065,17 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } @@ -2174,7 +2216,7 @@ static void _collision_convex_polygon_face(const GodotShape3D *p_a, const Transf Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -2266,6 +2308,17 @@ static void _collision_convex_polygon_face(const GodotShape3D *p_a, const Transf } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index d1e919ab6a..5364a9833d 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -1401,7 +1401,7 @@ bool GodotConcavePolygonShape3D::_cull(int p_idx, _CullParams *p_params) const { return false; } -void GodotConcavePolygonShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { +void GodotConcavePolygonShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const { // make matrix local to concave if (faces.size() == 0) { return; @@ -1416,6 +1416,7 @@ void GodotConcavePolygonShape3D::cull(const AABB &p_local_aabb, QueryCallback p_ GodotFaceShape3D face; // use this to send in the callback face.backface_collision = backface_collision; + face.invert_backface_collision = p_invert_backface_collision; _CullParams params; params.aabb = local_aabb; @@ -1961,7 +1962,7 @@ void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5); } -void GodotHeightMapShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { +void GodotHeightMapShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const { if (heights.is_empty()) { return; } @@ -1988,7 +1989,8 @@ void GodotHeightMapShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callb int end_z = MIN(depth - 1, aabb_max[2]); GodotFaceShape3D face; - face.backface_collision = true; + face.backface_collision = !p_invert_backface_collision; + face.invert_backface_collision = p_invert_backface_collision; for (int z = start_z; z < end_z; z++) { for (int x = start_x; x < end_x; x++) { diff --git a/servers/physics_3d/godot_shape_3d.h b/servers/physics_3d/godot_shape_3d.h index 7a32b69166..43319510d4 100644 --- a/servers/physics_3d/godot_shape_3d.h +++ b/servers/physics_3d/godot_shape_3d.h @@ -107,7 +107,7 @@ public: // Returns true to stop the query. typedef bool (*QueryCallback)(void *p_userdata, GodotShape3D *p_convex); - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const = 0; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const = 0; GodotConcaveShape3D() {} }; @@ -370,7 +370,7 @@ public: virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override; virtual Vector3 get_moment_of_inertia(real_t p_mass) const override; @@ -433,7 +433,7 @@ public: virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override; virtual Vector3 get_moment_of_inertia(real_t p_mass) const override; @@ -448,6 +448,7 @@ struct GodotFaceShape3D : public GodotShape3D { Vector3 normal; //cache Vector3 vertex[3]; bool backface_collision = false; + bool invert_backface_collision = false; virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; } diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index b8e9ab4fb9..231b8686f5 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -964,12 +964,6 @@ void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_area } } -void GodotSoftBody3D::_compute_area_gravity(const GodotArea3D *p_area) { - Vector3 area_gravity; - p_area->compute_gravity(get_transform().get_origin(), area_gravity); - gravity += area_gravity; -} - Vector3 GodotSoftBody3D::_compute_area_windforce(const GodotArea3D *p_area, const Face *p_face) { real_t wfm = p_area->get_wind_force_magnitude(); real_t waf = p_area->get_wind_attenuation_factor(); @@ -987,12 +981,12 @@ void GodotSoftBody3D::predict_motion(real_t p_delta) { ERR_FAIL_COND(!get_space()); - int ac = areas.size(); - bool gravity_done = false; + Vector3 gravity; LocalVector<GodotArea3D *> wind_areas; + int ac = areas.size(); if (ac) { areas.sort(); const AreaCMP *aa = &areas[0]; diff --git a/servers/physics_3d/godot_soft_body_3d.h b/servers/physics_3d/godot_soft_body_3d.h index c03951959f..5198186b5d 100644 --- a/servers/physics_3d/godot_soft_body_3d.h +++ b/servers/physics_3d/godot_soft_body_3d.h @@ -101,8 +101,6 @@ class GodotSoftBody3D : public GodotCollisionObject3D { real_t drag_coefficient = 0.0; // [0,1] LocalVector<int> pinned_vertices; - Vector3 gravity; - SelfList<GodotSoftBody3D> active_list; Set<GodotConstraint3D *> constraints; @@ -113,7 +111,6 @@ class GodotSoftBody3D : public GodotCollisionObject3D { uint64_t island_step = 0; - _FORCE_INLINE_ void _compute_area_gravity(const GodotArea3D *p_area); _FORCE_INLINE_ Vector3 _compute_area_windforce(const GodotArea3D *p_area, const Face *p_face); public: diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index e2f90b90ad..f503273c88 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -507,15 +507,17 @@ bool GodotPhysicsDirectSpaceState3D::rest_info(const ShapeParameters &p_paramete GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; - AABB aabb = p_parameters.transform.xform(shape->get_aabb()); aabb = aabb.grow(p_parameters.margin); int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); _RestCallbackData rcd; - rcd.min_allowed_depth = min_contact_depth; + + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + real_t motion_length = p_parameters.motion.length(); + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); for (int i = 0; i < amount; i++) { if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { diff --git a/tests/core/io/test_pck_packer.h b/tests/core/io/test_pck_packer.h index ae51d58522..75a4abffbe 100644 --- a/tests/core/io/test_pck_packer.h +++ b/tests/core/io/test_pck_packer.h @@ -40,17 +40,11 @@ namespace TestPCKPacker { -// Dummy 64-character encryption key (since it's required). -constexpr const char *ENCRYPTION_KEY = "0000000000000000000000000000000000000000000000000000000000000000"; - TEST_CASE("[PCKPacker] Pack an empty PCK file") { PCKPacker pck_packer; const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck"); CHECK_MESSAGE( - pck_packer.pck_start( - output_pck_path, - 32, - ENCRYPTION_KEY) == OK, + pck_packer.pck_start(output_pck_path) == OK, "Starting a PCK file should return an OK error code."); CHECK_MESSAGE( @@ -70,14 +64,27 @@ TEST_CASE("[PCKPacker] Pack an empty PCK file") { "The generated empty PCK file shouldn't be too large."); } +TEST_CASE("[PCKPacker] Pack empty with zero alignment invalid") { + PCKPacker pck_packer; + const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck"); + ERR_PRINT_OFF; + CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 0) != OK, "PCK with zero alignment should fail."); + ERR_PRINT_ON; +} + +TEST_CASE("[PCKPacker] Pack empty with invalid key") { + PCKPacker pck_packer; + const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_empty.pck"); + ERR_PRINT_OFF; + CHECK_MESSAGE(pck_packer.pck_start(output_pck_path, 32, "") != OK, "PCK with invalid key should fail."); + ERR_PRINT_ON; +} + TEST_CASE("[PCKPacker] Pack a PCK file with some files and directories") { PCKPacker pck_packer; const String output_pck_path = OS::get_singleton()->get_cache_path().plus_file("output_with_files.pck"); CHECK_MESSAGE( - pck_packer.pck_start( - output_pck_path, - 32, - ENCRYPTION_KEY) == OK, + pck_packer.pck_start(output_pck_path) == OK, "Starting a PCK file should return an OK error code."); const String base_dir = OS::get_singleton()->get_executable_path().get_base_dir(); |