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