Skip to content

Commit 13ad8e2

Browse files
authoredMar 16, 2020
Formspecs: Add starting frame to animated_image (#9411)
1 parent 1441281 commit 13ad8e2

8 files changed

+115
-92
lines changed
 

‎doc/lua_api.txt

+13-9
Original file line numberDiff line numberDiff line change
@@ -2120,27 +2120,29 @@ Elements
21202120
### `tooltip[<gui_element_name>;<tooltip_text>;<bgcolor>;<fontcolor>]`
21212121

21222122
* Adds tooltip for an element
2123-
* `<bgcolor>` tooltip background color as `ColorString` (optional)
2124-
* `<fontcolor>` tooltip font color as `ColorString` (optional)
2123+
* `bgcolor` tooltip background color as `ColorString` (optional)
2124+
* `fontcolor` tooltip font color as `ColorString` (optional)
21252125

21262126
### `tooltip[<X>,<Y>;<W>,<H>;<tooltip_text>;<bgcolor>;<fontcolor>]`
21272127

21282128
* Adds tooltip for an area. Other tooltips will take priority when present.
2129-
* `<bgcolor>` tooltip background color as `ColorString` (optional)
2130-
* `<fontcolor>` tooltip font color as `ColorString` (optional)
2129+
* `bgcolor` tooltip background color as `ColorString` (optional)
2130+
* `fontcolor` tooltip font color as `ColorString` (optional)
21312131

21322132
### `image[<X>,<Y>;<W>,<H>;<texture name>]`
21332133

21342134
* Show an image
21352135

2136-
### `animated_image[<X>,<Y>;<W>,<H>;<texture name>:<frame count>,<frame duration>]`
2136+
### `animated_image[<X>,<Y>;<W>,<H>;<name>;<texture name>;<frame count>;<frame duration>;<frame start>]`
21372137

21382138
* Show an animated image. The image is drawn like a "vertical_frames" tile
2139-
animation (See Tile animation definition), but uses a frame count/duration
2139+
animation (See [Tile animation definition]), but uses a frame count/duration
21402140
for simplicity
2141-
* `<texture name>` is the image to use
2142-
* `<frame count>` is the number of frames animating the image
2143-
* `<frame duration>` is in milliseconds
2141+
* `name`: Element name to send when an event occurs. The event value is the index of the current frame.
2142+
* `texture name`: The image to use.
2143+
* `frame count`: The number of frames animating the image.
2144+
* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
2145+
* `frame start` (Optional): The index of the frame to start on. Default `1`.
21442146

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

@@ -2575,6 +2577,7 @@ Setting a property to nothing will reset it to the default value. For example:
25752577

25762578
Some types may inherit styles from parent types.
25772579

2580+
* animated_image, inherits from image
25782581
* button
25792582
* button_exit, inherits from button
25802583
* checkbox
@@ -4325,6 +4328,7 @@ Call these functions only at load time!
43254328
is a table containing each formspecs element value (as string), with
43264329
the `name` parameter as index for each. The value depends on the
43274330
formspec element type:
4331+
* `animated_image`: Returns the index of the current frame.
43284332
* `button` and variants: If pressed, contains the user-facing button
43294333
text as value. If not pressed, is `nil`
43304334
* `field`, `textarea` and variants: Text in the field

‎games/minimal/mods/test/formspec.lua

+19-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ local clip_fs = [[
1717
scrollbar[0,9;3,0.8;horizontal;x9;3]
1818
tablecolumns[text;text]
1919
table[0,10;3,1;x10;one,two,three,four;1]
20-
animated_image[0,11;3,1;test_animation.png:4,100]
20+
animated_image[-0.5,11;4.5,1;;test_animation.png;4;100]
2121
]]
2222

2323

@@ -172,11 +172,19 @@ local pages = {
172172
[[
173173
formspec_version[3]
174174
size[12,12]
175-
animated_image[0.5,0.5;1,1;test_animation.png:4,100]
176-
animated_image[1.75,0.5;1,1;test_animation.png:100,100]
177-
animated_image[0.5,1.75;1,1;test_animation.jpg:4,100]
178-
animated_image[3,0.5;5,2;test_animation.png:4,100]
179-
animated_image[3,2.75;5,2;test_animation.jpg:4,100]
175+
animated_image[0.5,0.5;1,1;;test_animation.png;4;100]
176+
animated_image[0.5,1.75;1,1;;test_animation.jpg;4;100]
177+
animated_image[1.75,0.5;1,1;;test_animation.png;100;100]
178+
animated_image[3,0.5;1,1;ani_img_1;test_animation.png;4;1000]
179+
button[4.25,0.5;1,1;ani_btn_1;Current
180+
Number]
181+
animated_image[3,1.75;1,1;ani_img_2;test_animation.png;4;1000;2]
182+
button[4.25,1.75;1,1;ani_btn_2;Current
183+
Number]
184+
animated_image[3,3;1,1;;test_animation.png;4;0]
185+
animated_image[3,4.25;1,1;;test_animation.png;4;0;3]
186+
animated_image[5.5,0.5;5,2;;test_animation.png;4;100]
187+
animated_image[5.5,2.75;5,2;;test_animation.jpg;4;100]
180188
]]
181189
}
182190

@@ -198,6 +206,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
198206
return true
199207
end
200208

209+
if fields.ani_img_1 and fields.ani_btn_1 then
210+
minetest.chat_send_all(fields.ani_img_1)
211+
elseif fields.ani_img_2 and fields.ani_btn_2 then
212+
minetest.chat_send_all(fields.ani_img_2)
213+
end
201214
end)
202215

