diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/core_bind.cpp | 6 | ||||
| -rw-r--r-- | core/core_bind.h | 1 | ||||
| -rw-r--r-- | core/input/input.cpp | 43 | ||||
| -rw-r--r-- | core/input/input.h | 11 | ||||
| -rw-r--r-- | core/input/input_event.cpp | 28 | ||||
| -rw-r--r-- | core/input/input_event.h | 10 | ||||
| -rw-r--r-- | core/input/input_map.cpp | 22 | ||||
| -rw-r--r-- | core/input/input_map.h | 6 | ||||
| -rw-r--r-- | core/io/image.cpp | 22 | ||||
| -rw-r--r-- | core/io/image.h | 2 | ||||
| -rw-r--r-- | core/math/transform.h | 4 | ||||
| -rw-r--r-- | core/math/vector3.h | 8 | ||||
| -rw-r--r-- | core/object/script_language.cpp | 8 | ||||
| -rw-r--r-- | core/variant/variant_call.cpp | 3 |
14 files changed, 121 insertions, 53 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index f568ee754d..dd99c32fa8 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -1254,6 +1254,11 @@ Error _File::open(const String &p_path, ModeFlags p_mode_flags) { return err; } +void _File::flush() { + ERR_FAIL_COND_MSG(!f, "File must be opened before flushing."); + f->flush(); +} + void _File::close() { if (f) { memdelete(f); @@ -1547,6 +1552,7 @@ void _File::_bind_methods() { ClassDB::bind_method(D_METHOD("open_compressed", "path", "mode_flags", "compression_mode"), &_File::open_compressed, DEFVAL(0)); ClassDB::bind_method(D_METHOD("open", "path", "flags"), &_File::open); + ClassDB::bind_method(D_METHOD("flush"), &_File::flush); ClassDB::bind_method(D_METHOD("close"), &_File::close); ClassDB::bind_method(D_METHOD("get_path"), &_File::get_path); ClassDB::bind_method(D_METHOD("get_path_absolute"), &_File::get_path_absolute); diff --git a/core/core_bind.h b/core/core_bind.h index 44e620085a..7f945a9314 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -386,6 +386,7 @@ public: Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ); Error open(const String &p_path, ModeFlags p_mode_flags); // open a file. + void flush(); // Flush a file (write its buffer to disk). void close(); // Close a file. bool is_open() const; // True when file is open. diff --git a/core/input/input.cpp b/core/input/input.cpp index 047aeb47fd..48e573626d 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -97,11 +97,11 @@ void Input::_bind_methods() { ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed); ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed); ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed); - ClassDB::bind_method(D_METHOD("is_action_pressed", "action"), &Input::is_action_pressed); - ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action"), &Input::is_action_just_pressed); - ClassDB::bind_method(D_METHOD("is_action_just_released", "action"), &Input::is_action_just_released); - ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &Input::get_action_strength); - ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action"), &Input::get_action_strength); + ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact"), &Input::is_action_pressed, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_action_just_pressed", "action", "exact"), &Input::is_action_just_pressed, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_action_just_released", "action", "exact"), &Input::is_action_just_released, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact"), &Input::get_action_strength, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_action_raw_strength", "action", "exact"), &Input::get_action_strength, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_axis", "negative_action", "positive_action"), &Input::get_axis); ClassDB::bind_method(D_METHOD("get_vector", "negative_x", "positive_x", "negative_y", "positive_y", "deadzone"), &Input::get_vector, DEFVAL(-1.0f)); ClassDB::bind_method(D_METHOD("add_joy_mapping", "mapping", "update_existing"), &Input::add_joy_mapping, DEFVAL(false)); @@ -240,16 +240,20 @@ bool Input::is_joy_button_pressed(int p_device, int p_button) const { return joy_buttons_pressed.has(_combine_device(p_button, p_device)); } -bool Input::is_action_pressed(const StringName &p_action) const { - return action_state.has(p_action) && action_state[p_action].pressed; +bool Input::is_action_pressed(const StringName &p_action, bool p_exact) const { + return action_state.has(p_action) && action_state[p_action].pressed && (p_exact ? action_state[p_action].exact : true); } -bool Input::is_action_just_pressed(const StringName &p_action) const { +bool Input::is_action_just_pressed(const StringName &p_action, bool p_exact) const { const Map<StringName, Action>::Element *E = action_state.find(p_action); if (!E) { return false; } + if (p_exact && E->get().exact == false) { + return false; + } + if (Engine::get_singleton()->is_in_physics_frame()) { return E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); } else { @@ -257,12 +261,16 @@ bool Input::is_action_just_pressed(const StringName &p_action) const { } } -bool Input::is_action_just_released(const StringName &p_action) const { +bool Input::is_action_just_released(const StringName &p_action, bool p_exact) const { const Map<StringName, Action>::Element *E = action_state.find(p_action); if (!E) { return false; } + if (p_exact && E->get().exact == false) { + return false; + } + if (Engine::get_singleton()->is_in_physics_frame()) { return !E->get().pressed && E->get().physics_frame == Engine::get_singleton()->get_physics_frames(); } else { @@ -270,21 +278,29 @@ bool Input::is_action_just_released(const StringName &p_action) const { } } -float Input::get_action_strength(const StringName &p_action) const { +float Input::get_action_strength(const StringName &p_action, bool p_exact) const { const Map<StringName, Action>::Element *E = action_state.find(p_action); if (!E) { return 0.0f; } + if (p_exact && E->get().exact == false) { + return 0.0f; + } + return E->get().strength; } -float Input::get_action_raw_strength(const StringName &p_action) const { +float Input::get_action_raw_strength(const StringName &p_action, bool p_exact) const { const Map<StringName, Action>::Element *E = action_state.find(p_action); if (!E) { return 0.0f; } + if (p_exact && E->get().exact == false) { + return 0.0f; + } + return E->get().raw_strength; } @@ -590,14 +606,15 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em for (const Map<StringName, InputMap::Action>::Element *E = InputMap::get_singleton()->get_action_map().front(); E; E = E->next()) { if (InputMap::get_singleton()->event_is_action(p_event, E->key())) { - // Save the action's state - if (!p_event->is_echo() && is_action_pressed(E->key()) != p_event->is_action_pressed(E->key())) { + // If not echo and action pressed state has changed + if (!p_event->is_echo() && is_action_pressed(E->key(), false) != p_event->is_action_pressed(E->key())) { Action action; action.physics_frame = Engine::get_singleton()->get_physics_frames(); action.process_frame = Engine::get_singleton()->get_process_frames(); action.pressed = p_event->is_action_pressed(E->key()); action.strength = 0.0f; action.raw_strength = 0.0f; + action.exact = InputMap::get_singleton()->event_is_action(p_event, E->key(), true); action_state[E->key()] = action; } action_state[E->key()].strength = p_event->get_action_strength(E->key()); diff --git a/core/input/input.h b/core/input/input.h index 445b7ff0cf..0e3af42381 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -116,6 +116,7 @@ private: uint64_t physics_frame; uint64_t process_frame; bool pressed; + bool exact; float strength; float raw_strength; }; @@ -261,11 +262,11 @@ public: bool is_key_pressed(int p_keycode) const; bool is_mouse_button_pressed(int p_button) const; bool is_joy_button_pressed(int p_device, int p_button) const; - bool is_action_pressed(const StringName &p_action) const; - bool is_action_just_pressed(const StringName &p_action) const; - bool is_action_just_released(const StringName &p_action) const; - float get_action_strength(const StringName &p_action) const; - float get_action_raw_strength(const StringName &p_action) const; + bool is_action_pressed(const StringName &p_action, bool p_exact = false) const; + bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const; + bool is_action_just_released(const StringName &p_action, bool p_exact = false) const; + float get_action_strength(const StringName &p_action, bool p_exact = false) const; + float get_action_raw_strength(const StringName &p_action, bool p_exact = false) const; float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const; Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const; diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index c91dc4d067..b1c8f1ad66 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -44,31 +44,31 @@ int InputEvent::get_device() const { return device; } -bool InputEvent::is_action(const StringName &p_action) const { - return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action); +bool InputEvent::is_action(const StringName &p_action, bool p_exact_match) const { + return InputMap::get_singleton()->event_is_action(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match); } -bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo) const { +bool InputEvent::is_action_pressed(const StringName &p_action, bool p_allow_echo, bool p_exact_match) const { bool pressed; - bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr); return valid && pressed && (p_allow_echo || !is_echo()); } -bool InputEvent::is_action_released(const StringName &p_action) const { +bool InputEvent::is_action_released(const StringName &p_action, bool p_exact_match) const { bool pressed; - bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, &pressed); + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, &pressed, nullptr, nullptr); return valid && !pressed; } -float InputEvent::get_action_strength(const StringName &p_action) const { +float InputEvent::get_action_strength(const StringName &p_action, bool p_exact_match) const { float strength; - bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, &strength); + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, &strength, nullptr); return valid ? strength : 0.0f; } -float InputEvent::get_action_raw_strength(const StringName &p_action) const { +float InputEvent::get_action_raw_strength(const StringName &p_action, bool p_exact_match) const { float raw_strength; - bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, nullptr, nullptr, &raw_strength); + bool valid = InputMap::get_singleton()->event_get_action_status(Ref<InputEvent>((InputEvent *)this), p_action, p_exact_match, nullptr, nullptr, &raw_strength); return valid ? raw_strength : 0.0f; } @@ -100,10 +100,10 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("set_device", "device"), &InputEvent::set_device); ClassDB::bind_method(D_METHOD("get_device"), &InputEvent::get_device); - ClassDB::bind_method(D_METHOD("is_action", "action"), &InputEvent::is_action); - ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo"), &InputEvent::is_action_pressed, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("is_action_released", "action"), &InputEvent::is_action_released); - ClassDB::bind_method(D_METHOD("get_action_strength", "action"), &InputEvent::get_action_strength); + ClassDB::bind_method(D_METHOD("is_action", "action", "exact_match"), &InputEvent::is_action, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "allow_echo", "exact_match"), &InputEvent::is_action_pressed, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("is_action_released", "action", "exact_match"), &InputEvent::is_action_released, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_action_strength", "action", "exact_match"), &InputEvent::get_action_strength, DEFVAL(false)); ClassDB::bind_method(D_METHOD("is_pressed"), &InputEvent::is_pressed); ClassDB::bind_method(D_METHOD("is_echo"), &InputEvent::is_echo); diff --git a/core/input/input_event.h b/core/input/input_event.h index a354119cf9..1ce1fad9c2 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -128,11 +128,11 @@ public: void set_device(int p_device); int get_device() const; - bool is_action(const StringName &p_action) const; - bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false) const; - bool is_action_released(const StringName &p_action) const; - float get_action_strength(const StringName &p_action) const; - float get_action_raw_strength(const StringName &p_action) const; + bool is_action(const StringName &p_action, bool p_exact_match = false) const; + bool is_action_pressed(const StringName &p_action, bool p_allow_echo = false, bool p_exact_match = false) const; + bool is_action_released(const StringName &p_action, bool p_exact_match = false) const; + float get_action_strength(const StringName &p_action, bool p_exact_match = false) const; + float get_action_raw_strength(const StringName &p_action, bool p_exact_match = false) const; // To be removed someday, since they do not make sense for all events virtual bool is_pressed() const; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 53ed925c1f..c03e64eaf4 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -50,7 +50,7 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); ClassDB::bind_method(D_METHOD("action_erase_events", "action"), &InputMap::action_erase_events); ClassDB::bind_method(D_METHOD("action_get_events", "action"), &InputMap::_action_get_events); - ClassDB::bind_method(D_METHOD("event_is_action", "event", "action"), &InputMap::event_is_action); + ClassDB::bind_method(D_METHOD("event_is_action", "event", "action", "exact_match"), &InputMap::event_is_action, DEFVAL(false)); ClassDB::bind_method(D_METHOD("load_from_project_settings"), &InputMap::load_from_project_settings); } @@ -95,7 +95,7 @@ List<StringName> InputMap::get_actions() const { return actions; } -List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength) const { +List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const { ERR_FAIL_COND_V(!p_event.is_valid(), nullptr); for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) { @@ -106,7 +106,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re int device = e->get_device(); if (device == ALL_DEVICES || device == p_event->get_device()) { - if (e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { + if (p_exact_match && e->shortcut_match(p_event)) { + return E; + } else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { return E; } } @@ -134,7 +136,7 @@ void InputMap::action_set_deadzone(const StringName &p_action, float p_deadzone) void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND_MSG(p_event.is_null(), "It's not a reference to a valid InputEvent object."); ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'."); - if (_find_event(input_map[p_action], p_event)) { + if (_find_event(input_map[p_action], p_event, true)) { return; // Already addded. } @@ -143,13 +145,13 @@ void InputMap::action_add_event(const StringName &p_action, const Ref<InputEvent bool InputMap::action_has_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND_V_MSG(!input_map.has(p_action), false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); - return (_find_event(input_map[p_action], p_event) != nullptr); + return (_find_event(input_map[p_action], p_event, true) != nullptr); } void InputMap::action_erase_event(const StringName &p_action, const Ref<InputEvent> &p_event) { ERR_FAIL_COND_MSG(!input_map.has(p_action), "Request for nonexistent InputMap action '" + String(p_action) + "'."); - List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event); + List<Ref<InputEvent>>::Element *E = _find_event(input_map[p_action], p_event, true); if (E) { input_map[p_action].inputs.erase(E); if (Input::get_singleton()->is_action_pressed(p_action)) { @@ -185,11 +187,11 @@ const List<Ref<InputEvent>> *InputMap::action_get_events(const StringName &p_act return &E->get().inputs; } -bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const { - return event_get_action_status(p_event, p_action); +bool InputMap::event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match) const { + return event_get_action_status(p_event, p_action, p_exact_match); } -bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed, float *p_strength, float *p_raw_strength) const { +bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match, bool *p_pressed, float *p_strength, float *p_raw_strength) const { Map<StringName, Action>::Element *E = input_map.find(p_action); ERR_FAIL_COND_V_MSG(!E, false, "Request for nonexistent InputMap action '" + String(p_action) + "'."); @@ -207,7 +209,7 @@ bool InputMap::event_get_action_status(const Ref<InputEvent> &p_event, const Str bool pressed; float strength; float raw_strength; - List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, &pressed, &strength, &raw_strength); + List<Ref<InputEvent>>::Element *event = _find_event(E->get(), p_event, p_exact_match, &pressed, &strength, &raw_strength); if (event != nullptr) { if (p_pressed != nullptr) { *p_pressed = pressed; diff --git a/core/input/input_map.h b/core/input/input_map.h index 1646e7fadb..28c692c7ba 100644 --- a/core/input/input_map.h +++ b/core/input/input_map.h @@ -54,7 +54,7 @@ private: mutable Map<StringName, Action> input_map; - List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; + List<Ref<InputEvent>>::Element *_find_event(Action &p_action, const Ref<InputEvent> &p_event, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; Array _action_get_events(const StringName &p_action); Array _get_actions(); @@ -78,8 +78,8 @@ public: void action_erase_events(const StringName &p_action); const List<Ref<InputEvent>> *action_get_events(const StringName &p_action); - bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action) const; - bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; + bool event_is_action(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false) const; + bool event_get_action_status(const Ref<InputEvent> &p_event, const StringName &p_action, bool p_exact_match = false, bool *p_pressed = nullptr, float *p_strength = nullptr, float *p_raw_strength = nullptr) const; const Map<StringName, Action> &get_action_map() const; void load_from_project_settings(); diff --git a/core/io/image.cpp b/core/io/image.cpp index 986c29b539..5d46d75efe 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -2985,6 +2985,26 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { _set_color_at_ofs(data.ptrw(), ofs, p_color); } +void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { + uint8_t *w = data.ptrw(); + uint32_t pixel_size = get_format_pixel_size(format); + uint32_t pixel_count = data.size() / pixel_size; + + for (uint32_t i = 0; i < pixel_count; i++) { + Color c = _get_color_at_ofs(w, i); + Vector3 rgb(c.r, c.g, c.b); + + rgb *= p_brightness; + rgb = Vector3(0.5, 0.5, 0.5).lerp(rgb, p_contrast); + float center = (rgb.x + rgb.y + rgb.z) / 3.0; + rgb = Vector3(center, center, center).lerp(rgb, p_saturation); + c.r = rgb.x; + c.g = rgb.y; + c.b = rgb.z; + _set_color_at_ofs(w, i, c); + } +} + Image::UsedChannels Image::detect_used_channels(CompressSource p_source) { ERR_FAIL_COND_V(data.size() == 0, USED_CHANNELS_RGBA); ERR_FAIL_COND_V(is_compressed(), USED_CHANNELS_RGBA); @@ -3132,6 +3152,8 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pixelv", "point", "color"), &Image::set_pixelv); ClassDB::bind_method(D_METHOD("set_pixel", "x", "y", "color"), &Image::set_pixel); + ClassDB::bind_method(D_METHOD("adjust_bcs", "brightness", "contrast", "saturation"), &Image::adjust_bcs); + ClassDB::bind_method(D_METHOD("load_png_from_buffer", "buffer"), &Image::load_png_from_buffer); ClassDB::bind_method(D_METHOD("load_jpg_from_buffer", "buffer"), &Image::load_jpg_from_buffer); ClassDB::bind_method(D_METHOD("load_webp_from_buffer", "buffer"), &Image::load_webp_from_buffer); diff --git a/core/io/image.h b/core/io/image.h index b894be7df4..df8f9b35a1 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -390,6 +390,8 @@ public: void set_pixelv(const Point2i &p_point, const Color &p_color); void set_pixel(int p_x, int p_y, const Color &p_color); + void adjust_bcs(float p_brightness, float p_contrast, float p_saturation); + void set_as_black(); void copy_internals_from(const Ref<Image> &p_image) { diff --git a/core/math/transform.h b/core/math/transform.h index 60da6f5593..1c05dbe554 100644 --- a/core/math/transform.h +++ b/core/math/transform.h @@ -51,8 +51,8 @@ public: void rotate(const Vector3 &p_axis, real_t p_phi); void rotate_basis(const Vector3 &p_axis, real_t p_phi); - void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up); - Transform looking_at(const Vector3 &p_target, const Vector3 &p_up) const; + void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; void scale(const Vector3 &p_scale); Transform scaled(const Vector3 &p_scale) const; diff --git a/core/math/vector3.h b/core/math/vector3.h index 6b4ff3f9a8..377581bb45 100644 --- a/core/math/vector3.h +++ b/core/math/vector3.h @@ -110,6 +110,7 @@ struct Vector3 { _FORCE_INLINE_ Vector3 project(const Vector3 &p_to) const; _FORCE_INLINE_ real_t angle_to(const Vector3 &p_to) const; + _FORCE_INLINE_ real_t signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const; _FORCE_INLINE_ Vector3 direction_to(const Vector3 &p_to) const; _FORCE_INLINE_ Vector3 slide(const Vector3 &p_normal) const; @@ -230,6 +231,13 @@ real_t Vector3::angle_to(const Vector3 &p_to) const { return Math::atan2(cross(p_to).length(), dot(p_to)); } +real_t Vector3::signed_angle_to(const Vector3 &p_to, const Vector3 &p_axis) const { + Vector3 cross_to = cross(p_to); + real_t unsigned_angle = Math::atan2(cross_to.length(), dot(p_to)); + real_t sign = cross_to.dot(p_axis); + return (sign < 0) ? -unsigned_angle : unsigned_angle; +} + Vector3 Vector3::direction_to(const Vector3 &p_to) const { Vector3 ret(p_to.x - x, p_to.y - y, p_to.z - z); ret.normalize(); diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index d0636e8b84..42fb0a0caf 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -275,6 +275,14 @@ void ScriptServer::save_global_classes() { gcarr.push_back(d); } + Array old; + if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { + old = ProjectSettings::get_singleton()->get("_global_script_classes"); + } + if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) { + return; + } + if (gcarr.is_empty()) { if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) { ProjectSettings::get_singleton()->clear("_global_script_classes"); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 8f2cba138b..54ca1a911d 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1059,6 +1059,7 @@ static void _register_variant_builtin_methods() { bind_method(Vector3, min_axis, sarray(), varray()); bind_method(Vector3, max_axis, sarray(), varray()); bind_method(Vector3, angle_to, sarray("to"), varray()); + bind_method(Vector3, signed_angle_to, sarray("to", "axis"), varray()); bind_method(Vector3, direction_to, sarray("b"), varray()); bind_method(Vector3, distance_to, sarray("b"), varray()); bind_method(Vector3, distance_squared_to, sarray("b"), varray()); @@ -1256,7 +1257,7 @@ static void _register_variant_builtin_methods() { bind_method(Transform, rotated, sarray("axis", "phi"), varray()); bind_method(Transform, scaled, sarray("scale"), varray()); bind_method(Transform, translated, sarray("offset"), varray()); - bind_method(Transform, looking_at, sarray("target", "up"), varray()); + bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform, is_equal_approx, sarray("xform"), varray()); |