Improve waypoints and add image variant (#9480)
authorLars Müller <34514239+appgurueu@users.noreply.github.com>
Sat, 11 Apr 2020 21:09:46 +0000 (23:09 +0200)
committerGitHub <noreply@github.com>
Sat, 11 Apr 2020 21:09:46 +0000 (22:09 +0100)
doc/client_lua_api.txt
doc/lua_api.txt
src/client/hud.cpp
src/client/hud.h
src/hud.cpp
src/hud.h
src/script/common/c_content.cpp

index 71df91c6814ee938e3b2986a76e57de1dc36a370..53ed680d08515920e42b2b047ae20819d948bb7a 100644 (file)
@@ -1416,12 +1416,35 @@ Displays a horizontal bar made up of half-images.
 * `offset`: offset in pixels from position.
 
 ### `waypoint`
+
 Displays distance to selected world position.
 
 * `name`: The name of the waypoint.
 * `text`: Distance suffix. Can be blank.
-* `number:` An integer containing the RGB value of the color used to draw the text.
+* `precision`: Waypoint precision, integer >= 0. Defaults to 10.
+  If set to 0, distance is not shown. Shown value is `floor(distance*precision)/precision`.
+  When the precision is an integer multiple of 10, there will be `log_10(precision)` digits after the decimal point.
+  `precision = 1000`, for example, will show 3 decimal places (eg: `0.999`).
+  `precision = 2` will show multiples of `0.5`; precision = 5 will show multiples of `0.2` and so on:
+  `precision = n` will show multiples of `1/n`
+* `number:` An integer containing the RGB value of the color used to draw the
+  text.
 * `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
+* `alignment`: The alignment of the waypoint.
+
+### `image_waypoint`
+
+Same as `image`, but does not accept a `position`; the position is instead determined by `world_pos`, the world position of the waypoint.
+
+* `scale`: The scale of the image, with 1 being the original texture size.
+  Only the X coordinate scale is used (positive values).
+  Negative values represent that percentage of the screen it
+  should take; e.g. `x=-100` means 100% (width).
+* `text`: The name of the texture that is displayed.
+* `alignment`: The alignment of the image.
+* `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
 
 ### Particle definition (`add_particle`)
 
index b083b290770709d1647516fd39c00952e2f0bc26..1a9aad3443420ea464e7e9b8e992f8173113d50b 100644 (file)
@@ -1364,10 +1364,30 @@ Displays distance to selected world position.
 
 * `name`: The name of the waypoint.
 * `text`: Distance suffix. Can be blank.
+* `precision`: Waypoint precision, integer >= 0. Defaults to 10.
+  If set to 0, distance is not shown. Shown value is `floor(distance*precision)/precision`.
+  When the precision is an integer multiple of 10, there will be `log_10(precision)` digits after the decimal point.
+  `precision = 1000`, for example, will show 3 decimal places (eg: `0.999`).
+  `precision = 2` will show multiples of `0.5`; precision = 5 will show multiples of `0.2` and so on:
+  `precision = n` will show multiples of `1/n`
 * `number:` An integer containing the RGB value of the color used to draw the
   text.
 * `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
+* `alignment`: The alignment of the waypoint.
+
+### `image_waypoint`
+
+Same as `image`, but does not accept a `position`; the position is instead determined by `world_pos`, the world position of the waypoint.
 
+* `scale`: The scale of the image, with 1 being the original texture size.
+  Only the X coordinate scale is used (positive values).
+  Negative values represent that percentage of the screen it
+  should take; e.g. `x=-100` means 100% (width).
+* `text`: The name of the texture that is displayed.
+* `alignment`: The alignment of the image.
+* `world_pos`: World position of the waypoint.
+* `offset`: offset in pixels from position.
 
 
 
index 37de6640bc978bbd4f3f2ec432cf58faa1f71fd5..56763e7e48b709e65d8aa7832a881cf89dafee67 100644 (file)
@@ -272,6 +272,25 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
        }
 }
 
+// Calculates screen position of waypoint. Returns true if waypoint is visible (in front of the player), else false.
+bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos)
+{
+       v3f w_pos = e->world_pos * BS;
+       scene::ICameraSceneNode* camera =
+               RenderingEngine::get_scene_manager()->getActiveCamera();
+       w_pos -= intToFloat(camera_offset, BS);
+       core::matrix4 trans = camera->getProjectionMatrix();
+       trans *= camera->getViewMatrix();
+       f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
+       trans.multiplyWith1x4Matrix(transformed_pos);
+       if (transformed_pos[3] < 0)
+               return false;
+       f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
+               core::reciprocal(transformed_pos[3]);
+       pos->X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
+       pos->Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
+       return true;
+}
 
 void Hud::drawLuaElements(const v3s16 &camera_offset)
 {
@@ -299,28 +318,6 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
                v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
                                floor(e->pos.Y * (float) m_screensize.Y + 0.5));
                switch (e->type) {
-                       case HUD_ELEM_IMAGE: {
-                               video::ITexture *texture = tsrc->getTexture(e->text);
-                               if (!texture)
-                                       continue;
-
-                               const video::SColor color(255, 255, 255, 255);
-                               const video::SColor colors[] = {color, color, color, color};
-                               core::dimension2di imgsize(texture->getOriginalSize());
-                               v2s32 dstsize(imgsize.Width * e->scale.X,
-                                             imgsize.Height * e->scale.Y);
-                               if (e->scale.X < 0)
-                                       dstsize.X = m_screensize.X * (e->scale.X * -0.01);
-                               if (e->scale.Y < 0)
-                                       dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
-                               v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
-                                            (e->align.Y - 1.0) * dstsize.Y / 2);
-                               core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
-                               rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
-                               draw2DImageFilterScaled(driver, texture, rect,
-                                       core::rect<s32>(core::position2d<s32>(0,0), imgsize),
-                                       NULL, colors, true);
-                               break; }
                        case HUD_ELEM_TEXT: {
                                video::SColor color(255, (e->number >> 16) & 0xFF,
                                                                                 (e->number >> 8)  & 0xFF,
@@ -343,34 +340,58 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
                                        inv, e->item, e->dir);
                                break; }
                        case HUD_ELEM_WAYPOINT: {
-                               v3f p_pos = player->getPosition() / BS;
-                               v3f w_pos = e->world_pos * BS;
-                               float distance = std::floor(10 * p_pos.getDistanceFrom(e->world_pos)) /
-                                       10.0f;
-                               scene::ICameraSceneNode* camera =
-                                       RenderingEngine::get_scene_manager()->getActiveCamera();
-                               w_pos -= intToFloat(camera_offset, BS);
-                               core::matrix4 trans = camera->getProjectionMatrix();
-                               trans *= camera->getViewMatrix();
-                               f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
-                               trans.multiplyWith1x4Matrix(transformed_pos);
-                               if (transformed_pos[3] < 0)
+                               if (!calculateScreenPos(camera_offset, e, &pos))
                                        break;
-                               f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
-                                       core::reciprocal(transformed_pos[3]);
-                               pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
-                               pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
+                               v3f p_pos = player->getPosition() / BS;
+                               pos += v2s32(e->offset.X, e->offset.Y);
                                video::SColor color(255, (e->number >> 16) & 0xFF,
                                                                                 (e->number >> 8)  & 0xFF,
                                                                                 (e->number >> 0)  & 0xFF);
-                               core::rect<s32> size(0, 0, 200, 2 * text_height);
                                std::wstring text = unescape_translate(utf8_to_wide(e->name));
-                               font->draw(text.c_str(), size + pos, color);
-                               std::ostringstream os;
-                               os << distance << e->text;
-                               text = unescape_translate(utf8_to_wide(os.str()));
-                               pos.Y += text_height;
-                               font->draw(text.c_str(), size + pos, color);
+                               const std::string &unit = e->text;
+                               // waypoints reuse the item field to store precision, item = precision + 1
+                               u32 item = e->item;
+                               float precision = (item == 0) ? 10.0f : (item - 1.f);
+                               bool draw_precision = precision > 0;
+
+                               core::rect<s32> bounds(0, 0, font->getDimension(text.c_str()).Width, (draw_precision ? 2:1) * text_height);
+                               pos.Y += (e->align.Y - 1.0) * bounds.getHeight() / 2;
+                               bounds += pos;
+                               font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0) * bounds.getWidth() / 2, 0), color);
+                               if (draw_precision) {
+                                       std::ostringstream os;
+                                       float distance = std::floor(precision * p_pos.getDistanceFrom(e->world_pos)) / precision;
+                                       os << distance << unit;
+                                       text = unescape_translate(utf8_to_wide(os.str()));
+                                       bounds.LowerRightCorner.X = bounds.UpperLeftCorner.X + font->getDimension(text.c_str()).Width;
+                                       font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0f) * bounds.getWidth() / 2, text_height), color);
+                               }
+                               break; }
+                       case HUD_ELEM_IMAGE_WAYPOINT: {
+                               if (!calculateScreenPos(camera_offset, e, &pos))
+                                       break;
+                       }
+                       case HUD_ELEM_IMAGE: {
+                               video::ITexture *texture = tsrc->getTexture(e->text);
+                               if (!texture)
+                                       continue;
+
+                               const video::SColor color(255, 255, 255, 255);
+                               const video::SColor colors[] = {color, color, color, color};
+                               core::dimension2di imgsize(texture->getOriginalSize());
+                               v2s32 dstsize(imgsize.Width * e->scale.X,
+                                             imgsize.Height * e->scale.Y);
+                               if (e->scale.X < 0)
+                                       dstsize.X = m_screensize.X * (e->scale.X * -0.01);
+                               if (e->scale.Y < 0)
+                                       dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
+                               v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
+                                            (e->align.Y - 1.0) * dstsize.Y / 2);
+                               core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
+                               rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
+                               draw2DImageFilterScaled(driver, texture, rect,
+                                       core::rect<s32>(core::position2d<s32>(0,0), imgsize),
+                                       NULL, colors, true);
                                break; }
                        default:
                                infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
index d9b5e0686c3b8682f6de49b39eebfbf64a48adac..cab115990d313a5ca6fa14ce2ab5d38ee313f88a 100644 (file)
@@ -81,6 +81,7 @@ public:
        void drawLuaElements(const v3s16 &camera_offset);
 
 private:
+       bool calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos);
        void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture,
                        s32 count, v2s32 offset, v2s32 size = v2s32());
 
index 7711e3a4a143368bf1fbf4a25ab5af10507f65ab..39625b5fdb9801d186a3e9c3ce7687b961cfba10 100644 (file)
@@ -27,6 +27,7 @@ const struct EnumString es_HudElementType[] =
        {HUD_ELEM_STATBAR,   "statbar"},
        {HUD_ELEM_INVENTORY, "inventory"},
        {HUD_ELEM_WAYPOINT,  "waypoint"},
+       {HUD_ELEM_IMAGE_WAYPOINT, "image_waypoint"},
        {0, NULL},
 };
 
index 23f189dff5cd9c9001081509d360f598cf731d0a..b0977c6a426b9f1a5502cdbd12c36beea8ee1cac 100644 (file)
--- a/src/hud.h
+++ b/src/hud.h
@@ -61,6 +61,7 @@ enum HudElementType {
        HUD_ELEM_STATBAR   = 2,
        HUD_ELEM_INVENTORY = 3,
        HUD_ELEM_WAYPOINT  = 4,
+       HUD_ELEM_IMAGE_WAYPOINT = 5
 };
 
 enum HudElementStat {
index c8cd7539fc460cc14c2f015a0ad7be9a17bef14b..ff9ceec6dbbf102c1f383b8d679484288281334b 100644 (file)
@@ -1850,7 +1850,11 @@ void read_hud_element(lua_State *L, HudElement *elem)
        elem->name    = getstringfield_default(L, 2, "name", "");
        elem->text    = getstringfield_default(L, 2, "text", "");
        elem->number  = getintfield_default(L, 2, "number", 0);
-       elem->item    = getintfield_default(L, 2, "item", 0);
+       if (elem->type == HUD_ELEM_WAYPOINT)
+               // waypoints reuse the item field to store precision, item = precision + 1
+               elem->item = getintfield_default(L, 2, "precision", -1) + 1;
+       else
+               elem->item = getintfield_default(L, 2, "item", 0);
        elem->dir     = getintfield_default(L, 2, "direction", 0);
        elem->z_index = MYMAX(S16_MIN, MYMIN(S16_MAX,
                        getintfield_default(L, 2, "z_index", 0)));