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