Newer
Older
Perttu Ahola
committed
/*
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Perttu Ahola
committed
This program is free software; you can redistribute it and/or modify
Perttu Ahola
committed
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
Perttu Ahola
committed
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Perttu Ahola
committed
GNU Lesser General Public License for more details.
Perttu Ahola
committed
Perttu Ahola
committed
You should have received a copy of the GNU Lesser General Public License along
Perttu Ahola
committed
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "mapblock_mesh.h"
#include "light.h"
#include "mapblock.h"
#include "map.h"
Kahrl
committed
#include "main.h" // for g_profiler
Kahrl
committed
#include "mesh.h"
Perttu Ahola
committed
#include "settings.h"
#include "util/directiontables.h"
Perttu Ahola
committed
void applyContrast(video::SColor& color, float Factor)
float r = color.getRed();
float g = color.getGreen();
float b = color.getBlue();
color.setRed(irr::core::clamp((int)sqrt(r * r * Factor), 0, 255));
color.setGreen(irr::core::clamp((int)sqrt(g * g * Factor), 0, 255));
color.setBlue(irr::core::clamp((int)sqrt(b * b * Factor), 0, 255));
Kahrl
committed
/*
MeshMakeData
*/
MeshMakeData::MeshMakeData(IGameDef *gamedef):
m_vmanip(),
m_blockpos(-1337,-1337,-1337),
m_crack_pos_relative(-1337, -1337, -1337),
m_smooth_lighting(false),
m_gamedef(gamedef)
{}
void MeshMakeData::fill(MapBlock *block)
Perttu Ahola
committed
{
m_blockpos = block->getPos();
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
Perttu Ahola
committed
/*
Copy data
*/
// Allocate this block + neighbors
m_vmanip.clear();
m_vmanip.addArea(VoxelArea(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1)));
{
//TimeTaker timer("copy central block data");
// 0ms
// Copy our data
block->copyTo(m_vmanip);
}
{
//TimeTaker timer("copy neighbor block data");
// 0ms
/*
Copy neighbors. This is lightning fast.
Copying only the borders would be *very* slow.
*/
Perttu Ahola
committed
// Get map
Perttu Ahola
committed
Perttu Ahola
committed
{
Perttu Ahola
committed
v3s16 bp = m_blockpos + dir;
MapBlock *b = map->getBlockNoCreateNoEx(bp);
if(b)
b->copyTo(m_vmanip);
}
}
}
Kahrl
committed
void MeshMakeData::fillSingleNode(MapNode *node)
{
m_blockpos = v3s16(0,0,0);
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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;
}
Kahrl
committed
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,
sapier
committed
INodeDefManager *ndef)
Kahrl
committed
{
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.
*/
sapier
committed
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef)
Kahrl
committed
{
sapier
committed
u16 day = getInteriorLight(LIGHTBANK_DAY, n, increment, ndef);
u16 night = getInteriorLight(LIGHTBANK_NIGHT, n, increment, ndef);
Kahrl
committed
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,
sapier
committed
v3s16 face_dir, INodeDefManager *ndef)
Kahrl
committed
{
u8 light;
u8 l1 = n.getLight(bank, ndef);
u8 l2 = n2.getLight(bank, ndef);
if(l1 > l2)
light = l1;
else
light = l2;
Perttu Ahola
committed
// Boost light level for light sources
u8 light_source = MYMAX(ndef->get(n).light_source,
ndef->get(n2).light_source);
//if(light_source >= light)
//return decode_light(undiminish_light(light_source));
if(light_source > light)
//return decode_light(light_source);
light = light_source;
Kahrl
committed
return decode_light(light);
}
/*
Calculate non-smooth lighting at face of node.
Both light banks.
*/
sapier
committed
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef)
Kahrl
committed
{
sapier
committed
u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, face_dir, ndef);
u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, face_dir, ndef);
Kahrl
committed
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;
Perttu Ahola
committed
u8 light_source_max = 0;
Kahrl
committed
for(u32 i=0; i<8; i++)
{
MapNode n = data->m_vmanip.getNodeNoEx(p - dirs8[i]);
// if it's CONTENT_IGNORE we can't do any light calculations
if (n.getContent() == CONTENT_IGNORE) {
continue;
}
Kahrl
committed
const ContentFeatures &f = ndef->get(n);
Perttu Ahola
committed
if(f.light_source > light_source_max)
light_source_max = f.light_source;
Kahrl
committed
// 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++;
}
Kahrl
committed
}
if(light_count == 0)
return 255;
Kahrl
committed
light /= light_count;
Perttu Ahola
committed
// Boost brightness around light sources
if(decode_light(light_source_max) >= light)
//return decode_light(undiminish_light(light_source_max));
return decode_light(light_source_max);
Kahrl
committed
if(ambient_occlusion > 4)
{
//ambient_occlusion -= 4;
//light = (float)light / ((float)ambient_occlusion * 0.5 + 1.0);
float light_amount = (8 - ambient_occlusion) / 4.0;
float light_f = (float)light / 255.0;
light_f = pow(light_f, 2.2f); // gamma -> linear space
light_f = pow(light_f, 1.0f/2.2f); // linear -> gamma space
if(light_f > 1.0)
light_f = 1.0;
light = 255.0 * light_f + 0.5;
Kahrl
committed
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
}
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);
Kahrl
committed
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,
};
b += emphase_blue_when_dark[b / 8];
Kahrl
committed
// 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];
Kahrl
committed
result.setRed(rg);
result.setGreen(rg);
result.setBlue(b);
}
/*
Mesh generation helpers
*/
Perttu Ahola
committed
/*
vertex_dirs: v3s16[4]
*/
static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
Perttu Ahola
committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
{
/*
If looked from outside the node towards the face, the corners are:
0: bottom-right
1: bottom-left
2: top-left
3: top-right
*/
if(dir == v3s16(0,0,1))
{
// If looking towards z+, this is the face that is behind
// the center point, facing towards z+.
vertex_dirs[0] = v3s16(-1,-1, 1);
vertex_dirs[1] = v3s16( 1,-1, 1);
vertex_dirs[2] = v3s16( 1, 1, 1);
vertex_dirs[3] = v3s16(-1, 1, 1);
}
else if(dir == v3s16(0,0,-1))
{
// faces towards Z-
vertex_dirs[0] = v3s16( 1,-1,-1);
vertex_dirs[1] = v3s16(-1,-1,-1);
vertex_dirs[2] = v3s16(-1, 1,-1);
vertex_dirs[3] = v3s16( 1, 1,-1);
}
else if(dir == v3s16(1,0,0))
{
// faces towards X+
vertex_dirs[0] = v3s16( 1,-1, 1);
vertex_dirs[1] = v3s16( 1,-1,-1);
vertex_dirs[2] = v3s16( 1, 1,-1);
vertex_dirs[3] = v3s16( 1, 1, 1);
}
else if(dir == v3s16(-1,0,0))
{
// faces towards X-
vertex_dirs[0] = v3s16(-1,-1,-1);
vertex_dirs[1] = v3s16(-1,-1, 1);
vertex_dirs[2] = v3s16(-1, 1, 1);
vertex_dirs[3] = v3s16(-1, 1,-1);
}
else if(dir == v3s16(0,1,0))
{
// faces towards Y+ (assume Z- as "down" in texture)
vertex_dirs[0] = v3s16( 1, 1,-1);
vertex_dirs[1] = v3s16(-1, 1,-1);
vertex_dirs[2] = v3s16(-1, 1, 1);
vertex_dirs[3] = v3s16( 1, 1, 1);
}
else if(dir == v3s16(0,-1,0))
{
// faces towards Y- (assume Z+ as "down" in texture)
vertex_dirs[0] = v3s16( 1,-1, 1);
vertex_dirs[1] = v3s16(-1,-1, 1);
vertex_dirs[2] = v3s16(-1,-1,-1);
vertex_dirs[3] = v3s16( 1,-1,-1);
}
}
struct FastFace
{
TileSpec tile;
video::S3DVertex vertices[4]; // Precalculated vertices
};
Kahrl
committed
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
Perttu Ahola
committed
{
FastFace face;
Perttu Ahola
committed
// Position is at the center of the cube.
v3f pos = p * BS;
float x0 = 0.0;
float y0 = 0.0;
float w = 1.0;
float h = 1.0;
Perttu Ahola
committed
v3f vertex_pos[4];
v3s16 vertex_dirs[4];
getNodeVertexDirs(dir, vertex_dirs);
switch (tile.rotation)
{
case 0:
break;
case 1: //R90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
t1=li0;
li0=li3;
li3=li2;
li2=li1;
li1=t1;
break;
case 2: //R180
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[2];
vertex_dirs[2] = t;
t = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[3];
vertex_dirs[3] = t;
t1 = li0;
li0 = li2;
li2 = t1;
t1 = li1;
li1 = li3;
li3 = t1;
break;
case 3: //R270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
t1 = li0;
li0 = li1;
li1 = li2;
li2 = li3;
li3 = t1;
break;
case 4: //FXR90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
t1 = li0;
li0 = li3;
li3 = li2;
li2 = li1;
li1 = t1;
y0 += h;
h *= -1;
break;
case 5: //FXR270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
t1 = li0;
li0 = li1;
li1 = li2;
li2 = li3;
li3 = t1;
y0 += h;
h *= -1;
break;
case 6: //FYR90
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[3];
vertex_dirs[3] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[1];
vertex_dirs[1] = t;
t1 = li0;
li0 = li3;
li3 = li2;
li2 = li1;
li1 = t1;
x0 += w;
w *= -1;
break;
case 7: //FYR270
t = vertex_dirs[0];
vertex_dirs[0] = vertex_dirs[1];
vertex_dirs[1] = vertex_dirs[2];
vertex_dirs[2] = vertex_dirs[3];
vertex_dirs[3] = t;
t1 = li0;
li0 = li1;
li1 = li2;
li2 = li3;
li3 = t1;
x0 += w;
w *= -1;
y0 += h;
h *= -1;
x0 += w;
w *= -1;
Perttu Ahola
committed
for(u16 i=0; i<4; i++)
{
vertex_pos[i] = v3f(
BS/2*vertex_dirs[i].X,
BS/2*vertex_dirs[i].Y,
BS/2*vertex_dirs[i].Z
);
}
for(u16 i=0; i<4; i++)
{
vertex_pos[i].X *= scale.X;
vertex_pos[i].Y *= scale.Y;
vertex_pos[i].Z *= scale.Z;
Kahrl
committed
vertex_pos[i] += pos;
Perttu Ahola
committed
}
Perttu Ahola
committed
if (scale.X < 0.999 || scale.X > 1.001) abs_scale = scale.X;
else if(scale.Y < 0.999 || scale.Y > 1.001) abs_scale = scale.Y;
else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
v3f normal(dir.X, dir.Y, dir.Z);
Perttu Ahola
committed
u8 alpha = tile.alpha;
face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
Perttu Ahola
committed
MapBlock_LightColor(alpha, li0, light_source),
Perttu Ahola
committed
core::vector2d<f32>(x0+w*abs_scale, y0+h));
face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
Perttu Ahola
committed
MapBlock_LightColor(alpha, li1, light_source),
Perttu Ahola
committed
core::vector2d<f32>(x0, y0+h));
face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
Perttu Ahola
committed
MapBlock_LightColor(alpha, li2, light_source),
Perttu Ahola
committed
core::vector2d<f32>(x0, y0));
face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
Perttu Ahola
committed
MapBlock_LightColor(alpha, li3, light_source),
Perttu Ahola
committed
core::vector2d<f32>(x0+w*abs_scale, y0));
face.tile = tile;
dest.push_back(face);
}
Kahrl
committed
/*
Nodes make a face if contents differ and solidness differs.
Return value:
0: No face
1: Face uses m1's content
2: Face uses m2's content
equivalent: Whether the blocks share the same face (eg. water and glass)
TODO: Add 3: Both faces drawn with backface culling, remove equivalent
*/
static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
INodeDefManager *ndef)
{
*equivalent = false;
if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
return 0;
Kahrl
committed
bool contents_differ = (m1 != m2);
Kahrl
committed
const ContentFeatures &f1 = ndef->get(m1);
const ContentFeatures &f2 = ndef->get(m2);
// Contents don't differ for different forms of same liquid
if(f1.sameLiquid(f2))
contents_differ = false;
Kahrl
committed
u8 c1 = f1.solidness;
u8 c2 = f2.solidness;
bool solidness_differs = (c1 != c2);
bool makes_face = contents_differ && solidness_differs;
if(makes_face == false)
return 0;
Kahrl
committed
if(c1 == 0)
c1 = f1.visual_solidness;
if(c2 == 0)
c2 = f2.visual_solidness;
Kahrl
committed
if(c1 == c2){
*equivalent = true;
// If same solidness, liquid takes precense
if(f1.isLiquid())
return 1;
if(f2.isLiquid())
return 2;
}
Kahrl
committed
if(c1 > c2)
return 1;
else
return 2;
}
/*
Gets nth node tile (0 <= n <= 5).
*/
TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
Kahrl
committed
INodeDefManager *ndef = data->m_gamedef->ndef();
TileSpec spec = ndef->get(mn).tiles[tileindex];
// Apply temporary crack
if(p == data->m_crack_pos_relative)
{
spec.material_flags |= MATERIAL_FLAG_CRACK;
Kahrl
committed
return spec;
}
/*
Gets node tile given a face direction.
*/
TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data)
{
INodeDefManager *ndef = data->m_gamedef->ndef();
// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
// (0,0,1), (0,0,-1) or (0,0,0)
assert(dir.X * dir.X + dir.Y * dir.Y + dir.Z * dir.Z <= 1);
// Convert direction to single integer for table lookup
// 0 = (0,0,0)
// 1 = (1,0,0)
// 2 = (0,1,0)
// 3 = (0,0,1)
// 4 = invalid, treat as (0,0,0)
// 5 = (0,0,-1)
// 6 = (0,-1,0)
// 7 = (-1,0,0)
// Get rotation for things like chests
Kahrl
committed
u8 facedir = mn.getFaceDir(ndef);
0,0, 2,0 , 0,0 , 4,0 , 0,0, 5,0 , 1,0 , 3,0 , // rotate around y+ 0 - 3
0,0, 4,0 , 0,3 , 3,0 , 0,0, 2,0 , 1,1 , 5,0 ,
0,0, 3,0 , 0,2 , 5,0 , 0,0, 4,0 , 1,2 , 2,0 ,
0,0, 5,0 , 0,1 , 2,0 , 0,0, 3,0 , 1,3 , 4,0 ,
0,0, 2,3 , 5,0 , 0,2 , 0,0, 1,0 , 4,2 , 3,1 , // rotate around z+ 4 - 7
0,0, 4,3 , 2,0 , 0,1 , 0,0, 1,1 , 3,2 , 5,1 ,
0,0, 5,3 , 3,0 , 0,3 , 0,0, 1,3 , 2,2 , 4,1 ,
0,0, 2,1 , 4,2 , 1,2 , 0,0, 0,0 , 5,0 , 3,3 , // rotate around z- 8 - 11
0,0, 4,1 , 3,2 , 1,3 , 0,0, 0,3 , 2,0 , 5,3 ,
0,0, 3,1 , 5,2 , 1,0 , 0,0, 0,2 , 4,0 , 2,3 ,
0,0, 5,1 , 2,2 , 1,1 , 0,0, 0,1 , 3,0 , 4,3 ,
0,0, 0,3 , 3,3 , 4,1 , 0,0, 5,3 , 2,3 , 1,3 , // rotate around x+ 12 - 15
0,0, 0,2 , 5,3 , 3,1 , 0,0, 2,3 , 4,3 , 1,0 ,
0,0, 0,1 , 2,3 , 5,1 , 0,0, 4,3 , 3,3 , 1,1 ,
0,0, 0,0 , 4,3 , 2,1 , 0,0, 3,3 , 5,3 , 1,2 ,
0,0, 1,1 , 2,1 , 4,3 , 0,0, 5,1 , 3,1 , 0,1 , // rotate around x- 16 - 19
0,0, 1,3 , 3,1 , 5,3 , 0,0, 4,1 , 2,1 , 0,3 ,
0,0, 1,0 , 5,1 , 2,3 , 0,0, 3,1 , 4,1 , 0,2 ,
0,0, 3,2 , 1,2 , 4,2 , 0,0, 5,2 , 0,2 , 2,2 , // rotate around y- 20 - 23
0,0, 5,2 , 1,3 , 3,2 , 0,0, 2,2 , 0,1 , 4,2 ,
0,0, 2,2 , 1,0 , 5,2 , 0,0, 4,2 , 0,0 , 3,2 ,
0,0, 4,2 , 1,1 , 2,2 , 0,0, 3,2 , 0,3 , 5,2
u16 tile_index=facedir*16 + dir_i;
TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data);
spec.rotation=dir_to_tile[tile_index + 1];
spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id);
Perttu Ahola
committed
return spec;
Perttu Ahola
committed
}
Perttu Ahola
committed
// Input:
Kahrl
committed
MeshMakeData *data,
Perttu Ahola
committed
v3s16 p,
v3s16 face_dir,
// Output:
bool &makes_face,
v3s16 &p_corrected,
v3s16 &face_dir_corrected,
Kahrl
committed
u16 *lights,
Perttu Ahola
committed
TileSpec &tile,
u8 &light_source
Perttu Ahola
committed
)
{
Kahrl
committed
VoxelManipulator &vmanip = data->m_vmanip;
INodeDefManager *ndef = data->m_gamedef->ndef();
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
Perttu Ahola
committed
MapNode n0 = vmanip.getNodeNoEx(blockpos_nodes + p);
// Don't even try to get n1 if n0 is already CONTENT_IGNORE
if (n0.getContent() == CONTENT_IGNORE ) {
makes_face = false;
return;
}
Perttu Ahola
committed
MapNode n1 = vmanip.getNodeNoEx(blockpos_nodes + p + face_dir);
Perttu Ahola
committed
// This is hackish
Kahrl
committed
u8 mf = face_contents(n0.getContent(), n1.getContent(),
&equivalent, ndef);
Perttu Ahola
committed
if(mf == 0)
{
makes_face = false;
return;
}
makes_face = true;
Perttu Ahola
committed
if(mf == 1)
{
Perttu Ahola
committed
p_corrected = p;
face_dir_corrected = face_dir;
Perttu Ahola
committed
light_source = ndef->get(n0).light_source;
Perttu Ahola
committed
}
else
{
tile = getNodeTile(n1, p + face_dir, -face_dir, data);
Perttu Ahola
committed
p_corrected = p + face_dir;
face_dir_corrected = -face_dir;
Perttu Ahola
committed
light_source = ndef->get(n1).light_source;
Perttu Ahola
committed
}
// eg. water and glass
if(equivalent)
tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
Perttu Ahola
committed
Kahrl
committed
if(data->m_smooth_lighting == false)
Perttu Ahola
committed
{
lights[0] = lights[1] = lights[2] = lights[3] =
sapier
committed
getFaceLight(n0, n1, face_dir, ndef);
Perttu Ahola
committed
}
else
{
v3s16 vertex_dirs[4];
getNodeVertexDirs(face_dir_corrected, vertex_dirs);
for(u16 i=0; i<4; i++)
{
Kahrl
committed
lights[i] = getSmoothLight(
blockpos_nodes + p_corrected,
vertex_dirs[i], data);
Perttu Ahola
committed
}
}
Perttu Ahola
committed
return;
}
/*
startpos:
translate_dir: unit vector with only one of x, y or z
face_dir: unit vector with only one of x, y or z
*/
Kahrl
committed
MeshMakeData *data,
Perttu Ahola
committed
v3s16 startpos,
v3s16 translate_dir,
v3f translate_dir_f,
v3s16 face_dir,
v3f face_dir_f,
Perttu Ahola
committed
{
v3s16 p = startpos;
Perttu Ahola
committed
u16 continuous_tiles_count = 0;
Perttu Ahola
committed
bool makes_face = false;
Perttu Ahola
committed
v3s16 p_corrected;
v3s16 face_dir_corrected;
Kahrl
committed
u16 lights[4] = {0,0,0,0};
Perttu Ahola
committed
TileSpec tile;
Perttu Ahola
committed
u8 light_source = 0;
Kahrl
committed
makes_face, p_corrected, face_dir_corrected,
Perttu Ahola
committed
lights, tile, light_source);
Perttu Ahola
committed
Kahrl
committed
for(u16 j=0; j<MAP_BLOCKSIZE; j++)
Perttu Ahola
committed
{
// If tiling can be done, this is set to false in the next step
bool next_is_different = true;
Perttu Ahola
committed
v3s16 p_next;
Perttu Ahola
committed
bool next_makes_face = false;
v3s16 next_p_corrected;
v3s16 next_face_dir_corrected;
Kahrl
committed
u16 next_lights[4] = {0,0,0,0};
Perttu Ahola
committed
TileSpec next_tile;
Perttu Ahola
committed
u8 next_light_source = 0;
Perttu Ahola
committed
// If at last position, there is nothing to compare to and
// the face must be drawn anyway
Kahrl
committed
if(j != MAP_BLOCKSIZE - 1)
Perttu Ahola
committed
{
p_next = p + translate_dir;
Kahrl
committed
getTileInfo(data, p_next, face_dir,
Perttu Ahola
committed
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
Perttu Ahola
committed
next_tile, next_light_source);
Perttu Ahola
committed
if(next_makes_face == makes_face
&& next_p_corrected == p_corrected + translate_dir
Perttu Ahola
committed
&& next_face_dir_corrected == face_dir_corrected
&& next_lights[0] == lights[0]
&& next_lights[1] == lights[1]
&& next_lights[2] == lights[2]
&& next_lights[3] == lights[3]
Perttu Ahola
committed
&& next_tile == tile
Perttu Ahola
committed
&& next_light_source == light_source)
Perttu Ahola
committed
{
next_is_different = false;
}
else{
/*if(makes_face){
g_profiler->add("Meshgen: diff: next_makes_face != makes_face",
next_makes_face != makes_face ? 1 : 0);
g_profiler->add("Meshgen: diff: n_p_corr != p_corr + t_dir",
(next_p_corrected != p_corrected + translate_dir) ? 1 : 0);
g_profiler->add("Meshgen: diff: next_f_dir_corr != f_dir_corr",
next_face_dir_corrected != face_dir_corrected ? 1 : 0);
g_profiler->add("Meshgen: diff: next_lights[] != lights[]",
(next_lights[0] != lights[0] ||
next_lights[0] != lights[0] ||
next_lights[0] != lights[0] ||
next_lights[0] != lights[0]) ? 1 : 0);
g_profiler->add("Meshgen: diff: !(next_tile == tile)",
!(next_tile == tile) ? 1 : 0);
}*/
}
/*g_profiler->add("Meshgen: Total faces checked", 1);
if(makes_face)
g_profiler->add("Meshgen: Total makes_face checked", 1);*/
} else {
/*if(makes_face)
g_profiler->add("Meshgen: diff: last position", 1);*/
Perttu Ahola
committed
}
continuous_tiles_count++;
if(next_is_different)
Perttu Ahola
committed
{
/*
Create a face if there should be one
*/
if(makes_face)
{
// Floating point conversion of the position vector
v3f pf(p_corrected.X, p_corrected.Y, p_corrected.Z);
// Center point of face (kind of)
v3f sp = pf - ((f32)continuous_tiles_count / 2. - 0.5) * translate_dir_f;
if(continuous_tiles_count != 1)
sp += translate_dir_f;
Perttu Ahola
committed
v3f scale(1,1,1);
if(translate_dir.X != 0)
{
scale.X = continuous_tiles_count;
}
if(translate_dir.Y != 0)
{
scale.Y = continuous_tiles_count;
}
if(translate_dir.Z != 0)
{
scale.Z = continuous_tiles_count;
}
Perttu Ahola
committed
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
Perttu Ahola
committed
sp, face_dir_corrected, scale, light_source,
Kahrl
committed
dest);
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
for(int i=1; i<continuous_tiles_count; i++){
g_profiler->avg("Meshgen: faces drawn by tiling", 1);
}
Perttu Ahola
committed
}
continuous_tiles_count = 0;
Perttu Ahola
committed
makes_face = next_makes_face;
p_corrected = next_p_corrected;
face_dir_corrected = next_face_dir_corrected;
lights[0] = next_lights[0];
lights[1] = next_lights[1];
lights[2] = next_lights[2];
lights[3] = next_lights[3];
tile = next_tile;
Perttu Ahola
committed
light_source = next_light_source;
Perttu Ahola
committed
}
Perttu Ahola
committed
p = p_next;
}
}
Kahrl
committed
static void updateAllFastFaceRows(MeshMakeData *data,
Perttu Ahola
committed
{
Kahrl
committed
/*
Go through every y,z and get top(y+) faces in rows of x+
*/
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
for(s16 z=0; z<MAP_BLOCKSIZE; z++){
updateFastFaceRow(data,
v3s16(0,y,z),
v3s16(1,0,0), //dir
v3f (1,0,0),
v3s16(0,1,0), //face dir
v3f (0,1,0),
dest);
}
}
Perttu Ahola
committed
Kahrl
committed
/*
Go through every x,y and get right(x+) faces in rows of z+
*/
for(s16 x=0; x<MAP_BLOCKSIZE; x++){
for(s16 y=0; y<MAP_BLOCKSIZE; y++){
updateFastFaceRow(data,
v3s16(x,y,0),
v3s16(0,0,1), //dir
v3f (0,0,1),
v3s16(1,0,0), //face dir
v3f (1,0,0),
dest);
}
}
Perttu Ahola
committed
/*
Kahrl
committed
Go through every y,z and get back(z+) faces in rows of x+