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 "game.h" // CameraModes
35 #include <IGUIStaticText.h>
38 Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr,
39 gui::IGUIEnvironment* guienv, gui::IGUIFont *font,
40 u32 text_height, IGameDef *gamedef,
41 LocalPlayer *player, Inventory *inventory) {
42 this->driver = driver;
44 this->guienv = guienv;
46 this->text_height = text_height;
47 this->gamedef = gamedef;
48 this->player = player;
49 this->inventory = inventory;
51 screensize = v2u32(0, 0);
52 displaycenter = v2s32(0, 0);
53 hotbar_imagesize = 48;
55 tsrc = gamedef->getTextureSource();
57 v3f crosshair_color = g_settings->getV3F("crosshair_color");
58 u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255);
59 u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255);
60 u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255);
61 u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255);
62 crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b);
64 v3f selectionbox_color = g_settings->getV3F("selectionbox_color");
65 u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255);
66 u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255);
67 u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255);
68 selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
70 use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
73 use_hotbar_image = false;
74 hotbar_selected_image = "";
75 use_hotbar_selected_image = false;
79 //NOTE: selectitem = 0 -> no selected; selectitem 1-based
80 void Hud::drawItem(v2s32 upperleftpos, s32 imgsize, s32 itemcount,
81 InventoryList *mainlist, u16 selectitem, u16 direction)
83 s32 padding = imgsize / 12;
84 s32 height = imgsize + padding * 2;
85 s32 width = itemcount * (imgsize + padding * 2);
86 if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) {
87 width = imgsize + padding * 2;
88 height = itemcount * (imgsize + padding * 2);
90 s32 fullimglen = imgsize + padding * 2;
92 // Position of upper left corner of bar
93 v2s32 pos = upperleftpos;
95 // Draw background color
96 /*core::rect<s32> barrect(0,0,width,height);
98 video::SColor bgcolor(255,128,128,128);
99 driver->draw2DRectangle(bgcolor, barrect, NULL);*/
101 core::rect<s32> imgrect(0, 0, imgsize, imgsize);
102 const video::SColor hbar_color(255, 255, 255, 255);
103 const video::SColor hbar_colors[] = {hbar_color, hbar_color, hbar_color, hbar_color};
105 if (hotbar_image != player->hotbar_image) {
106 hotbar_image = player->hotbar_image;
107 if (hotbar_image != "")
108 use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image);
110 use_hotbar_image = false;
113 if (hotbar_selected_image != player->hotbar_selected_image) {
114 hotbar_selected_image = player->hotbar_selected_image;
115 if (hotbar_selected_image != "")
116 use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image);
118 use_hotbar_selected_image = false;
121 if (use_hotbar_image) {
122 core::rect<s32> imgrect2(-padding/2, -padding/2, width+padding/2, height+padding/2);
123 core::rect<s32> rect2 = imgrect2 + pos;
124 video::ITexture *texture = tsrc->getTexture(hotbar_image);
125 core::dimension2di imgsize(texture->getOriginalSize());
126 driver->draw2DImage(texture, rect2,
127 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
128 NULL, hbar_colors, true);
131 for (s32 i = 0; i < itemcount; i++)
133 const ItemStack &item = mainlist->getItem(i);
137 case HUD_DIR_RIGHT_LEFT:
138 steppos = v2s32(-(padding + i * fullimglen), padding);
140 case HUD_DIR_TOP_BOTTOM:
141 steppos = v2s32(padding, padding + i * fullimglen);
143 case HUD_DIR_BOTTOM_TOP:
144 steppos = v2s32(padding, -(padding + i * fullimglen));
147 steppos = v2s32(padding + i * fullimglen, padding);
150 core::rect<s32> rect = imgrect + pos + steppos;
152 if (selectitem == i + 1) {
153 if (use_hotbar_selected_image) {
154 core::rect<s32> imgrect2(-padding*2, -padding*2, height, height);
155 rect = imgrect2 + pos + steppos;
156 video::ITexture *texture = tsrc->getTexture(hotbar_selected_image);
157 core::dimension2di imgsize(texture->getOriginalSize());
158 driver->draw2DImage(texture, rect,
159 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
160 NULL, hbar_colors, true);
161 rect = imgrect + pos + steppos;
163 rect = imgrect + pos + steppos;
164 video::SColor c_outside(255,255,0,0);
165 //video::SColor c_outside(255,0,0,0);
166 //video::SColor c_inside(255,192,192,192);
167 s32 x1 = rect.UpperLeftCorner.X;
168 s32 y1 = rect.UpperLeftCorner.Y;
169 s32 x2 = rect.LowerRightCorner.X;
170 s32 y2 = rect.LowerRightCorner.Y;
171 // Black base borders
172 driver->draw2DRectangle(c_outside,
174 v2s32(x1 - padding, y1 - padding),
175 v2s32(x2 + padding, y1)
177 driver->draw2DRectangle(c_outside,
179 v2s32(x1 - padding, y2),
180 v2s32(x2 + padding, y2 + padding)
182 driver->draw2DRectangle(c_outside,
184 v2s32(x1 - padding, y1),
187 driver->draw2DRectangle(c_outside,
190 v2s32(x2 + padding, y2)
192 /*// Light inside borders
193 driver->draw2DRectangle(c_inside,
195 v2s32(x1 - padding/2, y1 - padding/2),
196 v2s32(x2 + padding/2, y1)
198 driver->draw2DRectangle(c_inside,
200 v2s32(x1 - padding/2, y2),
201 v2s32(x2 + padding/2, y2 + padding/2)
203 driver->draw2DRectangle(c_inside,
205 v2s32(x1 - padding/2, y1),
208 driver->draw2DRectangle(c_inside,
211 v2s32(x2 + padding/2, y2)
217 video::SColor bgcolor2(128, 0, 0, 0);
218 if (!use_hotbar_image)
219 driver->draw2DRectangle(bgcolor2, rect, NULL);
220 drawItemStack(driver, font, item, rect, NULL, gamedef);
225 void Hud::drawLuaElements() {
226 for (size_t i = 0; i != player->hud.size(); i++) {
227 HudElement *e = player->hud[i];
231 v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
233 case HUD_ELEM_IMAGE: {
234 video::ITexture *texture = tsrc->getTexture(e->text);
238 const video::SColor color(255, 255, 255, 255);
239 const video::SColor colors[] = {color, color, color, color};
240 core::dimension2di imgsize(texture->getOriginalSize());
241 v2s32 dstsize(imgsize.Width * e->scale.X,
242 imgsize.Height * e->scale.Y);
244 dstsize.X = screensize.X * (e->scale.X * -0.01);
246 dstsize.Y = screensize.Y * (e->scale.Y * -0.01);
247 v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
248 (e->align.Y - 1.0) * dstsize.Y / 2);
249 core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
250 rect += pos + offset + v2s32(e->offset.X, e->offset.Y);
251 driver->draw2DImage(texture, rect,
252 core::rect<s32>(core::position2d<s32>(0,0), imgsize),
255 case HUD_ELEM_TEXT: {
256 video::SColor color(255, (e->number >> 16) & 0xFF,
257 (e->number >> 8) & 0xFF,
258 (e->number >> 0) & 0xFF);
259 core::rect<s32> size(0, 0, e->scale.X, text_height * e->scale.Y);
260 std::wstring text = narrow_to_wide(e->text);
261 core::dimension2d<u32> textsize = font->getDimension(text.c_str());
262 v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2),
263 (e->align.Y - 1.0) * (textsize.Height / 2));
264 v2s32 offs(e->offset.X, e->offset.Y);
265 font->draw(text.c_str(), size + pos + offset + offs, color);
267 case HUD_ELEM_STATBAR: {
268 v2s32 offs(e->offset.X, e->offset.Y);
269 drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs);
271 case HUD_ELEM_INVENTORY: {
272 InventoryList *inv = inventory->getList(e->text);
273 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
275 case HUD_ELEM_WAYPOINT: {
276 v3f p_pos = player->getPosition() / BS;
277 v3f w_pos = e->world_pos * BS;
278 float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10;
279 scene::ICameraSceneNode* camera = smgr->getActiveCamera();
280 core::matrix4 trans = camera->getProjectionMatrix();
281 trans *= camera->getViewMatrix();
282 f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f };
283 trans.multiplyWith1x4Matrix(transformed_pos);
284 if (transformed_pos[3] < 0)
286 f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
287 core::reciprocal(transformed_pos[3]);
288 pos.X = screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5);
289 pos.Y = screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5);
290 video::SColor color(255, (e->number >> 16) & 0xFF,
291 (e->number >> 8) & 0xFF,
292 (e->number >> 0) & 0xFF);
293 core::rect<s32> size(0, 0, 200, 2 * text_height);
294 std::wstring text = narrow_to_wide(e->name);
295 font->draw(text.c_str(), size + pos, color);
296 std::ostringstream os;
297 os<<distance<<e->text;
298 text = narrow_to_wide(os.str());
299 pos.Y += text_height;
300 font->draw(text.c_str(), size + pos, color);
303 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
304 " of hud element ID " << i << " due to unrecognized type" << std::endl;
310 void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, s32 count, v2s32 offset) {
311 const video::SColor color(255, 255, 255, 255);
312 const video::SColor colors[] = {color, color, color, color};
314 video::ITexture *stat_texture = tsrc->getTexture(texture);
318 core::dimension2di srcd(stat_texture->getOriginalSize());
321 if (corner & HUD_CORNER_LOWER)
328 case HUD_DIR_RIGHT_LEFT:
329 steppos = v2s32(-1, 0);
331 case HUD_DIR_TOP_BOTTOM:
332 steppos = v2s32(0, 1);
334 case HUD_DIR_BOTTOM_TOP:
335 steppos = v2s32(0, -1);
338 steppos = v2s32(1, 0);
340 steppos.X *= srcd.Width;
341 steppos.Y *= srcd.Height;
343 for (s32 i = 0; i < count / 2; i++)
345 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
346 core::rect<s32> dstrect(srcrect);
349 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
355 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
356 core::rect<s32> dstrect(srcrect);
359 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
364 void Hud::drawHotbar(v2s32 centerlowerpos, s32 halfheartcount, u16 playeritem, s32 breath) {
365 InventoryList *mainlist = inventory->getList("main");
366 if (mainlist == NULL) {
367 //silently ignore this we may not be initialized completely
371 s32 hotbar_itemcount = player->hud_hotbar_itemcount;
372 s32 padding = hotbar_imagesize / 12;
373 s32 width = hotbar_itemcount * (hotbar_imagesize + padding * 2);
374 v2s32 pos = centerlowerpos - v2s32(width / 2, hotbar_imagesize + padding * 3);
376 if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE)
377 drawItem(pos, hotbar_imagesize, hotbar_itemcount, mainlist, playeritem + 1, 0);
378 if (player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)
379 drawStatbar(pos - v2s32(0, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
380 "heart.png", halfheartcount, v2s32(0, 0));
381 if (player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE && breath <= 10)
382 drawStatbar(pos - v2s32(-180, 4), HUD_CORNER_LOWER, HUD_DIR_LEFT_RIGHT,
383 "bubble.png", breath*2, v2s32(0, 0));
387 void Hud::drawCrosshair() {
388 if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) ||
389 player->camera_mode == CAMERA_MODE_THIRD_FRONT)
392 if (use_crosshair_image) {
393 video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
394 v2u32 size = crosshair->getOriginalSize();
395 v2s32 lsize = v2s32(displaycenter.X - (size.X / 2),
396 displaycenter.Y - (size.Y / 2));
397 driver->draw2DImage(crosshair, lsize,
398 core::rect<s32>(0, 0, size.X, size.Y),
399 0, crosshair_argb, true);
401 driver->draw2DLine(displaycenter - v2s32(10, 0),
402 displaycenter + v2s32(10, 0), crosshair_argb);
403 driver->draw2DLine(displaycenter - v2s32(0, 10),
404 displaycenter + v2s32(0, 10), crosshair_argb);
409 void Hud::drawSelectionBoxes(std::vector<aabb3f> &hilightboxes) {
410 for (std::vector<aabb3f>::const_iterator
411 i = hilightboxes.begin();
412 i != hilightboxes.end(); i++) {
413 driver->draw3DBox(*i, selectionbox_argb);
418 void Hud::resizeHotbar() {
419 if (screensize.Y <= 800)
420 hotbar_imagesize = 32;
421 else if (screensize.Y <= 1280)
422 hotbar_imagesize = 48;
424 hotbar_imagesize = 64;
427 void drawItemStack(video::IVideoDriver *driver,
429 const ItemStack &item,
430 const core::rect<s32> &rect,
431 const core::rect<s32> *clip,
437 const ItemDefinition &def = item.getDefinition(gamedef->idef());
438 video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
440 // Draw the inventory texture
443 const video::SColor color(255,255,255,255);
444 const video::SColor colors[] = {color,color,color,color};
445 driver->draw2DImage(texture, rect,
446 core::rect<s32>(core::position2d<s32>(0,0),
447 core::dimension2di(texture->getOriginalSize())),
451 if(def.type == ITEM_TOOL && item.wear != 0)
453 // Draw a progressbar
454 float barheight = rect.getHeight()/16;
455 float barpad_x = rect.getWidth()/16;
456 float barpad_y = rect.getHeight()/16;
457 core::rect<s32> progressrect(
458 rect.UpperLeftCorner.X + barpad_x,
459 rect.LowerRightCorner.Y - barpad_y - barheight,
460 rect.LowerRightCorner.X - barpad_x,
461 rect.LowerRightCorner.Y - barpad_y);
463 // Shrink progressrect by amount of tool damage
464 float wear = item.wear / 65535.0;
466 wear * progressrect.UpperLeftCorner.X +
467 (1-wear) * progressrect.LowerRightCorner.X;
469 // Compute progressbar color
471 // wear = 0.5: yellow
473 video::SColor color(255,255,255,255);
474 int wear_i = MYMIN(floor(wear * 600), 511);
475 wear_i = MYMIN(wear_i + 10, 511);
477 color.set(255, wear_i, 255, 0);
479 color.set(255, 255, 511-wear_i, 0);
481 core::rect<s32> progressrect2 = progressrect;
482 progressrect2.LowerRightCorner.X = progressmid;
483 driver->draw2DRectangle(color, progressrect2, clip);
485 color = video::SColor(255,0,0,0);
486 progressrect2 = progressrect;
487 progressrect2.UpperLeftCorner.X = progressmid;
488 driver->draw2DRectangle(color, progressrect2, clip);
491 if(font != NULL && item.count >= 2)
493 // Get the item count as a string
494 std::string text = itos(item.count);
495 v2u32 dim = font->getDimension(narrow_to_wide(text).c_str());
496 v2s32 sdim(dim.X,dim.Y);
498 core::rect<s32> rect2(
499 /*rect.UpperLeftCorner,
500 core::dimension2d<u32>(rect.getWidth(), 15)*/
501 rect.LowerRightCorner - sdim,
505 video::SColor bgcolor(128,0,0,0);
506 driver->draw2DRectangle(bgcolor, rect2, clip);
508 video::SColor color(255,255,255,255);
509 font->draw(text.c_str(), rect2, color, false, false, clip);