diff --git a/res/block.png b/res/block.png deleted file mode 100644 index 3766eb6f..00000000 Binary files a/res/block.png and /dev/null differ diff --git a/res/font.png b/res/fonts/font.png similarity index 100% rename from res/font.png rename to res/fonts/font.png diff --git a/res/font_0.png b/res/fonts/font_0.png similarity index 100% rename from res/font_0.png rename to res/fonts/font_0.png diff --git a/res/font_1.png b/res/fonts/font_1.png similarity index 100% rename from res/font_1.png rename to res/fonts/font_1.png diff --git a/res/font_2.png b/res/fonts/font_2.png similarity index 100% rename from res/font_2.png rename to res/fonts/font_2.png diff --git a/res/font_3.png b/res/fonts/font_3.png similarity index 100% rename from res/font_3.png rename to res/fonts/font_3.png diff --git a/res/font_4.png b/res/fonts/font_4.png similarity index 100% rename from res/font_4.png rename to res/fonts/font_4.png diff --git a/res/lines.glslf b/res/shaders/lines.glslf similarity index 100% rename from res/lines.glslf rename to res/shaders/lines.glslf diff --git a/res/lines.glslv b/res/shaders/lines.glslv similarity index 100% rename from res/lines.glslv rename to res/shaders/lines.glslv diff --git a/res/main.glslf b/res/shaders/main.glslf similarity index 100% rename from res/main.glslf rename to res/shaders/main.glslf diff --git a/res/main.glslv b/res/shaders/main.glslv similarity index 100% rename from res/main.glslv rename to res/shaders/main.glslv diff --git a/res/screen.glslf b/res/shaders/screen.glslf similarity index 100% rename from res/screen.glslf rename to res/shaders/screen.glslf diff --git a/res/screen.glslv b/res/shaders/screen.glslv similarity index 100% rename from res/screen.glslv rename to res/shaders/screen.glslv diff --git a/res/ui.glslf b/res/shaders/ui.glslf similarity index 100% rename from res/ui.glslf rename to res/shaders/ui.glslf diff --git a/res/ui.glslv b/res/shaders/ui.glslv similarity index 100% rename from res/ui.glslv rename to res/shaders/ui.glslv diff --git a/res/textures/block.png b/res/textures/block.png new file mode 100644 index 00000000..8309b545 Binary files /dev/null and b/res/textures/block.png differ diff --git a/res/menubg.png b/res/textures/menubg.png similarity index 100% rename from res/menubg.png rename to res/textures/menubg.png diff --git a/res/slot.png b/res/textures/slot.png similarity index 100% rename from res/slot.png rename to res/textures/slot.png diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 4b004d97..2e62556e 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -2,9 +2,12 @@ #include "Assets.h" #include +#include #include "../constants.h" +using std::unique_ptr; + AssetsLoader::AssetsLoader(Assets* assets) : assets(assets) { } @@ -62,18 +65,17 @@ bool _load_texture(Assets* assets, const std::string& filename, const std::strin } bool _load_atlas(Assets* assets, const std::string& filename, const std::string& name) { - ImageData* image = png::load_image(filename); + unique_ptr image (png::load_image(filename)); if (image == nullptr) { std::cerr << "failed to load image '" << name << "'" << std::endl; return false; } for (int i = 0; i < ATLAS_MARGIN_SIZE; i++) { - ImageData* newimage = add_atlas_margins(image, 16); - delete image; - image = newimage; + ImageData* newimage = add_atlas_margins(image.get(), 16); + image.reset(newimage); } - Texture* texture = Texture::from(image); + Texture* texture = Texture::from(image.get()); assets->store(texture, name); return true; } @@ -101,14 +103,14 @@ void AssetsLoader::createDefaults(AssetsLoader& loader) { } void AssetsLoader::addDefaults(AssetsLoader& loader) { - loader.add(ASSET_SHADER, "res/main", "main"); - loader.add(ASSET_SHADER, "res/lines", "lines"); - loader.add(ASSET_SHADER, "res/ui", "ui"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/main", "main"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/lines", "lines"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui", "ui"); - loader.add(ASSET_ATLAS, "res/block.png", "block"); - loader.add(ASSET_TEXTURE, "res/block.png", "block_tex"); - loader.add(ASSET_TEXTURE, "res/slot.png", "slot"); - loader.add(ASSET_TEXTURE, "res/menubg.png", "menubg"); + loader.add(ASSET_ATLAS, TEXTURES_FOLDER"/block.png", "block"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/block.png", "block_tex"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/slot.png", "slot"); + loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/menubg.png", "menubg"); - loader.add(ASSET_FONT, "res/font", "normal"); + loader.add(ASSET_FONT, FONTS_FOLDER"/font", "normal"); } diff --git a/src/coders/json.cpp b/src/coders/json.cpp index 648dc8d1..81741df3 100644 --- a/src/coders/json.cpp +++ b/src/coders/json.cpp @@ -258,6 +258,10 @@ JObject& JObject::put(string key, string value){ return *this; } +JObject& JObject::put(std::string key, const char* value) { + return put(key, string(value)); +} + JObject& JObject::put(string key, JObject* value){ auto found = map.find(key); if (found != map.end()) delete found->second; diff --git a/src/coders/json.h b/src/coders/json.h index 95fc4a23..f7b4c9cc 100644 --- a/src/coders/json.h +++ b/src/coders/json.h @@ -81,6 +81,7 @@ namespace json { JObject& put(std::string key, int value); JObject& put(std::string key, float value); JObject& put(std::string key, double value); + JObject& put(std::string key, const char* value); JObject& put(std::string key, std::string value); JObject& put(std::string key, JObject* value); JObject& put(std::string key, JArray* value); diff --git a/src/coders/png.cpp b/src/coders/png.cpp index e4d7090b..e15e0a98 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -326,12 +326,12 @@ ImageData* png::load_image(std::string filename) { } Texture* png::load_texture(std::string filename) { - ImageData* image = _png_load(filename.c_str()); + unique_ptr image (_png_load(filename.c_str())); if (image == nullptr){ std::cerr << "Could not load image " << filename << std::endl; return nullptr; } - return Texture::from(image); + return Texture::from(image.get()); } void png::write_image(std::string filename, const ImageData* image) { diff --git a/src/constants.h b/src/constants.h index 06d0f67a..97a3f4e7 100644 --- a/src/constants.h +++ b/src/constants.h @@ -20,4 +20,10 @@ inline uint vox_index(int x, int y, int z, int w, int d) { #define ATLAS_MARGIN_SIZE 2 +#define RES_FLODER "res/" + +#define SHADERS_FOLDER "res/shaders" +#define TEXTURES_FOLDER "res/textures" +#define FONTS_FOLDER "res/fonts" + #endif // SRC_CONSTANTS_H_ diff --git a/src/core_defs.h b/src/core_defs.h new file mode 100644 index 00000000..c30135bf --- /dev/null +++ b/src/core_defs.h @@ -0,0 +1,21 @@ +#ifndef SRC_CORE_DEFS_H_ +#define SRC_CORE_DEFS_H_ + +/* blocks and bindings used in engine code */ + +#define BLOCK_AIR 0 + +#define BIND_MOVE_FORWARD "movement.forward" +#define BIND_MOVE_BACK "movement.back" +#define BIND_MOVE_LEFT "movement.left" +#define BIND_MOVE_RIGHT "movement.right" +#define BIND_MOVE_JUMP "movement.jump" +#define BIND_MOVE_SPRINT "movement.sprint" +#define BIND_MOVE_CROUCH "movement.crouch" +#define BIND_MOVE_CHEAT "movement.cheat" +#define BIND_CAM_ZOOM "camera.zoom" +#define BIND_PLAYER_NOCLIP "player.noclip" +#define BIND_PLAYER_FLIGHT "player.flight" +#define BIND_HUD_INVENTORY "hud.inventory" + +#endif // SRC_CORE_DEFS_H_ \ No newline at end of file diff --git a/src/definitions.cpp b/src/definitions.cpp index 31d7be5f..d0112e48 100644 --- a/src/definitions.cpp +++ b/src/definitions.cpp @@ -1,6 +1,8 @@ #include "definitions.h" #include "window/Window.h" +#include "window/Events.h" +#include "window/input.h" #include "voxels/Block.h" // All in-game definitions (blocks, items, etc..) @@ -91,3 +93,18 @@ void setup_definitions() { block = new Block(BLOCK_RUST, 19); Block::blocks[block->id] = block; } + +void setup_bindings() { + Events::bind(BIND_MOVE_FORWARD, inputtype::keyboard, keycode::W); + Events::bind(BIND_MOVE_BACK, inputtype::keyboard, keycode::S); + Events::bind(BIND_MOVE_RIGHT, inputtype::keyboard, keycode::D); + Events::bind(BIND_MOVE_LEFT, inputtype::keyboard, keycode::A); + Events::bind(BIND_MOVE_JUMP, inputtype::keyboard, keycode::SPACE); + Events::bind(BIND_MOVE_SPRINT, inputtype::keyboard, keycode::LEFT_CONTROL); + Events::bind(BIND_MOVE_CROUCH, inputtype::keyboard, keycode::LEFT_SHIFT); + Events::bind(BIND_MOVE_CHEAT, inputtype::keyboard, keycode::R); + Events::bind(BIND_CAM_ZOOM, inputtype::keyboard, keycode::C); + Events::bind(BIND_PLAYER_NOCLIP, inputtype::keyboard, keycode::N); + Events::bind(BIND_PLAYER_FLIGHT, inputtype::keyboard, keycode::F); + Events::bind(BIND_HUD_INVENTORY, inputtype::keyboard, keycode::TAB); +} \ No newline at end of file diff --git a/src/definitions.h b/src/definitions.h index 236ac204..c4b5e0ba 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -2,8 +2,8 @@ #define DECLARATIONS_H #include +#include "core_defs.h" -#define BLOCK_AIR 0 #define BLOCK_DIRT 1 #define BLOCK_GRASS_BLOCK 2 #define BLOCK_LAMP 3 @@ -21,7 +21,8 @@ #define BLOCK_METAL 15 #define BLOCK_RUST 16 -void setup_definitions(); +extern void setup_bindings(); +extern void setup_definitions(); #endif // DECLARATIONS_H diff --git a/src/engine.cpp b/src/engine.cpp index f9be1b35..572db177 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -59,8 +59,6 @@ Engine::Engine(EngineSettings& settings) : settings(settings) { Audio::initialize(); gui = new GUI(); std::cout << "-- initializing finished" << std::endl; - - setScreen(shared_ptr(new MenuScreen(this))); } void Engine::updateTimers() { @@ -81,6 +79,8 @@ void Engine::updateHotkeys() { } void Engine::mainloop() { + setScreen(shared_ptr(new MenuScreen(this))); + std::cout << "-- preparing systems" << std::endl; Batch2D batch(1024); diff --git a/src/frontend/gui/GUI.cpp b/src/frontend/gui/GUI.cpp index 2ccf4895..f28ad67d 100644 --- a/src/frontend/gui/GUI.cpp +++ b/src/frontend/gui/GUI.cpp @@ -45,6 +45,7 @@ void GUI::act(float delta) { } this->hover = hover; + auto prevfocus = focus; if (Events::jclicked(0)) { if (pressed == nullptr && this->hover) { pressed = hover; @@ -52,7 +53,10 @@ void GUI::act(float delta) { if (focus && focus != pressed) { focus->defocus(); } - focus = pressed; + if (focus != pressed) { + focus = pressed; + focus->focus(this); + } } if (this->hover == nullptr && focus) { focus->defocus(); @@ -63,9 +67,7 @@ void GUI::act(float delta) { pressed = nullptr; } if (focus) { - if (!focus->isfocused()){ - focus = nullptr; - } else if (Events::jpressed(keycode::ESCAPE)) { + if (Events::jpressed(keycode::ESCAPE)) { focus->defocus(); focus = nullptr; } else { @@ -78,8 +80,17 @@ void GUI::act(float delta) { if (Events::clicked(mousecode::BUTTON_1)) { focus->mouseMove(this, mx, my); } + if (prevfocus == focus) + for (int i = mousecode::BUTTON_1; i < mousecode::BUTTON_1+12; i++) { + if (Events::jclicked(i)) { + focus->clicked(this, i); + } + } } } + if (focus && !focus->isfocused()) { + focus = nullptr; + } } void GUI::draw(Batch2D* batch, Assets* assets) { diff --git a/src/frontend/gui/UINode.cpp b/src/frontend/gui/UINode.cpp index cd4c9477..751c341a 100644 --- a/src/frontend/gui/UINode.cpp +++ b/src/frontend/gui/UINode.cpp @@ -52,7 +52,6 @@ UINode* UINode::getParent() const { void UINode::click(GUI*, int x, int y) { pressed_ = true; - focused_ = true; } void UINode::mouseRelease(GUI*, int x, int y) { @@ -103,7 +102,7 @@ void UINode::size(vec2 size) { this->size_ = size; if (parent) { sizelock = true; - parent->refresh(); + //parent->refresh(); sizelock = false; } } diff --git a/src/frontend/gui/UINode.h b/src/frontend/gui/UINode.h index e9699118..1620fc5a 100644 --- a/src/frontend/gui/UINode.h +++ b/src/frontend/gui/UINode.h @@ -56,7 +56,9 @@ namespace gui { virtual void margin(glm::vec4 margin); glm::vec4 margin() const; + virtual void focus(GUI*) {focused_ = true;} virtual void click(GUI*, int x, int y); + virtual void clicked(GUI*, int button) {} virtual void mouseMove(GUI*, int x, int y) {}; virtual void mouseRelease(GUI*, int x, int y); diff --git a/src/frontend/gui/controls.cpp b/src/frontend/gui/controls.cpp index c0293703..8b4935cb 100644 --- a/src/frontend/gui/controls.cpp +++ b/src/frontend/gui/controls.cpp @@ -5,6 +5,7 @@ #include "../../assets/Assets.h" #include "../../graphics/Batch2D.h" #include "../../graphics/Font.h" +#include "../../util/stringutil.h" using std::string; using std::wstring; @@ -36,7 +37,7 @@ void Label::draw(Batch2D* batch, Assets* assets) { } batch->color = color_; Font* font = assets->getFont(fontName_); - vec2 size = this->size(); + vec2 size = UINode::size(); vec2 newsize = vec2(font->calcWidth(text_), font->lineHeight()); if (newsize.x > size.x) { this->size(newsize); @@ -51,6 +52,11 @@ Label* Label::textSupplier(wstringsupplier supplier) { return this; } +void Label::size(vec2 sizenew) { + UINode::size(vec2(UINode::size().x, sizenew.y)); +} + +// ================================= Button =================================== Button::Button(shared_ptr content, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) { add(content); } @@ -86,12 +92,12 @@ Button* Button::listenAction(onaction action) { return this; } +// ================================ TextBox =================================== TextBox::TextBox(wstring placeholder, vec4 padding) : Panel(vec2(200,32), padding, 0, false), input(L""), placeholder(placeholder) { label = new Label(L""); - label->align(Align::center); add(shared_ptr(label)); } @@ -151,6 +157,42 @@ wstring TextBox::text() const { return input; } +// ============================== InputBindBox ================================ +InputBindBox::InputBindBox(Binding& binding, vec4 padding) + : Panel(vec2(100,32), padding, 0, false), + binding(binding) { + label = new Label(L""); + //label->align(Align::center); + add(shared_ptr(label)); +} + +shared_ptr InputBindBox::getAt(vec2 pos, shared_ptr self) { + return UINode::getAt(pos, self); +} + +void InputBindBox::drawBackground(Batch2D* batch, Assets* assets) { + vec2 coord = calcCoord(); + batch->texture(nullptr); + batch->color = (isfocused() ? focusedColor : (hover_ ? hoverColor : color_)); + batch->rect(coord.x, coord.y, size_.x, size_.y); + label->text(util::str2wstr_utf8(binding.text())); +} + +void InputBindBox::clicked(GUI*, int button) { + binding.type = inputtype::mouse; + binding.code = button; + defocus(); +} + +void InputBindBox::keyPressed(int key) { + if (key != keycode::ESCAPE) { + binding.type = inputtype::keyboard; + binding.code = key; + } + defocus(); +} + +// ================================ TrackBar ================================== TrackBar::TrackBar(double min, double max, double value, double step, int trackWidth) : UINode(vec2(), vec2(32)), min(min), max(max), value(value), step(step), trackWidth(trackWidth) { color(vec4(0.f, 0.f, 0.f, 0.4f)); @@ -194,6 +236,7 @@ void TrackBar::mouseMove(GUI*, int x, int y) { } } +// ================================ CheckBox ================================== CheckBox::CheckBox(bool checked) : UINode(vec2(), vec2(32.0f)), checked_(checked) { color(vec4(0.0f, 0.0f, 0.0f, 0.5f)); } diff --git a/src/frontend/gui/controls.h b/src/frontend/gui/controls.h index 8bbe6f1e..0ef15269 100644 --- a/src/frontend/gui/controls.h +++ b/src/frontend/gui/controls.h @@ -8,6 +8,7 @@ #include #include "UINode.h" #include "panels.h" +#include "../../window/input.h" class Batch2D; class Assets; @@ -36,6 +37,7 @@ namespace gui { virtual void draw(Batch2D* batch, Assets* assets) override; virtual Label* textSupplier(wstringsupplier supplier); + virtual void size(glm::vec2 size) override; }; class Button : public Panel { @@ -79,6 +81,22 @@ namespace gui { virtual std::wstring text() const; }; + class InputBindBox : public Panel { + protected: + glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f}; + glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f}; + Label* label; + Binding& binding; + public: + InputBindBox(Binding& binding, glm::vec4 padding=glm::vec4(6.0f)); + virtual void drawBackground(Batch2D* batch, Assets* assets) override; + virtual std::shared_ptr getAt(glm::vec2 pos, std::shared_ptr self) override; + + virtual void clicked(GUI*, int button) override; + virtual void keyPressed(int key) override; + virtual bool isfocuskeeper() const override {return true;} + }; + class TrackBar : public UINode { protected: glm::vec4 hoverColor {0.01f, 0.02f, 0.03f, 0.5f}; diff --git a/src/frontend/gui/panels.cpp b/src/frontend/gui/panels.cpp index 85bedbbb..6488b6be 100644 --- a/src/frontend/gui/panels.cpp +++ b/src/frontend/gui/panels.cpp @@ -1,15 +1,14 @@ #include "panels.h" +#include + #include "../../window/Window.h" #include "../../assets/Assets.h" #include "../../graphics/Batch2D.h" using std::shared_ptr; -using gui::UINode; -using gui::Container; -using gui::Panel; -using gui::Orientation; +using namespace gui; using glm::vec2; using glm::vec4; @@ -138,7 +137,8 @@ void Panel::refresh() { y += nodesize.y + margin.w + interval; float width = size.x - padding.x - padding.z - margin.x - margin.z; - node->size(vec2(width, nodesize.y)); + node->size(vec2(width, nodesize.y));; + node->refresh(); maxw = fmax(maxw, ex+node->size().x+margin.z+padding.z); } if (resizing_) @@ -154,6 +154,7 @@ void Panel::refresh() { float height = size.y - padding.y - padding.w - margin.y - margin.w; node->size(vec2(nodesize.x, height)); + node->refresh(); maxh = fmax(maxh, y+margin.y+node->size().y+margin.w+padding.w); } bool increased = maxh > size.y; @@ -177,4 +178,53 @@ void Panel::lock(){ node->lock(); } resizing_ = false; +} + +PagesControl::PagesControl() : Container(vec2(), vec2(1)){ +} + +void PagesControl::add(std::string name, std::shared_ptr panel) { + pages[name] = Page{panel}; +} + +void PagesControl::set(std::string name, bool history) { + auto found = pages.find(name); + if (found == pages.end()) { + throw std::runtime_error("no page found"); + } + if (current_.panel) { + Container::remove(current_.panel); + } + if (history) { + pageStack.push(curname_); + } + curname_ = name; + current_ = found->second; + Container::add(current_.panel); + size(current_.panel->size()); +} + +void PagesControl::back() { + if (pageStack.empty()) + return; + std::string name = pageStack.top(); + pageStack.pop(); + set(name, false); +} + +Page PagesControl::current() { + return current_; +} + +void PagesControl::clearHistory() { + pageStack = std::stack(); +} + +void PagesControl::reset() { + clearHistory(); + if (current_.panel) { + curname_ = ""; + Container::remove(current_.panel); + current_ = Page{nullptr}; + } } \ No newline at end of file diff --git a/src/frontend/gui/panels.h b/src/frontend/gui/panels.h index 7441f211..174180c7 100644 --- a/src/frontend/gui/panels.h +++ b/src/frontend/gui/panels.h @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "UINode.h" @@ -56,5 +58,27 @@ namespace gui { virtual void refresh() override; virtual void lock() override; }; + + struct Page { + std::shared_ptr panel = nullptr; + }; + + class PagesControl : public Container { + protected: + std::unordered_map pages; + std::stack pageStack; + Page current_; + std::string curname_ = ""; + public: + PagesControl(); + + void set(std::string name, bool history=true); + void add(std::string name, std::shared_ptr panel); + void back(); + void clearHistory(); + void reset(); + + Page current(); + }; } #endif // FRONTEND_GUI_PANELS_H_ \ No newline at end of file diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index e95bedf2..0d0b04cb 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -30,6 +30,7 @@ #include "gui/GUI.h" #include "screens.h" #include "../engine.h" +#include "../core_defs.h" using std::wstring; using std::shared_ptr; @@ -44,12 +45,15 @@ inline Label* create_label(gui::wstringsupplier supplier) { return label; } -HudRenderer::HudRenderer(Engine* engine, Level* level) : level(level), assets(engine->getAssets()), guiController(engine->getGUI()) { +HudRenderer::HudRenderer(Engine* engine, Level* level) : level(level), assets(engine->getAssets()), gui(engine->getGUI()) { batch = new Batch2D(1024); - uicamera = new Camera(vec3(), Window::height); + uicamera = new Camera(vec3(), 1); uicamera->perspective = false; uicamera->flipped = true; + auto pagesptr = gui->get("pages"); + PagesControl* pages = (PagesControl*)(pagesptr.get()); + Panel* panel = new Panel(vec2(250, 200), vec4(5.0f), 1.0f); debugPanel = shared_ptr(panel); panel->listenInterval(1.0f, [this]() { @@ -115,37 +119,35 @@ HudRenderer::HudRenderer(Engine* engine, Level* level) : level(level), assets(en panel->refresh(); panel = new Panel(vec2(350, 200)); - pauseMenu = shared_ptr(panel); + auto pauseMenu = shared_ptr(panel); panel->color(vec4(0.0f)); { Button* button = new Button(L"Continue", vec4(10.0f)); - button->listenAction([this](GUI*){ - this->pause = false; - pauseMenu->visible(false); + button->listenAction([=](GUI*){ + pages->reset(); + pause = false; }); panel->add(shared_ptr(button)); } panel->add((new Button(L"Settings", vec4(10.f)))->listenAction([=](GUI* gui) { - pauseMenu->visible(false); - gui->store("back", pauseMenu); - gui->get("settings")->visible(true); + pages->set("settings"); })); { Button* button = new Button(L"Save and Quit to Menu", vec4(10.f)); button->listenAction([this, engine](GUI*){ - this->pauseMenu->visible(false); engine->setScreen(shared_ptr(new MenuScreen(engine))); }); panel->add(shared_ptr(button)); } - panel->visible(false); - guiController->add(this->debugPanel); - guiController->add(this->pauseMenu); + + pages->reset(); + pages->add("pause", pauseMenu); + gui->add(this->debugPanel); } HudRenderer::~HudRenderer() { - guiController->remove(debugPanel); - guiController->remove(pauseMenu); + gui->remove(debugPanel); + //gui->remove(gui->get("pages")); delete batch; delete uicamera; } @@ -157,7 +159,11 @@ void HudRenderer::drawDebug(int fps, bool occlusion){ fpsMax = max(fps, fpsMax); } -void HudRenderer::drawInventory(Player* player) { +void HudRenderer::drawInventory(const GfxContext& ctx, Player* player) { + const Viewport& viewport = ctx.getViewport(); + const uint width = viewport.getWidth(); + const uint height = viewport.getHeight(); + Texture* blocks = assets->getTexture("block_tex"); uint size = 48; uint step = 64; @@ -165,15 +171,15 @@ void HudRenderer::drawInventory(Player* player) { uint inv_rows = 8; uint inv_w = step*inv_cols + size; uint inv_h = step*inv_rows + size; - int inv_x = (Window::width - (inv_w)) / 2; - int inv_y = (Window::height - (inv_h)) / 2; - int xs = (Window::width - inv_w + step)/2; - int ys = (Window::height - inv_h + step)/2; - if (Window::width > inv_w*3){ - inv_x = (Window::width + (inv_w)) / 2; - inv_y = (Window::height - (inv_h)) / 2; - xs = (Window::width + inv_w + step)/2; - ys = (Window::height - inv_h + step)/2; + int inv_x = (width - (inv_w)) / 2; + int inv_y = (height - (inv_h)) / 2; + int xs = (width - inv_w + step)/2; + int ys = (height - inv_h + step)/2; + if (width > inv_w*3){ + inv_x = (width + (inv_w)) / 2; + inv_y = (height - (inv_h)) / 2; + xs = (width + inv_w + step)/2; + ys = (height - inv_h + step)/2; } vec4 tint = vec4(1.0f); int mx = Events::x; @@ -221,8 +227,7 @@ void HudRenderer::drawInventory(Player* player) { if (Events::jclicked(GLFW_MOUSE_BUTTON_LEFT)) { player->choosenBlock = i+1; } - } else - { + } else { tint = vec4(1.0f); } @@ -234,17 +239,38 @@ void HudRenderer::drawInventory(Player* player) { } } -void HudRenderer::draw(){ +void HudRenderer::update() { + PagesControl* pages = (PagesControl*)(gui->get("pages").get()); + if (Events::jpressed(keycode::ESCAPE) && !gui->isFocusCaught()) { + if (pause) { + pause = false; + pages->reset(); + } else if (inventoryOpen) { + inventoryOpen = false; + } else { + pause = true; + pages->set("pause"); + } + } + if (Events::jactive(BIND_HUD_INVENTORY)) { + if (!pause) { + inventoryOpen = !inventoryOpen; + } + } + if ((pause || inventoryOpen) == Events::_cursor_locked) + Events::toggleCursor(); +} + +void HudRenderer::draw(const GfxContext& ctx){ + const Viewport& viewport = ctx.getViewport(); + const uint width = viewport.getWidth(); + const uint height = viewport.getHeight(); + auto pages = gui->get("pages"); + debugPanel->visible(level->player->debug); - pauseMenu->setCoord((Window::size() - pauseMenu->size()) / 2.0f); + pages->setCoord((viewport.size() - pages->size()) / 2.0f); - auto settingsPanel = guiController->get("settings"); - settingsPanel->setCoord((Window::size() - settingsPanel->size()) / 2.0f); - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - uicamera->fov = Window::height; + uicamera->fov = height; Shader* uishader = assets->getShader("ui"); uishader->use(); @@ -256,9 +282,7 @@ void HudRenderer::draw(){ batch->texture(nullptr); batch->color = vec4(1.0f); if (Events::_cursor_locked && !level->player->debug) { - glLineWidth(2); - const uint width = Window::width; - const uint height = Window::height; + batch->lineWidth(2); batch->line(width/2, height/2-6, width/2, height/2+6, 0.2f, 0.2f, 0.2f, 1.0f); batch->line(width/2+6, height/2, width/2-6, height/2, 0.2f, 0.2f, 0.2f, 1.0f); batch->line(width/2-5, height/2-5, width/2+5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f); @@ -266,19 +290,19 @@ void HudRenderer::draw(){ } Player* player = level->player; - batch->rect(Window::width/2-128-4, Window::height-80-4, 256+8, 64+8, + batch->rect(width/2-128-4, height-80-4, 256+8, 64+8, 0.95f, 0.95f, 0.95f, 0.85f, 0.85f, 0.85f, 0.7f, 0.7f, 0.7f, 0.55f, 0.55f, 0.55f, 0.45f, 0.45f, 0.45f, 4); - batch->rect(Window::width/2-128, Window::height - 80, 256, 64, + batch->rect(width/2-128, height - 80, 256, 64, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 4); - batch->rect(Window::width/2-32+2, Window::height - 80+2, 60, 60, + batch->rect(width/2-32+2, height - 80+2, 60, 60, 0.45f, 0.45f, 0.45f, 0.55f, 0.55f, 0.55f, 0.7f, 0.7f, 0.7f, 0.85f, 0.85f, 0.85f, 0.95f, 0.95f, 0.95f, 2); - batch->rect(Window::width/2-32+4, Window::height - 80+4, 56, 56, + batch->rect(width/2-32+4, height - 80+4, 56, 56, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 2); @@ -288,39 +312,19 @@ void HudRenderer::draw(){ { Block* cblock = Block::blocks[player->choosenBlock]; if (cblock->model == BlockModel::block){ - batch->blockSprite(Window::width/2-24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces, vec4(1.0f)); + batch->blockSprite(width/2-24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces, vec4(1.0f)); } else if (cblock->model == BlockModel::xsprite){ - batch->sprite(Window::width/2-24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces[3], vec4(1.0f)); + batch->sprite(width/2-24, uicamera->fov - 72, 48, 48, 16, cblock->textureFaces[3], vec4(1.0f)); } } - if (Events::jpressed(keycode::ESCAPE) && !guiController->isFocusCaught()) { - if (pause) { - pause = false; - pauseMenu->visible(false); - settingsPanel->visible(false); - } else if (inventoryOpen) { - inventoryOpen = false; - } else { - pause = true; - pauseMenu->visible(true); - } - } - if (Events::jpressed(keycode::TAB)) { - if (!pause) { - inventoryOpen = !inventoryOpen; - } - } - if ((pause || inventoryOpen) == Events::_cursor_locked) - Events::toggleCursor(); - if (pause || inventoryOpen) { batch->texture(nullptr); batch->color = vec4(0.0f, 0.0f, 0.0f, 0.5f); - batch->rect(0, 0, Window::width, Window::height); + batch->rect(0, 0, width, height); } if (inventoryOpen) { - drawInventory(player); + drawInventory(ctx, player); } batch->render(); } diff --git a/src/frontend/hud.h b/src/frontend/hud.h index a9b0ae4a..2da61830 100644 --- a/src/frontend/hud.h +++ b/src/frontend/hud.h @@ -4,6 +4,8 @@ #include #include +#include "../graphics/GfxContext.h" + class Batch2D; class Camera; class Level; @@ -32,13 +34,14 @@ class HudRenderer { bool pause = false; std::shared_ptr debugPanel; - std::shared_ptr pauseMenu; - gui::GUI* guiController; + gui::GUI* gui; public: HudRenderer(Engine* engine, Level* level); ~HudRenderer(); - void drawInventory(Player* player); - void draw(); + + void update(); + void drawInventory(const GfxContext& ctx, Player* player); + void draw(const GfxContext& context); void drawDebug(int fps, bool occlusion); bool isInventoryOpen() const; diff --git a/src/frontend/screens.cpp b/src/frontend/screens.cpp index 984ebc0e..22cb092f 100644 --- a/src/frontend/screens.cpp +++ b/src/frontend/screens.cpp @@ -13,6 +13,7 @@ #include "../window/input.h" #include "../graphics/Shader.h" #include "../graphics/Batch2D.h" +#include "../graphics/GfxContext.h" #include "../assets/Assets.h" #include "../world/Level.h" #include "../world/World.h" @@ -28,6 +29,7 @@ #include "../engine.h" #include "../files/engine_files.h" #include "../util/stringutil.h" +#include "../core_defs.h" using std::string; using std::wstring; @@ -39,53 +41,52 @@ using std::filesystem::u8path; using std::filesystem::directory_iterator; using namespace gui; -shared_ptr create_main_menu_panel(Engine* engine) { +shared_ptr create_main_menu_panel(Engine* engine, PagesControl* pages) { Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f); shared_ptr panelptr(panel); panel->color(vec4(0.0f)); - panel->setCoord(vec2(10, 10)); panel->add((new Button(L"New World", vec4(10.f)))->listenAction([=](GUI* gui) { - panel->visible(false); - gui->get("new-world")->visible(true); + pages->set("new-world"); })); Panel* worldsPanel = new Panel(vec2(390, 200), vec4(5.0f)); worldsPanel->color(vec4(0.1f)); - for (auto const& entry : directory_iterator(enginefs::get_worlds_folder())) { - string name = entry.path().filename().string(); - Button* button = new Button(util::str2wstr_utf8(name), - vec4(10.0f, 8.0f, 10.0f, 8.0f)); - button->color(vec4(0.5f)); - button->listenAction([engine, panel, name](GUI*) { - EngineSettings& settings = engine->getSettings(); + path worldsFolder = enginefs::get_worlds_folder(); + if (std::filesystem::is_directory(worldsFolder)) { + for (auto const& entry : directory_iterator(worldsFolder)) { + string name = entry.path().filename().string(); + Button* button = new Button(util::str2wstr_utf8(name), + vec4(10.0f, 8.0f, 10.0f, 8.0f)); + button->color(vec4(0.5f)); + button->listenAction([engine, panel, name](GUI*) { + EngineSettings& settings = engine->getSettings(); - auto folder = enginefs::get_worlds_folder()/u8path(name); - World* world = new World(name, folder, 42, settings); - auto screen = new LevelScreen(engine, world->load(settings)); - engine->setScreen(shared_ptr(screen)); - }); - worldsPanel->add(button); + auto folder = enginefs::get_worlds_folder()/u8path(name); + World* world = new World(name, folder, 42, settings); + auto screen = new LevelScreen(engine, world->load(settings)); + engine->setScreen(shared_ptr(screen)); + }); + worldsPanel->add(button); + } } panel->add(worldsPanel); panel->add((new Button(L"Settings", vec4(10.f)))->listenAction([=](GUI* gui) { - panel->visible(false); - gui->store("back", panelptr); - gui->get("settings")->visible(true); + pages->set("settings"); })); panel->add((new Button(L"Quit", vec4(10.f)))->listenAction([](GUI*) { Window::setShouldClose(true); })); + panel->refresh(); return panelptr; } -shared_ptr create_new_world_panel(Engine* engine) { +shared_ptr create_new_world_panel(Engine* engine, PagesControl* pages) { Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f); shared_ptr panelptr(panel); panel->color(vec4(0.0f)); - panel->setCoord(vec2(10, 10)); TextBox* worldNameInput; { @@ -163,17 +164,43 @@ shared_ptr create_new_world_panel(Engine* engine) { } panel->add((new Button(L"Back", vec4(10.f)))->listenAction([=](GUI* gui) { - panel->visible(false); - gui->get("main-menu")->visible(true); + pages->back(); })); - + panel->refresh(); return panelptr; } -Panel* create_settings_panel(Engine* engine) { +Panel* create_controls_panel(Engine* engine, PagesControl* pages) { Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f); panel->color(vec4(0.0f)); - panel->setCoord(vec2(10, 10)); + + for (auto& entry : Events::bindings){ + string bindname = entry.first; + + Panel* subpanel = new Panel(vec2(400, 45), vec4(5.0f), 1.0f); + subpanel->color(vec4(0.0f)); + subpanel->orientation(Orientation::horizontal); + + InputBindBox* bindbox = new InputBindBox(entry.second); + subpanel->add(bindbox); + Label* label = new Label(util::str2wstr_utf8(bindname)); + label->margin(vec4(6.0f)); + subpanel->add(label); + panel->add(subpanel); + } + + panel->add((new Button(L"Back", vec4(10.f)))->listenAction([=](GUI* gui) { + pages->back(); + })); + panel->refresh(); + return panel; +} + +shared_ptr create_settings_panel(Engine* engine, PagesControl* pages) { + Panel* panel = new Panel(vec2(400, 200), vec4(5.0f), 1.0f); + panel->color(vec4(0.0f)); + + shared_ptr panelptr(panel); /* Load Distance setting track bar */{ panel->add((new Label(L""))->textSupplier([=]() { @@ -228,30 +255,44 @@ Panel* create_settings_panel(Engine* engine) { panel->add(checkpanel); } - panel->add((new Button(L"Back", vec4(10.f)))->listenAction([=](GUI* gui) { - panel->visible(false); - gui->get("back")->visible(true); + panel->add((new Button(L"Controls", vec4(10.f)))->listenAction([=](GUI* gui) { + pages->set("controls"); })); - return panel; + + panel->add((new Button(L"Back", vec4(10.f)))->listenAction([=](GUI* gui) { + pages->back(); + })); + panel->refresh(); + return panelptr; } MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) { GUI* gui = engine->getGUI(); - panel = create_main_menu_panel(engine); - newWorldPanel = create_new_world_panel(engine); - newWorldPanel->visible(false); - auto settingsPanel = shared_ptr(create_settings_panel(engine)); - settingsPanel->visible(false); + auto pagesptr = gui->get("pages"); + PagesControl* pages; + if (pagesptr == nullptr) { + pages = new PagesControl(); + auto newWorldPanel = create_new_world_panel(engine, pages); - gui->store("main-menu", panel); - gui->store("new-world", newWorldPanel); - if (gui->get("settings") == nullptr) { - gui->store("settings", settingsPanel); + auto settingsPanel = shared_ptr(create_settings_panel(engine, pages)); + auto controlsPanel = shared_ptr(create_controls_panel(engine, pages)); + + pages->add("new-world", newWorldPanel); + pages->add("settings", settingsPanel); + pages->add("controls", controlsPanel); + + this->pages = shared_ptr(pages); + gui->add(this->pages); + gui->store("pages", this->pages); + } else { + this->pages = pagesptr; + pages = (PagesControl*)(pagesptr.get()); + pages->reset(); } - gui->add(panel); - gui->add(newWorldPanel); - gui->add(settingsPanel); + auto mainMenuPanel = create_main_menu_panel(engine, pages); + pages->add("main", mainMenuPanel); + pages->set("main"); batch = new Batch2D(1024); uicamera = new Camera(vec3(), Window::height); @@ -260,13 +301,6 @@ MenuScreen::MenuScreen(Engine* engine_) : Screen(engine_) { } MenuScreen::~MenuScreen() { - GUI* gui = engine->getGUI(); - - gui->remove("main-menu"); - gui->remove("new-world"); - - gui->remove(newWorldPanel); - gui->remove(panel); delete batch; delete uicamera; } @@ -275,11 +309,7 @@ void MenuScreen::update(float delta) { } void MenuScreen::draw(float delta) { - panel->setCoord((Window::size() - panel->size()) / 2.0f); - newWorldPanel->setCoord((Window::size() - newWorldPanel->size()) / 2.0f); - - auto settingsPanel = engine->getGUI()->get("settings"); - settingsPanel->setCoord((Window::size() - settingsPanel->size()) / 2.0f); + pages->setCoord((Window::size() - pages->size()) / 2.0f); Window::clear(); Window::setBgColor(vec3(0.2f, 0.2f, 0.2f)); @@ -348,13 +378,18 @@ void LevelScreen::update(float delta) { level->update(); level->chunksController->update(settings.chunks.loadSpeed); + + hud->update(); } void LevelScreen::draw(float delta) { Camera* camera = level->player->camera; - worldRenderer->draw(camera, occlusion); - hud->draw(); + Viewport viewport(Window::width, Window::height); + GfxContext ctx(nullptr, viewport, nullptr); + + worldRenderer->draw(ctx, camera, occlusion); + hud->draw(ctx); if (level->player->debug) { hud->drawDebug( 1 / delta, occlusion); } diff --git a/src/frontend/screens.h b/src/frontend/screens.h index 37c72b7f..c29299c8 100644 --- a/src/frontend/screens.h +++ b/src/frontend/screens.h @@ -28,8 +28,7 @@ public: }; class MenuScreen : public Screen { - std::shared_ptr panel; - std::shared_ptr newWorldPanel; + std::shared_ptr pages; Batch2D* batch; Camera* uicamera; public: diff --git a/src/frontend/world_render.cpp b/src/frontend/world_render.cpp index c3227872..5e102287 100644 --- a/src/frontend/world_render.cpp +++ b/src/frontend/world_render.cpp @@ -60,51 +60,15 @@ bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool } mat4 model = glm::translate(mat4(1.0f), vec3(chunk->x*CHUNK_W, 0.0f, chunk->z*CHUNK_D+1)); shader->uniformMatrix("u_model", model); - mesh->draw(GL_TRIANGLES); + mesh->draw(); return true; } - -void WorldRenderer::draw(Camera* camera, bool occlusion){ - EngineSettings& settings = engine->getSettings(); - Assets* assets = engine->getAssets(); - Chunks* chunks = level->chunks; - - vec3 skyColor(0.7f, 0.81f, 1.0f); - - Window::setBgColor(skyColor); - Window::clear(); - Window::viewport(0, 0, Window::width, Window::height); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); - - float fogFactor = 18.0f / (float)settings.chunks.loadDistance; - - Texture* texture = assets->getTexture("block"); - Shader* shader = assets->getShader("main"); - Shader* linesShader = assets->getShader("lines"); - shader->use(); - shader->uniformMatrix("u_proj", camera->getProjection()); - shader->uniformMatrix("u_view", camera->getView()); - shader->uniform1f("u_gamma", 1.6f); - shader->uniform3f("u_skyLightColor", 1.1f,1.1f,1.1f); - shader->uniform3f("u_fogColor", skyColor); - shader->uniform1f("u_fogFactor", fogFactor); - shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); - shader->uniform3f("u_cameraPos", camera->position); - - Block* cblock = Block::blocks[level->player->choosenBlock]; - float multiplier = 0.5f; - shader->uniform3f("u_torchlightColor", - cblock->emission[0] / 15.0f * multiplier, - cblock->emission[1] / 15.0f * multiplier, - cblock->emission[2] / 15.0f * multiplier); - shader->uniform1f("u_torchlightDistance", 6.0f); - texture->bind(); - +void WorldRenderer::drawChunks(Chunks* chunks, + Camera* camera, + Shader* shader, + bool occlusion) { std::vector indices; - for (size_t i = 0; i < chunks->volume; i++){ shared_ptr chunk = chunks->chunks[i]; if (chunk == nullptr) @@ -126,34 +90,84 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){ for (size_t i = 0; i < indices.size(); i++){ chunks->visible += drawChunk(indices[i], camera, shader, occlusion); } +} - shader->uniformMatrix("u_model", mat4(1.0f)); - if (level->playerController->selectedBlockId != -1){ - Block* selectedBlock = Block::blocks[level->playerController->selectedBlockId]; - vec3 pos = level->playerController->selectedBlockPosition; - linesShader->use(); - linesShader->uniformMatrix("u_projview", camera->getProjection()*camera->getView()); - glLineWidth(2.0f); - if (selectedBlock->model == BlockModel::block){ - lineBatch->box(pos.x+0.5f, pos.y+0.5f, pos.z+0.5f, 1.005f,1.005f,1.005f, 0,0,0,0.5f); - } else if (selectedBlock->model == BlockModel::xsprite){ - lineBatch->box(pos.x+0.5f, pos.y+0.35f, pos.z+0.5f, 0.805f,0.705f,0.805f, 0,0,0,0.5f); +void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool occlusion){ + Assets* assets = engine->getAssets(); + Texture* texture = assets->getTexture("block"); + Shader* shader = assets->getShader("main"); + Shader* linesShader = assets->getShader("lines"); + + const Viewport& viewport = pctx.getViewport(); + int displayWidth = viewport.getWidth(); + int displayHeight = viewport.getHeight(); + { + GfxContext ctx = pctx.sub(); + ctx.depthTest(true); + ctx.cullFace(true); + + EngineSettings& settings = engine->getSettings(); + + vec3 skyColor(0.7f, 0.81f, 1.0f); + + Window::setBgColor(skyColor); + Window::clear(); + Window::viewport(0, 0, displayWidth, displayHeight); + + float fogFactor = 18.0f / (float)settings.chunks.loadDistance; + + shader->use(); + shader->uniformMatrix("u_proj", camera->getProjection()); + shader->uniformMatrix("u_view", camera->getView()); + shader->uniform1f("u_gamma", 1.6f); + shader->uniform3f("u_skyLightColor", 1.1f,1.1f,1.1f); + shader->uniform3f("u_fogColor", skyColor); + shader->uniform1f("u_fogFactor", fogFactor); + shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); + shader->uniform3f("u_cameraPos", camera->position); + + Block* cblock = Block::blocks[level->player->choosenBlock]; + float multiplier = 0.5f; + shader->uniform3f("u_torchlightColor", + cblock->emission[0] / 15.0f * multiplier, + cblock->emission[1] / 15.0f * multiplier, + cblock->emission[2] / 15.0f * multiplier); + shader->uniform1f("u_torchlightDistance", 6.0f); + texture->bind(); + + Chunks* chunks = level->chunks; + drawChunks(chunks, camera, shader, occlusion); + + shader->uniformMatrix("u_model", mat4(1.0f)); + + if (level->playerController->selectedBlockId != -1){ + Block* block = Block::blocks[level->playerController->selectedBlockId]; + vec3 pos = level->playerController->selectedBlockPosition; + linesShader->use(); + linesShader->uniformMatrix("u_projview", camera->getProjView()); + lineBatch->lineWidth(2.0f); + if (block->model == BlockModel::block){ + lineBatch->box(pos.x+0.5f, pos.y+0.5f, pos.z+0.5f, + 1.008f,1.008f,1.008f, 0,0,0,0.5f); + } else if (block->model == BlockModel::xsprite){ + lineBatch->box(pos.x+0.5f, pos.y+0.35f, pos.z+0.5f, + 0.805f,0.705f,0.805f, 0,0,0,0.5f); + } + lineBatch->render(); } - lineBatch->render(); } - glDisable(GL_DEPTH_TEST); - if (level->player->debug) { float length = 40.f; linesShader->use(); - vec3 tsl = vec3(Window::width/2, -((int)Window::height)/2, 0.f); + // top-right: vec3 tsl = vec3(displayWidth - length - 4, -length - 4, 0.f); + vec3 tsl = vec3(displayWidth/2, -((int)displayHeight)/2, 0.f); glm::mat4 model(glm::translate(glm::mat4(1.f), tsl)); linesShader->uniformMatrix("u_projview", glm::ortho( - 0.f, (float)Window::width, - -(float)Window::height, 0.f, + 0.f, (float)displayWidth, + -(float)displayHeight, 0.f, -length, length) * model * glm::inverse(camera->rotation)); lineBatch->lineWidth(4.0f); diff --git a/src/frontend/world_render.h b/src/frontend/world_render.h index 34e9df8b..3ff65c19 100644 --- a/src/frontend/world_render.h +++ b/src/frontend/world_render.h @@ -10,6 +10,8 @@ #include #include +#include "../graphics/GfxContext.h" + class Level; class Camera; class LineBatch; @@ -18,6 +20,7 @@ class Shader; class Texture; class Frustum; class Engine; +class Chunks; class WorldRenderer { Engine* engine; @@ -26,12 +29,13 @@ class WorldRenderer { LineBatch* lineBatch; ChunksRenderer* renderer; bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion); + void drawChunks(Chunks* chunks, Camera* camera, Shader* shader, bool occlusion); public: WorldRenderer(Engine* engine, Level* level); ~WorldRenderer(); - void draw(Camera* camera, bool occlusion); + void draw(const GfxContext& context, Camera* camera, bool occlusion); }; diff --git a/src/graphics/Batch2D.cpp b/src/graphics/Batch2D.cpp index e74a72a4..c27af864 100644 --- a/src/graphics/Batch2D.cpp +++ b/src/graphics/Batch2D.cpp @@ -361,3 +361,7 @@ void Batch2D::render(unsigned int gl_primitive) { void Batch2D::render() { render(GL_TRIANGLES); } + +void Batch2D::lineWidth(float width) { + glLineWidth(width); +} diff --git a/src/graphics/Batch2D.h b/src/graphics/Batch2D.h index 3f2933b9..6d66106f 100644 --- a/src/graphics/Batch2D.h +++ b/src/graphics/Batch2D.h @@ -62,6 +62,8 @@ public: float r4, float g4, float b4, int sh); void render(unsigned int gl_primitive); void render(); + + void lineWidth(float width); }; #endif /* SRC_GRAPHICS_BATCH2D_H_ */ diff --git a/src/graphics/GfxContext.cpp b/src/graphics/GfxContext.cpp new file mode 100644 index 00000000..e15dd5bf --- /dev/null +++ b/src/graphics/GfxContext.cpp @@ -0,0 +1,59 @@ +#include "GfxContext.h" + +#include + +#include "Batch2D.h" + +GfxContext::GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d) + : parent(parent), viewport(viewport), g2d(g2d) { +} + +GfxContext::~GfxContext() { + if (parent == nullptr) + return; + if (depthTest_ != parent->depthTest_) { + if (depthTest_) glDisable(GL_DEPTH_TEST); + else glEnable(GL_DEPTH_TEST); + } + if (cullFace_ != parent->cullFace_) { + if (cullFace_) glDisable(GL_CULL_FACE); + else glEnable(GL_CULL_FACE); + } +} + +const Viewport& GfxContext::getViewport() const { + return viewport; +} + +Batch2D* GfxContext::getBatch2D() const { + return g2d; +} + +GfxContext GfxContext::sub() const { + auto ctx = GfxContext(this, viewport, g2d); + ctx.depthTest_ = depthTest_; + ctx.cullFace_ = cullFace_; + return ctx; +} + +void GfxContext::depthTest(bool flag) { + if (depthTest_ == flag) + return; + depthTest_ = flag; + if (depthTest_) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } +} + +void GfxContext::cullFace(bool flag) { + if (cullFace_ == flag) + return; + cullFace_ = flag; + if (cullFace_) { + glEnable(GL_CULL_FACE); + } else { + glDisable(GL_CULL_FACE); + } +} \ No newline at end of file diff --git a/src/graphics/GfxContext.h b/src/graphics/GfxContext.h new file mode 100644 index 00000000..43e97b5c --- /dev/null +++ b/src/graphics/GfxContext.h @@ -0,0 +1,27 @@ +#ifndef GRAPHICS_GFX_CONTEXT_H_ +#define GRAPHICS_GFX_CONTEXT_H_ + +#include "../typedefs.h" +#include "Viewport.h" + +class Batch2D; + +class GfxContext { + const GfxContext* parent; + Viewport& viewport; + Batch2D* const g2d; + bool depthTest_ = false; + bool cullFace_ = false; +public: + GfxContext(const GfxContext* parent, Viewport& viewport, Batch2D* g2d); + ~GfxContext(); + + Batch2D* getBatch2D() const; + const Viewport& getViewport() const; + GfxContext sub() const; + + void depthTest(bool flag); + void cullFace(bool flag); +}; + +#endif // GRAPHICS_GFX_CONTEXT_H_ \ No newline at end of file diff --git a/src/graphics/Viewport.cpp b/src/graphics/Viewport.cpp new file mode 100644 index 00000000..166d28f8 --- /dev/null +++ b/src/graphics/Viewport.cpp @@ -0,0 +1,13 @@ +#include "Viewport.h" + +Viewport::Viewport(uint width, uint height) + : width(width), height(height) { +} + +uint Viewport::getWidth() const { + return width; +} + +uint Viewport::getHeight() const { + return height; +} \ No newline at end of file diff --git a/src/graphics/Viewport.h b/src/graphics/Viewport.h new file mode 100644 index 00000000..da027b8e --- /dev/null +++ b/src/graphics/Viewport.h @@ -0,0 +1,22 @@ +#ifndef GRAPHICS_VIEWPORT_H_ +#define GRAPHICS_VIEWPORT_H_ + +#include + +#include "../typedefs.h" + +class Viewport { + uint width; + uint height; +public: + Viewport(uint width, uint height); + + virtual uint getWidth() const; + virtual uint getHeight() const; + + glm::vec2 size() const { + return glm::vec2(width, height); + } +}; + +#endif // GRAPHICS_VIEWPORT_H_ \ No newline at end of file diff --git a/src/objects/player_control.cpp b/src/objects/player_control.cpp index 6c3b4fdc..0c426164 100644 --- a/src/objects/player_control.cpp +++ b/src/objects/player_control.cpp @@ -12,6 +12,8 @@ #include "../window/Events.h" #include "../window/input.h" +#include "../core_defs.h" + #define CROUCH_SPEED_MUL 0.25f #define CROUCH_SHIFT_Y -0.2f #define RUN_SPEED_MUL 1.5f @@ -38,18 +40,18 @@ void PlayerController::refreshCamera() { } void PlayerController::updateKeyboard() { - input.zoom = Events::pressed(keycode::C); - input.moveForward = Events::pressed(keycode::W); - input.moveBack = Events::pressed(keycode::S); - input.moveLeft = Events::pressed(keycode::A); - input.moveRight = Events::pressed(keycode::D); - input.sprint = Events::pressed(keycode::LEFT_CONTROL); - input.shift = Events::pressed(keycode::LEFT_SHIFT); - input.cheat = Events::pressed(keycode::R); - input.jump = Events::pressed(keycode::SPACE); + input.moveForward = Events::active(BIND_MOVE_FORWARD); + input.moveBack = Events::active(BIND_MOVE_BACK); + input.moveLeft = Events::active(BIND_MOVE_LEFT); + input.moveRight = Events::active(BIND_MOVE_RIGHT); + input.sprint = Events::active(BIND_MOVE_SPRINT); + input.shift = Events::active(BIND_MOVE_CROUCH); + input.cheat = Events::active(BIND_MOVE_CHEAT); + input.jump = Events::active(BIND_MOVE_JUMP); + input.zoom = Events::active(BIND_CAM_ZOOM); - input.noclip = Events::jpressed(keycode::N); - input.flight = Events::jpressed(keycode::F); + input.noclip = Events::jactive(BIND_PLAYER_NOCLIP); + input.flight = Events::jactive(BIND_PLAYER_FLIGHT); // block choice for (int i = 1; i < 10; i++){ @@ -215,8 +217,21 @@ void PlayerController::updateInteraction(){ Camera* camera = player->camera; vec3 end; vec3 norm; + + bool xkey = Events::pressed(keycode::X); + bool lclick = Events::jclicked(mousecode::BUTTON_1) || + (xkey && Events::clicked(mousecode::BUTTON_1)); + bool rclick = Events::jclicked(mousecode::BUTTON_2) || + (xkey && Events::clicked(mousecode::BUTTON_2)); + float maxDistance = 10.0f; + if (xkey) { + maxDistance *= 20.0f; + } vec3 iend; - voxel* vox = chunks->rayCast(camera->position, camera->front, 10.0f, end, norm, iend); + voxel* vox = chunks->rayCast(camera->position, + camera->front, + maxDistance, + end, norm, iend); if (vox != nullptr){ player->selectedVoxel = *vox; selectedBlockId = vox->id; @@ -238,11 +253,11 @@ void PlayerController::updateInteraction(){ } Block* block = Block::blocks[vox->id]; - if (Events::jclicked(mousecode::BUTTON_1) && block->breakable){ + if (lclick && block->breakable){ chunks->set(x,y,z, 0, 0); lighting->onBlockSet(x,y,z, 0); } - if (Events::jclicked(mousecode::BUTTON_2)){ + if (rclick){ if (block->model != BlockModel::xsprite){ x = (int)(iend.x)+(int)(norm.x); y = (int)(iend.y)+(int)(norm.y); diff --git a/src/typedefs.h b/src/typedefs.h index 8bc06297..920015c6 100644 --- a/src/typedefs.h +++ b/src/typedefs.h @@ -1,3 +1,6 @@ +#ifndef VOX_TYPEDEFS_H +#define VOX_TYPEDEFS_H + #include #include @@ -6,3 +9,5 @@ typedef unsigned char ubyte; typedef uint8_t blockid_t; typedef uint16_t light_t; + +#endif diff --git a/src/util/platform.cpp b/src/util/platform.cpp index 8681d7fc..d4f338d9 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -1,19 +1,23 @@ #include "platform.h" #include -#include #include #include #include "../typedefs.h" #define SETTINGS_FILE "settings.toml" +#define CONTROLS_FILE "controls.json" -using std::string; +using std::filesystem::path; -string platform::get_settings_file() { - return SETTINGS_FILE; +path platform::get_settings_file() { + return path(SETTINGS_FILE); +} + +path platform::get_controls_file() { + return path(CONTROLS_FILE); } #ifdef WIN32 diff --git a/src/util/platform.h b/src/util/platform.h index a56e7d3a..65ed3ce8 100644 --- a/src/util/platform.h +++ b/src/util/platform.h @@ -2,10 +2,12 @@ #define UTIL_PLATFORM_H_ #include +#include namespace platform { extern void configure_encoding(); - extern std::string get_settings_file(); + extern std::filesystem::path get_settings_file(); + extern std::filesystem::path get_controls_file(); } #endif // UTIL_PLATFORM_H_ \ No newline at end of file diff --git a/src/voxel_engine.cpp b/src/voxel_engine.cpp index b0a57e77..00203474 100644 --- a/src/voxel_engine.cpp +++ b/src/voxel_engine.cpp @@ -1,9 +1,9 @@ #include #include #include - #include #include +#include #include "definitions.h" @@ -11,8 +11,11 @@ #include "engine.h" #include "coders/toml.h" +#include "coders/json.h" #include "files/files.h" +#include "window/Events.h" + toml::Wrapper create_wrapper(EngineSettings& settings) { toml::Wrapper wrapper; toml::Section& display = wrapper.add("display"); @@ -38,6 +41,48 @@ toml::Wrapper create_wrapper(EngineSettings& settings) { return wrapper; } +std::string write_controls() { + json::JObject* obj = new json::JObject(); + for (auto& entry : Events::bindings) { + const auto& binding = entry.second; + + json::JObject* jentry = new json::JObject(); + switch (binding.type) { + case inputtype::keyboard: jentry->put("type", "keyboard"); break; + case inputtype::mouse: jentry->put("type", "mouse"); break; + default: throw std::runtime_error("unsupported control type"); + } + jentry->put("code", binding.code); + obj->put(entry.first, jentry); + } + return json::stringify(obj, true, " "); +} + +void load_controls(std::string filename, std::string source) { + json::JObject* obj = json::parse(filename, source); + for (auto& entry : Events::bindings) { + auto& binding = entry.second; + + json::JObject* jentry = obj->obj(entry.first); + if (jentry == nullptr) + continue; + inputtype type; + std::string typestr; + jentry->str("type", typestr); + + if (typestr == "keyboard") { + type = inputtype::keyboard; + } else if (typestr == "mouse") { + type = inputtype::mouse; + } else { + std::cerr << "unknown input type '" << typestr << "'" << std::endl; + continue; + } + binding.type = type; + jentry->num("code", binding.code); + } +} + int main() { platform::configure_encoding(); setup_definitions(); @@ -45,21 +90,26 @@ int main() { EngineSettings settings; toml::Wrapper wrapper = create_wrapper(settings); - std::string settings_file = platform::get_settings_file(); + std::filesystem::path settings_file = platform::get_settings_file(); + std::filesystem::path controls_file = platform::get_controls_file(); if (std::filesystem::is_regular_file(settings_file)) { std::cout << "-- loading settings" << std::endl; std::string content = files::read_string(settings_file); toml::Reader reader(&wrapper, settings_file, content); reader.read(); - } else { - std::cout << "-- creating settings file " << settings_file << std::endl; - files::write_string(settings_file, wrapper.write()); } Engine engine(settings); + setup_bindings(); + if (std::filesystem::is_regular_file(controls_file)) { + std::cout << "-- loading controls" << std::endl; + std::string content = files::read_string(controls_file); + load_controls(controls_file.string(), content); + } engine.mainloop(); std::cout << "-- saving settings" << std::endl; files::write_string(settings_file, wrapper.write()); + files::write_string(controls_file, write_controls()); } catch (const initialize_error& err) { std::cerr << "could not to initialize engine" << std::endl; diff --git a/src/window/Events.cpp b/src/window/Events.cpp index b89c5a4f..6bbc7f63 100644 --- a/src/window/Events.cpp +++ b/src/window/Events.cpp @@ -14,6 +14,7 @@ bool Events::_cursor_locked = false; bool Events::_cursor_started = false; std::vector Events::codepoints; std::vector Events::pressedKeys; +std::unordered_map Events::bindings; int Events::initialize(){ _keys = new bool[1032]; @@ -64,4 +65,47 @@ void Events::pullEvents(){ codepoints.clear(); pressedKeys.clear(); glfwPollEvents(); + + for (auto& entry : bindings) { + auto& binding = entry.second; + binding.justChange = false; + + bool newstate = false; + switch (binding.type) { + case inputtype::keyboard: newstate = pressed(binding.code); break; + case inputtype::mouse: newstate = clicked(binding.code); break; + } + + if (newstate) { + if (!binding.state) { + binding.state = true; + binding.justChange = true; + } + } else { + if (binding.state) { + binding.state = false; + binding.justChange = true; + } + } + } +} + +void Events::bind(std::string name, inputtype type, int code) { + bindings[name] = {type, code, false, false}; +} + +bool Events::active(std::string name) { + const auto& found = bindings.find(name); + if (found == bindings.end()) { + return false; + } + return found->second.active(); +} + +bool Events::jactive(std::string name) { + const auto& found = bindings.find(name); + if (found == bindings.end()) { + return false; + } + return found->second.jactive(); } diff --git a/src/window/Events.h b/src/window/Events.h index 1627ffb1..c4d4813f 100644 --- a/src/window/Events.h +++ b/src/window/Events.h @@ -2,6 +2,11 @@ #define WINDOW_EVENTS_H_ #include "Window.h" +#include "input.h" + +#include +#include +#include typedef unsigned int uint; @@ -18,6 +23,7 @@ public: static bool _cursor_started; static std::vector codepoints; static std::vector pressedKeys; + static std::unordered_map bindings; static int initialize(); static void finalize(); @@ -30,6 +36,10 @@ public: static bool jclicked(int button); static void toggleCursor(); + + static void bind(std::string name, inputtype type, int code); + static bool active(std::string name); + static bool jactive(std::string name); }; #define _MOUSE_BUTTONS 1024 diff --git a/src/window/input.cpp b/src/window/input.cpp index 1f5e50ec..cd39a996 100644 --- a/src/window/input.cpp +++ b/src/window/input.cpp @@ -65,7 +65,81 @@ int keycode::NUM_6 = GLFW_KEY_6; int keycode::NUM_7 = GLFW_KEY_7; int keycode::NUM_8 = GLFW_KEY_8; int keycode::NUM_9 = GLFW_KEY_9; +int keycode::MENU = GLFW_KEY_MENU; +int keycode::PAUSE = GLFW_KEY_PAUSE; +int keycode::INSERT = GLFW_KEY_INSERT; +int keycode::LEFT_SUPER = GLFW_KEY_LEFT_SUPER; +int keycode::RIGHT_SUPER = GLFW_KEY_RIGHT_SUPER; +int keycode::DELETE = GLFW_KEY_DELETE; +int keycode::PAGE_UP = GLFW_KEY_PAGE_UP; +int keycode::PAGE_DOWN = GLFW_KEY_PAGE_DOWN; +int keycode::HOME = GLFW_KEY_HOME; +int keycode::END = GLFW_KEY_END; +int keycode::PRINT_SCREEN = GLFW_KEY_PRINT_SCREEN; +int keycode::NUM_LOCK = GLFW_KEY_NUM_LOCK; +int keycode::LEFT_BRACKET = GLFW_KEY_LEFT_BRACKET; +int keycode::RIGHT_BRACKET = GLFW_KEY_RIGHT_BRACKET; + +const char* keycode::name(int code) { + const char* name = glfwGetKeyName(code, glfwGetKeyScancode(code)); + if (name == nullptr) { + switch (code) { + case GLFW_KEY_TAB: return "Tab"; + case GLFW_KEY_LEFT_CONTROL: return "Left Ctrl"; + case GLFW_KEY_RIGHT_CONTROL: return "Right Ctrl"; + case GLFW_KEY_LEFT_ALT: return "Left Alt"; + case GLFW_KEY_RIGHT_ALT: return "Right Alt"; + case GLFW_KEY_LEFT_SHIFT: return "Left Shift"; + case GLFW_KEY_RIGHT_SHIFT: return "Right Shift"; + case GLFW_KEY_CAPS_LOCK: return "Caps-Lock"; + case GLFW_KEY_SPACE: return "Space"; + case GLFW_KEY_ESCAPE: return "Esc"; + case GLFW_KEY_ENTER: return "Enter"; + case GLFW_KEY_UP: return "Up"; + case GLFW_KEY_DOWN: return "Down"; + case GLFW_KEY_LEFT: return "Left"; + case GLFW_KEY_RIGHT: return "Right"; + case GLFW_KEY_BACKSPACE: return "Backspace"; + case GLFW_KEY_F1: return "F1"; + case GLFW_KEY_F2: return "F2"; + case GLFW_KEY_F3: return "F3"; + case GLFW_KEY_F4: return "F4"; + case GLFW_KEY_F5: return "F5"; + case GLFW_KEY_F6: return "F6"; + case GLFW_KEY_F7: return "F7"; + case GLFW_KEY_F8: return "F8"; + case GLFW_KEY_F9: return "F9"; + case GLFW_KEY_F10: return "F10"; + case GLFW_KEY_F11: return "F11"; + case GLFW_KEY_F12: return "F12"; + case GLFW_KEY_DELETE: return "Delete"; + case GLFW_KEY_HOME: return "Home"; + case GLFW_KEY_END: return "End"; + case GLFW_KEY_LEFT_SUPER: return "Left Super"; + case GLFW_KEY_RIGHT_SUPER: return "Right Super"; + case GLFW_KEY_PAGE_UP: return "Page Up"; + case GLFW_KEY_PAGE_DOWN: return "Page Down"; + case GLFW_KEY_INSERT: return "Insert"; + case GLFW_KEY_PRINT_SCREEN: return "Print Screen"; + case GLFW_KEY_NUM_LOCK: return "Num Lock"; + case GLFW_KEY_MENU: return "Menu"; + case GLFW_KEY_PAUSE: return "Pause"; + default: + return "Unknown"; + } + } + return name; +} int mousecode::BUTTON_1 = GLFW_MOUSE_BUTTON_1; int mousecode::BUTTON_2 = GLFW_MOUSE_BUTTON_2; int mousecode::BUTTON_3 = GLFW_MOUSE_BUTTON_3; + +const char* mousecode::name(int code) { + switch (code) { + case GLFW_MOUSE_BUTTON_1: return "LMB"; + case GLFW_MOUSE_BUTTON_2: return "RMB"; + case GLFW_MOUSE_BUTTON_3: return "MMB"; + } + return "unknown button"; +} diff --git a/src/window/input.h b/src/window/input.h index 9cb9ce3b..afc27935 100644 --- a/src/window/input.h +++ b/src/window/input.h @@ -66,12 +66,59 @@ namespace keycode { extern int NUM_7; extern int NUM_8; extern int NUM_9; + extern int MENU; + extern int PAUSE; + extern int INSERT; + extern int LEFT_SUPER; + extern int RIGHT_SUPER; + extern int DELETE; + extern int PAGE_UP; + extern int PAGE_DOWN; + extern int HOME; + extern int END; + extern int PRINT_SCREEN; + extern int NUM_LOCK; + extern int LEFT_BRACKET; + extern int RIGHT_BRACKET; + + extern const char* name(int code); } namespace mousecode { extern int BUTTON_1; extern int BUTTON_2; extern int BUTTON_3; + + extern const char* name(int code); } +enum class inputtype { + keyboard, + mouse, +}; + +struct Binding { + inputtype type; + int code; + bool state = false; + bool justChange = false; + + bool active() const { + return state; + } + + bool jactive() const { + return state && justChange; + } + + const char* text() const { + switch (type) { + case inputtype::keyboard: return keycode::name(code); + case inputtype::mouse: return mousecode::name(code); + } + return ""; + } +}; + + #endif // WINDOW_INPUT_H_ \ No newline at end of file