178 lines
4.8 KiB
C++
178 lines
4.8 KiB
C++
// http://www.apache.org/licenses/LICENSE-2.0
|
|
// Copyright 2014 Perttu Ahola <celeron55@gmail.com>
|
|
#include "interface/block.h"
|
|
#include "core/log.h"
|
|
#define MODULE "block"
|
|
|
|
namespace interface {
|
|
|
|
static const pv::Vector3DUint8 FACE_DIRS[6] = {
|
|
pv::Vector3DUint8(0, 1, 0),
|
|
pv::Vector3DUint8(0, -1, 0),
|
|
pv::Vector3DUint8(1, 0, 0),
|
|
pv::Vector3DUint8(-1, 0, 0),
|
|
pv::Vector3DUint8(0, 0, 1),
|
|
pv::Vector3DUint8(0, 0, -1),
|
|
};
|
|
|
|
// Map part block segment's face to atlas segment definition
|
|
static void texmap_segment_face(const pv::Vector3DUint8 &block_size,
|
|
const pv::Vector3DUint8 &block_segi, size_t face_i,
|
|
magic::IntVector2 &total_segments, magic::IntVector2 &select_segment)
|
|
{
|
|
if(face_i == 0){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getX(),
|
|
block_size.getZ()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_segi.getX(),
|
|
block_segi.getZ()
|
|
);
|
|
} else if(face_i == 1){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getX(),
|
|
block_size.getZ()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_size.getX() - 1 - block_segi.getX(),
|
|
block_size.getZ() - 1 - block_segi.getZ()
|
|
);
|
|
} else if(face_i == 2){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getY(),
|
|
block_size.getZ()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_segi.getY(),
|
|
block_segi.getZ()
|
|
);
|
|
} else if(face_i == 3){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getY(),
|
|
block_size.getZ()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_size.getY() - 1 - block_segi.getY(),
|
|
block_size.getZ() - 1 - block_segi.getZ()
|
|
);
|
|
} else if(face_i == 4){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getX(),
|
|
block_size.getY()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_segi.getX(),
|
|
block_segi.getY()
|
|
);
|
|
} else if(face_i == 5){
|
|
total_segments = magic::IntVector2(
|
|
block_size.getX(),
|
|
block_size.getY()
|
|
);
|
|
select_segment = magic::IntVector2(
|
|
block_size.getX() - 1 - block_segi.getX(),
|
|
block_size.getY() - 1 - block_segi.getY()
|
|
);
|
|
}
|
|
}
|
|
|
|
struct CBlockRegistry: public BlockRegistry
|
|
{
|
|
VoxelRegistry *m_voxel_reg;
|
|
sv_<BlockDefinition> m_defs;
|
|
sm_<BlockName, BlockTypeId> m_name_to_id;
|
|
|
|
CBlockRegistry(VoxelRegistry *voxel_reg):
|
|
m_voxel_reg(voxel_reg)
|
|
{
|
|
m_defs.resize(1); // Id 0 is BLOCKTYPEID_UNDEFINEDD
|
|
}
|
|
|
|
BlockTypeId add_block_with_predefined_segments(const BlockDefinition &def)
|
|
{
|
|
BlockTypeId id = m_defs.size();
|
|
m_defs.resize(id + 1);
|
|
m_defs[id] = def;
|
|
m_defs[id].id = id;
|
|
m_name_to_id[def.name] = id;
|
|
return id;
|
|
}
|
|
|
|
BlockTypeId add_block_generate_segments(const BlockSourceDefinition &def)
|
|
{
|
|
// Check this because VoxelDefinition has a static number of textures
|
|
if(def.side_textures.size() != 6)
|
|
throw Exception("BlockSourceDefinition::side_textures must contain "
|
|
"6 resource names");
|
|
// Create block definition without segments
|
|
BlockDefinition plain_def;
|
|
plain_def.name = def.name;
|
|
plain_def.num_rotations = def.num_rotations;
|
|
plain_def.size = def.size;
|
|
// Generate voxels for segments
|
|
// TODO: Rotations
|
|
// NOTE: The secondary rotation rotates the block segments (done first)
|
|
// NOTE: The primary rotation rotates the face (done second)
|
|
for(int z = 0; z < def.size.getZ(); z++){
|
|
for(int y = 0; y < def.size.getY(); y++){
|
|
for(int x = 0; x < def.size.getX(); x++){
|
|
VoxelDefinition vdef;
|
|
vdef.name.block_name = def.name;
|
|
vdef.name.segment_x = x;
|
|
vdef.name.segment_y = y;
|
|
vdef.name.segment_z = z;
|
|
vdef.name.rotation_primary = 0;
|
|
vdef.name.rotation_secondary = 0;
|
|
vdef.handler_module = def.handler_module;
|
|
for(size_t i = 0; i < 6; i++){
|
|
AtlasSegmentDefinition &seg = vdef.textures[i];
|
|
seg.resource_name = def.side_textures[i];
|
|
// Map block segment face to atlas segment
|
|
// - x, y, z is block segment
|
|
// - i is segment face index
|
|
texmap_segment_face(def.size, pv::Vector3DUint8(x, y, z), i,
|
|
seg.total_segments, seg.select_segment);
|
|
// TODO: Rotation
|
|
}
|
|
VoxelTypeId vid = m_voxel_reg->add_voxel(vdef);
|
|
plain_def.segments.push_back(vid);
|
|
}
|
|
}
|
|
}
|
|
// Add final block definition
|
|
return add_block_with_predefined_segments(plain_def);
|
|
}
|
|
|
|
const BlockDefinition* get(const BlockTypeId &id)
|
|
{
|
|
if(id >= m_defs.size()){
|
|
log_w(MODULE, "BlockRegistry::get(): id=%i not found", id);
|
|
return NULL;
|
|
}
|
|
return &m_defs[id];
|
|
}
|
|
|
|
const BlockDefinition* get(const BlockName &name)
|
|
{
|
|
auto it = m_name_to_id.find(name);
|
|
if(it == m_name_to_id.end()){
|
|
log_w(MODULE, "CBlockRegistry::get(): name=\"%s\" not found", cs(name));
|
|
return NULL;
|
|
}
|
|
BlockTypeId id = it->second;
|
|
return get(id);
|
|
}
|
|
|
|
// TODO: Network serialization
|
|
// TODO: Ability to track changes (just some kind of set_dirty()?)
|
|
};
|
|
|
|
BlockRegistry* createBlockRegistry(VoxelRegistry *voxel_reg)
|
|
{
|
|
return new CBlockRegistry(voxel_reg);
|
|
}
|
|
|
|
}
|
|
// vim: set noet ts=4 sw=4:
|