Merge branch 'main' into lua_audio
This commit is contained in:
commit
dc13c109e6
@ -16,6 +16,7 @@
|
||||
#include "../content/Content.h"
|
||||
#include "../items/ItemDef.h"
|
||||
#include "../items/Inventory.h"
|
||||
#include "../items/Inventories.h"
|
||||
#include "../maths/voxmaths.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../voxels/Block.h"
|
||||
@ -47,7 +48,7 @@ InventoryBuilder::InventoryBuilder() {
|
||||
/** Add slots grid to inventory view
|
||||
* @param cols grid columns
|
||||
* @param count total number of grid slots
|
||||
* @param coord position of the first slot of the grid
|
||||
* @param pos position of the first slot of the grid
|
||||
* @param padding additional space around the grid
|
||||
* @param addpanel automatically create panel behind the grid
|
||||
* with size including padding
|
||||
@ -55,7 +56,7 @@ InventoryBuilder::InventoryBuilder() {
|
||||
*/
|
||||
void InventoryBuilder::addGrid(
|
||||
int cols, int count,
|
||||
glm::vec2 coord,
|
||||
glm::vec2 pos,
|
||||
int padding,
|
||||
bool addpanel,
|
||||
SlotLayout slotLayout)
|
||||
@ -69,18 +70,18 @@ void InventoryBuilder::addGrid(
|
||||
uint height = rows * (slotSize + interval) - interval + padding*2;
|
||||
|
||||
glm::vec2 vsize = view->getSize();
|
||||
if (coord.x + width > vsize.x) {
|
||||
vsize.x = coord.x + width;
|
||||
if (pos.x + width > vsize.x) {
|
||||
vsize.x = pos.x + width;
|
||||
}
|
||||
if (coord.y + height > vsize.y) {
|
||||
vsize.y = coord.y + height;
|
||||
if (pos.y + height > vsize.y) {
|
||||
vsize.y = pos.y + height;
|
||||
}
|
||||
view->setSize(vsize);
|
||||
|
||||
if (addpanel) {
|
||||
auto panel = std::make_shared<gui::Container>(coord, glm::vec2(width, height));
|
||||
auto panel = std::make_shared<gui::Container>(glm::vec2(width, height));
|
||||
view->setColor(glm::vec4(0.122f, 0.122f, 0.122f, 0.878f));
|
||||
view->add(panel);
|
||||
view->add(panel, pos);
|
||||
}
|
||||
|
||||
for (int row = 0; row < rows; row++) {
|
||||
@ -109,7 +110,7 @@ std::shared_ptr<InventoryView> InventoryBuilder::build() {
|
||||
|
||||
SlotView::SlotView(
|
||||
SlotLayout layout
|
||||
) : UINode(glm::vec2(), glm::vec2(InventoryView::SLOT_SIZE)),
|
||||
) : UINode(glm::vec2(InventoryView::SLOT_SIZE)),
|
||||
layout(layout)
|
||||
{
|
||||
setColor(glm::vec4(0, 0, 0, 0.2f));
|
||||
@ -121,7 +122,7 @@ void SlotView::draw(const GfxContext* pctx, Assets* assets) {
|
||||
|
||||
ItemStack& stack = *bound;
|
||||
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
|
||||
int slotSize = InventoryView::SLOT_SIZE;
|
||||
|
||||
@ -137,9 +138,9 @@ void SlotView::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (color.a > 0.0) {
|
||||
batch->texture(nullptr);
|
||||
if (highlighted) {
|
||||
batch->rect(coord.x-4, coord.y-4, slotSize+8, slotSize+8);
|
||||
batch->rect(pos.x-4, pos.y-4, slotSize+8, slotSize+8);
|
||||
} else {
|
||||
batch->rect(coord.x, coord.y, slotSize, slotSize);
|
||||
batch->rect(pos.x, pos.y, slotSize, slotSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +159,7 @@ void SlotView::draw(const GfxContext* pctx, Assets* assets) {
|
||||
|
||||
UVRegion region = previews->get(cblock.name);
|
||||
batch->rect(
|
||||
coord.x, coord.y, slotSize, slotSize,
|
||||
pos.x, pos.y, slotSize, slotSize,
|
||||
0, 0, 0, region, false, true, tint);
|
||||
break;
|
||||
}
|
||||
@ -177,7 +178,7 @@ void SlotView::draw(const GfxContext* pctx, Assets* assets) {
|
||||
}
|
||||
}
|
||||
batch->rect(
|
||||
coord.x, coord.y, slotSize, slotSize,
|
||||
pos.x, pos.y, slotSize, slotSize,
|
||||
0, 0, 0, region, false, true, tint);
|
||||
break;
|
||||
}
|
||||
@ -187,8 +188,8 @@ void SlotView::draw(const GfxContext* pctx, Assets* assets) {
|
||||
auto font = assets->getFont("normal");
|
||||
std::wstring text = std::to_wstring(stack.getCount());
|
||||
|
||||
int x = coord.x+slotSize-text.length()*8;
|
||||
int y = coord.y+slotSize-16;
|
||||
int x = pos.x+slotSize-text.length()*8;
|
||||
int y = pos.y+slotSize-16;
|
||||
|
||||
batch->setColor(glm::vec4(0, 0, 0, 1.0f));
|
||||
font->draw(batch, text, x+1, y+1);
|
||||
@ -259,7 +260,7 @@ void SlotView::clicked(gui::GUI* gui, mousecode button) {
|
||||
}
|
||||
}
|
||||
|
||||
void SlotView::focus(gui::GUI* gui) {
|
||||
void SlotView::onFocus(gui::GUI* gui) {
|
||||
clicked(gui, mousecode::BUTTON_1);
|
||||
}
|
||||
|
||||
@ -280,7 +281,7 @@ const SlotLayout& SlotView::getLayout() const {
|
||||
return layout;
|
||||
}
|
||||
|
||||
InventoryView::InventoryView() : Container(glm::vec2(), glm::vec2()) {
|
||||
InventoryView::InventoryView() : Container(glm::vec2()) {
|
||||
setColor(glm::vec4(0, 0, 0, 0.0f));
|
||||
}
|
||||
|
||||
@ -291,13 +292,13 @@ std::shared_ptr<SlotView> InventoryView::addSlot(SlotLayout layout) {
|
||||
uint width = InventoryView::SLOT_SIZE + layout.padding;
|
||||
uint height = InventoryView::SLOT_SIZE + layout.padding;
|
||||
|
||||
auto coord = layout.position;
|
||||
auto pos = layout.position;
|
||||
auto vsize = getSize();
|
||||
if (coord.x + width > vsize.x) {
|
||||
vsize.x = coord.x + width;
|
||||
if (pos.x + width > vsize.x) {
|
||||
vsize.x = pos.x + width;
|
||||
}
|
||||
if (coord.y + height > vsize.y) {
|
||||
vsize.y = coord.y + height;
|
||||
if (pos.y + height > vsize.y) {
|
||||
vsize.y = pos.y + height;
|
||||
}
|
||||
setSize(vsize);
|
||||
|
||||
@ -337,6 +338,12 @@ void InventoryView::bind(
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryView::unbind() {
|
||||
if (inventory->isVirtual()) {
|
||||
frontend->getLevel()->inventories->remove(inventory->getId());
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryView::setSelected(int index) {
|
||||
for (int i = 0; i < int(slots.size()); i++) {
|
||||
auto slot = slots[i];
|
||||
@ -344,8 +351,8 @@ void InventoryView::setSelected(int index) {
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryView::setCoord(glm::vec2 coord) {
|
||||
Container::setCoord(coord - origin);
|
||||
void InventoryView::setPos(glm::vec2 pos) {
|
||||
Container::setPos(pos - origin);
|
||||
}
|
||||
|
||||
void InventoryView::setOrigin(glm::vec2 origin) {
|
||||
@ -378,8 +385,8 @@ static void readSlot(InventoryView* view, gui::UiXmlReader& reader, xml::xmlelem
|
||||
int index = element->attr("index", "0").asInt();
|
||||
bool itemSource = element->attr("item-source", "false").asBool();
|
||||
SlotLayout layout(index, glm::vec2(), true, itemSource, nullptr, nullptr);
|
||||
if (element->has("coord")) {
|
||||
layout.position = element->attr("coord").asVec2();
|
||||
if (element->has("pos")) {
|
||||
layout.position = element->attr("pos").asVec2();
|
||||
}
|
||||
if (element->has("sharefunc")) {
|
||||
layout.shareFunc = readSlotFunc(view, reader, element, "sharefunc");
|
||||
|
||||
@ -73,7 +73,7 @@ public:
|
||||
bool isHighlighted() const;
|
||||
|
||||
virtual void clicked(gui::GUI*, mousecode) override;
|
||||
virtual void focus(gui::GUI*) override;
|
||||
virtual void onFocus(gui::GUI*) override;
|
||||
|
||||
void bind(
|
||||
int64_t inventoryid,
|
||||
@ -101,7 +101,7 @@ public:
|
||||
|
||||
void setInventory(std::shared_ptr<Inventory> inventory);
|
||||
|
||||
virtual void setCoord(glm::vec2 coord) override;
|
||||
virtual void setPos(glm::vec2 pos) override;
|
||||
|
||||
void setOrigin(glm::vec2 origin);
|
||||
glm::vec2 getOrigin() const;
|
||||
@ -113,6 +113,8 @@ public:
|
||||
LevelFrontend* frontend,
|
||||
InventoryInteraction* interaction
|
||||
);
|
||||
|
||||
void unbind();
|
||||
|
||||
std::shared_ptr<SlotView> addSlot(SlotLayout layout);
|
||||
|
||||
@ -133,7 +135,7 @@ public:
|
||||
|
||||
void addGrid(
|
||||
int cols, int count,
|
||||
glm::vec2 coord,
|
||||
glm::vec2 pos,
|
||||
int padding,
|
||||
bool addpanel,
|
||||
SlotLayout slotLayout
|
||||
|
||||
148
src/frontend/debug_panel.cpp
Normal file
148
src/frontend/debug_panel.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "gui/controls.h"
|
||||
#include "../graphics/Mesh.h"
|
||||
#include "../objects/Player.h"
|
||||
#include "../physics/Hitbox.h"
|
||||
#include "../world/Level.h"
|
||||
#include "../world/World.h"
|
||||
#include "../voxels/Chunks.h"
|
||||
#include "../voxels/Block.h"
|
||||
#include "../util/stringutil.h"
|
||||
#include "../delegates.h"
|
||||
#include "../engine.h"
|
||||
|
||||
#include "WorldRenderer.h"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
static std::shared_ptr<Label> create_label(wstringsupplier supplier) {
|
||||
auto label = std::make_shared<Label>(L"-");
|
||||
label->textSupplier(supplier);
|
||||
return label;
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> create_debug_panel(
|
||||
Engine* engine,
|
||||
Level* level,
|
||||
Player* player
|
||||
) {
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(250, 200), glm::vec4(5.0f), 2.0f);
|
||||
panel->setPos(glm::vec2(10, 10));
|
||||
|
||||
static int fps = 0;
|
||||
static int fpsMin = fps;
|
||||
static int fpsMax = fps;
|
||||
static std::wstring fpsString = L"";
|
||||
|
||||
panel->listenInterval(0.016f, [engine]() {
|
||||
fps = 1.0f / engine->getDelta();
|
||||
fpsMin = std::min(fps, fpsMin);
|
||||
fpsMax = std::max(fps, fpsMax);
|
||||
});
|
||||
|
||||
panel->listenInterval(0.5f, []() {
|
||||
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
|
||||
fpsMin = fps;
|
||||
fpsMax = fps;
|
||||
});
|
||||
panel->add(create_label([](){ return L"fps: "+fpsString;}));
|
||||
|
||||
panel->add(create_label([](){
|
||||
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
auto& settings = engine->getSettings();
|
||||
bool culling = settings.graphics.frustumCulling;
|
||||
return L"frustum-culling: "+std::wstring(culling ? L"on" : L"off");
|
||||
}));
|
||||
panel->add(create_label([=]() {
|
||||
return L"chunks: "+std::to_wstring(level->chunks->chunksCount)+
|
||||
L" visible: "+std::to_wstring(level->chunks->visible);
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
auto* indices = level->content->getIndices();
|
||||
auto def = indices->getBlockDef(player->selectedVoxel.id);
|
||||
std::wstringstream stream;
|
||||
stream << std::hex << player->selectedVoxel.states;
|
||||
if (def) {
|
||||
stream << L" (" << util::str2wstr_utf8(def->name) << L")";
|
||||
}
|
||||
return L"block: "+std::to_wstring(player->selectedVoxel.id)+
|
||||
L" "+stream.str();
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
return L"seed: "+std::to_wstring(level->world->getSeed());
|
||||
}));
|
||||
|
||||
for (int ax = 0; ax < 3; ax++) {
|
||||
auto sub = std::make_shared<Container>(glm::vec2(250, 27));
|
||||
|
||||
std::wstring str = L"x: ";
|
||||
str[0] += ax;
|
||||
auto label = std::make_shared<Label>(str);
|
||||
label->setMargin(glm::vec4(2, 3, 2, 3));
|
||||
label->setSize(glm::vec2(20, 27));
|
||||
sub->add(label);
|
||||
sub->setColor(glm::vec4(0.0f));
|
||||
|
||||
// Coord input
|
||||
auto box = std::make_shared<TextBox>(L"");
|
||||
box->setTextSupplier([=]() {
|
||||
Hitbox* hitbox = player->hitbox.get();
|
||||
return util::to_wstring(hitbox->position[ax], 2);
|
||||
});
|
||||
box->setTextConsumer([=](std::wstring text) {
|
||||
try {
|
||||
glm::vec3 position = player->hitbox->position;
|
||||
position[ax] = std::stoi(text);
|
||||
player->teleport(position);
|
||||
} catch (std::invalid_argument& _){
|
||||
}
|
||||
});
|
||||
box->setOnEditStart([=](){
|
||||
Hitbox* hitbox = player->hitbox.get();
|
||||
box->setText(std::to_wstring(int(hitbox->position[ax])));
|
||||
});
|
||||
box->setSize(glm::vec2(230, 27));
|
||||
|
||||
sub->add(box, glm::vec2(20, 0));
|
||||
panel->add(sub);
|
||||
}
|
||||
panel->add(create_label([=](){
|
||||
int hour, minute, second;
|
||||
timeutil::from_value(level->world->daytime, hour, minute, second);
|
||||
|
||||
std::wstring timeString =
|
||||
util::lfill(std::to_wstring(hour), 2, L'0') + L":" +
|
||||
util::lfill(std::to_wstring(minute), 2, L'0');
|
||||
return L"time: "+timeString;
|
||||
}));
|
||||
{
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
bar->setSupplier([=]() {return level->world->daytime;});
|
||||
bar->setConsumer([=](double val) {level->world->daytime = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
bar->setSupplier([=]() {return WorldRenderer::fog;});
|
||||
bar->setConsumer([=](double val) {WorldRenderer::fog = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Chunk Borders", glm::vec2(400, 24)
|
||||
);
|
||||
checkbox->setSupplier([=]() {
|
||||
return engine->getSettings().debug.showChunkBorders;
|
||||
});
|
||||
checkbox->setConsumer([=](bool checked) {
|
||||
engine->getSettings().debug.showChunkBorders = checked;
|
||||
});
|
||||
panel->add(checkbox);
|
||||
}
|
||||
panel->refresh();
|
||||
return panel;
|
||||
}
|
||||
@ -16,7 +16,7 @@
|
||||
using namespace gui;
|
||||
|
||||
GUI::GUI() {
|
||||
container = std::make_shared<Container>(glm::vec2(0, 0), glm::vec2(1000));
|
||||
container = std::make_shared<Container>(glm::vec2(1000));
|
||||
uicamera = std::make_unique<Camera>(glm::vec3(), Window::height);
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
@ -58,7 +58,7 @@ void GUI::actMouse(float delta) {
|
||||
}
|
||||
if (focus != pressed) {
|
||||
focus = pressed;
|
||||
focus->focus(this);
|
||||
focus->onFocus(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -126,7 +126,7 @@ void GUI::draw(const GfxContext* pctx, Assets* assets) {
|
||||
auto& viewport = pctx->getViewport();
|
||||
glm::vec2 wsize = viewport.size();
|
||||
|
||||
menu->setCoord((wsize - menu->getSize()) / 2.0f);
|
||||
menu->setPos((wsize - menu->getSize()) / 2.0f);
|
||||
uicamera->setFov(wsize.y);
|
||||
|
||||
Shader* uishader = assets->getShader("ui");
|
||||
@ -175,7 +175,7 @@ void GUI::setFocus(std::shared_ptr<UINode> node) {
|
||||
}
|
||||
focus = node;
|
||||
if (focus) {
|
||||
focus->focus(this);
|
||||
focus->onFocus(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ namespace gui {
|
||||
class Container;
|
||||
class PagesControl;
|
||||
|
||||
/** The main UI controller */
|
||||
/// @brief The main UI controller
|
||||
class GUI {
|
||||
std::shared_ptr<Container> container;
|
||||
std::shared_ptr<UINode> hover = nullptr;
|
||||
@ -67,55 +67,58 @@ namespace gui {
|
||||
GUI();
|
||||
~GUI();
|
||||
|
||||
/** Get the main menu (PagesControl) node */
|
||||
/// @brief Get the main menu (PagesControl) node
|
||||
std::shared_ptr<PagesControl> getMenu();
|
||||
|
||||
/** Get current focused node
|
||||
* @return focused node or nullptr */
|
||||
/// @brief Get current focused node
|
||||
/// @return focused node or nullptr
|
||||
std::shared_ptr<UINode> getFocused() const;
|
||||
|
||||
/** Check if all user input is caught by some element like TextBox */
|
||||
/// @brief Check if all user input is caught by some element like TextBox
|
||||
bool isFocusCaught() const;
|
||||
|
||||
/** Main input handling and logic update method
|
||||
* @param delta delta time */
|
||||
/// @brief Main input handling and logic update method
|
||||
/// @param delta delta time
|
||||
void act(float delta);
|
||||
|
||||
/** Draw all visible elements on main container
|
||||
* @param pctx parent graphics context
|
||||
* @param assets active assets storage */
|
||||
/// @brief Draw all visible elements on main container
|
||||
/// @param pctx parent graphics context
|
||||
/// @param assets active assets storage
|
||||
void draw(const GfxContext* pctx, Assets* assets);
|
||||
|
||||
/** Add node to the main container */
|
||||
/// @brief Add element to the main container
|
||||
/// @param node UI element
|
||||
void add(std::shared_ptr<UINode> node);
|
||||
|
||||
/** Remove node from the main container */
|
||||
/// @brief Add element to the main container
|
||||
/// @param node UI element
|
||||
/// @param coord element position within the main container
|
||||
void add(std::shared_ptr<UINode> node, glm::vec2 coord);
|
||||
|
||||
/// @brief Remove node from the main container
|
||||
void remove(std::shared_ptr<UINode> node) noexcept;
|
||||
|
||||
/** Store node in the GUI nodes dictionary
|
||||
* (does not add node to the main container)
|
||||
* @param name node key
|
||||
* @param node target node
|
||||
*/
|
||||
/// @brief Store node in the GUI nodes dictionary
|
||||
/// (does not add node to the main container)
|
||||
/// @param name node key
|
||||
/// @param node target node
|
||||
void store(std::string name, std::shared_ptr<UINode> node);
|
||||
|
||||
/** Get node from the GUI nodes dictionary
|
||||
* @param name node key
|
||||
* @return stored node or nullptr
|
||||
*/
|
||||
/// @brief Get node from the GUI nodes dictionary
|
||||
/// @param name node key
|
||||
/// @return stored node or nullptr
|
||||
std::shared_ptr<UINode> get(std::string name) noexcept;
|
||||
|
||||
/** Remove node from the GUI nodes dictionary
|
||||
* @param name node key
|
||||
*/
|
||||
/// @brief Remove node from the GUI nodes dictionary
|
||||
/// @param name node key
|
||||
void remove(std::string name) noexcept;
|
||||
|
||||
/** Set node as focused
|
||||
* @param node new focused node or nullptr to remove focus
|
||||
*/
|
||||
/// @brief Set node as focused
|
||||
/// @param node new focused node or nullptr to remove focus
|
||||
void setFocus(std::shared_ptr<UINode> node);
|
||||
|
||||
/** Get the main container */
|
||||
/// @brief Get the main container
|
||||
/// @deprecated
|
||||
std::shared_ptr<Container> getContainer() const;
|
||||
|
||||
void postRunnable(runnable callback);
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
using gui::UINode;
|
||||
using gui::Align;
|
||||
|
||||
UINode::UINode(glm::vec2 coord, glm::vec2 size) : coord(coord), size(size) {
|
||||
UINode::UINode(glm::vec2 size) : size(size) {
|
||||
}
|
||||
|
||||
UINode::~UINode() {
|
||||
@ -63,18 +63,18 @@ bool UINode::isFocused() const {
|
||||
return focused;
|
||||
}
|
||||
|
||||
bool UINode::isInside(glm::vec2 pos) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
bool UINode::isInside(glm::vec2 point) {
|
||||
glm::vec2 pos = calcPos();
|
||||
glm::vec2 size = getSize();
|
||||
return (pos.x >= coord.x && pos.y >= coord.y &&
|
||||
pos.x < coord.x + size.x && pos.y < coord.y + size.y);
|
||||
return (point.x >= pos.x && point.y >= pos.y &&
|
||||
point.x < pos.x + size.x && point.y < pos.y + size.y);
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> UINode::getAt(glm::vec2 pos, std::shared_ptr<UINode> self) {
|
||||
std::shared_ptr<UINode> UINode::getAt(glm::vec2 point, std::shared_ptr<UINode> self) {
|
||||
if (!interactive) {
|
||||
return nullptr;
|
||||
}
|
||||
return isInside(pos) ? self : nullptr;
|
||||
return isInside(point) ? self : nullptr;
|
||||
}
|
||||
|
||||
bool UINode::isInteractive() const {
|
||||
@ -93,11 +93,11 @@ bool UINode::isResizing() const {
|
||||
return resizing;
|
||||
}
|
||||
|
||||
glm::vec2 UINode::calcCoord() const {
|
||||
glm::vec2 UINode::calcPos() const {
|
||||
if (parent) {
|
||||
return coord + parent->calcCoord() + parent->contentOffset();
|
||||
return pos + parent->calcPos() + parent->contentOffset();
|
||||
}
|
||||
return coord;
|
||||
return pos;
|
||||
}
|
||||
|
||||
void UINode::scrolled(int value) {
|
||||
@ -106,12 +106,12 @@ void UINode::scrolled(int value) {
|
||||
}
|
||||
}
|
||||
|
||||
void UINode::setCoord(glm::vec2 coord) {
|
||||
this->coord = coord;
|
||||
void UINode::setPos(glm::vec2 pos) {
|
||||
this->pos = pos;
|
||||
}
|
||||
|
||||
glm::vec2 UINode::getCoord() const {
|
||||
return coord;
|
||||
glm::vec2 UINode::getPos() const {
|
||||
return pos;
|
||||
}
|
||||
|
||||
glm::vec2 UINode::getSize() const {
|
||||
@ -187,6 +187,53 @@ const std::string& UINode::getId() const {
|
||||
|
||||
void UINode::reposition() {
|
||||
if (positionfunc) {
|
||||
setCoord(positionfunc());
|
||||
setPos(positionfunc());
|
||||
}
|
||||
}
|
||||
|
||||
void UINode::setGravity(Gravity gravity) {
|
||||
if (gravity == Gravity::none) {
|
||||
setPositionFunc(nullptr);
|
||||
return;
|
||||
}
|
||||
setPositionFunc([this, gravity](){
|
||||
auto parent = getParent();
|
||||
if (parent == nullptr) {
|
||||
return getPos();
|
||||
}
|
||||
glm::vec4 margin = getMargin();
|
||||
glm::vec2 size = getSize();
|
||||
glm::vec2 parentSize = parent->getSize();
|
||||
|
||||
float x = 0.0f, y = 0.0f;
|
||||
switch (gravity) {
|
||||
case Gravity::top_left:
|
||||
case Gravity::center_left:
|
||||
case Gravity::bottom_left: x = parentSize.x+margin.x; break;
|
||||
case Gravity::top_center:
|
||||
case Gravity::center_center:
|
||||
case Gravity::bottom_center: x = (parentSize.x-size.x)/2.0f; break;
|
||||
case Gravity::top_right:
|
||||
case Gravity::center_right:
|
||||
case Gravity::bottom_right: x = parentSize.x-size.x-margin.z; break;
|
||||
default: break;
|
||||
}
|
||||
switch (gravity) {
|
||||
case Gravity::top_left:
|
||||
case Gravity::top_center:
|
||||
case Gravity::top_right: y = parentSize.y+margin.y; break;
|
||||
case Gravity::center_left:
|
||||
case Gravity::center_center:
|
||||
case Gravity::center_right: y = (parentSize.y-size.y)/2.0f; break;
|
||||
case Gravity::bottom_left:
|
||||
case Gravity::bottom_center:
|
||||
case Gravity::bottom_right: y = parentSize.y-size.y-margin.w; break;
|
||||
default: break;
|
||||
}
|
||||
return glm::vec2(x, y);
|
||||
});
|
||||
|
||||
if (parent) {
|
||||
reposition();
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,34 +24,66 @@ namespace gui {
|
||||
top=left, bottom=right,
|
||||
};
|
||||
|
||||
enum class Gravity {
|
||||
none,
|
||||
|
||||
top_left,
|
||||
top_center,
|
||||
top_right,
|
||||
|
||||
center_left,
|
||||
center_center,
|
||||
center_right,
|
||||
|
||||
bottom_left,
|
||||
bottom_center,
|
||||
bottom_right
|
||||
};
|
||||
|
||||
/// @brief Base abstract class for all UI elements
|
||||
class UINode {
|
||||
/**
|
||||
* element identifier used for direct access in UiDocument
|
||||
*/
|
||||
/// @brief element identifier used for direct access in UiDocument
|
||||
std::string id = "";
|
||||
protected:
|
||||
glm::vec2 coord;
|
||||
/// @brief element position within the parent element
|
||||
glm::vec2 pos {0.0f};
|
||||
/// @brief element size (width, height)
|
||||
glm::vec2 size;
|
||||
/// @brief minimal element size
|
||||
glm::vec2 minSize {1.0f};
|
||||
/// @brief element primary color (background-color or text-color if label)
|
||||
glm::vec4 color {1.0f};
|
||||
/// @brief element color when mouse is over it
|
||||
glm::vec4 hoverColor {1.0f};
|
||||
/// @brief element margin (only supported for Panel sub-nodes)
|
||||
glm::vec4 margin {1.0f};
|
||||
/// @brief is element visible
|
||||
bool visible = true;
|
||||
/// @brief is mouse over the element
|
||||
bool hover = false;
|
||||
/// @brief is mouse has been pressed over the element and not released yet
|
||||
bool pressed = false;
|
||||
/// @brief is element focused
|
||||
bool focused = false;
|
||||
/// @brief is element opaque for cursor interaction
|
||||
bool interactive = true;
|
||||
/// @brief does the element support resizing by parent elements
|
||||
bool resizing = true;
|
||||
/// @brief z-index property specifies the stack order of an element
|
||||
int zindex = 0;
|
||||
/// @brief element content alignment (supported by Label only)
|
||||
Align align = Align::left;
|
||||
/// @brief parent element
|
||||
UINode* parent = nullptr;
|
||||
/// @brief position supplier for the element (called on parent element size update)
|
||||
vec2supplier positionfunc = nullptr;
|
||||
UINode(glm::vec2 coord, glm::vec2 size);
|
||||
|
||||
UINode(glm::vec2 size);
|
||||
public:
|
||||
virtual ~UINode();
|
||||
/** Called every frame for all visible elements
|
||||
* @param delta delta time
|
||||
*/
|
||||
|
||||
/// @brief Called every frame for all visible elements
|
||||
/// @param delta delta timУ
|
||||
virtual void act(float delta) {};
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) = 0;
|
||||
|
||||
@ -67,11 +99,12 @@ namespace gui {
|
||||
virtual void setParent(UINode* node);
|
||||
UINode* getParent() const;
|
||||
|
||||
/** Set element color (doesn't affect inner elements).
|
||||
Also replaces hover color to avoid adding extra properties. */
|
||||
/// @brief Set element color (doesn't affect inner elements).
|
||||
/// Also replaces hover color to avoid adding extra properties
|
||||
virtual void setColor(glm::vec4 newColor);
|
||||
|
||||
/** Get element color (float R,G,B,A in range [0.0, 1.0])*/
|
||||
/// @brief Get element color
|
||||
/// @return (float R,G,B,A in range [0.0, 1.0])
|
||||
glm::vec4 getColor() const;
|
||||
|
||||
virtual void setHoverColor(glm::vec4 newColor);
|
||||
@ -80,12 +113,14 @@ namespace gui {
|
||||
virtual void setMargin(glm::vec4 margin);
|
||||
glm::vec4 getMargin() const;
|
||||
|
||||
/** Influences container elements sort order
|
||||
Doesn't work in Panel */
|
||||
/// @brief Specifies the stack order of an element
|
||||
/// @attention Is not supported by Panel
|
||||
virtual void setZIndex(int idx);
|
||||
|
||||
/// @brief Get element z-index
|
||||
int getZIndex() const;
|
||||
|
||||
virtual void focus(GUI*) {focused = true;}
|
||||
virtual void onFocus(GUI*) {focused = true;}
|
||||
virtual void click(GUI*, int x, int y);
|
||||
virtual void clicked(GUI*, mousecode button) {}
|
||||
virtual void mouseMove(GUI*, int x, int y) {};
|
||||
@ -123,9 +158,9 @@ namespace gui {
|
||||
/* Get inner content offset. Used for scroll */
|
||||
virtual glm::vec2 contentOffset() {return glm::vec2(0.0f);};
|
||||
/* Calculate screen position of the element */
|
||||
virtual glm::vec2 calcCoord() const;
|
||||
virtual void setCoord(glm::vec2 coord);
|
||||
virtual glm::vec2 getCoord() const;
|
||||
virtual glm::vec2 calcPos() const;
|
||||
virtual void setPos(glm::vec2 pos);
|
||||
virtual glm::vec2 getPos() const;
|
||||
virtual glm::vec2 getSize() const;
|
||||
virtual void setSize(glm::vec2 size);
|
||||
virtual glm::vec2 getMinSize() const;
|
||||
@ -140,8 +175,10 @@ namespace gui {
|
||||
void setId(const std::string& id);
|
||||
const std::string& getId() const;
|
||||
|
||||
/* Fetch coord from positionfunc if assigned */
|
||||
/* Fetch pos from positionfunc if assigned */
|
||||
void reposition();
|
||||
|
||||
virtual void setGravity(Gravity gravity);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
using namespace gui;
|
||||
|
||||
Container::Container(glm::vec2 coord, glm::vec2 size) : UINode(coord, size) {
|
||||
Container::Container(glm::vec2 size) : UINode(size) {
|
||||
actualLength = size.y;
|
||||
setColor(glm::vec4());
|
||||
}
|
||||
@ -79,7 +79,7 @@ void Container::setScrollable(bool flag) {
|
||||
}
|
||||
|
||||
void Container::draw(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
glm::vec2 size = getSize();
|
||||
drawBackground(pctx, assets);
|
||||
|
||||
@ -88,7 +88,7 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
|
||||
batch->flush();
|
||||
{
|
||||
GfxContext ctx = pctx->sub();
|
||||
ctx.scissors(glm::vec4(coord.x, coord.y, size.x, size.y));
|
||||
ctx.scissors(glm::vec4(pos.x, pos.y, size.x, size.y));
|
||||
for (auto node : nodes) {
|
||||
if (node->isVisible())
|
||||
node->draw(pctx, assets);
|
||||
@ -100,12 +100,12 @@ void Container::draw(const GfxContext* pctx, Assets* assets) {
|
||||
void Container::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
if (color.a <= 0.0f)
|
||||
return;
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(color);
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void Container::add(std::shared_ptr<UINode> node) {
|
||||
@ -115,8 +115,8 @@ void Container::add(std::shared_ptr<UINode> node) {
|
||||
refresh();
|
||||
}
|
||||
|
||||
void Container::add(std::shared_ptr<UINode> node, glm::vec2 coord) {
|
||||
node->setCoord(coord);
|
||||
void Container::add(std::shared_ptr<UINode> node, glm::vec2 pos) {
|
||||
node->setPos(pos);
|
||||
add(node);
|
||||
}
|
||||
|
||||
@ -157,9 +157,10 @@ const std::vector<std::shared_ptr<UINode>>& Container::getNodes() const {
|
||||
}
|
||||
|
||||
Panel::Panel(glm::vec2 size, glm::vec4 padding, float interval)
|
||||
: Container(glm::vec2(), size),
|
||||
padding(padding),
|
||||
interval(interval) {
|
||||
: Container(size),
|
||||
padding(padding),
|
||||
interval(interval)
|
||||
{
|
||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||
}
|
||||
|
||||
@ -210,7 +211,7 @@ void Panel::refresh() {
|
||||
y += margin.y;
|
||||
|
||||
float ex = x + margin.x;
|
||||
node->setCoord(glm::vec2(ex, y));
|
||||
node->setPos(glm::vec2(ex, y));
|
||||
y += nodesize.y + margin.w + interval;
|
||||
|
||||
float width = size.x - padding.x - padding.z - margin.x - margin.z;
|
||||
@ -227,7 +228,7 @@ void Panel::refresh() {
|
||||
glm::vec2 nodesize = node->getSize();
|
||||
const glm::vec4 margin = node->getMargin();
|
||||
x += margin.x;
|
||||
node->setCoord(glm::vec2(x, y+margin.y));
|
||||
node->setPos(glm::vec2(x, y+margin.y));
|
||||
x += nodesize.x + margin.z + interval;
|
||||
|
||||
node->refresh();
|
||||
@ -245,7 +246,7 @@ Orientation Panel::getOrientation() const {
|
||||
return orientation;
|
||||
}
|
||||
|
||||
PagesControl::PagesControl() : Container(glm::vec2(), glm::vec2(1)){
|
||||
PagesControl::PagesControl() : Container(glm::vec2(1)){
|
||||
}
|
||||
|
||||
bool PagesControl::has(std::string name) {
|
||||
|
||||
@ -33,14 +33,14 @@ namespace gui {
|
||||
int actualLength = 0;
|
||||
bool scrollable = true;
|
||||
public:
|
||||
Container(glm::vec2 coord, glm::vec2 size);
|
||||
Container(glm::vec2 size);
|
||||
|
||||
virtual void act(float delta) override;
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets);
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
||||
virtual void add(std::shared_ptr<UINode> node);
|
||||
virtual void add(std::shared_ptr<UINode> node, glm::vec2 coord);
|
||||
virtual void add(std::shared_ptr<UINode> node, glm::vec2 pos);
|
||||
virtual void remove(std::shared_ptr<UINode> node);
|
||||
virtual void scrolled(int value) override;
|
||||
virtual void setScrollable(bool flag);
|
||||
|
||||
@ -17,17 +17,19 @@
|
||||
using namespace gui;
|
||||
|
||||
Label::Label(std::string text, std::string fontName)
|
||||
: UINode(glm::vec2(), glm::vec2(text.length() * 8, 15)),
|
||||
text(util::str2wstr_utf8(text)),
|
||||
fontName(fontName) {
|
||||
: UINode(glm::vec2(text.length() * 8, 15)),
|
||||
text(util::str2wstr_utf8(text)),
|
||||
fontName(fontName)
|
||||
{
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
|
||||
Label::Label(std::wstring text, std::string fontName)
|
||||
: UINode(glm::vec2(), glm::vec2(text.length() * 8, 15)),
|
||||
text(text),
|
||||
fontName(fontName) {
|
||||
: UINode(glm::vec2(text.length() * 8, 15)),
|
||||
text(text),
|
||||
fontName(fontName)
|
||||
{
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
@ -137,28 +139,28 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
|
||||
(lines == 1 ? lineHeight : lineHeight*lineInterval)*lines + font->getYOffset()
|
||||
);
|
||||
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
switch (align) {
|
||||
case Align::left:
|
||||
break;
|
||||
case Align::center:
|
||||
coord.x += (size.x-newsize.x)*0.5f;
|
||||
pos.x += (size.x-newsize.x)*0.5f;
|
||||
break;
|
||||
case Align::right:
|
||||
coord.x += size.x-newsize.x;
|
||||
pos.x += size.x-newsize.x;
|
||||
break;
|
||||
}
|
||||
switch (valign) {
|
||||
case Align::top:
|
||||
break;
|
||||
case Align::center:
|
||||
coord.y += (size.y-newsize.y)*0.5f;
|
||||
pos.y += (size.y-newsize.y)*0.5f;
|
||||
break;
|
||||
case Align::bottom:
|
||||
coord.y += size.y-newsize.y;
|
||||
pos.y += size.y-newsize.y;
|
||||
break;
|
||||
}
|
||||
textYOffset = coord.y-calcCoord().y;
|
||||
textYOffset = pos.y-calcPos().y;
|
||||
totalLineHeight = lineHeight * lineInterval;
|
||||
|
||||
if (multiline) {
|
||||
@ -170,10 +172,10 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
|
||||
view = std::wstring_view(text.c_str()+offset, end);
|
||||
offset += end + 1;
|
||||
}
|
||||
font->draw(batch, view, coord.x, coord.y + i * totalLineHeight, FontStyle::none);
|
||||
font->draw(batch, view, pos.x, pos.y + i * totalLineHeight, FontStyle::none);
|
||||
}
|
||||
} else {
|
||||
font->draw(batch, text, coord.x, coord.y, FontStyle::none);
|
||||
font->draw(batch, text, pos.x, pos.y, FontStyle::none);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,12 +193,12 @@ bool Label::isMultiline() const {
|
||||
}
|
||||
|
||||
// ================================= Image ====================================
|
||||
Image::Image(std::string texture, glm::vec2 size) : UINode(glm::vec2(), size), texture(texture) {
|
||||
Image::Image(std::string texture, glm::vec2 size) : UINode(size), texture(texture) {
|
||||
setInteractive(false);
|
||||
}
|
||||
|
||||
void Image::draw(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
glm::vec4 color = getColor();
|
||||
auto batch = pctx->getBatch2D();
|
||||
|
||||
@ -206,7 +208,7 @@ void Image::draw(const GfxContext* pctx, Assets* assets) {
|
||||
}
|
||||
batch->texture(texture);
|
||||
batch->setColor(color);
|
||||
batch->rect(coord.x, coord.y, size.x, size.y,
|
||||
batch->rect(pos.x, pos.y, size.x, size.y,
|
||||
0, 0, 0, UVRegion(), false, true, color);
|
||||
}
|
||||
|
||||
@ -294,11 +296,11 @@ void Button::refresh() {
|
||||
}
|
||||
|
||||
void Button::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(isPressed() ? pressedColor : (hover ? hoverColor : color));
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void Button::mouseRelease(GUI* gui, int x, int y) {
|
||||
@ -330,7 +332,7 @@ Align Button::getTextAlign() const {
|
||||
}
|
||||
|
||||
// ============================== RichButton ==================================
|
||||
RichButton::RichButton(glm::vec2 size) : Container(glm::vec2(), size) {
|
||||
RichButton::RichButton(glm::vec2 size) : Container(size) {
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.15f, 0.75f));
|
||||
}
|
||||
|
||||
@ -349,11 +351,11 @@ RichButton* RichButton::listenAction(onaction action) {
|
||||
}
|
||||
|
||||
void RichButton::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(isPressed() ? pressedColor : (hover ? hoverColor : color));
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
// ================================ TextBox ===================================
|
||||
@ -366,7 +368,7 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||
add(label);
|
||||
setHoverColor(glm::vec4(0.05f, 0.1f, 0.2f, 0.75f));
|
||||
|
||||
textInitX = label->getCoord().x;
|
||||
textInitX = label->getPos().x;
|
||||
}
|
||||
|
||||
void TextBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
@ -377,14 +379,14 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (!isFocused())
|
||||
return;
|
||||
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
glm::vec2 size = getSize();
|
||||
|
||||
auto subctx = pctx->sub();
|
||||
subctx.scissors(glm::vec4(coord.x, coord.y, size.x, size.y));
|
||||
subctx.scissors(glm::vec4(pos.x, pos.y, size.x, size.y));
|
||||
|
||||
const int lineHeight = font->getLineHeight() * label->getLineInterval();
|
||||
glm::vec2 lcoord = label->calcCoord();
|
||||
glm::vec2 lcoord = label->calcPos();
|
||||
lcoord.y -= 2;
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
@ -420,7 +422,7 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
}
|
||||
|
||||
void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
@ -437,14 +439,14 @@ void TextBox::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
batch->setColor(invalidColor);
|
||||
}
|
||||
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
if (!isFocused() && supplier) {
|
||||
input = supplier();
|
||||
}
|
||||
|
||||
if (isFocused() && multiline) {
|
||||
batch->setColor(glm::vec4(1, 1, 1, 0.1f));
|
||||
glm::vec2 lcoord = label->calcCoord();
|
||||
glm::vec2 lcoord = label->calcPos();
|
||||
lcoord.y -= 2;
|
||||
uint line = label->getLineByTextIndex(caret);
|
||||
int lineY = label->getLineYOffset(line);
|
||||
@ -536,7 +538,7 @@ size_t TextBox::getSelectionLength() const {
|
||||
/// @brief Set scroll offset
|
||||
/// @param x scroll offset
|
||||
void TextBox::setTextOffset(uint x) {
|
||||
label->setCoord(glm::vec2(textInitX - int(x), label->getCoord().y));
|
||||
label->setPos(glm::vec2(textInitX - int(x), label->getPos().y));
|
||||
textOffset = x;
|
||||
}
|
||||
|
||||
@ -583,8 +585,8 @@ void TextBox::setOnEditStart(runnable oneditstart) {
|
||||
onEditStart = oneditstart;
|
||||
}
|
||||
|
||||
void TextBox::focus(GUI* gui) {
|
||||
Panel::focus(gui);
|
||||
void TextBox::onFocus(GUI* gui) {
|
||||
Panel::onFocus(gui);
|
||||
if (onEditStart){
|
||||
setCaret(input.size());
|
||||
onEditStart();
|
||||
@ -611,7 +613,7 @@ size_t TextBox::normalizeIndex(int index) {
|
||||
int TextBox::calcIndexAt(int x, int y) const {
|
||||
if (font == nullptr)
|
||||
return 0;
|
||||
glm::vec2 lcoord = label->calcCoord();
|
||||
glm::vec2 lcoord = label->calcPos();
|
||||
uint line = label->getLineByYOffset(y-lcoord.y);
|
||||
line = std::min(line, label->getLinesNumber()-1);
|
||||
size_t lineLength = getLineLength(line);
|
||||
@ -883,11 +885,11 @@ InputBindBox::InputBindBox(Binding& binding, glm::vec4 padding)
|
||||
}
|
||||
|
||||
void InputBindBox::drawBackground(const GfxContext* pctx, Assets* assets) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(isFocused() ? focusedColor : (hover ? hoverColor : color));
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
label->setText(util::str2wstr_utf8(binding.text()));
|
||||
}
|
||||
|
||||
@ -904,17 +906,19 @@ void InputBindBox::keyPressed(keycode key) {
|
||||
}
|
||||
|
||||
// ================================ TrackBar ==================================
|
||||
TrackBar::TrackBar(double min,
|
||||
double max,
|
||||
double value,
|
||||
double step,
|
||||
int trackWidth)
|
||||
: UINode(glm::vec2(), glm::vec2(26)),
|
||||
min(min),
|
||||
max(max),
|
||||
value(value),
|
||||
step(step),
|
||||
trackWidth(trackWidth) {
|
||||
TrackBar::TrackBar(
|
||||
double min,
|
||||
double max,
|
||||
double value,
|
||||
double step,
|
||||
int trackWidth
|
||||
) : UINode(glm::vec2(26)),
|
||||
min(min),
|
||||
max(max),
|
||||
value(value),
|
||||
step(step),
|
||||
trackWidth(trackWidth)
|
||||
{
|
||||
setColor(glm::vec4(0.f, 0.f, 0.f, 0.4f));
|
||||
setHoverColor(glm::vec4(0.01f, 0.02f, 0.03f, 0.5f));
|
||||
}
|
||||
@ -923,18 +927,18 @@ void TrackBar::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (supplier) {
|
||||
value = supplier();
|
||||
}
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(hover ? hoverColor : color);
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
|
||||
float width = size.x;
|
||||
float t = (value - min) / (max-min+trackWidth*step);
|
||||
|
||||
batch->setColor(trackColor);
|
||||
int actualWidth = size.x * (trackWidth / (max-min+trackWidth*step) * step);
|
||||
batch->rect(coord.x + width * t, coord.y, actualWidth, size.y);
|
||||
batch->rect(pos.x + width * t, pos.y, actualWidth, size.y);
|
||||
}
|
||||
|
||||
void TrackBar::setSupplier(doublesupplier supplier) {
|
||||
@ -946,9 +950,9 @@ void TrackBar::setConsumer(doubleconsumer consumer) {
|
||||
}
|
||||
|
||||
void TrackBar::mouseMove(GUI*, int x, int y) {
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
value = x;
|
||||
value -= coord.x;
|
||||
value -= pos.x;
|
||||
value = (value)/size.x * (max-min+trackWidth*step);
|
||||
value += min;
|
||||
value = (value > max) ? max : value;
|
||||
@ -1009,7 +1013,7 @@ void TrackBar::setTrackColor(glm::vec4 color) {
|
||||
}
|
||||
|
||||
// ================================ CheckBox ==================================
|
||||
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(), glm::vec2(32.0f)), checked(checked) {
|
||||
CheckBox::CheckBox(bool checked) : UINode(glm::vec2(32.0f)), checked(checked) {
|
||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.5f));
|
||||
}
|
||||
|
||||
@ -1017,11 +1021,11 @@ void CheckBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (supplier) {
|
||||
checked = supplier();
|
||||
}
|
||||
glm::vec2 coord = calcCoord();
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->setColor(checked ? checkColor : (hover ? hoverColor : color));
|
||||
batch->rect(coord.x, coord.y, size.x, size.y);
|
||||
batch->rect(pos.x, pos.y, size.x, size.y);
|
||||
}
|
||||
|
||||
void CheckBox::mouseRelease(GUI*, int x, int y) {
|
||||
|
||||
@ -272,7 +272,7 @@ namespace gui {
|
||||
/// @brief Set runnable called on textbox focus
|
||||
virtual void setOnEditStart(runnable oneditstart);
|
||||
|
||||
virtual void focus(GUI*) override;
|
||||
virtual void onFocus(GUI*) override;
|
||||
virtual void refresh() override;
|
||||
virtual void click(GUI*, int, int) override;
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
|
||||
@ -22,13 +22,32 @@ static Align align_from_string(const std::string& str, Align def) {
|
||||
return def;
|
||||
}
|
||||
|
||||
static Gravity gravity_from_string(const std::string& str) {
|
||||
static const std::unordered_map<std::string, Gravity> gravity_names {
|
||||
{"top-left", Gravity::top_left},
|
||||
{"top-center", Gravity::top_center},
|
||||
{"top-right", Gravity::top_right},
|
||||
{"center-left", Gravity::center_left},
|
||||
{"center-center", Gravity::center_center},
|
||||
{"center-right", Gravity::center_right},
|
||||
{"bottom-left", Gravity::bottom_left},
|
||||
{"bottom-center", Gravity::bottom_center},
|
||||
{"bottom-right", Gravity::bottom_right},
|
||||
};
|
||||
auto found = gravity_names.find(str);
|
||||
if (found == gravity_names.end()) {
|
||||
return found->second;
|
||||
}
|
||||
return Gravity::none;
|
||||
}
|
||||
|
||||
/* Read basic UINode properties */
|
||||
static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& node) {
|
||||
if (element->has("id")) {
|
||||
node.setId(element->attr("id").getText());
|
||||
}
|
||||
if (element->has("pos")) {
|
||||
node.setCoord(element->attr("pos").asVec2());
|
||||
node.setPos(element->attr("pos").asVec2());
|
||||
}
|
||||
if (element->has("size")) {
|
||||
node.setSize(element->attr("size").asVec2());
|
||||
@ -67,6 +86,12 @@ static void _readUINode(UiXmlReader& reader, xml::xmlelement element, UINode& no
|
||||
}
|
||||
std::string alignName = element->attr("align", "").getText();
|
||||
node.setAlign(align_from_string(alignName, node.getAlign()));
|
||||
|
||||
if (element->has("gravity")) {
|
||||
node.setGravity(gravity_from_string(
|
||||
element->attr("gravity").getText()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -149,7 +174,7 @@ static std::shared_ptr<UINode> readLabel(UiXmlReader& reader, xml::xmlelement el
|
||||
}
|
||||
|
||||
static std::shared_ptr<UINode> readContainer(UiXmlReader& reader, xml::xmlelement element) {
|
||||
auto container = std::make_shared<Container>(glm::vec2(), glm::vec2());
|
||||
auto container = std::make_shared<Container>(glm::vec2());
|
||||
_readContainer(reader, element, *container);
|
||||
return container;
|
||||
}
|
||||
|
||||
@ -1,15 +1,11 @@
|
||||
#include "hud.h"
|
||||
|
||||
// TODO: refactor this garbage
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "../typedefs.h"
|
||||
#include "../content/Content.h"
|
||||
@ -55,13 +51,50 @@
|
||||
#include "../items/Inventories.h"
|
||||
#include "../logic/scripting/scripting.h"
|
||||
|
||||
using namespace gui;
|
||||
|
||||
static std::shared_ptr<Label> create_label(wstringsupplier supplier) {
|
||||
auto label = std::make_shared<Label>(L"-");
|
||||
label->textSupplier(supplier);
|
||||
return label;
|
||||
}
|
||||
// implemented in debug_panel.cpp
|
||||
extern std::shared_ptr<gui::UINode> create_debug_panel(
|
||||
Engine* engine,
|
||||
Level* level,
|
||||
Player* player
|
||||
);
|
||||
|
||||
class DeltaGrapher : public gui::UINode {
|
||||
std::unique_ptr<int[]> points;
|
||||
float multiplier;
|
||||
int index = 0;
|
||||
int dmwidth;
|
||||
int dmheight;
|
||||
public:
|
||||
DeltaGrapher(uint width, uint height, float multiplier)
|
||||
: gui::UINode(glm::vec2(width, height)),
|
||||
multiplier(multiplier),
|
||||
dmwidth(width),
|
||||
dmheight(height)
|
||||
{
|
||||
points = std::make_unique<int[]>(width);
|
||||
}
|
||||
|
||||
void act(float delta) override {
|
||||
index = index + 1 % dmwidth;
|
||||
int value = static_cast<int>(delta * multiplier);
|
||||
points[index % dmwidth] = std::min(value, dmheight);
|
||||
}
|
||||
|
||||
void draw(const GfxContext* pctx, Assets* assets) override {
|
||||
glm::vec2 pos = calcPos();
|
||||
auto batch = pctx->getBatch2D();
|
||||
batch->texture(nullptr);
|
||||
batch->lineWidth(1);
|
||||
for (int i = index+1; i < index+dmwidth; i++) {
|
||||
int j = i % dmwidth;
|
||||
batch->line(
|
||||
pos.x + i - index, pos.y + size.y - points[j],
|
||||
pos.x + i - index, pos.y + size.y, 1.0f, 1.0f, 1.0f, 0.2f
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
HudElement::HudElement(
|
||||
hud_element_mode mode,
|
||||
@ -74,6 +107,7 @@ HudElement::HudElement(
|
||||
void HudElement::update(bool pause, bool inventoryOpen, bool debugMode) {
|
||||
if (debug && !debugMode) {
|
||||
node->setVisible(false);
|
||||
return;
|
||||
}
|
||||
switch (mode) {
|
||||
case hud_element_mode::permanent:
|
||||
@ -99,115 +133,6 @@ std::shared_ptr<gui::UINode> HudElement::getNode() const {
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> Hud::createDebugPanel(Engine* engine) {
|
||||
auto level = frontend->getLevel();
|
||||
|
||||
auto panel = std::make_shared<Panel>(glm::vec2(250, 200), glm::vec4(5.0f), 2.0f);
|
||||
panel->listenInterval(0.5f, [this]() {
|
||||
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
|
||||
fpsMin = fps;
|
||||
fpsMax = fps;
|
||||
});
|
||||
panel->setCoord(glm::vec2(10, 10));
|
||||
panel->add(create_label([this](){ return L"fps: "+this->fpsString;}));
|
||||
panel->add(create_label([](){
|
||||
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
auto& settings = engine->getSettings();
|
||||
bool culling = settings.graphics.frustumCulling;
|
||||
return L"frustum-culling: "+std::wstring(culling ? L"on" : L"off");
|
||||
}));
|
||||
panel->add(create_label([=]() {
|
||||
return L"chunks: "+std::to_wstring(level->chunks->chunksCount)+
|
||||
L" visible: "+std::to_wstring(level->chunks->visible);
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
auto* indices = level->content->getIndices();
|
||||
auto def = indices->getBlockDef(player->selectedVoxel.id);
|
||||
std::wstringstream stream;
|
||||
stream << std::hex << player->selectedVoxel.states;
|
||||
if (def) {
|
||||
stream << L" (" << util::str2wstr_utf8(def->name) << L")";
|
||||
}
|
||||
return L"block: "+std::to_wstring(player->selectedVoxel.id)+
|
||||
L" "+stream.str();
|
||||
}));
|
||||
panel->add(create_label([=](){
|
||||
return L"seed: "+std::to_wstring(level->world->getSeed());
|
||||
}));
|
||||
|
||||
for (int ax = 0; ax < 3; ax++) {
|
||||
auto sub = std::make_shared<Container>(glm::vec2(), glm::vec2(250, 27));
|
||||
|
||||
std::wstring str = L"x: ";
|
||||
str[0] += ax;
|
||||
auto label = std::make_shared<Label>(str);
|
||||
label->setMargin(glm::vec4(2, 3, 2, 3));
|
||||
label->setSize(glm::vec2(20, 27));
|
||||
sub->add(label);
|
||||
sub->setColor(glm::vec4(0.0f));
|
||||
|
||||
// Coord input
|
||||
auto box = std::make_shared<TextBox>(L"");
|
||||
box->setTextSupplier([=]() {
|
||||
Hitbox* hitbox = player->hitbox.get();
|
||||
return util::to_wstring(hitbox->position[ax], 2);
|
||||
});
|
||||
box->setTextConsumer([=](std::wstring text) {
|
||||
try {
|
||||
glm::vec3 position = player->hitbox->position;
|
||||
position[ax] = std::stoi(text);
|
||||
player->teleport(position);
|
||||
} catch (std::invalid_argument& _){
|
||||
}
|
||||
});
|
||||
box->setOnEditStart([=](){
|
||||
Hitbox* hitbox = player->hitbox.get();
|
||||
box->setText(std::to_wstring(int(hitbox->position[ax])));
|
||||
});
|
||||
box->setSize(glm::vec2(230, 27));
|
||||
|
||||
sub->add(box, glm::vec2(20, 0));
|
||||
panel->add(sub);
|
||||
}
|
||||
panel->add(create_label([=](){
|
||||
int hour, minute, second;
|
||||
timeutil::from_value(level->world->daytime, hour, minute, second);
|
||||
|
||||
std::wstring timeString =
|
||||
util::lfill(std::to_wstring(hour), 2, L'0') + L":" +
|
||||
util::lfill(std::to_wstring(minute), 2, L'0');
|
||||
return L"time: "+timeString;
|
||||
}));
|
||||
{
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 1.0f, 0.005f, 8);
|
||||
bar->setSupplier([=]() {return level->world->daytime;});
|
||||
bar->setConsumer([=](double val) {level->world->daytime = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto bar = std::make_shared<TrackBar>(0.0f, 1.0f, 0.0f, 0.005f, 8);
|
||||
bar->setSupplier([=]() {return WorldRenderer::fog;});
|
||||
bar->setConsumer([=](double val) {WorldRenderer::fog = val;});
|
||||
panel->add(bar);
|
||||
}
|
||||
{
|
||||
auto checkbox = std::make_shared<FullCheckBox>(
|
||||
L"Show Chunk Borders", glm::vec2(400, 24)
|
||||
);
|
||||
checkbox->setSupplier([=]() {
|
||||
return engine->getSettings().debug.showChunkBorders;
|
||||
});
|
||||
checkbox->setConsumer([=](bool checked) {
|
||||
engine->getSettings().debug.showChunkBorders = checked;
|
||||
});
|
||||
panel->add(checkbox);
|
||||
}
|
||||
panel->refresh();
|
||||
return panel;
|
||||
}
|
||||
|
||||
std::shared_ptr<InventoryView> Hud::createContentAccess() {
|
||||
auto level = frontend->getLevel();
|
||||
auto content = level->content;
|
||||
@ -252,14 +177,12 @@ std::shared_ptr<InventoryView> Hud::createHotbar() {
|
||||
}
|
||||
|
||||
Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||
: engine(engine),
|
||||
assets(engine->getAssets()),
|
||||
gui(engine->getGUI()),
|
||||
frontend(frontend),
|
||||
player(player)
|
||||
: engine(engine),
|
||||
assets(engine->getAssets()),
|
||||
gui(engine->getGUI()),
|
||||
frontend(frontend),
|
||||
player(player)
|
||||
{
|
||||
auto menu = gui->getMenu();
|
||||
|
||||
interaction = std::make_unique<InventoryInteraction>();
|
||||
grabbedItemView = std::make_shared<SlotView>(
|
||||
SlotLayout(-1, glm::vec2(), false, false, nullptr, nullptr)
|
||||
@ -275,7 +198,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||
grabbedItemView->setZIndex(1);
|
||||
|
||||
contentAccess = createContentAccess();
|
||||
contentAccessPanel = std::make_shared<Panel>(
|
||||
contentAccessPanel = std::make_shared<gui::Panel>(
|
||||
contentAccess->getSize(), glm::vec4(0.0f), 0.0f
|
||||
);
|
||||
contentAccessPanel->setColor(glm::vec4());
|
||||
@ -283,7 +206,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||
contentAccessPanel->setScrollable(true);
|
||||
|
||||
hotbarView = createHotbar();
|
||||
darkOverlay = std::make_unique<Panel>(glm::vec2(4000.0f));
|
||||
darkOverlay = std::make_unique<gui::Panel>(glm::vec2(4000.0f));
|
||||
darkOverlay->setColor(glm::vec4(0, 0, 0, 0.5f));
|
||||
darkOverlay->setZIndex(-1);
|
||||
darkOverlay->setVisible(false);
|
||||
@ -292,9 +215,7 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||
uicamera->perspective = false;
|
||||
uicamera->flipped = true;
|
||||
|
||||
debugPanel = createDebugPanel(engine);
|
||||
menu->reset();
|
||||
|
||||
debugPanel = create_debug_panel(engine, frontend->getLevel(), player);
|
||||
debugPanel->setZIndex(2);
|
||||
|
||||
gui->add(darkOverlay);
|
||||
@ -302,13 +223,17 @@ Hud::Hud(Engine* engine, LevelFrontend* frontend, Player* player)
|
||||
gui->add(debugPanel);
|
||||
gui->add(contentAccessPanel);
|
||||
gui->add(grabbedItemView);
|
||||
|
||||
auto dgrapher = std::make_shared<DeltaGrapher>(350, 250, 2000);
|
||||
dgrapher->setGravity(gui::Gravity::bottom_right);
|
||||
add(HudElement(hud_element_mode::permanent, nullptr, dgrapher, true));
|
||||
}
|
||||
|
||||
Hud::~Hud() {
|
||||
// removing all controlled ui
|
||||
gui->remove(grabbedItemView);
|
||||
for (auto& element : elements) {
|
||||
remove(element);
|
||||
onRemove(element);
|
||||
}
|
||||
gui->remove(hotbarView);
|
||||
gui->remove(darkOverlay);
|
||||
@ -316,21 +241,55 @@ Hud::~Hud() {
|
||||
gui->remove(debugPanel);
|
||||
}
|
||||
|
||||
void Hud::drawDebug(int fps){
|
||||
this->fps = fps;
|
||||
fpsMin = min(fps, fpsMin);
|
||||
fpsMax = max(fps, fpsMax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all elements marked as removed
|
||||
*/
|
||||
/// @brief Remove all elements marked as removed
|
||||
void Hud::cleanup() {
|
||||
auto it = std::remove_if(elements.begin(), elements.end(), [](const HudElement& e) {
|
||||
return e.isRemoved();
|
||||
});
|
||||
elements.erase(it, elements.end());
|
||||
}
|
||||
}
|
||||
|
||||
void Hud::processInput(bool visible) {
|
||||
if (Events::jpressed(keycode::ESCAPE)) {
|
||||
if (pause) {
|
||||
setPause(false);
|
||||
} else if (inventoryOpen) {
|
||||
closeInventory();
|
||||
} else {
|
||||
setPause(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (visible && Events::jactive(BIND_HUD_INVENTORY)) {
|
||||
if (inventoryOpen) {
|
||||
closeInventory();
|
||||
} else {
|
||||
openInventory();
|
||||
}
|
||||
}
|
||||
if (!pause) {
|
||||
if (!inventoryOpen && Events::scroll) {
|
||||
int slot = player->getChosenSlot();
|
||||
slot = (slot - Events::scroll) % 10;
|
||||
if (slot < 0) {
|
||||
slot += 10;
|
||||
}
|
||||
player->setChosenSlot(slot);
|
||||
}
|
||||
for (
|
||||
int i = static_cast<int>(keycode::NUM_1);
|
||||
i <= static_cast<int>(keycode::NUM_9);
|
||||
i++
|
||||
) {
|
||||
if (Events::jpressed(i)) {
|
||||
player->setChosenSlot(i - static_cast<int>(keycode::NUM_1));
|
||||
}
|
||||
}
|
||||
if (Events::jpressed(keycode::NUM_0)) {
|
||||
player->setChosenSlot(9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hud::update(bool visible) {
|
||||
auto level = frontend->getLevel();
|
||||
@ -344,31 +303,16 @@ void Hud::update(bool visible) {
|
||||
if (pause && menu->getCurrent().panel == nullptr) {
|
||||
setPause(false);
|
||||
}
|
||||
if (Events::jpressed(keycode::ESCAPE) && !gui->isFocusCaught()) {
|
||||
if (pause) {
|
||||
setPause(false);
|
||||
} else if (inventoryOpen) {
|
||||
closeInventory();
|
||||
} else {
|
||||
setPause(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (visible && !gui->isFocusCaught() && !pause) {
|
||||
if (Events::jactive(BIND_HUD_INVENTORY)) {
|
||||
if (inventoryOpen) {
|
||||
closeInventory();
|
||||
} else {
|
||||
openInventory();
|
||||
}
|
||||
}
|
||||
if (!gui->isFocusCaught()) {
|
||||
processInput(visible);
|
||||
}
|
||||
if ((pause || inventoryOpen) == Events::_cursor_locked) {
|
||||
Events::toggleCursor();
|
||||
}
|
||||
|
||||
if (blockUI) {
|
||||
voxel* vox = level->chunks->get(currentblock.x, currentblock.y, currentblock.z);
|
||||
voxel* vox = level->chunks->get(blockPos.x, blockPos.y, blockPos.z);
|
||||
if (vox == nullptr || vox->id != currentblockid) {
|
||||
closeInventory();
|
||||
}
|
||||
@ -384,58 +328,33 @@ void Hud::update(bool visible) {
|
||||
contentAccess->setMinSize(glm::vec2(1, Window::height));
|
||||
hotbarView->setVisible(visible);
|
||||
|
||||
if (!gui->isFocusCaught() && !pause) {
|
||||
for (int i = static_cast<int>(keycode::NUM_1); i <= static_cast<int>(keycode::NUM_9); i++) {
|
||||
if (Events::jpressed(i)) {
|
||||
player->setChosenSlot(i - static_cast<int>(keycode::NUM_1));
|
||||
}
|
||||
}
|
||||
if (Events::jpressed(keycode::NUM_0)) {
|
||||
player->setChosenSlot(9);
|
||||
}
|
||||
}
|
||||
if (!pause && !inventoryOpen && Events::scroll) {
|
||||
int slot = player->getChosenSlot();
|
||||
slot = (slot - Events::scroll) % 10;
|
||||
if (slot < 0) {
|
||||
slot += 10;
|
||||
}
|
||||
player->setChosenSlot(slot);
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
for (auto& element : elements) {
|
||||
element.update(pause, inventoryOpen, player->debug);
|
||||
if (element.isRemoved()) {
|
||||
remove(element);
|
||||
onRemove(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show inventory on the screen and turn on inventory mode blocking movement
|
||||
*/
|
||||
/// @brief Show inventory on the screen and turn on inventory mode blocking movement
|
||||
void Hud::openInventory() {
|
||||
auto inventory = player->getInventory();
|
||||
|
||||
inventoryOpen = true;
|
||||
|
||||
auto inventory = player->getInventory();
|
||||
auto inventoryDocument = assets->getLayout("core:inventory");
|
||||
inventoryView = std::dynamic_pointer_cast<InventoryView>(inventoryDocument->getRoot());
|
||||
inventoryView->bind(inventory, frontend, interaction.get());
|
||||
add(HudElement(hud_element_mode::inventory_bound, inventoryDocument, inventoryView, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show player inventory + block UI
|
||||
* @param block world position of the open block
|
||||
* @param doc block UI document (root element must be an InventoryView)
|
||||
* @param blockinv block inventory.
|
||||
* In case of nullptr a new virtual inventory will be created
|
||||
*/
|
||||
void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr<Inventory> blockinv, bool playerInventory) {
|
||||
void Hud::openInventory(
|
||||
glm::ivec3 block,
|
||||
UiDocument* doc,
|
||||
std::shared_ptr<Inventory> blockinv,
|
||||
bool playerInventory
|
||||
) {
|
||||
if (isInventoryOpen()) {
|
||||
closeInventory();
|
||||
}
|
||||
@ -444,6 +363,7 @@ void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr<Inven
|
||||
if (blockUI == nullptr) {
|
||||
throw std::runtime_error("block UI root element must be 'inventory'");
|
||||
}
|
||||
secondUI = blockUI;
|
||||
if (playerInventory) {
|
||||
openInventory();
|
||||
} else {
|
||||
@ -454,15 +374,24 @@ void Hud::openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr<Inven
|
||||
}
|
||||
level->chunks->getChunkByVoxel(block.x, block.y, block.z)->setUnsaved(true);
|
||||
blockUI->bind(blockinv, frontend, interaction.get());
|
||||
currentblock = block;
|
||||
blockPos = block;
|
||||
currentblockid = level->chunks->get(block.x, block.y, block.z)->id;
|
||||
add(HudElement(hud_element_mode::inventory_bound, doc, blockUI, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add element as permanent overlay
|
||||
* @param doc element layout document
|
||||
*/
|
||||
void Hud::showOverlay(UiDocument* doc, bool playerInventory) {
|
||||
if (isInventoryOpen()) {
|
||||
closeInventory();
|
||||
}
|
||||
secondUI = doc->getRoot();
|
||||
if (playerInventory) {
|
||||
openInventory();
|
||||
} else {
|
||||
inventoryOpen = true;
|
||||
}
|
||||
add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false));
|
||||
}
|
||||
|
||||
void Hud::openPermanent(UiDocument* doc) {
|
||||
auto root = doc->getRoot();
|
||||
remove(root);
|
||||
@ -475,24 +404,13 @@ void Hud::openPermanent(UiDocument* doc) {
|
||||
add(HudElement(hud_element_mode::permanent, doc, doc->getRoot(), false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide inventory and turn off inventory mode
|
||||
*/
|
||||
void Hud::closeInventory() {
|
||||
auto level = frontend->getLevel();
|
||||
|
||||
inventoryOpen = false;
|
||||
ItemStack& grabbed = interaction->getGrabbedItem();
|
||||
grabbed.clear();
|
||||
inventoryView = nullptr;
|
||||
if (blockUI) {
|
||||
auto blockinv = blockUI->getInventory();
|
||||
// todo: do it automatically
|
||||
if (blockinv->isVirtual()) {
|
||||
level->inventories->remove(blockinv->getId());
|
||||
}
|
||||
blockUI = nullptr;
|
||||
}
|
||||
blockUI = nullptr;
|
||||
secondUI = nullptr;
|
||||
}
|
||||
|
||||
void Hud::add(HudElement element) {
|
||||
@ -505,20 +423,20 @@ void Hud::add(HudElement element) {
|
||||
scripting::on_ui_open(
|
||||
element.getDocument(),
|
||||
inventory.get(),
|
||||
currentblock
|
||||
blockPos
|
||||
);
|
||||
} else {
|
||||
scripting::on_ui_open(
|
||||
element.getDocument(),
|
||||
nullptr,
|
||||
currentblock
|
||||
blockPos
|
||||
);
|
||||
}
|
||||
}
|
||||
elements.push_back(element);
|
||||
}
|
||||
|
||||
void Hud::remove(HudElement& element) {
|
||||
void Hud::onRemove(HudElement& element) {
|
||||
auto document = element.getDocument();
|
||||
if (document) {
|
||||
Inventory* inventory = nullptr;
|
||||
@ -527,16 +445,18 @@ void Hud::remove(HudElement& element) {
|
||||
inventory = invview->getInventory().get();
|
||||
}
|
||||
scripting::on_ui_close(document, inventory);
|
||||
if (invview) {
|
||||
invview->unbind();
|
||||
}
|
||||
}
|
||||
gui->remove(element.getNode());
|
||||
}
|
||||
|
||||
// todo: refactor this garbage
|
||||
void Hud::remove(std::shared_ptr<UINode> node) {
|
||||
void Hud::remove(std::shared_ptr<gui::UINode> node) {
|
||||
for (auto& element : elements) {
|
||||
if (element.getNode() == node) {
|
||||
element.setRemoved();
|
||||
remove(element);
|
||||
onRemove(element);
|
||||
}
|
||||
}
|
||||
cleanup();
|
||||
@ -547,6 +467,8 @@ void Hud::draw(const GfxContext& ctx){
|
||||
const uint width = viewport.getWidth();
|
||||
const uint height = viewport.getHeight();
|
||||
|
||||
updateElementsPosition(viewport);
|
||||
|
||||
uicamera->setFov(height);
|
||||
|
||||
auto batch = ctx.getBatch2D();
|
||||
@ -555,12 +477,9 @@ void Hud::draw(const GfxContext& ctx){
|
||||
Shader* uishader = assets->getShader("ui");
|
||||
uishader->use();
|
||||
uishader->uniformMatrix("u_projview", uicamera->getProjView());
|
||||
|
||||
hotbarView->setCoord(glm::vec2(width/2, height-65));
|
||||
hotbarView->setSelected(player->getChosenSlot());
|
||||
|
||||
// Crosshair
|
||||
if (!pause && Events::_cursor_locked && !player->debug) {
|
||||
if (!pause && !inventoryOpen && !player->debug) {
|
||||
GfxContext chctx = ctx.sub();
|
||||
chctx.blendMode(blendmode::inversion);
|
||||
auto texture = assets->getTexture("gui/crosshair");
|
||||
@ -573,55 +492,45 @@ void Hud::draw(const GfxContext& ctx){
|
||||
);
|
||||
batch->flush();
|
||||
}
|
||||
batch->flush();
|
||||
}
|
||||
|
||||
// Delta-time visualizer
|
||||
if (player->debug) {
|
||||
batch->texture(nullptr);
|
||||
const int dmwidth = 256;
|
||||
const float dmscale = 4000.0f;
|
||||
static float deltameter[dmwidth]{};
|
||||
static int index=0;
|
||||
index = index + 1 % dmwidth;
|
||||
deltameter[index%dmwidth] = glm::min(0.2f, 1.f/fps)*dmscale;
|
||||
batch->lineWidth(1);
|
||||
for (int i = index+1; i < index+dmwidth; i++) {
|
||||
int j = i % dmwidth;
|
||||
batch->line(width-dmwidth+i-index, height-deltameter[j],
|
||||
width-dmwidth+i-index, height, 1.0f, 1.0f, 1.0f, 0.2f);
|
||||
}
|
||||
}
|
||||
|
||||
void Hud::updateElementsPosition(const Viewport& viewport) {
|
||||
const uint width = viewport.getWidth();
|
||||
const uint height = viewport.getHeight();
|
||||
|
||||
if (inventoryOpen) {
|
||||
float caWidth = inventoryView ? contentAccess->getSize().x : 0.0f;
|
||||
contentAccessPanel->setCoord(glm::vec2(width-caWidth, 0));
|
||||
contentAccessPanel->setPos(glm::vec2(width-caWidth, 0));
|
||||
|
||||
glm::vec2 invSize = inventoryView ? inventoryView->getSize() : glm::vec2();
|
||||
if (blockUI == nullptr) {
|
||||
if (secondUI == nullptr) {
|
||||
if (inventoryView) {
|
||||
inventoryView->setCoord(glm::vec2(
|
||||
inventoryView->setPos(glm::vec2(
|
||||
glm::min(width/2-invSize.x/2, width-caWidth-10-invSize.x),
|
||||
height/2-invSize.y/2
|
||||
));
|
||||
}
|
||||
} else {
|
||||
glm::vec2 blockInvSize = blockUI->getSize();
|
||||
float invwidth = glm::max(invSize.x, blockInvSize.x);
|
||||
glm::vec2 secondUISize = secondUI->getSize();
|
||||
float invwidth = glm::max(invSize.x, secondUISize.x);
|
||||
int interval = invSize.y > 0.0 ? 5 : 0;
|
||||
float totalHeight = invSize.y + blockInvSize.y + interval;
|
||||
float totalHeight = invSize.y + secondUISize.y + interval;
|
||||
if (inventoryView) {
|
||||
inventoryView->setCoord(glm::vec2(
|
||||
inventoryView->setPos(glm::vec2(
|
||||
glm::min(width/2-invwidth/2, width-caWidth-10-invwidth),
|
||||
height/2+totalHeight/2-invSize.y
|
||||
));
|
||||
}
|
||||
blockUI->setCoord(glm::vec2(
|
||||
secondUI->setPos(glm::vec2(
|
||||
glm::min(width/2-invwidth/2, width-caWidth-10-invwidth),
|
||||
height/2-totalHeight/2
|
||||
));
|
||||
}
|
||||
}
|
||||
grabbedItemView->setCoord(glm::vec2(Events::cursor));
|
||||
batch->flush();
|
||||
grabbedItemView->setPos(glm::vec2(Events::cursor));
|
||||
hotbarView->setPos(glm::vec2(width/2, height-65));
|
||||
hotbarView->setSelected(player->getChosenSlot());
|
||||
}
|
||||
|
||||
bool Hud::isInventoryOpen() const {
|
||||
|
||||
@ -9,11 +9,9 @@
|
||||
#include "../graphics/GfxContext.h"
|
||||
|
||||
class Camera;
|
||||
class Level;
|
||||
class Block;
|
||||
class Assets;
|
||||
class Player;
|
||||
class Level;
|
||||
class Engine;
|
||||
class SlotView;
|
||||
class Inventory;
|
||||
@ -23,104 +21,138 @@ class UiDocument;
|
||||
class InventoryInteraction;
|
||||
|
||||
namespace gui {
|
||||
class GUI;
|
||||
class UINode;
|
||||
class GUI;
|
||||
class UINode;
|
||||
class Panel;
|
||||
class Container;
|
||||
class Container;
|
||||
}
|
||||
|
||||
enum class hud_element_mode {
|
||||
// element is hidden if menu or inventory open
|
||||
ingame,
|
||||
// element is visible if hud is visible
|
||||
permanent,
|
||||
// element is visible in inventory mode
|
||||
inventory_any,
|
||||
// element will be removed on inventory close
|
||||
inventory_bound
|
||||
// element is hidden if menu or inventory open
|
||||
ingame,
|
||||
// element is visible if hud is visible
|
||||
permanent,
|
||||
// element is visible in inventory mode
|
||||
inventory_any,
|
||||
// element will be removed on inventory close
|
||||
inventory_bound
|
||||
};
|
||||
|
||||
class HudElement {
|
||||
hud_element_mode mode;
|
||||
UiDocument* document;
|
||||
std::shared_ptr<gui::UINode> node;
|
||||
hud_element_mode mode;
|
||||
UiDocument* document;
|
||||
std::shared_ptr<gui::UINode> node;
|
||||
|
||||
bool debug;
|
||||
bool removed = false;
|
||||
bool debug;
|
||||
bool removed = false;
|
||||
public:
|
||||
HudElement(hud_element_mode mode, UiDocument* document, std::shared_ptr<gui::UINode> node, bool debug);
|
||||
HudElement(hud_element_mode mode, UiDocument* document, std::shared_ptr<gui::UINode> node, bool debug);
|
||||
|
||||
void update(bool pause, bool inventoryOpen, bool debug);
|
||||
void update(bool pause, bool inventoryOpen, bool debug);
|
||||
|
||||
UiDocument* getDocument() const;
|
||||
std::shared_ptr<gui::UINode> getNode() const;
|
||||
UiDocument* getDocument() const;
|
||||
std::shared_ptr<gui::UINode> getNode() const;
|
||||
|
||||
void setRemoved() {
|
||||
removed = true;
|
||||
}
|
||||
|
||||
bool isRemoved() const {
|
||||
return removed;
|
||||
}
|
||||
bool isRemoved() const {
|
||||
return removed;
|
||||
}
|
||||
};
|
||||
|
||||
class Hud {
|
||||
Engine* engine;
|
||||
Assets* assets;
|
||||
std::unique_ptr<Camera> uicamera;
|
||||
|
||||
int fps = 60;
|
||||
int fpsMin = 60;
|
||||
int fpsMax = 60;
|
||||
std::wstring fpsString;
|
||||
bool inventoryOpen = false;
|
||||
bool pause = false;
|
||||
|
||||
std::shared_ptr<gui::Container> contentAccessPanel;
|
||||
std::shared_ptr<InventoryView> contentAccess;
|
||||
std::shared_ptr<InventoryView> hotbarView;
|
||||
std::shared_ptr<gui::UINode> debugPanel;
|
||||
std::shared_ptr<gui::Panel> darkOverlay;
|
||||
std::unique_ptr<InventoryInteraction> interaction;
|
||||
std::shared_ptr<SlotView> grabbedItemView;
|
||||
gui::GUI* gui;
|
||||
LevelFrontend* frontend;
|
||||
std::unique_ptr<Camera> uicamera;
|
||||
gui::GUI* gui;
|
||||
LevelFrontend* frontend;
|
||||
Player* player;
|
||||
|
||||
std::vector<HudElement> elements;
|
||||
/// @brief Is any overlay/inventory open
|
||||
bool inventoryOpen = false;
|
||||
/// @brief Is pause mode on
|
||||
bool pause = false;
|
||||
|
||||
/// @brief Content access panel scroll container
|
||||
std::shared_ptr<gui::Container> contentAccessPanel;
|
||||
/// @brief Content access panel itself
|
||||
std::shared_ptr<InventoryView> contentAccess;
|
||||
/// @brief Player inventory hotbar
|
||||
std::shared_ptr<InventoryView> hotbarView;
|
||||
/// @brief Debug info and control panel (F3 key)
|
||||
std::shared_ptr<gui::UINode> debugPanel;
|
||||
/// @brief Overlay used in pause mode
|
||||
std::shared_ptr<gui::Panel> darkOverlay;
|
||||
/// @brief Inventories interaction agent (grabbed item and other info)
|
||||
std::unique_ptr<InventoryInteraction> interaction;
|
||||
/// @brief Grabbed item visual element
|
||||
std::shared_ptr<SlotView> grabbedItemView;
|
||||
/// @brief List of all controlled hud elements
|
||||
std::vector<HudElement> elements;
|
||||
|
||||
/// @brief Player inventory view
|
||||
std::shared_ptr<InventoryView> inventoryView = nullptr;
|
||||
std::shared_ptr<InventoryView> blockUI = nullptr;
|
||||
glm::ivec3 currentblock {};
|
||||
/// @brief Block inventory view
|
||||
std::shared_ptr<InventoryView> blockUI = nullptr;
|
||||
/// @brief Position of the block open
|
||||
glm::ivec3 blockPos {};
|
||||
/// @brief Id of the block open (used to detect block destruction or replacement)
|
||||
blockid_t currentblockid = 0;
|
||||
|
||||
std::shared_ptr<gui::UINode> createDebugPanel(Engine* engine);
|
||||
/// @brief UI element will be dynamicly positioned near to inventory or in screen center
|
||||
std::shared_ptr<gui::UINode> secondUI = nullptr;
|
||||
|
||||
std::shared_ptr<InventoryView> createContentAccess();
|
||||
std::shared_ptr<InventoryView> createHotbar();
|
||||
|
||||
void processInput(bool visible);
|
||||
void updateElementsPosition(const Viewport& viewport);
|
||||
void cleanup();
|
||||
public:
|
||||
Hud(Engine* engine, LevelFrontend* frontend, Player* player);
|
||||
~Hud();
|
||||
Hud(Engine* engine, LevelFrontend* frontend, Player* player);
|
||||
~Hud();
|
||||
|
||||
void update(bool hudVisible);
|
||||
void draw(const GfxContext& context);
|
||||
void drawDebug(int fps);
|
||||
void update(bool hudVisible);
|
||||
void draw(const GfxContext& context);
|
||||
|
||||
bool isInventoryOpen() const;
|
||||
bool isPause() const;
|
||||
/// @brief Check if inventory mode on
|
||||
bool isInventoryOpen() const;
|
||||
|
||||
/// @brief Check if pause mode on
|
||||
bool isPause() const;
|
||||
|
||||
/// @brief Enable/disable pause mode
|
||||
void setPause(bool pause);
|
||||
|
||||
/// @brief Show player inventory in inventory-mode
|
||||
void openInventory();
|
||||
void openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr<Inventory> blockInv, bool playerInventory);
|
||||
|
||||
/// @brief Show block inventory in inventory-mode
|
||||
/// @param block block position
|
||||
/// @param doc block ui layout
|
||||
/// @param blockInv block inventory
|
||||
/// @param playerInventory show player inventory too
|
||||
void openInventory(glm::ivec3 block, UiDocument* doc, std::shared_ptr<Inventory> blockInv, bool playerInventory);
|
||||
|
||||
/// @brief Show element in inventory-mode
|
||||
/// @param doc element layout
|
||||
/// @param playerInventory show player inventory too
|
||||
void showOverlay(UiDocument* doc, bool playerInventory);
|
||||
|
||||
/// @brief Close all open inventories and overlay
|
||||
void closeInventory();
|
||||
|
||||
/// @brief Add element will be visible until removed
|
||||
/// @param doc element layout
|
||||
void openPermanent(UiDocument* doc);
|
||||
|
||||
void add(HudElement element);
|
||||
void remove(HudElement& element);
|
||||
void add(HudElement element);
|
||||
void onRemove(HudElement& element);
|
||||
void remove(std::shared_ptr<gui::UINode> node);
|
||||
|
||||
Player* getPlayer() const;
|
||||
};
|
||||
|
||||
#endif /* SRC_HUD_H_ */
|
||||
#endif // SRC_HUD_H_
|
||||
|
||||
@ -92,6 +92,8 @@ static bool backlight;
|
||||
LevelScreen::LevelScreen(Engine* engine, Level* level) : Screen(engine) {
|
||||
auto& settings = engine->getSettings();
|
||||
auto assets = engine->getAssets();
|
||||
auto menu = engine->getGUI()->getMenu();
|
||||
menu->reset();
|
||||
|
||||
controller = std::make_unique<LevelController>(settings, level);
|
||||
frontend = std::make_unique<LevelFrontend>(level, assets);
|
||||
@ -186,8 +188,5 @@ void LevelScreen::draw(float delta) {
|
||||
|
||||
if (hudVisible) {
|
||||
hud->draw(ctx);
|
||||
if (controller->getPlayer()->debug) {
|
||||
hud->drawDebug(1 / delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,12 +19,11 @@ Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){
|
||||
ubyte pixels[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
blank = new Texture(pixels, 1, 1, GL_RGBA);
|
||||
blank = std::make_unique<Texture>(pixels, 1, 1, GL_RGBA);
|
||||
_texture = nullptr;
|
||||
}
|
||||
|
||||
Batch2D::~Batch2D(){
|
||||
delete blank;
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
|
||||
@ -15,10 +15,9 @@ class Batch2D {
|
||||
float* buffer;
|
||||
size_t capacity;
|
||||
std::unique_ptr<Mesh> mesh;
|
||||
std::unique_ptr<Texture> blank;
|
||||
size_t index;
|
||||
glm::vec4 color;
|
||||
|
||||
Texture* blank;
|
||||
Texture* _texture;
|
||||
|
||||
void vertex(
|
||||
|
||||
@ -171,7 +171,7 @@ static int l_gui_getattr(lua_State* L) {
|
||||
if (attr == "color") {
|
||||
return lua::pushcolor_arr(L, node->getColor());
|
||||
} else if (attr == "pos") {
|
||||
return lua::pushvec2_arr(L, node->getCoord());
|
||||
return lua::pushvec2_arr(L, node->getPos());
|
||||
} else if (attr == "size") {
|
||||
return lua::pushvec2_arr(L, node->getSize());
|
||||
} else if (attr == "hoverColor") {
|
||||
@ -210,7 +210,7 @@ static int l_gui_setattr(lua_State* L) {
|
||||
|
||||
auto node = getDocumentNode(L, docname, element);
|
||||
if (attr == "pos") {
|
||||
node->setCoord(lua::tovec2(L, 4));
|
||||
node->setPos(lua::tovec2(L, 4));
|
||||
} else if (attr == "size") {
|
||||
node->setSize(lua::tovec2(L, 4));
|
||||
} else if (attr == "color") {
|
||||
|
||||
@ -65,6 +65,19 @@ static int l_hud_open_block(lua_State* L) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int l_hud_show_overlay(lua_State* L) {
|
||||
const char* name = lua_tostring(L, 1);
|
||||
bool playerInventory = lua_toboolean(L, 2);
|
||||
|
||||
auto assets = scripting::engine->getAssets();
|
||||
auto layout = assets->getLayout(name);
|
||||
if (layout == nullptr) {
|
||||
luaL_error(L, "there is no ui layout '%s'", name);
|
||||
}
|
||||
scripting::hud->showOverlay(layout, playerInventory);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UiDocument* require_layout(lua_State* L, const char* name) {
|
||||
auto assets = scripting::engine->getAssets();
|
||||
auto layout = assets->getLayout(name);
|
||||
@ -91,6 +104,7 @@ const luaL_Reg hudlib [] = {
|
||||
{"close_inventory", lua_wrap_errors<l_hud_close_inventory>},
|
||||
{"open_block", lua_wrap_errors<l_hud_open_block>},
|
||||
{"open_permanent", lua_wrap_errors<l_hud_open_permanent>},
|
||||
{"show_overlay", lua_wrap_errors<l_hud_show_overlay>},
|
||||
{"close", lua_wrap_errors<l_hud_close>},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user