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");
70 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
71 void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
72 InventoryList *mainlist, u16 selectitem, u16 direction)
74 s32 padding = imgsize / 12;
75 s32 height = imgsize + padding * 2;
76 s32 width = itemcount * (imgsize + padding * 2);
77 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
78 width = imgsize + padding * 2;
79 height = itemcount * (imgsize + padding * 2);
81 s32 fullimglen = imgsize + padding * 2;
83 // Position of upper left corner of bar
84 v2s32 pos = upperleftpos;
86 // Draw background color
87 /*core::rect<s32> barrect(0,0,width,height);
89 video::SColor bgcolor(255,128,128,128);
90 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
92 core::rect<s32> imgrect(0, 0, imgsize, imgsize);
94 for (s32 i = 0; i < itemcount; i++)
96 const ItemStack &item = mainlist->getItem(i);
100 case HUD_DIR_RIGHT_LEFT:
101 steppos = v2s32(-(padding + i * fullimglen), padding);
103 case HUD_DIR_TOP_BOTTOM:
104 steppos = v2s32(padding, padding + i * fullimglen);
106 case HUD_DIR_BOTTOM_TOP:
107 steppos = v2s32(padding, -(padding + i * fullimglen));
110 steppos = v2s32(padding + i * fullimglen, padding);
113 core::rect<s32> rect = imgrect + pos + steppos;
115 if (selectitem == i + 1)
117 video::SColor c_outside(255,255,0,0);
118 //video::SColor c_outside(255,0,0,0);
119 //video::SColor c_inside(255,192,192,192);
120 s32 x1 = rect.UpperLeftCorner.X;
121 s32 y1 = rect.UpperLeftCorner.Y;
122 s32 x2 = rect.LowerRightCorner.X;
123 s32 y2 = rect.LowerRightCorner.Y;
124 // Black base borders
125 driver->draw2DRectangle(c_outside,
127 v2s32(x1 - padding, y1 - padding),
128 v2s32(x2 + padding, y1)
130 driver->draw2DRectangle(c_outside,
132 v2s32(x1 - padding, y2),
133 v2s32(x2 + padding, y2 + padding)
135 driver->draw2DRectangle(c_outside,
137 v2s32(x1 - padding, y1),
140 driver->draw2DRectangle(c_outside,
143 v2s32(x2 + padding, y2)
145 /*// Light inside borders
146 driver->draw2DRectangle(c_inside,
148 v2s32(x1 - padding/2, y1 - padding/2),
149 v2s32(x2 + padding/2, y1)
151 driver->draw2DRectangle(c_inside,
153 v2s32(x1 - padding/2, y2),
154 v2s32(x2 + padding/2, y2 + padding/2)
156 driver->draw2DRectangle(c_inside,
158 v2s32(x1 - padding/2, y1),
161 driver->draw2DRectangle(c_inside,
164 v2s32(x2 + padding/2, y2)
169 video::SColor bgcolor2(128, 0, 0, 0);
170 driver->draw2DRectangle(bgcolor2, rect, NULL);
171 drawItemStack(driver, font, item, rect, NULL, gamedef);
176 void Hud::drawLuaElements() {
177 for (size_t i = 0; i != player->hud.size(); i++) {
178 HudElement *e = player->hud[i];
182 v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
184 case HUD_ELEM_IMAGE: {
185 video::ITexture *texture = tsrc->getTexture(e->text);
189 const video::SColor color(255, 255, 255, 255);
190 const video::SColor colors[] = {color, color, color, color};
191 core::dimension2di imgsize(texture->getOriginalSize());
192 core::rect<s32> rect(0, 0, imgsize.Width * e->scale.X,
193 imgsize.Height * e->scale.X);
195 v2s32 offset((e->align.X - 1.0) * ((imgsize.Width * e->scale.X) / 2),
196 (e->align.Y - 1.0) * ((imgsize.Height * e->scale.X) / 2));
198 rect += v2s32(e->offset.X, e->offset.Y);
199 driver->draw2DImage(texture, rect,
200 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
203 case HUD_ELEM_TEXT: {
204 video::SColor color(255, (e->number >> 16) & 0xFF,
205 (e->number >> 8) & 0xFF,
206 (e->number >> 0) & 0xFF);
207 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
208 std::wstring text = narrow_to_wide(e->text);
209 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
210 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
211 (e->align.Y - 1.0) * (textsize.Height / 2));
212 v2s32 offs(e->offset.X, e->offset.Y);
213 font->draw(text.c_str(), size + pos + offset + offs, color);
215 case HUD_ELEM_STATBAR: {
216 v2s32 offs(e->offset.X, e->offset.Y);
217 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
219 case HUD_ELEM_INVENTORY: {
220 InventoryList *inv = inventory->getList(e->text);
221 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
224 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
225 "of hud element ID " << i << " due to unrecognized type" << std::endl;
231 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
232 const video::SColor color(255, 255, 255, 255);
233 const video::SColor colors[] = {color, color, color, color};
235 video::ITexture *stat_texture = tsrc->getTexture(texture);
239 core::dimension2di srcd(stat_texture->getOriginalSize());
242 if (corner & HUD_CORNER_LOWER)
249 case HUD_DIR_RIGHT_LEFT:
250 steppos = v2s32(-1, 0);
252 case HUD_DIR_TOP_BOTTOM:
253 steppos = v2s32(0, 1);
255 case HUD_DIR_BOTTOM_TOP:
256 steppos = v2s32(0, -1);
259 steppos = v2s32(1, 0);
261 steppos.X *= srcd.Width;
262 steppos.Y *= srcd.Height;
264 for (s32 i = 0; i < count / 2; i++)
266 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
267 core::rect<s32> dstrect(srcrect);
270 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
276 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
277 core::rect<s32> dstrect(srcrect);
280 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
285 void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) {
286 InventoryList *mainlist = inventory->getList("main");
287 if (mainlist == NULL) {
288 errorstream << "draw_hotbar(): mainlist == NULL" << std::endl;
292 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
293 s32 padding = hotbar_imagesize / 12;
294 s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
295 v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 2);
297 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE)
298 drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
299 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
300 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
301 "heart.png", halfheartcount, v2s32(0, 0));
302 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
303 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
304 "bubble.png", breath*2, v2s32(0, 0));
308 void Hud::drawCrosshair() {
309 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
312 if (use_crosshair_image) {
313 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
314 v2u32 size = crosshair->getOriginalSize();
315 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
316 displaycenter.Y - (size.Y / 2));
317 driver->draw2DImage(crosshair, lsize,
318 core::rect<s32>(0, 0, size.X, size.Y),
319 0, crosshair_argb, true);
321 driver->draw2DLine(displaycenter - v2s32(10, 0),
322 displaycenter + v2s32(10, 0), crosshair_argb);
323 driver->draw2DLine(displaycenter - v2s32(0, 10),
324 displaycenter + v2s32(0, 10), crosshair_argb);
329 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
330 for (std::vector<aabb3f>::const_iterator
331 i = hilightboxes.begin();
332 i != hilightboxes.end(); i++) {
333 driver->draw3DBox(*i, selectionbox_argb);
338 void Hud::resizeHotbar() {
339 if (screensize.Y <= 800)
340 hotbar_imagesize = 32;
341 else if (screensize.Y <= 1280)
342 hotbar_imagesize = 48;
344 hotbar_imagesize = 64;
347 void drawItemStack(video::IVideoDriver *driver,
349 const ItemStack &item,
350 const core::rect<s32> &rect,
351 const core::rect<s32> *clip,
357 const ItemDefinition &def = item.getDefinition(gamedef->idef());
358 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
360 // Draw the inventory texture
363 const video::SColor color(255,255,255,255);
364 const video::SColor colors[] = {color,color,color,color};
365 driver->draw2DImage(texture, rect,
366 core::rect<s32>(core::position2d<s32>(0,0),
367 core::dimension2di(texture->getOriginalSize())),
371 if(def.type == ITEM_TOOL && item.wear != 0)
373 // Draw a progressbar
374 float barheight = rect.getHeight()/16;
375 float barpad_x = rect.getWidth()/16;
376 float barpad_y = rect.getHeight()/16;
377 core::rect<s32> progressrect(
378 rect.UpperLeftCorner.X + barpad_x,
379 rect.LowerRightCorner.Y - barpad_y - barheight,
380 rect.LowerRightCorner.X - barpad_x,
381 rect.LowerRightCorner.Y - barpad_y);
383 // Shrink progressrect by amount of tool damage
384 float wear = item.wear / 65535.0;
386 wear * progressrect.UpperLeftCorner.X +
387 (1-wear) * progressrect.LowerRightCorner.X;
389 // Compute progressbar color
391 // wear = 0.5: yellow
393 video::SColor color(255,255,255,255);
394 int wear_i = MYMIN(floor(wear * 600), 511);
395 wear_i = MYMIN(wear_i + 10, 511);
397 color.set(255, wear_i, 255, 0);
399 color.set(255, 255, 511-wear_i, 0);
401 core::rect<s32> progressrect2 = progressrect;
402 progressrect2.LowerRightCorner.X = progressmid;
403 driver->draw2DRectangle(color, progressrect2, clip);
405 color = video::SColor(255,0,0,0);
406 progressrect2 = progressrect;
407 progressrect2.UpperLeftCorner.X = progressmid;
408 driver->draw2DRectangle(color, progressrect2, clip);
411 if(font != NULL && item.count >= 2)
413 // Get the item count as a string
414 std::string text = itos(item.count);
415 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
416 v2s32 sdim(dim.X,dim.Y);
418 core::rect<s32> rect2(
419 /*rect.UpperLeftCorner,
420 core::dimension2d<u32>(rect.getWidth(), 15)*/
421 rect.LowerRightCorner - sdim,
425 video::SColor bgcolor(128,0,0,0);
426 driver->draw2DRectangle(bgcolor, rect2, clip);
428 video::SColor color(255,255,255,255);
429 font->draw(text.c_str(), rect2, color, false, false, clip);