]> git.lizzy.rs Git - dragonfireclient.git/blob - src/hud.cpp
Omnicleanup: header cleanup, add ModApiUtil shared between game and mainmenu
[dragonfireclient.git] / src / hud.cpp
1 /*
2 Minetest
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>
6
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.
11
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.
16
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.
20 */
21
22 #include "hud.h"
23 #include "main.h"
24 #include "settings.h"
25 #include "util/numeric.h"
26 #include "log.h"
27 #include "gamedef.h"
28 #include "itemdef.h"
29 #include "inventory.h"
30 #include "tile.h"
31 #include "localplayer.h"
32
33 #include <IGUIStaticText.h>
34
35
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;
41         this->font        = font;
42         this->text_height = text_height;
43         this->gamedef     = gamedef;
44         this->player      = player;
45         this->inventory   = inventory;
46         
47         screensize       = v2u32(0, 0);
48         displaycenter    = v2s32(0, 0);
49         hotbar_imagesize = 48;
50         
51         tsrc = gamedef->getTextureSource();
52         
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);
59         
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);
65         
66         use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
67 }
68
69
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)
73 {
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);
80         }
81         s32 fullimglen = imgsize + padding * 2;
82
83         // Position of upper left corner of bar
84         v2s32 pos = upperleftpos;
85
86         // Draw background color
87         /*core::rect<s32> barrect(0,0,width,height);
88         barrect += pos;
89         video::SColor bgcolor(255,128,128,128);
90         driver->draw2DRectangle(bgcolor, barrect, NULL);*/
91
92         core::rect<s32> imgrect(0, 0, imgsize, imgsize);
93
94         for (s32 i = 0; i < itemcount; i++)
95         {
96                 const ItemStack &item = mainlist->getItem(i);
97
98                 v2s32 steppos;
99                 switch (direction) {
100                         case HUD_DIR_RIGHT_LEFT:
101                                 steppos = v2s32(-(padding + i * fullimglen), padding);
102                                 break;
103                         case HUD_DIR_TOP_BOTTOM:
104                                 steppos = v2s32(padding, padding + i * fullimglen);
105                                 break;
106                         case HUD_DIR_BOTTOM_TOP:
107                                 steppos = v2s32(padding, -(padding + i * fullimglen));
108                                 break;
109                         default:
110                                 steppos = v2s32(padding + i * fullimglen, padding);     
111                 }
112                         
113                 core::rect<s32> rect = imgrect + pos + steppos;
114
115                 if (selectitem == i + 1)
116                 {
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,
126                                         core::rect<s32>(
127                                                 v2s32(x1 - padding, y1 - padding),
128                                                 v2s32(x2 + padding, y1)
129                                         ), NULL);
130                         driver->draw2DRectangle(c_outside,
131                                         core::rect<s32>(
132                                                 v2s32(x1 - padding, y2),
133                                                 v2s32(x2 + padding, y2 + padding)
134                                         ), NULL);
135                         driver->draw2DRectangle(c_outside,
136                                         core::rect<s32>(
137                                                 v2s32(x1 - padding, y1),
138                                                 v2s32(x1, y2)
139                                         ), NULL);
140                         driver->draw2DRectangle(c_outside,
141                                         core::rect<s32>(
142                                                 v2s32(x2, y1),
143                                                 v2s32(x2 + padding, y2)
144                                         ), NULL);
145                         /*// Light inside borders
146                         driver->draw2DRectangle(c_inside,
147                                         core::rect<s32>(
148                                                 v2s32(x1 - padding/2, y1 - padding/2),
149                                                 v2s32(x2 + padding/2, y1)
150                                         ), NULL);
151                         driver->draw2DRectangle(c_inside,
152                                         core::rect<s32>(
153                                                 v2s32(x1 - padding/2, y2),
154                                                 v2s32(x2 + padding/2, y2 + padding/2)
155                                         ), NULL);
156                         driver->draw2DRectangle(c_inside,
157                                         core::rect<s32>(
158                                                 v2s32(x1 - padding/2, y1),
159                                                 v2s32(x1, y2)
160                                         ), NULL);
161                         driver->draw2DRectangle(c_inside,
162                                         core::rect<s32>(
163                                                 v2s32(x2, y1),
164                                                 v2s32(x2 + padding/2, y2)
165                                         ), NULL);
166                         */
167                 }
168
169                 video::SColor bgcolor2(128, 0, 0, 0);
170                 driver->draw2DRectangle(bgcolor2, rect, NULL);
171                 drawItemStack(driver, font, item, rect, NULL, gamedef);
172         }
173 }
174
175
176 void Hud::drawLuaElements() {
177         for (size_t i = 0; i != player->hud.size(); i++) {
178                 HudElement *e = player->hud[i];
179                 if (!e)
180                         continue;
181                 
182                 v2s32 pos(e->pos.X * screensize.X, e->pos.Y * screensize.Y);
183                 switch (e->type) {
184                         case HUD_ELEM_IMAGE: {
185                                 video::ITexture *texture = tsrc->getTexture(e->text);
186                                 if (!texture)
187                                         continue;
188
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);
194                                 rect += pos;
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));
197                                 rect += offset;
198                                 rect += v2s32(e->offset.X, e->offset.Y);
199                                 driver->draw2DImage(texture, rect,
200                                         core::rect<s32>(core::position2d<s32>(0,0), imgsize),
201                                         NULL, colors, true);
202                                 break; }
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);
214                                 break; }
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);
218                                 break; }
219                         case HUD_ELEM_INVENTORY: {
220                                 InventoryList *inv = inventory->getList(e->text);
221                                 drawItem(pos, hotbar_imagesize, e->number, inv, e->item, e->dir);
222                                 break; }
223                         default:
224                                 infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
225                                         "of hud element ID " << i << " due to unrecognized type" << std::endl;
226                 }
227         }
228 }
229
230
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};
234         
235         video::ITexture *stat_texture = tsrc->getTexture(texture);
236         if (!stat_texture)
237                 return;
238                 
239         core::dimension2di srcd(stat_texture->getOriginalSize());
240
241         v2s32 p = pos;
242         if (corner & HUD_CORNER_LOWER)
243                 p -= srcd.Height;
244
245         p += offset;
246
247         v2s32 steppos;
248         switch (drawdir) {
249                 case HUD_DIR_RIGHT_LEFT:
250                         steppos = v2s32(-1, 0);
251                         break;
252                 case HUD_DIR_TOP_BOTTOM:
253                         steppos = v2s32(0, 1);
254                         break;
255                 case HUD_DIR_BOTTOM_TOP:
256                         steppos = v2s32(0, -1);
257                         break;
258                 default:
259                         steppos = v2s32(1, 0);  
260         }
261         steppos.X *= srcd.Width;
262         steppos.Y *= srcd.Height;
263         
264         for (s32 i = 0; i < count / 2; i++)
265         {
266                 core::rect<s32> srcrect(0, 0, srcd.Width, srcd.Height);
267                 core::rect<s32> dstrect(srcrect);
268
269                 dstrect += p;
270                 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
271                 p += steppos;
272         }
273         
274         if (count % 2 == 1)
275         {
276                 core::rect<s32> srcrect(0, 0, srcd.Width / 2, srcd.Height);
277                 core::rect<s32> dstrect(srcrect);
278
279                 dstrect += p;
280                 driver->draw2DImage(stat_texture, dstrect, srcrect, NULL, colors, true);
281         }
282 }
283
284
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;
289                 return;
290         }
291         
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);
296         
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));
305 }
306
307
308 void Hud::drawCrosshair() {
309         if (!(player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE))
310                 return;
311                 
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);
320         } else {
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);
325         }
326 }
327
328
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);
334         }
335 }
336
337
338 void Hud::resizeHotbar() {
339         if (screensize.Y <= 800)
340                 hotbar_imagesize = 32;
341         else if (screensize.Y <= 1280)
342                 hotbar_imagesize = 48;
343         else
344                 hotbar_imagesize = 64;
345 }
346
347 void drawItemStack(video::IVideoDriver *driver,
348                 gui::IGUIFont *font,
349                 const ItemStack &item,
350                 const core::rect<s32> &rect,
351                 const core::rect<s32> *clip,
352                 IGameDef *gamedef)
353 {
354         if(item.empty())
355                 return;
356         
357         const ItemDefinition &def = item.getDefinition(gamedef->idef());
358         video::ITexture *texture = gamedef->idef()->getInventoryTexture(def.name, gamedef);
359
360         // Draw the inventory texture
361         if(texture != NULL)
362         {
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())),
368                         clip, colors, true);
369         }
370
371         if(def.type == ITEM_TOOL && item.wear != 0)
372         {
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);
382
383                 // Shrink progressrect by amount of tool damage
384                 float wear = item.wear / 65535.0;
385                 int progressmid =
386                         wear * progressrect.UpperLeftCorner.X +
387                         (1-wear) * progressrect.LowerRightCorner.X;
388
389                 // Compute progressbar color
390                 //   wear = 0.0: green
391                 //   wear = 0.5: yellow
392                 //   wear = 1.0: red
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);
396                 if(wear_i <= 255)
397                         color.set(255, wear_i, 255, 0);
398                 else
399                         color.set(255, 255, 511-wear_i, 0);
400
401                 core::rect<s32> progressrect2 = progressrect;
402                 progressrect2.LowerRightCorner.X = progressmid;
403                 driver->draw2DRectangle(color, progressrect2, clip);
404
405                 color = video::SColor(255,0,0,0);
406                 progressrect2 = progressrect;
407                 progressrect2.UpperLeftCorner.X = progressmid;
408                 driver->draw2DRectangle(color, progressrect2, clip);
409         }
410
411         if(font != NULL && item.count >= 2)
412         {
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);
417
418                 core::rect<s32> rect2(
419                         /*rect.UpperLeftCorner,
420                         core::dimension2d<u32>(rect.getWidth(), 15)*/
421                         rect.LowerRightCorner - sdim,
422                         sdim
423                 );
424
425                 video::SColor bgcolor(128,0,0,0);
426                 driver->draw2DRectangle(bgcolor, rect2, clip);
427
428                 video::SColor color(255,255,255,255);
429                 font->draw(text.c_str(), rect2, color, false, false, clip);
430         }
431 }
432