Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add animated_image[] formspec element (#9258)
  • Loading branch information
Df458 committed Feb 15, 2020
1 parent ee7d357 commit 7ce2178
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 4 deletions.
1 change: 1 addition & 0 deletions build/android/jni/Android.mk
Expand Up @@ -178,6 +178,7 @@ LOCAL_SRC_FILES := \
jni/src/filesys.cpp \
jni/src/genericobject.cpp \
jni/src/gettext.cpp \
jni/src/gui/guiAnimatedImage.cpp \
jni/src/gui/guiBackgroundImage.cpp \
jni/src/gui/guiBox.cpp \
jni/src/gui/guiButton.cpp \
Expand Down
11 changes: 11 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -2133,6 +2133,15 @@ Elements

* Show an image

### `animated_image[<X>,<Y>;<W>,<H>;<texture name>:<frame count>,<frame duration>]`

* Show an animated image. The image is drawn like a "vertical_frames" tile
animation (See Tile animation definition), but uses a frame count/duration
for simplicity
* `<texture name>` is the image to use
* `<frame count>` is the number of frames animating the image
* `<frame duration>` is in milliseconds

### `item_image[<X>,<Y>;<W>,<H>;<item name>]`

* Show an inventory image of registered item/node
Expand Down Expand Up @@ -2580,6 +2589,8 @@ Some types may inherit styles from parent types.

### Valid Properties

* animated_image
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* box
* noclip - boolean, set to true to allow the element to exceed formspec bounds.
* Default to false in formspec_version version 3 or higher
Expand Down
20 changes: 16 additions & 4 deletions games/minimal/mods/test/formspec.lua
Expand Up @@ -12,6 +12,7 @@ local clip_fs = [[
style_type[dropdown;noclip=%c]
style_type[scrollbar;noclip=%c]
style_type[table;noclip=%c]
style_type[animated_image;noclip=%c]
label[0,0;A clipping test]
button[0,1;3,0.8;x;A clipping test]
Expand All @@ -25,6 +26,7 @@ local clip_fs = [[
scrollbar[0,9;3,0.8;horizontal;x9;3]
tablecolumns[text;text]
table[0,10;3,1;x10;one,two,three,four;1]
animated_image[0,11;3,1;test_animation.png:4,100]
]]


Expand Down Expand Up @@ -119,8 +121,8 @@ local style_fs = [[

local pages = {
[[
formspec_version[3]
size[12,12]
real_coordinates[true]
image_button[0,0;1,1;logo.png;;1x1]
image_button[1,0;2,2;logo.png;;2x2]
button[0,2;1,1;;1x1]
Expand Down Expand Up @@ -157,7 +159,7 @@ local pages = {
tabheader[6.5,0;6,0.65;name;Tab 1,Tab 2,Tab 3,Secrets;1;false;false]
]],

"size[12,12]real_coordinates[true]" ..
"formspec_version[3]size[12,12]" ..
("label[0.375,0.375;Styled - %s %s]"):format(
color("#F00", "red text"),
color("#77FF00CC", "green text")) ..
Expand All @@ -170,17 +172,27 @@ local pages = {
style_fs:gsub("one_", "two_"):gsub("style%[[^%]]+%]", ""):gsub("style_type%[[^%]]+%]", "") ..
"container_end[]",

"size[12,12]real_coordinates[true]" ..
"formspec_version[3]size[12,13]" ..
"label[0.1,0.5;Clip]" ..
"container[-2.5,1]" .. clip_fs:gsub("%%c", "false") .. "container_end[]" ..
"label[11,0.5;Noclip]" ..
"container[11.5,1]" .. clip_fs:gsub("%%c", "true") .. "container_end[]",

[[
formspec_version[3]
size[12,12]
animated_image[0.5,0.5;1,1;test_animation.png:4,100]
animated_image[1.75,0.5;1,1;test_animation.png:100,100]
animated_image[0.5,1.75;1,1;test_animation.jpg:4,100]
animated_image[3,0.5;5,2;test_animation.png:4,100]
animated_image[3,2.75;5,2;test_animation.jpg:4,100]
]]
}

local function show_test_formspec(pname, page_id)
page_id = page_id or 2

local fs = pages[page_id] .. "tabheader[0,0;6,0.65;maintabs;Real Coord,Styles,Noclip;" .. page_id .. ";false;false]"
local fs = pages[page_id] .. "tabheader[0,0;6,0.65;maintabs;Real Coord,Styles,Noclip,MiscEle;" .. page_id .. ";false;false]"

minetest.show_formspec(pname, "test:formspec", fs)
end
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/gui/CMakeLists.txt
@@ -1,4 +1,5 @@
set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiAnimatedImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiBackgroundImage.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiBox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiButton.cpp
Expand Down
83 changes: 83 additions & 0 deletions src/gui/guiAnimatedImage.cpp
@@ -0,0 +1,83 @@
#include "guiAnimatedImage.h"

#include "client/guiscalingfilter.h"
#include "client/tile.h" // ITextureSource
#include "log.h"
#include "porting.h"
#include <string>

GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
s32 id, const core::rect<s32> &rectangle, const std::string &name,
ISimpleTextureSource *tsrc) :
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
m_name(name), m_tsrc(tsrc), m_texture(nullptr), m_global_time(0),
m_frame_idx(0), m_frame_count(1), m_frame_duration(1), m_frame_time(0)
{
// Expected format: "texture_name:frame_count,frame_duration"
// If this format is not met, the string will be loaded as a normal texture

std::string::size_type colon_position = name.find(':', 0);
std::string::size_type comma_position = name.find(',', 0);

if (comma_position != std::string::npos &&
colon_position != std::string::npos &&
comma_position < name.size()) {
m_texture = m_tsrc->getTexture(name.substr(0, colon_position));

m_frame_count = std::max(stoi(name.substr(
colon_position + 1, comma_position - colon_position - 1)), 1);

m_frame_duration = std::max(stoi(name.substr(comma_position + 1)), 1);
} else {
// Leave the count/duration and display a static image
m_texture = m_tsrc->getTexture(name);
errorstream << "animated_image[]: Invalid texture format " << name <<
". Expected format: texture_name:frame_count,frame_duration" << std::endl;
}

if (m_texture != nullptr) {
core::dimension2d<u32> size = m_texture->getOriginalSize();
if (size.Height < (u64)m_frame_count) {
m_frame_count = size.Height;
}
} else {
// No need to step an animation if we have nothing to draw
m_frame_count = 1;
}
}

void GUIAnimatedImage::draw()
{
// Render the current frame
if (m_texture != nullptr) {
video::IVideoDriver *driver = Environment->getVideoDriver();

const video::SColor color(255, 255, 255, 255);
const video::SColor colors[] = {color, color, color, color};

core::dimension2d<u32> size = m_texture->getOriginalSize();
size.Height /= m_frame_count;

draw2DImageFilterScaled( driver, m_texture, AbsoluteRect,
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
}

// Step the animation
if (m_frame_count > 1) {
// Determine the delta time to step
u64 new_global_time = porting::getTimeMs();
if (m_global_time > 0)
m_frame_time += new_global_time - m_global_time;

m_global_time = new_global_time;

// Advance by the number of elapsed frames, looping if necessary
m_frame_idx += u32(m_frame_time / m_frame_duration);
m_frame_idx %= m_frame_count;

// If 1 or more frames have elapsed, reset the frame time counter with
// the remainder
m_frame_time %= m_frame_duration;
}
}
26 changes: 26 additions & 0 deletions src/gui/guiAnimatedImage.h
@@ -0,0 +1,26 @@
#pragma once

#include "irrlichttypes_extrabloated.h"
#include "util/string.h"

class ISimpleTextureSource;

class GUIAnimatedImage : public gui::IGUIElement {
public:
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, const std::string &name,
ISimpleTextureSource *tsrc);

virtual void draw() override;

private:
std::string m_name;
ISimpleTextureSource *m_tsrc;

video::ITexture *m_texture;
u64 m_global_time;
s32 m_frame_idx;
s32 m_frame_count;
u64 m_frame_duration;
u64 m_frame_time;
};
58 changes: 58 additions & 0 deletions src/gui/guiFormSpecMenu.cpp
Expand Up @@ -55,6 +55,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" // for parseColorString()
#include "irrlicht_changes/static_text.h"
#include "client/guiscalingfilter.h"
#include "guiAnimatedImage.h"
#include "guiBackgroundImage.h"
#include "guiBox.h"
#include "guiButton.h"
Expand Down Expand Up @@ -779,6 +780,58 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
errorstream<< "Invalid image element(" << parts.size() << "): '" << element << "'" << std::endl;
}

void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ';');

if (parts.size() != 3 &&
!(parts.size() > 3 && m_formspec_version > FORMSPEC_API_VERSION)) {
errorstream << "Invalid animated image element(" << parts.size()
<< "): '" << element << "'" << std::endl;
return;
}

std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
std::string name = unescape_string(parts[2]);

MY_CHECKPOS("animated_image", 0);
MY_CHECKGEOM("animated_image", 1);

v2s32 pos;
v2s32 geom;

if (data->real_coordinates) {
pos = getRealCoordinateBasePos(v_pos);
geom = getRealCoordinateGeometry(v_geom);
} else {
pos = getElementBasePos(&v_pos);
geom.X = stof(v_geom[0]) * (float)imgsize.X;
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
}

if (!data->explicit_size)
warningstream << "invalid use of animated_image without a size[] element" << std::endl;

FieldSpec spec(
"",
L"",
L"",
258 + m_fields.size()
);

core::rect<s32> rect = core::rect<s32>(pos, pos + geom);

gui::IGUIElement *e = new GUIAnimatedImage(Environment, this, spec.fid,
rect, name, m_tsrc);

auto style = getStyleForElement("animated_image", spec.fname);
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
e->drop();

m_fields.push_back(spec);
}

void GUIFormSpecMenu::parseItemImage(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
Expand Down Expand Up @@ -2500,6 +2553,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
return;
}

if (type == "animated_image") {
parseAnimatedImage(data, description);
return;
}

if (type == "item_image") {
parseItemImage(data, description);
return;
Expand Down
2 changes: 2 additions & 0 deletions src/gui/guiFormSpecMenu.h
Expand Up @@ -38,6 +38,7 @@ class InventoryManager;
class ISimpleTextureSource;
class Client;
class GUIScrollBar;
class TexturePool;

typedef enum {
f_Button,
Expand Down Expand Up @@ -388,6 +389,7 @@ class GUIFormSpecMenu : public GUIModalMenu
void parseListRing(parserData* data, const std::string &element);
void parseCheckbox(parserData* data, const std::string &element);
void parseImage(parserData* data, const std::string &element);
void parseAnimatedImage(parserData *data, const std::string &element);
void parseItemImage(parserData* data, const std::string &element);
void parseButton(parserData* data, const std::string &element,
const std::string &typ);
Expand Down
2 changes: 2 additions & 0 deletions util/travis/clang-format-whitelist.txt
Expand Up @@ -155,6 +155,8 @@ src/genericobject.cpp
src/genericobject.h
src/gettext.cpp
src/gettext.h
src/gui/guiAnimatedImage.cpp
src/gui/guiAnimatedImage.h
src/gui/guiBackgroundImage.cpp
src/gui/guiBackgroundImage.h
src/gui/guiBox.cpp
Expand Down

0 comments on commit 7ce2178

Please sign in to comment.