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"
33 #include <IGUIStaticText.h>
36 Hud::Hud(video::IVideoDriver *driver, gui::IGUIEnvironment* guienv,
37 gui::IGUIFont *font, u32 text_height, IGameDef *gamedef,
38 LocalPlayer *player, Inventory *inventory) {
39 this->driver = driver;
40 this->guienv = guienv;
42 this->text_height = text_height;
43 this->gamedef = gamedef;
44 this->player = player;
45 this->inventory = inventory;
47 screensize = v2u32(0, 0);
48 displaycenter = v2s32(0, 0);
49 hotbar_imagesize = 48;
51 tsrc = gamedef->getTextureSource();
53 v3f crosshair_color = g_settings->getV3F("crosshair_color");
54 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
55 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
56 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
57 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
58 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
60 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
61 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
62 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
63 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
64 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
66 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
69 use_hotbar_image = false;
70 hotbar_selected_image = "";
71 use_hotbar_selected_image = false;
75 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
76 void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
77 InventoryList *mainlist, u16 selectitem, u16 direction)
79 s32 padding = imgsize / 12;
80 s32 height = imgsize + padding * 2;
81 s32 width = itemcount * (imgsize + padding * 2);
82 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
83 width = imgsize + padding * 2;
84 height = itemcount * (imgsize + padding * 2);
86 s32 fullimglen = imgsize + padding * 2;
88 // Position of upper left corner of bar
89 v2s32 pos = upperleftpos;
91 // Draw background color
92 /*core::rect<s32> barrect(0,0,width,height);
94 video::SColor bgcolor(255,128,128,128);
95 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
97 core::rect<s32> imgrect(0, 0, imgsize, imgsize);
98 const video::SColor hbar_color(255, 255, 255, 255);
99 const video::SColor hbar_colors[] = {hbar_color, hbar_color, hbar_color, hbar_color};
101 if (hotbar_image != player->hotbar_image) {
102 hotbar_image = player->hotbar_image;
103 if (hotbar_image != "")
104 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
106 use_hotbar_image = false;
109 if (hotbar_selected_image != player->hotbar_selected_image) {
110 hotbar_selected_image = player->hotbar_selected_image;
111 if (hotbar_selected_image != "")
112 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
114 use_hotbar_selected_image = false;
117 if (use_hotbar_image) {
118 core::rect<s32> imgrect2(-padding/2, -padding/2, width+padding/2, height+padding/2);
119 core::rect<s32> rect2 = imgrect2 + pos;
120 video::ITexture *texture = tsrc->getTexture(hotbar_image);
121 core::dimension2di imgsize(texture->getOriginalSize());
122 driver->draw2DImage(texture, rect2,
123 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
124 NULL, hbar_colors, true);
127 for (s32 i = 0; i < itemcount; i++)
129 const ItemStack &item = mainlist->getItem(i);
133 case HUD_DIR_RIGHT_LEFT:
134 steppos = v2s32(-(padding + i * fullimglen), padding);
136 case HUD_DIR_TOP_BOTTOM:
137 steppos = v2s32(padding, padding + i * fullimglen);
139 case HUD_DIR_BOTTOM_TOP:
140 steppos = v2s32(padding, -(padding + i * fullimglen));
143 steppos = v2s32(padding + i * fullimglen, padding);
146 core::rect<s32> rect = imgrect + pos + steppos;
148 if (selectitem == i + 1) {
149 if (use_hotbar_selected_image) {
150 core::rect<s32> imgrect2(-padding*2, -padding*2, height, height);
151 rect = imgrect2 + pos + steppos;
152 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
153 core::dimension2di imgsize(texture->getOriginalSize());
154 driver->draw2DImage(texture, rect,
155 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
156 NULL, hbar_colors, true);
157 rect = imgrect + pos + steppos;
159 rect = imgrect + pos + steppos;
160 video::SColor c_outside(255,255,0,0);
161 //video::SColor c_outside(255,0,0,0);
162 //video::SColor c_inside(255,192,192,192);
163 s32 x1 = rect.UpperLeftCorner.X;
164 s32 y1 = rect.UpperLeftCorner.Y;
165 s32 x2 = rect.LowerRightCorner.X;
166 s32 y2 = rect.LowerRightCorner.Y;
167 // Black base borders
168 driver->draw2DRectangle(c_outside,
170 v2s32(x1 - padding, y1 - padding),
171 v2s32(x2 + padding, y1)
173 driver->draw2DRectangle(c_outside,
175 v2s32(x1 - padding, y2),
176 v2s32(x2 + padding, y2 + padding)
178 driver->draw2DRectangle(c_outside,
180 v2s32(x1 - padding, y1),
183 driver->draw2DRectangle(c_outside,
186 v2s32(x2 + padding, y2)
188 /*// Light inside borders
189 driver->draw2DRectangle(c_inside,
191 v2s32(x1 - padding/2, y1 - padding/2),
192 v2s32(x2 + padding/2, y1)
194 driver->draw2DRectangle(c_inside,
196 v2s32(x1 - padding/2, y2),
197 v2s32(x2 + padding/2, y2 + padding/2)
199 driver->draw2DRectangle(c_inside,
201 v2s32(x1 - padding/2, y1),
204 driver->draw2DRectangle(c_inside,
207 v2s32(x2 + padding/2, y2)
213 video::SColor bgcolor2(128, 0, 0, 0);
214 if (!use_hotbar_image)
215 driver->draw2DRectangle(bgcolor2, rect, NULL);
216 drawItemStack(driver, font, item, rect, NULL, gamedef);
221 void Hud::drawLuaElements() {
222 for (size_t i = 0; i != player->hud.size(); i++) {
223 HudElement *e = player->hud[i];
227 v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
229 case HUD_ELEM_IMAGE: {
230 video::ITexture *texture = tsrc->getTexture(e->text);
234 const video::SColor color(255, 255, 255, 255);
235 const video::SColor colors[] = {color, color, color, color};
236 core::dimension2di imgsize(texture->getOriginalSize());
237 v2s32 dstsize(imgsize.Width * e->scale.X,
238 imgsize.Height * e->scale.Y);
240 dstsize.X = screensize.X * (e->scale.X * -0.01);
242 dstsize.Y = screensize.Y * (e->scale.Y * -0.01);
243 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
244 (e->align.Y - 1.0) * dstsize.Y / 2);
245 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
246 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
247 driver->draw2DImage(texture, rect,
248 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
251 case HUD_ELEM_TEXT: {
252 video::SColor color(255, (e->number >> 16) & 0xFF,
253 (e->number >> 8) & 0xFF,
254 (e->number >> 0) & 0xFF);
255 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
256 std::wstring text = narrow_to_wide(e->text);
257 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
258 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
259 (e->align.Y - 1.0) * (textsize.Height / 2));
260 v2s32 offs(e->offset.X, e->offset.Y);
261 font->draw(text.c_str(), size + pos + offset + offs, color);
263 case HUD_ELEM_STATBAR: {
264 v2s32 offs(e->offset.X, e->offset.Y);
265 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
267 case HUD_ELEM_INVENTORY: {
268 InventoryList *inv = inventory->getList(e->text);
269 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
272 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
273 " of hud element ID " << i << " due to unrecognized type" << std::endl;
279 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
280 const video::SColor color(255, 255, 255, 255);
281 const video::SColor colors[] = {color, color, color, color};
283 video::ITexture *stat_texture = tsrc->getTexture(texture);
287 core::dimension2di srcd(stat_texture->getOriginalSize());
290 if (corner & HUD_CORNER_LOWER)
297 case HUD_DIR_RIGHT_LEFT:
298 steppos = v2s32(-1, 0);
300 case HUD_DIR_TOP_BOTTOM:
301 steppos = v2s32(0, 1);
303 case HUD_DIR_BOTTOM_TOP:
304 steppos = v2s32(0, -1);
307 steppos = v2s32(1, 0);
309 steppos.X *= srcd.Width;
310 steppos.Y *= srcd.Height;
312 for (s32 i = 0; i < count / 2; i++)
314 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
315 core::rect<s32> dstrect(srcrect);
318 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
324 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
325 core::rect<s32> dstrect(srcrect);
328 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
333 void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) {
334 InventoryList *mainlist = inventory->getList("main");
335 if (mainlist == NULL) {
336 errorstream << "draw_hotbar(): mainlist == NULL" << std::endl;
340 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
341 s32 padding = hotbar_imagesize / 12;
342 s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
343 v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 3);
345 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE)
346 drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
347 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
348 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
349 "heart.png", halfheartcount, v2s32(0, 0));
350 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
351 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
352 "bubble.png", breath*2, v2s32(0, 0));
356 void Hud::drawCrosshair() {
357 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
360 if (use_crosshair_image) {
361 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
362 v2u32 size = crosshair->getOriginalSize();
363 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
364 displaycenter.Y - (size.Y / 2));
365 driver->draw2DImage(crosshair, lsize,
366 core::rect<s32>(0, 0, size.X, size.Y),
367 0, crosshair_argb, true);
369 driver->draw2DLine(displaycenter - v2s32(10, 0),
370 displaycenter + v2s32(10, 0), crosshair_argb);
371 driver->draw2DLine(displaycenter - v2s32(0, 10),
372 displaycenter + v2s32(0, 10), crosshair_argb);
377 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
378 for (std::vector<aabb3f>::const_iterator
379 i = hilightboxes.begin();
380 i != hilightboxes.end(); i++) {
381 driver->draw3DBox(*i, selectionbox_argb);
386 void Hud::resizeHotbar() {
387 if (screensize.Y <= 800)
388 hotbar_imagesize = 32;
389 else if (screensize.Y <= 1280)
390 hotbar_imagesize = 48;
392 hotbar_imagesize = 64;
395 void drawItemStack(video::IVideoDriver *driver,
397 const ItemStack &item,
398 const core::rect<s32> &rect,
399 const core::rect<s32> *clip,
405 const ItemDefinition &def = item.getDefinition(gamedef->idef());
406 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
408 // Draw the inventory texture
411 const video::SColor color(255,255,255,255);
412 const video::SColor colors[] = {color,color,color,color};
413 driver->draw2DImage(texture, rect,
414 core::rect<s32>(core::position2d<s32>(0,0),
415 core::dimension2di(texture->getOriginalSize())),
419 if(def.type == ITEM_TOOL && item.wear != 0)
421 // Draw a progressbar
422 float barheight = rect.getHeight()/16;
423 float barpad_x = rect.getWidth()/16;
424 float barpad_y = rect.getHeight()/16;
425 core::rect<s32> progressrect(
426 rect.UpperLeftCorner.X + barpad_x,
427 rect.LowerRightCorner.Y - barpad_y - barheight,
428 rect.LowerRightCorner.X - barpad_x,
429 rect.LowerRightCorner.Y - barpad_y);
431 // Shrink progressrect by amount of tool damage
432 float wear = item.wear / 65535.0;
434 wear * progressrect.UpperLeftCorner.X +
435 (1-wear) * progressrect.LowerRightCorner.X;
437 // Compute progressbar color
439 // wear = 0.5: yellow
441 video::SColor color(255,255,255,255);
442 int wear_i = MYMIN(floor(wear * 600), 511);
443 wear_i = MYMIN(wear_i + 10, 511);
445 color.set(255, wear_i, 255, 0);
447 color.set(255, 255, 511-wear_i, 0);
449 core::rect<s32> progressrect2 = progressrect;
450 progressrect2.LowerRightCorner.X = progressmid;
451 driver->draw2DRectangle(color, progressrect2, clip);
453 color = video::SColor(255,0,0,0);
454 progressrect2 = progressrect;
455 progressrect2.UpperLeftCorner.X = progressmid;
456 driver->draw2DRectangle(color, progressrect2, clip);
459 if(font != NULL && item.count >= 2)
461 // Get the item count as a string
462 std::string text = itos(item.count);
463 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
464 v2s32 sdim(dim.X,dim.Y);
466 core::rect<s32> rect2(
467 /*rect.UpperLeftCorner,
468 core::dimension2d<u32>(rect.getWidth(), 15)*/
469 rect.LowerRightCorner - sdim,
473 video::SColor bgcolor(128,0,0,0);
474 driver->draw2DRectangle(bgcolor, rect2, clip);
476 video::SColor color(255,255,255,255);
477 font->draw(text.c_str(), rect2, color, false, false, clip);