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 <IGUIStaticText.h>
37 Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
38 gui::IGUIEnvironment* guienv, gui::IGUIFont *font,
39 u32 text_height, IGameDef *gamedef,
40 LocalPlayer *player, Inventory *inventory) {
41 this->driver = driver;
43 this->guienv = guienv;
45 this->text_height = text_height;
46 this->gamedef = gamedef;
47 this->player = player;
48 this->inventory = inventory;
50 m_screensize = v2u32(0, 0);
51 m_displaycenter = v2s32(0, 0);
52 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
53 m_padding = m_hotbar_imagesize / 12;
55 const video::SColor hbar_color(255, 255, 255, 255);
56 for (unsigned int i=0; i < 4; i++ ){
57 hbar_colors[i] = hbar_color;
60 tsrc = gamedef->getTextureSource();
62 v3f crosshair_color = g_settings->getV3F("crosshair_color");
63 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
64 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
65 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
66 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
67 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
69 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
70 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
71 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
72 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
73 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
75 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
78 use_hotbar_image = false;
79 hotbar_selected_image = "";
80 use_hotbar_selected_image = false;
83 void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect, bool selected) {
86 /* draw hihlighting around selected item */
87 if (use_hotbar_selected_image) {
88 core::rect<s32> imgrect2 = rect;
89 imgrect2.UpperLeftCorner.X -= (m_padding*2);
90 imgrect2.UpperLeftCorner.Y -= (m_padding*2);
91 imgrect2.LowerRightCorner.X += (m_padding*2);
92 imgrect2.LowerRightCorner.Y += (m_padding*2);
93 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
94 core::dimension2di imgsize(texture->getOriginalSize());
95 driver->draw2DImage(texture, imgrect2,
96 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
97 NULL, hbar_colors, true);
99 video::SColor c_outside(255,255,0,0);
100 //video::SColor c_outside(255,0,0,0);
101 //video::SColor c_inside(255,192,192,192);
102 s32 x1 = rect.UpperLeftCorner.X;
103 s32 y1 = rect.UpperLeftCorner.Y;
104 s32 x2 = rect.LowerRightCorner.X;
105 s32 y2 = rect.LowerRightCorner.Y;
106 // Black base borders
107 driver->draw2DRectangle(c_outside,
109 v2s32(x1 - m_padding, y1 - m_padding),
110 v2s32(x2 + m_padding, y1)
112 driver->draw2DRectangle(c_outside,
114 v2s32(x1 - m_padding, y2),
115 v2s32(x2 + m_padding, y2 + m_padding)
117 driver->draw2DRectangle(c_outside,
119 v2s32(x1 - m_padding, y1),
122 driver->draw2DRectangle(c_outside,
125 v2s32(x2 + m_padding, y2)
127 /*// Light inside borders
128 driver->draw2DRectangle(c_inside,
130 v2s32(x1 - padding/2, y1 - padding/2),
131 v2s32(x2 + padding/2, y1)
133 driver->draw2DRectangle(c_inside,
135 v2s32(x1 - padding/2, y2),
136 v2s32(x2 + padding/2, y2 + padding/2)
138 driver->draw2DRectangle(c_inside,
140 v2s32(x1 - padding/2, y1),
143 driver->draw2DRectangle(c_inside,
146 v2s32(x2 + padding/2, y2)
152 video::SColor bgcolor2(128, 0, 0, 0);
153 if (!use_hotbar_image)
154 driver->draw2DRectangle(bgcolor2, rect, NULL);
155 drawItemStack(driver, font, item, rect, NULL, gamedef);
158 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
159 void Hud::drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
160 InventoryList *mainlist, u16 selectitem, u16 direction)
162 s32 height = m_hotbar_imagesize + m_padding * 2;
163 s32 width = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
165 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
166 width = m_hotbar_imagesize + m_padding * 2;
167 height = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
170 // Position of upper left corner of bar
171 v2s32 pos = upperleftpos;
173 if (hotbar_image != player->hotbar_image) {
174 hotbar_image = player->hotbar_image;
175 if (hotbar_image != "")
176 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
178 use_hotbar_image = false;
181 if (hotbar_selected_image != player->hotbar_selected_image) {
182 hotbar_selected_image = player->hotbar_selected_image;
183 if (hotbar_selected_image != "")
184 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
186 use_hotbar_selected_image = false;
189 /* draw customized item background */
190 if (use_hotbar_image) {
191 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
192 width+m_padding/2, height+m_padding/2);
193 core::rect<s32> rect2 = imgrect2 + pos;
194 video::ITexture *texture = tsrc->getTexture(hotbar_image);
195 core::dimension2di imgsize(texture->getOriginalSize());
196 driver->draw2DImage(texture, rect2,
197 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
198 NULL, hbar_colors, true);
201 for (s32 i = offset; i < itemcount && (size_t)i < mainlist->getSize(); i++)
204 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
206 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
209 case HUD_DIR_RIGHT_LEFT:
210 steppos = v2s32(-(m_padding + (i - offset) * fullimglen), m_padding);
212 case HUD_DIR_TOP_BOTTOM:
213 steppos = v2s32(m_padding, m_padding + (i - offset) * fullimglen);
215 case HUD_DIR_BOTTOM_TOP:
216 steppos = v2s32(m_padding, -(m_padding + (i - offset) * fullimglen));
219 steppos = v2s32(m_padding + (i - offset) * fullimglen, m_padding);
223 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i +1) == selectitem );
228 void Hud::drawLuaElements(v3s16 camera_offset) {
229 for (size_t i = 0; i != player->maxHudId(); i++) {
230 HudElement *e = player->getHud(i);
234 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
235 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
237 case HUD_ELEM_IMAGE: {
238 video::ITexture *texture = tsrc->getTexture(e->text);
242 const video::SColor color(255, 255, 255, 255);
243 const video::SColor colors[] = {color, color, color, color};
244 core::dimension2di imgsize(texture->getOriginalSize());
245 v2s32 dstsize(imgsize.Width * e->scale.X,
246 imgsize.Height * e->scale.Y);
248 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
250 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
251 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
252 (e->align.Y - 1.0) * dstsize.Y / 2);
253 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
254 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
255 driver->draw2DImage(texture, rect,
256 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
259 case HUD_ELEM_TEXT: {
260 video::SColor color(255, (e->number >> 16) & 0xFF,
261 (e->number >> 8) & 0xFF,
262 (e->number >> 0) & 0xFF);
263 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
264 std::wstring text = narrow_to_wide(e->text);
265 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
266 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
267 (e->align.Y - 1.0) * (textsize.Height / 2));
268 v2s32 offs(e->offset.X, e->offset.Y);
269 font->draw(text.c_str(), size + pos + offset + offs, color);
271 case HUD_ELEM_STATBAR: {
272 v2s32 offs(e->offset.X, e->offset.Y);
273 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
275 case HUD_ELEM_INVENTORY: {
276 InventoryList *inv = inventory->getList(e->text);
277 drawItems(pos, e->number, 0, inv, e->item, e->dir);
279 case HUD_ELEM_WAYPOINT: {
280 v3f p_pos = player->getPosition() / BS;
281 v3f w_pos = e->world_pos * BS;
282 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
283 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
284 w_pos -= intToFloat(camera_offset, BS);
285 core::matrix4 trans = camera->getProjectionMatrix();
286 trans *= camera->getViewMatrix();
287 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
288 trans.multiplyWith1x4Matrix(transformed_pos);
289 if (transformed_pos[3] < 0)
291 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
292 core::reciprocal(transformed_pos[3]);
293 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
294 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
295 video::SColor color(255, (e->number >> 16) & 0xFF,
296 (e->number >> 8) & 0xFF,
297 (e->number >> 0) & 0xFF);
298 core::rect<s32> size(0, 0, 200, 2 * text_height);
299 std::wstring text = narrow_to_wide(e->name);
300 font->draw(text.c_str(), size + pos, color);
301 std::ostringstream os;
302 os<<distance<<e->text;
303 text = narrow_to_wide(os.str());
304 pos.Y += text_height;
305 font->draw(text.c_str(), size + pos, color);
308 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
309 " of hud element ID " << i << " due to unrecognized type" << std::endl;
315 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
316 s32 count, v2s32 offset, v2s32 size)
318 const video::SColor color(255, 255, 255, 255);
319 const video::SColor colors[] = {color, color, color, color};
321 video::ITexture *stat_texture = tsrc->getTexture(texture);
325 core::dimension2di srcd(stat_texture->getOriginalSize());
326 core::dimension2di dstd;
327 if (size == v2s32()) {
330 dstd.Height = size.Y * g_settings->getFloat("gui_scaling") *
331 porting::getDisplayDensity();
332 dstd.Width = size.X * g_settings->getFloat("gui_scaling") *
333 porting::getDisplayDensity();
335 offset.X *= g_settings->getFloat("gui_scaling") *
336 porting::getDisplayDensity();
338 offset.Y *= g_settings->getFloat("gui_scaling") *
339 porting::getDisplayDensity();
343 if (corner & HUD_CORNER_LOWER)
350 case HUD_DIR_RIGHT_LEFT:
351 steppos = v2s32(-1, 0);
353 case HUD_DIR_TOP_BOTTOM:
354 steppos = v2s32(0, 1);
356 case HUD_DIR_BOTTOM_TOP:
357 steppos = v2s32(0, -1);
360 steppos = v2s32(1, 0);
362 steppos.X *= dstd.Width;
363 steppos.Y *= dstd.Height;
365 for (s32 i = 0; i < count / 2; i++)
367 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
368 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
371 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
377 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
378 core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
381 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
386 void Hud::drawHotbar(u16 playeritem) {
388 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
390 InventoryList *mainlist = inventory->getList("main");
391 if (mainlist == NULL) {
392 //silently ignore this we may not be initialized completely
396 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
397 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
398 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
400 if ( (float) width / (float) porting::getWindowSize().X <=
401 g_settings->getFloat("hud_hotbar_max_width")) {
402 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
403 drawItems(pos, hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
409 v2s32 secondpos = pos;
410 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
412 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
413 drawItems(pos, hotbar_itemcount/2, 0, mainlist, playeritem + 1, 0);
414 drawItems(secondpos, hotbar_itemcount, hotbar_itemcount/2, mainlist, playeritem + 1, 0);
418 //////////////////////////// compatibility code to be removed //////////////
419 // this is ugly as hell but there's no other way to keep compatibility to
421 if ( player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
422 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
423 floor(1 * (float) m_screensize.Y + 0.5)),
424 HUD_CORNER_UPPER, 0, "heart.png",
425 player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
427 if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
428 (player->getBreath() < 11))
429 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
430 floor(1 * (float) m_screensize.Y + 0.5)),
431 HUD_CORNER_UPPER, 0, "heart.png",
432 player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
433 ////////////////////////////////////////////////////////////////////////////
437 void Hud::drawCrosshair() {
439 if (use_crosshair_image) {
440 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
441 v2u32 size = crosshair->getOriginalSize();
442 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
443 m_displaycenter.Y - (size.Y / 2));
444 driver->draw2DImage(crosshair, lsize,
445 core::rect<s32>(0, 0, size.X, size.Y),
446 0, crosshair_argb, true);
448 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
449 m_displaycenter + v2s32(10, 0), crosshair_argb);
450 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
451 m_displaycenter + v2s32(0, 10), crosshair_argb);
456 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
457 for (std::vector<aabb3f>::const_iterator
458 i = hilightboxes.begin();
459 i != hilightboxes.end(); i++) {
460 driver->draw3DBox(*i, selectionbox_argb);
465 void Hud::resizeHotbar() {
466 if (m_screensize != porting::getWindowSize()) {
467 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
468 m_padding = m_hotbar_imagesize / 12;
469 m_screensize = porting::getWindowSize();
470 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
474 void drawItemStack(video::IVideoDriver *driver,
476 const ItemStack &item,
477 const core::rect<s32> &rect,
478 const core::rect<s32> *clip,
484 const ItemDefinition &def = item.getDefinition(gamedef->idef());
485 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
487 // Draw the inventory texture
490 const video::SColor color(255,255,255,255);
491 const video::SColor colors[] = {color,color,color,color};
492 driver->draw2DImage(texture, rect,
493 core::rect<s32>(core::position2d<s32>(0,0),
494 core::dimension2di(texture->getOriginalSize())),
498 if(def.type == ITEM_TOOL && item.wear != 0)
500 // Draw a progressbar
501 float barheight = rect.getHeight()/16;
502 float barpad_x = rect.getWidth()/16;
503 float barpad_y = rect.getHeight()/16;
504 core::rect<s32> progressrect(
505 rect.UpperLeftCorner.X + barpad_x,
506 rect.LowerRightCorner.Y - barpad_y - barheight,
507 rect.LowerRightCorner.X - barpad_x,
508 rect.LowerRightCorner.Y - barpad_y);
510 // Shrink progressrect by amount of tool damage
511 float wear = item.wear / 65535.0;
513 wear * progressrect.UpperLeftCorner.X +
514 (1-wear) * progressrect.LowerRightCorner.X;
516 // Compute progressbar color
518 // wear = 0.5: yellow
520 video::SColor color(255,255,255,255);
521 int wear_i = MYMIN(floor(wear * 600), 511);
522 wear_i = MYMIN(wear_i + 10, 511);
524 color.set(255, wear_i, 255, 0);
526 color.set(255, 255, 511-wear_i, 0);
528 core::rect<s32> progressrect2 = progressrect;
529 progressrect2.LowerRightCorner.X = progressmid;
530 driver->draw2DRectangle(color, progressrect2, clip);
532 color = video::SColor(255,0,0,0);
533 progressrect2 = progressrect;
534 progressrect2.UpperLeftCorner.X = progressmid;
535 driver->draw2DRectangle(color, progressrect2, clip);
538 if(font != NULL && item.count >= 2)
540 // Get the item count as a string
541 std::string text = itos(item.count);
542 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
543 v2s32 sdim(dim.X,dim.Y);
545 core::rect<s32> rect2(
546 /*rect.UpperLeftCorner,
547 core::dimension2d<u32>(rect.getWidth(), 15)*/
548 rect.LowerRightCorner - sdim,
552 video::SColor bgcolor(128,0,0,0);
553 driver->draw2DRectangle(bgcolor, rect2, clip);
555 video::SColor color(255,255,255,255);
556 font->draw(text.c_str(), rect2, color, false, false, clip);