1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Graphics/Camera.h"
26 #include "../Graphics/Graphics.h"
27 #include "../Graphics/Renderer.h"
28 #include "../Graphics/RenderPath.h"
29 #include "../Graphics/View.h"
30 #include "../Resource/ResourceCache.h"
31 #include "../Resource/XMLFile.h"
32 #include "../Scene/Scene.h"
33 
34 #include "../DebugNew.h"
35 
36 namespace Urho3D
37 {
38 
Viewport(Context * context)39 Viewport::Viewport(Context* context) :
40     Object(context),
41     rect_(IntRect::ZERO),
42     drawDebug_(true)
43 {
44     SetRenderPath((RenderPath*)0);
45 }
46 
Viewport(Context * context,Scene * scene,Camera * camera,RenderPath * renderPath)47 Viewport::Viewport(Context* context, Scene* scene, Camera* camera, RenderPath* renderPath) :
48     Object(context),
49     scene_(scene),
50     camera_(camera),
51     rect_(IntRect::ZERO),
52     drawDebug_(true)
53 {
54     SetRenderPath(renderPath);
55 }
56 
Viewport(Context * context,Scene * scene,Camera * camera,const IntRect & rect,RenderPath * renderPath)57 Viewport::Viewport(Context* context, Scene* scene, Camera* camera, const IntRect& rect, RenderPath* renderPath) :
58     Object(context),
59     scene_(scene),
60     camera_(camera),
61     rect_(rect),
62     drawDebug_(true)
63 {
64     SetRenderPath(renderPath);
65 }
66 
~Viewport()67 Viewport::~Viewport()
68 {
69 }
70 
SetScene(Scene * scene)71 void Viewport::SetScene(Scene* scene)
72 {
73     scene_ = scene;
74 }
75 
SetCamera(Camera * camera)76 void Viewport::SetCamera(Camera* camera)
77 {
78     camera_ = camera;
79 }
80 
SetCullCamera(Camera * camera)81 void Viewport::SetCullCamera(Camera* camera)
82 {
83     cullCamera_ = camera;
84 }
85 
SetRect(const IntRect & rect)86 void Viewport::SetRect(const IntRect& rect)
87 {
88     rect_ = rect;
89 }
90 
SetDrawDebug(bool enable)91 void Viewport::SetDrawDebug(bool enable)
92 {
93     drawDebug_ = enable;
94 }
95 
SetRenderPath(RenderPath * renderPath)96 void Viewport::SetRenderPath(RenderPath* renderPath)
97 {
98     if (renderPath)
99         renderPath_ = renderPath;
100     else
101     {
102         Renderer* renderer = GetSubsystem<Renderer>();
103         if (renderer)
104             renderPath_ = renderer->GetDefaultRenderPath();
105     }
106 }
107 
SetRenderPath(XMLFile * file)108 void Viewport::SetRenderPath(XMLFile* file)
109 {
110     SharedPtr<RenderPath> newRenderPath(new RenderPath());
111     if (newRenderPath->Load(file))
112         renderPath_ = newRenderPath;
113 }
114 
GetScene() const115 Scene* Viewport::GetScene() const
116 {
117     return scene_;
118 }
119 
GetCamera() const120 Camera* Viewport::GetCamera() const
121 {
122     return camera_;
123 }
124 
GetCullCamera() const125 Camera* Viewport::GetCullCamera() const
126 {
127     return cullCamera_;
128 }
129 
GetView() const130 View* Viewport::GetView() const
131 {
132     return view_;
133 }
134 
GetRenderPath() const135 RenderPath* Viewport::GetRenderPath() const
136 {
137     return renderPath_;
138 }
139 
GetScreenRay(int x,int y) const140 Ray Viewport::GetScreenRay(int x, int y) const
141 {
142     if (!camera_)
143         return Ray();
144 
145     float screenX;
146     float screenY;
147 
148     if (rect_ == IntRect::ZERO)
149     {
150         Graphics* graphics = GetSubsystem<Graphics>();
151         screenX = (float)x / (float)graphics->GetWidth();
152         screenY = (float)y / (float)graphics->GetHeight();
153     }
154     else
155     {
156         screenX = float(x - rect_.left_) / (float)rect_.Width();
157         screenY = float(y - rect_.top_) / (float)rect_.Height();
158     }
159 
160     return camera_->GetScreenRay(screenX, screenY);
161 }
162 
WorldToScreenPoint(const Vector3 & worldPos) const163 IntVector2 Viewport::WorldToScreenPoint(const Vector3& worldPos) const
164 {
165     if (!camera_)
166         return IntVector2::ZERO;
167 
168     Vector2 screenPoint = camera_->WorldToScreenPoint(worldPos);
169 
170     int x;
171     int y;
172     if (rect_ == IntRect::ZERO)
173     {
174         /// \todo This is incorrect if the viewport is used on a texture rendertarget instead of the backbuffer, as it may have different dimensions.
175         Graphics* graphics = GetSubsystem<Graphics>();
176         x = (int)(screenPoint.x_ * graphics->GetWidth());
177         y = (int)(screenPoint.y_ * graphics->GetHeight());
178     }
179     else
180     {
181         x = (int)(rect_.left_ + screenPoint.x_ * rect_.Width());
182         y = (int)(rect_.top_ + screenPoint.y_ * rect_.Height());
183     }
184 
185     return IntVector2(x, y);
186 }
187 
ScreenToWorldPoint(int x,int y,float depth) const188 Vector3 Viewport::ScreenToWorldPoint(int x, int y, float depth) const
189 {
190     if (!camera_)
191         return Vector3::ZERO;
192 
193     float screenX;
194     float screenY;
195 
196     if (rect_ == IntRect::ZERO)
197     {
198         /// \todo This is incorrect if the viewport is used on a texture rendertarget instead of the backbuffer, as it may have different dimensions.
199         Graphics* graphics = GetSubsystem<Graphics>();
200         screenX = (float)x / (float)graphics->GetWidth();
201         screenY = (float)y / (float)graphics->GetHeight();
202     }
203     else
204     {
205         screenX = float(x - rect_.left_) / (float)rect_.Width();
206         screenY = float(y - rect_.top_) / (float)rect_.Height();
207     }
208 
209     return camera_->ScreenToWorldPoint(Vector3(screenX, screenY, depth));
210 }
211 
AllocateView()212 void Viewport::AllocateView()
213 {
214     view_ = new View(context_);
215 }
216 
217 }
218