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 if (!hotbar_image.empty())
225 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
227 use_hotbar_image = false;
230 // Store hotbar_selected_image in member variable, used by drawItem()
231 if (hotbar_selected_image != player->hotbar_selected_image) {
232 hotbar_selected_image = player->hotbar_selected_image;
233 if (!hotbar_selected_image.empty())
234 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
236 use_hotbar_selected_image = false;
239 // draw customized item background
240 if (use_hotbar_image) {
241 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
242 width+m_padding/2, height+m_padding/2);
243 core::rect<s32> rect2 = imgrect2 + pos;
244 video::ITexture *texture = tsrc->getTexture(hotbar_image);
245 core::dimension2di imgsize(texture->getOriginalSize());
246 draw2DImageFilterScaled(driver, texture, rect2,
247 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
248 NULL, hbar_colors, true);
252 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
253 for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) {
254 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
258 case HUD_DIR_RIGHT_LEFT:
259 steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding);
261 case HUD_DIR_TOP_BOTTOM:
262 steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen);
264 case HUD_DIR_BOTTOM_TOP:
265 steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen));
268 steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding);
272 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem);
274 #ifdef HAVE_TOUCHSCREENGUI
275 if (g_touchscreengui)
276 g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
282 void Hud::drawLuaElements(const v3s16 &camera_offset)
284 u32 text_height = g_fontengine->getTextHeight();
285 irr::gui::IGUIFont* font = g_fontengine->getFont();
286 for (size_t i = 0; i != player->maxHudId(); i++) {
287 HudElement *e = player->getHud(i);
291 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
292 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
294 case HUD_ELEM_IMAGE: {
295 video::ITexture *texture = tsrc->getTexture(e->text);
299 const video::SColor color(255, 255, 255, 255);
300 const video::SColor colors[] = {color, color, color, color};
301 core::dimension2di imgsize(texture->getOriginalSize());
302 v2s32 dstsize(imgsize.Width * e->scale.X,
303 imgsize.Height * e->scale.Y);
305 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
307 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
308 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
309 (e->align.Y - 1.0) * dstsize.Y / 2);
310 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
311 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
312 draw2DImageFilterScaled(driver, texture, rect,
313 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
316 case HUD_ELEM_TEXT: {
317 video::SColor color(255, (e->number >> 16) & 0xFF,
318 (e->number >> 8) & 0xFF,
319 (e->number >> 0) & 0xFF);
320 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
321 std::wstring text = unescape_translate(utf8_to_wide(e->text));
322 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
323 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
324 (e->align.Y - 1.0) * (textsize.Height / 2));
325 v2s32 offs(e->offset.X, e->offset.Y);
326 font->draw(text.c_str(), size + pos + offset + offs, color);
328 case HUD_ELEM_STATBAR: {
329 v2s32 offs(e->offset.X, e->offset.Y);
330 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
332 case HUD_ELEM_INVENTORY: {
333 InventoryList *inv = inventory->getList(e->text);
334 drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
335 inv, e->item, e->dir);
337 case HUD_ELEM_WAYPOINT: {
338 v3f p_pos = player->getPosition() / BS;
339 v3f w_pos = e->world_pos * BS;
340 float distance = std::floor(10 * p_pos.getDistanceFrom(e->world_pos)) /
342 scene::ICameraSceneNode* camera =
343 RenderingEngine::get_scene_manager()->getActiveCamera();
344 w_pos -= intToFloat(camera_offset, BS);
345 core::matrix4 trans = camera->getProjectionMatrix();
346 trans *= camera->getViewMatrix();
347 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
348 trans.multiplyWith1x4Matrix(transformed_pos);
349 if (transformed_pos[3] < 0)
351 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
352 core::reciprocal(transformed_pos[3]);
353 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
354 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
355 video::SColor color(255, (e->number >> 16) & 0xFF,
356 (e->number >> 8) & 0xFF,
357 (e->number >> 0) & 0xFF);
358 core::rect<s32> size(0, 0, 200, 2 * text_height);
359 std::wstring text = unescape_translate(utf8_to_wide(e->name));
360 font->draw(text.c_str(), size + pos, color);
361 std::ostringstream os;
362 os << distance << e->text;
363 text = unescape_translate(utf8_to_wide(os.str()));
364 pos.Y += text_height;
365 font->draw(text.c_str(), size + pos, color);
368 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
369 " of hud element ID " << i << " due to unrecognized type" << std::endl;
375 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
376 s32 count, v2s32 offset, v2s32 size)
378 const video::SColor color(255, 255, 255, 255);
379 const video::SColor colors[] = {color, color, color, color};
381 video::ITexture *stat_texture = tsrc->getTexture(texture);
385 core::dimension2di srcd(stat_texture->getOriginalSize());
386 core::dimension2di dstd;
387 if (size == v2s32()) {
390 float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
391 dstd.Height = size.Y * size_factor;
392 dstd.Width = size.X * size_factor;
393 offset.X *= size_factor;
394 offset.Y *= size_factor;
398 if (corner & HUD_CORNER_LOWER)
404 core::rect<s32> srchalfrect, dsthalfrect;
406 case HUD_DIR_RIGHT_LEFT:
407 steppos = v2s32(-1, 0);
408 srchalfrect = core::rect<s32>(srcd.Width / 2, 0, srcd.Width, srcd.Height);
409 dsthalfrect = core::rect<s32>(dstd.Width / 2, 0, dstd.Width, dstd.Height);
411 case HUD_DIR_TOP_BOTTOM:
412 steppos = v2s32(0, 1);
413 srchalfrect = core::rect<s32>(0, 0, srcd.Width, srcd.Height / 2);
414 dsthalfrect = core::rect<s32>(0, 0, dstd.Width, dstd.Height / 2);
416 case HUD_DIR_BOTTOM_TOP:
417 steppos = v2s32(0, -1);
418 srchalfrect = core::rect<s32>(0, srcd.Height / 2, srcd.Width, srcd.Height);
419 dsthalfrect = core::rect<s32>(0, dstd.Height / 2, dstd.Width, dstd.Height);
422 steppos = v2s32(1, 0);
423 srchalfrect = core::rect<s32>(0, 0, srcd.Width / 2, srcd.Height);
424 dsthalfrect = core::rect<s32>(0, 0, dstd.Width / 2, dstd.Height);
426 steppos.X *= dstd.Width;
427 steppos.Y *= dstd.Height;
429 for (s32 i = 0; i < count / 2; i++) {
430 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
431 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
434 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
438 if (count % 2 == 1) {
440 draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true);
445 void Hud::drawHotbar(u16 playeritem) {
447 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
449 InventoryList *mainlist = inventory->getList("main");
450 if (mainlist == NULL) {
451 //silently ignore this we may not be initialized completely
455 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
456 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
457 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
459 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
460 if ( (float) width / (float) window_size.X <=
461 g_settings->getFloat("hud_hotbar_max_width")) {
462 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
463 drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
468 v2s32 secondpos = pos;
469 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
471 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
472 drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
473 mainlist, playeritem + 1, 0);
474 drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
475 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
479 //////////////////////////// compatibility code to be removed //////////////
480 // this is ugly as hell but there's no other way to keep compatibility to
482 if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
483 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
484 floor(1 * (float) m_screensize.Y + 0.5)),
485 HUD_CORNER_UPPER, 0, "heart.png",
486 player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
489 if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
490 (player->getBreath() < 11)) {
491 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
492 floor(1 * (float) m_screensize.Y + 0.5)),
493 HUD_CORNER_UPPER, 0, "bubble.png",
494 player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
496 ////////////////////////////////////////////////////////////////////////////
500 void Hud::drawCrosshair()
502 if (use_crosshair_image) {
503 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
504 v2u32 size = crosshair->getOriginalSize();
505 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
506 m_displaycenter.Y - (size.Y / 2));
507 driver->draw2DImage(crosshair, lsize,
508 core::rect<s32>(0, 0, size.X, size.Y),
509 0, crosshair_argb, true);
511 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
512 m_displaycenter + v2s32(10, 0), crosshair_argb);
513 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
514 m_displaycenter + v2s32(0, 10), crosshair_argb);
518 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
520 m_camera_offset = camera_offset;
521 m_selection_pos = pos;
522 m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
525 void Hud::drawSelectionMesh()
527 if (m_mode == HIGHLIGHT_BOX) {
528 // Draw 3D selection boxes
529 video::SMaterial oldmaterial = driver->getMaterial2D();
530 driver->setMaterial(m_selection_material);
531 for (std::vector<aabb3f>::const_iterator
532 i = m_selection_boxes.begin();
533 i != m_selection_boxes.end(); ++i) {
535 i->MinEdge + m_selection_pos_with_offset,
536 i->MaxEdge + m_selection_pos_with_offset);
538 u32 r = (selectionbox_argb.getRed() *
539 m_selection_mesh_color.getRed() / 255);
540 u32 g = (selectionbox_argb.getGreen() *
541 m_selection_mesh_color.getGreen() / 255);
542 u32 b = (selectionbox_argb.getBlue() *
543 m_selection_mesh_color.getBlue() / 255);
544 driver->draw3DBox(box, video::SColor(255, r, g, b));
546 driver->setMaterial(oldmaterial);
547 } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
548 // Draw selection mesh
549 video::SMaterial oldmaterial = driver->getMaterial2D();
550 driver->setMaterial(m_selection_material);
551 setMeshColor(m_selection_mesh, m_selection_mesh_color);
552 video::SColor face_color(0,
553 MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
554 MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
555 MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
556 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
558 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
559 translateMesh(mesh, m_selection_pos_with_offset);
560 u32 mc = m_selection_mesh->getMeshBufferCount();
561 for (u32 i = 0; i < mc; i++) {
562 scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
563 driver->drawMeshBuffer(buf);
566 driver->setMaterial(oldmaterial);
570 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
572 m_camera_offset = camera_offset;
573 if (m_mode != HIGHLIGHT_HALO)
576 if (m_selection_mesh) {
577 m_selection_mesh->drop();
578 m_selection_mesh = NULL;
581 if (m_selection_boxes.empty()) {
586 // New pointed object, create new mesh.
588 // Texture UV coordinates for selection boxes
589 static f32 texture_uv[24] = {
598 // Use single halo box instead of multiple overlapping boxes.
599 // Temporary solution - problem can be solved with multiple
600 // rendering targets, or some method to remove inner surfaces.
601 // Thats because of halo transparency.
603 aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
604 m_halo_boxes.clear();
606 for (const auto &selection_box : m_selection_boxes) {
607 halo_box.addInternalBox(selection_box);
610 m_halo_boxes.push_back(halo_box);
611 m_selection_mesh = convertNodeboxesToMesh(
612 m_halo_boxes, texture_uv, 0.5);
615 void Hud::resizeHotbar() {
616 const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
618 if (m_screensize != window_size) {
619 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
620 RenderingEngine::getDisplayDensity() + 0.5);
621 m_hotbar_imagesize *= m_hud_scaling;
622 m_padding = m_hotbar_imagesize / 12;
623 m_screensize = window_size;
624 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
628 struct MeshTimeInfo {
633 void drawItemStack(video::IVideoDriver *driver,
635 const ItemStack &item,
636 const core::rect<s32> &rect,
637 const core::rect<s32> *clip,
639 ItemRotationKind rotation_kind)
641 static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
642 static thread_local bool enable_animations =
643 g_settings->getBool("inventory_items_animations");
646 if (rotation_kind < IT_ROT_NONE) {
647 rotation_time_infos[rotation_kind].mesh = NULL;
652 const ItemDefinition &def = item.getDefinition(client->idef());
653 ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
655 if (imesh && imesh->mesh) {
656 scene::IMesh *mesh = imesh->mesh;
657 driver->clearZBuffer();
659 if (rotation_kind < IT_ROT_NONE) {
660 MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
661 if (mesh != ti.mesh) {
663 ti.time = porting::getTimeMs();
665 delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
668 core::rect<s32> oldViewPort = driver->getViewPort();
669 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
670 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
671 core::matrix4 ProjMatrix;
672 ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
673 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
674 driver->setTransform(video::ETS_VIEW, ProjMatrix);
675 core::matrix4 matrix;
676 matrix.makeIdentity();
678 if (enable_animations) {
679 float timer_f = (float) delta / 5000.0;
680 matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
683 driver->setTransform(video::ETS_WORLD, matrix);
684 driver->setViewPort(rect);
686 video::SColor basecolor =
687 client->idef()->getItemstackColor(item, client);
689 u32 mc = mesh->getMeshBufferCount();
690 for (u32 j = 0; j < mc; ++j) {
691 scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
692 // we can modify vertices relatively fast,
693 // because these meshes are not buffered.
694 assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
695 video::SColor c = basecolor;
696 if (imesh->buffer_colors.size() > j) {
697 ItemPartColor *p = &imesh->buffer_colors[j];
698 if (p->override_base)
701 if (imesh->needs_shading)
702 colorizeMeshBuffer(buf, &c);
704 setMeshBufferColor(buf, c);
705 video::SMaterial &material = buf->getMaterial();
706 material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
707 material.Lighting = false;
708 driver->setMaterial(material);
709 driver->drawMeshBuffer(buf);
712 driver->setTransform(video::ETS_VIEW, oldViewMat);
713 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
714 driver->setViewPort(oldViewPort);
717 if(def.type == ITEM_TOOL && item.wear != 0)
719 // Draw a progressbar
720 float barheight = rect.getHeight()/16;
721 float barpad_x = rect.getWidth()/16;
722 float barpad_y = rect.getHeight()/16;
723 core::rect<s32> progressrect(
724 rect.UpperLeftCorner.X + barpad_x,
725 rect.LowerRightCorner.Y - barpad_y - barheight,
726 rect.LowerRightCorner.X - barpad_x,
727 rect.LowerRightCorner.Y - barpad_y);
729 // Shrink progressrect by amount of tool damage
730 float wear = item.wear / 65535.0;
732 wear * progressrect.UpperLeftCorner.X +
733 (1-wear) * progressrect.LowerRightCorner.X;
735 // Compute progressbar color
737 // wear = 0.5: yellow
739 video::SColor color(255,255,255,255);
740 int wear_i = MYMIN(std::floor(wear * 600), 511);
741 wear_i = MYMIN(wear_i + 10, 511);
743 color.set(255, wear_i, 255, 0);
745 color.set(255, 255, 511 - wear_i, 0);
747 core::rect<s32> progressrect2 = progressrect;
748 progressrect2.LowerRightCorner.X = progressmid;
749 driver->draw2DRectangle(color, progressrect2, clip);
751 color = video::SColor(255,0,0,0);
752 progressrect2 = progressrect;
753 progressrect2.UpperLeftCorner.X = progressmid;
754 driver->draw2DRectangle(color, progressrect2, clip);
757 if(font != NULL && item.count >= 2)
759 // Get the item count as a string
760 std::string text = itos(item.count);
761 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
762 v2s32 sdim(dim.X,dim.Y);
764 core::rect<s32> rect2(
765 /*rect.UpperLeftCorner,
766 core::dimension2d<u32>(rect.getWidth(), 15)*/
767 rect.LowerRightCorner - sdim,
771 video::SColor bgcolor(128,0,0,0);
772 driver->draw2DRectangle(bgcolor, rect2, clip);
774 video::SColor color(255,255,255,255);
775 font->draw(text.c_str(), rect2, color, false, false, clip);