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