]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.cpp
Fix client profiler print interval
[minetest.git] / src / mapnode.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 #include "common_irrlicht.h"
21 #include "mapnode.h"
22 #ifndef SERVER
23 #include "tile.h"
24 #endif
25 #include "porting.h"
26 #include <string>
27 #include "mineral.h"
28 // For g_settings
29 #include "main.h"
30 #include "content_mapnode.h"
31 #include "nodemetadata.h"
32
33 ContentFeatures::~ContentFeatures()
34 {
35         delete initial_metadata;
36 #ifndef SERVER
37         delete special_material;
38         delete special_atlas;
39 #endif
40 }
41
42 #ifndef SERVER
43 void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
44 {
45         if(g_texturesource)
46         {
47                 tiles[i].texture = g_texturesource->getTexture(name);
48         }
49         
50         if(alpha != 255)
51         {
52                 tiles[i].alpha = alpha;
53                 tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
54         }
55
56         if(inventory_texture == NULL)
57                 setInventoryTexture(name);
58 }
59
60 void ContentFeatures::setInventoryTexture(std::string imgname)
61 {
62         if(g_texturesource == NULL)
63                 return;
64         
65         imgname += "^[forcesingle";
66         
67         inventory_texture = g_texturesource->getTextureRaw(imgname);
68 }
69
70 void ContentFeatures::setInventoryTextureCube(std::string top,
71                 std::string left, std::string right)
72 {
73         if(g_texturesource == NULL)
74                 return;
75         
76         str_replace_char(top, '^', '&');
77         str_replace_char(left, '^', '&');
78         str_replace_char(right, '^', '&');
79
80         std::string imgname_full;
81         imgname_full += "[inventorycube{";
82         imgname_full += top;
83         imgname_full += "{";
84         imgname_full += left;
85         imgname_full += "{";
86         imgname_full += right;
87         inventory_texture = g_texturesource->getTextureRaw(imgname_full);
88 }
89 #endif
90
91 struct ContentFeatures g_content_features[MAX_CONTENT+1];
92
93 ContentFeatures & content_features(content_t i)
94 {
95         return g_content_features[i];
96 }
97 ContentFeatures & content_features(MapNode &n)
98 {
99         return content_features(n.getContent());
100 }
101
102 /*
103         See mapnode.h for description.
104 */
105 void init_mapnode()
106 {
107         if(g_texturesource == NULL)
108         {
109                 dstream<<"INFO: Initial run of init_mapnode with "
110                                 "g_texturesource=NULL. If this segfaults, "
111                                 "there is a bug with something not checking for "
112                                 "the NULL value."<<std::endl;
113         }
114         else
115         {
116                 dstream<<"INFO: Full run of init_mapnode with "
117                                 "g_texturesource!=NULL"<<std::endl;
118         }
119
120         /*// Read some settings
121         bool new_style_water = g_settings.getBool("new_style_water");
122         bool new_style_leaves = g_settings.getBool("new_style_leaves");*/
123
124         /*
125                 Initialize content feature table
126         */
127
128 #ifndef SERVER
129         /*
130                 Set initial material type to same in all tiles, so that the
131                 same material can be used in more stuff.
132                 This is set according to the leaves because they are the only
133                 differing material to which all materials can be changed to
134                 get this optimization.
135         */
136         u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
137         /*if(new_style_leaves)
138                 initial_material_type = MATERIAL_ALPHA_SIMPLE;
139         else
140                 initial_material_type = MATERIAL_ALPHA_NONE;*/
141         for(u16 i=0; i<MAX_CONTENT+1; i++)
142         {
143                 ContentFeatures *f = &g_content_features[i];
144                 // Re-initialize
145                 f->reset();
146
147                 for(u16 j=0; j<6; j++)
148                         f->tiles[j].material_type = initial_material_type;
149         }
150 #endif
151
152         /*
153                 Initially set every block to be shown as an unknown block.
154                 Don't touch CONTENT_IGNORE or CONTENT_AIR.
155         */
156         for(u16 i=0; i<MAX_CONTENT+1; i++)
157         {
158                 if(i == CONTENT_IGNORE || i == CONTENT_AIR)
159                         continue;
160                 ContentFeatures *f = &g_content_features[i];
161                 f->setAllTextures("unknown_block.png");
162                 f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
163         }
164
165         /*
166                 Initialize mapnode content
167         */
168         content_mapnode_init();
169         
170 }
171
172 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
173 {
174         /*
175                 Face 2 (normally Z-) direction:
176                 facedir=0: Z-
177                 facedir=1: X-
178                 facedir=2: Z+
179                 facedir=3: X+
180         */
181         v3s16 newdir;
182         if(facedir==0) // Same
183                 newdir = v3s16(dir.X, dir.Y, dir.Z);
184         else if(facedir == 1) // Face is taken from rotXZccv(-90)
185                 newdir = v3s16(-dir.Z, dir.Y, dir.X);
186         else if(facedir == 2) // Face is taken from rotXZccv(180)
187                 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
188         else if(facedir == 3) // Face is taken from rotXZccv(90)
189                 newdir = v3s16(dir.Z, dir.Y, -dir.X);
190         else
191                 newdir = dir;
192         return newdir;
193 }
194
195 #ifndef SERVER
196 TileSpec MapNode::getTile(v3s16 dir)
197 {
198         if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
199                 dir = facedir_rotate(param1, dir);
200         
201         TileSpec spec;
202         
203         s32 dir_i = -1;
204         
205         if(dir == v3s16(0,0,0))
206                 dir_i = -1;
207         else if(dir == v3s16(0,1,0))
208                 dir_i = 0;
209         else if(dir == v3s16(0,-1,0))
210                 dir_i = 1;
211         else if(dir == v3s16(1,0,0))
212                 dir_i = 2;
213         else if(dir == v3s16(-1,0,0))
214                 dir_i = 3;
215         else if(dir == v3s16(0,0,1))
216                 dir_i = 4;
217         else if(dir == v3s16(0,0,-1))
218                 dir_i = 5;
219         
220         if(dir_i == -1)
221                 // Non-directional
222                 spec = content_features(*this).tiles[0];
223         else 
224                 spec = content_features(*this).tiles[dir_i];
225         
226         /*
227                 If it contains some mineral, change texture id
228         */
229         if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
230         {
231                 u8 mineral = getMineral();
232                 std::string mineral_texture_name = mineral_block_texture(mineral);
233                 if(mineral_texture_name != "")
234                 {
235                         u32 orig_id = spec.texture.id;
236                         std::string texture_name = g_texturesource->getTextureName(orig_id);
237                         //texture_name += "^blit:";
238                         texture_name += "^";
239                         texture_name += mineral_texture_name;
240                         u32 new_id = g_texturesource->getTextureId(texture_name);
241                         spec.texture = g_texturesource->getTexture(new_id);
242                 }
243         }
244
245         return spec;
246 }
247 #endif
248
249 u8 MapNode::getMineral()
250 {
251         if(content_features(*this).param_type == CPT_MINERAL)
252         {
253                 return param1 & 0x0f;
254         }
255
256         return MINERAL_NONE;
257 }
258
259 u32 MapNode::serializedLength(u8 version)
260 {
261         if(!ser_ver_supported(version))
262                 throw VersionMismatchException("ERROR: MapNode format not supported");
263                 
264         if(version == 0)
265                 return 1;
266         else if(version <= 9)
267                 return 2;
268         else
269                 return 3;
270 }
271 void MapNode::serialize(u8 *dest, u8 version)
272 {
273         if(!ser_ver_supported(version))
274                 throw VersionMismatchException("ERROR: MapNode format not supported");
275                 
276         // Translate to wanted version
277         MapNode n_foreign = mapnode_translate_from_internal(*this, version);
278
279         u8 actual_param0 = n_foreign.param0;
280
281         // Convert special values from new version to old
282         if(version <= 18)
283         {
284                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
285                 // are 255 and 254
286                 if(actual_param0 == CONTENT_IGNORE)
287                         actual_param0 = 255;
288                 else if(actual_param0 == CONTENT_AIR)
289                         actual_param0 = 254;
290         }
291
292         if(version == 0)
293         {
294                 dest[0] = actual_param0;
295         }
296         else if(version <= 9)
297         {
298                 dest[0] = actual_param0;
299                 dest[1] = n_foreign.param1;
300         }
301         else
302         {
303                 dest[0] = actual_param0;
304                 dest[1] = n_foreign.param1;
305                 dest[2] = n_foreign.param2;
306         }
307 }
308 void MapNode::deSerialize(u8 *source, u8 version)
309 {
310         if(!ser_ver_supported(version))
311                 throw VersionMismatchException("ERROR: MapNode format not supported");
312                 
313         if(version == 0)
314         {
315                 param0 = source[0];
316         }
317         else if(version == 1)
318         {
319                 param0 = source[0];
320                 // This version doesn't support saved lighting
321                 if(light_propagates() || light_source() > 0)
322                         param1 = 0;
323                 else
324                         param1 = source[1];
325         }
326         else if(version <= 9)
327         {
328                 param0 = source[0];
329                 param1 = source[1];
330         }
331         else
332         {
333                 param0 = source[0];
334                 param1 = source[1];
335                 param2 = source[2];
336         }
337         
338         // Convert special values from old version to new
339         if(version <= 18)
340         {
341                 // In these versions, CONTENT_IGNORE and CONTENT_AIR
342                 // are 255 and 254
343                 if(param0 == 255)
344                         param0 = CONTENT_IGNORE;
345                 else if(param0 == 254)
346                         param0 = CONTENT_AIR;
347         }
348         // version 19 is fucked up with sometimes the old values and sometimes not
349         if(version == 19)
350         {
351                 if(param0 == 255)
352                         param0 = CONTENT_IGNORE;
353                 else if(param0 == 254)
354                         param0 = CONTENT_AIR;
355         }
356
357         // Translate to our known version
358         *this = mapnode_translate_to_internal(*this, version);
359 }
360
361 /*
362         Gets lighting value at face of node
363         
364         Parameters must consist of air and !air.
365         Order doesn't matter.
366
367         If either of the nodes doesn't exist, light is 0.
368         
369         parameters:
370                 daynight_ratio: 0...1000
371                 n: getNodeParent(p)
372                 n2: getNodeParent(p + face_dir)
373                 face_dir: axis oriented unit vector from p to p2
374         
375         returns encoded light value.
376 */
377 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
378                 v3s16 face_dir)
379 {
380         try{
381                 u8 light;
382                 u8 l1 = n.getLightBlend(daynight_ratio);
383                 u8 l2 = n2.getLightBlend(daynight_ratio);
384                 if(l1 > l2)
385                         light = l1;
386                 else
387                         light = l2;
388
389                 // Make some nice difference to different sides
390
391                 // This makes light come from a corner
392                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
393                         light = diminish_light(diminish_light(light));
394                 else if(face_dir.X == -1 || face_dir.Z == -1)
395                         light = diminish_light(light);*/
396                 
397                 // All neighboring faces have different shade (like in minecraft)
398                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
399                         light = diminish_light(diminish_light(light));
400                 else if(face_dir.Z == 1 || face_dir.Z == -1)
401                         light = diminish_light(light);
402
403                 return light;
404         }
405         catch(InvalidPositionException &e)
406         {
407                 return 0;
408         }
409 }
410
411