]> git.lizzy.rs Git - minetest.git/blob - src/mapnode.cpp
7e26439877c497b20287446d8276cd2c33b5eff6
[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 #include "tile.h"
23 #include "porting.h"
24 #include <string>
25 #include "mineral.h"
26 // For g_settings
27 #include "main.h"
28 #include "content_mapnode.h"
29 #include "nodemetadata.h"
30
31 ContentFeatures::~ContentFeatures()
32 {
33         if(translate_to)
34                 delete translate_to;
35         if(initial_metadata)
36                 delete initial_metadata;
37 }
38
39 void ContentFeatures::setTexture(u16 i, std::string name, u8 alpha)
40 {
41         if(g_texturesource)
42         {
43                 tiles[i].texture = g_texturesource->getTexture(name);
44         }
45         
46         if(alpha != 255)
47         {
48                 tiles[i].alpha = alpha;
49                 tiles[i].material_type = MATERIAL_ALPHA_VERTEX;
50         }
51
52         if(inventory_texture == NULL)
53                 setInventoryTexture(name);
54 }
55
56 void ContentFeatures::setInventoryTexture(std::string imgname)
57 {
58         if(g_texturesource == NULL)
59                 return;
60         
61         imgname += "^[forcesingle";
62         
63         inventory_texture = g_texturesource->getTextureRaw(imgname);
64 }
65
66 void ContentFeatures::setInventoryTextureCube(std::string top,
67                 std::string left, std::string right)
68 {
69         if(g_texturesource == NULL)
70                 return;
71         
72         str_replace_char(top, '^', '&');
73         str_replace_char(left, '^', '&');
74         str_replace_char(right, '^', '&');
75
76         std::string imgname_full;
77         imgname_full += "[inventorycube{";
78         imgname_full += top;
79         imgname_full += "{";
80         imgname_full += left;
81         imgname_full += "{";
82         imgname_full += right;
83         inventory_texture = g_texturesource->getTextureRaw(imgname_full);
84 }
85
86 struct ContentFeatures g_content_features[256];
87
88 ContentFeatures & content_features(u8 i)
89 {
90         return g_content_features[i];
91 }
92
93 /*
94         See mapnode.h for description.
95 */
96 void init_mapnode()
97 {
98         if(g_texturesource == NULL)
99         {
100                 dstream<<"INFO: Initial run of init_mapnode with "
101                                 "g_texturesource=NULL. If this segfaults, "
102                                 "there is a bug with something not checking for "
103                                 "the NULL value."<<std::endl;
104         }
105         else
106         {
107                 dstream<<"INFO: Full run of init_mapnode with "
108                                 "g_texturesource!=NULL"<<std::endl;
109         }
110
111         /*// Read some settings
112         bool new_style_water = g_settings.getBool("new_style_water");
113         bool new_style_leaves = g_settings.getBool("new_style_leaves");*/
114
115         /*
116                 Initialize content feature table
117         */
118         
119         /*
120                 Set initial material type to same in all tiles, so that the
121                 same material can be used in more stuff.
122                 This is set according to the leaves because they are the only
123                 differing material to which all materials can be changed to
124                 get this optimization.
125         */
126         u8 initial_material_type = MATERIAL_ALPHA_SIMPLE;
127         /*if(new_style_leaves)
128                 initial_material_type = MATERIAL_ALPHA_SIMPLE;
129         else
130                 initial_material_type = MATERIAL_ALPHA_NONE;*/
131         for(u16 i=0; i<256; i++)
132         {
133                 ContentFeatures *f = &g_content_features[i];
134                 // Re-initialize
135                 f->reset();
136
137                 for(u16 j=0; j<6; j++)
138                         f->tiles[j].material_type = initial_material_type;
139         }
140
141         /*
142                 Initially set every block to be shown as an unknown block.
143                 Don't touch CONTENT_IGNORE or CONTENT_AIR.
144         */
145         for(u16 i=0; i<=253; i++)
146         {
147                 ContentFeatures *f = &g_content_features[i];
148                 f->setAllTextures("unknown_block.png");
149                 f->setInventoryTextureCube("unknown_block.png", "unknown_block.png", "unknown_block.png");
150                 f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
151         }
152
153         /*
154                 Initialize mapnode content
155         */
156         content_mapnode_init();
157         
158 }
159
160 v3s16 facedir_rotate(u8 facedir, v3s16 dir)
161 {
162         /*
163                 Face 2 (normally Z-) direction:
164                 facedir=0: Z-
165                 facedir=1: X-
166                 facedir=2: Z+
167                 facedir=3: X+
168         */
169         v3s16 newdir;
170         if(facedir==0) // Same
171                 newdir = v3s16(dir.X, dir.Y, dir.Z);
172         else if(facedir == 1) // Face is taken from rotXZccv(-90)
173                 newdir = v3s16(-dir.Z, dir.Y, dir.X);
174         else if(facedir == 2) // Face is taken from rotXZccv(180)
175                 newdir = v3s16(-dir.X, dir.Y, -dir.Z);
176         else if(facedir == 3) // Face is taken from rotXZccv(90)
177                 newdir = v3s16(dir.Z, dir.Y, -dir.X);
178         else
179                 newdir = dir;
180         return newdir;
181 }
182
183 TileSpec MapNode::getTile(v3s16 dir)
184 {
185         if(content_features(d).param_type == CPT_FACEDIR_SIMPLE)
186                 dir = facedir_rotate(param1, dir);
187         
188         TileSpec spec;
189         
190         s32 dir_i = -1;
191         
192         if(dir == v3s16(0,0,0))
193                 dir_i = -1;
194         else if(dir == v3s16(0,1,0))
195                 dir_i = 0;
196         else if(dir == v3s16(0,-1,0))
197                 dir_i = 1;
198         else if(dir == v3s16(1,0,0))
199                 dir_i = 2;
200         else if(dir == v3s16(-1,0,0))
201                 dir_i = 3;
202         else if(dir == v3s16(0,0,1))
203                 dir_i = 4;
204         else if(dir == v3s16(0,0,-1))
205                 dir_i = 5;
206         
207         if(dir_i == -1)
208                 // Non-directional
209                 spec = content_features(d).tiles[0];
210         else 
211                 spec = content_features(d).tiles[dir_i];
212         
213         /*
214                 If it contains some mineral, change texture id
215         */
216         if(content_features(d).param_type == CPT_MINERAL && g_texturesource)
217         {
218                 u8 mineral = param & 0x1f;
219                 std::string mineral_texture_name = mineral_block_texture(mineral);
220                 if(mineral_texture_name != "")
221                 {
222                         u32 orig_id = spec.texture.id;
223                         std::string texture_name = g_texturesource->getTextureName(orig_id);
224                         //texture_name += "^blit:";
225                         texture_name += "^";
226                         texture_name += mineral_texture_name;
227                         u32 new_id = g_texturesource->getTextureId(texture_name);
228                         spec.texture = g_texturesource->getTexture(new_id);
229                 }
230         }
231
232         return spec;
233 }
234
235 u8 MapNode::getMineral()
236 {
237         if(content_features(d).param_type == CPT_MINERAL)
238         {
239                 return param & 0x1f;
240         }
241
242         return MINERAL_NONE;
243 }
244
245 /*
246         Gets lighting value at face of node
247         
248         Parameters must consist of air and !air.
249         Order doesn't matter.
250
251         If either of the nodes doesn't exist, light is 0.
252         
253         parameters:
254                 daynight_ratio: 0...1000
255                 n: getNodeParent(p)
256                 n2: getNodeParent(p + face_dir)
257                 face_dir: axis oriented unit vector from p to p2
258         
259         returns encoded light value.
260 */
261 u8 getFaceLight(u32 daynight_ratio, MapNode n, MapNode n2,
262                 v3s16 face_dir)
263 {
264         try{
265                 u8 light;
266                 u8 l1 = n.getLightBlend(daynight_ratio);
267                 u8 l2 = n2.getLightBlend(daynight_ratio);
268                 if(l1 > l2)
269                         light = l1;
270                 else
271                         light = l2;
272
273                 // Make some nice difference to different sides
274
275                 // This makes light come from a corner
276                 /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
277                         light = diminish_light(diminish_light(light));
278                 else if(face_dir.X == -1 || face_dir.Z == -1)
279                         light = diminish_light(light);*/
280                 
281                 // All neighboring faces have different shade (like in minecraft)
282                 if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
283                         light = diminish_light(diminish_light(light));
284                 else if(face_dir.Z == 1 || face_dir.Z == -1)
285                         light = diminish_light(light);
286
287                 return light;
288         }
289         catch(InvalidPositionException &e)
290         {
291                 return 0;
292         }
293 }
294
295