Improve glass
[oweals/minetest.git] / src / nodedef.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 "nodedef.h"
21
22 #include "main.h" // For g_settings
23 #include "nodemetadata.h"
24 #ifndef SERVER
25 #include "tile.h"
26 #endif
27 #include "log.h"
28 #include "settings.h"
29
30 void NodeBox::serialize(std::ostream &os)
31 {
32         writeU8(os, 0); // version
33         writeU8(os, type);
34         writeV3F1000(os, fixed.MinEdge);
35         writeV3F1000(os, fixed.MaxEdge);
36         writeV3F1000(os, wall_top.MinEdge);
37         writeV3F1000(os, wall_top.MaxEdge);
38         writeV3F1000(os, wall_bottom.MinEdge);
39         writeV3F1000(os, wall_bottom.MaxEdge);
40         writeV3F1000(os, wall_side.MinEdge);
41         writeV3F1000(os, wall_side.MaxEdge);
42 }
43
44 void NodeBox::deSerialize(std::istream &is)
45 {
46         int version = readU8(is);
47         if(version != 0)
48                 throw SerializationError("unsupported NodeBox version");
49         type = (enum NodeBoxType)readU8(is);
50         fixed.MinEdge = readV3F1000(is);
51         fixed.MaxEdge = readV3F1000(is);
52         wall_top.MinEdge = readV3F1000(is);
53         wall_top.MaxEdge = readV3F1000(is);
54         wall_bottom.MinEdge = readV3F1000(is);
55         wall_bottom.MaxEdge = readV3F1000(is);
56         wall_side.MinEdge = readV3F1000(is);
57         wall_side.MaxEdge = readV3F1000(is);
58 }
59
60 void MaterialSpec::serialize(std::ostream &os)
61 {
62         os<<serializeString(tname);
63         writeU8(os, backface_culling);
64 }
65
66 void MaterialSpec::deSerialize(std::istream &is)
67 {
68         tname = deSerializeString(is);
69         backface_culling = readU8(is);
70 }
71
72 ContentFeatures::ContentFeatures()
73 {
74         reset();
75 }
76
77 ContentFeatures::~ContentFeatures()
78 {
79         delete initial_metadata;
80 #ifndef SERVER
81         for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
82                 delete special_materials[j];
83                 delete special_aps[j];
84         }
85 #endif
86 }
87
88 void ContentFeatures::reset()
89 {
90         /*
91                 Cached stuff
92         */
93 #ifndef SERVER
94         inventory_texture = NULL;
95         
96         for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
97                 special_materials[j] = NULL;
98                 special_aps[j] = NULL;
99         }
100         solidness = 2;
101         visual_solidness = 0;
102         backface_culling = true;
103 #endif
104         used_texturenames.clear();
105         modified = true; // NodeDefManager explicitly sets to false
106         /*
107                 Actual data
108         */
109         drawtype = NDT_NORMAL;
110         visual_scale = 1.0;
111         for(u32 i=0; i<6; i++)
112                 tname_tiles[i] = "";
113         for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
114                 mspec_special[j] = MaterialSpec();
115         tname_inventory = "";
116         alpha = 255;
117         post_effect_color = video::SColor(0, 0, 0, 0);
118         param_type = CPT_NONE;
119         is_ground_content = false;
120         light_propagates = false;
121         sunlight_propagates = false;
122         walkable = true;
123         pointable = true;
124         diggable = true;
125         climbable = false;
126         buildable_to = false;
127         wall_mounted = false;
128         air_equivalent = false;
129         often_contains_mineral = false;
130         dug_item = "";
131         initial_metadata = NULL;
132         liquid_type = LIQUID_NONE;
133         liquid_alternative_flowing = CONTENT_IGNORE;
134         liquid_alternative_source = CONTENT_IGNORE;
135         liquid_viscosity = 0;
136         light_source = 0;
137         damage_per_second = 0;
138         selection_box = NodeBox();
139         material = MaterialProperties();
140 }
141
142 void ContentFeatures::serialize(std::ostream &os)
143 {
144         writeU8(os, 0); // version
145         writeU8(os, drawtype);
146         writeF1000(os, visual_scale);
147         writeU8(os, 6);
148         for(u32 i=0; i<6; i++)
149                 os<<serializeString(tname_tiles[i]);
150         os<<serializeString(tname_inventory);
151         writeU8(os, CF_SPECIAL_COUNT);
152         for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
153                 mspec_special[i].serialize(os);
154         }
155         writeU8(os, alpha);
156         writeU8(os, post_effect_color.getAlpha());
157         writeU8(os, post_effect_color.getRed());
158         writeU8(os, post_effect_color.getGreen());
159         writeU8(os, post_effect_color.getBlue());
160         writeU8(os, param_type);
161         writeU8(os, is_ground_content);
162         writeU8(os, light_propagates);
163         writeU8(os, sunlight_propagates);
164         writeU8(os, walkable);
165         writeU8(os, pointable);
166         writeU8(os, diggable);
167         writeU8(os, climbable);
168         writeU8(os, buildable_to);
169         writeU8(os, wall_mounted);
170         writeU8(os, air_equivalent);
171         writeU8(os, often_contains_mineral);
172         os<<serializeString(dug_item);
173         os<<serializeString(extra_dug_item);
174         writeS32(os, extra_dug_item_rarity);
175         if(initial_metadata){
176                 writeU8(os, true);
177                 initial_metadata->serialize(os);
178         } else {
179                 writeU8(os, false);
180         }
181         writeU8(os, liquid_type);
182         writeU16(os, liquid_alternative_flowing);
183         writeU16(os, liquid_alternative_source);
184         writeU8(os, liquid_viscosity);
185         writeU8(os, light_source);
186         writeU32(os, damage_per_second);
187         selection_box.serialize(os);
188         material.serialize(os);
189 }
190
191 void ContentFeatures::deSerialize(std::istream &is, IGameDef *gamedef)
192 {
193         int version = readU8(is);
194         if(version != 0)
195                 throw SerializationError("unsupported ContentFeatures version");
196         drawtype = (enum NodeDrawType)readU8(is);
197         visual_scale = readF1000(is);
198         if(readU8(is) != 6)
199                 throw SerializationError("unsupported tile count");
200         for(u32 i=0; i<6; i++)
201                 tname_tiles[i] = deSerializeString(is);
202         tname_inventory = deSerializeString(is);
203         if(readU8(is) != CF_SPECIAL_COUNT)
204                 throw SerializationError("unsupported CF_SPECIAL_COUNT");
205         for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
206                 mspec_special[i].deSerialize(is);
207         }
208         alpha = readU8(is);
209         post_effect_color.setAlpha(readU8(is));
210         post_effect_color.setRed(readU8(is));
211         post_effect_color.setGreen(readU8(is));
212         post_effect_color.setBlue(readU8(is));
213         param_type = (enum ContentParamType)readU8(is);
214         is_ground_content = readU8(is);
215         light_propagates = readU8(is);
216         sunlight_propagates = readU8(is);
217         walkable = readU8(is);
218         pointable = readU8(is);
219         diggable = readU8(is);
220         climbable = readU8(is);
221         buildable_to = readU8(is);
222         wall_mounted = readU8(is);
223         air_equivalent = readU8(is);
224         often_contains_mineral = readU8(is);
225         dug_item = deSerializeString(is);
226         extra_dug_item = deSerializeString(is);
227         extra_dug_item_rarity = readS32(is);
228         if(readU8(is)){
229                 initial_metadata = NodeMetadata::deSerialize(is, gamedef);
230         } else {
231                 initial_metadata = NULL;
232         }
233         liquid_type = (enum LiquidType)readU8(is);
234         liquid_alternative_flowing = readU16(is);
235         liquid_alternative_source = readU16(is);
236         liquid_viscosity = readU8(is);
237         light_source = readU8(is);
238         damage_per_second = readU32(is);
239         selection_box.deSerialize(is);
240         material.deSerialize(is);
241 }
242
243 void ContentFeatures::setTexture(u16 i, std::string name)
244 {
245         used_texturenames.insert(name);
246         tname_tiles[i] = name;
247         if(tname_inventory == "")
248                 tname_inventory = name;
249 }
250
251 void ContentFeatures::setInventoryTexture(std::string imgname)
252 {
253         tname_inventory = imgname + "^[forcesingle";
254 }
255
256 void ContentFeatures::setInventoryTextureCube(std::string top,
257                 std::string left, std::string right)
258 {
259         str_replace_char(top, '^', '&');
260         str_replace_char(left, '^', '&');
261         str_replace_char(right, '^', '&');
262
263         std::string imgname_full;
264         imgname_full += "[inventorycube{";
265         imgname_full += top;
266         imgname_full += "{";
267         imgname_full += left;
268         imgname_full += "{";
269         imgname_full += right;
270         tname_inventory = imgname_full;
271 }
272
273 class CNodeDefManager: public IWritableNodeDefManager
274 {
275 public:
276         void clear()
277         {
278                 for(u16 i=0; i<=MAX_CONTENT; i++)
279                 {
280                         ContentFeatures *f = &m_content_features[i];
281                         f->reset(); // Reset to defaults
282                         f->modified = false; // Not changed from default
283                         if(i == CONTENT_IGNORE || i == CONTENT_AIR){
284                                 f->drawtype = NDT_AIRLIKE;
285                                 continue;
286                         }
287                         f->setAllTextures("unknown_block.png");
288                         //f->dug_item = std::string("MaterialItem2 ")+itos(i)+" 1";
289                 }
290 #ifndef SERVER
291                 // Make CONTENT_IGNORE to not block the view when occlusion culling
292                 m_content_features[CONTENT_IGNORE].solidness = 0;
293 #endif
294         }
295         CNodeDefManager()
296         {
297                 clear();
298         }
299         virtual ~CNodeDefManager()
300         {
301         }
302         virtual IWritableNodeDefManager* clone()
303         {
304                 CNodeDefManager *mgr = new CNodeDefManager();
305                 for(u16 i=0; i<=MAX_CONTENT; i++)
306                 {
307                         mgr->set(i, get(i));
308                 }
309                 return mgr;
310         }
311         virtual const ContentFeatures& get(content_t c) const
312         {
313                 assert(c <= MAX_CONTENT);
314                 return m_content_features[c];
315         }
316         virtual const ContentFeatures& get(const MapNode &n) const
317         {
318                 return get(n.getContent());
319         }
320         // Writable
321         virtual void set(content_t c, const ContentFeatures &def)
322         {
323                 infostream<<"registerNode: registering content \""<<c<<"\""<<std::endl;
324                 assert(c <= MAX_CONTENT);
325                 m_content_features[c] = def;
326         }
327         virtual ContentFeatures* getModifiable(content_t c)
328         {
329                 assert(c <= MAX_CONTENT);
330                 m_content_features[c].modified = true; // Assume it is modified
331                 return &m_content_features[c];
332         }
333         virtual void updateTextures(ITextureSource *tsrc)
334         {
335 #ifndef SERVER
336                 infostream<<"CNodeDefManager::updateTextures(): Updating "
337                                 <<"textures in node definitions"<<std::endl;
338
339                 bool new_style_water = g_settings->getBool("new_style_water");
340                 bool new_style_leaves = g_settings->getBool("new_style_leaves");
341                 bool opaque_water = g_settings->getBool("opaque_water");
342                 
343                 for(u16 i=0; i<=MAX_CONTENT; i++)
344                 {
345                         ContentFeatures *f = &m_content_features[i];
346
347                         switch(f->drawtype){
348                         default:
349                         case NDT_NORMAL:
350                                 f->solidness = 2;
351                                 break;
352                         case NDT_AIRLIKE:
353                                 f->solidness = 0;
354                                 break;
355                         case NDT_LIQUID:
356                                 assert(f->liquid_type == LIQUID_SOURCE);
357                                 if(opaque_water)
358                                         f->alpha = 255;
359                                 if(new_style_water){
360                                         f->solidness = 0;
361                                 } else {
362                                         f->solidness = 1;
363                                         if(f->alpha == 255)
364                                                 f->solidness = 2;
365                                 }
366                                 break;
367                         case NDT_FLOWINGLIQUID:
368                                 assert(f->liquid_type == LIQUID_FLOWING);
369                                 f->solidness = 0;
370                                 if(opaque_water)
371                                         f->alpha = 255;
372                                 break;
373                         case NDT_GLASSLIKE:
374                                 f->solidness = 0;
375                                 f->visual_solidness = 1;
376                                 break;
377                         case NDT_ALLFACES:
378                                 f->solidness = 0;
379                                 f->visual_solidness = 1;
380                                 break;
381                         case NDT_ALLFACES_OPTIONAL:
382                                 if(new_style_leaves){
383                                         f->drawtype = NDT_ALLFACES;
384                                         f->solidness = 0;
385                                         f->visual_solidness = 1;
386                                 } else {
387                                         f->drawtype = NDT_NORMAL;
388                                         f->solidness = 1;
389                                         for(u32 i=0; i<6; i++){
390                                                 f->tname_tiles[i] = std::string("[noalpha:")
391                                                                 + f->tname_tiles[i];
392                                         }
393                                 }
394                                 break;
395                         case NDT_TORCHLIKE:
396                         case NDT_SIGNLIKE:
397                         case NDT_PLANTLIKE:
398                         case NDT_FENCELIKE:
399                         case NDT_RAILLIKE:
400                                 f->solidness = 0;
401                                 break;
402                         }
403
404                         // Inventory texture
405                         if(f->tname_inventory != "")
406                                 f->inventory_texture = tsrc->getTextureRaw(f->tname_inventory);
407                         else
408                                 f->inventory_texture = NULL;
409                         // Tile textures
410                         for(u16 j=0; j<6; j++){
411                                 if(f->tname_tiles[j] == "")
412                                         continue;
413                                 f->tiles[j].texture = tsrc->getTexture(f->tname_tiles[j]);
414                                 f->tiles[j].alpha = f->alpha;
415                                 if(f->alpha == 255)
416                                         f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
417                                 else
418                                         f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
419                                 if(f->backface_culling)
420                                         f->tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
421                                 else
422                                         f->tiles[j].material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
423                         }
424                         // Special textures
425                         for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
426                                 // Remove all stuff
427                                 if(f->special_aps[j]){
428                                         delete f->special_aps[j];
429                                         f->special_aps[j] = NULL;
430                                 }
431                                 if(f->special_materials[j]){
432                                         delete f->special_materials[j];
433                                         f->special_materials[j] = NULL;
434                                 }
435                                 // Skip if should not exist
436                                 if(f->mspec_special[j].tname == "")
437                                         continue;
438                                 // Create all stuff
439                                 f->special_aps[j] = new AtlasPointer(
440                                                 tsrc->getTexture(f->mspec_special[j].tname));
441                                 f->special_materials[j] = new video::SMaterial;
442                                 f->special_materials[j]->setFlag(video::EMF_LIGHTING, false);
443                                 f->special_materials[j]->setFlag(video::EMF_BACK_FACE_CULLING,
444                                                 f->mspec_special[j].backface_culling);
445                                 f->special_materials[j]->setFlag(video::EMF_BILINEAR_FILTER, false);
446                                 f->special_materials[j]->setFlag(video::EMF_FOG_ENABLE, true);
447                                 f->special_materials[j]->setTexture(0, f->special_aps[j]->atlas);
448                         }
449                 }
450 #endif
451         }
452         void serialize(std::ostream &os)
453         {
454                 u16 count = 0;
455                 std::ostringstream tmp_os(std::ios::binary);
456                 for(u16 i=0; i<=MAX_CONTENT; i++)
457                 {
458                         ContentFeatures *f = &m_content_features[i];
459                         if(!f->modified)
460                                 continue;
461                         writeU16(tmp_os, i);
462                         f->serialize(tmp_os);
463                         count++;
464                 }
465                 writeU16(os, count);
466                 os<<serializeLongString(tmp_os.str());
467         }
468         void deSerialize(std::istream &is, IGameDef *gamedef)
469         {
470                 clear();
471                 u16 count = readU16(is);
472                 std::istringstream tmp_is(deSerializeLongString(is), std::ios::binary);
473                 for(u16 n=0; n<count; n++){
474                         u16 i = readU16(tmp_is);
475                         if(i > MAX_CONTENT){
476                                 errorstream<<"ContentFeatures::deSerialize(): "
477                                                 <<"Too large content id: "<<i<<std::endl;
478                                 continue;
479                         }
480                         ContentFeatures *f = &m_content_features[i];
481                         f->deSerialize(tmp_is, gamedef);
482                         f->modified = true;
483                 }
484         }
485 private:
486         ContentFeatures m_content_features[MAX_CONTENT+1];
487 };
488
489 IWritableNodeDefManager* createNodeDefManager()
490 {
491         return new CNodeDefManager();
492 }
493