]> git.lizzy.rs Git - dragonfireclient.git/blob - src/hud.cpp
2285fb71ee2b0e9575151da3b524ef7919415fde
[dragonfireclient.git] / src / hud.cpp
1 /*
2 Minetest
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>
6
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.
11
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.
16
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.
20 */
21
22 #include "hud.h"
23 #include "settings.h"
24 #include "util/numeric.h"
25 #include "log.h"
26 #include "client.h"
27 #include "inventory.h"
28 #include "client/tile.h"
29 #include "localplayer.h"
30 #include "camera.h"
31 #include "porting.h"
32 #include "fontengine.h"
33 #include "guiscalingfilter.h"
34 #include "mesh.h"
35 #include "wieldmesh.h"
36 #include <IGUIStaticText.h>
37 #include "client/renderingengine.h"
38
39 #ifdef HAVE_TOUCHSCREENGUI
40 #include "touchscreengui.h"
41 #endif
42
43 Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
44                 gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player,
45                 Inventory *inventory)
46 {
47         this->driver      = driver;
48         this->smgr        = smgr;
49         this->guienv      = guienv;
50         this->client      = client;
51         this->player      = player;
52         this->inventory   = inventory;
53
54         m_hud_scaling      = g_settings->getFloat("hud_scaling");
55         m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
56                 RenderingEngine::getDisplayDensity() + 0.5f);
57         m_hotbar_imagesize *= m_hud_scaling;
58         m_padding = m_hotbar_imagesize / 12;
59
60         for (unsigned int i = 0; i < 4; i++)
61                 hbar_colors[i] = video::SColor(255, 255, 255, 255);
62
63         tsrc = client->getTextureSource();
64
65         v3f crosshair_color = g_settings->getV3F("crosshair_color");
66         u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
67         u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
68         u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
69         u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
70         crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
71
72         v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
73         u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
74         u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
75         u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
76         selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
77
78         use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
79
80         m_selection_boxes.clear();
81         m_halo_boxes.clear();
82
83         std::string mode_setting = g_settings->get("node_highlighting");
84
85         if (mode_setting == "halo") {
86                 m_mode = HIGHLIGHT_HALO;
87         } else if (mode_setting == "none") {
88                 m_mode = HIGHLIGHT_NONE;
89         } else {
90                 m_mode = HIGHLIGHT_BOX;
91         }
92
93         m_selection_material.Lighting = false;
94
95         if (g_settings->getBool("enable_shaders")) {
96                 IShaderSource *shdrsrc = client->getShaderSource();
97                 u16 shader_id = shdrsrc->getShader(
98                         m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
99                 m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
100         } else {
101                 m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
102         }
103
104         if (m_mode == HIGHLIGHT_BOX) {
105                 m_selection_material.Thickness =
106                         rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
107         } else if (m_mode == HIGHLIGHT_HALO) {
108                 m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png"));
109                 m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true);
110         } else {
111                 m_selection_material.MaterialType = video::EMT_SOLID;
112         }
113 }
114
115 Hud::~Hud()
116 {
117         if (m_selection_mesh)
118                 m_selection_mesh->drop();
119 }
120
121 void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect,
122                 bool selected)
123 {
124         if (selected) {
125                 /* draw hihlighting around selected item */
126                 if (use_hotbar_selected_image) {
127                         core::rect<s32> imgrect2 = rect;
128                         imgrect2.UpperLeftCorner.X  -= (m_padding*2);
129                         imgrect2.UpperLeftCorner.Y  -= (m_padding*2);
130                         imgrect2.LowerRightCorner.X += (m_padding*2);
131                         imgrect2.LowerRightCorner.Y += (m_padding*2);
132                                 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
133                                 core::dimension2di imgsize(texture->getOriginalSize());
134                         draw2DImageFilterScaled(driver, texture, imgrect2,
135                                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
136                                         NULL, hbar_colors, true);
137                 } else {
138                         video::SColor c_outside(255,255,0,0);
139                         //video::SColor c_outside(255,0,0,0);
140                         //video::SColor c_inside(255,192,192,192);
141                         s32 x1 = rect.UpperLeftCorner.X;
142                         s32 y1 = rect.UpperLeftCorner.Y;
143                         s32 x2 = rect.LowerRightCorner.X;
144                         s32 y2 = rect.LowerRightCorner.Y;
145                         // Black base borders
146                         driver->draw2DRectangle(c_outside,
147                                 core::rect<s32>(
148                                 v2s32(x1 - m_padding, y1 - m_padding),
149                                 v2s32(x2 + m_padding, y1)
150                                 ), NULL);
151                         driver->draw2DRectangle(c_outside,
152                                 core::rect<s32>(
153                                 v2s32(x1 - m_padding, y2),
154                                 v2s32(x2 + m_padding, y2 + m_padding)
155                                 ), NULL);
156                         driver->draw2DRectangle(c_outside,
157                                 core::rect<s32>(
158                                 v2s32(x1 - m_padding, y1),
159                                         v2s32(x1, y2)
160                                 ), NULL);
161                         driver->draw2DRectangle(c_outside,
162                                 core::rect<s32>(
163                                         v2s32(x2, y1),
164                                 v2s32(x2 + m_padding, y2)
165                                 ), NULL);
166                         /*// Light inside borders
167                         driver->draw2DRectangle(c_inside,
168                                 core::rect<s32>(
169                                         v2s32(x1 - padding/2, y1 - padding/2),
170                                         v2s32(x2 + padding/2, y1)
171                                 ), NULL);
172                         driver->draw2DRectangle(c_inside,
173                                 core::rect<s32>(
174                                         v2s32(x1 - padding/2, y2),
175                                         v2s32(x2 + padding/2, y2 + padding/2)
176                                 ), NULL);
177                         driver->draw2DRectangle(c_inside,
178                                 core::rect<s32>(
179                                         v2s32(x1 - padding/2, y1),
180                                         v2s32(x1, y2)
181                                 ), NULL);
182                         driver->draw2DRectangle(c_inside,
183                                 core::rect<s32>(
184                                         v2s32(x2, y1),
185                                         v2s32(x2 + padding/2, y2)
186                                 ), NULL);
187                         */
188                 }
189         }
190
191         video::SColor bgcolor2(128, 0, 0, 0);
192         if (!use_hotbar_image)
193                 driver->draw2DRectangle(bgcolor2, rect, NULL);
194         drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL,
195                 client, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
196 }
197
198 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
199 void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
200                 s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction)
201 {
202 #ifdef HAVE_TOUCHSCREENGUI
203         if (g_touchscreengui && inv_offset == 0)
204                 g_touchscreengui->resetHud();
205 #endif
206
207         s32 height  = m_hotbar_imagesize + m_padding * 2;
208         s32 width   = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2);
209
210         if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
211                 s32 tmp = height;
212                 height = width;
213                 width = tmp;
214         }
215
216         // Position of upper left corner of bar
217         v2s32 pos = screen_offset;
218         pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity();
219         pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity();
220         pos += upperleftpos;
221
222         // Store hotbar_image in member variable, used by drawItem()
223         if (hotbar_image != player->hotbar_image) {
224                 hotbar_image = player->hotbar_image;
225                 if (hotbar_image != "")
226                         use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
227                 else
228                         use_hotbar_image = false;
229         }
230
231         // Store hotbar_selected_image in member variable, used by drawItem()
232         if (hotbar_selected_image != player->hotbar_selected_image) {
233                 hotbar_selected_image = player->hotbar_selected_image;
234                 if (hotbar_selected_image != "")
235                         use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
236                 else
237                         use_hotbar_selected_image = false;
238         }
239
240         // draw customized item background
241         if (use_hotbar_image) {
242                 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
243                         width+m_padding/2, height+m_padding/2);
244                 core::rect<s32> rect2 = imgrect2 + pos;
245                 video::ITexture *texture = tsrc->getTexture(hotbar_image);
246                 core::dimension2di imgsize(texture->getOriginalSize());
247                 draw2DImageFilterScaled(driver, texture, rect2,
248                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
249                         NULL, hbar_colors, true);
250         }
251
252         // Draw items
253         core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
254         for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) {
255                 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
256
257                 v2s32 steppos;
258                 switch (direction) {
259                 case HUD_DIR_RIGHT_LEFT:
260                         steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding);
261                         break;
262                 case HUD_DIR_TOP_BOTTOM:
263                         steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen);
264                         break;
265                 case HUD_DIR_BOTTOM_TOP:
266                         steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen));
267                         break;
268                 default:
269                         steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding);
270                         break;
271                 }
272
273                 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem);
274
275 #ifdef HAVE_TOUCHSCREENGUI
276                 if (g_touchscreengui)
277                         g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
278 #endif
279         }
280 }
281
282
283 void Hud::drawLuaElements(const v3s16 &camera_offset)
284 {
285         u32 text_height = g_fontengine->getTextHeight();
286         irr::gui::IGUIFont* font = g_fontengine->getFont();
287         for (size_t i = 0; i != player->maxHudId(); i++) {
288                 HudElement *e = player->getHud(i);
289                 if (!e)
290                         continue;
291
292                 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
293                                 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
294                 switch (e->type) {
295                         case HUD_ELEM_IMAGE: {
296                                 video::ITexture *texture = tsrc->getTexture(e->text);
297                                 if (!texture)
298                                         continue;
299
300                                 const video::SColor color(255, 255, 255, 255);
301                                 const video::SColor colors[] = {color, color, color, color};
302                                 core::dimension2di imgsize(texture->getOriginalSize());
303                                 v2s32 dstsize(imgsize.Width * e->scale.X,
304                                               imgsize.Height * e->scale.Y);
305                                 if (e->scale.X < 0)
306                                         dstsize.X = m_screensize.X * (e->scale.X * -0.01);
307                                 if (e->scale.Y < 0)
308                                         dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
309                                 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
310                                              (e->align.Y - 1.0) * dstsize.Y / 2);
311                                 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
312                                 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
313                                 draw2DImageFilterScaled(driver, texture, rect,
314                                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
315                                         NULL, colors, true);
316                                 break; }
317                         case HUD_ELEM_TEXT: {
318                                 video::SColor color(255, (e->number >> 16) & 0xFF,
319                                                                                  (e->number >> 8)  & 0xFF,
320                                                                                  (e->number >> 0)  & 0xFF);
321                                 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
322                                 std::wstring text = unescape_enriched(utf8_to_wide(e->text));
323                                 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
324                                 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
325                                              (e->align.Y - 1.0) * (textsize.Height / 2));
326                                 v2s32 offs(e->offset.X, e->offset.Y);
327                                 font->draw(text.c_str(), size + pos + offset + offs, color);
328                                 break; }
329                         case HUD_ELEM_STATBAR: {
330                                 v2s32 offs(e->offset.X, e->offset.Y);
331                                 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
332                                 break; }
333                         case HUD_ELEM_INVENTORY: {
334                                 InventoryList *inv = inventory->getList(e->text);
335                                 drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0,
336                                         inv, e->item, e->dir);
337                                 break; }
338                         case HUD_ELEM_WAYPOINT: {
339                                 v3f p_pos = player->getPosition() / BS;
340                                 v3f w_pos = e->world_pos * BS;
341                                 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
342                                 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
343                                 w_pos -= intToFloat(camera_offset, BS);
344                                 core::matrix4 trans = camera->getProjectionMatrix();
345                                 trans *= camera->getViewMatrix();
346                                 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
347                                 trans.multiplyWith1x4Matrix(transformed_pos);
348                                 if (transformed_pos[3] < 0)
349                                         break;
350                                 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
351                                         core::reciprocal(transformed_pos[3]);
352                                 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
353                                 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
354                                 video::SColor color(255, (e->number >> 16) & 0xFF,
355                                                                                  (e->number >> 8)  & 0xFF,
356                                                                                  (e->number >> 0)  & 0xFF);
357                                 core::rect<s32> size(0, 0, 200, 2 * text_height);
358                                 std::wstring text = unescape_enriched(utf8_to_wide(e->name));
359                                 font->draw(text.c_str(), size + pos, color);
360                                 std::ostringstream os;
361                                 os << distance << e->text;
362                                 text = unescape_enriched(utf8_to_wide(os.str()));
363                                 pos.Y += text_height;
364                                 font->draw(text.c_str(), size + pos, color);
365                                 break; }
366                         default:
367                                 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
368                                         " of hud element ID " << i << " due to unrecognized type" << std::endl;
369                 }
370         }
371 }
372
373
374 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
375                 s32 count, v2s32 offset, v2s32 size)
376 {
377         const video::SColor color(255, 255, 255, 255);
378         const video::SColor colors[] = {color, color, color, color};
379
380         video::ITexture *stat_texture = tsrc->getTexture(texture);
381         if (!stat_texture)
382                 return;
383
384         core::dimension2di srcd(stat_texture->getOriginalSize());
385         core::dimension2di dstd;
386         if (size == v2s32()) {
387                 dstd = srcd;
388         } else {
389                 float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity();
390                 dstd.Height = size.Y * size_factor;
391                 dstd.Width  = size.X * size_factor;
392                 offset.X *= size_factor;
393                 offset.Y *= size_factor;
394         }
395
396         v2s32 p = pos;
397         if (corner & HUD_CORNER_LOWER)
398                 p -= dstd.Height;
399
400         p += offset;
401
402         v2s32 steppos;
403         switch (drawdir) {
404                 case HUD_DIR_RIGHT_LEFT:
405                         steppos = v2s32(-1, 0);
406                         break;
407                 case HUD_DIR_TOP_BOTTOM:
408                         steppos = v2s32(0, 1);
409                         break;
410                 case HUD_DIR_BOTTOM_TOP:
411                         steppos = v2s32(0, -1);
412                         break;
413                 default:
414                         steppos = v2s32(1, 0);
415         }
416         steppos.X *= dstd.Width;
417         steppos.Y *= dstd.Height;
418
419         for (s32 i = 0; i < count / 2; i++)
420         {
421                 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
422                 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
423
424                 dstrect += p;
425                 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
426                 p += steppos;
427         }
428
429         if (count % 2 == 1)
430         {
431                 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
432                 core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
433
434                 dstrect += p;
435                 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
436         }
437 }
438
439
440 void Hud::drawHotbar(u16 playeritem) {
441
442         v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
443
444         InventoryList *mainlist = inventory->getList("main");
445         if (mainlist == NULL) {
446                 //silently ignore this we may not be initialized completely
447                 return;
448         }
449
450         s32 hotbar_itemcount = player->hud_hotbar_itemcount;
451         s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
452         v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
453
454         const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
455         if ( (float) width / (float) window_size.X <=
456                         g_settings->getFloat("hud_hotbar_max_width")) {
457                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
458                         drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
459                 }
460         } else {
461                 pos.X += width/4;
462
463                 v2s32 secondpos = pos;
464                 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
465
466                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
467                         drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
468                                 mainlist, playeritem + 1, 0);
469                         drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
470                                 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
471                 }
472         }
473
474         //////////////////////////// compatibility code to be removed //////////////
475         // this is ugly as hell but there's no other way to keep compatibility to
476         // old servers
477         if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
478                 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
479                         floor(1 * (float) m_screensize.Y + 0.5)),
480                         HUD_CORNER_UPPER, 0, "heart.png",
481                         player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
482         }
483
484         if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
485                         (player->getBreath() < 11)) {
486                 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
487                         floor(1 * (float) m_screensize.Y + 0.5)),
488                         HUD_CORNER_UPPER, 0, "bubble.png",
489                         player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
490         }
491         ////////////////////////////////////////////////////////////////////////////
492 }
493
494
495 void Hud::drawCrosshair()
496 {
497         if (use_crosshair_image) {
498                 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
499                 v2u32 size  = crosshair->getOriginalSize();
500                 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
501                                 m_displaycenter.Y - (size.Y / 2));
502                 driver->draw2DImage(crosshair, lsize,
503                                 core::rect<s32>(0, 0, size.X, size.Y),
504                                 0, crosshair_argb, true);
505         } else {
506                 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
507                                 m_displaycenter + v2s32(10, 0), crosshair_argb);
508                 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
509                                 m_displaycenter + v2s32(0, 10), crosshair_argb);
510         }
511 }
512
513 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
514 {
515         m_camera_offset = camera_offset;
516         m_selection_pos = pos;
517         m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
518 }
519
520 void Hud::drawSelectionMesh()
521 {
522         if (m_mode == HIGHLIGHT_BOX) {
523                 // Draw 3D selection boxes
524                 video::SMaterial oldmaterial = driver->getMaterial2D();
525                 driver->setMaterial(m_selection_material);
526                 for (std::vector<aabb3f>::const_iterator
527                                 i = m_selection_boxes.begin();
528                                 i != m_selection_boxes.end(); ++i) {
529                         aabb3f box = aabb3f(
530                                 i->MinEdge + m_selection_pos_with_offset,
531                                 i->MaxEdge + m_selection_pos_with_offset);
532
533                         u32 r = (selectionbox_argb.getRed() *
534                                         m_selection_mesh_color.getRed() / 255);
535                         u32 g = (selectionbox_argb.getGreen() *
536                                         m_selection_mesh_color.getGreen() / 255);
537                         u32 b = (selectionbox_argb.getBlue() *
538                                         m_selection_mesh_color.getBlue() / 255);
539                         driver->draw3DBox(box, video::SColor(255, r, g, b));
540                 }
541                 driver->setMaterial(oldmaterial);
542         } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) {
543                 // Draw selection mesh
544                 video::SMaterial oldmaterial = driver->getMaterial2D();
545                 driver->setMaterial(m_selection_material);
546                 setMeshColor(m_selection_mesh, m_selection_mesh_color);
547                 video::SColor face_color(0,
548                         MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
549                         MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
550                         MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
551                 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
552                         face_color);
553                 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
554                 translateMesh(mesh, m_selection_pos_with_offset);
555                 u32 mc = m_selection_mesh->getMeshBufferCount();
556                 for (u32 i = 0; i < mc; i++) {
557                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
558                         driver->drawMeshBuffer(buf);
559                 }
560                 mesh->drop();
561                 driver->setMaterial(oldmaterial);
562         }
563 }
564
565 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
566 {
567         m_camera_offset = camera_offset;
568         if (m_mode != HIGHLIGHT_HALO)
569                 return;
570
571         if (m_selection_mesh) {
572                 m_selection_mesh->drop();
573                 m_selection_mesh = NULL;
574         }
575
576         if (!m_selection_boxes.size()) {
577                 // No pointed object
578                 return;
579         }
580
581         // New pointed object, create new mesh.
582
583         // Texture UV coordinates for selection boxes
584         static f32 texture_uv[24] = {
585                 0,0,1,1,
586                 0,0,1,1,
587                 0,0,1,1,
588                 0,0,1,1,
589                 0,0,1,1,
590                 0,0,1,1
591         };
592
593         // Use single halo box instead of multiple overlapping boxes.
594         // Temporary solution - problem can be solved with multiple
595         // rendering targets, or some method to remove inner surfaces.
596         // Thats because of halo transparency.
597
598         aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
599         m_halo_boxes.clear();
600
601         for (std::vector<aabb3f>::iterator
602                         i = m_selection_boxes.begin();
603                         i != m_selection_boxes.end(); ++i) {
604                 halo_box.addInternalBox(*i);
605         }
606
607         m_halo_boxes.push_back(halo_box);
608         m_selection_mesh = convertNodeboxesToMesh(
609                 m_halo_boxes, texture_uv, 0.5);
610 }
611
612 void Hud::resizeHotbar() {
613         const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
614
615         if (m_screensize != window_size) {
616                 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
617                         RenderingEngine::getDisplayDensity() + 0.5);
618                 m_hotbar_imagesize *= m_hud_scaling;
619                 m_padding = m_hotbar_imagesize / 12;
620                 m_screensize = window_size;
621                 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
622         }
623 }
624
625 struct MeshTimeInfo {
626         u64 time;
627         scene::IMesh *mesh;
628 };
629
630 void drawItemStack(video::IVideoDriver *driver,
631                 gui::IGUIFont *font,
632                 const ItemStack &item,
633                 const core::rect<s32> &rect,
634                 const core::rect<s32> *clip,
635                 Client *client,
636                 ItemRotationKind rotation_kind)
637 {
638         static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
639         static thread_local bool enable_animations =
640                 g_settings->getBool("inventory_items_animations");
641
642         if (item.empty()) {
643                 if (rotation_kind < IT_ROT_NONE) {
644                         rotation_time_infos[rotation_kind].mesh = NULL;
645                 }
646                 return;
647         }
648
649         const ItemDefinition &def = item.getDefinition(client->idef());
650         ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
651
652         if (imesh && imesh->mesh) {
653                 scene::IMesh *mesh = imesh->mesh;
654                 driver->clearZBuffer();
655                 s32 delta = 0;
656                 if (rotation_kind < IT_ROT_NONE) {
657                         MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
658                         if (mesh != ti.mesh) {
659                                 ti.mesh = mesh;
660                                 ti.time = porting::getTimeMs();
661                         } else {
662                                 delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000;
663                         }
664                 }
665                 core::rect<s32> oldViewPort = driver->getViewPort();
666                 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
667                 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
668                 core::matrix4 ProjMatrix;
669                 ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
670                 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
671                 driver->setTransform(video::ETS_VIEW, ProjMatrix);
672                 core::matrix4 matrix;
673                 matrix.makeIdentity();
674
675                 if (enable_animations) {
676                         float timer_f = (float) delta / 5000.0;
677                         matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
678                 }
679
680                 driver->setTransform(video::ETS_WORLD, matrix);
681                 driver->setViewPort(rect);
682
683                 video::SColor basecolor =
684                         client->idef()->getItemstackColor(item, client);
685
686                 u32 mc = mesh->getMeshBufferCount();
687                 for (u32 j = 0; j < mc; ++j) {
688                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
689                         // we can modify vertices relatively fast,
690                         // because these meshes are not buffered.
691                         assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
692                         video::SColor c = basecolor;
693                         if (imesh->buffer_colors.size() > j) {
694                                 ItemPartColor *p = &imesh->buffer_colors[j];
695                                 if (p->override_base)
696                                         c = p->color;
697                         }
698                         if (imesh->needs_shading)
699                                 colorizeMeshBuffer(buf, &c);
700                         else
701                                 setMeshBufferColor(buf, c);
702                         video::SMaterial &material = buf->getMaterial();
703                         material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
704                         material.Lighting = false;
705                         driver->setMaterial(material);
706                         driver->drawMeshBuffer(buf);
707                 }
708
709                 driver->setTransform(video::ETS_VIEW, oldViewMat);
710                 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
711                 driver->setViewPort(oldViewPort);
712         }
713
714         if(def.type == ITEM_TOOL && item.wear != 0)
715         {
716                 // Draw a progressbar
717                 float barheight = rect.getHeight()/16;
718                 float barpad_x = rect.getWidth()/16;
719                 float barpad_y = rect.getHeight()/16;
720                 core::rect<s32> progressrect(
721                         rect.UpperLeftCorner.X + barpad_x,
722                         rect.LowerRightCorner.Y - barpad_y - barheight,
723                         rect.LowerRightCorner.X - barpad_x,
724                         rect.LowerRightCorner.Y - barpad_y);
725
726                 // Shrink progressrect by amount of tool damage
727                 float wear = item.wear / 65535.0;
728                 int progressmid =
729                         wear * progressrect.UpperLeftCorner.X +
730                         (1-wear) * progressrect.LowerRightCorner.X;
731
732                 // Compute progressbar color
733                 //   wear = 0.0: green
734                 //   wear = 0.5: yellow
735                 //   wear = 1.0: red
736                 video::SColor color(255,255,255,255);
737                 int wear_i = MYMIN(floor(wear * 600), 511);
738                 wear_i = MYMIN(wear_i + 10, 511);
739                 if(wear_i <= 255)
740                         color.set(255, wear_i, 255, 0);
741                 else
742                         color.set(255, 255, 511-wear_i, 0);
743
744                 core::rect<s32> progressrect2 = progressrect;
745                 progressrect2.LowerRightCorner.X = progressmid;
746                 driver->draw2DRectangle(color, progressrect2, clip);
747
748                 color = video::SColor(255,0,0,0);
749                 progressrect2 = progressrect;
750                 progressrect2.UpperLeftCorner.X = progressmid;
751                 driver->draw2DRectangle(color, progressrect2, clip);
752         }
753
754         if(font != NULL && item.count >= 2)
755         {
756                 // Get the item count as a string
757                 std::string text = itos(item.count);
758                 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
759                 v2s32 sdim(dim.X,dim.Y);
760
761                 core::rect<s32> rect2(
762                         /*rect.UpperLeftCorner,
763                         core::dimension2d<u32>(rect.getWidth(), 15)*/
764                         rect.LowerRightCorner - sdim,
765                         sdim
766                 );
767
768                 video::SColor bgcolor(128,0,0,0);
769                 driver->draw2DRectangle(bgcolor, rect2, clip);
770
771                 video::SColor color(255,255,255,255);
772                 font->draw(text.c_str(), rect2, color, false, false, clip);
773         }
774 }