]> git.lizzy.rs Git - dragonfireclient.git/blob - src/hud.cpp
Hardware coloring for itemstacks
[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
38 #ifdef HAVE_TOUCHSCREENGUI
39 #include "touchscreengui.h"
40 #endif
41
42 Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
43                 gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player,
44                 Inventory *inventory)
45 {
46         this->driver      = driver;
47         this->smgr        = smgr;
48         this->guienv      = guienv;
49         this->client      = client;
50         this->player      = player;
51         this->inventory   = inventory;
52
53         m_hud_scaling      = g_settings->getFloat("hud_scaling");
54         m_screensize       = v2u32(0, 0);
55         m_displaycenter    = v2s32(0, 0);
56         m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
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         hotbar_image = "";
81         use_hotbar_image = false;
82         hotbar_selected_image = "";
83         use_hotbar_selected_image = false;
84
85         m_selection_mesh = NULL;
86         m_selection_boxes.clear();
87         m_halo_boxes.clear();
88
89         m_selection_pos = v3f(0.0, 0.0, 0.0);
90         std::string mode = g_settings->get("node_highlighting");
91         m_selection_material.Lighting = false;
92
93         if (g_settings->getBool("enable_shaders")) {
94                 IShaderSource *shdrsrc = client->getShaderSource();
95                 u16 shader_id = shdrsrc->getShader(
96                         mode == "halo" ? "selection_shader" : "default_shader", 1, 1);
97                 m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
98         } else {
99                 m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
100         }
101
102         if (mode == "box") {
103                 m_use_selection_mesh = false;
104                 m_selection_material.Thickness =
105                         rangelim(g_settings->getS16("selectionbox_width"), 1, 5);
106         } else if (mode == "halo") {
107                 m_use_selection_mesh = true;
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 * porting::getDisplayDensity();
219         pos.Y *= m_hud_scaling * porting::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 * porting::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         if ( (float) width / (float) porting::getWindowSize().X <=
455                         g_settings->getFloat("hud_hotbar_max_width")) {
456                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
457                         drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
458                 }
459         } else {
460                 pos.X += width/4;
461
462                 v2s32 secondpos = pos;
463                 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
464
465                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
466                         drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0,
467                                 mainlist, playeritem + 1, 0);
468                         drawItems(secondpos, v2s32(0, 0), hotbar_itemcount,
469                                 hotbar_itemcount / 2, mainlist, playeritem + 1, 0);
470                 }
471         }
472
473         //////////////////////////// compatibility code to be removed //////////////
474         // this is ugly as hell but there's no other way to keep compatibility to
475         // old servers
476         if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
477                 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
478                         floor(1 * (float) m_screensize.Y + 0.5)),
479                         HUD_CORNER_UPPER, 0, "heart.png",
480                         player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
481         }
482
483         if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
484                         (player->getBreath() < 11)) {
485                 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
486                         floor(1 * (float) m_screensize.Y + 0.5)),
487                         HUD_CORNER_UPPER, 0, "bubble.png",
488                         player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
489         }
490         ////////////////////////////////////////////////////////////////////////////
491 }
492
493
494 void Hud::drawCrosshair()
495 {
496         if (use_crosshair_image) {
497                 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
498                 v2u32 size  = crosshair->getOriginalSize();
499                 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
500                                 m_displaycenter.Y - (size.Y / 2));
501                 driver->draw2DImage(crosshair, lsize,
502                                 core::rect<s32>(0, 0, size.X, size.Y),
503                                 0, crosshair_argb, true);
504         } else {
505                 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
506                                 m_displaycenter + v2s32(10, 0), crosshair_argb);
507                 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
508                                 m_displaycenter + v2s32(0, 10), crosshair_argb);
509         }
510 }
511
512 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
513 {
514         m_camera_offset = camera_offset;
515         m_selection_pos = pos;
516         m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
517 }
518
519 void Hud::drawSelectionMesh()
520 {
521         if (!m_use_selection_mesh) {
522                 // Draw 3D selection boxes
523                 video::SMaterial oldmaterial = driver->getMaterial2D();
524                 driver->setMaterial(m_selection_material);
525                 for (std::vector<aabb3f>::const_iterator
526                                 i = m_selection_boxes.begin();
527                                 i != m_selection_boxes.end(); ++i) {
528                         aabb3f box = aabb3f(
529                                 i->MinEdge + m_selection_pos_with_offset,
530                                 i->MaxEdge + m_selection_pos_with_offset);
531
532                         u32 r = (selectionbox_argb.getRed() *
533                                         m_selection_mesh_color.getRed() / 255);
534                         u32 g = (selectionbox_argb.getGreen() *
535                                         m_selection_mesh_color.getGreen() / 255);
536                         u32 b = (selectionbox_argb.getBlue() *
537                                         m_selection_mesh_color.getBlue() / 255);
538                         driver->draw3DBox(box, video::SColor(255, r, g, b));
539                 }
540                 driver->setMaterial(oldmaterial);
541         } else if (m_selection_mesh) {
542                 // Draw selection mesh
543                 video::SMaterial oldmaterial = driver->getMaterial2D();
544                 driver->setMaterial(m_selection_material);
545                 setMeshColor(m_selection_mesh, m_selection_mesh_color);
546                 video::SColor face_color(0,
547                         MYMIN(255, m_selection_mesh_color.getRed() * 1.5),
548                         MYMIN(255, m_selection_mesh_color.getGreen() * 1.5),
549                         MYMIN(255, m_selection_mesh_color.getBlue() * 1.5));
550                 setMeshColorByNormal(m_selection_mesh, m_selected_face_normal,
551                         face_color);
552                 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
553                 translateMesh(mesh, m_selection_pos_with_offset);
554                 u32 mc = m_selection_mesh->getMeshBufferCount();
555                 for (u32 i = 0; i < mc; i++) {
556                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
557                         driver->drawMeshBuffer(buf);
558                 }
559                 mesh->drop();
560                 driver->setMaterial(oldmaterial);
561         }
562 }
563
564 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
565 {
566         m_camera_offset = camera_offset;
567         if (!m_use_selection_mesh)
568                 return;
569
570         if (m_selection_mesh) {
571                 m_selection_mesh->drop();
572                 m_selection_mesh = NULL;
573         }
574
575         if (!m_selection_boxes.size()) {
576                 // No pointed object
577                 return;
578         }
579
580         // New pointed object, create new mesh.
581
582         // Texture UV coordinates for selection boxes
583         static f32 texture_uv[24] = {
584                 0,0,1,1,
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         };
591
592         // Use single halo box instead of multiple overlapping boxes.
593         // Temporary solution - problem can be solved with multiple
594         // rendering targets, or some method to remove inner surfaces.
595         // Thats because of halo transparency.
596
597         aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
598         m_halo_boxes.clear();
599
600         for (std::vector<aabb3f>::iterator
601                         i = m_selection_boxes.begin();
602                         i != m_selection_boxes.end(); ++i) {
603                 halo_box.addInternalBox(*i);
604         }
605
606         m_halo_boxes.push_back(halo_box);
607         m_selection_mesh = convertNodeboxesToMesh(
608                 m_halo_boxes, texture_uv, 0.5);
609 }
610
611 void Hud::resizeHotbar() {
612         if (m_screensize != porting::getWindowSize()) {
613                 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
614                 m_hotbar_imagesize *= m_hud_scaling;
615                 m_padding = m_hotbar_imagesize / 12;
616                 m_screensize = porting::getWindowSize();
617                 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
618         }
619 }
620
621 struct MeshTimeInfo {
622         s32 time;
623         scene::IMesh *mesh;
624 };
625
626 void drawItemStack(video::IVideoDriver *driver,
627                 gui::IGUIFont *font,
628                 const ItemStack &item,
629                 const core::rect<s32> &rect,
630                 const core::rect<s32> *clip,
631                 Client *client,
632                 ItemRotationKind rotation_kind)
633 {
634         static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
635         static bool enable_animations =
636                 g_settings->getBool("inventory_items_animations");
637
638         if (item.empty()) {
639                 if (rotation_kind < IT_ROT_NONE) {
640                         rotation_time_infos[rotation_kind].mesh = NULL;
641                 }
642                 return;
643         }
644
645         const ItemDefinition &def = item.getDefinition(client->idef());
646         ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
647
648         if (imesh && imesh->mesh) {
649                 scene::IMesh *mesh = imesh->mesh;
650                 driver->clearZBuffer();
651                 s32 delta = 0;
652                 if (rotation_kind < IT_ROT_NONE) {
653                         MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
654                         if (mesh != ti.mesh) {
655                                 ti.mesh = mesh;
656                                 ti.time = getTimeMs();
657                         } else {
658                                 delta = porting::getDeltaMs(ti.time, getTimeMs()) % 100000;
659                         }
660                 }
661                 core::rect<s32> oldViewPort = driver->getViewPort();
662                 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
663                 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
664                 core::matrix4 ProjMatrix;
665                 ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
666                 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
667                 driver->setTransform(video::ETS_VIEW, ProjMatrix);
668                 core::matrix4 matrix;
669                 matrix.makeIdentity();
670
671                 if (enable_animations) {
672                         float timer_f = (float) delta / 5000.0;
673                         matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
674                 }
675
676                 driver->setTransform(video::ETS_WORLD, matrix);
677                 driver->setViewPort(rect);
678
679                 video::SColor basecolor =
680                         client->idef()->getItemstackColor(item, client);
681
682                 u32 mc = mesh->getMeshBufferCount();
683                 for (u32 j = 0; j < mc; ++j) {
684                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
685                         // we can modify vertices relatively fast,
686                         // because these meshes are not buffered.
687                         assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER);
688                         video::SColor c = basecolor;
689                         if (imesh->buffer_colors.size() > j) {
690                                 std::pair<bool, video::SColor> p = imesh->buffer_colors[j];
691                                 c = p.first ? p.second : basecolor;
692                         }
693                         colorizeMeshBuffer(buf, &c);
694                         video::SMaterial &material = buf->getMaterial();
695                         material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
696                         material.Lighting = false;
697                         driver->setMaterial(material);
698                         driver->drawMeshBuffer(buf);
699                 }
700
701                 driver->setTransform(video::ETS_VIEW, oldViewMat);
702                 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
703                 driver->setViewPort(oldViewPort);
704         }
705
706         if(def.type == ITEM_TOOL && item.wear != 0)
707         {
708                 // Draw a progressbar
709                 float barheight = rect.getHeight()/16;
710                 float barpad_x = rect.getWidth()/16;
711                 float barpad_y = rect.getHeight()/16;
712                 core::rect<s32> progressrect(
713                         rect.UpperLeftCorner.X + barpad_x,
714                         rect.LowerRightCorner.Y - barpad_y - barheight,
715                         rect.LowerRightCorner.X - barpad_x,
716                         rect.LowerRightCorner.Y - barpad_y);
717
718                 // Shrink progressrect by amount of tool damage
719                 float wear = item.wear / 65535.0;
720                 int progressmid =
721                         wear * progressrect.UpperLeftCorner.X +
722                         (1-wear) * progressrect.LowerRightCorner.X;
723
724                 // Compute progressbar color
725                 //   wear = 0.0: green
726                 //   wear = 0.5: yellow
727                 //   wear = 1.0: red
728                 video::SColor color(255,255,255,255);
729                 int wear_i = MYMIN(floor(wear * 600), 511);
730                 wear_i = MYMIN(wear_i + 10, 511);
731                 if(wear_i <= 255)
732                         color.set(255, wear_i, 255, 0);
733                 else
734                         color.set(255, 255, 511-wear_i, 0);
735
736                 core::rect<s32> progressrect2 = progressrect;
737                 progressrect2.LowerRightCorner.X = progressmid;
738                 driver->draw2DRectangle(color, progressrect2, clip);
739
740                 color = video::SColor(255,0,0,0);
741                 progressrect2 = progressrect;
742                 progressrect2.UpperLeftCorner.X = progressmid;
743                 driver->draw2DRectangle(color, progressrect2, clip);
744         }
745
746         if(font != NULL && item.count >= 2)
747         {
748                 // Get the item count as a string
749                 std::string text = itos(item.count);
750                 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
751                 v2s32 sdim(dim.X,dim.Y);
752
753                 core::rect<s32> rect2(
754                         /*rect.UpperLeftCorner,
755                         core::dimension2d<u32>(rect.getWidth(), 15)*/
756                         rect.LowerRightCorner - sdim,
757                         sdim
758                 );
759
760                 video::SColor bgcolor(128,0,0,0);
761                 driver->draw2DRectangle(bgcolor, rect2, clip);
762
763                 video::SColor color(255,255,255,255);
764                 font->draw(text.c_str(), rect2, color, false, false, clip);
765         }
766 }