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