1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2009-2015 Joerg Henrichs
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #ifndef HEADER_IRR_DRIVER_HPP
20 #define HEADER_IRR_DRIVER_HPP
21 
22 /**
23  * \defgroup graphics
24  * This module contains the core graphics engine, that is mostly a thin layer
25  * on top of irrlicht providing some additional features we need for STK
26  * (like particles, more scene node types, mesh manipulation tools, material
27  * management, etc...)
28  */
29 
30 #include <IVideoDriver.h>
31 #include <vector2d.h>
32 #include <dimension2d.h>
33 #include <SColor.h>
34 #include "IrrlichtDevice.h"
35 #include "ISkinnedMesh.h"
36 #include "graphics/abstract_renderer.hpp"
37 #include "graphics/gl_headers.hpp"
38 #include "graphics/wind.hpp"
39 #include "io/file_manager.hpp"
40 #include "utils/aligned_array.hpp"
41 #include "utils/no_copy.hpp"
42 #include "utils/ptr_vector.hpp"
43 #include "utils/vec3.hpp"
44 #include <memory>
45 #include <string>
46 #include <vector>
47 
48 
49 namespace SP
50 {
51     class SPDynamicDrawCall;
52 }
53 
54 
55 namespace irr
56 {
57     namespace scene { class ISceneManager; class IMesh; class IAnimatedMeshSceneNode; class IAnimatedMesh;
58         class IMeshSceneNode; class IParticleSystemSceneNode; class ICameraSceneNode; class ILightSceneNode;
59         class CLensFlareSceneNode; }
60     namespace gui   { class IGUIEnvironment; class IGUIFont; }
61 }
62 using namespace irr;
63 
64 enum TypeRTT : unsigned int;
65 class AbstractKart;
66 class AbstractRenderer;
67 class Camera;
68 class FrameBuffer;
69 class LightNode;
70 class PerCameraNode;
71 class RenderInfo;
72 class RenderTarget;
73 
74 struct SHCoefficients;
75 
76 /**
77   * \brief class that creates the irrLicht device and offers higher-level
78   *  ways to manage the 3D scene
79   * \ingroup graphics
80   */
81 class IrrDriver : public IEventReceiver, public NoCopy
82 {
83 private:
84     /** The irrlicht device. */
85     IrrlichtDevice             *m_device;
86     /** Irrlicht scene manager. */
87     scene::ISceneManager       *m_scene_manager;
88     /** Irrlicht gui environment. */
89     gui::IGUIEnvironment       *m_gui_env;
90     /** Irrlicht video driver. */
91     video::IVideoDriver        *m_video_driver;
92     /** Irrlicht race font. */
93     gui::IGUIFont              *m_race_font;
94     /** Renderer. */
95     AbstractRenderer           *m_renderer;
96 
97     /** Wind. */
98     Wind                 *m_wind;
99 
100     core::dimension2du m_actual_screen_size;
101 
102     /** The main MRT setup. */
103     core::array<video::IRenderTarget> m_mrt;
104 
105     /** Matrixes used in several places stored here to avoid recomputation. */
106     core::matrix4 m_ViewMatrix, m_InvViewMatrix, m_ProjMatrix, m_InvProjMatrix, m_ProjViewMatrix, m_InvProjViewMatrix;
107 
108 
109 private:
110     /** Flag to indicate if a resolution change is pending (which will be
111      *  acted upon in the next update). None means no change, yes means
112      *  change to new resolution and trigger confirmation dialog.
113      *  Yes_warn means that the new resolution is unsupported and that
114      *  the confirmation dialog needs an additional warning message.
115      *  Same indicates a change of the resolution (back to the original
116      *  one), but no confirmation dialog. */
117     enum {RES_CHANGE_NONE, RES_CHANGE_YES,
118           RES_CHANGE_SAME, RES_CHANGE_YES_WARN} m_resolution_changing;
119 
120 
121 public:
122     /** A simple class to store video resolutions. */
123     class VideoMode
124     {
125     private:
126         int m_width;
127         int m_height;
128     public:
VideoMode(int w,int h)129         VideoMode(int w, int h) {m_width=w; m_height=h; }
getWidth() const130         int getWidth() const  {return m_width;  }
getHeight() const131         int getHeight() const {return m_height; }
132     };   // VideoMode
133 
134     struct BloomData {
135         scene::ISceneNode * node;
136         float power;
137     };
138 
139     video::SColorf getAmbientLight() const;
140 
141 
142 
143 private:
144     std::vector<VideoMode> m_modes;
145 
146     void                  setupViewports();
147 
148     /** Whether the mouse cursor is currently shown */
149     bool                  m_pointer_shown;
150 
151     /** Store if the scene is complex (based on polycount, etc) */
152     int                  m_scene_complexity;
153 
154     /** Internal method that applies the resolution in user settings. */
155     void                 applyResolutionSettings(bool recreate_device);
156     void                 createListOfVideoModes();
157 
158     bool                 m_request_screenshot;
159 
160     bool                 m_ssaoviz;
161     bool                 m_shadowviz;
162     bool                 m_lightviz;
163     bool                 m_boundingboxesviz;
164     bool                 m_recording;
165     bool                 m_render_nw_debug;
166 
167     /** Background colour to reset a buffer. Can be changed by each track. */
168     irr::video::SColor m_clear_color;
169 
170 
171     unsigned             m_last_light_bucket_distance;
172     unsigned             m_skinning_joint;
173 
174     SP::SPDynamicDrawCall* m_sun_interposer;
175     core::vector3df m_sun_direction;
176     video::SColorf m_suncolor;
177 
178 
179     std::vector<LightNode *> m_lights;
180 
181     std::vector<BloomData> m_forcedbloom;
182 
183     std::vector<scene::ISceneNode *> m_background;
184 
185     float m_ssao_radius;
186     float m_ssao_k;
187     float m_ssao_sigma;
188 
189 #ifdef DEBUG
190     /** Used to visualise skeletons. */
191     std::vector<irr::scene::IAnimatedMeshSceneNode*> m_debug_meshes;
192 #endif
193     // ------------------------------------------------------------------------
194     void resizeWindow();
195 public:
196     void doScreenShot();
197 public:
198          IrrDriver();
199         ~IrrDriver();
200     void initDevice();
201     void reset();
202     void setMaxTextureSize();
203     void unsetMaxTextureSize();
204     void getOpenGLData(std::string *vendor, std::string *renderer,
205                        std::string *version);
206 
207     void increaseObjectCount();
208     core::array<video::IRenderTarget> &getMainSetup();
209     void updateConfigIfRelevant();
210     core::recti getSplitscreenWindow(int WindowNum);
211     void setAllMaterialFlags(scene::IMesh *mesh) const;
212     scene::IAnimatedMesh *getAnimatedMesh(const std::string &name);
213     scene::IMesh         *getMesh(const std::string &name);
214     void displayFPS();
215     void displayStoryModeTimer();
216     bool                  OnEvent(const irr::SEvent &event);
217     void                  setAmbientLight(const video::SColorf &light,
218                                           bool force_SH_computation = true);
219     video::ITexture      *getTexture(FileManager::AssetType type,
220                                      const std::string &filename,
221                                      bool is_premul=false,
222                                      bool is_prediv=false,
223                                      bool complain_if_not_found=true);
224     video::ITexture      *getTexture(const std::string &filename,
225                                      bool is_premul=false,
226                                      bool is_prediv=false,
227                                      bool complain_if_not_found=true);
228     void                  grabAllTextures(const scene::IMesh *mesh);
229     void                  dropAllTextures(const scene::IMesh *mesh);
230     scene::IMesh         *createQuadMesh(const video::SMaterial *material=NULL,
231                                          bool create_one_quad=false);
232     scene::IMesh         *createTexturedQuadMesh(const video::SMaterial *material,
233                                                  const double w, const double h);
234     scene::ISceneNode    *addWaterNode(scene::IMesh *mesh, scene::IMesh **welded,
235                                        float wave_height,
236                                        float wave_speed, float wave_length);
237     scene::IMeshSceneNode*addOctTree(scene::IMesh *mesh);
238     scene::ISceneNode* addSphere(float radius,
239                  const video::SColor &color=video::SColor(128, 255, 255, 255));
240     scene::ISceneNode* addMesh(scene::IMesh *mesh,
241                                const std::string& debug_name,
242                                scene::ISceneNode *parent = NULL,
243                                std::shared_ptr<RenderInfo> render_info = nullptr);
244     PerCameraNode        *addPerCameraNode(scene::ISceneNode* node,
245                                            scene::ICameraSceneNode* cam,
246                                            scene::ISceneNode *parent = NULL);
247     scene::ISceneNode    *addBillboard(const core::dimension2d< f32 > size,
248                                        const std::string& tex_name,
249                                        scene::ISceneNode* parent=NULL);
250     scene::IParticleSystemSceneNode
251                          *addParticleNode(bool default_emitter=true);
252     scene::ISceneNode    *addSkyDome(video::ITexture *texture, int hori_res,
253                                      int vert_res, float texture_percent,
254                                      float sphere_percent);
255     scene::ISceneNode    *addSkyBox(const std::vector<video::ITexture*> &texture_names,
256                                     const std::vector<video::ITexture*> &spherical_harmonics_textures);
257     void suppressSkyBox();
258     void                  removeNode(scene::ISceneNode *node);
259     void                  removeMeshFromCache(scene::IMesh *mesh);
260     void                  removeTexture(video::ITexture *t);
261     scene::IAnimatedMeshSceneNode
262         *addAnimatedMesh(scene::IAnimatedMesh *mesh,
263                          const std::string& debug_name,
264                          scene::ISceneNode* parent = NULL,
265                          std::shared_ptr<RenderInfo> render_info = nullptr);
266     scene::ICameraSceneNode
267                          *addCameraSceneNode();
268     Camera               *addCamera(unsigned int index, AbstractKart *kart);
269     void                  removeCameraSceneNode(scene::ICameraSceneNode *camera);
270     void                  removeCamera(Camera *camera);
271     void                  update(float dt, bool loading=false);
272     /** Call to change resolution */
273     void                  changeResolution(const int w, const int h, const bool fullscreen);
274   /** Call this to roll back to the previous resolution if a resolution switch attempt goes bad */
275     void                  cancelResChange();
276 
277     bool                  moveWindow(int x, int y);
278 
279     void                  showPointer();
280     void                  hidePointer();
setLastLightBucketDistance(unsigned d)281     void                  setLastLightBucketDistance(unsigned d) { m_last_light_bucket_distance = d; }
setSkinningJoint(unsigned d)282     void                  setSkinningJoint(unsigned d) { m_skinning_joint = d; }
isPointerShown() const283     bool                  isPointerShown() const { return m_pointer_shown; }
284     core::position2di     getMouseLocation();
285 
286     void                  printRenderStats();
287     void                  requestScreenshot();
288     class GPUTimer        &getGPUTimer(unsigned);
289     const char*           getGPUQueryPhaseName(unsigned);
290 
291 #ifndef SERVER_ONLY
292     std::unique_ptr<RenderTarget> createRenderTarget(const irr::core::dimension2du &dimension,
293                                                      const std::string &name);
294 #endif
295     // ------------------------------------------------------------------------
296     /** Returns the color to clear the back buffer. */
getClearColor() const297     const irr::video::SColor& getClearColor() const { return m_clear_color; }
298     // ------------------------------------------------------------------------
299     /** Sets the color to use when clearing the back buffer. */
setClearbackBufferColor(irr::video::SColor color)300     void setClearbackBufferColor(irr::video::SColor color)
301     {
302         m_clear_color = color;
303     }   // setClearbackBufferColor
304 
305 
306     /** Returns a list of all video modes supports by the graphics card. */
getVideoModes() const307     const std::vector<VideoMode>& getVideoModes() const { return m_modes; }
308     // ------------------------------------------------------------------------
309     /** Returns the frame size. */
getFrameSize() const310     const core::dimension2d<u32>& getFrameSize() const
311                        { return m_video_driver->getCurrentRenderTargetSize(); }
312     // ------------------------------------------------------------------------
313     /** Returns the irrlicht device. */
getDevice() const314     IrrlichtDevice       *getDevice()       const { return m_device;        }
315     // ------------------------------------------------------------------------
316     /** Returns the irrlicht video driver. */
getVideoDriver() const317     video::IVideoDriver  *getVideoDriver()  const { return m_video_driver;  }
318     // ------------------------------------------------------------------------
319     /** Returns the irrlicht scene manager. */
getSceneManager() const320     scene::ISceneManager *getSceneManager() const { return m_scene_manager; }
321     // ------------------------------------------------------------------------
322     /** Returns the gui environment, used to add widgets to a screen. */
getGUI() const323     gui::IGUIEnvironment *getGUI() const { return m_gui_env; }
324     // ------------------------------------------------------------------------
325     /** Returns the current real time, which might not be 0 at start of the
326      *  application. Value in msec. */
getRealTime()327     unsigned int getRealTime() {return m_device->getTimer()->getRealTime(); }
328     // ------------------------------------------------------------------------
329     /** Use motion blur for a short time */
giveBoost(unsigned int cam_index)330     void giveBoost(unsigned int cam_index) { m_renderer->giveBoost(cam_index);}
331     // ------------------------------------------------------------------------
getWind()332     inline core::vector3df getWind()  {return m_wind->getWind();}
333 
334     // -----------------------------------------------------------------------
335     /** Returns a pointer to the spherical harmonics coefficients. */
getSHCoefficients()336     inline const SHCoefficients* getSHCoefficients()  {return m_renderer->getSHCoefficients();}
337     // -----------------------------------------------------------------------
getSunDirection() const338     const core::vector3df& getSunDirection() const { return m_sun_direction; };
339     // -----------------------------------------------------------------------
setSunDirection(const core::vector3df & SunPos)340     void setSunDirection(const core::vector3df &SunPos)
341     {
342         m_sun_direction = SunPos;
343     }
344     // -----------------------------------------------------------------------
getSunColor() const345     video::SColorf getSunColor() const { return m_suncolor; }
346     // -----------------------------------------------------------------------
setSunColor(const video::SColorf & col)347     void setSunColor(const video::SColorf &col)
348     {
349         m_suncolor = col;
350     }
351     // ------------------------------------------------------------------------
352     GLuint getRenderTargetTexture(TypeRTT which);
353     GLuint getDepthStencilTexture();
354     // ------------------------------------------------------------------------
355     void resetDebugModes();
356     // ------------------------------------------------------------------------
toggleSSAOViz()357     void toggleSSAOViz()          { m_ssaoviz = !m_ssaoviz;         }
358     // ------------------------------------------------------------------------
getSSAOViz()359     bool getSSAOViz()             { return m_ssaoviz;               }
360     // ------------------------------------------------------------------------
toggleShadowViz()361     void toggleShadowViz()        { m_shadowviz = !m_shadowviz;     }
362     // ------------------------------------------------------------------------
getShadowViz()363     bool getShadowViz()           { return m_shadowviz;             }
364     // ------------------------------------------------------------------------
toggleBoundingBoxesViz()365     void toggleBoundingBoxesViz() { m_boundingboxesviz = !m_boundingboxesviz; }
366     // ------------------------------------------------------------------------
toggleRenderNetworkDebug()367     void toggleRenderNetworkDebug() { m_render_nw_debug = !m_render_nw_debug; }
368     // ------------------------------------------------------------------------
getRenderNetworkDebug() const369     bool getRenderNetworkDebug() const            { return m_render_nw_debug; }
370     // ------------------------------------------------------------------------
371     void renderNetworkDebug();
372     // ------------------------------------------------------------------------
getBoundingBoxesViz()373     bool getBoundingBoxesViz()    { return m_boundingboxesviz;      }
374     // ------------------------------------------------------------------------
getSceneComplexity()375     int getSceneComplexity() { return m_scene_complexity;           }
resetSceneComplexity()376     void resetSceneComplexity() { m_scene_complexity = 0;           }
addSceneComplexity(int complexity)377     void addSceneComplexity(int complexity)
378     {
379         if (complexity > 1) m_scene_complexity += (complexity - 1);
380     }
381     // ------------------------------------------------------------------------
isRecording() const382     bool isRecording() const { return m_recording; }
383     // ------------------------------------------------------------------------
384     void setRecording(bool val);
385     // ------------------------------------------------------------------------
getLights()386     std::vector<LightNode *> getLights() { return m_lights; }
387     // ------------------------------------------------------------------------
addGlowingNode(scene::ISceneNode * n,float r=1.0f,float g=1.0f,float b=1.0f)388     void addGlowingNode(scene::ISceneNode *n, float r = 1.0f, float g = 1.0f,
389                         float b = 1.0f)
390     {
391         m_renderer->addGlowingNode(n, r, g, b);
392     }
393     // ------------------------------------------------------------------------
clearGlowingNodes()394     void clearGlowingNodes() { m_renderer->clearGlowingNodes(); }
395     // ------------------------------------------------------------------------
addForcedBloomNode(scene::ISceneNode * n,float power=1)396     void addForcedBloomNode(scene::ISceneNode *n, float power = 1)
397     {
398         BloomData dat;
399         dat.node = n;
400         dat.power = power;
401 
402         m_forcedbloom.push_back(dat);
403     }
404     // ------------------------------------------------------------------------
clearForcedBloom()405     void clearForcedBloom() { m_forcedbloom.clear(); }
406     // ------------------------------------------------------------------------
getForcedBloom() const407     const std::vector<BloomData> &getForcedBloom() const
408     {
409         return m_forcedbloom;
410     }
411     // ------------------------------------------------------------------------
clearBackgroundNodes()412     void clearBackgroundNodes() { m_background.clear(); }
413     // ------------------------------------------------------------------------
addBackgroundNode(scene::ISceneNode * const n)414     void addBackgroundNode(scene::ISceneNode * const n)
415     {
416         m_background.push_back(n);
417     }
418     // ------------------------------------------------------------------------
419     scene::ISceneNode *addLight(const core::vector3df &pos, float energy,
420                                 float radius, float r, float g, float b,
421                                 bool sun = false,
422                                 scene::ISceneNode* parent = NULL);
423     // ------------------------------------------------------------------------
424     void clearLights();
425     // ------------------------------------------------------------------------
getSunInterposer()426     SP::SPDynamicDrawCall* getSunInterposer() { return m_sun_interposer; }
427     // ------------------------------------------------------------------------
428 
429     void cleanSunInterposer();
430     void createSunInterposer();
431     // ------------------------------------------------------------------------
setViewMatrix(core::matrix4 matrix)432     void setViewMatrix(core::matrix4 matrix)
433     {
434         m_ViewMatrix = matrix; matrix.getInverse(m_InvViewMatrix);
435     }
436     // ------------------------------------------------------------------------
getViewMatrix() const437     const core::matrix4 &getViewMatrix() const { return m_ViewMatrix; }
438     // ------------------------------------------------------------------------
getInvViewMatrix() const439     const core::matrix4 &getInvViewMatrix() const { return m_InvViewMatrix; }
440     // ------------------------------------------------------------------------
setProjMatrix(core::matrix4 matrix)441     void setProjMatrix(core::matrix4 matrix)
442     {
443         m_ProjMatrix = matrix; matrix.getInverse(m_InvProjMatrix);
444     }
445     // ------------------------------------------------------------------------
getProjMatrix() const446     const core::matrix4 &getProjMatrix() const { return m_ProjMatrix; }
447     // ------------------------------------------------------------------------
getInvProjMatrix() const448     const core::matrix4 &getInvProjMatrix() const { return m_InvProjMatrix; }
449     // ------------------------------------------------------------------------
genProjViewMatrix()450     void genProjViewMatrix()
451     {
452         m_ProjViewMatrix = m_ProjMatrix * m_ViewMatrix;
453         m_InvProjViewMatrix = m_ProjViewMatrix;
454         m_InvProjViewMatrix.makeInverse();
455     }
456     // ------------------------------------------------------------------------
getProjViewMatrix() const457     const core::matrix4 &getProjViewMatrix() const { return m_ProjViewMatrix; }
458     // ------------------------------------------------------------------------
getInvProjViewMatrix() const459     const core::matrix4 &getInvProjViewMatrix() const
460     {
461         return m_InvProjViewMatrix;
462     }
463     // ------------------------------------------------------------------------
getCurrentScreenSize() const464     const core::vector2df &getCurrentScreenSize() const
465     {
466         return m_renderer->getCurrentScreenSize();
467     }
468     // ------------------------------------------------------------------------
getActualScreenSize() const469     const core::dimension2du getActualScreenSize() const
470     {
471         return m_actual_screen_size;
472     }
473     // ------------------------------------------------------------------------
getSSAORadius() const474     float getSSAORadius() const
475     {
476         return m_ssao_radius;
477     }
478 
479     // ------------------------------------------------------------------------
setSSAORadius(float v)480     void setSSAORadius(float v)
481     {
482         m_ssao_radius = v;
483     }
484 
485     // ------------------------------------------------------------------------
getSSAOK() const486     float getSSAOK() const
487     {
488         return m_ssao_k;
489     }
490 
491     // ------------------------------------------------------------------------
setSSAOK(float v)492     void setSSAOK(float v)
493     {
494         m_ssao_k = v;
495     }
496 
497     // ------------------------------------------------------------------------
getSSAOSigma() const498     float getSSAOSigma() const
499     {
500         return m_ssao_sigma;
501     }
502 
503     // ------------------------------------------------------------------------
setSSAOSigma(float v)504     void setSSAOSigma(float v)
505     {
506         m_ssao_sigma = v;
507     }
508 #ifdef DEBUG
getDebugMeshes()509     std::vector<scene::IAnimatedMeshSceneNode*> getDebugMeshes()
510     {
511         return m_debug_meshes;
512     }
513     /** Removes debug meshes. */
clearDebugMesh()514     void clearDebugMesh() { m_debug_meshes.clear(); }
515     // ------------------------------------------------------------------------
516     /** Adds a debug mesh to be displaed. */
addDebugMesh(scene::IAnimatedMeshSceneNode * node)517     void addDebugMesh(scene::IAnimatedMeshSceneNode *node)
518     {
519         m_debug_meshes.push_back(node);
520     }   // addDebugMesh
521 
522 #endif
523     void onLoadWorld();
524     void onUnloadWorld();
525 
526     void updateSplitAndLightcoordRangeFromComputeShaders(size_t width,
527                                                          size_t height);
528 
529     void uploadLightingData();
sameRestart()530     void sameRestart()             { m_resolution_changing = RES_CHANGE_SAME; }
531     // ------------------------------------------------------------------------
getDefaultFramebuffer() const532     u32 getDefaultFramebuffer() const
533                             { return m_video_driver->getDefaultFramebuffer(); }
534     // ------------------------------------------------------------------------
535     void handleWindowResize();
536 };   // IrrDriver
537 
538 extern IrrDriver *irr_driver;
539 
540 #endif   // HEADER_IRR_DRIVER_HPP
541