]> git.lizzy.rs Git - dragonfireclient.git/blob - src/hud.cpp
Use single box for halo mesh
[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 "gamedef.h"
27 #include "itemdef.h"
28 #include "inventory.h"
29 #include "client/tile.h"
30 #include "localplayer.h"
31 #include "camera.h"
32 #include "porting.h"
33 #include "fontengine.h"
34 #include "guiscalingfilter.h"
35 #include "mesh.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, IGameDef *gamedef, LocalPlayer *player,
44                 Inventory *inventory) {
45         this->driver      = driver;
46         this->smgr        = smgr;
47         this->guienv      = guienv;
48         this->gamedef     = gamedef;
49         this->player      = player;
50         this->inventory   = inventory;
51
52         m_screensize       = v2u32(0, 0);
53         m_displaycenter    = v2s32(0, 0);
54         m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
55         m_hotbar_imagesize *= g_settings->getFloat("hud_scaling");
56         m_padding = m_hotbar_imagesize / 12;
57
58         const video::SColor hbar_color(255, 255, 255, 255);
59         for (unsigned int i=0; i < 4; i++ ){
60                 hbar_colors[i] = hbar_color;
61         }
62
63         tsrc = gamedef->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 = gamedef->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                         gamedef, selected ? IT_ROT_SELECTED : IT_ROT_NONE);
196         }
197
198 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
199 void Hud::drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
200                 InventoryList *mainlist, u16 selectitem, u16 direction)
201 {
202 #ifdef HAVE_TOUCHSCREENGUI
203         if ( (g_touchscreengui) && (offset == 0))
204                 g_touchscreengui->resetHud();
205 #endif
206
207         s32 height  = m_hotbar_imagesize + m_padding * 2;
208         s32 width   = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
209
210         if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
211                 width  = m_hotbar_imagesize + m_padding * 2;
212                 height = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
213         }
214
215         // Position of upper left corner of bar
216         v2s32 pos = upperleftpos;
217
218         if (hotbar_image != player->hotbar_image) {
219                 hotbar_image = player->hotbar_image;
220                 if (hotbar_image != "")
221                         use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
222                 else
223                         use_hotbar_image = false;
224         }
225
226         if (hotbar_selected_image != player->hotbar_selected_image) {
227                 hotbar_selected_image = player->hotbar_selected_image;
228                 if (hotbar_selected_image != "")
229                         use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
230                 else
231                         use_hotbar_selected_image = false;
232         }
233
234         /* draw customized item background */
235         if (use_hotbar_image) {
236                 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
237                                 width+m_padding/2, height+m_padding/2);
238                 core::rect<s32> rect2 = imgrect2 + pos;
239                 video::ITexture *texture = tsrc->getTexture(hotbar_image);
240                 core::dimension2di imgsize(texture->getOriginalSize());
241                 draw2DImageFilterScaled(driver, texture, rect2,
242                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
243                         NULL, hbar_colors, true);
244         }
245
246         for (s32 i = offset; i < itemcount && (size_t)i < mainlist->getSize(); i++)
247         {
248                 v2s32 steppos;
249                 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
250
251                 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
252
253                 switch (direction) {
254                         case HUD_DIR_RIGHT_LEFT:
255                                 steppos = v2s32(-(m_padding + (i - offset) * fullimglen), m_padding);
256                                 break;
257                         case HUD_DIR_TOP_BOTTOM:
258                                 steppos = v2s32(m_padding, m_padding + (i - offset) * fullimglen);
259                                 break;
260                         case HUD_DIR_BOTTOM_TOP:
261                                 steppos = v2s32(m_padding, -(m_padding + (i - offset) * fullimglen));
262                                 break;
263                         default:
264                                 steppos = v2s32(m_padding + (i - offset) * fullimglen, m_padding);
265                                 break;
266                 }
267
268                 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i +1) == selectitem );
269
270 #ifdef HAVE_TOUCHSCREENGUI
271                 if (g_touchscreengui)
272                         g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
273 #endif
274         }
275 }
276
277
278 void Hud::drawLuaElements(const v3s16 &camera_offset) {
279         u32 text_height = g_fontengine->getTextHeight();
280         irr::gui::IGUIFont* font = g_fontengine->getFont();
281         for (size_t i = 0; i != player->maxHudId(); i++) {
282                 HudElement *e = player->getHud(i);
283                 if (!e)
284                         continue;
285
286                 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
287                                 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
288                 switch (e->type) {
289                         case HUD_ELEM_IMAGE: {
290                                 video::ITexture *texture = tsrc->getTexture(e->text);
291                                 if (!texture)
292                                         continue;
293
294                                 const video::SColor color(255, 255, 255, 255);
295                                 const video::SColor colors[] = {color, color, color, color};
296                                 core::dimension2di imgsize(texture->getOriginalSize());
297                                 v2s32 dstsize(imgsize.Width * e->scale.X,
298                                               imgsize.Height * e->scale.Y);
299                                 if (e->scale.X < 0)
300                                         dstsize.X = m_screensize.X * (e->scale.X * -0.01);
301                                 if (e->scale.Y < 0)
302                                         dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
303                                 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
304                                              (e->align.Y - 1.0) * dstsize.Y / 2);
305                                 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
306                                 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
307                                 draw2DImageFilterScaled(driver, texture, rect,
308                                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
309                                         NULL, colors, true);
310                                 break; }
311                         case HUD_ELEM_TEXT: {
312                                 video::SColor color(255, (e->number >> 16) & 0xFF,
313                                                                                  (e->number >> 8)  & 0xFF,
314                                                                                  (e->number >> 0)  & 0xFF);
315                                 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
316                                 std::wstring text = utf8_to_wide(e->text);
317                                 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
318                                 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
319                                              (e->align.Y - 1.0) * (textsize.Height / 2));
320                                 v2s32 offs(e->offset.X, e->offset.Y);
321                                 font->draw(text.c_str(), size + pos + offset + offs, color);
322                                 break; }
323                         case HUD_ELEM_STATBAR: {
324                                 v2s32 offs(e->offset.X, e->offset.Y);
325                                 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
326                                 break; }
327                         case HUD_ELEM_INVENTORY: {
328                                 InventoryList *inv = inventory->getList(e->text);
329                                 drawItems(pos, e->number, 0, inv, e->item, e->dir);
330                                 break; }
331                         case HUD_ELEM_WAYPOINT: {
332                                 v3f p_pos = player->getPosition() / BS;
333                                 v3f w_pos = e->world_pos * BS;
334                                 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
335                                 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
336                                 w_pos -= intToFloat(camera_offset, BS);
337                                 core::matrix4 trans = camera->getProjectionMatrix();
338                                 trans *= camera->getViewMatrix();
339                                 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
340                                 trans.multiplyWith1x4Matrix(transformed_pos);
341                                 if (transformed_pos[3] < 0)
342                                         break;
343                                 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
344                                         core::reciprocal(transformed_pos[3]);
345                                 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
346                                 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
347                                 video::SColor color(255, (e->number >> 16) & 0xFF,
348                                                                                  (e->number >> 8)  & 0xFF,
349                                                                                  (e->number >> 0)  & 0xFF);
350                                 core::rect<s32> size(0, 0, 200, 2 * text_height);
351                                 std::wstring text = utf8_to_wide(e->name);
352                                 font->draw(text.c_str(), size + pos, color);
353                                 std::ostringstream os;
354                                 os << distance << e->text;
355                                 text = utf8_to_wide(os.str());
356                                 pos.Y += text_height;
357                                 font->draw(text.c_str(), size + pos, color);
358                                 break; }
359                         default:
360                                 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
361                                         " of hud element ID " << i << " due to unrecognized type" << std::endl;
362                 }
363         }
364 }
365
366
367 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
368                 s32 count, v2s32 offset, v2s32 size)
369 {
370         const video::SColor color(255, 255, 255, 255);
371         const video::SColor colors[] = {color, color, color, color};
372
373         video::ITexture *stat_texture = tsrc->getTexture(texture);
374         if (!stat_texture)
375                 return;
376
377         core::dimension2di srcd(stat_texture->getOriginalSize());
378         core::dimension2di dstd;
379         if (size == v2s32()) {
380                 dstd = srcd;
381         } else {
382                 double size_factor = g_settings->getFloat("hud_scaling") *
383                                 porting::getDisplayDensity();
384                 dstd.Height = size.Y * size_factor;
385                 dstd.Width  = size.X * size_factor;
386                 offset.X *= size_factor;
387                 offset.Y *= size_factor;
388         }
389
390         v2s32 p = pos;
391         if (corner & HUD_CORNER_LOWER)
392                 p -= dstd.Height;
393
394         p += offset;
395
396         v2s32 steppos;
397         switch (drawdir) {
398                 case HUD_DIR_RIGHT_LEFT:
399                         steppos = v2s32(-1, 0);
400                         break;
401                 case HUD_DIR_TOP_BOTTOM:
402                         steppos = v2s32(0, 1);
403                         break;
404                 case HUD_DIR_BOTTOM_TOP:
405                         steppos = v2s32(0, -1);
406                         break;
407                 default:
408                         steppos = v2s32(1, 0);
409         }
410         steppos.X *= dstd.Width;
411         steppos.Y *= dstd.Height;
412
413         for (s32 i = 0; i < count / 2; i++)
414         {
415                 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
416                 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
417
418                 dstrect += p;
419                 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
420                 p += steppos;
421         }
422
423         if (count % 2 == 1)
424         {
425                 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
426                 core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
427
428                 dstrect += p;
429                 draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true);
430         }
431 }
432
433
434 void Hud::drawHotbar(u16 playeritem) {
435
436         v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
437
438         InventoryList *mainlist = inventory->getList("main");
439         if (mainlist == NULL) {
440                 //silently ignore this we may not be initialized completely
441                 return;
442         }
443
444         s32 hotbar_itemcount = player->hud_hotbar_itemcount;
445         s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
446         v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
447
448         if ( (float) width / (float) porting::getWindowSize().X <=
449                         g_settings->getFloat("hud_hotbar_max_width")) {
450                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
451                         drawItems(pos, hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
452                 }
453         }
454         else {
455                 pos.X += width/4;
456
457                 v2s32 secondpos = pos;
458                 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
459
460                 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
461                         drawItems(pos, hotbar_itemcount/2, 0, mainlist, playeritem + 1, 0);
462                         drawItems(secondpos, hotbar_itemcount, hotbar_itemcount/2, mainlist, playeritem + 1, 0);
463                 }
464         }
465
466         //////////////////////////// compatibility code to be removed //////////////
467         // this is ugly as hell but there's no other way to keep compatibility to
468         // old servers
469         if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) {
470                 drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5),
471                         floor(1 * (float) m_screensize.Y + 0.5)),
472                         HUD_CORNER_UPPER, 0, "heart.png",
473                         player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
474         }
475
476         if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
477                         (player->getBreath() < 11)) {
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, "bubble.png",
481                         player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
482         }
483         ////////////////////////////////////////////////////////////////////////////
484 }
485
486
487 void Hud::drawCrosshair() {
488
489         if (use_crosshair_image) {
490                 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
491                 v2u32 size  = crosshair->getOriginalSize();
492                 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
493                                 m_displaycenter.Y - (size.Y / 2));
494                 driver->draw2DImage(crosshair, lsize,
495                                 core::rect<s32>(0, 0, size.X, size.Y),
496                                 0, crosshair_argb, true);
497         } else {
498                 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
499                                 m_displaycenter + v2s32(10, 0), crosshair_argb);
500                 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
501                                 m_displaycenter + v2s32(0, 10), crosshair_argb);
502         }
503 }
504
505 void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset)
506 {
507         m_camera_offset = camera_offset;
508         m_selection_pos = pos;
509         m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS);
510 }
511         
512 void Hud::drawSelectionMesh()
513 {       
514         if (!m_use_selection_mesh) {
515                 // Draw 3D selection boxes
516                 video::SMaterial oldmaterial = driver->getMaterial2D();
517                 driver->setMaterial(m_selection_material);
518                 for (std::vector<aabb3f>::const_iterator
519                                 i = m_selection_boxes.begin();
520                                 i != m_selection_boxes.end(); ++i) {
521                         aabb3f box = aabb3f(
522                                 i->MinEdge + m_selection_pos_with_offset,
523                                 i->MaxEdge + m_selection_pos_with_offset);
524                         
525                         u32 r = (selectionbox_argb.getRed() *
526                                         m_selection_mesh_color.getRed() / 255);         
527                         u32 g = (selectionbox_argb.getGreen() *
528                                         m_selection_mesh_color.getGreen() / 255);
529                         u32 b = (selectionbox_argb.getBlue() *
530                                         m_selection_mesh_color.getBlue() / 255);
531                         driver->draw3DBox(box, video::SColor(255, r, g, b));
532                 }
533                 driver->setMaterial(oldmaterial);
534         } else if (m_selection_mesh) {
535                 // Draw selection mesh
536                 video::SMaterial oldmaterial = driver->getMaterial2D();
537                 driver->setMaterial(m_selection_material);
538                 setMeshColor(m_selection_mesh, m_selection_mesh_color);
539                 scene::IMesh* mesh = cloneMesh(m_selection_mesh);
540                 translateMesh(mesh, m_selection_pos_with_offset);
541                 u32 mc = m_selection_mesh->getMeshBufferCount();
542                 for (u32 i = 0; i < mc; i++) {
543                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
544                         driver->drawMeshBuffer(buf);
545                 }
546                 mesh->drop();
547                 driver->setMaterial(oldmaterial);
548         }
549 }
550
551 void Hud::updateSelectionMesh(const v3s16 &camera_offset)
552 {
553         m_camera_offset = camera_offset;
554         if (!m_use_selection_mesh)
555                 return;
556
557         if (m_selection_mesh) {
558                 m_selection_mesh->drop();
559                 m_selection_mesh = NULL;
560         }
561
562         if (!m_selection_boxes.size()) {
563                 // No pointed object
564                 return;
565         }
566
567         // New pointed object, create new mesh.
568
569         // Texture UV coordinates for selection boxes
570         static f32 texture_uv[24] = {
571                 0,0,1,1,
572                 0,0,1,1,
573                 0,0,1,1,
574                 0,0,1,1,
575                 0,0,1,1,
576                 0,0,1,1
577         };
578
579         // Use single halo box instead of multiple overlapping boxes.
580         // Temporary solution - problem can be solved with multiple
581         // rendering targets, or some method to remove inner surfaces.
582         // Thats because of halo transparency.
583
584         aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0);
585         m_halo_boxes.clear();
586
587         for (std::vector<aabb3f>::iterator
588                         i = m_selection_boxes.begin();
589                         i != m_selection_boxes.end(); ++i) {
590                 halo_box.addInternalBox(*i);
591         }
592
593         m_halo_boxes.push_back(halo_box);
594         m_selection_mesh = convertNodeboxesToMesh(
595                 m_halo_boxes, texture_uv, 0.5);
596 }
597
598 void Hud::resizeHotbar() {
599         if (m_screensize != porting::getWindowSize()) {
600                 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
601                 m_hotbar_imagesize *= g_settings->getFloat("hud_scaling");
602                 m_padding = m_hotbar_imagesize / 12;
603                 m_screensize = porting::getWindowSize();
604                 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
605         }
606 }
607
608 struct MeshTimeInfo {
609         s32 time;
610         scene::IMesh *mesh;
611 };
612
613 void drawItemStack(video::IVideoDriver *driver,
614                 gui::IGUIFont *font,
615                 const ItemStack &item,
616                 const core::rect<s32> &rect,
617                 const core::rect<s32> *clip,
618                 IGameDef *gamedef,
619                 ItemRotationKind rotation_kind)
620 {
621         static MeshTimeInfo rotation_time_infos[IT_ROT_NONE];
622         static bool enable_animations =
623                 g_settings->getBool("inventory_items_animations");
624
625         if (item.empty()) {
626                 if (rotation_kind < IT_ROT_NONE) {
627                         rotation_time_infos[rotation_kind].mesh = NULL;
628                 }
629                 return;
630         }
631
632         const ItemDefinition &def = item.getDefinition(gamedef->idef());
633         scene::IMesh* mesh = gamedef->idef()->getWieldMesh(def.name, gamedef);
634
635         if (mesh) {
636                 driver->clearZBuffer();
637                 s32 delta = 0;
638                 if (rotation_kind < IT_ROT_NONE) {
639                         MeshTimeInfo &ti = rotation_time_infos[rotation_kind];
640                         if (mesh != ti.mesh) {
641                                 ti.mesh = mesh;
642                                 ti.time = getTimeMs();
643                         } else {
644                                 delta = porting::getDeltaMs(ti.time, getTimeMs()) % 100000;
645                         }
646                 }
647                 core::rect<s32> oldViewPort = driver->getViewPort();
648                 core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
649                 core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
650                 core::matrix4 ProjMatrix;
651                 ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100);
652                 driver->setTransform(video::ETS_PROJECTION, ProjMatrix);
653                 driver->setTransform(video::ETS_VIEW, ProjMatrix);
654                 core::matrix4 matrix;
655                 matrix.makeIdentity();
656
657                 if (enable_animations) {
658                         float timer_f = (float)delta / 5000.0;
659                         matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0));
660                 }
661
662                 driver->setTransform(video::ETS_WORLD, matrix);
663                 driver->setViewPort(rect);
664
665                 u32 mc = mesh->getMeshBufferCount();
666                 for (u32 j = 0; j < mc; ++j) {
667                         scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
668                         video::SMaterial &material = buf->getMaterial();
669                         material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
670                         material.Lighting = false;
671                         driver->setMaterial(material);
672                         driver->drawMeshBuffer(buf);
673                 }
674
675                 driver->setTransform(video::ETS_VIEW, oldViewMat);
676                 driver->setTransform(video::ETS_PROJECTION, oldProjMat);
677                 driver->setViewPort(oldViewPort);
678         }
679
680         if(def.type == ITEM_TOOL && item.wear != 0)
681         {
682                 // Draw a progressbar
683                 float barheight = rect.getHeight()/16;
684                 float barpad_x = rect.getWidth()/16;
685                 float barpad_y = rect.getHeight()/16;
686                 core::rect<s32> progressrect(
687                         rect.UpperLeftCorner.X + barpad_x,
688                         rect.LowerRightCorner.Y - barpad_y - barheight,
689                         rect.LowerRightCorner.X - barpad_x,
690                         rect.LowerRightCorner.Y - barpad_y);
691
692                 // Shrink progressrect by amount of tool damage
693                 float wear = item.wear / 65535.0;
694                 int progressmid =
695                         wear * progressrect.UpperLeftCorner.X +
696                         (1-wear) * progressrect.LowerRightCorner.X;
697
698                 // Compute progressbar color
699                 //   wear = 0.0: green
700                 //   wear = 0.5: yellow
701                 //   wear = 1.0: red
702                 video::SColor color(255,255,255,255);
703                 int wear_i = MYMIN(floor(wear * 600), 511);
704                 wear_i = MYMIN(wear_i + 10, 511);
705                 if(wear_i <= 255)
706                         color.set(255, wear_i, 255, 0);
707                 else
708                         color.set(255, 255, 511-wear_i, 0);
709
710                 core::rect<s32> progressrect2 = progressrect;
711                 progressrect2.LowerRightCorner.X = progressmid;
712                 driver->draw2DRectangle(color, progressrect2, clip);
713
714                 color = video::SColor(255,0,0,0);
715                 progressrect2 = progressrect;
716                 progressrect2.UpperLeftCorner.X = progressmid;
717                 driver->draw2DRectangle(color, progressrect2, clip);
718         }
719
720         if(font != NULL && item.count >= 2)
721         {
722                 // Get the item count as a string
723                 std::string text = itos(item.count);
724                 v2u32 dim = font->getDimension(utf8_to_wide(text).c_str());
725                 v2s32 sdim(dim.X,dim.Y);
726
727                 core::rect<s32> rect2(
728                         /*rect.UpperLeftCorner,
729                         core::dimension2d<u32>(rect.getWidth(), 15)*/
730                         rect.LowerRightCorner - sdim,
731                         sdim
732                 );
733
734                 video::SColor bgcolor(128,0,0,0);
735                 driver->draw2DRectangle(bgcolor, rect2, clip);
736
737                 video::SColor color(255,255,255,255);
738                 font->draw(text.c_str(), rect2, color, false, false, clip);
739         }
740 }