^ The default functions handle regular use cases.
}
+Tile definition:
+- "image.png"
+- {name="image.png", animation={Tile Animation definition}}
+- {name="image.png", backface_culling=bool}
+ ^ backface culling only supported in special tiles
+- deprecated still supported field names:
+ - image -> name
+
+Tile animation definition:
+- {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}
+
Node definition (register_node)
{
<all fields allowed in item definitions>,
drawtype = "normal",
visual_scale = 1.0,
- tile_images = {"default_unknown_block.png"},
- special_materials = {
- {image="", backface_culling=true},
- {image="", backface_culling=true},
- },
+ tiles = {tile definition 1, def2, def3, def4, def5, def6},
+ ^ List can be shortened to needed length
+ ^ Old field name: tile_images
+ special_tiles = {tile definition 1, Tile definition 2},
+ ^ List can be shortened to needed length
+ ^ Old field name: special_materials
alpha = 255,
post_effect_color = {a=0, r=0, g=0, b=0},
paramtype = "none",
damage_per_second = 4*2,
post_effect_color = {a=192, r=255, g=64, b=0},
special_materials = {
- {image="default_lava.png", backface_culling=false},
- {image="default_lava.png", backface_culling=true},
+ {
+ image="default_lava_flowing_animated.png",
+ backface_culling=false,
+ animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3}
+ },
+ {
+ image="default_lava_flowing_animated.png",
+ backface_culling=true,
+ animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3}
+ },
},
groups = {lava=3, liquid=2, hot=3},
})
description = "Lava",
inventory_image = minetest.inventorycube("default_lava.png"),
drawtype = "liquid",
- tile_images = {"default_lava.png"},
+ --tile_images = {"default_lava.png"},
+ tile_images = {
+ {name="default_lava_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}}
+ },
paramtype = "light",
light_source = LIGHT_MAX - 1,
walkable = false,
PROTOCOL_VERSION 10:
TOCLIENT_PRIVILEGES
Version raised to force 'fly' and 'fast' privileges into effect.
+ Node metadata change (came in later; somewhat incompatible)
+ TileDef in ContentFeatures (non-TileDef deserialization is supported)
*/
#define PROTOCOL_VERSION 10
pa_liquid.x0(), pa_liquid.y0()),
};
- // This fixes a strange bug
+ // To get backface culling right, the vertices need to go
+ // clockwise around the front of the face. And we happened to
+ // calculate corner levels in exact reverse order.
s32 corner_resolve[4] = {3,2,1,0};
for(s32 i=0; i<4; i++)
vertices[i].Pos.Y += corner_levels[j];
vertices[i].Pos += intToFloat(p, BS);
}
+
+ // Default downwards-flowing texture animation goes from
+ // -Z towards +Z, thus the direction is +Z.
+ // Rotate texture to make animation go in flow direction
+ // Positive if liquid moves towards +Z
+ int dz = (corner_levels[side_corners[2][0]] +
+ corner_levels[side_corners[2][1]] <
+ corner_levels[side_corners[3][0]] +
+ corner_levels[side_corners[3][1]]);
+ // Positive if liquid moves towards +X
+ int dx = (corner_levels[side_corners[0][0]] +
+ corner_levels[side_corners[0][1]] <
+ corner_levels[side_corners[1][0]] +
+ corner_levels[side_corners[1][1]]);
+ // -X
+ if(-dx >= abs(dz))
+ {
+ v2f t = vertices[0].TCoords;
+ vertices[0].TCoords = vertices[1].TCoords;
+ vertices[1].TCoords = vertices[2].TCoords;
+ vertices[2].TCoords = vertices[3].TCoords;
+ vertices[3].TCoords = t;
+ }
+ // +X
+ if(dx >= abs(dz))
+ {
+ v2f t = vertices[0].TCoords;
+ vertices[0].TCoords = vertices[3].TCoords;
+ vertices[3].TCoords = vertices[2].TCoords;
+ vertices[2].TCoords = vertices[1].TCoords;
+ vertices[1].TCoords = t;
+ }
+ // -Z
+ if(-dz >= abs(dx))
+ {
+ v2f t = vertices[0].TCoords;
+ vertices[0].TCoords = vertices[3].TCoords;
+ vertices[3].TCoords = vertices[2].TCoords;
+ vertices[2].TCoords = vertices[1].TCoords;
+ vertices[1].TCoords = t;
+ t = vertices[0].TCoords;
+ vertices[0].TCoords = vertices[3].TCoords;
+ vertices[3].TCoords = vertices[2].TCoords;
+ vertices[2].TCoords = vertices[1].TCoords;
+ vertices[1].TCoords = t;
+ }
u16 indices[] = {0,1,2,2,3,0};
// Add to mesh collector
infotext = narrow_to_wide(meta->getString("infotext"));
} else {
MapNode n = map.getNode(nodepos);
- if(nodedef->get(n).tname_tiles[0] == "unknown_block.png"){
+ if(nodedef->get(n).tiledef[0].name == "unknown_block.png"){
infotext = L"Unknown node: ";
infotext += narrow_to_wide(nodedef->get(n).name);
}
if(def->inventory_texture == NULL)
{
def->inventory_texture =
- tsrc->getTextureRaw(f.tname_tiles[0]);
+ tsrc->getTextureRaw(f.tiledef[0].name);
}
}
#include "gamedef.h"
#include "mesh.h"
#include "content_mapblock.h"
+#include "noise.h"
/*
MeshMakeData
spec.material_flags |= MATERIAL_FLAG_CRACK;
spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
}
+ // If animated, replace tile texture with one without texture atlas
+ if(spec.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
+ {
+ spec.texture = data->m_gamedef->tsrc()->getTextureRawAP(spec.texture);
+ }
return spec;
}
crack_basename += "^[crack";
m_crack_materials.insert(std::make_pair(i, crack_basename));
}
+ // - Texture animation
+ if(p.tile.material_flags & MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
+ {
+ ITextureSource *tsrc = data->m_gamedef->tsrc();
+ // Add to MapBlockMesh in order to animate these tiles
+ m_animation_tiles[i] = p.tile;
+ m_animation_frames[i] = 0;
+ // Get starting position from noise
+ m_animation_frame_offsets[i] = 100000 * (2.0 + noise3d(
+ data->m_blockpos.X, data->m_blockpos.Y,
+ data->m_blockpos.Z, 0));
+ // Replace tile texture with the first animation frame
+ std::ostringstream os(std::ios::binary);
+ os<<tsrc->getTextureName(p.tile.texture.id);
+ os<<"^[verticalframe:"<<(int)p.tile.animation_frame_count<<":0";
+ p.tile.texture = tsrc->getTexture(os.str());
+ }
// - Lighting
for(u32 j = 0; j < p.vertices.size(); j++)
{
// Check if animation is required for this mesh
m_has_animation =
!m_crack_materials.empty() ||
- !m_daynight_diffs.empty();
+ !m_daynight_diffs.empty() ||
+ !m_animation_tiles.empty();
}
MapBlockMesh::~MapBlockMesh()
m_last_crack = crack;
}
+
+ // Texture animation
+ for(std::map<u32, TileSpec>::iterator
+ i = m_animation_tiles.begin();
+ i != m_animation_tiles.end(); i++)
+ {
+ const TileSpec &tile = i->second;
+ // Figure out current frame
+ int frameoffset = m_animation_frame_offsets[i->first];
+ int frame = (int)(time * 1000 / tile.animation_frame_length_ms
+ + frameoffset) % tile.animation_frame_count;
+ // If frame doesn't change, skip
+ if(frame == m_animation_frames[i->first])
+ continue;
+
+ m_animation_frames[i->first] = frame;
+
+ scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
+ ITextureSource *tsrc = m_gamedef->getTextureSource();
+
+ // Create new texture name from original
+ std::ostringstream os(std::ios::binary);
+ os<<tsrc->getTextureName(tile.texture.id);
+ os<<"^[verticalframe:"<<(int)tile.animation_frame_count<<":"<<frame;
+ // Set the texture
+ AtlasPointer ap = tsrc->getTexture(os.str());
+ buf->getMaterial().setTexture(0, ap.atlas);
+ }
// Day-night transition
if(daynight_ratio != m_last_daynight_ratio)
// Maps mesh buffer (i.e. material) indices to base texture names
std::map<u32, std::string> m_crack_materials;
+ // Animation info: texture animationi
+ // Maps meshbuffers to TileSpecs
+ std::map<u32, TileSpec> m_animation_tiles;
+ std::map<u32, int> m_animation_frames; // last animation frame
+ std::map<u32, int> m_animation_frame_offsets;
+
// Animation info: day/night transitions
// Last daynight_ratio value passed to animate()
u32 m_last_daynight_ratio;
}
/*
- MaterialSpec
+ TileDef
*/
-
-void MaterialSpec::serialize(std::ostream &os) const
+
+void TileDef::serialize(std::ostream &os) const
{
- os<<serializeString(tname);
- writeU8(os, backface_culling);
+ writeU8(os, 0); // version
+ os<<serializeString(name);
+ writeU8(os, animation.type);
+ writeU16(os, animation.aspect_w);
+ writeU16(os, animation.aspect_h);
+ writeF1000(os, animation.length);
}
-void MaterialSpec::deSerialize(std::istream &is)
+void TileDef::deSerialize(std::istream &is)
{
- tname = deSerializeString(is);
- backface_culling = readU8(is);
+ int version = readU8(is);
+ if(version != 0)
+ throw SerializationError("unsupported TileDef version");
+ name = deSerializeString(is);
+ animation.type = (TileAnimationType)readU8(is);
+ animation.aspect_w = readU16(is);
+ animation.aspect_h = readU16(is);
+ animation.length = readF1000(is);
}
/*
drawtype = NDT_NORMAL;
visual_scale = 1.0;
for(u32 i=0; i<6; i++)
- tname_tiles[i] = "";
+ tiledef[i] = TileDef();
for(u16 j=0; j<CF_SPECIAL_COUNT; j++)
- mspec_special[j] = MaterialSpec();
+ tiledef_special[j] = TileDef();
alpha = 255;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
void ContentFeatures::serialize(std::ostream &os)
{
- writeU8(os, 3); // version
+ writeU8(os, 4); // version
os<<serializeString(name);
writeU16(os, groups.size());
for(ItemGroupList::const_iterator
writeF1000(os, visual_scale);
writeU8(os, 6);
for(u32 i=0; i<6; i++)
- os<<serializeString(tname_tiles[i]);
+ tiledef[i].serialize(os);
writeU8(os, CF_SPECIAL_COUNT);
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
- mspec_special[i].serialize(os);
+ tiledef_special[i].serialize(os);
}
writeU8(os, alpha);
writeU8(os, post_effect_color.getAlpha());
void ContentFeatures::deSerialize(std::istream &is)
{
int version = readU8(is);
- if(version != 3)
+ if(version != 4 && version != 3)
throw SerializationError("unsupported ContentFeatures version");
name = deSerializeString(is);
groups.clear();
visual_scale = readF1000(is);
if(readU8(is) != 6)
throw SerializationError("unsupported tile count");
- for(u32 i=0; i<6; i++)
- tname_tiles[i] = deSerializeString(is);
+ for(u32 i=0; i<6; i++){
+ if(version == 4)
+ tiledef[i].deSerialize(is);
+ else if(version == 3) // Allow connecting to older servers
+ tiledef[i].name = deSerializeString(is);
+ }
if(readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for(u32 i=0; i<CF_SPECIAL_COUNT; i++){
- mspec_special[i].deSerialize(is);
+ if(version == 4){
+ tiledef_special[i].deSerialize(is);
+ } else if(version == 3){ // Allow connecting to older servers
+ tiledef_special[i].name = deSerializeString(is);
+ tiledef_special[i].backface_culling = readU8(is);
+ }
}
alpha = readU8(is);
post_effect_color.setAlpha(readU8(is));
selection_box.deSerialize(is);
legacy_facedir_simple = readU8(is);
legacy_wallmounted = readU8(is);
+ deSerializeSimpleSoundSpec(sound_footstep, is);
+ deSerializeSimpleSoundSpec(sound_dig, is);
+ deSerializeSimpleSoundSpec(sound_dug, is);
// If you add anything here, insert it primarily inside the try-catch
// block to not need to increase the version.
try{
- deSerializeSimpleSoundSpec(sound_footstep, is);
- deSerializeSimpleSoundSpec(sound_dig, is);
- deSerializeSimpleSoundSpec(sound_dug, is);
}catch(SerializationError &e) {};
}
for(u16 i=0; i<=MAX_CONTENT; i++)
{
ContentFeatures *f = &m_content_features[i];
-
- std::string tname_tiles[6];
+
+ // Figure out the actual tiles to use
+ TileDef tiledef[6];
for(u32 j=0; j<6; j++)
{
- tname_tiles[j] = f->tname_tiles[j];
- if(tname_tiles[j] == "")
- tname_tiles[j] = "unknown_block.png";
- }
+ tiledef[j] = f->tiledef[j];
+ if(tiledef[j].name == "")
+ tiledef[j].name = "unknown_block.png";
+ }
switch(f->drawtype){
default:
f->drawtype = NDT_NORMAL;
f->solidness = 2;
for(u32 i=0; i<6; i++){
- tname_tiles[i] += std::string("^[noalpha");
+ tiledef[i].name += std::string("^[noalpha");
}
}
break;
break;
}
- // Tile textures
+ // Tiles (fill in f->tiles[])
for(u16 j=0; j<6; j++){
- f->tiles[j].texture = tsrc->getTexture(tname_tiles[j]);
+ // Texture
+ f->tiles[j].texture = tsrc->getTexture(tiledef[j].name);
+ // Alpha
f->tiles[j].alpha = f->alpha;
if(f->alpha == 255)
f->tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
else
f->tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
+ // Material flags
f->tiles[j].material_flags = 0;
if(f->backface_culling)
f->tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+ if(tiledef[j].animation.type == TAT_VERTICAL_FRAMES)
+ f->tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ // Animation parameters
+ if(f->tiles[j].material_flags &
+ MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
+ {
+ // Get raw texture size to determine frame count by
+ // aspect ratio
+ video::ITexture *t = tsrc->getTextureRaw(tiledef[j].name);
+ v2u32 size = t->getOriginalSize();
+ int frame_height = (float)size.X /
+ (float)tiledef[j].animation.aspect_w *
+ (float)tiledef[j].animation.aspect_h;
+ int frame_count = size.Y / frame_height;
+ int frame_length_ms = 1000.0 *
+ tiledef[j].animation.length / frame_count;
+ f->tiles[j].animation_frame_count = frame_count;
+ f->tiles[j].animation_frame_length_ms = frame_length_ms;
+
+ // If there are no frames for an animation, switch
+ // animation off (so that having specified an animation
+ // for something but not using it in the texture pack
+ // gives no overhead)
+ if(frame_count == 1){
+ f->tiles[j].material_flags &=
+ ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ }
+ }
}
- // Special tiles
+ // Special tiles (fill in f->special_tiles[])
for(u16 j=0; j<CF_SPECIAL_COUNT; j++){
- f->special_tiles[j].texture = tsrc->getTexture(f->mspec_special[j].tname);
+ // Texture
+ f->special_tiles[j].texture =
+ tsrc->getTexture(f->tiledef_special[j].name);
+ // Alpha
f->special_tiles[j].alpha = f->alpha;
if(f->alpha == 255)
f->special_tiles[j].material_type = MATERIAL_ALPHA_SIMPLE;
else
f->special_tiles[j].material_type = MATERIAL_ALPHA_VERTEX;
+ // Material flags
f->special_tiles[j].material_flags = 0;
- if(f->mspec_special[j].backface_culling)
+ if(f->tiledef_special[j].backface_culling)
f->special_tiles[j].material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+ if(f->tiledef_special[j].animation.type == TAT_VERTICAL_FRAMES)
+ f->special_tiles[j].material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ // Animation parameters
+ if(f->special_tiles[j].material_flags &
+ MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES)
+ {
+ // Get raw texture size to determine frame count by
+ // aspect ratio
+ video::ITexture *t = tsrc->getTextureRaw(f->tiledef_special[j].name);
+ v2u32 size = t->getOriginalSize();
+ int frame_height = (float)size.X /
+ (float)f->tiledef_special[j].animation.aspect_w *
+ (float)f->tiledef_special[j].animation.aspect_h;
+ int frame_count = size.Y / frame_height;
+ int frame_length_ms = 1000.0 *
+ f->tiledef_special[j].animation.length / frame_count;
+ f->special_tiles[j].animation_frame_count = frame_count;
+ f->special_tiles[j].animation_frame_length_ms = frame_length_ms;
+
+ // If there are no frames for an animation, switch
+ // animation off (so that having specified an animation
+ // for something but not using it in the texture pack
+ // gives no overhead)
+ if(frame_count == 1){
+ f->special_tiles[j].material_flags &=
+ ~MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
+ }
+ }
}
}
#endif
struct MapNode;
class NodeMetadata;
-struct MaterialSpec
+/*
+ Stand-alone definition of a TileSpec (basically a server-side TileSpec)
+*/
+enum TileAnimationType{
+ TAT_NONE=0,
+ TAT_VERTICAL_FRAMES=1,
+};
+struct TileDef
{
- std::string tname;
- bool backface_culling;
-
- MaterialSpec(const std::string &tname_="", bool backface_culling_=true):
- tname(tname_),
- backface_culling(backface_culling_)
- {}
+ std::string name;
+ bool backface_culling; // Takes effect only in special cases
+ struct{
+ enum TileAnimationType type;
+ int aspect_w; // width for aspect ratio
+ int aspect_h; // height for aspect ratio
+ float length; // seconds
+ } animation;
+
+ TileDef()
+ {
+ name = "";
+ backface_culling = true;
+ animation.type = TAT_NONE;
+ animation.aspect_w = 1;
+ animation.aspect_h = 1;
+ animation.length = 1.0;
+ }
void serialize(std::ostream &os) const;
void deSerialize(std::istream &is);
// Visual definition
enum NodeDrawType drawtype;
float visual_scale; // Misc. scale parameter
- std::string tname_tiles[6];
- MaterialSpec mspec_special[CF_SPECIAL_COUNT]; // Use setter methods
+ TileDef tiledef[6];
+ TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid
u8 alpha;
// Post effect color, drawn when the camera is inside the node.
{0, NULL},
};
+struct EnumString es_TileAnimationType[] =
+{
+ {TAT_NONE, "none"},
+ {TAT_VERTICAL_FRAMES, "vertical_frames"},
+ {0, NULL},
+};
+
/*
C struct <-> Lua table converter functions
*/
return def;
}
+/*
+ TileDef
+*/
+
+static TileDef read_tiledef(lua_State *L, int index)
+{
+ if(index < 0)
+ index = lua_gettop(L) + 1 + index;
+
+ TileDef tiledef;
+
+ // key at index -2 and value at index
+ if(lua_isstring(L, index)){
+ // "default_lava.png"
+ tiledef.name = lua_tostring(L, index);
+ }
+ else if(lua_istable(L, index))
+ {
+ // {name="default_lava.png", animation={}}
+ tiledef.name = "";
+ getstringfield(L, index, "name", tiledef.name);
+ getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat.
+ tiledef.backface_culling = getboolfield_default(
+ L, index, "backface_culling", true);
+ // animation = {}
+ lua_getfield(L, index, "animation");
+ if(lua_istable(L, -1)){
+ // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
+ tiledef.animation.type = (TileAnimationType)
+ getenumfield(L, -1, "type", es_TileAnimationType,
+ TAT_NONE);
+ tiledef.animation.aspect_w =
+ getintfield_default(L, -1, "aspect_w", 16);
+ tiledef.animation.aspect_h =
+ getintfield_default(L, -1, "aspect_h", 16);
+ tiledef.animation.length =
+ getfloatfield_default(L, -1, "length", 1.0);
+ }
+ lua_pop(L, 1);
+ }
+
+ return tiledef;
+}
+
/*
ContentFeatures
*/
f.drawtype = (NodeDrawType)getenumfield(L, index, "drawtype", es_DrawType,
NDT_NORMAL);
getfloatfield(L, index, "visual_scale", f.visual_scale);
-
- lua_getfield(L, index, "tile_images");
+
+ // tiles = {}
+ lua_getfield(L, index, "tiles");
+ // If nil, try the deprecated name "tile_images" instead
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ warn_if_field_exists(L, index, "tile_images",
+ "Deprecated; new name is \"tiles\".");
+ lua_getfield(L, index, "tile_images");
+ }
if(lua_istable(L, -1)){
int table = lua_gettop(L);
lua_pushnil(L);
int i = 0;
while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- if(lua_isstring(L, -1))
- f.tname_tiles[i] = lua_tostring(L, -1);
- else
- f.tname_tiles[i] = "";
+ // Read tiledef from value
+ f.tiledef[i] = read_tiledef(L, -1);
// removes value, keeps key for next iteration
lua_pop(L, 1);
i++;
}
// Copy last value to all remaining textures
if(i >= 1){
- std::string lastname = f.tname_tiles[i-1];
+ TileDef lasttile = f.tiledef[i-1];
while(i < 6){
- f.tname_tiles[i] = lastname;
+ f.tiledef[i] = lasttile;
i++;
}
}
}
lua_pop(L, 1);
-
- lua_getfield(L, index, "special_materials");
+
+ // special_tiles = {}
+ lua_getfield(L, index, "special_tiles");
+ // If nil, try the deprecated name "special_materials" instead
+ if(lua_isnil(L, -1)){
+ lua_pop(L, 1);
+ warn_if_field_exists(L, index, "special_materials",
+ "Deprecated; new name is \"special_tiles\".");
+ lua_getfield(L, index, "special_materials");
+ }
if(lua_istable(L, -1)){
int table = lua_gettop(L);
lua_pushnil(L);
int i = 0;
while(lua_next(L, table) != 0){
- // key at index -2 and value at index -1
- int smtable = lua_gettop(L);
- std::string tname = getstringfield_default(
- L, smtable, "image", "");
- bool backface_culling = getboolfield_default(
- L, smtable, "backface_culling", true);
- MaterialSpec mspec(tname, backface_culling);
- f.mspec_special[i] = mspec;
+ // Read tiledef from value
+ f.tiledef_special[i] = read_tiledef(L, -1);
// removes value, keeps key for next iteration
lua_pop(L, 1);
i++;
f = ContentFeatures();
f.name = itemdef.name;
for(int i = 0; i < 6; i++)
- f.tname_tiles[i] = "default_stone.png";
+ f.tiledef[i].name = "default_stone.png";
f.is_ground_content = true;
idef->registerItem(itemdef);
ndef->set(i, f);
"{default_dirt.png&default_grass_side.png";
f = ContentFeatures();
f.name = itemdef.name;
- f.tname_tiles[0] = "default_grass.png";
- f.tname_tiles[1] = "default_dirt.png";
+ f.tiledef[0].name = "default_grass.png";
+ f.tiledef[1].name = "default_dirt.png";
for(int i = 2; i < 6; i++)
- f.tname_tiles[i] = "default_dirt.png^default_grass_side.png";
+ f.tiledef[i].name = "default_dirt.png^default_grass_side.png";
f.is_ground_content = true;
idef->registerItem(itemdef);
ndef->set(i, f);
const ContentFeatures &f = ndef->get(j);
for(u32 i=0; i<6; i++)
{
- std::string name = f.tname_tiles[i];
+ std::string name = f.tiledef[i].name;
sourcelist[name] = true;
}
}
src_x = pos_in_atlas.X;
}
s32 y = y0 + pos_in_atlas.Y;
- s32 src_y = MYMAX(pos_in_atlas.Y, MYMIN(pos_in_atlas.Y + dim.Height - 1, y));
+ s32 src_y = MYMAX((int)pos_in_atlas.Y, MYMIN((int)pos_in_atlas.Y + (int)dim.Height - 1, y));
s32 dst_y = y;
video::SColor c = atlas_img->getPixel(src_x, src_y);
atlas_img->setPixel(dst_x,dst_y,c);
img2->drop();
}
}
+ /*
+ [verticalframe:N:I
+ Crops a frame of a vertical animation.
+ N = frame count, I = frame index
+ */
+ else if(part_of_name.substr(0,15) == "[verticalframe:")
+ {
+ Strfnd sf(part_of_name);
+ sf.next(":");
+ u32 frame_count = stoi(sf.next(":"));
+ u32 frame_index = stoi(sf.next(":"));
+
+ if(baseimg == NULL){
+ errorstream<<"generate_image(): baseimg!=NULL "
+ <<"for part_of_name=\""<<part_of_name
+ <<"\", cancelling."<<std::endl;
+ return false;
+ }
+
+ v2u32 frame_size = baseimg->getDimension();
+ frame_size.Y /= frame_count;
+
+ video::IImage *img = driver->createImage(video::ECF_A8R8G8B8,
+ frame_size);
+ if(!img){
+ errorstream<<"generate_image(): Could not create image "
+ <<"for part_of_name=\""<<part_of_name
+ <<"\", cancelling."<<std::endl;
+ return false;
+ }
+
+ core::dimension2d<u32> dim = frame_size;
+ core::position2d<s32> pos_dst(0, 0);
+ core::position2d<s32> pos_src(0, frame_index * frame_size.Y);
+ baseimg->copyToWithAlpha(img, pos_dst,
+ core::rect<s32>(pos_src, dim),
+ video::SColor(255,255,255,255),
+ NULL);
+ // Replace baseimg
+ baseimg->drop();
+ baseimg = img;
+ }
else
{
errorstream<<"generate_image(): Invalid "
// Should the crack be drawn on transparent pixels (unset) or not (set)?
// Ignored if MATERIAL_FLAG_CRACK is not set.
#define MATERIAL_FLAG_CRACK_OVERLAY 0x04
+// Animation made up by splitting the texture to vertical frames, as
+// defined by extra parameters
+#define MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES 0x08
/*
This fully defines the looks of a tile.
material_flags(
//0 // <- DEBUG, Use the one below
MATERIAL_FLAG_BACKFACE_CULLING
- )
+ ),
+ animation_frame_count(1),
+ animation_frame_length_ms(0)
{
}
AtlasPointer texture;
// Vertex alpha
u8 alpha;
- // Material type
+ // Material parameters
u8 material_type;
- // Material flags
u8 material_flags;
+ // Animation parameters
+ u8 animation_frame_count;
+ u16 animation_frame_length_ms;
};
#endif