diff options
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/canvas_item.cpp | 11 | ||||
-rw-r--r-- | scene/2d/canvas_item.h | 2 | ||||
-rw-r--r-- | scene/gui/control.cpp | 4 | ||||
-rw-r--r-- | scene/main/scene_main_loop.cpp | 132 | ||||
-rw-r--r-- | scene/main/scene_main_loop.h | 34 | ||||
-rw-r--r-- | scene/main/viewport.cpp | 69 | ||||
-rw-r--r-- | scene/main/viewport.h | 8 |
7 files changed, 252 insertions, 8 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 8eb5c9dfc8..b9cddfa572 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -821,6 +821,17 @@ void CanvasItem::_bind_methods() { } +Matrix32 CanvasItem::get_canvas_transform() const { + + ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); + + if (canvas_layer) + return canvas_layer->get_transform(); + else + return get_viewport()->get_canvas_transform(); + +} + Matrix32 CanvasItem::get_viewport_transform() const { ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 397b206677..1c104c5fc2 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -195,6 +195,8 @@ public: void set_block_transform_notify(bool p_enable); bool is_block_transform_notify_enabled() const; + + Matrix32 get_canvas_transform() const; Matrix32 get_viewport_transform() const; Rect2 get_viewport_rect() const; RID get_viewport_rid() const; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 9e0faac716..e0604b7cb8 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -955,7 +955,7 @@ void Control::_window_input_event(InputEvent p_event) { window->key_event_accepted=false; - Point2 mpos =(get_viewport_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); + Point2 mpos =(get_canvas_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y)); if (p_event.mouse_button.pressed) { @@ -1102,7 +1102,7 @@ void Control::_window_input_event(InputEvent p_event) { window->key_event_accepted=false; - Matrix32 localizer = (get_viewport_transform()).affine_inverse(); + Matrix32 localizer = (get_canvas_transform()).affine_inverse(); Size2 pos = localizer.xform(Size2(p_event.mouse_motion.x,p_event.mouse_motion.y)) - _window_get_pos(); Vector2 speed = localizer.basis_xform(Point2(p_event.mouse_motion.speed_x,p_event.mouse_motion.speed_y)); Vector2 rel = localizer.basis_xform(Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y)); diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 32bc4b3e16..5ec416fb47 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -516,7 +516,8 @@ bool SceneMainLoop::idle(float p_time){ last_screen_size=win_size; - root->set_rect(Rect2(Point2(),last_screen_size)); + _update_root_rect(); + emit_signal("screen_resized"); @@ -849,6 +850,120 @@ int SceneMainLoop::get_node_count() const { return node_count; } + +void SceneMainLoop::_update_root_rect() { + + + if (stretch_mode==STRETCH_MODE_DISABLED) { + root->set_rect(Rect2(Point2(),last_screen_size)); + 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.get_aspect(); + float video_mode_aspect = video_mode.get_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_rect(Rect2(Point2(),video_mode)); + root->set_as_render_target(false); + root->set_rect(Rect2(margin,screen_size)); + root->set_size_override_stretch(true); + root->set_size_override(true,viewport_size); + + } break; + case STRETCH_MODE_VIEWPORT: { + + print_line("VP SIZE: "+viewport_size); + root->set_rect(Rect2(Point2(),viewport_size)); + root->set_size_override_stretch(false); + root->set_size_override(false,Size2()); + root->set_as_render_target(true); + root->set_render_target_update_mode(Viewport::RENDER_TARGET_UPDATE_ALWAYS); + root->set_render_target_to_screen_rect(Rect2(margin,screen_size)); + + } break; + + + } + +} + +void SceneMainLoop::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(); +} + + void SceneMainLoop::_bind_methods() { @@ -874,6 +989,9 @@ void SceneMainLoop::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_frame"),&SceneMainLoop::get_frame); ObjectTypeDB::bind_method(_MD("quit"),&SceneMainLoop::quit); + ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneMainLoop::set_screen_stretch); + + ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneMainLoop::queue_delete); @@ -899,6 +1017,14 @@ void SceneMainLoop::_bind_methods() { 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 ); + } SceneMainLoop::SceneMainLoop() { @@ -927,6 +1053,9 @@ SceneMainLoop::SceneMainLoop() { root->set_as_audio_listener(true); root->set_as_audio_listener_2d(true); + 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 ); root->set_rect(Rect2(Point2(),last_screen_size)); @@ -934,7 +1063,6 @@ SceneMainLoop::SceneMainLoop() { ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree,this); } - } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 1c8e0c90ae..8b9ea0b585 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -50,6 +50,25 @@ class SceneMainLoop : public MainLoop { _THREAD_SAFE_CLASS_ OBJ_TYPE( SceneMainLoop, MainLoop ); +public: + + + 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 { @@ -95,6 +114,12 @@ class SceneMainLoop : public MainLoop { Set<Node*> call_skip; //skip erased nodes + StretchMode stretch_mode; + StretchAspect stretch_aspect; + Size2i stretch_min; + + void _update_root_rect(); + List<ObjectID> delete_queue; Map<UGCall,Vector<Variant> > unique_group_calls; @@ -152,7 +177,6 @@ public: GROUP_CALL_MULIILEVEL=8, }; - _FORCE_INLINE_ Viewport *get_root() const { return root; } uint32_t get_last_event_id() const; @@ -196,10 +220,18 @@ public: void get_nodes_in_group(const StringName& p_group,List<Node*> *p_list); + void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize); + + SceneMainLoop(); ~SceneMainLoop(); }; +VARIANT_ENUM_CAST( SceneMainLoop::StretchMode ); +VARIANT_ENUM_CAST( SceneMainLoop::StretchAspect ); + + + #endif diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 56d0544abd..0e32fd006d 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -86,8 +86,9 @@ void Viewport::_update_stretch_transform() { if (size_override_stretch && size_override) { stretch_transform=Matrix32(); - stretch_transform.scale(rect.size/(size_override_size+size_override_margin*2)); - stretch_transform.elements[2]=size_override_margin; + Size2 scale = rect.size/(size_override_size+size_override_margin*2); + stretch_transform.scale(scale); + stretch_transform.elements[2]=size_override_margin*scale; } else { @@ -629,7 +630,9 @@ Ref<World> Viewport::get_world() const{ Ref<World> Viewport::find_world() const{ - if (world.is_valid()) + if (own_world.is_valid()) + return own_world; + else if (world.is_valid()) return world; else if (parent) return parent->find_world(); @@ -863,6 +866,60 @@ void Viewport::unhandled_input(const InputEvent& p_event) { } } +void Viewport::set_use_own_world(bool p_world) { + + if (p_world==own_world.is_valid()) + return; + + + if (is_inside_scene()) + _propagate_exit_world(this); + +#ifndef _3D_DISABLED + if (find_world().is_valid() && camera) + camera->notification(Camera::NOTIFICATION_LOST_CURRENT); +#endif + + if (!p_world) + own_world=Ref<World>(); + else + own_world=Ref<World>( memnew( World )); + + if (is_inside_scene()) + _propagate_enter_world(this); + +#ifndef _3D_DISABLED + if (find_world().is_valid() && camera) + camera->notification(Camera::NOTIFICATION_BECAME_CURRENT); +#endif + + //propagate exit + + if (is_inside_scene()) { + VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario()); + } + + _update_listener(); + + +} + +bool Viewport::is_using_own_world() const { + + return own_world.is_valid(); +} + +void Viewport::set_render_target_to_screen_rect(const Rect2& p_rect) { + + to_screen_rect=p_rect; + VisualServer::get_singleton()->viewport_set_render_target_to_screen_rect(viewport,to_screen_rect); +} + +Rect2 Viewport::get_render_target_to_screen_rect() const{ + + return to_screen_rect; +} + void Viewport::_bind_methods() { @@ -918,15 +975,20 @@ void Viewport::_bind_methods() { ObjectTypeDB::bind_method(_MD("update_worlds"), &Viewport::update_worlds); + ObjectTypeDB::bind_method(_MD("set_use_own_world","enable"), &Viewport::set_use_own_world); + ObjectTypeDB::bind_method(_MD("is_using_own_world"), &Viewport::is_using_own_world); + ObjectTypeDB::bind_method(_MD("set_as_audio_listener","enable"), &Viewport::set_as_audio_listener); ObjectTypeDB::bind_method(_MD("is_audio_listener","enable"), &Viewport::is_audio_listener); ObjectTypeDB::bind_method(_MD("set_as_audio_listener_2d","enable"), &Viewport::set_as_audio_listener_2d); ObjectTypeDB::bind_method(_MD("is_audio_listener_2d","enable"), &Viewport::is_audio_listener_2d); + ObjectTypeDB::bind_method(_MD("set_render_target_to_screen_rect"), &Viewport::set_render_target_to_screen_rect); ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"), _SCS("set_rect"), _SCS("get_rect") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") ); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") ); // ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world_2d",PROPERTY_HINT_RESOURCE_TYPE,"World2D"), _SCS("set_world_2d"), _SCS("get_world_2d") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transparent_bg"), _SCS("set_transparent_background"), _SCS("has_transparent_background") ); @@ -969,6 +1031,7 @@ Viewport::Viewport() { render_target_update_mode=RENDER_TARGET_UPDATE_WHEN_VISIBLE; render_target_texture = Ref<RenderTargetTexture>( memnew( RenderTargetTexture(this) ) ); + String id=itos(get_instance_ID()); input_group = "_vp_input"+id; gui_input_group = "_vp_gui_input"+id; diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 8ba84651f8..33e1f27b93 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -101,6 +101,7 @@ friend class RenderTargetTexture; Matrix32 stretch_transform; Rect2 rect; + Rect2 to_screen_rect; bool size_override; @@ -120,6 +121,7 @@ friend class RenderTargetTexture; Ref<World2D> world_2d; Ref<World> world; + Ref<World> own_world; StringName input_group; StringName gui_input_group; @@ -213,9 +215,15 @@ public: void queue_screen_capture(); Image get_screen_capture() const; + void set_use_own_world(bool p_world); + bool is_using_own_world() const; + void input(const InputEvent& p_event); void unhandled_input(const InputEvent& p_event); + void set_render_target_to_screen_rect(const Rect2& p_rect); + Rect2 get_render_target_to_screen_rect() const; + Viewport(); ~Viewport(); |