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