From 3ce046ee0c49b23bb1e5d59a5a0fe8c70bc64c7d Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Mon, 26 Jun 2017 22:58:03 -0300 Subject: -Fixed SCREEN_TEXTURE and other related 2D shader parameters. -Fixded BackBuffercopy object --- drivers/gles3/rasterizer_canvas_gles3.cpp | 139 +- drivers/gles3/rasterizer_canvas_gles3.h | 5 + drivers/gles3/rasterizer_gles3.cpp | 1 + drivers/gles3/rasterizer_storage_gles3.cpp | 6 + drivers/gles3/rasterizer_storage_gles3.h | 2 + drivers/gles3/shader_compiler_gles3.cpp | 4 +- drivers/gles3/shader_gles3.cpp | 33 +- drivers/gles3/shaders/canvas.glsl | 15 +- drivers/gles3/shaders/copy.glsl | 13 + drivers/gles3/shaders/effect_blur.glsl | 12 +- drivers/gles3/shaders/particles.glsl | 7 +- drivers/gles3/shaders/scene.glsl | 7 +- editor/editor_settings.cpp | 2 +- main/main.cpp | 2 +- main/performance.cpp | 2 +- main/tests/test_gui.cpp | 2 +- modules/gdnative/gdnative.cpp | 2 +- modules/visual_script/visual_script_func_nodes.cpp | 2 +- modules/visual_script/visual_script_nodes.cpp | 2 +- .../visual_script/visual_script_yield_nodes.cpp | 2 +- scene/2d/canvas_item.h | 2 +- scene/3d/spatial.h | 2 +- scene/main/node.h | 2 +- scene/main/scene_main_loop.cpp | 2427 -------------------- scene/main/scene_main_loop.h | 466 ---- scene/main/scene_tree.cpp | 2427 ++++++++++++++++++++ scene/main/scene_tree.h | 466 ++++ scene/register_scene_types.cpp | 2 +- scene/resources/shape.cpp | 2 +- servers/visual/shader_types.cpp | 6 +- 30 files changed, 3092 insertions(+), 2970 deletions(-) delete mode 100644 scene/main/scene_main_loop.cpp delete mode 100644 scene/main/scene_main_loop.h create mode 100644 scene/main/scene_tree.cpp create mode 100644 scene/main/scene_tree.h diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c71bf22965..8c3569bec0 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -28,10 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer_canvas_gles3.h" -#include "servers/visual/visual_server_raster.h" - #include "global_config.h" #include "os/os.h" +#include "rasterizer_scene_gles3.h" +#include "servers/visual/visual_server_raster.h" #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif @@ -172,6 +172,11 @@ void RasterizerCanvasGLES3::canvas_begin() { state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, Color(1, 1, 1, 1)); state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, Transform2D()); state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, Transform2D()); + if (storage->frame.current_rt) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); + } //state.canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX,state.vp); //state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX,Transform()); @@ -282,7 +287,11 @@ void RasterizerCanvasGLES3::_set_texture_rect_mode(bool p_enable, bool p_ninepat state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); - + if (storage->frame.current_rt) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); + } state.using_texture_rect = p_enable; state.using_ninepatch = p_ninepatch; } @@ -822,6 +831,78 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(ShaderMaterial *material, #endif +void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { + + state.canvas_texscreen_used = true; + //blur diffuse into effect mipmaps using separatable convolution + //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); + + Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); + + Color blur_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); + + if (p_rect != Rect2()) { + + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_BLUR_SECTION, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, true); + } + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES3::COPY_SECTION, blur_section); + + scene_render->_copy_screen(); + + for (int i = 0; i < storage->frame.current_rt->effects.mip_maps[1].sizes.size(); i++) { + + int vp_w = storage->frame.current_rt->effects.mip_maps[1].sizes[i].width; + int vp_h = storage->frame.current_rt->effects.mip_maps[1].sizes[i].height; + glViewport(0, 0, vp_w, vp_h); + //horizontal pass + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, true); + scene_render->state.effect_blur_shader.bind(); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::BLUR_SECTION, blur_section); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); //previous level, since mipmaps[0] starts one level bigger + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[1].sizes[i].fbo); + + scene_render->_copy_screen(); + + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_HORIZONTAL, false); + + //vertical pass + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, true); + scene_render->state.effect_blur_shader.bind(); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); + scene_render->state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::BLUR_SECTION, blur_section); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[1].color); + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger + + scene_render->_copy_screen(); + + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::GAUSSIAN_VERTICAL, false); + } + + scene_render->state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_BLUR_SECTION, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, false); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //back to front + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + state.canvas_shader.bind(); //back to canvas + + if (state.using_texture_rect) { + state.using_texture_rect = false; + _set_texture_rect_mode(state.using_texture_rect, state.using_ninepatch); + } +} + void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light) { Item *current_clip = NULL; @@ -875,44 +956,17 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons glDisable(GL_SCISSOR_TEST); } } -#if 0 - if (ci->copy_back_buffer && framebuffer.active && framebuffer.scale==1) { - Rect2 rect; - int x,y; + if (ci->copy_back_buffer) { if (ci->copy_back_buffer->full) { - x = viewport.x; - y = window_size.height-(viewport.height+viewport.y); - } else { - x = viewport.x+ci->copy_back_buffer->screen_rect.pos.x; - y = window_size.height-(viewport.y+ci->copy_back_buffer->screen_rect.pos.y+ci->copy_back_buffer->screen_rect.size.y); - } - glActiveTexture(GL_TEXTURE0+max_texture_units-1); - glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color); - -#ifdef GLEW_ENABLED - if (current_rt) { - glReadBuffer(GL_COLOR_ATTACHMENT0); - } else { - glReadBuffer(GL_BACK); - } -#endif - if (current_rt) { - glCopyTexSubImage2D(GL_TEXTURE_2D,0,viewport.x,viewport.y,viewport.x,viewport.y,viewport.width,viewport.height); - //window_size.height-(viewport.height+viewport.y) + _copy_texscreen(Rect2()); } else { - glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height); + _copy_texscreen(ci->copy_back_buffer->rect); } - - canvas_texscreen_used=true; - glActiveTexture(GL_TEXTURE0); - } -#endif - //begin rect Item *material_owner = ci->material_owner ? ci->material_owner : ci; @@ -934,6 +988,11 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (shader_ptr && shader_ptr != shader_cache) { + if (shader_ptr->canvas_item.uses_screen_texture && !state.canvas_texscreen_used) { + //copy if not copied before + _copy_texscreen(Rect2()); + } + state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); state.canvas_shader.bind(); @@ -1046,7 +1105,11 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix); - + if (storage->frame.current_rt) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); + } if (unshaded || (state.canvas_item_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked)) _canvas_item_render_commands(ci, current_clip, reclip); @@ -1376,6 +1439,12 @@ void RasterizerCanvasGLES3::reset_canvas() { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + //use for reading from screen + if (storage->frame.current_rt) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); + } + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); @@ -1543,7 +1612,7 @@ void RasterizerCanvasGLES3::initialize() { glBindBuffer(GL_UNIFORM_BUFFER, 0); state.canvas_shader.init(); - state.canvas_shader.set_base_material_tex_index(1); + state.canvas_shader.set_base_material_tex_index(2); state.canvas_shadow_shader.init(); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index 5859820364..ee018e15ea 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -34,6 +34,8 @@ #include "servers/visual/rasterizer.h" #include "shaders/canvas_shadow.glsl.gen.h" +class RasterizerSceneGLES3; + class RasterizerCanvasGLES3 : public RasterizerCanvas { public: struct CanvasItemUBO { @@ -42,6 +44,8 @@ public: float time; }; + RasterizerSceneGLES3 *scene_render; + struct Data { GLuint canvas_quad_vertices; @@ -118,6 +122,7 @@ public: _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip); + _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light); virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 53df7e9c3d..0cfa8a7d6e 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -412,6 +412,7 @@ RasterizerGLES3::RasterizerGLES3() { canvas = memnew(RasterizerCanvasGLES3); scene = memnew(RasterizerSceneGLES3); canvas->storage = storage; + canvas->scene_render = scene; storage->canvas = canvas; scene->storage = storage; storage->scene = scene; diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 24a57b772b..b1dc32e1c0 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1445,6 +1445,8 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; + p_shader->canvas_item.uses_screen_texture = false; + p_shader->canvas_item.uses_screen_uv = false; shaders.actions_canvas.render_mode_values["blend_add"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); shaders.actions_canvas.render_mode_values["blend_mix"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); @@ -1455,6 +1457,10 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_canvas.render_mode_values["unshaded"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); shaders.actions_canvas.render_mode_values["light_only"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); + shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; + shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; + shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; + actions = &shaders.actions_canvas; actions->uniforms = &p_shader->uniforms; diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 2ef47fe2cb..3f8055d613 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -401,6 +401,8 @@ public: }; int light_mode; + bool uses_screen_texture; + bool uses_screen_uv; } canvas_item; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 41421a3e2f..6c568714f8 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -680,7 +680,8 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[VS::SHADER_CANVAS_ITEM].renames["POSITION"] = "(gl_FragCoord.xy)"; + actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; + actions[VS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord"; actions[VS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec"; @@ -694,6 +695,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_COLOR"] = "#define SHADOW_COLOR_USED\n"; diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index e08ef0ad12..c821acadf5 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -289,16 +289,17 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { #endif strings.push_back(vertex_code0.get_data()); + if (cc) { - code_globals = cc->vertex_globals.ascii(); - strings.push_back(code_globals.get_data()); + material_string = cc->uniforms.ascii(); + strings.push_back(material_string.get_data()); } strings.push_back(vertex_code1.get_data()); if (cc) { - material_string = cc->uniforms.ascii(); - strings.push_back(material_string.get_data()); + code_globals = cc->vertex_globals.ascii(); + strings.push_back(code_globals.get_data()); } strings.push_back(vertex_code2.get_data()); @@ -387,15 +388,15 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { strings.push_back(fragment_code0.get_data()); if (cc) { - code_globals = cc->fragment_globals.ascii(); - strings.push_back(code_globals.get_data()); + material_string = cc->uniforms.ascii(); + strings.push_back(material_string.get_data()); } strings.push_back(fragment_code1.get_data()); if (cc) { - material_string = cc->uniforms.ascii(); - strings.push_back(material_string.get_data()); + code_globals = cc->fragment_globals.ascii(); + strings.push_back(code_globals.get_data()); } strings.push_back(fragment_code2.get_data()); @@ -617,21 +618,21 @@ void ShaderGLES3::setup(const char **p_conditional_defines, int p_conditional_co String material_tag = "\nMATERIAL_UNIFORMS"; String code_tag = "\nVERTEX_SHADER_CODE"; String code = vertex_code; - int cpos = code.find(globals_tag); + int cpos = code.find(material_tag); if (cpos == -1) { vertex_code0 = code.ascii(); } else { vertex_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + globals_tag.length(), code.length()); + code = code.substr(cpos + material_tag.length(), code.length()); - cpos = code.find(material_tag); + cpos = code.find(globals_tag); if (cpos == -1) { vertex_code1 = code.ascii(); } else { vertex_code1 = code.substr(0, cpos).ascii(); - String code2 = code.substr(cpos + material_tag.length(), code.length()); + String code2 = code.substr(cpos + globals_tag.length(), code.length()); cpos = code2.find(code_tag); if (cpos == -1) { @@ -651,14 +652,14 @@ void ShaderGLES3::setup(const char **p_conditional_defines, int p_conditional_co String code_tag = "\nFRAGMENT_SHADER_CODE"; String light_code_tag = "\nLIGHT_SHADER_CODE"; String code = fragment_code; - int cpos = code.find(globals_tag); + int cpos = code.find(material_tag); if (cpos == -1) { fragment_code0 = code.ascii(); } else { fragment_code0 = code.substr(0, cpos).ascii(); //print_line("CODE0:\n"+String(fragment_code0.get_data())); - code = code.substr(cpos + globals_tag.length(), code.length()); - cpos = code.find(material_tag); + code = code.substr(cpos + material_tag.length(), code.length()); + cpos = code.find(globals_tag); if (cpos == -1) { fragment_code1 = code.ascii(); @@ -667,7 +668,7 @@ void ShaderGLES3::setup(const char **p_conditional_defines, int p_conditional_co fragment_code1 = code.substr(0, cpos).ascii(); //print_line("CODE1:\n"+String(fragment_code1.get_data())); - String code2 = code.substr(cpos + material_tag.length(), code.length()); + String code2 = code.substr(cpos + globals_tag.length(), code.length()); cpos = code2.find(light_code_tag); if (cpos == -1) { diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index e97ce62daa..31bae66278 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -90,7 +90,6 @@ uniform int h_frames; uniform int v_frames; #endif -VERTEX_SHADER_GLOBALS #if defined(USE_MATERIAL) @@ -102,6 +101,8 @@ MATERIAL_UNIFORMS #endif +VERTEX_SHADER_GLOBALS + void main() { vec4 vertex_color = color_attrib; @@ -211,6 +212,11 @@ uniform sampler2D screen_texture; // texunit:-3 #endif +#if defined(SCREEN_UV_USED) + +uniform vec2 screen_pixel_size; +#endif + layout(std140) uniform CanvasItemData { highp mat4 projection_matrix; @@ -256,7 +262,7 @@ const bool at_light_pass = false; uniform mediump vec4 final_modulate; -FRAGMENT_SHADER_GLOBALS + layout(location=0) out mediump vec4 frag_color; @@ -272,6 +278,7 @@ MATERIAL_UNIFORMS #endif +FRAGMENT_SHADER_GLOBALS void light_compute(inout vec3 light,vec3 light_vec,float light_height,vec4 light_color,vec2 light_uv,vec4 shadow,vec3 normal,vec2 uv,vec2 screen_uv,vec4 color) { @@ -410,8 +417,8 @@ void main() { -#if defined(ENABLE_SCREEN_UV) - vec2 screen_uv = gl_FragCoord.xy*screen_uv_mult; +#if defined(SCREEN_UV_USED) + vec2 screen_uv = gl_FragCoord.xy*screen_pixel_size; #endif diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index b0fb525e20..a7c388815d 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -17,6 +17,12 @@ out vec2 uv_interp; out vec2 uv2_interp; +#ifdef USE_COPY_SECTION + +uniform vec4 copy_section; + +#endif + void main() { #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) @@ -30,6 +36,13 @@ void main() { #endif uv2_interp = uv2_in; gl_Position = vertex_attrib; + +#ifdef USE_COPY_SECTION + + uv_interp = copy_section.xy + uv_interp * copy_section.zw; + gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; +#endif + } [fragment] diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 89afa12f60..8ca8e21f11 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -6,11 +6,21 @@ layout(location=4) in vec2 uv_in; out vec2 uv_interp; +#ifdef USE_BLUR_SECTION + +uniform vec4 blur_section; + +#endif void main() { - uv_interp = uv_in; + uv_interp = uv_in; gl_Position = vertex_attrib; +#ifdef USE_BLUR_SECTION + + uv_interp = blur_section.xy + uv_interp * blur_section.zw; + gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0; +#endif } [fragment] diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index ec2577538c..6a977a201e 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -47,7 +47,6 @@ out highp vec4 out_xform_1; //tfb: out highp vec4 out_xform_2; //tfb: out highp vec4 out_xform_3; //tfb: -VERTEX_SHADER_GLOBALS #if defined(USE_MATERIAL) @@ -59,6 +58,9 @@ MATERIAL_UNIFORMS #endif + +VERTEX_SHADER_GLOBALS + uint hash(uint x) { x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b); @@ -233,7 +235,6 @@ VERTEX_SHADER_CODE //any code here is never executed, stuff is filled just so it works -FRAGMENT_SHADER_GLOBALS #if defined(USE_MATERIAL) @@ -245,6 +246,8 @@ MATERIAL_UNIFORMS #endif +FRAGMENT_SHADER_GLOBALS + void main() { { diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index a047e693cb..40a295bc83 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -146,7 +146,7 @@ out vec3 binormal_interp; #endif -VERTEX_SHADER_GLOBALS + #if defined(USE_MATERIAL) @@ -159,6 +159,8 @@ MATERIAL_UNIFORMS #endif +VERTEX_SHADER_GLOBALS + #ifdef RENDER_DEPTH_DUAL_PARABOLOID out highp float dp_clip; @@ -418,8 +420,6 @@ layout(std140) uniform Radiance { //ubo:2 /* Material Uniforms */ -FRAGMENT_SHADER_GLOBALS - #if defined(USE_MATERIAL) @@ -431,6 +431,7 @@ MATERIAL_UNIFORMS #endif +FRAGMENT_SHADER_GLOBALS layout(std140) uniform SceneData { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index f018603bfc..5e950f003b 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -42,7 +42,7 @@ #include "os/keyboard.h" #include "os/os.h" #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/main/viewport.h" #include "translations.gen.h" #include "version.h" diff --git a/main/main.cpp b/main/main.cpp index cd464de1aa..2d6b151e14 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -43,7 +43,7 @@ #include "input_map.h" #include "io/resource_loader.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "servers/audio_server.h" #include "io/resource_loader.h" diff --git a/main/performance.cpp b/main/performance.cpp index 5788f64239..c819e15f71 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -30,7 +30,7 @@ #include "performance.h" #include "message_queue.h" #include "os/os.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "servers/physics_2d_server.h" #include "servers/physics_server.h" #include "servers/visual_server.h" diff --git a/main/tests/test_gui.cpp b/main/tests/test_gui.cpp index 291a557d04..3c6a708cd8 100644 --- a/main/tests/test_gui.cpp +++ b/main/tests/test_gui.cpp @@ -50,7 +50,7 @@ #include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/3d/camera.h" #include "scene/main/viewport.h" diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 706b81f7a3..dad9a54df6 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -35,7 +35,7 @@ #include "os/file_access.h" #include "os/os.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/resources/scene_format_text.h" #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED) diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index b466e64aec..e0e1a217b3 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -33,7 +33,7 @@ #include "io/resource_loader.h" #include "os/os.h" #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "visual_script_nodes.h" ////////////////////////////////////////// diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index 8ea3b8098d..86c98d076e 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -34,7 +34,7 @@ #include "os/input.h" #include "os/os.h" #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" ////////////////////////////////////////// ////////////////FUNCTION////////////////// diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 8f96eb6800..be5b218d0a 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -31,7 +31,7 @@ #include "os/os.h" #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "visual_script_nodes.h" ////////////////////////////////////////// diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index bffc171fc1..06130e3252 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -31,7 +31,7 @@ #define CANVAS_ITEM_H #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/resources/material.h" #include "scene/resources/shader.h" #include "scene/resources/texture.h" diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 764950aa8e..d114a6231b 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -31,7 +31,7 @@ #define SPATIAL_H #include "scene/main/node.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" /** @author Juan Linietsky diff --git a/scene/main/node.h b/scene/main/node.h index 4a41fb82ab..ffd2b7ce5f 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -35,7 +35,7 @@ #include "map.h" #include "object.h" #include "path_db.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "script_language.h" class Viewport; diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp deleted file mode 100644 index f7a255cd33..0000000000 --- a/scene/main/scene_main_loop.cpp +++ /dev/null @@ -1,2427 +0,0 @@ -/*************************************************************************/ -/* scene_main_loop.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 "scene_main_loop.h" - -#include "global_config.h" -#include "message_queue.h" -#include "node.h" -#include "os/keyboard.h" -#include "os/os.h" -#include "print_string.h" -#include -//#include "servers/spatial_sound_2d_server.h" - -#include "io/marshalls.h" -#include "io/resource_loader.h" -#include "scene/resources/material.h" -#include "scene/resources/mesh.h" -#include "scene/resources/packed_scene.h" -#include "scene/scene_string_names.h" -#include "servers/physics_2d_server.h" -#include "servers/physics_server.h" -#include "viewport.h" - -void SceneTreeTimer::_bind_methods() { - - ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left); - ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left); - - ADD_SIGNAL(MethodInfo("timeout")); -} - -void SceneTreeTimer::set_time_left(float p_time) { - time_left = p_time; -} - -float SceneTreeTimer::get_time_left() const { - return time_left; -} - -void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) { - if (process_pause != p_pause_mode_process) { - process_pause = p_pause_mode_process; - } -} - -bool SceneTreeTimer::is_pause_mode_process() { - return process_pause; -} - -SceneTreeTimer::SceneTreeTimer() { - time_left = 0; - process_pause = true; -} - -void SceneTree::tree_changed() { - - tree_version++; - emit_signal(tree_changed_name); -} - -void SceneTree::node_removed(Node *p_node) { - - if (current_scene == p_node) { - current_scene = NULL; - } - emit_signal(node_removed_name, p_node); - if (call_lock > 0) - call_skip.insert(p_node); -} - -SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) { - - Map::Element *E = group_map.find(p_group); - if (!E) { - E = group_map.insert(p_group, Group()); - } - - if (E->get().nodes.find(p_node) != -1) { - ERR_EXPLAIN("Already in group: " + p_group); - ERR_FAIL_V(&E->get()); - } - E->get().nodes.push_back(p_node); - //E->get().last_tree_version=0; - E->get().changed = true; - return &E->get(); -} - -void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) { - - Map::Element *E = group_map.find(p_group); - ERR_FAIL_COND(!E); - - E->get().nodes.erase(p_node); - if (E->get().nodes.empty()) - group_map.erase(E); -} - -void SceneTree::_flush_transform_notifications() { - - SelfList *n = xform_change_list.first(); - while (n) { - - Node *node = n->self(); - SelfList *nx = n->next(); - xform_change_list.remove(n); - n = nx; - node->notification(NOTIFICATION_TRANSFORM_CHANGED); - } -} - -void SceneTree::_flush_ugc() { - - ugc_locked = true; - - while (unique_group_calls.size()) { - - Map >::Element *E = unique_group_calls.front(); - - Variant v[VARIANT_ARG_MAX]; - for (int i = 0; i < E->get().size(); i++) - v[i] = E->get()[i]; - - call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4]); - - unique_group_calls.erase(E); - } - - ugc_locked = false; -} - -void SceneTree::_update_group_order(Group &g) { - - if (!g.changed) - return; - if (g.nodes.empty()) - return; - - Node **nodes = &g.nodes[0]; - int node_count = g.nodes.size(); - - SortArray node_sort; - node_sort.sort(nodes, node_count); - g.changed = false; -} - -void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - Group &g = E->get(); - if (g.nodes.empty()) - return; - - if (p_call_flags & GROUP_CALL_UNIQUE && !(p_call_flags & GROUP_CALL_REALTIME)) { - - ERR_FAIL_COND(ugc_locked); - - UGCall ug; - ug.call = p_function; - ug.group = p_group; - - if (unique_group_calls.has(ug)) - return; - - VARIANT_ARGPTRS; - - Vector args; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) - break; - args.push_back(*argptr[i]); - } - - unique_group_calls[ug] = args; - return; - } - - _update_group_order(g); - - Vector nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; - int node_count = nodes_copy.size(); - - call_lock++; - - if (p_call_flags & GROUP_CALL_REVERSE) { - - for (int i = node_count - 1; i >= 0; i--) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - else - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } else - MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); - } - - } else { - - for (int i = 0; i < node_count; i++) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) { - if (p_call_flags & GROUP_CALL_MULTILEVEL) - nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); - else - nodes[i]->call(p_function, VARIANT_ARG_PASS); - } else - MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); - } - } - - call_lock--; - if (call_lock == 0) - call_skip.clear(); -} - -void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - Group &g = E->get(); - if (g.nodes.empty()) - return; - - _update_group_order(g); - - Vector nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; - int node_count = nodes_copy.size(); - - call_lock++; - - if (p_call_flags & GROUP_CALL_REVERSE) { - - for (int i = node_count - 1; i >= 0; i--) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) - nodes[i]->notification(p_notification); - else - MessageQueue::get_singleton()->push_notification(nodes[i], p_notification); - } - - } else { - - for (int i = 0; i < node_count; i++) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) - nodes[i]->notification(p_notification); - else - MessageQueue::get_singleton()->push_notification(nodes[i], p_notification); - } - } - - call_lock--; - if (call_lock == 0) - call_skip.clear(); -} - -void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - Group &g = E->get(); - if (g.nodes.empty()) - return; - - _update_group_order(g); - - Vector nodes_copy = g.nodes; - Node **nodes = &nodes_copy[0]; - int node_count = nodes_copy.size(); - - call_lock++; - - if (p_call_flags & GROUP_CALL_REVERSE) { - - for (int i = node_count - 1; i >= 0; i--) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) - nodes[i]->set(p_name, p_value); - else - MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value); - } - - } else { - - for (int i = 0; i < node_count; i++) { - - if (call_lock && call_skip.has(nodes[i])) - continue; - - if (p_call_flags & GROUP_CALL_REALTIME) - nodes[i]->set(p_name, p_value); - else - MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value); - } - } - - call_lock--; - if (call_lock == 0) - call_skip.clear(); -} - -void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { - - call_group_flags(0, p_group, VARIANT_ARG_PASS); -} - -void SceneTree::notify_group(const StringName &p_group, int p_notification) { - - notify_group_flags(0, p_group, p_notification); -} - -void SceneTree::set_group(const StringName &p_group, const String &p_name, const Variant &p_value) { - - set_group_flags(0, p_group, p_name, p_value); -} - -void SceneTree::set_input_as_handled() { - - input_handled = true; -} - -void SceneTree::input_text(const String &p_text) { - - root_lock++; - - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input_text", p_text); //special one for GUI, as controls use their own process check - - root_lock--; -} - -bool SceneTree::is_input_handled() { - return input_handled; -} - -void SceneTree::input_event(const Ref &p_event) { - - if (is_editor_hint() && (p_event->cast_to() || p_event->cast_to())) - return; //avoid joy input on editor - - root_lock++; - //last_id=p_event.ID; - - input_handled = false; - - Ref ev = p_event; - ev->set_id(++last_id); //this should work better -#if 0 - switch(ev.type) { - - case InputEvent::MOUSE_BUTTON: { - - Matrix32 ai = root->get_final_transform().affine_inverse(); - Vector2 g = ai.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y)); - Vector2 l = ai.xform(Vector2(ev->get_pos().x,ev->get_pos().y)); - ev->get_pos().x=l.x; - ev->get_pos().y=l.y; - ev.mouse_button.global_x=g.x; - ev.mouse_button.global_y=g.y; - - } break; - case InputEvent::MOUSE_MOTION: { - - Matrix32 ai = root->get_final_transform().affine_inverse(); - Vector2 g = ai.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y)); - Vector2 l = ai.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y)); - Vector2 r = ai.xform(Vector2(ev->get_relative().x,ev->get_relative().y)); - ev.mouse_motion.x=l.x; - ev.mouse_motion.y=l.y; - ev.mouse_motion.global_x=g.x; - ev.mouse_motion.global_y=g.y; - ev->get_relative().x=r.x; - ev->get_relative().y=r.y; - - } break; - case InputEvent::SCREEN_TOUCH: { - - Matrix32 ai = root->get_final_transform().affine_inverse(); - Vector2 t = ai.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y)); - ev.screen_touch.x=t.x; - ev.screen_touch.y=t.y; - - } break; - case InputEvent::SCREEN_DRAG: { - - Matrix32 ai = root->get_final_transform().affine_inverse(); - Vector2 t = ai.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y)); - Vector2 r = ai.xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); - Vector2 s = ai.xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y)); - ev.screen_drag.x=t.x; - ev.screen_drag.y=t.y; - ev.screen_drag.relative_x=r.x; - ev.screen_drag.relative_y=r.y; - ev.screen_drag.speed_x=s.x; - ev.screen_drag.speed_y=s.y; - } break; - } - -#endif - - MainLoop::input_event(ev); -#if 0 - _call_input_pause("input","_input",ev); - - call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"_gui_input","_gui_input",p_event); //special one for GUI, as controls use their own process check - - //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"input","_input",ev); - - /* - if (ev.type==InputEvent::KEY && ev->is_pressed() && !ev->is_echo() && ev->get_scancode()==KEY_F12) { - - print_line("RAM: "+itos(Memory::get_static_mem_usage())); - print_line("DRAM: "+itos(Memory::get_dynamic_mem_usage())); - } - if (ev.type==InputEvent::KEY && ev->is_pressed() && !ev->is_echo() && ev->get_scancode()==KEY_F11) { - - Memory::dump_static_mem_to_file("memdump.txt"); - } - */ - - //transform for the rest -#else - - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input", ev); //special one for GUI, as controls use their own process check - -#endif - - if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_remote()) { - //quit from game window using F8 - Ref k = ev; - if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_scancode() == KEY_F8) { - ScriptDebugger::get_singleton()->request_quit(); - } - } - - _flush_ugc(); - root_lock--; - MessageQueue::get_singleton()->flush(); //small little hack - - root_lock++; - - if (!input_handled) { - -#if 0 - _call_input_pause("unhandled_input","_unhandled_input",ev); - //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev); - if (!input_handled && ev.type==InputEvent::KEY) { - _call_input_pause("unhandled_key_input","_unhandled_key_input",ev); - //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev); - } -#else - - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check - -#endif - input_handled = true; - _flush_ugc(); - root_lock--; - MessageQueue::get_singleton()->flush(); //small little hack - } else { - input_handled = true; - root_lock--; - } - - _call_idle_callbacks(); -} - -void SceneTree::init() { - - //_quit=false; - initialized = true; - input_handled = false; - - pause = false; - - root->_set_tree(this); - MainLoop::init(); -} - -bool SceneTree::iteration(float p_time) { - - root_lock++; - - current_frame++; - - _flush_transform_notifications(); - - MainLoop::iteration(p_time); - fixed_process_time = p_time; - - emit_signal("fixed_frame"); - - _notify_group_pause("fixed_process_internal", Node::NOTIFICATION_INTERNAL_FIXED_PROCESS); - _notify_group_pause("fixed_process", Node::NOTIFICATION_FIXED_PROCESS); - _flush_ugc(); - _flush_transform_notifications(); - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); - root_lock--; - - _flush_delete_queue(); - _call_idle_callbacks(); - - return _quit; -} - -bool SceneTree::idle(float p_time) { - - //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); - //print_line("node count: "+itos(get_node_count())); - //print_line("TEXTURE RAM: "+itos(VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED))); - - root_lock++; - - MainLoop::idle(p_time); - - idle_process_time = p_time; - - _network_poll(); - - emit_signal("idle_frame"); - - _flush_transform_notifications(); - - _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); - _notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS); - - Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); - if (win_size != last_screen_size) { - - last_screen_size = win_size; - _update_root_rect(); - - emit_signal("screen_resized"); - } - - _flush_ugc(); - _flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); - - root_lock--; - - _flush_delete_queue(); - - //go through timers - - for (List >::Element *E = timers.front(); E;) { - - List >::Element *N = E->next(); - if (pause && !E->get()->is_pause_mode_process()) { - E = N; - continue; - } - float time_left = E->get()->get_time_left(); - time_left -= p_time; - E->get()->set_time_left(time_left); - - if (time_left < 0) { - E->get()->emit_signal("timeout"); - timers.erase(E); - } - E = N; - } - - _call_idle_callbacks(); - -#ifdef TOOLS_ENABLED - - if (is_editor_hint()) { - //simple hack to reload fallback environment if it changed from editor - String env_path = GlobalConfig::get_singleton()->get("rendering/viewport/default_environment"); - env_path = env_path.strip_edges(); //user may have added a space or two - String cpath; - Ref fallback = get_root()->get_world()->get_fallback_environment(); - if (fallback.is_valid()) { - cpath = fallback->get_path(); - } - if (cpath != env_path) { - - if (env_path != String()) { - fallback = ResourceLoader::load(env_path); - } else { - fallback.unref(); - } - get_root()->get_world()->set_fallback_environment(fallback); - } - } - -#endif - - return _quit; -} - -void SceneTree::finish() { - - _flush_delete_queue(); - - _flush_ugc(); - - initialized = false; - - MainLoop::finish(); - - if (root) { - root->_set_tree(NULL); - memdelete(root); //delete root - } -} - -void SceneTree::quit() { - - _quit = true; -} - -void SceneTree::_notification(int p_notification) { - - switch (p_notification) { - - case NOTIFICATION_WM_QUIT_REQUEST: { - - get_root()->propagate_notification(p_notification); - - if (accept_quit) { - _quit = true; - break; - } - } break; - case NOTIFICATION_WM_GO_BACK_REQUEST: { - - get_root()->propagate_notification(p_notification); - - if (quit_on_go_back) { - _quit = true; - break; - } - } break; - case NOTIFICATION_OS_MEMORY_WARNING: - case NOTIFICATION_WM_FOCUS_IN: - case NOTIFICATION_WM_FOCUS_OUT: { - - get_root()->propagate_notification(p_notification); - } break; - case NOTIFICATION_TRANSLATION_CHANGED: { - get_root()->propagate_notification(Node::NOTIFICATION_TRANSLATION_CHANGED); - } break; - case NOTIFICATION_WM_UNFOCUS_REQUEST: { - - notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST); - - } break; - - default: - break; - }; -}; - -void SceneTree::set_auto_accept_quit(bool p_enable) { - - accept_quit = p_enable; -} - -void SceneTree::set_quit_on_go_back(bool p_enable) { - - quit_on_go_back = p_enable; -} - -#ifdef TOOLS_ENABLED -void SceneTree::set_editor_hint(bool p_enabled) { - - editor_hint = p_enabled; -} - -bool SceneTree::is_node_being_edited(const Node *p_node) const { - - return editor_hint && edited_scene_root && edited_scene_root->is_a_parent_of(p_node); -} - -bool SceneTree::is_editor_hint() const { - - return editor_hint; -} -#endif - -#ifdef DEBUG_ENABLED -void SceneTree::set_debug_collisions_hint(bool p_enabled) { - - debug_collisions_hint = p_enabled; -} - -bool SceneTree::is_debugging_collisions_hint() const { - - return debug_collisions_hint; -} - -void SceneTree::set_debug_navigation_hint(bool p_enabled) { - - debug_navigation_hint = p_enabled; -} - -bool SceneTree::is_debugging_navigation_hint() const { - - return debug_navigation_hint; -} -#endif - -void SceneTree::set_debug_collisions_color(const Color &p_color) { - - debug_collisions_color = p_color; -} - -Color SceneTree::get_debug_collisions_color() const { - - return debug_collisions_color; -} - -void SceneTree::set_debug_collision_contact_color(const Color &p_color) { - - debug_collision_contact_color = p_color; -} - -Color SceneTree::get_debug_collision_contact_color() const { - - return debug_collision_contact_color; -} - -void SceneTree::set_debug_navigation_color(const Color &p_color) { - - debug_navigation_color = p_color; -} - -Color SceneTree::get_debug_navigation_color() const { - - return debug_navigation_color; -} - -void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) { - - debug_navigation_disabled_color = p_color; -} - -Color SceneTree::get_debug_navigation_disabled_color() const { - - return debug_navigation_disabled_color; -} - -Ref SceneTree::get_debug_navigation_material() { - - if (navigation_material.is_valid()) - return navigation_material; - - Ref line_material = Ref(memnew(SpatialMaterial)); - /* line_material->set_flag(Material::FLAG_UNSHADED, true); - line_material->set_line_width(3.0); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/ - - navigation_material = line_material; - - return navigation_material; -} - -Ref SceneTree::get_debug_navigation_disabled_material() { - - if (navigation_disabled_material.is_valid()) - return navigation_disabled_material; - - Ref line_material = Ref(memnew(SpatialMaterial)); - /* line_material->set_flag(Material::FLAG_UNSHADED, true); - line_material->set_line_width(3.0); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/ - - navigation_disabled_material = line_material; - - return navigation_disabled_material; -} -Ref SceneTree::get_debug_collision_material() { - - if (collision_material.is_valid()) - return collision_material; - - Ref line_material = Ref(memnew(SpatialMaterial)); - /*line_material->set_flag(Material::FLAG_UNSHADED, true); - line_material->set_line_width(3.0); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); - line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); - line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/ - - collision_material = line_material; - - return collision_material; -} - -Ref SceneTree::get_debug_contact_mesh() { - - if (debug_contact_mesh.is_valid()) - return debug_contact_mesh; - - debug_contact_mesh = Ref(memnew(ArrayMesh)); - - Ref mat = memnew(SpatialMaterial); - /*mat->set_flag(Material::FLAG_UNSHADED,true); - mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); - mat->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true); - mat->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/ - - Vector3 diamond[6] = { - Vector3(-1, 0, 0), - Vector3(1, 0, 0), - Vector3(0, -1, 0), - Vector3(0, 1, 0), - Vector3(0, 0, -1), - Vector3(0, 0, 1) - }; - - int diamond_faces[8 * 3] = { - 0, 2, 4, - 0, 3, 4, - 1, 2, 4, - 1, 3, 4, - 0, 2, 5, - 0, 3, 5, - 1, 2, 5, - 1, 3, 5, - }; - - PoolVector indices; - for (int i = 0; i < 8 * 3; i++) - indices.push_back(diamond_faces[i]); - - PoolVector vertices; - for (int i = 0; i < 6; i++) - vertices.push_back(diamond[i] * 0.1); - - Array arr; - arr.resize(Mesh::ARRAY_MAX); - arr[Mesh::ARRAY_VERTEX] = vertices; - arr[Mesh::ARRAY_INDEX] = indices; - - debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); - debug_contact_mesh->surface_set_material(0, mat); - - return debug_contact_mesh; -} - -void SceneTree::set_pause(bool p_enabled) { - - if (p_enabled == pause) - return; - pause = p_enabled; - PhysicsServer::get_singleton()->set_active(!p_enabled); - Physics2DServer::get_singleton()->set_active(!p_enabled); - if (get_root()) - get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED); -} - -bool SceneTree::is_paused() const { - - return pause; -} - -void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref &p_input) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - Group &g = E->get(); - if (g.nodes.empty()) - return; - - _update_group_order(g); - - //copy, so copy on write happens in case something is removed from process while being called - //performance is not lost because only if something is added/removed the vector is copied. - Vector nodes_copy = g.nodes; - - int node_count = nodes_copy.size(); - Node **nodes = &nodes_copy[0]; - - Variant arg = p_input; - const Variant *v[1] = { &arg }; - - call_lock++; - - for (int i = node_count - 1; i >= 0; i--) { - - if (input_handled) - break; - - Node *n = nodes[i]; - if (call_lock && call_skip.has(n)) - continue; - - if (!n->can_process()) - continue; - - Variant::CallError ce; - n->call_multilevel(p_method, (const Variant **)v, 1); - //ERR_FAIL_COND(node_count != g.nodes.size()); - } - - call_lock--; - if (call_lock == 0) - call_skip.clear(); -} - -void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - Group &g = E->get(); - if (g.nodes.empty()) - return; - - _update_group_order(g); - - //copy, so copy on write happens in case something is removed from process while being called - //performance is not lost because only if something is added/removed the vector is copied. - Vector nodes_copy = g.nodes; - - int node_count = nodes_copy.size(); - Node **nodes = &nodes_copy[0]; - - call_lock++; - - for (int i = 0; i < node_count; i++) { - - Node *n = nodes[i]; - if (call_lock && call_skip.has(n)) - continue; - - if (!n->can_process()) - continue; - - n->notification(p_notification); - //ERR_FAIL_COND(node_count != g.nodes.size()); - } - - call_lock--; - if (call_lock == 0) - call_skip.clear(); -} - -/* -void SceneMainLoop::_update_listener_2d() { - - if (listener_2d.is_valid()) { - - SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() ); - } - -} -*/ - -uint32_t SceneTree::get_last_event_id() const { - - return last_id; -} - -Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - r_error.error = Variant::CallError::CALL_OK; - - ERR_FAIL_COND_V(p_argcount < 3, Variant()); - ERR_FAIL_COND_V(!p_args[0]->is_num(), Variant()); - ERR_FAIL_COND_V(p_args[1]->get_type() != Variant::STRING, Variant()); - ERR_FAIL_COND_V(p_args[2]->get_type() != Variant::STRING, Variant()); - - int flags = *p_args[0]; - StringName group = *p_args[1]; - StringName method = *p_args[2]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(p_argcount - 3, 5); i++) { - - v[i] = *p_args[i + 3]; - } - - call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4]); - return Variant(); -} - -Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { - - r_error.error = Variant::CallError::CALL_OK; - - ERR_FAIL_COND_V(p_argcount < 2, Variant()); - ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING, Variant()); - ERR_FAIL_COND_V(p_args[1]->get_type() != Variant::STRING, Variant()); - - StringName group = *p_args[0]; - StringName method = *p_args[1]; - Variant v[VARIANT_ARG_MAX]; - - for (int i = 0; i < MIN(p_argcount - 2, 5); i++) { - - v[i] = *p_args[i + 2]; - } - - call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4]); - return Variant(); -} - -int64_t SceneTree::get_frame() const { - - return current_frame; -} - -Array SceneTree::_get_nodes_in_group(const StringName &p_group) { - - Array ret; - Map::Element *E = group_map.find(p_group); - if (!E) - return ret; - - _update_group_order(E->get()); //update order just in case - int nc = E->get().nodes.size(); - if (nc == 0) - return ret; - - ret.resize(nc); - - Node **ptr = E->get().nodes.ptr(); - for (int i = 0; i < nc; i++) { - - ret[i] = ptr[i]; - } - - return ret; -} - -bool SceneTree::has_group(const StringName &p_identifier) const { - - return group_map.has(p_identifier); -} -void SceneTree::get_nodes_in_group(const StringName &p_group, List *p_list) { - - Map::Element *E = group_map.find(p_group); - if (!E) - return; - - _update_group_order(E->get()); //update order just in case - int nc = E->get().nodes.size(); - if (nc == 0) - return; - Node **ptr = E->get().nodes.ptr(); - for (int i = 0; i < nc; i++) { - - p_list->push_back(ptr[i]); - } -} - -static void _fill_array(Node *p_node, Array &array, int p_level) { - - array.push_back(p_level); - array.push_back(p_node->get_name()); - array.push_back(p_node->get_class()); - array.push_back(p_node->get_instance_ID()); - for (int i = 0; i < p_node->get_child_count(); i++) { - - _fill_array(p_node->get_child(i), array, p_level + 1); - } -} - -void SceneTree::_debugger_request_tree(void *self) { - - SceneTree *sml = (SceneTree *)self; - - Array arr; - _fill_array(sml->root, arr, 0); - ScriptDebugger::get_singleton()->send_message("scene_tree", arr); -} - -void SceneTree::_flush_delete_queue() { - - _THREAD_SAFE_METHOD_ - - while (delete_queue.size()) { - - Object *obj = ObjectDB::get_instance(delete_queue.front()->get()); - if (obj) { - memdelete(obj); - } - delete_queue.pop_front(); - } -} - -void SceneTree::queue_delete(Object *p_object) { - - _THREAD_SAFE_METHOD_ - ERR_FAIL_NULL(p_object); - p_object->_is_queued_for_deletion = true; - delete_queue.push_back(p_object->get_instance_ID()); -} - -int SceneTree::get_node_count() const { - - return node_count; -} - -void SceneTree::_update_root_rect() { - - if (stretch_mode == STRETCH_MODE_DISABLED) { - - root->set_size(last_screen_size); - root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size)); - root->set_size_override_stretch(false); - root->set_size_override(false, Size2()); - return; //user will take care - } - - //actual screen video mode - Size2 video_mode = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); - Size2 desired_res = stretch_min; - - Size2 viewport_size; - Size2 screen_size; - - float viewport_aspect = desired_res.aspect(); - float video_mode_aspect = video_mode.aspect(); - - if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) { - //same aspect or ignore aspect - viewport_size = desired_res; - screen_size = video_mode; - } else if (viewport_aspect < video_mode_aspect) { - // screen ratio is smaller vertically - - if (stretch_aspect == STRETCH_ASPECT_KEEP_HEIGHT) { - - //will stretch horizontally - viewport_size.x = desired_res.y * video_mode_aspect; - viewport_size.y = desired_res.y; - screen_size = video_mode; - - } else { - //will need black bars - viewport_size = desired_res; - screen_size.x = video_mode.y * viewport_aspect; - screen_size.y = video_mode.y; - } - } else { - //screen ratio is smaller horizontally - if (stretch_aspect == STRETCH_ASPECT_KEEP_WIDTH) { - - //will stretch horizontally - viewport_size.x = desired_res.x; - viewport_size.y = desired_res.x / video_mode_aspect; - screen_size = video_mode; - - } else { - //will need black bars - viewport_size = desired_res; - screen_size.x = video_mode.x; - screen_size.y = video_mode.x / viewport_aspect; - } - } - - screen_size = screen_size.floor(); - viewport_size = viewport_size.floor(); - - Size2 margin; - Size2 offset; - //black bars and margin - if (screen_size.x < video_mode.x) { - margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); - VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0); - offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); - } else if (screen_size.y < video_mode.y) { - - margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); - VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y); - offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); - } else { - VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0); - } - - //print_line("VP SIZE: "+viewport_size+" OFFSET: "+offset+" = "+(offset*2+viewport_size)); - //print_line("SS: "+video_mode); - switch (stretch_mode) { - case STRETCH_MODE_2D: { - - root->set_size(screen_size); - root->set_attach_to_screen_rect(Rect2(margin, screen_size)); - root->set_size_override_stretch(true); - root->set_size_override(true, viewport_size); - - } break; - case STRETCH_MODE_VIEWPORT: { - - root->set_size(viewport_size); - root->set_attach_to_screen_rect(Rect2(margin, screen_size)); - root->set_size_override_stretch(false); - root->set_size_override(false, Size2()); - - } break; - } -} - -void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize) { - - stretch_mode = p_mode; - stretch_aspect = p_aspect; - stretch_min = p_minsize; - _update_root_rect(); -} - -#ifdef TOOLS_ENABLED -void SceneTree::set_edited_scene_root(Node *p_node) { - edited_scene_root = p_node; -} - -Node *SceneTree::get_edited_scene_root() const { - - return edited_scene_root; -} -#endif - -void SceneTree::set_current_scene(Node *p_scene) { - - ERR_FAIL_COND(p_scene && p_scene->get_parent() != root); - current_scene = p_scene; -} - -Node *SceneTree::get_current_scene() const { - - return current_scene; -} - -void SceneTree::_change_scene(Node *p_to) { - - if (current_scene) { - memdelete(current_scene); - current_scene = NULL; - } - - if (p_to) { - current_scene = p_to; - root->add_child(p_to); - } -} - -Error SceneTree::change_scene(const String &p_path) { - - Ref new_scene = ResourceLoader::load(p_path); - if (new_scene.is_null()) - return ERR_CANT_OPEN; - - return change_scene_to(new_scene); -} -Error SceneTree::change_scene_to(const Ref &p_scene) { - - Node *new_scene = NULL; - if (p_scene.is_valid()) { - new_scene = p_scene->instance(); - ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); - } - - call_deferred("_change_scene", new_scene); - return OK; -} -Error SceneTree::reload_current_scene() { - - ERR_FAIL_COND_V(!current_scene, ERR_UNCONFIGURED); - String fname = current_scene->get_filename(); - return change_scene(fname); -} - -void SceneTree::add_current_scene(Node *p_current) { - - current_scene = p_current; - root->add_child(p_current); -} -#ifdef DEBUG_ENABLED - -void SceneTree::_live_edit_node_path_func(const NodePath &p_path, int p_id) { - - live_edit_node_path_cache[p_id] = p_path; -} - -void SceneTree::_live_edit_res_path_func(const String &p_path, int p_id) { - - live_edit_resource_cache[p_id] = p_path; -} - -void SceneTree::_live_edit_node_set_func(int p_id, const StringName &p_prop, const Variant &p_value) { - - if (!live_edit_node_path_cache.has(p_id)) - return; - - NodePath np = live_edit_node_path_cache[p_id]; - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(np)) - continue; - Node *n2 = n->get_node(np); - - n2->set(p_prop, p_value); - } -} - -void SceneTree::_live_edit_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value) { - - RES r = ResourceLoader::load(p_value); - if (!r.is_valid()) - return; - _live_edit_node_set_func(p_id, p_prop, r); -} -void SceneTree::_live_edit_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { - - if (!live_edit_node_path_cache.has(p_id)) - return; - - NodePath np = live_edit_node_path_cache[p_id]; - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(np)) - continue; - Node *n2 = n->get_node(np); - - n2->call(p_method, VARIANT_ARG_PASS); - } -} -void SceneTree::_live_edit_res_set_func(int p_id, const StringName &p_prop, const Variant &p_value) { - - if (!live_edit_resource_cache.has(p_id)) - return; - - String resp = live_edit_resource_cache[p_id]; - - if (!ResourceCache::has(resp)) - return; - - RES r = ResourceCache::get(resp); - if (!r.is_valid()) - return; - - r->set(p_prop, p_value); -} -void SceneTree::_live_edit_res_set_res_func(int p_id, const StringName &p_prop, const String &p_value) { - - RES r = ResourceLoader::load(p_value); - if (!r.is_valid()) - return; - _live_edit_res_set_func(p_id, p_prop, r); -} -void SceneTree::_live_edit_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { - - if (!live_edit_resource_cache.has(p_id)) - return; - - String resp = live_edit_resource_cache[p_id]; - - if (!ResourceCache::has(resp)) - return; - - RES r = ResourceCache::get(resp); - if (!r.is_valid()) - return; - - r->call(p_method, VARIANT_ARG_PASS); -} - -void SceneTree::_live_edit_root_func(const NodePath &p_scene_path, const String &p_scene_from) { - - live_edit_root = p_scene_path; - live_edit_scene = p_scene_from; -} - -void SceneTree::_live_edit_create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_parent)) - continue; - Node *n2 = n->get_node(p_parent); - - Object *o = ClassDB::instance(p_type); - if (!o) - continue; - Node *no = o->cast_to(); - no->set_name(p_name); - - n2->add_child(no); - } -} -void SceneTree::_live_edit_instance_node_func(const NodePath &p_parent, const String &p_path, const String &p_name) { - - Ref ps = ResourceLoader::load(p_path); - - if (!ps.is_valid()) - return; - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_parent)) - continue; - Node *n2 = n->get_node(p_parent); - - Node *no = ps->instance(); - no->set_name(p_name); - - n2->add_child(no); - } -} -void SceneTree::_live_edit_remove_node_func(const NodePath &p_at) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F;) { - - Set::Element *N = F->next(); - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_at)) - continue; - Node *n2 = n->get_node(p_at); - - memdelete(n2); - - F = N; - } -} -void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_keep_id) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F;) { - - Set::Element *N = F->next(); - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_at)) - continue; - - Node *n2 = n->get_node(p_at); - - n2->get_parent()->remove_child(n2); - - live_edit_remove_list[n][p_keep_id] = n2; - - F = N; - } -} -void SceneTree::_live_edit_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_at_pos) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F;) { - - Set::Element *N = F->next(); - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_at)) - continue; - Node *n2 = n->get_node(p_at); - - Map >::Element *EN = live_edit_remove_list.find(n); - - if (!EN) - continue; - - Map::Element *FN = EN->get().find(p_id); - - if (!FN) - continue; - n2->add_child(FN->get()); - - EN->get().erase(FN); - - if (EN->get().size() == 0) { - live_edit_remove_list.erase(EN); - } - - F = N; - } -} -void SceneTree::_live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_at)) - continue; - Node *n2 = n->get_node(p_at); - - Node *dup = n2->duplicate(true); - - if (!dup) - continue; - - dup->set_name(p_new_name); - n2->get_parent()->add_child(dup); - } -} -void SceneTree::_live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { - - Node *base = NULL; - if (root->has_node(live_edit_root)) - base = root->get_node(live_edit_root); - - Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); - if (!E) - return; //scene not editable - - for (Set::Element *F = E->get().front(); F; F = F->next()) { - - Node *n = F->get(); - - if (base && !base->is_a_parent_of(n)) - continue; - - if (!n->has_node(p_at)) - continue; - Node *nfrom = n->get_node(p_at); - - if (!n->has_node(p_new_place)) - continue; - Node *nto = n->get_node(p_new_place); - - nfrom->get_parent()->remove_child(nfrom); - nfrom->set_name(p_new_name); - - nto->add_child(nfrom); - if (p_at_pos >= 0) - nto->move_child(nfrom, p_at_pos); - } -} - -#endif - -void SceneTree::drop_files(const Vector &p_files, int p_from_screen) { - - emit_signal("files_dropped", p_files, p_from_screen); - MainLoop::drop_files(p_files, p_from_screen); -} - -Ref SceneTree::create_timer(float p_delay_sec, bool p_process_pause) { - - Ref stt; - stt.instance(); - stt->set_pause_mode_process(p_process_pause); - stt->set_time_left(p_delay_sec); - timers.push_back(stt); - return stt; -} - -void SceneTree::_network_peer_connected(int p_id) { - - connected_peers.insert(p_id); - path_get_cache.insert(p_id, PathGetCache()); - - emit_signal("network_peer_connected", p_id); -} - -void SceneTree::_network_peer_disconnected(int p_id) { - - connected_peers.erase(p_id); - path_get_cache.erase(p_id); //I no longer need your cache, sorry - emit_signal("network_peer_disconnected", p_id); -} - -void SceneTree::_connected_to_server() { - - emit_signal("connected_to_server"); -} - -void SceneTree::_connection_failed() { - - emit_signal("connection_failed"); -} - -void SceneTree::_server_disconnected() { - - emit_signal("server_disconnected"); -} - -void SceneTree::set_network_peer(const Ref &p_network_peer) { - if (network_peer.is_valid()) { - network_peer->disconnect("peer_connected", this, "_network_peer_connected"); - network_peer->disconnect("peer_disconnected", this, "_network_peer_disconnected"); - network_peer->disconnect("connection_succeeded", this, "_connected_to_server"); - network_peer->disconnect("connection_failed", this, "_connection_failed"); - network_peer->disconnect("server_disconnected", this, "_server_disconnected"); - connected_peers.clear(); - path_get_cache.clear(); - path_send_cache.clear(); - last_send_cache_id = 1; - } - - ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); - ERR_FAIL_COND(p_network_peer.is_valid() && p_network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); - - network_peer = p_network_peer; - - if (network_peer.is_valid()) { - network_peer->connect("peer_connected", this, "_network_peer_connected"); - network_peer->connect("peer_disconnected", this, "_network_peer_disconnected"); - network_peer->connect("connection_succeeded", this, "_connected_to_server"); - network_peer->connect("connection_failed", this, "_connection_failed"); - network_peer->connect("server_disconnected", this, "_server_disconnected"); - } -} - -bool SceneTree::is_network_server() const { - - ERR_FAIL_COND_V(!network_peer.is_valid(), false); - return network_peer->is_server(); -} - -bool SceneTree::has_network_peer() const { - return network_peer.is_valid(); -} - -int SceneTree::get_network_unique_id() const { - - ERR_FAIL_COND_V(!network_peer.is_valid(), 0); - return network_peer->get_unique_id(); -} - -void SceneTree::set_refuse_new_network_connections(bool p_refuse) { - ERR_FAIL_COND(!network_peer.is_valid()); - network_peer->set_refuse_new_connections(p_refuse); -} - -bool SceneTree::is_refusing_new_network_connections() const { - - ERR_FAIL_COND_V(!network_peer.is_valid(), false); - - return network_peer->is_refusing_new_connections(); -} - -void SceneTree::_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { - - if (network_peer.is_null()) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); - ERR_FAIL(); - } - - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { - ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); - ERR_FAIL(); - } - - if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { - ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); - ERR_FAIL(); - } - - if (p_argcount > 255) { - ERR_EXPLAIN("Too many arguments >255."); - ERR_FAIL(); - } - - if (p_to != 0 && !connected_peers.has(ABS(p_to))) { - if (p_to == get_network_unique_id()) { - ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(get_network_unique_id())); - } else { - ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); - } - - ERR_FAIL(); - } - - NodePath from_path = p_from->get_path(); - ERR_FAIL_COND(from_path.is_empty()); - - //see if the path is cached - PathSentCache *psc = path_send_cache.getptr(from_path); - if (!psc) { - //path is not cached, create - path_send_cache[from_path] = PathSentCache(); - psc = path_send_cache.getptr(from_path); - psc->id = last_send_cache_id++; - } - - //create base packet, lots of harcode because it must be tight - - int ofs = 0; - -#define MAKE_ROOM(m_amount) \ - if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); - - //encode type - MAKE_ROOM(1); - packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; - ofs += 1; - - //encode ID - MAKE_ROOM(ofs + 4); - encode_uint32(psc->id, &packet_cache[ofs]); - ofs += 4; - - //encode function name - CharString name = String(p_name).utf8(); - int len = encode_cstring(name.get_data(), NULL); - MAKE_ROOM(ofs + len); - encode_cstring(name.get_data(), &packet_cache[ofs]); - ofs += len; - - if (p_set) { - //set argument - Error err = encode_variant(*p_arg[0], NULL, len); - ERR_FAIL_COND(err != OK); - MAKE_ROOM(ofs + len); - encode_variant(*p_arg[0], &packet_cache[ofs], len); - ofs += len; - - } else { - //call arguments - MAKE_ROOM(ofs + 1); - packet_cache[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - Error err = encode_variant(*p_arg[i], NULL, len); - ERR_FAIL_COND(err != OK); - MAKE_ROOM(ofs + len); - encode_variant(*p_arg[i], &packet_cache[ofs], len); - ofs += len; - } - } - - //see if all peers have cached path (is so, call can be fast) - bool has_all_peers = true; - - List peers_to_add; //if one is missing, take note to add it - - for (Set::Element *E = connected_peers.front(); E; E = E->next()) { - - if (p_to < 0 && E->get() == -p_to) - continue; //continue, excluded - - if (p_to > 0 && E->get() != p_to) - continue; //continue, not for this peer - - Map::Element *F = psc->confirmed_peers.find(E->get()); - - if (!F || F->get() == false) { - //path was not cached, or was cached but is unconfirmed - if (!F) { - //not cached at all, take note - peers_to_add.push_back(E->get()); - } - - has_all_peers = false; - } - } - - //those that need to be added, send a message for this - - for (List::Element *E = peers_to_add.front(); E; E = E->next()) { - - //encode function name - CharString pname = String(from_path).utf8(); - int len = encode_cstring(pname.get_data(), NULL); - - Vector packet; - - packet.resize(1 + 4 + len); - packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH; - encode_uint32(psc->id, &packet[1]); - encode_cstring(pname.get_data(), &packet[5]); - - network_peer->set_target_peer(E->get()); //to all of you - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); - network_peer->put_packet(packet.ptr(), packet.size()); - - psc->confirmed_peers.insert(E->get(), false); //insert into confirmed, but as false since it was not confirmed - } - - //take chance and set transfer mode, since all send methods will use it - network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); - - if (has_all_peers) { - - //they all have verified paths, so send fast - network_peer->set_target_peer(p_to); //to all of you - network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love - } else { - //not all verified path, so send one by one - - //apend path at the end, since we will need it for some packets - CharString pname = String(from_path).utf8(); - int path_len = encode_cstring(pname.get_data(), NULL); - MAKE_ROOM(ofs + path_len); - encode_cstring(pname.get_data(), &packet_cache[ofs]); - - for (Set::Element *E = connected_peers.front(); E; E = E->next()) { - - if (p_to < 0 && E->get() == -p_to) - continue; //continue, excluded - - if (p_to > 0 && E->get() != p_to) - continue; //continue, not for this peer - - Map::Element *F = psc->confirmed_peers.find(E->get()); - ERR_CONTINUE(!F); //should never happen - - network_peer->set_target_peer(E->get()); //to this one specifically - - if (F->get() == true) { - //this one confirmed path, so use id - encode_uint32(psc->id, &packet_cache[1]); - network_peer->put_packet(packet_cache.ptr(), ofs); - } else { - //this one did not confirm path yet, so use entire path (sorry!) - encode_uint32(0x80000000 | ofs, &packet_cache[1]); //offset to path and flag - network_peer->put_packet(packet_cache.ptr(), ofs + path_len); - } - } - } -} - -void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { - - ERR_FAIL_COND(p_packet_len < 5); - - uint8_t packet_type = p_packet[0]; - - switch (packet_type) { - - case NETWORK_COMMAND_REMOTE_CALL: - case NETWORK_COMMAND_REMOTE_SET: { - - ERR_FAIL_COND(p_packet_len < 5); - uint32_t target = decode_uint32(&p_packet[1]); - - Node *node = NULL; - - if (target & 0x80000000) { - - int ofs = target & 0x7FFFFFFF; - ERR_FAIL_COND(ofs >= p_packet_len); - - String paths; - paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); - - NodePath np = paths; - - node = get_root()->get_node(np); - if (node == NULL) { - ERR_EXPLAIN("Failed to get path from RPC: " + String(np)); - ERR_FAIL_COND(node == NULL); - } - } else { - - int id = target; - - Map::Element *E = path_get_cache.find(p_from); - ERR_FAIL_COND(!E); - - Map::Element *F = E->get().nodes.find(id); - ERR_FAIL_COND(!F); - - PathGetCache::NodeInfo *ni = &F->get(); - //do proper caching later - - node = get_root()->get_node(ni->path); - if (node == NULL) { - ERR_EXPLAIN("Failed to get cached path from RPC: " + String(ni->path)); - ERR_FAIL_COND(node == NULL); - } - } - - ERR_FAIL_COND(p_packet_len < 6); - - //detect cstring end - int len_end = 5; - for (; len_end < p_packet_len; len_end++) { - if (p_packet[len_end] == 0) { - break; - } - } - - ERR_FAIL_COND(len_end >= p_packet_len); - - StringName name = String::utf8((const char *)&p_packet[5]); - - if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - - if (!node->can_call_rpc(name)) - return; - - int ofs = len_end + 1; - - ERR_FAIL_COND(ofs >= p_packet_len); - - int argc = p_packet[ofs]; - Vector args; - Vector argp; - args.resize(argc); - argp.resize(argc); - - ofs++; - - for (int i = 0; i < argc; i++) { - - ERR_FAIL_COND(ofs >= p_packet_len); - int vlen; - Error err = decode_variant(args[i], &p_packet[ofs], p_packet_len - ofs, &vlen); - ERR_FAIL_COND(err != OK); - //args[i]=p_packet[3+i]; - argp[i] = &args[i]; - ofs += vlen; - } - - Variant::CallError ce; - - node->call(name, argp.ptr(), argc, ce); - if (ce.error != Variant::CallError::CALL_OK) { - String error = Variant::get_call_error_text(node, name, argp.ptr(), argc, ce); - error = "RPC - " + error; - ERR_PRINTS(error); - } - - } else { - - if (!node->can_call_rset(name)) - return; - - int ofs = len_end + 1; - - ERR_FAIL_COND(ofs >= p_packet_len); - - Variant value; - decode_variant(value, &p_packet[ofs], p_packet_len - ofs); - - bool valid; - - node->set(name, value, &valid); - if (!valid) { - String error = "Error setting remote property '" + String(name) + "', not found in object of type " + node->get_class(); - ERR_PRINTS(error); - } - } - - } break; - case NETWORK_COMMAND_SIMPLIFY_PATH: { - - ERR_FAIL_COND(p_packet_len < 5); - int id = decode_uint32(&p_packet[1]); - - String paths; - paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5); - - NodePath path = paths; - - if (!path_get_cache.has(p_from)) { - path_get_cache[p_from] = PathGetCache(); - } - - PathGetCache::NodeInfo ni; - ni.path = path; - ni.instance = 0; - - path_get_cache[p_from].nodes[id] = ni; - - { - //send ack - - //encode path - CharString pname = String(path).utf8(); - int len = encode_cstring(pname.get_data(), NULL); - - Vector packet; - - packet.resize(1 + len); - packet[0] = NETWORK_COMMAND_CONFIRM_PATH; - encode_cstring(pname.get_data(), &packet[1]); - - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); - network_peer->set_target_peer(p_from); - network_peer->put_packet(packet.ptr(), packet.size()); - } - } break; - case NETWORK_COMMAND_CONFIRM_PATH: { - - String paths; - paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1); - - NodePath path = paths; - - PathSentCache *psc = path_send_cache.getptr(path); - ERR_FAIL_COND(!psc); - - Map::Element *E = psc->confirmed_peers.find(p_from); - ERR_FAIL_COND(!E); - E->get() = true; - } break; - } -} - -void SceneTree::_network_poll() { - - if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) - return; - - network_peer->poll(); - - if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here - return; - - while (network_peer->get_available_packet_count()) { - - int sender = network_peer->get_packet_peer(); - const uint8_t *packet; - int len; - - Error err = network_peer->get_packet(&packet, len); - if (err != OK) { - ERR_PRINT("Error getting packet!"); - } - - _network_process_packet(sender, packet, len); - - if (!network_peer.is_valid()) { - break; //it's also possible that a packet or RPC caused a disconnection, so also check here - } - } -} - -void SceneTree::_bind_methods() { - - //ClassDB::bind_method(D_METHOD("call_group","call_flags","group","method","arg1","arg2"),&SceneMainLoop::_call_group,DEFVAL(Variant()),DEFVAL(Variant())); - - ClassDB::bind_method(D_METHOD("get_root:Viewport"), &SceneTree::get_root); - ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group); - - ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit); - - ClassDB::bind_method(D_METHOD("set_editor_hint", "enable"), &SceneTree::set_editor_hint); - ClassDB::bind_method(D_METHOD("is_editor_hint"), &SceneTree::is_editor_hint); - ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint); - ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint); - ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint); - ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint); - -#ifdef TOOLS_ENABLED - ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root); - ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root); -#endif - - ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); - ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); - ClassDB::bind_method(D_METHOD("set_input_as_handled"), &SceneTree::set_input_as_handled); - ClassDB::bind_method(D_METHOD("is_input_handled"), &SceneTree::is_input_handled); - - ClassDB::bind_method(D_METHOD("create_timer:SceneTreeTimer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true)); - - ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count); - ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); - ClassDB::bind_method(D_METHOD("quit"), &SceneTree::quit); - - ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize"), &SceneTree::set_screen_stretch); - - ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); - - MethodInfo mi; - mi.name = "call_group_flags"; - mi.arguments.push_back(PropertyInfo(Variant::INT, "flags")); - mi.arguments.push_back(PropertyInfo(Variant::STRING, "group")); - mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group_flags", &SceneTree::_call_group_flags, mi); - - ClassDB::bind_method(D_METHOD("notify_group_flags", "call_flags", "group", "notification"), &SceneTree::notify_group_flags); - ClassDB::bind_method(D_METHOD("set_group_flags", "call_flags", "group", "property", "value"), &SceneTree::set_group_flags); - - MethodInfo mi2; - mi2.name = "call_group"; - mi2.arguments.push_back(PropertyInfo(Variant::STRING, "group")); - mi2.arguments.push_back(PropertyInfo(Variant::STRING, "method")); - - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group", &SceneTree::_call_group, mi2); - - ClassDB::bind_method(D_METHOD("notify_group", "call_flags", "group", "notification"), &SceneTree::notify_group); - ClassDB::bind_method(D_METHOD("set_group", "call_flags", "group", "property", "value"), &SceneTree::set_group); - - ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group); - - ClassDB::bind_method(D_METHOD("set_current_scene", "child_node:Node"), &SceneTree::set_current_scene); - ClassDB::bind_method(D_METHOD("get_current_scene:Node"), &SceneTree::get_current_scene); - - ClassDB::bind_method(D_METHOD("change_scene", "path"), &SceneTree::change_scene); - ClassDB::bind_method(D_METHOD("change_scene_to", "packed_scene:PackedScene"), &SceneTree::change_scene_to); - - ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene); - - ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene); - - ClassDB::bind_method(D_METHOD("set_network_peer", "peer:NetworkedMultiplayerPeer"), &SceneTree::set_network_peer); - ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); - ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); - ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id); - ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); - ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); - ClassDB::bind_method(D_METHOD("_network_peer_connected"), &SceneTree::_network_peer_connected); - ClassDB::bind_method(D_METHOD("_network_peer_disconnected"), &SceneTree::_network_peer_disconnected); - ClassDB::bind_method(D_METHOD("_connected_to_server"), &SceneTree::_connected_to_server); - ClassDB::bind_method(D_METHOD("_connection_failed"), &SceneTree::_connection_failed); - ClassDB::bind_method(D_METHOD("_server_disconnected"), &SceneTree::_server_disconnected); - - ADD_SIGNAL(MethodInfo("tree_changed")); - ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node"))); - ADD_SIGNAL(MethodInfo("screen_resized")); - ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node"))); - - ADD_SIGNAL(MethodInfo("idle_frame")); - ADD_SIGNAL(MethodInfo("fixed_frame")); - - ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); - ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("connected_to_server")); - ADD_SIGNAL(MethodInfo("connection_failed")); - ADD_SIGNAL(MethodInfo("server_disconnected")); - - BIND_CONSTANT(GROUP_CALL_DEFAULT); - BIND_CONSTANT(GROUP_CALL_REVERSE); - BIND_CONSTANT(GROUP_CALL_REALTIME); - BIND_CONSTANT(GROUP_CALL_UNIQUE); - - BIND_CONSTANT(STRETCH_MODE_DISABLED); - BIND_CONSTANT(STRETCH_MODE_2D); - BIND_CONSTANT(STRETCH_MODE_VIEWPORT); - BIND_CONSTANT(STRETCH_ASPECT_IGNORE); - BIND_CONSTANT(STRETCH_ASPECT_KEEP); - BIND_CONSTANT(STRETCH_ASPECT_KEEP_WIDTH); - BIND_CONSTANT(STRETCH_ASPECT_KEEP_HEIGHT); -} - -SceneTree *SceneTree::singleton = NULL; - -SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS]; -int SceneTree::idle_callback_count = 0; - -void SceneTree::_call_idle_callbacks() { - - for (int i = 0; i < idle_callback_count; i++) { - idle_callbacks[i](); - } -} - -void SceneTree::add_idle_callback(IdleCallback p_callback) { - ERR_FAIL_COND(idle_callback_count >= MAX_IDLE_CALLBACKS); - idle_callbacks[idle_callback_count++] = p_callback; -} - -SceneTree::SceneTree() { - - singleton = this; - _quit = false; - accept_quit = true; - quit_on_go_back = true; - initialized = false; -#ifdef TOOLS_ENABLED - editor_hint = false; -#endif -#ifdef DEBUG_ENABLED - debug_collisions_hint = false; - debug_navigation_hint = false; -#endif - debug_collisions_color = GLOBAL_DEF("debug/collision/shape_color", Color(0.0, 0.6, 0.7, 0.5)); - debug_collision_contact_color = GLOBAL_DEF("debug/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8)); - debug_navigation_color = GLOBAL_DEF("debug/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4)); - debug_navigation_disabled_color = GLOBAL_DEF("debug/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4)); - collision_debug_contacts = GLOBAL_DEF("debug/collision/max_contacts_displayed", 10000); - - tree_version = 1; - fixed_process_time = 1; - idle_process_time = 1; - last_id = 1; - root = NULL; - current_frame = 0; - tree_changed_name = "tree_changed"; - node_removed_name = "node_removed"; - ugc_locked = false; - call_lock = 0; - root_lock = 0; - node_count = 0; - - //create with mainloop - - root = memnew(Viewport); - root->set_name("root"); - if (!root->get_world().is_valid()) - root->set_world(Ref(memnew(World))); - - //root->set_world_2d( Ref( memnew( World2D ))); - root->set_as_audio_listener(true); - root->set_as_audio_listener_2d(true); - current_scene = NULL; - - int ref_atlas_size = GLOBAL_DEF("rendering/reflections/atlas_size", 2048); - int ref_atlas_subdiv = GLOBAL_DEF("rendering/reflections/atlas_subdiv", 8); - int msaa_mode = GLOBAL_DEF("rendering/quality/msaa", 0); - GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/msaa", PropertyInfo(Variant::INT, "rendering/quality/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x")); - root->set_msaa(Viewport::MSAA(msaa_mode)); - bool hdr = GLOBAL_DEF("rendering/quality/hdr", true); - root->set_hdr(hdr); - - VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); - - { //load default fallback environment - //get possible extensions - List exts; - ResourceLoader::get_recognized_extensions_for_type("Environment", &exts); - String ext_hint; - for (List::Element *E = exts.front(); E; E = E->next()) { - if (ext_hint != String()) - ext_hint += ","; - ext_hint += "*." + E->get(); - } - //get path - String env_path = GLOBAL_DEF("rendering/viewport/default_environment", ""); - //setup property - GlobalConfig::get_singleton()->set_custom_property_info("rendering/viewport/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); - env_path = env_path.strip_edges(); - if (env_path != String()) { - Ref env = ResourceLoader::load(env_path); - if (env.is_valid()) { - root->get_world()->set_fallback_environment(env); - } else { - if (is_editor_hint()) { - //file was erased, clear the field. - GlobalConfig::get_singleton()->set("rendering/viewport/default_environment", ""); - } else { - //file was erased, notify user. - ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded.")); - } - } - } - } - - stretch_mode = STRETCH_MODE_DISABLED; - stretch_aspect = STRETCH_ASPECT_IGNORE; - - last_screen_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); - _update_root_rect(); - - if (ScriptDebugger::get_singleton()) { - ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this); - } - - root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true)); - -#ifdef TOOLS_ENABLED - edited_scene_root = NULL; -#endif - -#ifdef DEBUG_ENABLED - - live_edit_funcs.udata = this; - live_edit_funcs.node_path_func = _live_edit_node_path_funcs; - live_edit_funcs.res_path_func = _live_edit_res_path_funcs; - live_edit_funcs.node_set_func = _live_edit_node_set_funcs; - live_edit_funcs.node_set_res_func = _live_edit_node_set_res_funcs; - live_edit_funcs.node_call_func = _live_edit_node_call_funcs; - live_edit_funcs.res_set_func = _live_edit_res_set_funcs; - live_edit_funcs.res_set_res_func = _live_edit_res_set_res_funcs; - live_edit_funcs.res_call_func = _live_edit_res_call_funcs; - live_edit_funcs.root_func = _live_edit_root_funcs; - - live_edit_funcs.tree_create_node_func = _live_edit_create_node_funcs; - live_edit_funcs.tree_instance_node_func = _live_edit_instance_node_funcs; - live_edit_funcs.tree_remove_node_func = _live_edit_remove_node_funcs; - live_edit_funcs.tree_remove_and_keep_node_func = _live_edit_remove_and_keep_node_funcs; - live_edit_funcs.tree_restore_node_func = _live_edit_restore_node_funcs; - live_edit_funcs.tree_duplicate_node_func = _live_edit_duplicate_node_funcs; - live_edit_funcs.tree_reparent_node_func = _live_edit_reparent_node_funcs; - - if (ScriptDebugger::get_singleton()) { - ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs); - } - - live_edit_root = NodePath("/root"); - - last_send_cache_id = 1; - -#endif -} - -SceneTree::~SceneTree() { -} diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h deleted file mode 100644 index 2ea79bf945..0000000000 --- a/scene/main/scene_main_loop.h +++ /dev/null @@ -1,466 +0,0 @@ -/*************************************************************************/ -/* scene_main_loop.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 SCENE_MAIN_LOOP_H -#define SCENE_MAIN_LOOP_H - -#include "io/networked_multiplayer_peer.h" -#include "os/main_loop.h" -#include "os/thread_safe.h" -#include "scene/resources/mesh.h" -#include "scene/resources/world.h" -#include "scene/resources/world_2d.h" -#include "self_list.h" - -/** - @author Juan Linietsky -*/ - -class SceneTree; -class PackedScene; -class Node; -class Viewport; -class Material; -class Mesh; - -class SceneTreeTimer : public Reference { - GDCLASS(SceneTreeTimer, Reference); - - float time_left; - bool process_pause; - -protected: - static void _bind_methods(); - -public: - void set_time_left(float p_time); - float get_time_left() const; - - void set_pause_mode_process(bool p_pause_mode_process); - bool is_pause_mode_process(); - - SceneTreeTimer(); -}; - -class SceneTree : public MainLoop { - - _THREAD_SAFE_CLASS_ - - GDCLASS(SceneTree, MainLoop); - -public: - typedef void (*IdleCallback)(); - - enum StretchMode { - - STRETCH_MODE_DISABLED, - STRETCH_MODE_2D, - STRETCH_MODE_VIEWPORT, - }; - - enum StretchAspect { - - STRETCH_ASPECT_IGNORE, - STRETCH_ASPECT_KEEP, - STRETCH_ASPECT_KEEP_WIDTH, - STRETCH_ASPECT_KEEP_HEIGHT, - }; - -private: - struct Group { - - Vector nodes; - //uint64_t last_tree_version; - bool changed; - Group() { changed = false; }; - }; - - Viewport *root; - - uint64_t tree_version; - float fixed_process_time; - float idle_process_time; - bool accept_quit; - bool quit_on_go_back; - uint32_t last_id; - -#ifdef TOOLS_ENABLED - bool editor_hint; -#endif -#ifdef DEBUG_ENABLED - bool debug_collisions_hint; - bool debug_navigation_hint; -#endif - bool pause; - int root_lock; - - Map group_map; - bool _quit; - bool initialized; - bool input_handled; - Size2 last_screen_size; - StringName tree_changed_name; - StringName node_removed_name; - - int64_t current_frame; - int node_count; - -#ifdef TOOLS_ENABLED - Node *edited_scene_root; -#endif - struct UGCall { - - StringName group; - StringName call; - - bool operator<(const UGCall &p_with) const { return group == p_with.group ? call < p_with.call : group < p_with.group; } - }; - - //safety for when a node is deleted while a group is being called - int call_lock; - Set call_skip; //skip erased nodes - - StretchMode stretch_mode; - StretchAspect stretch_aspect; - Size2i stretch_min; - - void _update_root_rect(); - - List delete_queue; - - Map > unique_group_calls; - bool ugc_locked; - void _flush_ugc(); - void _flush_transform_notifications(); - - _FORCE_INLINE_ void _update_group_order(Group &g); - void _update_listener(); - - Array _get_nodes_in_group(const StringName &p_group); - - Node *current_scene; - - Color debug_collisions_color; - Color debug_collision_contact_color; - Color debug_navigation_color; - Color debug_navigation_disabled_color; - Ref debug_contact_mesh; - Ref navigation_material; - Ref navigation_disabled_material; - Ref collision_material; - int collision_debug_contacts; - - void _change_scene(Node *p_to); - //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); - - List > timers; - - ///network/// - - enum NetworkCommands { - NETWORK_COMMAND_REMOTE_CALL, - NETWORK_COMMAND_REMOTE_SET, - NETWORK_COMMAND_SIMPLIFY_PATH, - NETWORK_COMMAND_CONFIRM_PATH, - }; - - Ref network_peer; - - Set connected_peers; - void _network_peer_connected(int p_id); - void _network_peer_disconnected(int p_id); - - void _connected_to_server(); - void _connection_failed(); - void _server_disconnected(); - - //path sent caches - struct PathSentCache { - Map confirmed_peers; - int id; - }; - - HashMap path_send_cache; - int last_send_cache_id; - - //path get caches - struct PathGetCache { - struct NodeInfo { - NodePath path; - ObjectID instance; - }; - - Map nodes; - }; - - Map path_get_cache; - - Vector packet_cache; - - void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); - void _network_poll(); - - static SceneTree *singleton; - friend class Node; - - void _rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); - - void tree_changed(); - void node_removed(Node *p_node); - - Group *add_to_group(const StringName &p_group, Node *p_node); - void remove_from_group(const StringName &p_group, Node *p_node); - - void _notify_group_pause(const StringName &p_group, int p_notification); - void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref &p_input); - Variant _call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - Variant _call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error); - - static void _debugger_request_tree(void *self); - void _flush_delete_queue(); - //optimization - friend class CanvasItem; - friend class Spatial; - friend class Viewport; - - SelfList::List xform_change_list; - -#ifdef DEBUG_ENABLED - - Map live_edit_node_path_cache; - Map live_edit_resource_cache; - - NodePath live_edit_root; - String live_edit_scene; - - Map > live_scene_edit_cache; - Map > live_edit_remove_list; - - ScriptDebugger::LiveEditFuncs live_edit_funcs; - - void _live_edit_node_path_func(const NodePath &p_path, int p_id); - void _live_edit_res_path_func(const String &p_path, int p_id); - - void _live_edit_node_set_func(int p_id, const StringName &p_prop, const Variant &p_value); - void _live_edit_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value); - void _live_edit_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void _live_edit_res_set_func(int p_id, const StringName &p_prop, const Variant &p_value); - void _live_edit_res_set_res_func(int p_id, const StringName &p_prop, const String &p_value); - void _live_edit_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); - void _live_edit_root_func(const NodePath &p_scene_path, const String &p_scene_from); - - void _live_edit_create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name); - void _live_edit_instance_node_func(const NodePath &p_parent, const String &p_path, const String &p_name); - void _live_edit_remove_node_func(const NodePath &p_at); - void _live_edit_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_keep_id); - void _live_edit_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_at_pos); - void _live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name); - void _live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); - - static void _live_edit_node_path_funcs(void *self, const NodePath &p_path, int p_id) { reinterpret_cast(self)->_live_edit_node_path_func(p_path, p_id); } - static void _live_edit_res_path_funcs(void *self, const String &p_path, int p_id) { reinterpret_cast(self)->_live_edit_res_path_func(p_path, p_id); } - - static void _live_edit_node_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast(self)->_live_edit_node_set_func(p_id, p_prop, p_value); } - static void _live_edit_node_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast(self)->_live_edit_node_set_res_func(p_id, p_prop, p_value); } - static void _live_edit_node_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_node_call_func(p_id, p_method, VARIANT_ARG_PASS); } - static void _live_edit_res_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast(self)->_live_edit_res_set_func(p_id, p_prop, p_value); } - static void _live_edit_res_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast(self)->_live_edit_res_set_res_func(p_id, p_prop, p_value); } - static void _live_edit_res_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_res_call_func(p_id, p_method, VARIANT_ARG_PASS); } - static void _live_edit_root_funcs(void *self, const NodePath &p_scene_path, const String &p_scene_from) { reinterpret_cast(self)->_live_edit_root_func(p_scene_path, p_scene_from); } - - static void _live_edit_create_node_funcs(void *self, const NodePath &p_parent, const String &p_type, const String &p_name) { reinterpret_cast(self)->_live_edit_create_node_func(p_parent, p_type, p_name); } - static void _live_edit_instance_node_funcs(void *self, const NodePath &p_parent, const String &p_path, const String &p_name) { reinterpret_cast(self)->_live_edit_instance_node_func(p_parent, p_path, p_name); } - static void _live_edit_remove_node_funcs(void *self, const NodePath &p_at) { reinterpret_cast(self)->_live_edit_remove_node_func(p_at); } - static void _live_edit_remove_and_keep_node_funcs(void *self, const NodePath &p_at, ObjectID p_keep_id) { reinterpret_cast(self)->_live_edit_remove_and_keep_node_func(p_at, p_keep_id); } - static void _live_edit_restore_node_funcs(void *self, ObjectID p_id, const NodePath &p_at, int p_at_pos) { reinterpret_cast(self)->_live_edit_restore_node_func(p_id, p_at, p_at_pos); } - static void _live_edit_duplicate_node_funcs(void *self, const NodePath &p_at, const String &p_new_name) { reinterpret_cast(self)->_live_edit_duplicate_node_func(p_at, p_new_name); } - static void _live_edit_reparent_node_funcs(void *self, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { reinterpret_cast(self)->_live_edit_reparent_node_func(p_at, p_new_place, p_new_name, p_at_pos); } - -#endif - - enum { - MAX_IDLE_CALLBACKS = 256 - }; - - static IdleCallback idle_callbacks[MAX_IDLE_CALLBACKS]; - static int idle_callback_count; - void _call_idle_callbacks(); - -protected: - void _notification(int p_notification); - static void _bind_methods(); - -public: - enum { - NOTIFICATION_TRANSFORM_CHANGED = 29 - }; - - enum CallGroupFlags { - GROUP_CALL_DEFAULT = 0, - GROUP_CALL_REVERSE = 1, - GROUP_CALL_REALTIME = 2, - GROUP_CALL_UNIQUE = 4, - GROUP_CALL_MULTILEVEL = 8, - }; - - _FORCE_INLINE_ Viewport *get_root() const { return root; } - - uint32_t get_last_event_id() const; - - void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); - void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); - void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value); - - void call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); - void notify_group(const StringName &p_group, int p_notification); - void set_group(const StringName &p_group, const String &p_name, const Variant &p_value); - - virtual void input_text(const String &p_text); - virtual void input_event(const Ref &p_event); - virtual void init(); - - virtual bool iteration(float p_time); - virtual bool idle(float p_time); - - virtual void finish(); - - void set_auto_accept_quit(bool p_enable); - void set_quit_on_go_back(bool p_enable); - - void quit(); - - void set_input_as_handled(); - bool is_input_handled(); - _FORCE_INLINE_ float get_fixed_process_time() const { return fixed_process_time; } - _FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; } - -#ifdef TOOLS_ENABLED - void set_editor_hint(bool p_enabled); - - bool is_editor_hint() const; - bool is_node_being_edited(const Node *p_node) const; -#else - void set_editor_hint(bool p_enabled) {} - - bool is_editor_hint() const { return false; } - bool is_node_being_edited(const Node *p_node) const { return false; } -#endif - - void set_pause(bool p_enabled); - bool is_paused() const; - - void set_camera(const RID &p_camera); - RID get_camera() const; - -#ifdef DEBUG_ENABLED - void set_debug_collisions_hint(bool p_enabled); - bool is_debugging_collisions_hint() const; - - void set_debug_navigation_hint(bool p_enabled); - bool is_debugging_navigation_hint() const; -#else - void set_debug_collisions_hint(bool p_enabled) {} - bool is_debugging_collisions_hint() const { return false; } - - void set_debug_navigation_hint(bool p_enabled) {} - bool is_debugging_navigation_hint() const { return false; } -#endif - - void set_debug_collisions_color(const Color &p_color); - Color get_debug_collisions_color() const; - - void set_debug_collision_contact_color(const Color &p_color); - Color get_debug_collision_contact_color() const; - - void set_debug_navigation_color(const Color &p_color); - Color get_debug_navigation_color() const; - - void set_debug_navigation_disabled_color(const Color &p_color); - Color get_debug_navigation_disabled_color() const; - - Ref get_debug_navigation_material(); - Ref get_debug_navigation_disabled_material(); - Ref get_debug_collision_material(); - Ref get_debug_contact_mesh(); - - int get_collision_debug_contact_count() { return collision_debug_contacts; } - - int64_t get_frame() const; - - int get_node_count() const; - - void queue_delete(Object *p_object); - - void get_nodes_in_group(const StringName &p_group, List *p_list); - bool has_group(const StringName &p_identifier) const; - - void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize); - -//void change_scene(const String& p_path); -//Node *get_loaded_scene(); - -#ifdef TOOLS_ENABLED - void set_edited_scene_root(Node *p_node); - Node *get_edited_scene_root() const; -#endif - - void set_current_scene(Node *p_scene); - Node *get_current_scene() const; - Error change_scene(const String &p_path); - Error change_scene_to(const Ref &p_scene); - Error reload_current_scene(); - - Ref create_timer(float p_delay_sec, bool p_process_pause = true); - - //used by Main::start, don't use otherwise - void add_current_scene(Node *p_current); - - static SceneTree *get_singleton() { return singleton; } - - void drop_files(const Vector &p_files, int p_from_screen = 0); - - //network API - - void set_network_peer(const Ref &p_network_peer); - bool is_network_server() const; - bool has_network_peer() const; - int get_network_unique_id() const; - - void set_refuse_new_network_connections(bool p_refuse); - bool is_refusing_new_network_connections() const; - - static void add_idle_callback(IdleCallback p_callback); - SceneTree(); - ~SceneTree(); -}; - -VARIANT_ENUM_CAST(SceneTree::StretchMode); -VARIANT_ENUM_CAST(SceneTree::StretchAspect); - -#endif diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp new file mode 100644 index 0000000000..39d5469360 --- /dev/null +++ b/scene/main/scene_tree.cpp @@ -0,0 +1,2427 @@ +/*************************************************************************/ +/* scene_main_loop.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 "scene_tree.h" + +#include "global_config.h" +#include "message_queue.h" +#include "node.h" +#include "os/keyboard.h" +#include "os/os.h" +#include "print_string.h" +#include +//#include "servers/spatial_sound_2d_server.h" + +#include "io/marshalls.h" +#include "io/resource_loader.h" +#include "scene/resources/material.h" +#include "scene/resources/mesh.h" +#include "scene/resources/packed_scene.h" +#include "scene/scene_string_names.h" +#include "servers/physics_2d_server.h" +#include "servers/physics_server.h" +#include "viewport.h" + +void SceneTreeTimer::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left); + ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left); + + ADD_SIGNAL(MethodInfo("timeout")); +} + +void SceneTreeTimer::set_time_left(float p_time) { + time_left = p_time; +} + +float SceneTreeTimer::get_time_left() const { + return time_left; +} + +void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) { + if (process_pause != p_pause_mode_process) { + process_pause = p_pause_mode_process; + } +} + +bool SceneTreeTimer::is_pause_mode_process() { + return process_pause; +} + +SceneTreeTimer::SceneTreeTimer() { + time_left = 0; + process_pause = true; +} + +void SceneTree::tree_changed() { + + tree_version++; + emit_signal(tree_changed_name); +} + +void SceneTree::node_removed(Node *p_node) { + + if (current_scene == p_node) { + current_scene = NULL; + } + emit_signal(node_removed_name, p_node); + if (call_lock > 0) + call_skip.insert(p_node); +} + +SceneTree::Group *SceneTree::add_to_group(const StringName &p_group, Node *p_node) { + + Map::Element *E = group_map.find(p_group); + if (!E) { + E = group_map.insert(p_group, Group()); + } + + if (E->get().nodes.find(p_node) != -1) { + ERR_EXPLAIN("Already in group: " + p_group); + ERR_FAIL_V(&E->get()); + } + E->get().nodes.push_back(p_node); + //E->get().last_tree_version=0; + E->get().changed = true; + return &E->get(); +} + +void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) { + + Map::Element *E = group_map.find(p_group); + ERR_FAIL_COND(!E); + + E->get().nodes.erase(p_node); + if (E->get().nodes.empty()) + group_map.erase(E); +} + +void SceneTree::_flush_transform_notifications() { + + SelfList *n = xform_change_list.first(); + while (n) { + + Node *node = n->self(); + SelfList *nx = n->next(); + xform_change_list.remove(n); + n = nx; + node->notification(NOTIFICATION_TRANSFORM_CHANGED); + } +} + +void SceneTree::_flush_ugc() { + + ugc_locked = true; + + while (unique_group_calls.size()) { + + Map >::Element *E = unique_group_calls.front(); + + Variant v[VARIANT_ARG_MAX]; + for (int i = 0; i < E->get().size(); i++) + v[i] = E->get()[i]; + + call_group_flags(GROUP_CALL_REALTIME, E->key().group, E->key().call, v[0], v[1], v[2], v[3], v[4]); + + unique_group_calls.erase(E); + } + + ugc_locked = false; +} + +void SceneTree::_update_group_order(Group &g) { + + if (!g.changed) + return; + if (g.nodes.empty()) + return; + + Node **nodes = &g.nodes[0]; + int node_count = g.nodes.size(); + + SortArray node_sort; + node_sort.sort(nodes, node_count); + g.changed = false; +} + +void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + Group &g = E->get(); + if (g.nodes.empty()) + return; + + if (p_call_flags & GROUP_CALL_UNIQUE && !(p_call_flags & GROUP_CALL_REALTIME)) { + + ERR_FAIL_COND(ugc_locked); + + UGCall ug; + ug.call = p_function; + ug.group = p_group; + + if (unique_group_calls.has(ug)) + return; + + VARIANT_ARGPTRS; + + Vector args; + for (int i = 0; i < VARIANT_ARG_MAX; i++) { + if (argptr[i]->get_type() == Variant::NIL) + break; + args.push_back(*argptr[i]); + } + + unique_group_calls[ug] = args; + return; + } + + _update_group_order(g); + + Vector nodes_copy = g.nodes; + Node **nodes = &nodes_copy[0]; + int node_count = nodes_copy.size(); + + call_lock++; + + if (p_call_flags & GROUP_CALL_REVERSE) { + + for (int i = node_count - 1; i >= 0; i--) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) { + if (p_call_flags & GROUP_CALL_MULTILEVEL) + nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); + else + nodes[i]->call(p_function, VARIANT_ARG_PASS); + } else + MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); + } + + } else { + + for (int i = 0; i < node_count; i++) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) { + if (p_call_flags & GROUP_CALL_MULTILEVEL) + nodes[i]->call_multilevel(p_function, VARIANT_ARG_PASS); + else + nodes[i]->call(p_function, VARIANT_ARG_PASS); + } else + MessageQueue::get_singleton()->push_call(nodes[i], p_function, VARIANT_ARG_PASS); + } + } + + call_lock--; + if (call_lock == 0) + call_skip.clear(); +} + +void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + Group &g = E->get(); + if (g.nodes.empty()) + return; + + _update_group_order(g); + + Vector nodes_copy = g.nodes; + Node **nodes = &nodes_copy[0]; + int node_count = nodes_copy.size(); + + call_lock++; + + if (p_call_flags & GROUP_CALL_REVERSE) { + + for (int i = node_count - 1; i >= 0; i--) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) + nodes[i]->notification(p_notification); + else + MessageQueue::get_singleton()->push_notification(nodes[i], p_notification); + } + + } else { + + for (int i = 0; i < node_count; i++) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) + nodes[i]->notification(p_notification); + else + MessageQueue::get_singleton()->push_notification(nodes[i], p_notification); + } + } + + call_lock--; + if (call_lock == 0) + call_skip.clear(); +} + +void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + Group &g = E->get(); + if (g.nodes.empty()) + return; + + _update_group_order(g); + + Vector nodes_copy = g.nodes; + Node **nodes = &nodes_copy[0]; + int node_count = nodes_copy.size(); + + call_lock++; + + if (p_call_flags & GROUP_CALL_REVERSE) { + + for (int i = node_count - 1; i >= 0; i--) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) + nodes[i]->set(p_name, p_value); + else + MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value); + } + + } else { + + for (int i = 0; i < node_count; i++) { + + if (call_lock && call_skip.has(nodes[i])) + continue; + + if (p_call_flags & GROUP_CALL_REALTIME) + nodes[i]->set(p_name, p_value); + else + MessageQueue::get_singleton()->push_set(nodes[i], p_name, p_value); + } + } + + call_lock--; + if (call_lock == 0) + call_skip.clear(); +} + +void SceneTree::call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_DECLARE) { + + call_group_flags(0, p_group, VARIANT_ARG_PASS); +} + +void SceneTree::notify_group(const StringName &p_group, int p_notification) { + + notify_group_flags(0, p_group, p_notification); +} + +void SceneTree::set_group(const StringName &p_group, const String &p_name, const Variant &p_value) { + + set_group_flags(0, p_group, p_name, p_value); +} + +void SceneTree::set_input_as_handled() { + + input_handled = true; +} + +void SceneTree::input_text(const String &p_text) { + + root_lock++; + + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input_text", p_text); //special one for GUI, as controls use their own process check + + root_lock--; +} + +bool SceneTree::is_input_handled() { + return input_handled; +} + +void SceneTree::input_event(const Ref &p_event) { + + if (is_editor_hint() && (p_event->cast_to() || p_event->cast_to())) + return; //avoid joy input on editor + + root_lock++; + //last_id=p_event.ID; + + input_handled = false; + + Ref ev = p_event; + ev->set_id(++last_id); //this should work better +#if 0 + switch(ev.type) { + + case InputEvent::MOUSE_BUTTON: { + + Matrix32 ai = root->get_final_transform().affine_inverse(); + Vector2 g = ai.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y)); + Vector2 l = ai.xform(Vector2(ev->get_pos().x,ev->get_pos().y)); + ev->get_pos().x=l.x; + ev->get_pos().y=l.y; + ev.mouse_button.global_x=g.x; + ev.mouse_button.global_y=g.y; + + } break; + case InputEvent::MOUSE_MOTION: { + + Matrix32 ai = root->get_final_transform().affine_inverse(); + Vector2 g = ai.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y)); + Vector2 l = ai.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y)); + Vector2 r = ai.xform(Vector2(ev->get_relative().x,ev->get_relative().y)); + ev.mouse_motion.x=l.x; + ev.mouse_motion.y=l.y; + ev.mouse_motion.global_x=g.x; + ev.mouse_motion.global_y=g.y; + ev->get_relative().x=r.x; + ev->get_relative().y=r.y; + + } break; + case InputEvent::SCREEN_TOUCH: { + + Matrix32 ai = root->get_final_transform().affine_inverse(); + Vector2 t = ai.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y)); + ev.screen_touch.x=t.x; + ev.screen_touch.y=t.y; + + } break; + case InputEvent::SCREEN_DRAG: { + + Matrix32 ai = root->get_final_transform().affine_inverse(); + Vector2 t = ai.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y)); + Vector2 r = ai.xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); + Vector2 s = ai.xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y)); + ev.screen_drag.x=t.x; + ev.screen_drag.y=t.y; + ev.screen_drag.relative_x=r.x; + ev.screen_drag.relative_y=r.y; + ev.screen_drag.speed_x=s.x; + ev.screen_drag.speed_y=s.y; + } break; + } + +#endif + + MainLoop::input_event(ev); +#if 0 + _call_input_pause("input","_input",ev); + + call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"_gui_input","_gui_input",p_event); //special one for GUI, as controls use their own process check + + //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"input","_input",ev); + + /* + if (ev.type==InputEvent::KEY && ev->is_pressed() && !ev->is_echo() && ev->get_scancode()==KEY_F12) { + + print_line("RAM: "+itos(Memory::get_static_mem_usage())); + print_line("DRAM: "+itos(Memory::get_dynamic_mem_usage())); + } + if (ev.type==InputEvent::KEY && ev->is_pressed() && !ev->is_echo() && ev->get_scancode()==KEY_F11) { + + Memory::dump_static_mem_to_file("memdump.txt"); + } + */ + + //transform for the rest +#else + + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_input", ev); //special one for GUI, as controls use their own process check + +#endif + + if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_remote()) { + //quit from game window using F8 + Ref k = ev; + if (k.is_valid() && k->is_pressed() && !k->is_echo() && k->get_scancode() == KEY_F8) { + ScriptDebugger::get_singleton()->request_quit(); + } + } + + _flush_ugc(); + root_lock--; + MessageQueue::get_singleton()->flush(); //small little hack + + root_lock++; + + if (!input_handled) { + +#if 0 + _call_input_pause("unhandled_input","_unhandled_input",ev); + //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev); + if (!input_handled && ev.type==InputEvent::KEY) { + _call_input_pause("unhandled_key_input","_unhandled_key_input",ev); + //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev); + } +#else + + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_vp_unhandled_input", ev); //special one for GUI, as controls use their own process check + +#endif + input_handled = true; + _flush_ugc(); + root_lock--; + MessageQueue::get_singleton()->flush(); //small little hack + } else { + input_handled = true; + root_lock--; + } + + _call_idle_callbacks(); +} + +void SceneTree::init() { + + //_quit=false; + initialized = true; + input_handled = false; + + pause = false; + + root->_set_tree(this); + MainLoop::init(); +} + +bool SceneTree::iteration(float p_time) { + + root_lock++; + + current_frame++; + + _flush_transform_notifications(); + + MainLoop::iteration(p_time); + fixed_process_time = p_time; + + emit_signal("fixed_frame"); + + _notify_group_pause("fixed_process_internal", Node::NOTIFICATION_INTERNAL_FIXED_PROCESS); + _notify_group_pause("fixed_process", Node::NOTIFICATION_FIXED_PROCESS); + _flush_ugc(); + _flush_transform_notifications(); + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); + root_lock--; + + _flush_delete_queue(); + _call_idle_callbacks(); + + return _quit; +} + +bool SceneTree::idle(float p_time) { + + //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); + //print_line("node count: "+itos(get_node_count())); + //print_line("TEXTURE RAM: "+itos(VS::get_singleton()->get_render_info(VS::INFO_TEXTURE_MEM_USED))); + + root_lock++; + + MainLoop::idle(p_time); + + idle_process_time = p_time; + + _network_poll(); + + emit_signal("idle_frame"); + + _flush_transform_notifications(); + + _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); + _notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS); + + Size2 win_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); + if (win_size != last_screen_size) { + + last_screen_size = win_size; + _update_root_rect(); + + emit_signal("screen_resized"); + } + + _flush_ugc(); + _flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); + + root_lock--; + + _flush_delete_queue(); + + //go through timers + + for (List >::Element *E = timers.front(); E;) { + + List >::Element *N = E->next(); + if (pause && !E->get()->is_pause_mode_process()) { + E = N; + continue; + } + float time_left = E->get()->get_time_left(); + time_left -= p_time; + E->get()->set_time_left(time_left); + + if (time_left < 0) { + E->get()->emit_signal("timeout"); + timers.erase(E); + } + E = N; + } + + _call_idle_callbacks(); + +#ifdef TOOLS_ENABLED + + if (is_editor_hint()) { + //simple hack to reload fallback environment if it changed from editor + String env_path = GlobalConfig::get_singleton()->get("rendering/viewport/default_environment"); + env_path = env_path.strip_edges(); //user may have added a space or two + String cpath; + Ref fallback = get_root()->get_world()->get_fallback_environment(); + if (fallback.is_valid()) { + cpath = fallback->get_path(); + } + if (cpath != env_path) { + + if (env_path != String()) { + fallback = ResourceLoader::load(env_path); + } else { + fallback.unref(); + } + get_root()->get_world()->set_fallback_environment(fallback); + } + } + +#endif + + return _quit; +} + +void SceneTree::finish() { + + _flush_delete_queue(); + + _flush_ugc(); + + initialized = false; + + MainLoop::finish(); + + if (root) { + root->_set_tree(NULL); + memdelete(root); //delete root + } +} + +void SceneTree::quit() { + + _quit = true; +} + +void SceneTree::_notification(int p_notification) { + + switch (p_notification) { + + case NOTIFICATION_WM_QUIT_REQUEST: { + + get_root()->propagate_notification(p_notification); + + if (accept_quit) { + _quit = true; + break; + } + } break; + case NOTIFICATION_WM_GO_BACK_REQUEST: { + + get_root()->propagate_notification(p_notification); + + if (quit_on_go_back) { + _quit = true; + break; + } + } break; + case NOTIFICATION_OS_MEMORY_WARNING: + case NOTIFICATION_WM_FOCUS_IN: + case NOTIFICATION_WM_FOCUS_OUT: { + + get_root()->propagate_notification(p_notification); + } break; + case NOTIFICATION_TRANSLATION_CHANGED: { + get_root()->propagate_notification(Node::NOTIFICATION_TRANSLATION_CHANGED); + } break; + case NOTIFICATION_WM_UNFOCUS_REQUEST: { + + notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST); + + } break; + + default: + break; + }; +}; + +void SceneTree::set_auto_accept_quit(bool p_enable) { + + accept_quit = p_enable; +} + +void SceneTree::set_quit_on_go_back(bool p_enable) { + + quit_on_go_back = p_enable; +} + +#ifdef TOOLS_ENABLED +void SceneTree::set_editor_hint(bool p_enabled) { + + editor_hint = p_enabled; +} + +bool SceneTree::is_node_being_edited(const Node *p_node) const { + + return editor_hint && edited_scene_root && edited_scene_root->is_a_parent_of(p_node); +} + +bool SceneTree::is_editor_hint() const { + + return editor_hint; +} +#endif + +#ifdef DEBUG_ENABLED +void SceneTree::set_debug_collisions_hint(bool p_enabled) { + + debug_collisions_hint = p_enabled; +} + +bool SceneTree::is_debugging_collisions_hint() const { + + return debug_collisions_hint; +} + +void SceneTree::set_debug_navigation_hint(bool p_enabled) { + + debug_navigation_hint = p_enabled; +} + +bool SceneTree::is_debugging_navigation_hint() const { + + return debug_navigation_hint; +} +#endif + +void SceneTree::set_debug_collisions_color(const Color &p_color) { + + debug_collisions_color = p_color; +} + +Color SceneTree::get_debug_collisions_color() const { + + return debug_collisions_color; +} + +void SceneTree::set_debug_collision_contact_color(const Color &p_color) { + + debug_collision_contact_color = p_color; +} + +Color SceneTree::get_debug_collision_contact_color() const { + + return debug_collision_contact_color; +} + +void SceneTree::set_debug_navigation_color(const Color &p_color) { + + debug_navigation_color = p_color; +} + +Color SceneTree::get_debug_navigation_color() const { + + return debug_navigation_color; +} + +void SceneTree::set_debug_navigation_disabled_color(const Color &p_color) { + + debug_navigation_disabled_color = p_color; +} + +Color SceneTree::get_debug_navigation_disabled_color() const { + + return debug_navigation_disabled_color; +} + +Ref SceneTree::get_debug_navigation_material() { + + if (navigation_material.is_valid()) + return navigation_material; + + Ref line_material = Ref(memnew(SpatialMaterial)); + /* line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_color());*/ + + navigation_material = line_material; + + return navigation_material; +} + +Ref SceneTree::get_debug_navigation_disabled_material() { + + if (navigation_disabled_material.is_valid()) + return navigation_disabled_material; + + Ref line_material = Ref(memnew(SpatialMaterial)); + /* line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());*/ + + navigation_disabled_material = line_material; + + return navigation_disabled_material; +} +Ref SceneTree::get_debug_collision_material() { + + if (collision_material.is_valid()) + return collision_material; + + Ref line_material = Ref(memnew(SpatialMaterial)); + /*line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(SpatialMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collisions_color());*/ + + collision_material = line_material; + + return collision_material; +} + +Ref SceneTree::get_debug_contact_mesh() { + + if (debug_contact_mesh.is_valid()) + return debug_contact_mesh; + + debug_contact_mesh = Ref(memnew(ArrayMesh)); + + Ref mat = memnew(SpatialMaterial); + /*mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_fixed_flag(SpatialMaterial::FLAG_USE_ALPHA,true); + mat->set_parameter(SpatialMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());*/ + + Vector3 diamond[6] = { + Vector3(-1, 0, 0), + Vector3(1, 0, 0), + Vector3(0, -1, 0), + Vector3(0, 1, 0), + Vector3(0, 0, -1), + Vector3(0, 0, 1) + }; + + int diamond_faces[8 * 3] = { + 0, 2, 4, + 0, 3, 4, + 1, 2, 4, + 1, 3, 4, + 0, 2, 5, + 0, 3, 5, + 1, 2, 5, + 1, 3, 5, + }; + + PoolVector indices; + for (int i = 0; i < 8 * 3; i++) + indices.push_back(diamond_faces[i]); + + PoolVector vertices; + for (int i = 0; i < 6; i++) + vertices.push_back(diamond[i] * 0.1); + + Array arr; + arr.resize(Mesh::ARRAY_MAX); + arr[Mesh::ARRAY_VERTEX] = vertices; + arr[Mesh::ARRAY_INDEX] = indices; + + debug_contact_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr); + debug_contact_mesh->surface_set_material(0, mat); + + return debug_contact_mesh; +} + +void SceneTree::set_pause(bool p_enabled) { + + if (p_enabled == pause) + return; + pause = p_enabled; + PhysicsServer::get_singleton()->set_active(!p_enabled); + Physics2DServer::get_singleton()->set_active(!p_enabled); + if (get_root()) + get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED); +} + +bool SceneTree::is_paused() const { + + return pause; +} + +void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref &p_input) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + Group &g = E->get(); + if (g.nodes.empty()) + return; + + _update_group_order(g); + + //copy, so copy on write happens in case something is removed from process while being called + //performance is not lost because only if something is added/removed the vector is copied. + Vector nodes_copy = g.nodes; + + int node_count = nodes_copy.size(); + Node **nodes = &nodes_copy[0]; + + Variant arg = p_input; + const Variant *v[1] = { &arg }; + + call_lock++; + + for (int i = node_count - 1; i >= 0; i--) { + + if (input_handled) + break; + + Node *n = nodes[i]; + if (call_lock && call_skip.has(n)) + continue; + + if (!n->can_process()) + continue; + + Variant::CallError ce; + n->call_multilevel(p_method, (const Variant **)v, 1); + //ERR_FAIL_COND(node_count != g.nodes.size()); + } + + call_lock--; + if (call_lock == 0) + call_skip.clear(); +} + +void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + Group &g = E->get(); + if (g.nodes.empty()) + return; + + _update_group_order(g); + + //copy, so copy on write happens in case something is removed from process while being called + //performance is not lost because only if something is added/removed the vector is copied. + Vector nodes_copy = g.nodes; + + int node_count = nodes_copy.size(); + Node **nodes = &nodes_copy[0]; + + call_lock++; + + for (int i = 0; i < node_count; i++) { + + Node *n = nodes[i]; + if (call_lock && call_skip.has(n)) + continue; + + if (!n->can_process()) + continue; + + n->notification(p_notification); + //ERR_FAIL_COND(node_count != g.nodes.size()); + } + + call_lock--; + if (call_lock == 0) + call_skip.clear(); +} + +/* +void SceneMainLoop::_update_listener_2d() { + + if (listener_2d.is_valid()) { + + SpatialSound2DServer::get_singleton()->listener_set_space( listener_2d, world_2d->get_sound_space() ); + } + +} +*/ + +uint32_t SceneTree::get_last_event_id() const { + + return last_id; +} + +Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + r_error.error = Variant::CallError::CALL_OK; + + ERR_FAIL_COND_V(p_argcount < 3, Variant()); + ERR_FAIL_COND_V(!p_args[0]->is_num(), Variant()); + ERR_FAIL_COND_V(p_args[1]->get_type() != Variant::STRING, Variant()); + ERR_FAIL_COND_V(p_args[2]->get_type() != Variant::STRING, Variant()); + + int flags = *p_args[0]; + StringName group = *p_args[1]; + StringName method = *p_args[2]; + Variant v[VARIANT_ARG_MAX]; + + for (int i = 0; i < MIN(p_argcount - 3, 5); i++) { + + v[i] = *p_args[i + 3]; + } + + call_group_flags(flags, group, method, v[0], v[1], v[2], v[3], v[4]); + return Variant(); +} + +Variant SceneTree::_call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error) { + + r_error.error = Variant::CallError::CALL_OK; + + ERR_FAIL_COND_V(p_argcount < 2, Variant()); + ERR_FAIL_COND_V(p_args[0]->get_type() != Variant::STRING, Variant()); + ERR_FAIL_COND_V(p_args[1]->get_type() != Variant::STRING, Variant()); + + StringName group = *p_args[0]; + StringName method = *p_args[1]; + Variant v[VARIANT_ARG_MAX]; + + for (int i = 0; i < MIN(p_argcount - 2, 5); i++) { + + v[i] = *p_args[i + 2]; + } + + call_group_flags(0, group, method, v[0], v[1], v[2], v[3], v[4]); + return Variant(); +} + +int64_t SceneTree::get_frame() const { + + return current_frame; +} + +Array SceneTree::_get_nodes_in_group(const StringName &p_group) { + + Array ret; + Map::Element *E = group_map.find(p_group); + if (!E) + return ret; + + _update_group_order(E->get()); //update order just in case + int nc = E->get().nodes.size(); + if (nc == 0) + return ret; + + ret.resize(nc); + + Node **ptr = E->get().nodes.ptr(); + for (int i = 0; i < nc; i++) { + + ret[i] = ptr[i]; + } + + return ret; +} + +bool SceneTree::has_group(const StringName &p_identifier) const { + + return group_map.has(p_identifier); +} +void SceneTree::get_nodes_in_group(const StringName &p_group, List *p_list) { + + Map::Element *E = group_map.find(p_group); + if (!E) + return; + + _update_group_order(E->get()); //update order just in case + int nc = E->get().nodes.size(); + if (nc == 0) + return; + Node **ptr = E->get().nodes.ptr(); + for (int i = 0; i < nc; i++) { + + p_list->push_back(ptr[i]); + } +} + +static void _fill_array(Node *p_node, Array &array, int p_level) { + + array.push_back(p_level); + array.push_back(p_node->get_name()); + array.push_back(p_node->get_class()); + array.push_back(p_node->get_instance_ID()); + for (int i = 0; i < p_node->get_child_count(); i++) { + + _fill_array(p_node->get_child(i), array, p_level + 1); + } +} + +void SceneTree::_debugger_request_tree(void *self) { + + SceneTree *sml = (SceneTree *)self; + + Array arr; + _fill_array(sml->root, arr, 0); + ScriptDebugger::get_singleton()->send_message("scene_tree", arr); +} + +void SceneTree::_flush_delete_queue() { + + _THREAD_SAFE_METHOD_ + + while (delete_queue.size()) { + + Object *obj = ObjectDB::get_instance(delete_queue.front()->get()); + if (obj) { + memdelete(obj); + } + delete_queue.pop_front(); + } +} + +void SceneTree::queue_delete(Object *p_object) { + + _THREAD_SAFE_METHOD_ + ERR_FAIL_NULL(p_object); + p_object->_is_queued_for_deletion = true; + delete_queue.push_back(p_object->get_instance_ID()); +} + +int SceneTree::get_node_count() const { + + return node_count; +} + +void SceneTree::_update_root_rect() { + + if (stretch_mode == STRETCH_MODE_DISABLED) { + + root->set_size(last_screen_size); + root->set_attach_to_screen_rect(Rect2(Point2(), last_screen_size)); + root->set_size_override_stretch(false); + root->set_size_override(false, Size2()); + return; //user will take care + } + + //actual screen video mode + Size2 video_mode = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); + Size2 desired_res = stretch_min; + + Size2 viewport_size; + Size2 screen_size; + + float viewport_aspect = desired_res.aspect(); + float video_mode_aspect = video_mode.aspect(); + + if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) { + //same aspect or ignore aspect + viewport_size = desired_res; + screen_size = video_mode; + } else if (viewport_aspect < video_mode_aspect) { + // screen ratio is smaller vertically + + if (stretch_aspect == STRETCH_ASPECT_KEEP_HEIGHT) { + + //will stretch horizontally + viewport_size.x = desired_res.y * video_mode_aspect; + viewport_size.y = desired_res.y; + screen_size = video_mode; + + } else { + //will need black bars + viewport_size = desired_res; + screen_size.x = video_mode.y * viewport_aspect; + screen_size.y = video_mode.y; + } + } else { + //screen ratio is smaller horizontally + if (stretch_aspect == STRETCH_ASPECT_KEEP_WIDTH) { + + //will stretch horizontally + viewport_size.x = desired_res.x; + viewport_size.y = desired_res.x / video_mode_aspect; + screen_size = video_mode; + + } else { + //will need black bars + viewport_size = desired_res; + screen_size.x = video_mode.x; + screen_size.y = video_mode.x / viewport_aspect; + } + } + + screen_size = screen_size.floor(); + viewport_size = viewport_size.floor(); + + Size2 margin; + Size2 offset; + //black bars and margin + if (screen_size.x < video_mode.x) { + margin.x = Math::round((video_mode.x - screen_size.x) / 2.0); + VisualServer::get_singleton()->black_bars_set_margins(margin.x, 0, margin.x, 0); + offset.x = Math::round(margin.x * viewport_size.y / screen_size.y); + } else if (screen_size.y < video_mode.y) { + + margin.y = Math::round((video_mode.y - screen_size.y) / 2.0); + VisualServer::get_singleton()->black_bars_set_margins(0, margin.y, 0, margin.y); + offset.y = Math::round(margin.y * viewport_size.x / screen_size.x); + } else { + VisualServer::get_singleton()->black_bars_set_margins(0, 0, 0, 0); + } + + //print_line("VP SIZE: "+viewport_size+" OFFSET: "+offset+" = "+(offset*2+viewport_size)); + //print_line("SS: "+video_mode); + switch (stretch_mode) { + case STRETCH_MODE_2D: { + + root->set_size(screen_size); + root->set_attach_to_screen_rect(Rect2(margin, screen_size)); + root->set_size_override_stretch(true); + root->set_size_override(true, viewport_size); + + } break; + case STRETCH_MODE_VIEWPORT: { + + root->set_size(viewport_size); + root->set_attach_to_screen_rect(Rect2(margin, screen_size)); + root->set_size_override_stretch(false); + root->set_size_override(false, Size2()); + + } break; + } +} + +void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize) { + + stretch_mode = p_mode; + stretch_aspect = p_aspect; + stretch_min = p_minsize; + _update_root_rect(); +} + +#ifdef TOOLS_ENABLED +void SceneTree::set_edited_scene_root(Node *p_node) { + edited_scene_root = p_node; +} + +Node *SceneTree::get_edited_scene_root() const { + + return edited_scene_root; +} +#endif + +void SceneTree::set_current_scene(Node *p_scene) { + + ERR_FAIL_COND(p_scene && p_scene->get_parent() != root); + current_scene = p_scene; +} + +Node *SceneTree::get_current_scene() const { + + return current_scene; +} + +void SceneTree::_change_scene(Node *p_to) { + + if (current_scene) { + memdelete(current_scene); + current_scene = NULL; + } + + if (p_to) { + current_scene = p_to; + root->add_child(p_to); + } +} + +Error SceneTree::change_scene(const String &p_path) { + + Ref new_scene = ResourceLoader::load(p_path); + if (new_scene.is_null()) + return ERR_CANT_OPEN; + + return change_scene_to(new_scene); +} +Error SceneTree::change_scene_to(const Ref &p_scene) { + + Node *new_scene = NULL; + if (p_scene.is_valid()) { + new_scene = p_scene->instance(); + ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); + } + + call_deferred("_change_scene", new_scene); + return OK; +} +Error SceneTree::reload_current_scene() { + + ERR_FAIL_COND_V(!current_scene, ERR_UNCONFIGURED); + String fname = current_scene->get_filename(); + return change_scene(fname); +} + +void SceneTree::add_current_scene(Node *p_current) { + + current_scene = p_current; + root->add_child(p_current); +} +#ifdef DEBUG_ENABLED + +void SceneTree::_live_edit_node_path_func(const NodePath &p_path, int p_id) { + + live_edit_node_path_cache[p_id] = p_path; +} + +void SceneTree::_live_edit_res_path_func(const String &p_path, int p_id) { + + live_edit_resource_cache[p_id] = p_path; +} + +void SceneTree::_live_edit_node_set_func(int p_id, const StringName &p_prop, const Variant &p_value) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->set(p_prop, p_value); + } +} + +void SceneTree::_live_edit_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_node_set_func(p_id, p_prop, r); +} +void SceneTree::_live_edit_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->call(p_method, VARIANT_ARG_PASS); + } +} +void SceneTree::_live_edit_res_set_func(int p_id, const StringName &p_prop, const Variant &p_value) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->set(p_prop, p_value); +} +void SceneTree::_live_edit_res_set_res_func(int p_id, const StringName &p_prop, const String &p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_res_set_func(p_id, p_prop, r); +} +void SceneTree::_live_edit_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->call(p_method, VARIANT_ARG_PASS); +} + +void SceneTree::_live_edit_root_func(const NodePath &p_scene_path, const String &p_scene_from) { + + live_edit_root = p_scene_path; + live_edit_scene = p_scene_from; +} + +void SceneTree::_live_edit_create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + Object *o = ClassDB::instance(p_type); + if (!o) + continue; + Node *no = o->cast_to(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_instance_node_func(const NodePath &p_parent, const String &p_path, const String &p_name) { + + Ref ps = ResourceLoader::load(p_path); + + if (!ps.is_valid()) + return; + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + Node *no = ps->instance(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_remove_node_func(const NodePath &p_at) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F;) { + + Set::Element *N = F->next(); + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + memdelete(n2); + + F = N; + } +} +void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_keep_id) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F;) { + + Set::Element *N = F->next(); + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + + Node *n2 = n->get_node(p_at); + + n2->get_parent()->remove_child(n2); + + live_edit_remove_list[n][p_keep_id] = n2; + + F = N; + } +} +void SceneTree::_live_edit_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_at_pos) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F;) { + + Set::Element *N = F->next(); + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Map >::Element *EN = live_edit_remove_list.find(n); + + if (!EN) + continue; + + Map::Element *FN = EN->get().find(p_id); + + if (!FN) + continue; + n2->add_child(FN->get()); + + EN->get().erase(FN); + + if (EN->get().size() == 0) { + live_edit_remove_list.erase(EN); + } + + F = N; + } +} +void SceneTree::_live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Node *dup = n2->duplicate(true); + + if (!dup) + continue; + + dup->set_name(p_new_name); + n2->get_parent()->add_child(dup); + } +} +void SceneTree::_live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map >::Element *E = live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for (Set::Element *F = E->get().front(); F; F = F->next()) { + + Node *n = F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *nfrom = n->get_node(p_at); + + if (!n->has_node(p_new_place)) + continue; + Node *nto = n->get_node(p_new_place); + + nfrom->get_parent()->remove_child(nfrom); + nfrom->set_name(p_new_name); + + nto->add_child(nfrom); + if (p_at_pos >= 0) + nto->move_child(nfrom, p_at_pos); + } +} + +#endif + +void SceneTree::drop_files(const Vector &p_files, int p_from_screen) { + + emit_signal("files_dropped", p_files, p_from_screen); + MainLoop::drop_files(p_files, p_from_screen); +} + +Ref SceneTree::create_timer(float p_delay_sec, bool p_process_pause) { + + Ref stt; + stt.instance(); + stt->set_pause_mode_process(p_process_pause); + stt->set_time_left(p_delay_sec); + timers.push_back(stt); + return stt; +} + +void SceneTree::_network_peer_connected(int p_id) { + + connected_peers.insert(p_id); + path_get_cache.insert(p_id, PathGetCache()); + + emit_signal("network_peer_connected", p_id); +} + +void SceneTree::_network_peer_disconnected(int p_id) { + + connected_peers.erase(p_id); + path_get_cache.erase(p_id); //I no longer need your cache, sorry + emit_signal("network_peer_disconnected", p_id); +} + +void SceneTree::_connected_to_server() { + + emit_signal("connected_to_server"); +} + +void SceneTree::_connection_failed() { + + emit_signal("connection_failed"); +} + +void SceneTree::_server_disconnected() { + + emit_signal("server_disconnected"); +} + +void SceneTree::set_network_peer(const Ref &p_network_peer) { + if (network_peer.is_valid()) { + network_peer->disconnect("peer_connected", this, "_network_peer_connected"); + network_peer->disconnect("peer_disconnected", this, "_network_peer_disconnected"); + network_peer->disconnect("connection_succeeded", this, "_connected_to_server"); + network_peer->disconnect("connection_failed", this, "_connection_failed"); + network_peer->disconnect("server_disconnected", this, "_server_disconnected"); + connected_peers.clear(); + path_get_cache.clear(); + path_send_cache.clear(); + last_send_cache_id = 1; + } + + ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected."); + ERR_FAIL_COND(p_network_peer.is_valid() && p_network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED); + + network_peer = p_network_peer; + + if (network_peer.is_valid()) { + network_peer->connect("peer_connected", this, "_network_peer_connected"); + network_peer->connect("peer_disconnected", this, "_network_peer_disconnected"); + network_peer->connect("connection_succeeded", this, "_connected_to_server"); + network_peer->connect("connection_failed", this, "_connection_failed"); + network_peer->connect("server_disconnected", this, "_server_disconnected"); + } +} + +bool SceneTree::is_network_server() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), false); + return network_peer->is_server(); +} + +bool SceneTree::has_network_peer() const { + return network_peer.is_valid(); +} + +int SceneTree::get_network_unique_id() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), 0); + return network_peer->get_unique_id(); +} + +void SceneTree::set_refuse_new_network_connections(bool p_refuse) { + ERR_FAIL_COND(!network_peer.is_valid()); + network_peer->set_refuse_new_connections(p_refuse); +} + +bool SceneTree::is_refusing_new_network_connections() const { + + ERR_FAIL_COND_V(!network_peer.is_valid(), false); + + return network_peer->is_refusing_new_connections(); +} + +void SceneTree::_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { + + if (network_peer.is_null()) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) { + ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree."); + ERR_FAIL(); + } + + if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { + ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected."); + ERR_FAIL(); + } + + if (p_argcount > 255) { + ERR_EXPLAIN("Too many arguments >255."); + ERR_FAIL(); + } + + if (p_to != 0 && !connected_peers.has(ABS(p_to))) { + if (p_to == get_network_unique_id()) { + ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(get_network_unique_id())); + } else { + ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to)); + } + + ERR_FAIL(); + } + + NodePath from_path = p_from->get_path(); + ERR_FAIL_COND(from_path.is_empty()); + + //see if the path is cached + PathSentCache *psc = path_send_cache.getptr(from_path); + if (!psc) { + //path is not cached, create + path_send_cache[from_path] = PathSentCache(); + psc = path_send_cache.getptr(from_path); + psc->id = last_send_cache_id++; + } + + //create base packet, lots of harcode because it must be tight + + int ofs = 0; + +#define MAKE_ROOM(m_amount) \ + if (packet_cache.size() < m_amount) packet_cache.resize(m_amount); + + //encode type + MAKE_ROOM(1); + packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + ofs += 1; + + //encode ID + MAKE_ROOM(ofs + 4); + encode_uint32(psc->id, &packet_cache[ofs]); + ofs += 4; + + //encode function name + CharString name = String(p_name).utf8(); + int len = encode_cstring(name.get_data(), NULL); + MAKE_ROOM(ofs + len); + encode_cstring(name.get_data(), &packet_cache[ofs]); + ofs += len; + + if (p_set) { + //set argument + Error err = encode_variant(*p_arg[0], NULL, len); + ERR_FAIL_COND(err != OK); + MAKE_ROOM(ofs + len); + encode_variant(*p_arg[0], &packet_cache[ofs], len); + ofs += len; + + } else { + //call arguments + MAKE_ROOM(ofs + 1); + packet_cache[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + Error err = encode_variant(*p_arg[i], NULL, len); + ERR_FAIL_COND(err != OK); + MAKE_ROOM(ofs + len); + encode_variant(*p_arg[i], &packet_cache[ofs], len); + ofs += len; + } + } + + //see if all peers have cached path (is so, call can be fast) + bool has_all_peers = true; + + List peers_to_add; //if one is missing, take note to add it + + for (Set::Element *E = connected_peers.front(); E; E = E->next()) { + + if (p_to < 0 && E->get() == -p_to) + continue; //continue, excluded + + if (p_to > 0 && E->get() != p_to) + continue; //continue, not for this peer + + Map::Element *F = psc->confirmed_peers.find(E->get()); + + if (!F || F->get() == false) { + //path was not cached, or was cached but is unconfirmed + if (!F) { + //not cached at all, take note + peers_to_add.push_back(E->get()); + } + + has_all_peers = false; + } + } + + //those that need to be added, send a message for this + + for (List::Element *E = peers_to_add.front(); E; E = E->next()) { + + //encode function name + CharString pname = String(from_path).utf8(); + int len = encode_cstring(pname.get_data(), NULL); + + Vector packet; + + packet.resize(1 + 4 + len); + packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH; + encode_uint32(psc->id, &packet[1]); + encode_cstring(pname.get_data(), &packet[5]); + + network_peer->set_target_peer(E->get()); //to all of you + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->put_packet(packet.ptr(), packet.size()); + + psc->confirmed_peers.insert(E->get(), false); //insert into confirmed, but as false since it was not confirmed + } + + //take chance and set transfer mode, since all send methods will use it + network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + + if (has_all_peers) { + + //they all have verified paths, so send fast + network_peer->set_target_peer(p_to); //to all of you + network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love + } else { + //not all verified path, so send one by one + + //apend path at the end, since we will need it for some packets + CharString pname = String(from_path).utf8(); + int path_len = encode_cstring(pname.get_data(), NULL); + MAKE_ROOM(ofs + path_len); + encode_cstring(pname.get_data(), &packet_cache[ofs]); + + for (Set::Element *E = connected_peers.front(); E; E = E->next()) { + + if (p_to < 0 && E->get() == -p_to) + continue; //continue, excluded + + if (p_to > 0 && E->get() != p_to) + continue; //continue, not for this peer + + Map::Element *F = psc->confirmed_peers.find(E->get()); + ERR_CONTINUE(!F); //should never happen + + network_peer->set_target_peer(E->get()); //to this one specifically + + if (F->get() == true) { + //this one confirmed path, so use id + encode_uint32(psc->id, &packet_cache[1]); + network_peer->put_packet(packet_cache.ptr(), ofs); + } else { + //this one did not confirm path yet, so use entire path (sorry!) + encode_uint32(0x80000000 | ofs, &packet_cache[1]); //offset to path and flag + network_peer->put_packet(packet_cache.ptr(), ofs + path_len); + } + } + } +} + +void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) { + + ERR_FAIL_COND(p_packet_len < 5); + + uint8_t packet_type = p_packet[0]; + + switch (packet_type) { + + case NETWORK_COMMAND_REMOTE_CALL: + case NETWORK_COMMAND_REMOTE_SET: { + + ERR_FAIL_COND(p_packet_len < 5); + uint32_t target = decode_uint32(&p_packet[1]); + + Node *node = NULL; + + if (target & 0x80000000) { + + int ofs = target & 0x7FFFFFFF; + ERR_FAIL_COND(ofs >= p_packet_len); + + String paths; + paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs); + + NodePath np = paths; + + node = get_root()->get_node(np); + if (node == NULL) { + ERR_EXPLAIN("Failed to get path from RPC: " + String(np)); + ERR_FAIL_COND(node == NULL); + } + } else { + + int id = target; + + Map::Element *E = path_get_cache.find(p_from); + ERR_FAIL_COND(!E); + + Map::Element *F = E->get().nodes.find(id); + ERR_FAIL_COND(!F); + + PathGetCache::NodeInfo *ni = &F->get(); + //do proper caching later + + node = get_root()->get_node(ni->path); + if (node == NULL) { + ERR_EXPLAIN("Failed to get cached path from RPC: " + String(ni->path)); + ERR_FAIL_COND(node == NULL); + } + } + + ERR_FAIL_COND(p_packet_len < 6); + + //detect cstring end + int len_end = 5; + for (; len_end < p_packet_len; len_end++) { + if (p_packet[len_end] == 0) { + break; + } + } + + ERR_FAIL_COND(len_end >= p_packet_len); + + StringName name = String::utf8((const char *)&p_packet[5]); + + if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { + + if (!node->can_call_rpc(name)) + return; + + int ofs = len_end + 1; + + ERR_FAIL_COND(ofs >= p_packet_len); + + int argc = p_packet[ofs]; + Vector args; + Vector argp; + args.resize(argc); + argp.resize(argc); + + ofs++; + + for (int i = 0; i < argc; i++) { + + ERR_FAIL_COND(ofs >= p_packet_len); + int vlen; + Error err = decode_variant(args[i], &p_packet[ofs], p_packet_len - ofs, &vlen); + ERR_FAIL_COND(err != OK); + //args[i]=p_packet[3+i]; + argp[i] = &args[i]; + ofs += vlen; + } + + Variant::CallError ce; + + node->call(name, argp.ptr(), argc, ce); + if (ce.error != Variant::CallError::CALL_OK) { + String error = Variant::get_call_error_text(node, name, argp.ptr(), argc, ce); + error = "RPC - " + error; + ERR_PRINTS(error); + } + + } else { + + if (!node->can_call_rset(name)) + return; + + int ofs = len_end + 1; + + ERR_FAIL_COND(ofs >= p_packet_len); + + Variant value; + decode_variant(value, &p_packet[ofs], p_packet_len - ofs); + + bool valid; + + node->set(name, value, &valid); + if (!valid) { + String error = "Error setting remote property '" + String(name) + "', not found in object of type " + node->get_class(); + ERR_PRINTS(error); + } + } + + } break; + case NETWORK_COMMAND_SIMPLIFY_PATH: { + + ERR_FAIL_COND(p_packet_len < 5); + int id = decode_uint32(&p_packet[1]); + + String paths; + paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5); + + NodePath path = paths; + + if (!path_get_cache.has(p_from)) { + path_get_cache[p_from] = PathGetCache(); + } + + PathGetCache::NodeInfo ni; + ni.path = path; + ni.instance = 0; + + path_get_cache[p_from].nodes[id] = ni; + + { + //send ack + + //encode path + CharString pname = String(path).utf8(); + int len = encode_cstring(pname.get_data(), NULL); + + Vector packet; + + packet.resize(1 + len); + packet[0] = NETWORK_COMMAND_CONFIRM_PATH; + encode_cstring(pname.get_data(), &packet[1]); + + network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_target_peer(p_from); + network_peer->put_packet(packet.ptr(), packet.size()); + } + } break; + case NETWORK_COMMAND_CONFIRM_PATH: { + + String paths; + paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1); + + NodePath path = paths; + + PathSentCache *psc = path_send_cache.getptr(path); + ERR_FAIL_COND(!psc); + + Map::Element *E = psc->confirmed_peers.find(p_from); + ERR_FAIL_COND(!E); + E->get() = true; + } break; + } +} + +void SceneTree::_network_poll() { + + if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) + return; + + network_peer->poll(); + + if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here + return; + + while (network_peer->get_available_packet_count()) { + + int sender = network_peer->get_packet_peer(); + const uint8_t *packet; + int len; + + Error err = network_peer->get_packet(&packet, len); + if (err != OK) { + ERR_PRINT("Error getting packet!"); + } + + _network_process_packet(sender, packet, len); + + if (!network_peer.is_valid()) { + break; //it's also possible that a packet or RPC caused a disconnection, so also check here + } + } +} + +void SceneTree::_bind_methods() { + + //ClassDB::bind_method(D_METHOD("call_group","call_flags","group","method","arg1","arg2"),&SceneMainLoop::_call_group,DEFVAL(Variant()),DEFVAL(Variant())); + + ClassDB::bind_method(D_METHOD("get_root:Viewport"), &SceneTree::get_root); + ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group); + + ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit); + + ClassDB::bind_method(D_METHOD("set_editor_hint", "enable"), &SceneTree::set_editor_hint); + ClassDB::bind_method(D_METHOD("is_editor_hint"), &SceneTree::is_editor_hint); + ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint); + ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint); + ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint); + ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint); + +#ifdef TOOLS_ENABLED + ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root); + ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root); +#endif + + ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); + ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); + ClassDB::bind_method(D_METHOD("set_input_as_handled"), &SceneTree::set_input_as_handled); + ClassDB::bind_method(D_METHOD("is_input_handled"), &SceneTree::is_input_handled); + + ClassDB::bind_method(D_METHOD("create_timer:SceneTreeTimer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true)); + + ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count); + ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); + ClassDB::bind_method(D_METHOD("quit"), &SceneTree::quit); + + ClassDB::bind_method(D_METHOD("set_screen_stretch", "mode", "aspect", "minsize"), &SceneTree::set_screen_stretch); + + ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); + + MethodInfo mi; + mi.name = "call_group_flags"; + mi.arguments.push_back(PropertyInfo(Variant::INT, "flags")); + mi.arguments.push_back(PropertyInfo(Variant::STRING, "group")); + mi.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group_flags", &SceneTree::_call_group_flags, mi); + + ClassDB::bind_method(D_METHOD("notify_group_flags", "call_flags", "group", "notification"), &SceneTree::notify_group_flags); + ClassDB::bind_method(D_METHOD("set_group_flags", "call_flags", "group", "property", "value"), &SceneTree::set_group_flags); + + MethodInfo mi2; + mi2.name = "call_group"; + mi2.arguments.push_back(PropertyInfo(Variant::STRING, "group")); + mi2.arguments.push_back(PropertyInfo(Variant::STRING, "method")); + + ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "call_group", &SceneTree::_call_group, mi2); + + ClassDB::bind_method(D_METHOD("notify_group", "call_flags", "group", "notification"), &SceneTree::notify_group); + ClassDB::bind_method(D_METHOD("set_group", "call_flags", "group", "property", "value"), &SceneTree::set_group); + + ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group); + + ClassDB::bind_method(D_METHOD("set_current_scene", "child_node:Node"), &SceneTree::set_current_scene); + ClassDB::bind_method(D_METHOD("get_current_scene:Node"), &SceneTree::get_current_scene); + + ClassDB::bind_method(D_METHOD("change_scene", "path"), &SceneTree::change_scene); + ClassDB::bind_method(D_METHOD("change_scene_to", "packed_scene:PackedScene"), &SceneTree::change_scene_to); + + ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene); + + ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene); + + ClassDB::bind_method(D_METHOD("set_network_peer", "peer:NetworkedMultiplayerPeer"), &SceneTree::set_network_peer); + ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); + ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); + ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id); + ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); + ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); + ClassDB::bind_method(D_METHOD("_network_peer_connected"), &SceneTree::_network_peer_connected); + ClassDB::bind_method(D_METHOD("_network_peer_disconnected"), &SceneTree::_network_peer_disconnected); + ClassDB::bind_method(D_METHOD("_connected_to_server"), &SceneTree::_connected_to_server); + ClassDB::bind_method(D_METHOD("_connection_failed"), &SceneTree::_connection_failed); + ClassDB::bind_method(D_METHOD("_server_disconnected"), &SceneTree::_server_disconnected); + + ADD_SIGNAL(MethodInfo("tree_changed")); + ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node"))); + ADD_SIGNAL(MethodInfo("screen_resized")); + ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node"))); + + ADD_SIGNAL(MethodInfo("idle_frame")); + ADD_SIGNAL(MethodInfo("fixed_frame")); + + ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); + ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("connected_to_server")); + ADD_SIGNAL(MethodInfo("connection_failed")); + ADD_SIGNAL(MethodInfo("server_disconnected")); + + BIND_CONSTANT(GROUP_CALL_DEFAULT); + BIND_CONSTANT(GROUP_CALL_REVERSE); + BIND_CONSTANT(GROUP_CALL_REALTIME); + BIND_CONSTANT(GROUP_CALL_UNIQUE); + + BIND_CONSTANT(STRETCH_MODE_DISABLED); + BIND_CONSTANT(STRETCH_MODE_2D); + BIND_CONSTANT(STRETCH_MODE_VIEWPORT); + BIND_CONSTANT(STRETCH_ASPECT_IGNORE); + BIND_CONSTANT(STRETCH_ASPECT_KEEP); + BIND_CONSTANT(STRETCH_ASPECT_KEEP_WIDTH); + BIND_CONSTANT(STRETCH_ASPECT_KEEP_HEIGHT); +} + +SceneTree *SceneTree::singleton = NULL; + +SceneTree::IdleCallback SceneTree::idle_callbacks[SceneTree::MAX_IDLE_CALLBACKS]; +int SceneTree::idle_callback_count = 0; + +void SceneTree::_call_idle_callbacks() { + + for (int i = 0; i < idle_callback_count; i++) { + idle_callbacks[i](); + } +} + +void SceneTree::add_idle_callback(IdleCallback p_callback) { + ERR_FAIL_COND(idle_callback_count >= MAX_IDLE_CALLBACKS); + idle_callbacks[idle_callback_count++] = p_callback; +} + +SceneTree::SceneTree() { + + singleton = this; + _quit = false; + accept_quit = true; + quit_on_go_back = true; + initialized = false; +#ifdef TOOLS_ENABLED + editor_hint = false; +#endif +#ifdef DEBUG_ENABLED + debug_collisions_hint = false; + debug_navigation_hint = false; +#endif + debug_collisions_color = GLOBAL_DEF("debug/collision/shape_color", Color(0.0, 0.6, 0.7, 0.5)); + debug_collision_contact_color = GLOBAL_DEF("debug/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8)); + debug_navigation_color = GLOBAL_DEF("debug/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4)); + debug_navigation_disabled_color = GLOBAL_DEF("debug/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4)); + collision_debug_contacts = GLOBAL_DEF("debug/collision/max_contacts_displayed", 10000); + + tree_version = 1; + fixed_process_time = 1; + idle_process_time = 1; + last_id = 1; + root = NULL; + current_frame = 0; + tree_changed_name = "tree_changed"; + node_removed_name = "node_removed"; + ugc_locked = false; + call_lock = 0; + root_lock = 0; + node_count = 0; + + //create with mainloop + + root = memnew(Viewport); + root->set_name("root"); + if (!root->get_world().is_valid()) + root->set_world(Ref(memnew(World))); + + //root->set_world_2d( Ref( memnew( World2D ))); + root->set_as_audio_listener(true); + root->set_as_audio_listener_2d(true); + current_scene = NULL; + + int ref_atlas_size = GLOBAL_DEF("rendering/reflections/atlas_size", 2048); + int ref_atlas_subdiv = GLOBAL_DEF("rendering/reflections/atlas_subdiv", 8); + int msaa_mode = GLOBAL_DEF("rendering/quality/msaa", 0); + GlobalConfig::get_singleton()->set_custom_property_info("rendering/quality/msaa", PropertyInfo(Variant::INT, "rendering/quality/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x")); + root->set_msaa(Viewport::MSAA(msaa_mode)); + bool hdr = GLOBAL_DEF("rendering/quality/hdr", true); + root->set_hdr(hdr); + + VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(), ref_atlas_size, ref_atlas_subdiv); + + { //load default fallback environment + //get possible extensions + List exts; + ResourceLoader::get_recognized_extensions_for_type("Environment", &exts); + String ext_hint; + for (List::Element *E = exts.front(); E; E = E->next()) { + if (ext_hint != String()) + ext_hint += ","; + ext_hint += "*." + E->get(); + } + //get path + String env_path = GLOBAL_DEF("rendering/viewport/default_environment", ""); + //setup property + GlobalConfig::get_singleton()->set_custom_property_info("rendering/viewport/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); + env_path = env_path.strip_edges(); + if (env_path != String()) { + Ref env = ResourceLoader::load(env_path); + if (env.is_valid()) { + root->get_world()->set_fallback_environment(env); + } else { + if (is_editor_hint()) { + //file was erased, clear the field. + GlobalConfig::get_singleton()->set("rendering/viewport/default_environment", ""); + } else { + //file was erased, notify user. + ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded.")); + } + } + } + } + + stretch_mode = STRETCH_MODE_DISABLED; + stretch_aspect = STRETCH_ASPECT_IGNORE; + + last_screen_size = Size2(OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height); + _update_root_rect(); + + if (ScriptDebugger::get_singleton()) { + ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this); + } + + root->set_physics_object_picking(GLOBAL_DEF("physics/common/enable_object_picking", true)); + +#ifdef TOOLS_ENABLED + edited_scene_root = NULL; +#endif + +#ifdef DEBUG_ENABLED + + live_edit_funcs.udata = this; + live_edit_funcs.node_path_func = _live_edit_node_path_funcs; + live_edit_funcs.res_path_func = _live_edit_res_path_funcs; + live_edit_funcs.node_set_func = _live_edit_node_set_funcs; + live_edit_funcs.node_set_res_func = _live_edit_node_set_res_funcs; + live_edit_funcs.node_call_func = _live_edit_node_call_funcs; + live_edit_funcs.res_set_func = _live_edit_res_set_funcs; + live_edit_funcs.res_set_res_func = _live_edit_res_set_res_funcs; + live_edit_funcs.res_call_func = _live_edit_res_call_funcs; + live_edit_funcs.root_func = _live_edit_root_funcs; + + live_edit_funcs.tree_create_node_func = _live_edit_create_node_funcs; + live_edit_funcs.tree_instance_node_func = _live_edit_instance_node_funcs; + live_edit_funcs.tree_remove_node_func = _live_edit_remove_node_funcs; + live_edit_funcs.tree_remove_and_keep_node_func = _live_edit_remove_and_keep_node_funcs; + live_edit_funcs.tree_restore_node_func = _live_edit_restore_node_funcs; + live_edit_funcs.tree_duplicate_node_func = _live_edit_duplicate_node_funcs; + live_edit_funcs.tree_reparent_node_func = _live_edit_reparent_node_funcs; + + if (ScriptDebugger::get_singleton()) { + ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs); + } + + live_edit_root = NodePath("/root"); + + last_send_cache_id = 1; + +#endif +} + +SceneTree::~SceneTree() { +} diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h new file mode 100644 index 0000000000..2ea79bf945 --- /dev/null +++ b/scene/main/scene_tree.h @@ -0,0 +1,466 @@ +/*************************************************************************/ +/* scene_main_loop.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 SCENE_MAIN_LOOP_H +#define SCENE_MAIN_LOOP_H + +#include "io/networked_multiplayer_peer.h" +#include "os/main_loop.h" +#include "os/thread_safe.h" +#include "scene/resources/mesh.h" +#include "scene/resources/world.h" +#include "scene/resources/world_2d.h" +#include "self_list.h" + +/** + @author Juan Linietsky +*/ + +class SceneTree; +class PackedScene; +class Node; +class Viewport; +class Material; +class Mesh; + +class SceneTreeTimer : public Reference { + GDCLASS(SceneTreeTimer, Reference); + + float time_left; + bool process_pause; + +protected: + static void _bind_methods(); + +public: + void set_time_left(float p_time); + float get_time_left() const; + + void set_pause_mode_process(bool p_pause_mode_process); + bool is_pause_mode_process(); + + SceneTreeTimer(); +}; + +class SceneTree : public MainLoop { + + _THREAD_SAFE_CLASS_ + + GDCLASS(SceneTree, MainLoop); + +public: + typedef void (*IdleCallback)(); + + enum StretchMode { + + STRETCH_MODE_DISABLED, + STRETCH_MODE_2D, + STRETCH_MODE_VIEWPORT, + }; + + enum StretchAspect { + + STRETCH_ASPECT_IGNORE, + STRETCH_ASPECT_KEEP, + STRETCH_ASPECT_KEEP_WIDTH, + STRETCH_ASPECT_KEEP_HEIGHT, + }; + +private: + struct Group { + + Vector nodes; + //uint64_t last_tree_version; + bool changed; + Group() { changed = false; }; + }; + + Viewport *root; + + uint64_t tree_version; + float fixed_process_time; + float idle_process_time; + bool accept_quit; + bool quit_on_go_back; + uint32_t last_id; + +#ifdef TOOLS_ENABLED + bool editor_hint; +#endif +#ifdef DEBUG_ENABLED + bool debug_collisions_hint; + bool debug_navigation_hint; +#endif + bool pause; + int root_lock; + + Map group_map; + bool _quit; + bool initialized; + bool input_handled; + Size2 last_screen_size; + StringName tree_changed_name; + StringName node_removed_name; + + int64_t current_frame; + int node_count; + +#ifdef TOOLS_ENABLED + Node *edited_scene_root; +#endif + struct UGCall { + + StringName group; + StringName call; + + bool operator<(const UGCall &p_with) const { return group == p_with.group ? call < p_with.call : group < p_with.group; } + }; + + //safety for when a node is deleted while a group is being called + int call_lock; + Set call_skip; //skip erased nodes + + StretchMode stretch_mode; + StretchAspect stretch_aspect; + Size2i stretch_min; + + void _update_root_rect(); + + List delete_queue; + + Map > unique_group_calls; + bool ugc_locked; + void _flush_ugc(); + void _flush_transform_notifications(); + + _FORCE_INLINE_ void _update_group_order(Group &g); + void _update_listener(); + + Array _get_nodes_in_group(const StringName &p_group); + + Node *current_scene; + + Color debug_collisions_color; + Color debug_collision_contact_color; + Color debug_navigation_color; + Color debug_navigation_disabled_color; + Ref debug_contact_mesh; + Ref navigation_material; + Ref navigation_disabled_material; + Ref collision_material; + int collision_debug_contacts; + + void _change_scene(Node *p_to); + //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); + + List > timers; + + ///network/// + + enum NetworkCommands { + NETWORK_COMMAND_REMOTE_CALL, + NETWORK_COMMAND_REMOTE_SET, + NETWORK_COMMAND_SIMPLIFY_PATH, + NETWORK_COMMAND_CONFIRM_PATH, + }; + + Ref network_peer; + + Set connected_peers; + void _network_peer_connected(int p_id); + void _network_peer_disconnected(int p_id); + + void _connected_to_server(); + void _connection_failed(); + void _server_disconnected(); + + //path sent caches + struct PathSentCache { + Map confirmed_peers; + int id; + }; + + HashMap path_send_cache; + int last_send_cache_id; + + //path get caches + struct PathGetCache { + struct NodeInfo { + NodePath path; + ObjectID instance; + }; + + Map nodes; + }; + + Map path_get_cache; + + Vector packet_cache; + + void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len); + void _network_poll(); + + static SceneTree *singleton; + friend class Node; + + void _rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); + + void tree_changed(); + void node_removed(Node *p_node); + + Group *add_to_group(const StringName &p_group, Node *p_node); + void remove_from_group(const StringName &p_group, Node *p_node); + + void _notify_group_pause(const StringName &p_group, int p_notification); + void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref &p_input); + Variant _call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + Variant _call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error); + + static void _debugger_request_tree(void *self); + void _flush_delete_queue(); + //optimization + friend class CanvasItem; + friend class Spatial; + friend class Viewport; + + SelfList::List xform_change_list; + +#ifdef DEBUG_ENABLED + + Map live_edit_node_path_cache; + Map live_edit_resource_cache; + + NodePath live_edit_root; + String live_edit_scene; + + Map > live_scene_edit_cache; + Map > live_edit_remove_list; + + ScriptDebugger::LiveEditFuncs live_edit_funcs; + + void _live_edit_node_path_func(const NodePath &p_path, int p_id); + void _live_edit_res_path_func(const String &p_path, int p_id); + + void _live_edit_node_set_func(int p_id, const StringName &p_prop, const Variant &p_value); + void _live_edit_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value); + void _live_edit_node_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); + void _live_edit_res_set_func(int p_id, const StringName &p_prop, const Variant &p_value); + void _live_edit_res_set_res_func(int p_id, const StringName &p_prop, const String &p_value); + void _live_edit_res_call_func(int p_id, const StringName &p_method, VARIANT_ARG_DECLARE); + void _live_edit_root_func(const NodePath &p_scene_path, const String &p_scene_from); + + void _live_edit_create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name); + void _live_edit_instance_node_func(const NodePath &p_parent, const String &p_path, const String &p_name); + void _live_edit_remove_node_func(const NodePath &p_at); + void _live_edit_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_keep_id); + void _live_edit_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_at_pos); + void _live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name); + void _live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos); + + static void _live_edit_node_path_funcs(void *self, const NodePath &p_path, int p_id) { reinterpret_cast(self)->_live_edit_node_path_func(p_path, p_id); } + static void _live_edit_res_path_funcs(void *self, const String &p_path, int p_id) { reinterpret_cast(self)->_live_edit_res_path_func(p_path, p_id); } + + static void _live_edit_node_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast(self)->_live_edit_node_set_func(p_id, p_prop, p_value); } + static void _live_edit_node_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast(self)->_live_edit_node_set_res_func(p_id, p_prop, p_value); } + static void _live_edit_node_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_node_call_func(p_id, p_method, VARIANT_ARG_PASS); } + static void _live_edit_res_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast(self)->_live_edit_res_set_func(p_id, p_prop, p_value); } + static void _live_edit_res_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast(self)->_live_edit_res_set_res_func(p_id, p_prop, p_value); } + static void _live_edit_res_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast(self)->_live_edit_res_call_func(p_id, p_method, VARIANT_ARG_PASS); } + static void _live_edit_root_funcs(void *self, const NodePath &p_scene_path, const String &p_scene_from) { reinterpret_cast(self)->_live_edit_root_func(p_scene_path, p_scene_from); } + + static void _live_edit_create_node_funcs(void *self, const NodePath &p_parent, const String &p_type, const String &p_name) { reinterpret_cast(self)->_live_edit_create_node_func(p_parent, p_type, p_name); } + static void _live_edit_instance_node_funcs(void *self, const NodePath &p_parent, const String &p_path, const String &p_name) { reinterpret_cast(self)->_live_edit_instance_node_func(p_parent, p_path, p_name); } + static void _live_edit_remove_node_funcs(void *self, const NodePath &p_at) { reinterpret_cast(self)->_live_edit_remove_node_func(p_at); } + static void _live_edit_remove_and_keep_node_funcs(void *self, const NodePath &p_at, ObjectID p_keep_id) { reinterpret_cast(self)->_live_edit_remove_and_keep_node_func(p_at, p_keep_id); } + static void _live_edit_restore_node_funcs(void *self, ObjectID p_id, const NodePath &p_at, int p_at_pos) { reinterpret_cast(self)->_live_edit_restore_node_func(p_id, p_at, p_at_pos); } + static void _live_edit_duplicate_node_funcs(void *self, const NodePath &p_at, const String &p_new_name) { reinterpret_cast(self)->_live_edit_duplicate_node_func(p_at, p_new_name); } + static void _live_edit_reparent_node_funcs(void *self, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { reinterpret_cast(self)->_live_edit_reparent_node_func(p_at, p_new_place, p_new_name, p_at_pos); } + +#endif + + enum { + MAX_IDLE_CALLBACKS = 256 + }; + + static IdleCallback idle_callbacks[MAX_IDLE_CALLBACKS]; + static int idle_callback_count; + void _call_idle_callbacks(); + +protected: + void _notification(int p_notification); + static void _bind_methods(); + +public: + enum { + NOTIFICATION_TRANSFORM_CHANGED = 29 + }; + + enum CallGroupFlags { + GROUP_CALL_DEFAULT = 0, + GROUP_CALL_REVERSE = 1, + GROUP_CALL_REALTIME = 2, + GROUP_CALL_UNIQUE = 4, + GROUP_CALL_MULTILEVEL = 8, + }; + + _FORCE_INLINE_ Viewport *get_root() const { return root; } + + uint32_t get_last_event_id() const; + + void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); + void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification); + void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value); + + void call_group(const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST); + void notify_group(const StringName &p_group, int p_notification); + void set_group(const StringName &p_group, const String &p_name, const Variant &p_value); + + virtual void input_text(const String &p_text); + virtual void input_event(const Ref &p_event); + virtual void init(); + + virtual bool iteration(float p_time); + virtual bool idle(float p_time); + + virtual void finish(); + + void set_auto_accept_quit(bool p_enable); + void set_quit_on_go_back(bool p_enable); + + void quit(); + + void set_input_as_handled(); + bool is_input_handled(); + _FORCE_INLINE_ float get_fixed_process_time() const { return fixed_process_time; } + _FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; } + +#ifdef TOOLS_ENABLED + void set_editor_hint(bool p_enabled); + + bool is_editor_hint() const; + bool is_node_being_edited(const Node *p_node) const; +#else + void set_editor_hint(bool p_enabled) {} + + bool is_editor_hint() const { return false; } + bool is_node_being_edited(const Node *p_node) const { return false; } +#endif + + void set_pause(bool p_enabled); + bool is_paused() const; + + void set_camera(const RID &p_camera); + RID get_camera() const; + +#ifdef DEBUG_ENABLED + void set_debug_collisions_hint(bool p_enabled); + bool is_debugging_collisions_hint() const; + + void set_debug_navigation_hint(bool p_enabled); + bool is_debugging_navigation_hint() const; +#else + void set_debug_collisions_hint(bool p_enabled) {} + bool is_debugging_collisions_hint() const { return false; } + + void set_debug_navigation_hint(bool p_enabled) {} + bool is_debugging_navigation_hint() const { return false; } +#endif + + void set_debug_collisions_color(const Color &p_color); + Color get_debug_collisions_color() const; + + void set_debug_collision_contact_color(const Color &p_color); + Color get_debug_collision_contact_color() const; + + void set_debug_navigation_color(const Color &p_color); + Color get_debug_navigation_color() const; + + void set_debug_navigation_disabled_color(const Color &p_color); + Color get_debug_navigation_disabled_color() const; + + Ref get_debug_navigation_material(); + Ref get_debug_navigation_disabled_material(); + Ref get_debug_collision_material(); + Ref get_debug_contact_mesh(); + + int get_collision_debug_contact_count() { return collision_debug_contacts; } + + int64_t get_frame() const; + + int get_node_count() const; + + void queue_delete(Object *p_object); + + void get_nodes_in_group(const StringName &p_group, List *p_list); + bool has_group(const StringName &p_identifier) const; + + void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize); + +//void change_scene(const String& p_path); +//Node *get_loaded_scene(); + +#ifdef TOOLS_ENABLED + void set_edited_scene_root(Node *p_node); + Node *get_edited_scene_root() const; +#endif + + void set_current_scene(Node *p_scene); + Node *get_current_scene() const; + Error change_scene(const String &p_path); + Error change_scene_to(const Ref &p_scene); + Error reload_current_scene(); + + Ref create_timer(float p_delay_sec, bool p_process_pause = true); + + //used by Main::start, don't use otherwise + void add_current_scene(Node *p_current); + + static SceneTree *get_singleton() { return singleton; } + + void drop_files(const Vector &p_files, int p_from_screen = 0); + + //network API + + void set_network_peer(const Ref &p_network_peer); + bool is_network_server() const; + bool has_network_peer() const; + int get_network_unique_id() const; + + void set_refuse_new_network_connections(bool p_refuse); + bool is_refusing_new_network_connections() const; + + static void add_idle_callback(IdleCallback p_callback); + SceneTree(); + ~SceneTree(); +}; + +VARIANT_ENUM_CAST(SceneTree::StretchMode); +VARIANT_ENUM_CAST(SceneTree::StretchAspect); + +#endif diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 151bc80321..76e07db93d 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -129,7 +129,7 @@ #include "scene/animation/animation_tree_player.h" #include "scene/animation/tween.h" #include "scene/main/resource_preloader.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/resources/packed_scene.h" #include "scene/resources/mesh_data_tool.h" diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp index 77f2096d9b..6be88374e5 100644 --- a/scene/resources/shape.cpp +++ b/scene/resources/shape.cpp @@ -30,7 +30,7 @@ #include "shape.h" #include "os/os.h" -#include "scene/main/scene_main_loop.h" +#include "scene/main/scene_tree.h" #include "scene/resources/mesh.h" #include "servers/physics_server.h" diff --git a/servers/visual/shader_types.cpp b/servers/visual/shader_types.cpp index 42f1a98826..b04c8716fb 100644 --- a/servers/visual/shader_types.cpp +++ b/servers/visual/shader_types.cpp @@ -102,7 +102,6 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["AO"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["EMISSION"] = ShaderLanguage::TYPE_VEC3; - shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SPECIAL"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["DISCARD"] = ShaderLanguage::TYPE_BOOL; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; shader_modes[VS::SHADER_SPATIAL].functions["fragment"]["DEPTH_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; @@ -156,7 +155,7 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["vertex"]["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SRC_COLOR"] = ShaderLanguage::TYPE_VEC4; - shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POSITION"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["FRAGCOORD"] = ShaderLanguage::TYPE_VEC4; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMAL"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMALMAP"] = ShaderLanguage::TYPE_VEC3; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["NORMALMAP_DEPTH"] = ShaderLanguage::TYPE_FLOAT; @@ -165,9 +164,12 @@ ShaderTypes::ShaderTypes() { shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TEXTURE_PIXEL_SIZE"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_PIXEL_SIZE"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["POINT_COORD"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["TIME"] = ShaderLanguage::TYPE_FLOAT; shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["AT_LIGHT_PASS"] = ShaderLanguage::TYPE_BOOL; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_TEXTURE"] = ShaderLanguage::TYPE_SAMPLER2D; + shader_modes[VS::SHADER_CANVAS_ITEM].functions["fragment"]["SCREEN_UV"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["POSITION"] = ShaderLanguage::TYPE_VEC2; shader_modes[VS::SHADER_CANVAS_ITEM].functions["light"]["NORMAL"] = ShaderLanguage::TYPE_VEC3; -- cgit v1.2.3