1 // ============================================================================= 2 // PROJECT CHRONO - http://projectchrono.org 3 // 4 // Copyright (c) 2014 projectchrono.org 5 // All rights reserved. 6 // 7 // Use of this source code is governed by a BSD-style license that can be found 8 // in the LICENSE file at the top level of the distribution and at 9 // http://projectchrono.org/license-chrono.txt. 10 // 11 // ============================================================================= 12 13 #ifndef CHIRRAPPINTERFACE_H 14 #define CHIRRAPPINTERFACE_H 15 16 #include <vector> 17 18 #include <irrlicht.h> 19 20 #include "chrono/core/ChRealtimeStep.h" 21 #include "chrono/physics/ChSystem.h" 22 23 #include "chrono_irrlicht/ChApiIrr.h" 24 #include "chrono_irrlicht/ChIrrEffects.h" 25 #include "chrono_irrlicht/ChIrrTools.h" 26 #include "chrono_irrlicht/ChIrrUtils.h" 27 28 #ifdef CHRONO_POSTPROCESS 29 #include "chrono_postprocess/ChPovRay.h" 30 #endif 31 32 namespace chrono { 33 namespace irrlicht { 34 35 /// @addtogroup irrlicht_module 36 /// @{ 37 38 // Forward reference 39 class ChIrrAppEventReceiver; 40 41 /// Vertical direction 42 enum class VerticalDir { Y, Z }; 43 44 /// Class to add some GUI to Irrlicht + ChronoEngine applications. 45 /// This basic GUI can be used to monitor solver timings, to easily change 46 /// physical system settings, etc. 47 class ChApiIrr ChIrrAppInterface { 48 public: 49 /// Create the IRRLICHT context (device, etc.) 50 ChIrrAppInterface(ChSystem* psystem, 51 const std::wstring& title = L"Chrono", 52 const irr::core::dimension2d<irr::u32>& dimens = irr::core::dimension2d<irr::u32>(640, 480), 53 VerticalDir vert = VerticalDir::Y, 54 bool do_fullscreen = false, 55 bool do_shadows = false, 56 bool do_antialias = true, 57 irr::video::E_DRIVER_TYPE mydriver = irr::video::EDT_DIRECT3D9, 58 irr::ELOG_LEVEL log_level = irr::ELL_INFORMATION); 59 60 /// Safely delete all Irrlicht items (including the Irrlicht scene nodes) 61 virtual ~ChIrrAppInterface(); 62 63 //// Accessor functions GetDevice()64 irr::IrrlichtDevice* GetDevice() { return device; } GetVideoDriver()65 irr::video::IVideoDriver* GetVideoDriver() { return device->getVideoDriver(); } GetSceneManager()66 irr::scene::ISceneManager* GetSceneManager() { return device->getSceneManager(); } GetActiveCamera()67 irr::scene::ICameraSceneNode* GetActiveCamera() { return device->getSceneManager()->getActiveCamera(); } GetIGUIEnvironment()68 irr::gui::IGUIEnvironment* GetIGUIEnvironment() { return device->getGUIEnvironment(); } GetEffects()69 EffectHandler* GetEffects() { return effect.get(); } GetContainer()70 irr::scene::ISceneNode* GetContainer() { return container; } GetSystem()71 ChSystem* GetSystem() { return system; } 72 73 /// Show the info panel in the 3D view SetShowInfos(bool val)74 void SetShowInfos(bool val) { show_infos = val; } GetShowInfos()75 bool GetShowInfos() { return show_infos; } 76 77 /// Show the realtime profiler in the 3D view SetShowProfiler(bool val)78 void SetShowProfiler(bool val) { show_profiler = val; } GetShowProfiler()79 bool GetShowProfiler() { return show_profiler; } 80 81 /// Show the object explorer SetShowExplorer(bool val)82 void SetShowExplorer(bool val) { show_explorer = val; } GetShowExplorer()83 bool GetShowExplorer() { return show_explorer; } 84 85 /// Set/Get the time step for time integration. This value is used when 86 /// calling DoStep() in a loop, to advance the simulation by one timestep. 87 void SetTimestep(double val); GetTimestep()88 double GetTimestep() { return timestep; } 89 90 /// If set to true, you can use DoStep() in the simulation loop to advance the 91 /// simulation by one timestep. Otherwise, you have to handle the time 92 /// stepping by yourself, e.g. by calling ChSystem::DoStepDynamics(). 93 /// Default: true. SetStepManage(bool val)94 void SetStepManage(bool val) { step_manage = val; } 95 96 /// If enabled, the function DoStep() will enforce soft real-time, by spinning in place until simulation time 97 /// catches up with real time. SetTryRealtime(bool val)98 void SetTryRealtime(bool val) { try_realtime = val; } 99 100 /// Set/Get the simulation state (running or paused) SetPaused(bool val)101 void SetPaused(bool val) { pause_step = val; } GetPaused()102 bool GetPaused() { return pause_step; } 103 104 /// If set to true, each frame of the animation will be saved on the disk 105 /// as snapshot0001.bmp, snapshot0002.bmp, etc. SetVideoframeSave(bool val)106 void SetVideoframeSave(bool val) { videoframe_save = val; } GetVideoframeSave()107 bool GetVideoframeSave() { return videoframe_save; } 108 109 /// Set to 1 if you need to save on disk all simulation steps, set to 2 for 110 /// saving each 2 steps, etc. SetVideoframeSaveInterval(int val)111 void SetVideoframeSaveInterval(int val) { videoframe_each = val; } GetVideoframeSaveInterval()112 int GetVideoframeSaveInterval() { return videoframe_each; } 113 114 #ifdef CHRONO_POSTPROCESS 115 116 /// If set to true, each frame of the animation will be saved on the disk 117 /// as a sequence of scripts to be rendered via POVray. Only if solution build with ENABLE_MODULE_POSTPROCESS. 118 void SetPOVraySave(bool val); GetPOVraySave()119 bool GetPOVraySave() { return povray_save; } 120 121 /// Set to 1 if you need to save on disk all simulation steps, set to 2 for 122 /// saving each 2 steps, etc. SetPOVraySaveInterval(int val)123 void SetPOVraySaveInterval(int val) { povray_each = val; } GetPOVrayframeSaveInterval()124 int GetPOVrayframeSaveInterval() { return povray_each; } 125 126 /// Access the internal ChPovRay exporter, for advanced tweaking. 127 /// Returns 0 if not yet started (use SetPOVraySave(true) to start it) GetPOVrayexporter()128 postprocess::ChPovRay* GetPOVrayexporter() { return pov_exporter.get(); } 129 130 #endif 131 132 /// Set the label mode for contacts SetContactsLabelMode(IrrContactsLabelMode mm)133 void SetContactsLabelMode(IrrContactsLabelMode mm) { this->gad_labelcontacts->setSelected((int)mm); } 134 /// Set the draw mode for contacts SetContactsDrawMode(IrrContactsDrawMode mm)135 void SetContactsDrawMode(IrrContactsDrawMode mm) { this->gad_drawcontacts->setSelected((int)mm); } 136 /// Set the label mode for links SetLinksLabelMode(IrrLinkLabelMode mm)137 void SetLinksLabelMode(IrrLinkLabelMode mm) { this->gad_labellinks->setSelected((int)mm); } 138 /// Set the draw mode for links SetLinksDrawMode(IrrLinkDrawMode mm)139 void SetLinksDrawMode(IrrLinkDrawMode mm) { this->gad_drawlinks->setSelected((int)mm); } 140 /// Set if the AABB collision shapes will be plotted SetPlotAABB(bool val)141 void SetPlotAABB(bool val) { this->gad_plot_aabb->setChecked(val); } 142 /// Set if the COG frames will be plotted SetPlotCOGFrames(bool val)143 void SetPlotCOGFrames(bool val) { this->gad_plot_cogs->setChecked(val); } 144 /// Set if the Bullet collision shapes will be plotted SetPlotCollisionShapes(bool val)145 void SetPlotCollisionShapes(bool val) { this->gad_plot_collisionshapes->setChecked(val); } 146 /// Set if the link frames will be plotted SetPlotLinkFrames(bool val)147 void SetPlotLinkFrames(bool val) { this->gad_plot_linkframes->setChecked(val); } 148 /// Set if the COG frames will be plotted SetPlotConvergence(bool val)149 void SetPlotConvergence(bool val) { this->gad_plot_convergence->setChecked(val); } 150 151 /// Set the scale for symbol drawing (link frames, COGs, etc.) 152 void SetSymbolscale(double val); GetSymbolscale()153 double GetSymbolscale() { return symbolscale; } 154 155 /// Use this function to hook a custom event receiver to the application. SetUserEventReceiver(irr::IEventReceiver * mreceiver)156 void SetUserEventReceiver(irr::IEventReceiver* mreceiver) { user_receivers.push_back(mreceiver); } 157 158 /// Set the fonts to be used from now on. Note that the font must be in the 159 /// XML format of Irrlicht - this can be generated using a tool provided with 160 /// Irrlicht. 161 void SetFonts(const std::string& mfontdir = GetChronoDataFile("fonts/arial8.xml")); 162 163 /// Call this to clean the canvas at the beginning of each animation frame 164 virtual void BeginScene(bool backBuffer = true, 165 bool zBuffer = true, 166 irr::video::SColor color = irr::video::SColor(255, 0, 0, 0)); 167 168 /// Call this function inside a loop such as 169 /// <pre> 170 /// while(application.GetDevice()->run()) {...} 171 /// </pre> 172 /// in order to advance the dynamics by one timestep. The value of the timestep can be set via SetTimestep(). 173 /// Optionally, you can use SetTryRealtime(true) if your simulation can run in realtime; this will enforce soft 174 /// real-time. Alternatively, to use ChSystem::DoStepDynamics() directly in the loop, use SetStepManage(false). 175 virtual void DoStep(); 176 177 /// Call this function inside a loop such as 178 /// <pre> 179 /// while(application.GetDevice()->run()) {...} 180 /// </pre> 181 /// to draw all 3D shapes and GUI elements at the current frame. 182 virtual void DrawAll(); 183 184 /// Call this to end the scene draw at the end of each animation frame 185 virtual void EndScene(); 186 187 /// Dump the last used system matrices and vectors in the current directory, 188 /// as 'dump_xxxx.dat' files that can be loaded with Matlab for debugging, 189 /// benchmarking etc. It saves M mass matrix, Cq jacobians, E compliance 190 /// as Matlab sparse matrix format, and known vectors fb, bi as column Matlab 191 /// matrices. 192 void DumpSystemMatrices(); 193 194 // 195 // Some wrapper functions for 'easy setup' of the application window: 196 // 197 198 void AddTypicalLogo(const std::string& mlogofilename = GetChronoDataFile("logo_chronoengine_alpha.png")); 199 200 void AddTypicalCamera(irr::core::vector3df pos = irr::core::vector3df(0, 0, -8), 201 irr::core::vector3df targ = irr::core::vector3df(0, 0, 0)); 202 203 void AddTypicalLights(irr::core::vector3df pos1 = irr::core::vector3df(30.f, 100.f, 30.f), 204 irr::core::vector3df pos2 = irr::core::vector3df(30.f, 80.f, -30.f), 205 double rad1 = 290, 206 double rad2 = 190, 207 irr::video::SColorf col1 = irr::video::SColorf(0.7f, 0.7f, 0.7f, 1.0f), 208 irr::video::SColorf col2 = irr::video::SColorf(0.7f, 0.8f, 0.8f, 1.0f)); 209 210 void AddTypicalSky(const std::string& mtexturedir = GetChronoDataFile("skybox/")); 211 212 /// Add a point light to the scene 213 irr::scene::ILightSceneNode* AddLight(irr::core::vector3df pos, 214 double radius, 215 irr::video::SColorf color = irr::video::SColorf(0.7f, 0.7f, 0.7f, 1.0f)); 216 217 /// Add a point light that cast shadow (using soft shadows/shadow maps) 218 /// Note that the quality of the shadow strictly depends on how you set 'mnear' 219 /// and 'mfar' parameters as close as possible to the bounding box of the scene. 220 /// NOTE: use myapplication.AddShadow(myitem) to enable shadow for an object! 221 /// Otherwise, use myapplication.AddShadowAll(). 222 irr::scene::ILightSceneNode* AddLightWithShadow(irr::core::vector3df pos, 223 irr::core::vector3df aim, 224 double radius, 225 double mnear, 226 double mfar, 227 double angle, 228 irr::u32 resolution = 512, 229 irr::video::SColorf color = irr::video::SColorf(1.f, 1.f, 1.f, 1.f), 230 bool directional = false, 231 bool clipborder = true); 232 233 private: 234 // The Irrlicht engine: 235 irr::IrrlichtDevice* device; 236 237 // Xeffects for shadow maps! 238 std::unique_ptr<EffectHandler> effect; 239 bool use_effects; 240 241 // The ChronoEngine system: 242 ChSystem* system; 243 244 std::unique_ptr<ChIrrAppEventReceiver> receiver; 245 246 std::vector<irr::IEventReceiver*> user_receivers; 247 248 irr::scene::ISceneNode* container; 249 250 bool y_up; 251 252 bool show_infos; 253 bool show_profiler; 254 bool show_explorer; 255 256 bool step_manage; 257 bool pause_step; 258 bool try_realtime; 259 double timestep; 260 bool do_single_step; 261 bool videoframe_save; 262 int videoframe_num; 263 int videoframe_each; 264 265 #ifdef CHRONO_POSTPROCESS 266 bool povray_save; 267 std::unique_ptr<postprocess::ChPovRay> pov_exporter; 268 int povray_num; 269 int povray_each; 270 #endif 271 272 double symbolscale; 273 274 double camera_auto_rotate_speed; 275 276 ChRealtimeStepTimer m_realtime_timer; 277 278 irr::gui::IGUITabControl* gad_tabbed; 279 irr::gui::IGUITab* gad_tab1; 280 irr::gui::IGUITab* gad_tab2; 281 irr::gui::IGUITab* gad_tab3; 282 283 irr::gui::IGUIStaticText* gad_textFPS; 284 irr::gui::IGUIComboBox* gad_drawcontacts; 285 irr::gui::IGUIComboBox* gad_labelcontacts; 286 irr::gui::IGUIComboBox* gad_drawlinks; 287 irr::gui::IGUIComboBox* gad_labellinks; 288 irr::gui::IGUICheckBox* gad_plot_aabb; 289 irr::gui::IGUICheckBox* gad_plot_cogs; 290 irr::gui::IGUICheckBox* gad_plot_collisionshapes; 291 irr::gui::IGUICheckBox* gad_plot_linkframes; 292 irr::gui::IGUICheckBox* gad_plot_convergence; 293 294 irr::gui::IGUIScrollBar* gad_speed_iternumber; 295 irr::gui::IGUIStaticText* gad_speed_iternumber_info; 296 irr::gui::IGUIScrollBar* gad_clamping; 297 irr::gui::IGUIStaticText* gad_clamping_info; 298 irr::gui::IGUIScrollBar* gad_minbounce; 299 irr::gui::IGUIStaticText* gad_minbounce_info; 300 irr::gui::IGUICheckBox* gad_usesleep; 301 irr::gui::IGUIComboBox* gad_ccpsolver; 302 irr::gui::IGUIComboBox* gad_stepper; 303 irr::gui::IGUIEditBox* gad_timestep; 304 irr::gui::IGUIStaticText* gad_timestep_info; 305 irr::gui::IGUICheckBox* gad_try_realtime; 306 irr::gui::IGUICheckBox* gad_pause_step; 307 irr::gui::IGUIEditBox* gad_symbolscale; 308 irr::gui::IGUIStaticText* gad_symbolscale_info; 309 irr::gui::IGUIStaticText* gad_textHelp; 310 311 irr::gui::IGUITreeView* gad_treeview; 312 313 friend class ChIrrAppEventReceiver; 314 }; 315 316 /// @} irrlicht_module 317 318 } // end namespace irrlicht 319 } // end namespace chrono 320 321 #endif 322