From 5c4b560b6812bbdf7a9d3202c95bad5c9df97d66 Mon Sep 17 00:00:00 2001 From: EvidenceB <49488517+EvidenceBKidscode@users.noreply.github.com> Date: Sat, 29 Aug 2020 20:13:30 +0200 Subject: [PATCH] Add compass HUD element (#9312) Co-authored-by: Jean-Patrick Guerrero Co-authored-by: Pierre-Yves Rollo Co-authored-by: SmallJoker --- doc/lua_api.txt | 18 +++++- src/client/hud.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++++ src/client/hud.h | 8 +++ src/hud.cpp | 1 + src/hud.h | 10 +++- 5 files changed, 175 insertions(+), 2 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 08bdba03e..c81824163 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -1451,7 +1451,23 @@ Same as `image`, but does not accept a `position`; the position is instead deter * `world_pos`: World position of the waypoint. * `offset`: offset in pixels from position. +### `compass` +Displays an image oriented or translated according to current heading direction. + +* `size`: The size of this element. Negative values represent percentage + of the screen; e.g. `x=-100` means 100% (width). +* `scale`: Scale of the translated image (used only for dir = 2 or dir = 3). +* `text`: The name of the texture to use. +* `alignment`: The alignment of the image. +* `offset`: Offset in pixels from position. +* `dir`: How the image is rotated/translated: + * 0 - Rotate as heading direction + * 1 - Rotate in reverse direction + * 2 - Translate as landscape direction + * 3 - Translate in reverse direction + +If translation is chosen, texture is repeated horizontally to fill the whole element. Representations of simple things ================================ @@ -7968,7 +7984,7 @@ Used by `Player:hud_add`. Returned by `Player:hud_get`. { hud_elem_type = "image", -- See HUD element types - -- Type of element, can be "image", "text", "statbar", or "inventory" + -- Type of element, can be "image", "text", "statbar", "inventory" or "compass" position = {x=0.5, y=0.5}, -- Left corner position of element diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 2b347c1e0..d3038230c 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -114,6 +114,28 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, } else { m_selection_material.MaterialType = video::EMT_SOLID; } + + // Prepare mesh for compass drawing + m_rotation_mesh_buffer.Vertices.set_used(4); + m_rotation_mesh_buffer.Indices.set_used(6); + + video::SColor white(255, 255, 255, 255); + v3f normal(0.f, 0.f, 1.f); + + m_rotation_mesh_buffer.Vertices[0] = video::S3DVertex(v3f(-1.f, -1.f, 0.f), normal, white, v2f(0.f, 1.f)); + m_rotation_mesh_buffer.Vertices[1] = video::S3DVertex(v3f(-1.f, 1.f, 0.f), normal, white, v2f(0.f, 0.f)); + m_rotation_mesh_buffer.Vertices[2] = video::S3DVertex(v3f( 1.f, 1.f, 0.f), normal, white, v2f(1.f, 0.f)); + m_rotation_mesh_buffer.Vertices[3] = video::S3DVertex(v3f( 1.f, -1.f, 0.f), normal, white, v2f(1.f, 1.f)); + + m_rotation_mesh_buffer.Indices[0] = 0; + m_rotation_mesh_buffer.Indices[1] = 1; + m_rotation_mesh_buffer.Indices[2] = 2; + m_rotation_mesh_buffer.Indices[3] = 2; + m_rotation_mesh_buffer.Indices[4] = 3; + m_rotation_mesh_buffer.Indices[5] = 0; + + m_rotation_mesh_buffer.getMaterial().Lighting = false; + m_rotation_mesh_buffer.getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; } Hud::~Hud() @@ -423,6 +445,54 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) core::rect(core::position2d(0,0), imgsize), NULL, colors, true); break; } + case HUD_ELEM_COMPASS: { + video::ITexture *texture = tsrc->getTexture(e->text); + if (!texture) + continue; + + // Positionning : + v2s32 dstsize(e->size.X, e->size.Y); + if (e->size.X < 0) + dstsize.X = m_screensize.X * (e->size.X * -0.01); + if (e->size.Y < 0) + dstsize.Y = m_screensize.Y * (e->size.Y * -0.01); + + if (dstsize.X <= 0 || dstsize.Y <= 0) + return; // Avoid zero divides + + // Angle according to camera view + v3f fore(0.f, 0.f, 1.f); + scene::ICameraSceneNode *cam = RenderingEngine::get_scene_manager()->getActiveCamera(); + cam->getAbsoluteTransformation().rotateVect(fore); + int angle = - fore.getHorizontalAngle().Y; + + // Limit angle and ajust with given offset + angle = (angle + (int)e->number) % 360; + + core::rect dstrect(0, 0, dstsize.X, dstsize.Y); + dstrect += pos + v2s32( + (e->align.X - 1.0) * dstsize.X / 2, + (e->align.Y - 1.0) * dstsize.Y / 2) + + v2s32(e->offset.X * m_hud_scaling, e->offset.Y * m_hud_scaling); + + switch (e->dir) { + case HUD_COMPASS_ROTATE: + drawCompassRotate(e, texture, dstrect, angle); + break; + case HUD_COMPASS_ROTATE_REVERSE: + drawCompassRotate(e, texture, dstrect, -angle); + break; + case HUD_COMPASS_TRANSLATE: + drawCompassTranslate(e, texture, dstrect, angle); + break; + case HUD_COMPASS_TRANSLATE_REVERSE: + drawCompassTranslate(e, texture, dstrect, -angle); + break; + default: + break; + } + + break; } default: infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << " of hud element ID " << i << " due to unrecognized type" << std::endl; @@ -430,6 +500,76 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) } } +void Hud::drawCompassTranslate(HudElement *e, video::ITexture *texture, + const core::rect &rect, int angle) +{ + const video::SColor color(255, 255, 255, 255); + const video::SColor colors[] = {color, color, color, color}; + + // Compute source image scaling + core::dimension2di imgsize(texture->getOriginalSize()); + core::rect srcrect(0, 0, imgsize.Width, imgsize.Height); + + v2s32 dstsize(rect.getHeight() * e->scale.X * imgsize.Width / imgsize.Height, + rect.getHeight() * e->scale.Y); + + // Avoid infinite loop + if (dstsize.X <= 0 || dstsize.Y <= 0) + return; + + core::rect tgtrect(0, 0, dstsize.X, dstsize.Y); + tgtrect += v2s32( + (rect.getWidth() - dstsize.X) / 2, + (rect.getHeight() - dstsize.Y) / 2) + + rect.UpperLeftCorner; + + int offset = angle * dstsize.X / 360; + + tgtrect += v2s32(offset, 0); + + // Repeat image as much as needed + while (tgtrect.UpperLeftCorner.X > rect.UpperLeftCorner.X) + tgtrect -= v2s32(dstsize.X, 0); + + draw2DImageFilterScaled(driver, texture, tgtrect, srcrect, &rect, colors, true); + tgtrect += v2s32(dstsize.X, 0); + + while (tgtrect.UpperLeftCorner.X < rect.LowerRightCorner.X) { + draw2DImageFilterScaled(driver, texture, tgtrect, srcrect, &rect, colors, true); + tgtrect += v2s32(dstsize.X, 0); + } +} + +void Hud::drawCompassRotate(HudElement *e, video::ITexture *texture, + const core::rect &rect, int angle) +{ + core::dimension2di imgsize(texture->getOriginalSize()); + + core::rect oldViewPort = driver->getViewPort(); + core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); + core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); + + core::matrix4 Matrix; + Matrix.makeIdentity(); + Matrix.setRotationDegrees(v3f(0.f, 0.f, angle)); + + driver->setViewPort(rect); + driver->setTransform(video::ETS_PROJECTION, core::matrix4()); + driver->setTransform(video::ETS_VIEW, core::matrix4()); + driver->setTransform(video::ETS_WORLD, Matrix); + + video::SMaterial &material = m_rotation_mesh_buffer.getMaterial(); + material.TextureLayer[0].Texture = texture; + driver->setMaterial(material); + driver->drawMeshBuffer(&m_rotation_mesh_buffer); + + driver->setTransform(video::ETS_WORLD, core::matrix4()); + driver->setTransform(video::ETS_VIEW, oldViewMat); + driver->setTransform(video::ETS_PROJECTION, oldProjMat); + + // restore the view area + driver->setViewPort(oldViewPort); +} void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture, const std::string &bgtexture, diff --git a/src/client/hud.h b/src/client/hud.h index ba34d479d..cf83cb16e 100644 --- a/src/client/hud.h +++ b/src/client/hud.h @@ -95,6 +95,12 @@ private: void drawItem(const ItemStack &item, const core::rect &rect, bool selected); + void drawCompassTranslate(HudElement *e, video::ITexture *texture, + const core::rect &rect, int way); + + void drawCompassRotate(HudElement *e, video::ITexture *texture, + const core::rect &rect, int way); + float m_hud_scaling; // cached minetest setting float m_scale_factor; v3s16 m_camera_offset; @@ -115,6 +121,8 @@ private: video::SMaterial m_selection_material; + scene::SMeshBuffer m_rotation_mesh_buffer; + enum { HIGHLIGHT_BOX, diff --git a/src/hud.cpp b/src/hud.cpp index 4830c56a4..175701342 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -28,6 +28,7 @@ const struct EnumString es_HudElementType[] = {HUD_ELEM_INVENTORY, "inventory"}, {HUD_ELEM_WAYPOINT, "waypoint"}, {HUD_ELEM_IMAGE_WAYPOINT, "image_waypoint"}, + {HUD_ELEM_COMPASS, "compass"}, {0, NULL}, }; diff --git a/src/hud.h b/src/hud.h index e015baec1..0a6993c1b 100644 --- a/src/hud.h +++ b/src/hud.h @@ -60,7 +60,8 @@ enum HudElementType { HUD_ELEM_STATBAR = 2, HUD_ELEM_INVENTORY = 3, HUD_ELEM_WAYPOINT = 4, - HUD_ELEM_IMAGE_WAYPOINT = 5 + HUD_ELEM_IMAGE_WAYPOINT = 5, + HUD_ELEM_COMPASS = 6 }; enum HudElementStat { @@ -79,6 +80,13 @@ enum HudElementStat { HUD_STAT_TEXT2, }; +enum HudCompassDir { + HUD_COMPASS_ROTATE = 0, + HUD_COMPASS_ROTATE_REVERSE, + HUD_COMPASS_TRANSLATE, + HUD_COMPASS_TRANSLATE_REVERSE, +}; + struct HudElement { HudElementType type; v2f pos;