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->number, offs, e->size);
337 case HUD_ELEM_INVENTORY: {
338 InventoryList *inv = inventory->getList(e->text);
339 drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
340 inv, e->item, e->dir);
342 case HUD_ELEM_WAYPOINT: {
343 if (!calculateScreenPos(camera_offset, e, &pos))
345 v3f p_pos = player->getPosition() / BS;
346 pos += v2s32(e->offset.X, e->offset.Y);
347 video::SColor color(255, (e->number >> 16) & 0xFF,
348 (e->number >> 8) & 0xFF,
349 (e->number >> 0) & 0xFF);
350 std::wstring text = unescape_translate(utf8_to_wide(e->name));
351 const std::string &unit = e->text;
352 // waypoints reuse the item field to store precision, item = precision + 1
354 float precision = (item == 0) ? 10.0f : (item - 1.f);
355 bool draw_precision = precision > 0;
357 core::rect<s32> bounds(0, 0, font->getDimension(text.c_str()).Width, (draw_precision ? 2:1) * text_height);
358 pos.Y += (e->align.Y - 1.0) * bounds.getHeight() / 2;
360 font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0) * bounds.getWidth() / 2, 0), color);
361 if (draw_precision) {
362 std::ostringstream os;
363 float distance = std::floor(precision * p_pos.getDistanceFrom(e->world_pos)) / precision;
364 os << distance << unit;
365 text = unescape_translate(utf8_to_wide(os.str()));
366 bounds.LowerRightCorner.X = bounds.UpperLeftCorner.X + font->getDimension(text.c_str()).Width;
367 font->draw(text.c_str(), bounds + v2s32((e->align.X - 1.0f) * bounds.getWidth() / 2, text_height), color);
370 case HUD_ELEM_IMAGE_WAYPOINT: {
371 if (!calculateScreenPos(camera_offset, e, &pos))
374 case HUD_ELEM_IMAGE: {
375 video::ITexture *texture = tsrc->getTexture(e->text);
379 const video::SColor color(255, 255, 255, 255);
380 const video::SColor colors[] = {color, color, color, color};
381 core::dimension2di imgsize(texture->getOriginalSize());
382 v2s32 dstsize(imgsize.Width * e->scale.X,
383 imgsize.Height * e->scale.Y);
385 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
387 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
388 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
389 (e->align.Y - 1.0) * dstsize.Y / 2);
390 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
391 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
392 draw2DImageFilterScaled(driver, texture, rect,
393 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
397 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
398 " of hud element ID " << i << " due to unrecognized type" << std::endl;
404 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture,
405 s32 count, v2s32 offset, v2s32 size)
407 const video::SColor color(255, 255, 255, 255);
408 const video::SColor colors[] = {color, color, color, color};
410 video::ITexture *stat_texture = tsrc->getTexture(texture);
414 core::dimension2di srcd(stat_texture->getOriginalSize());
415 core::dimension2di dstd;
416 if (size == v2s32()) {
419 float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
420 dstd.Height = size.Y * size_factor;
421 dstd.Width = size.X * size_factor;
422 offset.X *= size_factor;
423 offset.Y *= size_factor;
427 if (corner & HUD_CORNER_LOWER)
433 core::rect<s32> srchalfrect, dsthalfrect;
435 case HUD_DIR_RIGHT_LEFT:
436 steppos = v2s32(-1, 0);
437 srchalfrect = core::rect<s32>(srcd.Width / 2, 0, srcd.Width, srcd.Height);
438 dsthalfrect = core::rect<s32>(dstd.Width / 2, 0, dstd.Width, dstd.Height);
440 case HUD_DIR_TOP_BOTTOM:
441 steppos = v2s32(0, 1);
442 srchalfrect = core::rect<s32>(0, 0, srcd.Width, srcd.Height / 2);
443 dsthalfrect = core::rect<s32>(0, 0, dstd.Width, dstd.Height / 2);
445 case HUD_DIR_BOTTOM_TOP:
446 steppos = v2s32(0, -1);
447 srchalfrect = core::rect<s32>(0, srcd.Height / 2, srcd.Width, srcd.Height);
448 dsthalfrect = core::rect<s32>(0, dstd.Height / 2, dstd.Width, dstd.Height);
451 steppos = v2s32(1, 0);
452 srchalfrect = core::rect<s32>(0, 0, srcd.Width / 2, srcd.Height);
453 dsthalfrect = core::rect<s32>(0, 0, dstd.Width / 2, dstd.Height);
455 steppos.X *= dstd.Width;
456 steppos.Y *= dstd.Height;
458 for (s32 i = 0; i < count / 2; i++) {
459 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
460 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
463 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
467 if (count % 2 == 1) {
469 draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
474 void Hud::drawHotbar(u16 playeritem) {
476 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
478 InventoryList *mainlist = inventory->getList("main");
479 if (mainlist == NULL) {
480 //silently ignore this we may not be initialized completely
484 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
485 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
486 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
488 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
489 if ( (float) width / (float) window_size.X <=
490 g_settings->getFloat("hud_hotbar_max_width")) {
491 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
492 drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
497 v2s32 secondpos = pos;
498 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
500 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
501 drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
502 mainlist, playeritem + 1, 0);
503 drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
504 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
510 void Hud::drawCrosshair()
512 if (use_crosshair_image) {
513 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
514 v2u32 size = crosshair->getOriginalSize();
515 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
516 m_displaycenter.Y - (size.Y / 2));
517 driver->draw2DImage(crosshair, lsize,
518 core::rect<s32>(0, 0, size.X, size.Y),
519 0, crosshair_argb, true);
521 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
522 m_displaycenter + v2s32(10, 0), crosshair_argb);
523 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
524 m_displaycenter + v2s32(0, 10), crosshair_argb);
528 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
530 m_camera_offset = camera_offset;
531 m_selection_pos = pos;
532 m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
535 void Hud::drawSelectionMesh()
537 if (m_mode == HIGHLIGHT_BOX) {
538 // Draw 3D selection boxes
539 video::SMaterial oldmaterial = driver->getMaterial2D();
540 driver->setMaterial(m_selection_material);
541 for (std::vector<aabb3f>::const_iterator
542 i = m_selection_boxes.begin();
543 i != m_selection_boxes.end(); ++i) {
545 i->MinEdge + m_selection_pos_with_offset,
546 i->MaxEdge + m_selection_pos_with_offset);
548 u32 r = (selectionbox_argb.getRed() *
549 m_selection_mesh_color.getRed() / 255);
550 u32 g = (selectionbox_argb.getGreen() *
551 m_selection_mesh_color.getGreen() / 255);
552 u32 b = (selectionbox_argb.getBlue() *
553 m_selection_mesh_color.getBlue() / 255);
554 driver->draw3DBox(box, video::SColor(255, r, g, b));
556 driver->setMaterial(oldmaterial);
557 } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
558 // Draw selection mesh
559 video::SMaterial oldmaterial = driver->getMaterial2D();
560 driver->setMaterial(m_selection_material);
561 setMeshColor(m_selection_mesh, m_selection_mesh_color);
562 video::SColor face_color(0,
563 MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
564 MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
565 MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
566 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
568 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
569 translateMesh(mesh, m_selection_pos_with_offset);
570 u32 mc = m_selection_mesh->getMeshBufferCount();
571 for (u32 i = 0; i < mc; i++) {
572 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
573 driver->drawMeshBuffer(buf);
576 driver->setMaterial(oldmaterial);
580 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
582 m_camera_offset = camera_offset;
583 if (m_mode != HIGHLIGHT_HALO)
586 if (m_selection_mesh) {
587 m_selection_mesh->drop();
588 m_selection_mesh = NULL;
591 if (m_selection_boxes.empty()) {
596 // New pointed object, create new mesh.
598 // Texture UV coordinates for selection boxes
599 static f32 texture_uv[24] = {
608 // Use single halo box instead of multiple overlapping boxes.
609 // Temporary solution - problem can be solved with multiple
610 // rendering targets, or some method to remove inner surfaces.
611 // Thats because of halo transparency.
613 aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
614 m_halo_boxes.clear();
616 for (const auto &selection_box : m_selection_boxes) {
617 halo_box.addInternalBox(selection_box);
620 m_halo_boxes.push_back(halo_box);
621 m_selection_mesh = convertNodeboxesToMesh(
622 m_halo_boxes, texture_uv, 0.5);
625 void Hud::resizeHotbar() {
626 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
628 if (m_screensize != window_size) {
629 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
630 RenderingEngine::getDisplayDensity() + 0.5);
631 m_hotbar_imagesize *= m_hud_scaling;
632 m_padding = m_hotbar_imagesize / 12;
633 m_screensize = window_size;
634 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
638 struct MeshTimeInfo {
640 scene::IMesh *mesh = nullptr;
644 video::IVideoDriver *driver,
646 const ItemStack &item,
647 const core::rect<s32> &rect,
648 const core::rect<s32> *clip,
650 ItemRotationKind rotation_kind,
652 const v3s16 &rotation_speed)
654 static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
657 if (rotation_kind < IT_ROT_NONE && rotation_kind != IT_ROT_OTHER) {
658 rotation_time_infos[rotation_kind].mesh = NULL;
663 const ItemDefinition &def = item.getDefinition(client->idef());
664 ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
666 if (imesh && imesh->mesh) {
667 scene::IMesh *mesh = imesh->mesh;
668 driver->clearZBuffer();
670 if (rotation_kind < IT_ROT_NONE) {
671 MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
672 if (mesh != ti.mesh && rotation_kind != IT_ROT_OTHER) {
674 ti.time = porting::getTimeMs();
676 delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
679 core::rect<s32> oldViewPort = driver->getViewPort();
680 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
681 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
682 core::rect<s32> viewrect = rect;
684 viewrect.clipAgainst(*clip);
686 core::matrix4 ProjMatrix;
687 ProjMatrix.buildProjectionMatrixOrthoLH(2.0f, 2.0f, -1.0f, 100.0f);
689 core::matrix4 ViewMatrix;
690 ViewMatrix.buildProjectionMatrixOrthoLH(
691 2.0f * viewrect.getWidth() / rect.getWidth(),
692 2.0f * viewrect.getHeight() / rect.getHeight(),
695 ViewMatrix.setTranslation(core::vector3df(
696 1.0f * (rect.LowerRightCorner.X + rect.UpperLeftCorner.X -
697 viewrect.LowerRightCorner.X - viewrect.UpperLeftCorner.X) /
699 1.0f * (viewrect.LowerRightCorner.Y + viewrect.UpperLeftCorner.Y -
700 rect.LowerRightCorner.Y - rect.UpperLeftCorner.Y) /
701 viewrect.getHeight(),
704 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
705 driver->setTransform(video::ETS_VIEW, ViewMatrix);
707 core::matrix4 matrix;
708 matrix.makeIdentity();
710 static thread_local bool enable_animations =
711 g_settings->getBool("inventory_items_animations");
713 if (enable_animations) {
714 float timer_f = (float) delta / 5000.f;
715 matrix.setRotationDegrees(v3f(
716 angle.X + rotation_speed.X * 3.60f * timer_f,
717 angle.Y + rotation_speed.Y * 3.60f * timer_f,
718 angle.Z + rotation_speed.Z * 3.60f * timer_f)
722 driver->setTransform(video::ETS_WORLD, matrix);
723 driver->setViewPort(viewrect);
725 video::SColor basecolor =
726 client->idef()->getItemstackColor(item, client);
728 u32 mc = mesh->getMeshBufferCount();
729 for (u32 j = 0; j < mc; ++j) {
730 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
731 // we can modify vertices relatively fast,
732 // because these meshes are not buffered.
733 assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
734 video::SColor c = basecolor;
736 if (imesh->buffer_colors.size() > j) {
737 ItemPartColor *p = &imesh->buffer_colors[j];
738 if (p->override_base)
742 if (imesh->needs_shading)
743 colorizeMeshBuffer(buf, &c);
745 setMeshBufferColor(buf, c);
747 video::SMaterial &material = buf->getMaterial();
748 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
749 material.Lighting = false;
750 driver->setMaterial(material);
751 driver->drawMeshBuffer(buf);
754 driver->setTransform(video::ETS_VIEW, oldViewMat);
755 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
756 driver->setViewPort(oldViewPort);
758 // draw the inventory_overlay
759 if (def.type == ITEM_NODE && def.inventory_image.empty() &&
760 !def.inventory_overlay.empty()) {
761 ITextureSource *tsrc = client->getTextureSource();
762 video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
763 core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
764 core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
765 draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
769 if (def.type == ITEM_TOOL && item.wear != 0) {
770 // Draw a progressbar
771 float barheight = rect.getHeight() / 16;
772 float barpad_x = rect.getWidth() / 16;
773 float barpad_y = rect.getHeight() / 16;
775 core::rect<s32> progressrect(
776 rect.UpperLeftCorner.X + barpad_x,
777 rect.LowerRightCorner.Y - barpad_y - barheight,
778 rect.LowerRightCorner.X - barpad_x,
779 rect.LowerRightCorner.Y - barpad_y);
781 // Shrink progressrect by amount of tool damage
782 float wear = item.wear / 65535.0f;
784 wear * progressrect.UpperLeftCorner.X +
785 (1 - wear) * progressrect.LowerRightCorner.X;
787 // Compute progressbar color
789 // wear = 0.5: yellow
791 video::SColor color(255, 255, 255, 255);
792 int wear_i = MYMIN(std::floor(wear * 600), 511);
793 wear_i = MYMIN(wear_i + 10, 511);
796 color.set(255, wear_i, 255, 0);
798 color.set(255, 255, 511 - wear_i, 0);
800 core::rect<s32> progressrect2 = progressrect;
801 progressrect2.LowerRightCorner.X = progressmid;
802 driver->draw2DRectangle(color, progressrect2, clip);
804 color = video::SColor(255, 0, 0, 0);
805 progressrect2 = progressrect;
806 progressrect2.UpperLeftCorner.X = progressmid;
807 driver->draw2DRectangle(color, progressrect2, clip);
810 if (font != NULL && item.count >= 2) {
811 // Get the item count as a string
812 std::string text = itos(item.count);
813 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
814 v2s32 sdim(dim.X, dim.Y);
816 core::rect<s32> rect2(
817 /*rect.UpperLeftCorner,
818 core::dimension2d<u32>(rect.getWidth(), 15)*/
819 rect.LowerRightCorner - sdim,
823 video::SColor bgcolor(128, 0, 0, 0);
824 driver->draw2DRectangle(bgcolor, rect2, clip);
826 video::SColor color(255, 255, 255, 255);
827 font->draw(text.c_str(), rect2, color, false, false, clip);
832 video::IVideoDriver *driver,
834 const ItemStack &item,
835 const core::rect<s32> &rect,
836 const core::rect<s32> *clip,
838 ItemRotationKind rotation_kind)
840 drawItemStack(driver, font, item, rect, clip, client, rotation_kind,
841 v3s16(0, 0, 0), v3s16(0, 100, 0));