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));
276 void Hud::drawLuaElements(const v3s16 &camera_offset)
278 u32 text_height = g_fontengine->getTextHeight();
279 irr::gui::IGUIFont* font = g_fontengine->getFont();
281 // Reorder elements by z_index
282 std::vector<size_t> ids;
284 for (size_t i = 0; i != player->maxHudId(); i++) {
285 HudElement *e = player->getHud(i);
289 auto it = ids.begin();
290 while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index)
296 for (size_t i : ids) {
297 HudElement *e = player->getHud(i);
299 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
300 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
302 case HUD_ELEM_IMAGE: {
303 video::ITexture *texture = tsrc->getTexture(e->text);
307 const video::SColor color(255, 255, 255, 255);
308 const video::SColor colors[] = {color, color, color, color};
309 core::dimension2di imgsize(texture->getOriginalSize());
310 v2s32 dstsize(imgsize.Width * e->scale.X,
311 imgsize.Height * e->scale.Y);
313 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
315 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
316 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
317 (e->align.Y - 1.0) * dstsize.Y / 2);
318 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
319 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
320 draw2DImageFilterScaled(driver, texture, rect,
321 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
324 case HUD_ELEM_TEXT: {
325 video::SColor color(255, (e->number >> 16) & 0xFF,
326 (e->number >> 8) & 0xFF,
327 (e->number >> 0) & 0xFF);
328 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
329 std::wstring text = unescape_translate(utf8_to_wide(e->text));
330 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
331 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
332 (e->align.Y - 1.0) * (textsize.Height / 2));
333 v2s32 offs(e->offset.X, e->offset.Y);
334 font->draw(text.c_str(), size + pos + offset + offs, color);
336 case HUD_ELEM_STATBAR: {
337 v2s32 offs(e->offset.X, e->offset.Y);
338 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
340 case HUD_ELEM_INVENTORY: {
341 InventoryList *inv = inventory->getList(e->text);
342 drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
343 inv, e->item, e->dir);
345 case HUD_ELEM_WAYPOINT: {
346 v3f p_pos = player->getPosition() / BS;
347 v3f w_pos = e->world_pos * BS;
348 float distance = std::floor(10 * p_pos.getDistanceFrom(e->world_pos)) /
350 scene::ICameraSceneNode* camera =
351 RenderingEngine::get_scene_manager()->getActiveCamera();
352 w_pos -= intToFloat(camera_offset, BS);
353 core::matrix4 trans = camera->getProjectionMatrix();
354 trans *= camera->getViewMatrix();
355 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
356 trans.multiplyWith1x4Matrix(transformed_pos);
357 if (transformed_pos[3] < 0)
359 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
360 core::reciprocal(transformed_pos[3]);
361 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
362 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
363 video::SColor color(255, (e->number >> 16) & 0xFF,
364 (e->number >> 8) & 0xFF,
365 (e->number >> 0) & 0xFF);
366 core::rect<s32> size(0, 0, 200, 2 * text_height);
367 std::wstring text = unescape_translate(utf8_to_wide(e->name));
368 font->draw(text.c_str(), size + pos, color);
369 std::ostringstream os;
370 os << distance << e->text;
371 text = unescape_translate(utf8_to_wide(os.str()));
372 pos.Y += text_height;
373 font->draw(text.c_str(), size + pos, color);
376 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
377 " of hud element ID " << i << " due to unrecognized type" << std::endl;
383 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, const std::string &texture,
384 s32 count, v2s32 offset, v2s32 size)
386 const video::SColor color(255, 255, 255, 255);
387 const video::SColor colors[] = {color, color, color, color};
389 video::ITexture *stat_texture = tsrc->getTexture(texture);
393 core::dimension2di srcd(stat_texture->getOriginalSize());
394 core::dimension2di dstd;
395 if (size == v2s32()) {
398 float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
399 dstd.Height = size.Y * size_factor;
400 dstd.Width = size.X * size_factor;
401 offset.X *= size_factor;
402 offset.Y *= size_factor;
406 if (corner & HUD_CORNER_LOWER)
412 core::rect<s32> srchalfrect, dsthalfrect;
414 case HUD_DIR_RIGHT_LEFT:
415 steppos = v2s32(-1, 0);
416 srchalfrect = core::rect<s32>(srcd.Width / 2, 0, srcd.Width, srcd.Height);
417 dsthalfrect = core::rect<s32>(dstd.Width / 2, 0, dstd.Width, dstd.Height);
419 case HUD_DIR_TOP_BOTTOM:
420 steppos = v2s32(0, 1);
421 srchalfrect = core::rect<s32>(0, 0, srcd.Width, srcd.Height / 2);
422 dsthalfrect = core::rect<s32>(0, 0, dstd.Width, dstd.Height / 2);
424 case HUD_DIR_BOTTOM_TOP:
425 steppos = v2s32(0, -1);
426 srchalfrect = core::rect<s32>(0, srcd.Height / 2, srcd.Width, srcd.Height);
427 dsthalfrect = core::rect<s32>(0, dstd.Height / 2, dstd.Width, dstd.Height);
430 steppos = v2s32(1, 0);
431 srchalfrect = core::rect<s32>(0, 0, srcd.Width / 2, srcd.Height);
432 dsthalfrect = core::rect<s32>(0, 0, dstd.Width / 2, dstd.Height);
434 steppos.X *= dstd.Width;
435 steppos.Y *= dstd.Height;
437 for (s32 i = 0; i < count / 2; i++) {
438 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
439 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
442 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
446 if (count % 2 == 1) {
448 draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
453 void Hud::drawHotbar(u16 playeritem) {
455 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
457 InventoryList *mainlist = inventory->getList("main");
458 if (mainlist == NULL) {
459 //silently ignore this we may not be initialized completely
463 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
464 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
465 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
467 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
468 if ( (float) width / (float) window_size.X <=
469 g_settings->getFloat("hud_hotbar_max_width")) {
470 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
471 drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
476 v2s32 secondpos = pos;
477 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
479 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
480 drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
481 mainlist, playeritem + 1, 0);
482 drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
483 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
489 void Hud::drawCrosshair()
491 if (use_crosshair_image) {
492 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
493 v2u32 size = crosshair->getOriginalSize();
494 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
495 m_displaycenter.Y - (size.Y / 2));
496 driver->draw2DImage(crosshair, lsize,
497 core::rect<s32>(0, 0, size.X, size.Y),
498 0, crosshair_argb, true);
500 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
501 m_displaycenter + v2s32(10, 0), crosshair_argb);
502 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
503 m_displaycenter + v2s32(0, 10), crosshair_argb);
507 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
509 m_camera_offset = camera_offset;
510 m_selection_pos = pos;
511 m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
514 void Hud::drawSelectionMesh()
516 if (m_mode == HIGHLIGHT_BOX) {
517 // Draw 3D selection boxes
518 video::SMaterial oldmaterial = driver->getMaterial2D();
519 driver->setMaterial(m_selection_material);
520 for (std::vector<aabb3f>::const_iterator
521 i = m_selection_boxes.begin();
522 i != m_selection_boxes.end(); ++i) {
524 i->MinEdge + m_selection_pos_with_offset,
525 i->MaxEdge + m_selection_pos_with_offset);
527 u32 r = (selectionbox_argb.getRed() *
528 m_selection_mesh_color.getRed() / 255);
529 u32 g = (selectionbox_argb.getGreen() *
530 m_selection_mesh_color.getGreen() / 255);
531 u32 b = (selectionbox_argb.getBlue() *
532 m_selection_mesh_color.getBlue() / 255);
533 driver->draw3DBox(box, video::SColor(255, r, g, b));
535 driver->setMaterial(oldmaterial);
536 } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
537 // Draw selection mesh
538 video::SMaterial oldmaterial = driver->getMaterial2D();
539 driver->setMaterial(m_selection_material);
540 setMeshColor(m_selection_mesh, m_selection_mesh_color);
541 video::SColor face_color(0,
542 MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
543 MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
544 MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
545 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
547 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
548 translateMesh(mesh, m_selection_pos_with_offset);
549 u32 mc = m_selection_mesh->getMeshBufferCount();
550 for (u32 i = 0; i < mc; i++) {
551 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
552 driver->drawMeshBuffer(buf);
555 driver->setMaterial(oldmaterial);
559 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
561 m_camera_offset = camera_offset;
562 if (m_mode != HIGHLIGHT_HALO)
565 if (m_selection_mesh) {
566 m_selection_mesh->drop();
567 m_selection_mesh = NULL;
570 if (m_selection_boxes.empty()) {
575 // New pointed object, create new mesh.
577 // Texture UV coordinates for selection boxes
578 static f32 texture_uv[24] = {
587 // Use single halo box instead of multiple overlapping boxes.
588 // Temporary solution - problem can be solved with multiple
589 // rendering targets, or some method to remove inner surfaces.
590 // Thats because of halo transparency.
592 aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
593 m_halo_boxes.clear();
595 for (const auto &selection_box : m_selection_boxes) {
596 halo_box.addInternalBox(selection_box);
599 m_halo_boxes.push_back(halo_box);
600 m_selection_mesh = convertNodeboxesToMesh(
601 m_halo_boxes, texture_uv, 0.5);
604 void Hud::resizeHotbar() {
605 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
607 if (m_screensize != window_size) {
608 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
609 RenderingEngine::getDisplayDensity() + 0.5);
610 m_hotbar_imagesize *= m_hud_scaling;
611 m_padding = m_hotbar_imagesize / 12;
612 m_screensize = window_size;
613 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
617 struct MeshTimeInfo {
619 scene::IMesh *mesh = nullptr;
623 video::IVideoDriver *driver,
625 const ItemStack &item,
626 const core::rect<s32> &rect,
627 const core::rect<s32> *clip,
629 ItemRotationKind rotation_kind,
631 const v3s16 &rotation_speed)
633 static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
636 if (rotation_kind < IT_ROT_NONE && rotation_kind != IT_ROT_OTHER) {
637 rotation_time_infos[rotation_kind].mesh = NULL;
642 const ItemDefinition &def = item.getDefinition(client->idef());
643 ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
645 if (imesh && imesh->mesh) {
646 scene::IMesh *mesh = imesh->mesh;
647 driver->clearZBuffer();
649 if (rotation_kind < IT_ROT_NONE) {
650 MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
651 if (mesh != ti.mesh && rotation_kind != IT_ROT_OTHER) {
653 ti.time = porting::getTimeMs();
655 delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
658 core::rect<s32> oldViewPort = driver->getViewPort();
659 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
660 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
661 core::rect<s32> viewrect = rect;
663 viewrect.clipAgainst(*clip);
665 core::matrix4 ProjMatrix;
666 ProjMatrix.buildProjectionMatrixOrthoLH(2.0f, 2.0f, -1.0f, 100.0f);
668 core::matrix4 ViewMatrix;
669 ViewMatrix.buildProjectionMatrixOrthoLH(
670 2.0f * viewrect.getWidth() / rect.getWidth(),
671 2.0f * viewrect.getHeight() / rect.getHeight(),
674 ViewMatrix.setTranslation(core::vector3df(
675 1.0f * (rect.LowerRightCorner.X + rect.UpperLeftCorner.X -
676 viewrect.LowerRightCorner.X - viewrect.UpperLeftCorner.X) /
678 1.0f * (viewrect.LowerRightCorner.Y + viewrect.UpperLeftCorner.Y -
679 rect.LowerRightCorner.Y - rect.UpperLeftCorner.Y) /
680 viewrect.getHeight(),
683 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
684 driver->setTransform(video::ETS_VIEW, ViewMatrix);
686 core::matrix4 matrix;
687 matrix.makeIdentity();
689 static thread_local bool enable_animations =
690 g_settings->getBool("inventory_items_animations");
692 if (enable_animations) {
693 float timer_f = (float) delta / 5000.f;
694 matrix.setRotationDegrees(v3f(
695 angle.X + rotation_speed.X * 3.60f * timer_f,
696 angle.Y + rotation_speed.Y * 3.60f * timer_f,
697 angle.Z + rotation_speed.Z * 3.60f * timer_f)
701 driver->setTransform(video::ETS_WORLD, matrix);
702 driver->setViewPort(viewrect);
704 video::SColor basecolor =
705 client->idef()->getItemstackColor(item, client);
707 u32 mc = mesh->getMeshBufferCount();
708 for (u32 j = 0; j < mc; ++j) {
709 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
710 // we can modify vertices relatively fast,
711 // because these meshes are not buffered.
712 assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
713 video::SColor c = basecolor;
715 if (imesh->buffer_colors.size() > j) {
716 ItemPartColor *p = &imesh->buffer_colors[j];
717 if (p->override_base)
721 if (imesh->needs_shading)
722 colorizeMeshBuffer(buf, &c);
724 setMeshBufferColor(buf, c);
726 video::SMaterial &material = buf->getMaterial();
727 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
728 material.Lighting = false;
729 driver->setMaterial(material);
730 driver->drawMeshBuffer(buf);
733 driver->setTransform(video::ETS_VIEW, oldViewMat);
734 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
735 driver->setViewPort(oldViewPort);
737 // draw the inventory_overlay
738 if (def.type == ITEM_NODE && def.inventory_image.empty() &&
739 !def.inventory_overlay.empty()) {
740 ITextureSource *tsrc = client->getTextureSource();
741 video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
742 core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
743 core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
744 draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
748 if (def.type == ITEM_TOOL && item.wear != 0) {
749 // Draw a progressbar
750 float barheight = rect.getHeight() / 16;
751 float barpad_x = rect.getWidth() / 16;
752 float barpad_y = rect.getHeight() / 16;
754 core::rect<s32> progressrect(
755 rect.UpperLeftCorner.X + barpad_x,
756 rect.LowerRightCorner.Y - barpad_y - barheight,
757 rect.LowerRightCorner.X - barpad_x,
758 rect.LowerRightCorner.Y - barpad_y);
760 // Shrink progressrect by amount of tool damage
761 float wear = item.wear / 65535.0f;
763 wear * progressrect.UpperLeftCorner.X +
764 (1 - wear) * progressrect.LowerRightCorner.X;
766 // Compute progressbar color
768 // wear = 0.5: yellow
770 video::SColor color(255, 255, 255, 255);
771 int wear_i = MYMIN(std::floor(wear * 600), 511);
772 wear_i = MYMIN(wear_i + 10, 511);
775 color.set(255, wear_i, 255, 0);
777 color.set(255, 255, 511 - wear_i, 0);
779 core::rect<s32> progressrect2 = progressrect;
780 progressrect2.LowerRightCorner.X = progressmid;
781 driver->draw2DRectangle(color, progressrect2, clip);
783 color = video::SColor(255, 0, 0, 0);
784 progressrect2 = progressrect;
785 progressrect2.UpperLeftCorner.X = progressmid;
786 driver->draw2DRectangle(color, progressrect2, clip);
789 if (font != NULL && item.count >= 2) {
790 // Get the item count as a string
791 std::string text = itos(item.count);
792 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
793 v2s32 sdim(dim.X, dim.Y);
795 core::rect<s32> rect2(
796 /*rect.UpperLeftCorner,
797 core::dimension2d<u32>(rect.getWidth(), 15)*/
798 rect.LowerRightCorner - sdim,
802 video::SColor bgcolor(128, 0, 0, 0);
803 driver->draw2DRectangle(bgcolor, rect2, clip);
805 video::SColor color(255, 255, 255, 255);
806 font->draw(text.c_str(), rect2, color, false, false, clip);
811 video::IVideoDriver *driver,
813 const ItemStack &item,
814 const core::rect<s32> &rect,
815 const core::rect<s32> *clip,
817 ItemRotationKind rotation_kind)
819 drawItemStack(driver, font, item, rect, clip, client, rotation_kind,
820 v3s16(0, 0, 0), v3s16(0, 100, 0));