summaryrefslogtreecommitdiff
path: root/scene/2d
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d')
-rw-r--r--scene/2d/animated_sprite.cpp9
-rw-r--r--scene/2d/animated_sprite.h16
-rw-r--r--scene/2d/area_2d.cpp54
-rw-r--r--scene/2d/area_2d.h10
-rw-r--r--scene/2d/audio_stream_player_2d.cpp463
-rw-r--r--scene/2d/audio_stream_player_2d.h96
-rw-r--r--scene/2d/camera_2d.cpp132
-rw-r--r--scene/2d/camera_2d.h13
-rw-r--r--scene/2d/canvas_item.cpp267
-rw-r--r--scene/2d/canvas_item.h106
-rw-r--r--scene/2d/collision_object_2d.cpp339
-rw-r--r--scene/2d/collision_object_2d.h62
-rw-r--r--scene/2d/collision_polygon_2d.cpp186
-rw-r--r--scene/2d/collision_polygon_2d.h32
-rw-r--r--scene/2d/collision_shape_2d.cpp176
-rw-r--r--scene/2d/collision_shape_2d.h26
-rw-r--r--scene/2d/line_2d.cpp3
-rw-r--r--scene/2d/particles_2d.cpp1191
-rw-r--r--scene/2d/particles_2d.h251
-rw-r--r--scene/2d/physics_body_2d.cpp452
-rw-r--r--scene/2d/physics_body_2d.h86
-rw-r--r--scene/2d/sprite.cpp41
-rw-r--r--scene/2d/sprite.h8
-rw-r--r--scene/2d/tile_map.cpp19
24 files changed, 2050 insertions, 1988 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index eba638b0f5..a1ab51b3c8 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -30,7 +30,8 @@
#include "animated_sprite.h"
#include "os/os.h"
#include "scene/scene_string_names.h"
-#include "scene/scene_string_names.h"
+
+#define NORMAL_SUFFIX "_normal"
////////////////////////////
@@ -82,6 +83,7 @@ void SpriteFrames::add_animation(const StringName &p_anim) {
ERR_FAIL_COND(animations.has(p_anim));
animations[p_anim] = Anim();
+ animations[p_anim].normal_name = String(p_anim) + NORMAL_SUFFIX;
}
bool SpriteFrames::has_animation(const StringName &p_anim) const {
@@ -101,6 +103,7 @@ void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &
Anim anim = animations[p_prev];
animations.erase(p_prev);
animations[p_next] = anim;
+ animations[p_next].normal_name = String(p_next) + NORMAL_SUFFIX;
}
Vector<String> SpriteFrames::_get_animation_list() const {
@@ -374,6 +377,8 @@ void AnimatedSprite::_notification(int p_what) {
return;
}
+ Ref<Texture> normal = frames->get_normal_frame(animation, frame);
+
//print_line("DECIDED TO DRAW");
RID ci = get_canvas_item();
@@ -400,7 +405,7 @@ void AnimatedSprite::_notification(int p_what) {
dst_rect.size.y = -dst_rect.size.y;
//texture->draw_rect(ci,dst_rect,false,modulate);
- texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()));
+ texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), Color(1, 1, 1), false, normal);
//VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate);
} break;
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index 64794b0ca3..80defac079 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -47,6 +47,8 @@ class SpriteFrames : public Resource {
loop = true;
speed = 5;
}
+
+ StringName normal_name;
};
Map<StringName, Anim> animations;
@@ -89,6 +91,20 @@ public:
return E->get().frames[p_idx];
}
+ _FORCE_INLINE_ Ref<Texture> get_normal_frame(const StringName &p_anim, int p_idx) const {
+
+ const Map<StringName, Anim>::Element *E = animations.find(p_anim);
+ ERR_FAIL_COND_V(!E, Ref<Texture>());
+ ERR_FAIL_COND_V(p_idx < 0, Ref<Texture>());
+
+ const Map<StringName, Anim>::Element *EN = animations.find(E->get().normal_name);
+
+ if (!EN || p_idx >= EN->get().frames.size())
+ return Ref<Texture>();
+
+ return EN->get().frames[p_idx];
+ }
+
void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture> &p_frame) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
ERR_FAIL_COND(!E);
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index aca7a8c736..db22a38cec 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -29,7 +29,9 @@
/*************************************************************************/
#include "area_2d.h"
#include "scene/scene_string_names.h"
+#include "servers/audio_server.h"
#include "servers/physics_2d_server.h"
+
void Area2D::set_space_override_mode(SpaceOverride p_mode) {
space_override = p_mode;
@@ -542,6 +544,47 @@ bool Area2D::get_collision_layer_bit(int p_bit) const {
return get_collision_layer() & (1 << p_bit);
}
+void Area2D::set_audio_bus_override(bool p_override) {
+
+ audio_bus_override = p_override;
+}
+
+bool Area2D::is_overriding_audio_bus() const {
+
+ return audio_bus_override;
+}
+
+void Area2D::set_audio_bus(const StringName &p_audio_bus) {
+
+ audio_bus = p_audio_bus;
+}
+
+StringName Area2D::get_audio_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == audio_bus) {
+ return audio_bus;
+ }
+ }
+ return "Master";
+}
+
+void Area2D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "audio_bus_name") {
+
+ String options;
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (i > 0)
+ options += ",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options += name;
+ }
+
+ property.hint_string = options;
+ }
+}
+
void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_body_enter_tree", "id"), &Area2D::_body_enter_tree);
@@ -598,6 +641,12 @@ void Area2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("overlaps_body", "body"), &Area2D::overlaps_body);
ClassDB::bind_method(D_METHOD("overlaps_area", "area"), &Area2D::overlaps_area);
+ ClassDB::bind_method(D_METHOD("set_audio_bus", "name"), &Area2D::set_audio_bus);
+ ClassDB::bind_method(D_METHOD("get_audio_bus"), &Area2D::get_audio_bus);
+
+ ClassDB::bind_method(D_METHOD("set_audio_bus_override", "enable"), &Area2D::set_audio_bus_override);
+ ClassDB::bind_method(D_METHOD("is_overriding_audio_bus"), &Area2D::is_overriding_audio_bus);
+
ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout);
ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout);
@@ -624,6 +673,10 @@ void Area2D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
+
+ ADD_GROUP("Audio Bus", "audio_bus_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "audio_bus_name", PROPERTY_HINT_ENUM, ""), "set_audio_bus", "get_audio_bus");
}
Area2D::Area2D()
@@ -642,6 +695,7 @@ Area2D::Area2D()
monitorable = false;
collision_mask = 1;
collision_layer = 1;
+ audio_bus_override = false;
set_monitoring(true);
set_monitorable(true);
}
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index f0eb1e9240..12d71f3911 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -126,9 +126,13 @@ private:
Map<ObjectID, AreaState> area_map;
void _clear_monitoring();
+ bool audio_bus_override;
+ StringName audio_bus;
+
protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
public:
void set_space_override_mode(SpaceOverride p_mode);
@@ -179,6 +183,12 @@ public:
bool overlaps_area(Node *p_area) const;
bool overlaps_body(Node *p_body) const;
+ void set_audio_bus_override(bool p_override);
+ bool is_overriding_audio_bus() const;
+
+ void set_audio_bus(const StringName &p_audio_bus);
+ StringName get_audio_bus() const;
+
Area2D();
~Area2D();
};
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
new file mode 100644
index 0000000000..cef473dcdf
--- /dev/null
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -0,0 +1,463 @@
+
+#include "audio_stream_player_2d.h"
+#include "scene/2d/area_2d.h"
+#include "scene/main/viewport.h"
+void AudioStreamPlayer2D::_mix_audio() {
+
+ if (!stream_playback.is_valid()) {
+ return;
+ }
+
+ if (!active) {
+ return;
+ }
+
+ if (setseek >= 0.0) {
+ stream_playback->start(setseek);
+ setseek = -1.0; //reset seek
+ }
+
+ //get data
+ AudioFrame *buffer = mix_buffer.ptr();
+ int buffer_size = mix_buffer.size();
+
+ //mix
+ stream_playback->mix(buffer, 1.0, buffer_size);
+
+ //write all outputs
+ for (int i = 0; i < output_count; i++) {
+
+ Output current = outputs[i];
+
+ //see if current output exists, to keep volume ramp
+ bool found = false;
+ for (int j = i; j < prev_output_count; j++) {
+ if (prev_outputs[j].viewport == current.viewport) {
+ if (j != i) {
+ SWAP(prev_outputs[j], prev_outputs[i]);
+ }
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ //create new if was not used before
+ if (prev_output_count < MAX_OUTPUTS) {
+ prev_outputs[prev_output_count] = prev_outputs[i]; //may be owned by another viewport
+ prev_output_count++;
+ }
+ prev_outputs[i] = current;
+ }
+
+ //mix!
+ AudioFrame vol_inc = (current.vol - prev_outputs[i].vol) / float(buffer_size);
+ AudioFrame vol = current.vol;
+
+ switch (AudioServer::get_singleton()->get_speaker_mode()) {
+
+ case AudioServer::SPEAKER_MODE_STEREO: {
+ AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 0);
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ target[j] += buffer[j] * vol;
+ vol += vol_inc;
+ }
+
+ } break;
+ case AudioServer::SPEAKER_SURROUND_51: {
+
+ AudioFrame *targets[2] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 2),
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] += frame;
+ targets[1][j] += frame;
+ vol += vol_inc;
+ }
+
+ } break;
+ case AudioServer::SPEAKER_SURROUND_71: {
+
+ AudioFrame *targets[3] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 2),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(current.bus_index, 3)
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] += frame;
+ targets[1][j] += frame;
+ targets[2][j] += frame;
+ vol += vol_inc;
+ }
+
+ } break;
+ }
+
+ prev_outputs[i] = current;
+ }
+
+ prev_output_count = output_count;
+
+ //stream is no longer active, disable this.
+ if (!stream_playback->is_playing()) {
+ active = false;
+ }
+
+ output_ready = false;
+}
+
+void AudioStreamPlayer2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ AudioServer::get_singleton()->add_callback(_mix_audios, this);
+ if (autoplay && !get_tree()->is_editor_hint()) {
+ play();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+
+ AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+ }
+
+ if (p_what == NOTIFICATION_INTERNAL_FIXED_PROCESS) {
+
+ //update anything related to position first, if possible of course
+
+ if (!output_ready) {
+ List<Viewport *> viewports;
+ Ref<World2D> world_2d = get_world_2d();
+ ERR_FAIL_COND(world_2d.is_null());
+
+ int new_output_count = 0;
+
+ Vector2 global_pos = get_global_position();
+
+ int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+
+ //check if any area is diverting sound into a bus
+
+ Physics2DDirectSpaceState *space_state = Physics2DServer::get_singleton()->space_get_direct_state(world_2d->get_space());
+
+ Physics2DDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
+
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, Physics2DDirectSpaceState::TYPE_MASK_AREA);
+
+ for (int i = 0; i < areas; i++) {
+ if (!sr[i].collider)
+ continue;
+
+ Area2D *area2d = sr[i].collider->cast_to<Area2D>();
+ if (!area2d)
+ continue;
+
+ if (!area2d->is_overriding_audio_bus())
+ continue;
+
+ StringName bus_name = area2d->get_audio_bus();
+ bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus_name);
+ break;
+ }
+
+ world_2d->get_viewport_list(&viewports);
+ for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) {
+
+ Viewport *vp = E->get();
+ if (vp->is_audio_listener_2d()) {
+
+ //compute matrix to convert to screen
+ Transform2D to_screen = vp->get_global_canvas_transform() * vp->get_canvas_transform();
+ Vector2 screen_size = vp->get_visible_rect().size;
+
+ //screen in global is used for attenuation
+ Vector2 screen_in_global = to_screen.affine_inverse().xform(screen_size * 0.5);
+
+ float dist = global_pos.distance_to(screen_in_global); //distance to screen center
+
+ if (dist > max_distance)
+ continue; //cant hear this sound in this viewport
+
+ float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
+ multiplier *= Math::db2linear(volume_db); //also apply player volume!
+
+ //point in screen is used for panning
+ Vector2 point_in_screen = to_screen.xform(global_pos);
+
+ float pan = CLAMP(point_in_screen.x / screen_size.width, 0.0, 1.0);
+
+ float l = 1.0 - pan;
+ float r = pan;
+
+ outputs[new_output_count].vol = AudioFrame(l, r) * multiplier;
+ outputs[new_output_count].bus_index = bus_index;
+ outputs[new_output_count].viewport = vp; //keep pointer only for reference
+ new_output_count++;
+ if (new_output_count == MAX_OUTPUTS)
+ break;
+ }
+ }
+
+ output_count = new_output_count;
+ output_ready = true;
+ }
+
+ //start playing if requested
+ if (setplay >= 0.0) {
+ setseek = setplay;
+ active = true;
+ setplay = -1;
+ _change_notify("playing"); //update property in editor
+ }
+
+ //stop playing if no longer active
+ if (!active) {
+ set_fixed_process_internal(false);
+ _change_notify("playing"); //update property in editor
+ }
+ }
+}
+
+void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
+
+ ERR_FAIL_COND(!p_stream.is_valid());
+ AudioServer::get_singleton()->lock();
+
+ mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+
+ if (stream_playback.is_valid()) {
+ stream_playback.unref();
+ stream.unref();
+ active = false;
+ setseek = -1;
+ }
+
+ stream = p_stream;
+ stream_playback = p_stream->instance_playback();
+
+ if (stream_playback.is_null()) {
+ stream.unref();
+ ERR_FAIL_COND(stream_playback.is_null());
+ }
+
+ AudioServer::get_singleton()->unlock();
+}
+
+Ref<AudioStream> AudioStreamPlayer2D::get_stream() const {
+
+ return stream;
+}
+
+void AudioStreamPlayer2D::set_volume_db(float p_volume) {
+
+ volume_db = p_volume;
+}
+float AudioStreamPlayer2D::get_volume_db() const {
+
+ return volume_db;
+}
+
+void AudioStreamPlayer2D::play(float p_from_pos) {
+
+ if (stream_playback.is_valid()) {
+ setplay = p_from_pos;
+ output_ready = false;
+ set_fixed_process_internal(true);
+ }
+}
+
+void AudioStreamPlayer2D::seek(float p_seconds) {
+
+ if (stream_playback.is_valid()) {
+ setseek = p_seconds;
+ }
+}
+
+void AudioStreamPlayer2D::stop() {
+
+ if (stream_playback.is_valid()) {
+ active = false;
+ set_fixed_process_internal(false);
+ setplay = -1;
+ }
+}
+
+bool AudioStreamPlayer2D::is_playing() const {
+
+ if (stream_playback.is_valid()) {
+ return active; // && stream_playback->is_playing();
+ }
+
+ return false;
+}
+
+float AudioStreamPlayer2D::get_pos() {
+
+ if (stream_playback.is_valid()) {
+ return stream_playback->get_pos();
+ }
+
+ return 0;
+}
+
+void AudioStreamPlayer2D::set_bus(const StringName &p_bus) {
+
+ //if audio is active, must lock this
+ AudioServer::get_singleton()->lock();
+ bus = p_bus;
+ AudioServer::get_singleton()->unlock();
+}
+StringName AudioStreamPlayer2D::get_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == bus) {
+ return bus;
+ }
+ }
+ return "Master";
+}
+
+void AudioStreamPlayer2D::set_autoplay(bool p_enable) {
+
+ autoplay = p_enable;
+}
+bool AudioStreamPlayer2D::is_autoplay_enabled() {
+
+ return autoplay;
+}
+
+void AudioStreamPlayer2D::_set_playing(bool p_enable) {
+
+ if (p_enable)
+ play();
+ else
+ stop();
+}
+bool AudioStreamPlayer2D::_is_active() const {
+
+ return active;
+}
+
+void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "bus") {
+
+ String options;
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (i > 0)
+ options += ",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options += name;
+ }
+
+ property.hint_string = options;
+ }
+}
+
+void AudioStreamPlayer2D::_bus_layout_changed() {
+
+ _change_notify();
+}
+
+void AudioStreamPlayer2D::set_max_distance(float p_pixels) {
+
+ ERR_FAIL_COND(p_pixels <= 0.0);
+ max_distance = p_pixels;
+}
+
+float AudioStreamPlayer2D::get_max_distance() const {
+
+ return max_distance;
+}
+
+void AudioStreamPlayer2D::set_attenuation(float p_curve) {
+
+ attenuation = p_curve;
+}
+float AudioStreamPlayer2D::get_attenuation() const {
+
+ return attenuation;
+}
+
+void AudioStreamPlayer2D::set_area_mask(uint32_t p_mask) {
+
+ area_mask = p_mask;
+}
+
+uint32_t AudioStreamPlayer2D::get_area_mask() const {
+
+ return area_mask;
+}
+
+void AudioStreamPlayer2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_stream", "stream:AudioStream"), &AudioStreamPlayer2D::set_stream);
+ ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream);
+
+ ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer2D::set_volume_db);
+ ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer2D::get_volume_db);
+
+ ClassDB::bind_method(D_METHOD("play", "from_pos"), &AudioStreamPlayer2D::play, DEFVAL(0.0));
+ ClassDB::bind_method(D_METHOD("seek", "to_pos"), &AudioStreamPlayer2D::seek);
+ ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop);
+
+ ClassDB::bind_method(D_METHOD("is_playing"), &AudioStreamPlayer2D::is_playing);
+ ClassDB::bind_method(D_METHOD("get_pos"), &AudioStreamPlayer2D::get_pos);
+
+ ClassDB::bind_method(D_METHOD("set_bus", "bus"), &AudioStreamPlayer2D::set_bus);
+ ClassDB::bind_method(D_METHOD("get_bus"), &AudioStreamPlayer2D::get_bus);
+
+ ClassDB::bind_method(D_METHOD("set_autoplay", "enable"), &AudioStreamPlayer2D::set_autoplay);
+ ClassDB::bind_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer2D::is_autoplay_enabled);
+
+ ClassDB::bind_method(D_METHOD("_set_playing", "enable"), &AudioStreamPlayer2D::_set_playing);
+ ClassDB::bind_method(D_METHOD("_is_active"), &AudioStreamPlayer2D::_is_active);
+
+ ClassDB::bind_method(D_METHOD("set_max_distance", "pixels"), &AudioStreamPlayer2D::set_max_distance);
+ ClassDB::bind_method(D_METHOD("get_max_distance"), &AudioStreamPlayer2D::get_max_distance);
+
+ ClassDB::bind_method(D_METHOD("set_attenuation", "curve"), &AudioStreamPlayer2D::set_attenuation);
+ ClassDB::bind_method(D_METHOD("get_attenuation"), &AudioStreamPlayer2D::get_attenuation);
+
+ ClassDB::bind_method(D_METHOD("set_area_mask", "mask"), &AudioStreamPlayer2D::set_area_mask);
+ ClassDB::bind_method(D_METHOD("get_area_mask"), &AudioStreamPlayer2D::get_area_mask);
+
+ ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "_is_active");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
+}
+
+AudioStreamPlayer2D::AudioStreamPlayer2D() {
+
+ volume_db = 0;
+ autoplay = false;
+ setseek = -1;
+ active = false;
+ output_count = 0;
+ prev_output_count = 0;
+ max_distance = 2000;
+ attenuation = 1;
+ setplay = -1;
+ output_ready = false;
+ area_mask = 1;
+ AudioServer::get_singleton()->connect("bus_layout_changed", this, "_bus_layout_changed");
+}
+
+AudioStreamPlayer2D::~AudioStreamPlayer2D() {
+}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
new file mode 100644
index 0000000000..25eff61b76
--- /dev/null
+++ b/scene/2d/audio_stream_player_2d.h
@@ -0,0 +1,96 @@
+#ifndef AUDIO_STREAM_PLAYER_2D_H
+#define AUDIO_STREAM_PLAYER_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "servers/audio/audio_stream.h"
+#include "servers/audio_server.h"
+
+class AudioStreamPlayer2D : public Node2D {
+
+ GDCLASS(AudioStreamPlayer2D, Node2D)
+
+private:
+ enum {
+ MAX_OUTPUTS = 8,
+ MAX_INTERSECT_AREAS = 32
+
+ };
+
+ struct Output {
+
+ AudioFrame vol;
+ int bus_index;
+ Viewport *viewport; //pointer only used for reference to previous mix
+ };
+
+ Output outputs[MAX_OUTPUTS];
+ volatile int output_count;
+ volatile bool output_ready;
+
+ //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks)
+ Output prev_outputs[MAX_OUTPUTS];
+ int prev_output_count;
+
+ Ref<AudioStreamPlayback> stream_playback;
+ Ref<AudioStream> stream;
+ Vector<AudioFrame> mix_buffer;
+
+ volatile float setseek;
+ volatile bool active;
+ volatile float setplay;
+
+ float volume_db;
+ bool autoplay;
+ StringName bus;
+
+ void _mix_audio();
+ static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_mix_audio(); }
+
+ void _set_playing(bool p_enable);
+ bool _is_active() const;
+
+ void _bus_layout_changed();
+
+ uint32_t area_mask;
+
+ float max_distance;
+ float attenuation;
+
+protected:
+ void _validate_property(PropertyInfo &property) const;
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_stream(Ref<AudioStream> p_stream);
+ Ref<AudioStream> get_stream() const;
+
+ void set_volume_db(float p_volume);
+ float get_volume_db() const;
+
+ void play(float p_from_pos = 0.0);
+ void seek(float p_seconds);
+ void stop();
+ bool is_playing() const;
+ float get_pos();
+
+ void set_bus(const StringName &p_bus);
+ StringName get_bus() const;
+
+ void set_autoplay(bool p_enable);
+ bool is_autoplay_enabled();
+
+ void set_max_distance(float p_pixels);
+ float get_max_distance() const;
+
+ void set_attenuation(float p_curve);
+ float get_attenuation() const;
+
+ void set_area_mask(uint32_t p_mask);
+ uint32_t get_area_mask() const;
+
+ AudioStreamPlayer2D();
+ ~AudioStreamPlayer2D();
+};
+
+#endif
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 9d8b5da366..908c95b50c 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -199,10 +199,8 @@ Transform2D Camera2D::get_camera_transform() {
/*
if (0) {
-
xform = get_global_transform() * xform;
} else {
-
xform.elements[2]+=get_global_transform().get_origin();
}
*/
@@ -267,25 +265,76 @@ void Camera2D::_notification(int p_what) {
if (!is_inside_tree() || !get_tree()->is_editor_hint())
break;
- Color area_axis_color(0.5, 0.42, 0.87, 0.63);
- float area_axis_width = 1;
- if (current)
- area_axis_width = 3;
+ if (screen_drawing_enabled) {
+ Color area_axis_color(0.5, 0.42, 0.87, 0.63);
+ float area_axis_width = 1;
+ if (is_current()) {
+ area_axis_width = 3;
+ area_axis_color.a = 0.83;
+ }
- Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
- Size2 screen_size = get_viewport_rect().size;
+ Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
+ Size2 screen_size = get_viewport_rect().size;
- Vector2 screen_endpoints[4] = {
- inv_camera_transform.xform(Vector2(0, 0)),
- inv_camera_transform.xform(Vector2(screen_size.width, 0)),
- inv_camera_transform.xform(Vector2(screen_size.width, screen_size.height)),
- inv_camera_transform.xform(Vector2(0, screen_size.height))
- };
+ Vector2 screen_endpoints[4] = {
+ inv_camera_transform.xform(Vector2(0, 0)),
+ inv_camera_transform.xform(Vector2(screen_size.width, 0)),
+ inv_camera_transform.xform(Vector2(screen_size.width, screen_size.height)),
+ inv_camera_transform.xform(Vector2(0, screen_size.height))
+ };
- Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space
+ Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space
- for (int i = 0; i < 4; i++) {
- draw_line(inv_transform.xform(screen_endpoints[i]), inv_transform.xform(screen_endpoints[(i + 1) % 4]), area_axis_color, area_axis_width);
+ for (int i = 0; i < 4; i++) {
+ draw_line(inv_transform.xform(screen_endpoints[i]), inv_transform.xform(screen_endpoints[(i + 1) % 4]), area_axis_color, area_axis_width);
+ }
+ }
+
+ if (limit_drawing_enabled) {
+ Color limit_drawing_color(1, 1, 0, 0.63);
+ float limit_drawing_width = 1;
+ if (is_current()) {
+ limit_drawing_color.a = 0.83;
+ limit_drawing_width = 3;
+ }
+
+ Vector2 camera_origin = get_global_transform().get_origin();
+ Vector2 camera_scale = get_global_transform().get_scale().abs();
+ Vector2 limit_points[4] = {
+ (Vector2(limit[MARGIN_LEFT], limit[MARGIN_TOP]) - camera_origin) / camera_scale,
+ (Vector2(limit[MARGIN_RIGHT], limit[MARGIN_TOP]) - camera_origin) / camera_scale,
+ (Vector2(limit[MARGIN_RIGHT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale,
+ (Vector2(limit[MARGIN_LEFT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale
+ };
+
+ for (int i = 0; i < 4; i++) {
+ draw_line(limit_points[i], limit_points[(i + 1) % 4], limit_drawing_color, limit_drawing_width);
+ }
+ }
+
+ if (margin_drawing_enabled) {
+ Color margin_drawing_color(0, 1, 1, 0.63);
+ float margin_drawing_width = 1;
+ if (is_current()) {
+ margin_drawing_width = 3;
+ margin_drawing_color.a = 0.83;
+ }
+
+ Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
+ Size2 screen_size = get_viewport_rect().size;
+
+ Vector2 margin_endpoints[4] = {
+ inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
+ inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
+ inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[MARGIN_BOTTOM]))),
+ inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[MARGIN_BOTTOM])))
+ };
+
+ Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space
+
+ for (int i = 0; i < 4; i++) {
+ draw_line(inv_transform.xform(margin_endpoints[i]), inv_transform.xform(margin_endpoints[(i + 1) % 4]), margin_drawing_color, margin_drawing_width);
+ }
}
} break;
@@ -330,7 +379,6 @@ void Camera2D::_make_current(Object *p_which) {
if (p_which == this) {
current = true;
- _update_scroll();
} else {
current = false;
}
@@ -342,6 +390,7 @@ void Camera2D::_set_current(bool p_current) {
make_current();
current = p_current;
+ update();
}
bool Camera2D::is_current() const {
@@ -370,6 +419,7 @@ void Camera2D::set_limit(Margin p_margin, int p_limit) {
ERR_FAIL_INDEX(p_margin, 4);
limit[p_margin] = p_limit;
+ update();
}
int Camera2D::get_limit(Margin p_margin) const {
@@ -393,6 +443,7 @@ void Camera2D::set_drag_margin(Margin p_margin, float p_drag_margin) {
ERR_FAIL_INDEX(p_margin, 4);
drag_margin[p_margin] = p_drag_margin;
+ update();
}
float Camera2D::get_drag_margin(Margin p_margin) const {
@@ -554,6 +605,33 @@ Node *Camera2D::get_custom_viewport() const {
return custom_viewport;
}
+void Camera2D::set_screen_drawing_enabled(bool enable) {
+ screen_drawing_enabled = enable;
+ update();
+}
+
+bool Camera2D::is_screen_drawing_enabled() const {
+ return screen_drawing_enabled;
+}
+
+void Camera2D::set_limit_drawing_enabled(bool enable) {
+ limit_drawing_enabled = enable;
+ update();
+}
+
+bool Camera2D::is_limit_drawing_enabled() const {
+ return limit_drawing_enabled;
+}
+
+void Camera2D::set_margin_drawing_enabled(bool enable) {
+ margin_drawing_enabled = enable;
+ update();
+}
+
+bool Camera2D::is_margin_drawing_enabled() const {
+ return margin_drawing_enabled;
+}
+
void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Camera2D::set_offset);
@@ -616,6 +694,15 @@ void Camera2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_old_smoothing", "follow_smoothing"), &Camera2D::_set_old_smoothing);
+ ClassDB::bind_method(D_METHOD("set_screen_drawing_enabled", "screen_drawing_enabled"), &Camera2D::set_screen_drawing_enabled);
+ ClassDB::bind_method(D_METHOD("is_screen_drawing_enabled"), &Camera2D::is_screen_drawing_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_limit_drawing_enabled", "limit_drawing_enabled"), &Camera2D::set_limit_drawing_enabled);
+ ClassDB::bind_method(D_METHOD("is_limit_drawing_enabled"), &Camera2D::is_limit_drawing_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_margin_drawing_enabled", "margin_drawing_enabled"), &Camera2D::set_margin_drawing_enabled);
+ ClassDB::bind_method(D_METHOD("is_margin_drawing_enabled"), &Camera2D::is_margin_drawing_enabled);
+
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_mode", PROPERTY_HINT_ENUM, "Fixed TopLeft,Drag Center"), "set_anchor_mode", "get_anchor_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
@@ -643,6 +730,11 @@ void Camera2D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "drag_margin_right", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_RIGHT);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "drag_margin_bottom", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_BOTTOM);
+ ADD_GROUP("Editor", "editor_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_draw_screen"), "set_screen_drawing_enabled", "is_screen_drawing_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_draw_limits"), "set_limit_drawing_enabled", "is_limit_drawing_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_draw_drag_margin"), "set_margin_drawing_enabled", "is_margin_drawing_enabled");
+
BIND_CONSTANT(ANCHOR_MODE_DRAG_CENTER);
BIND_CONSTANT(ANCHOR_MODE_FIXED_TOP_LEFT);
}
@@ -671,6 +763,10 @@ Camera2D::Camera2D() {
smoothing = 5.0;
zoom = Vector2(1, 1);
+ screen_drawing_enabled = true;
+ limit_drawing_enabled = false;
+ margin_drawing_enabled = false;
+
h_drag_enabled = true;
v_drag_enabled = true;
h_ofs = 0;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 686f40bedf..8d9e76be85 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -79,6 +79,10 @@ protected:
void _set_old_smoothing(float p_enable);
+ bool screen_drawing_enabled;
+ bool limit_drawing_enabled;
+ bool margin_drawing_enabled;
+
protected:
virtual Transform2D get_camera_transform();
void _notification(int p_what);
@@ -138,6 +142,15 @@ public:
void reset_smoothing();
void align();
+ void set_screen_drawing_enabled(bool enable);
+ bool is_screen_drawing_enabled() const;
+
+ void set_limit_drawing_enabled(bool enable);
+ bool is_limit_drawing_enabled() const;
+
+ void set_margin_drawing_enabled(bool enable);
+ bool is_margin_drawing_enabled() const;
+
Camera2D();
};
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index b2258ec94b..4a80aba355 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "canvas_item.h"
+#include "core/method_bind_ext.gen.inc"
#include "message_queue.h"
#include "os/input.h"
#include "scene/main/canvas_layer.h"
@@ -38,6 +39,196 @@
#include "scene/scene_string_names.h"
#include "servers/visual_server.h"
+Mutex *CanvasItemMaterial::material_mutex = NULL;
+SelfList<CanvasItemMaterial>::List CanvasItemMaterial::dirty_materials;
+Map<CanvasItemMaterial::MaterialKey, CanvasItemMaterial::ShaderData> CanvasItemMaterial::shader_map;
+
+void CanvasItemMaterial::init_shaders() {
+
+#ifndef NO_THREADS
+ material_mutex = Mutex::create();
+#endif
+}
+
+void CanvasItemMaterial::finish_shaders() {
+
+#ifndef NO_THREADS
+ memdelete(material_mutex);
+#endif
+}
+
+void CanvasItemMaterial::_update_shader() {
+
+ dirty_materials.remove(&element);
+
+ MaterialKey mk = _compute_key();
+ if (mk.key == current_key.key)
+ return; //no update required in the end
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ VS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+ }
+
+ current_key = mk;
+
+ if (shader_map.has(mk)) {
+
+ VS::get_singleton()->material_set_shader(_get_material(), shader_map[mk].shader);
+ shader_map[mk].users++;
+ return;
+ }
+
+ //must create a shader!
+
+ String code = "shader_type canvas_item;\nrender_mode ";
+ switch (blend_mode) {
+ case BLEND_MODE_MIX: code += "blend_mix"; break;
+ case BLEND_MODE_ADD: code += "blend_add"; break;
+ case BLEND_MODE_SUB: code += "blend_sub"; break;
+ case BLEND_MODE_MUL: code += "blend_mul"; break;
+ case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
+ }
+
+ switch (light_mode) {
+ case LIGHT_MODE_NORMAL: break;
+ case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
+ case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
+ }
+ code += ";\n"; //thats it.
+
+ ShaderData shader_data;
+ shader_data.shader = VS::get_singleton()->shader_create();
+ shader_data.users = 1;
+
+ VS::get_singleton()->shader_set_code(shader_data.shader, code);
+
+ shader_map[mk] = shader_data;
+
+ VS::get_singleton()->material_set_shader(_get_material(), shader_data.shader);
+}
+
+void CanvasItemMaterial::flush_changes() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ while (dirty_materials.first()) {
+
+ dirty_materials.first()->self()->_update_shader();
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
+}
+
+void CanvasItemMaterial::_queue_shader_change() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ if (!element.in_list()) {
+ dirty_materials.add(&element);
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
+}
+
+bool CanvasItemMaterial::_is_shader_dirty() const {
+
+ bool dirty = false;
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ dirty = element.in_list();
+
+ if (material_mutex)
+ material_mutex->unlock();
+
+ return dirty;
+}
+void CanvasItemMaterial::set_blend_mode(BlendMode p_blend_mode) {
+
+ blend_mode = p_blend_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::BlendMode CanvasItemMaterial::get_blend_mode() const {
+ return blend_mode;
+}
+
+void CanvasItemMaterial::set_light_mode(LightMode p_light_mode) {
+
+ light_mode = p_light_mode;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const {
+
+ return light_mode;
+}
+
+void CanvasItemMaterial::_validate_property(PropertyInfo &property) const {
+}
+
+void CanvasItemMaterial::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_blend_mode", "blend_mode"), &CanvasItemMaterial::set_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_mode"), &CanvasItemMaterial::get_blend_mode);
+
+ ClassDB::bind_method(D_METHOD("set_light_mode", "light_mode"), &CanvasItemMaterial::set_light_mode);
+ ClassDB::bind_method(D_METHOD("get_light_mode"), &CanvasItemMaterial::get_light_mode);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,Premult Alpha"), "set_blend_mode", "get_blend_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mode", PROPERTY_HINT_ENUM, "Normal,Unshaded,Light Only"), "set_light_mode", "get_light_mode");
+
+ BIND_CONSTANT(BLEND_MODE_MIX);
+ BIND_CONSTANT(BLEND_MODE_ADD);
+ BIND_CONSTANT(BLEND_MODE_SUB);
+ BIND_CONSTANT(BLEND_MODE_MUL);
+ BIND_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
+ BIND_CONSTANT(LIGHT_MODE_NORMAL);
+ BIND_CONSTANT(LIGHT_MODE_UNSHADED);
+ BIND_CONSTANT(LIGHT_MODE_LIGHT_ONLY);
+}
+
+CanvasItemMaterial::CanvasItemMaterial()
+ : element(this) {
+
+ blend_mode = BLEND_MODE_MIX;
+ light_mode = LIGHT_MODE_NORMAL;
+
+ current_key.key = 0;
+ current_key.invalid_key = 1;
+ _queue_shader_change();
+}
+
+CanvasItemMaterial::~CanvasItemMaterial() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ VS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+
+ VS::get_singleton()->material_set_shader(_get_material(), RID());
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
+}
+
///////////////////////////////////////////////////////////////////
bool CanvasItem::is_visible_in_tree() const {
@@ -176,7 +367,9 @@ Transform2D CanvasItem::get_global_transform_with_canvas() const {
}
Transform2D CanvasItem::get_global_transform() const {
-
+#ifdef DEBUG_ENABLED
+ ERR_FAIL_COND_V(!is_inside_tree(), get_transform());
+#endif
if (global_invalid) {
const CanvasItem *pi = get_parent_item();
@@ -416,14 +609,22 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color
VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width, p_antialiased);
}
-void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color) {
+void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
- VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
+ if (p_filled) {
+
+ VisualServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
+ } else {
+ VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(p_rect.size.width, 0), p_color);
+ VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position, p_rect.position + Size2(0, p_rect.size.height), p_color);
+ VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(0, p_rect.size.height), p_rect.position + p_rect.size, p_color);
+ VisualServer::get_singleton()->canvas_item_add_line(canvas_item, p_rect.position + Point2(p_rect.size.width, 0), p_rect.position + p_rect.size, p_color);
+ }
}
void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) {
@@ -436,7 +637,7 @@ void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p
VisualServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color);
}
-void CanvasItem::draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate) {
+void CanvasItem::draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate, const Ref<Texture> &p_normal_map) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -448,7 +649,7 @@ void CanvasItem::draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos
p_texture->draw(canvas_item, p_pos, p_modulate);
}
-void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose) {
+void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -456,16 +657,16 @@ void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p
}
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose);
+ p_texture->draw_rect(canvas_item, p_rect, p_tile, p_modulate, p_transpose, p_normal_map);
}
-void CanvasItem::draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose) {
+void CanvasItem::draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
ERR_FAIL();
}
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose);
+ p_texture->draw_rect_region(canvas_item, p_rect, p_src_rect, p_modulate, p_transpose, p_normal_map, p_clip_uv);
}
void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect) {
@@ -478,7 +679,7 @@ void CanvasItem::draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p
p_style_box->draw(canvas_item, p_rect);
}
-void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture, float p_width) {
+void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture, float p_width, const Ref<Texture> &p_normal_map) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -486,8 +687,9 @@ void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Col
}
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width);
+ VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid, p_width, rid_normal);
}
void CanvasItem::draw_set_transform(const Point2 &p_offset, float p_rot, const Size2 &p_scale) {
@@ -511,7 +713,7 @@ void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) {
VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix);
}
-void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture) {
+void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture, const Ref<Texture> &p_normal_map) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -519,11 +721,12 @@ void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color
}
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid);
+ VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, p_colors, p_uvs, rid, rid_normal);
}
-void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture> p_texture) {
+void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs, Ref<Texture> p_texture, const Ref<Texture> &p_normal_map) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -533,8 +736,9 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
Vector<Color> colors;
colors.push_back(p_color);
RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID rid_normal = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid);
+ VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal);
}
void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
@@ -563,8 +767,9 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const
void CanvasItem::_notify_transform(CanvasItem *p_node) {
- if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid)
+ if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
return; //nothing to do
+ }
p_node->global_invalid = true;
@@ -653,7 +858,7 @@ bool CanvasItem::is_draw_behind_parent_enabled() const {
return behind;
}
-void CanvasItem::set_material(const Ref<ShaderMaterial> &p_material) {
+void CanvasItem::set_material(const Ref<Material> &p_material) {
material = p_material;
RID rid;
@@ -674,7 +879,7 @@ bool CanvasItem::get_use_parent_material() const {
return use_parent_material;
}
-Ref<ShaderMaterial> CanvasItem::get_material() const {
+Ref<Material> CanvasItem::get_material() const {
return material;
}
@@ -750,15 +955,15 @@ void CanvasItem::_bind_methods() {
//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color"), &CanvasItem::draw_rect);
+ ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled"), &CanvasItem::draw_rect, DEFVAL(true));
ClassDB::bind_method(D_METHOD("draw_circle", "pos", "radius", "color"), &CanvasItem::draw_circle);
- ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
- ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture:Texture", "rect", "src_rect", "modulate", "transpose"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_texture", "texture:Texture", "pos", "modulate", "normal_map:Texture"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture:Texture", "rect", "tile", "modulate", "transpose", "normal_map:Texture"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture:Texture", "rect", "src_rect", "modulate", "transpose", "normal_map:Texture", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box:StyleBox", "rect"), &CanvasItem::draw_style_box);
- ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture:Texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Variant()), DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture:Texture"), &CanvasItem::draw_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()));
- ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture:Texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture:Texture", "width", "normal_map:Texture"), &CanvasItem::draw_primitive, DEFVAL(Variant()), DEFVAL(1.0), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture:Texture", "normal_map:Texture"), &CanvasItem::draw_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture:Texture", "normal_map:Texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("draw_string", "font:Font", "pos", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("draw_char", "font:Font", "pos", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
@@ -776,8 +981,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasItem::get_world_2d);
//ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasItem::get_viewport);
- ClassDB::bind_method(D_METHOD("set_material", "material:ShaderMaterial"), &CanvasItem::set_material);
- ClassDB::bind_method(D_METHOD("get_material:ShaderMaterial"), &CanvasItem::get_material);
+ ClassDB::bind_method(D_METHOD("set_material", "material:Material"), &CanvasItem::set_material);
+ ClassDB::bind_method(D_METHOD("get_material:Material"), &CanvasItem::get_material);
ClassDB::bind_method(D_METHOD("set_use_parent_material", "enable"), &CanvasItem::set_use_parent_material);
ClassDB::bind_method(D_METHOD("get_use_parent_material"), &CanvasItem::get_use_parent_material);
@@ -803,7 +1008,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Material", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
//exporting these two things doesn't really make much sense i think
//ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ;
@@ -865,7 +1070,15 @@ bool CanvasItem::is_local_transform_notification_enabled() const {
}
void CanvasItem::set_notify_transform(bool p_enable) {
+ if (notify_transform == p_enable)
+ return;
+
notify_transform = p_enable;
+
+ if (notify_transform && is_inside_tree()) {
+ //this ensures that invalid globals get resolved, so notifications can be received
+ get_global_transform();
+ }
}
bool CanvasItem::is_transform_notification_enabled() const {
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index bea4301326..bffc171fc1 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -42,6 +42,92 @@ class Font;
class StyleBox;
+class CanvasItemMaterial : public Material {
+
+ GDCLASS(CanvasItemMaterial, Material)
+
+public:
+ enum BlendMode {
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_PREMULT_ALPHA
+ };
+
+ enum LightMode {
+ LIGHT_MODE_NORMAL,
+ LIGHT_MODE_UNSHADED,
+ LIGHT_MODE_LIGHT_ONLY
+ };
+
+private:
+ union MaterialKey {
+
+ struct {
+ uint32_t blend_mode : 4;
+ uint32_t light_mode : 4;
+ uint32_t invalid_key : 1;
+ };
+
+ uint32_t key;
+
+ bool operator<(const MaterialKey &p_key) const {
+ return key < p_key.key;
+ }
+ };
+
+ struct ShaderData {
+ RID shader;
+ int users;
+ };
+
+ static Map<MaterialKey, ShaderData> shader_map;
+
+ MaterialKey current_key;
+
+ _FORCE_INLINE_ MaterialKey _compute_key() const {
+
+ MaterialKey mk;
+ mk.key = 0;
+ mk.blend_mode = blend_mode;
+ mk.light_mode = light_mode;
+ return mk;
+ }
+
+ static Mutex *material_mutex;
+ static SelfList<CanvasItemMaterial>::List dirty_materials;
+ SelfList<CanvasItemMaterial> element;
+
+ void _update_shader();
+ _FORCE_INLINE_ void _queue_shader_change();
+ _FORCE_INLINE_ bool _is_shader_dirty() const;
+
+ BlendMode blend_mode;
+ LightMode light_mode;
+
+protected:
+ static void _bind_methods();
+ void _validate_property(PropertyInfo &property) const;
+
+public:
+ void set_blend_mode(BlendMode p_blend_mode);
+ BlendMode get_blend_mode() const;
+
+ void set_light_mode(LightMode p_light_mode);
+ LightMode get_light_mode() const;
+
+ static void init_shaders();
+ static void finish_shaders();
+ static void flush_changes();
+
+ CanvasItemMaterial();
+ virtual ~CanvasItemMaterial();
+};
+
+VARIANT_ENUM_CAST(CanvasItemMaterial::BlendMode)
+VARIANT_ENUM_CAST(CanvasItemMaterial::LightMode)
+
class CanvasItem : public Node {
GDCLASS(CanvasItem, Node);
@@ -83,7 +169,7 @@ private:
bool notify_local_transform;
bool notify_transform;
- Ref<ShaderMaterial> material;
+ Ref<Material> material;
mutable Transform2D global_transform;
mutable bool global_invalid;
@@ -156,15 +242,15 @@ public:
/* DRAWING API */
void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void draw_rect(const Rect2 &p_rect, const Color &p_color);
+ void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true);
void draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color);
- void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1));
- void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
- void draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
+ void draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1), const Ref<Texture> &p_normal_map = Ref<Texture>());
+ void draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>());
+ void draw_texture_rect_region(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true);
void draw_style_box(const Ref<StyleBox> &p_style_box, const Rect2 &p_rect);
- void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture = Ref<Texture>(), float p_width = 1);
- void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>());
- void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>());
+ void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture> p_texture = Ref<Texture>(), float p_width = 1, const Ref<Texture> &p_normal_map = Ref<Texture>());
+ void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>());
+ void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>());
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
@@ -203,8 +289,8 @@ public:
RID get_canvas() const;
Ref<World2D> get_world_2d() const;
- void set_material(const Ref<ShaderMaterial> &p_material);
- Ref<ShaderMaterial> get_material() const;
+ void set_material(const Ref<Material> &p_material);
+ Ref<Material> get_material() const;
void set_use_parent_material(bool p_use_parent_material);
bool get_use_parent_material() const;
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index caf9cf201a..c5c274e225 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -31,18 +31,6 @@
#include "scene/scene_string_names.h"
#include "servers/physics_2d_server.h"
-void CollisionObject2D::_update_shapes_from_children() {
-
- shapes.clear();
- for (int i = 0; i < get_child_count(); i++) {
-
- Node *n = get_child(i);
- n->call("_add_to_collision_object", this);
- }
-
- _update_shapes();
-}
-
void CollisionObject2D::_notification(int p_what) {
switch (p_what) {
@@ -88,82 +76,197 @@ void CollisionObject2D::_notification(int p_what) {
}
}
-void CollisionObject2D::_update_shapes() {
+uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) {
- if (!rid.is_valid())
- return;
+ ShapeData sd;
+ uint32_t id;
+
+ if (shapes.size() == 0) {
+ id = 1;
+ } else {
+ id = shapes.back()->key() + 1;
+ }
+
+ sd.owner = p_owner;
+
+ shapes[id] = sd;
+
+ return id;
+}
+
+void CollisionObject2D::remove_shape_owner(uint32_t owner) {
+
+ ERR_FAIL_COND(!shapes.has(owner));
+
+ shape_owner_clear_shapes(owner);
+
+ shapes.erase(owner);
+}
+
+void CollisionObject2D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabled) {
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.disabled = p_disabled;
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ if (area) {
+ Physics2DServer::get_singleton()->area_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ } else {
+ Physics2DServer::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled);
+ }
+ }
+}
+
+bool CollisionObject2D::is_shape_owner_disabled(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), false);
+
+ return shapes[p_owner].disabled;
+}
+
+void CollisionObject2D::shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable) {
if (area)
- Physics2DServer::get_singleton()->area_clear_shapes(rid);
- else
- Physics2DServer::get_singleton()->body_clear_shapes(rid);
-
- for (int i = 0; i < shapes.size(); i++) {
-
- if (shapes[i].shape.is_null())
- continue;
- if (area)
- Physics2DServer::get_singleton()->area_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform);
- else {
- Physics2DServer::get_singleton()->body_add_shape(rid, shapes[i].shape->get_rid(), shapes[i].xform);
- if (shapes[i].trigger)
- Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, i, shapes[i].trigger);
+ return; //not for areas
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.one_way_collision = p_enable;
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ Physics2DServer::get_singleton()->body_set_shape_as_one_way_collision(rid, sd.shapes[i].index, p_enable);
+ }
+}
+
+bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), false);
+
+ return shapes[p_owner].one_way_collision;
+}
+
+void CollisionObject2D::get_shape_owners(List<uint32_t> *r_owners) {
+
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ r_owners->push_back(E->key());
+ }
+}
+
+void CollisionObject2D::shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+
+ ShapeData &sd = shapes[p_owner];
+ sd.xform = p_transform;
+ for (int i = 0; i < sd.shapes.size(); i++) {
+ if (area) {
+ Physics2DServer::get_singleton()->area_set_shape_transform(rid, sd.shapes[i].index, p_transform);
+ } else {
+ Physics2DServer::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform);
}
}
}
+Transform2D CollisionObject2D::shape_owner_get_transform(uint32_t p_owner) const {
-bool CollisionObject2D::_set(const StringName &p_name, const Variant &p_value) {
- String name = p_name;
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Transform2D());
- if (name.begins_with("shapes/")) {
+ return shapes[p_owner].xform;
+}
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
- if (what == "shape") {
- if (idx >= shapes.size())
- add_shape(RefPtr(p_value));
- else
- set_shape(idx, RefPtr(p_value));
- } else if (what == "transform")
- set_shape_transform(idx, p_value);
- else if (what == "trigger")
- set_shape_as_trigger(idx, p_value);
- } else
- return false;
-
- return true;
+Object *CollisionObject2D::shape_owner_get_owner(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), NULL);
+
+ return shapes[p_owner].owner;
+}
+
+void CollisionObject2D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+ ERR_FAIL_COND(p_shape.is_null());
+
+ ShapeData &sd = shapes[p_owner];
+ ShapeData::Shape s;
+ s.index = total_subshapes;
+ s.shape = p_shape;
+ if (area) {
+ Physics2DServer::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform);
+ } else {
+ Physics2DServer::get_singleton()->body_add_shape(rid, p_shape->get_rid(), sd.xform);
+ }
+ sd.shapes.push_back(s);
+
+ total_subshapes++;
+}
+int CollisionObject2D::shape_owner_get_shape_count(uint32_t p_owner) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), 0);
+
+ return shapes[p_owner].shapes.size();
+}
+Ref<Shape> CollisionObject2D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape>());
+ ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape>());
+
+ return shapes[p_owner].shapes[p_shape].shape;
+}
+int CollisionObject2D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const {
+
+ ERR_FAIL_COND_V(!shapes.has(p_owner), -1);
+ ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1);
+
+ return shapes[p_owner].shapes[p_shape].index;
}
-bool CollisionObject2D::_get(const StringName &p_name, Variant &r_ret) const {
+void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
+
+ ERR_FAIL_COND(!shapes.has(p_owner));
+ ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());
+
+ int index_to_remove = shapes[p_owner].shapes[p_shape].index;
+ if (area) {
+ Physics2DServer::get_singleton()->area_remove_shape(rid, index_to_remove);
+ } else {
+ Physics2DServer::get_singleton()->body_remove_shape(rid, index_to_remove);
+ }
+
+ shapes[p_owner].shapes.remove(p_shape);
+
+ for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+ if (E->get().shapes[i].index > index_to_remove) {
+ E->get().shapes[i].index -= 1;
+ }
+ }
+ }
- String name = p_name;
+ total_subshapes--;
+}
- if (name.begins_with("shapes/")) {
+void CollisionObject2D::shape_owner_clear_shapes(uint32_t p_owner) {
- int idx = name.get_slicec('/', 1).to_int();
- String what = name.get_slicec('/', 2);
- if (what == "shape")
- r_ret = get_shape(idx);
- else if (what == "transform")
- r_ret = get_shape_transform(idx);
- else if (what == "trigger")
- r_ret = is_shape_set_as_trigger(idx);
- } else
- return false;
+ ERR_FAIL_COND(!shapes.has(p_owner));
- return true;
+ while (shape_owner_get_shape_count(p_owner) > 0) {
+ shape_owner_remove_shape(p_owner, 0);
+ }
}
-void CollisionObject2D::_get_property_list(List<PropertyInfo> *p_list) const {
+uint32_t CollisionObject2D::shape_find_owner(int p_shape_index) const {
- //p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);
- for (int i = 0; i < shapes.size(); i++) {
- String path = "shapes/" + itos(i) + "/";
- p_list->push_back(PropertyInfo(Variant::OBJECT, path + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE));
- p_list->push_back(PropertyInfo(Variant::TRANSFORM, path + "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE));
- p_list->push_back(PropertyInfo(Variant::BOOL, path + "trigger", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_NO_INSTANCE_STATE));
+ for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
+ for (int i = 0; i < E->get().shapes.size(); i++) {
+ if (E->get().shapes[i].index == p_shape_index) {
+ return E->key();
+ }
+ }
}
+
+ //in theory it should be unreachable
+ return 0;
}
void CollisionObject2D::set_pickable(bool p_enabled) {
@@ -216,16 +319,6 @@ void CollisionObject2D::_update_pickable() {
void CollisionObject2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_shape", "shape:Shape2D", "transform"), &CollisionObject2D::add_shape, DEFVAL(Transform2D()));
- ClassDB::bind_method(D_METHOD("get_shape_count"), &CollisionObject2D::get_shape_count);
- ClassDB::bind_method(D_METHOD("set_shape", "shape_idx", "shape:Shape"), &CollisionObject2D::set_shape);
- ClassDB::bind_method(D_METHOD("set_shape_transform", "shape_idx", "transform"), &CollisionObject2D::set_shape_transform);
- ClassDB::bind_method(D_METHOD("set_shape_as_trigger", "shape_idx", "enable"), &CollisionObject2D::set_shape_as_trigger);
- ClassDB::bind_method(D_METHOD("get_shape:Shape2D", "shape_idx"), &CollisionObject2D::get_shape);
- ClassDB::bind_method(D_METHOD("get_shape_transform", "shape_idx"), &CollisionObject2D::get_shape_transform);
- ClassDB::bind_method(D_METHOD("is_shape_set_as_trigger", "shape_idx"), &CollisionObject2D::is_shape_set_as_trigger);
- ClassDB::bind_method(D_METHOD("remove_shape", "shape_idx"), &CollisionObject2D::remove_shape);
- ClassDB::bind_method(D_METHOD("clear_shapes"), &CollisionObject2D::clear_shapes);
ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid);
ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable);
@@ -242,100 +335,13 @@ void CollisionObject2D::_bind_methods() {
ADD_GROUP("", "");
}
-void CollisionObject2D::add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform) {
-
- ERR_FAIL_COND(p_shape.is_null());
-
- ShapeData sdata;
- sdata.shape = p_shape;
- sdata.xform = p_transform;
- sdata.trigger = false;
-
- if (area)
- Physics2DServer::get_singleton()->area_add_shape(get_rid(), p_shape->get_rid(), p_transform);
- else
- Physics2DServer::get_singleton()->body_add_shape(get_rid(), p_shape->get_rid(), p_transform);
-
- shapes.push_back(sdata);
-}
-int CollisionObject2D::get_shape_count() const {
-
- return shapes.size();
-}
-void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape) {
-
- ERR_FAIL_INDEX(p_shape_idx, shapes.size());
- ERR_FAIL_COND(p_shape.is_null());
-
- shapes[p_shape_idx].shape = p_shape;
- if (area)
- Physics2DServer::get_singleton()->area_set_shape(get_rid(), p_shape_idx, p_shape->get_rid());
- else
- Physics2DServer::get_singleton()->body_set_shape(get_rid(), p_shape_idx, p_shape->get_rid());
-
- //_update_shapes();
-}
-
-void CollisionObject2D::set_shape_transform(int p_shape_idx, const Transform2D &p_transform) {
-
- ERR_FAIL_INDEX(p_shape_idx, shapes.size());
- shapes[p_shape_idx].xform = p_transform;
-
- if (area)
- Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(), p_shape_idx, p_transform);
- else
- Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(), p_shape_idx, p_transform);
-
- //_update_shapes();
-}
-
-Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const {
-
- ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Ref<Shape2D>());
- return shapes[p_shape_idx].shape;
-}
-Transform2D CollisionObject2D::get_shape_transform(int p_shape_idx) const {
-
- ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), Transform2D());
- return shapes[p_shape_idx].xform;
-}
-void CollisionObject2D::remove_shape(int p_shape_idx) {
-
- ERR_FAIL_INDEX(p_shape_idx, shapes.size());
- shapes.remove(p_shape_idx);
-
- _update_shapes();
-}
-
-void CollisionObject2D::set_shape_as_trigger(int p_shape_idx, bool p_trigger) {
-
- ERR_FAIL_INDEX(p_shape_idx, shapes.size());
- shapes[p_shape_idx].trigger = p_trigger;
- if (!area && rid.is_valid()) {
-
- Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid, p_shape_idx, p_trigger);
- }
-}
-
-bool CollisionObject2D::is_shape_set_as_trigger(int p_shape_idx) const {
-
- ERR_FAIL_INDEX_V(p_shape_idx, shapes.size(), false);
- return shapes[p_shape_idx].trigger;
-}
-
-void CollisionObject2D::clear_shapes() {
-
- shapes.clear();
-
- _update_shapes();
-}
-
CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
rid = p_rid;
area = p_area;
pickable = true;
set_notify_transform(true);
+ total_subshapes = 0;
if (p_area) {
@@ -348,6 +354,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) {
CollisionObject2D::CollisionObject2D() {
//owner=
+
set_notify_transform(true);
}
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 4d4611afd1..deffe8a002 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -35,37 +35,40 @@
class CollisionObject2D : public Node2D {
- GDCLASS(CollisionObject2D, Node2D);
+ GDCLASS(CollisionObject2D, Node2D)
bool area;
RID rid;
bool pickable;
struct ShapeData {
+
+ Object *owner;
Transform2D xform;
- Ref<Shape2D> shape;
- bool trigger;
+ struct Shape {
+ Ref<Shape2D> shape;
+ int index;
+ };
+
+ Vector<Shape> shapes;
+ bool disabled;
+ bool one_way_collision;
ShapeData() {
- trigger = false;
+ disabled = false;
+ one_way_collision = false;
+ owner = NULL;
}
};
- Vector<ShapeData> shapes;
-
- void _update_shapes();
+ int total_subshapes;
- friend class CollisionShape2D;
- friend class CollisionPolygon2D;
- void _update_shapes_from_children();
+ Map<uint32_t, ShapeData> shapes;
protected:
CollisionObject2D(RID p_rid, bool p_area);
void _notification(int p_what);
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
void _update_pickable();
@@ -75,16 +78,29 @@ protected:
void _mouse_exit();
public:
- void add_shape(const Ref<Shape2D> &p_shape, const Transform2D &p_transform = Transform2D());
- int get_shape_count() const;
- void set_shape(int p_shape_idx, const Ref<Shape2D> &p_shape);
- void set_shape_transform(int p_shape_idx, const Transform2D &p_transform);
- Ref<Shape2D> get_shape(int p_shape_idx) const;
- Transform2D get_shape_transform(int p_shape_idx) const;
- void set_shape_as_trigger(int p_shape_idx, bool p_trigger);
- bool is_shape_set_as_trigger(int p_shape_idx) const;
- void remove_shape(int p_shape_idx);
- void clear_shapes();
+ uint32_t create_shape_owner(Object *p_owner);
+ void remove_shape_owner(uint32_t owner);
+ void get_shape_owners(List<uint32_t> *r_owners);
+
+ void shape_owner_set_transform(uint32_t p_owner, const Transform2D &p_transform);
+ Transform2D shape_owner_get_transform(uint32_t p_owner) const;
+ Object *shape_owner_get_owner(uint32_t p_owner) const;
+
+ void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled);
+ bool is_shape_owner_disabled(uint32_t p_owner) const;
+
+ void shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable);
+ bool is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const;
+
+ void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape);
+ int shape_owner_get_shape_count(uint32_t p_owner) const;
+ Ref<Shape> shape_owner_get_shape(uint32_t p_owner, int p_shape) const;
+ int shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const;
+
+ void shape_owner_remove_shape(uint32_t p_owner, int p_shape);
+ void shape_owner_clear_shapes(uint32_t p_owner);
+
+ uint32_t shape_find_owner(int p_shape_index) const;
void set_pickable(bool p_enabled);
bool is_pickable() const;
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 6b603c6473..bd669eb4c8 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -35,13 +35,9 @@
#include "thirdparty/misc/triangulator.h"
-void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
+void CollisionPolygon2D::_build_polygon() {
- if (unparenting || !can_update_body)
- return;
-
- CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
- ERR_FAIL_COND(!co);
+ parent->shape_owner_clear_shapes(owner_id);
if (polygon.size() == 0)
return;
@@ -53,18 +49,10 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
Vector<Vector<Vector2> > decomp = _decompose_in_convex();
- shape_from = co->get_shape_count();
for (int i = 0; i < decomp.size(); i++) {
Ref<ConvexPolygonShape2D> convex = memnew(ConvexPolygonShape2D);
convex->set_points(decomp[i]);
- co->add_shape(convex, get_transform());
- if (trigger)
- co->set_shape_as_trigger(co->get_shape_count() - 1, true);
- }
- shape_to = co->get_shape_count() - 1;
- if (shape_to < shape_from) {
- shape_from = -1;
- shape_to = -1;
+ parent->shape_owner_add_shape(owner_id, convex);
}
} else {
@@ -83,28 +71,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
w = PoolVector<Vector2>::Write();
concave->set_segments(segments);
- co->add_shape(concave, get_transform());
- if (trigger)
- co->set_shape_as_trigger(co->get_shape_count() - 1, true);
-
- shape_from = co->get_shape_count() - 1;
- shape_to = co->get_shape_count() - 1;
+ parent->shape_owner_add_shape(owner_id, concave);
}
-
- //co->add_shape(shape,get_transform());
-}
-
-void CollisionPolygon2D::_update_parent() {
-
- if (!can_update_body)
- return;
- Node *parent = get_parent();
- if (!parent)
- return;
- CollisionObject2D *co = parent->cast_to<CollisionObject2D>();
- if (!co)
- return;
- co->_update_shapes_from_children();
}
Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
@@ -155,33 +123,38 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
void CollisionPolygon2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- unparenting = false;
- can_update_body = get_tree()->is_editor_hint();
- if (!get_tree()->is_editor_hint()) {
+ case NOTIFICATION_PARENTED: {
+
+ parent = get_parent()->cast_to<CollisionObject2D>();
+ if (parent) {
+ owner_id = parent->create_shape_owner(this);
+ _build_polygon();
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ parent->shape_owner_set_disabled(owner_id, disabled);
+ parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+ }
+
+ /*if (get_tree()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
set_z(VS::CANVAS_ITEM_Z_MAX - 1);
- }
+ }*/
} break;
- case NOTIFICATION_EXIT_TREE: {
- can_update_body = false;
- } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (!is_inside_tree())
- break;
- if (can_update_body) {
- _update_parent();
- } else if (shape_from >= 0 && shape_to >= 0) {
- CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
- for (int i = shape_from; i <= shape_to; i++) {
- co->set_shape_transform(i, get_transform());
- }
+ if (parent) {
+ parent->shape_owner_set_transform(owner_id, get_transform());
}
} break;
+ case NOTIFICATION_UNPARENTED: {
+ if (parent) {
+ parent->remove_shape_owner(owner_id);
+ }
+ owner_id = 0;
+ parent = NULL;
+ } break;
case NOTIFICATION_DRAW: {
@@ -210,10 +183,22 @@ void CollisionPolygon2D::_notification(int p_what) {
draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color());
#endif
- } break;
- case NOTIFICATION_UNPARENTED: {
- unparenting = true;
- _update_parent();
+ if (one_way_collision) {
+ Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
+ dcol.a = 1.0;
+ Vector2 line_to(0, 20);
+ draw_line(Vector2(), line_to, dcol, 3);
+ Vector<Vector2> pts;
+ float tsize = 8;
+ pts.push_back(line_to + (Vector2(0, tsize)));
+ pts.push_back(line_to + (Vector2(0.707 * tsize, 0)));
+ pts.push_back(line_to + (Vector2(-0.707 * tsize, 0)));
+ Vector<Color> cols;
+ for (int i = 0; i < 3; i++)
+ cols.push_back(dcol);
+
+ draw_primitive(pts, cols, Vector<Vector2>()); //small arrow
+ }
} break;
}
}
@@ -222,7 +207,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
polygon = p_polygon;
- if (can_update_body) {
+ {
for (int i = 0; i < polygon.size(); i++) {
if (i == 0)
aabb = Rect2(polygon[i], Size2());
@@ -236,7 +221,10 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) {
aabb.position -= aabb.size * 0.3;
aabb.size += aabb.size * 0.6;
}
- _update_parent();
+ }
+
+ if (parent) {
+ _build_polygon();
}
update();
update_configuration_warning();
@@ -251,7 +239,9 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) {
ERR_FAIL_INDEX(p_mode, 2);
build_mode = p_mode;
- _update_parent();
+ if (parent) {
+ _build_polygon();
+ }
}
CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const {
@@ -264,79 +254,69 @@ Rect2 CollisionPolygon2D::get_item_rect() const {
return aabb;
}
-void CollisionPolygon2D::set_trigger(bool p_trigger) {
+String CollisionPolygon2D::get_configuration_warning() const {
- trigger = p_trigger;
- _update_parent();
- if (!can_update_body && is_inside_tree() && shape_from >= 0 && shape_to >= 0) {
- CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
- for (int i = shape_from; i <= shape_to; i++) {
- co->set_shape_as_trigger(i, p_trigger);
- }
+ if (!get_parent()->cast_to<CollisionObject2D>()) {
+ return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
}
-}
-bool CollisionPolygon2D::is_trigger() const {
+ if (polygon.empty()) {
+ return TTR("An empty CollisionPolygon2D has no effect on collision.");
+ }
- return trigger;
+ return String();
}
-void CollisionPolygon2D::_set_shape_range(const Vector2 &p_range) {
-
- shape_from = p_range.x;
- shape_to = p_range.y;
+void CollisionPolygon2D::set_disabled(bool p_disabled) {
+ disabled = p_disabled;
+ update();
+ if (parent) {
+ parent->shape_owner_set_disabled(owner_id, p_disabled);
+ }
}
-Vector2 CollisionPolygon2D::_get_shape_range() const {
-
- return Vector2(shape_from, shape_to);
+bool CollisionPolygon2D::is_disabled() const {
+ return disabled;
}
-String CollisionPolygon2D::get_configuration_warning() const {
-
- if (!get_parent()->cast_to<CollisionObject2D>()) {
- return TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+void CollisionPolygon2D::set_one_way_collision(bool p_enable) {
+ one_way_collision = p_enable;
+ update();
+ if (parent) {
+ parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
+}
- if (polygon.empty()) {
- return TTR("An empty CollisionPolygon2D has no effect on collision.");
- }
+bool CollisionPolygon2D::is_one_way_collision_enabled() const {
- return String();
+ return one_way_collision;
}
void CollisionPolygon2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionPolygon2D::_add_to_collision_object);
ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &CollisionPolygon2D::set_polygon);
ClassDB::bind_method(D_METHOD("get_polygon"), &CollisionPolygon2D::get_polygon);
ClassDB::bind_method(D_METHOD("set_build_mode", "build_mode"), &CollisionPolygon2D::set_build_mode);
ClassDB::bind_method(D_METHOD("get_build_mode"), &CollisionPolygon2D::get_build_mode);
-
- ClassDB::bind_method(D_METHOD("set_trigger", "trigger"), &CollisionPolygon2D::set_trigger);
- ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionPolygon2D::is_trigger);
-
- ClassDB::bind_method(D_METHOD("_set_shape_range", "shape_range"), &CollisionPolygon2D::_set_shape_range);
- ClassDB::bind_method(D_METHOD("_get_shape_range"), &CollisionPolygon2D::_get_shape_range);
-
- ClassDB::bind_method(D_METHOD("get_collision_object_first_shape"), &CollisionPolygon2D::get_collision_object_first_shape);
- ClassDB::bind_method(D_METHOD("get_collision_object_last_shape"), &CollisionPolygon2D::get_collision_object_last_shape);
+ ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon2D::set_disabled);
+ ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon2D::is_disabled);
+ ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionPolygon2D::set_one_way_collision);
+ ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionPolygon2D::is_one_way_collision_enabled);
ADD_PROPERTY(PropertyInfo(Variant::INT, "build_mode", PROPERTY_HINT_ENUM, "Solids,Segments"), "set_build_mode", "get_build_mode");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "shape_range", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_shape_range", "_get_shape_range");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
}
CollisionPolygon2D::CollisionPolygon2D() {
aabb = Rect2(-10, -10, 20, 20);
build_mode = BUILD_SOLIDS;
- trigger = false;
- unparenting = false;
- shape_from = -1;
- shape_to = -1;
- can_update_body = false;
set_notify_local_transform(true);
+ parent = NULL;
+ owner_id = 0;
+ disabled = false;
+ one_way_collision = false;
}
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index b1a4a4822d..f0666ba9de 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -33,6 +33,8 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
+class CollisionObject2D;
+
class CollisionPolygon2D : public Node2D {
GDCLASS(CollisionPolygon2D, Node2D);
@@ -47,29 +49,20 @@ protected:
Rect2 aabb;
BuildMode build_mode;
Vector<Point2> polygon;
- bool trigger;
- bool unparenting;
-
- void _add_to_collision_object(Object *p_obj);
- void _update_parent();
-
- bool can_update_body;
- int shape_from;
- int shape_to;
-
- void _set_shape_range(const Vector2 &p_range);
- Vector2 _get_shape_range() const;
+ uint32_t owner_id;
+ CollisionObject2D *parent;
+ bool disabled;
+ bool one_way_collision;
Vector<Vector<Vector2> > _decompose_in_convex();
+ void _build_polygon();
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- void set_trigger(bool p_trigger);
- bool is_trigger() const;
-
void set_build_mode(BuildMode p_mode);
BuildMode get_build_mode() const;
@@ -78,11 +71,14 @@ public:
virtual Rect2 get_item_rect() const;
- int get_collision_object_first_shape() const { return shape_from; }
- int get_collision_object_last_shape() const { return shape_to; }
-
virtual String get_configuration_warning() const;
+ void set_disabled(bool p_disabled);
+ bool is_disabled() const;
+
+ void set_one_way_collision(bool p_enable);
+ bool is_one_way_collision_enabled() const;
+
CollisionPolygon2D();
};
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 1687a898db..ff4aa245ec 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -37,68 +37,48 @@
#include "scene/resources/segment_shape_2d.h"
#include "scene/resources/shape_line_2d.h"
-void CollisionShape2D::_add_to_collision_object(Object *p_obj) {
-
- if (unparenting)
- return;
-
- CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
- ERR_FAIL_COND(!co);
- update_shape_index = co->get_shape_count();
- co->add_shape(shape, get_transform());
- if (trigger)
- co->set_shape_as_trigger(co->get_shape_count() - 1, true);
-}
-
void CollisionShape2D::_shape_changed() {
update();
- _update_parent();
-}
-
-void CollisionShape2D::_update_parent() {
-
- Node *parent = get_parent();
- if (!parent)
- return;
- CollisionObject2D *co = parent->cast_to<CollisionObject2D>();
- if (!co)
- return;
- co->_update_shapes_from_children();
}
void CollisionShape2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- unparenting = false;
- can_update_body = get_tree()->is_editor_hint();
- if (!get_tree()->is_editor_hint()) {
+ case NOTIFICATION_PARENTED: {
+
+ parent = get_parent()->cast_to<CollisionObject2D>();
+ if (parent) {
+ owner_id = parent->create_shape_owner(this);
+ if (shape.is_valid()) {
+ parent->shape_owner_add_shape(owner_id, shape);
+ }
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ parent->shape_owner_set_disabled(owner_id, disabled);
+ parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+ }
+
+ /*if (get_tree()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
set_z(VS::CANVAS_ITEM_Z_MAX - 1);
- }
+ }*/
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
- if (!is_inside_tree())
- break;
- if (can_update_body) {
- _update_parent();
- } else if (update_shape_index >= 0) {
-
- CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
- if (co) {
- co->set_shape_transform(update_shape_index, get_transform());
- }
+ if (parent) {
+ parent->shape_owner_set_transform(owner_id, get_transform());
}
} break;
- case NOTIFICATION_EXIT_TREE: {
- can_update_body = false;
-
+ case NOTIFICATION_UNPARENTED: {
+ if (parent) {
+ parent->remove_shape_owner(owner_id);
+ }
+ owner_id = 0;
+ parent = NULL;
} break;
/*
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -121,15 +101,33 @@ void CollisionShape2D::_notification(int p_what) {
rect = Rect2();
Color draw_col = get_tree()->get_debug_collisions_color();
+ if (disabled) {
+ float g = draw_col.gray();
+ draw_col.r = g;
+ draw_col.g = g;
+ draw_col.b = g;
+ }
shape->draw(get_canvas_item(), draw_col);
rect = shape->get_rect();
rect = rect.grow(3);
- } break;
- case NOTIFICATION_UNPARENTED: {
- unparenting = true;
- _update_parent();
+ if (one_way_collision) {
+ Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4);
+ dcol.a = 1.0;
+ Vector2 line_to(0, 20);
+ draw_line(Vector2(), line_to, dcol, 3);
+ Vector<Vector2> pts;
+ float tsize = 8;
+ pts.push_back(line_to + (Vector2(0, tsize)));
+ pts.push_back(line_to + (Vector2(0.707 * tsize, 0)));
+ pts.push_back(line_to + (Vector2(-0.707 * tsize, 0)));
+ Vector<Color> cols;
+ for (int i = 0; i < 3; i++)
+ cols.push_back(dcol);
+
+ draw_primitive(pts, cols, Vector<Vector2>()); //small arrow
+ }
} break;
}
}
@@ -140,14 +138,13 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) {
shape->disconnect("changed", this, "_shape_changed");
shape = p_shape;
update();
- if (is_inside_tree() && can_update_body)
- _update_parent();
- if (is_inside_tree() && !can_update_body && update_shape_index >= 0) {
- CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
- if (co) {
- co->set_shape(update_shape_index, p_shape);
+ if (parent) {
+ parent->shape_owner_clear_shapes(owner_id);
+ if (shape.is_valid()) {
+ parent->shape_owner_add_shape(owner_id, shape);
}
}
+
if (shape.is_valid())
shape->connect("changed", this, "_shape_changed");
@@ -164,72 +161,65 @@ Rect2 CollisionShape2D::get_item_rect() const {
return rect;
}
-void CollisionShape2D::set_trigger(bool p_trigger) {
+String CollisionShape2D::get_configuration_warning() const {
- trigger = p_trigger;
- if (can_update_body) {
- _update_parent();
- } else if (is_inside_tree() && update_shape_index >= 0) {
- CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
- if (co) {
- co->set_shape_as_trigger(update_shape_index, p_trigger);
- }
+ if (!get_parent()->cast_to<CollisionObject2D>()) {
+ return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
}
-}
-bool CollisionShape2D::is_trigger() const {
+ if (!shape.is_valid()) {
+ return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
+ }
- return trigger;
+ return String();
}
-void CollisionShape2D::_set_update_shape_index(int p_index) {
-
- update_shape_index = p_index;
+void CollisionShape2D::set_disabled(bool p_disabled) {
+ disabled = p_disabled;
+ update();
+ if (parent) {
+ parent->shape_owner_set_disabled(owner_id, p_disabled);
+ }
}
-int CollisionShape2D::_get_update_shape_index() const {
-
- return update_shape_index;
+bool CollisionShape2D::is_disabled() const {
+ return disabled;
}
-String CollisionShape2D::get_configuration_warning() const {
-
- if (!get_parent()->cast_to<CollisionObject2D>()) {
- return TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.");
+void CollisionShape2D::set_one_way_collision(bool p_enable) {
+ one_way_collision = p_enable;
+ update();
+ if (parent) {
+ parent->shape_owner_set_one_way_collision(owner_id, p_enable);
}
+}
- if (!shape.is_valid()) {
- return TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!");
- }
+bool CollisionShape2D::is_one_way_collision_enabled() const {
- return String();
+ return one_way_collision;
}
void CollisionShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shape", "shape"), &CollisionShape2D::set_shape);
ClassDB::bind_method(D_METHOD("get_shape"), &CollisionShape2D::get_shape);
+ ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionShape2D::set_disabled);
+ ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionShape2D::is_disabled);
+ ClassDB::bind_method(D_METHOD("set_one_way_collision", "enabled"), &CollisionShape2D::set_one_way_collision);
+ ClassDB::bind_method(D_METHOD("is_one_way_collision_enabled"), &CollisionShape2D::is_one_way_collision_enabled);
ClassDB::bind_method(D_METHOD("_shape_changed"), &CollisionShape2D::_shape_changed);
- ClassDB::bind_method(D_METHOD("_add_to_collision_object"), &CollisionShape2D::_add_to_collision_object);
- ClassDB::bind_method(D_METHOD("set_trigger", "enable"), &CollisionShape2D::set_trigger);
- ClassDB::bind_method(D_METHOD("is_trigger"), &CollisionShape2D::is_trigger);
-
- ClassDB::bind_method(D_METHOD("_set_update_shape_index", "index"), &CollisionShape2D::_set_update_shape_index);
- ClassDB::bind_method(D_METHOD("_get_update_shape_index"), &CollisionShape2D::_get_update_shape_index);
-
- ClassDB::bind_method(D_METHOD("get_collision_object_shape_index"), &CollisionShape2D::get_collision_object_shape_index);
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "trigger"), "set_trigger", "is_trigger");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_update_shape_index", "_get_update_shape_index");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "one_way_collision"), "set_one_way_collision", "is_one_way_collision_enabled");
}
CollisionShape2D::CollisionShape2D() {
rect = Rect2(-Point2(10, 10), Point2(20, 20));
set_notify_local_transform(true);
- trigger = false;
- unparenting = false;
- can_update_body = false;
- update_shape_index = -1;
+ owner_id = 0;
+ parent = NULL;
+ disabled = false;
+ one_way_collision = false;
}
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 3e63981010..1f2b96b91f 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -33,35 +33,33 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/shape_2d.h"
+class CollisionObject2D;
+
class CollisionShape2D : public Node2D {
- GDCLASS(CollisionShape2D, Node2D);
+ GDCLASS(CollisionShape2D, Node2D)
Ref<Shape2D> shape;
Rect2 rect;
- bool trigger;
- bool unparenting;
- bool can_update_body;
+ uint32_t owner_id;
+ CollisionObject2D *parent;
void _shape_changed();
- int update_shape_index;
-
- void _set_update_shape_index(int p_index);
- int _get_update_shape_index() const;
+ bool disabled;
+ bool one_way_collision;
protected:
- void _update_parent();
void _notification(int p_what);
static void _bind_methods();
- void _add_to_collision_object(Object *p_obj);
-
public:
void set_shape(const Ref<Shape2D> &p_shape);
Ref<Shape2D> get_shape() const;
virtual Rect2 get_item_rect() const;
- void set_trigger(bool p_trigger);
- bool is_trigger() const;
- int get_collision_object_shape_index() const { return _get_update_shape_index(); }
+ void set_disabled(bool p_disabled);
+ bool is_disabled() const;
+
+ void set_one_way_collision(bool p_enable);
+ bool is_one_way_collision_enabled() const;
virtual String get_configuration_warning() const;
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 1a57d24342..5438557d0b 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -310,12 +310,15 @@ void Line2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "width"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color");
+ ADD_GROUP("Fill", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "None,Tile"), "set_texture_mode", "get_texture_mode");
+ ADD_GROUP("Capping", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "joint_mode", PROPERTY_HINT_ENUM, "Sharp,Bevel,Round"), "set_joint_mode", "get_joint_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "begin_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_begin_cap_mode", "get_begin_cap_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "end_cap_mode", PROPERTY_HINT_ENUM, "None,Box,Round"), "set_end_cap_mode", "get_end_cap_mode");
+ ADD_GROUP("Border", "");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "sharp_limit"), "set_sharp_limit", "get_sharp_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "round_precision"), "set_round_precision", "get_round_precision");
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 21d64c5d64..aa9258c7b4 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -28,903 +28,246 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "particles_2d.h"
-#include "scene/scene_string_names.h"
-
-void ParticleAttractor2D::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- _update_owner();
- } break;
- case NOTIFICATION_DRAW: {
-
- if (!get_tree()->is_editor_hint())
- return;
-
- Vector2 pv;
- float dr = MIN(disable_radius, radius);
- for (int i = 0; i <= 32; i++) {
- Vector2 v(Math::sin(i / 32.0 * Math_PI * 2), Math::cos(i / 32.0 * Math_PI * 2));
- if (i > 0) {
- draw_line(pv * radius, v * radius, Color(0, 0, 0.5, 0.9));
- if (dr > 0) {
- draw_line(pv * dr, v * dr, Color(0.5, 0, 0.0, 0.9));
- }
- }
- pv = v;
- }
+#include "scene/3d/particles.h"
+#include "scene/scene_string_names.h"
- } break;
- case NOTIFICATION_EXIT_TREE: {
- if (owner) {
- _set_owner(NULL);
- }
+void Particles2D::set_emitting(bool p_emitting) {
- } break;
- }
+ emitting = p_emitting;
+ VS::get_singleton()->particles_set_emitting(particles, emitting);
}
-void ParticleAttractor2D::_owner_exited() {
+void Particles2D::set_amount(int p_amount) {
- ERR_FAIL_COND(!owner);
- owner->attractors.erase(this);
- owner = NULL;
+ ERR_FAIL_COND(p_amount < 1);
+ amount = p_amount;
+ VS::get_singleton()->particles_set_amount(particles, amount);
}
+void Particles2D::set_lifetime(float p_lifetime) {
-void ParticleAttractor2D::_update_owner() {
-
- if (!is_inside_tree() || !has_node(path)) {
- _set_owner(NULL);
- return;
- }
-
- Node *n = get_node(path);
- ERR_FAIL_COND(!n);
- Particles2D *pn = n->cast_to<Particles2D>();
- if (!pn) {
- _set_owner(NULL);
- return;
- }
-
- _set_owner(pn);
+ ERR_FAIL_COND(p_lifetime <= 0);
+ lifetime = p_lifetime;
+ VS::get_singleton()->particles_set_lifetime(particles, lifetime);
}
-void ParticleAttractor2D::_set_owner(Particles2D *p_owner) {
-
- if (owner == p_owner)
- return;
-
- if (owner) {
- owner->disconnect("tree_exited", this, "_owner_exited");
- owner->attractors.erase(this);
- owner = NULL;
- }
- owner = p_owner;
-
- if (owner) {
+void Particles2D::set_one_shot(bool p_enable) {
- owner->connect("tree_exited", this, "_owner_exited", varray(), CONNECT_ONESHOT);
- owner->attractors.insert(this);
- }
+ one_shot = p_enable;
+ VS::get_singleton()->particles_set_one_shot(particles, one_shot);
}
+void Particles2D::set_pre_process_time(float p_time) {
-void ParticleAttractor2D::_bind_methods() {
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &ParticleAttractor2D::set_enabled);
- ClassDB::bind_method(D_METHOD("is_enabled"), &ParticleAttractor2D::is_enabled);
-
- ClassDB::bind_method(D_METHOD("set_radius", "radius"), &ParticleAttractor2D::set_radius);
- ClassDB::bind_method(D_METHOD("get_radius"), &ParticleAttractor2D::get_radius);
-
- ClassDB::bind_method(D_METHOD("set_disable_radius", "radius"), &ParticleAttractor2D::set_disable_radius);
- ClassDB::bind_method(D_METHOD("get_disable_radius"), &ParticleAttractor2D::get_disable_radius);
-
- ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &ParticleAttractor2D::set_gravity);
- ClassDB::bind_method(D_METHOD("get_gravity"), &ParticleAttractor2D::get_gravity);
-
- ClassDB::bind_method(D_METHOD("set_absorption", "absorption"), &ParticleAttractor2D::set_absorption);
- ClassDB::bind_method(D_METHOD("get_absorption"), &ParticleAttractor2D::get_absorption);
-
- ClassDB::bind_method(D_METHOD("set_particles_path", "path"), &ParticleAttractor2D::set_particles_path);
- ClassDB::bind_method(D_METHOD("get_particles_path"), &ParticleAttractor2D::get_particles_path);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,16000,0.1"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "disable_radius", PROPERTY_HINT_RANGE, "0.1,16000,0.1"), "set_disable_radius", "get_disable_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-512,512,0.01"), "set_gravity", "get_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "absorption", PROPERTY_HINT_RANGE, "0,512,0.01"), "set_absorption", "get_absorption");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "particles_path", PROPERTY_HINT_RESOURCE_TYPE, "Particles2D"), "set_particles_path", "get_particles_path");
+ pre_process_time = p_time;
+ VS::get_singleton()->particles_set_pre_process_time(particles, pre_process_time);
}
+void Particles2D::set_explosiveness_ratio(float p_ratio) {
-void ParticleAttractor2D::set_enabled(bool p_enabled) {
-
- enabled = p_enabled;
+ explosiveness_ratio = p_ratio;
+ VS::get_singleton()->particles_set_explosiveness_ratio(particles, explosiveness_ratio);
}
+void Particles2D::set_randomness_ratio(float p_ratio) {
-bool ParticleAttractor2D::is_enabled() const {
-
- return enabled;
+ randomness_ratio = p_ratio;
+ VS::get_singleton()->particles_set_randomness_ratio(particles, randomness_ratio);
}
+void Particles2D::set_visibility_rect(const Rect2 &p_aabb) {
-void ParticleAttractor2D::set_radius(float p_radius) {
-
- radius = p_radius;
- update();
-}
+ visibility_rect = p_aabb;
+ Rect3 aabb;
+ aabb.position.x = p_aabb.position.x;
+ aabb.position.y = p_aabb.position.y;
+ aabb.size.x = p_aabb.size.x;
+ aabb.size.y = p_aabb.size.y;
-float ParticleAttractor2D::get_radius() const {
+ VS::get_singleton()->particles_set_custom_aabb(particles, aabb);
- return radius;
-}
-
-void ParticleAttractor2D::set_disable_radius(float p_disable_radius) {
-
- disable_radius = p_disable_radius;
+ _change_notify("visibility_rect");
update();
}
-float ParticleAttractor2D::get_disable_radius() const {
-
- return disable_radius;
-}
-
-void ParticleAttractor2D::set_gravity(float p_gravity) {
-
- gravity = p_gravity;
-}
-float ParticleAttractor2D::get_gravity() const {
-
- return gravity;
-}
-
-void ParticleAttractor2D::set_absorption(float p_absorption) {
+void Particles2D::set_use_local_coordinates(bool p_enable) {
- absorption = p_absorption;
-}
-float ParticleAttractor2D::get_absorption() const {
-
- return absorption;
-}
-
-void ParticleAttractor2D::set_particles_path(NodePath p_path) {
-
- path = p_path;
- _update_owner();
- update_configuration_warning();
-}
-NodePath ParticleAttractor2D::get_particles_path() const {
-
- return path;
-}
-
-String ParticleAttractor2D::get_configuration_warning() const {
-
- if (!has_node(path) || !get_node(path) || !get_node(path)->cast_to<Particles2D>()) {
- return TTR("Path property must point to a valid Particles2D node to work.");
+ local_coords = p_enable;
+ VS::get_singleton()->particles_set_use_local_coordinates(particles, local_coords);
+ set_notify_transform(!p_enable);
+ if (!p_enable && is_inside_tree()) {
+ _update_particle_emission_transform();
}
-
- return String();
}
-ParticleAttractor2D::ParticleAttractor2D() {
+void Particles2D::_update_particle_emission_transform() {
- owner = NULL;
- radius = 50;
- disable_radius = 0;
- gravity = 100;
- absorption = 0;
- path = String("..");
- enabled = true;
-}
-
-/****************************************/
+ Transform2D xf2d = get_global_transform();
+ Transform xf;
+ xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0));
+ xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0));
+ xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0));
-_FORCE_INLINE_ static float _rand_from_seed(uint64_t *seed) {
-
- uint32_t r = Math::rand_from_seed(seed);
- return 2.0f * (float)r / (float)Math::RANDOM_MAX - 1.0f;
+ VS::get_singleton()->particles_set_emission_transform(particles, xf);
}
-void Particles2D::_process_particles(float p_delta) {
-
- if (particles.size() == 0 || lifetime == 0)
- return;
-
- p_delta *= time_scale;
-
- float frame_time = p_delta;
-
- if (emit_timeout > 0) {
- time_to_live -= frame_time;
- if (time_to_live < 0) {
-
- emitting = false;
- _change_notify("config/emitting");
- };
- };
-
- float next_time = time + frame_time;
-
- if (next_time > lifetime)
- next_time = Math::fmod(next_time, lifetime);
-
- Particle *pdata = &particles[0];
- int particle_count = particles.size();
- Transform2D xform;
- if (!local_space)
- xform = get_global_transform();
-
- active_count = 0;
+void Particles2D::set_process_material(const Ref<Material> &p_material) {
- PoolVector<Point2>::Read r;
- int emission_point_count = 0;
- if (emission_points.size()) {
-
- emission_point_count = emission_points.size();
- r = emission_points.read();
- }
-
- int attractor_count = 0;
- AttractorCache *attractor_ptr = NULL;
-
- if (attractors.size()) {
- if (attractors.size() != attractor_cache.size()) {
- attractor_cache.resize(attractors.size());
- }
-
- int idx = 0;
- Transform2D m;
- if (local_space) {
- m = get_global_transform().affine_inverse();
- }
- for (Set<ParticleAttractor2D *>::Element *E = attractors.front(); E; E = E->next()) {
-
- attractor_cache[idx].pos = m.xform(E->get()->get_global_position());
- attractor_cache[idx].attractor = E->get();
- idx++;
- }
-
- attractor_ptr = attractor_cache.ptr();
- attractor_count = attractor_cache.size();
+ process_material = p_material;
+ Ref<ParticlesMaterial> pm = p_material;
+ if (pm.is_valid() && !pm->get_flag(ParticlesMaterial::FLAG_DISABLE_Z) && pm->get_gravity() == Vector3(0, -9.8, 0)) {
+ //likely a new material, modify it!
+ pm->set_flag(ParticlesMaterial::FLAG_DISABLE_Z, true);
+ pm->set_gravity(Vector3(0, 98, 0));
}
+ RID material_rid;
+ if (process_material.is_valid())
+ material_rid = process_material->get_rid();
+ VS::get_singleton()->particles_set_process_material(particles, material_rid);
- for (int i = 0; i < particle_count; i++) {
-
- Particle &p = pdata[i];
-
- float restart_time = (i * lifetime / particle_count) * explosiveness;
-
- bool restart = false;
-
- if (next_time < time) {
-
- if (restart_time > time || restart_time < next_time)
- restart = true;
-
- } else if (restart_time > time && restart_time < next_time) {
- restart = true;
- }
-
- if (restart) {
-
- if (emitting) {
-
- p.pos = emissor_offset;
- if (emission_point_count) {
-
- Vector2 ep = r[Math::rand() % emission_point_count];
- if (!local_space) {
- p.pos = xform.xform(p.pos + ep * extents);
- } else {
- p.pos += ep * extents;
- }
- } else {
- if (!local_space) {
- p.pos = xform.xform(p.pos + Vector2(Math::random(-extents.x, extents.x), Math::random(-extents.y, extents.y)));
- } else {
- p.pos += Vector2(Math::random(-extents.x, extents.x), Math::random(-extents.y, extents.y));
- }
- }
- p.seed = Math::rand() % 12345678;
- uint64_t rand_seed = p.seed * (i + 1);
-
- float angle = Math::deg2rad(param[PARAM_DIRECTION] + _rand_from_seed(&rand_seed) * param[PARAM_SPREAD]);
-
- p.velocity = Vector2(Math::sin(angle), Math::cos(angle));
- if (!local_space) {
-
- p.velocity = xform.basis_xform(p.velocity).normalized();
- }
-
- p.velocity *= param[PARAM_LINEAR_VELOCITY] + param[PARAM_LINEAR_VELOCITY] * _rand_from_seed(&rand_seed) * randomness[PARAM_LINEAR_VELOCITY];
- p.velocity += initial_velocity;
- p.active = true;
- p.rot = Math::deg2rad(param[PARAM_INITIAL_ANGLE] + param[PARAM_INITIAL_ANGLE] * randomness[PARAM_INITIAL_ANGLE] * _rand_from_seed(&rand_seed));
- active_count++;
-
- p.frame = Math::fmod(param[PARAM_ANIM_INITIAL_POS] + randomness[PARAM_ANIM_INITIAL_POS] * _rand_from_seed(&rand_seed), 1.0f);
-
- } else {
-
- p.active = false;
- }
-
- } else {
-
- if (!p.active)
- continue;
-
- uint64_t rand_seed = p.seed * (i + 1);
-
- Vector2 force;
-
- //apply gravity
- float gravity_dir = Math::deg2rad(param[PARAM_GRAVITY_DIRECTION] + 180 * randomness[PARAM_GRAVITY_DIRECTION] * _rand_from_seed(&rand_seed));
- force += Vector2(Math::sin(gravity_dir), Math::cos(gravity_dir)) * (param[PARAM_GRAVITY_STRENGTH] + param[PARAM_GRAVITY_STRENGTH] * randomness[PARAM_GRAVITY_STRENGTH] * _rand_from_seed(&rand_seed));
- //apply radial
- Vector2 rvec = (p.pos - emissor_offset).normalized();
- force += rvec * (param[PARAM_RADIAL_ACCEL] + param[PARAM_RADIAL_ACCEL] * randomness[PARAM_RADIAL_ACCEL] * _rand_from_seed(&rand_seed));
- //apply orbit
- float orbitvel = (param[PARAM_ORBIT_VELOCITY] + param[PARAM_ORBIT_VELOCITY] * randomness[PARAM_ORBIT_VELOCITY] * _rand_from_seed(&rand_seed));
- if (orbitvel != 0) {
- Vector2 rel = p.pos - xform.elements[2];
- Transform2D rot(orbitvel * frame_time, Vector2());
- p.pos = rot.xform(rel) + xform.elements[2];
- }
-
- Vector2 tvec = rvec.tangent();
- force += tvec * (param[PARAM_TANGENTIAL_ACCEL] + param[PARAM_TANGENTIAL_ACCEL] * randomness[PARAM_TANGENTIAL_ACCEL] * _rand_from_seed(&rand_seed));
-
- for (int j = 0; j < attractor_count; j++) {
-
- Vector2 vec = (attractor_ptr[j].pos - p.pos);
- float vl = vec.length();
-
- if (!attractor_ptr[j].attractor->enabled || vl == 0 || vl > attractor_ptr[j].attractor->radius)
- continue;
-
- force += vec * attractor_ptr[j].attractor->gravity;
- float fvl = p.velocity.length();
- if (fvl && attractor_ptr[j].attractor->absorption) {
- Vector2 target = vec.normalized();
- p.velocity = p.velocity.normalized().linear_interpolate(target, MIN(frame_time * attractor_ptr[j].attractor->absorption, 1)) * fvl;
- }
-
- if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) {
- p.active = false;
- }
- }
-
- p.velocity += force * frame_time;
-
- if (param[PARAM_DAMPING]) {
- float dmp = param[PARAM_DAMPING] + param[PARAM_DAMPING] * randomness[PARAM_DAMPING] * _rand_from_seed(&rand_seed);
- float v = p.velocity.length();
- v -= dmp * frame_time;
- if (v <= 0) {
- p.velocity = Vector2();
- } else {
- p.velocity = p.velocity.normalized() * v;
- }
- }
-
- p.pos += p.velocity * frame_time;
- p.rot += Math::lerp(param[PARAM_SPIN_VELOCITY], param[PARAM_SPIN_VELOCITY] * randomness[PARAM_SPIN_VELOCITY] * _rand_from_seed(&rand_seed), randomness[PARAM_SPIN_VELOCITY]) * frame_time;
- float anim_spd = param[PARAM_ANIM_SPEED_SCALE] + param[PARAM_ANIM_SPEED_SCALE] * randomness[PARAM_ANIM_SPEED_SCALE] * _rand_from_seed(&rand_seed);
- p.frame = Math::fposmod(p.frame + (frame_time / lifetime) * anim_spd, 1.0f);
-
- active_count++;
- }
- }
-
- time = Math::fmod(time + frame_time, lifetime);
- if (!emitting && active_count == 0) {
- emit_signal(SceneStringNames::get_singleton()->emission_finished);
- set_process(false);
- set_fixed_process(false);
- }
-
- update();
+ update_configuration_warning();
}
-void Particles2D::_notification(int p_what) {
-
- switch (p_what) {
-
- case NOTIFICATION_PROCESS: {
-
- _process_particles(get_process_delta_time());
- } break;
-
- case NOTIFICATION_FIXED_PROCESS: {
-
- _process_particles(get_fixed_process_delta_time());
- } break;
-
- case NOTIFICATION_ENTER_TREE: {
-
- float ppt = preprocess;
- while (ppt > 0) {
- _process_particles(0.1);
- ppt -= 0.1;
- }
- } break;
- case NOTIFICATION_DRAW: {
-
- if (particles.size() == 0 || lifetime == 0)
- return;
-
- RID ci = get_canvas_item();
- Size2 size(1, 1);
- Point2 center;
- int total_frames = 1;
+void Particles2D::set_speed_scale(float p_scale) {
- if (!texture.is_null()) {
- size = texture->get_size();
- size.x /= h_frames;
- size.y /= v_frames;
- total_frames = h_frames * v_frames;
- }
-
- float time_pos = (time / lifetime);
-
- Particle *pdata = &particles[0];
- int particle_count = particles.size();
-
- RID texrid;
-
- if (texture.is_valid())
- texrid = texture->get_rid();
-
- Transform2D invxform;
- if (!local_space)
- invxform = get_global_transform().affine_inverse();
-
- int start_particle = (int)(time * (float)particle_count / lifetime);
-
- for (int id = 0; id < particle_count; ++id) {
- int i = start_particle + id;
- if (i >= particle_count) {
- i -= particle_count;
- }
-
- Particle &p = pdata[i];
- if (!p.active)
- continue;
-
- float ptime = ((float)i / particle_count) * explosiveness;
-
- if (ptime < time_pos)
- ptime = time_pos - ptime;
- else
- ptime = (1.0 - ptime) + time_pos;
-
- uint64_t rand_seed = p.seed * (i + 1);
-
- Color color;
-
- if (gradient.is_valid()) {
- color = gradient->get_color_at_offset(ptime);
- } else {
- color = default_color;
- }
-
- {
- float huerand = _rand_from_seed(&rand_seed);
- float huerot = param[PARAM_HUE_VARIATION] + randomness[PARAM_HUE_VARIATION] * huerand;
-
- if (Math::abs(huerot) > CMP_EPSILON) {
-
- float h = color.get_h();
- float s = color.get_s();
- float v = color.get_v();
- float a = color.a;
- //float preh=h;
- h += huerot;
- h = Math::abs(Math::fposmod(h, 1.0f));
- //print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand));
- //print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h));
- color.set_hsv(h, s, v);
- color.a = a;
- }
- }
-
- float initial_size = param[PARAM_INITIAL_SIZE] + param[PARAM_INITIAL_SIZE] * _rand_from_seed(&rand_seed) * randomness[PARAM_INITIAL_SIZE];
- float final_size = param[PARAM_FINAL_SIZE] + param[PARAM_FINAL_SIZE] * _rand_from_seed(&rand_seed) * randomness[PARAM_FINAL_SIZE];
-
- float size_mult = initial_size * (1.0 - ptime) + final_size * ptime;
-
- //Size2 rectsize=size * size_mult;
- //rectsize=rectsize.floor();
-
- //Rect2 r = Rect2(Vecto,rectsize);
-
- Transform2D xform;
-
- if (p.rot) {
-
- xform.set_rotation(p.rot);
- xform.translate(-size * size_mult / 2.0);
- xform.elements[2] += p.pos;
- } else {
- xform.elements[2] = -size * size_mult / 2.0;
- xform.elements[2] += p.pos;
- }
-
- if (!local_space) {
- xform = invxform * xform;
- }
-
- xform.scale_basis(Size2(size_mult, size_mult));
-
- VisualServer::get_singleton()->canvas_item_add_set_transform(ci, xform);
-
- if (texrid.is_valid()) {
-
- Rect2 src_rect;
- src_rect.size = size;
-
- if (total_frames > 1) {
- int frame = Math::fast_ftoi(Math::floor(p.frame * total_frames)) % total_frames;
- src_rect.position.x = size.x * (frame % h_frames);
- src_rect.position.y = size.y * (frame / h_frames);
- }
- Rect2 dst_rect(Point2(), size);
- if (flip_h)
- dst_rect.size.x = -dst_rect.size.x;
- if (flip_v)
- dst_rect.size.y = -dst_rect.size.y;
-
- texture->draw_rect_region(ci, dst_rect, src_rect, color);
- //VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color);
- } else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(), size), color);
- }
- }
-
- } break;
- }
-}
-
-static const char *_particlesframe_property_names[Particles2D::PARAM_MAX] = {
- "params/direction",
- "params/spread",
- "params/linear_velocity",
- "params/spin_velocity",
- "params/orbit_velocity",
- "params/gravity_direction",
- "params/gravity_strength",
- "params/radial_accel",
- "params/tangential_accel",
- "params/damping",
- "params/initial_angle",
- "params/initial_size",
- "params/final_size",
- "params/hue_variation",
- "params/anim_speed_scale",
- "params/anim_initial_pos",
-};
-
-static const char *_particlesframe_property_rnames[Particles2D::PARAM_MAX] = {
- "randomness/direction",
- "randomness/spread",
- "randomness/linear_velocity",
- "randomness/spin_velocity",
- "randomness/orbit_velocity",
- "randomness/gravity_direction",
- "randomness/gravity_strength",
- "randomness/radial_accel",
- "randomness/tangential_accel",
- "randomness/damping",
- "randomness/initial_angle",
- "randomness/initial_size",
- "randomness/final_size",
- "randomness/hue_variation",
- "randomness/anim_speed_scale",
- "randomness/anim_initial_pos",
-};
-
-static const char *_particlesframe_property_ranges[Particles2D::PARAM_MAX] = {
- "0,360,0.01",
- "0,180,0.01",
- "-1024,1024,0.01",
- "-1024,1024,0.01",
- "-1024,1024,0.01",
- "0,360,0.01",
- "0,1024,0.01",
- "-128,128,0.01",
- "-128,128,0.01",
- "0,1024,0.001",
- "0,360,0.01",
- "0,1024,0.01",
- "0,1024,0.01",
- "0,1,0.01",
- "0,128,0.01",
- "0,1,0.01",
-};
-
-void Particles2D::set_emitting(bool p_emitting) {
-
- if (emitting == p_emitting)
- return;
-
- if (p_emitting) {
-
- if (active_count == 0)
- time = 0;
- set_process(process_mode == PROCESS_IDLE);
- set_fixed_process(process_mode == PROCESS_FIXED);
- time_to_live = emit_timeout;
- };
- emitting = p_emitting;
- _change_notify("config/emitting");
+ speed_scale = p_scale;
+ VS::get_singleton()->particles_set_speed_scale(particles, p_scale);
}
bool Particles2D::is_emitting() const {
return emitting;
}
-
-void Particles2D::set_process_mode(ProcessMode p_mode) {
-
- process_mode = p_mode;
- const bool should_process = emitting || active_count != 0;
- set_process(should_process && process_mode == PROCESS_IDLE);
- set_fixed_process(should_process && process_mode == PROCESS_FIXED);
-}
-
-Particles2D::ProcessMode Particles2D::get_process_mode() const {
-
- return process_mode;
-}
-
-void Particles2D::set_amount(int p_amount) {
-
- ERR_FAIL_INDEX(p_amount, 1024 + 1);
-
- particles.resize(p_amount);
-}
int Particles2D::get_amount() const {
- return particles.size();
-}
-
-void Particles2D::set_emit_timeout(float p_timeout) {
-
- emit_timeout = p_timeout;
- time_to_live = p_timeout;
-};
-
-float Particles2D::get_emit_timeout() const {
-
- return emit_timeout;
-};
-
-void Particles2D::set_lifetime(float p_lifetime) {
-
- ERR_FAIL_INDEX(p_lifetime, 3600 + 1);
-
- lifetime = p_lifetime;
+ return amount;
}
float Particles2D::get_lifetime() const {
return lifetime;
}
-void Particles2D::set_time_scale(float p_time_scale) {
+bool Particles2D::get_one_shot() const {
- time_scale = p_time_scale;
+ return one_shot;
}
-float Particles2D::get_time_scale() const {
-
- return time_scale;
-}
-
-void Particles2D::set_pre_process_time(float p_pre_process_time) {
-
- preprocess = p_pre_process_time;
-}
-
float Particles2D::get_pre_process_time() const {
- return preprocess;
-}
-
-void Particles2D::set_param(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- param[p_param] = p_value;
+ return pre_process_time;
}
-float Particles2D::get_param(Parameter p_param) const {
+float Particles2D::get_explosiveness_ratio() const {
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return param[p_param];
+ return explosiveness_ratio;
}
+float Particles2D::get_randomness_ratio() const {
-void Particles2D::set_randomness(Parameter p_param, float p_value) {
-
- ERR_FAIL_INDEX(p_param, PARAM_MAX);
- randomness[p_param] = p_value;
+ return randomness_ratio;
}
-float Particles2D::get_randomness(Parameter p_param) const {
+Rect2 Particles2D::get_visibility_rect() const {
- ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return visibility_rect;
}
+bool Particles2D::get_use_local_coordinates() const {
-void Particles2D::set_texture(const Ref<Texture> &p_texture) {
-
- texture = p_texture;
-}
-
-Ref<Texture> Particles2D::get_texture() const {
-
- return texture;
+ return local_coords;
}
+Ref<Material> Particles2D::get_process_material() const {
-void Particles2D::set_color(const Color &p_color) {
-
- default_color = p_color;
+ return process_material;
}
-Color Particles2D::get_color() const {
+float Particles2D::get_speed_scale() const {
- return default_color;
+ return speed_scale;
}
-void Particles2D::set_gradient(const Ref<Gradient> &p_gradient) {
+void Particles2D::set_draw_order(DrawOrder p_order) {
- gradient = p_gradient;
+ draw_order = p_order;
+ VS::get_singleton()->particles_set_draw_order(particles, VS::ParticlesDrawOrder(p_order));
}
-Ref<Gradient> Particles2D::get_gradient() const {
+Particles2D::DrawOrder Particles2D::get_draw_order() const {
- return gradient;
+ return draw_order;
}
-void Particles2D::set_emissor_offset(const Point2 &p_offset) {
-
- emissor_offset = p_offset;
+void Particles2D::set_fixed_fps(int p_count) {
+ fixed_fps = p_count;
+ VS::get_singleton()->particles_set_fixed_fps(particles, p_count);
}
-Point2 Particles2D::get_emissor_offset() const {
-
- return emissor_offset;
+int Particles2D::get_fixed_fps() const {
+ return fixed_fps;
}
-void Particles2D::set_use_local_space(bool p_use) {
-
- local_space = p_use;
+void Particles2D::set_fractional_delta(bool p_enable) {
+ fractional_delta = p_enable;
+ VS::get_singleton()->particles_set_fractional_delta(particles, p_enable);
}
-bool Particles2D::is_using_local_space() const {
-
- return local_space;
+bool Particles2D::get_fractional_delta() const {
+ return fractional_delta;
}
-//Deprecated. Converts color phases to color ramp
-void Particles2D::set_color_phases(int p_phases) {
-
- //Create color ramp if we have 2 or more phases.
- //Otherwise first phase phase will be assigned to default color.
- if (p_phases > 1 && gradient.is_null()) {
- gradient = Ref<Gradient>(memnew(Gradient()));
- }
- if (gradient.is_valid()) {
- gradient->get_points().resize(p_phases);
- }
-}
+String Particles2D::get_configuration_warning() const {
-//Deprecated.
-int Particles2D::get_color_phases() const {
+ String warnings;
- if (gradient.is_valid()) {
- return gradient->get_points_count();
+ if (process_material.is_null()) {
+ if (warnings != String())
+ warnings += "\n";
+ warnings += "- " + TTR("A material to process the particles is not assigned, so no behavior is imprinted.");
}
- return 0;
-}
-
-//Deprecated. Converts color phases to color ramp
-void Particles2D::set_color_phase_color(int p_phase, const Color &p_color) {
-
- ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES);
- if (gradient.is_valid()) {
- if (gradient->get_points_count() > p_phase)
- gradient->set_color(p_phase, p_color);
- } else {
- if (p_phase == 0)
- default_color = p_color;
- }
-}
-
-//Deprecated.
-Color Particles2D::get_color_phase_color(int p_phase) const {
-
- ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, Color());
- if (gradient.is_valid()) {
- return gradient->get_color(p_phase);
- }
- return Color(0, 0, 0, 1);
-}
-
-//Deprecated. Converts color phases to color ramp
-void Particles2D::set_color_phase_pos(int p_phase, float p_pos) {
- ERR_FAIL_INDEX(p_phase, MAX_COLOR_PHASES);
- ERR_FAIL_COND(p_pos < 0.0 || p_pos > 1.0);
- if (gradient.is_valid() && gradient->get_points_count() > p_phase) {
- return gradient->set_offset(p_phase, p_pos);
- }
-}
-
-//Deprecated.
-float Particles2D::get_color_phase_pos(int p_phase) const {
-
- ERR_FAIL_INDEX_V(p_phase, MAX_COLOR_PHASES, 0);
- if (gradient.is_valid()) {
- return gradient->get_offset(p_phase);
- }
- return 0;
-}
-
-void Particles2D::set_emission_half_extents(const Vector2 &p_extents) {
- extents = p_extents;
+ return warnings;
}
-Vector2 Particles2D::get_emission_half_extents() const {
+Rect2 Particles2D::capture_rect() const {
- return extents;
+ Rect3 aabb = VS::get_singleton()->particles_get_current_aabb(particles);
+ Rect2 r;
+ r.position.x = aabb.position.x;
+ r.position.y = aabb.position.y;
+ r.size.x = aabb.size.x;
+ r.size.y = aabb.size.y;
+ return r;
}
-void Particles2D::set_initial_velocity(const Vector2 &p_velocity) {
-
- initial_velocity = p_velocity;
-}
-Vector2 Particles2D::get_initial_velocity() const {
-
- return initial_velocity;
+void Particles2D::set_texture(const Ref<Texture> &p_texture) {
+ texture = p_texture;
+ update();
}
-void Particles2D::pre_process(float p_delta) {
-
- _process_particles(p_delta);
+Ref<Texture> Particles2D::get_texture() const {
+ return texture;
}
-void Particles2D::set_explosiveness(float p_value) {
+void Particles2D::set_normal_map(const Ref<Texture> &p_normal_map) {
- explosiveness = p_value;
+ normal_map = p_normal_map;
+ update();
}
-float Particles2D::get_explosiveness() const {
-
- return explosiveness;
+Ref<Texture> Particles2D::get_normal_map() const {
+ return normal_map;
}
-void Particles2D::set_flip_h(bool p_flip) {
-
- flip_h = p_flip;
+void Particles2D::_validate_property(PropertyInfo &property) const {
}
-bool Particles2D::is_flipped_h() const {
+void Particles2D::set_v_frames(int p_count) {
- return flip_h;
+ ERR_FAIL_COND(p_count < 1);
+ v_frames = p_count;
+ update();
}
-void Particles2D::set_flip_v(bool p_flip) {
-
- flip_v = p_flip;
-}
-bool Particles2D::is_flipped_v() const {
+int Particles2D::get_v_frames() const {
- return flip_v;
+ return v_frames;
}
-void Particles2D::set_h_frames(int p_frames) {
+void Particles2D::set_h_frames(int p_count) {
- ERR_FAIL_COND(p_frames < 1);
- h_frames = p_frames;
+ ERR_FAIL_COND(p_count < 1);
+ h_frames = p_count;
+ update();
}
int Particles2D::get_h_frames() const {
@@ -932,215 +275,133 @@ int Particles2D::get_h_frames() const {
return h_frames;
}
-void Particles2D::set_v_frames(int p_frames) {
-
- ERR_FAIL_COND(p_frames < 1);
- v_frames = p_frames;
+void Particles2D::restart() {
+ VS::get_singleton()->particles_restart(particles);
}
-int Particles2D::get_v_frames() const {
- return v_frames;
-}
+void Particles2D::_notification(int p_what) {
-void Particles2D::set_emission_points(const PoolVector<Vector2> &p_points) {
+ if (p_what == NOTIFICATION_DRAW) {
- emission_points = p_points;
-}
+ RID texture_rid;
+ if (texture.is_valid())
+ texture_rid = texture->get_rid();
+ RID normal_rid;
+ if (normal_map.is_valid())
+ normal_rid = texture->get_rid();
-PoolVector<Vector2> Particles2D::get_emission_points() const {
+ VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames);
- return emission_points;
-}
+#ifdef TOOLS_ENABLED
+ if (get_tree()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) {
-void Particles2D::reset() {
+ draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false);
+ }
+#endif
+ }
- for (int i = 0; i < particles.size(); i++) {
- particles[i].active = false;
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+ _update_particle_emission_transform();
}
- time = 0;
- active_count = 0;
}
void Particles2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_emitting", "active"), &Particles2D::set_emitting);
- ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
-
- ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Particles2D::set_process_mode);
- ClassDB::bind_method(D_METHOD("get_process_mode"), &Particles2D::get_process_mode);
-
+ ClassDB::bind_method(D_METHOD("set_emitting", "emitting"), &Particles2D::set_emitting);
ClassDB::bind_method(D_METHOD("set_amount", "amount"), &Particles2D::set_amount);
- ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
+ ClassDB::bind_method(D_METHOD("set_lifetime", "secs"), &Particles2D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("set_one_shot", "secs"), &Particles2D::set_one_shot);
+ ClassDB::bind_method(D_METHOD("set_pre_process_time", "secs"), &Particles2D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("set_explosiveness_ratio", "ratio"), &Particles2D::set_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("set_randomness_ratio", "ratio"), &Particles2D::set_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("set_visibility_rect", "aabb"), &Particles2D::set_visibility_rect);
+ ClassDB::bind_method(D_METHOD("set_use_local_coordinates", "enable"), &Particles2D::set_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("set_fixed_fps", "fps"), &Particles2D::set_fixed_fps);
+ ClassDB::bind_method(D_METHOD("set_fractional_delta", "enable"), &Particles2D::set_fractional_delta);
+ ClassDB::bind_method(D_METHOD("set_process_material", "material:Material"), &Particles2D::set_process_material);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &Particles2D::set_speed_scale);
- ClassDB::bind_method(D_METHOD("set_lifetime", "lifetime"), &Particles2D::set_lifetime);
+ ClassDB::bind_method(D_METHOD("is_emitting"), &Particles2D::is_emitting);
+ ClassDB::bind_method(D_METHOD("get_amount"), &Particles2D::get_amount);
ClassDB::bind_method(D_METHOD("get_lifetime"), &Particles2D::get_lifetime);
-
- ClassDB::bind_method(D_METHOD("set_time_scale", "time_scale"), &Particles2D::set_time_scale);
- ClassDB::bind_method(D_METHOD("get_time_scale"), &Particles2D::get_time_scale);
-
- ClassDB::bind_method(D_METHOD("set_pre_process_time", "time"), &Particles2D::set_pre_process_time);
+ ClassDB::bind_method(D_METHOD("get_one_shot"), &Particles2D::get_one_shot);
ClassDB::bind_method(D_METHOD("get_pre_process_time"), &Particles2D::get_pre_process_time);
-
- ClassDB::bind_method(D_METHOD("set_emit_timeout", "value"), &Particles2D::set_emit_timeout);
- ClassDB::bind_method(D_METHOD("get_emit_timeout"), &Particles2D::get_emit_timeout);
-
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &Particles2D::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &Particles2D::get_param);
-
- ClassDB::bind_method(D_METHOD("set_randomness", "param", "value"), &Particles2D::set_randomness);
- ClassDB::bind_method(D_METHOD("get_randomness", "param"), &Particles2D::get_randomness);
-
- ClassDB::bind_method(D_METHOD("set_texture:Texture", "texture"), &Particles2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_explosiveness_ratio"), &Particles2D::get_explosiveness_ratio);
+ ClassDB::bind_method(D_METHOD("get_randomness_ratio"), &Particles2D::get_randomness_ratio);
+ ClassDB::bind_method(D_METHOD("get_visibility_rect"), &Particles2D::get_visibility_rect);
+ ClassDB::bind_method(D_METHOD("get_use_local_coordinates"), &Particles2D::get_use_local_coordinates);
+ ClassDB::bind_method(D_METHOD("get_fixed_fps"), &Particles2D::get_fixed_fps);
+ ClassDB::bind_method(D_METHOD("get_fractional_delta"), &Particles2D::get_fractional_delta);
+ ClassDB::bind_method(D_METHOD("get_process_material:Material"), &Particles2D::get_process_material);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &Particles2D::get_speed_scale);
+
+ ClassDB::bind_method(D_METHOD("set_draw_order", "order"), &Particles2D::set_draw_order);
+ ClassDB::bind_method(D_METHOD("get_draw_order"), &Particles2D::get_draw_order);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Particles2D::set_texture);
ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Particles2D::get_texture);
- ClassDB::bind_method(D_METHOD("set_color", "color"), &Particles2D::set_color);
- ClassDB::bind_method(D_METHOD("get_color"), &Particles2D::get_color);
-
- ClassDB::bind_method(D_METHOD("set_gradient:Gradient", "gradient"), &Particles2D::set_gradient);
- ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &Particles2D::get_gradient);
+ ClassDB::bind_method(D_METHOD("set_normal_map", "texture:Texture"), &Particles2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map:Texture"), &Particles2D::get_normal_map);
- ClassDB::bind_method(D_METHOD("set_emissor_offset", "offset"), &Particles2D::set_emissor_offset);
- ClassDB::bind_method(D_METHOD("get_emissor_offset"), &Particles2D::get_emissor_offset);
-
- ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &Particles2D::set_flip_h);
- ClassDB::bind_method(D_METHOD("is_flipped_h"), &Particles2D::is_flipped_h);
-
- ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &Particles2D::set_flip_v);
- ClassDB::bind_method(D_METHOD("is_flipped_v"), &Particles2D::is_flipped_v);
-
- ClassDB::bind_method(D_METHOD("set_h_frames", "enable"), &Particles2D::set_h_frames);
- ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
+ ClassDB::bind_method(D_METHOD("capture_rect"), &Particles2D::capture_rect);
- ClassDB::bind_method(D_METHOD("set_v_frames", "enable"), &Particles2D::set_v_frames);
+ ClassDB::bind_method(D_METHOD("set_v_frames", "frames"), &Particles2D::set_v_frames);
ClassDB::bind_method(D_METHOD("get_v_frames"), &Particles2D::get_v_frames);
- ClassDB::bind_method(D_METHOD("set_emission_half_extents", "extents"), &Particles2D::set_emission_half_extents);
- ClassDB::bind_method(D_METHOD("get_emission_half_extents"), &Particles2D::get_emission_half_extents);
-
- ClassDB::bind_method(D_METHOD("set_color_phases", "phases"), &Particles2D::set_color_phases);
- ClassDB::bind_method(D_METHOD("get_color_phases"), &Particles2D::get_color_phases);
-
- ClassDB::bind_method(D_METHOD("set_color_phase_color", "phase", "color"), &Particles2D::set_color_phase_color);
- ClassDB::bind_method(D_METHOD("get_color_phase_color", "phase"), &Particles2D::get_color_phase_color);
-
- ClassDB::bind_method(D_METHOD("set_color_phase_pos", "phase", "pos"), &Particles2D::set_color_phase_pos);
- ClassDB::bind_method(D_METHOD("get_color_phase_pos", "phase"), &Particles2D::get_color_phase_pos);
-
- ClassDB::bind_method(D_METHOD("pre_process", "time"), &Particles2D::pre_process);
- ClassDB::bind_method(D_METHOD("reset"), &Particles2D::reset);
-
- ClassDB::bind_method(D_METHOD("set_use_local_space", "enable"), &Particles2D::set_use_local_space);
- ClassDB::bind_method(D_METHOD("is_using_local_space"), &Particles2D::is_using_local_space);
-
- ClassDB::bind_method(D_METHOD("set_initial_velocity", "velocity"), &Particles2D::set_initial_velocity);
- ClassDB::bind_method(D_METHOD("get_initial_velocity"), &Particles2D::get_initial_velocity);
-
- ClassDB::bind_method(D_METHOD("set_explosiveness", "amount"), &Particles2D::set_explosiveness);
- ClassDB::bind_method(D_METHOD("get_explosiveness"), &Particles2D::get_explosiveness);
-
- ClassDB::bind_method(D_METHOD("set_emission_points", "points"), &Particles2D::set_emission_points);
- ClassDB::bind_method(D_METHOD("get_emission_points"), &Particles2D::get_emission_points);
-
- ADD_SIGNAL(MethodInfo("emission_finished"));
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "config/amount", PROPERTY_HINT_EXP_RANGE, "1,1024"), "set_amount", "get_amount");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "config/lifetime", PROPERTY_HINT_EXP_RANGE, "0.1,3600,0.1"), "set_lifetime", "get_lifetime");
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "config/time_scale", PROPERTY_HINT_EXP_RANGE, "0.01,128,0.01"), "set_time_scale", "get_time_scale");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "config/preprocess", PROPERTY_HINT_EXP_RANGE, "0,3600,0.1"), "set_pre_process_time", "get_pre_process_time");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "config/emit_timeout", PROPERTY_HINT_RANGE, "0,3600,0.1"), "set_emit_timeout", "get_emit_timeout");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "config/emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "config/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), "set_process_mode", "get_process_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "config/offset"), "set_emissor_offset", "get_emissor_offset");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "config/half_extents"), "set_emission_half_extents", "get_emission_half_extents");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "config/local_space"), "set_use_local_space", "is_using_local_space");
- ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "config/explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness", "get_explosiveness");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "config/flip_h"), "set_flip_h", "is_flipped_h");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "config/flip_v"), "set_flip_v", "is_flipped_v");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "config/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "config/h_frames", PROPERTY_HINT_RANGE, "1,512,1"), "set_h_frames", "get_h_frames");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "config/v_frames", PROPERTY_HINT_RANGE, "1,512,1"), "set_v_frames", "get_v_frames");
-
- for (int i = 0; i < PARAM_MAX; i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, _particlesframe_property_names[i], PROPERTY_HINT_RANGE, _particlesframe_property_ranges[i]), "set_param", "get_param", i);
- }
-
- for (int i = 0; i < PARAM_MAX; i++) {
- ADD_PROPERTYINZ(PropertyInfo(Variant::REAL, _particlesframe_property_rnames[i], PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_randomness", "get_randomness", i);
- }
-
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "color_phases/count", PROPERTY_HINT_RANGE, "0,4,1", 0), "set_color_phases", "get_color_phases");
-
- //Backward compatibility. They will be converted to color ramp
- for (int i = 0; i < MAX_COLOR_PHASES; i++) {
- String phase = "phase_" + itos(i) + "/";
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, phase + "pos", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_color_phase_pos", "get_color_phase_pos", i);
- ADD_PROPERTYI(PropertyInfo(Variant::COLOR, phase + "color", PROPERTY_HINT_NONE, "", 0), "set_color_phase_color", "get_color_phase_color", i);
- }
+ ClassDB::bind_method(D_METHOD("set_h_frames", "frames"), &Particles2D::set_h_frames);
+ ClassDB::bind_method(D_METHOD("get_h_frames"), &Particles2D::get_h_frames);
- ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"), "set_color", "get_color");
- ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "color/color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
-
- ADD_PROPERTYNZ(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "emission_points", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_emission_points", "get_emission_points");
-
- BIND_CONSTANT(PARAM_DIRECTION);
- BIND_CONSTANT(PARAM_SPREAD);
- BIND_CONSTANT(PARAM_LINEAR_VELOCITY);
- BIND_CONSTANT(PARAM_SPIN_VELOCITY);
- BIND_CONSTANT(PARAM_ORBIT_VELOCITY);
- BIND_CONSTANT(PARAM_GRAVITY_DIRECTION);
- BIND_CONSTANT(PARAM_GRAVITY_STRENGTH);
- BIND_CONSTANT(PARAM_RADIAL_ACCEL);
- BIND_CONSTANT(PARAM_TANGENTIAL_ACCEL);
- BIND_CONSTANT(PARAM_DAMPING);
- BIND_CONSTANT(PARAM_INITIAL_ANGLE);
- BIND_CONSTANT(PARAM_INITIAL_SIZE);
- BIND_CONSTANT(PARAM_FINAL_SIZE);
- BIND_CONSTANT(PARAM_HUE_VARIATION);
- BIND_CONSTANT(PARAM_ANIM_SPEED_SCALE);
- BIND_CONSTANT(PARAM_ANIM_INITIAL_POS);
- BIND_CONSTANT(PARAM_MAX);
-
- BIND_CONSTANT(MAX_COLOR_PHASES);
+ ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_GROUP("Time", "");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_fps", PROPERTY_HINT_RANGE, "0,1000,1"), "set_fixed_fps", "get_fixed_fps");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta");
+ ADD_GROUP("Drawing", "");
+ ADD_PROPERTY(PropertyInfo(Variant::RECT3, "visibility_rect"), "set_visibility_rect", "get_visibility_rect");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "local_coords"), "set_use_local_coordinates", "get_use_local_coordinates");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime"), "set_draw_order", "get_draw_order");
+ ADD_GROUP("Process Material", "process_");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material");
+ ADD_GROUP("Textures", "");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "h_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_h_frames", "get_h_frames");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "v_frames", PROPERTY_HINT_RANGE, "1,1024,1"), "set_v_frames", "get_v_frames");
+
+ BIND_CONSTANT(DRAW_ORDER_INDEX);
+ BIND_CONSTANT(DRAW_ORDER_LIFETIME);
}
Particles2D::Particles2D() {
- for (int i = 0; i < PARAM_MAX; i++) {
+ particles = VS::get_singleton()->particles_create();
- param[i] = 0;
- randomness[i] = 0;
- }
-
- set_param(PARAM_SPREAD, 10);
- set_param(PARAM_LINEAR_VELOCITY, 20);
- set_param(PARAM_GRAVITY_STRENGTH, 9.8);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_INITIAL_ANGLE, 0.0);
- set_param(PARAM_INITIAL_SIZE, 1.0);
- set_param(PARAM_FINAL_SIZE, 1.0);
- set_param(PARAM_ANIM_SPEED_SCALE, 1.0);
-
- set_color(Color(1, 1, 1, 1));
-
- time = 0;
- lifetime = 2;
- emitting = false;
- particles.resize(32);
- active_count = -1;
set_emitting(true);
- process_mode = PROCESS_IDLE;
- local_space = true;
- preprocess = 0;
- time_scale = 1.0;
-
- flip_h = false;
- flip_v = false;
-
- v_frames = 1;
+ set_one_shot(false);
+ set_amount(8);
+ set_lifetime(1);
+ set_fixed_fps(0);
+ set_fractional_delta(true);
+ set_pre_process_time(0);
+ set_explosiveness_ratio(0);
+ set_randomness_ratio(0);
+ set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
+ set_use_local_coordinates(true);
+ set_speed_scale(1);
h_frames = 1;
+ v_frames = 1;
+}
+
+Particles2D::~Particles2D() {
- emit_timeout = 0;
- time_to_live = 0;
- explosiveness = 1.0;
+ VS::get_singleton()->free(particles);
}
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index 856beaa836..23278ce746 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -34,235 +34,102 @@
#include "scene/resources/color_ramp.h"
#include "scene/resources/texture.h"
-class Particles2D;
-class ParticleAttractor2D : public Node2D {
-
- GDCLASS(ParticleAttractor2D, Node2D);
-
- friend class Particles2D;
- bool enabled;
- float radius;
- float disable_radius;
- float gravity;
- float absorption;
- NodePath path;
-
- Particles2D *owner;
-
- void _update_owner();
- void _owner_exited();
- void _set_owner(Particles2D *p_owner);
-
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- void set_enabled(bool p_enabled);
- bool is_enabled() const;
-
- void set_radius(float p_radius);
- float get_radius() const;
-
- void set_disable_radius(float p_disable_radius);
- float get_disable_radius() const;
-
- void set_gravity(float p_gravity);
- float get_gravity() const;
-
- void set_absorption(float p_absorption);
- float get_absorption() const;
-
- void set_particles_path(NodePath p_path);
- NodePath get_particles_path() const;
-
- virtual String get_configuration_warning() const;
-
- ParticleAttractor2D();
-};
-
class Particles2D : public Node2D {
-
- GDCLASS(Particles2D, Node2D);
+private:
+ GDCLASS(Particles2D, Node2D)
public:
- enum Parameter {
- PARAM_DIRECTION,
- PARAM_SPREAD,
- PARAM_LINEAR_VELOCITY,
- PARAM_SPIN_VELOCITY,
- PARAM_ORBIT_VELOCITY,
- PARAM_GRAVITY_DIRECTION,
- PARAM_GRAVITY_STRENGTH,
- PARAM_RADIAL_ACCEL,
- PARAM_TANGENTIAL_ACCEL,
- PARAM_DAMPING,
- PARAM_INITIAL_ANGLE,
- PARAM_INITIAL_SIZE,
- PARAM_FINAL_SIZE,
- PARAM_HUE_VARIATION,
- PARAM_ANIM_SPEED_SCALE,
- PARAM_ANIM_INITIAL_POS,
- PARAM_MAX
- };
-
- enum {
- MAX_COLOR_PHASES = 4
- };
-
- enum ProcessMode {
- PROCESS_FIXED,
- PROCESS_IDLE,
+ enum DrawOrder {
+ DRAW_ORDER_INDEX,
+ DRAW_ORDER_LIFETIME,
};
private:
- float param[PARAM_MAX];
- float randomness[PARAM_MAX];
+ RID particles;
- struct Particle {
- bool active;
- Point2 pos;
- Vector2 velocity;
- float rot;
- float frame;
- uint64_t seed;
- Particle() {
- active = false;
- seed = 123465789;
- rot = 0;
- frame = 0;
- }
- };
-
- Vector<Particle> particles;
-
- struct AttractorCache {
-
- Vector2 pos;
- ParticleAttractor2D *attractor;
- };
-
- Vector<AttractorCache> attractor_cache;
-
- float explosiveness;
- float preprocess;
- float lifetime;
bool emitting;
- bool local_space;
- float emit_timeout;
- float time_to_live;
- float time_scale;
- bool flip_h;
- bool flip_v;
- int h_frames;
+ bool one_shot;
+ int amount;
+ float lifetime;
+ float pre_process_time;
+ float explosiveness_ratio;
+ float randomness_ratio;
+ float speed_scale;
+ Rect2 visibility_rect;
+ bool local_coords;
+ int fixed_fps;
+ bool fractional_delta;
int v_frames;
- Point2 emissor_offset;
- Vector2 initial_velocity;
- Vector2 extents;
- PoolVector<Vector2> emission_points;
+ int h_frames;
- ProcessMode process_mode;
+ Ref<Material> process_material;
- float time;
- int active_count;
+ DrawOrder draw_order;
Ref<Texture> texture;
+ Ref<Texture> normal_map;
- //If no color ramp is set then default color is used. Created as simple alternative to color_ramp.
- Color default_color;
- Ref<Gradient> gradient;
-
- void _process_particles(float p_delta);
- friend class ParticleAttractor2D;
-
- Set<ParticleAttractor2D *> attractors;
+ void _update_particle_emission_transform();
protected:
- void _notification(int p_what);
static void _bind_methods();
+ virtual void _validate_property(PropertyInfo &property) const;
+ void _notification(int p_what);
public:
void set_emitting(bool p_emitting);
- bool is_emitting() const;
-
- void set_process_mode(ProcessMode p_mode);
- ProcessMode get_process_mode() const;
-
void set_amount(int p_amount);
- int get_amount() const;
-
void set_lifetime(float p_lifetime);
- float get_lifetime() const;
-
- void set_time_scale(float p_time_scale);
- float get_time_scale() const;
+ void set_one_shot(bool p_enabled);
+ void set_pre_process_time(float p_time);
+ void set_explosiveness_ratio(float p_ratio);
+ void set_randomness_ratio(float p_ratio);
+ void set_visibility_rect(const Rect2 &p_aabb);
+ void set_use_local_coordinates(bool p_enable);
+ void set_process_material(const Ref<Material> &p_material);
+ void set_speed_scale(float p_scale);
- void set_pre_process_time(float p_pre_process_time);
+ bool is_emitting() const;
+ int get_amount() const;
+ float get_lifetime() const;
+ bool get_one_shot() const;
float get_pre_process_time() const;
+ float get_explosiveness_ratio() const;
+ float get_randomness_ratio() const;
+ Rect2 get_visibility_rect() const;
+ bool get_use_local_coordinates() const;
+ Ref<Material> get_process_material() const;
+ float get_speed_scale() const;
- void set_emit_timeout(float p_timeout);
- float get_emit_timeout() const;
-
- void set_emission_half_extents(const Vector2 &p_extents);
- Vector2 get_emission_half_extents() const;
+ void set_fixed_fps(int p_count);
+ int get_fixed_fps() const;
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
+ void set_fractional_delta(bool p_enable);
+ bool get_fractional_delta() const;
- void set_randomness(Parameter p_randomness, float p_value);
- float get_randomness(Parameter p_randomness) const;
-
- void set_explosiveness(float p_value);
- float get_explosiveness() const;
-
- void set_flip_h(bool p_flip);
- bool is_flipped_h() const;
-
- void set_flip_v(bool p_flip);
- bool is_flipped_v() const;
-
- void set_h_frames(int p_frames);
- int get_h_frames() const;
-
- void set_v_frames(int p_frames);
- int get_v_frames() const;
-
- void set_color_phases(int p_phases);
- int get_color_phases() const;
-
- void set_color_phase_color(int p_phase, const Color &p_color);
- Color get_color_phase_color(int p_phase) const;
-
- void set_color_phase_pos(int p_phase, float p_pos);
- float get_color_phase_pos(int p_phase) const;
+ void set_draw_order(DrawOrder p_order);
+ DrawOrder get_draw_order() const;
void set_texture(const Ref<Texture> &p_texture);
Ref<Texture> get_texture() const;
- void set_color(const Color &p_color);
- Color get_color() const;
-
- void set_gradient(const Ref<Gradient> &p_texture);
- Ref<Gradient> get_gradient() const;
-
- void set_emissor_offset(const Point2 &p_offset);
- Point2 get_emissor_offset() const;
+ void set_normal_map(const Ref<Texture> &p_normal_map);
+ Ref<Texture> get_normal_map() const;
- void set_use_local_space(bool p_use);
- bool is_using_local_space() const;
-
- void set_initial_velocity(const Vector2 &p_velocity);
- Vector2 get_initial_velocity() const;
+ virtual String get_configuration_warning() const;
- void set_emission_points(const PoolVector<Vector2> &p_points);
- PoolVector<Vector2> get_emission_points() const;
+ void set_v_frames(int p_count);
+ int get_v_frames() const;
- void pre_process(float p_delta);
- void reset();
+ void set_h_frames(int p_count);
+ int get_h_frames() const;
+ void restart();
+ Rect2 capture_rect() const;
Particles2D();
+ ~Particles2D();
};
-VARIANT_ENUM_CAST(Particles2D::ProcessMode);
-VARIANT_ENUM_CAST(Particles2D::Parameter);
+VARIANT_ENUM_CAST(Particles2D::DrawOrder)
#endif // PARTICLES_FRAME_H
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 68270ed771..fd261117e1 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -44,28 +44,6 @@ void PhysicsBody2D::_notification(int p_what) {
*/
}
-void PhysicsBody2D::set_one_way_collision_direction(const Vector2 &p_dir) {
-
- one_way_collision_direction = p_dir;
- Physics2DServer::get_singleton()->body_set_one_way_collision_direction(get_rid(), p_dir);
-}
-
-Vector2 PhysicsBody2D::get_one_way_collision_direction() const {
-
- return one_way_collision_direction;
-}
-
-void PhysicsBody2D::set_one_way_collision_max_depth(float p_depth) {
-
- one_way_collision_max_depth = p_depth;
- Physics2DServer::get_singleton()->body_set_one_way_collision_max_depth(get_rid(), p_depth);
-}
-
-float PhysicsBody2D::get_one_way_collision_max_depth() const {
-
- return one_way_collision_max_depth;
-}
-
void PhysicsBody2D::_set_layers(uint32_t p_mask) {
set_collision_layer(p_mask);
@@ -92,10 +70,6 @@ void PhysicsBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_layers", "mask"), &PhysicsBody2D::_set_layers);
ClassDB::bind_method(D_METHOD("_get_layers"), &PhysicsBody2D::_get_layers);
- ClassDB::bind_method(D_METHOD("set_one_way_collision_direction", "dir"), &PhysicsBody2D::set_one_way_collision_direction);
- ClassDB::bind_method(D_METHOD("get_one_way_collision_direction"), &PhysicsBody2D::get_one_way_collision_direction);
- ClassDB::bind_method(D_METHOD("set_one_way_collision_max_depth", "depth"), &PhysicsBody2D::set_one_way_collision_max_depth);
- ClassDB::bind_method(D_METHOD("get_one_way_collision_max_depth"), &PhysicsBody2D::get_one_way_collision_max_depth);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body:PhysicsBody2D"), &PhysicsBody2D::remove_collision_exception_with);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", 0), "_set_layers", "_get_layers"); //for backwards compat
@@ -103,9 +77,6 @@ void PhysicsBody2D::_bind_methods() {
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask");
- ADD_GROUP("", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "one_way_collision/direction"), "set_one_way_collision_direction", "get_one_way_collision_direction");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "one_way_collision/max_depth"), "set_one_way_collision_max_depth", "get_one_way_collision_max_depth");
}
void PhysicsBody2D::set_collision_layer(uint32_t p_layer) {
@@ -164,7 +135,6 @@ PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode)
collision_layer = 1;
collision_mask = 1;
- set_one_way_collision_max_depth(0);
set_pickable(false);
}
@@ -971,248 +941,105 @@ RigidBody2D::~RigidBody2D() {
//////////////////////////
-Variant KinematicBody2D::_get_collider() const {
-
- ObjectID oid = get_collider();
- if (oid == 0)
- return Variant();
- Object *obj = ObjectDB::get_instance(oid);
- if (!obj)
- return Variant();
-
- Reference *ref = obj->cast_to<Reference>();
- if (ref) {
- return Ref<Reference>(ref);
- }
-
- return obj;
-}
-
-void KinematicBody2D::revert_motion() {
+Dictionary KinematicBody2D::_move(const Vector2 &p_motion) {
+
+ Collision col;
+ if (move(p_motion, col)) {
+ Dictionary d;
+ d["position"] = col.collision;
+ d["normal"] = col.collision;
+ d["local_shape"] = col.local_shape;
+ d["travel"] = col.travel;
+ d["remainder"] = col.remainder;
+ d["collider_id"] = col.collider;
+ if (col.collider) {
+ d["collider"] = ObjectDB::get_instance(col.collider);
+ } else {
+ d["collider"] = Variant();
+ }
- Transform2D gt = get_global_transform();
- gt.elements[2] -= travel;
- travel = Vector2();
- set_global_transform(gt);
-}
+ d["collider_shape_index"] = col.collider_shape;
+ d["collider_metadata"] = col.collider_metadata;
-Vector2 KinematicBody2D::get_travel() const {
+ return d;
- return travel;
+ } else {
+ return Dictionary();
+ }
}
-Vector2 KinematicBody2D::move(const Vector2 &p_motion) {
-
-#if 1
+bool KinematicBody2D::move(const Vector2 &p_motion, Collision &r_collision) {
Transform2D gt = get_global_transform();
Physics2DServer::MotionResult result;
- colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result);
-
- collider_metadata = result.collider_metadata;
- collider_shape = result.collider_shape;
- collider_vel = result.collider_velocity;
- collision = result.collision_point;
- normal = result.collision_normal;
- collider = result.collider_id;
-
- gt.elements[2] += result.motion;
- set_global_transform(gt);
- travel = result.motion;
-
- return result.remainder;
-
-#else
- //give me back regular physics engine logic
- //this is madness
- //and most people using this function will think
- //what it does is simpler than using physics
- //this took about a week to get right..
- //but is it right? who knows at this point..
-
- colliding = false;
- ERR_FAIL_COND_V(!is_inside_tree(), Vector2());
- Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
- ERR_FAIL_COND_V(!dss, Vector2());
- const int max_shapes = 32;
- Vector2 sr[max_shapes * 2];
- int res_shapes;
-
- Set<RID> exclude;
- exclude.insert(get_rid());
-
- //recover first
- int recover_attempts = 4;
-
- bool collided = false;
- uint32_t mask = 0;
- if (true)
- mask |= Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY;
- if (true)
- mask |= Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
- if (true)
- mask |= Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY;
- if (true)
- mask |= Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
-
- //print_line("margin: "+rtos(margin));
- do {
-
- //motion recover
- for (int i = 0; i < get_shape_count(); i++) {
-
- if (is_shape_set_as_trigger(i))
- continue;
- if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), Vector2(), margin, sr, max_shapes, res_shapes, exclude, get_layer_mask(), mask))
- collided = true;
- }
-
- if (!collided)
- break;
-
- Vector2 recover_motion;
-
- for (int i = 0; i < res_shapes; i++) {
-
- Vector2 a = sr[i * 2 + 0];
- Vector2 b = sr[i * 2 + 1];
-
- float d = a.distance_to(b);
-
- /*
- if (d<margin)
- continue;
- */
- recover_motion += (b - a) * 0.4;
- }
-
- if (recover_motion == Vector2()) {
- collided = false;
- break;
- }
-
- Transform2D gt = get_global_transform();
- gt.elements[2] += recover_motion;
- set_global_transform(gt);
-
- recover_attempts--;
-
- } while (recover_attempts);
-
- //move second
- float safe = 1.0;
- float unsafe = 1.0;
- int best_shape = -1;
-
- for (int i = 0; i < get_shape_count(); i++) {
-
- if (is_shape_set_as_trigger(i))
- continue;
-
- float lsafe, lunsafe;
- bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0, lsafe, lunsafe, exclude, get_layer_mask(), mask);
- //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
- if (!valid) {
-
- safe = 0;
- unsafe = 0;
- best_shape = i; //sadly it's the best
- break;
- }
- if (lsafe == 1.0) {
- continue;
- }
- if (lsafe < safe) {
-
- safe = lsafe;
- unsafe = lunsafe;
- best_shape = i;
- }
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result);
+
+ if (colliding) {
+ r_collision.collider_metadata = result.collider_metadata;
+ r_collision.collider_shape = result.collider_shape;
+ r_collision.collider_vel = result.collider_velocity;
+ r_collision.collision = result.collision_point;
+ r_collision.normal = result.collision_normal;
+ r_collision.collider = result.collider_id;
+ r_collision.travel = result.motion;
+ r_collision.remainder = result.remainder;
+ r_collision.local_shape = result.collision_local_shape;
}
- //print_line("best shape: "+itos(best_shape)+" motion "+p_motion);
-
- if (safe >= 1) {
- //not collided
- colliding = false;
-
- } else {
-
- //it collided, let's get the rest info in unsafe advance
- Transform2D ugt = get_global_transform();
- ugt.elements[2] += p_motion * unsafe;
- Physics2DDirectSpaceState::ShapeRestInfo rest_info;
- bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt * get_shape_transform(best_shape), Vector2(), margin, &rest_info, exclude, get_layer_mask(), mask);
- if (!c2) {
- //should not happen, but floating point precision is so weird..
-
- colliding = false;
- } else {
-
- //print_line("Travel: "+rtos(travel));
- colliding = true;
- collision = rest_info.point;
- normal = rest_info.normal;
- collider = rest_info.collider_id;
- collider_vel = rest_info.linear_velocity;
- collider_shape = rest_info.shape;
- collider_metadata = rest_info.metadata;
- }
- }
-
- Vector2 motion = p_motion * safe;
- Transform2D gt = get_global_transform();
- gt.elements[2] += motion;
+ gt.elements[2] += result.motion;
set_global_transform(gt);
- return p_motion - motion;
-#endif
+ return colliding;
}
Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_bounces, float p_floor_max_angle) {
- Vector2 motion = (move_and_slide_floor_velocity + p_linear_velocity) * get_fixed_process_delta_time();
+ Vector2 motion = (floor_velocity + p_linear_velocity) * get_fixed_process_delta_time();
Vector2 lv = p_linear_velocity;
- move_and_slide_on_floor = false;
- move_and_slide_on_ceiling = false;
- move_and_slide_on_wall = false;
- move_and_slide_colliders.clear();
- move_and_slide_floor_velocity = Vector2();
+ on_floor = false;
+ on_ceiling = false;
+ on_wall = false;
+ colliders.clear();
+ floor_velocity = Vector2();
while (p_max_bounces) {
- motion = move(motion);
+ Collision collision;
+
+ bool collided = move(motion, collision);
- if (is_colliding()) {
+ if (collided) {
+
+ motion = collision.remainder;
if (p_floor_direction == Vector2()) {
//all is a wall
- move_and_slide_on_wall = true;
+ on_wall = true;
} else {
- if (get_collision_normal().dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
+ if (collision.normal.dot(p_floor_direction) >= Math::cos(p_floor_max_angle)) { //floor
- move_and_slide_on_floor = true;
- move_and_slide_floor_velocity = get_collider_velocity();
+ on_floor = true;
+ floor_velocity = collision.collider_vel;
- if (get_travel().length() < 1 && ABS((lv.x - move_and_slide_floor_velocity.x)) < p_slope_stop_min_velocity) {
- revert_motion();
+ if (collision.travel.length() < 1 && ABS((lv.x - floor_velocity.x)) < p_slope_stop_min_velocity) {
+ Transform2D gt = get_global_transform();
+ gt.elements[2] -= collision.travel;
+ set_global_transform(gt);
return Vector2();
}
- } else if (get_collision_normal().dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
- move_and_slide_on_ceiling = true;
+ } else if (collision.normal.dot(-p_floor_direction) >= Math::cos(p_floor_max_angle)) { //ceiling
+ on_ceiling = true;
} else {
- move_and_slide_on_wall = true;
+ on_wall = true;
}
}
- Vector2 n = get_collision_normal();
+ Vector2 n = collision.normal;
motion = motion.slide(n);
lv = lv.slide(n);
- Variant collider = _get_collider();
- if (collider.get_type() != Variant::NIL) {
- move_and_slide_colliders.push_back(collider);
- }
+
+ colliders.push_back(collision);
} else {
break;
@@ -1226,26 +1053,22 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
return lv;
}
-bool KinematicBody2D::is_move_and_slide_on_floor() const {
+bool KinematicBody2D::is_on_floor() const {
- return move_and_slide_on_floor;
+ return on_floor;
}
-bool KinematicBody2D::is_move_and_slide_on_wall() const {
+bool KinematicBody2D::is_on_wall() const {
- return move_and_slide_on_wall;
+ return on_wall;
}
-bool KinematicBody2D::is_move_and_slide_on_ceiling() const {
+bool KinematicBody2D::is_on_ceiling() const {
- return move_and_slide_on_ceiling;
+ return on_ceiling;
}
-Array KinematicBody2D::get_move_and_slide_colliders() const {
- return move_and_slide_colliders;
-}
+Vector2 KinematicBody2D::get_floor_velocity() const {
-Vector2 KinematicBody2D::move_to(const Vector2 &p_position) {
-
- return move(p_position - get_global_position());
+ return floor_velocity;
}
bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion) {
@@ -1255,98 +1078,123 @@ bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_moti
return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, margin);
}
-Vector2 KinematicBody2D::get_collision_pos() const {
+void KinematicBody2D::set_safe_margin(float p_margin) {
- ERR_FAIL_COND_V(!colliding, Vector2());
- return collision;
+ margin = p_margin;
}
-Vector2 KinematicBody2D::get_collision_normal() const {
+float KinematicBody2D::get_safe_margin() const {
- ERR_FAIL_COND_V(!colliding, Vector2());
- return normal;
+ return margin;
}
-Vector2 KinematicBody2D::get_collider_velocity() const {
+int KinematicBody2D::get_collision_count() const {
- return collider_vel;
+ return colliders.size();
}
+Vector2 KinematicBody2D::get_collision_position(int p_collision) const {
-ObjectID KinematicBody2D::get_collider() const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2());
- ERR_FAIL_COND_V(!colliding, 0);
- return collider;
+ return colliders[p_collision].collision;
}
-
-int KinematicBody2D::get_collider_shape() const {
-
- ERR_FAIL_COND_V(!colliding, 0);
- return collider_shape;
+Vector2 KinematicBody2D::get_collision_normal(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2());
+ return colliders[p_collision].normal;
}
-Variant KinematicBody2D::get_collider_metadata() const {
-
- ERR_FAIL_COND_V(!colliding, 0);
- return collider_metadata;
+Vector2 KinematicBody2D::get_collision_travel(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2());
+ return colliders[p_collision].travel;
}
-
-bool KinematicBody2D::is_colliding() const {
-
- return colliding;
+Vector2 KinematicBody2D::get_collision_remainder(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2());
+ return colliders[p_collision].remainder;
}
+Object *KinematicBody2D::get_collision_local_shape(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL);
+ uint32_t owner = shape_find_owner(colliders[p_collision].local_shape);
+ return shape_owner_get_owner(owner);
+}
+Object *KinematicBody2D::get_collision_collider(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL);
-void KinematicBody2D::set_collision_margin(float p_margin) {
+ if (colliders[p_collision].collider) {
+ return ObjectDB::get_instance(colliders[p_collision].collider);
+ }
- margin = p_margin;
+ return NULL;
}
+ObjectID KinematicBody2D::get_collision_collider_id(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), 0);
-float KinematicBody2D::get_collision_margin() const {
+ return colliders[p_collision].collider;
+}
+Object *KinematicBody2D::get_collision_collider_shape(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), NULL);
+ Object *collider = get_collision_collider(p_collision);
+ if (collider) {
+ CollisionObject2D *obj2d = collider->cast_to<CollisionObject2D>();
+ if (obj2d) {
+ uint32_t owner = shape_find_owner(colliders[p_collision].collider_shape);
+ return obj2d->shape_owner_get_owner(owner);
+ }
+ }
- return margin;
+ return NULL;
+}
+int KinematicBody2D::get_collision_collider_shape_index(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), -1);
+ return colliders[p_collision].collider_shape;
+}
+Vector2 KinematicBody2D::get_collision_collider_velocity(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Vector2());
+ return colliders[p_collision].collider_vel;
+}
+Variant KinematicBody2D::get_collision_collider_metadata(int p_collision) const {
+ ERR_FAIL_INDEX_V(p_collision, colliders.size(), Variant());
+ return colliders[p_collision].collider_metadata;
}
void KinematicBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::move);
- ClassDB::bind_method(D_METHOD("move_to", "position"), &KinematicBody2D::move_to);
+ ClassDB::bind_method(D_METHOD("move", "rel_vec"), &KinematicBody2D::_move);
ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody2D::test_move);
- ClassDB::bind_method(D_METHOD("get_travel"), &KinematicBody2D::get_travel);
- ClassDB::bind_method(D_METHOD("revert_motion"), &KinematicBody2D::revert_motion);
- ClassDB::bind_method(D_METHOD("is_colliding"), &KinematicBody2D::is_colliding);
+ ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor);
+ ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling);
+ ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall);
+ ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity);
- ClassDB::bind_method(D_METHOD("get_collision_pos"), &KinematicBody2D::get_collision_pos);
- ClassDB::bind_method(D_METHOD("get_collision_normal"), &KinematicBody2D::get_collision_normal);
- ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicBody2D::get_collider_velocity);
- ClassDB::bind_method(D_METHOD("get_collider:Variant"), &KinematicBody2D::_get_collider);
- ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicBody2D::get_collider_shape);
- ClassDB::bind_method(D_METHOD("get_collider_metadata:Variant"), &KinematicBody2D::get_collider_metadata);
- ClassDB::bind_method(D_METHOD("get_move_and_slide_colliders"), &KinematicBody2D::get_move_and_slide_colliders);
- ClassDB::bind_method(D_METHOD("is_move_and_slide_on_floor"), &KinematicBody2D::is_move_and_slide_on_floor);
- ClassDB::bind_method(D_METHOD("is_move_and_slide_on_ceiling"), &KinematicBody2D::is_move_and_slide_on_ceiling);
- ClassDB::bind_method(D_METHOD("is_move_and_slide_on_wall"), &KinematicBody2D::is_move_and_slide_on_wall);
+ ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin);
+ ClassDB::bind_method(D_METHOD("get_safe_margin", "pixels"), &KinematicBody2D::get_safe_margin);
- ClassDB::bind_method(D_METHOD("set_collision_margin", "pixels"), &KinematicBody2D::set_collision_margin);
- ClassDB::bind_method(D_METHOD("get_collision_margin", "pixels"), &KinematicBody2D::get_collision_margin);
+ ClassDB::bind_method(D_METHOD("get_collision_count"), &KinematicBody2D::get_collision_count);
+ ClassDB::bind_method(D_METHOD("get_collision_position", "collision"), &KinematicBody2D::get_collision_position);
+ ClassDB::bind_method(D_METHOD("get_collision_normal", "collision"), &KinematicBody2D::get_collision_normal);
+ ClassDB::bind_method(D_METHOD("get_collision_travel", "collision"), &KinematicBody2D::get_collision_travel);
+ ClassDB::bind_method(D_METHOD("get_collision_remainder", "collision"), &KinematicBody2D::get_collision_remainder);
+ ClassDB::bind_method(D_METHOD("get_collision_local_shape", "collision"), &KinematicBody2D::get_collision_local_shape);
+ ClassDB::bind_method(D_METHOD("get_collision_collider", "collision"), &KinematicBody2D::get_collision_collider);
+ ClassDB::bind_method(D_METHOD("get_collision_collider_id", "collision"), &KinematicBody2D::get_collision_collider_id);
+ ClassDB::bind_method(D_METHOD("get_collision_collider_shape", "collision"), &KinematicBody2D::get_collision_collider_shape);
+ ClassDB::bind_method(D_METHOD("get_collision_collider_shape_index", "collision"), &KinematicBody2D::get_collision_collider_shape_index);
+ ClassDB::bind_method(D_METHOD("get_collision_collider_velocity", "collision"), &KinematicBody2D::get_collision_collider_velocity);
+ ClassDB::bind_method(D_METHOD("get_collision_collider_metadata", "collision"), &KinematicBody2D::get_collision_collider_metadata);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_collision_margin", "get_collision_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin");
}
KinematicBody2D::KinematicBody2D()
: PhysicsBody2D(Physics2DServer::BODY_MODE_KINEMATIC) {
- colliding = false;
- collider = 0;
-
- collider_shape = 0;
-
margin = 0.08;
- move_and_slide_on_floor = false;
- move_and_slide_on_ceiling = false;
- move_and_slide_on_wall = false;
+ on_floor = false;
+ on_ceiling = false;
+ on_wall = false;
}
KinematicBody2D::~KinematicBody2D() {
}
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 50c9865f18..8c8e4ebc77 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -40,8 +40,6 @@ class PhysicsBody2D : public CollisionObject2D {
uint32_t collision_layer;
uint32_t collision_mask;
- Vector2 one_way_collision_direction;
- float one_way_collision_max_depth;
void _set_layers(uint32_t p_mask);
uint32_t _get_layers() const;
@@ -68,12 +66,6 @@ public:
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
- void set_one_way_collision_direction(const Vector2 &p_dir);
- Vector2 get_one_way_collision_direction() const;
-
- void set_one_way_collision_max_depth(float p_dir);
- float get_one_way_collision_max_depth() const;
-
PhysicsBody2D();
};
@@ -272,54 +264,60 @@ class KinematicBody2D : public PhysicsBody2D {
GDCLASS(KinematicBody2D, PhysicsBody2D);
+public:
+ struct Collision {
+ Vector2 collision;
+ Vector2 normal;
+ Vector2 collider_vel;
+ ObjectID collider;
+ int collider_shape;
+ Variant collider_metadata;
+ Vector2 remainder;
+ Vector2 travel;
+ int local_shape;
+ };
+
+private:
float margin;
- bool colliding;
- Vector2 collision;
- Vector2 normal;
- Vector2 collider_vel;
- ObjectID collider;
- int collider_shape;
- Variant collider_metadata;
- Vector2 travel;
-
- Vector2 move_and_slide_floor_velocity;
- bool move_and_slide_on_floor;
- bool move_and_slide_on_ceiling;
- bool move_and_slide_on_wall;
- Array move_and_slide_colliders;
-
- Variant _get_collider() const;
+
+ Vector2 floor_velocity;
+ bool on_floor;
+ bool on_ceiling;
+ bool on_wall;
+ Vector<Collision> colliders;
_FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
+ Dictionary _move(const Vector2 &p_motion);
+
protected:
static void _bind_methods();
public:
- Vector2 move(const Vector2 &p_motion);
- Vector2 move_to(const Vector2 &p_position);
-
+ bool move(const Vector2 &p_motion, Collision &r_collision);
bool test_move(const Transform2D &p_from, const Vector2 &p_motion);
- bool is_colliding() const;
-
- Vector2 get_travel() const;
- void revert_motion();
-
- Vector2 get_collision_pos() const;
- Vector2 get_collision_normal() const;
- Vector2 get_collider_velocity() const;
- ObjectID get_collider() const;
- int get_collider_shape() const;
- Variant get_collider_metadata() const;
- void set_collision_margin(float p_margin);
- float get_collision_margin() const;
+ void set_safe_margin(float p_margin);
+ float get_safe_margin() const;
Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), float p_slope_stop_min_velocity = 5, int p_max_bounces = 4, float p_floor_max_angle = Math::deg2rad((float)45));
- bool is_move_and_slide_on_floor() const;
- bool is_move_and_slide_on_wall() const;
- bool is_move_and_slide_on_ceiling() const;
- Array get_move_and_slide_colliders() const;
+ bool is_on_floor() const;
+ bool is_on_wall() const;
+ bool is_on_ceiling() const;
+ Vector2 get_floor_velocity() const;
+
+ int get_collision_count() const;
+ Vector2 get_collision_position(int p_collision) const;
+ Vector2 get_collision_normal(int p_collision) const;
+ Vector2 get_collision_travel(int p_collision) const;
+ Vector2 get_collision_remainder(int p_collision) const;
+ Object *get_collision_local_shape(int p_collision) const;
+ Object *get_collision_collider(int p_collision) const;
+ ObjectID get_collision_collider_id(int p_collision) const;
+ Object *get_collision_collider_shape(int p_collision) const;
+ int get_collision_collider_shape_index(int p_collision) const;
+ Vector2 get_collision_collider_velocity(int p_collision) const;
+ Variant get_collision_collider_metadata(int p_collision) const;
KinematicBody2D();
~KinematicBody2D();
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index c1eb90e52a..450f8e2474 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -65,11 +65,13 @@ void Sprite::_notification(int p_what) {
Size2 s;
Rect2 src_rect;
+ bool filter_clip = false;
if (region) {
s = region_rect.size;
src_rect = region_rect;
+ filter_clip = region_filter_clip;
} else {
s = Size2(texture->get_size());
s = s / Size2(hframes, vframes);
@@ -93,7 +95,7 @@ void Sprite::_notification(int p_what) {
if (vflip)
dst_rect.size.y = -dst_rect.size.y;
- texture->draw_rect_region(ci, dst_rect, src_rect);
+ texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip);
} break;
}
@@ -109,17 +111,30 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) {
}
#endif
texture = p_texture;
+ /* this should no longer be needed in 3.0
#ifdef DEBUG_ENABLED
if (texture.is_valid()) {
texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->update);
}
#endif
+*/
update();
emit_signal("texture_changed");
item_rect_changed();
}
+void Sprite::set_normal_map(const Ref<Texture> &p_texture) {
+
+ normal_map = p_texture;
+ update();
+}
+
+Ref<Texture> Sprite::get_normal_map() const {
+
+ return normal_map;
+}
+
Ref<Texture> Sprite::get_texture() const {
return texture;
@@ -201,6 +216,15 @@ Rect2 Sprite::get_region_rect() const {
return region_rect;
}
+void Sprite::set_region_filter_clip(bool p_enable) {
+ region_filter_clip = p_enable;
+ update();
+}
+
+bool Sprite::is_region_filter_clip_enabled() const {
+ return region_filter_clip;
+}
+
void Sprite::set_frame(int p_frame) {
ERR_FAIL_INDEX(p_frame, vframes * hframes);
@@ -289,6 +313,9 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture:Texture"), &Sprite::set_texture);
ClassDB::bind_method(D_METHOD("get_texture:Texture"), &Sprite::get_texture);
+ ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map:Texture"), &Sprite::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map:Texture"), &Sprite::get_normal_map);
+
ClassDB::bind_method(D_METHOD("set_centered", "centered"), &Sprite::set_centered);
ClassDB::bind_method(D_METHOD("is_centered"), &Sprite::is_centered);
@@ -307,6 +334,9 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite::set_region_rect);
ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite::get_region_rect);
+ ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite::set_region_filter_clip);
+ ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite::is_region_filter_clip_enabled);
+
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &Sprite::get_frame);
@@ -320,15 +350,21 @@ void Sprite::_bind_methods() {
ADD_SIGNAL(MethodInfo("texture_changed"));
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+ ADD_GROUP("Offset", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
+ ADD_GROUP("Animation", "");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region"), "set_region", "is_region");
+
+ ADD_GROUP("Region", "region_");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled");
}
Sprite::Sprite() {
@@ -337,6 +373,7 @@ Sprite::Sprite() {
hflip = false;
vflip = false;
region = false;
+ region_filter_clip = false;
frame = 0;
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index 86ef335d42..d3f9a5f032 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -38,6 +38,7 @@ class Sprite : public Node2D {
GDCLASS(Sprite, Node2D);
Ref<Texture> texture;
+ Ref<Texture> normal_map;
bool centered;
Point2 offset;
@@ -46,6 +47,7 @@ class Sprite : public Node2D {
bool vflip;
bool region;
Rect2 region_rect;
+ bool region_filter_clip;
int frame;
@@ -67,6 +69,9 @@ public:
void set_texture(const Ref<Texture> &p_texture);
Ref<Texture> get_texture() const;
+ void set_normal_map(const Ref<Texture> &p_texture);
+ Ref<Texture> get_normal_map() const;
+
void set_centered(bool p_center);
bool is_centered() const;
@@ -82,6 +87,9 @@ public:
void set_region(bool p_region);
bool is_region() const;
+ void set_region_filter_clip(bool p_enable);
+ bool is_region_filter_clip_enabled() const;
+
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 4f892a31fc..57e25ec609 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "tile_map.h"
#include "io/marshalls.h"
-#include "method_bind_ext.inc"
+#include "method_bind_ext.gen.inc"
#include "os/os.h"
#include "servers/physics_2d_server.h"
@@ -441,35 +441,36 @@ void TileMap::_update_dirty_quadrants() {
rect.position.y -= center.y;
}
+ Ref<Texture> normal_map = tile_set->tile_get_normal_map(c.id);
Color modulate = tile_set->tile_get_modulate(c.id);
Color self_modulate = get_self_modulate();
modulate = Color(modulate.r * self_modulate.r, modulate.g * self_modulate.g,
modulate.b * self_modulate.b, modulate.a * self_modulate.a);
if (r == Rect2()) {
- tex->draw_rect(canvas_item, rect, false, modulate, c.transpose);
+ tex->draw_rect(canvas_item, rect, false, modulate, c.transpose, normal_map);
} else {
- tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose);
+ tex->draw_rect_region(canvas_item, rect, r, modulate, c.transpose, normal_map);
}
- Vector<Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id);
+ Vector<TileSet::ShapeData> shapes = tile_set->tile_get_shapes(c.id);
for (int i = 0; i < shapes.size(); i++) {
- Ref<Shape2D> shape = shapes[i];
+ Ref<Shape2D> shape = shapes[i].shape;
if (shape.is_valid()) {
-
- Vector2 shape_ofs = tile_set->tile_get_shape_offset(c.id);
Transform2D xform;
xform.set_origin(offset.floor());
- _fix_cell_transform(xform, c, shape_ofs + center_ofs, s);
+ _fix_cell_transform(xform, c, shapes[i].shape_offset + center_ofs, s);
if (debug_canvas_item.is_valid()) {
vs->canvas_item_add_set_transform(debug_canvas_item, xform);
shape->draw(debug_canvas_item, debug_collision_color);
}
ps->body_add_shape(q.body, shape->get_rid(), xform);
- ps->body_set_shape_metadata(q.body, shape_idx++, Vector2(E->key().x, E->key().y));
+ shape_idx++;
+ ps->body_set_shape_as_one_way_collision(q.body, shape_idx, shapes[i].one_way_collision);
+ ps->body_set_shape_metadata(q.body, shape_idx, Vector2(E->key().x, E->key().y));
}
}