+void MeshMakeData::fillSingleNode(MapNode *node)
+{
+ m_blockpos = v3s16(0,0,0);
+
+ v3s16 blockpos_nodes = v3s16(0,0,0);
+ VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
+ blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
+ s32 volume = area.getVolume();
+ s32 our_node_index = area.index(1,1,1);
+
+ // Allocate this block + neighbors
+ m_vmanip.clear();
+ m_vmanip.addArea(area);
+
+ // Fill in data
+ MapNode *data = new MapNode[volume];
+ for(s32 i = 0; i < volume; i++)
+ {
+ if(i == our_node_index)
+ {
+ data[i] = *node;
+ }
+ else
+ {
+ data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
+ }
+ }
+ m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
+ delete[] data;
+}
+
+void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
+{
+ if(crack_level >= 0)
+ m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
+}
+
+void MeshMakeData::setSmoothLighting(bool smooth_lighting)
+{
+ m_smooth_lighting = smooth_lighting;
+}
+
+/*
+ Light and vertex color functions
+*/
+
+/*
+ Calculate non-smooth lighting at interior of node.
+ Single light bank.
+*/
+static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
+ MeshMakeData *data)
+{
+ INodeDefManager *ndef = data->m_gamedef->ndef();
+ u8 light = n.getLight(bank, ndef);
+
+ while(increment > 0)
+ {
+ light = undiminish_light(light);
+ --increment;
+ }
+ while(increment < 0)
+ {
+ light = diminish_light(light);
+ ++increment;
+ }
+
+ return decode_light(light);
+}
+
+/*
+ Calculate non-smooth lighting at interior of node.
+ Both light banks.
+*/
+u16 getInteriorLight(MapNode n, s32 increment, MeshMakeData *data)
+{
+ u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, data);
+ u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, data);
+ return day | (night << 8);
+}
+
+/*
+ Calculate non-smooth lighting at face of node.
+ Single light bank.
+*/
+static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
+ v3s16 face_dir, MeshMakeData *data)
+{
+ INodeDefManager *ndef = data->m_gamedef->ndef();
+
+ u8 light;
+ u8 l1 = n.getLight(bank, ndef);
+ u8 l2 = n2.getLight(bank, ndef);
+ if(l1 > l2)
+ light = l1;
+ else
+ light = l2;
+
+ // Make some nice difference to different sides
+
+ // This makes light come from a corner
+ /*if(face_dir.X == 1 || face_dir.Z == 1 || face_dir.Y == -1)
+ light = diminish_light(diminish_light(light));
+ else if(face_dir.X == -1 || face_dir.Z == -1)
+ light = diminish_light(light);*/
+
+ // All neighboring faces have different shade (like in minecraft)
+ if(face_dir.X == 1 || face_dir.X == -1 || face_dir.Y == -1)
+ light = diminish_light(diminish_light(light));
+ else if(face_dir.Z == 1 || face_dir.Z == -1)
+ light = diminish_light(light);
+
+ return decode_light(light);
+}
+
+/*
+ Calculate non-smooth lighting at face of node.
+ Both light banks.
+*/
+u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, MeshMakeData *data)
+{
+ u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, data);
+ u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, data);
+ return day | (night << 8);
+}
+
+/*
+ Calculate smooth lighting at the XYZ- corner of p.
+ Single light bank.
+*/
+static u8 getSmoothLight(enum LightBank bank, v3s16 p, MeshMakeData *data)
+{
+ static v3s16 dirs8[8] = {
+ v3s16(0,0,0),
+ v3s16(0,0,1),
+ v3s16(0,1,0),
+ v3s16(0,1,1),
+ v3s16(1,0,0),
+ v3s16(1,1,0),
+ v3s16(1,0,1),
+ v3s16(1,1,1),
+ };
+
+ INodeDefManager *ndef = data->m_gamedef->ndef();
+
+ u16 ambient_occlusion = 0;
+ u16 light = 0;
+ u16 light_count = 0;
+ for(u32 i=0; i<8; i++)
+ {
+ MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
+ const ContentFeatures &f = ndef->get(n);
+ // Check f.solidness because fast-style leaves look
+ // better this way
+ if(f.param_type == CPT_LIGHT && f.solidness != 2)
+ {
+ light += decode_light(n.getLight(bank, ndef));
+ light_count++;
+ }
+ else if(n.getContent() != CONTENT_IGNORE)
+ {
+ ambient_occlusion++;
+ }
+ }
+
+ if(light_count == 0)
+ return 255;
+
+ light /= light_count;
+
+ if(ambient_occlusion > 4)
+ {
+ ambient_occlusion -= 4;
+ light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
+ }
+
+ return light;
+}
+
+/*
+ Calculate smooth lighting at the XYZ- corner of p.
+ Both light banks.
+*/
+static u16 getSmoothLight(v3s16 p, MeshMakeData *data)
+{
+ u16 day = getSmoothLight(LIGHTBANK_DAY, p, data);
+ u16 night = getSmoothLight(LIGHTBANK_NIGHT, p, data);
+ return day | (night << 8);
+}
+
+/*
+ Calculate smooth lighting at the given corner of p.
+ Both light banks.
+*/
+u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
+{
+ if(corner.X == 1) p.X += 1;
+ else assert(corner.X == -1);
+ if(corner.Y == 1) p.Y += 1;
+ else assert(corner.Y == -1);
+ if(corner.Z == 1) p.Z += 1;
+ else assert(corner.Z == -1);
+
+ return getSmoothLight(p, data);
+}
+
+/*
+ Converts from day + night color values (0..255)
+ and a given daynight_ratio to the final SColor shown on screen.
+*/
+static void finalColorBlend(video::SColor& result,
+ u8 day, u8 night, u32 daynight_ratio)
+{
+ s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
+ s32 b = rg;
+
+ // Moonlight is blue
+ b += (day - night) / 13;
+ rg -= (day - night) / 23;
+
+ // Emphase blue a bit in darker places
+ // Each entry of this array represents a range of 8 blue levels
+ static u8 emphase_blue_when_dark[32] = {
+ 1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ if(b < 0)
+ b = 0;
+ if(b > 255)
+ b = 255;
+ b += emphase_blue_when_dark[b / 8];
+
+ // Artificial light is yellow-ish
+ static u8 emphase_yellow_when_artificial[16] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
+ };
+ rg += emphase_yellow_when_artificial[night/16];
+ if(rg < 0)
+ rg = 0;
+ if(rg > 255)
+ rg = 255;
+
+ result.setRed(rg);
+ result.setGreen(rg);
+ result.setBlue(b);
+}
+
+/*
+ Mesh generation helpers
+*/
+