1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2011-2015 Joerg Henrichs
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "graphics/referee.hpp"
20 #include "config/stk_config.hpp"
21 #include "graphics/central_settings.hpp"
22 #include "graphics/irr_driver.hpp"
23 #include "graphics/light.hpp"
24 #include "graphics/material.hpp"
25 #include "graphics/mesh_tools.hpp"
26 #include "graphics/sp/sp_mesh_buffer.hpp"
27 #include "graphics/sp/sp_mesh_node.hpp"
28 #include "karts/abstract_kart.hpp"
29 #include "io/file_manager.hpp"
30 #include "io/xml_node.hpp"
31 #include "modes/world.hpp"
32 #include "utils/constants.hpp"
33 #include "utils/log.hpp"
34 #include "utils/string_utils.hpp"
35 
36 int                   Referee::m_st_first_start_frame  = 1;
37 int                   Referee::m_st_last_start_frame   = 1;
38 int                   Referee::m_st_first_rescue_frame = 1;
39 int                   Referee::m_st_last_rescue_frame  = 1;
40 int                   Referee::m_st_traffic_buffer     = -1;
41 Vec3                  Referee::m_st_start_offset       = Vec3(-2, 2, 2);
42 Vec3                  Referee::m_st_start_rotation     = Vec3(0, 180, 0);
43 Vec3                  Referee::m_st_scale              = Vec3(1, 1, 1);
44 float                 Referee::m_height                = 0.0f;
45 scene::IAnimatedMesh *Referee::m_st_referee_mesh       = NULL;
46 
47 // ----------------------------------------------------------------------------
48 /** Loads the static mesh.
49  */
init()50 void Referee::init()
51 {
52     assert(!m_st_referee_mesh);
53     const std::string filename=file_manager->getAssetChecked(FileManager::MODEL,
54                                                              "referee.xml", true);
55     XMLNode *node = file_manager->createXMLTree(filename);
56     if(!node)
57     {
58         Log::fatal("referee", "Can't read XML file referee.xml, aborting.");
59     }
60     if(node->getName()!="referee")
61     {
62         Log::fatal("referee", "The file referee.xml does not contain a referee"
63                "node, aborting.");
64     }
65     std::string model_filename;
66     node->get("model", &model_filename);
67 
68     m_st_referee_mesh = irr_driver->getAnimatedMesh(
69                                  file_manager->getAsset(FileManager::MODEL,
70                                                         model_filename)      );
71     if(!m_st_referee_mesh)
72     {
73         Log::fatal("referee", "Can't find referee model '%s', aborting.",
74                model_filename.c_str());
75     }
76 
77     node->get("first-rescue-frame", &m_st_first_rescue_frame);
78     node->get("last-rescue-frame",  &m_st_last_rescue_frame );
79     node->get("first-start-frame",  &m_st_first_start_frame );
80     node->get("last-start-frame",   &m_st_last_start_frame  );
81     node->get("start-offset",       &m_st_start_offset      );
82     node->get("scale",              &m_st_scale             );
83     node->get("start-rotation",     &m_st_start_rotation    );
84 
85     float angle_to_kart = atan2(m_st_start_offset.getX(),
86                                 m_st_start_offset.getZ())
87                         * RAD_TO_DEGREE;
88     m_st_start_rotation.setY(m_st_start_rotation.getY()+angle_to_kart);
89 
90     for(unsigned int i=0; i<m_st_referee_mesh->getMeshBufferCount(); i++)
91     {
92         if (m_st_traffic_buffer != -1)
93         {
94             break;
95         }
96         scene::IMeshBuffer *mb = m_st_referee_mesh->getMeshBuffer(i);
97         SP::SPMeshBuffer* spmb = dynamic_cast<SP::SPMeshBuffer*>(mb);
98         if (spmb)
99         {
100             auto ret = spmb->getAllSTKMaterials();
101             for (unsigned j = 0; j < ret.size(); j++)
102             {
103                 std::string name =
104                     StringUtils::getBasename(ret[j]->getSamplerPath(0));
105                 if (name == "traffic_light.png")
106                 {
107                     m_st_traffic_buffer = i;
108                     spmb->enableTextureMatrix(j);
109                     break;
110                 }
111             }
112             continue;
113         }
114         video::SMaterial &irrMaterial = mb->getMaterial();
115         video::ITexture* t=irrMaterial.getTexture(0);
116         if(!t) continue;
117 
118         std::string name=StringUtils::getBasename(t->getName()
119                                                   .getInternalName().c_str());
120         if (name == "traffic_light.png")
121         {
122             m_st_traffic_buffer = i;
123             break;
124         }
125         else
126         {
127             irrMaterial.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
128         }
129 
130     }
131 
132     delete node;
133 }   // init
134 
135 // ----------------------------------------------------------------------------
136 /** Frees the static mesh.
137  */
cleanup()138 void Referee::cleanup()
139 {
140     irr_driver->removeMeshFromCache(m_st_referee_mesh);
141     m_st_referee_mesh = NULL;
142     m_st_traffic_buffer = -1;
143 }   // cleanup
144 
145 // ----------------------------------------------------------------------------
146 /** Creates an instance of the referee, using the static values to initialise
147  *  it. This is the constructor used when a start referee is needed.
148  */
Referee()149 Referee::Referee()
150 {
151     assert(m_st_referee_mesh);
152     // First add a NULL mesh, then set the material to be read only
153     // (this appears to be the only way to get read only materials).
154     // This way we only need to adjust the materials in the original
155     // mesh. ATM it doesn't make any difference, but if we ever should
156     // decide to use more than one referee model at startup we only
157     // have to change the textures once, and all models will be in synch.
158     m_scene_node = irr_driver->addAnimatedMesh(NULL, "referee");
159     m_scene_node->setReadOnlyMaterials(true);
160     m_scene_node->setMesh(m_st_referee_mesh);
161     m_scene_node->grab();
162     m_scene_node->setRotation(m_st_start_rotation.toIrrVector());
163     m_scene_node->setScale(m_st_scale.toIrrVector());
164     m_scene_node->setFrameLoop(m_st_first_start_frame,
165                                m_st_last_start_frame);
166 #ifndef SERVER_ONLY
167     if (CVS->isGLSL() && CVS->isDeferredEnabled())
168     {
169         m_light = irr_driver->addLight(core::vector3df(0.0f, 0.0f, 0.6f), 0.7f, 2.0f,
170             0.7f /* r */, 0.0 /* g */, 0.0f /* b */, false /* sun */, m_scene_node);
171     }
172     else
173 #endif
174     {
175         m_light = NULL;
176     }
177 }   // Referee
178 
179 // ----------------------------------------------------------------------------
180 /** Creates an instance of the referee, using the static values to initialise
181  *  it. This is the constructor used when a rescue referee is needed.
182  *  \param kart The kart which the referee should rescue.
183  */
Referee(const AbstractKart & kart)184 Referee::Referee(const AbstractKart &kart)
185 {
186     assert(m_st_referee_mesh);
187     // First add a NULL mesh, then set the material to be read only
188     // (this appears to be the only way to get read only materials).
189     // This way we only need to adjust the materials in the original
190     // mesh. ATM it doesn't make any difference, but if we ever should
191     // decide to use more than one referee model at startup we only
192     // have to change the textures once, and all models will be in synch.
193     m_scene_node = irr_driver->addAnimatedMesh(NULL, "referee");
194     m_scene_node->setReadOnlyMaterials(true);
195     m_scene_node->setMesh(m_st_referee_mesh);
196     m_scene_node->grab();
197     m_scene_node->setScale(m_st_scale.toIrrVector());
198     m_scene_node->setPosition(core::vector3df(0, kart.getKartHeight() + 0.4f, 0));
199 
200 }   // Referee
201 
202 // ----------------------------------------------------------------------------
~Referee()203 Referee::~Referee()
204 {
205     if(m_scene_node->getParent())
206         irr_driver->removeNode(m_scene_node);
207     m_scene_node->drop();
208 }   // ~Referee
209 
210 // ----------------------------------------------------------------------------
211 /** Make sure that this referee is attached to the scene graph. This is used
212  *  for the start referee, which is removed from scene graph once the ready-
213  *  set-go phase is over (it is kept in case of a restart of the race).
214  */
attachToSceneNode()215 void Referee::attachToSceneNode()
216 {
217     if(!m_scene_node->getParent())
218         m_scene_node->setParent(irr_driver->getSceneManager()
219                                           ->getRootSceneNode());
220 
221     if (m_light != NULL)
222         m_light->setVisible(true);
223 }   // attachToSceneNode
224 
225 // ----------------------------------------------------------------------------
226 /** Removes the referee's scene node from the scene graph, but still keeps
227  *  the scene node in memory. This is used for the start referee, so that
228  *  it is quickly available in case of a restart.
229  */
removeFromSceneGraph()230 void Referee::removeFromSceneGraph()
231 {
232     if(isAttached())
233         irr_driver->removeNode(m_scene_node);
234     if (m_light != NULL)
235         m_light->setVisible(false);
236 }   // removeFromSceneGraph
237 
238 // ----------------------------------------------------------------------------
239 /** Selects one of the states 'ready', 'set', or 'go' to be displayed by
240  *  the referee.
241  *  \param rsg 0=ready, 1=set, 2=go.
242  */
selectReadySetGo(int rsg)243 void Referee::selectReadySetGo(int rsg)
244 {
245     if (m_st_traffic_buffer < 0)
246         return;
247 
248     SP::SPMeshNode* spmn = dynamic_cast<SP::SPMeshNode*>(m_scene_node);
249     if (spmn)
250     {
251         spmn->setTextureMatrix(m_st_traffic_buffer, {{ 0.0f, rsg * 0.333f }});
252     }
253     else
254     {
255         video::SMaterial &m = m_scene_node->getMaterial(m_st_traffic_buffer);
256         core::matrix4* matrix = &m.getTextureMatrix(0);
257         matrix->setTextureTranslate(0.0f, rsg*0.333f);
258         // disable lighting, we need to see the traffic light even if facing away
259         // from the sun
260         m.AmbientColor  = video::SColor(255, 255, 255, 255);
261         m.DiffuseColor  = video::SColor(255, 255, 255, 255);
262         m.EmissiveColor = video::SColor(255, 255, 255, 255);
263         m.SpecularColor = video::SColor(255, 255, 255, 255);
264     }
265 
266     if (m_light != NULL)
267     {
268         if (rsg == 0)
269         {
270             ((LightNode*)m_light)->setColor(0.6f, 0.0f, 0.0f);
271         }
272         else if (rsg == 1)
273         {
274             ((LightNode*)m_light)->setColor(0.7f, 0.23f, 0.0f);
275         }
276         else if (rsg == 2)
277         {
278             ((LightNode*)m_light)->setColor(0.0f, 0.6f, 0.0f);
279         }
280     }
281 }   // selectReadySetGo
282 
283 // ----------------------------------------------------------------------------
284 /** Set the referee animation frame with created ticks of \ref RescueAnimation,
285  *  so that it's synchronized with world ticks, and can be rewound easily.
286  */
setAnimationFrameWithCreatedTicks(int created_ticks)287 void Referee::setAnimationFrameWithCreatedTicks(int created_ticks)
288 {
289     float dur = stk_config->ticks2Time(
290         World::getWorld()->getTicksSinceStart() - created_ticks);
291     dur *= 25.0f;
292     float ref_dur = (float)(m_st_last_rescue_frame - m_st_first_rescue_frame);
293     float frame = std::fmod(dur, ref_dur);
294     frame += (float)m_st_first_rescue_frame;
295     m_scene_node->setCurrentFrame(frame);
296 }   // setAnimationFrameWithCreatedTicks
297