Added pause menu, new F3 debug panel, fogCurve setting

This commit is contained in:
MihailRis 2023-11-11 15:35:27 +03:00
parent b9ed7a2b28
commit e48e41c99a
28 changed files with 1267 additions and 324 deletions

View File

@ -8,6 +8,7 @@ out vec4 f_color;
uniform sampler2D u_texture0;
uniform vec3 u_fogColor;
uniform float u_fogFactor;
uniform float u_fogCurve;
void main(){
vec4 tex_color = texture(u_texture0, a_texCoord);
@ -16,6 +17,6 @@ void main(){
// anyway it's any alpha-test alternative required
if (alpha < 0.1f)
discard;
f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, depth*u_fogFactor));
f_color = mix(a_color * tex_color, vec4(u_fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve)));
f_color.a = alpha;
}

View File

@ -72,6 +72,7 @@ void setup_definitions() {
block->lightPassing = true;
block->obstacle = false;
block->model = 2;
block->hitboxScale = 0.5f;
Block::blocks[block->id] = block;
block = new Block(BLOCK_FLOWER, 16);

160
src/engine.cpp Normal file
View File

@ -0,0 +1,160 @@
#include "engine.h"
#include <memory>
#include <iostream>
#include <glm/glm.hpp>
#include "audio/Audio.h"
#include "assets/Assets.h"
#include "assets/AssetsLoader.h"
#include "window/Window.h"
#include "window/Events.h"
#include "window/Camera.h"
#include "window/input.h"
#include "graphics/Batch2D.h"
#include "world/World.h"
#include "world/Level.h"
#include "voxels/Chunk.h"
#include "voxels/Chunks.h"
#include "voxels/ChunksController.h"
#include "voxels/ChunksStorage.h"
#include "objects/Player.h"
#include "frontend/world_render.h"
#include "frontend/hud.h"
#include "frontend/gui/GUI.h"
#include "coders/json.h"
#include "files/files.h"
using std::shared_ptr;
using glm::vec3;
using gui::GUI;
void load_settings(EngineSettings& settings, std::string filename) {
std::string source = files::read_string(filename);
std::unique_ptr<json::JObject> obj(json::parse(filename, source));
obj->num("display-width", settings.displayWidth);
obj->num("display-height", settings.displayHeight);
obj->num("display-samples", settings.displaySamples);
obj->num("display-swap-interval", settings.displaySwapInterval);
obj->num("chunks-load-distance", settings.chunksLoadDistance);
obj->num("chunks-load-speed", settings.chunksLoadSpeed);
obj->num("chunks-padding", settings.chunksPadding);
obj->num("fog-curve", settings.fogCurve);
}
void save_settings(EngineSettings& settings, std::string filename) {
json::JObject obj;
obj.put("display-width", settings.displayWidth);
obj.put("display-height", settings.displayHeight);
obj.put("display-samples", settings.displaySamples);
obj.put("display-swap-interval", settings.displaySwapInterval);
obj.put("chunks-load-distance", settings.chunksLoadDistance);
obj.put("chunks-load-speed", settings.chunksLoadSpeed);
obj.put("chunks-padding", settings.chunksPadding);
obj.put("fog-curve", settings.fogCurve);
files::write_string(filename, json::stringify(&obj, true, " "));
}
Engine::Engine(const EngineSettings& settings) {
this->settings = settings;
Window::initialize(settings.displayWidth,
settings.displayHeight,
settings.displayTitle,
settings.displaySamples);
Window::swapInterval(settings.displaySwapInterval);
assets = new Assets();
std::cout << "-- loading assets" << std::endl;
AssetsLoader loader(assets);
AssetsLoader::createDefaults(loader);
AssetsLoader::addDefaults(loader);
while (loader.hasNext()) {
if (!loader.loadNext()) {
delete assets;
Window::terminate();
throw initialize_error("could not to initialize assets");
}
}
std::cout << "-- loading world" << std::endl;
vec3 playerPosition = vec3(0, 64, 0);
Camera* camera = new Camera(playerPosition, radians(90.0f));
World* world = new World("world-1", "world/", 42);
Player* player = new Player(playerPosition, 4.0f, camera);
level = world->loadLevel(player, settings.chunksLoadDistance, settings.chunksPadding);
std::cout << "-- initializing finished" << std::endl;
Audio::initialize();
gui = new GUI();
}
void Engine::updateTimers() {
frame++;
double currentTime = Window::time();
delta = currentTime - lastTime;
lastTime = currentTime;
}
void Engine::updateHotkeys() {
if (Events::jpressed(keycode::O)) {
occlusion = !occlusion;
}
if (Events::jpressed(keycode::F3)) {
level->player->debug = !level->player->debug;
}
if (Events::jpressed(keycode::F5)) {
for (uint i = 0; i < level->chunks->volume; i++) {
shared_ptr<Chunk> chunk = level->chunks->chunks[i];
if (chunk != nullptr && chunk->isReady()) {
chunk->setModified(true);
}
}
}
}
void Engine::mainloop() {
Camera* camera = level->player->camera;
std::cout << "-- preparing systems" << std::endl;
WorldRenderer worldRenderer(level, assets);
HudRenderer hud(gui, level, assets);
Batch2D batch(1024);
lastTime = Window::time();
while (!Window::isShouldClose()){
updateTimers();
updateHotkeys();
level->update(delta, Events::_cursor_locked, Events::_cursor_locked);
level->chunksController->update(settings.chunksLoadSpeed);
worldRenderer.draw(camera, occlusion, 1.6f / (float)settings.chunksLoadDistance, settings.fogCurve);
hud.draw();
if (level->player->debug) {
hud.drawDebug( 1 / delta, occlusion);
}
gui->act();
gui->draw(&batch, assets);
Window::swapBuffers();
Events::pullEvents();
}
}
Engine::~Engine() {
Audio::finalize();
World* world = level->world;
std::cout << "-- saving world" << std::endl;
world->write(level);
delete level;
delete world;
std::cout << "-- shutting down" << std::endl;
delete assets;
Window::terminate();
}

67
src/engine.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef SRC_ENGINE_H_
#define SRC_ENGINE_H_
#include <string>
#include <memory>
#include <stdexcept>
#include "typedefs.h"
class Assets;
class Level;
namespace gui {
class GUI;
}
struct EngineSettings {
/* Window width (pixels) */
int displayWidth;
/* Window height (pixels) */
int displayHeight;
/* Anti-aliasing samples */
int displaySamples;
/* GLFW swap interval value, 0 - unlimited fps, 1 - vsync*/
int displaySwapInterval;
/* Window title */
const char* displayTitle;
/* Max milliseconds that engine uses for chunks loading only */
uint chunksLoadSpeed;
/* Radius of chunks loading zone (chunk is unit) */
uint chunksLoadDistance;
/* Buffer zone where chunks are not unloading (chunk is unit)*/
uint chunksPadding;
/* Fog opacity is calculated as `pow(depth*k, fogCurve)` where k depends on chunksLoadDistance.
Use values in range [1.0 - 2.0] where 1.0 is linear, 2.0 is quadratic
*/
float fogCurve;
};
void load_settings(EngineSettings& settings, std::string filename);
void save_settings(EngineSettings& settings, std::string filename);
class initialize_error : public std::runtime_error {
public:
initialize_error(const std::string& message) : std::runtime_error(message) {}
};
class Engine {
Assets* assets;
Level* level;
EngineSettings settings;
uint64_t frame = 0;
double lastTime = 0.0;
double delta = 0.0;
bool occlusion = true;
gui::GUI* gui;
public:
Engine(const EngineSettings& settings);
~Engine();
void updateTimers();
void updateHotkeys();
void mainloop();
};
#endif // SRC_ENGINE_H_

85
src/frontend/gui/GUI.cpp Normal file
View File

@ -0,0 +1,85 @@
#include "GUI.h"
#include "UINode.h"
#include "panels.h"
#include <iostream>
#include "../../assets/Assets.h"
#include "../../graphics/Batch2D.h"
#include "../../window/Events.h"
#include "../../window/input.h"
using std::shared_ptr;
using namespace gui;
GUI::GUI() {
container = new Container(vec2(0, 0), vec2(Window::width, Window::height));
}
GUI::~GUI() {
delete container;
}
void GUI::act() {
container->size(vec2(Window::width, Window::height));
int mx = Events::x;
int my = Events::y;
auto hover = container->getAt(vec2(mx, my), nullptr);
if (this->hover && this->hover != hover) {
this->hover->hover(false);
}
if (hover) {
hover->hover(true);
}
this->hover = hover;
if (Events::clicked(0)) {
if (pressed == nullptr && this->hover) {
pressed = hover;
pressed->click(this, mx, my);
if (focus) {
focus->defocus();
}
focus = pressed;
}
if (this->hover == nullptr && focus) {
focus->defocus();
focus = nullptr;
}
} else if (pressed) {
pressed->mouseRelease(this, mx, my);
pressed = nullptr;
}
if (focus) {
if (!focus->isfocused()){
focus = nullptr;
} else if (Events::jpressed(keycode::ESCAPE)) {
focus->defocus();
focus = nullptr;
} else {
for (auto codepoint : Events::codepoints) {
focus->typed(codepoint);
}
for (auto key : Events::pressedKeys) {
focus->keyPressed(key);
}
}
}
}
void GUI::draw(Batch2D* batch, Assets* assets) {
container->draw(batch, assets);
}
shared_ptr<UINode> GUI::getFocused() const {
return focus;
}
bool GUI::isFocusCaught() const {
return focus && focus->isfocuskeeper();
}
void GUI::add(shared_ptr<UINode> panel) {
container->add(panel);
}

64
src/frontend/gui/GUI.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef FRONTEND_GUI_GUI_H_
#define FRONTEND_GUI_GUI_H_
#include <memory>
#include <vector>
#include <glm/glm.hpp>
class Batch2D;
class Assets;
/*
Some info about padding and margin.
Padding is element inner space, margin is outer
glm::vec4 usage:
x - left
y - top
z - right
w - bottom
Outer element
+======================================================================+
| . . . . |
| .padding.y . . . |
| padding.x . . . . padding.z |
|- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - |
| . . . . |
| . .margin.y . . |
| .margin.x . . margin.z. |
|- - - - - - + - - - - - +====================+- - - - - + - - - - - - |
| . | Inner element | . |
|- - - - - - + - - - - - +====================+- - - - - + - - - - - - |
| . . . . |
| . .margin.w . . |
| . . . . |
|- - - - - - + - - - - - + - - - - - - - - - -+- - - - - + - - - - - - |
| . . . . |
| .padding.w . . . |
| . . . . |
+======================================================================+
*/
namespace gui {
class UINode;
class Container;
class GUI {
Container* container;
std::shared_ptr<UINode> hover = nullptr;
std::shared_ptr<UINode> pressed = nullptr;
std::shared_ptr<UINode> focus = nullptr;
public:
GUI();
~GUI();
std::shared_ptr<UINode> getFocused() const;
bool isFocusCaught() const;
void act();
void draw(Batch2D* batch, Assets* assets);
void add(std::shared_ptr<UINode> panel);
};
}
#endif // FRONTEND_GUI_GUI_H_

View File

@ -0,0 +1,24 @@
#include "Panel.h"
#include "../../graphics/Batch2D.h"
using gui::Panel;
Panel::Panel(glm::vec2 coord, glm::vec2 size, glm::vec4 color)
: coord(coord), size(size), color(color) {
}
void Panel::draw(Batch2D* batch) {
batch->texture(nullptr);
batch->color = color;
batch->rect(coord.x, coord.y, size.x, size.y);
}
bool Panel::isVisible() const {
return visible;
}
void Panel::setVisible(bool flag) {
visible = flag;
}

24
src/frontend/gui/Panel.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef FRONTEND_GUI_PANEL_H_
#define FRONTEND_GUI_PANEL_H_
#include <glm/glm.hpp>
class Batch2D;
namespace gui {
class Panel {
glm::vec2 coord;
glm::vec2 size;
glm::vec4 color;
bool visible = true;
public:
Panel(glm::vec2 coord, glm::vec2 size, glm::vec4 color);
void draw(Batch2D* batch);
void setVisible(bool flag);
bool isVisible() const;
};
}
#endif // FRONTEND_GUI_PANEL_H_

134
src/frontend/gui/UINode.cpp Normal file
View File

@ -0,0 +1,134 @@
#include "UINode.h"
#include "../../graphics/Batch2D.h"
using std::shared_ptr;
using gui::UINode;
using gui::Align;
using glm::vec2;
using glm::vec4;
#include <iostream>
UINode::UINode(vec2 coord, vec2 size) : coord(coord), size_(size) {
}
UINode::~UINode() {
}
bool UINode::visible() const {
return isvisible;
}
void UINode::visible(bool flag) {
isvisible = flag;
}
Align UINode::align() const {
return align_;
}
void UINode::align(Align align) {
align_ = align;
}
void UINode::hover(bool flag) {
hover_ = flag;
}
bool UINode::hover() const {
return hover_;
}
void UINode::setParent(UINode* node) {
parent = node;
}
UINode* UINode::getParent() const {
return parent;
}
void UINode::click(GUI*, int x, int y) {
pressed_ = true;
focused_ = true;
}
void UINode::mouseRelease(GUI*, int x, int y) {
pressed_ = false;
}
bool UINode::ispressed() const {
return pressed_;
}
void UINode::defocus() {
focused_ = false;
}
bool UINode::isfocused() const {
return focused_;
}
bool UINode::isInside(glm::vec2 pos) {
vec2 coord = calcCoord();
vec2 size = this->size();
return (pos.x >= coord.x && pos.y >= coord.y &&
pos.x < coord.x + size.x && pos.y < coord.y + size.y);
}
shared_ptr<UINode> UINode::getAt(vec2 pos, shared_ptr<UINode> self) {
return isInside(pos) ? self : nullptr;
}
vec2 UINode::calcCoord() const {
if (parent) {
return coord + parent->calcCoord();
}
return coord;
}
void UINode::setCoord(vec2 coord) {
this->coord = coord;
}
vec2 UINode::size() const {
return size_;
}
void UINode::size(vec2 size) {
if (sizelock)
return;
this->size_ = size;
if (parent) {
sizelock = true;
parent->refresh();
sizelock = false;
}
}
void UINode::_size(vec2 size) {
if (sizelock)
return;
this->size_ = size;
}
void UINode::color(vec4 color) {
this->color_ = color;
}
vec4 UINode::color() const {
return color_;
}
void UINode::margin(vec4 margin) {
this->margin_ = margin;
}
vec4 UINode::margin() const {
return margin_;
}
void UINode::lock() {
}

82
src/frontend/gui/UINode.h Normal file
View File

@ -0,0 +1,82 @@
#ifndef FRONTEND_GUI_UINODE_H_
#define FRONTEND_GUI_UINODE_H_
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include <functional>
class Batch2D;
class Assets;
namespace gui {
class UINode;
class GUI;
typedef std::function<void(GUI*)> onaction;
typedef std::function<void(GUI*, double)> onnumberchange;
enum class Align {
left, center, right
};
class UINode {
protected:
glm::vec2 coord;
glm::vec2 size_;
glm::vec4 color_ {1.0f};
glm::vec4 margin_ {1.0f};
bool isvisible = true;
bool sizelock = false;
bool hover_ = false;
bool pressed_ = false;
bool focused_ = false;
Align align_ = Align::left;
UINode* parent = nullptr;
UINode(glm::vec2 coord, glm::vec2 size);
public:
virtual ~UINode();
virtual void draw(Batch2D* batch, Assets* assets) = 0;
virtual void visible(bool flag);
bool visible() const;
virtual void align(Align align);
Align align() const;
virtual void hover(bool flag);
bool hover() const;
virtual void setParent(UINode* node);
UINode* getParent() const;
virtual void color(glm::vec4 newColor);
glm::vec4 color() const;
virtual void margin(glm::vec4 margin);
glm::vec4 margin() const;
virtual void click(GUI*, int x, int y);
virtual void mouseRelease(GUI*, int x, int y);
bool ispressed() const;
void defocus();
bool isfocused() const;
virtual bool isfocuskeeper() const {return false;}
virtual void typed(unsigned int codepoint) {};
virtual void keyPressed(int key) {};
virtual bool isInside(glm::vec2 pos);
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self);
glm::vec2 calcCoord() const;
void setCoord(glm::vec2 coord);
glm::vec2 size() const;
virtual void size(glm::vec2 size);
void _size(glm::vec2 size);
virtual void refresh() {};
virtual void lock();
};
}
#endif // FRONTEND_GUI_UINODE_H_

