summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/canvas_item.cpp11
-rw-r--r--scene/2d/canvas_item.h2
-rw-r--r--scene/gui/control.cpp4
-rw-r--r--scene/main/scene_main_loop.cpp132
-rw-r--r--scene/main/scene_main_loop.h34
-rw-r--r--scene/main/viewport.cpp69
-rw-r--r--scene/main/viewport.h8
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();