Refactor and fixes

This commit is contained in:
MihailRis 2023-11-12 02:44:02 +03:00
parent b4a3608302
commit 63b5f4bc6b
25 changed files with 394 additions and 278 deletions

View File

@ -106,7 +106,7 @@ int _png_load(const char* file, int* width, int* height){
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 3); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);

View File

@ -30,40 +30,12 @@ using std::shared_ptr;
using glm::vec3; using glm::vec3;
using gui::GUI; 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) { Engine::Engine(const EngineSettings& settings_) {
this->settings = settings; this->settings = settings_;
Window::initialize(settings.displayWidth, Window::initialize(settings.display);
settings.displayHeight,
settings.displayTitle,
settings.displaySamples);
Window::swapInterval(settings.displaySwapInterval);
assets = new Assets(); assets = new Assets();
std::cout << "-- loading assets" << std::endl; std::cout << "-- loading assets" << std::endl;
@ -82,7 +54,7 @@ Engine::Engine(const EngineSettings& settings) {
Camera* camera = new Camera(playerPosition, radians(90.0f)); Camera* camera = new Camera(playerPosition, radians(90.0f));
World* world = new World("world-1", "world/", 42); World* world = new World("world-1", "world/", 42);
Player* player = new Player(playerPosition, 4.0f, camera); Player* player = new Player(playerPosition, 4.0f, camera);
level = world->loadLevel(player, settings.chunksLoadDistance, settings.chunksPadding); level = world->loadLevel(player, settings);
std::cout << "-- initializing finished" << std::endl; std::cout << "-- initializing finished" << std::endl;
@ -116,8 +88,9 @@ void Engine::updateHotkeys() {
} }
void Engine::mainloop() { void Engine::mainloop() {
Camera* camera = level->player->camera;
std::cout << "-- preparing systems" << std::endl; std::cout << "-- preparing systems" << std::endl;
Camera* camera = level->player->camera;
WorldRenderer worldRenderer(level, assets); WorldRenderer worldRenderer(level, assets);
HudRenderer hud(gui, level, assets); HudRenderer hud(gui, level, assets);
Batch2D batch(1024); Batch2D batch(1024);
@ -127,15 +100,18 @@ void Engine::mainloop() {
updateTimers(); updateTimers();
updateHotkeys(); updateHotkeys();
level->update(delta, Events::_cursor_locked, Events::_cursor_locked); bool inputLocked = hud.isPause() || hud.isInventoryOpen() || gui->isFocusCaught();
level->chunksController->update(settings.chunksLoadSpeed); level->updatePlayer(delta, !inputLocked, hud.isPause(), !inputLocked);
level->update();
level->chunksController->update(settings.chunks.loadSpeed);
worldRenderer.draw(camera, occlusion, 1.6f / (float)settings.chunksLoadDistance, settings.fogCurve); float fovFactor = 1.6f / (float)settings.chunks.loadDistance;
worldRenderer.draw(camera, occlusion, fovFactor, settings.fogCurve);
hud.draw(); hud.draw();
if (level->player->debug) { if (level->player->debug) {
hud.drawDebug( 1 / delta, occlusion); hud.drawDebug( 1 / delta, occlusion);
} }
gui->act(); gui->act(delta);
gui->draw(&batch, assets); gui->draw(&batch, assets);
Window::swapBuffers(); Window::swapBuffers();

View File

@ -5,6 +5,7 @@
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
#include "typedefs.h" #include "typedefs.h"
#include "settings.h"
class Assets; class Assets;
class Level; class Level;
@ -13,32 +14,6 @@ namespace gui {
class 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 { class initialize_error : public std::runtime_error {
public: public:
initialize_error(const std::string& message) : std::runtime_error(message) {} initialize_error(const std::string& message) : std::runtime_error(message) {}

View File

@ -20,7 +20,15 @@ GUI::~GUI() {
delete container; delete container;
} }
void GUI::act() { void GUI::act(float delta) {
for (IntervalEvent& event : intervalEvents) {
event.timer += delta;
if (event.timer > event.interval) {
event.callback();
event.timer = fmod(event.timer, event.interval);
}
}
container->size(vec2(Window::width, Window::height)); container->size(vec2(Window::width, Window::height));
int mx = Events::x; int mx = Events::x;
int my = Events::y; int my = Events::y;
@ -83,3 +91,7 @@ bool GUI::isFocusCaught() const {
void GUI::add(shared_ptr<UINode> panel) { void GUI::add(shared_ptr<UINode> panel) {
container->add(panel); container->add(panel);
} }
void GUI::interval(float interval, ontimeout callback) {
intervalEvents.push_back({callback, interval, 0.0f});
}

View File

@ -4,6 +4,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <functional>
class Batch2D; class Batch2D;
class Assets; class Assets;
@ -43,11 +44,19 @@ namespace gui {
class UINode; class UINode;
class Container; class Container;
typedef std::function<void()> ontimeout;
struct IntervalEvent {
ontimeout callback;
float interval;
float timer;
};
class GUI { class GUI {
Container* container; Container* container;
std::shared_ptr<UINode> hover = nullptr; std::shared_ptr<UINode> hover = nullptr;
std::shared_ptr<UINode> pressed = nullptr; std::shared_ptr<UINode> pressed = nullptr;
std::shared_ptr<UINode> focus = nullptr; std::shared_ptr<UINode> focus = nullptr;
std::vector<IntervalEvent> intervalEvents;
public: public:
GUI(); GUI();
~GUI(); ~GUI();
@ -55,9 +64,11 @@ namespace gui {
std::shared_ptr<UINode> getFocused() const; std::shared_ptr<UINode> getFocused() const;
bool isFocusCaught() const; bool isFocusCaught() const;
void act(); void act(float delta);
void draw(Batch2D* batch, Assets* assets); void draw(Batch2D* batch, Assets* assets);
void add(std::shared_ptr<UINode> panel); void add(std::shared_ptr<UINode> panel);
void interval(float interval, ontimeout callback);
}; };
} }

View File

@ -1,24 +0,0 @@
#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;
}

View File

@ -1,24 +0,0 @@
#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_

View File

@ -34,12 +34,7 @@ using std::shared_ptr;
using glm::vec2; using glm::vec2;
using glm::vec3; using glm::vec3;
using glm::vec4; using glm::vec4;
using gui::GUI; using namespace gui;
using gui::UINode;
using gui::Panel;
using gui::Label;
using gui::Button;
using gui::TextBox;
inline Label* create_label(gui::wstringsupplier supplier) { inline Label* create_label(gui::wstringsupplier supplier) {
Label* label = new Label(L"-"); Label* label = new Label(L"-");
@ -49,10 +44,15 @@ inline Label* create_label(gui::wstringsupplier supplier) {
HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level), assets(assets), guiController(gui) { HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level), assets(assets), guiController(gui) {
batch = new Batch2D(1024); batch = new Batch2D(1024);
uicamera = new Camera(glm::vec3(), Window::height); uicamera = new Camera(vec3(), Window::height);
uicamera->perspective = false; uicamera->perspective = false;
uicamera->flipped = true; uicamera->flipped = true;
gui->interval(1.0f, [this]() {
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
fpsMin = fps;
fpsMax = fps;
});
Panel* panel = new Panel(vec2(200, 200), vec4(5.0f), 1.0f); Panel* panel = new Panel(vec2(200, 200), vec4(5.0f), 1.0f);
panel->setCoord(vec2(10, 10)); panel->setCoord(vec2(10, 10));
panel->add(shared_ptr<Label>(create_label([this](){ panel->add(shared_ptr<Label>(create_label([this](){
@ -74,11 +74,14 @@ HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level),
}))); })));
for (int ax = 0; ax < 3; ax++){ for (int ax = 0; ax < 3; ax++){
Panel* sub = new Panel(vec2(10, 27), vec4(0.0f)); Panel* sub = new Panel(vec2(10, 27), vec4(0.0f));
sub->orientation(gui::Orientation::horizontal); sub->orientation(Orientation::horizontal);
Label* label = new Label(wstring({L'x'+ax})+L": "); Label* label = new Label(wstring({L'x'+ax})+L": ");
label->margin(vec4(2, 3, 2, 3)); label->margin(vec4(2, 3, 2, 3));
sub->add(shared_ptr<UINode>(label)); sub->add(shared_ptr<UINode>(label));
sub->color(vec4(0.0f)); sub->color(vec4(0.0f));
// Coordinate input
TextBox* box = new TextBox(L""); TextBox* box = new TextBox(L"");
box->textSupplier([this, ax]() { box->textSupplier([this, ax]() {
Hitbox* hitbox = this->level->player->hitbox; Hitbox* hitbox = this->level->player->hitbox;
@ -86,7 +89,9 @@ HudRenderer::HudRenderer(GUI* gui, Level* level, Assets* assets) : level(level),
}); });
box->textConsumer([this, ax](wstring text) { box->textConsumer([this, ax](wstring text) {
try { try {
this->level->player->hitbox->position[ax] = std::stoi(text); vec3 position = this->level->player->hitbox->position;
position[ax] = std::stoi(text);
this->level->player->teleport(position);
} catch (std::invalid_argument& _){ } catch (std::invalid_argument& _){
} }
}); });
@ -125,12 +130,7 @@ HudRenderer::~HudRenderer() {
void HudRenderer::drawDebug(int fps, bool occlusion){ void HudRenderer::drawDebug(int fps, bool occlusion){
this->occlusion = occlusion; this->occlusion = occlusion;
if (fpsFrame % 60 == 0) { this->fps = fps;
fpsString = std::to_wstring(fpsMax)+L" / "+std::to_wstring(fpsMin);
fpsMin = fps;
fpsMax = fps;
}
fpsFrame++;
fpsMin = min(fps, fpsMin); fpsMin = min(fps, fpsMin);
fpsMax = max(fps, fpsMax); fpsMax = max(fps, fpsMax);
} }
@ -240,6 +240,7 @@ void HudRenderer::draw(){
batch->line(width/2-5, height/2-5, width/2+5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f); batch->line(width/2-5, height/2-5, width/2+5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f);
batch->line(width/2+5, height/2-5, width/2-5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f); batch->line(width/2+5, height/2-5, width/2-5, height/2+5, 0.9f, 0.9f, 0.9f, 1.0f);
} }
Player* player = level->player;
batch->rect(Window::width/2-128-4, Window::height-80-4, 256+8, 64+8, batch->rect(Window::width/2-128-4, Window::height-80-4, 256+8, 64+8,
0.95f, 0.95f, 0.95f, 0.85f, 0.85f, 0.85f, 0.95f, 0.95f, 0.95f, 0.85f, 0.85f, 0.85f,
@ -259,7 +260,7 @@ void HudRenderer::draw(){
0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 2); 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 2);
batch->texture(blocks); batch->texture(blocks);
Player* player = level->player;
{ {
Block* cblock = Block::blocks[player->choosenBlock]; Block* cblock = Block::blocks[player->choosenBlock];
if (cblock->model == BLOCK_MODEL_CUBE){ if (cblock->model == BLOCK_MODEL_CUBE){
@ -296,3 +297,11 @@ void HudRenderer::draw(){
} }
batch->render(); batch->render();
} }
bool HudRenderer::isInventoryOpen() const {
return inventoryOpen;
}
bool HudRenderer::isPause() const {
return pause;
}

View File

@ -21,9 +21,9 @@ class HudRenderer {
Batch2D* batch; Batch2D* batch;
Camera* uicamera; Camera* uicamera;
int fps = 60;
int fpsMin = 60; int fpsMin = 60;
int fpsMax = 60; int fpsMax = 60;
int fpsFrame = 0;
std::wstring fpsString; std::wstring fpsString;
bool occlusion; bool occlusion;
bool inventoryOpen = false; bool inventoryOpen = false;
@ -38,6 +38,9 @@ public:
void drawInventory(Player* player); void drawInventory(Player* player);
void draw(); void draw();
void drawDebug(int fps, bool occlusion); void drawDebug(int fps, bool occlusion);
bool isInventoryOpen() const;
bool isPause() const;
}; };
#endif /* SRC_HUD_H_ */ #endif /* SRC_HUD_H_ */

View File

@ -7,17 +7,12 @@ Texture::Texture(unsigned int id, int width, int height) : id(id), width(width),
Texture::Texture(unsigned char* data, int width, int height) : width(width), height(height) { Texture::Texture(unsigned char* data, int width, int height) : width(width), height(height) {
glGenTextures(1, &id); glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data); GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
} }
Texture::~Texture() { Texture::~Texture() {
@ -31,10 +26,7 @@ void Texture::bind(){
void Texture::reload(unsigned char* data){ void Texture::reload(unsigned char* data){
glBindTexture(GL_TEXTURE_2D, id); glBindTexture(GL_TEXTURE_2D, id);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data); GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data);
// glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
} }

View File

@ -17,3 +17,7 @@ Player::Player(glm::vec3 position, float speed, Camera* camera) :
Player::~Player(){ Player::~Player(){
delete hitbox; delete hitbox;
} }
void Player::teleport(glm::vec3 position) {
hitbox->position = position;
}

View File

@ -26,6 +26,8 @@ public:
voxel selectedVoxel {0, 0}; voxel selectedVoxel {0, 0};
Player(glm::vec3 position, float speed, Camera* camera); Player(glm::vec3 position, float speed, Camera* camera);
~Player(); ~Player();
void teleport(glm::vec3 position);
}; };
#endif /* SRC_OBJECTS_PLAYER_H_ */ #endif /* SRC_OBJECTS_PLAYER_H_ */

View File

@ -29,46 +29,100 @@
#define CHEAT_SPEED_MUL 5.0f #define CHEAT_SPEED_MUL 5.0f
#define JUMP_FORCE 7.0f #define JUMP_FORCE 7.0f
PlayerController::PlayerController(Level* level) : level(level) { PlayerController::PlayerController(Level* level, const EngineSettings& settings)
: level(level), player(level->player), camSettings(settings.camera) {
} }
void PlayerController::update_controls(float delta, bool movement){ void PlayerController::refreshCamera() {
Player* player = level->player; level->player->camera->position = level->player->hitbox->position + cameraOffset;
}
/*block choose*/{ 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.noclip = Events::jpressed(keycode::N);
input.flight = Events::jpressed(keycode::F);
// block choice
for (int i = 1; i < 10; i++){ for (int i = 1; i < 10; i++){
if (Events::jpressed(keycode::NUM_0+i)){ if (Events::jpressed(keycode::NUM_0+i)){
player->choosenBlock = i; player->choosenBlock = i;
} }
} }
}//end }
void PlayerController::resetKeyboard() {
input.zoom = false;
input.moveForward = false;
input.moveBack = false;
input.moveLeft = false;
input.moveRight = false;
input.sprint = false;
input.shift = false;
input.cheat = false;
input.jump = false;
}
void PlayerController::updateControls(float delta){
Player* player = level->player;
Camera* camera = player->camera; Camera* camera = player->camera;
Hitbox* hitbox = player->hitbox; Hitbox* hitbox = player->hitbox;
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;
bool crouch = input.shift && hitbox->grounded && !input.sprint;
float speed = player->speed; float speed = player->speed;
if (player->flight){ if (player->flight){
speed *= FLIGHT_SPEED_MUL; speed *= FLIGHT_SPEED_MUL;
} }
if (cheat){ if (input.cheat){
speed *= CHEAT_SPEED_MUL; speed *= CHEAT_SPEED_MUL;
} }
vec3 dir(0,0,0);
if (input.moveForward){
dir.x += camera->dir.x;
dir.z += camera->dir.z;
}
if (input.moveBack){
dir.x -= camera->dir.x;
dir.z -= camera->dir.z;
}
if (input.moveRight){
dir.x += camera->right.x;
dir.z += camera->right.z;
}
if (input.moveLeft){
dir.x -= camera->right.x;
dir.z -= camera->right.z;
}
if (length(dir) > 0.0f){
dir = normalize(dir);
hitbox->velocity.x += dir.x * speed * delta * 9;
hitbox->velocity.z += dir.z * speed * delta * 9;
}
int substeps = (int)(delta * 1000); int substeps = (int)(delta * 1000);
substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps)); substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps));
if (movement) level->physics->step(level->chunks, hitbox, delta, substeps, crouch, player->flight ? 0.0f : 1.0f, !player->noclip);
level->physics->step(level->chunks, hitbox, delta, substeps, shift, player->flight ? 0.0f : 1.0f, !player->noclip); if (player->flight && hitbox->grounded) {
camera->position.x = hitbox->position.x;
camera->position.y = hitbox->position.y + 0.7f;
camera->position.z = hitbox->position.z;
if (player->flight && hitbox->grounded)
player->flight = false; player->flight = false;
}
/*camera shaking*/{ if (input.jump && hitbox->grounded){
hitbox->velocity.y = JUMP_FORCE;
}
cameraOffset = vec3(0.0f, 0.7f, 0.0f);
if (camSettings.shaking) {
player->interpVel = player->interpVel * (1.0f - delta * 5) + hitbox->velocity * delta * 0.1f; player->interpVel = player->interpVel * (1.0f - delta * 5) + hitbox->velocity * delta * 0.1f;
if (hitbox->grounded && player->interpVel.y < 0.0f){ if (hitbox->grounded && player->interpVel.y < 0.0f){
player->interpVel.y *= -30.0f; player->interpVel.y *= -30.0f;
@ -77,84 +131,62 @@ void PlayerController::update_controls(float delta, bool movement){
player->cameraShakingTimer += delta * factor * CAMERA_SHAKING_SPEED; player->cameraShakingTimer += delta * factor * CAMERA_SHAKING_SPEED;
float shakeTimer = player->cameraShakingTimer; float shakeTimer = player->cameraShakingTimer;
player->cameraShaking = player->cameraShaking * (1.0f - delta * CAMERA_SHAKING_DELTA_K) + factor * delta * CAMERA_SHAKING_DELTA_K; player->cameraShaking = player->cameraShaking * (1.0f - delta * CAMERA_SHAKING_DELTA_K) + factor * delta * CAMERA_SHAKING_DELTA_K;
camera->position += camera->right * sin(shakeTimer) * CAMERA_SHAKING_OFFSET * player->cameraShaking; cameraOffset += camera->right * sin(shakeTimer) * CAMERA_SHAKING_OFFSET * player->cameraShaking;
camera->position += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking; cameraOffset += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking;
camera->position -= min(player->interpVel * 0.05f, 1.0f); cameraOffset -= min(player->interpVel * 0.05f, 1.0f);
}//end }
if ((Events::jpressed(keycode::F) && movement && !player->noclip) || if ((input.flight && !player->noclip) ||
(Events::jpressed(keycode::N) && movement && player->flight == player->noclip)){ (input.noclip && player->flight == player->noclip)){
player->flight = !player->flight; player->flight = !player->flight;
if (player->flight){ if (player->flight){
hitbox->grounded = false; hitbox->grounded = false;
} }
} }
if (Events::jpressed(keycode::N) && movement) { if (input.noclip) {
player->noclip = !player->noclip; player->noclip = !player->noclip;
} }
/*field of view manipulations*/{ if (camSettings.fovEvents){
float dt = min(1.0f, delta * ZOOM_SPEED); float dt = min(1.0f, delta * ZOOM_SPEED);
float zoomValue = 1.0f; float zoomValue = 1.0f;
if (shift){ if (crouch){
speed *= CROUCH_SPEED_MUL; speed *= CROUCH_SPEED_MUL;
camera->position.y += CROUCH_SHIFT_Y; cameraOffset += CROUCH_SHIFT_Y;
zoomValue = CROUCH_ZOOM; zoomValue = CROUCH_ZOOM;
} else if (sprint){ } else if (input.sprint){
speed *= RUN_SPEED_MUL; speed *= RUN_SPEED_MUL;
zoomValue = RUN_ZOOM; zoomValue = RUN_ZOOM;
} }
if (zoom) if (input.zoom)
zoomValue *= C_ZOOM; zoomValue *= C_ZOOM;
camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt); camera->zoom = zoomValue * dt + camera->zoom * (1.0f - dt);
}//end
if (Events::pressed(keycode::SPACE) && movement && hitbox->grounded){
hitbox->velocity.y = JUMP_FORCE;
}
vec3 dir(0,0,0);
if (Events::pressed(keycode::W) && movement){
dir.x += camera->dir.x;
dir.z += camera->dir.z;
}
if (Events::pressed(keycode::S) && movement){
dir.x -= camera->dir.x;
dir.z -= camera->dir.z;
}
if (Events::pressed(keycode::D) && movement){
dir.x += camera->right.x;
dir.z += camera->right.z;
}
if (Events::pressed(keycode::A) && movement){
dir.x -= camera->right.x;
dir.z -= camera->right.z;
} }
hitbox->linear_damping = PLAYER_GROUND_DAMPING; hitbox->linear_damping = PLAYER_GROUND_DAMPING;
if (player->flight){ if (player->flight){
hitbox->linear_damping = PLAYER_AIR_DAMPING; hitbox->linear_damping = PLAYER_AIR_DAMPING;
hitbox->velocity.y *= 1.0f - delta * 9; hitbox->velocity.y *= 1.0f - delta * 9;
if (Events::pressed(keycode::SPACE) && movement){ if (input.jump){
hitbox->velocity.y += speed * delta * 9; hitbox->velocity.y += speed * delta * 9;
} }
if (Events::pressed(keycode::LEFT_SHIFT) && movement){ if (input.shift){
hitbox->velocity.y -= speed * delta * 9; hitbox->velocity.y -= speed * delta * 9;
} }
} }
if (!hitbox->grounded) if (!hitbox->grounded) {
hitbox->linear_damping = PLAYER_AIR_DAMPING; hitbox->linear_damping = PLAYER_AIR_DAMPING;
if (length(dir) > 0.0f){
dir = normalize(dir);
hitbox->velocity.x += dir.x * speed * delta * 9;
hitbox->velocity.z += dir.z * speed * delta * 9;
} }
input.noclip = false;
input.flight = false;
}
/*camera rotate*/{ void PlayerController::updateCameraControl() {
if (Events::_cursor_locked){ Camera* camera = player->camera;
float rotX = -Events::deltaX / Window::height * 2; float rotX = -Events::deltaX / Window::height * 2;
float rotY = -Events::deltaY / Window::height * 2; float rotY = -Events::deltaY / Window::height * 2;
if (zoom){ if (input.zoom){
rotX /= 4; rotX /= 4;
rotY /= 4; rotY /= 4;
} }
@ -171,10 +203,8 @@ void PlayerController::update_controls(float delta, bool movement){
camera->rotation = mat4(1.0f); camera->rotation = mat4(1.0f);
camera->rotate(player->camY, player->camX, 0); camera->rotate(player->camY, player->camX, 0);
} }
}//end
}
void PlayerController::update_interaction(){ void PlayerController::updateInteraction(){
Chunks* chunks = level->chunks; Chunks* chunks = level->chunks;
Player* player = level->player; Player* player = level->player;
Lighting* lighting = level->lighting; Lighting* lighting = level->lighting;
@ -193,22 +223,13 @@ void PlayerController::update_interaction(){
uint8_t states = 0; uint8_t states = 0;
if (Block::blocks[player->choosenBlock]->rotatable){ if (Block::blocks[player->choosenBlock]->rotatable){
// states = states & 0b11111100;
// if (abs(norm.x) > abs(norm.z)){
// if (abs(norm.x) > abs(norm.y)) states = states | 0b00000001;
// if (abs(norm.x) < abs(norm.y)) states = states | 0b00000010;
// }
// if (abs(norm.x) < abs(norm.z)){
// if (abs(norm.z) > abs(norm.y)) states = states | 0b00000011;
// if (abs(norm.z) < abs(norm.y)) states = states | 0b00000010;
// }
if (abs(norm.x) > abs(norm.z)){ if (abs(norm.x) > abs(norm.z)){
if (abs(norm.x) > abs(norm.y)) states = 0x31; if (abs(norm.x) > abs(norm.y)) states = BLOCK_DIR_X;
if (abs(norm.x) < abs(norm.y)) states = 0x32; if (abs(norm.x) < abs(norm.y)) states = BLOCK_DIR_Y;
} }
if (abs(norm.x) < abs(norm.z)){ if (abs(norm.x) < abs(norm.z)){
if (abs(norm.z) > abs(norm.y)) states = 0x33; if (abs(norm.z) > abs(norm.y)) states = BLOCK_DIR_Z;
if (abs(norm.z) < abs(norm.y)) states = 0x32; if (abs(norm.z) < abs(norm.y)) states = BLOCK_DIR_Y;
} }
} }

View File

@ -3,19 +3,45 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include "../settings.h"
class PhysicsSolver; class PhysicsSolver;
class Chunks; class Chunks;
class Player; class Player;
class Level; class Level;
struct PlayerInput {
bool zoom;
bool moveForward;
bool moveBack;
bool moveRight;
bool moveLeft;
bool sprint;
bool shift;
bool cheat;
bool jump;
bool noclip;
bool flight;
};
class PlayerController { class PlayerController {
Level* level; Level* level;
Player* player;
PlayerInput input;
const CameraSettings& camSettings;
public: public:
glm::vec3 selectedBlockPosition; glm::vec3 selectedBlockPosition;
glm::vec3 cameraOffset {0.0f, 0.7f, 0.0f};
int selectedBlockId = -1; int selectedBlockId = -1;
PlayerController(Level* level); PlayerController(Level* level, const EngineSettings& settings);
void update_controls(float delta, bool movement); void updateKeyboard();
void update_interaction(); void resetKeyboard();
void updateCameraControl();
void updateControls(float delta);
void updateInteraction();
void refreshCamera();
}; };
#endif /* PLAYER_CONTROL_H_ */ #endif /* PLAYER_CONTROL_H_ */

61
src/settings.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "settings.h"
#include <memory>
#include <string>
#include "files/files.h"
#include "coders/json.h"
using std::string;
using std::unique_ptr;
void load_settings(EngineSettings& settings, string filename) {
string source = files::read_string(filename);
unique_ptr<json::JObject> obj(json::parse(filename, source));
{
auto& display = settings.display;
obj->num("display-width", display.width);
obj->num("display-height", display.height);
obj->num("display-samples", display.samples);
obj->num("display-swap-interval", display.swapInterval);
}
{
auto& chunks = settings.chunks;
obj->num("chunks-load-distance", chunks.loadDistance);
obj->num("chunks-load-speed", chunks.loadSpeed);
obj->num("chunks-padding", chunks.padding);
}
{
auto& camera = settings.camera;
obj->flag("camera-fov-effects", camera.fovEvents);
obj->flag("camera-shaking", camera.shaking);
}
obj->num("fog-curve", settings.fogCurve);
}
void save_settings(EngineSettings& settings, string filename) {
json::JObject obj;
{
auto& display = settings.display;
obj.put("display-width", display.width);
obj.put("display-height", display.height);
obj.put("display-samples", display.samples);
obj.put("display-swap-interval", display.swapInterval);
}
{
auto& chunks = settings.chunks;
obj.put("chunks-load-distance", chunks.loadDistance);
obj.put("chunks-load-speed", chunks.loadSpeed);
obj.put("chunks-padding", chunks.padding);
}
{
auto& camera = settings.camera;
obj.put("camera-fov-effects", camera.fovEvents);
obj.put("camera-shaking", camera.shaking);
}
obj.put("fog-curve", settings.fogCurve);
files::write_string(filename, json::stringify(&obj, true, " "));
}

51
src/settings.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef SRC_SETTINGS_H_
#define SRC_SETTINGS_H_
#include <string>
#include "typedefs.h"
struct DisplaySettings {
/* Window width (pixels) */
int width = 1280;
/* Window height (pixels) */
int height = 720;
/* Anti-aliasing samples */
int samples = 0;
/* GLFW swap interval value, 0 - unlimited fps, 1 - vsync*/
int swapInterval = 1;
/* Window title */
const char* title = "VoxelEngine-Cpp v0.13";
};
struct ChunksSettings {
/* Max milliseconds that engine uses for chunks loading only */
uint loadSpeed = 10;
/* Radius of chunks loading zone (chunk is unit) */
uint loadDistance = 22;
/* Buffer zone where chunks are not unloading (chunk is unit)*/
uint padding = 2;
};
struct CameraSettings {
/* Camera dynamic field of view effects */
bool fovEvents = true;
/* Camera movement shake */
bool shaking = true;
};
struct EngineSettings {
DisplaySettings display;
ChunksSettings chunks;
CameraSettings camera;
/* 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 = 1.6f;
};
void load_settings(EngineSettings& settings, std::string filename);
void save_settings(EngineSettings& settings, std::string filename);
#endif // SRC_SETTINGS_H_

View File

@ -15,16 +15,6 @@ int main() {
setup_definitions(); setup_definitions();
try { try {
EngineSettings settings; EngineSettings settings;
settings.displayWidth = 1280;
settings.displayHeight = 720;
settings.displaySamples = 0; // верну мультисемплинг позже
settings.displayTitle = "VoxelEngine-Cpp v0.13";
settings.chunksLoadSpeed = 10;
settings.chunksLoadDistance = 12;
settings.chunksPadding = 2;
settings.displaySwapInterval = 1;
settings.fogCurve = 1.6f;
std::string settings_file = platform::get_settings_file(); std::string settings_file = platform::get_settings_file();
if (std::filesystem::is_regular_file(settings_file)) { if (std::filesystem::is_regular_file(settings_file)) {
std::cout << "-- loading settings" << std::endl; std::cout << "-- loading settings" << std::endl;

View File

@ -140,7 +140,7 @@ void WorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
int tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 12); int tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 12);
if (tree) { if (tree) {
id = tree; id = tree;
states = 0x32; states = BLOCK_DIR_Y;
// } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 19))){ // } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 19))){
// id = tree; // id = tree;
// } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 23))){ // } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 23))){
@ -162,7 +162,7 @@ void WorldGenerator::generate(voxel* voxels, int cx, int cz, int seed){
} }
if ((height > 56) && ((int)(height + 1) == real_y) && ((unsigned short)randomgrass.rand() > 65533)){ if ((height > 56) && ((int)(height + 1) == real_y) && ((unsigned short)randomgrass.rand() > 65533)){
id = BLOCK_WOOD; id = BLOCK_WOOD;
states = 0x32; states = BLOCK_DIR_Y;
} }
voxels[(y * CHUNK_D + z) * CHUNK_W + x].id = id; voxels[(y * CHUNK_D + z) * CHUNK_W + x].id = id;
voxels[(y * CHUNK_D + z) * CHUNK_W + x].states = states; voxels[(y * CHUNK_D + z) * CHUNK_W + x].states = states;

View File

@ -3,6 +3,10 @@
#include "../typedefs.h" #include "../typedefs.h"
#define BLOCK_DIR_X 0x1
#define BLOCK_DIR_Y 0x2
#define BLOCK_DIR_Z 0x3
struct voxel { struct voxel {
blockid_t id; blockid_t id;
uint8_t states; uint8_t states;

View File

@ -64,15 +64,18 @@ void character_callback(GLFWwindow* window, unsigned int codepoint){
} }
int Window::initialize(uint width, uint height, const char* title, int samples){ int Window::initialize(DisplaySettings& settings){
Window::width = settings.width;
Window::height = settings.height;
glfwInit(); glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, samples); glfwWindowHint(GLFW_SAMPLES, settings.samples);
window = glfwCreateWindow(width, height, title, nullptr, nullptr); window = glfwCreateWindow(width, height, settings.title, nullptr, nullptr);
if (window == nullptr){ if (window == nullptr){
std::cerr << "Failed to create GLFW Window" << std::endl; std::cerr << "Failed to create GLFW Window" << std::endl;
glfwTerminate(); glfwTerminate();
@ -95,15 +98,14 @@ int Window::initialize(uint width, uint height, const char* title, int samples){
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Window::width = width;
Window::height = height;
Events::initialize(); Events::initialize();
glfwSetKeyCallback(window, key_callback); glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetCursorPosCallback(window, cursor_position_callback); glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetWindowSizeCallback(window, window_size_callback); glfwSetWindowSizeCallback(window, window_size_callback);
glfwSetCharCallback(window, character_callback); glfwSetCharCallback(window, character_callback);
glfwSwapInterval(settings.swapInterval);
return 0; return 0;
} }

View File

@ -2,6 +2,8 @@
#define WINDOW_WINDOW_H_ #define WINDOW_WINDOW_H_
#include "../typedefs.h" #include "../typedefs.h"
#include "../settings.h"
#include <stack> #include <stack>
#include <vector> #include <vector>
@ -16,7 +18,7 @@ class Window {
public: public:
static uint width; static uint width;
static uint height; static uint height;
static int initialize(uint width, uint height, const char* title, int samples); static int initialize(DisplaySettings& settings);
static void terminate(); static void terminate();
static void viewport(int x, int y, int width, int height); static void viewport(int x, int y, int width, int height);

View File

@ -11,17 +11,20 @@
#include "../objects/Player.h" #include "../objects/Player.h"
#include "../objects/player_control.h" #include "../objects/player_control.h"
Level::Level(World* world, Player* player, ChunksStorage* chunksStorage, LevelEvents* events, uint loadDistance, uint chunksPadding) : Level::Level(World* world, Player* player, ChunksStorage* chunksStorage, LevelEvents* events, EngineSettings& settings) :
world(world), world(world),
player(player), player(player),
chunksStorage(chunksStorage), chunksStorage(chunksStorage),
events(events) { events(events) {
physics = new PhysicsSolver(vec3(0, -19.6f, 0)); physics = new PhysicsSolver(vec3(0, -19.6f, 0));
uint matrixSize = (loadDistance+chunksPadding) * 2;
uint matrixSize = (settings.chunks.loadDistance+
settings.chunks.padding) * 2;
chunks = new Chunks(matrixSize, matrixSize, 0, 0, world->wfile, events); chunks = new Chunks(matrixSize, matrixSize, 0, 0, world->wfile, events);
lighting = new Lighting(chunks); lighting = new Lighting(chunks);
chunksController = new ChunksController(this, chunks, lighting, chunksPadding); chunksController = new ChunksController(this, chunks, lighting, settings.chunks.padding);
playerController = new PlayerController(this); playerController = new PlayerController(this, settings);
events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) { events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) {
this->chunksStorage->remove(chunk->x, chunk->z); this->chunksStorage->remove(chunk->x, chunk->z);
}); });
@ -38,16 +41,29 @@ Level::~Level(){
delete playerController; delete playerController;
} }
void Level::update(float delta, bool updatePlayer, bool interactions) { void Level::updatePlayer(float delta,
if (updatePlayer) bool input,
playerController->update_controls(delta, updatePlayer); bool pause,
if (interactions) { bool interactions) {
playerController->update_interaction(); if (!pause) {
if (input) {
playerController->updateKeyboard();
playerController->updateCameraControl();
} else {
playerController->resetKeyboard();
} }
else playerController->updateControls(delta);
{
}
playerController->refreshCamera();
if (interactions) {
playerController->updateInteraction();
} else {
playerController->selectedBlockId = -1; playerController->selectedBlockId = -1;
} }
}
void Level::update() {
vec3 position = player->hitbox->position; vec3 position = player->hitbox->position;
chunks->setCenter(position.x, position.z); chunks->setCenter(position.x, position.z);
} }

View File

@ -2,6 +2,7 @@
#define WORLD_LEVEL_H_ #define WORLD_LEVEL_H_
#include "../typedefs.h" #include "../typedefs.h"
#include "../settings.h"
class World; class World;
class Player; class Player;
@ -24,15 +25,20 @@ public:
ChunksController* chunksController; ChunksController* chunksController;
PlayerController* playerController; PlayerController* playerController;
LevelEvents* events; LevelEvents* events;
Level(World* world, Level(World* world,
Player* player, Player* player,
ChunksStorage* chunksStorage, ChunksStorage* chunksStorage,
LevelEvents* events, LevelEvents* events,
uint loadDistance, EngineSettings& settings);
uint chunksPadding);
~Level(); ~Level();
void update(float delta, bool updatePlayer, bool interactions); void updatePlayer(float delta,
bool input,
bool pause,
bool interactions);
void update();
}; };
#endif /* WORLD_LEVEL_H_ */ #endif /* WORLD_LEVEL_H_ */

View File

@ -36,10 +36,10 @@ void World::write(Level* level) {
wfile->writePlayer(level->player); wfile->writePlayer(level->player);
} }
Level* World::loadLevel(Player* player, uint loadDistance, uint chunksPadding) { Level* World::loadLevel(Player* player, EngineSettings& settings) {
ChunksStorage* storage = new ChunksStorage(); ChunksStorage* storage = new ChunksStorage();
LevelEvents* events = new LevelEvents(); LevelEvents* events = new LevelEvents();
Level* level = new Level(this, player, storage, events, loadDistance, chunksPadding); Level* level = new Level(this, player, storage, events, settings);
wfile->readPlayer(player); wfile->readPlayer(player);
Camera* camera = player->camera; Camera* camera = player->camera;

View File

@ -3,6 +3,7 @@
#include <string> #include <string>
#include "../typedefs.h" #include "../typedefs.h"
#include "../settings.h"
class WorldFiles; class WorldFiles;
class Chunks; class Chunks;
@ -19,7 +20,7 @@ public:
~World(); ~World();
void write(Level* level); void write(Level* level);
Level* loadLevel(Player* player, uint loadDistance, uint chunksPadding); Level* loadLevel(Player* player, EngineSettings& settings);
}; };
#endif /* WORLD_WORLD_H_ */ #endif /* WORLD_WORLD_H_ */