1 //  SuperTuxKart - a fun racing game with go-kart
2 //
3 //  Copyright (C) 2004-2015  Steve Baker <sjbaker1@airmail.net>
4 //  Copyright (C) 2009-2015  Joerg Henrichs, Steve Baker
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 3
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 
20 #include "tracks/track.hpp"
21 
22 #include "addons/addon.hpp"
23 #include "audio/music_manager.hpp"
24 #include "challenges/challenge_status.hpp"
25 #include "challenges/unlock_manager.hpp"
26 #include "config/player_manager.hpp"
27 #include "config/stk_config.hpp"
28 #include "config/user_config.hpp"
29 #include "graphics/camera_end.hpp"
30 #include "graphics/CBatchingMesh.hpp"
31 #include "graphics/central_settings.hpp"
32 #include "graphics/cpu_particle_manager.hpp"
33 #include "graphics/irr_driver.hpp"
34 #include "graphics/lod_node.hpp"
35 #include "graphics/material.hpp"
36 #include "graphics/material_manager.hpp"
37 #include "graphics/mesh_tools.hpp"
38 #include "graphics/moving_texture.hpp"
39 #include "graphics/particle_emitter.hpp"
40 #include "graphics/particle_kind.hpp"
41 #include "graphics/particle_kind_manager.hpp"
42 #include "graphics/render_target.hpp"
43 #include "graphics/shader_files_manager.hpp"
44 #include "graphics/stk_tex_manager.hpp"
45 #include "graphics/sp/sp_base.hpp"
46 #include "graphics/sp/sp_mesh.hpp"
47 #include "graphics/sp/sp_mesh_buffer.hpp"
48 #include "graphics/sp/sp_mesh_node.hpp"
49 #include "graphics/sp/sp_shader_manager.hpp"
50 #include "graphics/sp/sp_texture_manager.hpp"
51 #include "io/file_manager.hpp"
52 #include "io/xml_node.hpp"
53 #include "items/item.hpp"
54 #include "items/item_manager.hpp"
55 #include "items/network_item_manager.hpp"
56 #include "items/powerup_manager.hpp"
57 #include "karts/abstract_kart.hpp"
58 #include "karts/kart_properties.hpp"
59 #include "main_loop.hpp"
60 #include "modes/linear_world.hpp"
61 #include "modes/easter_egg_hunt.hpp"
62 #include "network/network_config.hpp"
63 #include "network/protocols/game_protocol.hpp"
64 #include "network/protocols/server_lobby.hpp"
65 #include "physics/physical_object.hpp"
66 #include "physics/physics.hpp"
67 #include "physics/triangle_mesh.hpp"
68 #include "race/race_manager.hpp"
69 #include "scriptengine/script_engine.hpp"
70 #include "tracks/arena_graph.hpp"
71 #include "tracks/bezier_curve.hpp"
72 #include "tracks/check_manager.hpp"
73 #include "tracks/check_structure.hpp"
74 #include "tracks/drive_graph.hpp"
75 #include "tracks/drive_node.hpp"
76 #include "tracks/model_definition_loader.hpp"
77 #include "tracks/track_manager.hpp"
78 #include "tracks/track_object_manager.hpp"
79 #include "utils/constants.hpp"
80 #include "utils/log.hpp"
81 #include "utils/mini_glm.hpp"
82 #include "utils/string_utils.hpp"
83 #include "utils/translation.hpp"
84 
85 #include <IBillboardTextSceneNode.h>
86 #include <ILightSceneNode.h>
87 #include <IMeshCache.h>
88 #include <IMeshManipulator.h>
89 #include <IMeshSceneNode.h>
90 #include <ISceneManager.h>
91 #include <SMeshBuffer.h>
92 
93 #include <iostream>
94 #include <stdexcept>
95 #include <sstream>
96 #include <wchar.h>
97 
98 using namespace irr;
99 
100 
101 const float Track::NOHIT               = -99999.9f;
102 bool        Track::m_dont_load_navmesh = false;
103 std::atomic<Track*> Track::m_current_track[PT_COUNT];
104 
105 // ----------------------------------------------------------------------------
Track(const std::string & filename)106 Track::Track(const std::string &filename)
107 {
108 #ifdef DEBUG
109     m_magic_number          = 0x17AC3802;
110 #endif
111 
112     m_minimap_invert_x_z    = false;
113     m_materials_loaded      = false;
114     m_filename              = filename;
115     m_root                  =
116         StringUtils::getPath(StringUtils::removeExtension(m_filename));
117     m_ident                 = StringUtils::getBasename(m_root);
118     // If this is an addon track, add "addon_" to the identifier - just in
119     // case that an addon track has the same directory name (and therefore
120     // identifier) as an included track.
121     if(Addon::isAddon(filename))
122     {
123         m_ident = Addon::createAddonId(m_ident);
124         m_is_addon = true;
125     }
126     else
127         m_is_addon = false;
128 
129     // The directory should always have a '/' at the end, but getBasename
130     // above returns "" if a "/" is at the end, so we add the "/" here.
131     m_root                 += "/";
132     m_designer              = "";
133     m_screenshot            = "";
134     m_version               = 0;
135     m_track_mesh            = NULL;
136     m_gfx_effect_mesh       = NULL;
137     m_internal              = false;
138     m_enable_auto_rescue    = true;  // Below set to false in arenas
139     m_enable_push_back      = true;
140     m_reverse_available     = false;
141     m_is_arena              = false;
142     m_is_ctf                = false;
143     m_max_arena_players     = 0;
144     m_has_easter_eggs       = false;
145     m_has_navmesh           = false;
146     m_is_soccer             = false;
147     m_is_cutscene           = false;
148     m_camera_far            = 1000.0f;
149     m_bloom                 = true;
150     m_is_day                = true;
151     m_bloom_threshold       = 0.75f;
152     m_color_inlevel         = core::vector3df(0.0,1.0, 255.0);
153     m_color_outlevel        = core::vector2df(0.0, 255.0);
154     m_clouds                = false;
155     m_godrays               = false;
156     m_displacement_speed    = 1.0f;
157     m_physical_object_uid   = 0;
158     m_shadows               = true;
159     m_sky_particles         = NULL;
160     m_sky_dx                = 0.05f;
161     m_sky_dy                = 0.0f;
162     m_godrays_opacity       = 1.0f;
163     m_godrays_color         = video::SColor(255, 255, 255, 255);
164     m_weather_lightning      = false;
165     m_weather_sound         = "";
166     m_cache_track           = UserConfigParams::m_cache_overworld &&
167                               m_ident=="overworld";
168     m_render_target         = NULL;
169     m_check_manager         = NULL;
170     m_minimap_x_scale       = 1.0f;
171     m_minimap_y_scale       = 1.0f;
172     m_force_disable_fog     = false;
173     m_startup_run           = false;
174     m_red_flag = m_blue_flag =
175         btTransform(btQuaternion(0.0f, 0.0f, 0.0f, 1.0f));
176     m_default_number_of_laps = 3;
177     m_all_nodes.clear();
178     m_static_physics_only_nodes.clear();
179     m_all_cached_meshes.clear();
180     loadTrackInfo();
181 }   // Track
182 
183 //-----------------------------------------------------------------------------
184 /** Destructor, removes quad data structures etc. */
~Track()185 Track::~Track()
186 {
187     // Note that the music information in m_music is globally managed
188     // by the music_manager, and is freed there. So no need to free it
189     // here (esp. since various track might share the same music).
190 #ifdef DEBUG
191     assert(m_magic_number == 0x17AC3802);
192     m_magic_number = 0xDEADBEEF;
193 #endif
194 }   // ~Track
195 
196 //-----------------------------------------------------------------------------
197 /** A < comparison of tracks. This is used to sort the tracks when displaying
198  *  them in the gui.
199  */
operator <(const Track & other) const200 bool Track::operator<(const Track &other) const
201 {
202     PlayerProfile *p = PlayerManager::getCurrentPlayer();
203     bool this_is_locked = p->isLocked(getIdent());
204     bool other_is_locked = p->isLocked(other.getIdent());
205     if(this_is_locked == other_is_locked)
206     {
207         return getSortName() < other.getSortName();
208     }
209     else
210         return other_is_locked;
211 }   // operator<
212 
213 //-----------------------------------------------------------------------------
214 /** Returns the name of the track, which is e.g. displayed on the screen. */
getName() const215 core::stringw Track::getName() const
216 {
217     core::stringw translated = _(m_name.c_str());
218     int index = translated.find("|");
219     if(index>-1)
220     {
221         translated = translated.subString(0, index);
222     }
223     return translated;
224 }   // getName
225 
226 //-----------------------------------------------------------------------------
227 /** Returns the name of the track used to sort the tracks alphabetically.
228  *  This can be used to e.g. sort 'The Island' as 'Island,The'; or
229  *  to replace certain language-specific characters (e.g. German 'ae' with 'a')
230  *  The sort name can be specified by setting the name of a track to:
231  *  "normal name|sort name"
232  */
getSortName() const233 core::stringw Track::getSortName() const
234 {
235     core::stringw translated = translations->w_gettext(m_name.c_str());
236     translated.make_lower();
237     int index = translated.find("|");
238     if(index>-1)
239     {
240         translated = translated.subString(index+1, translated.size());
241     }
242     return translated;
243 }   // getSortName
244 
245 //-----------------------------------------------------------------------------
246 /** Returns true if this track belongs to the specified track group.
247  *  \param group_name Group name to test for.
248  */
isInGroup(const std::string & group_name)249 bool Track::isInGroup(const std::string &group_name)
250 {
251     return std::find(m_groups.begin(), m_groups.end(), group_name)
252         != m_groups.end();
253 }   // isInGroup
254 
255 //-----------------------------------------------------------------------------
256 /** Returns number of completed challenges */
getNumOfCompletedChallenges()257 unsigned int Track::getNumOfCompletedChallenges()
258 {
259     unsigned int unlocked_challenges = 0;
260     PlayerProfile *player = PlayerManager::getCurrentPlayer();
261     for (unsigned int i=0; i<m_challenges.size(); i++)
262     {
263         if (m_challenges[i].m_challenge_id == "tutorial")
264         {
265             unlocked_challenges++;
266             continue;
267         }
268         if (player->getChallengeStatus(m_challenges[i].m_challenge_id)
269                 ->isSolvedAtAnyDifficulty())
270         {
271             unlocked_challenges++;
272         }
273     }
274 
275     return unlocked_challenges;
276 }   // getNumOfCompletedChallenges
277 
278 //-----------------------------------------------------------------------------
279 /** Removes all cached data structures. This is called before the resolution
280  *  is changed.
281  */
removeCachedData()282 void Track::removeCachedData()
283 {
284     m_materials_loaded = false;
285 }   // cleanCachedData
286 
287 //-----------------------------------------------------------------------------
288 /** Prepates the track for a new race. This function must be called after all
289  *  karts are created, since the check objects allocate data structures
290  *  depending on the number of karts.
291  */
reset()292 void Track::reset()
293 {
294     m_ambient_color = m_default_ambient_color;
295     m_check_manager->reset(*this);
296     m_item_manager->reset();
297     m_track_object_manager->reset();
298     m_startup_run = false;
299 }   // reset
300 
301 //-----------------------------------------------------------------------------
302 /** Removes the physical body from the world.
303  *  Called at the end of a race.
304  */
cleanup()305 void Track::cleanup()
306 {
307     irr_driver->resetSceneComplexity();
308     m_physical_object_uid = 0;
309 #ifdef USE_RESIZE_CACHE
310     if (!UserConfigParams::m_high_definition_textures)
311     {
312         file_manager->popTextureSearchPath();
313     }
314 #endif
315     file_manager->popTextureSearchPath();
316     file_manager->popModelSearchPath();
317 
318     Graph::destroy();
319     m_item_manager = nullptr;
320 #ifndef SERVER_ONLY
321     if (CVS->isGLSL())
322     {
323         if (!GUIEngine::isNoGraphics())
324         {
325             CPUParticleManager::getInstance()->cleanMaterialMap();
326         }
327 
328         SP::resetEmptyFogColor();
329     }
330     ParticleKindManager::get()->cleanUpTrackSpecificGfx();
331 #endif
332 
333     for (unsigned int i = 0; i < m_animated_textures.size(); i++)
334     {
335         delete m_animated_textures[i];
336     }
337     m_animated_textures.clear();
338 
339     for (unsigned int i = 0; i < m_all_nodes.size(); i++)
340     {
341         irr_driver->removeNode(m_all_nodes[i]);
342     }
343     m_all_nodes.clear();
344 
345     for (unsigned int i = 0; i < m_static_physics_only_nodes.size(); i++)
346     {
347         m_static_physics_only_nodes[i]->remove();
348     }
349     m_static_physics_only_nodes.clear();
350 
351     delete m_check_manager;
352     m_check_manager = NULL;
353 
354     delete m_track_object_manager;
355     m_track_object_manager = NULL;
356 
357     for (unsigned int i = 0; i < m_object_physics_only_nodes.size(); i++)
358     {
359         m_object_physics_only_nodes[i]->drop();
360     }
361     m_object_physics_only_nodes.clear();
362 
363 #ifndef SERVER_ONLY
364     irr_driver->removeNode(m_sun);
365     if (CVS->isGLSL())
366         m_sun->drop();
367 #endif
368     delete m_track_mesh;
369     m_track_mesh = NULL;
370 
371     delete m_gfx_effect_mesh;
372     m_gfx_effect_mesh = NULL;
373 
374 #ifndef SERVER_ONLY
375     if (CVS->isGLSL())
376         irr_driver->cleanSunInterposer();
377 #endif
378 
379 
380     // The m_all_cached_mesh contains each mesh loaded from a file, which
381     // means that the mesh is stored in irrlichts mesh cache. To clean
382     // everything loaded by this track, we drop the ref count for each mesh
383     // here, till the ref count is 1, which means the mesh is only contained
384     // in the mesh cache, and can therefore be removed. Meshes load more
385     // than once are in m_all_cached_mesh more than once (which is easier
386     // than storing the mesh only once, but then having to test for each
387     // mesh if it is already contained in the list or not).
388     for (unsigned int i = 0; i < m_all_cached_meshes.size(); i++)
389     {
390         irr_driver->dropAllTextures(m_all_cached_meshes[i]);
391         // If a mesh is not in Irrlicht's texture cache, its refcount is
392         // 1 (since its scene node was removed, so the only other reference
393         // is in m_all_cached_meshes). In this case we only drop it once
394         // and don't try to remove it from the cache.
395         if (m_all_cached_meshes[i]->getReferenceCount() == 1)
396         {
397             m_all_cached_meshes[i]->drop();
398             continue;
399         }
400         m_all_cached_meshes[i]->drop();
401         if (m_all_cached_meshes[i]->getReferenceCount() == 1)
402             irr_driver->removeMeshFromCache(m_all_cached_meshes[i]);
403     }
404     m_all_cached_meshes.clear();
405 
406     // Now free meshes that are not associated to any scene node.
407     for (unsigned int i = 0; i < m_detached_cached_meshes.size(); i++)
408     {
409         irr_driver->dropAllTextures(m_detached_cached_meshes[i]);
410         irr_driver->removeMeshFromCache(m_detached_cached_meshes[i]);
411     }
412     m_detached_cached_meshes.clear();
413 
414     for(unsigned int i=0; i<m_sky_textures.size(); i++)
415     {
416         m_sky_textures[i]->drop();
417         if(m_sky_textures[i]->getReferenceCount()==1)
418             irr_driver->removeTexture(m_sky_textures[i]);
419     }
420     m_sky_textures.clear();
421 
422     for (unsigned int i = 0; i<m_spherical_harmonics_textures.size(); i++)
423     {
424         m_spherical_harmonics_textures[i]->drop();
425         if (m_spherical_harmonics_textures[i]->getReferenceCount() == 1)
426             irr_driver->removeTexture(m_spherical_harmonics_textures[i]);
427     }
428     m_spherical_harmonics_textures.clear();
429 
430     if(m_cache_track)
431         material_manager->makeMaterialsPermanent();
432     else
433     {
434         // remove temporary materials loaded by the material manager
435         material_manager->popTempMaterial();
436     }
437 
438 #ifndef SERVER_ONLY
439     irr_driver->clearGlowingNodes();
440     irr_driver->clearLights();
441     irr_driver->clearForcedBloom();
442     irr_driver->clearBackgroundNodes();
443 
444     if (CVS->isGLSL())
445     {
446         SP::SPShaderManager::get()->removeUnusedShaders();
447         ShaderFilesManager::getInstance()->removeUnusedShaderFiles();
448         SP::SPTextureManager::get()->removeUnusedTextures();
449     }
450 #endif
451     if(UserConfigParams::logMemory())
452     {
453         Log::debug("track",
454               "[memory] After cleaning '%s': mesh cache %d texture cache %d\n",
455                 getIdent().c_str(),
456                 irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
457                 irr_driver->getVideoDriver()->getTextureCount());
458 #ifdef DEBUG
459         scene::IMeshCache *cache = irr_driver->getSceneManager()->getMeshCache();
460         for(unsigned int i=0; i<cache->getMeshCount(); i++)
461         {
462             const io::SNamedPath &name = cache->getMeshName(i);
463             std::vector<std::string>::iterator p;
464             p = std::find(m_old_mesh_buffers.begin(), m_old_mesh_buffers.end(),
465                          name.getInternalName().c_str());
466             if(p!=m_old_mesh_buffers.end())
467                 m_old_mesh_buffers.erase(p);
468             else
469             {
470                 Log::debug("track", "[memory] Leaked mesh buffer '%s'.\n",
471                        name.getInternalName().c_str());
472             }   // if name not found
473         }   // for i < cache size
474 
475         video::IVideoDriver *vd = irr_driver->getVideoDriver();
476         for(unsigned int i=0; i<vd->getTextureCount(); i++)
477         {
478             video::ITexture *t = vd->getTextureByIndex(i);
479             std::vector<video::ITexture*>::iterator p;
480             p = std::find(m_old_textures.begin(), m_old_textures.end(),
481                           t);
482             if(p!=m_old_textures.end())
483             {
484                 m_old_textures.erase(p);
485             }
486             else
487             {
488                 Log::debug("track", "[memory] Leaked texture '%s'.\n",
489                     t->getName().getInternalName().c_str());
490             }
491         }
492 #endif
493     }   // if verbose
494 
495 #ifdef __DEBUG_DUMP_MESH_CACHE_AFTER_CLEANUP__
496     scene::IMeshCache* meshCache = irr_driver->getSceneManager()->getMeshCache();
497     int count = meshCache->getMeshCount();
498     for (int i = 0; i < count; i++)
499     {
500         scene::IAnimatedMesh* mesh = meshCache->getMeshByIndex(i);
501         io::SNamedPath path = meshCache->getMeshName(mesh);
502         Log::info("CACHE", "[%i] %s", i, path.getPath().c_str());
503     }
504 #endif
505 
506     m_meta_library.clear();
507     Scripting::ScriptEngine::getInstance()->cleanupCache();
508 
509     m_current_track[PT_MAIN] = NULL;
510 }   // cleanup
511 
512 //-----------------------------------------------------------------------------
loadTrackInfo()513 void Track::loadTrackInfo()
514 {
515     // Default values
516     m_use_fog               = false;
517     m_fog_max               = 1.0f;
518     m_fog_start             = 0.0f;
519     m_fog_end               = 1000.0f;
520     m_fog_height_start      = 0.0f;
521     m_fog_height_end        = 100.0f;
522     m_gravity               = 9.80665f;
523     m_friction              = stk_config->m_default_track_friction;
524     m_smooth_normals        = false;
525     m_godrays               = false;
526     m_godrays_opacity       = 1.0f;
527     m_godrays_color         = video::SColor(255, 255, 255, 255);
528                               /* ARGB */
529     m_fog_color             = video::SColor(255, 77, 179, 230);
530     m_default_ambient_color = video::SColor(255, 120, 120, 120);
531     m_sun_specular_color    = video::SColor(255, 255, 255, 255);
532     m_sun_diffuse_color     = video::SColor(255, 255, 255, 255);
533     m_sun_position          = core::vector3df(0, 10, 10);
534     irr_driver->setSSAORadius(1.);
535     irr_driver->setSSAOK(1.5);
536     irr_driver->setSSAOSigma(1.);
537     XMLNode *root           = file_manager->createXMLTree(m_filename);
538 
539     if(!root || root->getName()!="track")
540     {
541         delete root;
542         std::ostringstream o;
543         o<<"Can't load track '"<<m_filename<<"', no track element.";
544         throw std::runtime_error(o.str());
545     }
546     root->get("name",                  &m_name);
547 
548     std::string designer;
549     root->get("designer",              &designer);
550     m_designer = StringUtils::xmlDecode(designer);
551 
552     root->get("version",               &m_version);
553     std::vector<std::string> filenames;
554     root->get("music",                 &filenames);
555     root->get("screenshot",            &m_screenshot);
556     root->get("gravity",               &m_gravity);
557     root->get("friction",              &m_friction);
558     root->get("soccer",                &m_is_soccer);
559     root->get("arena",                 &m_is_arena);
560     root->get("ctf",                   &m_is_ctf);
561     root->get("max-arena-players",     &m_max_arena_players);
562     root->get("cutscene",              &m_is_cutscene);
563     root->get("groups",                &m_groups);
564     root->get("internal",              &m_internal);
565     root->get("reverse",               &m_reverse_available);
566     root->get("default-number-of-laps",&m_default_number_of_laps);
567     root->get("push-back",             &m_enable_push_back);
568     root->get("clouds",                &m_clouds);
569     root->get("bloom",                 &m_bloom);
570     root->get("bloom-threshold",       &m_bloom_threshold);
571     root->get("shadows",               &m_shadows);
572     root->get("is-during-day",         &m_is_day);
573     root->get("displacement-speed",    &m_displacement_speed);
574     root->get("color-level-in",        &m_color_inlevel);
575     root->get("color-level-out",       &m_color_outlevel);
576 
577     getMusicInformation(filenames, m_music);
578     if (m_default_number_of_laps <= 0)
579         m_default_number_of_laps = 3;
580     m_actual_number_of_laps = m_default_number_of_laps;
581 
582     // Make the default for auto-rescue in battle mode and soccer mode to be false
583     if(m_is_arena || m_is_soccer)
584         m_enable_auto_rescue = false;
585     root->get("auto-rescue",           &m_enable_auto_rescue);
586     root->get("smooth-normals",        &m_smooth_normals);
587     // Reverse is meaningless in arena
588     if(m_is_arena || m_is_soccer)
589         m_reverse_available = false;
590 
591 
592     for(unsigned int i=0; i<root->getNumNodes(); i++)
593     {
594         const XMLNode *mode=root->getNode(i);
595         if(mode->getName()!="mode") continue;
596         TrackMode tm;
597         mode->get("name",  &tm.m_name      );
598         mode->get("quads", &tm.m_quad_name );
599         mode->get("graph", &tm.m_graph_name);
600         mode->get("scene", &tm.m_scene     );
601         m_all_modes.push_back(tm);
602     }
603     // If no mode is specified, add a default mode.
604     if(m_all_modes.size()==0)
605     {
606         TrackMode tm;
607         m_all_modes.push_back(tm);
608     }
609 
610     if(m_groups.size()==0) m_groups.push_back(DEFAULT_GROUP_NAME);
611     const XMLNode *xml_node = root->getNode("curves");
612 
613     if(xml_node) loadCurves(*xml_node);
614 
615     // Set the correct paths
616     if (m_screenshot.length() > 0)
617     {
618         m_screenshot = m_root+m_screenshot;
619     }
620     delete root;
621 
622     std::string dir = StringUtils::getPath(m_filename);
623     std::string easter_name = dir + "/easter_eggs.xml";
624 
625     XMLNode *easter = file_manager->createXMLTree(easter_name);
626 
627     if(easter)
628     {
629         for(unsigned int i=0; i<easter->getNumNodes(); i++)
630         {
631             const XMLNode *eggs = easter->getNode(i);
632             if(eggs->getNumNodes() > 0)
633             {
634                 m_has_easter_eggs = true;
635                 break;
636             }
637         }
638         delete easter;
639     }
640 
641     if(file_manager->fileExists(m_root+"navmesh.xml") && !m_dont_load_navmesh)
642         m_has_navmesh = true;
643     else if ( (m_is_arena || m_is_soccer) && !m_dont_load_navmesh)
644     {
645         Log::warn("Track", "NavMesh is not found for arena %s, "
646                   "disable AI for it.\n", m_name.c_str());
647     }
648     if (m_is_soccer)
649     {
650         // Currently only max eight players in soccer mode
651         m_max_arena_players = 8;
652     }
653     // Max 10 players supported in arena
654     if (m_max_arena_players > 10)
655         m_max_arena_players = 10;
656 
657 }   // loadTrackInfo
658 
659 //-----------------------------------------------------------------------------
660 /** Loads all curves from the XML node.
661  */
loadCurves(const XMLNode & node)662 void Track::loadCurves(const XMLNode &node)
663 {
664     for(unsigned int i=0; i<node.getNumNodes(); i++)
665     {
666         const XMLNode *curve = node.getNode(i);
667         m_all_curves.push_back(new BezierCurve(*curve));
668     }   // for i<node.getNumNodes
669 }   // loadCurves
670 
671 //-----------------------------------------------------------------------------
672 /** Loads all music information for the specified files (which is taken from
673  *  the track.xml file).
674  *  \param filenames List of filenames to load.
675  *  \param music On return contains the music information object for the
676  *         specified files.
677  */
getMusicInformation(std::vector<std::string> & filenames,std::vector<MusicInformation * > & music)678 void Track::getMusicInformation(std::vector<std::string>&       filenames,
679                                 std::vector<MusicInformation*>& music    )
680 {
681     for(int i=0; i<(int)filenames.size(); i++)
682     {
683         std::string full_path = m_root+filenames[i];
684         MusicInformation* mi = music_manager->getMusicInformation(full_path);
685         if(!mi)
686         {
687             try
688             {
689                 std::string shared_name = file_manager->searchMusic(filenames[i]);
690                 if(shared_name!="")
691                     mi = music_manager->getMusicInformation(shared_name);
692             }
693             catch (...)
694             {
695                 mi = NULL;
696             }
697         }
698         if(mi)
699             m_music.push_back(mi);
700         else
701             Log::warn("track",
702                       "Music information file '%s' not found for track '%s' - ignored.\n",
703                       filenames[i].c_str(), m_name.c_str());
704 
705     }   // for i in filenames
706 
707     if (m_music.empty() && !isInternal() && !m_is_cutscene)
708     {
709         m_music.push_back(stk_config->m_default_music);
710 
711         Log::warn("track",
712             "Music information for track '%s' replaced by default music.\n",
713             m_name.c_str());
714     }
715 
716 }   // getMusicInformation
717 
718 //-----------------------------------------------------------------------------
719 /** Select and set the music for this track (doesn't actually start it yet).
720  */
startMusic() const721 void Track::startMusic() const
722 {
723     // In case that the music wasn't found (a warning was already printed)
724     if(m_music.size()>0)
725         music_manager->startMusic(m_music[rand()% m_music.size()], false);
726     else
727         music_manager->clearCurrentMusic();
728 }   // startMusic
729 
730 //-----------------------------------------------------------------------------
731 /** Loads the quad graph for arena, i.e. the definition of all quads, and the
732  *  way they are connected to each other. Input file name is hardcoded for now
733  */
loadArenaGraph(const XMLNode & node)734 void Track::loadArenaGraph(const XMLNode &node)
735 {
736     // Determine if rotate minimap is needed for soccer mode (for blue team)
737     // Only need to test local player
738     if (RaceManager::get()->isSoccerMode())
739     {
740         const unsigned pk = RaceManager::get()->getNumPlayers();
741         for (unsigned i = 0; i < pk; i++)
742         {
743             if (!RaceManager::get()->getKartInfo(i).isNetworkPlayer() &&
744                 RaceManager::get()->getKartInfo(i).getKartTeam() ==
745                 KART_TEAM_BLUE)
746             {
747                 m_minimap_invert_x_z = true;
748                 break;
749             }
750         }
751     }
752 
753     ArenaGraph* graph = new ArenaGraph(m_root+"navmesh.xml", &node);
754     Graph::setGraph(graph);
755 
756     if(Graph::get()->getNumNodes()==0)
757     {
758         Log::warn("track", "No graph nodes defined for track '%s'\n",
759                 m_filename.c_str());
760     }
761     else
762     {
763         loadMinimap();
764     }
765 }   // loadArenaGraph
766 
767 //-----------------------------------------------------------------------------
getArenaStartRotation(const Vec3 & xyz,float heading)768 btQuaternion Track::getArenaStartRotation(const Vec3& xyz, float heading)
769 {
770     btQuaternion def_pos(Vec3(0, 1, 0), heading * DEGREE_TO_RAD);
771     if (!ArenaGraph::get())
772         return def_pos;
773 
774     // Set the correct axis based on normal of the starting position
775     int node = Graph::UNKNOWN_SECTOR;
776     Graph::get()->findRoadSector(xyz, &node);
777     if (node == Graph::UNKNOWN_SECTOR)
778     {
779         Log::warn("track", "Starting position is not on ArenaGraph");
780         return def_pos;
781     }
782 
783     const Vec3& normal = Graph::get()->getQuad(node)->getNormal();
784     btQuaternion q = shortestArcQuat(Vec3(0, 1, 0), normal);
785     btMatrix3x3 m;
786     m.setRotation(q);
787     return btQuaternion(m.getColumn(1), heading * DEGREE_TO_RAD) * q;
788 
789 }   // getArenaStartRotation
790 
791 //-----------------------------------------------------------------------------
792 /** Loads the drive graph, i.e. the definition of all quads, and the way
793  *  they are connected to each other.
794  */
loadDriveGraph(unsigned int mode_id,const bool reverse)795 void Track::loadDriveGraph(unsigned int mode_id, const bool reverse)
796 {
797     new DriveGraph(m_root+m_all_modes[mode_id].m_quad_name,
798         m_root+m_all_modes[mode_id].m_graph_name, reverse);
799 
800     // setGraph is done in DriveGraph constructor
801     assert(DriveGraph::get());
802     DriveGraph::get()->setupPaths();
803 #ifdef DEBUG
804     for(unsigned int i=0; i<DriveGraph::get()->getNumNodes(); i++)
805     {
806         assert(DriveGraph::get()->getNode(i)->getPredecessor(0)!=-1);
807     }
808 #endif
809 
810     if(DriveGraph::get()->getNumNodes()==0)
811     {
812         Log::warn("track", "No graph nodes defined for track '%s'\n",
813                 m_filename.c_str());
814         if (RaceManager::get()->getNumberOfKarts() > 1)
815         {
816             Log::fatal("track", "I can handle the lack of driveline in single"
817                 "kart mode, but not with AIs\n");
818         }
819     }
820     else
821     {
822         loadMinimap();
823     }
824 }   // loadDriveGraph
825 
826 // -----------------------------------------------------------------------------
827 
mapPoint2MiniMap(const Vec3 & xyz,Vec3 * draw_at) const828 void Track::mapPoint2MiniMap(const Vec3 &xyz, Vec3 *draw_at) const
829 {
830     if (m_minimap_invert_x_z)
831     {
832         Vec3 invert = xyz;
833         invert.setX(-xyz.x());
834         invert.setZ(-xyz.z());
835         Graph::get()->mapPoint2MiniMap(invert, draw_at);
836     }
837     else
838         Graph::get()->mapPoint2MiniMap(xyz, draw_at);
839     draw_at->setX(draw_at->getX() * m_minimap_x_scale);
840     draw_at->setY(draw_at->getY() * m_minimap_y_scale);
841 }
842 // -----------------------------------------------------------------------------
843 /** Convert the track tree into its physics equivalents.
844  *  \param main_track_count The number of meshes that are already converted
845  *         when the main track was converted. Only the additional meshes
846  *         added later still need to be converted.
847  */
createPhysicsModel(unsigned int main_track_count)848 void Track::createPhysicsModel(unsigned int main_track_count)
849 {
850     // Remove the temporary track rigid body, and then convert all objects
851     // (i.e. the track and all additional objects) into a new rigid body
852     // and convert this again. So this way we have an optimised track
853     // rigid body which includes all track objects.
854     // Note that removing the rigid body does not remove the already collected
855     // triangle information, so there is no need to convert the actual track
856     // (first element in m_track_mesh) again!
857 
858     if (m_track_mesh == NULL)
859     {
860         Log::error("track",
861                    "m_track_mesh == NULL, cannot createPhysicsModel\n");
862         return;
863     }
864 
865 
866     // Now convert all objects that are only used for the physics
867     // (like invisible walls).
868     for (unsigned int i = 0; i<m_static_physics_only_nodes.size(); i++)
869     {
870         main_loop->renderGUI(5550, i, m_static_physics_only_nodes.size());
871 
872         convertTrackToBullet(m_static_physics_only_nodes[i]);
873         if (UserConfigParams::m_physics_debug &&
874             m_static_physics_only_nodes[i]->getType() == scene::ESNT_MESH)
875         {
876             const video::SColor color(255, 255, 105, 180);
877 
878             scene::IMesh *mesh = ((scene::IMeshSceneNode*)m_static_physics_only_nodes[i])->getMesh();
879             scene::IMeshBuffer *mb = mesh->getMeshBuffer(0);
880             mb->getMaterial().BackfaceCulling = false;
881             video::S3DVertex * const verts = (video::S3DVertex *) mb->getVertices();
882             const u32 max = mb->getVertexCount();
883             for (i = 0; i < max; i++)
884             {
885                 verts[i].Color = color;
886             }
887         }
888         else
889             irr_driver->removeNode(m_static_physics_only_nodes[i]);
890     }
891     main_loop->renderGUI(5560);
892     if (!UserConfigParams::m_physics_debug)
893         m_static_physics_only_nodes.clear();
894 
895     for (unsigned int i = 0; i<m_object_physics_only_nodes.size(); i++)
896     {
897         main_loop->renderGUI(5565, i, m_static_physics_only_nodes.size());
898         convertTrackToBullet(m_object_physics_only_nodes[i]);
899         m_object_physics_only_nodes[i]->setVisible(false);
900         m_object_physics_only_nodes[i]->grab();
901         irr_driver->removeNode(m_object_physics_only_nodes[i]);
902     }
903 
904     m_track_mesh->removeAll();
905     m_gfx_effect_mesh->removeAll();
906     for(unsigned int i=main_track_count; i<m_all_nodes.size(); i++)
907     {
908         main_loop->renderGUI(5570, i, m_all_nodes.size());
909         convertTrackToBullet(m_all_nodes[i]);
910         uploadNodeVertexBuffer(m_all_nodes[i]);
911     }
912     main_loop->renderGUI(5580);
913     m_track_mesh->createPhysicalBody(m_friction);
914     main_loop->renderGUI(5585);
915     m_gfx_effect_mesh->createCollisionShape();
916     main_loop->renderGUI(5590);
917 
918 }   // createPhysicsModel
919 
920 // -----------------------------------------------------------------------------
921 
922 
923 /** Convert the graohics track into its physics equivalents.
924  *  \param mesh The mesh to convert.
925  *  \param node The scene node.
926  */
convertTrackToBullet(scene::ISceneNode * node)927 void Track::convertTrackToBullet(scene::ISceneNode *node)
928 {
929     if (node->getType() == scene::ESNT_TEXT)
930         return;
931 
932     if (node->getType() == scene::ESNT_LOD_NODE)
933     {
934         node = ((LODNode*)node)->getFirstNode();
935         if (node == NULL)
936         {
937             Log::warn("track",
938                       "This track contains an empty LOD group.");
939             return;
940         }
941     }
942     node->updateAbsolutePosition();
943 
944     std::vector<core::matrix4> matrices;
945     matrices.push_back(node->getAbsoluteTransformation());
946 
947     scene::IMesh *mesh;
948     switch(node->getType())
949     {
950         case scene::ESNT_MESH          :
951         case scene::ESNT_WATER_SURFACE :
952         case scene::ESNT_OCTREE        :
953              mesh = ((scene::IMeshSceneNode*)node)->getMesh();
954              break;
955         case scene::ESNT_ANIMATED_MESH :
956              mesh = ((scene::IAnimatedMeshSceneNode*)node)->getMesh();
957              break;
958         case scene::ESNT_SKY_BOX :
959         case scene::ESNT_SKY_DOME:
960         case scene::ESNT_PARTICLE_SYSTEM :
961         case scene::ESNT_TEXT:
962             // These are non-physical
963             return;
964             break;
965         default:
966             int type_as_int = node->getType();
967             char* type = (char*)&type_as_int;
968             Log::debug("track",
969                 "[convertTrackToBullet] Unknown scene node type : %c%c%c%c.\n",
970                    type[0], type[1], type[2], type[3]);
971             return;
972     }   // switch node->getType()
973 
974     //core::matrix4 mat;
975     //mat.setRotationDegrees(hpr);
976     //mat.setTranslation(pos);
977     //core::matrix4 mat_scale;
978     //// Note that we can't simply call mat.setScale, since this would
979     //// overwrite the elements on the diagonal, making any rotation incorrect.
980     //mat_scale.setScale(scale);
981     //mat *= mat_scale;
982 
983     for(unsigned int i=0; i<mesh->getMeshBufferCount(); i++)
984     {
985         scene::IMeshBuffer *mb = mesh->getMeshBuffer(i);
986         // FIXME: take translation/rotation into account
987         if (mb->getVertexType() != video::EVT_STANDARD &&
988             mb->getVertexType() != video::EVT_2TCOORDS &&
989             mb->getVertexType() != video::EVT_TANGENTS &&
990             mb->getVertexType() != video::EVT_SKINNED_MESH)
991         {
992             Log::warn("track", "convertTrackToBullet: Ignoring type '%d'!\n",
993                 mb->getVertexType());
994             continue;
995         }
996         u16 *mbIndices = mb->getIndices();
997         Vec3 vertices[3];
998         Vec3 normals[3];
999 
1000 #ifndef SERVER_ONLY
1001         SP::SPMeshBuffer* spmb = dynamic_cast<SP::SPMeshBuffer*>(mb);
1002         if (spmb)
1003         {
1004             video::S3DVertexSkinnedMesh* mbVertices = (video::S3DVertexSkinnedMesh*)mb->getVertices();
1005             for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
1006             {
1007                 for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)
1008                 {
1009                     TriangleMesh* tmesh = m_track_mesh;
1010                     Material* material = spmb->getSTKMaterial(j);
1011                     if (material->isSurface())
1012                     {
1013                         tmesh = m_gfx_effect_mesh;
1014                     }
1015                     else if (material->isIgnore())
1016                     {
1017                         continue;
1018                     }
1019                     for (unsigned int k = 0; k < 3; k++)
1020                     {
1021                         int indx = mbIndices[j + k];
1022                         core::vector3df v = mbVertices[indx].m_position;
1023                         matrices[matrix_index].transformVect(v);
1024                         vertices[k] = v;
1025                         normals[k] = MiniGLM::decompressVector3(mbVertices[indx].m_normal);
1026                     }   // for k
1027                     if (tmesh)
1028                     {
1029                         tmesh->addTriangle(vertices[0], vertices[1],
1030                             vertices[2], normals[0],
1031                             normals[1], normals[2],
1032                             material);
1033                     }
1034                 }   // for j
1035             } // for matrix_index
1036         }
1037         else
1038 #endif
1039         {
1040             const video::SMaterial& irrMaterial = mb->getMaterial();
1041             std::string t1_full_path, t2_full_path;
1042             video::ITexture* t1 = irrMaterial.getTexture(0);
1043             if (t1)
1044             {
1045                 t1_full_path = t1->getName().getPtr();
1046                 t1_full_path = file_manager->getFileSystem()->getAbsolutePath(
1047                     t1_full_path.c_str()).c_str();
1048             }
1049             video::ITexture* t2 = irrMaterial.getTexture(1);
1050             if (t2)
1051             {
1052                 t2_full_path = t2->getName().getPtr();
1053                 t2_full_path = file_manager->getFileSystem()->getAbsolutePath(
1054                     t2_full_path.c_str()).c_str();
1055             }
1056             const Material* material = material_manager->getMaterialSPM(
1057                 t1_full_path, t2_full_path);
1058             TriangleMesh *tmesh = m_track_mesh;
1059             // Special gfx meshes will not be stored as a normal physics body,
1060             // but converted to a collision body only, so that ray tests
1061             // against them can be done.
1062             if (material->isSurface())
1063                 tmesh = m_gfx_effect_mesh;
1064             // A material which is a surface must be converted,
1065             // even if it's marked as ignore. So only ignore
1066             // non-surface materials.
1067             else if(material->isIgnore())
1068                 continue;
1069 
1070             if (mb->getVertexType() == video::EVT_STANDARD)
1071             {
1072                 irr::video::S3DVertex* mbVertices=(video::S3DVertex*)mb->getVertices();
1073                 for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
1074                 {
1075                     for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)
1076                     {
1077                         for (unsigned int k = 0; k < 3; k++)
1078                         {
1079                             int indx = mbIndices[j + k];
1080                             core::vector3df v = mbVertices[indx].Pos;
1081                             matrices[matrix_index].transformVect(v);
1082                             vertices[k] = v;
1083                             normals[k] = mbVertices[indx].Normal;
1084                         }   // for k
1085 
1086                         if (tmesh)
1087                         {
1088                             tmesh->addTriangle(vertices[0], vertices[1],
1089                                 vertices[2], normals[0],
1090                                 normals[1], normals[2],
1091                                 material);
1092                         }
1093                     }   // for j
1094                 } // for matrix_index
1095             }
1096             else if (mb->getVertexType() == video::EVT_2TCOORDS)
1097             {
1098                 irr::video::S3DVertex2TCoords* mbVertices = (video::S3DVertex2TCoords*)mb->getVertices();
1099                 for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
1100                 {
1101                     for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)
1102                     {
1103                         for (unsigned int k = 0; k < 3; k++)
1104                         {
1105                             int indx = mbIndices[j + k];
1106                             core::vector3df v = mbVertices[indx].Pos;
1107                             matrices[matrix_index].transformVect(v);
1108                             vertices[k] = v;
1109                             normals[k] = mbVertices[indx].Normal;
1110                         }   // for k
1111 
1112                         if (tmesh)
1113                         {
1114                             tmesh->addTriangle(vertices[0], vertices[1],
1115                                 vertices[2], normals[0],
1116                                 normals[1], normals[2],
1117                                 material);
1118                         }
1119                     }   // for j
1120                 } // for matrix_index
1121             }
1122             else if (mb->getVertexType() == video::EVT_TANGENTS)
1123             {
1124                 irr::video::S3DVertexTangents* mbVertices = (video::S3DVertexTangents*)mb->getVertices();
1125                 for (unsigned int matrix_index = 0; matrix_index < matrices.size(); matrix_index++)
1126                 {
1127                     for (unsigned int j = 0; j < mb->getIndexCount(); j += 3)
1128                     {
1129                         for (unsigned int k = 0; k < 3; k++)
1130                         {
1131                             int indx = mbIndices[j + k];
1132                             core::vector3df v = mbVertices[indx].Pos;
1133                             matrices[matrix_index].transformVect(v);
1134                             vertices[k] = v;
1135                             normals[k] = mbVertices[indx].Normal;
1136                         }   // for k
1137 
1138                         if (tmesh)
1139                         {
1140                             tmesh->addTriangle(vertices[0], vertices[1],
1141                                 vertices[2], normals[0],
1142                                 normals[1], normals[2],
1143                                 material);
1144                         }
1145                     }   // for j
1146                 } // for matrix_index
1147             }
1148         }
1149     }   // for i<getMeshBufferCount
1150 
1151 }   // convertTrackToBullet
1152 
1153 // ----------------------------------------------------------------------------
1154 
loadMinimap()1155 void Track::loadMinimap()
1156 {
1157 #ifndef SERVER_ONLY
1158     if (GUIEngine::isNoGraphics())
1159         return;
1160 
1161     //Create the minimap resizing it as necessary.
1162     core::dimension2du mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
1163 
1164     //Use twice the size of the rendered minimap to reduce significantly aliasing
1165     m_render_target = Graph::get()->makeMiniMap(mini_map_size * 2,
1166         "minimap::" + m_ident, video::SColor(127, 255, 255, 255),
1167         m_minimap_invert_x_z);
1168 
1169     updateMiniMapScale();
1170 #endif
1171 }   // loadMinimap
1172 
1173 // ----------------------------------------------------------------------------
updateMiniMapScale()1174 void Track::updateMiniMapScale()
1175 {
1176     if (!m_render_target)
1177         return;
1178 
1179     core::dimension2du mini_map_size = World::getWorld()->getRaceGUI()->getMiniMapSize();
1180     // Happens in race result gui
1181     if (mini_map_size.Width == 0 || mini_map_size.Height == 0)
1182         return;
1183     core::dimension2du mini_map_texture_size = m_render_target->getTextureSize();
1184 
1185     if(mini_map_texture_size.Width)
1186         m_minimap_x_scale = float(mini_map_size.Width) / float(mini_map_texture_size.Width);
1187     else
1188         m_minimap_x_scale = 0;
1189 
1190     if(mini_map_texture_size.Height)
1191         m_minimap_y_scale = float(mini_map_size.Height) / float(mini_map_texture_size.Height);
1192     else
1193         m_minimap_y_scale = 0;
1194 }
1195 
1196 // ----------------------------------------------------------------------------
1197 /** Loads the main track model (i.e. all other objects contained in the
1198  *  scene might use raycast on this track model to determine the actual
1199  *  height of the terrain.
1200  */
loadMainTrack(const XMLNode & root)1201 bool Track::loadMainTrack(const XMLNode &root)
1202 {
1203     assert(m_track_mesh==NULL);
1204     assert(m_gfx_effect_mesh==NULL);
1205 
1206     m_challenges.clear();
1207 
1208     m_track_mesh      = new TriangleMesh(/*can_be_transformed*/false);
1209     m_gfx_effect_mesh = new TriangleMesh(/*can_be_transformed*/false);
1210 
1211     const XMLNode *track_node = root.getNode("track");
1212     std::string model_name;
1213     track_node->get("model", &model_name);
1214     std::string full_path = m_root+model_name;
1215     scene::IMesh *mesh = irr_driver->getMesh(full_path);
1216 
1217     if(!mesh)
1218     {
1219         Log::fatal("track",
1220                    "Main track model '%s' in '%s' not found, aborting.\n",
1221                    track_node->getName().c_str(), model_name.c_str());
1222     }
1223 
1224     scene::ISceneNode* scene_node = NULL;
1225     scene::IMesh* tangent_mesh = NULL;
1226 #ifdef SERVER_ONLY
1227     if (false)
1228 #else
1229     if (m_version < 7 && !CVS->isGLSL() && !GUIEngine::isNoGraphics())
1230 #endif
1231     {
1232         // The mesh as returned does not have all mesh buffers with the same
1233         // texture combined. This can result in a _HUGE_ overhead. E.g. instead
1234         // of 46 different mesh buffers over 500 (for some tracks even >1000)
1235         // were created. This means less effect from hardware support, less
1236         // vertices per opengl operation, more overhead on CPU, ...
1237         // So till we have a better b3d exporter which can combine the different
1238         // meshes which use the same texture when exporting, the meshes are
1239         // combined using CBatchingMesh.
1240         scene::CBatchingMesh *merged_mesh = new scene::CBatchingMesh();
1241         merged_mesh->addMesh(mesh);
1242         merged_mesh->finalize();
1243         tangent_mesh = merged_mesh;
1244         // The reference count of the mesh is 1, since it is in irrlicht's
1245         // cache. So we only have to remove it from the cache.
1246         irr_driver->removeMeshFromCache(mesh);
1247     }
1248     else
1249     {
1250         // SPM does the combine for you
1251         tangent_mesh = mesh;
1252         tangent_mesh->grab();
1253     }
1254     // The merged mesh is grabbed by the octtree, so we don't need
1255     // to keep a reference to it.
1256     scene_node = irr_driver->addMesh(tangent_mesh, "track_main");
1257     // We should drop the merged mesh (since it's now referred to in the
1258     // scene node), but then we need to grab it since it's in the
1259     // m_all_cached_meshes.
1260     m_all_cached_meshes.push_back(tangent_mesh);
1261     irr_driver->grabAllTextures(tangent_mesh);
1262     main_loop->renderGUI(4000);
1263 
1264 #ifdef DEBUG
1265     std::string debug_name=model_name+" (main track, octtree)";
1266     scene_node->setName(debug_name.c_str());
1267 #endif
1268     //merged_mesh->setHardwareMappingHint(scene::EHM_STATIC);
1269 
1270     core::vector3df xyz(0,0,0);
1271     track_node->getXYZ(&xyz);
1272     core::vector3df hpr(0,0,0);
1273     track_node->getHPR(&hpr);
1274     scene_node->setPosition(xyz);
1275     scene_node->setRotation(hpr);
1276     handleAnimatedTextures(scene_node, *track_node);
1277     m_all_nodes.push_back(scene_node);
1278 
1279     MeshTools::minMax3D(tangent_mesh, &m_aabb_min, &m_aabb_max);
1280     // Increase the maximum height of the track: since items that fly
1281     // too high explode, e.g. cakes can not be show when being at the
1282     // top of the track (since they will explode when leaving the AABB
1283     // of the track). While the test for this in Flyable::updateAndDelete
1284     // could be relaxed to fix this, it is not certain how the physics
1285     // will handle items that are out of the AABB
1286     m_aabb_max.setY(m_aabb_max.getY()+30.0f);
1287     Physics::get()->init(m_aabb_min, m_aabb_max);
1288 
1289     ModelDefinitionLoader lodLoader(this);
1290 
1291     // Load LOD groups
1292     const XMLNode *lod_xml_node = root.getNode("lod");
1293     if (lod_xml_node != NULL)
1294     {
1295         for (unsigned int i = 0; i < lod_xml_node->getNumNodes(); i++)
1296         {
1297             main_loop->renderGUI(4100, i, lod_xml_node->getNumNodes());
1298 
1299             const XMLNode* lod_group_xml = lod_xml_node->getNode(i);
1300             for (unsigned int j = 0; j < lod_group_xml->getNumNodes(); j++)
1301             {
1302                 lodLoader.addModelDefinition(lod_group_xml->getNode(j));
1303             }
1304         }
1305     }
1306     main_loop->renderGUI(4200);
1307 
1308     for (unsigned int i=0; i<track_node->getNumNodes(); i++)
1309     {
1310         main_loop->renderGUI(4300, i, track_node->getNumNodes());
1311 
1312         const XMLNode *n=track_node->getNode(i);
1313         // Animated textures have already been handled
1314         if(n->getName()=="animated-texture") continue;
1315         // Only "object" entries are allowed now inside of the model tag
1316         if(n->getName()!="static-object")
1317         {
1318             Log::error("track",
1319                 "Incorrect tag '%s' inside <model> of scene file - ignored\n",
1320                     n->getName().c_str());
1321             continue;
1322         }
1323 
1324         core::vector3df xyz(0,0,0);
1325         n->get("xyz", &xyz);
1326         core::vector3df hpr(0,0,0);
1327         n->get("hpr", &hpr);
1328         core::vector3df scale(1.0f, 1.0f, 1.0f);
1329         n->get("scale", &scale);
1330 
1331         bool tangent = false;
1332         n->get("tangents", &tangent);
1333 
1334         scene::ISceneNode* scene_node;
1335         model_name="";
1336         n->get("model", &model_name);
1337         full_path = m_root+model_name;
1338         std::string interaction;
1339         n->get("interaction", &interaction);
1340 
1341         // a special challenge orb object for overworld
1342         std::string challenge;
1343         n->get("challenge", &challenge);
1344 
1345         bool lod_instance = false;
1346         n->get("lod_instance", &lod_instance);
1347 
1348         if (lod_instance)
1349         {
1350             LODNode* node = lodLoader.instanciateAsLOD(n, NULL, NULL);
1351             if (node != NULL)
1352             {
1353                 node->setPosition(xyz);
1354                 node->setRotation(hpr);
1355                 node->setScale(scale);
1356                 node->updateAbsolutePosition();
1357 
1358                 m_all_nodes.push_back( node );
1359             }
1360         }
1361         else
1362         {
1363             // TODO: check if mesh is animated or not
1364             scene::IMesh *a_mesh = irr_driver->getMesh(full_path);
1365             if(!a_mesh)
1366             {
1367                 Log::error("track", "Object model '%s' not found, ignored.\n",
1368                            full_path.c_str());
1369                 continue;
1370             }
1371 
1372             // The meshes loaded here are in irrlicht's mesh cache. So we
1373             // have to keep track of them in order to properly remove them
1374             // from memory. We could add each track only once in a list, but
1375             // it's actually faster to add meshes multipl times (if they are
1376             // used more than once), and increase the ref count each time.
1377             // When removing the meshes, we drop them till the ref count is
1378             // 1 - which means that the only reference is now in the cache,
1379             // and can therefore be removed.
1380             m_all_cached_meshes.push_back(a_mesh);
1381             irr_driver->grabAllTextures(a_mesh);
1382             a_mesh->grab();
1383             scene_node = irr_driver->addMesh(a_mesh, model_name);
1384             scene_node->setPosition(xyz);
1385             scene_node->setRotation(hpr);
1386             scene_node->setScale(scale);
1387 #ifdef DEBUG
1388             std::string debug_name = model_name+" (static track-object)";
1389             scene_node->setName(debug_name.c_str());
1390 #endif
1391 
1392             handleAnimatedTextures(scene_node, *n);
1393 
1394             // for challenge orbs, a bit more work to do
1395             // TODO: this is hardcoded for the overworld, convert to scripting
1396             if (challenge.size() > 0)
1397             {
1398                 const ChallengeData* c = NULL;
1399 
1400                 if (challenge != "tutorial")
1401                 {
1402                     c = unlock_manager->getChallengeData(challenge);
1403                     if (c == NULL)
1404                     {
1405                         Log::error("track", "Cannot find challenge named <%s>\n",
1406                                    challenge.c_str());
1407                         scene_node->remove();
1408                         continue;
1409                     }
1410                 }
1411 
1412                 m_challenges.push_back( OverworldChallenge(xyz, challenge) );
1413 
1414                 if (c && c->isGrandPrix())
1415                 {
1416 
1417                 }
1418                 else
1419                 {
1420                     if (challenge != "tutorial")
1421                     {
1422                         Track* t = track_manager->getTrack(c->getTrackId());
1423                         if (t == NULL)
1424                         {
1425                             Log::error("track", "Cannot find track named <%s>\n",
1426                                        c->getTrackId().c_str());
1427                             continue;
1428                         }
1429 
1430                         std::string sshot = t->getScreenshotFile();
1431                         video::ITexture* screenshot = irr_driver->getTexture(sshot);
1432 
1433                         if (screenshot == NULL)
1434                         {
1435                             Log::error("track",
1436                                        "Cannot find track screenshot <%s>",
1437                                        sshot.c_str());
1438                             continue;
1439                         }
1440                         scene_node->getMaterial(0).setTexture(0, screenshot);
1441                     }
1442                 }
1443 
1444                 // make transparent
1445                 for (unsigned int m=0; m<a_mesh->getMeshBufferCount(); m++)
1446                 {
1447                     scene::IMeshBuffer* mb = a_mesh->getMeshBuffer(m);
1448                     if (mb->getVertexType() == video::EVT_STANDARD)
1449                     {
1450                         video::S3DVertex* v = (video::S3DVertex*)mb->getVertices();
1451                         for (unsigned int n=0; n<mb->getVertexCount(); n++)
1452                         {
1453                             v[n].Color.setAlpha(125);
1454                         }
1455                     }
1456                 }
1457 
1458 
1459                 LODNode* lod_node = new LODNode("challenge_orb",
1460                                                 irr_driver->getSceneManager()->getRootSceneNode(),
1461                                                 irr_driver->getSceneManager());
1462                 lod_node->setPosition(xyz);
1463                 lod_node->add(50, scene_node, true /* reparent */);
1464 
1465                 m_all_nodes.push_back( lod_node );
1466             }
1467             else
1468             {
1469                 if(interaction=="physics-only")
1470                     m_static_physics_only_nodes.push_back(scene_node);
1471                 else
1472                     m_all_nodes.push_back( scene_node );
1473             }
1474         }
1475 
1476     }   // for i
1477 
1478     // This will (at this stage) only convert the main track model.
1479     for(unsigned int i=0; i<m_all_nodes.size(); i++)
1480     {
1481         main_loop->renderGUI(4350, i, m_all_nodes.size());
1482         convertTrackToBullet(m_all_nodes[i]);
1483         main_loop->renderGUI(4360, i, m_all_nodes.size());
1484         uploadNodeVertexBuffer(m_all_nodes[i]);
1485         main_loop->renderGUI(4400, i, m_all_nodes.size());
1486     }
1487 
1488     // Free the tangent (track mesh) after converting to physics
1489     if (GUIEngine::isNoGraphics())
1490         tangent_mesh->freeMeshVertexBuffer();
1491 
1492     if (m_track_mesh == NULL)
1493     {
1494         Log::fatal("track", "m_track_mesh == NULL, cannot loadMainTrack\n");
1495     }
1496 
1497     m_gfx_effect_mesh->createCollisionShape();
1498     scene_node->setMaterialFlag(video::EMF_LIGHTING, true);
1499     scene_node->setMaterialFlag(video::EMF_GOURAUD_SHADING, true);
1500     main_loop->renderGUI(4500);
1501 
1502     return true;
1503 }   // loadMainTrack
1504 
1505 // ----------------------------------------------------------------------------
freeCachedMeshVertexBuffer()1506 void Track::freeCachedMeshVertexBuffer()
1507 {
1508     if (GUIEngine::isNoGraphics())
1509     {
1510         for (unsigned i = 0; i < m_all_cached_meshes.size(); i++)
1511             m_all_cached_meshes[i]->freeMeshVertexBuffer();
1512     }
1513 }   // freeCachedMeshVertexBuffer
1514 
1515 // ----------------------------------------------------------------------------
1516 /** Handles animated textures.
1517  *  \param node The scene node for which animated textures are handled.
1518  *  \param xml The node containing the data for the animated notion.
1519  */
handleAnimatedTextures(scene::ISceneNode * node,const XMLNode & xml)1520 void Track::handleAnimatedTextures(scene::ISceneNode *node, const XMLNode &xml)
1521 {
1522     for(unsigned int node_number = 0; node_number<xml.getNumNodes();
1523         node_number++)
1524     {
1525         const XMLNode *texture_node = xml.getNode(node_number);
1526         if(texture_node->getName()!="animated-texture") continue;
1527         std::string name;
1528         texture_node->get("name", &name);
1529         if(name=="")
1530         {
1531             Log::error("track",
1532                 "Animated texture: no texture name specified for track '%s'\n",
1533                  m_ident.c_str());
1534             continue;
1535         }
1536 
1537         // to lower case, for case-insensitive comparison
1538         name = StringUtils::toLowerCase(name);
1539 
1540         int moving_textures_found = 0;
1541         SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(node);
1542         if (spmn)
1543         {
1544             for (unsigned i = 0; i < spmn->getSPM()->getMeshBufferCount(); i++)
1545             {
1546                 SP::SPMeshBuffer* spmb = spmn->getSPM()->getSPMeshBuffer(i);
1547                 const std::vector<Material*>& m = spmb->getAllSTKMaterials();
1548                 bool found = false;
1549                 for (unsigned j = 0; j < m.size(); j++)
1550                 {
1551                     Material* mat = m[j];
1552                     std::string mat_name =
1553                         StringUtils::getBasename(mat->getSamplerPath(0));
1554                     mat_name = StringUtils::toLowerCase(mat_name);
1555                     if (mat_name == name)
1556                     {
1557                         found = true;
1558                         moving_textures_found++;
1559                         spmb->enableTextureMatrix(j);
1560                         MovingTexture* mt =
1561                             new MovingTexture(NULL, *texture_node);
1562                         mt->setSPTM(spmn->getTextureMatrix(i).data());
1563                         m_animated_textures.push_back(mt);
1564                         // For spm only 1 texture matrix per mesh buffer is
1565                         // possible
1566                         break;
1567                     }
1568                 }
1569                 if (found)
1570                 {
1571                     break;
1572                 }
1573             }
1574         }
1575         else
1576         {
1577             for(unsigned int i=0; i<node->getMaterialCount(); i++)
1578             {
1579                 video::SMaterial &irrMaterial=node->getMaterial(i);
1580                 for(unsigned int j=0; j<video::MATERIAL_MAX_TEXTURES; j++)
1581                 {
1582                     video::ITexture* t=irrMaterial.getTexture(j);
1583                     if(!t) continue;
1584                     std::string texture_name =
1585                         StringUtils::getBasename(t->getName().getPtr());
1586 
1587                     // to lower case, for case-insensitive comparison
1588                     texture_name = StringUtils::toLowerCase(texture_name);
1589 
1590                     if (texture_name != name) continue;
1591                     core::matrix4 *m = &irrMaterial.getTextureMatrix(j);
1592                     m_animated_textures.push_back(new MovingTexture(m, *texture_node));
1593                     moving_textures_found++;
1594                 }   // for j<MATERIAL_MAX_TEXTURES
1595             }   // for i<getMaterialCount
1596         }
1597         if (moving_textures_found == 0)
1598             Log::warn("AnimTexture", "Did not find animate texture '%s'", name.c_str());
1599     }   // for node_number < xml->getNumNodes
1600 }   // handleAnimatedTextures
1601 
1602 // ----------------------------------------------------------------------------
1603 /** This updates all only graphical elements. It is only called once per
1604  *  rendered frame, not once per time step.
1605  *  float dt Time since last rame.
1606  */
updateGraphics(float dt)1607 void Track::updateGraphics(float dt)
1608 {
1609     m_track_object_manager->updateGraphics(dt);
1610 
1611     for (unsigned int i = 0; i<m_animated_textures.size(); i++)
1612     {
1613         m_animated_textures[i]->update(dt);
1614     }
1615     m_item_manager->updateGraphics(dt);
1616 
1617 }   // updateGraphics
1618 
1619 // ----------------------------------------------------------------------------
1620 /** Update, called once per physics time step.
1621  *  \param dt Timestep.
1622  */
update(int ticks)1623 void Track::update(int ticks)
1624 {
1625     ProcessType type = STKProcess::getType();
1626     if (type == PT_MAIN && !m_startup_run) // first time running update = good point to run startup script
1627     {
1628         Scripting::ScriptEngine::getInstance()->runFunction(false, "void onStart()");
1629         m_startup_run = true;
1630         // After onStart all track objects will be hidden as needed
1631         // we only copy track objects with physical body which affects network
1632         if (LobbyProtocol::getByType<LobbyProtocol>(PT_CHILD))
1633         {
1634             Track* child_track = clone();
1635             m_current_track[PT_CHILD] = child_track;
1636         }
1637     }
1638     float dt = stk_config->ticks2Time(ticks);
1639     m_check_manager->update(dt);
1640     m_item_manager->update(ticks);
1641 
1642     // TODO: enable onUpdate scripts if we ever find a compelling use for them
1643     //Scripting::ScriptEngine* script_engine = World::getWorld()->getScriptEngine();
1644     //script_engine->runScript("void onUpdate()");
1645 }   // update
1646 
1647 // ----------------------------------------------------------------------------
1648 /** Handles an explosion, i.e. it makes sure that all physical objects are
1649  *  affected accordingly.
1650  *  \param pos  Position of the explosion.
1651  *  \param obj  If the hit was a physical object, this object will be affected
1652  *              more. Otherwise this is NULL.
1653  *  \param secondary_hits True if items that are not directly hit should
1654  *         also be affected. */
handleExplosion(const Vec3 & pos,const PhysicalObject * obj,bool secondary_hits) const1655 void Track::handleExplosion(const Vec3 &pos, const PhysicalObject *obj,
1656                             bool secondary_hits) const
1657 {
1658     m_track_object_manager->handleExplosion(pos, obj, secondary_hits);
1659 }   // handleExplosion
1660 
1661 // ----------------------------------------------------------------------------
1662 /** Creates a water node. OBSOLETE, kept for backwards compat only
1663  *  \param node The XML node containing the specifications for the water node.
1664  */
createWater(const XMLNode & node)1665 void Track::createWater(const XMLNode &node)
1666 {
1667     std::string model_name;
1668     node.get("model", &model_name);
1669     std::string full_path = m_root+model_name;
1670 
1671     scene::IMesh *mesh = irr_driver->getMesh(full_path);
1672     if (mesh == NULL)
1673     {
1674         Log::warn("Track", "Water not found : '%s'", full_path.c_str());
1675         return;
1676     }
1677 
1678     /*
1679     float wave_height  = 2.0f;
1680     float wave_speed   = 300.0f;
1681     float wave_length  = 10.0f;
1682     node.get("height", &wave_height);
1683     float time;
1684     if(node.get("time", &time))
1685     {
1686         wave_speed = time * 1000.0f/(2.0f*M_PI);
1687     }
1688     else
1689         node.get("speed",  &wave_speed);
1690     if(wave_speed==0)
1691     {
1692         // A speed of 0 results in a division by zero, so avoid this.
1693         // The actual time for a wave from one maximum to the next is
1694         // given by 2*M_PI*speed/1000.
1695         Log::warn("Track",
1696                   "Wave-speed or time is 0, resetting it to the default.");
1697         wave_speed =300.0f;
1698     }
1699     node.get("length", &wave_length);
1700     */
1701     scene::ISceneNode* scene_node = NULL;
1702     /*
1703     if (UserConfigParams::m_particles_effects > 1)
1704     {
1705         scene::IMesh *welded;
1706         scene_node = irr_driver->addWaterNode(mesh, &welded,
1707                                               wave_height,
1708                                               wave_speed,
1709                                               wave_length);
1710 
1711         mesh->grab();
1712         irr_driver->grabAllTextures(mesh);
1713         m_all_cached_meshes.push_back(mesh);
1714 
1715         mesh = welded;
1716     }
1717     else
1718     {*/
1719         scene_node = irr_driver->addMesh(mesh, "water");
1720     //}
1721 
1722     if(!mesh || !scene_node)
1723     {
1724         Log::error("track", "Water model '%s' in '%s' not found, ignored.\n",
1725                     node.getName().c_str(), model_name.c_str());
1726         return;
1727     }
1728 
1729 #ifdef DEBUG
1730     std::string debug_name = model_name+"(water node)";
1731     scene_node->setName(debug_name.c_str());
1732 #endif
1733     mesh->grab();
1734     m_all_cached_meshes.push_back(mesh);
1735     irr_driver->grabAllTextures(mesh);
1736 
1737     core::vector3df xyz(0,0,0);
1738     node.get("xyz", &xyz);
1739     core::vector3df hpr(0,0,0);
1740     node.get("hpr", &hpr);
1741     scene_node->setPosition(xyz);
1742     scene_node->setRotation(hpr);
1743     m_all_nodes.push_back(scene_node);
1744     handleAnimatedTextures(scene_node, node);
1745 
1746     scene_node->getMaterial(0).setFlag(video::EMF_GOURAUD_SHADING, true);
1747 }   // createWater
1748 
1749 // ----------------------------------------------------------------------------
recursiveUpdatePosition(scene::ISceneNode * node)1750 static void recursiveUpdatePosition(scene::ISceneNode *node)
1751 {
1752     node->updateAbsolutePosition();
1753 
1754     scene::ISceneNodeList::ConstIterator it = node->getChildren().begin();
1755     for (; it != node->getChildren().end(); ++it)
1756     {
1757         recursiveUpdatePosition(*it);
1758     }
1759 }   // recursiveUpdatePosition
1760 
1761 // ----------------------------------------------------------------------------
recursiveUpdatePhysics(std::vector<TrackObject * > & tos)1762 static void recursiveUpdatePhysics(std::vector<TrackObject*>& tos)
1763 {
1764     for (TrackObject* to : tos)
1765     {
1766         if (to->getPhysicalObject())
1767         {
1768             TrackObjectPresentationSceneNode* sn = to
1769                 ->getPresentation<TrackObjectPresentationSceneNode>();
1770             if (sn)
1771             {
1772                 to->getPhysicalObject()->move(
1773                     sn->getNode()->getAbsoluteTransformation().getTranslation(),
1774                     sn->getNode()->getAbsoluteTransformation()
1775                     .getRotationDegrees());
1776             }
1777         }
1778         recursiveUpdatePhysics(to->getChildren());
1779     }
1780 }   // recursiveUpdatePhysics
1781 
1782 // ----------------------------------------------------------------------------
1783 /** This function load the actual scene, i.e. all parts of the track,
1784  *  animations, items, ... It  is called from world during initialisation.
1785  *  Track is the first model to be loaded, so at this stage the root scene node
1786  *  is empty.
1787  *  \param parent The actual world.
1788  *  \param reverse_track True if the track should be run in reverse.
1789  *  \param mode_id Which of the modes of a track to use. This determines which
1790  *         scene, quad, and graph file to load.
1791  */
loadTrackModel(bool reverse_track,unsigned int mode_id)1792 void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
1793 {
1794     assert(m_current_track[PT_MAIN].load() == NULL);
1795 
1796     // Use m_filename to also get the path, not only the identifier
1797     STKTexManager::getInstance()
1798         ->setTextureErrorMessage("While loading track '%s'", m_filename);
1799     if(!m_reverse_available)
1800     {
1801         reverse_track = false;
1802     }
1803     main_loop->renderGUI(3000);
1804     m_check_manager = new CheckManager();
1805     assert(m_all_cached_meshes.size()==0);
1806     if(UserConfigParams::logMemory())
1807     {
1808         Log::debug("[memory] Before loading '%s': mesh cache %d "
1809                    "texture cache %d\n",
1810             getIdent().c_str(),
1811             irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
1812             irr_driver->getVideoDriver()->getTextureCount());
1813 #ifdef DEBUG
1814         scene::IMeshCache *cache =
1815             irr_driver->getSceneManager()->getMeshCache();
1816         m_old_mesh_buffers.clear();
1817         for(unsigned int i=0; i<cache->getMeshCount(); i++)
1818         {
1819             const io::SNamedPath &name=cache->getMeshName(i);
1820             m_old_mesh_buffers.push_back(name.getInternalName().c_str());
1821         }
1822 
1823         m_old_textures.clear();
1824         video::IVideoDriver *vd = irr_driver->getVideoDriver();
1825         for(unsigned int i=0; i<vd->getTextureCount(); i++)
1826         {
1827             video::ITexture *t=vd->getTextureByIndex(i);
1828             m_old_textures.push_back(t);
1829         }
1830 #endif
1831     }
1832 
1833     CameraEnd::clearEndCameras();
1834     m_minimap_invert_x_z   = false;
1835     m_sky_type             = SKY_NONE;
1836     m_track_object_manager = new TrackObjectManager();
1837 
1838     std::string unique_id = StringUtils::insertValues("tracks/%s", m_ident.c_str());
1839 
1840     // Add the track directory to the texture search path
1841     file_manager->pushTextureSearchPath(m_root, unique_id);
1842     file_manager->pushModelSearchPath(m_root);
1843     main_loop->renderGUI(3100);
1844 
1845 #ifndef SERVER_ONLY
1846     if (CVS->isGLSL())
1847     {
1848         SP::SPShaderManager::get()->loadSPShaders(m_root);
1849     }
1850 #endif
1851     main_loop->renderGUI(3200);
1852 
1853     // First read the temporary materials.xml file if it exists
1854     try
1855     {
1856         std::string materials_file = m_root+"materials.xml";
1857         if(m_cache_track)
1858         {
1859             if(!m_materials_loaded)
1860                 material_manager->addSharedMaterial(materials_file);
1861             m_materials_loaded = true;
1862         }
1863         else
1864             material_manager->pushTempMaterial(materials_file);
1865     }
1866     catch (std::exception& e)
1867     {
1868         // no temporary materials.xml file, ignore
1869         (void)e;
1870     }
1871     main_loop->renderGUI(3300);
1872 
1873     // Start building the scene graph
1874     // Soccer field with navmesh requires it
1875     // for two goal line to be drawn them in minimap
1876     std::string path = m_root + m_all_modes[mode_id].m_scene;
1877     XMLNode *root    = file_manager->createXMLTree(path);
1878 
1879     // Make sure that we have a track (which is used for raycasts to
1880     // place other objects).
1881     if (!root || root->getName()!="scene")
1882     {
1883         std::ostringstream msg;
1884         msg<< "No track model defined in '"<<path
1885            <<"', aborting.";
1886         throw std::runtime_error(msg.str());
1887     }
1888 
1889     m_current_track[PT_MAIN] = this;
1890     m_current_track[PT_CHILD] = NULL;
1891 
1892     // Load the graph only now: this function is called from world, after
1893     // the race gui was created. The race gui is needed since it stores
1894     // the information about the size of the texture to render the mini
1895     // map to.
1896     // Load the un-raycasted flag position first (for minimap)
1897     if (m_is_ctf && RaceManager::get()->isCTFMode())
1898     {
1899         for (unsigned int i=0; i<root->getNumNodes(); i++)
1900         {
1901             const XMLNode *node = root->getNode(i);
1902             const std::string &name = node->getName();
1903             if (name == "red-flag")
1904             {
1905                 m_red_flag.setOrigin(flagCommand(node));
1906             }
1907             else if (name == "blue-flag")
1908             {
1909                 m_blue_flag.setOrigin(flagCommand(node));
1910             }
1911         }   // for i<root->getNumNodes()
1912     }
1913     main_loop->renderGUI(3320);
1914 
1915     if (!m_is_arena && !m_is_soccer && !m_is_cutscene)
1916         loadDriveGraph(mode_id, reverse_track);
1917     else if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh)
1918         loadArenaGraph(*root);
1919     main_loop->renderGUI(3340);
1920 
1921     if (NetworkConfig::get()->isNetworking())
1922     {
1923         auto nim = std::make_shared<NetworkItemManager>();
1924         nim->rewinderAdd();
1925         m_item_manager = nim;
1926     }
1927     else
1928     {
1929         // Seed random engine locally
1930         uint32_t seed = (uint32_t)StkTime::getTimeSinceEpoch();
1931         ItemManager::updateRandomSeed(seed);
1932         m_item_manager = std::make_shared<ItemManager>();
1933         powerup_manager->setRandomSeed(seed);
1934     }
1935     main_loop->renderGUI(3360);
1936 
1937     // Set the default start positions. Node that later the default
1938     // positions can still be overwritten.
1939     float forwards_distance  = 1.5f;
1940     float sidewards_distance = 3.0f;
1941     float upwards_distance   = 0.1f;
1942     int   karts_per_row      = 2;
1943 
1944     const XMLNode *default_start = root->getNode("default-start");
1945     if (default_start)
1946     {
1947         default_start->get("forwards-distance",  &forwards_distance );
1948         default_start->get("sidewards-distance", &sidewards_distance);
1949         default_start->get("upwards-distance",   &upwards_distance  );
1950         default_start->get("karts-per-row",      &karts_per_row     );
1951     }
1952 
1953     if (!m_is_arena && !m_is_soccer && !m_is_cutscene)
1954     {
1955         if (RaceManager::get()->isFollowMode())
1956         {
1957             // In a FTL race the non-leader karts are placed at the end of the
1958             // field, so we need all start positions.
1959             m_start_transforms.resize(stk_config->m_max_karts);
1960         }
1961         else
1962             m_start_transforms.resize(RaceManager::get()->getNumberOfKarts());
1963         DriveGraph::get()->setDefaultStartPositions(&m_start_transforms,
1964                                                    karts_per_row,
1965                                                    forwards_distance,
1966                                                    sidewards_distance,
1967                                                    upwards_distance);
1968     }
1969     main_loop->renderGUI(3400);
1970 
1971     // we need to check for fog before loading the main track model
1972     if (const XMLNode *node = root->getNode("sun"))
1973     {
1974         node->get("xyz",           &m_sun_position );
1975         node->get("ambient",       &m_default_ambient_color);
1976         node->get("sun-specular",  &m_sun_specular_color);
1977         node->get("sun-diffuse",   &m_sun_diffuse_color);
1978         node->get("fog",           &m_use_fog);
1979         node->get("fog-color",     &m_fog_color);
1980         node->get("fog-max",       &m_fog_max);
1981         node->get("fog-start",     &m_fog_start);
1982         node->get("fog-end",       &m_fog_end);
1983         node->get("fog-start-height", &m_fog_height_start);
1984         node->get("fog-end-height",   &m_fog_height_end);
1985     }
1986     main_loop->renderGUI(3500);
1987 
1988 #ifndef SERVER_ONLY
1989     if (!GUIEngine::isNoGraphics() && CVS->isGLSL() && m_use_fog)
1990     {
1991         glBindBuffer(GL_UNIFORM_BUFFER, SP::sp_fog_ubo);
1992         glBufferSubData(GL_UNIFORM_BUFFER, 0, 4, &m_fog_start);
1993         glBufferSubData(GL_UNIFORM_BUFFER, 4, 4, &m_fog_end);
1994         glBufferSubData(GL_UNIFORM_BUFFER, 8, 4, &m_fog_max);
1995         // Fog density
1996         float val = -(1.0f / (40.0f * (m_fog_start + 0.001f)));
1997         glBufferSubData(GL_UNIFORM_BUFFER, 12, 4, &val);
1998         val = (float)m_fog_color.getRed() / 255.0f;
1999         glBufferSubData(GL_UNIFORM_BUFFER, 16, 4, &val);
2000         val = (float)m_fog_color.getGreen() / 255.0f;
2001         glBufferSubData(GL_UNIFORM_BUFFER, 20, 4, &val);
2002         val = (float)m_fog_color.getBlue() / 255.0f;
2003         glBufferSubData(GL_UNIFORM_BUFFER, 24, 4, &val);
2004         val = 0.0f;
2005         glBufferSubData(GL_UNIFORM_BUFFER, 28, 4, &val);
2006         glBindBuffer(GL_UNIFORM_BUFFER, 0);
2007     }
2008     else if (CVS->isGLSL())
2009     {
2010         SP::resetEmptyFogColor();
2011     }
2012 #endif
2013     main_loop->renderGUI(3600);
2014 
2015     if (const XMLNode *node = root->getNode("lightshaft"))
2016     {
2017         m_godrays = true;
2018         node->get("opacity", &m_godrays_opacity);
2019         node->get("color", &m_godrays_color);
2020         node->get("xyz", &m_godrays_position);
2021     }
2022 
2023     loadMainTrack(*root);
2024     main_loop->renderGUI(4700);
2025 
2026     unsigned int main_track_count = (unsigned int)m_all_nodes.size();
2027 
2028     ModelDefinitionLoader model_def_loader(this);
2029     main_loop->renderGUI(4800);
2030 
2031     // Load LOD groups
2032     const XMLNode *lod_xml_node = root->getNode("lod");
2033     if (lod_xml_node != NULL)
2034     {
2035         for (unsigned int i = 0; i < lod_xml_node->getNumNodes(); i++)
2036         {
2037             main_loop->renderGUI(4900, i, lod_xml_node->getNumNodes());
2038 
2039             const XMLNode* lod_group_xml = lod_xml_node->getNode(i);
2040             for (unsigned int j = 0; j < lod_group_xml->getNumNodes(); j++)
2041             {
2042                 model_def_loader.addModelDefinition(lod_group_xml->getNode(j));
2043             }
2044         }
2045     }
2046 
2047     loadObjects(root, path, model_def_loader, true, NULL, NULL);
2048     main_loop->renderGUI(5000);
2049 
2050     Log::info("Track", "Overall scene complexity estimated at %d", irr_driver->getSceneComplexity());
2051     // Correct the parenting of meta library
2052     for (auto& p : m_meta_library)
2053     {
2054         auto* ln = p.first->getPresentation<TrackObjectPresentationLibraryNode>();
2055         assert(ln);
2056         TrackObjectPresentationLibraryNode* meta_ln = p.second
2057             ->getPresentation<TrackObjectPresentationLibraryNode>();
2058         assert(meta_ln);
2059         meta_ln->getNode()->setParent(ln->getNode());
2060         recursiveUpdatePosition(meta_ln->getNode());
2061         recursiveUpdatePhysics(p.second->getChildren());
2062         main_loop->renderGUI(5050);
2063 
2064     }
2065 
2066     model_def_loader.cleanLibraryNodesAfterLoad();
2067     main_loop->renderGUI(5100);
2068 
2069     Scripting::ScriptEngine::getInstance()->compileLoadedScripts();
2070     main_loop->renderGUI(5200);
2071 
2072     // Init all track objects
2073     m_track_object_manager->init();
2074     main_loop->renderGUI(5300);
2075 
2076 
2077     // ---- Fog
2078     // It's important to execute this BEFORE the code that creates the skycube,
2079     // otherwise the skycube node could be modified to have fog enabled, which
2080     // we don't want
2081 #ifndef SERVER_ONLY
2082     if (m_use_fog && Camera::getDefaultCameraType()!=Camera::CM_TYPE_DEBUG &&
2083         !CVS->isGLSL())
2084     {
2085         /* NOTE: if LINEAR type, density does not matter, if EXP or EXP2, start
2086            and end do not matter */
2087         irr_driver->getVideoDriver()->setFog(m_fog_color,
2088                                              video::EFT_FOG_LINEAR,
2089                                              m_fog_start, m_fog_end,
2090                                              1.0f);
2091     }
2092 #endif
2093 
2094     // Sky dome and boxes support
2095     // --------------------------
2096     irr_driver->suppressSkyBox();
2097 #ifndef SERVER_ONLY
2098     if(!CVS->isGLSL() && m_sky_type==SKY_DOME && m_sky_textures.size() > 0)
2099     {
2100         scene::ISceneNode *node = irr_driver->addSkyDome(m_sky_textures[0],
2101                                                          m_sky_hori_segments,
2102                                                          m_sky_vert_segments,
2103                                                          m_sky_texture_percent,
2104                                                          m_sky_sphere_percent);
2105         for(unsigned int i=0; i<node->getMaterialCount(); i++)
2106         {
2107             main_loop->renderGUI(5350, i, node->getMaterialCount());
2108 
2109             video::SMaterial &irrMaterial=node->getMaterial(i);
2110             for(unsigned int j=0; j<video::MATERIAL_MAX_TEXTURES; j++)
2111             {
2112                 video::ITexture* t=irrMaterial.getTexture(j);
2113                 if(!t) continue;
2114                 core::matrix4 *m = &irrMaterial.getTextureMatrix(j);
2115                 m_animated_textures.push_back(new MovingTexture(m, m_sky_dx, m_sky_dy));
2116             }   // for j<MATERIAL_MAX_TEXTURES
2117         }   // for i<getMaterialCount
2118 
2119         m_all_nodes.push_back(node);
2120     }
2121     else if(m_sky_type==SKY_BOX && m_sky_textures.size() == 6)
2122     {
2123         //if (m_spherical_harmonics_textures.size() > 0)
2124             m_all_nodes.push_back(irr_driver->addSkyBox(m_sky_textures, m_spherical_harmonics_textures));
2125         //else
2126         //    m_all_nodes.push_back(irr_driver->addSkyBox(m_sky_textures, m_sky_textures));
2127     }
2128     else if(m_sky_type==SKY_COLOR)
2129     {
2130         irr_driver->setClearbackBufferColor(m_sky_color);
2131     }
2132 #endif
2133     main_loop->renderGUI(5400);
2134 
2135     // ---- Set ambient color
2136     m_ambient_color = m_default_ambient_color;
2137     irr_driver->setAmbientLight(m_ambient_color,
2138         m_spherical_harmonics_textures.size() != 6/*force_SH_computation*/);
2139 
2140     // ---- Create sun (non-ambient directional light)
2141     if (m_sun_position.getLengthSQ() < 0.03f)
2142     {
2143         m_sun_position = core::vector3df(500, 250, 250);
2144     }
2145 
2146     const video::SColorf tmpf(m_sun_diffuse_color);
2147     m_sun = irr_driver->addLight(m_sun_position, 0., 0., tmpf.r, tmpf.g, tmpf.b, true);
2148 
2149 #ifndef SERVER_ONLY
2150     if (!CVS->isGLSL())
2151     {
2152         scene::ILightSceneNode *sun = (scene::ILightSceneNode *) m_sun;
2153 
2154         sun->setLightType(video::ELT_DIRECTIONAL);
2155 
2156         // The angle of the light is rather important - let the sun
2157         // point towards (0,0,0).
2158         if (m_sun_position.getLengthSQ() < 0.03f)
2159             // Backward compatibility: if no sun is specified, use the
2160             // old hardcoded default angle
2161             m_sun->setRotation(core::vector3df(180, 45, 45));
2162         else
2163             m_sun->setRotation((-m_sun_position).getHorizontalAngle());
2164 
2165         sun->getLightData().SpecularColor = m_sun_specular_color;
2166     }
2167     else
2168     {
2169         irr_driver->createSunInterposer();
2170         m_sun->grab();
2171     }
2172 #endif
2173     main_loop->renderGUI(5500);
2174 
2175     // Join all static physics only object to main track if possible
2176     // Take the visibility condition by scripting into account
2177     std::vector<TrackObject*> objs_removing;
2178     for (auto* to : m_track_object_manager->getObjects().m_contents_vector)
2179     {
2180         if (to->joinToMainTrack())
2181         {
2182             m_track_object_manager->removeDriveableObject(to);
2183             TrackObjectPresentationSceneNode* ts =
2184                 to->getPresentation<TrackObjectPresentationSceneNode>();
2185             // physicial only node is always hidden, remove it from stk after
2186             // joining to track mesh
2187             if (ts && ts->isAlwaysHidden())
2188                 objs_removing.push_back(to);
2189         }
2190     }
2191     for (auto* obj : objs_removing)
2192         m_track_object_manager->removeObject(obj);
2193 
2194     createPhysicsModel(main_track_count);
2195     main_loop->renderGUI(5600);
2196 
2197     freeCachedMeshVertexBuffer();
2198 
2199     const bool arena_random_item_created =
2200         m_item_manager->randomItemsForArena(m_start_transforms);
2201 
2202     if (!arena_random_item_created)
2203     {
2204         for (unsigned int i=0; i<root->getNumNodes(); i++)
2205         {
2206             const XMLNode *node = root->getNode(i);
2207             const std::string &name = node->getName();
2208             if (name=="banana"      || name=="item"      ||
2209                 name=="small-nitro" || name=="big-nitro" ||
2210                 name=="easter-egg"                           )
2211             {
2212                 itemCommand(node);
2213             }
2214         }   // for i<root->getNumNodes()
2215     }
2216     main_loop->renderGUI(5700);
2217 
2218     if (m_is_ctf && RaceManager::get()->isCTFMode())
2219     {
2220         for (unsigned int i=0; i<root->getNumNodes(); i++)
2221         {
2222             const XMLNode *node = root->getNode(i);
2223             const std::string &name = node->getName();
2224             if (name == "red-flag" || name == "blue-flag")
2225             {
2226                 flagCommand(node);
2227             }
2228         }   // for i<root->getNumNodes()
2229     }
2230     delete root;
2231     main_loop->renderGUI(5800);
2232 
2233     if (auto sl = LobbyProtocol::get<ServerLobby>())
2234     {
2235         sl->saveInitialItems(
2236             std::dynamic_pointer_cast<NetworkItemManager>(m_item_manager));
2237     }
2238 
2239     main_loop->renderGUI(5900);
2240 
2241     if (UserConfigParams::m_track_debug && Graph::get() && !m_is_cutscene)
2242         Graph::get()->createDebugMesh();
2243 
2244     // Only print warning if not in battle mode, since battle tracks don't have
2245     // any quads or check lines.
2246     if (m_check_manager->getCheckStructureCount()==0  &&
2247         !RaceManager::get()->isBattleMode() && !m_is_cutscene)
2248     {
2249         Log::warn("track", "No check lines found in track '%s'.",
2250                   m_ident.c_str());
2251         Log::warn("track", "Lap counting will not work, and start "
2252                   "positions might be incorrect.");
2253     }
2254 
2255     if (UserConfigParams::logMemory())
2256     {
2257         Log::debug("track", "[memory] After loading  '%s': mesh cache %d "
2258                    "texture cache %d\n", getIdent().c_str(),
2259                 irr_driver->getSceneManager()->getMeshCache()->getMeshCount(),
2260                 irr_driver->getVideoDriver()->getTextureCount());
2261     }
2262 
2263     World *world = World::getWorld();
2264     if (world->useChecklineRequirements())
2265     {
2266         DriveGraph::get()->computeChecklineRequirements();
2267     }
2268     main_loop->renderGUI(6000);
2269 
2270     EasterEggHunt *easter_world = dynamic_cast<EasterEggHunt*>(world);
2271     if(easter_world)
2272     {
2273         std::string dir = StringUtils::getPath(m_filename);
2274         easter_world->readData(dir+"/easter_eggs.xml");
2275     }
2276     main_loop->renderGUI(6100);
2277 
2278     STKTexManager::getInstance()->unsetTextureErrorMessage();
2279 #ifndef SERVER_ONLY
2280     if (CVS->isGLSL())
2281     {
2282         for (video::ITexture* t : m_sky_textures)
2283         {
2284             t->drop();
2285         }
2286         m_sky_textures.clear();
2287         for (video::ITexture* t : m_spherical_harmonics_textures)
2288         {
2289             t->drop();
2290         }
2291         m_spherical_harmonics_textures.clear();
2292     }
2293 #endif   // !SERVER_ONLY
2294 }   // loadTrackModel
2295 
2296 //-----------------------------------------------------------------------------
2297 
loadObjects(const XMLNode * root,const std::string & path,ModelDefinitionLoader & model_def_loader,bool create_lod_definitions,scene::ISceneNode * parent,TrackObject * parent_library)2298 void Track::loadObjects(const XMLNode* root, const std::string& path,
2299                         ModelDefinitionLoader& model_def_loader,
2300                         bool create_lod_definitions, scene::ISceneNode* parent,
2301                         TrackObject* parent_library)
2302 {
2303     unsigned int start_position_counter = 0;
2304 
2305     unsigned int node_count = root->getNumNodes();
2306     const bool is_mode_ctf = m_is_ctf && RaceManager::get()->isCTFMode();
2307 
2308     // We keep track of the complexity of the scene (amount of objects loaded, etc)
2309     irr_driver->addSceneComplexity(node_count);
2310     for (unsigned int i = 0; i < node_count; i++)
2311     {
2312         main_loop->renderGUI(4950, i, node_count);
2313         const XMLNode *node = root->getNode(i);
2314         const std::string name = node->getName();
2315         // The track object was already converted before the loop, and the
2316         // default start was already used, too - so ignore those.
2317         if (name == "track" || name == "default-start") continue;
2318         if (name == "object" || name == "library")
2319         {
2320             int geo_level = 0;
2321             node->get("geometry-level", &geo_level);
2322             if (UserConfigParams::m_geometry_level + geo_level - 2 > 0 &&
2323                 !NetworkConfig::get()->isNetworking())
2324                 continue;
2325             m_track_object_manager->add(*node, parent, model_def_loader, parent_library);
2326         }
2327         else if (name == "water")
2328         {
2329             createWater(*node);
2330         }
2331         else if (name == "banana"      || name == "item" ||
2332                  name == "small-nitro" || name == "big-nitro" ||
2333                  name == "easter-egg"  || name == "red-flag" ||
2334                  name == "blue-flag")
2335         {
2336             // will be handled later
2337         }
2338         else if (name == "start" || name == "ctf-start")
2339         {
2340             if ((name == "start" && is_mode_ctf) ||
2341                 (name == "ctf-start" && !is_mode_ctf))
2342                 continue;
2343             unsigned int position = start_position_counter;
2344             start_position_counter++;
2345             node->get("position", &position);
2346             Vec3 xyz(0,0,0);
2347             node->getXYZ(&xyz);
2348             float h=0;
2349             node->get("h", &h);
2350 
2351             if (position >= m_start_transforms.size())
2352             {
2353                 m_start_transforms.resize(position + 1);
2354             }
2355 
2356             m_start_transforms[position].setOrigin(xyz);
2357             m_start_transforms[position]
2358                 .setRotation(getArenaStartRotation(xyz, h));
2359         }
2360         else if (name == "camera")
2361         {
2362             node->get("far", &m_camera_far);
2363         }
2364         else if (name == "checks")
2365         {
2366             m_check_manager->load(*node);
2367         }
2368         else if (name == "particle-emitter")
2369         {
2370             if (UserConfigParams::m_particles_effects > 1)
2371             {
2372                 m_track_object_manager->add(*node, parent, model_def_loader, parent_library);
2373             }
2374         }
2375         else if (name == "sky-dome" || name == "sky-box" || name == "sky-color")
2376         {
2377             handleSky(*node, path);
2378         }
2379         else if (name == "end-cameras")
2380         {
2381             CameraEnd::readEndCamera(*node);
2382         }
2383         else if (name == "light")
2384         {
2385             m_track_object_manager->add(*node, parent, model_def_loader, parent_library);
2386         }
2387         else if (name == "weather")
2388         {
2389             std::string weather_particles;
2390 
2391             node->get("particles", &weather_particles);
2392             node->get("lightning", &m_weather_lightning);
2393             node->get("sound", &m_weather_sound);
2394 
2395             if (weather_particles.size() > 0)
2396             {
2397                 m_sky_particles =
2398                     ParticleKindManager::get()->getParticles(weather_particles);
2399             }
2400         }
2401         else if (name == "sun")
2402         {
2403             // handled above
2404         }
2405         else if (name == "lod")
2406         {
2407             // handled above
2408         }
2409         else if (name == "lightshaft")
2410         {
2411             // handled above
2412         }
2413         else if (name == "instancing")
2414         {
2415             // TODO: eventually remove, this is now automatic
2416         }
2417         else if (name == "subtitles")
2418         {
2419             std::vector<XMLNode*> subtitles;
2420             node->getNodes("subtitle", subtitles);
2421             for (unsigned int i = 0; i < subtitles.size(); i++)
2422             {
2423                 int from = -1, to = -1;
2424                 std::string subtitle_text;
2425                 subtitles[i]->get("from", &from);
2426                 subtitles[i]->get("to", &to);
2427                 subtitles[i]->get("text", &subtitle_text);
2428                 if (from != -1 && to != -1 && subtitle_text.size() > 0)
2429                 {
2430                     m_subtitles.push_back( Subtitle(from, to, _(subtitle_text.c_str())) );
2431                 }
2432             }
2433         }
2434         else
2435         {
2436             Log::warn("track", "While loading track '%s', element '%s' was "
2437                       "met but is unknown.",
2438                       m_ident.c_str(), node->getName().c_str());
2439         }
2440 
2441     }   // for i<root->getNumNodes()
2442 }
2443 
2444 //-----------------------------------------------------------------------------
2445 /** Handles a sky-dome or sky-box. It takes the xml node with the
2446  *  corresponding data for the sky and stores the corresponding data in
2447  *  the corresponding data structures.
2448  *  \param xml_node XML node with the sky data.
2449  *  \param filename Name of the file which is read, only used to print
2450  *         meaningful error messages.
2451  */
handleSky(const XMLNode & xml_node,const std::string & filename)2452 void Track::handleSky(const XMLNode &xml_node, const std::string &filename)
2453 {
2454     if(xml_node.getName()=="sky-dome")
2455     {
2456         m_sky_type            = SKY_DOME;
2457         m_sky_vert_segments   = 16;
2458         m_sky_hori_segments   = 16;
2459         m_sky_sphere_percent  = 1.0f;
2460         m_sky_texture_percent = 1.0f;
2461         std::string s;
2462         xml_node.get("texture",          &s                   );
2463         video::ITexture *t = irr_driver->getTexture(s);
2464         if (t != NULL)
2465         {
2466             t->grab();
2467             m_sky_textures.push_back(t);
2468             xml_node.get("vertical",        &m_sky_vert_segments  );
2469             xml_node.get("horizontal",      &m_sky_hori_segments  );
2470             xml_node.get("sphere-percent",  &m_sky_sphere_percent );
2471             xml_node.get("texture-percent", &m_sky_texture_percent);
2472             xml_node.get("speed-x", &m_sky_dx );
2473             xml_node.get("speed-y", &m_sky_dy);
2474         }
2475         else
2476         {
2477             Log::error("track", "Sky-dome texture '%s' not found - ignored.",
2478                         s.c_str());
2479         }
2480     }   // if sky-dome
2481     else if(xml_node.getName()=="sky-box")
2482     {
2483         std::string s;
2484         xml_node.get("texture", &s);
2485         std::vector<std::string> v = StringUtils::split(s, ' ');
2486         for(unsigned int i=0; i<v.size(); i++)
2487         {
2488             video::ITexture* t = NULL;
2489 #ifndef SERVER_ONLY
2490             if (CVS->isGLSL())
2491             {
2492                 t = STKTexManager::getInstance()->getTexture(v[i],
2493                     (TexConfig*)NULL/*tex_config*/, true/*no_upload*/);
2494             }
2495             else
2496 #endif   // !SERVER_ONLY
2497             {
2498                 t = irr_driver->getTexture(v[i]);
2499             }
2500             if (t)
2501             {
2502 #ifndef SERVER_ONLY
2503                 if (!CVS->isGLSL())
2504 #endif   // !SERVER_ONLY
2505                     t->grab();
2506                 m_sky_textures.push_back(t);
2507             }
2508             else
2509             {
2510                 Log::error("track","Sky-box texture '%s' not found - ignored.",
2511                            v[i].c_str());
2512             }
2513         }   // for i<v.size()
2514         if(m_sky_textures.size()!=6)
2515         {
2516             Log::error("track",
2517                        "A skybox needs 6 textures, but %d are specified",
2518                        (int)m_sky_textures.size());
2519             Log::error("track", "in '%s'.", filename.c_str());
2520 
2521         }
2522         else
2523         {
2524             m_sky_type = SKY_BOX;
2525         }
2526 
2527         std::string sh_textures;
2528         xml_node.get("sh-texture", &sh_textures);
2529         v = StringUtils::split(sh_textures, ' ');
2530         for (unsigned int i = 0; i<v.size(); i++)
2531         {
2532             video::ITexture* t = NULL;
2533 #ifndef SERVER_ONLY
2534             if (CVS->isGLSL())
2535             {
2536                 t = STKTexManager::getInstance()->getTexture(v[i],
2537                     (TexConfig*)NULL/*tex_config*/, true/*no_upload*/);
2538             }
2539             else
2540 #endif   // !SERVER_ONLY
2541             {
2542                 t = irr_driver->getTexture(v[i]);
2543             }
2544             if (t)
2545             {
2546 #ifndef SERVER_ONLY
2547                 if (!CVS->isGLSL())
2548 #endif   // !SERVER_ONLY
2549                     t->grab();
2550                 m_spherical_harmonics_textures.push_back(t);
2551             }
2552             else
2553             {
2554                 Log::error("track", "Sky-box spherical harmonics texture '%s' not found - ignored.",
2555                     v[i].c_str());
2556             }
2557         }   // for i<v.size()
2558     }
2559     else if (xml_node.getName() == "sky-color")
2560     {
2561         m_sky_type = SKY_COLOR;
2562         xml_node.get("rgb", &m_sky_color);
2563     }   // if sky-box
2564 }   // handleSky
2565 
2566 //-----------------------------------------------------------------------------
flagCommand(const XMLNode * node)2567 Vec3 Track::flagCommand(const XMLNode *node)
2568 {
2569     Vec3 xyz;
2570     // Set some kind of default in case Y is not defined in the file
2571     // (with the new track exporter it always is defined anyway).
2572     // Y is the height from which the item is dropped on the track.
2573     xyz.setY(1000);
2574     node->getXYZ(&xyz);
2575 
2576     if (!m_track_mesh)
2577         return xyz;
2578 
2579     Vec3 loc(xyz);
2580 
2581     // Test if the item lies on a 3d node, if so adjust the normal
2582     // Also do a raycast if drop item is given
2583     Vec3 normal(0, 1, 0);
2584     Vec3 quad_normal = normal;
2585     Vec3 hit_point = loc;
2586     if (Graph::get())
2587     {
2588         int road_sector = Graph::UNKNOWN_SECTOR;
2589         Graph::get()->findRoadSector(xyz, &road_sector);
2590         // Only do custom direction of raycast if item is on quad graph
2591         if (road_sector != Graph::UNKNOWN_SECTOR)
2592         {
2593             quad_normal = Graph::get()->getQuad(road_sector)->getNormal();
2594         }
2595     }
2596 
2597     const Material *m;
2598     // If raycast is used, increase the start position slightly
2599     // in case that the point is too close to the actual surface
2600     // (e.g. floating point errors can cause a problem here).
2601     loc += quad_normal * 0.1f;
2602 
2603 #ifndef DEBUG
2604     m_track_mesh->castRay(loc, loc + (-10000 * quad_normal), &hit_point,
2605         &m, &normal);
2606 #else
2607     bool drop_success = m_track_mesh->castRay(loc, loc +
2608         (-10000 * quad_normal), &hit_point, &m, &normal);
2609     if (!drop_success)
2610     {
2611         Log::warn("track", "flag at position (%f,%f,%f) can not be dropped",
2612             loc.getX(), loc.getY(), loc.getZ());
2613         Log::warn("track", "onto terrain - position unchanged.");
2614     }
2615 #endif
2616 
2617     m_track_object_manager->castRay
2618         (loc, loc + (-10000 * quad_normal), &hit_point, &m, &normal,
2619          /*interpolate*/false);
2620 
2621     const std::string &name = node->getName();
2622     if (name == "red-flag")
2623     {
2624         m_red_flag = btTransform(shortestArcQuat(Vec3(0, 1, 0), normal),
2625             hit_point);
2626     }
2627     else
2628     {
2629         m_blue_flag = btTransform(shortestArcQuat(Vec3(0, 1, 0), normal),
2630             hit_point);
2631     }
2632     return hit_point;
2633 }   // flagCommand
2634 
2635 //-----------------------------------------------------------------------------
2636 /** Handle creation and placement of an item.
2637  *  \param xyz The position of the item.
2638  *  \param type The item type.
2639  *  \param drop True if the item Z position should be determined based on
2640  *         the track topology.
2641  */
itemCommand(const XMLNode * node)2642 void Track::itemCommand(const XMLNode *node)
2643 {
2644     const std::string &name = node->getName();
2645 
2646     const bool is_mode_ctf = m_is_ctf && RaceManager::get()->isCTFMode();
2647     bool ctf = false;
2648     node->get("ctf", &ctf);
2649     if ((is_mode_ctf && !ctf) || (!is_mode_ctf && ctf))
2650         return;
2651 
2652     Item::ItemType type;
2653     if     (name=="banana"     ) type = Item::ITEM_BANANA;
2654     else if(name=="item"       ) type = Item::ITEM_BONUS_BOX;
2655     else if(name=="small-nitro") type = Item::ITEM_NITRO_SMALL;
2656     else if(name=="easter-egg" ) type = Item::ITEM_EASTER_EGG;
2657     else                         type = Item::ITEM_NITRO_BIG;
2658     Vec3 xyz;
2659     // Set some kind of default in case Y is not defined in the file
2660     // (with the new track exporter it always is defined anyway).
2661     // Y is the height from which the item is dropped on the track.
2662     xyz.setY(1000);
2663     node->getXYZ(&xyz);
2664     bool drop=true;
2665     node->get("drop", &drop);
2666 
2667     // Some modes (e.g. time trial) don't have any bonus boxes
2668     if(type==Item::ITEM_BONUS_BOX &&
2669        !World::getWorld()->haveBonusBoxes())
2670         return;
2671 
2672     // Only do easter eggs in easter egg mode.
2673     if(!(RaceManager::get()->isEggHuntMode()) && type==Item::ITEM_EASTER_EGG)
2674     {
2675         Log::warn("track",
2676                   "Found easter egg in non-easter-egg mode - ignored.\n");
2677         return;
2678     }
2679 
2680     Vec3 loc(xyz);
2681 
2682     // Test if the item lies on a 3d node, if so adjust the normal
2683     // Also do a raycast if drop item is given
2684     Vec3 normal(0, 1, 0);
2685     Vec3 quad_normal = normal;
2686     Vec3 hit_point = loc;
2687     if (Graph::get())
2688     {
2689         int road_sector = Graph::UNKNOWN_SECTOR;
2690         Graph::get()->findRoadSector(xyz, &road_sector);
2691         // Only do custom direction of raycast if item is on quad graph
2692         if (road_sector != Graph::UNKNOWN_SECTOR)
2693         {
2694             quad_normal = Graph::get()->getQuad(road_sector)->getNormal();
2695         }
2696     }
2697 
2698     if (drop)
2699     {
2700         const Material *m;
2701         // If raycast is used, increase the start position slightly
2702         // in case that the point is too close to the actual surface
2703         // (e.g. floating point errors can cause a problem here).
2704         loc += quad_normal * 0.1f;
2705 
2706 #ifndef DEBUG
2707         m_track_mesh->castRay(loc, loc + (-10000 * quad_normal), &hit_point,
2708             &m, &normal);
2709         m_track_object_manager->castRay(loc,
2710             loc + (-10000 * quad_normal), &hit_point, &m, &normal,
2711             /*interpolate*/false);
2712 #else
2713         bool drop_success = m_track_mesh->castRay(loc, loc +
2714             (-10000 * quad_normal), &hit_point, &m, &normal);
2715         bool over_driveable = m_track_object_manager->castRay(loc,
2716             loc + (-10000 * quad_normal), &hit_point, &m, &normal,
2717             /*interpolate*/false);
2718         if (!drop_success && !over_driveable)
2719         {
2720             Log::warn("track",
2721                       "Item at position (%f,%f,%f) can not be dropped",
2722                       loc.getX(), loc.getY(), loc.getZ());
2723             Log::warn("track", "onto terrain - position unchanged.");
2724         }
2725 #endif
2726     }
2727 
2728     m_item_manager->placeItem(type, drop ? hit_point : loc, normal);
2729 }   // itemCommand
2730 
2731 // ----------------------------------------------------------------------------
2732 
buildHeightMap()2733 std::vector< std::vector<float> > Track::buildHeightMap()
2734 {
2735     std::vector< std::vector<float> > out(HEIGHT_MAP_RESOLUTION);
2736 
2737     float x = m_aabb_min.getX();
2738     const float x_len = m_aabb_max.getX() - m_aabb_min.getX();
2739     const float z_len = m_aabb_max.getZ() - m_aabb_min.getZ();
2740 
2741     const float x_step = x_len/HEIGHT_MAP_RESOLUTION;
2742     const float z_step = z_len/HEIGHT_MAP_RESOLUTION;
2743 
2744     btVector3 hitpoint;
2745     const Material* material;
2746     btVector3 normal;
2747 
2748     for (int i=0; i<HEIGHT_MAP_RESOLUTION; i++)
2749     {
2750         out[i].resize(HEIGHT_MAP_RESOLUTION);
2751         float z = m_aabb_min.getZ();
2752 
2753         for (int j=0; j<HEIGHT_MAP_RESOLUTION; j++)
2754         {
2755             btVector3 pos(x, 100.0f, z);
2756             btVector3 to = pos;
2757             to.setY(-100000.f);
2758 
2759             m_track_mesh->castRay(pos, to, &hitpoint, &material, &normal);
2760             z += z_step;
2761 
2762             out[i][j] = hitpoint.getY();
2763         }   // j<HEIGHT_MAP_RESOLUTION
2764         x += x_step;
2765     }
2766 
2767     return out;
2768 }   // buildHeightMap
2769 
2770 // ----------------------------------------------------------------------------
drawMiniMap(const core::rect<s32> & dest_rect) const2771 void Track::drawMiniMap(const core::rect<s32>& dest_rect) const
2772 {
2773     if(m_render_target)
2774         m_render_target->draw2DImage(dest_rect, NULL,
2775                                      video::SColor(127, 255, 255, 255),
2776                                      true);
2777 }
2778 
2779 // ----------------------------------------------------------------------------
2780 /** Returns the rotation of the sun. */
getSunRotation()2781 const core::vector3df& Track::getSunRotation()
2782 {
2783     return m_sun->getRotation();
2784 }
2785 //-----------------------------------------------------------------------------
2786 /** Determines if the kart is over ground.
2787  *  Used in setting the starting positions of all the karts.
2788  *  \param k The kart to project downward.
2789  *  \return True of the kart is on terrain.
2790  */
2791 
findGround(AbstractKart * kart)2792 bool Track::findGround(AbstractKart *kart)
2793 {
2794     const Vec3 &xyz = kart->getXYZ();
2795     Vec3 down = kart->getTrans().getBasis() * Vec3(0, -10000.0f, 0);
2796 
2797     // Material and hit point are not needed;
2798     const Material *m;
2799     Vec3 hit_point, normal;
2800     bool over_ground = m_track_mesh->castRay(xyz, down, &hit_point,
2801                                              &m, &normal);
2802 
2803     // Now also raycast against all track objects (that are driveable). If
2804     // there should be a closer result (than the one against the main track
2805     // mesh), its data will be returned.
2806     // From TerrainInfo::update
2807     bool over_driveable = m_track_object_manager->castRay(xyz, down,
2808         &hit_point, &m, &normal, /*interpolate*/false);
2809 
2810     if (!over_ground && !over_driveable)
2811     {
2812         Log::warn("physics", "Kart at (%f %f %f) can not be dropped.",
2813                   xyz.getX(),xyz.getY(),xyz.getZ());
2814         return false;
2815     }
2816 
2817     // Check if the material the kart is about to be placed on would trigger
2818     // a reset. If so, this is not a valid position.
2819     if(m && m->isDriveReset())
2820     {
2821         Log::warn("physics","Kart at (%f %f %f) over reset terrain '%s'",
2822                    xyz.getX(),xyz.getY(),xyz.getZ(),
2823                    m->getTexFname().c_str());
2824         return false;
2825     }
2826 
2827     // See if the kart is too high above the ground - it would drop
2828     // too long.
2829     if(xyz.getY() - hit_point.getY() > 5)
2830     {
2831         Log::warn("physics",
2832                   "Kart at (%f %f %f) is too high above ground at (%f %f %f)",
2833                   xyz.getX(),xyz.getY(),xyz.getZ(),
2834                   hit_point.getX(),hit_point.getY(),hit_point.getZ());
2835         return false;
2836     }
2837 
2838     btTransform t = kart->getBody()->getCenterOfMassTransform();
2839     // The computer offset is slightly too large, it should take
2840     // the default suspension rest instead of suspension rest (i.e. the
2841     // length of the suspension with the weight of the kart resting on
2842     // it). On the other hand this initial bouncing looks nice imho
2843     // - so I'll leave it in for now.
2844     float offset = kart->getKartProperties()->getSuspensionRest();
2845     t.setOrigin(hit_point + normal * offset);
2846     kart->getBody()->setCenterOfMassTransform(t);
2847     kart->setTrans(t);
2848 
2849     return true;
2850 }   // findGround
2851 
2852 //-----------------------------------------------------------------------------
getTrackLength() const2853 float Track::getTrackLength() const
2854 {
2855     return DriveGraph::get()->getLapLength();
2856 }   // getTrackLength
2857 
2858 //-----------------------------------------------------------------------------
getAngle(int n) const2859 float Track::getAngle(int n) const
2860 {
2861     return DriveGraph::get()->getAngleToNext(n, 0);
2862 }   // getAngle
2863 
2864 //-----------------------------------------------------------------------------
uploadNodeVertexBuffer(scene::ISceneNode * node)2865 void Track::uploadNodeVertexBuffer(scene::ISceneNode *node)
2866 {
2867 #ifndef SERVER_ONLY
2868     if (!CVS->isGLSL())
2869     {
2870         return;
2871     }
2872     SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(node);
2873     if (spmn)
2874     {
2875         SP::uploadSPM(spmn->getSPM());
2876     }
2877 #endif
2878 }   // uploadNodeVertexBuffer
2879 
2880 //-----------------------------------------------------------------------------
copyFromMainProcess()2881 void Track::copyFromMainProcess()
2882 {
2883     // Clear all unneeded objects copied in main process track
2884     m_physical_object_uid = 0;
2885     m_animated_textures.clear();
2886     m_animated_textures.shrink_to_fit();
2887     m_all_nodes.clear();
2888     m_all_nodes.shrink_to_fit();
2889     m_static_physics_only_nodes.clear();
2890     m_static_physics_only_nodes.shrink_to_fit();
2891     m_object_physics_only_nodes.clear();
2892     m_object_physics_only_nodes.shrink_to_fit();
2893     m_sun = NULL;
2894     m_all_cached_meshes.clear();
2895     m_all_cached_meshes.shrink_to_fit();
2896     m_detached_cached_meshes.clear();
2897     m_detached_cached_meshes.shrink_to_fit();
2898     m_sky_textures.clear();
2899     m_sky_textures.shrink_to_fit();
2900     m_spherical_harmonics_textures.clear();
2901     m_spherical_harmonics_textures.shrink_to_fit();
2902     m_meta_library.clear();
2903     m_meta_library.shrink_to_fit();
2904 
2905     // Clone the needed object now in main process
2906     Track* main_track = m_current_track[PT_MAIN];
2907     CheckManager* main_cm = main_track->m_check_manager;
2908     m_check_manager = new CheckManager();
2909     for (unsigned i = 0; i < main_cm->getCheckStructureCount(); i++)
2910     {
2911         CheckStructure* cs = main_cm->getCheckStructure(i);
2912         m_check_manager->add(cs->clone());
2913     }
2914 
2915     TrackObjectManager* main_tom = m_track_object_manager;
2916     m_track_object_manager = new TrackObjectManager();
2917     for (auto* to : main_tom->getObjects().m_contents_vector)
2918     {
2919         TrackObject* clone = to->cloneToChild();
2920         if (clone)
2921             m_track_object_manager->insertObject(clone);
2922     }
2923 
2924     m_track_mesh = new TriangleMesh(/*can_be_transformed*/false);
2925     m_gfx_effect_mesh = new TriangleMesh(/*can_be_transformed*/false);
2926     m_track_mesh->copyFrom(*main_track->m_track_mesh);
2927     m_gfx_effect_mesh->copyFrom(*main_track->m_gfx_effect_mesh);
2928 
2929     // At the moment we only use network for child track
2930     auto nim = std::make_shared<NetworkItemManager>();
2931     for (unsigned i = 0; i < m_item_manager->getNumberOfItems(); i++)
2932     {
2933         ItemState* it = m_item_manager->getItem(i);
2934         nim->insertItem(new Item(it->getType(), it->getXYZ(), it->getNormal(),
2935             NULL/*mesh*/, NULL/*lowres_mesh*/, NULL/*owner*/));
2936     }
2937     m_item_manager = nim;
2938 }   // copyFromMainProcess
2939 
2940 //-----------------------------------------------------------------------------
initChildTrack()2941 void Track::initChildTrack()
2942 {
2943     // This will be called in child process after main one copied to it
2944     assert(STKProcess::getType() == PT_CHILD);
2945     // Add in child process for rewind manager
2946     std::dynamic_pointer_cast<NetworkItemManager>
2947         (m_item_manager)->rewinderAdd();
2948     std::dynamic_pointer_cast<NetworkItemManager>
2949         (m_item_manager)->initServer();
2950 
2951     // We call physics init in child process too
2952     Physics::get()->init(m_aabb_min, m_aabb_max);
2953     m_track_mesh->createPhysicalBody(m_friction);
2954     m_gfx_effect_mesh->createCollisionShape();
2955 
2956     // All child track objects are only cloned if they have physical objects
2957     for (auto* to : m_track_object_manager->getObjects().m_contents_vector)
2958         to->getPhysicalObject()->addBody();
2959     m_track_object_manager->init();
2960 
2961     if (auto sl = LobbyProtocol::get<ServerLobby>())
2962     {
2963         sl->saveInitialItems(
2964             std::dynamic_pointer_cast<NetworkItemManager>(m_item_manager));
2965     }
2966 }   // initChildTrack
2967 
2968 //-----------------------------------------------------------------------------
cleanChildTrack()2969 void Track::cleanChildTrack()
2970 {
2971     assert(STKProcess::getType() == PT_CHILD);
2972     Track* child_track = m_current_track[PT_CHILD];
2973     child_track->m_item_manager = nullptr;
2974     delete child_track->m_check_manager;
2975     delete child_track->m_track_object_manager;
2976     delete child_track->m_track_mesh;
2977     delete child_track->m_gfx_effect_mesh;
2978     delete child_track;
2979     m_current_track[PT_CHILD] = NULL;
2980 }   // cleanChildTrack
2981