203216
minetest.register_node("test:node", {
680 Bytes
Loading
Loading

‎src/gui/guiAnimatedImage.cpp

+21-31
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,24 @@
44
#include "client/tile.h" // ITextureSource
55
#include "log.h"
66
#include "porting.h"
7+
#include "util/string.h"
78
#include <string>
9+
#include <vector>
810

911
GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
10-
s32 id, const core::rect<s32> &rectangle, const std::string &name,
11-
ISimpleTextureSource *tsrc) :
12-
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle),
13-
m_name(name), m_tsrc(tsrc), m_texture(nullptr), m_global_time(0),
14-
m_frame_idx(0), m_frame_count(1), m_frame_duration(1), m_frame_time(0)
12+
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
13+
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc) :
14+
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), m_tsrc(tsrc)
1515
{
16-
// Expected format: "texture_name:frame_count,frame_duration"
17-
// If this format is not met, the string will be loaded as a normal texture
16+
m_texture = m_tsrc->getTexture(texture_name);
1817

19-
std::string::size_type colon_position = name.find(':', 0);
20-
std::string::size_type comma_position = name.find(',', 0);
21-
22-
if (comma_position != std::string::npos &&
23-
colon_position != std::string::npos &&
24-
comma_position < name.size()) {
25-
m_texture = m_tsrc->getTexture(name.substr(0, colon_position));
26-
27-
m_frame_count = std::max(stoi(name.substr(
28-
colon_position + 1, comma_position - colon_position - 1)), 1);
29-
30-
m_frame_duration = std::max(stoi(name.substr(comma_position + 1)), 1);
31-
} else {
32-
// Leave the count/duration and display a static image
33-
m_texture = m_tsrc->getTexture(name);
34-
errorstream << "animated_image[]: Invalid texture format " << name <<
35-
". Expected format: texture_name:frame_count,frame_duration" << std::endl;
36-
}
18+
m_frame_count = std::max(frame_count, 1);
19+
m_frame_duration = std::max(frame_duration, 0);
3720

3821
if (m_texture != nullptr) {
3922
core::dimension2d<u32> size = m_texture->getOriginalSize();
40-
if (size.Height < (u64)m_frame_count) {
23+
if (size.Height < (u64)m_frame_count)
4124
m_frame_count = size.Height;
42-
}
4325
} else {
4426
// No need to step an animation if we have nothing to draw
4527
m_frame_count = 1;
@@ -58,13 +40,13 @@ void GUIAnimatedImage::draw()
5840
core::dimension2d<u32> size = m_texture->getOriginalSize();
5941
size.Height /= m_frame_count;
6042

61-
draw2DImageFilterScaled( driver, m_texture, AbsoluteRect,
62-
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
63-
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
43+
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect,
44+
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
45+
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
6446
}
6547

6648
// Step the animation
67-
if (m_frame_count > 1) {
49+
if (m_frame_count > 1 && m_frame_duration > 0) {
6850
// Determine the delta time to step
6951
u64 new_global_time = porting::getTimeMs();
7052
if (m_global_time > 0)
@@ -81,3 +63,11 @@ void GUIAnimatedImage::draw()
8163
m_frame_time %= m_frame_duration;
8264
}
8365
}
66+
67+
68+
void GUIAnimatedImage::setFrameIndex(s32 frame)
69+
{
70+
s32 idx = std::max(frame, 0);
71+
if (idx > 0 && idx < m_frame_count)
72+
m_frame_idx = idx;
73+
}

‎src/gui/guiAnimatedImage.h

+13-11
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
#pragma once
22

33
#include "irrlichttypes_extrabloated.h"
4-
#include "util/string.h"
4+
#include <string>
55

66
class ISimpleTextureSource;
77

88
class GUIAnimatedImage : public gui::IGUIElement {
99
public:
10-
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
11-
const core::rect<s32> &rectangle, const std::string &name,
12-
ISimpleTextureSource *tsrc);
10+
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
11+
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
12+
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc);
1313

1414
virtual void draw() override;
1515

16+
void setFrameIndex(s32 frame);
17+
s32 getFrameIndex() const { return m_frame_idx; };
18+
1619
private:
17-
std::string m_name;
1820
ISimpleTextureSource *m_tsrc;
1921

20-
video::ITexture *m_texture;
21-
u64 m_global_time;
22-
s32 m_frame_idx;
23-
s32 m_frame_count;
24-
u64 m_frame_duration;
25-
u64 m_frame_time;
22+
video::ITexture *m_texture = nullptr;
23+
u64 m_global_time = 0;
24+
s32 m_frame_idx = 0;
25+
s32 m_frame_count = 1;
26+
u64 m_frame_duration = 1;
27+
u64 m_frame_time = 0;
2628
};

