diff options
80 files changed, 2801 insertions, 2890 deletions
diff --git a/core/class_db.cpp b/core/class_db.cpp index 1fe02c8cd9..6b8c290a99 100644 --- a/core/class_db.cpp +++ b/core/class_db.cpp @@ -497,7 +497,7 @@ void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherit } } -void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance) { +void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance, bool p_exclude_from_properties) { OBJTYPE_RLOCK; @@ -528,6 +528,9 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b minfo.name = E->get(); minfo.id = method->get_method_id(); + if (p_exclude_from_properties && type->methods_in_properties.has(minfo.name)) + continue; + for (int i = 0; i < method->get_argument_count(); i++) { //Variant::Type t=method->get_argument_type(i); @@ -802,7 +805,14 @@ void ClassDB::add_property(StringName p_class, const PropertyInfo &p_pinfo, cons OBJTYPE_WLOCK type->property_list.push_back(p_pinfo); - +#ifdef DEBUG_METHODS_ENABLED + if (mb_get) { + type->methods_in_properties.insert(p_getter); + } + if (mb_set) { + type->methods_in_properties.insert(p_setter); + } +#endif PropertySetGet psg; psg.setter = p_setter; psg.getter = p_getter; diff --git a/core/class_db.h b/core/class_db.h index 547068da5f..4f00a16e91 100644 --- a/core/class_db.h +++ b/core/class_db.h @@ -139,6 +139,7 @@ public: #ifdef DEBUG_METHODS_ENABLED List<StringName> constant_order; List<StringName> method_order; + Set<StringName> methods_in_properties; List<MethodInfo> virtual_methods; StringName category; #endif @@ -486,7 +487,7 @@ public: static bool has_method(StringName p_class, StringName p_method, bool p_no_inheritance = false); static void set_method_flags(StringName p_class, StringName p_method, int p_flags); - static void get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false); + static void get_method_list(StringName p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false); static MethodBind *get_method(StringName p_class, StringName p_name); static void add_virtual_method(const StringName &p_class, const MethodInfo &p_method, bool p_virtual = true); diff --git a/core/image.cpp b/core/image.cpp index ec21260b19..023a058667 100644 --- a/core/image.cpp +++ b/core/image.cpp @@ -1646,6 +1646,62 @@ void Image::blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Po } } +void Image::blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest) { + + ERR_FAIL_COND(p_src.is_null()); + ERR_FAIL_COND(p_mask.is_null()); + int dsize = data.size(); + int srcdsize = p_src->data.size(); + int maskdsize = p_mask->data.size(); + ERR_FAIL_COND(dsize == 0); + ERR_FAIL_COND(srcdsize == 0); + ERR_FAIL_COND(maskdsize == 0); + ERR_FAIL_COND(p_src->width != p_mask->width); + ERR_FAIL_COND(p_src->height != p_mask->height); + ERR_FAIL_COND(format != p_src->format); + + Rect2i clipped_src_rect = Rect2i(0, 0, p_src->width, p_src->height).clip(p_src_rect); + if (clipped_src_rect.size.x <= 0 || clipped_src_rect.size.y <= 0) + return; + + Rect2i dest_rect = Rect2i(0, 0, width, height).clip(Rect2i(p_dest, clipped_src_rect.size)); + + PoolVector<uint8_t>::Write wp = data.write(); + uint8_t *dst_data_ptr = wp.ptr(); + + PoolVector<uint8_t>::Read rp = p_src->data.read(); + const uint8_t *src_data_ptr = rp.ptr(); + + int pixel_size = get_format_pixel_size(format); + + Ref<Image> msk = p_mask; + msk->lock(); + + for (int i = 0; i < dest_rect.size.y; i++) { + + for (int j = 0; j < dest_rect.size.x; j++) { + + int src_x = clipped_src_rect.position.x + j; + int src_y = clipped_src_rect.position.y + i; + + if (msk->get_pixel(src_x, src_y).a != 0) { + + int dst_x = dest_rect.position.x + j; + int dst_y = dest_rect.position.y + i; + + const uint8_t *src = &src_data_ptr[(src_y * p_src->width + src_x) * pixel_size]; + uint8_t *dst = &dst_data_ptr[(dst_y * width + dst_x) * pixel_size]; + + for (int k = 0; k < pixel_size; k++) { + dst[k] = src[k]; + } + } + } + } + + msk->unlock(); +} + void Image::blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest) { ERR_FAIL_COND(p_src.is_null()); @@ -2167,7 +2223,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset); - ClassDB::bind_method(D_METHOD("resize_to_po2", "square"), &Image::resize_to_po2, DEFVAL("false")); + ClassDB::bind_method(D_METHOD("resize_to_po2", "square"), &Image::resize_to_po2, DEFVAL(false)); ClassDB::bind_method(D_METHOD("resize", "width", "height", "interpolation"), &Image::resize, DEFVAL(INTERPOLATE_BILINEAR)); ClassDB::bind_method(D_METHOD("shrink_x2"), &Image::shrink_x2); ClassDB::bind_method(D_METHOD("expand_x2_hq2x"), &Image::expand_x2_hq2x); @@ -2199,6 +2255,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("normalmap_to_xy"), &Image::normalmap_to_xy); ClassDB::bind_method(D_METHOD("blit_rect", "src:Image", "src_rect", "dst"), &Image::blit_rect); + ClassDB::bind_method(D_METHOD("blit_rect_mask", "src:Image", "mask:Image", "src_rect", "dst"), &Image::blit_rect_mask); ClassDB::bind_method(D_METHOD("blend_rect", "src:Image", "src_rect", "dst"), &Image::blend_rect); ClassDB::bind_method(D_METHOD("blend_rect_mask", "src:Image", "mask:Image", "src_rect", "dst"), &Image::blend_rect_mask); ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill); diff --git a/core/image.h b/core/image.h index 3323afdc4b..e523f703fa 100644 --- a/core/image.h +++ b/core/image.h @@ -283,6 +283,7 @@ public: void normalmap_to_xy(); void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); + void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest); void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest); void fill(const Color &c); diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp index dbdf9628e3..e60f588be3 100644 --- a/core/os/input_event.cpp +++ b/core/os/input_event.cpp @@ -89,6 +89,11 @@ bool InputEvent::action_match(const Ref<InputEvent> &p_event) const { return false; } +bool InputEvent::shortcut_match(const Ref<InputEvent> &p_event) const { + + return false; +} + bool InputEvent::is_action_type() const { return false; @@ -130,6 +135,7 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text); ClassDB::bind_method(D_METHOD("action_match", "event:InputEvent"), &InputEvent::action_match); + ClassDB::bind_method(D_METHOD("shortcut_match", "event:InputEvent"), &InputEvent::shortcut_match); ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); @@ -276,6 +282,27 @@ uint32_t InputEventKey::get_scancode_with_modifiers() const { return sc; } +String InputEventKey::as_text() const { + + String kc = keycode_get_string(scancode); + if (kc == String()) + return kc; + + if (get_metakey()) { + kc = "Meta+" + kc; + } + if (get_alt()) { + kc = "Alt+" + kc; + } + if (get_shift()) { + kc = "Shift+" + kc; + } + if (get_control()) { + kc = "Ctrl+" + kc; + } + return kc; +} + bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { Ref<InputEventKey> key = p_event; @@ -288,6 +315,18 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event) const { return get_scancode() == key->get_scancode() && (!key->is_pressed() || (code & event_code) == code); } +bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const { + + Ref<InputEventKey> key = p_event; + if (key.is_null()) + return false; + + uint32_t code = get_scancode_with_modifiers(); + uint32_t event_code = key->get_scancode_with_modifiers(); + + return code == event_code; +} + void InputEventKey::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventKey::set_pressed); diff --git a/core/os/input_event.h b/core/os/input_event.h index 6a694df345..b120d4b840 100644 --- a/core/os/input_event.h +++ b/core/os/input_event.h @@ -165,6 +165,7 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const; InputEvent(); @@ -243,9 +244,12 @@ public: uint32_t get_scancode_with_modifiers() const; virtual bool action_match(const Ref<InputEvent> &p_event) const; + virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; virtual bool is_action_type() const { return true; } + virtual String as_text() const; + InputEventKey(); }; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 913aa62452..96c3da99f0 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -977,6 +977,27 @@ void RasterizerSceneGLES3::environment_set_fog_height(RID p_env, bool p_enable, env->fog_height_curve = p_height_curve; } +bool RasterizerSceneGLES3::is_environment(RID p_env) { + + return environment_owner.owns(p_env); +} + +VS::EnvironmentBG RasterizerSceneGLES3::environment_get_background(RID p_env) { + + const Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX); + + return env->bg_mode; +} + +int RasterizerSceneGLES3::environment_get_canvas_max_layer(RID p_env) { + + const Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND_V(!env, -1); + + return env->canvas_max_layer; +} + RID RasterizerSceneGLES3::light_instance_create(RID p_light) { LightInstance *light_instance = memnew(LightInstance); @@ -3561,7 +3582,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glUniform2iv(state.exposure_shader.get_uniform(ExposureShaderGLES3::SOURCE_RENDER_SIZE), 1, ss); glUniform2iv(state.exposure_shader.get_uniform(ExposureShaderGLES3::TARGET_SIZE), 1, ds); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse); + glBindTexture(GL_TEXTURE_2D, composite_from); glBindFramebuffer(GL_FRAMEBUFFER, exposure_shrink[0].fbo); glViewport(0, 0, exposure_shrink_size, exposure_shrink_size); @@ -3957,6 +3978,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; + use_mrt = use_mrt && env && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); @@ -4020,6 +4042,10 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->frame.clear_request = false; } + } else if (env->bg_mode == VS::ENV_BG_CANVAS) { + + clear_color = env->bg_color.to_linear(); + storage->frame.clear_request = false; } else if (env->bg_mode == VS::ENV_BG_COLOR) { clear_color = env->bg_color.to_linear(); @@ -4037,7 +4063,39 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->frame.clear_request = false; } - glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular + if (!env || env->bg_mode != VS::ENV_BG_KEEP) { + glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular + } + + if (env && env->bg_mode == VS::ENV_BG_CANVAS) { + //copy canvas to 3d buffer and convert it to linear + + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); + + storage->shaders.copy.bind(); + + _copy_screen(); + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + } state.texscreen_copied = false; diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 3e15da52ab..c52a00bf17 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -536,6 +536,11 @@ public: virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve); virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); + virtual bool is_environment(RID p_env); + + virtual VS::EnvironmentBG environment_get_background(RID p_env); + virtual int environment_get_canvas_max_layer(RID p_env); + /* LIGHT INSTANCE */ struct LightDataUBO { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 81baf542c0..f7e1fdee9d 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5288,6 +5288,7 @@ void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_de if (particles->clear) { particles->cycle_number = 0; + particles->random_seed = Math::rand(); } else if (new_phase < particles->phase) { particles->cycle_number++; } @@ -5298,6 +5299,8 @@ void RasterizerStorageGLES3::_particles_process(Particles *particles, float p_de shaders.particles.set_uniform(ParticlesShaderGLES3::DELTA, p_delta * particles->speed_scale); shaders.particles.set_uniform(ParticlesShaderGLES3::CLEAR, particles->clear); + glUniform1ui(shaders.particles.get_uniform_location(ParticlesShaderGLES3::RANDOM_SEED), particles->random_seed); + if (particles->use_local_coords) shaders.particles.set_uniform(ParticlesShaderGLES3::EMISSION_TRANSFORM, Transform()); else @@ -5353,6 +5356,33 @@ void RasterizerStorageGLES3::update_particles() { Particles *particles = particle_update_list.first()->self(); + if (particles->inactive && !particles->emitting) { + + particle_update_list.remove(particle_update_list.first()); + continue; + } + + if (particles->emitting) { + if (particles->inactive) { + //restart system from scratch + particles->prev_ticks = 0; + particles->phase = 0; + particles->prev_phase = 0; + particles->clear = true; + particles->particle_valid_histories[0] = false; + particles->particle_valid_histories[1] = false; + } + particles->inactive = false; + particles->inactive_time = 0; + } else { + particles->inactive_time += particles->speed_scale * frame.delta; + if (particles->inactive_time > particles->lifetime * 1.2) { + particles->inactive = true; + particle_update_list.remove(particle_update_list.first()); + continue; + } + } + Material *material = material_owner.getornull(particles->process_material); if (!material || !material->shader || material->shader->mode != VS::SHADER_PARTICLES) { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index ca0194bd5e..65026a16ec 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -1033,6 +1033,8 @@ public: struct Particles : public GeometryOwner { + bool inactive; + float inactive_time; bool emitting; int amount; float lifetime; @@ -1060,6 +1062,7 @@ public: float phase; float prev_phase; uint64_t prev_ticks; + uint32_t random_seed; uint32_t cycle_number; @@ -1088,6 +1091,7 @@ public: frame_remainder = 0; histories_enabled = false; speed_scale = 1.0; + random_seed = 0; custom_aabb = Rect3(Vector3(-4, -4, -4), Vector3(8, 8, 8)); @@ -1098,6 +1102,8 @@ public: prev_ticks = 0; clear = true; + inactive = true; + inactive_time = false; glGenBuffers(2, particle_buffers); glGenVertexArrays(2, particle_vaos); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 3376f99112..41421a3e2f 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -795,6 +795,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index"; actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; + actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index 4c8648903e..b0fb525e20 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -129,6 +129,11 @@ void main() { color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308))); #endif +#ifdef SRGB_TO_LINEAR + + color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1 + 0.055)),vec3(2.4)),color.rgb * (1.0 / 12.92),lessThan(color.rgb,vec3(0.04045))); +#endif + #ifdef DEBUG_GRADIENT color.rg=uv_interp; color.b=0.0; diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index 7e7b083f73..ec2577538c 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -37,6 +37,7 @@ uniform bool clear; uniform uint cycle; uniform float lifetime; uniform mat4 emission_transform; +uniform uint random_seed; out highp vec4 out_color; //tfb: @@ -104,7 +105,9 @@ void main() { bool shader_active = velocity_active.a > 0.5; if (system_phase > prev_system_phase) { - if (prev_system_phase < restart_phase && system_phase >= restart_phase) { + // restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed + + if (restart_phase >= prev_system_phase && restart_phase < system_phase ) { restart=true; #ifdef USE_FRACTIONAL_DELTA local_delta = (system_phase - restart_phase) * lifetime; @@ -112,12 +115,12 @@ void main() { } } else { - if (prev_system_phase < restart_phase) { + if (restart_phase >= prev_system_phase) { restart=true; #ifdef USE_FRACTIONAL_DELTA local_delta = (1.0 - restart_phase + system_phase) * lifetime; #endif - } else if (system_phase >= restart_phase) { + } else if (restart_phase < system_phase ) { restart=true; #ifdef USE_FRACTIONAL_DELTA local_delta = (system_phase - restart_phase) * lifetime; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 56b62cdf6e..04257b8cd1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -77,7 +77,6 @@ #include "plugins/curve_editor_plugin.h" #include "plugins/gi_probe_editor_plugin.h" #include "plugins/gradient_editor_plugin.h" -#include "plugins/gradient_texture_editor_plugin.h" #include "plugins/item_list_editor_plugin.h" #include "plugins/light_occluder_2d_editor_plugin.h" #include "plugins/line_2d_editor_plugin.h" @@ -5311,36 +5310,6 @@ EditorNode::EditorNode() { top_region->add_child(left_menu_hb); menu_hb->add_child(top_region); - PopupMenu *p; - - project_menu = memnew(MenuButton); - project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools.")); - project_menu->set_text(TTR("Project")); - project_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); - left_menu_hb->add_child(project_menu); - - p = project_menu->get_popup(); - p->connect("id_pressed", this, "_menu_option"); - p->add_item(TTR("Run Script"), FILE_RUN_SCRIPT, KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_R); - p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); - - PopupMenu *tool_menu = memnew(PopupMenu); - tool_menu->set_name("Tools"); - tool_menu->connect("id_pressed", this, "_menu_option"); - p->add_child(tool_menu); - p->add_submenu_item(TTR("Tools"), "Tools"); - tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); - p->add_separator(); - p->add_item(TTR("Project Settings"), RUN_SETTINGS); - p->add_separator(); - -#ifdef OSX_ENABLED - p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q); -#else - p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Q); -#endif - p->add_item(TTR("Quit"), FILE_QUIT, KEY_MASK_CMD + KEY_Q); - file_menu = memnew(MenuButton); file_menu->set_text(TTR("Scene")); //file_menu->set_icon(gui_base->get_icon("Save","EditorIcons")); @@ -5360,6 +5329,7 @@ EditorNode::EditorNode() { ED_SHORTCUT("editor/next_tab", TTR("Next tab"), KEY_MASK_CMD + KEY_TAB); ED_SHORTCUT("editor/prev_tab", TTR("Previous tab"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_TAB); ED_SHORTCUT("editor/filter_files", TTR("Filter Files.."), KEY_MASK_ALT + KEY_MASK_CMD + KEY_P); + PopupMenu *p; file_menu->set_tooltip(TTR("Operations with scene files.")); p = file_menu->get_popup(); @@ -5379,7 +5349,6 @@ EditorNode::EditorNode() { p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene.."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCENE); p->add_shortcut(ED_SHORTCUT("editor/quick_open_script", TTR("Quick Open Script.."), KEY_MASK_ALT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCRIPT); p->add_separator(); - PopupMenu *pm_export = memnew(PopupMenu); pm_export->set_name("Export"); p->add_child(pm_export); @@ -5405,6 +5374,35 @@ EditorNode::EditorNode() { sp->set_custom_minimum_size(Size2(30, 0) * EDSCALE); menu_hb->add_child(sp); } + p->add_separator(); + p->add_item(TTR("Quit"), FILE_QUIT, KEY_MASK_CMD + KEY_Q); + + project_menu = memnew(MenuButton); + project_menu->set_tooltip(TTR("Miscellaneous project or scene-wide tools.")); + project_menu->set_text(TTR("Project")); + project_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); + left_menu_hb->add_child(project_menu); + + p = project_menu->get_popup(); + p->add_item(TTR("Project Settings"), RUN_SETTINGS); + p->add_separator(); + p->connect("id_pressed", this, "_menu_option"); + p->add_item(TTR("Run Script"), FILE_RUN_SCRIPT, KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_R); + p->add_item(TTR("Export"), FILE_EXPORT_PROJECT); + + PopupMenu *tool_menu = memnew(PopupMenu); + tool_menu->set_name("Tools"); + tool_menu->connect("id_pressed", this, "_menu_option"); + p->add_child(tool_menu); + p->add_submenu_item(TTR("Tools"), "Tools"); + tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); + p->add_separator(); + +#ifdef OSX_ENABLED + p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q); +#else + p->add_item(TTR("Quit to Project List"), RUN_PROJECT_MANAGER, KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Q); +#endif PanelContainer *editor_region = memnew(PanelContainer); main_editor_button_vb = memnew(HBoxContainer); @@ -6113,9 +6111,8 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(LightOccluder2DEditorPlugin(this))); add_editor_plugin(memnew(NavigationPolygonEditorPlugin(this))); add_editor_plugin(memnew(GradientEditorPlugin(this))); - add_editor_plugin(memnew(GradientTextureEditorPlugin(this))); add_editor_plugin(memnew(CollisionShape2DEditorPlugin(this))); - add_editor_plugin(memnew(CurveTextureEditorPlugin(this))); + add_editor_plugin(memnew(CurveEditorPlugin(this))); add_editor_plugin(memnew(TextureEditorPlugin(this))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); //add_editor_plugin( memnew( MaterialEditorPlugin(this) ) ); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index d869d703f1..50a625ddc1 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -27,528 +27,695 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "curve_editor_plugin.h" #include "canvas_item_editor_plugin.h" +#include "core_string_names.h" +#include "os/input.h" #include "os/keyboard.h" -#include "spatial_editor_plugin.h" -void CurveTextureEdit::_gui_input(const Ref<InputEvent> &p_event) { +CurveEditor::CurveEditor() { + _selected_point = -1; + _hover_point = -1; + _selected_tangent = TANGENT_NONE; + _hover_radius = 6; + _tangents_length = 40; + _dragging = false; + _has_undo_data = false; + _world_rect = Rect2(0, 0, 1, 1); - Ref<InputEventKey> k = p_event; - if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && grabbed != -1) { + set_focus_mode(FOCUS_ALL); + set_clip_contents(true); + + _context_menu = memnew(PopupMenu); + _context_menu->connect("id_pressed", this, "_on_context_menu_item_selected"); + add_child(_context_menu); + + _presets_menu = memnew(PopupMenu); + _presets_menu->set_name("_presets_menu"); + _presets_menu->add_item("Flat0", PRESET_FLAT0); + _presets_menu->add_item("Flat1", PRESET_FLAT1); + _presets_menu->add_item("Linear", PRESET_LINEAR); + _presets_menu->add_item("Ease in", PRESET_EASE_IN); + _presets_menu->add_item("Ease out", PRESET_EASE_OUT); + _presets_menu->add_item("Smoothstep", PRESET_SMOOTHSTEP); + _presets_menu->connect("id_pressed", this, "_on_preset_item_selected"); + _context_menu->add_child(_presets_menu); +} - points.remove(grabbed); - grabbed = -1; - update(); - emit_signal("curve_changed"); - accept_event(); +void CurveEditor::set_curve(Ref<Curve> curve) { + + if (curve == _curve_ref) + return; + + if (_curve_ref.is_valid()) { + _curve_ref->disconnect("changed", this, "_curve_changed"); + } + _curve_ref = curve; + if (_curve_ref.is_valid()) { + _curve_ref->connect("changed", this, "_curve_changed"); } - Ref<InputEventMouseButton> mb = p_event; + _selected_point = -1; + _hover_point = -1; + _selected_tangent = TANGENT_NONE; - if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { + update(); - update(); - Ref<Font> font = get_font("font", "Label"); + // Note: if you edit a curve, then set another, and try to undo, + // it will normally apply on the previous curve, but you won't see it +} + +Size2 CurveEditor::get_minimum_size() const { + return Vector2(64, 64); +} + +void CurveEditor::_notification(int p_what) { + if (p_what == NOTIFICATION_DRAW) + _draw(); +} + +void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { + + Ref<InputEventMouseButton> mb_ref = p_event; + if (mb_ref.is_valid()) { + + const InputEventMouseButton &mb = **mb_ref; - int font_h = font->get_height(); + if (mb.is_pressed() && !_dragging) { - Vector2 size = get_size(); - size.y -= font_h; + Vector2 mpos = mb.get_position(); - Point2 p = Vector2(mb->get_position().x, mb->get_position().y) / size; - p.y = CLAMP(1.0 - p.y, 0, 1) * (max - min) + min; - grabbed = -1; - grabbing = true; + _selected_tangent = get_tangent_at(mpos); + if (_selected_tangent == TANGENT_NONE) + set_selected_point(get_point_at(mpos)); - for (int i = 0; i < points.size(); i++) { + switch (mb.get_button_index()) { + case BUTTON_RIGHT: + _context_click_pos = mpos; + open_context_menu(get_global_transform().xform(mpos)); + break; - Vector2 ps = p * get_size(); - Vector2 pt = Vector2(points[i].offset, points[i].height) * get_size(); - if (ps.distance_to(pt) < 4) { - grabbed = i; + case BUTTON_MIDDLE: + remove_point(_hover_point); + break; + + case BUTTON_LEFT: + _dragging = true; + break; } } - //grab or select - if (grabbed != -1) { - return; - } - //insert - - Point np; - np.offset = p.x; - np.height = p.y; - - points.push_back(np); - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == p.x && points[i].height == p.y) { - grabbed = i; - break; + if (!mb.is_pressed() && _dragging && mb.get_button_index() == BUTTON_LEFT) { + _dragging = false; + if (_has_undo_data) { + push_undo(_undo_data); + _has_undo_data = false; } } - - emit_signal("curve_changed"); } - if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { + Ref<InputEventMouseMotion> mm_ref = p_event; + if (mm_ref.is_valid()) { - if (grabbing) { - grabbing = false; - emit_signal("curve_changed"); - } - update(); - } + const InputEventMouseMotion &mm = **mm_ref; - Ref<InputEventMouseMotion> mm = p_event; + Vector2 mpos = mm.get_position(); - if (mm.is_valid() && grabbing && grabbed != -1) { + if (_dragging && _curve_ref.is_valid()) { + if (_selected_point != -1) { - Ref<Font> font = get_font("font", "Label"); - int font_h = font->get_height(); - Vector2 size = get_size(); - size.y -= font_h; + if (!_has_undo_data) { + // Save curve state before dragging points + _undo_data = _curve_ref->get_data(); + _has_undo_data = true; + } - Point2 p = mm->get_position() / size; - p.y = CLAMP(1.0 - p.y, 0, 1) * (max - min) + min; - p.x = CLAMP(p.x, 0.0, 1.0); + if (_selected_tangent == TANGENT_NONE) { + // Drag point - bool valid = true; + Vector2 point_pos = get_world_pos(mpos); - for (int i = 0; i < points.size(); i++) { + int i = _curve_ref->set_point_offset(_selected_point, point_pos.x); + // The index may change if the point is dragged across another one + set_hover_point_index(i); + set_selected_point(i); - if (points[i].offset == p.x && points[i].height == p.y && i != grabbed) { - valid = false; - } - } + // TODO Get rid of this clamp if zoom is implemented in this editor. + // This is to prevent the user from loosing a point out of view. + if (point_pos.y < 0.0) + point_pos.y = 0.0; + else if (point_pos.y > 1.0) + point_pos.y = 1.0; + + _curve_ref->set_point_value(_selected_point, point_pos.y); - if (!valid) - return; + //auto_calculate_tangents(i); - points[grabbed].offset = p.x; - points[grabbed].height = p.y; + } else { + // Drag tangent - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == p.x && points[i].height == p.y) { - grabbed = i; - break; + Vector2 point_pos = _curve_ref->get_point_pos(_selected_point); + Vector2 control_pos = get_world_pos(mpos); + + Vector2 dir = (control_pos - point_pos).normalized(); + + real_t tangent; + if (Math::abs(dir.x) > CMP_EPSILON) + tangent = dir.y / dir.x; + else + tangent = 9999 * (dir.y >= 0 ? 1 : -1); + + bool link = !Input::get_singleton()->is_key_pressed(KEY_SHIFT); + + if (_selected_tangent == TANGENT_LEFT) { + _curve_ref->set_point_left_tangent(_selected_point, tangent); + if (link && _selected_point != _curve_ref->get_point_count() - 1) + _curve_ref->set_point_right_tangent(_selected_point, tangent); + } else { + _curve_ref->set_point_right_tangent(_selected_point, tangent); + if (link && _selected_point != 0) + _curve_ref->set_point_left_tangent(_selected_point, tangent); + } + } } + + } else { + set_hover_point_index(get_point_at(mpos)); } + } - emit_signal("curve_changed"); + Ref<InputEventKey> key_ref = p_event; + if (key_ref.is_valid()) { + const InputEventKey &key = **key_ref; - update(); + if (key.is_pressed() && _selected_point != -1) { + if (key.get_scancode() == KEY_DELETE) + remove_point(_selected_point); + } } } -void CurveTextureEdit::_plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d) { +void CurveEditor::on_preset_item_selected(int preset_id) { + ERR_FAIL_COND(preset_id < 0 || preset_id >= PRESET_COUNT); + ERR_FAIL_COND(_curve_ref.is_null()); - Ref<Font> font = get_font("font", "Label"); - - int font_h = font->get_height(); + Curve &curve = **_curve_ref; + Array previous_data = curve.get_data(); - float geometry[4][4]; - float tmp1[4][4]; - float tmp2[4][4]; - float deltas[4][4]; - double x, dx, dx2, dx3; - double y, dy, dy2, dy3; - double d, d2, d3; - int lastx, lasty; - int newx, newy; - int ntimes; - int i, j; + curve.clear_points(); - int xmax = get_size().x; - int ymax = get_size().y - font_h; + switch (preset_id) { + case PRESET_FLAT0: + curve.add_point(Vector2(0, 0)); + curve.add_point(Vector2(1, 0)); + break; - int vsplits = 4; + case PRESET_FLAT1: + curve.add_point(Vector2(0, 1)); + curve.add_point(Vector2(1, 1)); + break; - int zero_ofs = (1.0 - (0.0 - min) / (max - min)) * ymax; + case PRESET_LINEAR: + curve.add_point(Vector2(0, 0), 0, 1); + curve.add_point(Vector2(1, 1), 1, 0); + break; - draw_line(Vector2(0, zero_ofs), Vector2(xmax, zero_ofs), Color(0.8, 0.8, 0.8, 0.15), 2.0); + case PRESET_EASE_IN: + curve.add_point(Vector2(0, 0)); + curve.add_point(Vector2(1, 1), 1.4, 0); + break; - for (int i = 0; i <= vsplits; i++) { - float fofs = float(i) / vsplits; - int yofs = fofs * ymax; - draw_line(Vector2(xmax, yofs), Vector2(xmax - 4, yofs), Color(0.8, 0.8, 0.8, 0.8), 2.0); + case PRESET_EASE_OUT: + curve.add_point(Vector2(0, 0), 0, 1.4); + curve.add_point(Vector2(1, 1)); + break; - String text = rtos((1.0 - fofs) * (max - min) + min); - int ppos = text.find("."); - if (ppos != -1) { - if (text.length() > ppos + 2) - text = text.substr(0, ppos + 2); - } + case PRESET_SMOOTHSTEP: + curve.add_point(Vector2(0, 0)); + curve.add_point(Vector2(1, 1)); + break; - int size = font->get_string_size(text).x; - int xofs = xmax - size - 4; - yofs -= font_h / 2; + default: + break; + } - if (yofs < 2) { - yofs = 2; - } else if (yofs + font_h > ymax - 2) { - yofs = ymax - font_h - 2; - } + push_undo(previous_data); +} - draw_string(font, Vector2(xofs, yofs + font->get_ascent()), text, Color(0.8, 0.8, 0.8, 1)); +void CurveEditor::_curve_changed() { + update(); + // Point count can change in case of undo + if (_selected_point >= _curve_ref->get_point_count()) { + set_selected_point(-1); } +} - /* construct the geometry matrix from the segment */ - for (i = 0; i < 4; i++) { - geometry[i][2] = 0; - geometry[i][3] = 0; - } +void CurveEditor::on_context_menu_item_selected(int action_id) { + switch (action_id) { + case CONTEXT_ADD_POINT: + add_point(_context_click_pos); + break; - geometry[0][0] = (p_a[0] * xmax); - geometry[1][0] = (p_b[0] * xmax); - geometry[2][0] = (p_c[0] * xmax); - geometry[3][0] = (p_d[0] * xmax); - - geometry[0][1] = ((p_a[1] - min) / (max - min) * ymax); - geometry[1][1] = ((p_b[1] - min) / (max - min) * ymax); - geometry[2][1] = ((p_c[1] - min) / (max - min) * ymax); - geometry[3][1] = ((p_d[1] - min) / (max - min) * ymax); - - /* subdivide the curve ntimes (1000) times */ - ntimes = 4 * xmax; - /* ntimes can be adjusted to give a finer or coarser curve */ - d = 1.0 / ntimes; - d2 = d * d; - d3 = d * d * d; - - /* construct a temporary matrix for determining the forward differencing deltas */ - tmp2[0][0] = 0; - tmp2[0][1] = 0; - tmp2[0][2] = 0; - tmp2[0][3] = 1; - tmp2[1][0] = d3; - tmp2[1][1] = d2; - tmp2[1][2] = d; - tmp2[1][3] = 0; - tmp2[2][0] = 6 * d3; - tmp2[2][1] = 2 * d2; - tmp2[2][2] = 0; - tmp2[2][3] = 0; - tmp2[3][0] = 6 * d3; - tmp2[3][1] = 0; - tmp2[3][2] = 0; - tmp2[3][3] = 0; - - /* compose the basis and geometry matrices */ - - static const float CR_basis[4][4] = { - { -0.5, 1.5, -1.5, 0.5 }, - { 1.0, -2.5, 2.0, -0.5 }, - { -0.5, 0.0, 0.5, 0.0 }, - { 0.0, 1.0, 0.0, 0.0 }, - }; - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] + - CR_basis[i][1] * geometry[1][j] + - CR_basis[i][2] * geometry[2][j] + - CR_basis[i][3] * geometry[3][j]); - } + case CONTEXT_REMOVE_POINT: + remove_point(_selected_point); + break; } - /* compose the above results to get the deltas matrix */ - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - deltas[i][j] = (tmp2[i][0] * tmp1[0][j] + - tmp2[i][1] * tmp1[1][j] + - tmp2[i][2] * tmp1[2][j] + - tmp2[i][3] * tmp1[3][j]); +} + +void CurveEditor::open_context_menu(Vector2 pos) { + _context_menu->set_position(pos); + + _context_menu->clear(); + + if (_curve_ref.is_valid()) { + _context_menu->add_item(TTR("Add point"), CONTEXT_ADD_POINT); + if (_selected_point >= 0) { + _context_menu->add_item(TTR("Remove point"), CONTEXT_REMOVE_POINT); } + _context_menu->add_separator(); } - /* extract the x deltas */ - x = deltas[0][0]; - dx = deltas[1][0]; - dx2 = deltas[2][0]; - dx3 = deltas[3][0]; + _context_menu->add_submenu_item(TTR("Load preset"), _presets_menu->get_name()); - /* extract the y deltas */ - y = deltas[0][1]; - dy = deltas[1][1]; - dy2 = deltas[2][1]; - dy3 = deltas[3][1]; + _context_menu->popup(); +} - lastx = CLAMP(x, 0, xmax); - lasty = CLAMP(y, 0, ymax); +int CurveEditor::get_point_at(Vector2 pos) const { + if (_curve_ref.is_null()) + return -1; + const Curve &curve = **_curve_ref; - /* if (fix255) - { - cd->curve[cd->outline][lastx] = lasty; - } - else - { - cd->curve_ptr[cd->outline][lastx] = lasty; - if(gb_debug) printf("bender_plot_curve xmax:%d ymax:%d\n", (int)xmax, (int)ymax); + const float r = _hover_radius * _hover_radius; + + for (int i = 0; i < curve.get_point_count(); ++i) { + Vector2 p = get_view_pos(curve.get_point_pos(i)); + if (p.distance_squared_to(pos) <= r) { + return i; } -*/ - /* loop over the curve */ - for (i = 0; i < ntimes; i++) { - /* increment the x values */ - x += dx; - dx += dx2; - dx2 += dx3; - - /* increment the y values */ - y += dy; - dy += dy2; - dy2 += dy3; - - newx = CLAMP((Math::round(x)), 0, xmax); - newy = CLAMP((Math::round(y)), 0, ymax); - - /* if this point is different than the last one...then draw it */ - if ((lastx != newx) || (lasty != newy)) { -#if 0 - if(fix255) - { - /* use fixed array size (for the curve graph) */ - cd->curve[cd->outline][newx] = newy; - } - else - { - /* use dynamic allocated curve_ptr (for the real curve) */ - cd->curve_ptr[cd->outline][newx] = newy; + } - if(gb_debug) printf("outline: %d cX: %d cY: %d\n", (int)cd->outline, (int)newx, (int)newy); - } -#endif - draw_line(Vector2(lastx, ymax - lasty), Vector2(newx, ymax - newy), Color(0.8, 0.8, 0.8, 0.8), 2.0); + return -1; +} + +int CurveEditor::get_tangent_at(Vector2 pos) const { + if (_curve_ref.is_null() || _selected_point < 0) + return TANGENT_NONE; + + if (_selected_point != 0) { + Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_LEFT); + if (control_pos.distance_to(pos) < _hover_radius) { + return TANGENT_LEFT; } + } - lastx = newx; - lasty = newy; + if (_selected_point != _curve_ref->get_point_count() - 1) { + Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_RIGHT); + if (control_pos.distance_to(pos) < _hover_radius) { + return TANGENT_RIGHT; + } } - int splits = 8; + return TANGENT_NONE; +} - draw_line(Vector2(0, ymax - 1), Vector2(xmax, ymax - 1), Color(0.8, 0.8, 0.8, 0.3), 2.0); +void CurveEditor::add_point(Vector2 pos) { + ERR_FAIL_COND(_curve_ref.is_null()); - for (int i = 0; i <= splits; i++) { - float fofs = float(i) / splits; - draw_line(Vector2(fofs * xmax, ymax), Vector2(fofs * xmax, ymax - 2), Color(0.8, 0.8, 0.8, 0.8), 2.0); + Array prev_data = _curve_ref->get_data(); - String text = rtos(fofs); - int size = font->get_string_size(text).x; - int ofs = fofs * xmax - size * 0.5; - if (ofs < 2) { - ofs = 2; - } else if (ofs + size > xmax - 2) { - ofs = xmax - size - 2; - } + Vector2 point_pos = get_world_pos(pos); + if (point_pos.y < 0.0) + point_pos.y = 0.0; + else if (point_pos.y > 1.0) + point_pos.y = 1.0; - draw_string(font, Vector2(ofs, ymax + font->get_ascent()), text, Color(0.8, 0.8, 0.8, 1)); - } + _curve_ref->add_point(point_pos); + + push_undo(prev_data); } -void CurveTextureEdit::_notification(int p_what) { +void CurveEditor::remove_point(int index) { + ERR_FAIL_COND(_curve_ref.is_null()); - if (p_what == NOTIFICATION_DRAW) { + Array prev_data = _curve_ref->get_data(); - Ref<Font> font = get_font("font", "Label"); + _curve_ref->remove_point(index); - int font_h = font->get_height(); + if (index == _selected_point) + set_selected_point(-1); - draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), get_size())); + push_undo(prev_data); +} - int w = get_size().x; - int h = get_size().y; +void CurveEditor::set_selected_point(int index) { + if (index != _selected_point) { + _selected_point = index; + update(); + } +} - Vector2 prev = Vector2(0, 0); - Vector2 prev2 = Vector2(0, 0); +void CurveEditor::set_hover_point_index(int index) { + if (index != _hover_point) { + _hover_point = index; + update(); + } +} - for (int i = -1; i < points.size(); i++) { +void CurveEditor::push_undo(Array previous_curve_data) { + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - Vector2 next; - Vector2 next2; - if (i + 1 >= points.size()) { - next = Vector2(1, 0); - } else { - next = Vector2(points[i + 1].offset, points[i + 1].height); - } + ur->create_action(TTR("Modify Curve")); + ur->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data()); + ur->add_undo_method(*_curve_ref, "_set_data", previous_curve_data); - if (i + 2 >= points.size()) { - next2 = Vector2(1, 0); - } else { - next2 = Vector2(points[i + 2].offset, points[i + 2].height); - } + // This boolean is to prevent commit_action from executing the do method, + // because at this point it's already done, there is no point in doing it twice + _curve_ref->_disable_set_data = true; + ur->commit_action(); + _curve_ref->_disable_set_data = false; +} - /*if (i==-1 && prev.offset==next.offset) { - prev=next; - continue; - }*/ +void CurveEditor::update_view_transform() { + Vector2 control_size = get_size(); + const real_t margin = 24; - _plot_curve(prev2, prev, next, next2); + _world_rect = Rect2(Curve::MIN_X, 0, Curve::MAX_X, 1); + Vector2 wm = Vector2(margin, margin) / control_size; + _world_rect.position -= wm; + _world_rect.size += 2.0 * wm; - prev2 = prev; - prev = next; - } + _world_to_view = Transform2D(); + _world_to_view.translate(-_world_rect.position - Vector2(0, _world_rect.size.y)); + _world_to_view.scale(Vector2(control_size.x, -control_size.y) / _world_rect.size); +} - Vector2 size = get_size(); - size.y -= font_h; - for (int i = 0; i < points.size(); i++) { +Vector2 CurveEditor::get_tangent_view_pos(int i, TangentIndex tangent) const { - Color col = i == grabbed ? Color(1, 0.0, 0.0, 0.9) : Color(1, 1, 1, 0.8); + Vector2 dir; + if (tangent == TANGENT_LEFT) + dir = -Vector2(1, _curve_ref->get_point_left_tangent(i)); + else + dir = Vector2(1, _curve_ref->get_point_right_tangent(i)); - float h = (points[i].height - min) / (max - min); - draw_rect(Rect2(Vector2(points[i].offset, 1.0 - h) * size - Vector2(2, 2), Vector2(5, 5)), col); - } + Vector2 point_pos = get_view_pos(_curve_ref->get_point_pos(i)); + Vector2 control_pos = get_view_pos(_curve_ref->get_point_pos(i) + dir); - /* if (grabbed!=-1) { + return point_pos + _tangents_length * (control_pos - point_pos).normalized(); +} - draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color); - } -*/ - if (has_focus()) { +Vector2 CurveEditor::get_view_pos(Vector2 world_pos) const { + return _world_to_view.xform(world_pos); +} + +Vector2 CurveEditor::get_world_pos(Vector2 view_pos) const { + return _world_to_view.affine_inverse().xform(view_pos); +} - draw_line(Vector2(-1, -1), Vector2(w + 1, -1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(w + 1, -1), Vector2(w + 1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); +// Uses non-baked points, but takes advantage of ordered iteration to be faster +template <typename T> +static void plot_curve_accurate(const Curve &curve, float step, T plot_func) { + + if (curve.get_point_count() <= 1) { + // Not enough points to make a curve, so it's just a straight line + float y = curve.interpolate(0); + plot_func(Vector2(0, y), Vector2(1.f, y), true); + + } else { + Vector2 first_point = curve.get_point_pos(0); + Vector2 last_point = curve.get_point_pos(curve.get_point_count() - 1); + + // Edge lines + plot_func(Vector2(0, first_point.y), first_point, false); + plot_func(Vector2(Curve::MAX_X, last_point.y), last_point, false); + + // Draw section by section, so that we get maximum precision near points. + // It's an accurate representation, but slower than using the baked one. + for (int i = 1; i < curve.get_point_count(); ++i) { + Vector2 a = curve.get_point_pos(i - 1); + Vector2 b = curve.get_point_pos(i); + + Vector2 pos = a; + Vector2 prev_pos = a; + + float len = b.x - a.x; + //float step = 4.f / view_size.x; + + for (float x = step; x < len; x += step) { + pos.x = a.x + x; + pos.y = curve.interpolate_local_nocheck(i - 1, x); + plot_func(prev_pos, pos, true); + prev_pos = pos; + } + + plot_func(prev_pos, b, true); } } } -Size2 CurveTextureEdit::get_minimum_size() const { +struct CanvasItemPlotCurve { - return Vector2(64, 64); -} + CanvasItem &ci; + Color color1; + Color color2; -void CurveTextureEdit::set_range(float p_min, float p_max) { - max = p_max; - min = p_min; - update(); -} + CanvasItemPlotCurve(CanvasItem &p_ci, Color p_color1, Color p_color2) + : ci(p_ci), color1(p_color1), color2(p_color2) {} -void CurveTextureEdit::set_points(const Vector<Vector2> &p_points) { + void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) { + ci.draw_line(pos0, pos1, in_definition ? color1 : color2); + } +}; + +void CurveEditor::_draw() { + if (_curve_ref.is_null()) + return; + Curve &curve = **_curve_ref; + + update_view_transform(); + + // Background + + Vector2 view_size = get_rect().size; + draw_style_box(get_stylebox("bg", "Tree"), Rect2(Point2(), view_size)); + + // Grid + + draw_set_transform_matrix(_world_to_view); + + Vector2 min_edge = get_world_pos(Vector2(0, view_size.y)); + Vector2 max_edge = get_world_pos(Vector2(view_size.x, 0)); + + const Color grid_color0(0, 0, 0, 0.5); + const Color grid_color1(0, 0, 0, 0.15); + draw_line(Vector2(min_edge.x, 0), Vector2(max_edge.x, 0), grid_color0); + draw_line(Vector2(0, min_edge.y), Vector2(0, max_edge.y), grid_color0); + draw_line(Vector2(1, max_edge.y), Vector2(1, min_edge.y), grid_color0); + draw_line(Vector2(max_edge.x, 1), Vector2(min_edge.x, 1), grid_color0); - points.clear(); - for (int i = 0; i < p_points.size(); i++) { - Point p; - p.offset = p_points[i].x; - p.height = p_points[i].y; - points.push_back(p); + const Vector2 grid_step(0.25, 0.5); + + for (real_t x = 0; x < 1.0; x += grid_step.x) { + draw_line(Vector2(x, min_edge.y), Vector2(x, max_edge.y), grid_color1); + } + for (real_t y = 0; y < 1.0; y += grid_step.y) { + draw_line(Vector2(min_edge.x, y), Vector2(max_edge.x, y), grid_color1); } - points.sort(); - update(); -} + // Markings -Vector<Vector2> CurveTextureEdit::get_points() const { - Vector<Vector2> ret; - for (int i = 0; i < points.size(); i++) - ret.push_back(Vector2(points[i].offset, points[i].height)); - return ret; -} + draw_set_transform_matrix(Transform2D()); -void CurveTextureEdit::_bind_methods() { + Ref<Font> font = get_font("font", "Label"); + const Color text_color(1, 1, 1, 0.3); - ClassDB::bind_method(D_METHOD("_gui_input"), &CurveTextureEdit::_gui_input); + draw_string(font, get_view_pos(Vector2(0, 0)), "0.0", text_color); - ADD_SIGNAL(MethodInfo("curve_changed")); -} + draw_string(font, get_view_pos(Vector2(0.25, 0)), "0.25", text_color); + draw_string(font, get_view_pos(Vector2(0.5, 0)), "0.5", text_color); + draw_string(font, get_view_pos(Vector2(0.75, 0)), "0.75", text_color); + draw_string(font, get_view_pos(Vector2(1, 0)), "1.0", text_color); -CurveTextureEdit::CurveTextureEdit() { + draw_string(font, get_view_pos(Vector2(0, 0.5)), "0.5", text_color); + draw_string(font, get_view_pos(Vector2(0, 1)), "1.0", text_color); - grabbed = -1; - grabbing = false; - max = 1; - min = 0; - set_focus_mode(FOCUS_ALL); -} + // Draw tangents for current point -void CurveTextureEditorPlugin::_curve_settings_changed() { + if (_selected_point >= 0) { - if (!curve_texture_ref.is_valid()) - return; - curve_editor->set_points(Variant(curve_texture_ref->get_points())); - curve_editor->set_range(curve_texture_ref->get_min(), curve_texture_ref->get_max()); -} + const Color tangent_color(0.5, 0.5, 1, 1); + + int i = _selected_point; + Vector2 pos = curve.get_point_pos(i); + + if (i != 0) { + Vector2 control_pos = get_tangent_view_pos(i, TANGENT_LEFT); + draw_line(get_view_pos(pos), control_pos, tangent_color); + draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), tangent_color); + } -CurveTextureEditorPlugin::CurveTextureEditorPlugin(EditorNode *p_node) { + if (i != curve.get_point_count() - 1) { + Vector2 control_pos = get_tangent_view_pos(i, TANGENT_RIGHT); + draw_line(get_view_pos(pos), control_pos, tangent_color); + draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(2), tangent_color); + } + } - editor = p_node; - curve_editor = memnew(CurveTextureEdit); + // Draw lines - curve_button = editor->add_bottom_panel_item("CurveTexture", curve_editor); + draw_set_transform_matrix(_world_to_view); - curve_button->hide(); - curve_editor->set_custom_minimum_size(Size2(100, 128 * EDSCALE)); - curve_editor->hide(); - curve_editor->connect("curve_changed", this, "curve_changed"); -} + const Color line_color(1, 1, 1, 0.85); + const Color edge_line_color(1, 1, 1, 0.4); + + CanvasItemPlotCurve plot_func(*this, line_color, edge_line_color); + plot_curve_accurate(curve, 4.f / view_size.x, plot_func); + + /*// TEST draw baked curve + { + Vector2 pos = Vector2(0, curve.interpolate_baked(0)); + Vector2 prev_pos = pos; -void CurveTextureEditorPlugin::edit(Object *p_object) { + float len = 1.0; + float step = 4.f / view_size.x; - if (curve_texture_ref.is_valid()) { - curve_texture_ref->disconnect("changed", this, "_curve_settings_changed"); + for(float x = step; x < len; x += step) { + pos.x = x; + pos.y = curve.interpolate_baked(x); + draw_line(get_point_view_pos(prev_pos), get_point_view_pos(pos), Color(0,1,0)); + prev_pos = pos; + } + + draw_line(get_point_view_pos(prev_pos), get_point_view_pos(Vector2(1, curve.interpolate_baked(1))), Color(0,1,0)); + }//*/ + + // Draw points + + draw_set_transform_matrix(Transform2D()); + + const Color point_color(1, 1, 1); + const Color selected_point_color(1, 0.5, 0.5); + + for (int i = 0; i < curve.get_point_count(); ++i) { + Vector2 pos = curve.get_point_pos(i); + draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(3), i == _selected_point ? selected_point_color : point_color); + // TODO Circles are prettier. Needs a fix! Or a texture + //draw_circle(pos, 2, point_color); } - CurveTexture *curve_texture = p_object->cast_to<CurveTexture>(); - if (!curve_texture) - return; - curve_texture_ref = Ref<CurveTexture>(curve_texture); - curve_editor->set_points(Variant(curve_texture_ref->get_points())); - curve_editor->set_range(curve_texture_ref->get_min(), curve_texture_ref->get_max()); - if (!curve_texture_ref->is_connected("changed", this, "_curve_settings_changed")) { - curve_texture_ref->connect("changed", this, "_curve_settings_changed"); + + // Hover + + if (_hover_point != -1) { + const Color hover_color = line_color; + Vector2 pos = curve.get_point_pos(_hover_point); + stroke_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(_hover_radius), hover_color); } } -bool CurveTextureEditorPlugin::handles(Object *p_object) const { +// TODO That should be part of the drawing API... +void CurveEditor::stroke_rect(Rect2 rect, Color color) { + + // a---b + // | | + // c---d + Vector2 a(rect.position); + Vector2 b(rect.position.x + rect.size.x, rect.position.y); + Vector2 c(rect.position.x, rect.position.y + rect.size.y); + Vector2 d(rect.position + rect.size); + + draw_line(a, b, color); + draw_line(b, d, color); + draw_line(d, c, color); + draw_line(c, a, color); +} - return p_object->is_class("CurveTexture"); +void CurveEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_gui_input"), &CurveEditor::on_gui_input); + ClassDB::bind_method(D_METHOD("_on_preset_item_selected"), &CurveEditor::on_preset_item_selected); + ClassDB::bind_method(D_METHOD("_curve_changed"), &CurveEditor::_curve_changed); + ClassDB::bind_method(D_METHOD("_on_context_menu_item_selected"), &CurveEditor::on_context_menu_item_selected); } -void CurveTextureEditorPlugin::make_visible(bool p_visible) { +//--------------- - if (p_visible) { - curve_button->show(); - editor->make_bottom_panel_item_visible(curve_editor); +CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { + _editor_node = p_node; - } else { + _view = memnew(CurveEditor); + _view->set_custom_minimum_size(Size2(100, 128 * EDSCALE)); + _view->hide(); - curve_button->hide(); - if (curve_editor->is_visible_in_tree()) - editor->hide_bottom_panel(); - } + _toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view); + _toggle_button->hide(); } -void CurveTextureEditorPlugin::_curve_changed() { +CurveEditorPlugin::~CurveEditorPlugin() { +} - if (curve_texture_ref.is_valid()) { +void CurveEditorPlugin::edit(Object *p_object) { - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + Ref<Curve> curve_ref; - Vector<Vector2> points = curve_editor->get_points(); - PoolVector<Vector2> ppoints = Variant(points); + if (_current_ref.is_valid()) { + CurveTexture *ct = _current_ref->cast_to<CurveTexture>(); + if (ct) + ct->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); + } + + if (p_object) { + Resource *res = p_object->cast_to<Resource>(); + ERR_FAIL_COND(res == NULL); + ERR_FAIL_COND(!handles(p_object)); + + _current_ref = Ref<Resource>(p_object->cast_to<Resource>()); + + if (_current_ref.is_valid()) { + Curve *curve = _current_ref->cast_to<Curve>(); + if (curve) + curve_ref = Ref<Curve>(curve); + else { + CurveTexture *ct = _current_ref->cast_to<CurveTexture>(); + if (ct) { + ct->connect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); + curve_ref = ct->get_curve(); + } + } + } - ur->create_action(TTR("Modify Curve"), UndoRedo::MERGE_ENDS); - ur->add_do_method(this, "undo_redo_curve_texture", ppoints); - ur->add_undo_method(this, "undo_redo_curve_texture", curve_texture_ref->get_points()); - ur->commit_action(); + } else { + _current_ref = Ref<Resource>(); } + + _view->set_curve(curve_ref); } -void CurveTextureEditorPlugin::_undo_redo_curve_texture(const PoolVector<Vector2> &points) { +bool CurveEditorPlugin::handles(Object *p_object) const { + // Both handled so that we can keep the curve editor open + return p_object->cast_to<Curve>() || p_object->cast_to<CurveTexture>(); +} - curve_texture_ref->set_points(points); - curve_editor->set_points(Variant(curve_texture_ref->get_points())); - curve_editor->update(); +void CurveEditorPlugin::make_visible(bool p_visible) { + if (p_visible) { + _toggle_button->show(); + _editor_node->make_bottom_panel_item_visible(_view); + } else { + _toggle_button->hide(); + if (_view->is_visible_in_tree()) + _editor_node->hide_bottom_panel(); + } } -CurveTextureEditorPlugin::~CurveTextureEditorPlugin() { +void CurveEditorPlugin::_curve_texture_changed() { + // If the curve is shown indirectly as a CurveTexture is edited, + // we need to monitor when the curve property gets assigned + CurveTexture *ct = _current_ref->cast_to<CurveTexture>(); + if (ct) { + _view->set_curve(ct->get_curve()); + } } -void CurveTextureEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("curve_changed"), &CurveTextureEditorPlugin::_curve_changed); - ClassDB::bind_method(D_METHOD("_curve_settings_changed"), &CurveTextureEditorPlugin::_curve_settings_changed); - ClassDB::bind_method(D_METHOD("undo_redo_curve_texture", "points"), &CurveTextureEditorPlugin::_undo_redo_curve_texture); +void CurveEditorPlugin::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed); } diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 4e75ba407c..0ed4ee3517 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -27,69 +27,119 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef CURVE_EDITOR_PLUGIN_H #define CURVE_EDITOR_PLUGIN_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" +#include "scene/resources/curve.h" -class CurveTextureEdit : public Control { +// Edits a y(x) curve +class CurveEditor : public Control { + GDCLASS(CurveEditor, Control) +public: + CurveEditor(); - GDCLASS(CurveTextureEdit, Control); + Size2 get_minimum_size() const; - struct Point { + void set_curve(Ref<Curve> curve); - float offset; - float height; - bool operator<(const Point &p_ponit) const { - return offset < p_ponit.offset; - } + enum PresetID { + PRESET_FLAT0 = 0, + PRESET_FLAT1, + PRESET_LINEAR, + PRESET_EASE_IN, + PRESET_EASE_OUT, + PRESET_SMOOTHSTEP, + PRESET_COUNT }; - bool grabbing; - int grabbed; - Vector<Point> points; - float max, min; + enum ContextAction { + CONTEXT_ADD_POINT = 0, + CONTEXT_REMOVE_POINT + }; - void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d); + enum TangentIndex { + TANGENT_NONE = -1, + TANGENT_LEFT = 0, + TANGENT_RIGHT = 1 + }; protected: - void _gui_input(const Ref<InputEvent> &p_event); void _notification(int p_what); + static void _bind_methods(); -public: - void set_range(float p_min, float p_max); - void set_points(const Vector<Vector2> &p_points); - Vector<Vector2> get_points() const; - virtual Size2 get_minimum_size() const; - CurveTextureEdit(); +private: + void on_gui_input(const Ref<InputEvent> &p_event); + void on_preset_item_selected(int preset_id); + void _curve_changed(); + void on_context_menu_item_selected(int action_id); + + void open_context_menu(Vector2 pos); + int get_point_at(Vector2 pos) const; + int get_tangent_at(Vector2 pos) const; + void add_point(Vector2 pos); + void remove_point(int index); + void set_selected_point(int index); + void set_hover_point_index(int index); + void push_undo(Array previous_curve_data); + void update_view_transform(); + + Vector2 get_tangent_view_pos(int i, TangentIndex tangent) const; + Vector2 get_view_pos(Vector2 world_pos) const; + Vector2 get_world_pos(Vector2 view_pos) const; + + void _draw(); + + void stroke_rect(Rect2 rect, Color color); + +private: + Rect2 _world_rect; + Transform2D _world_to_view; + + Ref<Curve> _curve_ref; + PopupMenu *_context_menu; + PopupMenu *_presets_menu; + + Array _undo_data; + bool _has_undo_data; + bool _undo_no_commit; + + Vector2 _context_click_pos; + int _selected_point; + int _hover_point; + int _selected_tangent; + bool _dragging; + + // Constant + float _hover_radius; + float _tangents_length; }; -class CurveTextureEditorPlugin : public EditorPlugin { - - GDCLASS(CurveTextureEditorPlugin, EditorPlugin); +class CurveEditorPlugin : public EditorPlugin { + GDCLASS(CurveEditorPlugin, EditorPlugin) +public: + CurveEditorPlugin(EditorNode *p_node); + ~CurveEditorPlugin(); - CurveTextureEdit *curve_editor; - Ref<CurveTexture> curve_texture_ref; - EditorNode *editor; - ToolButton *curve_button; + String get_name() const { return "Curve"; } + bool has_main_screen() const { return false; } + void edit(Object *p_object); + bool handles(Object *p_object) const; + void make_visible(bool p_visible); -protected: +private: static void _bind_methods(); - void _curve_changed(); - void _undo_redo_curve_texture(const PoolVector<Vector2> &points); - void _curve_settings_changed(); -public: - virtual String get_name() const { return "CurveTexture"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); + void _curve_texture_changed(); - CurveTextureEditorPlugin(EditorNode *p_node); - ~CurveTextureEditorPlugin(); +private: + CurveEditor *_view; + Ref<Resource> _current_ref; + EditorNode *_editor_node; + ToolButton *_toggle_button; }; #endif // CURVE_EDITOR_PLUGIN_H diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 9884db934b..4aaa155cfd 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -91,8 +91,7 @@ void GradientEditorPlugin::_ramp_changed() { } } -void GradientEditorPlugin::_undo_redo_gradient(const Vector<float> &offsets, - const Vector<Color> &colors) { +void GradientEditorPlugin::_undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors) { gradient_ref->set_offsets(offsets); gradient_ref->set_colors(colors); diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 843e98a917..c319a13a01 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -38,7 +38,6 @@ class GradientEditorPlugin : public EditorPlugin { GDCLASS(GradientEditorPlugin, EditorPlugin); - bool _2d; Ref<Gradient> gradient_ref; GradientEdit *ramp_editor; EditorNode *editor; diff --git a/editor/plugins/gradient_texture_editor_plugin.cpp b/editor/plugins/gradient_texture_editor_plugin.cpp deleted file mode 100644 index bc985dcdf7..0000000000 --- a/editor/plugins/gradient_texture_editor_plugin.cpp +++ /dev/null @@ -1,539 +0,0 @@ -/*************************************************************************/ -/* gradient_texture_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "gradient_texture_editor_plugin.h" - -#include "canvas_item_editor_plugin.h" -#include "os/keyboard.h" -#include "scene/resources/default_theme/theme_data.h" -#include "spatial_editor_plugin.h" - -#define POINT_WIDTH 8 - -GradientTextureEdit::GradientTextureEdit() { - grabbed = -1; - grabbing = false; - set_focus_mode(FOCUS_ALL); - - popup = memnew(PopupPanel); - picker = memnew(ColorPicker); - popup->add_child(picker); - - add_child(popup); - - checker = Ref<ImageTexture>(memnew(ImageTexture)); - Ref<Image> checker_bg = memnew(Image(checker_bg_png)); - checker->create_from_image(checker_bg, ImageTexture::FLAG_REPEAT); -} - -int GradientTextureEdit::_get_point_from_pos(int x) { - int result = -1; - int total_w = get_size().width - get_size().height - 3; - for (int i = 0; i < points.size(); i++) { - //Check if we clicked at point - if (ABS(x - points[i].offset * total_w + 1) < (POINT_WIDTH / 2 + 1)) { - result = i; - } - } - return result; -} - -void GradientTextureEdit::_show_color_picker() { - if (grabbed == -1) - return; - Size2 ms = Size2(350, picker->get_combined_minimum_size().height + 10); - picker->set_pick_color(points[grabbed].color); - popup->set_position(get_global_position() - Vector2(ms.width - get_size().width, ms.height)); - popup->set_size(ms); - popup->popup(); -} - -GradientTextureEdit::~GradientTextureEdit() { -} - -void GradientTextureEdit::_gui_input(const Ref<InputEvent> &p_event) { - - Ref<InputEventKey> k = p_event; - - if (k.is_valid() && k->is_pressed() && k->get_scancode() == KEY_DELETE && grabbed != -1) { - - points.remove(grabbed); - grabbed = -1; - grabbing = false; - update(); - emit_signal("ramp_changed"); - accept_event(); - } - - Ref<InputEventMouseButton> mb = p_event; - //Show color picker on double click. - if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_doubleclick() && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - _show_color_picker(); - accept_event(); - } - - //Delete point on right click - if (mb.is_valid() && mb->get_button_index() == 2 && mb->is_pressed()) { - grabbed = _get_point_from_pos(mb->get_position().x); - if (grabbed != -1) { - points.remove(grabbed); - grabbed = -1; - grabbing = false; - update(); - emit_signal("ramp_changed"); - accept_event(); - } - } - - //Hold alt key to duplicate selected color - if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed() && mb->get_alt()) { - - int x = mb->get_position().x; - grabbed = _get_point_from_pos(x); - - if (grabbed != -1) { - int total_w = get_size().width - get_size().height - 3; - GradientTexture::Point newPoint = points[grabbed]; - newPoint.offset = CLAMP(x / float(total_w), 0, 1); - - points.push_back(newPoint); - points.sort(); - for (int i = 0; i < points.size(); ++i) { - if (points[i].offset == newPoint.offset) { - grabbed = i; - break; - } - } - - emit_signal("ramp_changed"); - update(); - } - } - - if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { - - update(); - int x = mb->get_position().x; - int total_w = get_size().width - get_size().height - 3; - - //Check if color selector was clicked. - if (x > total_w + 3) { - _show_color_picker(); - return; - } - - grabbing = true; - - grabbed = _get_point_from_pos(x); - //grab or select - if (grabbed != -1) { - return; - } - - //insert - GradientTexture::Point newPoint; - newPoint.offset = CLAMP(x / float(total_w), 0, 1); - - GradientTexture::Point prev; - GradientTexture::Point next; - - int pos = -1; - for (int i = 0; i < points.size(); i++) { - if (points[i].offset < newPoint.offset) - pos = i; - } - - if (pos == -1) { - - prev.color = Color(0, 0, 0); - prev.offset = 0; - if (points.size()) { - next = points[0]; - } else { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } - } else { - - if (pos == points.size() - 1) { - next.color = Color(1, 1, 1); - next.offset = 1.0; - } else { - next = points[pos + 1]; - } - prev = points[pos]; - } - - newPoint.color = prev.color.linear_interpolate(next.color, (newPoint.offset - prev.offset) / (next.offset - prev.offset)); - - points.push_back(newPoint); - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == newPoint.offset) { - grabbed = i; - break; - } - } - - emit_signal("ramp_changed"); - } - - if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { - - if (grabbing) { - grabbing = false; - emit_signal("ramp_changed"); - } - update(); - } - - Ref<InputEventMouseMotion> mm = p_event; - - if (mm.is_valid() && grabbing) { - - int total_w = get_size().width - get_size().height - 3; - - int x = mm->get_position().x; - float newofs = CLAMP(x / float(total_w), 0, 1); - - //Snap to nearest point if holding shift - if (mm->get_shift()) { - float snap_treshhold = 0.03; - float smallest_ofs = snap_treshhold; - bool founded = false; - int nearest_point; - for (int i = 0; i < points.size(); ++i) { - if (i != grabbed) { - float temp_ofs = ABS(points[i].offset - newofs); - if (temp_ofs < smallest_ofs) { - smallest_ofs = temp_ofs; - nearest_point = i; - if (founded) - break; - founded = true; - } - } - } - if (founded) { - if (points[nearest_point].offset < newofs) - newofs = points[nearest_point].offset + 0.00001; - else - newofs = points[nearest_point].offset - 0.00001; - newofs = CLAMP(newofs, 0, 1); - } - } - - bool valid = true; - for (int i = 0; i < points.size(); i++) { - - if (points[i].offset == newofs && i != grabbed) { - valid = false; - } - } - - if (!valid) - return; - - points[grabbed].offset = newofs; - - points.sort(); - for (int i = 0; i < points.size(); i++) { - if (points[i].offset == newofs) { - grabbed = i; - break; - } - } - - emit_signal("ramp_changed"); - - update(); - } -} - -void GradientTextureEdit::_notification(int p_what) { - - if (p_what == NOTIFICATION_ENTER_TREE) { - if (!picker->is_connected("color_changed", this, "_color_changed")) { - picker->connect("color_changed", this, "_color_changed"); - } - } - if (p_what == NOTIFICATION_DRAW) { - - int w = get_size().x; - int h = get_size().y; - - if (w == 0 || h == 0) - return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size - - int total_w = get_size().width - get_size().height - 3; - - //Draw checker pattern for ramp - _draw_checker(0, 0, total_w, h); - - //Draw color ramp - GradientTexture::Point prev; - prev.offset = 0; - if (points.size() == 0) - prev.color = Color(0, 0, 0); //Draw black rectangle if we have no points - else - prev.color = points[0].color; //Extend color of first point to the beginning. - - for (int i = -1; i < points.size(); i++) { - - GradientTexture::Point next; - //If there is no next point - if (i + 1 == points.size()) { - if (points.size() == 0) - next.color = Color(0, 0, 0); //Draw black rectangle if we have no points - else - next.color = points[i].color; //Extend color of last point to the end. - next.offset = 1; - } else { - next = points[i + 1]; - } - - if (prev.offset == next.offset) { - prev = next; - continue; - } - - Vector<Vector2> points; - Vector<Color> colors; - points.push_back(Vector2(prev.offset * total_w, h)); - points.push_back(Vector2(prev.offset * total_w, 0)); - points.push_back(Vector2(next.offset * total_w, 0)); - points.push_back(Vector2(next.offset * total_w, h)); - colors.push_back(prev.color); - colors.push_back(prev.color); - colors.push_back(next.color); - colors.push_back(next.color); - draw_primitive(points, colors, Vector<Point2>()); - prev = next; - } - - //Draw point markers - for (int i = 0; i < points.size(); i++) { - - Color col = i == grabbed ? Color(1, 0.0, 0.0, 0.9) : points[i].color.contrasted(); - col.a = 0.9; - - draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col); - draw_rect(Rect2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2, POINT_WIDTH, h / 2), Color(0.6, 0.6, 0.6, i == grabbed ? 0.9 : 0.4)); - draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h - 1), col); - draw_line(Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h - 1), col); - draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h / 2), col); - draw_line(Vector2(points[i].offset * total_w - POINT_WIDTH / 2, h - 1), Vector2(points[i].offset * total_w + POINT_WIDTH / 2, h - 1), col); - } - - //Draw "button" for color selector - _draw_checker(total_w + 3, 0, h, h); - if (grabbed != -1) { - //Draw with selection color - draw_rect(Rect2(total_w + 3, 0, h, h), points[grabbed].color); - } else { - //if no color selected draw grey color with 'X' on top. - draw_rect(Rect2(total_w + 3, 0, h, h), Color(0.5, 0.5, 0.5, 1)); - draw_line(Vector2(total_w + 3, 0), Vector2(total_w + 3 + h, h), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 3, h), Vector2(total_w + 3 + h, 0), Color(1, 1, 1, 0.6)); - } - - //Draw borders around color ramp if in focus - if (has_focus()) { - - draw_line(Vector2(-1, -1), Vector2(total_w + 1, -1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, -1), Vector2(total_w + 1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(total_w + 1, h + 1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6)); - } - } -} - -void GradientTextureEdit::_draw_checker(int x, int y, int w, int h) { - //Draw it with polygon to insert UVs for scale - Vector<Vector2> backPoints; - backPoints.push_back(Vector2(x, y)); - backPoints.push_back(Vector2(x, y + h)); - backPoints.push_back(Vector2(x + w, y + h)); - backPoints.push_back(Vector2(x + w, y)); - Vector<Color> colorPoints; - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - colorPoints.push_back(Color(1, 1, 1, 1)); - Vector<Vector2> uvPoints; - //Draw checker pattern pixel-perfect and scale it by 2. - uvPoints.push_back(Vector2(x, y)); - uvPoints.push_back(Vector2(x, y + h * .5f / checker->get_height())); - uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y + h * .5f / checker->get_height())); - uvPoints.push_back(Vector2(x + w * .5f / checker->get_width(), y)); - draw_polygon(backPoints, colorPoints, uvPoints, checker); -} - -Size2 GradientTextureEdit::get_minimum_size() const { - - return Vector2(0, 16); -} - -void GradientTextureEdit::_color_changed(const Color &p_color) { - - if (grabbed == -1) - return; - points[grabbed].color = p_color; - update(); - emit_signal("ramp_changed"); -} - -void GradientTextureEdit::set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors) { - - ERR_FAIL_COND(p_offsets.size() != p_colors.size()); - points.clear(); - for (int i = 0; i < p_offsets.size(); i++) { - GradientTexture::Point p; - p.offset = p_offsets[i]; - p.color = p_colors[i]; - points.push_back(p); - } - - points.sort(); - update(); -} - -Vector<float> GradientTextureEdit::get_offsets() const { - Vector<float> ret; - for (int i = 0; i < points.size(); i++) - ret.push_back(points[i].offset); - return ret; -} - -Vector<Color> GradientTextureEdit::get_colors() const { - Vector<Color> ret; - for (int i = 0; i < points.size(); i++) - ret.push_back(points[i].color); - return ret; -} - -void GradientTextureEdit::set_points(Vector<GradientTexture::Point> &p_points) { - if (points.size() != p_points.size()) - grabbed = -1; - points.clear(); - points = p_points; -} - -Vector<GradientTexture::Point> &GradientTextureEdit::get_points() { - return points; -} - -void GradientTextureEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_gui_input"), &GradientTextureEdit::_gui_input); - ClassDB::bind_method(D_METHOD("_color_changed"), &GradientTextureEdit::_color_changed); - ADD_SIGNAL(MethodInfo("ramp_changed")); -} - -GradientTextureEditorPlugin::GradientTextureEditorPlugin(EditorNode *p_node) { - - editor = p_node; - ramp_editor = memnew(GradientTextureEdit); - - gradient_button = editor->add_bottom_panel_item("GradientTexture", ramp_editor); - - gradient_button->hide(); - ramp_editor->set_custom_minimum_size(Size2(100, 100 * EDSCALE)); - ramp_editor->hide(); - ramp_editor->connect("ramp_changed", this, "ramp_changed"); -} - -void GradientTextureEditorPlugin::edit(Object *p_object) { - - GradientTexture *gradient_texture = p_object->cast_to<GradientTexture>(); - if (!gradient_texture) - return; - gradient_texture_ref = Ref<GradientTexture>(gradient_texture); - ramp_editor->set_points(gradient_texture_ref->get_points()); -} - -bool GradientTextureEditorPlugin::handles(Object *p_object) const { - - return p_object->is_class("GradientTexture"); -} - -void GradientTextureEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) { - gradient_button->show(); - editor->make_bottom_panel_item_visible(ramp_editor); - - } else { - - gradient_button->hide(); - if (ramp_editor->is_visible_in_tree()) - editor->hide_bottom_panel(); - } -} - -void GradientTextureEditorPlugin::_ramp_changed() { - - if (gradient_texture_ref.is_valid()) { - - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - - //Not sure if I should convert this data to PoolVector - Vector<float> new_offsets = ramp_editor->get_offsets(); - Vector<Color> new_colors = ramp_editor->get_colors(); - Vector<float> old_offsets = gradient_texture_ref->get_offsets(); - Vector<Color> old_colors = gradient_texture_ref->get_colors(); - - if (old_offsets.size() != new_offsets.size()) - ur->create_action(TTR("Add/Remove Color Ramp Point")); - else - ur->create_action(TTR("Modify Color Ramp"), UndoRedo::MERGE_ENDS); - ur->add_do_method(this, "undo_redo_gradient_texture", new_offsets, new_colors); - ur->add_undo_method(this, "undo_redo_gradient_texture", old_offsets, old_colors); - ur->commit_action(); - - //gradient_texture_ref->set_points(ramp_editor->get_points()); - } -} - -void GradientTextureEditorPlugin::_undo_redo_gradient_texture(const Vector<float> &offsets, - const Vector<Color> &colors) { - - gradient_texture_ref->set_offsets(offsets); - gradient_texture_ref->set_colors(colors); - ramp_editor->set_points(gradient_texture_ref->get_points()); - ramp_editor->update(); -} - -GradientTextureEditorPlugin::~GradientTextureEditorPlugin() { -} - -void GradientTextureEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("ramp_changed"), &GradientTextureEditorPlugin::_ramp_changed); - ClassDB::bind_method(D_METHOD("undo_redo_gradient_texture", "offsets", "colors"), &GradientTextureEditorPlugin::_undo_redo_gradient_texture); -} diff --git a/editor/plugins/gradient_texture_editor_plugin.h b/editor/plugins/gradient_texture_editor_plugin.h deleted file mode 100644 index 842d586541..0000000000 --- a/editor/plugins/gradient_texture_editor_plugin.h +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************/ -/* gradient_texture_editor_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef GRADIENT_TEXTURE_EDITOR_PLUGIN_H -#define GRADIENT_TEXTURE_EDITOR_PLUGIN_H - -#include "editor/editor_node.h" -#include "editor/editor_plugin.h" -#include "scene/resources/texture.h" - -class GradientTextureEdit : public Control { - - GDCLASS(GradientTextureEdit, Control); - - PopupPanel *popup; - ColorPicker *picker; - - Ref<ImageTexture> checker; - - bool grabbing; - int grabbed; - Vector<GradientTexture::Point> points; - - void _draw_checker(int x, int y, int w, int h); - void _color_changed(const Color &p_color); - int _get_point_from_pos(int x); - void _show_color_picker(); - -protected: - void _gui_input(const Ref<InputEvent> &p_event); - void _notification(int p_what); - static void _bind_methods(); - -public: - void set_ramp(const Vector<float> &p_offsets, const Vector<Color> &p_colors); - Vector<float> get_offsets() const; - Vector<Color> get_colors() const; - void set_points(Vector<GradientTexture::Point> &p_points); - Vector<GradientTexture::Point> &get_points(); - virtual Size2 get_minimum_size() const; - - GradientTextureEdit(); - virtual ~GradientTextureEdit(); -}; - -class GradientTextureEditorPlugin : public EditorPlugin { - - GDCLASS(GradientTextureEditorPlugin, EditorPlugin); - - bool _2d; - Ref<GradientTexture> gradient_texture_ref; - GradientTextureEdit *ramp_editor; - EditorNode *editor; - ToolButton *gradient_button; - -protected: - static void _bind_methods(); - void _ramp_changed(); - void _undo_redo_gradient_texture(const Vector<float> &offsets, const Vector<Color> &colors); - -public: - virtual String get_name() const { return "GradientTexture"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); - - GradientTextureEditorPlugin(EditorNode *p_node); - ~GradientTextureEditorPlugin(); -}; - -#endif // GRADIENT_TEXTURE_EDITOR_PLUGIN_H diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 7c8ee97f22..bad88979ac 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -188,7 +188,7 @@ void ShaderTextEditor::_validate_script() { if (err != OK) { String error_text = "error(" + itos(sl.get_error_line()) + "): " + sl.get_error_text(); set_error(error_text); - get_text_edit()->set_line_as_marked(sl.get_error_line(), true); + get_text_edit()->set_line_as_marked(sl.get_error_line() - 1, true); } else { for (int i = 0; i < get_text_edit()->get_line_count(); i++) diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 2d27e218ec..c55bef1b03 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -775,6 +775,11 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } freelook_active = b->is_pressed(); + if (freelook_active && !surface->has_focus()) { + // Focus usually doesn't trigger on right-click, but in case of freelook it should, + // otherwise using keyboard navigation would misbehave + surface->grab_focus(); + } } break; case BUTTON_MIDDLE: { diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 676e50d61c..c4fe15e61c 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -61,9 +61,21 @@ void TextureEditor::_notification(int p_what) { tex_height = texture->get_height() * tex_width / texture->get_width(); } + // Prevent the texture from being unpreviewable after the rescale, so that we can still see something + if (tex_height <= 0) + tex_height = 1; + if (tex_width <= 0) + tex_width = 1; + int ofs_x = (size.width - tex_width) / 2; int ofs_y = (size.height - tex_height) / 2; + if (texture->cast_to<CurveTexture>()) { + // In the case of CurveTextures we know they are 1 in height, so fill the preview to see the gradient + ofs_y = 0; + tex_height = size.height; + } + draw_texture_rect(texture, Rect2(ofs_x, ofs_y, tex_width, tex_height)); Ref<Font> font = get_font("font", "Label"); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index ea5bf437ff..8a7dcea393 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -218,7 +218,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) { mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-4, 0) }; - Ref<InputEventMouseButton> mb; + Ref<InputEventMouseButton> mb = p_input; if (mb.is_valid()) { if (mb->get_button_index() == BUTTON_LEFT) { diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 0b088f7171..14b25681b7 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -105,13 +105,16 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { if (!child2->cast_to<StaticBody2D>()) continue; StaticBody2D *sb = child2->cast_to<StaticBody2D>(); - int shape_count = sb->get_shape_count(); - if (shape_count == 0) - continue; - for (int shape_index = 0; shape_index < shape_count; ++shape_index) { - Ref<Shape2D> collision = sb->get_shape(shape_index); - if (collision.is_valid()) { - collisions.push_back(collision); + + List<uint32_t> shapes; + sb->get_shape_owners(&shapes); + + for (List<uint32_t>::Element *E = shapes.front(); E; E = E->next()) { + + for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { + + Ref<Shape> shape = sb->shape_owner_get_shape(E->get(), k); + collisions.push_back(shape); //uh what about transform? } } } diff --git a/editor/project_export.cpp b/editor/project_export.cpp index d58454a223..355f8ba22e 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -235,7 +235,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { export_button->set_disabled(true); } else { - export_error->show(); + export_error->hide(); export_templates_error->hide(); export_button->set_disabled(false); } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index da26c84e45..65ec697b73 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -824,7 +824,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: color_picker->show(); color_picker->set_edit_alpha(hint != PROPERTY_HINT_COLOR_NO_ALPHA); color_picker->set_pick_color(v); - set_size(Size2(300 * EDSCALE, color_picker->get_combined_minimum_size().height + 10 * EDSCALE)); + set_size(Size2(307 * EDSCALE, 460 * EDSCALE)); color_picker->set_focus_on_line_edit(); /* int ofs=80; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index dbd0758256..0f3f5500a8 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -245,7 +245,7 @@ void ScriptCreateDialog::_lang_changed(int l) { template_menu->clear(); template_menu->add_item(TTR("Default")); for (int i = 0; i < template_list.size(); i++) { - template_menu->add_item(template_list[i]); + template_menu->add_item(template_list[i].capitalize()); } } diff --git a/main/input_default.cpp b/main/input_default.cpp index e488438059..bde1e84926 100644 --- a/main/input_default.cpp +++ b/main/input_default.cpp @@ -874,6 +874,8 @@ void InputDefault::joy_axis(int p_device, int p_axis, const JoyAxis &p_value) { _THREAD_SAFE_METHOD_; + ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX); + Joypad &joy = joy_names[p_device]; if (joy.last_axis[p_axis] == p_value.value) { diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 5e3ce31dd6..adf3c8edc4 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -1276,7 +1276,7 @@ static void _find_identifiers_in_class(GDCompletionContext &context, bool p_stat } } List<MethodInfo> methods; - ClassDB::get_method_list(type, &methods); + ClassDB::get_method_list(type, &methods, false, true); for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) { if (E->get().name.begins_with("_")) continue; @@ -1643,7 +1643,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N } else { //regular method - if (p_method.operator String() == "connect") { + if (p_method.operator String() == "connect" || (p_method.operator String() == "emit_signal" && p_argidx == 0)) { if (p_argidx == 0) { List<MethodInfo> sigs; @@ -2251,7 +2251,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base } List<MethodInfo> mi; - ClassDB::get_method_list(t.obj_type, &mi); + ClassDB::get_method_list(t.obj_type, &mi, false, true); for (List<MethodInfo>::Element *E = mi.front(); E; E = E->next()) { if (E->get().name.begins_with("_")) diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 2033bc76a1..474d286405 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "export.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -40,381 +41,283 @@ #include "platform/osx/logo.h" #include "string.h" #include "version.h" -#if 0 class EditorExportPlatformOSX : public EditorExportPlatform { - GDCLASS( EditorExportPlatformOSX,EditorExportPlatform ); - - String custom_release_package; - String custom_debug_package; - - enum BitsMode { - BITS_FAT, - BITS_64, - BITS_32 - }; + GDCLASS(EditorExportPlatformOSX, EditorExportPlatform); int version_code; - String app_name; - String info; - String icon; - String identifier; - String short_version; - String version; - String signature; - String copyright; - BitsMode bits_mode; - bool high_resolution; - Ref<ImageTexture> logo; - void _fix_plist(Vector<uint8_t>& plist, const String &p_binary); - void _make_icon(const Image& p_icon,Vector<uint8_t>& data); - + void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary); + void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data); protected: - - 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; + virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); + virtual void get_export_options(List<ExportOption> *r_options); public: - virtual String get_name() const { return "Mac OSX"; } - virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; } virtual Ref<Texture> get_logo() const { return logo; } - - virtual bool poll_devices() { return false;} - virtual int get_device_count() const { return 0; } - virtual String get_device_name(int p_device) const { return String(); } - virtual String get_device_info(int p_device) const { return String(); } - virtual Error run(int p_device,int p_flags=0); - - virtual bool requires_password(bool p_debug) const { return false; } virtual String get_binary_extension() const { return "zip"; } - virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0); + virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); - virtual bool can_export(String *r_error=NULL) const; + virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const; EditorExportPlatformOSX(); ~EditorExportPlatformOSX(); }; -bool EditorExportPlatformOSX::_set(const StringName& p_name, const Variant& p_value) { - - String n=p_name; - - if (n=="custom_package/debug") - custom_debug_package=p_value; - else if (n=="custom_package/release") - custom_release_package=p_value; - else if (n=="application/name") - app_name=p_value; - else if (n=="application/info") - info=p_value; - else if (n=="application/icon") - icon=p_value; - else if (n=="application/identifier") - identifier=p_value; - else if (n=="application/signature") - signature=p_value; - else if (n=="application/short_version") - short_version=p_value; - else if (n=="application/version") - version=p_value; - else if (n=="application/copyright") - copyright=p_value; - else if (n=="application/bits_mode") - bits_mode=BitsMode(int(p_value)); - else if (n=="display/high_res") - high_resolution=p_value; - else - return false; - - return true; -} - -bool EditorExportPlatformOSX::_get(const StringName& p_name,Variant &r_ret) const{ - - String n=p_name; - - if (n=="custom_package/debug") - r_ret=custom_debug_package; - else if (n=="custom_package/release") - r_ret=custom_release_package; - else if (n=="application/name") - r_ret=app_name; - else if (n=="application/info") - r_ret=info; - else if (n=="application/icon") - r_ret=icon; - else if (n=="application/identifier") - r_ret=identifier; - else if (n=="application/signature") - r_ret=signature; - else if (n=="application/short_version") - r_ret=short_version; - else if (n=="application/version") - r_ret=version; - else if (n=="application/copyright") - r_ret=copyright; - else if (n=="application/bits_mode") - r_ret=bits_mode; - else if (n=="display/high_res") - r_ret=high_resolution; - else - return false; +void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) { - return true; + // what does this need to do? } -void EditorExportPlatformOSX::_get_property_list( List<PropertyInfo> *p_list) const{ - - p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE,"zip")); - p_list->push_back( PropertyInfo( Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE,"zip")); - - p_list->push_back( PropertyInfo( Variant::STRING, "application/name") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/info") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/icon",PROPERTY_HINT_FILE,"png") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/identifier") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/signature") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/short_version") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/version") ); - p_list->push_back( PropertyInfo( Variant::STRING, "application/copyright") ); - p_list->push_back( PropertyInfo( Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits") ); - p_list->push_back( PropertyInfo( Variant::BOOL, "display/high_res") ); +void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) { + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/debug", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_package/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), "")); + + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "png"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier"), "org.godotengine.macgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "godotmacgame")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/bits_mode", PROPERTY_HINT_ENUM, "Fat (32 & 64 bits),64 bits,32 bits"), 0)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); } -void EditorExportPlatformOSX::_make_icon(const Image& p_icon,Vector<uint8_t>& icon) { +void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) { - - Ref<ImageTexture> it = memnew( ImageTexture ); - int size=512; + Ref<ImageTexture> it = memnew(ImageTexture); + int size = 512; Vector<uint8_t> data; data.resize(8); - data[0]='i'; - data[1]='c'; - data[2]='n'; - data[3]='s'; + data[0] = 'i'; + data[1] = 'c'; + data[2] = 'n'; + data[3] = 's'; - const char *name[]={"ic09","ic08","ic07","icp6","icp5","icp4"}; - int index=0; + const char *name[] = { "ic09", "ic08", "ic07", "icp6", "icp5", "icp4" }; + int index = 0; - while(size>=16) { + while (size >= 16) { - Image copy = p_icon; - copy.convert(Image::FORMAT_RGBA8); - copy.resize(size,size); + Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? + copy->convert(Image::FORMAT_RGBA8); + copy->resize(size, size); it->create_from_image(copy); - String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/icon.png"; - ResourceSaver::save(path,it); + String path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/icon.png"; + ResourceSaver::save(path, it); - FileAccess *f = FileAccess::open(path,FileAccess::READ); + FileAccess *f = FileAccess::open(path, FileAccess::READ); ERR_FAIL_COND(!f); int ofs = data.size(); uint32_t len = f->get_len(); - data.resize(data.size()+len+8); - f->get_buffer(&data[ofs+8],len); + data.resize(data.size() + len + 8); + f->get_buffer(&data[ofs + 8], len); memdelete(f); - len+=8; - len=BSWAP32(len); - copymem(&data[ofs],name[index],4); - encode_uint32(len,&data[ofs+4]); + len += 8; + len = BSWAP32(len); + copymem(&data[ofs], name[index], 4); + encode_uint32(len, &data[ofs + 4]); index++; - size/=2; + size /= 2; } uint32_t total_len = data.size(); total_len = BSWAP32(total_len); - encode_uint32(total_len,&data[4]); + encode_uint32(total_len, &data[4]); - icon=data; + p_data = data; } - -void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_binary) { - +void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary) { String str; String strnew; - str.parse_utf8((const char*)plist.ptr(),plist.size()); - Vector<String> lines=str.split("\n"); - for(int i=0;i<lines.size();i++) { - if (lines[i].find("$binary")!=-1) { - strnew+=lines[i].replace("$binary",p_binary)+"\n"; - } else if (lines[i].find("$name")!=-1) { - strnew+=lines[i].replace("$name",p_binary)+"\n"; - } else if (lines[i].find("$info")!=-1) { - strnew+=lines[i].replace("$info",info)+"\n"; - } else if (lines[i].find("$identifier")!=-1) { - strnew+=lines[i].replace("$identifier",identifier)+"\n"; - } else if (lines[i].find("$short_version")!=-1) { - strnew+=lines[i].replace("$short_version",short_version)+"\n"; - } else if (lines[i].find("$version")!=-1) { - strnew+=lines[i].replace("$version",version)+"\n"; - } else if (lines[i].find("$signature")!=-1) { - strnew+=lines[i].replace("$signature",signature)+"\n"; - } else if (lines[i].find("$copyright")!=-1) { - strnew+=lines[i].replace("$copyright",copyright)+"\n"; - } else if (lines[i].find("$highres")!=-1) { - strnew+=lines[i].replace("$highres",high_resolution?"<true/>":"<false/>")+"\n"; + str.parse_utf8((const char *)plist.ptr(), plist.size()); + Vector<String> lines = str.split("\n"); + for (int i = 0; i < lines.size(); i++) { + if (lines[i].find("$binary") != -1) { + strnew += lines[i].replace("$binary", p_binary) + "\n"; + } else if (lines[i].find("$name") != -1) { + strnew += lines[i].replace("$name", p_binary) + "\n"; + } else if (lines[i].find("$info") != -1) { + strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n"; + } else if (lines[i].find("$identifier") != -1) { + strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n"; + } else if (lines[i].find("$short_version") != -1) { + strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n"; + } else if (lines[i].find("$version") != -1) { + strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; + } else if (lines[i].find("$signature") != -1) { + strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; + } else if (lines[i].find("$copyright") != -1) { + strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; + } else if (lines[i].find("$highres") != -1) { + strnew += lines[i].replace("$highres", p_preset->get("display/high_res") ? "<true/>" : "<false/>") + "\n"; } else { - strnew+=lines[i]+"\n"; + strnew += lines[i] + "\n"; } } CharString cs = strnew.utf8(); plist.resize(cs.size()); - for(int i=9;i<cs.size();i++) { - plist[i]=cs[i]; + for (int i = 9; i < cs.size(); i++) { + plist[i] = cs[i]; } } -Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, int p_flags) { +Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) { String src_pkg; - EditorProgress ep("export","Exporting for OSX",104); - + EditorProgress ep("export", "Exporting for OSX", 104); if (p_debug) - src_pkg=custom_debug_package; + src_pkg = p_preset->get("custom_package/debug"); else - src_pkg=custom_release_package; + src_pkg = p_preset->get("custom_package/release"); - if (src_pkg=="") { + if (src_pkg == "") { String err; - src_pkg=find_export_template("osx.zip", &err); - if (src_pkg=="") { + src_pkg = find_export_template("osx.zip", &err); + if (src_pkg == "") { EditorNode::add_io_error(err); return ERR_FILE_NOT_FOUND; } } - - FileAccess *src_f=NULL; + FileAccess *src_f = NULL; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - ep.step("Creating app",0); + ep.step("Creating app", 0); unzFile pkg = unzOpen2(src_pkg.utf8().get_data(), &io); if (!pkg) { - EditorNode::add_io_error("Could not find template app to export:\n"+src_pkg); + EditorNode::add_io_error("Could not find template app to export:\n" + src_pkg); return ERR_FILE_NOT_FOUND; } ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN); int ret = unzGoToFirstFile(pkg); - zlib_filefunc_def io2=io; - FileAccess *dst_f=NULL; - io2.opaque=&dst_f; - zipFile dpkg=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io2); + zlib_filefunc_def io2 = io; + FileAccess *dst_f = NULL; + io2.opaque = &dst_f; + zipFile dpkg = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io2); String binary_to_use = "godot_osx_" + String(p_debug ? "debug" : "release") + "."; - binary_to_use += String(bits_mode==BITS_FAT ? "fat" : bits_mode==BITS_64 ? "64" : "32"); + int bits_mode = p_preset->get("application/bits_mode"); + binary_to_use += String(bits_mode == 0 ? "fat" : bits_mode == 1 ? "64" : "32"); - print_line("binary: "+binary_to_use); + print_line("binary: " + binary_to_use); String pkg_name; - if (app_name!="") - pkg_name=app_name; - else if (String(GlobalConfig::get_singleton()->get("application/name"))!="") - pkg_name=String(GlobalConfig::get_singleton()->get("application/name")); + if (p_preset->get("application/name") != "") + pkg_name = p_preset->get("application/name"); // app_name + else if (String(GlobalConfig::get_singleton()->get("application/name")) != "") + pkg_name = String(GlobalConfig::get_singleton()->get("application/name")); else - pkg_name="Unnamed"; - + pkg_name = "Unnamed"; bool found_binary = false; - while(ret==UNZ_OK) { + while (ret == UNZ_OK) { //get filename unz_file_info info; char fname[16384]; - ret = unzGetCurrentFileInfo(pkg,&info,fname,16384,NULL,0,NULL,0); + ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0); - String file=fname; + String file = fname; - print_line("READ: "+file); + print_line("READ: " + file); Vector<uint8_t> data; data.resize(info.uncompressed_size); //read unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg,data.ptr(),data.size()); + unzReadCurrentFile(pkg, data.ptr(), data.size()); unzCloseCurrentFile(pkg); //write - file = file.replace_first("osx_template.app/",""); + file = file.replace_first("osx_template.app/", ""); - - if (file=="Contents/Info.plist") { + if (file == "Contents/Info.plist") { print_line("parse plist"); - _fix_plist(data,pkg_name); + _fix_plist(p_preset, data, pkg_name); } if (file.begins_with("Contents/MacOS/godot_")) { - if (file!="Contents/MacOS/"+binary_to_use) { + if (file != "Contents/MacOS/" + binary_to_use) { ret = unzGoToNextFile(pkg); continue; //ignore! } found_binary = true; - file="Contents/MacOS/"+pkg_name; + file = "Contents/MacOS/" + pkg_name; } - if (file=="Contents/Resources/icon.icns") { + if (file == "Contents/Resources/icon.icns") { //see if there is an icon - String iconpath = GlobalConfig::get_singleton()->get("application/icon"); - print_line("icon? "+iconpath); - if (iconpath!="") { - Image icon; - icon.load(iconpath); - if (!icon.empty()) { + String iconpath; + if (p_preset->get("application/icon") != "") + iconpath = p_preset->get("application/icon"); + else + iconpath = GlobalConfig::get_singleton()->get("application/icon"); + print_line("icon? " + iconpath); + if (iconpath != "") { + Ref<Image> icon; + icon.instance(); + icon->load(iconpath); + if (!icon->empty()) { print_line("loaded?"); - _make_icon(icon,data); + _make_icon(icon, data); } } //bleh? } - file=pkg_name+".app/"+file; + file = pkg_name + ".app/" + file; - if (data.size()>0) { - print_line("ADDING: "+file+" size: "+itos(data.size())); + if (data.size() > 0) { + print_line("ADDING: " + file + " size: " + itos(data.size())); zip_fileinfo fi; - fi.tmz_date.tm_hour=info.tmu_date.tm_hour; - fi.tmz_date.tm_min=info.tmu_date.tm_min; - fi.tmz_date.tm_sec=info.tmu_date.tm_sec; - fi.tmz_date.tm_mon=info.tmu_date.tm_mon; - fi.tmz_date.tm_mday=info.tmu_date.tm_mday; - fi.tmz_date.tm_year=info.tmu_date.tm_year; - fi.dosDate=info.dosDate; - fi.internal_fa=info.internal_fa; - fi.external_fa=info.external_fa; + fi.tmz_date.tm_hour = info.tmu_date.tm_hour; + fi.tmz_date.tm_min = info.tmu_date.tm_min; + fi.tmz_date.tm_sec = info.tmu_date.tm_sec; + fi.tmz_date.tm_mon = info.tmu_date.tm_mon; + fi.tmz_date.tm_mday = info.tmu_date.tm_mday; + fi.tmz_date.tm_year = info.tmu_date.tm_year; + fi.dosDate = info.dosDate; + fi.internal_fa = info.internal_fa; + fi.external_fa = info.external_fa; int err = zipOpenNewFileInZip(dpkg, - file.utf8().get_data(), - &fi, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - print_line("OPEN ERR: "+itos(err)); - err = zipWriteInFileInZip(dpkg,data.ptr(),data.size()); - print_line("WRITE ERR: "+itos(err)); + file.utf8().get_data(), + &fi, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + print_line("OPEN ERR: " + itos(err)); + err = zipWriteInFileInZip(dpkg, data.ptr(), data.size()); + print_line("WRITE ERR: " + itos(err)); zipCloseFileInZip(dpkg); } @@ -422,126 +325,98 @@ Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug } if (!found_binary) { - ERR_PRINTS("Requested template binary '"+binary_to_use+"' not found. It might be missing from your template archive."); - zipClose(dpkg,NULL); + ERR_PRINTS("Requested template binary '" + binary_to_use + "' not found. It might be missing from your template archive."); + zipClose(dpkg, NULL); unzClose(pkg); return ERR_FILE_NOT_FOUND; } + ep.step("Making PKG", 1); - ep.step("Making PKG",1); - - String pack_path=EditorSettings::get_singleton()->get_settings_path()+"/tmp/data.pck"; - FileAccess *pfs = FileAccess::open(pack_path,FileAccess::WRITE); - Error err = save_pack(pfs); - memdelete(pfs); + String pack_path = EditorSettings::get_singleton()->get_settings_path() + "/tmp/data.pck"; + Error err = save_pack(p_preset, pack_path); if (err) { - zipClose(dpkg,NULL); + zipClose(dpkg, NULL); unzClose(pkg); return err; - } { //write datapack zipOpenNewFileInZip(dpkg, - (pkg_name+".app/Contents/Resources/data.pck").utf8().get_data(), - NULL, - NULL, - 0, - NULL, - 0, - NULL, - Z_DEFLATED, - Z_DEFAULT_COMPRESSION); - - - FileAccess *pf = FileAccess::open(pack_path,FileAccess::READ); - ERR_FAIL_COND_V(!pf,ERR_CANT_OPEN); + (pkg_name + ".app/Contents/Resources/data.pck").utf8().get_data(), + NULL, + NULL, + 0, + NULL, + 0, + NULL, + Z_DEFLATED, + Z_DEFAULT_COMPRESSION); + + FileAccess *pf = FileAccess::open(pack_path, FileAccess::READ); + ERR_FAIL_COND_V(!pf, ERR_CANT_OPEN); const int BSIZE = 16384; uint8_t buf[BSIZE]; - while(true) { + while (true) { - int r = pf->get_buffer(buf,BSIZE); - if (r<=0) + int r = pf->get_buffer(buf, BSIZE); + if (r <= 0) break; - zipWriteInFileInZip(dpkg,buf,r); - + zipWriteInFileInZip(dpkg, buf, r); } zipCloseFileInZip(dpkg); memdelete(pf); - } - zipClose(dpkg,NULL); + zipClose(dpkg, NULL); unzClose(pkg); return OK; } +bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { -Error EditorExportPlatformOSX::run(int p_device, int p_flags) { - - return OK; -} - - -EditorExportPlatformOSX::EditorExportPlatformOSX() { - - Image img( _osx_logo ); - logo = Ref<ImageTexture>( memnew( ImageTexture )); - logo->create_from_image(img); - - info="Made with Godot Engine"; - identifier="org.godotengine.macgame"; - signature="godotmacgame"; - short_version="1.0"; - version="1.0"; - bits_mode=BITS_FAT; - high_resolution=false; - -} - -bool EditorExportPlatformOSX::can_export(String *r_error) const { - - - bool valid=true; + bool valid = true; String err; - if (!exists_export_template("osx.zip")) { - valid=false; - err+="No export templates found.\nDownload and install export templates.\n"; + if (!exists_export_template("osx.zip", &err)) { + valid = false; } - if (custom_debug_package!="" && !FileAccess::exists(custom_debug_package)) { - valid=false; - err+="Custom debug package not found.\n"; + if (p_preset->get("custom_package/debug") != "" && !FileAccess::exists(p_preset->get("custom_package/debug"))) { + valid = false; + err += "Custom debug package not found.\n"; } - if (custom_release_package!="" && !FileAccess::exists(custom_release_package)) { - valid=false; - err+="Custom release package not found.\n"; + if (p_preset->get("custom_package/release") != "" && !FileAccess::exists(p_preset->get("custom_package/release"))) { + valid = false; + err += "Custom release package not found.\n"; } - if (r_error) - *r_error=err; + if (!err.empty()) + r_error = err; return valid; } +EditorExportPlatformOSX::EditorExportPlatformOSX() { -EditorExportPlatformOSX::~EditorExportPlatformOSX() { + Ref<Image> img = memnew(Image(_osx_logo)); + logo.instance(); + logo->create_from_image(img); +} +EditorExportPlatformOSX::~EditorExportPlatformOSX() { } -#endif void register_osx_exporter() { -#if 0 - Ref<EditorExportPlatformOSX> exporter = Ref<EditorExportPlatformOSX>( memnew(EditorExportPlatformOSX) ); - EditorImportExport::get_singleton()->add_export_platform(exporter); -#endif + Ref<EditorExportPlatformOSX> platform; + platform.instance(); + + EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico Binary files differindex fd5c28944f..dd611e07da 100644 --- a/platform/windows/godot.ico +++ b/platform/windows/godot.ico diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 3d9e64ae79..cef473dcdf 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -61,7 +61,7 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { - target[j] = buffer[j] * vol; + target[j] += buffer[j] * vol; vol += vol_inc; } @@ -76,8 +76,8 @@ void AudioStreamPlayer2D::_mix_audio() { for (int j = 0; j < buffer_size; j++) { AudioFrame frame = buffer[j] * vol; - targets[0][j] = frame; - targets[1][j] = frame; + targets[0][j] += frame; + targets[1][j] += frame; vol += vol_inc; } @@ -93,9 +93,9 @@ void AudioStreamPlayer2D::_mix_audio() { 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; + targets[0][j] += frame; + targets[1][j] += frame; + targets[2][j] += frame; vol += vol_inc; } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 89b89a50d8..189dd66a26 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -39,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 { @@ -665,7 +855,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; @@ -686,7 +876,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; } @@ -788,8 +978,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); @@ -815,7 +1005,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") ; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 906a08d219..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; @@ -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/particles_2d.cpp b/scene/2d/particles_2d.cpp index 7c864c3430..beff247264 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "particles_2d.h" + #include "scene/3d/particles.h" #include "scene/scene_string_names.h" @@ -276,10 +277,12 @@ void Particles2D::_notification(int p_what) { VS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid, normal_rid, h_frames, v_frames); +#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))) { draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); } +#endif } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { @@ -346,7 +349,7 @@ void Particles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); 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, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); + 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"); 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/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 5b5bce342d..e755b1480b 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -98,7 +98,7 @@ void MeshInstance::_get_property_list(List<PropertyInfo> *p_list) const { if (mesh.is_valid()) { for (int i = 0; i < mesh->get_surface_count(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "Material")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "material/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial")); } } } diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp index 3394c1e204..722b698b75 100644 --- a/scene/3d/particles.cpp +++ b/scene/3d/particles.cpp @@ -303,7 +303,7 @@ void Particles::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fract_delta"), "set_fractional_delta", "get_fractional_delta"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_order", PROPERTY_HINT_ENUM, "Index,Lifetime,View Depth"), "set_draw_order", "get_draw_order"); ADD_GROUP("Process Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ParticlesMaterial,ShaderMaterial"), "set_process_material", "get_process_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "process_material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,ParticlesMaterial"), "set_process_material", "get_process_material"); ADD_GROUP("Draw Passes", "draw_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "draw_passes", PROPERTY_HINT_RANGE, "0," + itos(MAX_DRAW_PASSES) + ",1"), "set_draw_passes", "get_draw_passes"); for (int i = 0; i < MAX_DRAW_PASSES; i++) { @@ -571,7 +571,7 @@ void ParticlesMaterial::_update_shader() { code += "\n"; code += " uint base_number=NUMBER/uint(trail_divisor);\n"; - code += " uint alt_seed=hash(base_number+uint(1));\n"; + code += " uint alt_seed=hash(base_number+uint(1)+RANDOM_SEED);\n"; code += " float angle_rand=rand_from_seed(alt_seed);\n"; code += " float scale_rand=rand_from_seed(alt_seed);\n"; code += " float hue_rot_rand=rand_from_seed(alt_seed);\n"; @@ -1082,16 +1082,9 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> case PARAM_SCALE: { VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); - Ref<CurveTexture> curve = p_texture; - if (curve.is_valid()) { - if (curve->get_min() == 0 && curve->get_max() == 1) { - - curve->set_max(32); - PoolVector<Vector2> points; - points.push_back(Vector2(0, 1)); - points.push_back(Vector2(1, 1)); - curve->set_points(points); - } + Ref<CurveTexture> curve_tex = p_texture; + if (curve_tex.is_valid()) { + curve_tex->ensure_default_setup(); } } break; @@ -1257,14 +1250,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail Ref<CurveTexture> curve = trail_size_modifier; if (curve.is_valid()) { - if (curve->get_min() == 0 && curve->get_max() == 1) { - - curve->set_max(32); - PoolVector<Vector2> points; - points.push_back(Vector2(0, 1)); - points.push_back(Vector2(1, 1)); - curve->set_points(points); - } + curve->ensure_default_setup(); } RID texture; diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp index 874c21546d..abc7766ecb 100644 --- a/scene/3d/scenario_fx.cpp +++ b/scene/3d/scenario_fx.cpp @@ -28,43 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "scenario_fx.h" +#include "scene/main/viewport.h" void WorldEnvironment::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_WORLD) { + if (p_what == Spatial::NOTIFICATION_ENTER_WORLD || p_what == Spatial::NOTIFICATION_ENTER_TREE) { if (environment.is_valid()) { - if (get_world()->get_environment().is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); } - get_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } - } else if (p_what == NOTIFICATION_EXIT_WORLD) { + } else if (p_what == Spatial::NOTIFICATION_EXIT_WORLD || p_what == Spatial::NOTIFICATION_EXIT_TREE) { - if (environment.is_valid() && get_world()->get_environment() == environment) { - get_world()->set_environment(Ref<Environment>()); - remove_from_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + if (environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref<Environment>()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } } } void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { - if (is_inside_world() && environment.is_valid() && get_world()->get_environment() == environment) { - get_world()->set_environment(Ref<Environment>()); - remove_from_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world()->get_environment() == environment) { + get_viewport()->find_world()->set_environment(Ref<Environment>()); + remove_from_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); //clean up } environment = p_environment; - if (is_inside_world() && environment.is_valid()) { - if (get_world()->get_environment().is_valid()) { + if (is_inside_tree() && environment.is_valid()) { + if (get_viewport()->find_world()->get_environment().is_valid()) { WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); } - get_world()->set_environment(environment); - add_to_group("_world_environment_" + itos(get_world()->get_scenario().get_id())); + get_viewport()->find_world()->set_environment(environment); + add_to_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id())); } update_configuration_warning(); @@ -77,11 +78,11 @@ Ref<Environment> WorldEnvironment::get_environment() const { String WorldEnvironment::get_configuration_warning() const { - if (!is_visible_in_tree() || !is_inside_tree() || !environment.is_valid()) + if (/*!is_visible_in_tree() ||*/ !is_inside_tree() || !environment.is_valid()) return String(); List<Node *> nodes; - get_tree()->get_nodes_in_group("_world_environment_" + itos(get_world()->get_scenario().get_id()), &nodes); + get_tree()->get_nodes_in_group("_world_environment_" + itos(get_viewport()->find_world()->get_scenario().get_id()), &nodes); if (nodes.size() > 1) { return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h index b2a4bc5472..d1e0a63130 100644 --- a/scene/3d/scenario_fx.h +++ b/scene/3d/scenario_fx.h @@ -36,9 +36,9 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class WorldEnvironment : public Spatial { +class WorldEnvironment : public Node { - GDCLASS(WorldEnvironment, Spatial); + GDCLASS(WorldEnvironment, Node); Ref<Environment> environment; diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index 104fa0f70f..6f8c38eddd 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -316,7 +316,7 @@ void GeometryInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance::get_aabb); ADD_GROUP("Geometry", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_material_override", "get_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial"), "set_material_override", "get_material_override"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "visible_in_all_rooms"), "set_flag", "get_flag", FLAG_VISIBLE_IN_ALL_ROOMS); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index ee6af21dbd..9ef340edbc 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -122,9 +122,6 @@ void ColorPicker::_value_changed(double) { } set_pick_color(color); - - _update_text_value(); - emit_signal("color_changed", color); } @@ -257,7 +254,7 @@ void ColorPicker::_update_text_value() { } void ColorPicker::_sample_draw() { - sample->draw_rect(Rect2(Point2(), Size2(256, 20)), color); + sample->draw_rect(Rect2(Point2(), Size2(uv_edit->get_size().width, 20)), color); } void ColorPicker::_hsv_draw(int p_wich, Control *c) { @@ -277,12 +274,12 @@ void ColorPicker::_hsv_draw(int p_wich, Control *c) { c->draw_polygon(points, colors); Vector<Color> colors2; Color col = color; - col.set_hsv(color.get_h(), 1, 1); + col.set_hsv(h, 1, 1); col.a = 0; colors2.push_back(col); col.a = 1; colors2.push_back(col); - col.set_hsv(color.get_h(), 1, 0); + col.set_hsv(h, 1, 0); colors2.push_back(col); col.a = 0; colors2.push_back(col); @@ -311,10 +308,10 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &ev) { if (bev.is_valid()) { if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { changing_color = true; - float x = CLAMP((float)bev->get_position().x, 0, 256); - float y = CLAMP((float)bev->get_position().y, 0, 256); - s = x / 256; - v = 1.0 - y / 256.0; + float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width); + float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height); + s = x / uv_edit->get_size().width; + v = 1.0 - y / uv_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -330,10 +327,10 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &ev) { if (mev.is_valid()) { if (!changing_color) return; - float x = CLAMP((float)mev->get_position().x, 0, 256); - float y = CLAMP((float)mev->get_position().y, 0, 256); - s = x / 256; - v = 1.0 - y / 256.0; + float x = CLAMP((float)mev->get_position().x, 0, uv_edit->get_size().width); + float y = CLAMP((float)mev->get_position().y, 0, uv_edit->get_size().height); + s = x / uv_edit->get_size().width; + v = 1.0 - y / uv_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -350,8 +347,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { changing_color = true; - h = 1 - (256.0 - (float)bev->get_position().y) / 256.0; - + float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); + h = y / w_edit->get_size().height; } else { changing_color = false; } @@ -368,9 +365,8 @@ void ColorPicker::_w_input(const Ref<InputEvent> &ev) { if (!changing_color) return; - float y = CLAMP((float)mev->get_position().y, 0, 256); - //h = 1.0 - y / 256.0; - h = y / 256.0; + float y = CLAMP((float)mev->get_position().y, 0, w_edit->get_size().height); + h = y / w_edit->get_size().height; color.set_hsv(h, s, v, color.a); last_hsv = color; set_pick_color(color); @@ -508,12 +504,14 @@ ColorPicker::ColorPicker() add_child(hb_smpl); HBoxContainer *hb_edit = memnew(HBoxContainer); + hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); uv_edit = memnew(Control); uv_edit->connect("gui_input", this, "_uv_input"); uv_edit->set_mouse_filter(MOUSE_FILTER_PASS); - uv_edit->set_custom_minimum_size(Size2(256, 256)); + uv_edit->set_h_size_flags(SIZE_EXPAND_FILL); + uv_edit->set_v_size_flags(SIZE_EXPAND_FILL); Vector<Variant> args = Vector<Variant>(); args.push_back(0); args.push_back(uv_edit); @@ -523,7 +521,9 @@ ColorPicker::ColorPicker() w_edit = memnew(Control); //w_edit->set_ignore_mouse(false); - w_edit->set_custom_minimum_size(Size2(30, 256)); + w_edit->set_custom_minimum_size(Size2(30, 0)); + w_edit->set_h_size_flags(SIZE_FILL); + w_edit->set_v_size_flags(SIZE_EXPAND_FILL); w_edit->connect("gui_input", this, "_w_input"); args.clear(); args.push_back(1); @@ -549,6 +549,7 @@ ColorPicker::ColorPicker() HBoxContainer *hbc = memnew(HBoxContainer); labels[i] = memnew(Label(lt[i])); + labels[i]->set_custom_minimum_size(Size2(10, 0)); hbc->add_child(labels[i]); scroll[i] = memnew(HSlider); @@ -570,7 +571,7 @@ ColorPicker::ColorPicker() HBoxContainer *hhb = memnew(HBoxContainer); btn_mode = memnew(CheckButton); - btn_mode->set_text("RAW Mode"); + btn_mode->set_text(TTR("RAW Mode")); btn_mode->connect("toggled", this, "set_raw_mode"); hhb->add_child(btn_mode); vbr->add_child(hhb); @@ -601,7 +602,7 @@ ColorPicker::ColorPicker() bt_add_preset = memnew(Button); bt_add_preset->set_icon(get_icon("add_preset")); - bt_add_preset->set_tooltip("Add current color as a preset"); + bt_add_preset->set_tooltip(TTR("Add current color as a preset")); bt_add_preset->connect("pressed", this, "_add_preset_pressed"); bbc->add_child(bt_add_preset); } diff --git a/scene/gui/input_action.cpp b/scene/gui/input_action.cpp index 311cb4ab13..3f80c31c8b 100644 --- a/scene/gui/input_action.cpp +++ b/scene/gui/input_action.cpp @@ -43,7 +43,7 @@ Ref<InputEvent> ShortCut::get_shortcut() const { bool ShortCut::is_shortcut(const Ref<InputEvent> &p_event) const { - return shortcut.is_valid() && shortcut->action_match(p_event); + return shortcut.is_valid() && shortcut->shortcut_match(p_event); } String ShortCut::get_as_text() const { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 0b8595de42..78ede6e494 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1831,7 +1831,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("add_image", "image:Texture"), &RichTextLabel::add_image); ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline); ClassDB::bind_method(D_METHOD("remove_line"), &RichTextLabel::remove_line); - ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font); + ClassDB::bind_method(D_METHOD("push_font", "font:Font"), &RichTextLabel::push_font); ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color); ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align); ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent); @@ -1854,7 +1854,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scroll_follow", "follow"), &RichTextLabel::set_scroll_follow); ClassDB::bind_method(D_METHOD("is_scroll_following"), &RichTextLabel::is_scroll_following); - ClassDB::bind_method(D_METHOD("get_v_scroll"), &RichTextLabel::get_v_scroll); + ClassDB::bind_method(D_METHOD("get_v_scroll:VScrollBar"), &RichTextLabel::get_v_scroll); ClassDB::bind_method(D_METHOD("scroll_to_line", "line"), &RichTextLabel::scroll_to_line); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 714327c5b7..a87c83f17c 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -49,6 +49,7 @@ #include "scene/scene_string_names.h" #include "global_config.h" +#include "scene/3d/scenario_fx.h" void ViewportTexture::setup_local_to_scene() { @@ -1017,10 +1018,9 @@ void Viewport::_propagate_enter_world(Node *p_node) { if (!p_node->is_inside_tree()) //may not have entered scene yet return; - Spatial *s = p_node->cast_to<Spatial>(); - if (s) { + if (p_node->cast_to<Spatial>() || p_node->cast_to<WorldEnvironment>()) { - s->notification(Spatial::NOTIFICATION_ENTER_WORLD); + p_node->notification(Spatial::NOTIFICATION_ENTER_WORLD); } else { Viewport *v = p_node->cast_to<Viewport>(); if (v) { @@ -1055,10 +1055,9 @@ void Viewport::_propagate_exit_world(Node *p_node) { if (!p_node->is_inside_tree()) //may have exited scene already return; - Spatial *s = p_node->cast_to<Spatial>(); - if (s) { + if (p_node->cast_to<Spatial>() || p_node->cast_to<WorldEnvironment>()) { - s->notification(Spatial::NOTIFICATION_EXIT_WORLD, true); + p_node->notification(Spatial::NOTIFICATION_EXIT_WORLD); } else { Viewport *v = p_node->cast_to<Viewport>(); if (v) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index d4ca55346a..151bc80321 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -469,6 +469,9 @@ void register_scene_types() { ClassDB::register_class<Shader>(); ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); + ClassDB::register_class<CanvasItemMaterial>(); + SceneTree::add_idle_callback(CanvasItemMaterial::flush_changes); + CanvasItemMaterial::init_shaders(); ClassDB::register_class<Node2D>(); ClassDB::register_class<Particles2D>(); //ClassDB::register_class<ParticleAttractor2D>(); @@ -577,6 +580,7 @@ void register_scene_types() { ClassDB::register_class<Animation>(); ClassDB::register_virtual_class<Font>(); ClassDB::register_class<BitmapFont>(); + ClassDB::register_class<Curve>(); ClassDB::register_class<DynamicFontData>(); ClassDB::register_class<DynamicFont>(); @@ -663,5 +667,6 @@ void unregister_scene_types() { SpatialMaterial::finish_shaders(); ParticlesMaterial::finish_shaders(); + CanvasItemMaterial::finish_shaders(); SceneStringNames::free(); } diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 10c12c9411..006e7de562 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -380,6 +380,365 @@ Curve2D::Curve2D() #endif +Curve::Curve() { + _bake_resolution = 100; + _baked_cache_dirty = false; +#ifdef TOOLS_ENABLED + _disable_set_data = false; +#endif +} + +int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) { + // Add a point and preserve order + + // Curve bounds is in 0..1 + if (p_pos.x > MAX_X) + p_pos.x = MAX_X; + else if (p_pos.x < MIN_X) + p_pos.x = MIN_X; + + int ret = -1; + + if (_points.size() == 0) { + _points.push_back(Point(p_pos, left_tangent, right_tangent)); + ret = 0; + + } else if (_points.size() == 1) { + // TODO Is the `else` able to handle this block already? + + real_t diff = p_pos.x - _points[0].pos.x; + + if (diff > 0) { + _points.push_back(Point(p_pos, left_tangent, right_tangent)); + ret = 1; + } else { + _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + ret = 0; + } + + } else { + + int i = get_index(p_pos.x); + + int nearest_index = i; + if (i + 1 < _points.size()) { + real_t diff0 = p_pos.x - _points[i].pos.x; + real_t diff1 = _points[i + 1].pos.x - p_pos.x; + + if (diff1 < diff0) + nearest_index = i + 1; + } + + if (i == 0 && p_pos.x < _points[0].pos.x) { + // Insert before anything else + _points.insert(0, Point(p_pos, left_tangent, right_tangent)); + ret = 0; + } else { + // Insert between i and i+1 + ++i; + _points.insert(i, Point(p_pos, left_tangent, right_tangent)); + ret = i; + } + } + + mark_dirty(); + + return ret; +} + +int Curve::get_index(real_t offset) const { + + // Lower-bound float binary search + + int imin = 0; + int imax = _points.size() - 1; + + while (imax - imin > 1) { + int m = (imin + imax) / 2; + + real_t a = _points[m].pos.x; + real_t b = _points[m + 1].pos.x; + + if (a < offset && b < offset) { + imin = m; + + } else if (a > offset) { + imax = m; + + } else { + return m; + } + } + + // Will happen if the offset is out of bounds + if (offset > _points[imax].pos.x) + return imax; + return imin; +} + +void Curve::clean_dupes() { + + bool dirty = false; + + for (int i = 1; i < _points.size(); ++i) { + real_t diff = _points[i - 1].pos.x - _points[i].pos.x; + if (diff <= CMP_EPSILON) { + _points.remove(i); + --i; + dirty = true; + } + } + + if (dirty) + mark_dirty(); +} + +void Curve::set_point_left_tangent(int i, real_t tangent) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].left_tangent = tangent; + mark_dirty(); +} + +void Curve::set_point_right_tangent(int i, real_t tangent) { + ERR_FAIL_INDEX(i, _points.size()); + _points[i].right_tangent = tangent; + mark_dirty(); +} + +real_t Curve::get_point_left_tangent(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), 0); + return _points[i].left_tangent; +} + +real_t Curve::get_point_right_tangent(int i) const { + ERR_FAIL_INDEX_V(i, _points.size(), 0); + return _points[i].right_tangent; +} + +void Curve::remove_point(int p_index) { + ERR_FAIL_INDEX(p_index, _points.size()); + _points.remove(p_index); + mark_dirty(); +} + +void Curve::clear_points() { + _points.clear(); + mark_dirty(); +} + +void Curve::set_point_value(int p_index, real_t pos) { + ERR_FAIL_INDEX(p_index, _points.size()); + _points[p_index].pos.y = pos; + mark_dirty(); +} + +int Curve::set_point_offset(int p_index, float offset) { + ERR_FAIL_INDEX_V(p_index, _points.size(), -1); + Point p = _points[p_index]; + remove_point(p_index); + int i = add_point(Vector2(offset, p.pos.y)); + _points[i].left_tangent = p.left_tangent; + _points[i].right_tangent = p.right_tangent; + return i; +} + +Vector2 Curve::get_point_pos(int p_index) const { + ERR_FAIL_INDEX_V(p_index, _points.size(), Vector2(0, 0)); + return _points[p_index].pos; +} + +real_t Curve::interpolate(real_t offset) const { + if (_points.size() == 0) + return 0; + if (_points.size() == 1) + return _points[0].pos.y; + + int i = get_index(offset); + + if (i == _points.size() - 1) + return _points[i].pos.y; + + real_t local = offset - _points[i].pos.x; + + if (i == 0 && local <= 0) + return _points[0].pos.y; + + return interpolate_local_nocheck(i, local); +} + +real_t Curve::interpolate_local_nocheck(int index, real_t local_offset) const { + + const Point a = _points[index]; + const Point b = _points[index + 1]; + + // Cubic bezier + + // ac-----bc + // / \ + // / \ Here with a.right_tangent > 0 + // / \ and b.left_tangent < 0 + // / \ + // a b + // + // |-d1--|-d2--|-d3--| + // + // d1 == d2 == d3 == d / 3 + + // Control points are chosen at equal distances + real_t d = b.pos.x - a.pos.x; + if (Math::abs(d) <= CMP_EPSILON) + return b.pos.y; + local_offset /= d; + d /= 3.0; + real_t yac = a.pos.y + d * a.right_tangent; + real_t ybc = b.pos.y - d * b.left_tangent; + + real_t y = _bezier_interp(local_offset, a.pos.y, yac, ybc, b.pos.y); + + return y; +} + +void Curve::mark_dirty() { + _baked_cache_dirty = true; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +Array Curve::get_data() const { + + Array output; + output.resize(_points.size() * 3); + + for (int j = 0; j < _points.size(); ++j) { + + const Point p = _points[j]; + int i = j * 3; + + output[i] = p.pos; + output[i + 1] = p.left_tangent; + output[i + 2] = p.right_tangent; + } + + return output; +} + +void Curve::set_data(Array input) { + ERR_FAIL_COND(input.size() % 3 != 0); + +#ifdef TOOLS_ENABLED + if (_disable_set_data) + return; +#endif + + _points.clear(); + + // Validate input + for (int i = 0; i < input.size(); i += 3) { + ERR_FAIL_COND(input[i].get_type() != Variant::VECTOR2); + ERR_FAIL_COND(input[i + 1].get_type() != Variant::REAL); + ERR_FAIL_COND(input[i + 2].get_type() != Variant::REAL); + } + + _points.resize(input.size() / 3); + + for (int j = 0; j < _points.size(); ++j) { + + Point &p = _points[j]; + int i = j * 3; + + p.pos = input[i]; + p.left_tangent = input[i + 1]; + p.right_tangent = input[i + 2]; + } + + mark_dirty(); +} + +void Curve::bake() { + _baked_cache.clear(); + + _baked_cache.resize(_bake_resolution); + + for (int i = 1; i < _bake_resolution - 1; ++i) { + real_t x = i / static_cast<real_t>(_bake_resolution); + real_t y = interpolate(x); + _baked_cache[i] = y; + } + + if (_points.size() != 0) { + _baked_cache[0] = _points[0].pos.y; + _baked_cache[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y; + } + + _baked_cache_dirty = false; +} + +void Curve::set_bake_resolution(int p_resolution) { + ERR_FAIL_COND(p_resolution < 1); + ERR_FAIL_COND(p_resolution > 1000); + _bake_resolution = p_resolution; + _baked_cache_dirty = true; +} + +real_t Curve::interpolate_baked(real_t offset) { + if (_baked_cache_dirty) { + // Last-second bake if not done already + bake(); + } + + // Special cases if the cache is too small + if (_baked_cache.size() == 0) { + if (_points.size() == 0) + return 0; + return _points[0].pos.y; + } else if (_baked_cache.size() == 1) { + return _baked_cache[0]; + } + + // Get interpolation index + real_t fi = offset * _baked_cache.size(); + int i = Math::floor(fi); + if (i < 0) { + i = 0; + fi = 0; + } else if (i >= _baked_cache.size()) { + i = _baked_cache.size() - 1; + fi = 0; + } + + // Interpolate + if (i + 1 < _baked_cache.size()) { + real_t t = fi - i; + return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t); + } else { + return _baked_cache[_baked_cache.size() - 1]; + } +} + +void Curve::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_point", "pos", "left_tangent", "right_tangent"), &Curve::add_point, DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point); + ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points); + ClassDB::bind_method(D_METHOD("get_point_pos", "index"), &Curve::get_point_pos); + ClassDB::bind_method(D_METHOD("set_point_value", "index, y"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("set_point_offset", "index, offset"), &Curve::set_point_value); + ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate); + ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked); + ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent); + ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_left_tangent); + ClassDB::bind_method(D_METHOD("set_point_left_tangent", "index", "tangent"), &Curve::set_point_left_tangent); + ClassDB::bind_method(D_METHOD("set_point_right_tangent", "index", "tangent"), &Curve::set_point_left_tangent); + ClassDB::bind_method(D_METHOD("clean_dupes"), &Curve::clean_dupes); + ClassDB::bind_method(D_METHOD("bake"), &Curve::bake); + ClassDB::bind_method(D_METHOD("get_bake_resolution"), &Curve::get_bake_resolution); + ClassDB::bind_method(D_METHOD("set_bake_resolution", "resolution"), &Curve::set_bake_resolution); + ClassDB::bind_method(D_METHOD("_get_data"), &Curve::get_data); + ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve::set_data); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); +} + int Curve2D::get_point_count() const { return points.size(); diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 17c0ac9f5e..63b9a07f07 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -82,6 +82,78 @@ public: #endif +// y(x) curve +class Curve : public Resource { + GDCLASS(Curve, Resource) +public: + static const int MIN_X = 0.f; + static const int MAX_X = 1.f; + +#ifdef TOOLS_ENABLED + bool _disable_set_data; +#endif + + struct Point { + Vector2 pos; + real_t left_tangent; + real_t right_tangent; + + Point() { + left_tangent = 0; + right_tangent = 0; + } + + Point(Vector2 p, real_t left = 0, real_t right = 0) { + pos = p; + left_tangent = left; + right_tangent = right; + } + }; + + Curve(); + + int get_point_count() const { return _points.size(); } + + int add_point(Vector2 p_pos, real_t left_tangent = 0, real_t right_tangent = 0); + void remove_point(int p_index); + void clear_points(); + + int get_index(real_t offset) const; + + void set_point_value(int p_index, real_t pos); + int set_point_offset(int p_index, float offset); + Vector2 get_point_pos(int p_index) const; + + real_t interpolate(real_t offset) const; + real_t interpolate_local_nocheck(int index, real_t local_offset) const; + + void clean_dupes(); + + void set_point_left_tangent(int i, real_t tangent); + void set_point_right_tangent(int i, real_t tangent); + real_t get_point_left_tangent(int i) const; + real_t get_point_right_tangent(int i) const; + + Array get_data() const; + void set_data(Array input); + + void bake(); + int get_bake_resolution() const { return _bake_resolution; } + void set_bake_resolution(int p_interval); + real_t interpolate_baked(real_t offset); + +protected: + static void _bind_methods(); + +private: + void mark_dirty(); + + Vector<Point> _points; + bool _baked_cache_dirty; + Vector<real_t> _baked_cache; + int _bake_resolution; +}; + class Curve2D : public Resource { GDCLASS(Curve2D, Resource); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index a435ba06cc..24e3977de8 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -959,7 +959,6 @@ void Environment::_bind_methods() { ADD_GROUP("SS Reflections", "ss_reflections_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ss_reflections_enabled"), "set_ssr_enabled", "is_ssr_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ss_reflections_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_accel", PROPERTY_HINT_RANGE, "0,4,0.01"), "set_ssr_accel", "get_ssr_accel"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_in", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_in", "get_ssr_fade_in"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_fade_out", PROPERTY_HINT_EXP_EASING), "set_ssr_fade_out", "get_ssr_fade_out"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "ss_reflections_depth_tolerance", PROPERTY_HINT_RANGE, "0.1,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance"); @@ -1040,7 +1039,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_far_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_far_amount", "get_dof_blur_far_amount"); ADD_PROPERTY(PropertyInfo(Variant::INT, "dof_blur_far_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_dof_blur_far_quality", "get_dof_blur_far_quality"); - ADD_GROUP("DOF Far Near", "dof_blur_near_"); + ADD_GROUP("DOF Near Blur", "dof_blur_near_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index a3180ee1df..ef7011b2af 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -668,7 +668,11 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::DICTIONARY, "surfaces/" + itos(i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "Material", PROPERTY_USAGE_EDITOR)); + if (surfaces[i].is_2d) { + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR)); + } else { + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial", PROPERTY_USAGE_EDITOR)); + } } p_list->push_back(PropertyInfo(Variant::RECT3, "custom_aabb/custom_aabb")); @@ -692,6 +696,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const Surface s; s.aabb = p_aabb; + s.is_2d = p_format & ARRAY_FLAG_USE_2D_VERTICES; surfaces.push_back(s); _recompute_aabb(); @@ -709,7 +714,8 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & /* make aABB? */ { - PoolVector<Vector3> vertices = p_arrays[ARRAY_VERTEX]; + Variant arr = p_arrays[ARRAY_VERTEX]; + PoolVector<Vector3> vertices = arr; int len = vertices.size(); ERR_FAIL_COND(len == 0); PoolVector<Vector3>::Read r = vertices.read(); @@ -726,6 +732,7 @@ void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array & } surfaces[surfaces.size() - 1].aabb = aabb; + surfaces[surfaces.size() - 1].is_2d = arr.get_type() == Variant::POOL_VECTOR2_ARRAY; _recompute_aabb(); } diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 37fddf3aa6..f716b59fe9 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -147,6 +147,7 @@ private: String name; Rect3 aabb; Ref<Material> material; + bool is_2d; }; Vector<Surface> surfaces; RID mesh; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 2120b37497..5049c0a1d6 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -30,7 +30,9 @@ #include "texture.h" #include "core/method_bind_ext.inc" #include "core/os/os.h" +#include "core_string_names.h" #include "io/image_loader.h" + Size2 Texture::get_size() const { return Size2(get_width(), get_height()); @@ -1376,254 +1378,126 @@ void CurveTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width); - ClassDB::bind_method(D_METHOD("set_points", "points"), &CurveTexture::set_points); - ClassDB::bind_method(D_METHOD("get_points"), &CurveTexture::get_points); + ClassDB::bind_method(D_METHOD("set_curve", "curve:Curve"), &CurveTexture::set_curve); + ClassDB::bind_method(D_METHOD("get_curve:Curve"), &CurveTexture::get_curve); + + ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update); ADD_PROPERTY(PropertyInfo(Variant::REAL, "min", PROPERTY_HINT_RANGE, "-1024,1024"), "set_min", "get_min"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "max", PROPERTY_HINT_RANGE, "-1024,1024"), "set_max", "get_max"); ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); } void CurveTexture::set_max(float p_max) { - max = p_max; + _max = p_max; emit_changed(); } float CurveTexture::get_max() const { - return max; + return _max; } void CurveTexture::set_min(float p_min) { - min = p_min; + _min = p_min; emit_changed(); } float CurveTexture::get_min() const { - return min; + return _min; } void CurveTexture::set_width(int p_width) { ERR_FAIL_COND(p_width < 32 || p_width > 4096); - width = p_width; - if (points.size()) - set_points(points); + _width = p_width; + _update(); } int CurveTexture::get_width() const { - return width; + return _width; } -static void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, float *p_heights, bool *p_useds, int p_width, float p_min, float p_max) { - - float geometry[4][4]; - float tmp1[4][4]; - float tmp2[4][4]; - float deltas[4][4]; - double x, dx, dx2, dx3; - double y, dy, dy2, dy3; - double d, d2, d3; - int lastx; - int newx; - float lasty; - float newy; - int ntimes; - int i, j; - - int xmax = p_width; - - /* construct the geometry matrix from the segment */ - for (i = 0; i < 4; i++) { - geometry[i][2] = 0; - geometry[i][3] = 0; - } +void CurveTexture::ensure_default_setup() { - geometry[0][0] = (p_a[0] * xmax); - geometry[1][0] = (p_b[0] * xmax); - geometry[2][0] = (p_c[0] * xmax); - geometry[3][0] = (p_d[0] * xmax); - - geometry[0][1] = (p_a[1]); - geometry[1][1] = (p_b[1]); - geometry[2][1] = (p_c[1]); - geometry[3][1] = (p_d[1]); - - /* subdivide the curve ntimes (1000) times */ - ntimes = 4 * xmax; - /* ntimes can be adjusted to give a finer or coarser curve */ - d = 1.0 / ntimes; - d2 = d * d; - d3 = d * d * d; - - /* construct a temporary matrix for determining the forward differencing deltas */ - tmp2[0][0] = 0; - tmp2[0][1] = 0; - tmp2[0][2] = 0; - tmp2[0][3] = 1; - tmp2[1][0] = d3; - tmp2[1][1] = d2; - tmp2[1][2] = d; - tmp2[1][3] = 0; - tmp2[2][0] = 6 * d3; - tmp2[2][1] = 2 * d2; - tmp2[2][2] = 0; - tmp2[2][3] = 0; - tmp2[3][0] = 6 * d3; - tmp2[3][1] = 0; - tmp2[3][2] = 0; - tmp2[3][3] = 0; - - /* compose the basis and geometry matrices */ - - static const float CR_basis[4][4] = { - { -0.5, 1.5, -1.5, 0.5 }, - { 1.0, -2.5, 2.0, -0.5 }, - { -0.5, 0.0, 0.5, 0.0 }, - { 0.0, 1.0, 0.0, 0.0 }, - }; - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] + - CR_basis[i][1] * geometry[1][j] + - CR_basis[i][2] * geometry[2][j] + - CR_basis[i][3] * geometry[3][j]); - } + if (_curve.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + set_curve(curve); } - /* compose the above results to get the deltas matrix */ - - for (i = 0; i < 4; i++) { - for (j = 0; j < 4; j++) { - deltas[i][j] = (tmp2[i][0] * tmp1[0][j] + - tmp2[i][1] * tmp1[1][j] + - tmp2[i][2] * tmp1[2][j] + - tmp2[i][3] * tmp1[3][j]); - } + + if (get_min() == 0 && get_max() == 1) { + set_max(32); } +} - /* extract the x deltas */ - x = deltas[0][0]; - dx = deltas[1][0]; - dx2 = deltas[2][0]; - dx3 = deltas[3][0]; - - /* extract the y deltas */ - y = deltas[0][1]; - dy = deltas[1][1]; - dy2 = deltas[2][1]; - dy3 = deltas[3][1]; - - lastx = CLAMP(x, 0, xmax); - lasty = y; - - p_heights[lastx] = lasty; - p_useds[lastx] = true; - - /* loop over the curve */ - for (i = 0; i < ntimes; i++) { - /* increment the x values */ - x += dx; - dx += dx2; - dx2 += dx3; - - /* increment the y values */ - y += dy; - dy += dy2; - dy2 += dy3; - - newx = CLAMP((Math::round(x)), 0, xmax); - newy = CLAMP(y, p_min, p_max); - - /* if this point is different than the last one...then draw it */ - if ((lastx != newx) || (lasty != newy)) { - p_useds[newx] = true; - p_heights[newx] = newy; +void CurveTexture::set_curve(Ref<Curve> p_curve) { + if (_curve != p_curve) { + if (_curve.is_valid()) { + _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_update"); } - - lastx = newx; - lasty = newy; + _curve = p_curve; + if (_curve.is_valid()) { + _curve->connect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + _update(); } } -void CurveTexture::set_points(const PoolVector<Vector2> &p_points) { - - points = p_points; +void CurveTexture::_update() { PoolVector<uint8_t> data; - PoolVector<bool> used; - data.resize(width * sizeof(float)); - used.resize(width); + data.resize(_width * sizeof(float)); + + // The array is locked in that scope { PoolVector<uint8_t>::Write wd8 = data.write(); float *wd = (float *)wd8.ptr(); - PoolVector<bool>::Write wu = used.write(); - int pc = p_points.size(); - PoolVector<Vector2>::Read pr = p_points.read(); - - for (int i = 0; i < width; i++) { - wd[i] = 0.0; - wu[i] = false; - } - - Vector2 prev = Vector2(0, 0); - Vector2 prev2 = Vector2(0, 0); - - for (int i = -1; i < pc; i++) { - Vector2 next; - Vector2 next2; - if (i + 1 >= pc) { - next = Vector2(1, 0); - } else { - next = Vector2(pr[i + 1].x, pr[i + 1].y); + if (_curve.is_valid()) { + Curve &curve = **_curve; + float height = _max - _min; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + float v = curve.interpolate_baked(t); + wd[i] = CLAMP(_min + v * height, _min, _max); } - if (i + 2 >= pc) { - next2 = Vector2(1, 0); - } else { - next2 = Vector2(pr[i + 2].x, pr[i + 2].y); + } else { + for (int i = 0; i < _width; ++i) { + wd[i] = 0; } - - /*if (i==-1 && prev.offset==next.offset) { - prev=next; - continue; - }*/ - - _plot_curve(prev2, prev, next, next2, wd, wu.ptr(), width, min, max); - - prev2 = prev; - prev = next; } } - Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RF, data)); + Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data)); - VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER); - VS::get_singleton()->texture_set_data(texture, image); + VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER); + VS::get_singleton()->texture_set_data(_texture, image); emit_changed(); } -PoolVector<Vector2> CurveTexture::get_points() const { +Ref<Curve> CurveTexture::get_curve() const { - return points; + return _curve; } RID CurveTexture::get_rid() const { - return texture; + return _texture; } CurveTexture::CurveTexture() { - max = 1; - min = 0; - width = 2048; - texture = VS::get_singleton()->texture_create(); + _max = 1; + _min = 0; + _width = 2048; + _texture = VS::get_singleton()->texture_create(); } CurveTexture::~CurveTexture() { - VS::get_singleton()->free(texture); + VS::get_singleton()->free(_texture); } ////////////////// @@ -1634,13 +1508,6 @@ CurveTexture::~CurveTexture() { #define COLOR_RAMP_SET_COLORS "set_colors" GradientTexture::GradientTexture() { - //Set initial color ramp transition from black to white - points.resize(2); - points[0].color = Color(0, 0, 0, 1); - points[0].offset = 0; - points[1].color = Color(1, 1, 1, 1); - points[1].offset = 1; - is_sorted = true; update_pending = false; width = 2048; @@ -1654,32 +1521,33 @@ GradientTexture::~GradientTexture() { void GradientTexture::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &GradientTexture::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset", "color"), &GradientTexture::remove_point); - - ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &GradientTexture::set_offset); - ClassDB::bind_method(D_METHOD("get_offset", "point"), &GradientTexture::get_offset); - - ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &GradientTexture::set_color); - ClassDB::bind_method(D_METHOD("get_color", "point"), &GradientTexture::get_color); + ClassDB::bind_method(D_METHOD("set_gradient", "gradient:Gradient"), &GradientTexture::set_gradient); + ClassDB::bind_method(D_METHOD("get_gradient:Gradient"), &GradientTexture::get_gradient); ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width); - ClassDB::bind_method(D_METHOD("interpolate", "offset"), &GradientTexture::get_color_at_offset); - - ClassDB::bind_method(D_METHOD("get_point_count"), &GradientTexture::get_points_count); - ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_OFFSETS, "offsets"), &GradientTexture::set_offsets); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_OFFSETS), &GradientTexture::get_offsets); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width"); +} - ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &GradientTexture::set_colors); - ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &GradientTexture::get_colors); +void GradientTexture::set_gradient(Ref<Gradient> p_gradient) { + if (p_gradient == gradient) + return; + if (gradient.is_valid()) { + gradient->disconnect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + gradient = p_gradient; + if (gradient.is_valid()) { + gradient->connect(CoreStringNames::get_singleton()->changed, this, "_update"); + } + _update(); + emit_changed(); +} - ADD_PROPERTY(PropertyInfo(Variant::INT, "width"), "set_width", "get_width"); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS); - ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS); +Ref<Gradient> GradientTexture::get_gradient() const { + return gradient; } void GradientTexture::_queue_update() { @@ -1692,16 +1560,22 @@ void GradientTexture::_queue_update() { void GradientTexture::_update() { + if (gradient.is_null()) + return; + update_pending = false; PoolVector<uint8_t> data; data.resize(width * 4); { PoolVector<uint8_t>::Write wd8 = data.write(); + Gradient &g = **gradient; + for (int i = 0; i < width; i++) { + float ofs = float(i) / (width - 1); + Color color = g.get_color_at_offset(ofs); - Color color = get_color_at_offset(ofs); wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255)); wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255)); wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255)); @@ -1727,112 +1601,6 @@ int GradientTexture::get_width() const { return width; } -Vector<float> GradientTexture::get_offsets() const { - Vector<float> offsets; - offsets.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - offsets[i] = points[i].offset; - } - return offsets; -} - -Vector<Color> GradientTexture::get_colors() const { - Vector<Color> colors; - colors.resize(points.size()); - for (int i = 0; i < points.size(); i++) { - colors[i] = points[i].color; - } - return colors; -} - -void GradientTexture::set_offsets(const Vector<float> &p_offsets) { - points.resize(p_offsets.size()); - for (int i = 0; i < points.size(); i++) { - points[i].offset = p_offsets[i]; - } - is_sorted = false; - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_colors(const Vector<Color> &p_colors) { - if (points.size() < p_colors.size()) - is_sorted = false; - points.resize(p_colors.size()); - for (int i = 0; i < points.size(); i++) { - points[i].color = p_colors[i]; - } - emit_changed(); - _queue_update(); -} - -Vector<GradientTexture::Point> &GradientTexture::get_points() { - return points; -} - -void GradientTexture::add_point(float p_offset, const Color &p_color) { - - Point p; - p.offset = p_offset; - p.color = p_color; - is_sorted = false; - points.push_back(p); - - emit_changed(); - _queue_update(); -} - -void GradientTexture::remove_point(int p_index) { - - ERR_FAIL_INDEX(p_index, points.size()); - ERR_FAIL_COND(points.size() <= 2); - points.remove(p_index); - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_points(Vector<GradientTexture::Point> &p_points) { - points = p_points; - is_sorted = false; - emit_changed(); - _queue_update(); -} - -void GradientTexture::set_offset(int pos, const float offset) { - if (points.size() <= pos) - points.resize(pos + 1); - points[pos].offset = offset; - is_sorted = false; - emit_changed(); - _queue_update(); -} - -float GradientTexture::get_offset(int pos) const { - if (points.size() > pos) - return points[pos].offset; - return 0; //TODO: Maybe throw some error instead? -} - Ref<Image> GradientTexture::get_data() const { return VisualServer::get_singleton()->texture_get_data(texture); } - -void GradientTexture::set_color(int pos, const Color &color) { - if (points.size() <= pos) { - points.resize(pos + 1); - is_sorted = false; - } - points[pos].color = color; - emit_changed(); - _queue_update(); -} - -Color GradientTexture::get_color(int pos) const { - if (points.size() > pos) - return points[pos].color; - return Color(0, 0, 0, 1); //TODO: Maybe throw some error instead? -} - -int GradientTexture::get_points_count() const { - return points.size(); -} diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 2b82dbd21f..ff5a58c221 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -30,9 +30,11 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include "curve.h" #include "io/resource_loader.h" #include "math_2d.h" #include "resource.h" +#include "scene/resources/color_ramp.h" #include "servers/visual_server.h" /** @@ -389,20 +391,22 @@ public: ~CubeMap(); }; -VARIANT_ENUM_CAST(CubeMap::Flags); -VARIANT_ENUM_CAST(CubeMap::Side); -VARIANT_ENUM_CAST(CubeMap::Storage); +VARIANT_ENUM_CAST(CubeMap::Flags) +VARIANT_ENUM_CAST(CubeMap::Side) +VARIANT_ENUM_CAST(CubeMap::Storage) class CurveTexture : public Texture { - GDCLASS(CurveTexture, Texture); - RES_BASE_EXTENSION("curvetex"); + GDCLASS(CurveTexture, Texture) + RES_BASE_EXTENSION("curvetex") private: - RID texture; - PoolVector<Vector2> points; - float min, max; - int width; + RID _texture; + Ref<Curve> _curve; + float _min, _max; + int _width; + + void _update(); protected: static void _bind_methods(); @@ -417,8 +421,10 @@ public: void set_width(int p_width); int get_width() const; - void set_points(const PoolVector<Vector2> &p_points); - PoolVector<Vector2> get_points() const; + void ensure_default_setup(); + + void set_curve(Ref<Curve> p_curve); + Ref<Curve> get_curve() const; virtual RID get_rid() const; @@ -446,7 +452,7 @@ public: //VARIANT_ENUM_CAST( Texture::CubeMapSide ); class GradientTexture : public Texture { - GDCLASS(GradientTexture, Texture); + GDCLASS(GradientTexture, Texture) public: struct Point { @@ -459,8 +465,7 @@ public: }; private: - Vector<Point> points; - bool is_sorted; + Ref<Gradient> gradient; bool update_pending; RID texture; int width; @@ -472,23 +477,8 @@ protected: static void _bind_methods(); public: - void add_point(float p_offset, const Color &p_color); - void remove_point(int p_index); - - void set_points(Vector<Point> &points); - Vector<Point> &get_points(); - - void set_offset(int pos, const float offset); - float get_offset(int pos) const; - - void set_color(int pos, const Color &color); - Color get_color(int pos) const; - - void set_offsets(const Vector<float> &offsets); - Vector<float> get_offsets() const; - - void set_colors(const Vector<Color> &colors); - Vector<Color> get_colors() const; + void set_gradient(Ref<Gradient> p_gradient); + Ref<Gradient> get_gradient() const; void set_width(int p_width); int get_width() const; @@ -500,52 +490,8 @@ public: virtual void set_flags(uint32_t p_flags) {} virtual uint32_t get_flags() const { return FLAG_FILTER; } - _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { - - if (points.empty()) - return Color(0, 0, 0, 1); - - if (!is_sorted) { - points.sort(); - is_sorted = true; - } - - //binary search - int low = 0; - int high = points.size() - 1; - int middle; - - while (low <= high) { - middle = (low + high) / 2; - Point &point = points[middle]; - if (point.offset > p_offset) { - high = middle - 1; //search low end of array - } else if (point.offset < p_offset) { - low = middle + 1; //search high end of array - } else { - return point.color; - } - } - - //return interpolated value - if (points[middle].offset > p_offset) { - middle--; - } - int first = middle; - int second = middle + 1; - if (second >= points.size()) - return points[points.size() - 1].color; - if (first < 0) - return points[0].color; - Point &pointFirst = points[first]; - Point &pointSecond = points[second]; - return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); - } - virtual Ref<Image> get_data() const; - int get_points_count() const; - GradientTexture(); virtual ~GradientTexture(); }; diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index c98375fc44..184db944da 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -32,7 +32,13 @@ bool AreaPair2DSW::setup(real_t p_step) { - bool result = area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), NULL, this); + bool result = false; + + if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) { + result = false; + } else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), NULL, this)) { + result = true; + } if (result != colliding) { @@ -90,7 +96,12 @@ AreaPair2DSW::~AreaPair2DSW() { bool Area2Pair2DSW::setup(real_t p_step) { - bool result = area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), NULL, this); + bool result = false; + if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) { + result = false; + } else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), NULL, this)) { + result = true; + } if (result != colliding) { diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index 03ad66d4e9..538ea10211 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -676,8 +676,6 @@ Body2DSW::Body2DSW() area_linear_damp = 0; contact_count = 0; gravity_scale = 1.0; - using_one_way_cache = false; - one_way_collision_max_depth = 0.1; first_integration = false; still_time = 0; diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 23adebbad6..9e5deef3f2 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -67,9 +67,6 @@ class Body2DSW : public CollisionObject2DSW { Vector2 applied_force; real_t applied_torque; - Vector2 one_way_collision_direction; - real_t one_way_collision_max_depth; - SelfList<Body2DSW> active_list; SelfList<Body2DSW> inertia_update_list; SelfList<Body2DSW> direct_state_query_list; @@ -81,7 +78,6 @@ class Body2DSW : public CollisionObject2DSW { bool can_sleep; bool first_time_kinematic; bool first_integration; - bool using_one_way_cache; void _update_inertia(); virtual void _shapes_changed(); Transform2D new_transform; @@ -246,17 +242,6 @@ public: _FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; } _FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; } - void set_one_way_collision_direction(const Vector2 &p_dir) { - one_way_collision_direction = p_dir; - using_one_way_cache = one_way_collision_direction != Vector2(); - } - Vector2 get_one_way_collision_direction() const { return one_way_collision_direction; } - - void set_one_way_collision_max_depth(real_t p_depth) { one_way_collision_max_depth = p_depth; } - real_t get_one_way_collision_max_depth() const { return one_way_collision_max_depth; } - - _FORCE_INLINE_ bool is_using_one_way_collision() const { return using_one_way_cache; } - void set_space(Space2DSW *p_space); void update_inertias(); diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index 47e9afbde6..484d4503d0 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -225,6 +225,11 @@ bool BodyPair2DSW::setup(real_t p_step) { return false; } + if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) { + collided = false; + return false; + } + //use local A coordinates to avoid numerical issues on collision detection offset_B = B->get_transform().get_origin() - A->get_transform().get_origin(); @@ -280,8 +285,8 @@ bool BodyPair2DSW::setup(real_t p_step) { //if (!prev_collided) { { - if (A->is_using_one_way_collision()) { - Vector2 direction = A->get_one_way_collision_direction(); + if (A->is_shape_set_as_one_way_collision(shape_A)) { + Vector2 direction = xform_A.get_axis(1).normalized(); bool valid = false; if (B->get_linear_velocity().dot(direction) >= 0) { for (int i = 0; i < contact_count; i++) { @@ -303,8 +308,8 @@ bool BodyPair2DSW::setup(real_t p_step) { } } - if (B->is_using_one_way_collision()) { - Vector2 direction = B->get_one_way_collision_direction(); + if (B->is_shape_set_as_one_way_collision(shape_B)) { + Vector2 direction = xform_B.get_axis(1).normalized(); bool valid = false; if (A->get_linear_velocity().dot(direction) >= 0) { for (int i = 0; i < contact_count; i++) { @@ -390,7 +395,7 @@ bool BodyPair2DSW::setup(real_t p_step) { } } - if (A->is_shape_set_as_trigger(shape_A) || B->is_shape_set_as_trigger(shape_B) || (A->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC)) { + if ((A->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC && B->get_mode() <= Physics2DServer::BODY_MODE_KINEMATIC)) { c.active = false; collided = false; continue; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 0163a18850..8f13f1130a 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -37,7 +37,8 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra s.xform = p_transform; s.xform_inv = s.xform.affine_inverse(); s.bpid = 0; //needs update - s.trigger = false; + s.disabled = false; + s.one_way_collision = false; shapes.push_back(s); p_shape->add_owner(this); _update_shapes(); diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index f2059e8618..5e29132e8d 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -58,8 +58,12 @@ private: Rect2 aabb_cache; //for rayqueries Shape2DSW *shape; Variant metadata; - bool trigger; - Shape() { trigger = false; } + bool disabled; + bool one_way_collision; + Shape() { + disabled = false; + one_way_collision = false; + } }; Vector<Shape> shapes; @@ -116,8 +120,11 @@ public: _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; } _FORCE_INLINE_ Space2DSW *get_space() const { return space; } - _FORCE_INLINE_ void set_shape_as_trigger(int p_idx, bool p_enable) { shapes[p_idx].trigger = p_enable; } - _FORCE_INLINE_ bool is_shape_set_as_trigger(int p_idx) const { return shapes[p_idx].trigger; } + _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_disabled) { shapes[p_idx].disabled = p_disabled; } + _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { return shapes[p_idx].disabled; } + + _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision) { shapes[p_idx].one_way_collision = p_one_way_collision; } + _FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const { return shapes[p_idx].one_way_collision; } void set_collision_mask(uint32_t p_mask) { collision_mask = p_mask; } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index 9a31fa49b0..1d88710f1a 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -352,6 +352,15 @@ void Physics2DServerSW::area_set_shape_transform(RID p_area, int p_shape_idx, co area->set_shape_transform(p_shape_idx, p_transform); } +void Physics2DServerSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { + + Area2DSW *area = area_owner.get(p_area); + ERR_FAIL_COND(!area); + + ERR_FAIL_INDEX(p_shape, area->get_shape_count()); + area->set_shape_as_disabled(p_shape, p_disabled); +} + int Physics2DServerSW::area_get_shape_count(RID p_area) const { Area2DSW *area = area_owner.get(p_area); @@ -640,24 +649,23 @@ void Physics2DServerSW::body_clear_shapes(RID p_body) { body->remove_shape(0); } -void Physics2DServerSW::body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable) { +void Physics2DServerSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); - body->set_shape_as_trigger(p_shape_idx, p_enable); + body->set_shape_as_disabled(p_shape_idx, p_disabled); } +void Physics2DServerSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable) { -bool Physics2DServerSW::body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const { - - const Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, false); + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); - ERR_FAIL_INDEX_V(p_shape_idx, body->get_shape_count(), false); + ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); - return body->is_shape_set_as_trigger(p_shape_idx); + body->set_shape_as_one_way_collision(p_shape_idx, p_enable); } void Physics2DServerSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) { @@ -887,34 +895,6 @@ int Physics2DServerSW::body_get_max_contacts_reported(RID p_body) const { return body->get_max_contacts_reported(); } -void Physics2DServerSW::body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction) { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND(!body); - body->set_one_way_collision_direction(p_direction); -} - -Vector2 Physics2DServerSW::body_get_one_way_collision_direction(RID p_body) const { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, Vector2()); - return body->get_one_way_collision_direction(); -} - -void Physics2DServerSW::body_set_one_way_collision_max_depth(RID p_body, real_t p_max_depth) { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND(!body); - body->set_one_way_collision_max_depth(p_max_depth); -} - -real_t Physics2DServerSW::body_get_one_way_collision_max_depth(RID p_body) const { - - Body2DSW *body = body_owner.get(p_body); - ERR_FAIL_COND_V(!body, 0); - return body->get_one_way_collision_max_depth(); -} - void Physics2DServerSW::body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata) { Body2DSW *body = body_owner.get(p_body); diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index be67e3157d..9cbdfc598f 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -123,6 +123,8 @@ public: virtual RID area_get_shape(RID p_area, int p_shape_idx) const; virtual Transform2D area_get_shape_transform(RID p_area, int p_shape_idx) const; + virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled); + virtual void area_remove_shape(RID p_area, int p_shape_idx); virtual void area_clear_shapes(RID p_area); @@ -167,8 +169,8 @@ public: virtual void body_remove_shape(RID p_body, int p_shape_idx); virtual void body_clear_shapes(RID p_body); - virtual void body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable); - virtual bool body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const; + virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled); + virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled); virtual void body_attach_object_instance_ID(RID p_body, uint32_t p_ID); virtual uint32_t body_get_object_instance_ID(RID p_body) const; @@ -212,12 +214,6 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts); virtual int body_get_max_contacts_reported(RID p_body) const; - virtual void body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction); - virtual Vector2 body_get_one_way_collision_direction(RID p_body) const; - - virtual void body_set_one_way_collision_max_depth(RID p_body, real_t p_max_depth); - virtual real_t body_get_one_way_collision_max_depth(RID p_body) const; - virtual void body_set_force_integration_callback(RID p_body, Object *p_receiver, const StringName &p_method, const Variant &p_udata = Variant()); virtual bool body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 1026d84fd9..9fcfebef6b 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -145,6 +145,7 @@ public: FUNC3(area_add_shape, RID, RID, const Transform2D &); FUNC3(area_set_shape, RID, int, RID); FUNC3(area_set_shape_transform, RID, int, const Transform2D &); + FUNC3(area_set_shape_disabled, RID, int, bool); FUNC1RC(int, area_get_shape_count, RID); FUNC2RC(RID, area_get_shape, RID, int); @@ -191,8 +192,8 @@ public: FUNC2RC(Variant, body_get_shape_metadata, RID, int); FUNC2RC(RID, body_get_shape, RID, int); - FUNC3(body_set_shape_as_trigger, RID, int, bool); - FUNC2RC(bool, body_is_shape_set_as_trigger, RID, int); + FUNC3(body_set_shape_disabled, RID, int, bool); + FUNC3(body_set_shape_as_one_way_collision, RID, int, bool); FUNC2(body_remove_shape, RID, int); FUNC1(body_clear_shapes, RID); @@ -232,12 +233,6 @@ public: FUNC2(body_set_max_contacts_reported, RID, int); FUNC1RC(int, body_get_max_contacts_reported, RID); - FUNC2(body_set_one_way_collision_direction, RID, const Vector2 &); - FUNC1RC(Vector2, body_get_one_way_collision_direction, RID); - - FUNC2(body_set_one_way_collision_max_depth, RID, real_t); - FUNC1RC(real_t, body_get_one_way_collision_max_depth, RID); - FUNC2(body_set_contacts_reported_depth_treshold, RID, real_t); FUNC1RC(real_t, body_get_contacts_reported_depth_treshold, RID); diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index fd94fc01cd..0b31ff144b 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -265,14 +265,6 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor //test initial overlap if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, p_margin)) { - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - //if one way collision direction ignore initial overlap - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - if (body->get_one_way_collision_direction() != Vector2()) { - continue; - } - } - return false; } @@ -297,27 +289,6 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID &p_shape, const Transfor } } - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - if (body->get_one_way_collision_direction() != Vector2()) { - - Vector2 cd[2]; - Physics2DServerSW::CollCbkData cbk; - cbk.max = 1; - cbk.amount = 0; - cbk.ptr = cd; - cbk.valid_dir = body->get_one_way_collision_direction(); - cbk.valid_depth = body->get_one_way_collision_max_depth(); - - Vector2 sep = mnormal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * (hi + space->contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, p_margin); - if (!collided || cbk.amount == 0) { - continue; - } - } - } - if (low < best_safe) { best_safe = low; best_unsafe = hi; @@ -369,15 +340,9 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D & if (p_exclude.has(col_obj->get_self())) continue; - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - cbk.valid_dir = body->get_one_way_collision_direction(); - cbk.valid_depth = body->get_one_way_collision_max_depth(); - } else { - cbk.valid_dir = Vector2(); - cbk.valid_depth = 0; - } + cbk.valid_dir = Vector2(); + cbk.valid_depth = 0; if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) { collided = p_result_max == 0 || cbk.amount > 0; @@ -407,13 +372,10 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, _RestCallbackData2D *rd = (_RestCallbackData2D *)p_userdata; if (rd->valid_dir != Vector2()) { - - if (rd->valid_dir != Vector2()) { - if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth) - return; - if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25) - return; - } + if (p_point_A.distance_squared_to(p_point_B) > rd->valid_depth * rd->valid_depth) + return; + if (rd->valid_dir.dot((p_point_A - p_point_B).normalized()) < Math_PI * 0.25) + return; } Vector2 contact_rel = p_point_B - p_point_A; @@ -455,16 +417,8 @@ bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Transform2D &p_sh if (p_exclude.has(col_obj->get_self())) continue; - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - rcd.valid_dir = body->get_one_way_collision_direction(); - rcd.valid_depth = body->get_one_way_collision_max_depth(); - } else { - rcd.valid_dir = Vector2(); - rcd.valid_depth = 0; - } - + rcd.valid_dir = Vector2(); + rcd.valid_depth = 0; rcd.object = col_obj; rcd.shape = shape_idx; bool sc = CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, NULL, p_margin); @@ -517,7 +471,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { keep = false; else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) keep = false; - else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_trigger(intersection_query_subindex_results[i])) + else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i])) keep = false; if (!keep) { @@ -589,7 +543,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int amount = _cull_aabb_for_body(p_body, body_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_trigger(j)) + if (p_body->is_shape_set_as_disabled(j)) continue; Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j); @@ -599,18 +553,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - - Vector2 cdir = body->get_one_way_collision_direction(); - /* - if (cdir!=Vector2() && p_motion.dot(cdir)<0) - continue; - */ + if (col_obj->is_shape_set_as_one_way_collision(j)) { - cbk.valid_dir = cdir; - cbk.valid_depth = body->get_one_way_collision_max_depth(); + cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); + cbk.valid_depth = p_margin; //only valid depth is the collision margin } else { cbk.valid_dir = Vector2(); cbk.valid_depth = 0; @@ -678,7 +624,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_trigger(j)) + if (p_body->is_shape_set_as_disabled(j)) continue; Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j); @@ -703,12 +649,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co //test initial overlap if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) { - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - //if one way collision direction ignore initial overlap - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - if (body->get_one_way_collision_direction() != Vector2()) { - continue; - } + if (col_obj->is_shape_set_as_one_way_collision(j)) { + continue; } stuck = true; @@ -720,7 +662,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co real_t hi = 1; Vector2 mnormal = p_motion.normalized(); - for (int i = 0; i < 8; i++) { //steps should be customizable.. + for (int k = 0; k < 8; k++) { //steps should be customizable.. real_t ofs = (low + hi) * 0.5; @@ -739,15 +681,16 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - if (body->get_one_way_collision_direction() != Vector2()) { + if (col_obj->is_shape_set_as_one_way_collision(j)) { Vector2 cd[2]; Physics2DServerSW::CollCbkData cbk; cbk.max = 1; cbk.amount = 0; cbk.ptr = cd; - cbk.valid_dir = body->get_one_way_collision_direction(); - cbk.valid_depth = body->get_one_way_collision_max_depth(); + cbk.valid_dir = body_shape_xform.get_axis(1).normalized(); + ; + cbk.valid_depth = 10e20; Vector2 sep = mnormal; //important optimization for this to work fast enough bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0); @@ -816,11 +759,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co const CollisionObject2DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { + if (col_obj->is_shape_set_as_one_way_collision(shape_idx)) { - const Body2DSW *body = static_cast<const Body2DSW *>(col_obj); - rcd.valid_dir = body->get_one_way_collision_direction(); - rcd.valid_depth = body->get_one_way_collision_max_depth(); + rcd.valid_dir = body_shape_xform.get_axis(1).normalized(); + rcd.valid_depth = 10e20; } else { rcd.valid_dir = Vector2(); rcd.valid_depth = 0; @@ -839,6 +781,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co r_result->collider = rcd.best_object->get_self(); r_result->collider_id = rcd.best_object->get_instance_id(); r_result->collider_shape = rcd.best_shape; + r_result->collision_local_shape = best_shape; r_result->collision_normal = rcd.best_normal; r_result->collision_point = rcd.best_contact; r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index 8ffa82214c..55ea2b41e7 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -496,6 +496,7 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D())); ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &Physics2DServer::area_set_shape); ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &Physics2DServer::area_set_shape_transform); + ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disable"), &Physics2DServer::area_set_shape_disabled); ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &Physics2DServer::area_get_shape_count); ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &Physics2DServer::area_get_shape); @@ -539,8 +540,8 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &Physics2DServer::body_remove_shape); ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &Physics2DServer::body_clear_shapes); - ClassDB::bind_method(D_METHOD("body_set_shape_as_trigger", "body", "shape_idx", "enable"), &Physics2DServer::body_set_shape_as_trigger); - ClassDB::bind_method(D_METHOD("body_is_shape_set_as_trigger", "body", "shape_idx"), &Physics2DServer::body_is_shape_set_as_trigger); + ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disable"), &Physics2DServer::body_set_shape_disabled); + ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable"), &Physics2DServer::body_set_shape_as_one_way_collision); ClassDB::bind_method(D_METHOD("body_attach_object_instance_ID", "body", "id"), &Physics2DServer::body_attach_object_instance_ID); ClassDB::bind_method(D_METHOD("body_get_object_instance_ID", "body"), &Physics2DServer::body_get_object_instance_ID); @@ -571,12 +572,6 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_max_contacts_reported", "body", "amount"), &Physics2DServer::body_set_max_contacts_reported); ClassDB::bind_method(D_METHOD("body_get_max_contacts_reported", "body"), &Physics2DServer::body_get_max_contacts_reported); - ClassDB::bind_method(D_METHOD("body_set_one_way_collision_direction", "body", "normal"), &Physics2DServer::body_set_one_way_collision_direction); - ClassDB::bind_method(D_METHOD("body_get_one_way_collision_direction", "body"), &Physics2DServer::body_get_one_way_collision_direction); - - ClassDB::bind_method(D_METHOD("body_set_one_way_collision_max_depth", "body", "depth"), &Physics2DServer::body_set_one_way_collision_max_depth); - ClassDB::bind_method(D_METHOD("body_get_one_way_collision_max_depth", "body"), &Physics2DServer::body_get_one_way_collision_max_depth); - ClassDB::bind_method(D_METHOD("body_set_omit_force_integration", "body", "enable"), &Physics2DServer::body_set_omit_force_integration); ClassDB::bind_method(D_METHOD("body_is_omitting_force_integration", "body"), &Physics2DServer::body_is_omitting_force_integration); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 80113dd7d6..f50faa42eb 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -332,6 +332,8 @@ public: virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0; virtual void area_clear_shapes(RID p_area) = 0; + virtual void area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) = 0; + virtual void area_attach_object_instance_ID(RID p_area, ObjectID p_ID) = 0; virtual ObjectID area_get_object_instance_ID(RID p_area) const = 0; @@ -380,8 +382,8 @@ public: virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0; virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0; - virtual void body_set_shape_as_trigger(RID p_body, int p_shape_idx, bool p_enable) = 0; - virtual bool body_is_shape_set_as_trigger(RID p_body, int p_shape_idx) const = 0; + virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0; + virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled) = 0; virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0; virtual void body_clear_shapes(RID p_body) = 0; @@ -451,12 +453,6 @@ public: virtual void body_set_max_contacts_reported(RID p_body, int p_contacts) = 0; virtual int body_get_max_contacts_reported(RID p_body) const = 0; - virtual void body_set_one_way_collision_direction(RID p_body, const Vector2 &p_direction) = 0; - virtual Vector2 body_get_one_way_collision_direction(RID p_body) const = 0; - - virtual void body_set_one_way_collision_max_depth(RID p_body, float p_max_depth) = 0; - virtual float body_get_one_way_collision_max_depth(RID p_body) const = 0; - //missing remove virtual void body_set_contacts_reported_depth_treshold(RID p_body, float p_treshold) = 0; virtual float body_get_contacts_reported_depth_treshold(RID p_body) const = 0; @@ -478,6 +474,7 @@ public: Vector2 collision_point; Vector2 collision_normal; Vector2 collider_velocity; + int collision_local_shape; ObjectID collider_id; RID collider; int collider_shape; diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 43452b714c..2ce83e6c64 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -75,6 +75,10 @@ public: virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) = 0; virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) = 0; + virtual bool is_environment(RID p_env) = 0; + virtual VS::EnvironmentBG environment_get_background(RID p_env) = 0; + virtual int environment_get_canvas_max_layer(RID p_env) = 0; + struct InstanceBase : RID_Data { VS::InstanceType base_type; diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 81139ecc1c..42f1a98826 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -212,6 +212,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["NUMBER"] = ShaderLanguage::TYPE_UINT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["INDEX"] = ShaderLanguage::TYPE_INT; shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["EMISSION_TRANSFORM"] = ShaderLanguage::TYPE_MAT4; + shader_modes[VS::SHADER_PARTICLES].functions["vertex"]["RANDOM_SEED"] = ShaderLanguage::TYPE_UINT; shader_modes[VS::SHADER_PARTICLES].modes.insert("billboard"); shader_modes[VS::SHADER_PARTICLES].modes.insert("disable_force"); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 616990b311..1227863b72 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -58,6 +58,12 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor if (!ci->visible) return; + if (p_canvas_item->children_order_dirty) { + + p_canvas_item->child_items.sort_custom<ItemIndexSort>(); + p_canvas_item->children_order_dirty = false; + } + Rect2 rect = ci->get_rect(); Transform2D xform = p_transform * ci->xform; Rect2 global_rect = xform.xform(rect); @@ -171,6 +177,12 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr VSG::canvas_render->canvas_begin(); + if (p_canvas->children_order_dirty) { + + p_canvas->child_items.sort(); + p_canvas->children_order_dirty = false; + } + int l = p_canvas->child_items.size(); Canvas::ChildItem *ci = p_canvas->child_items.ptr(); diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h index f78ef635f4..57c7515367 100644 --- a/servers/visual/visual_server_canvas.h +++ b/servers/visual/visual_server_canvas.h @@ -63,6 +63,14 @@ public: } }; + struct ItemIndexSort { + + _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { + + return p_left->index < p_right->index; + } + }; + struct ItemPtrSort { _FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const { diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 6d1f698a5c..fb1c66d0b9 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -2162,6 +2162,18 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform, const Cam VSG::scene_render->render_scene(p_cam_transform, p_cam_projection, p_cam_orthogonal, (RasterizerScene::InstanceBase **)instance_cull_result, cull_count, light_instance_cull_result, light_cull_count + directional_light_count, reflection_probe_instance_cull_result, reflection_probe_cull_count, environment, p_shadow_atlas, scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass); } +void VisualServerScene::render_empty_scene(RID p_scenario, RID p_shadow_atlas) { + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + RID environment; + if (scenario->environment.is_valid()) + environment = scenario->environment; + else + environment = scenario->fallback_environment; + VSG::scene_render->render_scene(Transform(), CameraMatrix(), true, NULL, 0, NULL, 0, NULL, 0, environment, p_shadow_atlas, scenario->reflection_atlas, RID(), 0); +} + bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int p_step) { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 92c6421987..d13c24ae24 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -519,6 +519,7 @@ public: _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + void render_empty_scene(RID p_scenario, RID p_shadow_atlas); void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 2fbbcd225f..2c2bd2b167 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -35,23 +35,24 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { -/* Camera should always be BEFORE any other 3D */ -#if 0 - bool scenario_draw_canvas_bg=false; - int scenario_canvas_max_layer=0; + /* Camera should always be BEFORE any other 3D */ - if (!p_viewport->hide_canvas && !p_viewport->disable_environment && scenario_owner.owns(p_viewport->scenario)) { + bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front + int scenario_canvas_max_layer = 0; - Scenario *scenario=scenario_owner.get(p_viewport->scenario); - if (scenario->environment.is_valid()) { - if (rasterizer->is_environment(scenario->environment)) { - scenario_draw_canvas_bg=rasterizer->environment_get_background(scenario->environment)==VS::ENV_BG_CANVAS; - scenario_canvas_max_layer=rasterizer->environment_get_background_param(scenario->environment,VS::ENV_BG_PARAM_CANVAS_MAX_LAYER); - } + if (!p_viewport->hide_canvas && !p_viewport->disable_environment && VSG::scene->scenario_owner.owns(p_viewport->scenario)) { + + VisualServerScene::Scenario *scenario = VSG::scene->scenario_owner.get(p_viewport->scenario); + if (VSG::scene_render->is_environment(scenario->environment)) { + scenario_draw_canvas_bg = VSG::scene_render->environment_get_background(scenario->environment) == VS::ENV_BG_CANVAS; + + scenario_canvas_max_layer = VSG::scene_render->environment_get_canvas_max_layer(scenario->environment); } } - bool can_draw_3d=!p_viewport->hide_scenario && camera_owner.owns(p_viewport->camera) && scenario_owner.owns(p_viewport->scenario); + bool can_draw_3d = !p_viewport->disable_3d && !p_viewport->disable_3d_by_usage && VSG::scene->camera_owner.owns(p_viewport->camera); +#if 0 + if (scenario_draw_canvas_bg) { @@ -88,7 +89,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { } } - if (!p_viewport->disable_3d && !p_viewport->disable_3d_by_usage && p_viewport->camera.is_valid()) { + if (!scenario_draw_canvas_bg && can_draw_3d) { VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } @@ -199,14 +200,15 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { VSG::rasterizer->restore_render_target(); -#if 0 - if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().layer>scenario_canvas_max_layer) { - - _draw_viewport_camera(p_viewport,!can_draw_3d); - scenario_draw_canvas_bg=false; + if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().layer > scenario_canvas_max_layer) { + if (can_draw_3d) { + VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + } else { + VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + } + scenario_draw_canvas_bg = false; } -#endif for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) { @@ -229,19 +231,29 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport) { VSG::canvas->render_canvas(canvas, xform, canvas_lights, lights_with_mask, clip_rect); i++; -#if 0 - if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) { - _draw_viewport_camera(p_viewport,!can_draw_3d); - scenario_draw_canvas_bg=false; + + if (scenario_draw_canvas_bg && E->key().layer >= scenario_canvas_max_layer) { + + if (can_draw_3d) { + VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + } else { + VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + } + + scenario_draw_canvas_bg = false; } -#endif } -#if 0 + if (scenario_draw_canvas_bg) { - _draw_viewport_camera(p_viewport,!can_draw_3d); - scenario_draw_canvas_bg=false; + + if (can_draw_3d) { + VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + } else { + VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas); + } + + scenario_draw_canvas_bg = false; } -#endif //VSG::canvas_render->canvas_debug_viewport_shadows(lights_with_shadow); } |