View File

@ -0,0 +1,133 @@
#include "controls.h"
#include <iostream>
#include "../../assets/Assets.h"
#include "../../graphics/Batch2D.h"
#include "../../graphics/Font.h"
using std::string;
using std::wstring;
using std::shared_ptr;
using glm::vec2;
#define KEY_ESCAPE 256
#define KEY_ENTER 257
#define KEY_BACKSPACE 259
using namespace gui;
Label::Label(wstring text, string fontName)
: UINode(vec2(), vec2(text.length() * 8, 15)), text_(text), fontName_(fontName) {
}
Label& Label::text(wstring text) {
this->text_ = text;
return *this;
}
wstring Label::text() const {
return text_;
}
void Label::draw(Batch2D* batch, Assets* assets) {
if (supplier) {
text(supplier());
}
batch->color = color_;
Font* font = assets->getFont(fontName_);
vec2 size = this->size();
vec2 newsize = vec2(font->calcWidth(text_), font->lineHeight());
if (newsize.x > size.x) {
this->size(newsize);
size = newsize;
}
vec2 coord = calcCoord();
font->draw(batch, text_, coord.x, coord.y);
}
void Label::textSupplier(wstringsupplier supplier) {
this->supplier = supplier;
}
Button::Button(shared_ptr<UINode> content, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) {
add(content);
}
Button::Button(wstring text, glm::vec4 padding) : Panel(vec2(32,32), padding, 0) {
Label* label = new Label(text);
label->align(Align::center);
add(shared_ptr<UINode>(label));
}
void Button::drawBackground(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
batch->texture(nullptr);
batch->color = (ispressed() ? pressedColor : (hover_ ? hoverColor : color_));
batch->rect(coord.x, coord.y, size_.x, size_.y);
}
shared_ptr<UINode> Button::getAt(vec2 pos, shared_ptr<UINode> self) {
return UINode::getAt(pos, self);
}
void Button::mouseRelease(GUI* gui, int x, int y) {
UINode::mouseRelease(gui, x, y);
if (isInside(vec2(x, y))) {
for (auto callback : actions) {
callback(gui);
}
}
}
void Button::listenAction(onaction action) {
actions.push_back(action);
}
TextBox::TextBox(wstring text, vec4 padding) : Panel(vec2(200,32), padding, 0, false) {
label = new Label(text);
label->align(Align::center);
add(shared_ptr<UINode>(label));
}
void TextBox::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);
if (!focused_ && supplier) {
label->text(supplier());
}
}
void TextBox::typed(unsigned int codepoint) {
label->text(label->text() + wstring({(wchar_t)codepoint}));
}
void TextBox::keyPressed(int key) {
wstring src = label->text();
switch (key) {
case KEY_BACKSPACE:
if (src.length())
label->text(src.substr(0, src.length()-1));
break;
case KEY_ENTER:
if (consumer) {
consumer(label->text());
}
defocus();
break;
}
}
shared_ptr<UINode> TextBox::getAt(vec2 pos, shared_ptr<UINode> self) {
return UINode::getAt(pos, self);
}
void TextBox::textSupplier(wstringsupplier supplier) {
this->supplier = supplier;
}
void TextBox::textConsumer(wstringconsumer consumer) {
this->consumer = consumer;
}

