1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2004-2015 Steve Baker <sjbaker1@airmail.net>
4 //  Copyright (C) 2010-2015 Steve Baker, Joerg Henrichs
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 #ifndef HEADER_MATERIAL_HPP
21 #define HEADER_MATERIAL_HPP
22 
23 #include "utils/no_copy.hpp"
24 #include "utils/random_generator.hpp"
25 
26 #include <array>
27 #include <assert.h>
28 #include <map>
29 #include <string>
30 #include <vector>
31 
32 namespace irr
33 {
34     namespace video { class ITexture; class SMaterial; }
35     namespace scene { class ISceneNode; class IMeshBuffer; }
36 }
37 using namespace irr;
38 
39 class XMLNode;
40 class SFXBase;
41 class ParticleKind;
42 
43 /**
44   * \ingroup graphics
45   */
46 class Material : public NoCopy
47 {
48 public:
49     enum ParticleConditions
50     {
51         EMIT_ON_DRIVE = 0,
52         EMIT_ON_SKID,
53 
54         EMIT_KINDS_COUNT
55     };
56 
57     enum CollisionReaction
58     {
59         NORMAL,
60         RESCUE,
61         PUSH_BACK,
62         PUSH_SOCCER_BALL
63     };
64 
65 private:
66 
67     /** Pointer to the texture. */
68     video::ITexture *m_texture;
69 
70     /** Name of the texture. */
71     std::string      m_texname;
72 
73     std::string      m_full_path;
74 
75     /** Name of a special sfx to play when a kart is on this terrain, or
76      *  "" if no special sfx exists. */
77     std::string      m_sfx_name;
78 
79     /** Either ' ' (no mirroring), 'U' or 'V' if a texture needs to be
80      *  mirrored when driving in reverse. Typically used for arrows indicating
81      *  the direction. */
82     char             m_mirror_axis_when_reverse;
83 
84     /** Set if being on this surface means being under some other mesh.
85      *  This is used to simulate that a kart is in water: the ground under
86      *  the water is marked as 'm_below_surface', which will then trigger a raycast
87      *  up to find the position of the actual water surface. */
88     bool             m_below_surface;
89 
90     /** If a kart is falling over a material with this flag set, it
91      *  will trigger the special camera fall effect. */
92     bool             m_falling_effect;
93     /** A material that is a surface only, i.e. the karts can fall through
94      *  but the information is still needed (for GFX mostly). An example is
95      *  a water surface: karts can drive while partly in water (so the water
96      *  surface is not a physical object), but the location of the water
97      *  effect is on the surface. */
98     bool             m_surface;
99 
100     /** If the material is a zipper, i.e. gives a speed boost. */
101     bool             m_zipper;
102 
103     /** If a kart is rescued when driving on this surface. */
104     bool             m_drive_reset;
105 
106     /** True if this is a texture that will start the jump animation when
107      *  leaving it and being in the air. */
108     bool             m_is_jump_texture;
109 
110     /** True if driving on this texture should adjust the gravity of the kart
111      *  to be along the normal of the triangle. This allows karts to drive e.g
112      *  upside down. */
113     bool             m_has_gravity;
114 
115     /** If the property should be ignored in the physics. Example would be
116      *  plants that a kart can just drive through. */
117     bool             m_ignore;
118 
119     /** True if the material shouldn't be "slippy" at an angle */
120     bool             m_high_tire_adhesion;
121 
122     bool  m_complain_if_not_found;
123 
124     bool  m_deprecated;
125 
126     bool  m_installed;
127 
128     /** True if this material can be colorized (like red/blue in team game). */
129     bool             m_colorizable;
130 
131     /** True if this material should use texture compression. */
132     bool             m_tex_compression;
133 
134     /** Minimum resulting saturation when colorized (from 0 to 1) */
135     float            m_colorization_factor;
136 
137     /** If a kart is rescued when crashing into this surface. */
138     CollisionReaction m_collision_reaction;
139 
140     /** Particles to show on touch */
141     std::string      m_collision_particles;
142 
143     /**
144     * Associated with m_mirror_axis_when_reverse, to avoid mirroring the same material twice
145     * (setAllMaterialFlags can be called multiple times on the same mesh buffer)
146     */
147     std::map<void*, bool> m_mirrorred_mesh_buffers;
148 
149     ParticleKind*    m_particles_effects[EMIT_KINDS_COUNT];
150 
151     /** Texture clamp bitmask */
152     unsigned int     m_clamp_tex;
153 
154     /** List of hue pre-defined for colorization (from 0 to 1) */
155     std::vector<float> m_hue_settings;
156 
157     /** Random generator for getting pre-defined hue */
158     RandomGenerator m_random_hue;
159 
160     /** How much the top speed is reduced per second. */
161     int              m_slowdown_ticks;
162 
163     /** Maximum speed at which no more slow down occurs. */
164     float            m_max_speed_fraction;
165 
166     /** Minimum speed on this terrain. This is used for zippers on a ramp to
167      *  guarantee the right jump distance. A negative value indicates no
168      *  minimum speed. */
169     float            m_zipper_min_speed;
170     /** The minimum speed at which a special sfx is started to be played. */
171     float            m_sfx_min_speed;
172     /** The speed at which the maximum pitch is used. */
173     float            m_sfx_max_speed;
174     /** The minimum pitch to be used (at minimum speed). */
175     float            m_sfx_min_pitch;
176     /** The maximum pitch to be used (at maximum speed). */
177     float            m_sfx_max_pitch;
178     /** (max_pitch-min_pitch) / (max_speed - min_speed). Used to adjust
179      *  the pitch of a sfx depending on speed of the kart.
180      */
181     float            m_sfx_pitch_per_speed;
182     /** Additional speed allowed on top of the kart-specific maximum kart speed
183      *  if a zipper is used. If this value is <0 the kart specific value will
184      *  be used. */
185     float            m_zipper_max_speed_increase;
186     /** Time a zipper stays activated. If this value is <0 the kart specific
187      *  value will be used. */
188     float            m_zipper_duration;
189     /** A one time additional speed gain - the kart will instantly add this
190      *  amount of speed to its current speed. If this value is <0 the kart
191      *  specific value will be used. */
192     float            m_zipper_speed_gain;
193     /**  Time it takes for the zipper advantage to fade out. If this value
194      *  is <0 the kart specific value will be used. */
195     float            m_zipper_fade_out_time;
196     /** Additional engine force. */
197     float            m_zipper_engine_force;
198 
199     std::string      m_mask;
200 
201     std::string      m_colorization_mask;
202 
203     void  init    ();
204     void  install (bool srgb = false, bool premul_alpha = false);
205     void  initCustomSFX(const XMLNode *sfx);
206     void  initParticlesEffect(const XMLNode *node);
207 
208     // SP usage
209     std::string      m_shader_name;
210     std::string      m_uv_two_tex;
211     // Full path for textures in sp shader
212     std::string      m_sampler_path[6];
213     std::string      m_container_id;
214     void loadContainerId();
215 
216 public:
217           Material(const XMLNode *node, bool deprecated);
218           Material(const std::string& fname,
219                    bool is_full_path=false,
220                    bool complain_if_not_found=true,
221                    bool load_texture = true,
222                    const std::string& shader_name = "solid");
223          ~Material ();
224 
225     void unloadTexture();
226 
227     void  setSFXSpeed(SFXBase *sfx, float speed, bool should_be_paused) const;
228     void  setMaterialProperties(video::SMaterial *m, scene::IMeshBuffer* mb);
229 
230     /** Returns the ITexture associated with this material. */
231     video::ITexture *getTexture(bool srgb = true, bool premul_alpha = false);
232     // ------------------------------------------------------------------------
isIgnore() const233     bool  isIgnore           () const { return m_ignore;             }
234     // ------------------------------------------------------------------------
235     /** Returns true if this material is a zipper. */
isZipper() const236     bool  isZipper           () const { return m_zipper;             }
237     // ------------------------------------------------------------------------
238     /** Returns if this material should trigger a rescue if a kart
239      *  is driving on it. */
isDriveReset() const240     bool  isDriveReset       () const { return m_drive_reset;        }
241     // ------------------------------------------------------------------------
242     /** Returns if this material can be colorized.
243      */
isColorizable() const244     bool  isColorizable      () const { return m_colorizable;        }
245     // ------------------------------------------------------------------------
246     /** Returns the minimum resulting saturation when colorized.
247      */
getColorizationFactor() const248     float getColorizationFactor () const { return m_colorization_factor;   }
249     // ------------------------------------------------------------------------
hasRandomHue() const250     bool hasRandomHue() const            { return !m_hue_settings.empty(); }
251     // ------------------------------------------------------------------------
252     /** Returns a random hue when colorized.
253      */
getRandomHue()254     float getRandomHue()
255     {
256         if (m_hue_settings.empty())
257             return 0.0f;
258         const unsigned int hue = m_random_hue.get((int)m_hue_settings.size());
259         assert(hue < m_hue_settings.size());
260         return m_hue_settings[hue];
261     }
262     // ------------------------------------------------------------------------
263     /** Returns if this material should trigger a rescue if a kart
264      *  crashes against it. */
getCollisionReaction() const265     CollisionReaction  getCollisionReaction() const { return m_collision_reaction; }
266 
267     // ------------------------------------------------------------------------
getCrashResetParticles() const268     std::string getCrashResetParticles() const { return m_collision_particles; }
269 
270     // ------------------------------------------------------------------------
highTireAdhesion() const271     bool  highTireAdhesion   () const { return m_high_tire_adhesion; }
272     // ------------------------------------------------------------------------
273     const std::string&
getTexFname() const274           getTexFname        () const { return m_texname;            }
275     // ------------------------------------------------------------------------
276     const std::string&
getTexFullPath() const277           getTexFullPath     () const { return m_full_path;          }
278 
279     // ------------------------------------------------------------------------
isTransparent() const280     bool  isTransparent      () const
281     {
282         return m_shader_name == "additive" || m_shader_name == "alphablend" ||
283                m_shader_name == "displace";
284     }
285 
286     // ------------------------------------------------------------------------
287     /** Returns the fraction of maximum speed on this material. */
getMaxSpeedFraction() const288     float getMaxSpeedFraction() const { return m_max_speed_fraction; }
289     // ------------------------------------------------------------------------
290     /** Returns how long it will take for a slowdown to take effect.
291      *  It is the time it takes till the full slowdown applies to
292      *  karts. So a short time will slowdown a kart much faster. */
getSlowDownTicks() const293     int getSlowDownTicks() const { return m_slowdown_ticks;          }
294     // ------------------------------------------------------------------------
295     /** Returns true if this material is under some other mesh and therefore
296      *  requires another raycast to find the surface it is under (used for
297      *  gfx, e.g. driving under water to find where the water splash should
298      *  be shown at. */
isBelowSurface() const299     bool isBelowSurface      () const { return m_below_surface; }
300     // ------------------------------------------------------------------------
301     /** Returns true if this material is a surface, i.e. it is going to be
302      *  ignored for the physics, but the information is needed e.g. for
303      *  gfx. See m_below_surface for more details. */
isSurface() const304     bool isSurface          () const { return m_surface; }
305     // ------------------------------------------------------------------------
306     /** Returns the name of a special sfx to play while a kart is on this
307      *  terrain. The string will be "" if no special sfx exists. */
getSFXName() const308     const std::string &getSFXName() const { return m_sfx_name; }
309     // ------------------------------------------------------------------------
310     /** \brief Get the kind of particles that are to be used on this material,
311      *  in the given conditions.
312      * \return The particles to use, or NULL if none. */
getParticlesWhen(ParticleConditions cond) const313     const ParticleKind* getParticlesWhen(ParticleConditions cond) const
314     {
315         return m_particles_effects[cond];
316     }   // getParticlesWhen
317     // ------------------------------------------------------------------------
318     /** Returns true if a kart falling over this kind of material triggers
319      *  the special falling camera. */
hasFallingEffect() const320     bool hasFallingEffect() const {return m_falling_effect; }
321     // ------------------------------------------------------------------------
322     /** Returns if being in the air after this texture should start the
323      *  jump animation. */
isJumpTexture() const324     bool isJumpTexture() const { return m_is_jump_texture; }
325     // ------------------------------------------------------------------------
326     /** Returns true if this texture adjusts the gravity vector of the kart
327      *  to be parallel to the normal of the triangle - which allows karts to
328      *  e.g. drive upside down. */
hasGravity() const329     bool hasGravity() const { return m_has_gravity; }
330     // ------------------------------------------------------------------------
331     /** Returns the zipper parametersfor the current material. */
getZipperParameter(float * zipper_max_speed_increase,float * zipper_duration,float * zipper_speed_gain,float * zipper_fade_out_time,float * zipper_engine_force) const332     void getZipperParameter(float *zipper_max_speed_increase,
333                              float *zipper_duration,
334                              float *zipper_speed_gain,
335                              float *zipper_fade_out_time,
336                              float *zipper_engine_force) const
337     {
338         *zipper_max_speed_increase = m_zipper_max_speed_increase;
339         *zipper_duration           = m_zipper_duration;
340         *zipper_speed_gain         = m_zipper_speed_gain;
341         *zipper_fade_out_time      = m_zipper_fade_out_time;
342         *zipper_engine_force       = m_zipper_engine_force;
343     }   // getZipperParameter
344     // ------------------------------------------------------------------------
345     /** Returns the minimum speed of a kart on this material. This is used
346      *  for zippers on a ramp to guarantee the right jump distance even
347      *  on lower speeds. A negative value indicates no minimum speed. */
getZipperMinSpeed() const348     float getZipperMinSpeed() const { return m_zipper_min_speed; }
349     // ------------------------------------------------------------------------
350     /** True if this texture should have the U coordinates mirrored. */
getMirrorAxisInReverse() const351     char getMirrorAxisInReverse() const { return m_mirror_axis_when_reverse; }
352     // ------------------------------------------------------------------------
getAlphaMask() const353     const std::string& getAlphaMask() const                 { return m_mask; }
354     // ------------------------------------------------------------------------
getColorizationMask() const355     const std::string& getColorizationMask() const
356                                                { return m_colorization_mask; }
357     // ------------------------------------------------------------------------
setShaderName(const std::string & name)358     void setShaderName(const std::string& name)      { m_shader_name = name; }
359     // ------------------------------------------------------------------------
getShaderName() const360     const std::string& getShaderName() const         { return m_shader_name; }
361     // ------------------------------------------------------------------------
362     /* This is used for finding correct material for spm*/
getUVTwoTexture() const363     const std::string& getUVTwoTexture() const
364                                                       { return m_uv_two_tex; }
365     // ------------------------------------------------------------------------
use2UV() const366     bool use2UV() const                      { return !m_uv_two_tex.empty(); }
367     // ------------------------------------------------------------------------
getSamplerPath(unsigned layer) const368     const std::string& getSamplerPath(unsigned layer) const
369     {
370         assert(layer < 6);
371         return m_sampler_path[layer];
372     }
373     // ------------------------------------------------------------------------
374     /* Return the container id used by texture compression to cache texture in
375      * cache folder with unique name, if no texture compression is used for
376      * this material, then it will always return empty. */
getContainerId() const377     const std::string& getContainerId() const
378     {
379         static std::string empty;
380         if (!m_tex_compression)
381             return empty;
382         return m_container_id;
383     }
384 };
385 
386 
387 #endif
388 
389 /* EOF */
390 
391