X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Fhud.cpp;h=01f4d6ff3bfdb1b832406fabbae2d7939be88b49;hb=a4ef62f5b215fe0f23e3e50672f1538854db4ed9;hp=f8f712762ef0ed5643685bb94dec188c0ff2c78b;hpb=6e1372bd894d955300c40d69e5c882e9cc7d7523;p=minetest.git diff --git a/src/client/hud.cpp b/src/client/hud.cpp index f8f712762..01f4d6ff3 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -20,6 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "client/hud.h" +#include +#include #include #include "settings.h" #include "util/numeric.h" @@ -36,21 +38,25 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mesh.h" #include "wieldmesh.h" #include "client/renderingengine.h" +#include "client/minimap.h" #ifdef HAVE_TOUCHSCREENGUI #include "gui/touchscreengui.h" #endif -Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, +#define OBJECT_CROSSHAIR_LINE_SIZE 8 +#define CROSSHAIR_LINE_SIZE 10 + +Hud::Hud(Client *client, LocalPlayer *player, Inventory *inventory) { driver = RenderingEngine::get_video_driver(); - this->guienv = guienv; this->client = client; this->player = player; this->inventory = inventory; m_hud_scaling = g_settings->getFloat("hud_scaling"); + m_scale_factor = m_hud_scaling * RenderingEngine::getDisplayDensity(); m_hotbar_imagesize = std::floor(HOTBAR_IMAGE_SIZE * RenderingEngine::getDisplayDensity() + 0.5f); m_hotbar_imagesize *= m_hud_scaling; @@ -75,6 +81,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b); use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png"); + use_object_crosshair_image = tsrc->isKnownSourceImage("object_crosshair.png"); m_selection_boxes.clear(); m_halo_boxes.clear(); @@ -94,7 +101,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, if (g_settings->getBool("enable_shaders")) { IShaderSource *shdrsrc = client->getShaderSource(); u16 shader_id = shdrsrc->getShader( - m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1); + m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA); m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; } else { m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -109,6 +116,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() @@ -195,6 +224,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect& rect, } //NOTE: selectitem = 0 -> no selected; selectitem 1-based +// mainlist can be NULL, but draw the frame anyway. void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction) { @@ -213,9 +243,7 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, } // Position of upper left corner of bar - v2s32 pos = screen_offset; - pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity(); - pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity(); + v2s32 pos = screen_offset * m_scale_factor; pos += upperleftpos; // Store hotbar_image in member variable, used by drawItem() @@ -244,7 +272,8 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, // Draw items core::rect imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize); - for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) { + const s32 list_size = mainlist ? mainlist->getSize() : 0; + for (s32 i = inv_offset; i < itemcount && i < list_size; i++) { s32 fullimglen = m_hotbar_imagesize + m_padding * 2; v2s32 steppos; @@ -272,12 +301,24 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, } } +bool Hud::hasElementOfType(HudElementType type) +{ + for (size_t i = 0; i != player->maxHudId(); i++) { + HudElement *e = player->getHud(i); + if (!e) + continue; + if (e->type == type) + return true; + } + return false; +} + // 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(); + client->getSceneManager()->getActiveCamera(); w_pos -= intToFloat(camera_offset, BS); core::matrix4 trans = camera->getProjectionMatrix(); trans *= camera->getViewMatrix(); @@ -294,41 +335,66 @@ bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *p void Hud::drawLuaElements(const v3s16 &camera_offset) { - u32 text_height = g_fontengine->getTextHeight(); - irr::gui::IGUIFont* font = g_fontengine->getFont(); + const u32 text_height = g_fontengine->getTextHeight(); + gui::IGUIFont *const font = g_fontengine->getFont(); // Reorder elements by z_index - std::vector ids; + std::vector elems; + elems.reserve(player->maxHudId()); for (size_t i = 0; i != player->maxHudId(); i++) { HudElement *e = player->getHud(i); if (!e) continue; - auto it = ids.begin(); - while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index) + auto it = elems.begin(); + while (it != elems.end() && (*it)->z_index <= e->z_index) ++it; - ids.insert(it, i); + elems.insert(it, e); } - for (size_t i : ids) { - HudElement *e = player->getHud(i); + for (HudElement *e : elems) { 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_TEXT: { + unsigned int font_size = g_fontengine->getDefaultFontSize(); + + if (e->size.X > 0) + font_size *= e->size.X; + +#ifdef __ANDROID__ + // The text size on Android is not proportional with the actual scaling + // FIXME: why do we have such a weird unportable hack?? + if (font_size > 3 && e->offset.X < -20) + font_size -= 3; +#endif + auto textfont = g_fontengine->getFont(FontSpec(font_size, + (e->style & HUD_STYLE_MONO) ? FM_Mono : FM_Unspecified, + e->style & HUD_STYLE_BOLD, e->style & HUD_STYLE_ITALIC)); + video::SColor color(255, (e->number >> 16) & 0xFF, (e->number >> 8) & 0xFF, (e->number >> 0) & 0xFF); - core::rect size(0, 0, e->scale.X, text_height * e->scale.Y); std::wstring text = unescape_translate(utf8_to_wide(e->text)); - core::dimension2d textsize = font->getDimension(text.c_str()); - v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2), - (e->align.Y - 1.0) * (textsize.Height / 2)); - v2s32 offs(e->offset.X, e->offset.Y); - font->draw(text.c_str(), size + pos + offset + offs, color); + core::dimension2d textsize = textfont->getDimension(text.c_str()); + + v2s32 offset(0, (e->align.Y - 1.0) * (textsize.Height / 2)); + core::rect size(0, 0, e->scale.X * m_scale_factor, + text_height * e->scale.Y * m_scale_factor); + v2s32 offs(e->offset.X * m_scale_factor, + e->offset.Y * m_scale_factor); + std::wstringstream wss(text); + std::wstring line; + while (std::getline(wss, line, L'\n')) + { + core::dimension2d linesize = textfont->getDimension(line.c_str()); + v2s32 line_offset((e->align.X - 1.0) * (linesize.Width / 2), 0); + textfont->draw(line.c_str(), size + pos + offset + offs + line_offset, color); + offset.Y += linesize.Height; + } break; } case HUD_ELEM_STATBAR: { v2s32 offs(e->offset.X, e->offset.Y); @@ -337,6 +403,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) break; } case HUD_ELEM_INVENTORY: { InventoryList *inv = inventory->getList(e->text); + if (!inv) + warningstream << "HUD: Unknown inventory list. name=" << e->text << std::endl; drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0, inv, e->item, e->dir); break; } @@ -380,8 +448,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) 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); + v2s32 dstsize(imgsize.Width * e->scale.X * m_scale_factor, + imgsize.Height * e->scale.Y * m_scale_factor); if (e->scale.X < 0) dstsize.X = m_screensize.X * (e->scale.X * -0.01); if (e->scale.Y < 0) @@ -389,18 +457,150 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) v2s32 offset((e->align.X - 1.0) * dstsize.X / 2, (e->align.Y - 1.0) * dstsize.Y / 2); core::rect rect(0, 0, dstsize.X, dstsize.Y); - rect += pos + offset + v2s32(e->offset.X, e->offset.Y); + rect += pos + offset + v2s32(e->offset.X * m_scale_factor, + e->offset.Y * m_scale_factor); draw2DImageFilterScaled(driver, texture, rect, 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 = client->getSceneManager()->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; } + case HUD_ELEM_MINIMAP: { + if (e->size.X <= 0 || e->size.Y <= 0) + break; + if (!client->getMinimap()) + break; + // Draw a minimap of size "size" + v2s32 dstsize(e->size.X * m_scale_factor, + e->size.Y * m_scale_factor); + // (no percent size as minimap would likely be anamorphosed) + v2s32 offset((e->align.X - 1.0) * dstsize.X / 2, + (e->align.Y - 1.0) * dstsize.Y / 2); + core::rect rect(0, 0, dstsize.X, dstsize.Y); + rect += pos + offset + v2s32(e->offset.X * m_scale_factor, + e->offset.Y * m_scale_factor); + client->getMinimap()->drawMinimap(rect); + break; } default: - infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << - " of hud element ID " << i << " due to unrecognized type" << std::endl; + infostream << "Hud::drawLuaElements: ignoring drawform " << e->type + << " due to unrecognized type" << std::endl; } } } +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::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, @@ -422,12 +622,15 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, core::dimension2di dstd; if (size == v2s32()) { dstd = srcd; + dstd.Height *= m_scale_factor; + dstd.Width *= m_scale_factor; + offset.X *= m_scale_factor; + offset.Y *= m_scale_factor; } else { - float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity(); - dstd.Height = size.Y * size_factor; - dstd.Width = size.X * size_factor; - offset.X *= size_factor; - offset.Y *= size_factor; + dstd.Height = size.Y * m_scale_factor; + dstd.Width = size.X * m_scale_factor; + offset.X *= m_scale_factor; + offset.Y *= m_scale_factor; } v2s32 p = pos; @@ -473,7 +676,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, // Rectangles for 1/2 the "off state" texture core::rect srchalfrect2, dsthalfrect2; - if (count % 2 == 1) { + if (count % 2 == 1 || maxcount % 2 == 1) { // Need to draw halves: Calculate rectangles srchalfrect = calculate_clipping_rect(srcd, steppos); dsthalfrect = calculate_clipping_rect(dstd, steppos); @@ -508,7 +711,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, } } - if (stat_texture_bg && maxcount > count / 2) { + if (stat_texture_bg && maxcount > count) { // Draw "off state" textures s32 start_offset; if (count % 2 == 1) @@ -528,8 +731,7 @@ void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, if (maxcount % 2 == 1) { draw2DImageFilterScaled(driver, stat_texture_bg, - dsthalfrect + p, srchalfrect, - NULL, colors, true); + dsthalfrect + p, srchalfrect, NULL, colors, true); } } } @@ -549,8 +751,8 @@ void Hud::drawHotbar(u16 playeritem) { s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); - if ( (float) width / (float) window_size.X <= + const v2u32 &window_size = RenderingEngine::getWindowSize(); + if ((float) width / (float) window_size.X <= g_settings->getFloat("hud_hotbar_max_width")) { if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0); @@ -573,6 +775,31 @@ void Hud::drawHotbar(u16 playeritem) { void Hud::drawCrosshair() { + if (pointing_at_object) { + if (use_object_crosshair_image) { + video::ITexture *object_crosshair = tsrc->getTexture("object_crosshair.png"); + v2u32 size = object_crosshair->getOriginalSize(); + v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2), + m_displaycenter.Y - (size.Y / 2)); + driver->draw2DImage(object_crosshair, lsize, + core::rect(0, 0, size.X, size.Y), + nullptr, crosshair_argb, true); + } else { + driver->draw2DLine( + m_displaycenter - v2s32(OBJECT_CROSSHAIR_LINE_SIZE, + OBJECT_CROSSHAIR_LINE_SIZE), + m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE, + OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb); + driver->draw2DLine( + m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE, + -OBJECT_CROSSHAIR_LINE_SIZE), + m_displaycenter + v2s32(-OBJECT_CROSSHAIR_LINE_SIZE, + OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb); + } + + return; + } + if (use_crosshair_image) { video::ITexture *crosshair = tsrc->getTexture("crosshair.png"); v2u32 size = crosshair->getOriginalSize(); @@ -580,12 +807,12 @@ void Hud::drawCrosshair() m_displaycenter.Y - (size.Y / 2)); driver->draw2DImage(crosshair, lsize, core::rect(0, 0, size.X, size.Y), - 0, crosshair_argb, true); + nullptr, crosshair_argb, true); } else { - driver->draw2DLine(m_displaycenter - v2s32(10, 0), - m_displaycenter + v2s32(10, 0), crosshair_argb); - driver->draw2DLine(m_displaycenter - v2s32(0, 10), - m_displaycenter + v2s32(0, 10), crosshair_argb); + driver->draw2DLine(m_displaycenter - v2s32(CROSSHAIR_LINE_SIZE, 0), + m_displaycenter + v2s32(CROSSHAIR_LINE_SIZE, 0), crosshair_argb); + driver->draw2DLine(m_displaycenter - v2s32(0, CROSSHAIR_LINE_SIZE), + m_displaycenter + v2s32(0, CROSSHAIR_LINE_SIZE), crosshair_argb); } } @@ -602,12 +829,10 @@ void Hud::drawSelectionMesh() // Draw 3D selection boxes video::SMaterial oldmaterial = driver->getMaterial2D(); driver->setMaterial(m_selection_material); - for (std::vector::const_iterator - i = m_selection_boxes.begin(); - i != m_selection_boxes.end(); ++i) { + for (auto & selection_box : m_selection_boxes) { aabb3f box = aabb3f( - i->MinEdge + m_selection_pos_with_offset, - i->MaxEdge + m_selection_pos_with_offset); + selection_box.MinEdge + m_selection_pos_with_offset, + selection_box.MaxEdge + m_selection_pos_with_offset); u32 r = (selectionbox_argb.getRed() * m_selection_mesh_color.getRed() / 255); @@ -641,6 +866,60 @@ void Hud::drawSelectionMesh() } } +enum Hud::BlockBoundsMode Hud::toggleBlockBounds() +{ + m_block_bounds_mode = static_cast(m_block_bounds_mode + 1); + + if (m_block_bounds_mode >= BLOCK_BOUNDS_MAX) { + m_block_bounds_mode = BLOCK_BOUNDS_OFF; + } + return m_block_bounds_mode; +} + +void Hud::disableBlockBounds() +{ + m_block_bounds_mode = BLOCK_BOUNDS_OFF; +} + +void Hud::drawBlockBounds() +{ + if (m_block_bounds_mode == BLOCK_BOUNDS_OFF) { + return; + } + + video::SMaterial old_material = driver->getMaterial2D(); + driver->setMaterial(m_selection_material); + + v3s16 pos = player->getStandingNodePos(); + + v3s16 blockPos( + floorf((float) pos.X / MAP_BLOCKSIZE), + floorf((float) pos.Y / MAP_BLOCKSIZE), + floorf((float) pos.Z / MAP_BLOCKSIZE) + ); + + v3f offset = intToFloat(client->getCamera()->getOffset(), BS); + + s8 radius = m_block_bounds_mode == BLOCK_BOUNDS_NEAR ? 2 : 0; + + v3f halfNode = v3f(BS, BS, BS) / 2.0f; + + for (s8 x = -radius; x <= radius; x++) + for (s8 y = -radius; y <= radius; y++) + for (s8 z = -radius; z <= radius; z++) { + v3s16 blockOffset(x, y, z); + + aabb3f box( + intToFloat((blockPos + blockOffset) * MAP_BLOCKSIZE, BS) - offset - halfNode, + intToFloat(((blockPos + blockOffset) * MAP_BLOCKSIZE) + (MAP_BLOCKSIZE - 1), BS) - offset + halfNode + ); + + driver->draw3DBox(box, video::SColor(255, 255, 0, 0)); + } + + driver->setMaterial(old_material); +} + void Hud::updateSelectionMesh(const v3s16 &camera_offset) { m_camera_offset = camera_offset; @@ -687,7 +966,7 @@ void Hud::updateSelectionMesh(const v3s16 &camera_offset) } void Hud::resizeHotbar() { - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + const v2u32 &window_size = RenderingEngine::getWindowSize(); if (m_screensize != window_size) { m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * @@ -724,12 +1003,28 @@ void drawItemStack( return; } + const static thread_local bool enable_animations = + g_settings->getBool("inventory_items_animations"); + const ItemDefinition &def = item.getDefinition(client->idef()); - ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); - if (imesh && imesh->mesh) { + bool draw_overlay = false; + + bool has_mesh = false; + ItemMesh *imesh; + + core::rect viewrect = rect; + if (clip != nullptr) + viewrect.clipAgainst(*clip); + + // Render as mesh if animated or no inventory image + if ((enable_animations && rotation_kind < IT_ROT_NONE) || def.inventory_image.empty()) { + imesh = client->idef()->getWieldMesh(def.name, client); + has_mesh = imesh && imesh->mesh; + } + if (has_mesh) { scene::IMesh *mesh = imesh->mesh; - driver->clearZBuffer(); + driver->clearBuffers(video::ECBF_DEPTH); s32 delta = 0; if (rotation_kind < IT_ROT_NONE) { MeshTimeInfo &ti = rotation_time_infos[rotation_kind]; @@ -743,9 +1038,6 @@ void drawItemStack( core::rect oldViewPort = driver->getViewPort(); core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); - core::rect viewrect = rect; - if (clip) - viewrect.clipAgainst(*clip); core::matrix4 ProjMatrix; ProjMatrix.buildProjectionMatrixOrthoLH(2.0f, 2.0f, -1.0f, 100.0f); @@ -771,9 +1063,6 @@ void drawItemStack( core::matrix4 matrix; matrix.makeIdentity(); - static thread_local bool enable_animations = - g_settings->getBool("inventory_items_animations"); - if (enable_animations) { float timer_f = (float) delta / 5000.f; matrix.setRotationDegrees(v3f( @@ -819,22 +1108,43 @@ void drawItemStack( driver->setTransform(video::ETS_PROJECTION, oldProjMat); driver->setViewPort(oldViewPort); - // draw the inventory_overlay - if (def.type == ITEM_NODE && def.inventory_image.empty() && - !def.inventory_overlay.empty()) { + draw_overlay = def.type == ITEM_NODE && def.inventory_image.empty(); + } else { // Otherwise just draw as 2D + video::ITexture *texture = client->idef()->getInventoryTexture(def.name, client); + video::SColor color; + if (texture) { + color = client->idef()->getItemstackColor(item, client); + } else { + color = video::SColor(255, 255, 255, 255); ITextureSource *tsrc = client->getTextureSource(); - video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay); - core::dimension2d dimens = overlay_texture->getOriginalSize(); - core::rect srcrect(0, 0, dimens.Width, dimens.Height); - draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true); + texture = tsrc->getTexture("no_texture.png"); + if (!texture) + return; } + + const video::SColor colors[] = { color, color, color, color }; + + draw2DImageFilterScaled(driver, texture, rect, + core::rect({0, 0}, core::dimension2di(texture->getOriginalSize())), + clip, colors, true); + + draw_overlay = true; + } + + // draw the inventory_overlay + if (!def.inventory_overlay.empty() && draw_overlay) { + ITextureSource *tsrc = client->getTextureSource(); + video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay); + core::dimension2d dimens = overlay_texture->getOriginalSize(); + core::rect srcrect(0, 0, dimens.Width, dimens.Height); + draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true); } if (def.type == ITEM_TOOL && item.wear != 0) { // Draw a progressbar - float barheight = rect.getHeight() / 16; - float barpad_x = rect.getWidth() / 16; - float barpad_y = rect.getHeight() / 16; + float barheight = static_cast(rect.getHeight()) / 16; + float barpad_x = static_cast(rect.getWidth()) / 16; + float barpad_y = static_cast(rect.getHeight()) / 16; core::rect progressrect( rect.UpperLeftCorner.X + barpad_x, @@ -871,24 +1181,68 @@ void drawItemStack( driver->draw2DRectangle(color, progressrect2, clip); } - if (font != NULL && item.count >= 2) { + const std::string &count_text = item.metadata.getString("count_meta"); + if (font != nullptr && (item.count >= 2 || !count_text.empty())) { // Get the item count as a string - std::string text = itos(item.count); - v2u32 dim = font->getDimension(utf8_to_wide(text).c_str()); + std::string text = count_text.empty() ? itos(item.count) : count_text; + v2u32 dim = font->getDimension(utf8_to_wide(unescape_enriched(text)).c_str()); v2s32 sdim(dim.X, dim.Y); core::rect rect2( - /*rect.UpperLeftCorner, - core::dimension2d(rect.getWidth(), 15)*/ rect.LowerRightCorner - sdim, - sdim + rect.LowerRightCorner ); - video::SColor bgcolor(128, 0, 0, 0); - driver->draw2DRectangle(bgcolor, rect2, clip); + // get the count alignment + s32 count_alignment = stoi(item.metadata.getString("count_alignment")); + if (count_alignment != 0) { + s32 a_x = count_alignment & 3; + s32 a_y = (count_alignment >> 2) & 3; + + s32 x1, x2, y1, y2; + switch (a_x) { + case 1: // left + x1 = rect.UpperLeftCorner.X; + x2 = x1 + sdim.X; + break; + case 2: // middle + x1 = (rect.UpperLeftCorner.X + rect.LowerRightCorner.X - sdim.X) / 2; + x2 = x1 + sdim.X; + break; + case 3: // right + x2 = rect.LowerRightCorner.X; + x1 = x2 - sdim.X; + break; + default: // 0 = default + x1 = rect2.UpperLeftCorner.X; + x2 = rect2.LowerRightCorner.X; + break; + } + + switch (a_y) { + case 1: // up + y1 = rect.UpperLeftCorner.Y; + y2 = y1 + sdim.Y; + break; + case 2: // middle + y1 = (rect.UpperLeftCorner.Y + rect.LowerRightCorner.Y - sdim.Y) / 2; + y2 = y1 + sdim.Y; + break; + case 3: // down + y2 = rect.LowerRightCorner.Y; + y1 = y2 - sdim.Y; + break; + default: // 0 = default + y1 = rect2.UpperLeftCorner.Y; + y2 = rect2.LowerRightCorner.Y; + break; + } + + rect2 = core::rect(x1, y1, x2, y2); + } video::SColor color(255, 255, 255, 255); - font->draw(text.c_str(), rect2, color, false, false, clip); + font->draw(utf8_to_wide(text).c_str(), rect2, color, false, false, &viewrect); } }