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