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 if (use_hotbar_selected_image) {
87 core::rect<s32> imgrect2 = rect;
88 imgrect2.UpperLeftCorner.X -= m_padding;
89 imgrect2.UpperLeftCorner.Y -= m_padding;
90 imgrect2.LowerRightCorner.X += m_padding;
91 imgrect2.LowerRightCorner.Y += m_padding;
92 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
93 core::dimension2di imgsize(texture->getOriginalSize());
94 driver->draw2DImage(texture, imgrect2,
95 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
96 NULL, hbar_colors, true);
98 video::SColor c_outside(255,255,0,0);
99 //video::SColor c_outside(255,0,0,0);
100 //video::SColor c_inside(255,192,192,192);
101 s32 x1 = rect.UpperLeftCorner.X;
102 s32 y1 = rect.UpperLeftCorner.Y;
103 s32 x2 = rect.LowerRightCorner.X;
104 s32 y2 = rect.LowerRightCorner.Y;
105 // Black base borders
106 driver->draw2DRectangle(c_outside,
108 v2s32(x1 - m_padding, y1 - m_padding),
109 v2s32(x2 + m_padding, y1)
111 driver->draw2DRectangle(c_outside,
113 v2s32(x1 - m_padding, y2),
114 v2s32(x2 + m_padding, y2 + m_padding)
116 driver->draw2DRectangle(c_outside,
118 v2s32(x1 - m_padding, y1),
121 driver->draw2DRectangle(c_outside,
124 v2s32(x2 + m_padding, y2)
126 /*// Light inside borders
127 driver->draw2DRectangle(c_inside,
129 v2s32(x1 - padding/2, y1 - padding/2),
130 v2s32(x2 + padding/2, y1)
132 driver->draw2DRectangle(c_inside,
134 v2s32(x1 - padding/2, y2),
135 v2s32(x2 + padding/2, y2 + padding/2)
137 driver->draw2DRectangle(c_inside,
139 v2s32(x1 - padding/2, y1),
142 driver->draw2DRectangle(c_inside,
145 v2s32(x2 + padding/2, y2)
151 video::SColor bgcolor2(128, 0, 0, 0);
152 if (!use_hotbar_image)
153 driver->draw2DRectangle(bgcolor2, rect, NULL);
154 drawItemStack(driver, font, item, rect, NULL, gamedef);
157 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
158 void Hud::drawItems(v2s32 upperleftpos, s32 itemcount, s32 offset,
159 InventoryList *mainlist, u16 selectitem, u16 direction)
161 s32 height = m_hotbar_imagesize + m_padding * 2;
162 s32 width = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
164 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
165 width = m_hotbar_imagesize + m_padding * 2;
166 height = (itemcount - offset) * (m_hotbar_imagesize + m_padding * 2);
169 // Position of upper left corner of bar
170 v2s32 pos = upperleftpos;
172 if (hotbar_image != player->hotbar_image) {
173 hotbar_image = player->hotbar_image;
174 if (hotbar_image != "")
175 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
177 use_hotbar_image = false;
180 if (hotbar_selected_image != player->hotbar_selected_image) {
181 hotbar_selected_image = player->hotbar_selected_image;
182 if (hotbar_selected_image != "")
183 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
185 use_hotbar_selected_image = false;
188 if (use_hotbar_image) {
189 core::rect<s32> imgrect2(-m_padding/2, -m_padding/2, width+m_padding/2, height+m_padding/2);
190 core::rect<s32> rect2 = imgrect2 + pos;
191 video::ITexture *texture = tsrc->getTexture(hotbar_image);
192 core::dimension2di imgsize(texture->getOriginalSize());
193 driver->draw2DImage(texture, rect2,
194 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
195 NULL, hbar_colors, true);
198 for (s32 i = offset; i < itemcount && (size_t)i < mainlist->getSize(); i++)
201 s32 fullimglen = m_hotbar_imagesize + m_padding * 2;
203 core::rect<s32> imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize);
206 case HUD_DIR_RIGHT_LEFT:
207 steppos = v2s32(-(m_padding + (i - offset) * fullimglen), m_padding);
209 case HUD_DIR_TOP_BOTTOM:
210 steppos = v2s32(m_padding, m_padding + (i - offset) * fullimglen);
212 case HUD_DIR_BOTTOM_TOP:
213 steppos = v2s32(m_padding, -(m_padding + (i - offset) * fullimglen));
216 steppos = v2s32(m_padding + (i - offset) * fullimglen, m_padding);
220 drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i +1) == selectitem );
225 void Hud::drawLuaElements() {
226 for (size_t i = 0; i != player->hud.size(); i++) {
227 HudElement *e = player->hud[i];
231 v2s32 pos(e->pos.X * m_screensize.X, e->pos.Y * m_screensize.Y);
233 case HUD_ELEM_IMAGE: {
234 video::ITexture *texture = tsrc->getTexture(e->text);
238 const video::SColor color(255, 255, 255, 255);
239 const video::SColor colors[] = {color, color, color, color};
240 core::dimension2di imgsize(texture->getOriginalSize());
241 v2s32 dstsize(imgsize.Width * e->scale.X,
242 imgsize.Height * e->scale.Y);
244 dstsize.X = m_screensize.X * (e->scale.X * -0.01);
246 dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01);
247 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
248 (e->align.Y - 1.0) * dstsize.Y / 2);
249 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
250 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
251 driver->draw2DImage(texture, rect,
252 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
255 case HUD_ELEM_TEXT: {
256 video::SColor color(255, (e->number >> 16) & 0xFF,
257 (e->number >> 8) & 0xFF,
258 (e->number >> 0) & 0xFF);
259 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
260 std::wstring text = narrow_to_wide(e->text);
261 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
262 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
263 (e->align.Y - 1.0) * (textsize.Height / 2));
264 v2s32 offs(e->offset.X, e->offset.Y);
265 font->draw(text.c_str(), size + pos + offset + offs, color);
267 case HUD_ELEM_STATBAR: {
268 v2s32 offs(e->offset.X, e->offset.Y);
269 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
271 case HUD_ELEM_INVENTORY: {
272 InventoryList *inv = inventory->getList(e->text);
273 drawItems(pos, e->number, 0, inv, e->item, e->dir);
275 case HUD_ELEM_WAYPOINT: {
276 v3f p_pos = player->getPosition() / BS;
277 v3f w_pos = e->world_pos * BS;
278 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
279 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
280 core::matrix4 trans = camera->getProjectionMatrix();
281 trans *= camera->getViewMatrix();
282 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
283 trans.multiplyWith1x4Matrix(transformed_pos);
284 if (transformed_pos[3] < 0)
286 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
287 core::reciprocal(transformed_pos[3]);
288 pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
289 pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
290 video::SColor color(255, (e->number >> 16) & 0xFF,
291 (e->number >> 8) & 0xFF,
292 (e->number >> 0) & 0xFF);
293 core::rect<s32> size(0, 0, 200, 2 * text_height);
294 std::wstring text = narrow_to_wide(e->name);
295 font->draw(text.c_str(), size + pos, color);
296 std::ostringstream os;
297 os<<distance<<e->text;
298 text = narrow_to_wide(os.str());
299 pos.Y += text_height;
300 font->draw(text.c_str(), size + pos, color);
303 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
304 " of hud element ID " << i << " due to unrecognized type" << std::endl;
310 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
311 const video::SColor color(255, 255, 255, 255);
312 const video::SColor colors[] = {color, color, color, color};
314 video::ITexture *stat_texture = tsrc->getTexture(texture);
318 core::dimension2di srcd(stat_texture->getOriginalSize());
321 if (corner & HUD_CORNER_LOWER)
328 case HUD_DIR_RIGHT_LEFT:
329 steppos = v2s32(-1, 0);
331 case HUD_DIR_TOP_BOTTOM:
332 steppos = v2s32(0, 1);
334 case HUD_DIR_BOTTOM_TOP:
335 steppos = v2s32(0, -1);
338 steppos = v2s32(1, 0);
340 steppos.X *= srcd.Width;
341 steppos.Y *= srcd.Height;
343 for (s32 i = 0; i < count / 2; i++)
345 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
346 core::rect<s32> dstrect(srcrect);
349 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
355 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
356 core::rect<s32> dstrect(srcrect);
359 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
364 void Hud::drawHotbar(s32 halfheartcount, u16 playeritem, s32 breath) {
366 v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y);
368 InventoryList *mainlist = inventory->getList("main");
369 if (mainlist == NULL) {
370 //silently ignore this we may not be initialized completely
374 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
375 s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
376 v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
378 if ( (float) width / (float) porting::getWindowSize().X <=
379 g_settings->getFloat("hud_hotbar_max_width")) {
380 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
381 drawItems(pos, hotbar_itemcount, 0, mainlist, playeritem + 1, 0);
387 v2s32 secondpos = pos;
388 pos = pos - v2s32(0, m_hotbar_imagesize + m_padding);
390 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
391 drawItems(pos, hotbar_itemcount/2, 0, mainlist, playeritem + 1, 0);
392 drawItems(secondpos, hotbar_itemcount, hotbar_itemcount/2, mainlist, playeritem + 1, 0);
396 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
397 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
398 "heart.png", halfheartcount, v2s32(0, 0));
399 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
400 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
401 "bubble.png", breath*2, v2s32(0, 0));
405 void Hud::drawCrosshair() {
406 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) ||
407 (player->camera_mode == CAMERA_MODE_THIRD_FRONT)) {
411 if (use_crosshair_image) {
412 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
413 v2u32 size = crosshair->getOriginalSize();
414 v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
415 m_displaycenter.Y - (size.Y / 2));
416 driver->draw2DImage(crosshair, lsize,
417 core::rect<s32>(0, 0, size.X, size.Y),
418 0, crosshair_argb, true);
420 driver->draw2DLine(m_displaycenter - v2s32(10, 0),
421 m_displaycenter + v2s32(10, 0), crosshair_argb);
422 driver->draw2DLine(m_displaycenter - v2s32(0, 10),
423 m_displaycenter + v2s32(0, 10), crosshair_argb);
428 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
429 for (std::vector<aabb3f>::const_iterator
430 i = hilightboxes.begin();
431 i != hilightboxes.end(); i++) {
432 driver->draw3DBox(*i, selectionbox_argb);
437 void Hud::resizeHotbar() {
438 if (m_screensize != porting::getWindowSize()) {
439 m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * porting::getDisplayDensity() + 0.5);
440 m_padding = m_hotbar_imagesize / 12;
441 m_screensize = porting::getWindowSize();
442 m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2);
446 void drawItemStack(video::IVideoDriver *driver,
448 const ItemStack &item,
449 const core::rect<s32> &rect,
450 const core::rect<s32> *clip,
456 const ItemDefinition &def = item.getDefinition(gamedef->idef());
457 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
459 // Draw the inventory texture
462 const video::SColor color(255,255,255,255);
463 const video::SColor colors[] = {color,color,color,color};
464 driver->draw2DImage(texture, rect,
465 core::rect<s32>(core::position2d<s32>(0,0),
466 core::dimension2di(texture->getOriginalSize())),
470 if(def.type == ITEM_TOOL && item.wear != 0)
472 // Draw a progressbar
473 float barheight = rect.getHeight()/16;
474 float barpad_x = rect.getWidth()/16;
475 float barpad_y = rect.getHeight()/16;
476 core::rect<s32> progressrect(
477 rect.UpperLeftCorner.X + barpad_x,
478 rect.LowerRightCorner.Y - barpad_y - barheight,
479 rect.LowerRightCorner.X - barpad_x,
480 rect.LowerRightCorner.Y - barpad_y);
482 // Shrink progressrect by amount of tool damage
483 float wear = item.wear / 65535.0;
485 wear * progressrect.UpperLeftCorner.X +
486 (1-wear) * progressrect.LowerRightCorner.X;
488 // Compute progressbar color
490 // wear = 0.5: yellow
492 video::SColor color(255,255,255,255);
493 int wear_i = MYMIN(floor(wear * 600), 511);
494 wear_i = MYMIN(wear_i + 10, 511);
496 color.set(255, wear_i, 255, 0);
498 color.set(255, 255, 511-wear_i, 0);
500 core::rect<s32> progressrect2 = progressrect;
501 progressrect2.LowerRightCorner.X = progressmid;
502 driver->draw2DRectangle(color, progressrect2, clip);
504 color = video::SColor(255,0,0,0);
505 progressrect2 = progressrect;
506 progressrect2.UpperLeftCorner.X = progressmid;
507 driver->draw2DRectangle(color, progressrect2, clip);
510 if(font != NULL && item.count >= 2)
512 // Get the item count as a string
513 std::string text = itos(item.count);
514 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
515 v2s32 sdim(dim.X,dim.Y);
517 core::rect<s32> rect2(
518 /*rect.UpperLeftCorner,
519 core::dimension2d<u32>(rect.getWidth(), 15)*/
520 rect.LowerRightCorner - sdim,
524 video::SColor bgcolor(128,0,0,0);
525 driver->draw2DRectangle(bgcolor, rect2, clip);
527 video::SColor color(255,255,255,255);
528 font->draw(text.c_str(), rect2, color, false, false, clip);