/*
Minetest-c55
Copyright (C) 2010-2011 celeron55, Perttu Ahola
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(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
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
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"
#include "main.h" // For g_settings and g_texturesource
#include "settings.h"
#include "profiler.h"
#include "nodedef.h"
#include "tile.h"
#include "gamedef.h"
#include "content_mapblock.h"
#include "mineral.h" // For mineral_block_texture
void MeshMakeData::fill(u32 daynight_ratio, MapBlock *block)
{
m_daynight_ratio = daynight_ratio;
m_blockpos = block->getPos();
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
/*
There is no harm not copying the TempMods of the neighbors
because they are already copied to this block
*/
m_temp_mods.clear();
block->copyTempMods(m_temp_mods);
/*
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.
*/
// Get map
Map *map = block->getParent();
for(u16 i=0; igetBlockNoCreateNoEx(bp);
if(b)
b->copyTo(m_vmanip);
}
}
}
/*
vertex_dirs: v3s16[4]
*/
static void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
{
/*
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);
}
}
video::SColor MapBlock_LightColor(u8 alpha, u8 light)
{
#if 0
return video::SColor(alpha,light,light,light);
#endif
//return video::SColor(alpha,light,light,MYMAX(0, (s16)light-25)+25);
/*return video::SColor(alpha,light,light,MYMAX(0,
pow((float)light/255.0, 0.8)*255.0));*/
#if 1
// Emphase blue a bit in darker places
float lim = 80;
float power = 0.8;
if(light > lim)
return video::SColor(alpha,light,light,light);
else
return video::SColor(alpha,light,light,MYMAX(0,
pow((float)light/lim, power)*lim));
#endif
}
struct FastFace
{
TileSpec tile;
video::S3DVertex vertices[4]; // Precalculated vertices
};
static void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
v3s16 dir, v3f scale, v3f posRelative_f,
core::array &dest)
{
FastFace face;
// Position is at the center of the cube.
v3f pos = p * BS;
posRelative_f *= BS;
v3f vertex_pos[4];
v3s16 vertex_dirs[4];
getNodeVertexDirs(dir, vertex_dirs);
for(u16 i=0; i 1.001) abs_scale = scale.Y;
else if(scale.Z < 0.999 || scale.Z > 1.001) abs_scale = scale.Z;
v3f zerovector = v3f(0,0,0);
u8 alpha = tile.alpha;
/*u8 alpha = 255;
if(tile.id == TILE_WATER)
alpha = WATER_ALPHA;*/
float x0 = tile.texture.pos.X;
float y0 = tile.texture.pos.Y;
float w = tile.texture.size.X;
float h = tile.texture.size.Y;
/*video::SColor c = MapBlock_LightColor(alpha, li);
face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
core::vector2d(x0+w*abs_scale, y0+h));
face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0), c,
core::vector2d(x0, y0+h));
face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0), c,
core::vector2d(x0, y0));
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0), c,
core::vector2d(x0+w*abs_scale, y0));*/
face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
MapBlock_LightColor(alpha, li0),
core::vector2d(x0+w*abs_scale, y0+h));
face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
MapBlock_LightColor(alpha, li1),
core::vector2d(x0, y0+h));
face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
MapBlock_LightColor(alpha, li2),
core::vector2d(x0, y0));
face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
MapBlock_LightColor(alpha, li3),
core::vector2d(x0+w*abs_scale, y0));
face.tile = tile;
//DEBUG
//f->tile = TILE_STONE;
dest.push_back(face);
}
static TileSpec getTile(const MapNode &node, v3s16 dir,
ITextureSource *tsrc, INodeDefManager *nodemgr)
{
const ContentFeatures &f = nodemgr->get(node);
if(f.param_type == CPT_FACEDIR_SIMPLE)
dir = facedir_rotate(node.param1, dir);
TileSpec spec;
s32 dir_i = -1;
if(dir == v3s16(0,0,0))
dir_i = -1;
else if(dir == v3s16(0,1,0))
dir_i = 0;
else if(dir == v3s16(0,-1,0))
dir_i = 1;
else if(dir == v3s16(1,0,0))
dir_i = 2;
else if(dir == v3s16(-1,0,0))
dir_i = 3;
else if(dir == v3s16(0,0,1))
dir_i = 4;
else if(dir == v3s16(0,0,-1))
dir_i = 5;
if(dir_i == -1)
// Non-directional
spec = f.tiles[0];
else
spec = f.tiles[dir_i];
/*
If it contains some mineral, change texture id
*/
if(f.param_type == CPT_MINERAL && tsrc)
{
u8 mineral = node.getMineral(nodemgr);
std::string mineral_texture_name = mineral_block_texture(mineral);
if(mineral_texture_name != "")
{
u32 orig_id = spec.texture.id;
std::string texture_name = tsrc->getTextureName(orig_id);
//texture_name += "^blit:";
texture_name += "^";
texture_name += mineral_texture_name;
u32 new_id = tsrc->getTextureId(texture_name);
spec.texture = tsrc->getTexture(new_id);
}
}
return spec;
}
/*
Gets node tile from any place relative to block.
Returns TILE_NODE if doesn't exist or should not be drawn.
*/
static TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
NodeModMap &temp_mods, ITextureSource *tsrc, INodeDefManager *ndef)
{
TileSpec spec;
spec = getTile(mn, face_dir, tsrc, ndef);
/*
Check temporary modifications on this node
*/
/*core::map::Node *n;
n = m_temp_mods.find(p);
// If modified
if(n != NULL)
{
struct NodeMod mod = n->getValue();*/
NodeMod mod;
if(temp_mods.get(p, &mod))
{
if(mod.type == NODEMOD_CHANGECONTENT)
{
MapNode mn2(mod.param);
spec = getTile(mn2, face_dir, tsrc, ndef);
}
if(mod.type == NODEMOD_CRACK)
{
/*
Get texture id, translate it to name, append stuff to
name, get texture id
*/
// Get original texture name
u32 orig_id = spec.texture.id;
std::string orig_name = tsrc->getTextureName(orig_id);
// Create new texture name
std::ostringstream os;
os