3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2010-2013 blue42u, Jonathon Anderson <anderjon@umail.iu.edu>
5 Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "client/hud.h"
25 #include "util/numeric.h"
28 #include "inventory.h"
30 #include "client/tile.h"
31 #include "localplayer.h"
34 #include "fontengine.h"
35 #include "guiscalingfilter.h"
37 #include "wieldmesh.h"
38 #include "client/renderingengine.h"
40 #ifdef HAVE_TOUCHSCREENGUI
41 #include "gui/touchscreengui.h"
44 Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
47 driver = RenderingEngine::get_video_driver();
48 this->guienv = guienv;
49 this->client = client;
50 this->player = player;
51 this->inventory = inventory;
53 m_hud_scaling = g_settings->getFloat("hud_scaling");
54 m_hotbar_imagesize = std::floor(HOTBAR_IMAGE_SIZE *
55 RenderingEngine::getDisplayDensity() + 0.5f);
56 m_hotbar_imagesize *= m_hud_scaling;
57 m_padding = m_hotbar_imagesize / 12;
59 for (auto &hbar_color : hbar_colors)
60 hbar_color = video::SColor(255, 255, 255, 255);
62 tsrc = client->getTextureSource();
64 v3f crosshair_color = g_settings->getV3F("crosshair_color");
65 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
66 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
67 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
68 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
69 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
71 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
72 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
73 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
74 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
75 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
77 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
79 m_selection_boxes.clear();
82 std::string mode_setting = g_settings->get("node_highlighting");
84 if (mode_setting == "halo") {
85 m_mode = HIGHLIGHT_HALO;
86 } else if (mode_setting == "none") {
87 m_mode = HIGHLIGHT_NONE;
89 m_mode = HIGHLIGHT_BOX;
92 m_selection_material.Lighting = false;
94 if (g_settings->getBool("enable_shaders")) {
95 IShaderSource *shdrsrc = client->getShaderSource();
96 u16 shader_id = shdrsrc->getShader(
97 m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
98 m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
100 m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
103 if (m_mode == HIGHLIGHT_BOX) {
104 m_selection_material.Thickness =
105 rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
106 } else if (m_mode == HIGHLIGHT_HALO) {
107 m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
108 m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
110 m_selection_material.MaterialType = video::EMT_SOLID;
116 if (m_selection_mesh)
117 m_selection_mesh->drop();
120 void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
124 /* draw hihlighting around selected item */
125 if (use_hotbar_selected_image) {
126 core::rect<s32> imgrect2 = rect;
127 imgrect2.UpperLeftCorner.X -= (m_padding*2);
128 imgrect2.UpperLeftCorner.Y -= (m_padding*2);
129 imgrect2.LowerRightCorner.X += (m_padding*2);
130 imgrect2.LowerRightCorner.Y += (m_padding*2);
131 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
132 core::dimension2di imgsize(texture->getOriginalSize());
133 draw2DImageFilterScaled(driver, texture, imgrect2,
134 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
135 NULL, hbar_colors, true);
137 video::SColor c_outside(255,255,0,0);
138 //video::SColor c_outside(255,0,0,0);
139 //video::SColor c_inside(255,192,192,192);
140 s32 x1 = rect.UpperLeftCorner.X;
141 s32 y1 = rect.UpperLeftCorner.Y;
142 s32 x2 = rect.LowerRightCorner.X;
143 s32 y2 = rect.LowerRightCorner.Y;
144 // Black base borders
145 driver->draw2DRectangle(c_outside,
147 v2s32(x1 - m_padding, y1 - m_padding),
148 v2s32(x2 + m_padding, y1)
150 driver->draw2DRectangle(c_outside,
152 v2s32(x1 - m_padding, y2),
153 v2s32(x2 + m_padding, y2 + m_padding)
155 driver->draw2DRectangle(c_outside,
157 v2s32(x1 - m_padding, y1),
160 driver->draw2DRectangle(c_outside,
163 v2s32(x2 + m_padding, y2)
165 /*// Light inside borders
166 driver->draw2DRectangle(c_inside,
168 v2s32(x1 - padding/2, y1 - padding/2),
169 v2s32(x2 + padding/2, y1)
171 driver->draw2DRectangle(c_inside,
173 v2s32(x1 - padding/2, y2),
174 v2s32(x2 + padding/2, y2 + padding/2)
176 driver->draw2DRectangle(c_inside,
178 v2s32(x1 - padding/2, y1),
181 driver->draw2DRectangle(c_inside,
184 v2s32(x2 + padding/2, y2)
190 video::SColor bgcolor2(128, 0, 0, 0);
191 if (!use_hotbar_image)
192 driver->draw2DRectangle(bgcolor2, rect, NULL);
193 drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
194 client, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
197 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
198 void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
199 s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction)
201 #ifdef HAVE_TOUCHSCREENGUI
202 if (g_touchscreengui && inv_offset == 0)
203 g_touchscreengui->resetHud();
206 s32 height = m_hotbar_imagesize + m_padding * 2;
207 s32 width = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2);
209 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
215 // Position of upper left corner of bar
216 v2s32 pos = screen_offset;
217 pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity();
218 pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity();
221 // Store hotbar_image in member variable, used by drawItem()
222 if (hotbar_image != player->hotbar_image) {
223 hotbar_image = player->hotbar_image;
224 use_hotbar_image = !hotbar_image.empty();
227 // Store hotbar_selected_image in member variable, used by drawItem()
228 if (hotbar_selected_image != player->hotbar_selected_image) {
229 hotbar_selected_image = player->hotbar_selected_image;
230 use_hotbar_selected_image = !hotbar_selected_image.empty();
233 // draw customized item background
234 if (use_hotbar_image) {
235 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
236 width+m_padding/2, height+m_padding/2);
237 core::rect<s32> rect2 = imgrect2 + pos;
238 video::ITexture *texture = tsrc->getTexture(hotbar_image);
239 core::dimension2di imgsize(texture->getOriginalSize());
240 draw2DImageFilterScaled(driver, texture, rect2,
241 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
242 NULL, hbar_colors, true);
246 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
247 for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) {
248 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
252 case HUD_DIR_RIGHT_LEFT:
253 steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding);
255 case HUD_DIR_TOP_BOTTOM:
256 steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen);
258 case HUD_DIR_BOTTOM_TOP:
259 steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen));
262 steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding);
266 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem);
268 #ifdef HAVE_TOUCHSCREENGUI
269 if (g_touchscreengui)
270 g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
275 // Calculates screen position of waypoint. Returns true if waypoint is visible (in front of the player), else false.
276 bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos)
278 v3f w_pos = e->world_pos * BS;
279 scene::ICameraSceneNode* camera =
280 RenderingEngine::get_scene_manager()->getActiveCamera();
281 w_pos -= intToFloat(camera_offset, BS);
282 core::matrix4 trans = camera->getProjectionMatrix();
283 trans *= camera->getViewMatrix();
284 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
285 trans.multiplyWith1x4Matrix(transformed_pos);
286 if (transformed_pos[3] < 0)
288 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
289 core::reciprocal(transformed_pos[3]);
290 pos->X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
291 pos->Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
295 void Hud::drawLuaElements(const v3s16 &camera_offset)
297 u32 text_height = g_fontengine->getTextHeight();
298 irr::gui::IGUIFont* font = g_fontengine->getFont();
300 // Reorder elements by z_index
301 std::vector<size_t> ids;
303 for (size_t i = 0; i != player->maxHudId(); i++) {
304 HudElement *e = player->getHud(i);
308 auto it = ids.begin();
309 while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index)
315 for (size_t i : ids) {
316 HudElement *e = player->getHud(i);
318 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
319 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
321 case HUD_ELEM_TEXT: {
322 video::SColor color(255, (e->number >> 16) & 0xFF,
323 (e->number >> 8) & 0xFF,
324 (e->number >> 0) & 0xFF);
325 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
326 std::wstring text = unescape_translate(utf8_to_wide(e->text));
327 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
328 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
329 (e->align.Y - 1.0) * (textsize.Height / 2));
330 v2s32 offs(e->offset.X, e->offset.Y);
331 font->draw(text.c_str(), size + pos + offset + offs, color);
333 case HUD_ELEM_STATBAR: {
334 v2s32 offs(e->offset.X, e->offset.Y);
335 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->text2,
336 e->number, e->item, offs, e->size);
338 case HUD_ELEM_INVENTORY: {
339 InventoryList *inv = inventory->getList(e->text);
340 drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
341 inv, e->item, e->dir);
343 case HUD_ELEM_WAYPOINT: {
344 if (!calculateScreenPos(camera_offset, e, &pos))
346 v3f p_pos = player->getPosition() / BS;
347 pos += v2s32(e->offset.X, e->offset.Y);
348 video::SColor color(255, (e->number >> 16) & 0xFF,
349 (e->number >> 8) & 0xFF,
350 (e->number >> 0) & 0xFF);
351 std::wstring text = unescape_translate(utf8_to_wide(e->name));
352 const std::string &unit = e->text;
353 // waypoints reuse the item field to store precision, item = precision + 1
355 float precision = (item == 0) ? 10.0f : (item - 1.f);
356 bool draw_precision = precision > 0;
358 core::rect<s32> bounds(0, 0, font->getDimension(text.c_str()).Width, (draw_precision ? 2:1) * text_height);
359 pos.Y += (e->align.Y - 1.0) * bounds.getHeight() / 2;
361 font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0) * bounds.getWidth() / 2, 0), color);
362 if (draw_precision) {
363 std::ostringstream os;
364 float distance = std::floor(precision * p_pos.getDistanceFrom(e->world_pos)) / precision;
365 os << distance << unit;
366 text = unescape_translate(utf8_to_wide(os.str()));
367 bounds.LowerRightCorner.X = bounds.UpperLeftCorner.X + font->getDimension(text.c_str()).Width;
368 font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0f) * bounds.getWidth() / 2, text_height), color);
371 case HUD_ELEM_IMAGE_WAYPOINT: {
372 if (!calculateScreenPos(camera_offset, e, &pos))
375 case HUD_ELEM_IMAGE: {
376 video::ITexture *texture = tsrc->getTexture(e->text);
380 const video::SColor color(255, 255, 255, 255);
381 const video::SColor colors[] = {color, color, color, color};
382 core::dimension2di imgsize(texture->getOriginalSize());
383 v2s32 dstsize(imgsize.Width * e->scale.X,
384 imgsize.Height * e->scale.Y);
386 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
388 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
389 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
390 (e->align.Y - 1.0) * dstsize.Y / 2);
391 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
392 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
393 draw2DImageFilterScaled(driver, texture, rect,
394 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
398 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
399 " of hud element ID " << i << " due to unrecognized type" << std::endl;
405 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
406 const std::string &texture, const std::string &bgtexture,
407 s32 count, s32 maxcount, v2s32 offset, v2s32 size)
409 const video::SColor color(255, 255, 255, 255);
410 const video::SColor colors[] = {color, color, color, color};
412 video::ITexture *stat_texture = tsrc->getTexture(texture);
416 video::ITexture *stat_texture_bg = nullptr;
417 if (!bgtexture.empty()) {
418 stat_texture_bg = tsrc->getTexture(bgtexture);
421 core::dimension2di srcd(stat_texture->getOriginalSize());
422 core::dimension2di dstd;
423 if (size == v2s32()) {
426 float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
427 dstd.Height = size.Y * size_factor;
428 dstd.Width = size.X * size_factor;
429 offset.X *= size_factor;
430 offset.Y *= size_factor;
434 if (corner & HUD_CORNER_LOWER)
441 case HUD_DIR_RIGHT_LEFT:
442 steppos = v2s32(-1, 0);
444 case HUD_DIR_TOP_BOTTOM:
445 steppos = v2s32(0, 1);
447 case HUD_DIR_BOTTOM_TOP:
448 steppos = v2s32(0, -1);
451 // From left to right
452 steppos = v2s32(1, 0);
456 auto calculate_clipping_rect = [] (core::dimension2di src,
457 v2s32 steppos) -> core::rect<s32> {
459 // Create basic rectangle
460 core::rect<s32> rect(0, 0,
461 src.Width - std::abs(steppos.X) * src.Width / 2,
462 src.Height - std::abs(steppos.Y) * src.Height / 2
464 // Move rectangle left or down
466 rect += v2s32(src.Width / 2, 0);
468 rect += v2s32(0, src.Height / 2);
471 // Rectangles for 1/2 the actual value to display
472 core::rect<s32> srchalfrect, dsthalfrect;
473 // Rectangles for 1/2 the "off state" texture
474 core::rect<s32> srchalfrect2, dsthalfrect2;
476 if (count % 2 == 1) {
477 // Need to draw halves: Calculate rectangles
478 srchalfrect = calculate_clipping_rect(srcd, steppos);
479 dsthalfrect = calculate_clipping_rect(dstd, steppos);
480 srchalfrect2 = calculate_clipping_rect(srcd, steppos * -1);
481 dsthalfrect2 = calculate_clipping_rect(dstd, steppos * -1);
484 steppos.X *= dstd.Width;
485 steppos.Y *= dstd.Height;
487 // Draw full textures
488 for (s32 i = 0; i < count / 2; i++) {
489 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
490 core::rect<s32> dstrect(0, 0, dstd.Width, dstd.Height);
493 draw2DImageFilterScaled(driver, stat_texture,
494 dstrect, srcrect, NULL, colors, true);
498 if (count % 2 == 1) {
499 // Draw half a texture
500 draw2DImageFilterScaled(driver, stat_texture,
501 dsthalfrect + p, srchalfrect, NULL, colors, true);
503 if (stat_texture_bg && maxcount > count) {
504 draw2DImageFilterScaled(driver, stat_texture_bg,
505 dsthalfrect2 + p, srchalfrect2,
511 if (stat_texture_bg && maxcount > count / 2) {
512 // Draw "off state" textures
515 start_offset = count / 2 + 1;
517 start_offset = count / 2;
518 for (s32 i = start_offset; i < maxcount / 2; i++) {
519 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
520 core::rect<s32> dstrect(0, 0, dstd.Width, dstd.Height);
523 draw2DImageFilterScaled(driver, stat_texture_bg,
529 if (maxcount % 2 == 1) {
530 draw2DImageFilterScaled(driver, stat_texture_bg,
531 dsthalfrect + p, srchalfrect,
538 void Hud::drawHotbar(u16 playeritem) {
540 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
542 InventoryList *mainlist = inventory->getList("main");
543 if (mainlist == NULL) {
544 //silently ignore this we may not be initialized completely
548 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
549 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
550 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
552 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
553 if ( (float) width / (float) window_size.X <=
554 g_settings->getFloat("hud_hotbar_max_width")) {
555 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
556 drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
561 v2s32 secondpos = pos;
562 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
564 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
565 drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
566 mainlist, playeritem + 1, 0);
567 drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
568 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
574 void Hud::drawCrosshair()
576 if (use_crosshair_image) {
577 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
578 v2u32 size = crosshair->getOriginalSize();
579 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
580 m_displaycenter.Y - (size.Y / 2));
581 driver->draw2DImage(crosshair, lsize,
582 core::rect<s32>(0, 0, size.X, size.Y),
583 0, crosshair_argb, true);
585 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
586 m_displaycenter + v2s32(10, 0), crosshair_argb);
587 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
588 m_displaycenter + v2s32(0, 10), crosshair_argb);
592 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
594 m_camera_offset = camera_offset;
595 m_selection_pos = pos;
596 m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
599 void Hud::drawSelectionMesh()
601 if (m_mode == HIGHLIGHT_BOX) {
602 // Draw 3D selection boxes
603 video::SMaterial oldmaterial = driver->getMaterial2D();
604 driver->setMaterial(m_selection_material);
605 for (std::vector<aabb3f>::const_iterator
606 i = m_selection_boxes.begin();
607 i != m_selection_boxes.end(); ++i) {
609 i->MinEdge + m_selection_pos_with_offset,
610 i->MaxEdge + m_selection_pos_with_offset);
612 u32 r = (selectionbox_argb.getRed() *
613 m_selection_mesh_color.getRed() / 255);
614 u32 g = (selectionbox_argb.getGreen() *
615 m_selection_mesh_color.getGreen() / 255);
616 u32 b = (selectionbox_argb.getBlue() *
617 m_selection_mesh_color.getBlue() / 255);
618 driver->draw3DBox(box, video::SColor(255, r, g, b));
620 driver->setMaterial(oldmaterial);
621 } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
622 // Draw selection mesh
623 video::SMaterial oldmaterial = driver->getMaterial2D();
624 driver->setMaterial(m_selection_material);
625 setMeshColor(m_selection_mesh, m_selection_mesh_color);
626 video::SColor face_color(0,
627 MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
628 MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
629 MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
630 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
632 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
633 translateMesh(mesh, m_selection_pos_with_offset);
634 u32 mc = m_selection_mesh->getMeshBufferCount();
635 for (u32 i = 0; i < mc; i++) {
636 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
637 driver->drawMeshBuffer(buf);
640 driver->setMaterial(oldmaterial);
644 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
646 m_camera_offset = camera_offset;
647 if (m_mode != HIGHLIGHT_HALO)
650 if (m_selection_mesh) {
651 m_selection_mesh->drop();
652 m_selection_mesh = NULL;
655 if (m_selection_boxes.empty()) {
660 // New pointed object, create new mesh.
662 // Texture UV coordinates for selection boxes
663 static f32 texture_uv[24] = {
672 // Use single halo box instead of multiple overlapping boxes.
673 // Temporary solution - problem can be solved with multiple
674 // rendering targets, or some method to remove inner surfaces.
675 // Thats because of halo transparency.
677 aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
678 m_halo_boxes.clear();
680 for (const auto &selection_box : m_selection_boxes) {
681 halo_box.addInternalBox(selection_box);
684 m_halo_boxes.push_back(halo_box);
685 m_selection_mesh = convertNodeboxesToMesh(
686 m_halo_boxes, texture_uv, 0.5);
689 void Hud::resizeHotbar() {
690 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
692 if (m_screensize != window_size) {
693 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
694 RenderingEngine::getDisplayDensity() + 0.5);
695 m_hotbar_imagesize *= m_hud_scaling;
696 m_padding = m_hotbar_imagesize / 12;
697 m_screensize = window_size;
698 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
702 struct MeshTimeInfo {
704 scene::IMesh *mesh = nullptr;
708 video::IVideoDriver *driver,
710 const ItemStack &item,
711 const core::rect<s32> &rect,
712 const core::rect<s32> *clip,
714 ItemRotationKind rotation_kind,
716 const v3s16 &rotation_speed)
718 static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
721 if (rotation_kind < IT_ROT_NONE && rotation_kind != IT_ROT_OTHER) {
722 rotation_time_infos[rotation_kind].mesh = NULL;
727 const ItemDefinition &def = item.getDefinition(client->idef());
728 ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
730 if (imesh && imesh->mesh) {
731 scene::IMesh *mesh = imesh->mesh;
732 driver->clearZBuffer();
734 if (rotation_kind < IT_ROT_NONE) {
735 MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
736 if (mesh != ti.mesh && rotation_kind != IT_ROT_OTHER) {
738 ti.time = porting::getTimeMs();
740 delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
743 core::rect<s32> oldViewPort = driver->getViewPort();
744 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
745 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
746 core::rect<s32> viewrect = rect;
748 viewrect.clipAgainst(*clip);
750 core::matrix4 ProjMatrix;
751 ProjMatrix.buildProjectionMatrixOrthoLH(2.0f, 2.0f, -1.0f, 100.0f);
753 core::matrix4 ViewMatrix;
754 ViewMatrix.buildProjectionMatrixOrthoLH(
755 2.0f * viewrect.getWidth() / rect.getWidth(),
756 2.0f * viewrect.getHeight() / rect.getHeight(),
759 ViewMatrix.setTranslation(core::vector3df(
760 1.0f * (rect.LowerRightCorner.X + rect.UpperLeftCorner.X -
761 viewrect.LowerRightCorner.X - viewrect.UpperLeftCorner.X) /
763 1.0f * (viewrect.LowerRightCorner.Y + viewrect.UpperLeftCorner.Y -
764 rect.LowerRightCorner.Y - rect.UpperLeftCorner.Y) /
765 viewrect.getHeight(),
768 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
769 driver->setTransform(video::ETS_VIEW, ViewMatrix);
771 core::matrix4 matrix;
772 matrix.makeIdentity();
774 static thread_local bool enable_animations =
775 g_settings->getBool("inventory_items_animations");
777 if (enable_animations) {
778 float timer_f = (float) delta / 5000.f;
779 matrix.setRotationDegrees(v3f(
780 angle.X + rotation_speed.X * 3.60f * timer_f,
781 angle.Y + rotation_speed.Y * 3.60f * timer_f,
782 angle.Z + rotation_speed.Z * 3.60f * timer_f)
786 driver->setTransform(video::ETS_WORLD, matrix);
787 driver->setViewPort(viewrect);
789 video::SColor basecolor =
790 client->idef()->getItemstackColor(item, client);
792 u32 mc = mesh->getMeshBufferCount();
793 for (u32 j = 0; j < mc; ++j) {
794 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
795 // we can modify vertices relatively fast,
796 // because these meshes are not buffered.
797 assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
798 video::SColor c = basecolor;
800 if (imesh->buffer_colors.size() > j) {
801 ItemPartColor *p = &imesh->buffer_colors[j];
802 if (p->override_base)
806 if (imesh->needs_shading)
807 colorizeMeshBuffer(buf, &c);
809 setMeshBufferColor(buf, c);
811 video::SMaterial &material = buf->getMaterial();
812 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
813 material.Lighting = false;
814 driver->setMaterial(material);
815 driver->drawMeshBuffer(buf);
818 driver->setTransform(video::ETS_VIEW, oldViewMat);
819 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
820 driver->setViewPort(oldViewPort);
822 // draw the inventory_overlay
823 if (def.type == ITEM_NODE && def.inventory_image.empty() &&
824 !def.inventory_overlay.empty()) {
825 ITextureSource *tsrc = client->getTextureSource();
826 video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
827 core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
828 core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
829 draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
833 if (def.type == ITEM_TOOL && item.wear != 0) {
834 // Draw a progressbar
835 float barheight = rect.getHeight() / 16;
836 float barpad_x = rect.getWidth() / 16;
837 float barpad_y = rect.getHeight() / 16;
839 core::rect<s32> progressrect(
840 rect.UpperLeftCorner.X + barpad_x,
841 rect.LowerRightCorner.Y - barpad_y - barheight,
842 rect.LowerRightCorner.X - barpad_x,
843 rect.LowerRightCorner.Y - barpad_y);
845 // Shrink progressrect by amount of tool damage
846 float wear = item.wear / 65535.0f;
848 wear * progressrect.UpperLeftCorner.X +
849 (1 - wear) * progressrect.LowerRightCorner.X;
851 // Compute progressbar color
853 // wear = 0.5: yellow
855 video::SColor color(255, 255, 255, 255);
856 int wear_i = MYMIN(std::floor(wear * 600), 511);
857 wear_i = MYMIN(wear_i + 10, 511);
860 color.set(255, wear_i, 255, 0);
862 color.set(255, 255, 511 - wear_i, 0);
864 core::rect<s32> progressrect2 = progressrect;
865 progressrect2.LowerRightCorner.X = progressmid;
866 driver->draw2DRectangle(color, progressrect2, clip);
868 color = video::SColor(255, 0, 0, 0);
869 progressrect2 = progressrect;
870 progressrect2.UpperLeftCorner.X = progressmid;
871 driver->draw2DRectangle(color, progressrect2, clip);
874 if (font != NULL && item.count >= 2) {
875 // Get the item count as a string
876 std::string text = itos(item.count);
877 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
878 v2s32 sdim(dim.X, dim.Y);
880 core::rect<s32> rect2(
881 /*rect.UpperLeftCorner,
882 core::dimension2d<u32>(rect.getWidth(), 15)*/
883 rect.LowerRightCorner - sdim,
887 video::SColor bgcolor(128, 0, 0, 0);
888 driver->draw2DRectangle(bgcolor, rect2, clip);
890 video::SColor color(255, 255, 255, 255);
891 font->draw(text.c_str(), rect2, color, false, false, clip);
896 video::IVideoDriver *driver,
898 const ItemStack &item,
899 const core::rect<s32> &rect,
900 const core::rect<s32> *clip,
902 ItemRotationKind rotation_kind)
904 drawItemStack(driver, font, item, rect, clip, client, rotation_kind,
905 v3s16(0, 0, 0), v3s16(0, 100, 0));