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