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