Re-add jungles, apple trees
[oweals/minetest.git] / src / voxelalgorithms.cpp
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 #include "voxelalgorithms.h"
21 #include "nodedef.h"
22
23 namespace voxalgo
24 {
25
26 void setLight(VoxelManipulator &v, VoxelArea a, u8 light,
27                 INodeDefManager *ndef)
28 {
29         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
30         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
31         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
32         {
33                 v3s16 p(x,y,z);
34                 MapNode &n = v.getNodeRefUnsafe(p);
35                 n.setLight(LIGHTBANK_DAY, light, ndef);
36                 n.setLight(LIGHTBANK_NIGHT, light, ndef);
37         }
38 }
39
40 void clearLightAndCollectSources(VoxelManipulator &v, VoxelArea a,
41                 enum LightBank bank, INodeDefManager *ndef,
42                 std::set<v3s16> & light_sources,
43                 std::map<v3s16, u8> & unlight_from)
44 {
45         // The full area we shall touch
46         VoxelArea required_a = a;
47         required_a.pad(v3s16(0,0,0));
48         // Make sure we have access to it
49         v.emerge(a);
50
51         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
52         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
53         for(s32 y=a.MinEdge.Y; y<=a.MaxEdge.Y; y++)
54         {
55                 v3s16 p(x,y,z);
56                 MapNode &n = v.getNodeRefUnsafe(p);
57                 u8 oldlight = n.getLight(bank, ndef);
58                 n.setLight(bank, 0, ndef);
59
60                 // If node sources light, add to list
61                 u8 source = ndef->get(n).light_source;
62                 if(source != 0)
63                         light_sources.insert(p);
64
65                 // Collect borders for unlighting
66                 if((x==a.MinEdge.X || x == a.MaxEdge.X
67                 || y==a.MinEdge.Y || y == a.MaxEdge.Y
68                 || z==a.MinEdge.Z || z == a.MaxEdge.Z)
69                 && oldlight != 0)
70                 {
71                         unlight_from[p] = oldlight;
72                 }
73         }
74 }
75
76 SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
77                 bool inexistent_top_provides_sunlight,
78                 std::set<v3s16> & light_sources,
79                 INodeDefManager *ndef)
80 {
81         // Return values
82         bool bottom_sunlight_valid = true;
83
84         // The full area we shall touch extends one extra at top and bottom
85         VoxelArea required_a = a;
86         required_a.pad(v3s16(0,1,0));
87         // Make sure we have access to it
88         v.emerge(a);
89
90         s16 max_y = a.MaxEdge.Y;
91         s16 min_y = a.MinEdge.Y;
92
93         for(s32 x=a.MinEdge.X; x<=a.MaxEdge.X; x++)
94         for(s32 z=a.MinEdge.Z; z<=a.MaxEdge.Z; z++)
95         {
96                 v3s16 p_overtop(x, max_y+1, z);
97                 bool overtop_has_sunlight = false;
98                 // If overtop node does not exist, trust heuristics
99                 if(!v.exists(p_overtop))
100                         overtop_has_sunlight = inexistent_top_provides_sunlight;
101                 else if(v.getNodeRefUnsafe(p_overtop).getContent() == CONTENT_IGNORE)
102                         overtop_has_sunlight = inexistent_top_provides_sunlight;
103                 // Otherwise refer to it's light value
104                 else
105                         overtop_has_sunlight = (v.getNodeRefUnsafe(p_overtop).getLight(
106                                         LIGHTBANK_DAY, ndef) == LIGHT_SUN);
107
108                 // Copy overtop's sunlight all over the place
109                 u8 incoming_light = overtop_has_sunlight ? LIGHT_SUN : 0;
110                 for(s32 y=max_y; y>=min_y; y--)
111                 {
112                         v3s16 p(x,y,z);
113                         MapNode &n = v.getNodeRefUnsafe(p);
114                         if(incoming_light == 0){
115                                 // Do nothing
116                         } else if(incoming_light == LIGHT_SUN &&
117                                         ndef->get(n).sunlight_propagates){
118                                 // Do nothing
119                         } else if(ndef->get(n).sunlight_propagates == false){
120                                 incoming_light = 0;
121                         } else {
122                                 incoming_light = diminish_light(incoming_light);
123                         }
124                         u8 old_light = n.getLight(LIGHTBANK_DAY, ndef);
125
126                         if(incoming_light > old_light)
127                                 n.setLight(LIGHTBANK_DAY, incoming_light, ndef);
128
129                         if(diminish_light(incoming_light) != 0)
130                                 light_sources.insert(p);
131                 }
132
133                 // Check validity of sunlight at top of block below if it
134                 // hasn't already been proven invalid
135                 if(bottom_sunlight_valid)
136                 {
137                         bool sunlight_should_continue_down = (incoming_light == LIGHT_SUN);
138                         v3s16 p_overbottom(x, min_y-1, z);
139                         if(!v.exists(p_overbottom) ||
140                                         v.getNodeRefUnsafe(p_overbottom
141                                                         ).getContent() == CONTENT_IGNORE){
142                                 // Is not known, cannot compare
143                         } else {
144                                 bool overbottom_has_sunlight = (v.getNodeRefUnsafe(p_overbottom
145                                                 ).getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN);
146                                 if(sunlight_should_continue_down != overbottom_has_sunlight){
147                                         bottom_sunlight_valid = false;
148                                 }
149                         }
150                 }
151         }
152
153         return SunlightPropagateResult(bottom_sunlight_valid);
154 }
155
156 } // namespace voxalgo
157