diff --git a/.gitignore b/.gitignore index 7b5ecab67..80415c830 100644 --- a/.gitignore +++ b/.gitignore @@ -86,6 +86,8 @@ locale/ *.gch cmake-build-debug/ cmake-build-release/ +cmake_config.h +cmake_config_githash.h ## Android build files build/android/src/main/assets diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index 375ab5ce4..72be8fe2c 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -270,6 +270,7 @@ LOCAL_SRC_FILES := \ jni/src/settings.cpp \ jni/src/wieldmesh.cpp \ jni/src/client/clientlauncher.cpp \ + jni/src/client/hud.cpp \ jni/src/client/inputhandler.cpp \ jni/src/client/renderingengine.cpp \ jni/src/client/tile.cpp \ diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua index 288b1b16c..a384fd6bf 100644 --- a/clientmods/preview/init.lua +++ b/clientmods/preview/init.lua @@ -7,7 +7,7 @@ dofile("preview:example.lua") core.register_on_shutdown(function() print("[PREVIEW] shutdown client") end) - +local id = 0 core.register_on_connect(function() print("[PREVIEW] Player connection completed") local server_info = core.get_server_info() @@ -15,7 +15,6 @@ core.register_on_connect(function() print("Server ip: " .. server_info.ip) print("Server address: " .. server_info.address) print("Server port: " .. server_info.port) - mod_channel = core.mod_channel_join("experimental_preview") core.after(4, function() @@ -25,6 +24,19 @@ core.register_on_connect(function() end) end) +core.after(1, function() + id = core.localplayer:hud_add({ + hud_elem_type = "text", + name = "example", + number = 0xff0000, + position = {x=0, y=1}, + offset = {x=8, y=-8}, + text = "You are using the preview mod", + scale = {x=200, y=60}, + alignment = {x=1, y=-1}, + }) +end) + core.register_on_modchannel_message(function(channel, sender, message) print("[PREVIEW][modchannels] Received message `" .. message .. "` on channel `" .. channel .. "` from sender `" .. sender .. "`") @@ -184,3 +196,9 @@ core.register_chatcommand("privs", { return true, core.privs_to_string(minetest.get_privilege_list()) end, }) + +core.register_chatcommand("text", { + func = function(param) + return core.localplayer:hud_change(id, "text", param) + end, +}) diff --git a/doc/client_lua_api.txt b/doc/client_lua_api.txt index d79b644d7..435cc5b2e 100644 --- a/doc/client_lua_api.txt +++ b/doc/client_lua_api.txt @@ -1025,6 +1025,17 @@ Methods: * returns last look vertical angle * `get_key_pressed()`: * returns last key typed by the player +* `hud_add(definition)` + * add a HUD element described by HUD def, returns ID number on success and `nil` on failure. + * See [`HUD definition`](#hud-definition-hud_add-hud_get) +* `hud_get(id)` + * returns the [`definition`](#hud-definition-hud_add-hud_get) of the HUD with that ID number or `nil`, if non-existent. +* `hud_remove(id)` + * remove the HUD element of the specified id, returns `true` on success +* `hud_change(id, stat, value)` + * change a value of a previously added HUD element + * element `stat` values: `position`, `name`, `scale`, `text`, `number`, `item`, `dir` + * Returns `true` on success, otherwise returns `nil` ### Settings An interface to read config files in the format of `minetest.conf`. @@ -1163,6 +1174,30 @@ Can be obtained via `minetest.get_meta(pos)`. } ``` +### HUD Definition (`hud_add`, `hud_get`) +```lua + { + hud_elem_type = "image", -- see HUD element types, default "text" + -- ^ type of HUD element, can be either of "image", "text", "statbar", or "inventory" + position = {x=0.5, y=0.5}, + -- ^ Left corner position of element, default `{x=0,y=0}`. + name = "", -- default "" + scale = {x=2, y=2}, -- default {x=0,y=0} + text = "", -- default "" + number = 2, -- default 0 + item = 3, -- default 0 + -- ^ Selected item in inventory. 0 for no item selected. + direction = 0, -- default 0 + -- ^ Direction: 0: left-right, 1: right-left, 2: top-bottom, 3: bottom-top + alignment = {x=0, y=0}, -- default {x=0, y=0} + -- ^ See "HUD Element Types" + offset = {x=0, y=0}, -- default {x=0, y=0} + -- ^ See "HUD Element Types" + size = { x=100, y=100 }, -- default {x=0, y=0} + -- ^ Size of element in pixels + } +``` + Escape sequences ---------------- Most text can contain escape sequences, that can for example color the text. @@ -1206,3 +1241,80 @@ value must (always) be two hexadecimal digits. `Color` ------------- `{a = alpha, r = red, g = green, b = blue}` defines an ARGB8 color. + +HUD element types +----------------- +The position field is used for all element types. + +To account for differing resolutions, the position coordinates are the percentage +of the screen, ranging in value from `0` to `1`. + +The name field is not yet used, but should contain a description of what the +HUD element represents. The direction field is the direction in which something +is drawn. + +`0` draws from left to right, `1` draws from right to left, `2` draws from +top to bottom, and `3` draws from bottom to top. + +The `alignment` field specifies how the item will be aligned. It ranges from `-1` to `1`, +with `0` being the center, `-1` is moved to the left/up, and `1` is to the right/down. +Fractional values can be used. + +The `offset` field specifies a pixel offset from the position. Contrary to position, +the offset is not scaled to screen size. This allows for some precisely-positioned +items in the HUD. + +**Note**: `offset` _will_ adapt to screen DPI as well as user defined scaling factor! + +Below are the specific uses for fields in each type; fields not listed for that type are ignored. + +**Note**: Future revisions to the HUD API may be incompatible; the HUD API is still +in the experimental stages. + +### `image` +Displays an image on the HUD. + +* `scale`: The scale of the image, with 1 being the original texture size. + Only the X coordinate scale is used (positive values). + Negative values represent that percentage of the screen it + should take; e.g. `x=-100` means 100% (width). +* `text`: The name of the texture that is displayed. +* `alignment`: The alignment of the image. +* `offset`: offset in pixels from position. + +### `text` +Displays text on the HUD. + +* `scale`: Defines the bounding rectangle of the text. + A value such as `{x=100, y=100}` should work. +* `text`: The text to be displayed in the HUD element. +* `number`: An integer containing the RGB value of the color used to draw the text. + Specify `0xFFFFFF` for white text, `0xFF0000` for red, and so on. +* `alignment`: The alignment of the text. +* `offset`: offset in pixels from position. + +### `statbar` +Displays a horizontal bar made up of half-images. + +* `text`: The name of the texture that is used. +* `number`: The number of half-textures that are displayed. + If odd, will end with a vertically center-split texture. +* `direction` +* `offset`: offset in pixels from position. +* `size`: If used, will force full-image size to this value (override texture pack image size) + +### `inventory` +* `text`: The name of the inventory list to be displayed. +* `number`: Number of items in the inventory to be displayed. +* `item`: Position of item that is selected. +* `direction` +* `offset`: offset in pixels from position. + +### `waypoint` +Displays distance to selected world position. + +* `name`: The name of the waypoint. +* `text`: Distance suffix. Can be blank. +* `number:` An integer containing the RGB value of the color used to draw the text. +* `world_pos`: World position of the waypoint. + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9964b828b..c2b28832a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -448,6 +448,7 @@ set(common_SRCS version.cpp voxel.cpp voxelalgorithms.cpp + hud.cpp ${common_network_SRCS} ${JTHREAD_SRCS} ${common_SCRIPT_SRCS} diff --git a/src/client.h b/src/client.h index 11f27e9bd..caa3a7b73 100644 --- a/src/client.h +++ b/src/client.h @@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gamedef.h" #include "inventorymanager.h" #include "localplayer.h" -#include "hud.h" +#include "client/hud.h" #include "particles.h" #include "mapnode.h" #include "tileanimation.h" @@ -554,6 +554,10 @@ private: // And relations to objects std::unordered_map m_sounds_to_objects; + // HUD + // Mapping from server hud ids to internal hud ids + std::unordered_map m_hud_server_to_client; + // Privileges std::unordered_set m_privileges; diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 3462636f4..c69b2c2d4 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -13,5 +13,6 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tile.cpp ${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hud.cpp PARENT_SCOPE ) diff --git a/src/client/hud.cpp b/src/client/hud.cpp new file mode 100644 index 000000000..5137c2f3e --- /dev/null +++ b/src/client/hud.cpp @@ -0,0 +1,775 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2010-2013 blue42u, Jonathon Anderson +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "client/hud.h" +#include "settings.h" +#include "util/numeric.h" +#include "log.h" +#include "client.h" +#include "inventory.h" +#include "shader.h" +#include "client/tile.h" +#include "localplayer.h" +#include "camera.h" +#include "porting.h" +#include "fontengine.h" +#include "guiscalingfilter.h" +#include "mesh.h" +#include "wieldmesh.h" +#include "client/renderingengine.h" + +#ifdef HAVE_TOUCHSCREENGUI +#include "gui/touchscreengui.h" +#endif + +Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, + Inventory *inventory) +{ + driver = RenderingEngine::get_video_driver(); + this->guienv = guienv; + this->client = client; + this->player = player; + this->inventory = inventory; + + m_hud_scaling = g_settings->getFloat("hud_scaling"); + m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * + RenderingEngine::getDisplayDensity() + 0.5f); + m_hotbar_imagesize *= m_hud_scaling; + m_padding = m_hotbar_imagesize / 12; + + for (auto &hbar_color : hbar_colors) + hbar_color = video::SColor(255, 255, 255, 255); + + tsrc = client->getTextureSource(); + + v3f crosshair_color = g_settings->getV3F("crosshair_color"); + u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255); + u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255); + u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255); + u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255); + crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b); + + v3f selectionbox_color = g_settings->getV3F("selectionbox_color"); + u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255); + u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255); + u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255); + selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b); + + use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png"); + + m_selection_boxes.clear(); + m_halo_boxes.clear(); + + std::string mode_setting = g_settings->get("node_highlighting"); + + if (mode_setting == "halo") { + m_mode = HIGHLIGHT_HALO; + } else if (mode_setting == "none") { + m_mode = HIGHLIGHT_NONE; + } else { + m_mode = HIGHLIGHT_BOX; + } + + m_selection_material.Lighting = false; + + if (g_settings->getBool("enable_shaders")) { + IShaderSource *shdrsrc = client->getShaderSource(); + u16 shader_id = shdrsrc->getShader( + m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1); + m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; + } else { + m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + } + + if (m_mode == HIGHLIGHT_BOX) { + m_selection_material.Thickness = + rangelim(g_settings->getS16("selectionbox_width"), 1, 5); + } else if (m_mode == HIGHLIGHT_HALO) { + m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png")); + m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true); + } else { + m_selection_material.MaterialType = video::EMT_SOLID; + } +} + +Hud::~Hud() +{ + if (m_selection_mesh) + m_selection_mesh->drop(); +} + +void Hud::drawItem(const ItemStack &item, const core::rect& rect, + bool selected) +{ + if (selected) { + /* draw hihlighting around selected item */ + if (use_hotbar_selected_image) { + core::rect imgrect2 = rect; + imgrect2.UpperLeftCorner.X -= (m_padding*2); + imgrect2.UpperLeftCorner.Y -= (m_padding*2); + imgrect2.LowerRightCorner.X += (m_padding*2); + imgrect2.LowerRightCorner.Y += (m_padding*2); + video::ITexture *texture = tsrc->getTexture(hotbar_selected_image); + core::dimension2di imgsize(texture->getOriginalSize()); + draw2DImageFilterScaled(driver, texture, imgrect2, + core::rect(core::position2d(0,0), imgsize), + NULL, hbar_colors, true); + } else { + video::SColor c_outside(255,255,0,0); + //video::SColor c_outside(255,0,0,0); + //video::SColor c_inside(255,192,192,192); + s32 x1 = rect.UpperLeftCorner.X; + s32 y1 = rect.UpperLeftCorner.Y; + s32 x2 = rect.LowerRightCorner.X; + s32 y2 = rect.LowerRightCorner.Y; + // Black base borders + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x1 - m_padding, y1 - m_padding), + v2s32(x2 + m_padding, y1) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x1 - m_padding, y2), + v2s32(x2 + m_padding, y2 + m_padding) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x1 - m_padding, y1), + v2s32(x1, y2) + ), NULL); + driver->draw2DRectangle(c_outside, + core::rect( + v2s32(x2, y1), + v2s32(x2 + m_padding, y2) + ), NULL); + /*// Light inside borders + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y1 - padding/2), + v2s32(x2 + padding/2, y1) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y2), + v2s32(x2 + padding/2, y2 + padding/2) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x1 - padding/2, y1), + v2s32(x1, y2) + ), NULL); + driver->draw2DRectangle(c_inside, + core::rect( + v2s32(x2, y1), + v2s32(x2 + padding/2, y2) + ), NULL); + */ + } + } + + video::SColor bgcolor2(128, 0, 0, 0); + if (!use_hotbar_image) + driver->draw2DRectangle(bgcolor2, rect, NULL); + drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL, + client, selected ? IT_ROT_SELECTED : IT_ROT_NONE); +} + +//NOTE: selectitem = 0 -> no selected; selectitem 1-based +void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, + s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction) +{ +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui && inv_offset == 0) + g_touchscreengui->resetHud(); +#endif + + s32 height = m_hotbar_imagesize + m_padding * 2; + s32 width = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2); + + if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) { + s32 tmp = height; + height = width; + width = tmp; + } + + // Position of upper left corner of bar + v2s32 pos = screen_offset; + pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity(); + pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity(); + pos += upperleftpos; + + // Store hotbar_image in member variable, used by drawItem() + if (hotbar_image != player->hotbar_image) { + hotbar_image = player->hotbar_image; + if (!hotbar_image.empty()) + use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image); + else + use_hotbar_image = false; + } + + // Store hotbar_selected_image in member variable, used by drawItem() + if (hotbar_selected_image != player->hotbar_selected_image) { + hotbar_selected_image = player->hotbar_selected_image; + if (!hotbar_selected_image.empty()) + use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image); + else + use_hotbar_selected_image = false; + } + + // draw customized item background + if (use_hotbar_image) { + core::rect imgrect2(-m_padding/2, -m_padding/2, + width+m_padding/2, height+m_padding/2); + core::rect rect2 = imgrect2 + pos; + video::ITexture *texture = tsrc->getTexture(hotbar_image); + core::dimension2di imgsize(texture->getOriginalSize()); + draw2DImageFilterScaled(driver, texture, rect2, + core::rect(core::position2d(0,0), imgsize), + NULL, hbar_colors, true); + } + + // Draw items + core::rect imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize); + for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) { + s32 fullimglen = m_hotbar_imagesize + m_padding * 2; + + v2s32 steppos; + switch (direction) { + case HUD_DIR_RIGHT_LEFT: + steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding); + break; + case HUD_DIR_TOP_BOTTOM: + steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen); + break; + case HUD_DIR_BOTTOM_TOP: + steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen)); + break; + default: + steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding); + break; + } + + drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem); + +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui) + g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos)); +#endif + } +} + + +void Hud::drawLuaElements(const v3s16 &camera_offset) +{ + u32 text_height = g_fontengine->getTextHeight(); + irr::gui::IGUIFont* font = g_fontengine->getFont(); + for (size_t i = 0; i != player->maxHudId(); i++) { + HudElement *e = player->getHud(i); + if (!e) + continue; + + v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5), + floor(e->pos.Y * (float) m_screensize.Y + 0.5)); + switch (e->type) { + case HUD_ELEM_IMAGE: { + video::ITexture *texture = tsrc->getTexture(e->text); + if (!texture) + continue; + + const video::SColor color(255, 255, 255, 255); + const video::SColor colors[] = {color, color, color, color}; + core::dimension2di imgsize(texture->getOriginalSize()); + v2s32 dstsize(imgsize.Width * e->scale.X, + imgsize.Height * e->scale.Y); + if (e->scale.X < 0) + dstsize.X = m_screensize.X * (e->scale.X * -0.01); + if (e->scale.Y < 0) + dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01); + v2s32 offset((e->align.X - 1.0) * dstsize.X / 2, + (e->align.Y - 1.0) * dstsize.Y / 2); + core::rect rect(0, 0, dstsize.X, dstsize.Y); + rect += pos + offset + v2s32(e->offset.X, e->offset.Y); + draw2DImageFilterScaled(driver, texture, rect, + core::rect(core::position2d(0,0), imgsize), + NULL, colors, true); + break; } + case HUD_ELEM_TEXT: { + video::SColor color(255, (e->number >> 16) & 0xFF, + (e->number >> 8) & 0xFF, + (e->number >> 0) & 0xFF); + core::rect size(0, 0, e->scale.X, text_height * e->scale.Y); + std::wstring text = unescape_translate(utf8_to_wide(e->text)); + core::dimension2d textsize = font->getDimension(text.c_str()); + v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2), + (e->align.Y - 1.0) * (textsize.Height / 2)); + v2s32 offs(e->offset.X, e->offset.Y); + font->draw(text.c_str(), size + pos + offset + offs, color); + break; } + case HUD_ELEM_STATBAR: { + v2s32 offs(e->offset.X, e->offset.Y); + drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size); + break; } + case HUD_ELEM_INVENTORY: { + InventoryList *inv = inventory->getList(e->text); + drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0, + inv, e->item, e->dir); + break; } + case HUD_ELEM_WAYPOINT: { + v3f p_pos = player->getPosition() / BS; + v3f w_pos = e->world_pos * BS; + float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10; + scene::ICameraSceneNode* camera = + RenderingEngine::get_scene_manager()->getActiveCamera(); + w_pos -= intToFloat(camera_offset, BS); + core::matrix4 trans = camera->getProjectionMatrix(); + trans *= camera->getViewMatrix(); + f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f }; + trans.multiplyWith1x4Matrix(transformed_pos); + if (transformed_pos[3] < 0) + break; + f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f : + core::reciprocal(transformed_pos[3]); + pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5); + pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5); + video::SColor color(255, (e->number >> 16) & 0xFF, + (e->number >> 8) & 0xFF, + (e->number >> 0) & 0xFF); + core::rect size(0, 0, 200, 2 * text_height); + std::wstring text = unescape_translate(utf8_to_wide(e->name)); + font->draw(text.c_str(), size + pos, color); + std::ostringstream os; + os << distance << e->text; + text = unescape_translate(utf8_to_wide(os.str())); + pos.Y += text_height; + font->draw(text.c_str(), size + pos, color); + break; } + default: + infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << + " of hud element ID " << i << " due to unrecognized type" << std::endl; + } + } +} + + +void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, + s32 count, v2s32 offset, v2s32 size) +{ + const video::SColor color(255, 255, 255, 255); + const video::SColor colors[] = {color, color, color, color}; + + video::ITexture *stat_texture = tsrc->getTexture(texture); + if (!stat_texture) + return; + + core::dimension2di srcd(stat_texture->getOriginalSize()); + core::dimension2di dstd; + if (size == v2s32()) { + dstd = srcd; + } else { + float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity(); + dstd.Height = size.Y * size_factor; + dstd.Width = size.X * size_factor; + offset.X *= size_factor; + offset.Y *= size_factor; + } + + v2s32 p = pos; + if (corner & HUD_CORNER_LOWER) + p -= dstd.Height; + + p += offset; + + v2s32 steppos; + core::rect srchalfrect, dsthalfrect; + switch (drawdir) { + case HUD_DIR_RIGHT_LEFT: + steppos = v2s32(-1, 0); + srchalfrect = core::rect(srcd.Width / 2, 0, srcd.Width, srcd.Height); + dsthalfrect = core::rect(dstd.Width / 2, 0, dstd.Width, dstd.Height); + break; + case HUD_DIR_TOP_BOTTOM: + steppos = v2s32(0, 1); + srchalfrect = core::rect(0, 0, srcd.Width, srcd.Height / 2); + dsthalfrect = core::rect(0, 0, dstd.Width, dstd.Height / 2); + break; + case HUD_DIR_BOTTOM_TOP: + steppos = v2s32(0, -1); + srchalfrect = core::rect(0, srcd.Height / 2, srcd.Width, srcd.Height); + dsthalfrect = core::rect(0, dstd.Height / 2, dstd.Width, dstd.Height); + break; + default: + steppos = v2s32(1, 0); + srchalfrect = core::rect(0, 0, srcd.Width / 2, srcd.Height); + dsthalfrect = core::rect(0, 0, dstd.Width / 2, dstd.Height); + } + steppos.X *= dstd.Width; + steppos.Y *= dstd.Height; + + for (s32 i = 0; i < count / 2; i++) { + core::rect srcrect(0, 0, srcd.Width, srcd.Height); + core::rect dstrect(0,0, dstd.Width, dstd.Height); + + dstrect += p; + draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true); + p += steppos; + } + + if (count % 2 == 1) { + dsthalfrect += p; + draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true); + } +} + + +void Hud::drawHotbar(u16 playeritem) { + + v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y); + + InventoryList *mainlist = inventory->getList("main"); + if (mainlist == NULL) { + //silently ignore this we may not be initialized completely + return; + } + + s32 hotbar_itemcount = player->hud_hotbar_itemcount; + s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); + v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); + + const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + if ( (float) width / (float) window_size.X <= + g_settings->getFloat("hud_hotbar_max_width")) { + if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { + drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0); + } + } else { + pos.X += width/4; + + v2s32 secondpos = pos; + pos = pos - v2s32(0, m_hotbar_imagesize + m_padding); + + if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { + drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0, + mainlist, playeritem + 1, 0); + drawItems(secondpos, v2s32(0, 0), hotbar_itemcount, + hotbar_itemcount / 2, mainlist, playeritem + 1, 0); + } + } + + //////////////////////////// compatibility code to be removed ////////////// + // this is ugly as hell but there's no other way to keep compatibility to + // old servers + if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) { + drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5), + floor(1 * (float) m_screensize.Y + 0.5)), + HUD_CORNER_UPPER, 0, "heart.png", + player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24)); + } + + if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) && + (player->getBreath() < 11)) { + drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5), + floor(1 * (float) m_screensize.Y + 0.5)), + HUD_CORNER_UPPER, 0, "bubble.png", + player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24)); + } + //////////////////////////////////////////////////////////////////////////// +} + + +void Hud::drawCrosshair() +{ + if (use_crosshair_image) { + video::ITexture *crosshair = tsrc->getTexture("crosshair.png"); + v2u32 size = crosshair->getOriginalSize(); + v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2), + m_displaycenter.Y - (size.Y / 2)); + driver->draw2DImage(crosshair, lsize, + core::rect(0, 0, size.X, size.Y), + 0, crosshair_argb, true); + } else { + driver->draw2DLine(m_displaycenter - v2s32(10, 0), + m_displaycenter + v2s32(10, 0), crosshair_argb); + driver->draw2DLine(m_displaycenter - v2s32(0, 10), + m_displaycenter + v2s32(0, 10), crosshair_argb); + } +} + +void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset) +{ + m_camera_offset = camera_offset; + m_selection_pos = pos; + m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS); +} + +void Hud::drawSelectionMesh() +{ + if (m_mode == HIGHLIGHT_BOX) { + // Draw 3D selection boxes + video::SMaterial oldmaterial = driver->getMaterial2D(); + driver->setMaterial(m_selection_material); + for (std::vector::const_iterator + i = m_selection_boxes.begin(); + i != m_selection_boxes.end(); ++i) { + aabb3f box = aabb3f( + i->MinEdge + m_selection_pos_with_offset, + i->MaxEdge + m_selection_pos_with_offset); + + u32 r = (selectionbox_argb.getRed() * + m_selection_mesh_color.getRed() / 255); + u32 g = (selectionbox_argb.getGreen() * + m_selection_mesh_color.getGreen() / 255); + u32 b = (selectionbox_argb.getBlue() * + m_selection_mesh_color.getBlue() / 255); + driver->draw3DBox(box, video::SColor(255, r, g, b)); + } + driver->setMaterial(oldmaterial); + } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) { + // Draw selection mesh + video::SMaterial oldmaterial = driver->getMaterial2D(); + driver->setMaterial(m_selection_material); + setMeshColor(m_selection_mesh, m_selection_mesh_color); + video::SColor face_color(0, + MYMIN(255, m_selection_mesh_color.getRed() * 1.5), + MYMIN(255, m_selection_mesh_color.getGreen() * 1.5), + MYMIN(255, m_selection_mesh_color.getBlue() * 1.5)); + setMeshColorByNormal(m_selection_mesh, m_selected_face_normal, + face_color); + scene::IMesh* mesh = cloneMesh(m_selection_mesh); + translateMesh(mesh, m_selection_pos_with_offset); + u32 mc = m_selection_mesh->getMeshBufferCount(); + for (u32 i = 0; i < mc; i++) { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); + driver->drawMeshBuffer(buf); + } + mesh->drop(); + driver->setMaterial(oldmaterial); + } +} + +void Hud::updateSelectionMesh(const v3s16 &camera_offset) +{ + m_camera_offset = camera_offset; + if (m_mode != HIGHLIGHT_HALO) + return; + + if (m_selection_mesh) { + m_selection_mesh->drop(); + m_selection_mesh = NULL; + } + + if (m_selection_boxes.empty()) { + // No pointed object + return; + } + + // New pointed object, create new mesh. + + // Texture UV coordinates for selection boxes + static f32 texture_uv[24] = { + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1, + 0,0,1,1 + }; + + // Use single halo box instead of multiple overlapping boxes. + // Temporary solution - problem can be solved with multiple + // rendering targets, or some method to remove inner surfaces. + // Thats because of halo transparency. + + aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0); + m_halo_boxes.clear(); + + for (const auto &selection_box : m_selection_boxes) { + halo_box.addInternalBox(selection_box); + } + + m_halo_boxes.push_back(halo_box); + m_selection_mesh = convertNodeboxesToMesh( + m_halo_boxes, texture_uv, 0.5); +} + +void Hud::resizeHotbar() { + const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + + if (m_screensize != window_size) { + m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * + RenderingEngine::getDisplayDensity() + 0.5); + m_hotbar_imagesize *= m_hud_scaling; + m_padding = m_hotbar_imagesize / 12; + m_screensize = window_size; + m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2); + } +} + +struct MeshTimeInfo { + u64 time; + scene::IMesh *mesh; +}; + +void drawItemStack(video::IVideoDriver *driver, + gui::IGUIFont *font, + const ItemStack &item, + const core::rect &rect, + const core::rect *clip, + Client *client, + ItemRotationKind rotation_kind) +{ + static MeshTimeInfo rotation_time_infos[IT_ROT_NONE]; + static thread_local bool enable_animations = + g_settings->getBool("inventory_items_animations"); + + if (item.empty()) { + if (rotation_kind < IT_ROT_NONE) { + rotation_time_infos[rotation_kind].mesh = NULL; + } + return; + } + + const ItemDefinition &def = item.getDefinition(client->idef()); + ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); + + if (imesh && imesh->mesh) { + scene::IMesh *mesh = imesh->mesh; + driver->clearZBuffer(); + s32 delta = 0; + if (rotation_kind < IT_ROT_NONE) { + MeshTimeInfo &ti = rotation_time_infos[rotation_kind]; + if (mesh != ti.mesh) { + ti.mesh = mesh; + ti.time = porting::getTimeMs(); + } else { + delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000; + } + } + core::rect oldViewPort = driver->getViewPort(); + core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); + core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); + core::matrix4 ProjMatrix; + ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100); + driver->setTransform(video::ETS_PROJECTION, ProjMatrix); + driver->setTransform(video::ETS_VIEW, ProjMatrix); + core::matrix4 matrix; + matrix.makeIdentity(); + + if (enable_animations) { + float timer_f = (float) delta / 5000.0; + matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0)); + } + + driver->setTransform(video::ETS_WORLD, matrix); + driver->setViewPort(rect); + + video::SColor basecolor = + client->idef()->getItemstackColor(item, client); + + u32 mc = mesh->getMeshBufferCount(); + for (u32 j = 0; j < mc; ++j) { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); + // we can modify vertices relatively fast, + // because these meshes are not buffered. + assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER); + video::SColor c = basecolor; + if (imesh->buffer_colors.size() > j) { + ItemPartColor *p = &imesh->buffer_colors[j]; + if (p->override_base) + c = p->color; + } + if (imesh->needs_shading) + colorizeMeshBuffer(buf, &c); + else + setMeshBufferColor(buf, c); + video::SMaterial &material = buf->getMaterial(); + material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + material.Lighting = false; + driver->setMaterial(material); + driver->drawMeshBuffer(buf); + } + + driver->setTransform(video::ETS_VIEW, oldViewMat); + driver->setTransform(video::ETS_PROJECTION, oldProjMat); + driver->setViewPort(oldViewPort); + } + + if(def.type == ITEM_TOOL && item.wear != 0) + { + // Draw a progressbar + float barheight = rect.getHeight()/16; + float barpad_x = rect.getWidth()/16; + float barpad_y = rect.getHeight()/16; + core::rect progressrect( + rect.UpperLeftCorner.X + barpad_x, + rect.LowerRightCorner.Y - barpad_y - barheight, + rect.LowerRightCorner.X - barpad_x, + rect.LowerRightCorner.Y - barpad_y); + + // Shrink progressrect by amount of tool damage + float wear = item.wear / 65535.0; + int progressmid = + wear * progressrect.UpperLeftCorner.X + + (1-wear) * progressrect.LowerRightCorner.X; + + // Compute progressbar color + // wear = 0.0: green + // wear = 0.5: yellow + // wear = 1.0: red + video::SColor color(255,255,255,255); + int wear_i = MYMIN(floor(wear * 600), 511); + wear_i = MYMIN(wear_i + 10, 511); + if(wear_i <= 255) + color.set(255, wear_i, 255, 0); + else + color.set(255, 255, 511-wear_i, 0); + + core::rect progressrect2 = progressrect; + progressrect2.LowerRightCorner.X = progressmid; + driver->draw2DRectangle(color, progressrect2, clip); + + color = video::SColor(255,0,0,0); + progressrect2 = progressrect; + progressrect2.UpperLeftCorner.X = progressmid; + driver->draw2DRectangle(color, progressrect2, clip); + } + + if(font != NULL && item.count >= 2) + { + // Get the item count as a string + std::string text = itos(item.count); + v2u32 dim = font->getDimension(utf8_to_wide(text).c_str()); + v2s32 sdim(dim.X,dim.Y); + + core::rect rect2( + /*rect.UpperLeftCorner, + core::dimension2d(rect.getWidth(), 15)*/ + rect.LowerRightCorner - sdim, + sdim + ); + + video::SColor bgcolor(128,0,0,0); + driver->draw2DRectangle(bgcolor, rect2, clip); + + video::SColor color(255,255,255,255); + font->draw(text.c_str(), rect2, color, false, false, clip); + } +} diff --git a/src/client/hud.h b/src/client/hud.h new file mode 100644 index 000000000..e9bcdf4e2 --- /dev/null +++ b/src/client/hud.h @@ -0,0 +1,136 @@ +/* +Minetest +Copyright (C) 2010-2013 kwolekr, Ryan Kwolek +Copyright (C) 2017 red-001 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef CLIENT_HUD_HEADER +#define CLIENT_HUD_HEADER + +#include +#include +#include "irr_aabb3d.h" +#include "../hud.h" + +class Client; +class ITextureSource; +class Inventory; +class InventoryList; +class LocalPlayer; +struct ItemStack; + +class Hud +{ +public: + video::IVideoDriver *driver; + scene::ISceneManager *smgr; + gui::IGUIEnvironment *guienv; + Client *client; + LocalPlayer *player; + Inventory *inventory; + ITextureSource *tsrc; + + video::SColor crosshair_argb; + video::SColor selectionbox_argb; + bool use_crosshair_image = false; + std::string hotbar_image = ""; + bool use_hotbar_image = false; + std::string hotbar_selected_image = ""; + bool use_hotbar_selected_image = false; + + Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, + Inventory *inventory); + ~Hud(); + + void drawHotbar(u16 playeritem); + void resizeHotbar(); + void drawCrosshair(); + void drawSelectionMesh(); + void updateSelectionMesh(const v3s16 &camera_offset); + + std::vector *getSelectionBoxes() { return &m_selection_boxes; } + + void setSelectionPos(const v3f &pos, const v3s16 &camera_offset); + + v3f getSelectionPos() const { return m_selection_pos; } + + void setSelectionMeshColor(const video::SColor &color) + { + m_selection_mesh_color = color; + } + + void setSelectedFaceNormal(const v3f &face_normal) + { + m_selected_face_normal = face_normal; + } + + void drawLuaElements(const v3s16 &camera_offset); + +private: + void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, + s32 count, v2s32 offset, v2s32 size = v2s32()); + + void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, + s32 inv_offset, InventoryList *mainlist, u16 selectitem, + u16 direction); + + void drawItem(const ItemStack &item, const core::rect &rect, bool selected); + + float m_hud_scaling; // cached minetest setting + v3s16 m_camera_offset; + v2u32 m_screensize; + v2s32 m_displaycenter; + s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar() + s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar() + video::SColor hbar_colors[4]; + + std::vector m_selection_boxes; + std::vector m_halo_boxes; + v3f m_selection_pos; + v3f m_selection_pos_with_offset; + + scene::IMesh *m_selection_mesh = nullptr; + video::SColor m_selection_mesh_color; + v3f m_selected_face_normal; + + video::SMaterial m_selection_material; + + enum + { + HIGHLIGHT_BOX, + HIGHLIGHT_HALO, + HIGHLIGHT_NONE + } m_mode; +}; + +enum ItemRotationKind +{ + IT_ROT_SELECTED, + IT_ROT_HOVERED, + IT_ROT_DRAGGED, + IT_ROT_NONE, // Must be last, also serves as number +}; + +void drawItemStack(video::IVideoDriver *driver, + gui::IGUIFont *font, + const ItemStack &item, + const core::rect &rect, + const core::rect *clip, + Client *client, + ItemRotationKind rotation_kind); + +#endif diff --git a/src/client/render/sidebyside.cpp b/src/client/render/sidebyside.cpp index d2c171794..b63e49dea 100644 --- a/src/client/render/sidebyside.cpp +++ b/src/client/render/sidebyside.cpp @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "sidebyside.h" #include -#include "hud.h" +#include "client/hud.h" RenderingCoreSideBySide::RenderingCoreSideBySide( IrrlichtDevice *_device, Client *_client, Hud *_hud, bool _horizontal) diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 3c48c28a8..94c9c5ef2 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -25,8 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clouds.h" #include "util/numeric.h" #include "guiscalingfilter.h" -#include "hud.h" #include "localplayer.h" +#include "client/hud.h" #include "camera.h" #include "minimap.h" #include "clientmap.h" diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 6ca4a2e16..a59143f77 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -39,7 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/renderingengine.h" #include "log.h" #include "client/tile.h" // ITextureSource -#include "hud.h" // drawItemStack +#include "client/hud.h" // drawItemStack #include "filesys.h" #include "gettime.h" #include "gettext.h" diff --git a/src/hud.cpp b/src/hud.cpp index ecd2a521d..0d2d092a7 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -1,775 +1,39 @@ -/* -Minetest -Copyright (C) 2010-2013 celeron55, Perttu Ahola -Copyright (C) 2010-2013 blue42u, Jonathon Anderson -Copyright (C) 2010-2013 kwolekr, Ryan Kwolek - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 2.1 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License along -with this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -*/ - #include "hud.h" -#include "settings.h" -#include "util/numeric.h" -#include "log.h" -#include "client.h" -#include "inventory.h" -#include "shader.h" -#include "client/tile.h" -#include "localplayer.h" -#include "camera.h" -#include "porting.h" -#include "fontengine.h" -#include "guiscalingfilter.h" -#include "mesh.h" -#include "wieldmesh.h" -#include "client/renderingengine.h" -#ifdef HAVE_TOUCHSCREENGUI -#include "gui/touchscreengui.h" -#endif -Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, - Inventory *inventory) +const struct EnumString es_HudElementType[] = { - driver = RenderingEngine::get_video_driver(); - this->guienv = guienv; - this->client = client; - this->player = player; - this->inventory = inventory; - - m_hud_scaling = g_settings->getFloat("hud_scaling"); - m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * - RenderingEngine::getDisplayDensity() + 0.5f); - m_hotbar_imagesize *= m_hud_scaling; - m_padding = m_hotbar_imagesize / 12; - - for (auto &hbar_color : hbar_colors) - hbar_color = video::SColor(255, 255, 255, 255); - - tsrc = client->getTextureSource(); - - v3f crosshair_color = g_settings->getV3F("crosshair_color"); - u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255); - u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255); - u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255); - u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255); - crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b); - - v3f selectionbox_color = g_settings->getV3F("selectionbox_color"); - u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255); - u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255); - u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255); - selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b); - - use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png"); - - m_selection_boxes.clear(); - m_halo_boxes.clear(); - - std::string mode_setting = g_settings->get("node_highlighting"); - - if (mode_setting == "halo") { - m_mode = HIGHLIGHT_HALO; - } else if (mode_setting == "none") { - m_mode = HIGHLIGHT_NONE; - } else { - m_mode = HIGHLIGHT_BOX; - } - - m_selection_material.Lighting = false; - - if (g_settings->getBool("enable_shaders")) { - IShaderSource *shdrsrc = client->getShaderSource(); - u16 shader_id = shdrsrc->getShader( - m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1); - m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; - } else { - m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - } - - if (m_mode == HIGHLIGHT_BOX) { - m_selection_material.Thickness = - rangelim(g_settings->getS16("selectionbox_width"), 1, 5); - } else if (m_mode == HIGHLIGHT_HALO) { - m_selection_material.setTexture(0, tsrc->getTextureForMesh("halo.png")); - m_selection_material.setFlag(video::EMF_BACK_FACE_CULLING, true); - } else { - m_selection_material.MaterialType = video::EMT_SOLID; - } -} - -Hud::~Hud() -{ - if (m_selection_mesh) - m_selection_mesh->drop(); -} - -void Hud::drawItem(const ItemStack &item, const core::rect& rect, - bool selected) -{ - if (selected) { - /* draw hihlighting around selected item */ - if (use_hotbar_selected_image) { - core::rect imgrect2 = rect; - imgrect2.UpperLeftCorner.X -= (m_padding*2); - imgrect2.UpperLeftCorner.Y -= (m_padding*2); - imgrect2.LowerRightCorner.X += (m_padding*2); - imgrect2.LowerRightCorner.Y += (m_padding*2); - video::ITexture *texture = tsrc->getTexture(hotbar_selected_image); - core::dimension2di imgsize(texture->getOriginalSize()); - draw2DImageFilterScaled(driver, texture, imgrect2, - core::rect(core::position2d(0,0), imgsize), - NULL, hbar_colors, true); - } else { - video::SColor c_outside(255,255,0,0); - //video::SColor c_outside(255,0,0,0); - //video::SColor c_inside(255,192,192,192); - s32 x1 = rect.UpperLeftCorner.X; - s32 y1 = rect.UpperLeftCorner.Y; - s32 x2 = rect.LowerRightCorner.X; - s32 y2 = rect.LowerRightCorner.Y; - // Black base borders - driver->draw2DRectangle(c_outside, - core::rect( - v2s32(x1 - m_padding, y1 - m_padding), - v2s32(x2 + m_padding, y1) - ), NULL); - driver->draw2DRectangle(c_outside, - core::rect( - v2s32(x1 - m_padding, y2), - v2s32(x2 + m_padding, y2 + m_padding) - ), NULL); - driver->draw2DRectangle(c_outside, - core::rect( - v2s32(x1 - m_padding, y1), - v2s32(x1, y2) - ), NULL); - driver->draw2DRectangle(c_outside, - core::rect( - v2s32(x2, y1), - v2s32(x2 + m_padding, y2) - ), NULL); - /*// Light inside borders - driver->draw2DRectangle(c_inside, - core::rect( - v2s32(x1 - padding/2, y1 - padding/2), - v2s32(x2 + padding/2, y1) - ), NULL); - driver->draw2DRectangle(c_inside, - core::rect( - v2s32(x1 - padding/2, y2), - v2s32(x2 + padding/2, y2 + padding/2) - ), NULL); - driver->draw2DRectangle(c_inside, - core::rect( - v2s32(x1 - padding/2, y1), - v2s32(x1, y2) - ), NULL); - driver->draw2DRectangle(c_inside, - core::rect( - v2s32(x2, y1), - v2s32(x2 + padding/2, y2) - ), NULL); - */ - } - } - - video::SColor bgcolor2(128, 0, 0, 0); - if (!use_hotbar_image) - driver->draw2DRectangle(bgcolor2, rect, NULL); - drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL, - client, selected ? IT_ROT_SELECTED : IT_ROT_NONE); -} - -//NOTE: selectitem = 0 -> no selected; selectitem 1-based -void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, - s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction) -{ -#ifdef HAVE_TOUCHSCREENGUI - if (g_touchscreengui && inv_offset == 0) - g_touchscreengui->resetHud(); -#endif - - s32 height = m_hotbar_imagesize + m_padding * 2; - s32 width = (itemcount - inv_offset) * (m_hotbar_imagesize + m_padding * 2); - - if (direction == HUD_DIR_TOP_BOTTOM || direction == HUD_DIR_BOTTOM_TOP) { - s32 tmp = height; - height = width; - width = tmp; - } - - // Position of upper left corner of bar - v2s32 pos = screen_offset; - pos.X *= m_hud_scaling * RenderingEngine::getDisplayDensity(); - pos.Y *= m_hud_scaling * RenderingEngine::getDisplayDensity(); - pos += upperleftpos; - - // Store hotbar_image in member variable, used by drawItem() - if (hotbar_image != player->hotbar_image) { - hotbar_image = player->hotbar_image; - if (!hotbar_image.empty()) - use_hotbar_image = tsrc->isKnownSourceImage(hotbar_image); - else - use_hotbar_image = false; - } - - // Store hotbar_selected_image in member variable, used by drawItem() - if (hotbar_selected_image != player->hotbar_selected_image) { - hotbar_selected_image = player->hotbar_selected_image; - if (!hotbar_selected_image.empty()) - use_hotbar_selected_image = tsrc->isKnownSourceImage(hotbar_selected_image); - else - use_hotbar_selected_image = false; - } - - // draw customized item background - if (use_hotbar_image) { - core::rect imgrect2(-m_padding/2, -m_padding/2, - width+m_padding/2, height+m_padding/2); - core::rect rect2 = imgrect2 + pos; - video::ITexture *texture = tsrc->getTexture(hotbar_image); - core::dimension2di imgsize(texture->getOriginalSize()); - draw2DImageFilterScaled(driver, texture, rect2, - core::rect(core::position2d(0,0), imgsize), - NULL, hbar_colors, true); - } - - // Draw items - core::rect imgrect(0, 0, m_hotbar_imagesize, m_hotbar_imagesize); - for (s32 i = inv_offset; i < itemcount && (size_t)i < mainlist->getSize(); i++) { - s32 fullimglen = m_hotbar_imagesize + m_padding * 2; - - v2s32 steppos; - switch (direction) { - case HUD_DIR_RIGHT_LEFT: - steppos = v2s32(-(m_padding + (i - inv_offset) * fullimglen), m_padding); - break; - case HUD_DIR_TOP_BOTTOM: - steppos = v2s32(m_padding, m_padding + (i - inv_offset) * fullimglen); - break; - case HUD_DIR_BOTTOM_TOP: - steppos = v2s32(m_padding, -(m_padding + (i - inv_offset) * fullimglen)); - break; - default: - steppos = v2s32(m_padding + (i - inv_offset) * fullimglen, m_padding); - break; - } - - drawItem(mainlist->getItem(i), (imgrect + pos + steppos), (i + 1) == selectitem); - -#ifdef HAVE_TOUCHSCREENGUI - if (g_touchscreengui) - g_touchscreengui->registerHudItem(i, (imgrect + pos + steppos)); -#endif - } -} - - -void Hud::drawLuaElements(const v3s16 &camera_offset) -{ - u32 text_height = g_fontengine->getTextHeight(); - irr::gui::IGUIFont* font = g_fontengine->getFont(); - for (size_t i = 0; i != player->maxHudId(); i++) { - HudElement *e = player->getHud(i); - if (!e) - continue; - - v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5), - floor(e->pos.Y * (float) m_screensize.Y + 0.5)); - switch (e->type) { - case HUD_ELEM_IMAGE: { - video::ITexture *texture = tsrc->getTexture(e->text); - if (!texture) - continue; - - const video::SColor color(255, 255, 255, 255); - const video::SColor colors[] = {color, color, color, color}; - core::dimension2di imgsize(texture->getOriginalSize()); - v2s32 dstsize(imgsize.Width * e->scale.X, - imgsize.Height * e->scale.Y); - if (e->scale.X < 0) - dstsize.X = m_screensize.X * (e->scale.X * -0.01); - if (e->scale.Y < 0) - dstsize.Y = m_screensize.Y * (e->scale.Y * -0.01); - v2s32 offset((e->align.X - 1.0) * dstsize.X / 2, - (e->align.Y - 1.0) * dstsize.Y / 2); - core::rect rect(0, 0, dstsize.X, dstsize.Y); - rect += pos + offset + v2s32(e->offset.X, e->offset.Y); - draw2DImageFilterScaled(driver, texture, rect, - core::rect(core::position2d(0,0), imgsize), - NULL, colors, true); - break; } - case HUD_ELEM_TEXT: { - video::SColor color(255, (e->number >> 16) & 0xFF, - (e->number >> 8) & 0xFF, - (e->number >> 0) & 0xFF); - core::rect size(0, 0, e->scale.X, text_height * e->scale.Y); - std::wstring text = unescape_translate(utf8_to_wide(e->text)); - core::dimension2d textsize = font->getDimension(text.c_str()); - v2s32 offset((e->align.X - 1.0) * (textsize.Width / 2), - (e->align.Y - 1.0) * (textsize.Height / 2)); - v2s32 offs(e->offset.X, e->offset.Y); - font->draw(text.c_str(), size + pos + offset + offs, color); - break; } - case HUD_ELEM_STATBAR: { - v2s32 offs(e->offset.X, e->offset.Y); - drawStatbar(pos, HUD_CORNER_UPPER, e->dir, e->text, e->number, offs, e->size); - break; } - case HUD_ELEM_INVENTORY: { - InventoryList *inv = inventory->getList(e->text); - drawItems(pos, v2s32(e->offset.X, e->offset.Y), e->number, 0, - inv, e->item, e->dir); - break; } - case HUD_ELEM_WAYPOINT: { - v3f p_pos = player->getPosition() / BS; - v3f w_pos = e->world_pos * BS; - float distance = floor(10 * p_pos.getDistanceFrom(e->world_pos)) / 10; - scene::ICameraSceneNode* camera = - RenderingEngine::get_scene_manager()->getActiveCamera(); - w_pos -= intToFloat(camera_offset, BS); - core::matrix4 trans = camera->getProjectionMatrix(); - trans *= camera->getViewMatrix(); - f32 transformed_pos[4] = { w_pos.X, w_pos.Y, w_pos.Z, 1.0f }; - trans.multiplyWith1x4Matrix(transformed_pos); - if (transformed_pos[3] < 0) - break; - f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f : - core::reciprocal(transformed_pos[3]); - pos.X = m_screensize.X * (0.5 * transformed_pos[0] * zDiv + 0.5); - pos.Y = m_screensize.Y * (0.5 - transformed_pos[1] * zDiv * 0.5); - video::SColor color(255, (e->number >> 16) & 0xFF, - (e->number >> 8) & 0xFF, - (e->number >> 0) & 0xFF); - core::rect size(0, 0, 200, 2 * text_height); - std::wstring text = unescape_translate(utf8_to_wide(e->name)); - font->draw(text.c_str(), size + pos, color); - std::ostringstream os; - os << distance << e->text; - text = unescape_translate(utf8_to_wide(os.str())); - pos.Y += text_height; - font->draw(text.c_str(), size + pos, color); - break; } - default: - infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << - " of hud element ID " << i << " due to unrecognized type" << std::endl; - } - } -} - - -void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, - s32 count, v2s32 offset, v2s32 size) -{ - const video::SColor color(255, 255, 255, 255); - const video::SColor colors[] = {color, color, color, color}; - - video::ITexture *stat_texture = tsrc->getTexture(texture); - if (!stat_texture) - return; - - core::dimension2di srcd(stat_texture->getOriginalSize()); - core::dimension2di dstd; - if (size == v2s32()) { - dstd = srcd; - } else { - float size_factor = m_hud_scaling * RenderingEngine::getDisplayDensity(); - dstd.Height = size.Y * size_factor; - dstd.Width = size.X * size_factor; - offset.X *= size_factor; - offset.Y *= size_factor; - } - - v2s32 p = pos; - if (corner & HUD_CORNER_LOWER) - p -= dstd.Height; - - p += offset; - - v2s32 steppos; - core::rect srchalfrect, dsthalfrect; - switch (drawdir) { - case HUD_DIR_RIGHT_LEFT: - steppos = v2s32(-1, 0); - srchalfrect = core::rect(srcd.Width / 2, 0, srcd.Width, srcd.Height); - dsthalfrect = core::rect(dstd.Width / 2, 0, dstd.Width, dstd.Height); - break; - case HUD_DIR_TOP_BOTTOM: - steppos = v2s32(0, 1); - srchalfrect = core::rect(0, 0, srcd.Width, srcd.Height / 2); - dsthalfrect = core::rect(0, 0, dstd.Width, dstd.Height / 2); - break; - case HUD_DIR_BOTTOM_TOP: - steppos = v2s32(0, -1); - srchalfrect = core::rect(0, srcd.Height / 2, srcd.Width, srcd.Height); - dsthalfrect = core::rect(0, dstd.Height / 2, dstd.Width, dstd.Height); - break; - default: - steppos = v2s32(1, 0); - srchalfrect = core::rect(0, 0, srcd.Width / 2, srcd.Height); - dsthalfrect = core::rect(0, 0, dstd.Width / 2, dstd.Height); - } - steppos.X *= dstd.Width; - steppos.Y *= dstd.Height; - - for (s32 i = 0; i < count / 2; i++) { - core::rect srcrect(0, 0, srcd.Width, srcd.Height); - core::rect dstrect(0,0, dstd.Width, dstd.Height); - - dstrect += p; - draw2DImageFilterScaled(driver, stat_texture, dstrect, srcrect, NULL, colors, true); - p += steppos; - } - - if (count % 2 == 1) { - dsthalfrect += p; - draw2DImageFilterScaled(driver, stat_texture, dsthalfrect, srchalfrect, NULL, colors, true); - } -} - - -void Hud::drawHotbar(u16 playeritem) { - - v2s32 centerlowerpos(m_displaycenter.X, m_screensize.Y); - - InventoryList *mainlist = inventory->getList("main"); - if (mainlist == NULL) { - //silently ignore this we may not be initialized completely - return; - } - - s32 hotbar_itemcount = player->hud_hotbar_itemcount; - s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); - v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); - - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); - if ( (float) width / (float) window_size.X <= - g_settings->getFloat("hud_hotbar_max_width")) { - if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { - drawItems(pos, v2s32(0, 0), hotbar_itemcount, 0, mainlist, playeritem + 1, 0); - } - } else { - pos.X += width/4; - - v2s32 secondpos = pos; - pos = pos - v2s32(0, m_hotbar_imagesize + m_padding); - - if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { - drawItems(pos, v2s32(0, 0), hotbar_itemcount / 2, 0, - mainlist, playeritem + 1, 0); - drawItems(secondpos, v2s32(0, 0), hotbar_itemcount, - hotbar_itemcount / 2, mainlist, playeritem + 1, 0); - } - } - - //////////////////////////// compatibility code to be removed ////////////// - // this is ugly as hell but there's no other way to keep compatibility to - // old servers - if ((player->hud_flags & HUD_FLAG_HEALTHBAR_VISIBLE)) { - drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5), - floor(1 * (float) m_screensize.Y + 0.5)), - HUD_CORNER_UPPER, 0, "heart.png", - player->hp, v2s32((-10*24)-25,-(48+24+10)), v2s32(24,24)); - } - - if ((player->hud_flags & HUD_FLAG_BREATHBAR_VISIBLE) && - (player->getBreath() < 11)) { - drawStatbar(v2s32(floor(0.5 * (float)m_screensize.X + 0.5), - floor(1 * (float) m_screensize.Y + 0.5)), - HUD_CORNER_UPPER, 0, "bubble.png", - player->getBreath(), v2s32(25,-(48+24+10)), v2s32(24,24)); - } - //////////////////////////////////////////////////////////////////////////// -} - - -void Hud::drawCrosshair() -{ - if (use_crosshair_image) { - video::ITexture *crosshair = tsrc->getTexture("crosshair.png"); - v2u32 size = crosshair->getOriginalSize(); - v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2), - m_displaycenter.Y - (size.Y / 2)); - driver->draw2DImage(crosshair, lsize, - core::rect(0, 0, size.X, size.Y), - 0, crosshair_argb, true); - } else { - driver->draw2DLine(m_displaycenter - v2s32(10, 0), - m_displaycenter + v2s32(10, 0), crosshair_argb); - driver->draw2DLine(m_displaycenter - v2s32(0, 10), - m_displaycenter + v2s32(0, 10), crosshair_argb); - } -} - -void Hud::setSelectionPos(const v3f &pos, const v3s16 &camera_offset) -{ - m_camera_offset = camera_offset; - m_selection_pos = pos; - m_selection_pos_with_offset = pos - intToFloat(camera_offset, BS); -} - -void Hud::drawSelectionMesh() -{ - if (m_mode == HIGHLIGHT_BOX) { - // Draw 3D selection boxes - video::SMaterial oldmaterial = driver->getMaterial2D(); - driver->setMaterial(m_selection_material); - for (std::vector::const_iterator - i = m_selection_boxes.begin(); - i != m_selection_boxes.end(); ++i) { - aabb3f box = aabb3f( - i->MinEdge + m_selection_pos_with_offset, - i->MaxEdge + m_selection_pos_with_offset); - - u32 r = (selectionbox_argb.getRed() * - m_selection_mesh_color.getRed() / 255); - u32 g = (selectionbox_argb.getGreen() * - m_selection_mesh_color.getGreen() / 255); - u32 b = (selectionbox_argb.getBlue() * - m_selection_mesh_color.getBlue() / 255); - driver->draw3DBox(box, video::SColor(255, r, g, b)); - } - driver->setMaterial(oldmaterial); - } else if (m_mode == HIGHLIGHT_HALO && m_selection_mesh) { - // Draw selection mesh - video::SMaterial oldmaterial = driver->getMaterial2D(); - driver->setMaterial(m_selection_material); - setMeshColor(m_selection_mesh, m_selection_mesh_color); - video::SColor face_color(0, - MYMIN(255, m_selection_mesh_color.getRed() * 1.5), - MYMIN(255, m_selection_mesh_color.getGreen() * 1.5), - MYMIN(255, m_selection_mesh_color.getBlue() * 1.5)); - setMeshColorByNormal(m_selection_mesh, m_selected_face_normal, - face_color); - scene::IMesh* mesh = cloneMesh(m_selection_mesh); - translateMesh(mesh, m_selection_pos_with_offset); - u32 mc = m_selection_mesh->getMeshBufferCount(); - for (u32 i = 0; i < mc; i++) { - scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); - driver->drawMeshBuffer(buf); - } - mesh->drop(); - driver->setMaterial(oldmaterial); - } -} - -void Hud::updateSelectionMesh(const v3s16 &camera_offset) -{ - m_camera_offset = camera_offset; - if (m_mode != HIGHLIGHT_HALO) - return; - - if (m_selection_mesh) { - m_selection_mesh->drop(); - m_selection_mesh = NULL; - } - - if (m_selection_boxes.empty()) { - // No pointed object - return; - } - - // New pointed object, create new mesh. - - // Texture UV coordinates for selection boxes - static f32 texture_uv[24] = { - 0,0,1,1, - 0,0,1,1, - 0,0,1,1, - 0,0,1,1, - 0,0,1,1, - 0,0,1,1 - }; - - // Use single halo box instead of multiple overlapping boxes. - // Temporary solution - problem can be solved with multiple - // rendering targets, or some method to remove inner surfaces. - // Thats because of halo transparency. - - aabb3f halo_box(100.0, 100.0, 100.0, -100.0, -100.0, -100.0); - m_halo_boxes.clear(); - - for (const auto &selection_box : m_selection_boxes) { - halo_box.addInternalBox(selection_box); - } - - m_halo_boxes.push_back(halo_box); - m_selection_mesh = convertNodeboxesToMesh( - m_halo_boxes, texture_uv, 0.5); -} - -void Hud::resizeHotbar() { - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); - - if (m_screensize != window_size) { - m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * - RenderingEngine::getDisplayDensity() + 0.5); - m_hotbar_imagesize *= m_hud_scaling; - m_padding = m_hotbar_imagesize / 12; - m_screensize = window_size; - m_displaycenter = v2s32(m_screensize.X/2,m_screensize.Y/2); - } -} - -struct MeshTimeInfo { - u64 time; - scene::IMesh *mesh; + {HUD_ELEM_IMAGE, "image"}, + {HUD_ELEM_TEXT, "text"}, + {HUD_ELEM_STATBAR, "statbar"}, + {HUD_ELEM_INVENTORY, "inventory"}, + {HUD_ELEM_WAYPOINT, "waypoint"}, + {0, NULL}, }; -void drawItemStack(video::IVideoDriver *driver, - gui::IGUIFont *font, - const ItemStack &item, - const core::rect &rect, - const core::rect *clip, - Client *client, - ItemRotationKind rotation_kind) +const struct EnumString es_HudElementStat[] = { - static MeshTimeInfo rotation_time_infos[IT_ROT_NONE]; - static thread_local bool enable_animations = - g_settings->getBool("inventory_items_animations"); + {HUD_STAT_POS, "position"}, + {HUD_STAT_POS, "pos"}, /* Deprecated, only for compatibility's sake */ + {HUD_STAT_NAME, "name"}, + {HUD_STAT_SCALE, "scale"}, + {HUD_STAT_TEXT, "text"}, + {HUD_STAT_NUMBER, "number"}, + {HUD_STAT_ITEM, "item"}, + {HUD_STAT_DIR, "direction"}, + {HUD_STAT_ALIGN, "alignment"}, + {HUD_STAT_OFFSET, "offset"}, + {HUD_STAT_WORLD_POS, "world_pos"}, + {0, NULL}, +}; - if (item.empty()) { - if (rotation_kind < IT_ROT_NONE) { - rotation_time_infos[rotation_kind].mesh = NULL; - } - return; - } - - const ItemDefinition &def = item.getDefinition(client->idef()); - ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); - - if (imesh && imesh->mesh) { - scene::IMesh *mesh = imesh->mesh; - driver->clearZBuffer(); - s32 delta = 0; - if (rotation_kind < IT_ROT_NONE) { - MeshTimeInfo &ti = rotation_time_infos[rotation_kind]; - if (mesh != ti.mesh) { - ti.mesh = mesh; - ti.time = porting::getTimeMs(); - } else { - delta = porting::getDeltaMs(ti.time, porting::getTimeMs()) % 100000; - } - } - core::rect oldViewPort = driver->getViewPort(); - core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION); - core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); - core::matrix4 ProjMatrix; - ProjMatrix.buildProjectionMatrixOrthoLH(2, 2, -1, 100); - driver->setTransform(video::ETS_PROJECTION, ProjMatrix); - driver->setTransform(video::ETS_VIEW, ProjMatrix); - core::matrix4 matrix; - matrix.makeIdentity(); - - if (enable_animations) { - float timer_f = (float) delta / 5000.0; - matrix.setRotationDegrees(core::vector3df(0, 360 * timer_f, 0)); - } - - driver->setTransform(video::ETS_WORLD, matrix); - driver->setViewPort(rect); - - video::SColor basecolor = - client->idef()->getItemstackColor(item, client); - - u32 mc = mesh->getMeshBufferCount(); - for (u32 j = 0; j < mc; ++j) { - scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); - // we can modify vertices relatively fast, - // because these meshes are not buffered. - assert(buf->getHardwareMappingHint_Vertex() == scene::EHM_NEVER); - video::SColor c = basecolor; - if (imesh->buffer_colors.size() > j) { - ItemPartColor *p = &imesh->buffer_colors[j]; - if (p->override_base) - c = p->color; - } - if (imesh->needs_shading) - colorizeMeshBuffer(buf, &c); - else - setMeshBufferColor(buf, c); - video::SMaterial &material = buf->getMaterial(); - material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - material.Lighting = false; - driver->setMaterial(material); - driver->drawMeshBuffer(buf); - } - - driver->setTransform(video::ETS_VIEW, oldViewMat); - driver->setTransform(video::ETS_PROJECTION, oldProjMat); - driver->setViewPort(oldViewPort); - } - - if(def.type == ITEM_TOOL && item.wear != 0) - { - // Draw a progressbar - float barheight = rect.getHeight()/16; - float barpad_x = rect.getWidth()/16; - float barpad_y = rect.getHeight()/16; - core::rect progressrect( - rect.UpperLeftCorner.X + barpad_x, - rect.LowerRightCorner.Y - barpad_y - barheight, - rect.LowerRightCorner.X - barpad_x, - rect.LowerRightCorner.Y - barpad_y); - - // Shrink progressrect by amount of tool damage - float wear = item.wear / 65535.0; - int progressmid = - wear * progressrect.UpperLeftCorner.X + - (1-wear) * progressrect.LowerRightCorner.X; - - // Compute progressbar color - // wear = 0.0: green - // wear = 0.5: yellow - // wear = 1.0: red - video::SColor color(255,255,255,255); - int wear_i = MYMIN(floor(wear * 600), 511); - wear_i = MYMIN(wear_i + 10, 511); - if(wear_i <= 255) - color.set(255, wear_i, 255, 0); - else - color.set(255, 255, 511-wear_i, 0); - - core::rect progressrect2 = progressrect; - progressrect2.LowerRightCorner.X = progressmid; - driver->draw2DRectangle(color, progressrect2, clip); - - color = video::SColor(255,0,0,0); - progressrect2 = progressrect; - progressrect2.UpperLeftCorner.X = progressmid; - driver->draw2DRectangle(color, progressrect2, clip); - } - - if(font != NULL && item.count >= 2) - { - // Get the item count as a string - std::string text = itos(item.count); - v2u32 dim = font->getDimension(utf8_to_wide(text).c_str()); - v2s32 sdim(dim.X,dim.Y); - - core::rect rect2( - /*rect.UpperLeftCorner, - core::dimension2d(rect.getWidth(), 15)*/ - rect.LowerRightCorner - sdim, - sdim - ); - - video::SColor bgcolor(128,0,0,0); - driver->draw2DRectangle(bgcolor, rect2, clip); - - video::SColor color(255,255,255,255); - font->draw(text.c_str(), rect2, color, false, false, clip); - } -} +const struct EnumString es_HudBuiltinElement[] = +{ + {HUD_FLAG_HOTBAR_VISIBLE, "hotbar"}, + {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, + {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, + {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, + {HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"}, + {HUD_FLAG_MINIMAP_VISIBLE, "minimap"}, + {0, NULL}, +}; diff --git a/src/hud.h b/src/hud.h index 3084478b1..699313980 100644 --- a/src/hud.h +++ b/src/hud.h @@ -1,6 +1,7 @@ /* Minetest Copyright (C) 2010-2013 kwolekr, Ryan Kwolek +Copyright (C) 2017 red-001 This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -17,10 +18,12 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#pragma once +#ifndef HUD_HEADER +#define HUD_HEADER #include "irrlichttypes_extrabloated.h" #include +#include "common/c_types.h" #define HUD_DIR_LEFT_RIGHT 0 #define HUD_DIR_RIGHT_LEFT 1 @@ -89,111 +92,8 @@ struct HudElement { v2s32 size; }; -#ifndef SERVER - -#include -#include -#include "irr_aabb3d.h" - -class Client; -class ITextureSource; -class Inventory; -class InventoryList; -class LocalPlayer; -struct ItemStack; - -class Hud { -public: - video::IVideoDriver *driver; - scene::ISceneManager* smgr; - gui::IGUIEnvironment *guienv; - Client *client; - LocalPlayer *player; - Inventory *inventory; - ITextureSource *tsrc; - - video::SColor crosshair_argb; - video::SColor selectionbox_argb; - bool use_crosshair_image = false; - std::string hotbar_image = ""; - bool use_hotbar_image = false; - std::string hotbar_selected_image = ""; - bool use_hotbar_selected_image = false; - - Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, - Inventory *inventory); - ~Hud(); - - void drawHotbar(u16 playeritem); - void resizeHotbar(); - void drawCrosshair(); - void drawSelectionMesh(); - void updateSelectionMesh(const v3s16 &camera_offset); - - std::vector *getSelectionBoxes() - { return &m_selection_boxes; } - - void setSelectionPos(const v3f &pos, const v3s16 &camera_offset); - - v3f getSelectionPos() const - { return m_selection_pos; } - - void setSelectionMeshColor(const video::SColor &color) - { m_selection_mesh_color = color; } - - void setSelectedFaceNormal(const v3f &face_normal) - { m_selected_face_normal = face_normal; } - - void drawLuaElements(const v3s16 &camera_offset); - -private: - void drawStatbar(v2s32 pos, u16 corner, u16 drawdir, std::string texture, - s32 count, v2s32 offset, v2s32 size=v2s32()); - - void drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount, - s32 inv_offset, InventoryList *mainlist, u16 selectitem, u16 direction); - - void drawItem(const ItemStack &item, const core::rect& rect, - bool selected); - - float m_hud_scaling; // cached minetest setting - v3s16 m_camera_offset; - v2u32 m_screensize; - v2s32 m_displaycenter; - s32 m_hotbar_imagesize; // Takes hud_scaling into account, updated by resizeHotbar() - s32 m_padding; // Takes hud_scaling into account, updated by resizeHotbar() - video::SColor hbar_colors[4]; - - std::vector m_selection_boxes; - std::vector m_halo_boxes; - v3f m_selection_pos; - v3f m_selection_pos_with_offset; - - scene::IMesh *m_selection_mesh = nullptr; - video::SColor m_selection_mesh_color; - v3f m_selected_face_normal; - - video::SMaterial m_selection_material; - - enum { - HIGHLIGHT_BOX, - HIGHLIGHT_HALO, - HIGHLIGHT_NONE } m_mode; -}; - -enum ItemRotationKind { - IT_ROT_SELECTED, - IT_ROT_HOVERED, - IT_ROT_DRAGGED, - IT_ROT_NONE, // Must be last, also serves as number -}; - -void drawItemStack(video::IVideoDriver *driver, - gui::IGUIFont *font, - const ItemStack &item, - const core::rect &rect, - const core::rect *clip, - Client *client, - ItemRotationKind rotation_kind); +extern const EnumString es_HudElementType[]; +extern const EnumString es_HudElementStat[]; +extern const EnumString es_HudBuiltinElement[]; #endif diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 14aa7b6e6..bd0cd6a08 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1028,7 +1028,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) std::string datastring(pkt->getString(0), pkt->getSize()); std::istringstream is(datastring, std::ios_base::binary); - u32 id; + u32 server_id; u8 type; v2f pos; std::string name; @@ -1042,7 +1042,7 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) v3f world_pos; v2s32 size; - *pkt >> id >> type >> pos >> name >> scale >> text >> number >> item + *pkt >> server_id >> type >> pos >> name >> scale >> text >> number >> item >> dir >> align >> offset; try { *pkt >> world_pos; @@ -1052,10 +1052,12 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) try { *pkt >> size; } catch(SerializationError &e) {}; + u32 client_id = getEnv().getLocalPlayer()->getFreeHudID(); + m_hud_server_to_client[server_id] = client_id; ClientEvent *event = new ClientEvent(); event->type = CE_HUDADD; - event->hudadd.id = id; + event->hudadd.id = client_id; event->hudadd.type = type; event->hudadd.pos = new v2f(pos); event->hudadd.name = new std::string(name); @@ -1073,14 +1075,20 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) void Client::handleCommand_HudRemove(NetworkPacket* pkt) { - u32 id; + u32 server_id; - *pkt >> id; + *pkt >> server_id; - ClientEvent *event = new ClientEvent(); - event->type = CE_HUDRM; - event->hudrm.id = id; - m_client_event_queue.push(event); + std::unordered_map::const_iterator i = m_hud_server_to_client.find(server_id); + if (i != m_hud_server_to_client.end()) { + int client_id = i->second; + m_hud_server_to_client.erase(i); + + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDRM; + event->hudrm.id = client_id; + m_client_event_queue.push(event); + } } void Client::handleCommand_HudChange(NetworkPacket* pkt) @@ -1090,10 +1098,10 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) v3f v3fdata; u32 intdata = 0; v2s32 v2s32data; - u32 id; + u32 server_id; u8 stat; - *pkt >> id >> stat; + *pkt >> server_id >> stat; if (stat == HUD_STAT_POS || stat == HUD_STAT_SCALE || stat == HUD_STAT_ALIGN || stat == HUD_STAT_OFFSET) @@ -1107,16 +1115,19 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) else *pkt >> intdata; - ClientEvent *event = new ClientEvent(); - event->type = CE_HUDCHANGE; - event->hudchange.id = id; - event->hudchange.stat = (HudElementStat)stat; - event->hudchange.v2fdata = new v2f(v2fdata); - event->hudchange.v3fdata = new v3f(v3fdata); - event->hudchange.sdata = new std::string(sdata); - event->hudchange.data = intdata; - event->hudchange.v2s32data = new v2s32(v2s32data); - m_client_event_queue.push(event); + std::unordered_map::const_iterator i = m_hud_server_to_client.find(server_id); + if (i != m_hud_server_to_client.end()) { + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDCHANGE; + event->hudchange.id = i->second; + event->hudchange.stat = (HudElementStat)stat; + event->hudchange.v2fdata = new v2f(v2fdata); + event->hudchange.v3fdata = new v3f(v3fdata); + event->hudchange.sdata = new std::string(sdata); + event->hudchange.data = intdata; + event->hudchange.v2s32data = new v2s32(v2s32data); + m_client_event_queue.push(event); + } } void Client::handleCommand_HudSetFlags(NetworkPacket* pkt) diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 507fd58b4..cac48d488 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -1792,3 +1792,142 @@ void push_objectRef(lua_State *L, const u16 id) lua_remove(L, -2); // object_refs lua_remove(L, -2); // core } + +void read_hud_element(lua_State *L, HudElement *elem) +{ + elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", + es_HudElementType, HUD_ELEM_TEXT); + + lua_getfield(L, 2, "position"); + elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "scale"); + elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "size"); + elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32(); + lua_pop(L, 1); + + elem->name = getstringfield_default(L, 2, "name", ""); + elem->text = getstringfield_default(L, 2, "text", ""); + elem->number = getintfield_default(L, 2, "number", 0); + elem->item = getintfield_default(L, 2, "item", 0); + elem->dir = getintfield_default(L, 2, "direction", 0); + + // Deprecated, only for compatibility's sake + if (elem->dir == 0) + elem->dir = getintfield_default(L, 2, "dir", 0); + + lua_getfield(L, 2, "alignment"); + elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "offset"); + elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); + lua_pop(L, 1); + + lua_getfield(L, 2, "world_pos"); + elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); + lua_pop(L, 1); + + /* check for known deprecated element usage */ + if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32())) + log_deprecated(L,"Deprecated usage of statbar without size!"); +} + +void push_hud_element(lua_State *L, HudElement *elem) +{ + lua_newtable(L); + + lua_pushstring(L, es_HudElementType[(u8)elem->type].str); + lua_setfield(L, -2, "type"); + + push_v2f(L, elem->pos); + lua_setfield(L, -2, "position"); + + lua_pushstring(L, elem->name.c_str()); + lua_setfield(L, -2, "name"); + + push_v2f(L, elem->scale); + lua_setfield(L, -2, "scale"); + + lua_pushstring(L, elem->text.c_str()); + lua_setfield(L, -2, "text"); + + lua_pushnumber(L, elem->number); + lua_setfield(L, -2, "number"); + + lua_pushnumber(L, elem->item); + lua_setfield(L, -2, "item"); + + lua_pushnumber(L, elem->dir); + lua_setfield(L, -2, "direction"); + + // Deprecated, only for compatibility's sake + lua_pushnumber(L, elem->dir); + lua_setfield(L, -2, "dir"); + + push_v3f(L, elem->world_pos); + lua_setfield(L, -2, "world_pos"); +} + +HudElementStat read_hud_change(lua_State *L, HudElement *elem, void **value) +{ + HudElementStat stat = HUD_STAT_NUMBER; + if (lua_isstring(L, 3)) { + int statint; + std::string statstr = lua_tostring(L, 3); + stat = string_to_enum(es_HudElementStat, statint, statstr) ? + (HudElementStat)statint : stat; + } + + switch (stat) { + case HUD_STAT_POS: + elem->pos = read_v2f(L, 4); + *value = &elem->pos; + break; + case HUD_STAT_NAME: + elem->name = luaL_checkstring(L, 4); + *value = &elem->name; + break; + case HUD_STAT_SCALE: + elem->scale = read_v2f(L, 4); + *value = &elem->scale; + break; + case HUD_STAT_TEXT: + elem->text = luaL_checkstring(L, 4); + *value = &elem->text; + break; + case HUD_STAT_NUMBER: + elem->number = luaL_checknumber(L, 4); + *value = &elem->number; + break; + case HUD_STAT_ITEM: + elem->item = luaL_checknumber(L, 4); + *value = &elem->item; + break; + case HUD_STAT_DIR: + elem->dir = luaL_checknumber(L, 4); + *value = &elem->dir; + break; + case HUD_STAT_ALIGN: + elem->align = read_v2f(L, 4); + *value = &elem->align; + break; + case HUD_STAT_OFFSET: + elem->offset = read_v2f(L, 4); + *value = &elem->offset; + break; + case HUD_STAT_WORLD_POS: + elem->world_pos = read_v3f(L, 4); + *value = &elem->world_pos; + break; + case HUD_STAT_SIZE: + elem->size = read_v2s32(L, 4); + *value = &elem->size; + break; + } + return stat; +} diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 80a96e327..d5c375a8f 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -39,6 +39,7 @@ extern "C" { #include "itemgroup.h" #include "itemdef.h" #include "c_types.h" +#include "hud.h" namespace Json { class Value; } @@ -181,4 +182,10 @@ void push_pointed_thing (lua_State *L, const PointedThing & void push_objectRef (lua_State *L, const u16 id); +void read_hud_element (lua_State *L, HudElement *elem); + +void push_hud_element (lua_State *L, HudElement *elem); + +HudElementStat read_hud_change (lua_State *L, HudElement *elem, void **value); + extern struct EnumString es_TileAnimationType[]; diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index da560c3ac..492422d92 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -21,6 +21,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "l_internal.h" #include "script/common/c_converter.h" #include "localplayer.h" +#include "hud.h" +#include "common/c_content.h" LuaLocalPlayer::LuaLocalPlayer(LocalPlayer *m) : m_localplayer(m) { @@ -272,6 +274,73 @@ int LuaLocalPlayer::l_get_movement(lua_State *L) return 1; } + +// hud_add(self, form) +int LuaLocalPlayer::l_hud_add(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + HudElement *elem = new HudElement; + read_hud_element(L, elem); + + u32 id = player->addHud(elem); + if (id == U32_MAX) { + delete elem; + return 0; + } + lua_pushnumber(L, id); + return 1; +} + +// hud_remove(self, id) +int LuaLocalPlayer::l_hud_remove(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + u32 id = luaL_checkinteger(L, 2); + HudElement *element = player->removeHud(id); + if (!element) + lua_pushboolean(L, false); + else + lua_pushboolean(L, true); + delete element; + return 1; +} + +// hud_change(self, id, stat, data) +int LuaLocalPlayer::l_hud_change(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + u32 id = luaL_checkinteger(L, 2); + + HudElement *element = player->getHud(id); + if (!element) + return 0; + + void *unused; + read_hud_change(L, element, &unused); + + lua_pushboolean(L, true); + return 1; +} + +// hud_get(self, id) +int LuaLocalPlayer::l_hud_get(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + u32 id = luaL_checkinteger(L, -1); + + HudElement *e = player->getHud(id); + if (!e) { + lua_pushnil(L); + return 1; + } + + push_hud_element(L, e); + return 1; +} + LuaLocalPlayer *LuaLocalPlayer::checkobject(lua_State *L, int narg) { luaL_checktype(L, narg, LUA_TUSERDATA); @@ -353,6 +422,10 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, get_movement_acceleration), luamethod(LuaLocalPlayer, get_movement_speed), luamethod(LuaLocalPlayer, get_movement), + luamethod(LuaLocalPlayer, hud_add), + luamethod(LuaLocalPlayer, hud_remove), + luamethod(LuaLocalPlayer, hud_change), + luamethod(LuaLocalPlayer, hud_get), {0, 0} }; diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h index d30fe1d64..01de2ed4e 100644 --- a/src/script/lua_api/l_localplayer.h +++ b/src/script/lua_api/l_localplayer.h @@ -66,6 +66,17 @@ private: static int l_get_movement(lua_State *L); + // hud_add(self, id, form) + static int l_hud_add(lua_State *L); + + // hud_rm(self, id) + static int l_hud_remove(lua_State *L); + + // hud_change(self, id, stat, data) + static int l_hud_change(lua_State *L); + // hud_get(self, id) + static int l_hud_get(lua_State *L); + LocalPlayer *m_localplayer = nullptr; public: diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index bc150d70f..3afd21ec3 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -32,44 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "scripting_server.h" -struct EnumString es_HudElementType[] = -{ - {HUD_ELEM_IMAGE, "image"}, - {HUD_ELEM_TEXT, "text"}, - {HUD_ELEM_STATBAR, "statbar"}, - {HUD_ELEM_INVENTORY, "inventory"}, - {HUD_ELEM_WAYPOINT, "waypoint"}, -{0, NULL}, -}; - -struct EnumString es_HudElementStat[] = -{ - {HUD_STAT_POS, "position"}, - {HUD_STAT_POS, "pos"}, /* Deprecated, only for compatibility's sake */ - {HUD_STAT_NAME, "name"}, - {HUD_STAT_SCALE, "scale"}, - {HUD_STAT_TEXT, "text"}, - {HUD_STAT_NUMBER, "number"}, - {HUD_STAT_ITEM, "item"}, - {HUD_STAT_DIR, "direction"}, - {HUD_STAT_ALIGN, "alignment"}, - {HUD_STAT_OFFSET, "offset"}, - {HUD_STAT_WORLD_POS, "world_pos"}, - {0, NULL}, -}; - -struct EnumString es_HudBuiltinElement[] = -{ - {HUD_FLAG_HOTBAR_VISIBLE, "hotbar"}, - {HUD_FLAG_HEALTHBAR_VISIBLE, "healthbar"}, - {HUD_FLAG_CROSSHAIR_VISIBLE, "crosshair"}, - {HUD_FLAG_WIELDITEM_VISIBLE, "wielditem"}, - {HUD_FLAG_BREATHBAR_VISIBLE, "breathbar"}, - {HUD_FLAG_MINIMAP_VISIBLE, "minimap"}, - {HUD_FLAG_MINIMAP_RADAR_VISIBLE, "minimap_radar"}, - {0, NULL}, -}; - /* ObjectRef */ @@ -1345,48 +1307,7 @@ int ObjectRef::l_hud_add(lua_State *L) return 0; HudElement *elem = new HudElement; - - elem->type = (HudElementType)getenumfield(L, 2, "hud_elem_type", - es_HudElementType, HUD_ELEM_TEXT); - - lua_getfield(L, 2, "position"); - elem->pos = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); - lua_pop(L, 1); - - lua_getfield(L, 2, "scale"); - elem->scale = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); - lua_pop(L, 1); - - lua_getfield(L, 2, "size"); - elem->size = lua_istable(L, -1) ? read_v2s32(L, -1) : v2s32(); - lua_pop(L, 1); - - elem->name = getstringfield_default(L, 2, "name", ""); - elem->text = getstringfield_default(L, 2, "text", ""); - elem->number = getintfield_default(L, 2, "number", 0); - elem->item = getintfield_default(L, 2, "item", 0); - elem->dir = getintfield_default(L, 2, "direction", 0); - - // Deprecated, only for compatibility's sake - if (elem->dir == 0) - elem->dir = getintfield_default(L, 2, "dir", 0); - - lua_getfield(L, 2, "alignment"); - elem->align = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); - lua_pop(L, 1); - - lua_getfield(L, 2, "offset"); - elem->offset = lua_istable(L, -1) ? read_v2f(L, -1) : v2f(); - lua_pop(L, 1); - - lua_getfield(L, 2, "world_pos"); - elem->world_pos = lua_istable(L, -1) ? read_v3f(L, -1) : v3f(); - lua_pop(L, 1); - - /* check for known deprecated element usage */ - if ((elem->type == HUD_ELEM_STATBAR) && (elem->size == v2s32())) { - log_deprecated(L,"Deprecated usage of statbar without size!"); - } + read_hud_element(L, elem); u32 id = getServer(L)->hudAdd(player, elem); if (id == U32_MAX) { @@ -1433,61 +1354,8 @@ int ObjectRef::l_hud_change(lua_State *L) if (!e) return 0; - HudElementStat stat = HUD_STAT_NUMBER; - if (lua_isstring(L, 3)) { - int statint; - std::string statstr = lua_tostring(L, 3); - stat = string_to_enum(es_HudElementStat, statint, statstr) ? - (HudElementStat)statint : HUD_STAT_NUMBER; - } - void *value = NULL; - switch (stat) { - case HUD_STAT_POS: - e->pos = read_v2f(L, 4); - value = &e->pos; - break; - case HUD_STAT_NAME: - e->name = luaL_checkstring(L, 4); - value = &e->name; - break; - case HUD_STAT_SCALE: - e->scale = read_v2f(L, 4); - value = &e->scale; - break; - case HUD_STAT_TEXT: - e->text = luaL_checkstring(L, 4); - value = &e->text; - break; - case HUD_STAT_NUMBER: - e->number = luaL_checknumber(L, 4); - value = &e->number; - break; - case HUD_STAT_ITEM: - e->item = luaL_checknumber(L, 4); - value = &e->item; - break; - case HUD_STAT_DIR: - e->dir = luaL_checknumber(L, 4); - value = &e->dir; - break; - case HUD_STAT_ALIGN: - e->align = read_v2f(L, 4); - value = &e->align; - break; - case HUD_STAT_OFFSET: - e->offset = read_v2f(L, 4); - value = &e->offset; - break; - case HUD_STAT_WORLD_POS: - e->world_pos = read_v3f(L, 4); - value = &e->world_pos; - break; - case HUD_STAT_SIZE: - e->size = read_v2s32(L, 4); - value = &e->size; - break; - } + HudElementStat stat = read_hud_change(L, e, &value); getServer(L)->hudChange(player, id, stat, value); @@ -1509,40 +1377,7 @@ int ObjectRef::l_hud_get(lua_State *L) HudElement *e = player->getHud(id); if (!e) return 0; - - lua_newtable(L); - - lua_pushstring(L, es_HudElementType[(u8)e->type].str); - lua_setfield(L, -2, "type"); - - push_v2f(L, e->pos); - lua_setfield(L, -2, "position"); - - lua_pushstring(L, e->name.c_str()); - lua_setfield(L, -2, "name"); - - push_v2f(L, e->scale); - lua_setfield(L, -2, "scale"); - - lua_pushstring(L, e->text.c_str()); - lua_setfield(L, -2, "text"); - - lua_pushnumber(L, e->number); - lua_setfield(L, -2, "number"); - - lua_pushnumber(L, e->item); - lua_setfield(L, -2, "item"); - - lua_pushnumber(L, e->dir); - lua_setfield(L, -2, "direction"); - - // Deprecated, only for compatibility's sake - lua_pushnumber(L, e->dir); - lua_setfield(L, -2, "dir"); - - push_v3f(L, e->world_pos); - lua_setfield(L, -2, "world_pos"); - + push_hud_element(L, e); return 1; } diff --git a/util/travis/clang-format-whitelist.txt b/util/travis/clang-format-whitelist.txt index 95a61fc28..f124cd7a5 100644 --- a/util/travis/clang-format-whitelist.txt +++ b/util/travis/clang-format-whitelist.txt @@ -2,30 +2,30 @@ src/activeobject.h src/ban.cpp src/camera.cpp src/camera.h -src/mapgen/cavegen.cpp -src/mapgen/cavegen.h src/chat.cpp src/chat.h src/chat_interface.h +src/client/clientlauncher.cpp +src/client/clientlauncher.h src/client.cpp -src/client.h src/clientenvironment.cpp src/clientenvironment.h +src/client/gameui.cpp +src/client.h +src/client/hud.cpp +src/client/hud.h src/clientiface.cpp src/clientiface.h +src/client/joystick_controller.cpp +src/client/joystick_controller.h src/clientmap.cpp src/clientmap.h src/clientmedia.cpp src/clientmedia.h src/clientobject.cpp src/clientobject.h -src/client/clientlauncher.cpp -src/client/clientlauncher.h -src/client/gameui.cpp -src/client/joystick_controller.cpp -src/client/joystick_controller.h -src/client/renderingengine.cpp src/client/render/core.cpp +src/client/renderingengine.cpp src/client/render/interlaced.cpp src/client/render/plain.cpp src/client/render/sidebyside.cpp @@ -65,8 +65,6 @@ src/daynightratio.h src/debug.cpp src/debug.h src/defaultsettings.cpp -src/mapgen/dungeongen.cpp -src/mapgen/dungeongen.h src/emerge.cpp src/emerge.h src/environment.cpp @@ -81,8 +79,8 @@ src/filesys.h src/fontengine.cpp src/fontengine.h src/game.cpp -src/game.h src/gamedef.h +src/game.h src/genericobject.cpp src/genericobject.h src/gettext.cpp @@ -93,26 +91,29 @@ src/gui/guiEditBoxWithScrollbar.cpp src/gui/guiEditBoxWithScrollbar.h src/gui/guiEngine.cpp src/gui/guiEngine.h -src/gui/guiPathSelectMenu.cpp -src/gui/guiPathSelectMenu.h src/gui/guiFormSpecMenu.cpp src/gui/guiFormSpecMenu.h src/gui/guiKeyChangeMenu.cpp src/gui/guiMainMenu.h src/gui/guiPasswordChange.cpp -src/guiscalingfilter.cpp -src/guiscalingfilter.h +src/gui/guiPathSelectMenu.cpp +src/gui/guiPathSelectMenu.h src/gui/guiTable.cpp src/gui/guiTable.h src/gui/guiVolumeChange.cpp src/gui/guiVolumeChange.h +src/gui/intlGUIEditBox.cpp +src/gui/intlGUIEditBox.h +src/gui/mainmenumanager.h +src/gui/modalMenu.h +src/guiscalingfilter.cpp +src/guiscalingfilter.h +src/gui/touchscreengui.cpp src/httpfetch.cpp src/hud.cpp src/hud.h src/imagefilters.cpp src/imagefilters.h -src/gui/intlGUIEditBox.cpp -src/gui/intlGUIEditBox.h src/inventory.cpp src/inventory.h src/inventorymanager.cpp @@ -132,21 +133,23 @@ src/localplayer.cpp src/log.cpp src/log.h src/main.cpp -src/gui/mainmenumanager.h src/mapblock.cpp src/mapblock.h src/mapblock_mesh.cpp src/mapblock_mesh.h src/map.cpp -src/map.h -src/mapgen/mapgen.cpp -src/mapgen/mapgen.h +src/mapgen/cavegen.cpp +src/mapgen/cavegen.h +src/mapgen/dungeongen.cpp +src/mapgen/dungeongen.h src/mapgen/mapgen_carpathian.cpp src/mapgen/mapgen_carpathian.h +src/mapgen/mapgen.cpp src/mapgen/mapgen_flat.cpp src/mapgen/mapgen_flat.h src/mapgen/mapgen_fractal.cpp src/mapgen/mapgen_fractal.h +src/mapgen/mapgen.h src/mapgen/mapgen_singlenode.cpp src/mapgen/mapgen_singlenode.h src/mapgen/mapgen_v5.cpp @@ -157,16 +160,6 @@ src/mapgen/mapgen_v7.cpp src/mapgen/mapgen_v7.h src/mapgen/mapgen_valleys.cpp src/mapgen/mapgen_valleys.h -src/mapnode.cpp -src/mapnode.h -src/mapsector.cpp -src/mapsector.h -src/map_settings_manager.cpp -src/map_settings_manager.h -src/mesh.cpp -src/mesh.h -src/mesh_generator_thread.cpp -src/metadata.h src/mapgen/mg_biome.cpp src/mapgen/mg_biome.h src/mapgen/mg_decoration.cpp @@ -175,9 +168,21 @@ src/mapgen/mg_ore.cpp src/mapgen/mg_ore.h src/mapgen/mg_schematic.cpp src/mapgen/mg_schematic.h +src/mapgen/treegen.cpp +src/mapgen/treegen.h +src/map.h +src/mapnode.cpp +src/mapnode.h +src/mapsector.cpp +src/mapsector.h +src/map_settings_manager.cpp +src/map_settings_manager.h +src/mesh.cpp +src/mesh_generator_thread.cpp +src/mesh.h +src/metadata.h src/minimap.cpp src/minimap.h -src/gui/modalMenu.h src/mods.cpp src/mods.h src/network/clientopcodes.cpp @@ -305,12 +310,12 @@ src/script/scripting_server.cpp src/script/scripting_server.h src/serialization.cpp src/serialization.h -src/server.cpp -src/server.h src/serveractiveobjectmap.cpp src/serveractiveobjectmap.h +src/server.cpp src/serverenvironment.cpp src/serverenvironment.h +src/server.h src/serverlist.cpp src/serverlist.h src/serverobject.cpp @@ -342,17 +347,14 @@ src/threads.h src/tileanimation.cpp src/tool.cpp src/tool.h -src/gui/touchscreengui.cpp src/translation.cpp -src/mapgen/treegen.cpp -src/mapgen/treegen.h -src/unittest/test.cpp -src/unittest/test.h src/unittest/test_areastore.cpp src/unittest/test_collision.cpp src/unittest/test_compression.cpp src/unittest/test_connection.cpp +src/unittest/test.cpp src/unittest/test_filepath.cpp +src/unittest/test.h src/unittest/test_inventory.cpp src/unittest/test_keycode.cpp src/unittest/test_map_settings_manager.cpp