‎src/gui/guiFormSpecMenu.cpp

+48-35
Original file line numberDiff line numberDiff line change
@@ -784,16 +784,19 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
784784
{
785785
std::vector<std::string> parts = split(element, ';');
786786

787-
if (parts.size() != 3 &&
788-
!(parts.size() > 3 && m_formspec_version > FORMSPEC_API_VERSION)) {
789-
errorstream << "Invalid animated image element(" << parts.size()
790-
<< "): '" << element << "'" << std::endl;
787+
if (parts.size() != 6 && parts.size() != 7 &&
788+
!(parts.size() > 7 && m_formspec_version > FORMSPEC_API_VERSION)) {
789+
errorstream << "Invalid animated_image element(" << parts.size()
790+
<< "): '" << element << "'" << std::endl;
791791
return;
792792
}
793793

794-
std::vector<std::string> v_pos = split(parts[0], ',');
795-
std::vector<std::string> v_geom = split(parts[1], ',');
796-
std::string name = unescape_string(parts[2]);
794+
std::vector<std::string> v_pos = split(parts[0], ',');
795+
std::vector<std::string> v_geom = split(parts[1], ',');
796+
std::string name = parts[2];
797+
std::string texture_name = unescape_string(parts[3]);
798+
s32 frame_count = stoi(parts[4]);
799+
s32 frame_duration = stoi(parts[5]);
797800

798801
MY_CHECKPOS("animated_image", 0);
799802
MY_CHECKGEOM("animated_image", 1);
@@ -811,21 +814,26 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
811814
}
812815

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

816819
FieldSpec spec(
817-
"",
818-
L"",
819-
L"",
820-
258 + m_fields.size()
820+
name,
821+
L"",
822+
L"",
823+
258 + m_fields.size()
821824
);
825+
spec.ftype = f_AnimatedImage;
826+
spec.send = true;
822827

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

825-
gui::IGUIElement *e = new GUIAnimatedImage(Environment, this, spec.fid,
826-
rect, name, m_tsrc);
830+
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, this, spec.fid,
831+
rect, texture_name, frame_count, frame_duration, m_tsrc);
832+
833+
if (parts.size() >= 7)
834+
e->setFrameIndex(stoi(parts[6]) - 1);
827835

828-
auto style = getStyleForElement("animated_image", spec.fname);
836+
auto style = getStyleForElement("animated_image", spec.fname, "image");
829837
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false));
830838
e->drop();
831839

@@ -3499,7 +3507,7 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
34993507
}
35003508

