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 "../Core/Profiler.h"
26 #include "../Graphics/AnimatedModel.h"
27 #include "../Graphics/Animation.h"
28 #include "../Graphics/AnimationController.h"
29 #include "../Graphics/Camera.h"
30 #include "../Graphics/CustomGeometry.h"
31 #include "../Graphics/DebugRenderer.h"
32 #include "../Graphics/DecalSet.h"
33 #include "../Graphics/Graphics.h"
34 #include "../Graphics/GraphicsImpl.h"
35 #include "../Graphics/Material.h"
36 #include "../Graphics/Octree.h"
37 #include "../Graphics/ParticleEffect.h"
38 #include "../Graphics/ParticleEmitter.h"
39 #include "../Graphics/RibbonTrail.h"
40 #include "../Graphics/Shader.h"
41 #include "../Graphics/ShaderPrecache.h"
42 #include "../Graphics/Skybox.h"
43 #include "../Graphics/StaticModelGroup.h"
44 #include "../Graphics/Technique.h"
45 #include "../Graphics/Terrain.h"
46 #include "../Graphics/TerrainPatch.h"
47 #include "../Graphics/Texture2D.h"
48 #include "../Graphics/Texture2DArray.h"
49 #include "../Graphics/Texture3D.h"
50 #include "../Graphics/TextureCube.h"
51 #include "../Graphics/Zone.h"
52 #include "../IO/FileSystem.h"
53 #include "../IO/Log.h"
54 
55 #include <SDL/SDL.h>
56 #include <SDL/SDL_syswm.h>
57 
58 #include "../DebugNew.h"
59 
60 namespace Urho3D
61 {
62 
SetExternalWindow(void * window)63 void Graphics::SetExternalWindow(void* window)
64 {
65     if (!window_)
66         externalWindow_ = window;
67     else
68         URHO3D_LOGERROR("Window already opened, can not set external window");
69 }
70 
SetWindowTitle(const String & windowTitle)71 void Graphics::SetWindowTitle(const String& windowTitle)
72 {
73     windowTitle_ = windowTitle;
74     if (window_)
75         SDL_SetWindowTitle(window_, windowTitle_.CString());
76 }
77 
SetWindowIcon(Image * windowIcon)78 void Graphics::SetWindowIcon(Image* windowIcon)
79 {
80     windowIcon_ = windowIcon;
81     if (window_)
82         CreateWindowIcon();
83 }
84 
SetWindowPosition(const IntVector2 & position)85 void Graphics::SetWindowPosition(const IntVector2& position)
86 {
87     if (window_)
88         SDL_SetWindowPosition(window_, position.x_, position.y_);
89     else
90         position_ = position; // Sets as initial position for OpenWindow()
91 }
92 
SetWindowPosition(int x,int y)93 void Graphics::SetWindowPosition(int x, int y)
94 {
95     SetWindowPosition(IntVector2(x, y));
96 }
97 
SetOrientations(const String & orientations)98 void Graphics::SetOrientations(const String& orientations)
99 {
100     orientations_ = orientations.Trimmed();
101     SDL_SetHint(SDL_HINT_ORIENTATIONS, orientations_.CString());
102 }
103 
ToggleFullscreen()104 bool Graphics::ToggleFullscreen()
105 {
106     return SetMode(width_, height_, !fullscreen_, borderless_, resizable_, highDPI_, vsync_, tripleBuffer_, multiSample_, monitor_, refreshRate_);
107 }
108 
SetShaderParameter(StringHash param,const Variant & value)109 void Graphics::SetShaderParameter(StringHash param, const Variant& value)
110 {
111     switch (value.GetType())
112     {
113     case VAR_BOOL:
114         SetShaderParameter(param, value.GetBool());
115         break;
116 
117     case VAR_INT:
118         SetShaderParameter(param, value.GetInt());
119         break;
120 
121     case VAR_FLOAT:
122     case VAR_DOUBLE:
123         SetShaderParameter(param, value.GetFloat());
124         break;
125 
126     case VAR_VECTOR2:
127         SetShaderParameter(param, value.GetVector2());
128         break;
129 
130     case VAR_VECTOR3:
131         SetShaderParameter(param, value.GetVector3());
132         break;
133 
134     case VAR_VECTOR4:
135         SetShaderParameter(param, value.GetVector4());
136         break;
137 
138     case VAR_COLOR:
139         SetShaderParameter(param, value.GetColor());
140         break;
141 
142     case VAR_MATRIX3:
143         SetShaderParameter(param, value.GetMatrix3());
144         break;
145 
146     case VAR_MATRIX3X4:
147         SetShaderParameter(param, value.GetMatrix3x4());
148         break;
149 
150     case VAR_MATRIX4:
151         SetShaderParameter(param, value.GetMatrix4());
152         break;
153 
154     case VAR_BUFFER:
155         {
156             const PODVector<unsigned char>& buffer = value.GetBuffer();
157             if (buffer.Size() >= sizeof(float))
158                 SetShaderParameter(param, reinterpret_cast<const float*>(&buffer[0]), buffer.Size() / sizeof(float));
159         }
160         break;
161 
162     default:
163         // Unsupported parameter type, do nothing
164         break;
165     }
166 }
167 
GetWindowPosition() const168 IntVector2 Graphics::GetWindowPosition() const
169 {
170     if (window_)
171         return position_;
172     return IntVector2::ZERO;
173 }
174 
GetResolutions(int monitor) const175 PODVector<IntVector3> Graphics::GetResolutions(int monitor) const
176 {
177     PODVector<IntVector3> ret;
178     // Emscripten is not able to return a valid list
179 #ifndef __EMSCRIPTEN__
180     unsigned numModes = (unsigned)SDL_GetNumDisplayModes(monitor);
181 
182     for (unsigned i = 0; i < numModes; ++i)
183     {
184         SDL_DisplayMode mode;
185         SDL_GetDisplayMode(monitor, i, &mode);
186         int width = mode.w;
187         int height = mode.h;
188         int rate = mode.refresh_rate;
189 
190         // Store mode if unique
191         bool unique = true;
192         for (unsigned j = 0; j < ret.Size(); ++j)
193         {
194             if (ret[j].x_ == width && ret[j].y_ == height && ret[j].z_ == rate)
195             {
196                 unique = false;
197                 break;
198             }
199         }
200 
201         if (unique)
202             ret.Push(IntVector3(width, height, rate));
203     }
204 #endif
205 
206     return ret;
207 }
208 
GetDesktopResolution(int monitor) const209 IntVector2 Graphics::GetDesktopResolution(int monitor) const
210 {
211 #if !defined(__ANDROID__) && !defined(IOS) && !defined(TVOS)
212     SDL_DisplayMode mode;
213     SDL_GetDesktopDisplayMode(monitor, &mode);
214     return IntVector2(mode.w, mode.h);
215 #else
216     // SDL_GetDesktopDisplayMode() may not work correctly on mobile platforms. Rather return the window size
217     return IntVector2(width_, height_);
218 #endif
219 }
220 
GetMonitorCount() const221 int Graphics::GetMonitorCount() const
222 {
223     return SDL_GetNumVideoDisplays();
224 }
225 
Maximize()226 void Graphics::Maximize()
227 {
228     if (!window_)
229         return;
230 
231     SDL_MaximizeWindow(window_);
232 }
233 
Minimize()234 void Graphics::Minimize()
235 {
236     if (!window_)
237         return;
238 
239     SDL_MinimizeWindow(window_);
240 }
241 
BeginDumpShaders(const String & fileName)242 void Graphics::BeginDumpShaders(const String& fileName)
243 {
244     shaderPrecache_ = new ShaderPrecache(context_, fileName);
245 }
246 
EndDumpShaders()247 void Graphics::EndDumpShaders()
248 {
249     shaderPrecache_.Reset();
250 }
251 
PrecacheShaders(Deserializer & source)252 void Graphics::PrecacheShaders(Deserializer& source)
253 {
254     URHO3D_PROFILE(PrecacheShaders);
255 
256     ShaderPrecache::LoadShaders(this, source);
257 }
258 
SetShaderCacheDir(const String & path)259 void Graphics::SetShaderCacheDir(const String& path)
260 {
261     String trimmedPath = path.Trimmed();
262     if (trimmedPath.Length())
263         shaderCacheDir_ = AddTrailingSlash(trimmedPath);
264 }
265 
AddGPUObject(GPUObject * object)266 void Graphics::AddGPUObject(GPUObject* object)
267 {
268     MutexLock lock(gpuObjectMutex_);
269 
270     gpuObjects_.Push(object);
271 }
272 
RemoveGPUObject(GPUObject * object)273 void Graphics::RemoveGPUObject(GPUObject* object)
274 {
275     MutexLock lock(gpuObjectMutex_);
276 
277     gpuObjects_.Remove(object);
278 }
279 
ReserveScratchBuffer(unsigned size)280 void* Graphics::ReserveScratchBuffer(unsigned size)
281 {
282     if (!size)
283         return 0;
284 
285     if (size > maxScratchBufferRequest_)
286         maxScratchBufferRequest_ = size;
287 
288     // First check for a free buffer that is large enough
289     for (Vector<ScratchBuffer>::Iterator i = scratchBuffers_.Begin(); i != scratchBuffers_.End(); ++i)
290     {
291         if (!i->reserved_ && i->size_ >= size)
292         {
293             i->reserved_ = true;
294             return i->data_.Get();
295         }
296     }
297 
298     // Then check if a free buffer can be resized
299     for (Vector<ScratchBuffer>::Iterator i = scratchBuffers_.Begin(); i != scratchBuffers_.End(); ++i)
300     {
301         if (!i->reserved_)
302         {
303             i->data_ = new unsigned char[size];
304             i->size_ = size;
305             i->reserved_ = true;
306 
307             URHO3D_LOGDEBUG("Resized scratch buffer to size " + String(size));
308 
309             return i->data_.Get();
310         }
311     }
312 
313     // Finally allocate a new buffer
314     ScratchBuffer newBuffer;
315     newBuffer.data_ = new unsigned char[size];
316     newBuffer.size_ = size;
317     newBuffer.reserved_ = true;
318     scratchBuffers_.Push(newBuffer);
319     return newBuffer.data_.Get();
320 
321     URHO3D_LOGDEBUG("Allocated scratch buffer with size " + String(size));
322 }
323 
FreeScratchBuffer(void * buffer)324 void Graphics::FreeScratchBuffer(void* buffer)
325 {
326     if (!buffer)
327         return;
328 
329     for (Vector<ScratchBuffer>::Iterator i = scratchBuffers_.Begin(); i != scratchBuffers_.End(); ++i)
330     {
331         if (i->reserved_ && i->data_.Get() == buffer)
332         {
333             i->reserved_ = false;
334             return;
335         }
336     }
337 
338     URHO3D_LOGWARNING("Reserved scratch buffer " + ToStringHex((unsigned)(size_t)buffer) + " not found");
339 }
340 
CleanupScratchBuffers()341 void Graphics::CleanupScratchBuffers()
342 {
343     for (Vector<ScratchBuffer>::Iterator i = scratchBuffers_.Begin(); i != scratchBuffers_.End(); ++i)
344     {
345         if (!i->reserved_ && i->size_ > maxScratchBufferRequest_ * 2 && i->size_ >= 1024 * 1024)
346         {
347             i->data_ = maxScratchBufferRequest_ > 0 ? new unsigned char[maxScratchBufferRequest_] : 0;
348             i->size_ = maxScratchBufferRequest_;
349 
350             URHO3D_LOGDEBUG("Resized scratch buffer to size " + String(maxScratchBufferRequest_));
351         }
352     }
353 
354     maxScratchBufferRequest_ = 0;
355 }
356 
CreateWindowIcon()357 void Graphics::CreateWindowIcon()
358 {
359     if (windowIcon_)
360     {
361         SDL_Surface* surface = windowIcon_->GetSDLSurface();
362         if (surface)
363         {
364             SDL_SetWindowIcon(window_, surface);
365             SDL_FreeSurface(surface);
366         }
367     }
368 }
369 
RegisterGraphicsLibrary(Context * context)370 void RegisterGraphicsLibrary(Context* context)
371 {
372     Animation::RegisterObject(context);
373     Material::RegisterObject(context);
374     Model::RegisterObject(context);
375     Shader::RegisterObject(context);
376     Technique::RegisterObject(context);
377     Texture2D::RegisterObject(context);
378     Texture2DArray::RegisterObject(context);
379     Texture3D::RegisterObject(context);
380     TextureCube::RegisterObject(context);
381     Camera::RegisterObject(context);
382     Drawable::RegisterObject(context);
383     Light::RegisterObject(context);
384     StaticModel::RegisterObject(context);
385     StaticModelGroup::RegisterObject(context);
386     Skybox::RegisterObject(context);
387     AnimatedModel::RegisterObject(context);
388     AnimationController::RegisterObject(context);
389     BillboardSet::RegisterObject(context);
390     ParticleEffect::RegisterObject(context);
391     ParticleEmitter::RegisterObject(context);
392     RibbonTrail::RegisterObject(context);
393     CustomGeometry::RegisterObject(context);
394     DecalSet::RegisterObject(context);
395     Terrain::RegisterObject(context);
396     TerrainPatch::RegisterObject(context);
397     DebugRenderer::RegisterObject(context);
398     Octree::RegisterObject(context);
399     Zone::RegisterObject(context);
400 }
401 
402 }
403