From a07b032245bef76a7695e139a9daca7cb646a73d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 23 Dec 2016 14:43:56 +0100 Subject: [PATCH] Add 2D sheet animation for nodes --- doc/lua_api.txt | 21 ++++++- games/minimal/mods/default/init.lua | 7 ++- .../textures/default_lava_source_animated.png | Bin 2902 -> 3145 bytes src/nodedef.cpp | 2 +- src/particles.cpp | 2 +- src/script/common/c_content.cpp | 25 ++++++--- src/tileanimation.cpp | 52 +++++++++++++----- src/tileanimation.h | 6 ++ 8 files changed, 88 insertions(+), 27 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 648a29303..6166826af 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3702,7 +3702,26 @@ Definition tables * `image` (name) ### Tile animation definition -* `{type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}` + + { + type = "vertical_frames", + aspect_w = 16, + -- ^ specify width of a frame in pixels + aspect_h = 16, + -- ^ specify height of a frame in pixels + length = 3.0, + -- ^ specify full loop length + } + + { + type = "sheet_2d", + frames_w = 5, + -- ^ specify width in number of frames + frames_h = 3, + -- ^ specify height in number of frames + frame_length = 0.5, + -- ^ specify length of a single frame + } ### Node definition (`register_node`) diff --git a/games/minimal/mods/default/init.lua b/games/minimal/mods/default/init.lua index f532e7193..2f73b53ef 100644 --- a/games/minimal/mods/default/init.lua +++ b/games/minimal/mods/default/init.lua @@ -1044,8 +1044,11 @@ minetest.register_node("default:lava_source", { inventory_image = minetest.inventorycube("default_lava.png"), drawtype = "liquid", --tiles ={"default_lava.png"}, - tiles ={ - {name="default_lava_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}} + tiles = { + { + name = "default_lava_source_animated.png", + animation = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5} + } }, special_tiles = { -- New-style lava source material (mostly unused) diff --git a/games/minimal/mods/default/textures/default_lava_source_animated.png b/games/minimal/mods/default/textures/default_lava_source_animated.png index aa9d57cf17d0be0dddfbb0cfe0aae10e362dac94..54f4c0ddda45bcc1bcf5b9c2aed872c64b3328f7 100644 GIT binary patch literal 3145 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 AlmGw# diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 21bceb94d..92cdf738e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -528,7 +528,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, tile->material_flags = 0; if (backface_culling) tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING; - if (tiledef->animation.type == TAT_VERTICAL_FRAMES) + if (tiledef->animation.type != TAT_NONE) tile->material_flags |= MATERIAL_FLAG_ANIMATION; if (tiledef->tileable_horizontal) tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL; diff --git a/src/particles.cpp b/src/particles.cpp index e9ddba986..97f42e2c4 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -570,7 +570,7 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s video::ITexture *texture; // Only use first frame of animated texture - if(tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) + if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) texture = tiles[texid].frames[0].texture; else texture = tiles[texid].texture; diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 6cd1d040b..b9bcfef69 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -39,6 +39,7 @@ struct EnumString es_TileAnimationType[] = { {TAT_NONE, "none"}, {TAT_VERTICAL_FRAMES, "vertical_frames"}, + {TAT_SHEET_2D, "sheet_2d"}, {0, NULL}, }; @@ -334,16 +335,26 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) // 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.vertical_frames.aspect_w = - getintfield_default(L, -1, "aspect_w", 16); - tiledef.animation.vertical_frames.aspect_h = - getintfield_default(L, -1, "aspect_h", 16); - tiledef.animation.vertical_frames.length = - getfloatfield_default(L, -1, "length", 1.0); + if (tiledef.animation.type == TAT_VERTICAL_FRAMES) { + // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} + tiledef.animation.vertical_frames.aspect_w = + getintfield_default(L, -1, "aspect_w", 16); + tiledef.animation.vertical_frames.aspect_h = + getintfield_default(L, -1, "aspect_h", 16); + tiledef.animation.vertical_frames.length = + getfloatfield_default(L, -1, "length", 1.0); + } else if (tiledef.animation.type == TAT_SHEET_2D) { + // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} + getintfield(L, -1, "frames_w", + tiledef.animation.sheet_2d.frames_w); + getintfield(L, -1, "frames_h", + tiledef.animation.sheet_2d.frames_h); + getfloatfield(L, -1, "frame_length", + tiledef.animation.sheet_2d.frame_length); + } } lua_pop(L, 1); } diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp index 891478c9f..a23eecc2e 100644 --- a/src/tileanimation.cpp +++ b/src/tileanimation.cpp @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) const { - if(protocol_version < 29 /* TODO bump */) { + if (protocol_version < 29) { if (type == TAT_VERTICAL_FRAMES) { writeU8(os, type); writeU16(os, vertical_frames.aspect_w); @@ -41,47 +41,69 @@ void TileAnimationParams::serialize(std::ostream &os, u16 protocol_version) cons writeU16(os, vertical_frames.aspect_w); writeU16(os, vertical_frames.aspect_h); writeF1000(os, vertical_frames.length); + } else if (type == TAT_SHEET_2D) { + writeU8(os, sheet_2d.frames_w); + writeU8(os, sheet_2d.frames_h); + writeF1000(os, sheet_2d.frame_length); } } void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version) { type = (TileAnimationType) readU8(is); - if(protocol_version < 29 /* TODO bump */) { + if (protocol_version < 29) { vertical_frames.aspect_w = readU16(is); vertical_frames.aspect_h = readU16(is); vertical_frames.length = readF1000(is); return; } - if(type == TAT_VERTICAL_FRAMES) { + if (type == TAT_VERTICAL_FRAMES) { vertical_frames.aspect_w = readU16(is); vertical_frames.aspect_h = readU16(is); vertical_frames.length = readF1000(is); + } else if (type == TAT_SHEET_2D) { + sheet_2d.frames_w = readU8(is); + sheet_2d.frames_h = readU8(is); + sheet_2d.frame_length = readF1000(is); } } void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const { - if (type == TAT_NONE) { + if (type == TAT_VERTICAL_FRAMES) { + int frame_height = (float)texture_size.X / + (float)vertical_frames.aspect_w * + (float)vertical_frames.aspect_h; + int _frame_count = texture_size.Y / frame_height; + if (frame_count) + *frame_count = _frame_count; + if (frame_length_ms) + *frame_length_ms = 1000.0 * vertical_frames.length / _frame_count; + } else if (type == TAT_SHEET_2D) { + if (frame_count) + *frame_count = sheet_2d.frames_w * sheet_2d.frames_h; + if (frame_length_ms) + *frame_length_ms = 1000 * sheet_2d.frame_length; + } else { // TAT_NONE *frame_count = 1; *frame_length_ms = 1000; - return; } - int frame_height = (float)texture_size.X / - (float)vertical_frames.aspect_w * - (float)vertical_frames.aspect_h; - if (frame_count) - *frame_count = texture_size.Y / frame_height; - if (frame_length_ms) - *frame_length_ms = 1000.0 * vertical_frames.length / (texture_size.Y / frame_height); } void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const { if (type == TAT_NONE) return; - int frame_count; - determineParams(texture_size, &frame_count, NULL); - os << "^[verticalframe:" << frame_count << ":" << frame; + if (type == TAT_VERTICAL_FRAMES) { + int frame_count; + determineParams(texture_size, &frame_count, NULL); + os << "^[verticalframe:" << frame_count << ":" << frame; + } else if (type == TAT_SHEET_2D) { + int q, r; + q = frame / sheet_2d.frames_w; + r = frame % sheet_2d.frames_w; + os << "^[sheet:" << sheet_2d.frames_w << "x" << sheet_2d.frames_h + << ":" << r << "," << q; + } } diff --git a/src/tileanimation.h b/src/tileanimation.h index d5172ed50..289ce515b 100644 --- a/src/tileanimation.h +++ b/src/tileanimation.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., enum TileAnimationType { TAT_NONE = 0, TAT_VERTICAL_FRAMES = 1, + TAT_SHEET_2D = 2, }; struct TileAnimationParams { @@ -38,6 +39,11 @@ struct TileAnimationParams { int aspect_h; // height for aspect ratio float length; // seconds } vertical_frames; + struct { + int frames_w; // number of frames left-to-right + int frames_h; // number of frames top-to-bottom + float frame_length; // seconds + } sheet_2d; }; void serialize(std::ostream &os, u16 protocol_version) const;