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 && (size_t)i < mainlist->getSize(); 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 //silently ignore this we may not be initialized completely
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) ||
388 player->camera_mode == CAMERA_MODE_THIRD_FRONT)
391 if (use_crosshair_image) {
392 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
393 v2u32 size = crosshair->getOriginalSize();
394 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
395 displaycenter.Y - (size.Y / 2));
396 driver->draw2DImage(crosshair, lsize,
397 core::rect<s32>(0, 0, size.X, size.Y),
398 0, crosshair_argb, true);
400 driver->draw2DLine(displaycenter - v2s32(10, 0),
401 displaycenter + v2s32(10, 0), crosshair_argb);
402 driver->draw2DLine(displaycenter - v2s32(0, 10),
403 displaycenter + v2s32(0, 10), crosshair_argb);
408 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
409 for (std::vector<aabb3f>::const_iterator
410 i = hilightboxes.begin();
411 i != hilightboxes.end(); i++) {
412 driver->draw3DBox(*i, selectionbox_argb);
417 void Hud::resizeHotbar() {
418 if (screensize.Y <= 800)
419 hotbar_imagesize = 32;
420 else if (screensize.Y <= 1280)
421 hotbar_imagesize = 48;
423 hotbar_imagesize = 64;
426 void drawItemStack(video::IVideoDriver *driver,
428 const ItemStack &item,
429 const core::rect<s32> &rect,
430 const core::rect<s32> *clip,
436 const ItemDefinition &def = item.getDefinition(gamedef->idef());
437 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
439 // Draw the inventory texture
442 const video::SColor color(255,255,255,255);
443 const video::SColor colors[] = {color,color,color,color};
444 driver->draw2DImage(texture, rect,
445 core::rect<s32>(core::position2d<s32>(0,0),
446 core::dimension2di(texture->getOriginalSize())),
450 if(def.type == ITEM_TOOL && item.wear != 0)
452 // Draw a progressbar
453 float barheight = rect.getHeight()/16;
454 float barpad_x = rect.getWidth()/16;
455 float barpad_y = rect.getHeight()/16;
456 core::rect<s32> progressrect(
457 rect.UpperLeftCorner.X + barpad_x,
458 rect.LowerRightCorner.Y - barpad_y - barheight,
459 rect.LowerRightCorner.X - barpad_x,
460 rect.LowerRightCorner.Y - barpad_y);
462 // Shrink progressrect by amount of tool damage
463 float wear = item.wear / 65535.0;
465 wear * progressrect.UpperLeftCorner.X +
466 (1-wear) * progressrect.LowerRightCorner.X;
468 // Compute progressbar color
470 // wear = 0.5: yellow
472 video::SColor color(255,255,255,255);
473 int wear_i = MYMIN(floor(wear * 600), 511);
474 wear_i = MYMIN(wear_i + 10, 511);
476 color.set(255, wear_i, 255, 0);
478 color.set(255, 255, 511-wear_i, 0);
480 core::rect<s32> progressrect2 = progressrect;
481 progressrect2.LowerRightCorner.X = progressmid;
482 driver->draw2DRectangle(color, progressrect2, clip);
484 color = video::SColor(255,0,0,0);
485 progressrect2 = progressrect;
486 progressrect2.UpperLeftCorner.X = progressmid;
487 driver->draw2DRectangle(color, progressrect2, clip);
490 if(font != NULL && item.count >= 2)
492 // Get the item count as a string
493 std::string text = itos(item.count);
494 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
495 v2s32 sdim(dim.X,dim.Y);
497 core::rect<s32> rect2(
498 /*rect.UpperLeftCorner,
499 core::dimension2d<u32>(rect.getWidth(), 15)*/
500 rect.LowerRightCorner - sdim,
504 video::SColor bgcolor(128,0,0,0);
505 driver->draw2DRectangle(bgcolor, rect2, clip);
507 video::SColor color(255,255,255,255);
508 font->draw(text.c_str(), rect2, color, false, false, clip);