View File

@ -0,0 +1,72 @@
#ifndef FRONTEND_GUI_CONTROLS_H_
#define FRONTEND_GUI_CONTROLS_H_
#include <string>
#include <memory>
#include <vector>
#include <functional>
#include <glm/glm.hpp>
#include "UINode.h"
#include "panels.h"
class Batch2D;
class Assets;
namespace gui {
typedef std::function<std::wstring()> wstringsupplier;
typedef std::function<void(std::wstring)> wstringconsumer;
class Label : public UINode {
protected:
std::wstring text_;
std::string fontName_;
wstringsupplier supplier = nullptr;
public:
Label(std::wstring text, std::string fontName="normal");
virtual Label& text(std::wstring text);
std::wstring text() const;
virtual void draw(Batch2D* batch, Assets* assets);
virtual void textSupplier(wstringsupplier supplier);
};
class Button : public Panel {
protected:
glm::vec4 hoverColor {0.05f, 0.1f, 0.2f, 0.75f};
glm::vec4 pressedColor {0.0f, 0.0f, 0.0f, 0.95f};
std::vector<onaction> actions;
public:
Button(std::shared_ptr<UINode> content, glm::vec4 padding=glm::vec4(2.0f));
Button(std::wstring text, glm::vec4 padding=glm::vec4(2.0f));
virtual void drawBackground(Batch2D* batch, Assets* assets);
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void mouseRelease(GUI*, int x, int y) override;
virtual void listenAction(onaction action);
};
class TextBox : 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;
wstringsupplier supplier = nullptr;
wstringconsumer consumer = nullptr;
public:
TextBox(std::wstring text, glm::vec4 padding=glm::vec4(2.0f));
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
virtual void typed(unsigned int codepoint) override;
virtual void keyPressed(int key) override;
virtual void textSupplier(wstringsupplier supplier);
virtual void textConsumer(wstringconsumer consumer);
virtual bool isfocuskeeper() const override {return true;}
};
}
#endif // FRONTEND_GUI_CONTROLS_H_

