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>
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.
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.
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.
25 #include "util/numeric.h"
29 #include "inventory.h"
31 #include "localplayer.h"
34 #include "fontengine.h"
35 #include <IGUIStaticText.h>
37 #ifdef HAVE_TOUCHSCREENGUI
38 #include "touchscreengui.h"
41 Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
42 gui::IGUIEnvironment* guienv, IGameDef *gamedef, LocalPlayer *player,
43 Inventory *inventory) {
44 this->driver = driver;
46 this->guienv = guienv;
47 this->gamedef = gamedef;
48 this->player = player;
49 this->inventory = inventory;
51 m_screensize = v2u32(0, 0);
52 m_displaycenter = v2s32(0, 0);
53 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
54 m_hotbar_imagesize *= g_settings->getFloat("hud_scaling");
55 m_padding = m_hotbar_imagesize / 12;
57 const video::SColor hbar_color(255, 255, 255, 255);
58 for (unsigned int i=0; i < 4; i++ ){
59 hbar_colors[i] = hbar_color;
62 tsrc = gamedef->getTextureSource();
64 v3f crosshair_color = g_settings->getV3F("crosshair_color");
65 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
66 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
67 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
68 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
69 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
71 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
72 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
73 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
74 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
75 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
77 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
80 use_hotbar_image = false;
81 hotbar_selected_image = "";
82 use_hotbar_selected_image = false;
85 void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect, bool selected) {
88 /* draw hihlighting around selected item */
89 if (use_hotbar_selected_image) {
90 core::rect<s32> imgrect2 = rect;
91 imgrect2.UpperLeftCorner.X -= (m_padding*2);
92 imgrect2.UpperLeftCorner.Y -= (m_padding*2);
93 imgrect2.LowerRightCorner.X += (m_padding*2);
94 imgrect2.LowerRightCorner.Y += (m_padding*2);
95 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
96 core::dimension2di imgsize(texture->getOriginalSize());
97 driver->draw2DImage(texture, imgrect2,
98 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
99 NULL, hbar_colors, true);
101 video::SColor c_outside(255,255,0,0);
102 //video::SColor c_outside(255,0,0,0);
103 //video::SColor c_inside(255,192,192,192);
104 s32 x1 = rect.UpperLeftCorner.X;
105 s32 y1 = rect.UpperLeftCorner.Y;
106 s32 x2 = rect.LowerRightCorner.X;
107 s32 y2 = rect.LowerRightCorner.Y;
108 // Black base borders
109 driver->draw2DRectangle(c_outside,
111 v2s32(x1 - m_padding, y1 - m_padding),
112 v2s32(x2 + m_padding, y1)
114 driver->draw2DRectangle(c_outside,
116 v2s32(x1 - m_padding, y2),
117 v2s32(x2 + m_padding, y2 + m_padding)
119 driver->draw2DRectangle(c_outside,
121 v2s32(x1 - m_padding, y1),
124 driver->draw2DRectangle(c_outside,
127 v2s32(x2 + m_padding, y2)
129 /*// Light inside borders
130 driver->draw2DRectangle(c_inside,
132 v2s32(x1 - padding/2, y1 - padding/2),
133 v2s32(x2 + padding/2, y1)
135 driver->draw2DRectangle(c_inside,
137 v2s32(x1 - padding/2, y2),
138 v2s32(x2 + padding/2, y2 + padding/2)
140 driver->draw2DRectangle(c_inside,
142 v2s32(x1 - padding/2, y1),
145 driver->draw2DRectangle(c_inside,
148 v2s32(x2 + padding/2, y2)
154 video::SColor bgcolor2(128, 0, 0, 0);
155 if (!use_hotbar_image)
156 driver->draw2DRectangle(bgcolor2, rect, NULL);
157 drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL, gamedef);
160 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
161 void Hud::drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
162 InventoryList *mainlist, u16 selectitem, u16 direction)
164 #ifdef HAVE_TOUCHSCREENGUI
165 if ( (g_touchscreengui) && (offset == 0))
166 g_touchscreengui->resetHud();
169 s32 height = m_hotbar_imagesize + m_padding * 2;
170 s32 width = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
172 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
173 width = m_hotbar_imagesize + m_padding * 2;
174 height = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
177 // Position of upper left corner of bar
178 v2s32 pos = upperleftpos;
180 if (hotbar_image != player->hotbar_image) {
181 hotbar_image = player->hotbar_image;
182 if (hotbar_image != "")
183 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
185 use_hotbar_image = false;
188 if (hotbar_selected_image != player->hotbar_selected_image) {
189 hotbar_selected_image = player->hotbar_selected_image;
190 if (hotbar_selected_image != "")
191 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
193 use_hotbar_selected_image = false;
196 /* draw customized item background */
197 if (use_hotbar_image) {
198 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
199 width+m_padding/2, height+m_padding/2);
200 core::rect<s32> rect2 = imgrect2 + pos;
201 video::ITexture *texture = tsrc->getTexture(hotbar_image);
202 core::dimension2di imgsize(texture->getOriginalSize());
203 driver->draw2DImage(texture, rect2,
204 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
205 NULL, hbar_colors, true);
208 for (s32 i = offset; i < itemcount && (size_t)i < mainlist->getSize(); i++)
211 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
213 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
216 case HUD_DIR_RIGHT_LEFT:
217 steppos = v2s32(-(m_padding + (i - offset) * fullimglen), m_padding);
219 case HUD_DIR_TOP_BOTTOM:
220 steppos = v2s32(m_padding, m_padding + (i - offset) * fullimglen);
222 case HUD_DIR_BOTTOM_TOP:
223 steppos = v2s32(m_padding, -(m_padding + (i - offset) * fullimglen));
226 steppos = v2s32(m_padding + (i - offset) * fullimglen, m_padding);
230 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i +1) == selectitem );
232 #ifdef HAVE_TOUCHSCREENGUI
233 if (g_touchscreengui)
234 g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos));
240 void Hud::drawLuaElements(v3s16 camera_offset) {
241 u32 text_height = g_fontengine->getTextHeight();
242 irr::gui::IGUIFont* font = g_fontengine->getFont();
243 for (size_t i = 0; i != player->maxHudId(); i++) {
244 HudElement *e = player->getHud(i);
248 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
249 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
251 case HUD_ELEM_IMAGE: {
252 video::ITexture *texture = tsrc->getTexture(e->text);
256 const video::SColor color(255, 255, 255, 255);
257 const video::SColor colors[] = {color, color, color, color};
258 core::dimension2di imgsize(texture->getOriginalSize());
259 v2s32 dstsize(imgsize.Width * e->scale.X,
260 imgsize.Height * e->scale.Y);
262 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
264 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
265 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
266 (e->align.Y - 1.0) * dstsize.Y / 2);
267 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
268 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
269 driver->draw2DImage(texture, rect,
270 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
273 case HUD_ELEM_TEXT: {
274 video::SColor color(255, (e->number >> 16) & 0xFF,
275 (e->number >> 8) & 0xFF,
276 (e->number >> 0) & 0xFF);
277 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
278 std::wstring text = narrow_to_wide(e->text);
279 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
280 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
281 (e->align.Y - 1.0) * (textsize.Height / 2));
282 v2s32 offs(e->offset.X, e->offset.Y);
283 font->draw(text.c_str(), size + pos + offset + offs, color);
285 case HUD_ELEM_STATBAR: {
286 v2s32 offs(e->offset.X, e->offset.Y);
287 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
289 case HUD_ELEM_INVENTORY: {
290 InventoryList *inv = inventory->getList(e->text);
291 drawItems(pos, e->number, 0, inv, e->item, e->dir);
293 case HUD_ELEM_WAYPOINT: {
294 v3f p_pos = player->getPosition() / BS;
295 v3f w_pos = e->world_pos * BS;
296 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
297 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
298 w_pos -= intToFloat(camera_offset, BS);
299 core::matrix4 trans = camera->getProjectionMatrix();
300 trans *= camera->getViewMatrix();
301 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
302 trans.multiplyWith1x4Matrix(transformed_pos);
303 if (transformed_pos[3] < 0)
305 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
306 core::reciprocal(transformed_pos[3]);
307 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
308 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
309 video::SColor color(255, (e->number >> 16) & 0xFF,
310 (e->number >> 8) & 0xFF,
311 (e->number >> 0) & 0xFF);
312 core::rect<s32> size(0, 0, 200, 2 * text_height);
313 std::wstring text = narrow_to_wide(e->name);
314 font->draw(text.c_str(), size + pos, color);
315 std::ostringstream os;
316 os<<distance<<e->text;
317 text = narrow_to_wide(os.str());
318 pos.Y += text_height;
319 font->draw(text.c_str(), size + pos, color);
322 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
323 " of hud element ID " << i << " due to unrecognized type" << std::endl;
329 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
330 s32 count, v2s32 offset, v2s32 size)
332 const video::SColor color(255, 255, 255, 255);
333 const video::SColor colors[] = {color, color, color, color};
335 video::ITexture *stat_texture = tsrc->getTexture(texture);
339 core::dimension2di srcd(stat_texture->getOriginalSize());
340 core::dimension2di dstd;
341 if (size == v2s32()) {
344 dstd.Height = size.Y * g_settings->getFloat("hud_scaling") *
345 porting::getDisplayDensity();
346 dstd.Width = size.X * g_settings->getFloat("hud_scaling") *
347 porting::getDisplayDensity();
349 offset.X *= g_settings->getFloat("hud_scaling") *
350 porting::getDisplayDensity();
352 offset.Y *= g_settings->getFloat("hud_scaling") *
353 porting::getDisplayDensity();
357 if (corner & HUD_CORNER_LOWER)
364 case HUD_DIR_RIGHT_LEFT:
365 steppos = v2s32(-1, 0);
367 case HUD_DIR_TOP_BOTTOM:
368 steppos = v2s32(0, 1);
370 case HUD_DIR_BOTTOM_TOP:
371 steppos = v2s32(0, -1);
374 steppos = v2s32(1, 0);
376 steppos.X *= dstd.Width;
377 steppos.Y *= dstd.Height;
379 for (s32 i = 0; i < count / 2; i++)
381 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
382 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
385 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
391 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
392 core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
395 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
400 void Hud::drawHotbar(u16 playeritem) {
402 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
404 InventoryList *mainlist = inventory->getList("main");
405 if (mainlist == NULL) {
406 //silently ignore this we may not be initialized completely
410 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
411 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
412 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
414 if ( (float) width / (float) porting::getWindowSize().X <=
415 g_settings->getFloat("hud_hotbar_max_width")) {
416 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
417 drawItems(pos, hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
423 v2s32 secondpos = pos;
424 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
426 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
427 drawItems(pos, hotbar_itemcount/2, 0, mainlist, playeritem + 1, 0);
428 drawItems(secondpos, hotbar_itemcount, hotbar_itemcount/2, mainlist, playeritem + 1, 0);
432 //////////////////////////// compatibility code to be removed //////////////
433 // this is ugly as hell but there's no other way to keep compatibility to
435 if ( player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
436 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
437 floor(1 * (float) m_screensize.Y + 0.5)),
438 HUD_CORNER_UPPER, 0, "heart.png",
439 player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
441 if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
442 (player->getBreath() < 11))
443 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
444 floor(1 * (float) m_screensize.Y + 0.5)),
445 HUD_CORNER_UPPER, 0, "heart.png",
446 player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
447 ////////////////////////////////////////////////////////////////////////////
451 void Hud::drawCrosshair() {
453 if (use_crosshair_image) {
454 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
455 v2u32 size = crosshair->getOriginalSize();
456 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
457 m_displaycenter.Y - (size.Y / 2));
458 driver->draw2DImage(crosshair, lsize,
459 core::rect<s32>(0, 0, size.X, size.Y),
460 0, crosshair_argb, true);
462 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
463 m_displaycenter + v2s32(10, 0), crosshair_argb);
464 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
465 m_displaycenter + v2s32(0, 10), crosshair_argb);
470 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
471 for (std::vector<aabb3f>::const_iterator
472 i = hilightboxes.begin();
473 i != hilightboxes.end(); i++) {
474 driver->draw3DBox(*i, selectionbox_argb);
479 void Hud::resizeHotbar() {
480 if (m_screensize != porting::getWindowSize()) {
481 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
482 m_hotbar_imagesize *= g_settings->getFloat("hud_scaling");
483 m_padding = m_hotbar_imagesize / 12;
484 m_screensize = porting::getWindowSize();
485 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
489 void drawItemStack(video::IVideoDriver *driver,
491 const ItemStack &item,
492 const core::rect<s32> &rect,
493 const core::rect<s32> *clip,
499 const ItemDefinition &def = item.getDefinition(gamedef->idef());
500 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
502 // Draw the inventory texture
505 const video::SColor color(255,255,255,255);
506 const video::SColor colors[] = {color,color,color,color};
507 driver->draw2DImage(texture, rect,
508 core::rect<s32>(core::position2d<s32>(0,0),
509 core::dimension2di(texture->getOriginalSize())),
513 if(def.type == ITEM_TOOL && item.wear != 0)
515 // Draw a progressbar
516 float barheight = rect.getHeight()/16;
517 float barpad_x = rect.getWidth()/16;
518 float barpad_y = rect.getHeight()/16;
519 core::rect<s32> progressrect(
520 rect.UpperLeftCorner.X + barpad_x,
521 rect.LowerRightCorner.Y - barpad_y - barheight,
522 rect.LowerRightCorner.X - barpad_x,
523 rect.LowerRightCorner.Y - barpad_y);
525 // Shrink progressrect by amount of tool damage
526 float wear = item.wear / 65535.0;
528 wear * progressrect.UpperLeftCorner.X +
529 (1-wear) * progressrect.LowerRightCorner.X;
531 // Compute progressbar color
533 // wear = 0.5: yellow
535 video::SColor color(255,255,255,255);
536 int wear_i = MYMIN(floor(wear * 600), 511);
537 wear_i = MYMIN(wear_i + 10, 511);
539 color.set(255, wear_i, 255, 0);
541 color.set(255, 255, 511-wear_i, 0);
543 core::rect<s32> progressrect2 = progressrect;
544 progressrect2.LowerRightCorner.X = progressmid;
545 driver->draw2DRectangle(color, progressrect2, clip);
547 color = video::SColor(255,0,0,0);
548 progressrect2 = progressrect;
549 progressrect2.UpperLeftCorner.X = progressmid;
550 driver->draw2DRectangle(color, progressrect2, clip);
553 if(font != NULL && item.count >= 2)
555 // Get the item count as a string
556 std::string text = itos(item.count);
557 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
558 v2s32 sdim(dim.X,dim.Y);
560 core::rect<s32> rect2(
561 /*rect.UpperLeftCorner,
562 core::dimension2d<u32>(rect.getWidth(), 15)*/
563 rect.LowerRightCorner - sdim,
567 video::SColor bgcolor(128,0,0,0);
568 driver->draw2DRectangle(bgcolor, rect2, clip);
570 video::SColor color(255,255,255,255);
571 font->draw(text.c_str(), rect2, color, false, false, clip);