1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2013-2015 Lionel Fuentes
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 #include "debug.hpp"
20 
21 #include "config/user_config.hpp"
22 #include "font/bold_face.hpp"
23 #include "font/digit_face.hpp"
24 #include "font/font_manager.hpp"
25 #include "font/regular_face.hpp"
26 #include "graphics/camera_debug.hpp"
27 #include "graphics/camera_fps.hpp"
28 #include "graphics/stk_text_billboard.hpp"
29 #include "karts/explosion_animation.hpp"
30 #include "graphics/irr_driver.hpp"
31 #include "graphics/light.hpp"
32 #include "graphics/shader.hpp"
33 #include "graphics/sp/sp_base.hpp"
34 #include "graphics/sp/sp_shader_manager.hpp"
35 #include "graphics/sp/sp_shader.hpp"
36 #include "graphics/sp/sp_texture_manager.hpp"
37 #include "graphics/sp/sp_uniform_assigner.hpp"
38 #include "guiengine/modaldialog.hpp"
39 #include "guiengine/screen_keyboard.hpp"
40 #include "guiengine/widgets/label_widget.hpp"
41 #include "guiengine/widgets/text_box_widget.hpp"
42 #include "items/powerup_manager.hpp"
43 #include "items/attachment.hpp"
44 #include "karts/abstract_kart.hpp"
45 #include "karts/kart_properties.hpp"
46 #include "karts/controller/controller.hpp"
47 #include "modes/cutscene_world.hpp"
48 #include "modes/world.hpp"
49 #include "physics/irr_debug_drawer.hpp"
50 #include "physics/physics.hpp"
51 #include "race/history.hpp"
52 #include "main_loop.hpp"
53 #include "replay/replay_recorder.hpp"
54 #include "scriptengine/script_engine.hpp"
55 #include "states_screens/dialogs/debug_slider.hpp"
56 #include "states_screens/dialogs/general_text_field_dialog.hpp"
57 #include "tracks/track_manager.hpp"
58 #include "utils/constants.hpp"
59 #include "utils/log.hpp"
60 #include "utils/profiler.hpp"
61 #include "utils/string_utils.hpp"
62 
63 #include <IGUIEnvironment.h>
64 #include <IGUIContextMenu.h>
65 
66 #include <cmath>
67 
68 using namespace irr;
69 using namespace gui;
70 
71 namespace Debug {
72 
73 /** This is to let mouse input events go through when the debug menu is
74  *  visible, otherwise GUI events would be blocked while in a race...
75  */
76 static bool g_debug_menu_visible = false;
77 
78 // -----------------------------------------------------------------------------
79 // Commands for the debug menu
80 enum DebugMenuCommand
81 {
82     //! graphics commands
83     DEBUG_GRAPHICS_RELOAD_SHADERS,
84     DEBUG_GRAPHICS_RESET,
85     DEBUG_GRAPHICS_SSAO_VIZ,
86     DEBUG_GRAPHICS_SHADOW_VIZ,
87     DEBUG_GRAPHICS_BOUNDING_BOXES_VIZ,
88     DEBUG_GRAPHICS_BULLET_1,
89     DEBUG_GRAPHICS_BULLET_2,
90     DEBUG_PROFILER,
91     DEBUG_PROFILER_WRITE_REPORT,
92     DEBUG_FONT_DUMP_GLYPH_PAGE,
93     DEBUG_FONT_RELOAD,
94     DEBUG_SP_RESET,
95     DEBUG_SP_TOGGLE_CULLING,
96     DEBUG_SP_WN_VIZ,
97     DEBUG_SP_NORMALS_VIZ,
98     DEBUG_SP_TANGENTS_VIZ,
99     DEBUG_SP_BITANGENTS_VIZ,
100     DEBUG_SP_WIREFRAME_VIZ,
101     DEBUG_SP_TN_VIZ,
102     DEBUG_FPS,
103     DEBUG_SAVE_REPLAY,
104     DEBUG_SAVE_HISTORY,
105     DEBUG_POWERUP_BOWLING,
106     DEBUG_POWERUP_BUBBLEGUM,
107     DEBUG_POWERUP_CAKE,
108     DEBUG_POWERUP_PARACHUTE,
109     DEBUG_POWERUP_PLUNGER,
110     DEBUG_POWERUP_RUBBERBALL,
111     DEBUG_POWERUP_SWATTER,
112     DEBUG_POWERUP_SWITCH,
113     DEBUG_POWERUP_ZIPPER,
114     DEBUG_POWERUP_NITRO,
115     DEBUG_ATTACHMENT_PARACHUTE,
116     DEBUG_ATTACHMENT_BOMB,
117     DEBUG_ATTACHMENT_ANVIL,
118     DEBUG_ATTACHMENT_EXPLOSION,
119     DEBUG_GUI_TOGGLE,
120     DEBUG_GUI_HIDE_KARTS,
121     DEBUG_GUI_CAM_FREE,
122     DEBUG_GUI_CAM_TOP,
123     DEBUG_GUI_CAM_WHEEL,
124     DEBUG_GUI_CAM_BEHIND_KART,
125     DEBUG_GUI_CAM_SIDE_OF_KART,
126     DEBUG_GUI_CAM_NORMAL,
127     DEBUG_GUI_CAM_SMOOTH,
128     DEBUG_GUI_CAM_ATTACH,
129     DEBUG_VIEW_KART_PREVIOUS,
130     DEBUG_VIEW_KART_ONE,
131     DEBUG_VIEW_KART_TWO,
132     DEBUG_VIEW_KART_THREE,
133     DEBUG_VIEW_KART_FOUR,
134     DEBUG_VIEW_KART_FIVE,
135     DEBUG_VIEW_KART_SIX,
136     DEBUG_VIEW_KART_SEVEN,
137     DEBUG_VIEW_KART_EIGHT,
138     DEBUG_VIEW_KART_NEXT,
139     DEBUG_HIDE_KARTS,
140     DEBUG_THROTTLE_FPS,
141     DEBUG_VISUAL_VALUES,
142     DEBUG_PRINT_START_POS,
143     DEBUG_ADJUST_LIGHTS,
144     DEBUG_SCRIPT_CONSOLE,
145     DEBUG_RUN_CUTSCENE,
146     DEBUG_TEXTURE_CONSOLE,
147     DEBUG_RENDER_NW_DEBUG,
148     DEBUG_START_RECORDING,
149     DEBUG_STOP_RECORDING
150 };   // DebugMenuCommand
151 
152 // -----------------------------------------------------------------------------
153 /** Add powerup selected from debug menu for all player karts */
addPowerup(PowerupManager::PowerupType powerup)154 void addPowerup(PowerupManager::PowerupType powerup)
155 {
156     World* world = World::getWorld();
157     if (!world) return;
158     for(unsigned int i = 0; i < RaceManager::get()->getNumLocalPlayers(); i++)
159     {
160         AbstractKart* kart = world->getLocalPlayerKart(i);
161         kart->setPowerup(powerup, 10000);
162     }
163 }   // addPowerup
164 
165 // ----------------------------------------------------------------------------
addAttachment(Attachment::AttachmentType type)166 void addAttachment(Attachment::AttachmentType type)
167 {
168     World* world = World::getWorld();
169     if (world == NULL) return;
170     for (unsigned int i = 0; i < world->getNumKarts(); i++)
171     {
172         AbstractKart *kart = world->getKart(i);
173         if (!kart->getController()->isLocalPlayerController())
174             continue;
175         if (type == Attachment::ATTACH_ANVIL)
176         {
177             kart->getAttachment()
178                 ->set(type,
179                       stk_config->time2Ticks(kart->getKartProperties()
180                                                  ->getAnvilDuration()) );
181             kart->adjustSpeed(kart->getKartProperties()->getAnvilSpeedFactor());
182         }
183         else if (type == Attachment::ATTACH_PARACHUTE)
184         {
185             kart->getAttachment()
186                 ->set(type, stk_config->time2Ticks(
187                 kart->getKartProperties()->getParachuteDuration()));
188         }
189         else if (type == Attachment::ATTACH_BOMB)
190         {
191             kart->getAttachment()
192                 ->set(type, stk_config->time2Ticks(stk_config->m_bomb_time) );
193         }
194     }
195 
196 }   // addAttachment
197 
198 // ----------------------------------------------------------------------------
changeCameraTarget(u32 num)199 void changeCameraTarget(u32 num)
200 {
201     World* world = World::getWorld();
202     Camera *cam = Camera::getActiveCamera();
203     if (world == NULL || cam == NULL) return;
204 
205     if (num < (world->getNumKarts() + 1))
206     {
207         AbstractKart* kart = world->getKart(num - 1);
208         if (kart == NULL) return;
209         cam->setMode(Camera::CM_NORMAL);
210         cam->setKart(kart);
211     }
212 
213 }   // changeCameraTarget
214 
215 // -----------------------------------------------------------------------------
216 
217 /** returns the light node with the lowest distance to the player kart (excluding
218  * nitro emitters) */
findNearestLight()219 LightNode* findNearestLight()
220 {
221 
222     Camera* camera = Camera::getActiveCamera();
223     if (camera == NULL) {
224         Log::error("[Debug Menu]", "No camera found.");
225         return NULL;
226     }
227 
228     core::vector3df cam_pos = camera->getCameraSceneNode()->getAbsolutePosition();
229     LightNode* nearest = 0;
230     float nearest_dist = 1000000.0; // big enough
231     for (unsigned int i = 0; i < irr_driver->getLights().size(); i++)
232     {
233         LightNode* light = irr_driver->getLights()[i];
234 
235         // Avoid modifying the nitro emitter or another invisible light
236         if (std::string(light->getName()).find("nitro emitter") == 0 || !light->isVisible())
237             continue;
238 
239         core::vector3df light_pos = light->getAbsolutePosition();
240         if ( cam_pos.getDistanceFrom(light_pos) < nearest_dist)
241         {
242             nearest      = irr_driver->getLights()[i];
243             nearest_dist = cam_pos.getDistanceFrom(light_pos);
244         }
245     }
246 
247     return nearest;
248 }
249 
250 // ----------------------------------------------------------------------------
251 
handleContextMenuAction(s32 cmd_id)252 bool handleContextMenuAction(s32 cmd_id)
253 {
254     if (cmd_id == -1)
255         return false;
256 
257     Camera* camera = Camera::getActiveCamera();
258     unsigned int kart_num = 0;
259     if (camera != NULL && camera->getKart() != NULL)
260     {
261         kart_num = camera->getKart()->getWorldKartId();
262     }
263 
264     World *world = World::getWorld();
265     Physics *physics = Physics::get();
266     SP::SPShader* nv = NULL;
267 #ifndef SERVER_ONLY
268     if (SP::getNormalVisualizer())
269     {
270         nv = SP::getNormalVisualizer();
271     }
272 #endif
273 
274     switch(cmd_id)
275     {
276     case DEBUG_GRAPHICS_RELOAD_SHADERS:
277 #ifndef SERVER_ONLY
278         Log::info("Debug", "Reloading shaders...");
279         SP::SPShaderManager::get()->unloadAll();
280         ShaderBase::killShaders();
281         ShaderFilesManager::getInstance()->removeAllShaderFiles();
282         SP::SPShaderManager::get()->initAll();
283 #endif
284         break;
285     case DEBUG_GRAPHICS_RESET:
286         if (physics)
287             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
288 
289         irr_driver->resetDebugModes();
290         break;
291     case DEBUG_GRAPHICS_SSAO_VIZ:
292         if (physics)
293             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
294 
295         irr_driver->resetDebugModes();
296         irr_driver->toggleSSAOViz();
297         break;
298     case DEBUG_GRAPHICS_SHADOW_VIZ:
299         if (physics)
300             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
301 
302         irr_driver->resetDebugModes();
303         irr_driver->toggleShadowViz();
304         break;
305     case DEBUG_GRAPHICS_BOUNDING_BOXES_VIZ:
306         if (physics)
307             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
308 
309         irr_driver->resetDebugModes();
310         irr_driver->toggleBoundingBoxesViz();
311         break;
312     case DEBUG_GRAPHICS_BULLET_1:
313         irr_driver->resetDebugModes();
314 
315         if (!world) return false;
316         physics->setDebugMode(IrrDebugDrawer::DM_KARTS_PHYSICS);
317         break;
318     case DEBUG_GRAPHICS_BULLET_2:
319     {
320         irr_driver->resetDebugModes();
321 
322         Physics *physics = Physics::get();
323         if (!physics) return false;
324         physics->setDebugMode(IrrDebugDrawer::DM_NO_KARTS_GRAPHICS);
325         break;
326     }
327     case DEBUG_SP_RESET:
328         irr_driver->resetDebugModes();
329         if (physics)
330             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
331 #ifndef SERVER_ONLY
332         SP::sp_culling = true;
333 #endif
334         break;
335     case DEBUG_SP_TOGGLE_CULLING:
336 #ifndef SERVER_ONLY
337         SP::sp_culling = !SP::sp_culling;
338 #endif
339         break;
340     case DEBUG_SP_WN_VIZ:
341         irr_driver->resetDebugModes();
342         if (physics)
343             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
344 #ifndef SERVER_ONLY
345         SP::sp_debug_view = true;
346 #endif
347         break;
348     case DEBUG_SP_NORMALS_VIZ:
349     {
350         irr_driver->resetDebugModes();
351         if (physics)
352             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
353 #ifndef SERVER_ONLY
354         SP::sp_debug_view = true;
355         int normal = 0;
356         if (nv)
357         {
358             SP::SPUniformAssigner* ua = nv->getUniformAssigner("enable_normals");
359             if (ua)
360             {
361                 ua->getValue(nv->getShaderProgram(SP::RP_1ST), normal);
362                 normal = normal == 0 ? 1 : 0;
363                 nv->use();
364                 ua->setValue(normal);
365                 glUseProgram(0);
366             }
367         }
368 #endif
369         break;
370     }
371     case DEBUG_SP_TANGENTS_VIZ:
372     {
373         irr_driver->resetDebugModes();
374         if (physics)
375             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
376 #ifndef SERVER_ONLY
377         SP::sp_debug_view = true;
378         int tangents = 0;
379         if (nv)
380         {
381             SP::SPUniformAssigner* ua = nv->getUniformAssigner("enable_tangents");
382             if (ua)
383             {
384                 ua->getValue(nv->getShaderProgram(SP::RP_1ST), tangents);
385                 tangents = tangents == 0 ? 1 : 0;
386                 nv->use();
387                 ua->setValue(tangents);
388                 glUseProgram(0);
389             }
390         }
391 #endif
392         break;
393     }
394     case DEBUG_SP_BITANGENTS_VIZ:
395     {
396         irr_driver->resetDebugModes();
397         if (physics)
398             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
399 #ifndef SERVER_ONLY
400         SP::sp_debug_view = true;
401         int bitangents = 0;
402         if (nv)
403         {
404             SP::SPUniformAssigner* ua = nv->getUniformAssigner("enable_bitangents");
405             if (ua)
406             {
407                 ua->getValue(nv->getShaderProgram(SP::RP_1ST), bitangents);
408                 bitangents = bitangents == 0 ? 1 : 0;
409                 nv->use();
410                 ua->setValue(bitangents);
411                 glUseProgram(0);
412             }
413         }
414 #endif
415         break;
416     }
417     case DEBUG_SP_WIREFRAME_VIZ:
418     {
419         irr_driver->resetDebugModes();
420         if (physics)
421             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
422 #ifndef SERVER_ONLY
423         SP::sp_debug_view = true;
424         int wireframe = 0;
425         if (nv)
426         {
427             SP::SPUniformAssigner* ua = nv->getUniformAssigner("enable_wireframe");
428             if (ua)
429             {
430                 ua->getValue(nv->getShaderProgram(SP::RP_1ST), wireframe);
431                 wireframe = wireframe == 0 ? 1 : 0;
432                 nv->use();
433                 ua->setValue(wireframe);
434                 glUseProgram(0);
435             }
436         }
437 #endif
438         break;
439     }
440     case DEBUG_SP_TN_VIZ:
441     {
442         irr_driver->resetDebugModes();
443         if (physics)
444             physics->setDebugMode(IrrDebugDrawer::DM_NONE);
445 #ifndef SERVER_ONLY
446         SP::sp_debug_view = true;
447         int triangle_normals = 0;
448         if (nv)
449         {
450             SP::SPUniformAssigner* ua = nv->getUniformAssigner("enable_triangle_normals");
451             if (ua)
452             {
453                 ua->getValue(nv->getShaderProgram(SP::RP_1ST), triangle_normals);
454                 triangle_normals = triangle_normals == 0 ? 1 : 0;
455                 nv->use();
456                 ua->setValue(triangle_normals);
457                 glUseProgram(0);
458             }
459         }
460 #endif
461         break;
462     }
463     case DEBUG_PROFILER:
464         profiler.toggleStatus();
465         break;
466     case DEBUG_PROFILER_WRITE_REPORT:
467         profiler.writeToFile();
468         break;
469     case DEBUG_THROTTLE_FPS:
470         main_loop->setThrottleFPS(false);
471         break;
472     case DEBUG_FONT_DUMP_GLYPH_PAGE:
473         font_manager->getFont<BoldFace>()->dumpGlyphPage("bold");
474         font_manager->getFont<DigitFace>()->dumpGlyphPage("digit");
475         font_manager->getFont<RegularFace>()->dumpGlyphPage("regular");
476         break;
477     case DEBUG_FONT_RELOAD:
478         font_manager->getFont<BoldFace>()->reset();
479         font_manager->getFont<DigitFace>()->reset();
480         font_manager->getFont<RegularFace>()->reset();
481 #ifndef SERVER_ONLY
482         STKTextBillboard::updateAllTextBillboards();
483 #endif
484         break;
485     case DEBUG_FPS:
486         UserConfigParams::m_display_fps =
487             !UserConfigParams::m_display_fps;
488         break;
489     case DEBUG_SAVE_REPLAY:
490         ReplayRecorder::get()->save();
491         break;
492     case DEBUG_SAVE_HISTORY:
493         history->Save();
494         break;
495     case DEBUG_POWERUP_BOWLING:
496         addPowerup(PowerupManager::POWERUP_BOWLING);
497         break;
498     case DEBUG_POWERUP_BUBBLEGUM:
499         addPowerup(PowerupManager::POWERUP_BUBBLEGUM);
500         break;
501     case DEBUG_POWERUP_CAKE:
502         addPowerup(PowerupManager::POWERUP_CAKE);
503         break;
504     case DEBUG_POWERUP_PARACHUTE:
505         addPowerup(PowerupManager::POWERUP_PARACHUTE);
506         break;
507     case DEBUG_POWERUP_PLUNGER:
508         addPowerup(PowerupManager::POWERUP_PLUNGER);
509         break;
510     case DEBUG_POWERUP_RUBBERBALL:
511         addPowerup(PowerupManager::POWERUP_RUBBERBALL);
512         break;
513     case DEBUG_POWERUP_SWATTER:
514         addPowerup(PowerupManager::POWERUP_SWATTER);
515         break;
516     case DEBUG_POWERUP_SWITCH:
517         addPowerup(PowerupManager::POWERUP_SWITCH);
518         break;
519     case DEBUG_POWERUP_ZIPPER:
520         addPowerup(PowerupManager::POWERUP_ZIPPER);
521         break;
522     case DEBUG_POWERUP_NITRO:
523     {
524         if (!world) return false;
525         const unsigned int num_local_players =
526             RaceManager::get()->getNumLocalPlayers();
527         for (unsigned int i = 0; i < num_local_players; i++)
528         {
529             AbstractKart* kart = world->getLocalPlayerKart(i);
530             kart->setEnergy(100.0f);
531         }
532         break;
533     }
534     case DEBUG_ATTACHMENT_ANVIL:
535         addAttachment(Attachment::ATTACH_ANVIL);
536         break;
537     case DEBUG_ATTACHMENT_BOMB:
538         addAttachment(Attachment::ATTACH_BOMB);
539         break;
540     case DEBUG_ATTACHMENT_PARACHUTE:
541         addAttachment(Attachment::ATTACH_PARACHUTE);
542         break;
543     case DEBUG_ATTACHMENT_EXPLOSION:
544         for (unsigned int i = 0; i < RaceManager::get()->getNumLocalPlayers(); i++)
545         {
546             AbstractKart* kart = world->getLocalPlayerKart(i);
547             ExplosionAnimation::create(kart, kart->getXYZ(), true);
548         }
549         break;
550     case DEBUG_GUI_TOGGLE:
551     {
552         if (!world) return false;
553         RaceGUIBase* gui = world->getRaceGUI();
554         if (gui != NULL) gui->m_enabled = !gui->m_enabled;
555         break;
556     }
557     case DEBUG_GUI_HIDE_KARTS:
558         if (!world) return false;
559         for (unsigned int n = 0; n<world->getNumKarts(); n++)
560         {
561             AbstractKart* kart = world->getKart(n);
562             if (kart->getController()->isPlayerController())
563                 kart->getNode()->setVisible(false);
564         }
565         break;
566     case DEBUG_GUI_CAM_TOP:
567         CameraDebug::setDebugType(CameraDebug::CM_DEBUG_TOP_OF_KART);
568         Camera::changeCamera(0, Camera::CM_TYPE_DEBUG);
569         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
570         irr_driver->getDevice()->getCursorControl()->setVisible(true);
571         break;
572     case DEBUG_GUI_CAM_WHEEL:
573         CameraDebug::setDebugType(CameraDebug::CM_DEBUG_GROUND);
574         Camera::changeCamera(0, Camera::CM_TYPE_DEBUG);
575         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
576         irr_driver->getDevice()->getCursorControl()->setVisible(true);
577         break;
578     case DEBUG_GUI_CAM_BEHIND_KART:
579         CameraDebug::setDebugType(CameraDebug::CM_DEBUG_BEHIND_KART);
580         Camera::changeCamera(0, Camera::CM_TYPE_DEBUG);
581         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
582         irr_driver->getDevice()->getCursorControl()->setVisible(true);
583         break;
584     case DEBUG_GUI_CAM_SIDE_OF_KART:
585         CameraDebug::setDebugType(CameraDebug::CM_DEBUG_SIDE_OF_KART);
586         Camera::changeCamera(0, Camera::CM_TYPE_DEBUG);
587         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
588         irr_driver->getDevice()->getCursorControl()->setVisible(true);
589         break;
590     case DEBUG_GUI_CAM_FREE:
591     {
592         Camera *camera = Camera::getActiveCamera();
593         Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_FPS);
594         irr_driver->getDevice()->getCursorControl()->setVisible(false);
595         // Reset camera rotation
596         CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
597         if(cam)
598         {
599             cam->setDirection(vector3df(0, 0, 1));
600             cam->setUpVector(vector3df(0, 1, 0));
601         }
602         break;
603     }
604     case DEBUG_GUI_CAM_NORMAL:
605     {
606         Camera *camera = Camera::getActiveCamera();
607         Camera::changeCamera(camera->getIndex(), Camera::CM_TYPE_NORMAL);
608         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
609         irr_driver->getDevice()->getCursorControl()->setVisible(true);
610         break;
611     }
612     case DEBUG_GUI_CAM_SMOOTH:
613     {
614         CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
615         if(cam)
616         {
617             cam->setSmoothMovement(!cam->getSmoothMovement());
618         }
619         break;
620     }
621     case DEBUG_GUI_CAM_ATTACH:
622     {
623         CameraFPS *cam = dynamic_cast<CameraFPS*>(Camera::getActiveCamera());
624         if(cam)
625         {
626             cam->setAttachedFpsCam(!cam->getAttachedFpsCam());
627         }
628         break;
629     }
630     case DEBUG_VIEW_KART_PREVIOUS:
631     {
632         if (kart_num == 0)
633         {
634             kart_num += World::getWorld()->getNumKarts() - 1;
635         }
636         else
637         {
638             kart_num--;
639         }
640         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
641         break;
642     }
643     case DEBUG_VIEW_KART_ONE:
644         changeCameraTarget(1);
645         break;
646     case DEBUG_VIEW_KART_TWO:
647         changeCameraTarget(2);
648         break;
649     case DEBUG_VIEW_KART_THREE:
650         changeCameraTarget(3);
651         break;
652     case DEBUG_VIEW_KART_FOUR:
653         changeCameraTarget(4);
654         break;
655     case DEBUG_VIEW_KART_FIVE:
656         changeCameraTarget(5);
657         break;
658     case DEBUG_VIEW_KART_SIX:
659         changeCameraTarget(6);
660         break;
661     case DEBUG_VIEW_KART_SEVEN:
662         changeCameraTarget(7);
663         break;
664     case DEBUG_VIEW_KART_EIGHT:
665         changeCameraTarget(8);
666         break;
667     case DEBUG_VIEW_KART_NEXT:
668     {
669         if (kart_num == World::getWorld()->getNumKarts() - 1)
670         {
671             kart_num = 0;
672         }
673         else
674         {
675              kart_num++;
676         }
677         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
678         break;
679     }
680 
681     case DEBUG_PRINT_START_POS:
682         if (!world) return false;
683         for (unsigned int i = 0; i<world->getNumKarts(); i++)
684         {
685             AbstractKart *kart = world->getKart(i);
686             Log::warn(kart->getIdent().c_str(),
687                 "<start position=\"%d\" x=\"%f\" y=\"%f\" z=\"%f\" h=\"%f\"/>",
688                 i, kart->getXYZ().getX(), kart->getXYZ().getY(),
689                 kart->getXYZ().getZ(), kart->getHeading()*RAD_TO_DEGREE
690                 );
691         }
692         break;
693     case DEBUG_VISUAL_VALUES:
694     {
695         DebugSliderDialog *dsd = new DebugSliderDialog();
696         dsd->setSliderHook("red_slider", 0, 255,
697             [](){ return int(irr_driver->getAmbientLight().r * 255.f); },
698             [](int v){
699             video::SColorf ambient = irr_driver->getAmbientLight();
700             ambient.setColorComponentValue(0, v / 255.f);
701             irr_driver->setAmbientLight(ambient); }
702         );
703         dsd->setSliderHook("green_slider", 0, 255,
704             [](){ return int(irr_driver->getAmbientLight().g * 255.f); },
705             [](int v){
706             video::SColorf ambient = irr_driver->getAmbientLight();
707             ambient.setColorComponentValue(1, v / 255.f);
708             irr_driver->setAmbientLight(ambient); }
709         );
710         dsd->setSliderHook("blue_slider", 0, 255,
711             [](){ return int(irr_driver->getAmbientLight().b * 255.f); },
712             [](int v){
713             video::SColorf ambient = irr_driver->getAmbientLight();
714             ambient.setColorComponentValue(2, v / 255.f);
715             irr_driver->setAmbientLight(ambient); }
716         );
717         dsd->setSliderHook("ssao_radius", 0, 100,
718             [](){ return int(irr_driver->getSSAORadius() * 10.f); },
719             [](int v){irr_driver->setSSAORadius(v / 10.f); }
720         );
721         dsd->setSliderHook("ssao_k", 0, 100,
722             [](){ return int(irr_driver->getSSAOK() * 10.f); },
723             [](int v){irr_driver->setSSAOK(v / 10.f); }
724         );
725         dsd->setSliderHook("ssao_sigma", 0, 100,
726             [](){ return int(irr_driver->getSSAOSigma() * 10.f); },
727             [](int v){irr_driver->setSSAOSigma(v / 10.f); }
728         );
729     }
730     break;
731     case DEBUG_ADJUST_LIGHTS:
732     {
733         if (!world) return false;
734         // Some sliders use multipliers because the spinner widget
735         // only supports integers
736         DebugSliderDialog *dsd = new DebugSliderDialog();
737         dsd->changeLabel("Red", "Red (x10)");
738         dsd->setSliderHook("red_slider", 0, 100,
739             []()
740             {
741                 return int(findNearestLight()->getColor().X * 100);
742             },
743             [](int intensity)
744             {
745                 LightNode* nearest = findNearestLight();
746                 core::vector3df color = nearest->getColor();
747                 nearest->setColor(intensity / 100.0f, color.Y, color.Z);
748             }
749         );
750         dsd->changeLabel("Green", "Green (x10)");
751         dsd->setSliderHook("green_slider", 0, 100,
752             []()
753             {
754                 return int(findNearestLight()->getColor().Y * 100);
755             },
756             [](int intensity)
757             {
758                 LightNode* nearest = findNearestLight();
759                 core::vector3df color = nearest->getColor();
760                 nearest->setColor(color.X, intensity / 100.0f, color.Z);
761             }
762         );
763         dsd->changeLabel("Blue", "Blue (x10)");
764         dsd->setSliderHook("blue_slider", 0, 100,
765             []()
766             {
767                 return int(findNearestLight()->getColor().Z * 100);
768             },
769             [](int intensity)
770             {
771                 LightNode* nearest = findNearestLight();
772                 core::vector3df color = nearest->getColor();
773                 nearest->setColor(color.X, color.Y, intensity / 100.0f);
774             }
775         );
776         dsd->changeLabel("SSAO radius", "energy (x10)");
777         dsd->setSliderHook("ssao_radius", 0, 100,
778             []()     { return int(findNearestLight()->getEnergy() * 10);  },
779             [](int v){        findNearestLight()->setEnergy(v / 10.0f); }
780         );
781         dsd->changeLabel("SSAO k", "radius");
782         dsd->setSliderHook("ssao_k", 0, 100,
783             []()     { return int(findNearestLight()->getRadius());  },
784             [](int v){        findNearestLight()->setRadius(float(v)); }
785         );
786         dsd->changeLabel("SSAO Sigma", "[None]");
787         break;
788     }
789     case DEBUG_SCRIPT_CONSOLE:
790         new GeneralTextFieldDialog(L"Run Script", []
791             (const irr::core::stringw& text) {},
792             [] (GUIEngine::LabelWidget* lw, GUIEngine::TextBoxWidget* tb)->bool
793             {
794                 Scripting::ScriptEngine* engine =
795                     Scripting::ScriptEngine::getInstance();
796                 if (engine == NULL)
797                 {
798                     Log::warn("Debug", "No scripting engine loaded!");
799                     return true;
800                 }
801                 engine->evalScript(StringUtils::wideToUtf8(tb->getText()));
802                 tb->setText(L"");
803                 // Don't close the console after each run
804                 return false;
805             });
806         break;
807     case DEBUG_RUN_CUTSCENE:
808         new GeneralTextFieldDialog(
809             L"Enter the cutscene names (separate parts by space)", []
810             (const irr::core::stringw& text)
811             {
812                 if (World::getWorld())
813                 {
814                     Log::warn("Debug", "Please run cutscene in main menu");
815                     return;
816                 }
817                 if (text.empty()) return;
818                 std::vector<std::string> parts =
819                     StringUtils::split(StringUtils::wideToUtf8(text), ' ');
820                 for (const std::string& track : parts)
821                 {
822                     Track* t = track_manager->getTrack(track);
823                     if (t == NULL)
824                     {
825                         Log::warn("Debug", "Cutscene %s not found!",
826                             track.c_str());
827                         return;
828                     }
829                 }
830                 CutsceneWorld::setUseDuration(true);
831                 StateManager::get()->enterGameState();
832                 RaceManager::get()->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE);
833                 RaceManager::get()->setNumKarts(0);
834                 RaceManager::get()->setNumPlayers(0);
835                 RaceManager::get()->startSingleRace(parts.front(), 999, false);
836                 ((CutsceneWorld*)World::getWorld())->setParts(parts);
837             });
838         break;
839         case DEBUG_TEXTURE_CONSOLE:
840         new GeneralTextFieldDialog(
841             L"Enter the texture filename(s) (separate names by ;)"
842             " to be reloaded (empty to reload all)\n"
843             "Press tus; for showing all mesh textures (shown in console)", []
844             (const irr::core::stringw& text) {},
845             [] (GUIEngine::LabelWidget* lw, GUIEngine::TextBoxWidget* tb)->bool
846             {
847 #ifndef SERVER_ONLY
848                 core::stringw t = tb->getText();
849                 SP::SPTextureManager* sptm = SP::SPTextureManager::get();
850                 if (t == "tus;")
851                 {
852                     sptm->dumpAllTextures();
853                     return false;
854                 }
855                 lw->setText(sptm->reloadTexture(t), true);
856 #endif
857                 // Don't close the dialog after each run
858                 return false;
859             });
860         break;
861         case DEBUG_RENDER_NW_DEBUG:
862             irr_driver->toggleRenderNetworkDebug();
863         break;
864         case DEBUG_START_RECORDING:
865             irr_driver->setRecording(true);
866         break;
867         case DEBUG_STOP_RECORDING:
868             irr_driver->setRecording(false);
869         break;
870     }   // switch
871     return false;
872 }
873 
874 // -----------------------------------------------------------------------------
875 /** Debug menu handling */
onEvent(const SEvent & event)876 bool onEvent(const SEvent &event)
877 {
878     // Only activated in artist debug mode
879     if(!UserConfigParams::m_artist_debug_mode)
880         return true;    // keep handling the events
881 
882     if (event.EventType == EET_MOUSE_INPUT_EVENT)
883     {
884         if (GUIEngine::ModalDialog::isADialogActive() ||
885             GUIEngine::ScreenKeyboard::isActive())
886             return true;
887 
888         // Create the menu (only one menu at a time)
889         #ifdef MOBILE_STK
890         int x = 10 * irr_driver->getActualScreenSize().Height / 480;
891         int y = 30 * irr_driver->getActualScreenSize().Height / 480;
892         if (event.MouseInput.X < x && event.MouseInput.Y < y &&
893         #else
894         if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN &&
895         #endif
896             !g_debug_menu_visible)
897         {
898             irr_driver->getDevice()->getCursorControl()->setVisible(true);
899 
900             // root menu
901             gui::IGUIEnvironment* guienv = irr_driver->getGUI();
902             core::rect<s32> r(100, 50, 150, 500);
903             IGUIContextMenu* mnu = guienv->addContextMenu(r, NULL);
904             int graphicsMenuIndex = mnu->addItem(L"Graphics >",-1,true,true);
905 
906             // graphics menu
907             IGUIContextMenu* sub = mnu->getSubMenu(graphicsMenuIndex);
908 
909             sub->addItem(L"Reload shaders", DEBUG_GRAPHICS_RELOAD_SHADERS);
910             sub->addItem(L"SSAO viz", DEBUG_GRAPHICS_SSAO_VIZ);
911             sub->addItem(L"Shadow viz", DEBUG_GRAPHICS_SHADOW_VIZ);
912             sub->addItem(L"Bounding Boxes viz", DEBUG_GRAPHICS_BOUNDING_BOXES_VIZ);
913             sub->addItem(L"Physics debug", DEBUG_GRAPHICS_BULLET_1);
914             sub->addItem(L"Physics debug (no kart)", DEBUG_GRAPHICS_BULLET_2);
915             sub->addItem(L"Reset debug views", DEBUG_GRAPHICS_RESET);
916 
917             mnu->addItem(L"Items >",-1,true,true);
918             sub = mnu->getSubMenu(1);
919             sub->addItem(L"Basketball", DEBUG_POWERUP_RUBBERBALL );
920             sub->addItem(L"Bowling", DEBUG_POWERUP_BOWLING );
921             sub->addItem(L"Bubblegum", DEBUG_POWERUP_BUBBLEGUM );
922             sub->addItem(L"Cake", DEBUG_POWERUP_CAKE );
923             sub->addItem(L"Parachute", DEBUG_POWERUP_PARACHUTE );
924             sub->addItem(L"Plunger", DEBUG_POWERUP_PLUNGER );
925             sub->addItem(L"Swatter", DEBUG_POWERUP_SWATTER );
926             sub->addItem(L"Switch", DEBUG_POWERUP_SWITCH );
927             sub->addItem(L"Zipper", DEBUG_POWERUP_ZIPPER );
928             sub->addItem(L"Nitro", DEBUG_POWERUP_NITRO );
929 
930             mnu->addItem(L"Attachments >",-1,true, true);
931             sub = mnu->getSubMenu(2);
932             sub->addItem(L"Bomb", DEBUG_ATTACHMENT_BOMB);
933             sub->addItem(L"Anvil", DEBUG_ATTACHMENT_ANVIL);
934             sub->addItem(L"Parachute", DEBUG_ATTACHMENT_PARACHUTE);
935             sub->addItem(L"Explosion", DEBUG_ATTACHMENT_EXPLOSION);
936 
937             mnu->addItem(L"GUI >",-1,true, true);
938             sub = mnu->getSubMenu(3);
939             sub->addItem(L"Toggle GUI", DEBUG_GUI_TOGGLE);
940             sub->addItem(L"Hide karts", DEBUG_GUI_HIDE_KARTS);
941             sub->addItem(L"Top view", DEBUG_GUI_CAM_TOP);
942             sub->addItem(L"Behind wheel view", DEBUG_GUI_CAM_WHEEL);
943             sub->addItem(L"Behind kart view", DEBUG_GUI_CAM_BEHIND_KART);
944             sub->addItem(L"Side of kart view", DEBUG_GUI_CAM_SIDE_OF_KART);
945             sub->addItem(L"First person view (Ctrl + F1)", DEBUG_GUI_CAM_FREE);
946             sub->addItem(L"Normal view (Ctrl + F2)", DEBUG_GUI_CAM_NORMAL);
947             sub->addItem(L"Toggle smooth camera", DEBUG_GUI_CAM_SMOOTH);
948             sub->addItem(L"Attach fps camera to kart", DEBUG_GUI_CAM_ATTACH);
949 
950             mnu->addItem(L"Recording >",-1,true, true);
951             sub = mnu->getSubMenu(4);
952                                                                                 //
953 #ifdef ENABLE_RECORDER
954             sub->addItem(L"Start recording", DEBUG_START_RECORDING);
955             sub->addItem(L"Stop recording", DEBUG_STOP_RECORDING);
956 #else
957             sub->addItem(L"Recording unavailable, STK was compiled without\n"
958                           "recording support.  Please re-compile STK with\n"
959                           "libopenglrecorder to enable recording.  If you got\n"
960                           "SuperTuxKart from your distribution's repositories,\n"
961                           "please use the official binaries, or contact your\n"
962                           "distributions's package mantainer.");
963 #endif
964 
965             mnu->addItem(L"Change camera target >",-1,true, true);
966             sub = mnu->getSubMenu(5);
967             sub->addItem(L"To previous kart (Ctrl + F5)", DEBUG_VIEW_KART_PREVIOUS);
968             sub->addItem(L"To kart one", DEBUG_VIEW_KART_ONE);
969             sub->addItem(L"To kart two", DEBUG_VIEW_KART_TWO);
970             sub->addItem(L"To kart three", DEBUG_VIEW_KART_THREE);
971             sub->addItem(L"To kart four", DEBUG_VIEW_KART_FOUR);
972             sub->addItem(L"To kart five", DEBUG_VIEW_KART_FIVE);
973             sub->addItem(L"To kart six", DEBUG_VIEW_KART_SIX);
974             sub->addItem(L"To kart seven", DEBUG_VIEW_KART_SEVEN);
975             sub->addItem(L"To kart eight", DEBUG_VIEW_KART_EIGHT);
976             sub->addItem(L"To next kart (Ctrl + F6)", DEBUG_VIEW_KART_NEXT);
977 
978             mnu->addItem(L"Font >",-1,true, true);
979             sub = mnu->getSubMenu(6);
980             sub->addItem(L"Dump glyph pages of fonts", DEBUG_FONT_DUMP_GLYPH_PAGE);
981             sub->addItem(L"Reload all fonts", DEBUG_FONT_RELOAD);
982 
983             mnu->addItem(L"SP debug >",-1,true, true);
984             sub = mnu->getSubMenu(7);
985             sub->addItem(L"Reset SP debug", DEBUG_SP_RESET);
986             sub->addItem(L"Toggle culling", DEBUG_SP_TOGGLE_CULLING);
987             sub->addItem(L"Draw world normal in texture", DEBUG_SP_WN_VIZ);
988             sub->addItem(L"Toggle normals visualization", DEBUG_SP_NORMALS_VIZ);
989             sub->addItem(L"Toggle tangents visualization", DEBUG_SP_TANGENTS_VIZ);
990             sub->addItem(L"Toggle bitangents visualization", DEBUG_SP_BITANGENTS_VIZ);
991             sub->addItem(L"Toggle wireframe visualization", DEBUG_SP_WIREFRAME_VIZ);
992             sub->addItem(L"Toggle triangle normals visualization", DEBUG_SP_TN_VIZ);
993 
994             mnu->addItem(L"Adjust values", DEBUG_VISUAL_VALUES);
995 
996             mnu->addItem(L"Profiler", DEBUG_PROFILER);
997             if (UserConfigParams::m_profiler_enabled)
998                 mnu->addItem(L"Save profiler report",
999                              DEBUG_PROFILER_WRITE_REPORT);
1000             mnu->addItem(L"Do not limit FPS", DEBUG_THROTTLE_FPS);
1001             mnu->addItem(L"Toggle FPS", DEBUG_FPS);
1002             mnu->addItem(L"Save replay", DEBUG_SAVE_REPLAY);
1003             mnu->addItem(L"Save history", DEBUG_SAVE_HISTORY);
1004             mnu->addItem(L"Print position", DEBUG_PRINT_START_POS);
1005             mnu->addItem(L"Adjust Lights", DEBUG_ADJUST_LIGHTS);
1006             mnu->addItem(L"Scripting console", DEBUG_SCRIPT_CONSOLE);
1007             mnu->addItem(L"Run cutscene(s)", DEBUG_RUN_CUTSCENE);
1008             mnu->addItem(L"Texture console", DEBUG_TEXTURE_CONSOLE);
1009             mnu->addItem(L"Network debugging", DEBUG_RENDER_NW_DEBUG);
1010             g_debug_menu_visible = true;
1011             irr_driver->showPointer();
1012         }
1013 
1014         // Let Irrlicht handle the event while the menu is visible.
1015         // Otherwise in a race the GUI events won't be generated
1016         if(g_debug_menu_visible)
1017             return false;
1018     }
1019 
1020     if (event.EventType == EET_GUI_EVENT)
1021     {
1022         if (event.GUIEvent.Caller != NULL &&
1023             event.GUIEvent.Caller->getType() == EGUIET_CONTEXT_MENU )
1024         {
1025             IGUIContextMenu *menu = (IGUIContextMenu*)event.GUIEvent.Caller;
1026             s32 cmdID = menu->getItemCommandId(menu->getSelectedItem());
1027 
1028             if (event.GUIEvent.EventType == EGET_ELEMENT_CLOSED)
1029             {
1030                 g_debug_menu_visible = false;
1031             }
1032             else if (event.GUIEvent.EventType == gui::EGET_MENU_ITEM_SELECTED)
1033             {
1034                 return handleContextMenuAction(cmdID);
1035             }
1036             return false;
1037         }
1038     }
1039 
1040     // continue event handling if menu is not opened
1041     return !g_debug_menu_visible;
1042 }   // onEvent
1043 
1044 // ----------------------------------------------------------------------------
1045 
handleStaticAction(int key)1046 bool handleStaticAction(int key)
1047 {
1048     Camera* camera = Camera::getActiveCamera();
1049     unsigned int kart_num = 0;
1050     if (camera != NULL && camera->getKart() != NULL)
1051     {
1052         kart_num = camera->getKart()->getWorldKartId();
1053     }
1054 
1055     if (key == IRR_KEY_F1)
1056     {
1057         handleContextMenuAction(DEBUG_GUI_CAM_FREE);
1058     }
1059     else if (key == IRR_KEY_F2)
1060     {
1061         handleContextMenuAction(DEBUG_GUI_CAM_NORMAL);
1062     }
1063     else if (key == IRR_KEY_F3)
1064     {
1065 #ifndef SERVER_ONLY
1066         SP::SPTextureManager::get()->reloadTexture("");
1067 #endif
1068         return true;
1069     }
1070     else if (key == IRR_KEY_F5)
1071     {
1072         if (kart_num == 0)
1073         {
1074             kart_num += World::getWorld()->getNumKarts() - 1;
1075         }
1076         else
1077         {
1078             kart_num--;
1079         }
1080         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
1081         return true;
1082     }
1083     else if (key == IRR_KEY_F6)
1084     {
1085         if (kart_num == World::getWorld()->getNumKarts() - 1)
1086         {
1087             kart_num = 0;
1088         }
1089         else
1090         {
1091              kart_num++;
1092         }
1093         Camera::getActiveCamera()->setKart(World::getWorld()->getKart(kart_num));
1094         return true;
1095     }
1096     else if (key == IRR_KEY_F7)
1097     {
1098         bool prev_val = UserConfigParams::m_soccer_player_list;
1099         UserConfigParams::m_soccer_player_list = !prev_val;
1100         return true;
1101     }
1102     // TODO: create more keyboard shortcuts
1103 
1104     return false;
1105 }
1106 
1107 // ----------------------------------------------------------------------------
1108 /** Returns if the debug menu is visible.
1109  */
isOpen()1110 bool isOpen()
1111 {
1112     return g_debug_menu_visible;
1113 }   // isOpen
1114 
1115 // ----------------------------------------------------------------------------
1116 /** Close the debug menu.
1117  */
closeDebugMenu()1118 void closeDebugMenu()
1119 {
1120     g_debug_menu_visible = false;
1121 }   // closeDebugMenu
1122 
1123 }  // namespace Debug
1124