130
src/frontend/gui/panels.cpp Normal file
View File

@ -0,0 +1,130 @@
#include "panels.h"
#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 glm::vec2;
using glm::vec4;
Container::Container(vec2 coord, vec2 size) : UINode(coord, size) {
}
shared_ptr<UINode> Container::getAt(vec2 pos, shared_ptr<UINode> self) {
for (auto node : nodes) {
if (!node->visible())
continue;
auto hover = node->getAt(pos, node);
if (hover != nullptr) {
return hover;
}
}
return UINode::getAt(pos, self);
}
void Container::draw(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
vec2 size = this->size();
drawBackground(batch, assets);
batch->texture(nullptr);
batch->render();
Window::pushScissor(vec4(coord.x, coord.y, size.x, size.y));
for (auto node : nodes) {
if (node->visible())
node->draw(batch, assets);
}
batch->render();
Window::popScissor();
}
void Container::add(shared_ptr<UINode> node) {
nodes.push_back(node);
node->setParent(this);
refresh();
}
Panel::Panel(vec2 size, glm::vec4 padding, float interval, bool resizing)
: Container(vec2(), size), padding(padding), interval(interval), resizing_(resizing) {
color_ = vec4(0.0f, 0.0f, 0.0f, 0.75f);
}
Panel::~Panel() {
}
void Panel::drawBackground(Batch2D* batch, Assets* assets) {
vec2 coord = calcCoord();
batch->texture(nullptr);
batch->color = color_;
batch->rect(coord.x, coord.y, size_.x, size_.y);
}
void Panel::refresh() {
float x = padding.x;
float y = padding.y;
vec2 size = this->size();
if (orientation_ == Orientation::vertical) {
float maxw = size.x;
for (auto node : nodes) {
vec2 nodesize = node->size();
const vec4 margin = node->margin();
y += margin.y;
float ex;
switch (node->align()) {
case Align::center:
ex = x + fmax(0.0f, (size.x - margin.z - padding.z) - node->size().x) / 2.0f;
break;
case Align::right:
ex = x + size.x - margin.z - padding.z - node->size().x;
break;
default:
ex = x + margin.x;
}
node->setCoord(vec2(ex, y));
y += nodesize.y + margin.w + interval;
node->size(vec2(size.x - padding.x - padding.z - margin.x - margin.z, nodesize.y));
maxw = fmax(maxw, ex+node->size().x+margin.z+padding.z);
}
if (resizing_)
this->size(vec2(maxw, y+padding.w));
} else {
float maxh = size.y;
for (auto node : nodes) {
vec2 nodesize = node->size();
const vec4 margin = node->margin();
x += margin.x;
node->setCoord(vec2(x, y+margin.y));
x += nodesize.x + margin.z + interval;
node->size(vec2(nodesize.x, size.y - padding.y - padding.w - margin.y - margin.w));
maxh = fmax(maxh, y+margin.y+node->size().y+margin.w+padding.w);
}
bool increased = maxh > size.y;
if (resizing_)
this->size(vec2(x+padding.z, maxh));
if (increased)
refresh();
}
}
void Panel::orientation(Orientation orientation) {
this->orientation_ = orientation;
}
Orientation Panel::orientation() const {
return orientation_;
}
void Panel::lock(){
for (auto node : nodes) {
node->lock();
}
resizing_ = false;
}

46
src/frontend/gui/panels.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef FRONTEND_GUI_PANELS_H_
#define FRONTEND_GUI_PANELS_H_
#include <glm/glm.hpp>
#include <vector>
#include <memory>
#include "UINode.h"
class Batch2D;
class Assets;
namespace gui {
enum class Orientation { vertical, horizontal };
class Container : public UINode {
protected:
std::vector<std::shared_ptr<UINode>> nodes;
public:
Container(glm::vec2 coord, glm::vec2 size);
virtual void drawBackground(Batch2D* batch, Assets* assets) {};
virtual void draw(Batch2D* batch, Assets* assets);
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
virtual void add(std::shared_ptr<UINode> node);
};
class Panel : public Container {
protected:
Orientation orientation_ = Orientation::vertical;
glm::vec4 padding {2.0f};
float interval = 2.0f;
bool resizing_;
public:
Panel(glm::vec2 size, glm::vec4 padding=glm::vec4(2.0f), float interval=2.0f, bool resizing=true);
virtual ~Panel();
virtual void drawBackground(Batch2D* batch, Assets* assets) override;
virtual void orientation(Orientation orientation);
Orientation orientation() const;
virtual void refresh() override;
virtual void lock() override;
};
}
#endif // FRONTEND_GUI_PANELS_H_

View File

