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_WRAP_S, 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);
glBindTexture(GL_TEXTURE_2D, 0);

View File

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

View File

@ -5,6 +5,7 @@
#include <memory>
#include <stdexcept>
#include "typedefs.h"
#include "settings.h"
class Assets;
class Level;
@ -13,32 +14,6 @@ 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) {}

View File

@ -20,7 +20,15 @@ GUI::~GUI() {
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));
int mx = Events::x;
int my = Events::y;
@ -83,3 +91,7 @@ bool GUI::isFocusCaught() const {
void GUI::add(shared_ptr<UINode> 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 <vector>
#include <glm/glm.hpp>
#include <functional>
class Batch2D;
class Assets;
@ -43,11 +44,19 @@ namespace gui {
class UINode;
class Container;
typedef std::function<void()> ontimeout;
struct IntervalEvent {
ontimeout callback;
float interval;
float timer;
};
class GUI {
Container* container;
std::shared_ptr<UINode> hover = nullptr;
std::shared_ptr<UINode> pressed = nullptr;
std::shared_ptr<UINode> focus = nullptr;
std::vector<IntervalEvent> intervalEvents;
public:
GUI();
~GUI();
@ -55,9 +64,11 @@ namespace gui {
std::shared_ptr<UINode> getFocused() const;
bool isFocusCaught() const;
void act();
void act(float delta);
void draw(Batch2D* batch, Assets* assets);
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::vec3;
using glm::vec4;
using gui::GUI;
using gui::UINode;
using gui::Panel;
using gui::Label;
using gui::Button;
using gui::TextBox;
using namespace gui;
inline Label* create_label(gui::wstringsupplier supplier) {
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) {
batch = new Batch2D(1024);
uicamera = new Camera(glm::vec3(), Window::height);
uicamera = new Camera(vec3(), Window::height);
uicamera->perspective = false;
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->setCoord(vec2(10, 10));
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++){
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->margin(vec4(2, 3, 2, 3));
sub->add(shared_ptr<UINode>(label));
sub->color(vec4(0.0f));
// Coordinate input
TextBox* box = new TextBox(L"");
box->textSupplier([this, ax]() {
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) {
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& _){
}
});
@ -125,12 +130,7 @@ HudRenderer::~HudRenderer() {
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++;
this->fps = fps;
fpsMin = min(fps, fpsMin);
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);
}
Player* player = level->player;
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,
@ -259,7 +260,7 @@ void HudRenderer::draw(){
0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 0.75f, 2);
batch->texture(blocks);
Player* player = level->player;
{
Block* cblock = Block::blocks[player->choosenBlock];
if (cblock->model == BLOCK_MODEL_CUBE){
@ -296,3 +297,11 @@ void HudRenderer::draw(){
}
batch->render();
}
bool HudRenderer::isInventoryOpen() const {
return inventoryOpen;
}
bool HudRenderer::isPause() const {
return pause;
}

View File

@ -21,9 +21,9 @@ class HudRenderer {
Batch2D* batch;
Camera* uicamera;
int fps = 60;
int fpsMin = 60;
int fpsMax = 60;
int fpsFrame = 0;
std::wstring fpsString;
bool occlusion;
bool inventoryOpen = false;
@ -38,6 +38,9 @@ public:
void drawInventory(Player* player);
void draw();
void drawDebug(int fps, bool occlusion);
bool isInventoryOpen() const;
bool isPause() const;
};
#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) {
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid *) data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_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_MULTISAMPLE, 0);
}
Texture::~Texture() {
@ -31,10 +26,7 @@ void Texture::bind(){
void Texture::reload(unsigned char* data){
glBindTexture(GL_TEXTURE_2D, id);
// glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
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_MULTISAMPLE, 0);
}

View File

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

View File

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

View File

@ -29,46 +29,100 @@
#define CHEAT_SPEED_MUL 5.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){
Player* player = level->player;
void PlayerController::refreshCamera() {
level->player->camera->position = level->player->hitbox->position + cameraOffset;
}
/*block choose*/{
for (int i = 1; i < 10; i++){
if (Events::jpressed(keycode::NUM_0+i)){
player->choosenBlock = i;
}
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++){
if (Events::jpressed(keycode::NUM_0+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;
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;
if (player->flight){
speed *= FLIGHT_SPEED_MUL;
}
if (cheat){
if (input.cheat){
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);
substeps = (substeps <= 0 ? 1 : (substeps > 100 ? 100 : substeps));
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;
if (player->flight && hitbox->grounded)
level->physics->step(level->chunks, hitbox, delta, substeps, crouch, player->flight ? 0.0f : 1.0f, !player->noclip);
if (player->flight && hitbox->grounded) {
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;
if (hitbox->grounded && player->interpVel.y < 0.0f){
player->interpVel.y *= -30.0f;
@ -77,104 +131,80 @@ void PlayerController::update_controls(float delta, bool movement){
player->cameraShakingTimer += delta * factor * CAMERA_SHAKING_SPEED;
float shakeTimer = player->cameraShakingTimer;
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;
camera->position += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking;
camera->position -= min(player->interpVel * 0.05f, 1.0f);
}//end
cameraOffset += camera->right * sin(shakeTimer) * CAMERA_SHAKING_OFFSET * player->cameraShaking;
cameraOffset += camera->up * abs(cos(shakeTimer)) * CAMERA_SHAKING_OFFSET_Y * player->cameraShaking;
cameraOffset -= min(player->interpVel * 0.05f, 1.0f);
}
if ((Events::jpressed(keycode::F) && movement && !player->noclip) ||
(Events::jpressed(keycode::N) && movement && player->flight == player->noclip)){
if ((input.flight && !player->noclip) ||
(input.noclip && player->flight == player->noclip)){
player->flight = !player->flight;
if (player->flight){
hitbox->grounded = false;
}
}
if (Events::jpressed(keycode::N) && movement) {
if (input.noclip) {
player->noclip = !player->noclip;
}
/*field of view manipulations*/{
if (camSettings.fovEvents){
float dt = min(1.0f, delta * ZOOM_SPEED);
float zoomValue = 1.0f;
if (shift){
if (crouch){
speed *= CROUCH_SPEED_MUL;
camera->position.y += CROUCH_SHIFT_Y;
cameraOffset += CROUCH_SHIFT_Y;
zoomValue = CROUCH_ZOOM;
} else if (sprint){
} else if (input.sprint){
speed *= RUN_SPEED_MUL;
zoomValue = RUN_ZOOM;
}
if (zoom)
if (input.zoom)
zoomValue *= C_ZOOM;
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;
if (player->flight){
hitbox->linear_damping = PLAYER_AIR_DAMPING;
hitbox->velocity.y *= 1.0f - delta * 9;
if (Events::pressed(keycode::SPACE) && movement){
if (input.jump){
hitbox->velocity.y += speed * delta * 9;
}
if (Events::pressed(keycode::LEFT_SHIFT) && movement){
if (input.shift){
hitbox->velocity.y -= speed * delta * 9;
}
}
if (!hitbox->grounded)
if (!hitbox->grounded) {
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;
}
/*camera rotate*/{
if (Events::_cursor_locked){
float rotX = -Events::deltaX / Window::height * 2;
float rotY = -Events::deltaY / Window::height * 2;
if (zoom){
rotX /= 4;
rotY /= 4;
}
player->camX += rotX;
player->camY += rotY;
if (player->camY < -radians(89.9f)){
player->camY = -radians(89.9f);
}
if (player->camY > radians(89.9f)){
player->camY = radians(89.9f);
}
camera->rotation = mat4(1.0f);
camera->rotate(player->camY, player->camX, 0);
}
}//end
input.noclip = false;
input.flight = false;
}
void PlayerController::update_interaction(){
void PlayerController::updateCameraControl() {
Camera* camera = player->camera;
float rotX = -Events::deltaX / Window::height * 2;
float rotY = -Events::deltaY / Window::height * 2;
if (input.zoom){
rotX /= 4;
rotY /= 4;
}
player->camX += rotX;
player->camY += rotY;
if (player->camY < -radians(89.9f)){
player->camY = -radians(89.9f);
}
if (player->camY > radians(89.9f)){
player->camY = radians(89.9f);
}
camera->rotation = mat4(1.0f);
camera->rotate(player->camY, player->camX, 0);
}
void PlayerController::updateInteraction(){
Chunks* chunks = level->chunks;
Player* player = level->player;
Lighting* lighting = level->lighting;
@ -193,22 +223,13 @@ void PlayerController::update_interaction(){
uint8_t states = 0;
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.y)) states = 0x31;
if (abs(norm.x) < abs(norm.y)) states = 0x32;
if (abs(norm.x) > abs(norm.y)) states = BLOCK_DIR_X;
if (abs(norm.x) < abs(norm.y)) states = BLOCK_DIR_Y;
}
if (abs(norm.x) < abs(norm.z)){
if (abs(norm.z) > abs(norm.y)) states = 0x33;
if (abs(norm.z) < abs(norm.y)) states = 0x32;
if (abs(norm.z) > abs(norm.y)) states = BLOCK_DIR_Z;
if (abs(norm.z) < abs(norm.y)) states = BLOCK_DIR_Y;
}
}

View File

@ -3,19 +3,45 @@
#include <glm/glm.hpp>
#include "../settings.h"
class PhysicsSolver;
class Chunks;
class Player;
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 {
Level* level;
Player* player;
PlayerInput input;
const CameraSettings& camSettings;
public:
glm::vec3 selectedBlockPosition;
glm::vec3 cameraOffset {0.0f, 0.7f, 0.0f};
int selectedBlockId = -1;
PlayerController(Level* level);
void update_controls(float delta, bool movement);
void update_interaction();
PlayerController(Level* level, const EngineSettings& settings);
void updateKeyboard();
void resetKeyboard();
void updateCameraControl();
void updateControls(float delta);
void updateInteraction();
void refreshCamera();
};
#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();
try {
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();
if (std::filesystem::is_regular_file(settings_file)) {
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);
if (tree) {
id = tree;
states = 0x32;
states = BLOCK_DIR_Y;
// } else if ((tree = generate_tree(&noise, &randomtree, heights, real_x, real_y, real_z, 19))){
// id = tree;
// } 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)){
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].states = states;

View File

@ -3,6 +3,10 @@
#include "../typedefs.h"
#define BLOCK_DIR_X 0x1
#define BLOCK_DIR_Y 0x2
#define BLOCK_DIR_Z 0x3
struct voxel {
blockid_t id;
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();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
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){
std::cerr << "Failed to create GLFW Window" << std::endl;
glfwTerminate();
@ -95,15 +98,14 @@ int Window::initialize(uint width, uint height, const char* title, int samples){
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Window::width = width;
Window::height = height;
Events::initialize();
glfwSetKeyCallback(window, key_callback);
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetCursorPosCallback(window, cursor_position_callback);
glfwSetWindowSizeCallback(window, window_size_callback);
glfwSetCharCallback(window, character_callback);
glfwSwapInterval(settings.swapInterval);
return 0;
}

View File

@ -2,6 +2,8 @@
#define WINDOW_WINDOW_H_
#include "../typedefs.h"
#include "../settings.h"
#include <stack>
#include <vector>
@ -16,7 +18,7 @@ class Window {
public:
static uint width;
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 viewport(int x, int y, int width, int height);

View File

@ -11,17 +11,20 @@
#include "../objects/Player.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),
player(player),
chunksStorage(chunksStorage),
events(events) {
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);
lighting = new Lighting(chunks);
chunksController = new ChunksController(this, chunks, lighting, chunksPadding);
playerController = new PlayerController(this);
chunksController = new ChunksController(this, chunks, lighting, settings.chunks.padding);
playerController = new PlayerController(this, settings);
events->listen(EVT_CHUNK_HIDDEN, [this](lvl_event_type type, Chunk* chunk) {
this->chunksStorage->remove(chunk->x, chunk->z);
});
@ -38,16 +41,29 @@ Level::~Level(){
delete playerController;
}
void Level::update(float delta, bool updatePlayer, bool interactions) {
if (updatePlayer)
playerController->update_controls(delta, updatePlayer);
if (interactions) {
playerController->update_interaction();
void Level::updatePlayer(float delta,
bool input,
bool pause,
bool interactions) {
if (!pause) {
if (input) {
playerController->updateKeyboard();
playerController->updateCameraControl();
} else {
playerController->resetKeyboard();
}
playerController->updateControls(delta);
}
else
{
playerController->refreshCamera();
if (interactions) {
playerController->updateInteraction();
} else {
playerController->selectedBlockId = -1;
}
}
void Level::update() {
vec3 position = player->hitbox->position;
chunks->setCenter(position.x, position.z);
}

View File

@ -2,6 +2,7 @@
#define WORLD_LEVEL_H_
#include "../typedefs.h"
#include "../settings.h"
class World;
class Player;
@ -24,15 +25,20 @@ public:
ChunksController* chunksController;
PlayerController* playerController;
LevelEvents* events;
Level(World* world,
Player* player,
ChunksStorage* chunksStorage,
LevelEvents* events,
uint loadDistance,
uint chunksPadding);
EngineSettings& settings);
~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_ */

View File

@ -36,10 +36,10 @@ void World::write(Level* level) {
wfile->writePlayer(level->player);
}
Level* World::loadLevel(Player* player, uint loadDistance, uint chunksPadding) {
Level* World::loadLevel(Player* player, EngineSettings& settings) {
ChunksStorage* storage = new ChunksStorage();
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);
Camera* camera = player->camera;

View File

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