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_hotbar_imagesize *= g_settings->getFloat("gui_scaling");
54 m_padding = m_hotbar_imagesize / 12;
56 const video::SColor hbar_color(255, 255, 255, 255);
57 for (unsigned int i=0; i < 4; i++ ){
58 hbar_colors[i] = hbar_color;
61 tsrc = gamedef->getTextureSource();
63 v3f crosshair_color = g_settings->getV3F("crosshair_color");
64 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
65 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
66 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
67 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
68 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
70 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
71 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
72 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
73 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
74 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
76 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
79 use_hotbar_image = false;
80 hotbar_selected_image = "";
81 use_hotbar_selected_image = false;
84 void Hud::drawItem(const ItemStack &item, const core::rect<s32>& rect, bool selected) {
87 /* draw hihlighting around selected item */
88 if (use_hotbar_selected_image) {
89 core::rect<s32> imgrect2 = rect;
90 imgrect2.UpperLeftCorner.X -= (m_padding*2);
91 imgrect2.UpperLeftCorner.Y -= (m_padding*2);
92 imgrect2.LowerRightCorner.X += (m_padding*2);
93 imgrect2.LowerRightCorner.Y += (m_padding*2);
94 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
95 core::dimension2di imgsize(texture->getOriginalSize());
96 driver->draw2DImage(texture, imgrect2,
97 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
98 NULL, hbar_colors, true);
100 video::SColor c_outside(255,255,0,0);
101 //video::SColor c_outside(255,0,0,0);
102 //video::SColor c_inside(255,192,192,192);
103 s32 x1 = rect.UpperLeftCorner.X;
104 s32 y1 = rect.UpperLeftCorner.Y;
105 s32 x2 = rect.LowerRightCorner.X;
106 s32 y2 = rect.LowerRightCorner.Y;
107 // Black base borders
108 driver->draw2DRectangle(c_outside,
110 v2s32(x1 - m_padding, y1 - m_padding),
111 v2s32(x2 + m_padding, y1)
113 driver->draw2DRectangle(c_outside,
115 v2s32(x1 - m_padding, y2),
116 v2s32(x2 + m_padding, y2 + m_padding)
118 driver->draw2DRectangle(c_outside,
120 v2s32(x1 - m_padding, y1),
123 driver->draw2DRectangle(c_outside,
126 v2s32(x2 + m_padding, y2)
128 /*// Light inside borders
129 driver->draw2DRectangle(c_inside,
131 v2s32(x1 - padding/2, y1 - padding/2),
132 v2s32(x2 + padding/2, y1)
134 driver->draw2DRectangle(c_inside,
136 v2s32(x1 - padding/2, y2),
137 v2s32(x2 + padding/2, y2 + padding/2)
139 driver->draw2DRectangle(c_inside,
141 v2s32(x1 - padding/2, y1),
144 driver->draw2DRectangle(c_inside,
147 v2s32(x2 + padding/2, y2)
153 video::SColor bgcolor2(128, 0, 0, 0);
154 if (!use_hotbar_image)
155 driver->draw2DRectangle(bgcolor2, rect, NULL);
156 drawItemStack(driver, font, item, rect, NULL, gamedef);
159 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
160 void Hud::drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
161 InventoryList *mainlist, u16 selectitem, u16 direction)
163 s32 height = m_hotbar_imagesize + m_padding * 2;
164 s32 width = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
166 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
167 width = m_hotbar_imagesize + m_padding * 2;
168 height = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
171 // Position of upper left corner of bar
172 v2s32 pos = upperleftpos;
174 if (hotbar_image != player->hotbar_image) {
175 hotbar_image = player->hotbar_image;
176 if (hotbar_image != "")
177 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
179 use_hotbar_image = false;
182 if (hotbar_selected_image != player->hotbar_selected_image) {
183 hotbar_selected_image = player->hotbar_selected_image;
184 if (hotbar_selected_image != "")
185 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
187 use_hotbar_selected_image = false;
190 /* draw customized item background */
191 if (use_hotbar_image) {
192 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2,
193 width+m_padding/2, height+m_padding/2);
194 core::rect<s32> rect2 = imgrect2 + pos;
195 video::ITexture *texture = tsrc->getTexture(hotbar_image);
196 core::dimension2di imgsize(texture->getOriginalSize());
197 driver->draw2DImage(texture, rect2,
198 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
199 NULL, hbar_colors, true);
202 for (s32 i = offset; i < itemcount && (size_t)i < mainlist->getSize(); i++)
205 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
207 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
210 case HUD_DIR_RIGHT_LEFT:
211 steppos = v2s32(-(m_padding + (i - offset) * fullimglen), m_padding);
213 case HUD_DIR_TOP_BOTTOM:
214 steppos = v2s32(m_padding, m_padding + (i - offset) * fullimglen);
216 case HUD_DIR_BOTTOM_TOP:
217 steppos = v2s32(m_padding, -(m_padding + (i - offset) * fullimglen));
220 steppos = v2s32(m_padding + (i - offset) * fullimglen, m_padding);
224 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i +1) == selectitem );
229 void Hud::drawLuaElements(v3s16 camera_offset) {
230 for (size_t i = 0; i != player->maxHudId(); i++) {
231 HudElement *e = player->getHud(i);
235 v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
236 floor(e->pos.Y * (float) m_screensize.Y + 0.5));
238 case HUD_ELEM_IMAGE: {
239 video::ITexture *texture = tsrc->getTexture(e->text);
243 const video::SColor color(255, 255, 255, 255);
244 const video::SColor colors[] = {color, color, color, color};
245 core::dimension2di imgsize(texture->getOriginalSize());
246 v2s32 dstsize(imgsize.Width * e->scale.X,
247 imgsize.Height * e->scale.Y);
249 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
251 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
252 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
253 (e->align.Y - 1.0) * dstsize.Y / 2);
254 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
255 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
256 driver->draw2DImage(texture, rect,
257 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
260 case HUD_ELEM_TEXT: {
261 video::SColor color(255, (e->number >> 16) & 0xFF,
262 (e->number >> 8) & 0xFF,
263 (e->number >> 0) & 0xFF);
264 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
265 std::wstring text = narrow_to_wide(e->text);
266 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
267 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
268 (e->align.Y - 1.0) * (textsize.Height / 2));
269 v2s32 offs(e->offset.X, e->offset.Y);
270 font->draw(text.c_str(), size + pos + offset + offs, color);
272 case HUD_ELEM_STATBAR: {
273 v2s32 offs(e->offset.X, e->offset.Y);
274 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size);
276 case HUD_ELEM_INVENTORY: {
277 InventoryList *inv = inventory->getList(e->text);
278 drawItems(pos, e->number, 0, inv, e->item, e->dir);
280 case HUD_ELEM_WAYPOINT: {
281 v3f p_pos = player->getPosition() / BS;
282 v3f w_pos = e->world_pos * BS;
283 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
284 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
285 w_pos -= intToFloat(camera_offset, BS);
286 core::matrix4 trans = camera->getProjectionMatrix();
287 trans *= camera->getViewMatrix();
288 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
289 trans.multiplyWith1x4Matrix(transformed_pos);
290 if (transformed_pos[3] < 0)
292 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
293 core::reciprocal(transformed_pos[3]);
294 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
295 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
296 video::SColor color(255, (e->number >> 16) & 0xFF,
297 (e->number >> 8) & 0xFF,
298 (e->number >> 0) & 0xFF);
299 core::rect<s32> size(0, 0, 200, 2 * text_height);
300 std::wstring text = narrow_to_wide(e->name);
301 font->draw(text.c_str(), size + pos, color);
302 std::ostringstream os;
303 os<<distance<<e->text;
304 text = narrow_to_wide(os.str());
305 pos.Y += text_height;
306 font->draw(text.c_str(), size + pos, color);
309 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
310 " of hud element ID " << i << " due to unrecognized type" << std::endl;
316 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture,
317 s32 count, v2s32 offset, v2s32 size)
319 const video::SColor color(255, 255, 255, 255);
320 const video::SColor colors[] = {color, color, color, color};
322 video::ITexture *stat_texture = tsrc->getTexture(texture);
326 core::dimension2di srcd(stat_texture->getOriginalSize());
327 core::dimension2di dstd;
328 if (size == v2s32()) {
331 dstd.Height = size.Y * g_settings->getFloat("gui_scaling") *
332 porting::getDisplayDensity();
333 dstd.Width = size.X * g_settings->getFloat("gui_scaling") *
334 porting::getDisplayDensity();
336 offset.X *= g_settings->getFloat("gui_scaling") *
337 porting::getDisplayDensity();
339 offset.Y *= g_settings->getFloat("gui_scaling") *
340 porting::getDisplayDensity();
344 if (corner & HUD_CORNER_LOWER)
351 case HUD_DIR_RIGHT_LEFT:
352 steppos = v2s32(-1, 0);
354 case HUD_DIR_TOP_BOTTOM:
355 steppos = v2s32(0, 1);
357 case HUD_DIR_BOTTOM_TOP:
358 steppos = v2s32(0, -1);
361 steppos = v2s32(1, 0);
363 steppos.X *= dstd.Width;
364 steppos.Y *= dstd.Height;
366 for (s32 i = 0; i < count / 2; i++)
368 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
369 core::rect<s32> dstrect(0,0, dstd.Width, dstd.Height);
372 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
378 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
379 core::rect<s32> dstrect(0,0, dstd.Width / 2, dstd.Height);
382 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
387 void Hud::drawHotbar(u16 playeritem) {
389 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
391 InventoryList *mainlist = inventory->getList("main");
392 if (mainlist == NULL) {
393 //silently ignore this we may not be initialized completely
397 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
398 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
399 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
401 if ( (float) width / (float) porting::getWindowSize().X <=
402 g_settings->getFloat("hud_hotbar_max_width")) {
403 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
404 drawItems(pos, hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
410 v2s32 secondpos = pos;
411 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
413 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
414 drawItems(pos, hotbar_itemcount/2, 0, mainlist, playeritem + 1, 0);
415 drawItems(secondpos, hotbar_itemcount, hotbar_itemcount/2, mainlist, playeritem + 1, 0);
419 //////////////////////////// compatibility code to be removed //////////////
420 // this is ugly as hell but there's no other way to keep compatibility to
422 if ( player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
423 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
424 floor(1 * (float) m_screensize.Y + 0.5)),
425 HUD_CORNER_UPPER, 0, "heart.png",
426 player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24));
428 if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) &&
429 (player->getBreath() < 11))
430 drawStatbar(v2s32(floor(0.5 * (float) m_screensize.X + 0.5),
431 floor(1 * (float) m_screensize.Y + 0.5)),
432 HUD_CORNER_UPPER, 0, "heart.png",
433 player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24));
434 ////////////////////////////////////////////////////////////////////////////
438 void Hud::drawCrosshair() {
440 if (use_crosshair_image) {
441 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
442 v2u32 size = crosshair->getOriginalSize();
443 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
444 m_displaycenter.Y - (size.Y / 2));
445 driver->draw2DImage(crosshair, lsize,
446 core::rect<s32>(0, 0, size.X, size.Y),
447 0, crosshair_argb, true);
449 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
450 m_displaycenter + v2s32(10, 0), crosshair_argb);
451 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
452 m_displaycenter + v2s32(0, 10), crosshair_argb);
457 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
458 for (std::vector<aabb3f>::const_iterator
459 i = hilightboxes.begin();
460 i != hilightboxes.end(); i++) {
461 driver->draw3DBox(*i, selectionbox_argb);
466 void Hud::resizeHotbar() {
467 if (m_screensize != porting::getWindowSize()) {
468 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
469 m_hotbar_imagesize *= g_settings->getFloat("gui_scaling");
470 m_padding = m_hotbar_imagesize / 12;
471 m_screensize = porting::getWindowSize();
472 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
476 void drawItemStack(video::IVideoDriver *driver,
478 const ItemStack &item,
479 const core::rect<s32> &rect,
480 const core::rect<s32> *clip,
486 const ItemDefinition &def = item.getDefinition(gamedef->idef());
487 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
489 // Draw the inventory texture
492 const video::SColor color(255,255,255,255);
493 const video::SColor colors[] = {color,color,color,color};
494 driver->draw2DImage(texture, rect,
495 core::rect<s32>(core::position2d<s32>(0,0),
496 core::dimension2di(texture->getOriginalSize())),
500 if(def.type == ITEM_TOOL && item.wear != 0)
502 // Draw a progressbar
503 float barheight = rect.getHeight()/16;
504 float barpad_x = rect.getWidth()/16;
505 float barpad_y = rect.getHeight()/16;
506 core::rect<s32> progressrect(
507 rect.UpperLeftCorner.X + barpad_x,
508 rect.LowerRightCorner.Y - barpad_y - barheight,
509 rect.LowerRightCorner.X - barpad_x,
510 rect.LowerRightCorner.Y - barpad_y);
512 // Shrink progressrect by amount of tool damage
513 float wear = item.wear / 65535.0;
515 wear * progressrect.UpperLeftCorner.X +
516 (1-wear) * progressrect.LowerRightCorner.X;
518 // Compute progressbar color
520 // wear = 0.5: yellow
522 video::SColor color(255,255,255,255);
523 int wear_i = MYMIN(floor(wear * 600), 511);
524 wear_i = MYMIN(wear_i + 10, 511);
526 color.set(255, wear_i, 255, 0);
528 color.set(255, 255, 511-wear_i, 0);
530 core::rect<s32> progressrect2 = progressrect;
531 progressrect2.LowerRightCorner.X = progressmid;
532 driver->draw2DRectangle(color, progressrect2, clip);
534 color = video::SColor(255,0,0,0);
535 progressrect2 = progressrect;
536 progressrect2.UpperLeftCorner.X = progressmid;
537 driver->draw2DRectangle(color, progressrect2, clip);
540 if(font != NULL && item.count >= 2)
542 // Get the item count as a string
543 std::string text = itos(item.count);
544 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
545 v2s32 sdim(dim.X,dim.Y);
547 core::rect<s32> rect2(
548 /*rect.UpperLeftCorner,
549 core::dimension2d<u32>(rect.getWidth(), 15)*/
550 rect.LowerRightCorner - sdim,
554 video::SColor bgcolor(128,0,0,0);
555 driver->draw2DRectangle(bgcolor, rect2, clip);
557 video::SColor color(255,255,255,255);
558 font->draw(text.c_str(), rect2, color, false, false, clip);