35013509
for (const GUIFormSpecMenu::FieldSpec &s : m_fields) {
3502-
if(s.send) {
3510+
if (s.send) {
35033511
std::string name = s.fname;
35043512
if (s.ftype == f_Button) {
35053513
fields[name] = wide_to_utf8(s.flabel);
@@ -3508,14 +3516,13 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
35083516
if (table) {
35093517
fields[name] = table->checkEvent();
35103518
}
3511-
}
3512-
else if(s.ftype == f_DropDown) {
3513-
// no dynamic cast possible due to some distributions shipped
3514-
// without rtti support in irrlicht
3519+
} else if (s.ftype == f_DropDown) {
3520+
// No dynamic cast possible due to some distributions shipped
3521+
// without rtti support in Irrlicht
35153522
IGUIElement *element = getElementFromId(s.fid, true);
35163523
gui::IGUIComboBox *e = NULL;
35173524
if ((element) && (element->getType() == gui::EGUIET_COMBO_BOX)) {
3518-
e = static_cast<gui::IGUIComboBox*>(element);
3525+
e = static_cast<gui::IGUIComboBox *>(element);
35193526
} else {
35203527
warningstream << "GUIFormSpecMenu::acceptInput: dropdown "
35213528
<< "field without dropdown element" << std::endl;
@@ -3529,10 +3536,9 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
35293536
fields[name] = (*dropdown_values)[selected];
35303537
}
35313538
}
3532-
}
3533-
else if (s.ftype == f_TabHeader) {
3534-
// no dynamic cast possible due to some distributions shipped
3535-
// without rttzi support in irrlicht
3539+
} else if (s.ftype == f_TabHeader) {
3540+
// No dynamic cast possible due to some distributions shipped
3541+
// without rtti support in Irrlicht
35363542
IGUIElement *element = getElementFromId(s.fid, true);
35373543
gui::IGUITabControl *e = nullptr;
35383544
if ((element) && (element->getType() == gui::EGUIET_TAB_CONTROL)) {
@@ -3544,10 +3550,9 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
35443550
ss << (e->getActiveTab() +1);
35453551
fields[name] = ss.str();
35463552
}
3547-
}
3548-
else if (s.ftype == f_CheckBox) {
3549-
// no dynamic cast possible due to some distributions shipped
3550-
// without rtti support in irrlicht
3553+
} else if (s.ftype == f_CheckBox) {
3554+
// No dynamic cast possible due to some distributions shipped
3555+
// without rtti support in Irrlicht
35513556
IGUIElement *element = getElementFromId(s.fid, true);
35523557
gui::IGUICheckBox *e = nullptr;
35533558
if ((element) && (element->getType() == gui::EGUIET_CHECK_BOX)) {
@@ -3560,10 +3565,9 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
35603565
else
35613566
fields[name] = "false";
35623567
}
3563-
}
3564-
else if (s.ftype == f_ScrollBar) {
3565-
// no dynamic cast possible due to some distributions shipped
3566-
// without rtti support in irrlicht
3568+
} else if (s.ftype == f_ScrollBar) {
3569+
// No dynamic cast possible due to some distributions shipped
3570+
// without rtti support in Irrlicht
35673571
IGUIElement *element = getElementFromId(s.fid, true);
35683572
GUIScrollBar *e = nullptr;
35693573
if (element && element->getType() == gui::EGUIET_ELEMENT)
@@ -3577,8 +3581,17 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no)
35773581
else
35783582
fields[name] = "VAL:" + os.str();
35793583
}
3580-
}
3581-
else {
3584+
} else if (s.ftype == f_AnimatedImage) {
3585+
// No dynamic cast possible due to some distributions shipped
3586+
// without rtti support in Irrlicht
3587+
IGUIElement *element = getElementFromId(s.fid, true);
3588+
GUIAnimatedImage *e = nullptr;
3589+
if (element && element->getType() == gui::EGUIET_ELEMENT)
3590+
e = static_cast<GUIAnimatedImage *>(element);
3591+
3592+
if (e)
3593+
fields[name] = std::to_string(e->getFrameIndex() + 1);
3594+
} else {
35823595
IGUIElement *e = getElementFromId(s.fid, true);
35833596
if (e)
35843597
fields[name] = wide_to_utf8(e->getText());

‎src/gui/guiFormSpecMenu.h

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ typedef enum {
5050
f_Box,
5151
f_ItemImage,
5252
f_HyperText,
53+
f_AnimatedImage,
5354
f_Unknown
5455
} FormspecFieldType;
5556

0 commit comments

Comments
 (0)
Please sign in to comment.