mirror of
https://github.com/minetest/minetest.git
synced 2024-11-23 08:03:45 +01:00
FormSpec: 9-slice images, animated_images, and fgimg_middle (#12453)
* FormSpec: 9-slice images and animated_images * Add fgimg_middle; clean up code * Address issues, add tests * Fix stupid error; bump formspec version * Re-add image[] elements without a size
This commit is contained in:
parent
5a562a597c
commit
f7bcf7fa46
@ -2310,6 +2310,8 @@ Version History
|
|||||||
* Allow dropdown indexing events
|
* Allow dropdown indexing events
|
||||||
* Formspec version 5 (5.5.0):
|
* Formspec version 5 (5.5.0):
|
||||||
* Added padding[] element
|
* Added padding[] element
|
||||||
|
* Formspec version 6 (5.6.0):
|
||||||
|
* Add nine-slice images, animated_images, and fgimg_middle
|
||||||
|
|
||||||
Elements
|
Elements
|
||||||
--------
|
--------
|
||||||
@ -2474,20 +2476,25 @@ Elements
|
|||||||
* `bgcolor` tooltip background color as `ColorString` (optional)
|
* `bgcolor` tooltip background color as `ColorString` (optional)
|
||||||
* `fontcolor` tooltip font color as `ColorString` (optional)
|
* `fontcolor` tooltip font color as `ColorString` (optional)
|
||||||
|
|
||||||
### `image[<X>,<Y>;<W>,<H>;<texture name>]`
|
### `image[<X>,<Y>;<W>,<H>;<texture name>;<middle>]`
|
||||||
|
|
||||||
* Show an image
|
* Show an image.
|
||||||
|
* `middle` (optional): Makes the image render in 9-sliced mode and defines the middle rect.
|
||||||
|
* Requires formspec version >= 6.
|
||||||
|
* See `background9[]` documentation for more information.
|
||||||
|
|
||||||
### `animated_image[<X>,<Y>;<W>,<H>;<name>;<texture name>;<frame count>;<frame duration>;<frame start>]`
|
### `animated_image[<X>,<Y>;<W>,<H>;<name>;<texture name>;<frame count>;<frame duration>;<frame start>;<middle>]`
|
||||||
|
|
||||||
* Show an animated image. The image is drawn like a "vertical_frames" tile
|
* Show an animated image. The image is drawn like a "vertical_frames" tile
|
||||||
animation (See [Tile animation definition]), but uses a frame count/duration
|
animation (See [Tile animation definition]), but uses a frame count/duration for simplicity
|
||||||
for simplicity
|
|
||||||
* `name`: Element name to send when an event occurs. The event value is the index of the current frame.
|
* `name`: Element name to send when an event occurs. The event value is the index of the current frame.
|
||||||
* `texture name`: The image to use.
|
* `texture name`: The image to use.
|
||||||
* `frame count`: The number of frames animating the image.
|
* `frame count`: The number of frames animating the image.
|
||||||
* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
|
* `frame duration`: Milliseconds between each frame. `0` means the frames don't advance.
|
||||||
* `frame start` (Optional): The index of the frame to start on. Default `1`.
|
* `frame start` (optional): The index of the frame to start on. Default `1`.
|
||||||
|
* `middle` (optional): Makes the image render in 9-sliced mode and defines the middle rect.
|
||||||
|
* Requires formspec version >= 6.
|
||||||
|
* See `background9[]` documentation for more information.
|
||||||
|
|
||||||
### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>;<frame loop range>;<animation speed>]`
|
### `model[<X>,<Y>;<W>,<H>;<name>;<mesh>;<textures>;<rotation X,Y>;<continuous>;<mouse control>;<frame loop range>;<animation speed>]`
|
||||||
|
|
||||||
@ -3101,6 +3108,8 @@ Some types may inherit styles from parent types.
|
|||||||
* This is deprecated, use states instead.
|
* This is deprecated, use states instead.
|
||||||
* fgimg_pressed - image when pressed. Defaults to fgimg when not provided.
|
* fgimg_pressed - image when pressed. Defaults to fgimg when not provided.
|
||||||
* This is deprecated, use states instead.
|
* This is deprecated, use states instead.
|
||||||
|
* fgimg_middle - Makes the fgimg textures render in 9-sliced mode and defines the middle rect.
|
||||||
|
See background9[] documentation for more details.
|
||||||
* NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed
|
* NOTE: The parameters of any given image_button will take precedence over fgimg/fgimg_pressed
|
||||||
* sound - a sound to be played when triggered.
|
* sound - a sound to be played when triggered.
|
||||||
* scrollbar
|
* scrollbar
|
||||||
|
@ -195,8 +195,10 @@ local style_fs = [[
|
|||||||
style[one_btn15;border=false;bgcolor=#1cc;bgimg=testformspec_bg.png;bgimg_hovered=testformspec_bg_hovered.png;bgimg_pressed=testformspec_bg_pressed.png]
|
style[one_btn15;border=false;bgcolor=#1cc;bgimg=testformspec_bg.png;bgimg_hovered=testformspec_bg_hovered.png;bgimg_pressed=testformspec_bg_pressed.png]
|
||||||
item_image_button[1.25,9.6;1,1;testformspec:item;one_btn15;Bg]
|
item_image_button[1.25,9.6;1,1;testformspec:item;one_btn15;Bg]
|
||||||
|
|
||||||
style[one_btn16;border=false;bgimg=testformspec_bg_9slice.png;bgimg_hovered=testformspec_bg_9slice_hovered.png;bgimg_pressed=testformspec_bg_9slice_pressed.png;bgimg_middle=4,6]
|
style[one_btn16;border=false;bgimg=testformspec_bg_9slice.png;bgimg_middle=4,6;padding=5,7;fgimg=testformspec_bg.png;fgimg_middle=1]
|
||||||
button[2.5,9.6;2,1;one_btn16;9-Slice Bg]
|
style[one_btn16:hovered;bgimg=testformspec_bg_9slice_hovered.png;fgimg=testformspec_bg_hovered.png]
|
||||||
|
style[one_btn16:pressed;bgimg=testformspec_bg_9slice_pressed.png;fgimg=testformspec_bg_pressed.png]
|
||||||
|
image_button[2.5,9.6;2,1;;one_btn16;9-Slice Bg]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -375,12 +377,16 @@ local pages = {
|
|||||||
|
|
||||||
-- Animation
|
-- Animation
|
||||||
[[
|
[[
|
||||||
formspec_version[3]
|
formspec_version[6]
|
||||||
size[12,13]
|
size[12,13]
|
||||||
animated_image[0.5,0.5;1,1;;testformspec_animation.png;4;100]
|
animated_image[0.5,0.5;1,1;;testformspec_animation.png;4;100]
|
||||||
animated_image[0.5,1.75;1,1;;testformspec_animation.jpg;4;100]
|
animated_image[0.5,1.75;1,1;;testformspec_animation.jpg;4;100]
|
||||||
animated_image[1.75,0.5;1,1;;testformspec_animation.png;100;100]
|
animated_image[1.75,0.5;1,1;;testformspec_animation.png;100;100]
|
||||||
animated_image[3,0.5;1,1;ani_img_1;testformspec_animation.png;4;1000]
|
animated_image[3,0.5;1,1;ani_img_1;testformspec_animation.png;4;1000]
|
||||||
|
image[0.5,3;1,1;testformspec_bg.png;1]
|
||||||
|
animated_image[0.5,4.25;1,1;;[combine:16x48:0,0=testformspec_bg.png:0,16=testformspec_bg_hovered.png:0,32=testformspec_bg_pressed.png;3;250;1;1]
|
||||||
|
image[0.5,5.5;2,1;testformspec_9slice.png;16,0,-16,-16]
|
||||||
|
animated_image[2.75,5.5;1.5,0.5;;[combine:300x140:0,0=testformspec_9slice.png:0,70=(testformspec_9slice.png^[transformFX);2;500;1;16,0,-16,-16]
|
||||||
button[4.25,0.5;1,1;ani_btn_1;Current
|
button[4.25,0.5;1,1;ani_btn_1;Current
|
||||||
Number]
|
Number]
|
||||||
animated_image[3,1.75;1,1;ani_img_2;testformspec_animation.png;4;1000;2]
|
animated_image[3,1.75;1,1;ani_img_2;testformspec_animation.png;4;1000;2]
|
||||||
|
BIN
games/devtest/mods/testformspec/textures/testformspec_9slice.png
Normal file
BIN
games/devtest/mods/testformspec/textures/testformspec_9slice.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
@ -176,52 +176,61 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
||||||
const core::rect<s32> &rect, const core::rect<s32> &middle,
|
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||||
const core::rect<s32> *cliprect, const video::SColor *const colors)
|
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect,
|
||||||
|
const video::SColor *const colors)
|
||||||
{
|
{
|
||||||
auto originalSize = texture->getOriginalSize();
|
// `-x` is interpreted as `w - x`
|
||||||
core::vector2di lowerRightOffset = core::vector2di(originalSize.Width, originalSize.Height) - middle.LowerRightCorner;
|
core::rect<s32> middle = middlerect;
|
||||||
|
|
||||||
|
if (middlerect.LowerRightCorner.X < 0)
|
||||||
|
middle.LowerRightCorner.X += srcrect.getWidth();
|
||||||
|
if (middlerect.LowerRightCorner.Y < 0)
|
||||||
|
middle.LowerRightCorner.Y += srcrect.getHeight();
|
||||||
|
|
||||||
|
core::vector2di lower_right_offset = core::vector2di(srcrect.getWidth(),
|
||||||
|
srcrect.getHeight()) - middle.LowerRightCorner;
|
||||||
|
|
||||||
for (int y = 0; y < 3; ++y) {
|
for (int y = 0; y < 3; ++y) {
|
||||||
for (int x = 0; x < 3; ++x) {
|
for (int x = 0; x < 3; ++x) {
|
||||||
core::rect<s32> src({0, 0}, originalSize);
|
core::rect<s32> src = srcrect;
|
||||||
core::rect<s32> dest = rect;
|
core::rect<s32> dest = destrect;
|
||||||
|
|
||||||
switch (x) {
|
switch (x) {
|
||||||
case 0:
|
case 0:
|
||||||
dest.LowerRightCorner.X = rect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
dest.LowerRightCorner.X = destrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
||||||
src.LowerRightCorner.X = middle.UpperLeftCorner.X;
|
src.LowerRightCorner.X = srcrect.UpperLeftCorner.X + middle.UpperLeftCorner.X;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
dest.UpperLeftCorner.X += middle.UpperLeftCorner.X;
|
dest.UpperLeftCorner.X += middle.UpperLeftCorner.X;
|
||||||
dest.LowerRightCorner.X -= lowerRightOffset.X;
|
dest.LowerRightCorner.X -= lower_right_offset.X;
|
||||||
src.UpperLeftCorner.X = middle.UpperLeftCorner.X;
|
src.UpperLeftCorner.X += middle.UpperLeftCorner.X;
|
||||||
src.LowerRightCorner.X = middle.LowerRightCorner.X;
|
src.LowerRightCorner.X -= lower_right_offset.X;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
dest.UpperLeftCorner.X = rect.LowerRightCorner.X - lowerRightOffset.X;
|
dest.UpperLeftCorner.X = destrect.LowerRightCorner.X - lower_right_offset.X;
|
||||||
src.UpperLeftCorner.X = middle.LowerRightCorner.X;
|
src.UpperLeftCorner.X = srcrect.LowerRightCorner.X - lower_right_offset.X;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (y) {
|
switch (y) {
|
||||||
case 0:
|
case 0:
|
||||||
dest.LowerRightCorner.Y = rect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
dest.LowerRightCorner.Y = destrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
||||||
src.LowerRightCorner.Y = middle.UpperLeftCorner.Y;
|
src.LowerRightCorner.Y = srcrect.UpperLeftCorner.Y + middle.UpperLeftCorner.Y;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
dest.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
|
dest.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
|
||||||
dest.LowerRightCorner.Y -= lowerRightOffset.Y;
|
dest.LowerRightCorner.Y -= lower_right_offset.Y;
|
||||||
src.UpperLeftCorner.Y = middle.UpperLeftCorner.Y;
|
src.UpperLeftCorner.Y += middle.UpperLeftCorner.Y;
|
||||||
src.LowerRightCorner.Y = middle.LowerRightCorner.Y;
|
src.LowerRightCorner.Y -= lower_right_offset.Y;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
dest.UpperLeftCorner.Y = rect.LowerRightCorner.Y - lowerRightOffset.Y;
|
dest.UpperLeftCorner.Y = destrect.LowerRightCorner.Y - lower_right_offset.Y;
|
||||||
src.UpperLeftCorner.Y = middle.LowerRightCorner.Y;
|
src.UpperLeftCorner.Y = srcrect.LowerRightCorner.Y - lower_right_offset.Y;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,13 +46,13 @@ video::ITexture *guiScalingImageButton(video::IVideoDriver *driver, video::IText
|
|||||||
*/
|
*/
|
||||||
void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
|
void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
|
||||||
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||||
const core::rect<s32> *cliprect = 0, const video::SColor *const colors = 0,
|
const core::rect<s32> *cliprect = nullptr,
|
||||||
bool usealpha = false);
|
const video::SColor *const colors = nullptr, bool usealpha = false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 9-slice / segment drawing
|
* 9-slice / segment drawing
|
||||||
*/
|
*/
|
||||||
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
|
||||||
const core::rect<s32> &rect, const core::rect<s32> &middle,
|
const core::rect<s32> &destrect, const core::rect<s32> &srcrect,
|
||||||
const core::rect<s32> *cliprect = nullptr,
|
const core::rect<s32> &middlerect, const core::rect<s32> *cliprect = nullptr,
|
||||||
const video::SColor *const colors = nullptr);
|
const video::SColor *const colors = nullptr);
|
||||||
|
@ -45,6 +45,7 @@ public:
|
|||||||
BGIMG_PRESSED, // Note: Deprecated property
|
BGIMG_PRESSED, // Note: Deprecated property
|
||||||
FGIMG,
|
FGIMG,
|
||||||
FGIMG_HOVERED, // Note: Deprecated property
|
FGIMG_HOVERED, // Note: Deprecated property
|
||||||
|
FGIMG_MIDDLE,
|
||||||
FGIMG_PRESSED, // Note: Deprecated property
|
FGIMG_PRESSED, // Note: Deprecated property
|
||||||
ALPHA,
|
ALPHA,
|
||||||
CONTENT_OFFSET,
|
CONTENT_OFFSET,
|
||||||
@ -101,6 +102,8 @@ public:
|
|||||||
return FGIMG;
|
return FGIMG;
|
||||||
} else if (name == "fgimg_hovered") {
|
} else if (name == "fgimg_hovered") {
|
||||||
return FGIMG_HOVERED;
|
return FGIMG_HOVERED;
|
||||||
|
} else if (name == "fgimg_middle") {
|
||||||
|
return FGIMG_MIDDLE;
|
||||||
} else if (name == "fgimg_pressed") {
|
} else if (name == "fgimg_pressed") {
|
||||||
return FGIMG_PRESSED;
|
return FGIMG_PRESSED;
|
||||||
} else if (name == "alpha") {
|
} else if (name == "alpha") {
|
||||||
|
@ -9,40 +9,37 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
GUIAnimatedImage::GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
||||||
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
|
s32 id, const core::rect<s32> &rectangle) :
|
||||||
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc) :
|
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle)
|
||||||
gui::IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, rectangle), m_tsrc(tsrc)
|
|
||||||
{
|
{
|
||||||
m_texture = m_tsrc->getTexture(texture_name);
|
|
||||||
|
|
||||||
m_frame_count = std::max(frame_count, 1);
|
|
||||||
m_frame_duration = std::max(frame_duration, 0);
|
|
||||||
|
|
||||||
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()
|
void GUIAnimatedImage::draw()
|
||||||
{
|
{
|
||||||
// Render the current frame
|
if (m_texture == nullptr)
|
||||||
if (m_texture != nullptr) {
|
return;
|
||||||
|
|
||||||
video::IVideoDriver *driver = Environment->getVideoDriver();
|
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();
|
core::dimension2d<u32> size = m_texture->getOriginalSize();
|
||||||
|
|
||||||
|
if ((u32)m_frame_count > size.Height)
|
||||||
|
m_frame_count = size.Height;
|
||||||
|
if (m_frame_idx >= m_frame_count)
|
||||||
|
m_frame_idx = m_frame_count - 1;
|
||||||
|
|
||||||
size.Height /= m_frame_count;
|
size.Height /= m_frame_count;
|
||||||
|
|
||||||
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect,
|
core::rect<s32> rect(core::position2d<s32>(0, size.Height * m_frame_idx), size);
|
||||||
core::rect<s32>(core::position2d<s32>(0, size.Height * m_frame_idx), size),
|
core::rect<s32> *cliprect = NoClip ? nullptr : &AbsoluteClippingRect;
|
||||||
NoClip ? nullptr : &AbsoluteClippingRect, colors, true);
|
|
||||||
|
if (m_middle.getArea() == 0) {
|
||||||
|
const video::SColor color(255, 255, 255, 255);
|
||||||
|
const video::SColor colors[] = {color, color, color, color};
|
||||||
|
draw2DImageFilterScaled(driver, m_texture, AbsoluteRect, rect, cliprect,
|
||||||
|
colors, true);
|
||||||
|
} else {
|
||||||
|
draw2DImage9Slice(driver, m_texture, AbsoluteRect, rect, m_middle, cliprect);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step the animation
|
// Step the animation
|
||||||
@ -55,7 +52,7 @@ void GUIAnimatedImage::draw()
|
|||||||
m_global_time = new_global_time;
|
m_global_time = new_global_time;
|
||||||
|
|
||||||
// Advance by the number of elapsed frames, looping if necessary
|
// Advance by the number of elapsed frames, looping if necessary
|
||||||
m_frame_idx += u32(m_frame_time / m_frame_duration);
|
m_frame_idx += (u32)(m_frame_time / m_frame_duration);
|
||||||
m_frame_idx %= m_frame_count;
|
m_frame_idx %= m_frame_count;
|
||||||
|
|
||||||
// If 1 or more frames have elapsed, reset the frame time counter with
|
// If 1 or more frames have elapsed, reset the frame time counter with
|
||||||
@ -63,11 +60,3 @@ void GUIAnimatedImage::draw()
|
|||||||
m_frame_time %= m_frame_duration;
|
m_frame_time %= m_frame_duration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void GUIAnimatedImage::setFrameIndex(s32 frame)
|
|
||||||
{
|
|
||||||
s32 idx = std::max(frame, 0);
|
|
||||||
if (idx > 0 && idx < m_frame_count)
|
|
||||||
m_frame_idx = idx;
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "irrlichttypes_extrabloated.h"
|
#include "irrlichttypes_extrabloated.h"
|
||||||
|
#include <algorithm>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class ISimpleTextureSource;
|
class ISimpleTextureSource;
|
||||||
@ -8,21 +9,33 @@ class ISimpleTextureSource;
|
|||||||
class GUIAnimatedImage : public gui::IGUIElement {
|
class GUIAnimatedImage : public gui::IGUIElement {
|
||||||
public:
|
public:
|
||||||
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
GUIAnimatedImage(gui::IGUIEnvironment *env, gui::IGUIElement *parent,
|
||||||
s32 id, const core::rect<s32> &rectangle, const std::string &texture_name,
|
s32 id, const core::rect<s32> &rectangle);
|
||||||
s32 frame_count, s32 frame_duration, ISimpleTextureSource *tsrc);
|
|
||||||
|
|
||||||
virtual void draw() override;
|
virtual void draw() override;
|
||||||
|
|
||||||
void setFrameIndex(s32 frame);
|
void setTexture(video::ITexture *texture) { m_texture = texture; };
|
||||||
|
video::ITexture *getTexture() const { return m_texture; };
|
||||||
|
|
||||||
|
void setMiddleRect(const core::rect<s32> &middle) { m_middle = middle; };
|
||||||
|
core::rect<s32> getMiddleRect() const { return m_middle; };
|
||||||
|
|
||||||
|
void setFrameDuration(u64 duration) { m_frame_duration = duration; };
|
||||||
|
u64 getFrameDuration() const { return m_frame_duration; };
|
||||||
|
|
||||||
|
void setFrameCount(s32 count) { m_frame_count = std::max(count, 1); };
|
||||||
|
s32 getFrameCount() const { return m_frame_count; };
|
||||||
|
|
||||||
|
void setFrameIndex(s32 frame) { m_frame_idx = std::max(frame, 0); };
|
||||||
s32 getFrameIndex() const { return m_frame_idx; };
|
s32 getFrameIndex() const { return m_frame_idx; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISimpleTextureSource *m_tsrc;
|
|
||||||
|
|
||||||
video::ITexture *m_texture = nullptr;
|
video::ITexture *m_texture = nullptr;
|
||||||
|
|
||||||
u64 m_global_time = 0;
|
u64 m_global_time = 0;
|
||||||
s32 m_frame_idx = 0;
|
s32 m_frame_idx = 0;
|
||||||
s32 m_frame_count = 1;
|
s32 m_frame_count = 1;
|
||||||
u64 m_frame_duration = 1;
|
u64 m_frame_duration = 0;
|
||||||
u64 m_frame_time = 0;
|
u64 m_frame_time = 0;
|
||||||
|
|
||||||
|
core::rect<s32> m_middle;
|
||||||
};
|
};
|
||||||
|
@ -48,21 +48,15 @@ void GUIBackgroundImage::draw()
|
|||||||
|
|
||||||
video::IVideoDriver *driver = Environment->getVideoDriver();
|
video::IVideoDriver *driver = Environment->getVideoDriver();
|
||||||
|
|
||||||
|
core::rect<s32> srcrect(core::position2d<s32>(0, 0),
|
||||||
|
core::dimension2di(texture->getOriginalSize()));
|
||||||
|
|
||||||
if (m_middle.getArea() == 0) {
|
if (m_middle.getArea() == 0) {
|
||||||
const video::SColor color(255, 255, 255, 255);
|
const video::SColor color(255, 255, 255, 255);
|
||||||
const video::SColor colors[] = {color, color, color, color};
|
const video::SColor colors[] = {color, color, color, color};
|
||||||
draw2DImageFilterScaled(driver, texture, rect,
|
draw2DImageFilterScaled(driver, texture, rect, srcrect, nullptr, colors, true);
|
||||||
core::rect<s32>(core::position2d<s32>(0, 0),
|
|
||||||
core::dimension2di(texture->getOriginalSize())),
|
|
||||||
nullptr, colors, true);
|
|
||||||
} else {
|
} else {
|
||||||
core::rect<s32> middle = m_middle;
|
draw2DImage9Slice(driver, texture, rect, srcrect, m_middle);
|
||||||
// `-x` is interpreted as `w - x`
|
|
||||||
if (middle.LowerRightCorner.X < 0)
|
|
||||||
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
|
|
||||||
if (middle.LowerRightCorner.Y < 0)
|
|
||||||
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
|
|
||||||
draw2DImage9Slice(driver, texture, rect, middle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IGUIElement::draw();
|
IGUIElement::draw();
|
||||||
|
@ -320,15 +320,9 @@ void GUIButton::draw()
|
|||||||
sourceRect, &AbsoluteClippingRect,
|
sourceRect, &AbsoluteClippingRect,
|
||||||
image_colors, UseAlphaChannel);
|
image_colors, UseAlphaChannel);
|
||||||
} else {
|
} else {
|
||||||
core::rect<s32> middle = BgMiddle;
|
|
||||||
// `-x` is interpreted as `w - x`
|
|
||||||
if (middle.LowerRightCorner.X < 0)
|
|
||||||
middle.LowerRightCorner.X += texture->getOriginalSize().Width;
|
|
||||||
if (middle.LowerRightCorner.Y < 0)
|
|
||||||
middle.LowerRightCorner.Y += texture->getOriginalSize().Height;
|
|
||||||
draw2DImage9Slice(driver, texture,
|
draw2DImage9Slice(driver, texture,
|
||||||
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
ScaleImage ? AbsoluteRect : core::rect<s32>(pos, sourceRect.getSize()),
|
||||||
middle, &AbsoluteClippingRect, image_colors);
|
sourceRect, BgMiddle, &AbsoluteClippingRect, image_colors);
|
||||||
}
|
}
|
||||||
// END PATCH
|
// END PATCH
|
||||||
}
|
}
|
||||||
|
@ -34,13 +34,13 @@ GUIButtonImage::GUIButtonImage(gui::IGUIEnvironment *environment,
|
|||||||
ISimpleTextureSource *tsrc, bool noclip)
|
ISimpleTextureSource *tsrc, bool noclip)
|
||||||
: GUIButton(environment, parent, id, rectangle, tsrc, noclip)
|
: GUIButton(environment, parent, id, rectangle, tsrc, noclip)
|
||||||
{
|
{
|
||||||
m_image = Environment->addImage(
|
GUIButton::setScaleImage(true);
|
||||||
core::rect<s32>(0,0,rectangle.getWidth(),rectangle.getHeight()), this);
|
m_image = new GUIAnimatedImage(environment, this, id, rectangle);
|
||||||
m_image->setScaleImage(isScalingImage());
|
|
||||||
sendToBack(m_image);
|
sendToBack(m_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIButtonImage::setForegroundImage(video::ITexture *image)
|
void GUIButtonImage::setForegroundImage(video::ITexture *image,
|
||||||
|
const core::rect<s32> &middle)
|
||||||
{
|
{
|
||||||
if (image == m_foreground_image)
|
if (image == m_foreground_image)
|
||||||
return;
|
return;
|
||||||
@ -52,7 +52,8 @@ void GUIButtonImage::setForegroundImage(video::ITexture *image)
|
|||||||
m_foreground_image->drop();
|
m_foreground_image->drop();
|
||||||
|
|
||||||
m_foreground_image = image;
|
m_foreground_image = image;
|
||||||
m_image->setImage(image);
|
m_image->setTexture(image);
|
||||||
|
m_image->setMiddleRect(middle);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Set element properties from a StyleSpec
|
//! Set element properties from a StyleSpec
|
||||||
@ -67,19 +68,13 @@ void GUIButtonImage::setFromStyle(const StyleSpec& style)
|
|||||||
getTextureSource());
|
getTextureSource());
|
||||||
|
|
||||||
setForegroundImage(guiScalingImageButton(driver, texture,
|
setForegroundImage(guiScalingImageButton(driver, texture,
|
||||||
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()));
|
AbsoluteRect.getWidth(), AbsoluteRect.getHeight()),
|
||||||
setScaleImage(true);
|
style.getRect(StyleSpec::FGIMG_MIDDLE, m_image->getMiddleRect()));
|
||||||
} else {
|
} else {
|
||||||
setForegroundImage(nullptr);
|
setForegroundImage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIButtonImage::setScaleImage(bool scaleImage)
|
|
||||||
{
|
|
||||||
GUIButton::setScaleImage(scaleImage);
|
|
||||||
m_image->setScaleImage(scaleImage);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
|
GUIButtonImage *GUIButtonImage::addButton(IGUIEnvironment *environment,
|
||||||
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
|
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
|
||||||
IGUIElement *parent, s32 id, const wchar_t *text,
|
IGUIElement *parent, s32 id, const wchar_t *text,
|
||||||
|
@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
#include "guiButton.h"
|
#include "guiButton.h"
|
||||||
#include "IGUIButton.h"
|
#include "IGUIButton.h"
|
||||||
|
#include "guiAnimatedImage.h"
|
||||||
|
|
||||||
using namespace irr;
|
using namespace irr;
|
||||||
|
|
||||||
@ -32,13 +33,12 @@ public:
|
|||||||
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
|
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
|
||||||
bool noclip = false);
|
bool noclip = false);
|
||||||
|
|
||||||
void setForegroundImage(video::ITexture *image = nullptr);
|
void setForegroundImage(video::ITexture *image = nullptr,
|
||||||
|
const core::rect<s32> &middle = core::rect<s32>());
|
||||||
|
|
||||||
//! Set element properties from a StyleSpec
|
//! Set element properties from a StyleSpec
|
||||||
virtual void setFromStyle(const StyleSpec &style) override;
|
virtual void setFromStyle(const StyleSpec &style) override;
|
||||||
|
|
||||||
virtual void setScaleImage(bool scaleImage=true) override;
|
|
||||||
|
|
||||||
//! Do not drop returned handle
|
//! Do not drop returned handle
|
||||||
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
|
static GUIButtonImage *addButton(gui::IGUIEnvironment *environment,
|
||||||
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
|
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
|
||||||
@ -47,5 +47,5 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
video::ITexture *m_foreground_image = nullptr;
|
video::ITexture *m_foreground_image = nullptr;
|
||||||
gui::IGUIImage *m_image;
|
GUIAnimatedImage *m_image;
|
||||||
};
|
};
|
||||||
|
@ -767,38 +767,50 @@ void GUIFormSpecMenu::parseScrollBarOptions(parserData* data, const std::string
|
|||||||
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
||||||
{
|
{
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
if (!precheckElement("image", element, 2, 3, parts))
|
if (!precheckElement("image", element, 2, 4, parts))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (parts.size() >= 3) {
|
size_t offset = parts.size() >= 3;
|
||||||
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]);
|
|
||||||
|
|
||||||
|
std::vector<std::string> v_pos = split(parts[0],',');
|
||||||
MY_CHECKPOS("image", 0);
|
MY_CHECKPOS("image", 0);
|
||||||
|
|
||||||
|
std::vector<std::string> v_geom;
|
||||||
|
if (parts.size() >= 3) {
|
||||||
|
v_geom = split(parts[1],',');
|
||||||
MY_CHECKGEOM("image", 1);
|
MY_CHECKGEOM("image", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = unescape_string(parts[1 + offset]);
|
||||||
|
video::ITexture *texture = m_tsrc->getTexture(name);
|
||||||
|
|
||||||
v2s32 pos;
|
v2s32 pos;
|
||||||
v2s32 geom;
|
v2s32 geom;
|
||||||
|
|
||||||
|
if (parts.size() < 3) {
|
||||||
|
if (texture != nullptr) {
|
||||||
|
core::dimension2du dim = texture->getOriginalSize();
|
||||||
|
geom.X = dim.Width;
|
||||||
|
geom.Y = dim.Height;
|
||||||
|
} else {
|
||||||
|
geom = v2s32(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data->real_coordinates) {
|
if (data->real_coordinates) {
|
||||||
pos = getRealCoordinateBasePos(v_pos);
|
pos = getRealCoordinateBasePos(v_pos);
|
||||||
|
if (parts.size() >= 3)
|
||||||
geom = getRealCoordinateGeometry(v_geom);
|
geom = getRealCoordinateGeometry(v_geom);
|
||||||
} else {
|
} else {
|
||||||
pos = getElementBasePos(&v_pos);
|
pos = getElementBasePos(&v_pos);
|
||||||
|
if (parts.size() >= 3) {
|
||||||
geom.X = stof(v_geom[0]) * (float)imgsize.X;
|
geom.X = stof(v_geom[0]) * (float)imgsize.X;
|
||||||
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
|
geom.Y = stof(v_geom[1]) * (float)imgsize.Y;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!data->explicit_size)
|
if (!data->explicit_size)
|
||||||
warningstream<<"invalid use of image without a size[] element"<<std::endl;
|
warningstream << "Invalid use of image without a size[] element" << std::endl;
|
||||||
|
|
||||||
video::ITexture *texture = m_tsrc->getTexture(name);
|
|
||||||
if (!texture) {
|
|
||||||
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
|
|
||||||
<< std::endl << "\t" << name << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldSpec spec(
|
FieldSpec spec(
|
||||||
name,
|
name,
|
||||||
@ -807,61 +819,32 @@ void GUIFormSpecMenu::parseImage(parserData* data, const std::string &element)
|
|||||||
258 + m_fields.size(),
|
258 + m_fields.size(),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
core::rect<s32> rect(pos, pos + geom);
|
|
||||||
gui::IGUIImage *e = Environment->addImage(rect, data->current_parent,
|
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
|
||||||
spec.fid, 0, true);
|
|
||||||
e->setImage(texture);
|
core::rect<s32> middle;
|
||||||
e->setScaleImage(true);
|
if (parts.size() >= 4)
|
||||||
|
parseMiddleRect(parts[3], &middle);
|
||||||
|
|
||||||
|
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
|
||||||
|
spec.fid, rect);
|
||||||
|
|
||||||
|
e->setTexture(texture);
|
||||||
|
e->setMiddleRect(middle);
|
||||||
|
|
||||||
auto style = getDefaultStyleForElement("image", spec.fname);
|
auto style = getDefaultStyleForElement("image", spec.fname);
|
||||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
||||||
m_fields.push_back(spec);
|
|
||||||
|
|
||||||
// images should let events through
|
// Animated images should let events through
|
||||||
e->grab();
|
|
||||||
m_clickthrough_elements.push_back(e);
|
m_clickthrough_elements.push_back(e);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Else: 2 arguments in "parts"
|
|
||||||
|
|
||||||
std::vector<std::string> v_pos = split(parts[0],',');
|
|
||||||
std::string name = unescape_string(parts[1]);
|
|
||||||
|
|
||||||
MY_CHECKPOS("image", 0);
|
|
||||||
|
|
||||||
v2s32 pos = getElementBasePos(&v_pos);
|
|
||||||
|
|
||||||
if (!data->explicit_size)
|
|
||||||
warningstream<<"invalid use of image without a size[] element"<<std::endl;
|
|
||||||
|
|
||||||
video::ITexture *texture = m_tsrc->getTexture(name);
|
|
||||||
if (!texture) {
|
|
||||||
errorstream << "GUIFormSpecMenu::parseImage() Unable to load texture:"
|
|
||||||
<< std::endl << "\t" << name << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldSpec spec(
|
|
||||||
name,
|
|
||||||
L"",
|
|
||||||
L"",
|
|
||||||
258 + m_fields.size()
|
|
||||||
);
|
|
||||||
gui::IGUIImage *e = Environment->addImage(texture, pos, true,
|
|
||||||
data->current_parent, spec.fid, 0);
|
|
||||||
auto style = getDefaultStyleForElement("image", spec.fname);
|
|
||||||
e->setNotClipped(style.getBool(StyleSpec::NOCLIP, m_formspec_version < 3));
|
|
||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
|
|
||||||
// images should let events through
|
|
||||||
e->grab();
|
|
||||||
m_clickthrough_elements.push_back(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
|
void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &element)
|
||||||
{
|
{
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
if (!precheckElement("animated_image", element, 6, 7, parts))
|
if (!precheckElement("animated_image", element, 6, 8, parts))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::vector<std::string> v_pos = split(parts[0], ',');
|
std::vector<std::string> v_pos = split(parts[0], ',');
|
||||||
@ -887,7 +870,8 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!data->explicit_size)
|
if (!data->explicit_size)
|
||||||
warningstream << "Invalid use of animated_image without a size[] element" << std::endl;
|
warningstream << "Invalid use of animated_image without a size[] element"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
FieldSpec spec(
|
FieldSpec spec(
|
||||||
name,
|
name,
|
||||||
@ -900,9 +884,17 @@ void GUIFormSpecMenu::parseAnimatedImage(parserData *data, const std::string &el
|
|||||||
|
|
||||||
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
|
core::rect<s32> rect = core::rect<s32>(pos, pos + geom);
|
||||||
|
|
||||||
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent, spec.fid,
|
core::rect<s32> middle;
|
||||||
rect, texture_name, frame_count, frame_duration, m_tsrc);
|
if (parts.size() >= 8)
|
||||||
|
parseMiddleRect(parts[7], &middle);
|
||||||
|
|
||||||
|
GUIAnimatedImage *e = new GUIAnimatedImage(Environment, data->current_parent,
|
||||||
|
spec.fid, rect);
|
||||||
|
|
||||||
|
e->setTexture(m_tsrc->getTexture(texture_name));
|
||||||
|
e->setMiddleRect(middle);
|
||||||
|
e->setFrameDuration(frame_duration);
|
||||||
|
e->setFrameCount(frame_count);
|
||||||
if (parts.size() >= 7)
|
if (parts.size() >= 7)
|
||||||
e->setFrameIndex(stoi(parts[6]) - 1);
|
e->setFrameIndex(stoi(parts[6]) - 1);
|
||||||
|
|
||||||
@ -1027,6 +1019,35 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element,
|
|||||||
m_fields.push_back(spec);
|
m_fields.push_back(spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GUIFormSpecMenu::parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect)
|
||||||
|
{
|
||||||
|
core::rect<s32> rect;
|
||||||
|
std::vector<std::string> v_rect = split(value, ',');
|
||||||
|
|
||||||
|
if (v_rect.size() == 1) {
|
||||||
|
s32 x = stoi(v_rect[0]);
|
||||||
|
rect.UpperLeftCorner = core::vector2di(x, x);
|
||||||
|
rect.LowerRightCorner = core::vector2di(-x, -x);
|
||||||
|
} else if (v_rect.size() == 2) {
|
||||||
|
s32 x = stoi(v_rect[0]);
|
||||||
|
s32 y = stoi(v_rect[1]);
|
||||||
|
rect.UpperLeftCorner = core::vector2di(x, y);
|
||||||
|
rect.LowerRightCorner = core::vector2di(-x, -y);
|
||||||
|
// `-x` is interpreted as `w - x`
|
||||||
|
} else if (v_rect.size() == 4) {
|
||||||
|
rect.UpperLeftCorner = core::vector2di(stoi(v_rect[0]), stoi(v_rect[1]));
|
||||||
|
rect.LowerRightCorner = core::vector2di(stoi(v_rect[2]), stoi(v_rect[3]));
|
||||||
|
} else {
|
||||||
|
warningstream << "Invalid rectangle string format: \"" << value
|
||||||
|
<< "\"" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*parsed_rect = rect;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
|
void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &element)
|
||||||
{
|
{
|
||||||
std::vector<std::string> parts;
|
std::vector<std::string> parts;
|
||||||
@ -1068,25 +1089,8 @@ void GUIFormSpecMenu::parseBackground(parserData* data, const std::string &eleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
core::rect<s32> middle;
|
core::rect<s32> middle;
|
||||||
if (parts.size() >= 5) {
|
if (parts.size() >= 5)
|
||||||
std::vector<std::string> v_middle = split(parts[4], ',');
|
parseMiddleRect(parts[4], &middle);
|
||||||
if (v_middle.size() == 1) {
|
|
||||||
s32 x = stoi(v_middle[0]);
|
|
||||||
middle.UpperLeftCorner = core::vector2di(x, x);
|
|
||||||
middle.LowerRightCorner = core::vector2di(-x, -x);
|
|
||||||
} else if (v_middle.size() == 2) {
|
|
||||||
s32 x = stoi(v_middle[0]);
|
|
||||||
s32 y = stoi(v_middle[1]);
|
|
||||||
middle.UpperLeftCorner = core::vector2di(x, y);
|
|
||||||
middle.LowerRightCorner = core::vector2di(-x, -y);
|
|
||||||
// `-x` is interpreted as `w - x`
|
|
||||||
} else if (v_middle.size() == 4) {
|
|
||||||
middle.UpperLeftCorner = core::vector2di(stoi(v_middle[0]), stoi(v_middle[1]));
|
|
||||||
middle.LowerRightCorner = core::vector2di(stoi(v_middle[2]), stoi(v_middle[3]));
|
|
||||||
} else {
|
|
||||||
warningstream << "Invalid rectangle given to middle param of background[] element" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data->explicit_size && !clip)
|
if (!data->explicit_size && !clip)
|
||||||
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
|
warningstream << "invalid use of unclipped background without a size[] element" << std::endl;
|
||||||
|
@ -457,6 +457,8 @@ private:
|
|||||||
void parseSetFocus(const std::string &element);
|
void parseSetFocus(const std::string &element);
|
||||||
void parseModel(parserData *data, const std::string &element);
|
void parseModel(parserData *data, const std::string &element);
|
||||||
|
|
||||||
|
bool parseMiddleRect(const std::string &value, core::rect<s32> *parsed_rect);
|
||||||
|
|
||||||
void tryClose();
|
void tryClose();
|
||||||
|
|
||||||
void showTooltip(const std::wstring &text, const irr::video::SColor &color,
|
void showTooltip(const std::wstring &text, const irr::video::SColor &color,
|
||||||
|
@ -228,8 +228,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
#define PASSWORD_SIZE 28 // Maximum password length. Allows for
|
||||||
// base64-encoded SHA-1 (27+\0).
|
// base64-encoded SHA-1 (27+\0).
|
||||||
|
|
||||||
// See also: Formspec Version History in doc/lua_api.txt
|
// See also formspec [Version History] in doc/lua_api.txt
|
||||||
#define FORMSPEC_API_VERSION 5
|
#define FORMSPEC_API_VERSION 6
|
||||||
|
|
||||||
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"
|
#define TEXTURENAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.-"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user