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 screensize = v2u32(0, 0);
51 displaycenter = v2s32(0, 0);
52 hotbar_imagesize = 48;
54 tsrc = gamedef->getTextureSource();
56 v3f crosshair_color = g_settings->getV3F("crosshair_color");
57 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
58 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
59 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
60 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
61 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
63 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
64 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
65 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
66 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
67 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
69 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
72 use_hotbar_image = false;
73 hotbar_selected_image = "";
74 use_hotbar_selected_image = false;
78 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
79 void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
80 InventoryList *mainlist, u16 selectitem, u16 direction)
82 s32 padding = imgsize / 12;
83 s32 height = imgsize + padding * 2;
84 s32 width = itemcount * (imgsize + padding * 2);
85 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
86 width = imgsize + padding * 2;
87 height = itemcount * (imgsize + padding * 2);
89 s32 fullimglen = imgsize + padding * 2;
91 // Position of upper left corner of bar
92 v2s32 pos = upperleftpos;
94 // Draw background color
95 /*core::rect<s32> barrect(0,0,width,height);
97 video::SColor bgcolor(255,128,128,128);
98 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
100 core::rect<s32> imgrect(0, 0, imgsize, imgsize);
101 const video::SColor hbar_color(255, 255, 255, 255);
102 const video::SColor hbar_colors[] = {hbar_color, hbar_color, hbar_color, hbar_color};
104 if (hotbar_image != player->hotbar_image) {
105 hotbar_image = player->hotbar_image;
106 if (hotbar_image != "")
107 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
109 use_hotbar_image = false;
112 if (hotbar_selected_image != player->hotbar_selected_image) {
113 hotbar_selected_image = player->hotbar_selected_image;
114 if (hotbar_selected_image != "")
115 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
117 use_hotbar_selected_image = false;
120 if (use_hotbar_image) {
121 core::rect<s32> imgrect2(-padding/2, -padding/2, width+padding/2, height+padding/2);
122 core::rect<s32> rect2 = imgrect2 + pos;
123 video::ITexture *texture = tsrc->getTexture(hotbar_image);
124 core::dimension2di imgsize(texture->getOriginalSize());
125 driver->draw2DImage(texture, rect2,
126 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
127 NULL, hbar_colors, true);
130 for (s32 i = 0; i < itemcount; i++)
132 const ItemStack &item = mainlist->getItem(i);
136 case HUD_DIR_RIGHT_LEFT:
137 steppos = v2s32(-(padding + i * fullimglen), padding);
139 case HUD_DIR_TOP_BOTTOM:
140 steppos = v2s32(padding, padding + i * fullimglen);
142 case HUD_DIR_BOTTOM_TOP:
143 steppos = v2s32(padding, -(padding + i * fullimglen));
146 steppos = v2s32(padding + i * fullimglen, padding);
149 core::rect<s32> rect = imgrect + pos + steppos;
151 if (selectitem == i + 1) {
152 if (use_hotbar_selected_image) {
153 core::rect<s32> imgrect2(-padding*2, -padding*2, height, height);
154 rect = imgrect2 + pos + steppos;
155 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
156 core::dimension2di imgsize(texture->getOriginalSize());
157 driver->draw2DImage(texture, rect,
158 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
159 NULL, hbar_colors, true);
160 rect = imgrect + pos + steppos;
162 rect = imgrect + pos + steppos;
163 video::SColor c_outside(255,255,0,0);
164 //video::SColor c_outside(255,0,0,0);
165 //video::SColor c_inside(255,192,192,192);
166 s32 x1 = rect.UpperLeftCorner.X;
167 s32 y1 = rect.UpperLeftCorner.Y;
168 s32 x2 = rect.LowerRightCorner.X;
169 s32 y2 = rect.LowerRightCorner.Y;
170 // Black base borders
171 driver->draw2DRectangle(c_outside,
173 v2s32(x1 - padding, y1 - padding),
174 v2s32(x2 + padding, y1)
176 driver->draw2DRectangle(c_outside,
178 v2s32(x1 - padding, y2),
179 v2s32(x2 + padding, y2 + padding)
181 driver->draw2DRectangle(c_outside,
183 v2s32(x1 - padding, y1),
186 driver->draw2DRectangle(c_outside,
189 v2s32(x2 + padding, y2)
191 /*// Light inside borders
192 driver->draw2DRectangle(c_inside,
194 v2s32(x1 - padding/2, y1 - padding/2),
195 v2s32(x2 + padding/2, y1)
197 driver->draw2DRectangle(c_inside,
199 v2s32(x1 - padding/2, y2),
200 v2s32(x2 + padding/2, y2 + padding/2)
202 driver->draw2DRectangle(c_inside,
204 v2s32(x1 - padding/2, y1),
207 driver->draw2DRectangle(c_inside,
210 v2s32(x2 + padding/2, y2)
216 video::SColor bgcolor2(128, 0, 0, 0);
217 if (!use_hotbar_image)
218 driver->draw2DRectangle(bgcolor2, rect, NULL);
219 drawItemStack(driver, font, item, rect, NULL, gamedef);
224 void Hud::drawLuaElements() {
225 for (size_t i = 0; i != player->hud.size(); i++) {
226 HudElement *e = player->hud[i];
230 v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
232 case HUD_ELEM_IMAGE: {
233 video::ITexture *texture = tsrc->getTexture(e->text);
237 const video::SColor color(255, 255, 255, 255);
238 const video::SColor colors[] = {color, color, color, color};
239 core::dimension2di imgsize(texture->getOriginalSize());
240 v2s32 dstsize(imgsize.Width * e->scale.X,
241 imgsize.Height * e->scale.Y);
243 dstsize.X = screensize.X * (e->scale.X * -0.01);
245 dstsize.Y = screensize.Y * (e->scale.Y * -0.01);
246 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
247 (e->align.Y - 1.0) * dstsize.Y / 2);
248 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
249 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
250 driver->draw2DImage(texture, rect,
251 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
254 case HUD_ELEM_TEXT: {
255 video::SColor color(255, (e->number >> 16) & 0xFF,
256 (e->number >> 8) & 0xFF,
257 (e->number >> 0) & 0xFF);
258 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
259 std::wstring text = narrow_to_wide(e->text);
260 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
261 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
262 (e->align.Y - 1.0) * (textsize.Height / 2));
263 v2s32 offs(e->offset.X, e->offset.Y);
264 font->draw(text.c_str(), size + pos + offset + offs, color);
266 case HUD_ELEM_STATBAR: {
267 v2s32 offs(e->offset.X, e->offset.Y);
268 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
270 case HUD_ELEM_INVENTORY: {
271 InventoryList *inv = inventory->getList(e->text);
272 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
274 case HUD_ELEM_WAYPOINT: {
275 v3f p_pos = player->getPosition() / BS;
276 v3f w_pos = e->world_pos * BS;
277 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
278 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
279 core::matrix4 trans = camera->getProjectionMatrix();
280 trans *= camera->getViewMatrix();
281 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
282 trans.multiplyWith1x4Matrix(transformed_pos);
283 if (transformed_pos[3] < 0)
285 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
286 core::reciprocal(transformed_pos[3]);
287 pos.X = screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
288 pos.Y = screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
289 video::SColor color(255, (e->number >> 16) & 0xFF,
290 (e->number >> 8) & 0xFF,
291 (e->number >> 0) & 0xFF);
292 core::rect<s32> size(0, 0, 200, 2 * text_height);
293 std::wstring text = narrow_to_wide(e->name);
294 font->draw(text.c_str(), size + pos, color);
295 std::ostringstream os;
296 os<<distance<<e->text;
297 text = narrow_to_wide(os.str());
298 pos.Y += text_height;
299 font->draw(text.c_str(), size + pos, color);
302 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
303 " of hud element ID " << i << " due to unrecognized type" << std::endl;
309 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
310 const video::SColor color(255, 255, 255, 255);
311 const video::SColor colors[] = {color, color, color, color};
313 video::ITexture *stat_texture = tsrc->getTexture(texture);
317 core::dimension2di srcd(stat_texture->getOriginalSize());
320 if (corner & HUD_CORNER_LOWER)
327 case HUD_DIR_RIGHT_LEFT:
328 steppos = v2s32(-1, 0);
330 case HUD_DIR_TOP_BOTTOM:
331 steppos = v2s32(0, 1);
333 case HUD_DIR_BOTTOM_TOP:
334 steppos = v2s32(0, -1);
337 steppos = v2s32(1, 0);
339 steppos.X *= srcd.Width;
340 steppos.Y *= srcd.Height;
342 for (s32 i = 0; i < count / 2; i++)
344 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
345 core::rect<s32> dstrect(srcrect);
348 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
354 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
355 core::rect<s32> dstrect(srcrect);
358 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
363 void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) {
364 InventoryList *mainlist = inventory->getList("main");
365 if (mainlist == NULL) {
366 errorstream << "draw_hotbar(): mainlist == NULL" << std::endl;
370 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
371 s32 padding = hotbar_imagesize / 12;
372 s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
373 v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 3);
375 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE)
376 drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
377 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
378 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
379 "heart.png", halfheartcount, v2s32(0, 0));
380 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
381 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
382 "bubble.png", breath*2, v2s32(0, 0));
386 void Hud::drawCrosshair() {
387 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
390 if (use_crosshair_image) {
391 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
392 v2u32 size = crosshair->getOriginalSize();
393 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
394 displaycenter.Y - (size.Y / 2));
395 driver->draw2DImage(crosshair, lsize,
396 core::rect<s32>(0, 0, size.X, size.Y),
397 0, crosshair_argb, true);
399 driver->draw2DLine(displaycenter - v2s32(10, 0),
400 displaycenter + v2s32(10, 0), crosshair_argb);
401 driver->draw2DLine(displaycenter - v2s32(0, 10),
402 displaycenter + v2s32(0, 10), crosshair_argb);
407 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
408 for (std::vector<aabb3f>::const_iterator
409 i = hilightboxes.begin();
410 i != hilightboxes.end(); i++) {
411 driver->draw3DBox(*i, selectionbox_argb);
416 void Hud::resizeHotbar() {
417 if (screensize.Y <= 800)
418 hotbar_imagesize = 32;
419 else if (screensize.Y <= 1280)
420 hotbar_imagesize = 48;
422 hotbar_imagesize = 64;
425 void drawItemStack(video::IVideoDriver *driver,
427 const ItemStack &item,
428 const core::rect<s32> &rect,
429 const core::rect<s32> *clip,
435 const ItemDefinition &def = item.getDefinition(gamedef->idef());
436 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
438 // Draw the inventory texture
441 const video::SColor color(255,255,255,255);
442 const video::SColor colors[] = {color,color,color,color};
443 driver->draw2DImage(texture, rect,
444 core::rect<s32>(core::position2d<s32>(0,0),
445 core::dimension2di(texture->getOriginalSize())),
449 if(def.type == ITEM_TOOL && item.wear != 0)
451 // Draw a progressbar
452 float barheight = rect.getHeight()/16;
453 float barpad_x = rect.getWidth()/16;
454 float barpad_y = rect.getHeight()/16;
455 core::rect<s32> progressrect(
456 rect.UpperLeftCorner.X + barpad_x,
457 rect.LowerRightCorner.Y - barpad_y - barheight,
458 rect.LowerRightCorner.X - barpad_x,
459 rect.LowerRightCorner.Y - barpad_y);
461 // Shrink progressrect by amount of tool damage
462 float wear = item.wear / 65535.0;
464 wear * progressrect.UpperLeftCorner.X +
465 (1-wear) * progressrect.LowerRightCorner.X;
467 // Compute progressbar color
469 // wear = 0.5: yellow
471 video::SColor color(255,255,255,255);
472 int wear_i = MYMIN(floor(wear * 600), 511);
473 wear_i = MYMIN(wear_i + 10, 511);
475 color.set(255, wear_i, 255, 0);
477 color.set(255, 255, 511-wear_i, 0);
479 core::rect<s32> progressrect2 = progressrect;
480 progressrect2.LowerRightCorner.X = progressmid;
481 driver->draw2DRectangle(color, progressrect2, clip);
483 color = video::SColor(255,0,0,0);
484 progressrect2 = progressrect;
485 progressrect2.UpperLeftCorner.X = progressmid;
486 driver->draw2DRectangle(color, progressrect2, clip);
489 if(font != NULL && item.count >= 2)
491 // Get the item count as a string
492 std::string text = itos(item.count);
493 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
494 v2s32 sdim(dim.X,dim.Y);
496 core::rect<s32> rect2(
497 /*rect.UpperLeftCorner,
498 core::dimension2d<u32>(rect.getWidth(), 15)*/
499 rect.LowerRightCorner - sdim,
503 video::SColor bgcolor(128,0,0,0);
504 driver->draw2DRectangle(bgcolor, rect2, clip);
506 video::SColor color(255,255,255,255);
507 font->draw(text.c_str(), rect2, color, false, false, clip);