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 core::rect<s32> rect(0, 0, imgsize.Width * e->scale.X,
238 imgsize.Height * e->scale.X);
240 v2s32 offset((e->align.X - 1.0) * ((imgsize.Width * e->scale.X) / 2),
241 (e->align.Y - 1.0) * ((imgsize.Height * e->scale.X) / 2));
243 rect += v2s32(e->offset.X, e->offset.Y);
244 driver->draw2DImage(texture, rect,
245 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
248 case HUD_ELEM_TEXT: {
249 video::SColor color(255, (e->number >> 16) & 0xFF,
250 (e->number >> 8) & 0xFF,
251 (e->number >> 0) & 0xFF);
252 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
253 std::wstring text = narrow_to_wide(e->text);
254 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
255 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
256 (e->align.Y - 1.0) * (textsize.Height / 2));
257 v2s32 offs(e->offset.X, e->offset.Y);
258 font->draw(text.c_str(), size + pos + offset + offs, color);
260 case HUD_ELEM_STATBAR: {
261 v2s32 offs(e->offset.X, e->offset.Y);
262 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
264 case HUD_ELEM_INVENTORY: {
265 InventoryList *inv = inventory->getList(e->text);
266 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
269 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
270 " of hud element ID " << i << " due to unrecognized type" << std::endl;
276 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
277 const video::SColor color(255, 255, 255, 255);
278 const video::SColor colors[] = {color, color, color, color};
280 video::ITexture *stat_texture = tsrc->getTexture(texture);
284 core::dimension2di srcd(stat_texture->getOriginalSize());
287 if (corner & HUD_CORNER_LOWER)
294 case HUD_DIR_RIGHT_LEFT:
295 steppos = v2s32(-1, 0);
297 case HUD_DIR_TOP_BOTTOM:
298 steppos = v2s32(0, 1);
300 case HUD_DIR_BOTTOM_TOP:
301 steppos = v2s32(0, -1);
304 steppos = v2s32(1, 0);
306 steppos.X *= srcd.Width;
307 steppos.Y *= srcd.Height;
309 for (s32 i = 0; i < count / 2; i++)
311 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
312 core::rect<s32> dstrect(srcrect);
315 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
321 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
322 core::rect<s32> dstrect(srcrect);
325 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
330 void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) {
331 InventoryList *mainlist = inventory->getList("main");
332 if (mainlist == NULL) {
333 errorstream << "draw_hotbar(): mainlist == NULL" << std::endl;
337 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
338 s32 padding = hotbar_imagesize / 12;
339 s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
340 v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2);
342 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE)
343 drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
344 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
345 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
346 "heart.png", halfheartcount, v2s32(0, 0));
347 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
348 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
349 "bubble.png", breath*2, v2s32(0, 0));
353 void Hud::drawCrosshair() {
354 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
357 if (use_crosshair_image) {
358 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
359 v2u32 size = crosshair->getOriginalSize();
360 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
361 displaycenter.Y - (size.Y / 2));
362 driver->draw2DImage(crosshair, lsize,
363 core::rect<s32>(0, 0, size.X, size.Y),
364 0, crosshair_argb, true);
366 driver->draw2DLine(displaycenter - v2s32(10, 0),
367 displaycenter + v2s32(10, 0), crosshair_argb);
368 driver->draw2DLine(displaycenter - v2s32(0, 10),
369 displaycenter + v2s32(0, 10), crosshair_argb);
374 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
375 for (std::vector<aabb3f>::const_iterator
376 i = hilightboxes.begin();
377 i != hilightboxes.end(); i++) {
378 driver->draw3DBox(*i, selectionbox_argb);
383 void Hud::resizeHotbar() {
384 if (screensize.Y <= 800)
385 hotbar_imagesize = 32;
386 else if (screensize.Y <= 1280)
387 hotbar_imagesize = 48;
389 hotbar_imagesize = 64;
392 void drawItemStack(video::IVideoDriver *driver,
394 const ItemStack &item,
395 const core::rect<s32> &rect,
396 const core::rect<s32> *clip,
402 const ItemDefinition &def = item.getDefinition(gamedef->idef());
403 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
405 // Draw the inventory texture
408 const video::SColor color(255,255,255,255);
409 const video::SColor colors[] = {color,color,color,color};
410 driver->draw2DImage(texture, rect,
411 core::rect<s32>(core::position2d<s32>(0,0),
412 core::dimension2di(texture->getOriginalSize())),
416 if(def.type == ITEM_TOOL && item.wear != 0)
418 // Draw a progressbar
419 float barheight = rect.getHeight()/16;
420 float barpad_x = rect.getWidth()/16;
421 float barpad_y = rect.getHeight()/16;
422 core::rect<s32> progressrect(
423 rect.UpperLeftCorner.X + barpad_x,
424 rect.LowerRightCorner.Y - barpad_y - barheight,
425 rect.LowerRightCorner.X - barpad_x,
426 rect.LowerRightCorner.Y - barpad_y);
428 // Shrink progressrect by amount of tool damage
429 float wear = item.wear / 65535.0;
431 wear * progressrect.UpperLeftCorner.X +
432 (1-wear) * progressrect.LowerRightCorner.X;
434 // Compute progressbar color
436 // wear = 0.5: yellow
438 video::SColor color(255,255,255,255);
439 int wear_i = MYMIN(floor(wear * 600), 511);
440 wear_i = MYMIN(wear_i + 10, 511);
442 color.set(255, wear_i, 255, 0);
444 color.set(255, 255, 511-wear_i, 0);
446 core::rect<s32> progressrect2 = progressrect;
447 progressrect2.LowerRightCorner.X = progressmid;
448 driver->draw2DRectangle(color, progressrect2, clip);
450 color = video::SColor(255,0,0,0);
451 progressrect2 = progressrect;
452 progressrect2.UpperLeftCorner.X = progressmid;
453 driver->draw2DRectangle(color, progressrect2, clip);
456 if(font != NULL && item.count >= 2)
458 // Get the item count as a string
459 std::string text = itos(item.count);
460 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
461 v2s32 sdim(dim.X,dim.Y);
463 core::rect<s32> rect2(
464 /*rect.UpperLeftCorner,
465 core::dimension2d<u32>(rect.getWidth(), 15)*/
466 rect.LowerRightCorner - sdim,
470 video::SColor bgcolor(128,0,0,0);
471 driver->draw2DRectangle(bgcolor, rect2, clip);
473 video::SColor color(255,255,255,255);
474 font->draw(text.c_str(), rect2, color, false, false, clip);