Modernize client code (#6250)
[oweals/minetest.git] / src / client / tile.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef TILE_HEADER
21 #define TILE_HEADER
22
23 #include "irrlichttypes.h"
24 #include "irr_v3d.h"
25 #include <ITexture.h>
26 #include <string>
27 #include <vector>
28 #include <SMaterial.h>
29 #include <memory>
30 #include "util/numeric.h"
31
32 class IGameDef;
33 struct TileSpec;
34 struct TileDef;
35
36 typedef std::vector<video::SColor> Palette;
37
38 /*
39         tile.{h,cpp}: Texture handling stuff.
40 */
41
42 /*
43         Find out the full path of an image by trying different filename
44         extensions.
45
46         If failed, return "".
47
48         TODO: Should probably be moved out from here, because things needing
49               this function do not need anything else from this header
50 */
51 std::string getImagePath(std::string path);
52
53 /*
54         Gets the path to a texture by first checking if the texture exists
55         in texture_path and if not, using the data path.
56
57         Checks all supported extensions by replacing the original extension.
58
59         If not found, returns "".
60
61         Utilizes a thread-safe cache.
62 */
63 std::string getTexturePath(const std::string &filename);
64
65 void clearTextureNameCache();
66
67 /*
68         ITextureSource::generateTextureFromMesh parameters
69 */
70 namespace irr {namespace scene {class IMesh;}}
71 struct TextureFromMeshParams
72 {
73         scene::IMesh *mesh = nullptr;
74         core::dimension2d<u32> dim;
75         std::string rtt_texture_name;
76         bool delete_texture_on_shutdown;
77         v3f camera_position;
78         v3f camera_lookat;
79         core::CMatrix4<f32> camera_projection_matrix;
80         video::SColorf ambient_light;
81         v3f light_position;
82         video::SColorf light_color;
83         f32 light_radius;
84 };
85
86 /*
87         TextureSource creates and caches textures.
88 */
89
90 class ISimpleTextureSource
91 {
92 public:
93         ISimpleTextureSource() = default;
94
95         virtual ~ISimpleTextureSource() = default;
96
97         virtual video::ITexture* getTexture(
98                         const std::string &name, u32 *id = nullptr) = 0;
99 };
100
101 class ITextureSource : public ISimpleTextureSource
102 {
103 public:
104         ITextureSource() = default;
105
106         virtual ~ITextureSource() = default;
107
108         virtual u32 getTextureId(const std::string &name)=0;
109         virtual std::string getTextureName(u32 id)=0;
110         virtual video::ITexture* getTexture(u32 id)=0;
111         virtual video::ITexture* getTexture(
112                         const std::string &name, u32 *id = nullptr)=0;
113         virtual video::ITexture* getTextureForMesh(
114                         const std::string &name, u32 *id = nullptr) = 0;
115         /*!
116          * Returns a palette from the given texture name.
117          * The pointer is valid until the texture source is
118          * destructed.
119          * Should be called from the main thread.
120          */
121         virtual Palette* getPalette(const std::string &name) = 0;
122         virtual bool isKnownSourceImage(const std::string &name)=0;
123         virtual video::ITexture* generateTextureFromMesh(
124                         const TextureFromMeshParams &params)=0;
125         virtual video::ITexture* getNormalTexture(const std::string &name)=0;
126         virtual video::SColor getTextureAverageColor(const std::string &name)=0;
127         virtual video::ITexture *getShaderFlagsTexture(bool normalmap_present)=0;
128 };
129
130 class IWritableTextureSource : public ITextureSource
131 {
132 public:
133         IWritableTextureSource() = default;
134
135         virtual ~IWritableTextureSource() = default;
136
137         virtual u32 getTextureId(const std::string &name)=0;
138         virtual std::string getTextureName(u32 id)=0;
139         virtual video::ITexture* getTexture(u32 id)=0;
140         virtual video::ITexture* getTexture(
141                         const std::string &name, u32 *id = nullptr)=0;
142         virtual bool isKnownSourceImage(const std::string &name)=0;
143         virtual video::ITexture* generateTextureFromMesh(
144                         const TextureFromMeshParams &params)=0;
145
146         virtual void processQueue()=0;
147         virtual void insertSourceImage(const std::string &name, video::IImage *img)=0;
148         virtual void rebuildImagesAndTextures()=0;
149         virtual video::ITexture* getNormalTexture(const std::string &name)=0;
150         virtual video::SColor getTextureAverageColor(const std::string &name)=0;
151         virtual video::ITexture *getShaderFlagsTexture(bool normalmap_present)=0;
152 };
153
154 IWritableTextureSource *createTextureSource();
155
156 #ifdef __ANDROID__
157 video::IImage * Align2Npot2(video::IImage * image, video::IVideoDriver* driver);
158 #endif
159
160 enum MaterialType{
161         TILE_MATERIAL_BASIC,
162         TILE_MATERIAL_ALPHA,
163         TILE_MATERIAL_LIQUID_TRANSPARENT,
164         TILE_MATERIAL_LIQUID_OPAQUE,
165         TILE_MATERIAL_WAVING_LEAVES,
166         TILE_MATERIAL_WAVING_PLANTS,
167         TILE_MATERIAL_OPAQUE
168 };
169
170 // Material flags
171 // Should backface culling be enabled?
172 #define MATERIAL_FLAG_BACKFACE_CULLING 0x01
173 // Should a crack be drawn?
174 #define MATERIAL_FLAG_CRACK 0x02
175 // Should the crack be drawn on transparent pixels (unset) or not (set)?
176 // Ignored if MATERIAL_FLAG_CRACK is not set.
177 #define MATERIAL_FLAG_CRACK_OVERLAY 0x04
178 #define MATERIAL_FLAG_ANIMATION 0x08
179 //#define MATERIAL_FLAG_HIGHLIGHTED 0x10
180 #define MATERIAL_FLAG_TILEABLE_HORIZONTAL 0x20
181 #define MATERIAL_FLAG_TILEABLE_VERTICAL 0x40
182
183 /*
184         This fully defines the looks of a tile.
185         The SMaterial of a tile is constructed according to this.
186 */
187 struct FrameSpec
188 {
189         FrameSpec() = default;
190
191         u32 texture_id = 0;
192         video::ITexture *texture = nullptr;
193         video::ITexture *normal_texture = nullptr;
194         video::ITexture *flags_texture = nullptr;
195 };
196
197 #define MAX_TILE_LAYERS 2
198
199 //! Defines a layer of a tile.
200 struct TileLayer
201 {
202         TileLayer() = default;
203
204         /*!
205          * Two layers are equal if they can be merged.
206          */
207         bool operator==(const TileLayer &other) const
208         {
209                 return
210                         texture_id == other.texture_id &&
211                         material_type == other.material_type &&
212                         material_flags == other.material_flags &&
213                         color == other.color;
214         }
215
216         /*!
217          * Two tiles are not equal if they must have different vertices.
218          */
219         bool operator!=(const TileLayer &other) const
220         {
221                 return !(*this == other);
222         }
223
224         // Sets everything else except the texture in the material
225         void applyMaterialOptions(video::SMaterial &material) const
226         {
227                 switch (material_type) {
228                 case TILE_MATERIAL_OPAQUE:
229                 case TILE_MATERIAL_LIQUID_OPAQUE:
230                         material.MaterialType = video::EMT_SOLID;
231                         break;
232                 case TILE_MATERIAL_BASIC:
233                 case TILE_MATERIAL_WAVING_LEAVES:
234                 case TILE_MATERIAL_WAVING_PLANTS:
235                         material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
236                         break;
237                 case TILE_MATERIAL_ALPHA:
238                 case TILE_MATERIAL_LIQUID_TRANSPARENT:
239                         material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
240                         break;
241                 }
242                 material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) != 0;
243                 if (!(material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)) {
244                         material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
245                 }
246                 if (!(material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
247                         material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
248                 }
249         }
250
251         void applyMaterialOptionsWithShaders(video::SMaterial &material) const
252         {
253                 material.BackfaceCulling = (material_flags & MATERIAL_FLAG_BACKFACE_CULLING) != 0;
254                 if (!(material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)) {
255                         material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
256                         material.TextureLayer[1].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
257                 }
258                 if (!(material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
259                         material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
260                         material.TextureLayer[1].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
261                 }
262         }
263
264         bool isTileable() const
265         {
266                 return (material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
267                         && (material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL);
268         }
269
270         // Ordered for size, please do not reorder
271
272         video::ITexture *texture = nullptr;
273         video::ITexture *normal_texture = nullptr;
274         video::ITexture *flags_texture = nullptr;
275
276         u32 shader_id = 0;
277
278         u32 texture_id = 0;
279
280         u16 animation_frame_length_ms = 0;
281         u8 animation_frame_count = 1;
282
283         u8 material_type = TILE_MATERIAL_BASIC;
284         u8 material_flags =
285                 //0 // <- DEBUG, Use the one below
286                 MATERIAL_FLAG_BACKFACE_CULLING |
287                 MATERIAL_FLAG_TILEABLE_HORIZONTAL|
288                 MATERIAL_FLAG_TILEABLE_VERTICAL;
289
290         //! If true, the tile has its own color.
291         bool has_color = false;
292
293         std::shared_ptr<std::vector<FrameSpec>> frames = nullptr;
294
295         /*!
296          * The color of the tile, or if the tile does not own
297          * a color then the color of the node owning this tile.
298          */
299         video::SColor color;
300 };
301
302 /*!
303  * Defines a face of a node. May have up to two layers.
304  */
305 struct TileSpec
306 {
307         TileSpec() {
308                 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++)
309                         layers[layer] = TileLayer();
310         }
311
312         /*!
313          * Returns true if this tile can be merged with the other tile.
314          */
315         bool isTileable(const TileSpec &other) const {
316                 for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
317                         if (layers[layer] != other.layers[layer])
318                                 return false;
319                         if (!layers[layer].isTileable())
320                                 return false;
321                 }
322                 return rotation == 0
323                         && rotation == other.rotation
324                         && emissive_light == other.emissive_light;
325         }
326
327         u8 rotation = 0;
328         //! This much light does the tile emit.
329         u8 emissive_light = 0;
330         //! The first is base texture, the second is overlay.
331         TileLayer layers[MAX_TILE_LAYERS];
332 };
333 #endif