@ -1,10 +1,14 @@
#include "hud_render.h"
#include "hud.h"
#include <iostream>
#include <sstream>
#include <memory>
#include <stdexcept>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../typedefs.h"
#include "../util/stringutil.h"
#include "../assets/Assets.h"
#include "../graphics/Shader.h"
#include "../graphics/Batch2D.h"
@ -13,59 +17,132 @@
#include "../window/Camera.h"
#include "../window/Window.h"
#include "../window/Events.h"
#include "../window/input.h"
#include "../voxels/Chunks.h"
#include "../voxels/Block.h"
#include "../world/World.h"
#include "../world/Level.h"
#include "../objects/Player.h"
#include "../physics/Hitbox.h"
#include "gui/controls.h"
#include "gui/panels.h"
#include "gui/UINode.h"
#include "gui/GUI.h"
using std::wstring;
using std::shared_ptr;
using glm::vec2;
using glm::vec3;
using glm::vec4;
using gui::GUI;
using gui::UINode;
using gui::Panel;
using gui::Label;
using gui::Button;
using gui::TextBox;
HudRenderer::HudRenderer(Assets* assets) : assets(assets) {
inline Label* create_label(gui::wstringsupplier supplier) {
Label* label = new Label(L"-");
label->textSupplier(supplier);
return label;
}
HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level), assets(assets), guiController(gui) {
batch = new Batch2D(1024);
uicamera = new Camera(glm::vec3(), Window::height);
uicamera->perspective = false;
uicamera->flipped = true;
Panel* panel = new Panel(vec2(200, 200), vec4(5.0f), 1.0f);
panel->setCoord(vec2(10, 10));
panel->add(shared_ptr<Label>(create_label([this](){
return L"chunks: "+std::to_wstring(this->level->chunks->chunksCount);
})));
panel->add(shared_ptr<Label>(create_label([this](){
return L"fps: "+this->fpsString;
})));
panel->add(shared_ptr<Label>(create_label([this](){
return L"occlusion: "+wstring(this->occlusion ? L"on" : L"off");
})));
panel->add(shared_ptr<Label>(create_label([this](){
std::wstringstream stream;
stream << std::hex << this->level->player->selectedVoxel.states;
return L"block-selected: "+std::to_wstring(this->level->player->selectedVoxel.id)+L" "+stream.str();
})));
panel->add(shared_ptr<Label>(create_label([this](){
return L"meshes: " + std::to_wstring(Mesh::meshesCount);
})));
for (int ax = 0; ax < 3; ax++){
Panel* sub = new Panel(vec2(10, 27), vec4(0.0f));
sub->orientation(gui::Orientation::horizontal);
Label* label = new Label(wstring({L'x'+ax})+L": ");
label->margin(vec4(2, 3, 2, 3));
sub->add(shared_ptr<UINode>(label));
sub->color(vec4(0.0f));
TextBox* box = new TextBox(L"");
box->textSupplier([this, ax]() {
Hitbox* hitbox = this->level->player->hitbox;
return std::to_wstring((int)hitbox->position[ax]);
});
box->textConsumer([this, ax](wstring text) {
try {
this->level->player->hitbox->position[ax] = std::stoi(text);
} catch (std::invalid_argument& _){
}
});
sub->add(shared_ptr<UINode>(box));
panel->add(shared_ptr<UINode>(sub));
}
panel->refresh();
debugPanel = panel;
pauseMenu = new Panel(vec2(350, 200));
pauseMenu->color(vec4(0.0f));
{
Button* button = new Button(L"Continue", vec4(12.0f, 10.0f, 12.0f, 12.0f));
button->listenAction([this](GUI*){
this->pause = false;
});
pauseMenu->add(shared_ptr<UINode>(button));
}
{
Button* button = new Button(L"Save and Quit", vec4(12.0f, 10.0f, 12.0f, 12.0f));
button->listenAction([this](GUI*){
Window::setShouldClose(true);
});
pauseMenu->add(shared_ptr<UINode>(button));
}
guiController->add(shared_ptr<UINode>(debugPanel));
guiController->add(shared_ptr<UINode>(pauseMenu));
}
HudRenderer::~HudRenderer() {
delete batch;
delete uicamera;
delete guiController;
}
void HudRenderer::drawDebug(Level* level, int fps, bool occlusion){
Chunks* chunks = level->chunks;
Player* player = level->player;
Font* font = assets->getFont("normal");
Shader* uishader = assets->getShader("ui");
uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
batch->color = vec4(1.0f);
batch->begin();
font->draw(batch, L"chunks: "+std::to_wstring(chunks->chunksCount), 16, 16, STYLE_OUTLINE);
font->draw(batch, std::to_wstring((int)player->camera->position.x), 10, 30, STYLE_OUTLINE);
font->draw(batch, std::to_wstring((int)player->camera->position.y), 90, 30, STYLE_OUTLINE);
font->draw(batch, std::to_wstring((int)player->camera->position.z), 170, 30, STYLE_OUTLINE);
font->draw(batch, L"fps:", 16, 42, STYLE_OUTLINE);
font->draw(batch, std::to_wstring(fps), 44, 42, STYLE_OUTLINE);
font->draw(batch, L"occlusion: "+std::to_wstring(occlusion), 16, 54, STYLE_OUTLINE);
std::wstringstream stream;
stream << std::hex << player->selectedVoxel.states;
font->draw(batch, L"block-selected: "+std::to_wstring(player->selectedVoxel.id)+L" "+stream.str(), 16, 78, STYLE_OUTLINE);
font->draw(batch, L"meshes: " + std::to_wstring(Mesh::meshesCount), 16, 102, STYLE_OUTLINE);
batch->render();
void HudRenderer::drawDebug(int fps, bool occlusion){
this->occlusion = occlusion;
if (fpsFrame % 60 == 0) {
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
fpsMin = fps;
fpsMax = fps;
}
fpsFrame++;
fpsMin = min(fps, fpsMin);
fpsMax = max(fps, fpsMax);
}
void HudRenderer::drawInventory(Player* player) {
Texture* blocks = assets->getTexture("block");
uint size = 48;
uint step = 64;
uint inv_wm = step*10;
uint inv_hm = step*8;
uint inv_w = inv_wm - (step - size);
uint inv_h = inv_hm - (step - size);
uint inv_cols = 10;
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;
@ -76,17 +153,14 @@ void HudRenderer::drawInventory(Player* player) {
xs = (Window::width + inv_w + step)/2;
ys = (Window::height - inv_h + step)/2;
}
int x = 0;
int y = 0;
vec4 tint = vec4(1.0f);
int mx = Events::x;
int my = Events::y;
uint count = (inv_w / step) * (inv_h / step) + 1;
uint count = inv_cols * inv_rows;
//back
// back
batch->texture(nullptr);
batch->color = vec4(0.0f, 0.0f, 0.0f, 0.3f);
batch->rect(0, 0, Window::width, Window::height);
batch->rect(inv_x - 4, inv_y - 4, inv_w+8, inv_h+8,
0.95f, 0.95f, 0.95f, 0.85f, 0.85f, 0.85f,
0.7f, 0.7f, 0.7f,
@ -97,9 +171,9 @@ void HudRenderer::drawInventory(Player* player) {
0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 4);
batch->color = vec4(0.35f, 0.35f, 0.35f, 1.0f);
for (uint i = 1; i < count; i++) {
x = xs + step * ((i-1) % (inv_w / step));
y = ys + step * ((i-1) / (inv_w / step));
for (uint i = 0; i < count; i++) {
int x = xs + step * (i % (inv_cols));
int y = ys + step * (i / (inv_cols));
batch->rect(x-2, y-2, size+4, size+4,
0.45f, 0.45f, 0.45f, 0.55f, 0.55f, 0.55f,
0.7f, 0.7f, 0.7f,
@ -110,20 +184,20 @@ void HudRenderer::drawInventory(Player* player) {
0.65f, 0.65f, 0.65f, 0.65f, 0.65f, 0.65f, 2);
}
//front
// front
batch->texture(blocks);
for (uint i = 1; i < count; i++) {
Block* cblock = Block::blocks[i];
for (uint i = 0; i < count; i++) {
Block* cblock = Block::blocks[i+1];
if (cblock == nullptr)
break;
x = xs + step * ((i-1) % (inv_w / step));
y = ys + step * ((i-1) / (inv_w / step));
int x = xs + step * (i % inv_cols);
int y = ys + step * (i / inv_cols);
if (mx > x && mx < x + (int)size && my > y && my < y + (int)size) {
tint.r *= 1.2f;
tint.g *= 1.2f;
tint.b *= 1.2f;
if (Events::jclicked(GLFW_MOUSE_BUTTON_LEFT)) {
player->choosenBlock = i;
player->choosenBlock = i+1;
}
} else
{
@ -138,13 +212,16 @@ void HudRenderer::drawInventory(Player* player) {
}
}
void HudRenderer::draw(Level* level){
glDisable(GL_MULTISAMPLE);
uicamera->fov = Window::height;
void HudRenderer::draw(){
debugPanel->visible(level->player->debug);
pauseMenu->visible(pause);
pauseMenu->setCoord(vec2(Window::width/2.0f, Window::height/2.0f) - pauseMenu->size() / 2.0f);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
uicamera->fov = Window::height;
Shader* uishader = assets->getShader("ui");
uishader->use();
uishader->uniformMatrix("u_projview", uicamera->getProjection()*uicamera->getView());
@ -181,7 +258,6 @@ void HudRenderer::draw(Level* level){
0.75f, 0.75f, 0.75f,
0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 2);
batch->texture(blocks);
Player* player = level->player;
{
@ -193,9 +269,30 @@ void HudRenderer::draw(Level* level){
}
}
if (!Events::_cursor_locked) {
if (Events::jpressed(keycode::ESCAPE) && !guiController->isFocusCaught()) {
if (pause) {
pause = false;
} else if (inventoryOpen) {
inventoryOpen = false;
} else {
pause = 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);
}
if (inventoryOpen) {
drawInventory(player);
}
batch->render();
glEnable(GL_MULTISAMPLE);
}

43
src/frontend/hud.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef SRC_HUD_H_
#define SRC_HUD_H_
#include <string>
class Batch2D;
class Camera;
class Level;
class Assets;
class Player;
class Level;
namespace gui {
class GUI;
class Panel;
}
class HudRenderer {
Level* level;
Assets* assets;
Batch2D* batch;
Camera* uicamera;
int fpsMin = 60;
int fpsMax = 60;
int fpsFrame = 0;
std::wstring fpsString;
bool occlusion;
bool inventoryOpen = false;
bool pause = true;
gui::Panel* debugPanel;
gui::Panel* pauseMenu;
gui::GUI* guiController;
public:
HudRenderer(gui::GUI* gui, Level* level, Assets* assets);
~HudRenderer();
void drawInventory(Player* player);
void draw();
void drawDebug(int fps, bool occlusion);
};
#endif /* SRC_HUD_H_ */

View File

@ -1,22 +0,0 @@
#ifndef SRC_HUD_RENDER_H_
#define SRC_HUD_RENDER_H_
class Batch2D;
class Camera;
class Level;
class Assets;
class Player;
class HudRenderer {
Assets* assets;
Batch2D* batch;
Camera* uicamera;
public:
HudRenderer(Assets* assets);
~HudRenderer();
void drawInventory(Player* player);
void draw(Level* level);
void drawDebug(Level* level, int fps, bool occlusion);
};
#endif /* SRC_HUD_RENDER_H_ */

View File

@ -24,9 +24,6 @@
using std::shared_ptr;
float _camera_cx;
float _camera_cz;
WorldRenderer::WorldRenderer(Level* level, Assets* assets) : assets(assets), level(level) {
lineBatch = new LineBatch(4096);
batch3d = new Batch3D(1024);
@ -42,15 +39,6 @@ WorldRenderer::~WorldRenderer() {
delete renderer;
}
Chunks* _chunks = nullptr;
bool chunks_distance_compare(size_t i, size_t j) {
shared_ptr<Chunk> a = _chunks->chunks[i];
shared_ptr<Chunk> b = _chunks->chunks[j];
return ((a->x + 0.5f - _camera_cx)*(a->x + 0.5f - _camera_cx) + (a->z + 0.5f - _camera_cz)*(a->z + 0.5f - _camera_cz) >
(b->x + 0.5f - _camera_cx)*(b->x + 0.5f - _camera_cx) + (b->z + 0.5f - _camera_cz)*(b->z + 0.5f - _camera_cz));
}
bool WorldRenderer::drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion){
shared_ptr<Chunk> chunk = level->chunks->chunks[index];
if (!chunk->isLighted())
@ -75,14 +63,12 @@ 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);
glDisable(GL_MULTISAMPLE);
mesh->draw(GL_TRIANGLES);
glEnable(GL_MULTISAMPLE);
return false;
}
void WorldRenderer::draw(Camera* camera, bool occlusion){
void WorldRenderer::draw(Camera* camera, bool occlusion, float fogFactor, float fogCurve){
Chunks* chunks = level->chunks;
vec4 skyColor(0.7f, 0.81f, 1.0f, 1.0f);
@ -103,7 +89,8 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){
shader->uniform1f("u_gamma", 1.6f);
shader->uniform3f("u_skyLightColor", 1.1f,1.1f,1.1f);
shader->uniform3f("u_fogColor", skyColor.r,skyColor.g,skyColor.b);
shader->uniform1f("u_fogFactor", 0.025f);
shader->uniform1f("u_fogFactor", fogFactor);
shader->uniform1f("u_fogCurve", fogCurve);
shader->uniform3f("u_cameraPos", camera->position.x,camera->position.y,camera->position.z);
Block* cblock = Block::blocks[level->player->choosenBlock];
@ -112,7 +99,6 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){
cblock->emission[1] / 15.0f,
cblock->emission[2] / 15.0f);
shader->uniform1f("u_torchlightDistance", 6.0f);
shader->uniform1f("u_fogFactor", 0.025f);
texture->bind();
std::vector<size_t> indices;
@ -126,11 +112,12 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){
float px = camera->position.x / (float)CHUNK_W;
float pz = camera->position.z / (float)CHUNK_D;
_camera_cx = px;
_camera_cz = pz;
_chunks = chunks;
std::sort(indices.begin(), indices.end(), chunks_distance_compare);
std::sort(indices.begin(), indices.end(), [this, chunks, px, pz](size_t i, size_t j) {
shared_ptr<Chunk> a = chunks->chunks[i];
shared_ptr<Chunk> b = chunks->chunks[j];
return ((a->x + 0.5f - px)*(a->x + 0.5f - px) + (a->z + 0.5f - pz)*(a->z + 0.5f - pz) >
(b->x + 0.5f - px)*(b->x + 0.5f - px) + (b->z + 0.5f - pz)*(b->z + 0.5f - pz));
});
int occludedChunks = 0;
@ -161,9 +148,9 @@ void WorldRenderer::draw(Camera* camera, bool occlusion){
linesShader->use();
linesShader->uniformMatrix("u_projview", camera->getProjection()*camera->getView());
vec3 point = vec3(camera->position.x+camera->front.x/1,
camera->position.y+camera->front.y/1,
camera->position.z+camera->front.z/1);
vec3 point = vec3(camera->position.x+camera->front.x,
camera->position.y+camera->front.y,
camera->position.z+camera->front.z);
glDisable(GL_DEPTH_TEST);

View File

@ -23,7 +23,7 @@ class Framebuffer;
class WorldRenderer {
Batch3D *batch3d;
Batch3D* batch3d;
Assets* assets;
Level* level;
bool drawChunk(size_t index, Camera* camera, Shader* shader, bool occlusion);
@ -34,7 +34,7 @@ public:
WorldRenderer(Level* level, Assets* assets);
~WorldRenderer();
void draw(Camera* camera, bool occlusion);
void draw(Camera* camera, bool occlusion, float fogFactor, float fogCurve);
};

View File

@ -32,7 +32,7 @@
PlayerController::PlayerController(Level* level) : level(level) {
}
void PlayerController::update_controls(float delta){
void PlayerController::update_controls(float delta, bool movement){
Player* player = level->player;
/*block choose*/{
@ -45,10 +45,10 @@ void PlayerController::update_controls(float delta){
Camera* camera = player->camera;
Hitbox* hitbox = player->hitbox;
bool sprint = Events::pressed(keycode::LEFT_CONTROL);
bool shift = Events::pressed(keycode::LEFT_SHIFT) && hitbox->grounded && !sprint;
bool zoom = Events::pressed(keycode::C);
bool cheat = Events::pressed(keycode::R);
bool sprint = Events::pressed(keycode::LEFT_CONTROL) && movement;
bool shift = Events::pressed(keycode::LEFT_SHIFT) && hitbox->grounded && !sprint && movement;
bool zoom = Events::pressed(keycode::C) && movement;
bool cheat = Events::pressed(keycode::R) && movement;
float speed = player->speed;
if (player->flight){
@ -59,7 +59,8 @@ void PlayerController::update_controls(float delta){
}
int substeps = (int)(delta * 1000);
substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps));
level->physics->step(level->chunks, hitbox, delta, substeps, shift, player->flight ? 0.0f : 1.0f, !player->noclip);
if (movement)
level->physics->step(level->chunks, hitbox, delta, substeps, shift, player->flight ? 0.0f : 1.0f, !player->noclip);
camera->position.x = hitbox->position.x;
camera->position.y = hitbox->position.y + 0.7f;
camera->position.z = hitbox->position.z;
@ -81,14 +82,14 @@ void PlayerController::update_controls(float delta){
camera->position -= min(player->interpVel * 0.05f, 1.0f);
}//end
if ((Events::jpressed(keycode::F) && !player->noclip) ||
(Events::jpressed(keycode::N) && player->flight == player->noclip)){
if ((Events::jpressed(keycode::F) && movement && !player->noclip) ||
(Events::jpressed(keycode::N) && movement && player->flight == player->noclip)){
player->flight = !player->flight;
if (player->flight){
hitbox->grounded = false;
}
}
if (Events::jpressed(keycode::N)) {
if (Events::jpressed(keycode::N) && movement) {
player->noclip = !player->noclip;
}
@ -108,23 +109,23 @@ void PlayerController::update_controls(float delta){
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
}//end
if (Events::pressed(keycode::SPACE) && hitbox->grounded){
if (Events::pressed(keycode::SPACE) && movement && hitbox->grounded){
hitbox->velocity.y = JUMP_FORCE;
}
vec3 dir(0,0,0);
if (Events::pressed(keycode::W)){
if (Events::pressed(keycode::W) && movement){
dir.x += camera->dir.x;
dir.z += camera->dir.z;
}
if (Events::pressed(keycode::S)){
if (Events::pressed(keycode::S) && movement){
dir.x -= camera->dir.x;
dir.z -= camera->dir.z;
}
if (Events::pressed(keycode::D)){
if (Events::pressed(keycode::D) && movement){
dir.x += camera->right.x;
dir.z += camera->right.z;
}
if (Events::pressed(keycode::A)){
if (Events::pressed(keycode::A) && movement){
dir.x -= camera->right.x;
dir.z -= camera->right.z;
}
@ -133,10 +134,10 @@ void PlayerController::update_controls(float delta){
if (player->flight){
hitbox->linear_damping = PLAYER_AIR_DAMPING;
hitbox->velocity.y *= 1.0f - delta * 9;
if (Events::pressed(keycode::SPACE)){
if (Events::pressed(keycode::SPACE) && movement){
hitbox->velocity.y += speed * delta * 9;
}
if (Events::pressed(keycode::LEFT_SHIFT)){
if (Events::pressed(keycode::LEFT_SHIFT) && movement){
hitbox->velocity.y -= speed * delta * 9;
}
}

View File

@ -14,7 +14,7 @@ public:
glm::vec3 selectedBlockPosition;
int selectedBlockId = -1;
PlayerController(Level* level);
void update_controls(float delta);
void update_controls(float delta, bool movement);
void update_interaction();
};

View File

@ -3,211 +3,15 @@
#include <stdint.h>
#include <memory>
#include <vector>
#include <ctime>
#include <exception>
#include <filesystem>
// GLM
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "coders/json.h"
#include "files/files.h"
#include "window/Window.h"
#include "window/Events.h"
#include "window/Camera.h"
#include "window/input.h"
#include "audio/Audio.h"
#include "voxels/Chunk.h"
#include "voxels/Chunks.h"
#include "voxels/ChunksController.h"
#include "voxels/ChunksStorage.h"
#include "objects/Player.h"
#include "world/Level.h"
#include "world/World.h"
#include "definitions.h"
#include "assets/Assets.h"
#include "assets/AssetsLoader.h"
#include "frontend/world_render.h"
#include "frontend/hud_render.h"
#define SETTINGS_FILE "settings.json"
using std::shared_ptr;
class initialize_error : public std::runtime_error {
public:
initialize_error(const std::string& message) : std::runtime_error(message) {}
};
struct EngineSettings {
/* Window width (pixels) */
int displayWidth;
/* Window height (pixels) */
int displayHeight;
/* Anti-aliasing samples */
int displaySamples;
/* GLFW swap interval value, 0 - unlimited fps, 1 - vsync*/
int displaySwapInterval;
/* Window title */
const char* displayTitle;
/* Max milliseconds that engine uses for chunks loading only */
uint chunksLoadSpeed;
/* Radius of chunks loading zone (chunk is unit) */
uint chunksLoadDistance;
/* Buffer zone where chunks are not unloading (chunk is unit)*/
uint chunksPadding;
};
void save_settings(EngineSettings& settings, std::string filename);
class Engine {
Assets* assets;
Level* level;
EngineSettings settings;
uint64_t frame = 0;
double lastTime = 0.0;
double delta = 0.0;
bool occlusion = true;
public:
Engine(const EngineSettings& settings);
~Engine();
void updateTimers();
void updateHotkeys();
void mainloop();
};
Engine::Engine(const EngineSettings& settings) {
this->settings = settings;
Window::initialize(settings.displayWidth,
settings.displayHeight,
settings.displayTitle,
settings.displaySamples);
Window::swapInterval(settings.displaySwapInterval);
assets = new Assets();
std::cout << "-- loading assets" << std::endl;
AssetsLoader loader(assets);
AssetsLoader::createDefaults(loader);
AssetsLoader::addDefaults(loader);
while (loader.hasNext()) {
if (!loader.loadNext()) {
delete assets;
Window::terminate();
throw initialize_error("could not to initialize assets");
}
}
std::cout << "-- loading world" << std::endl;
vec3 playerPosition = vec3(0, 64, 0);
Camera* camera = new Camera(playerPosition, radians(90.0f));
World* world = new World("world-1", "world/", 42);
Player* player = new Player(playerPosition, 4.0f, camera);
level = world->loadLevel(player, settings.chunksLoadDistance, settings.chunksPadding);
std::cout << "-- initializing finished" << std::endl;
Audio::initialize();
}
void Engine::updateTimers() {
frame++;
double currentTime = Window::time();
delta = currentTime - lastTime;
lastTime = currentTime;
}
void Engine::updateHotkeys() {
if (Events::jpressed(keycode::TAB)) {
Events::toggleCursor();
}
if (Events::jpressed(keycode::O)) {
occlusion = !occlusion;
}
if (Events::jpressed(keycode::F3)) {
level->player->debug = !level->player->debug;
}
if (Events::jpressed(keycode::F5)) {
for (uint i = 0; i < level->chunks->volume; i++) {
shared_ptr<Chunk> chunk = level->chunks->chunks[i];
if (chunk != nullptr && chunk->isReady()) {
chunk->setModified(true);
}
}
}
}
void Engine::mainloop() {
Camera* camera = level->player->camera;
std::cout << "-- preparing systems" << std::endl;
WorldRenderer worldRenderer(level, assets);
HudRenderer hud(assets);
lastTime = Window::time();
while (!Window::isShouldClose()){
updateTimers();
updateHotkeys();
level->update(delta, Events::_cursor_locked);
level->chunksController->update(settings.chunksLoadSpeed);
worldRenderer.draw(camera, occlusion);
hud.draw(level);
if (level->player->debug) {
hud.drawDebug(level, 1 / delta, occlusion);
}
Window::swapBuffers();
Events::pullEvents();
}
}
Engine::~Engine() {
Audio::finalize();
World* world = level->world;
std::cout << "-- saving world" << std::endl;
world->write(level);
delete level;
delete world;
std::cout << "-- shutting down" << std::endl;
delete assets;
Window::terminate();
}
void load_settings(EngineSettings& settings, std::string filename) {
std::string source = files::read_string(filename);
std::unique_ptr<json::JObject> obj(json::parse(filename, source));
obj->num("display-width", settings.displayWidth);
obj->num("display-height", settings.displayHeight);
obj->num("display-samples", settings.displaySamples);
obj->num("display-swap-interval", settings.displaySwapInterval);
obj->num("chunks-load-distance", settings.chunksLoadDistance);
obj->num("chunks-load-speed", settings.chunksLoadSpeed);
obj->num("chunks-padding", settings.chunksPadding);
}
void save_settings(EngineSettings& settings, std::string filename) {
json::JObject obj;
obj.put("display-width", settings.displayWidth);
obj.put("display-height", settings.displayHeight);
obj.put("display-samples", settings.displaySamples);
obj.put("display-swap-interval", settings.displaySwapInterval);
obj.put("chunks-load-distance", settings.chunksLoadDistance);
obj.put("chunks-load-speed", settings.chunksLoadSpeed);
obj.put("chunks-padding", settings.chunksPadding);
files::write_string(filename, json::stringify(&obj, true, " "));
}
#include "util/platform.h"
#include "engine.h"
int main() {
platform::configure_encoding();
setup_definitions();
try {
EngineSettings settings;
@ -219,12 +23,15 @@ int main() {
settings.chunksLoadDistance = 12;
settings.chunksPadding = 2;
settings.displaySwapInterval = 1;
settings.fogCurve = 1.6f;
if (std::filesystem::is_regular_file(SETTINGS_FILE)) {
std::string settings_file = platform::get_settings_file();
if (std::filesystem::is_regular_file(settings_file)) {
std::cout << "-- loading settings" << std::endl;
load_settings(settings, SETTINGS_FILE);
load_settings(settings, settings_file);
} else {
save_settings(settings, SETTINGS_FILE);
std::cout << "-- creating settings file " << settings_file << std::endl;
save_settings(settings, settings_file);
}
Engine engine(settings);
engine.mainloop();

View File

@ -28,7 +28,6 @@ public:
bool breakable = true;
bool rotatable = false;
float hitboxScale = 1;
float hitboxY = 1;
Block(unsigned int id, int texture);
};

View File

@ -137,7 +137,7 @@ void WorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
} else if (real_y < height){
id = BLOCK_DIRT;
} else {
int tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 23);
int tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 12);
if (tree) {
id = tree;
states = 0x32;

View File

@ -91,6 +91,8 @@ int Window::initialize(uint width, uint height, const char* title, int samples){
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Window::width = width;
@ -105,6 +107,10 @@ int Window::initialize(uint width, uint height, const char* title, int samples){
return 0;
}
void Window::clear() {
glClear(GL_COLOR_BUFFER_BIT);
}
void Window::viewport(int x, int y, int width, int height){
glViewport(x, y, width, height);
}

View File

@ -30,6 +30,8 @@ public:
static void popScissor();
static void resetScissor();
static void clear();
static double time();
};

View File

@ -38,8 +38,8 @@ Level::~Level(){
delete playerController;
}
void Level::update(float delta, bool interactions) {
playerController->update_controls(delta);
void Level::update(float delta, bool updatePlayer, bool interactions) {
playerController->update_controls(delta, updatePlayer);
if (interactions) {
playerController->update_interaction();
}

View File

@ -32,7 +32,7 @@ public:
uint chunksPadding);
~Level();
void update(float delta, bool interactions);
void update(float delta, bool updatePlayer, bool interactions);
};
#endif /* WORLD_LEVEL_H_ */