diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 73e235d7..a0d93487 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -101,7 +101,7 @@ void LevelScreen::saveWorldPreview() { Viewport viewport(previewSize * 1.5, previewSize); DrawContext ctx(&pctx, viewport, batch.get()); - worldRenderer->draw(ctx, &camera, false, true, 0.0f, postProcessing.get()); + worldRenderer->draw(ctx, camera, false, true, 0.0f, postProcessing.get()); auto image = postProcessing->toImage(); image->flipY(); imageio::write(paths->resolve("world:preview.png").u8string(), image.get()); @@ -164,7 +164,9 @@ void LevelScreen::draw(float delta) { Viewport viewport(Window::width, Window::height); DrawContext ctx(nullptr, viewport, batch.get()); - worldRenderer->draw(ctx, camera.get(), hudVisible, hud->isPause(), delta, postProcessing.get()); + worldRenderer->draw( + ctx, *camera, hudVisible, hud->isPause(), delta, postProcessing.get() + ); if (hudVisible) { hud->draw(ctx); diff --git a/src/graphics/render/ModelBatch.cpp b/src/graphics/render/ModelBatch.cpp index bda65de3..16f9393f 100644 --- a/src/graphics/render/ModelBatch.cpp +++ b/src/graphics/render/ModelBatch.cpp @@ -77,6 +77,7 @@ void ModelBatch::draw(const model::Mesh& mesh, const glm::mat4& matrix, const texture_names_map* varTextures, bool backlight) { glm::vec3 gpos = matrix * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); + gpos += lightsOffset; light_t light = chunks->getLight( std::floor(gpos.x), std::floor(std::min(CHUNK_H-1.0f, gpos.y)), @@ -137,6 +138,10 @@ void ModelBatch::render() { entries.clear(); } +void ModelBatch::setLightsOffset(const glm::vec3& offset) { + lightsOffset = offset; +} + void ModelBatch::setTexture(const std::string& name, const texture_names_map* varTextures) { if (name.at(0) == '$') { diff --git a/src/graphics/render/ModelBatch.hpp b/src/graphics/render/ModelBatch.hpp index fc3b1295..eeff0e7e 100644 --- a/src/graphics/render/ModelBatch.hpp +++ b/src/graphics/render/ModelBatch.hpp @@ -34,6 +34,7 @@ class ModelBatch { Texture* texture = nullptr; UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; const EngineSettings* settings; + glm::vec3 lightsOffset {}; static inline glm::vec3 SUN_VECTOR {0.411934f, 0.863868f, -0.279161f}; @@ -96,4 +97,6 @@ public: const model::Model* model, const texture_names_map* varTextures); void render(); + + void setLightsOffset(const glm::vec3& offset); }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 56cd662b..abbff328 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -78,17 +78,17 @@ WorldRenderer::WorldRenderer( WorldRenderer::~WorldRenderer() = default; bool WorldRenderer::drawChunk( - size_t index, Camera* camera, Shader* shader, bool culling + size_t index, const Camera& camera, Shader* shader, bool culling ) { auto chunk = level->chunks->getChunks()[index]; if (!chunk->flags.lighted) { return false; } float distance = glm::distance( - camera->position, + camera.position, glm::vec3( (chunk->x + 0.5f) * CHUNK_W, - camera->position.y, + camera.position.y, (chunk->z + 0.5f) * CHUNK_D ) ); @@ -113,7 +113,9 @@ bool WorldRenderer::drawChunk( return true; } -void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { +void WorldRenderer::drawChunks( + Chunks* chunks, const Camera& camera, Shader* shader +) { auto assets = engine->getAssets(); auto atlas = assets->get("blocks"); @@ -127,8 +129,8 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { if (chunks->getChunks()[i] == nullptr) continue; indices.emplace_back(i); } - float px = camera->position.x / static_cast(CHUNK_W) - 0.5f; - float pz = camera->position.z / static_cast(CHUNK_D) - 0.5f; + float px = camera.position.x / static_cast(CHUNK_W) - 0.5f; + float pz = camera.position.z / static_cast(CHUNK_D) - 0.5f; std::sort(indices.begin(), indices.end(), [chunks, px, pz](auto i, auto j) { const auto& chunksBuffer = chunks->getChunks(); const auto a = chunksBuffer[i].get(); @@ -141,7 +143,7 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { }); bool culling = engine->getSettings().graphics.frustumCulling.get(); if (culling) { - frustumCulling->update(camera->getProjView()); + frustumCulling->update(camera.getProjView()); } chunks->visible = 0; for (size_t i = 0; i < indices.size(); i++) { @@ -151,20 +153,20 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { void WorldRenderer::setupWorldShader( Shader* shader, - Camera* camera, + const Camera& camera, const EngineSettings& settings, float fogFactor ) { shader->use(); shader->uniformMatrix("u_model", glm::mat4(1.0f)); - shader->uniformMatrix("u_proj", camera->getProjection()); - shader->uniformMatrix("u_view", camera->getView()); + shader->uniformMatrix("u_proj", camera.getProjection()); + shader->uniformMatrix("u_view", camera.getView()); shader->uniform1f("u_timer", timer); shader->uniform1f("u_gamma", settings.graphics.gamma.get()); shader->uniform1f("u_fogFactor", fogFactor); shader->uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); shader->uniform1f("u_dayTime", level->getWorld()->getInfo().daytime); - shader->uniform3f("u_cameraPos", camera->position); + shader->uniform3f("u_cameraPos", camera.position); shader->uniform1i("u_cubemap", 1); auto indices = level->content->getIndices(); @@ -186,7 +188,7 @@ void WorldRenderer::setupWorldShader( void WorldRenderer::renderLevel( const DrawContext&, - Camera* camera, + const Camera& camera, const EngineSettings& settings, float delta, bool pause @@ -251,10 +253,10 @@ void WorldRenderer::renderBlockSelection() { } void WorldRenderer::renderLines( - Camera* camera, Shader* linesShader, const DrawContext& pctx + const Camera& camera, Shader* linesShader, const DrawContext& pctx ) { linesShader->use(); - linesShader->uniformMatrix("u_projview", camera->getProjView()); + linesShader->uniformMatrix("u_projview", camera.getProjView()); if (player->selection.vox.id != BLOCK_VOID) { renderBlockSelection(); } @@ -268,7 +270,7 @@ void WorldRenderer::renderLines( } void WorldRenderer::renderDebugLines( - const DrawContext& pctx, Camera* camera, Shader* linesShader + const DrawContext& pctx, const Camera& camera, Shader* linesShader ) { DrawContext ctx = pctx.sub(lineBatch.get()); const auto& viewport = ctx.getViewport(); @@ -280,7 +282,7 @@ void WorldRenderer::renderDebugLines( linesShader->use(); if (showChunkBorders) { - linesShader->uniformMatrix("u_projview", camera->getProjView()); + linesShader->uniformMatrix("u_projview", camera.getProjView()); glm::vec3 coord = player->camera->position; if (coord.x < 0) coord.x--; if (coord.z < 0) coord.z--; @@ -310,7 +312,7 @@ void WorldRenderer::renderDebugLines( -length, length ) * model * - glm::inverse(camera->rotation) + glm::inverse(camera.rotation) ); ctx.setDepthTest(false); @@ -327,9 +329,61 @@ void WorldRenderer::renderDebugLines( lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f); } +void WorldRenderer::renderHands(const Camera& camera, const Assets& assets) { + auto entityShader = assets.get("entity"); + auto indices = level->content->getIndices(); + + // get current chosen item + const auto& inventory = player->getInventory(); + int slot = player->getChosenSlot(); + const ItemStack& stack = inventory->getSlot(slot); + const auto& def = indices->items.require(stack.getItemId()); + + // prepare modified HUD camera + Camera hudcam = camera; + hudcam.far = 100.0f; + hudcam.setFov(1.2f); + hudcam.position = {}; + + // configure model matrix + const glm::vec3 itemOffset(0.08f, 0.035f, -0.1); + + glm::mat4 matrix = glm::translate(glm::mat4(1.0f), itemOffset); + matrix = glm::scale(matrix, glm::vec3(0.1f)); + matrix = camera.rotation * matrix * + glm::rotate( + glm::mat4(1.0f), -glm::pi() * 0.5f, glm::vec3(0, 1, 0) + ); + auto offset = -(camera.position - player->getPosition()); + float angle = glm::radians(player->cam.x - 90); + float cos = glm::cos(angle); + float sin = glm::sin(angle); + + float newX = offset.x * cos - offset.z * sin; + float newZ = offset.x * sin + offset.z * cos; + matrix = matrix * + glm::translate(glm::mat4(1.0f), glm::vec3(newX, offset.y, newZ)); + + // render + texture_names_map map = {}; + modelBatch->setLightsOffset(camera.position); + modelBatch->draw( + matrix, + glm::vec3(1.0f), + assets.get(def.name + ".model"), + &map + ); + Window::clearDepth(); + setupWorldShader(entityShader, hudcam, engine->getSettings(), 0.0f); + skybox->bind(); + modelBatch->render(); + modelBatch->setLightsOffset(glm::vec3()); + skybox->unbind(); +} + void WorldRenderer::draw( const DrawContext& pctx, - Camera* camera, + Camera& camera, bool hudVisible, bool pause, float delta, @@ -338,7 +392,7 @@ void WorldRenderer::draw( timer += delta * !pause; auto world = level->getWorld(); const Viewport& vp = pctx.getViewport(); - camera->aspect = vp.getWidth() / static_cast(vp.getHeight()); + camera.aspect = vp.getWidth() / static_cast(vp.getHeight()); const auto& settings = engine->getSettings(); const auto& worldInfo = world->getInfo(); @@ -356,7 +410,7 @@ void WorldRenderer::draw( Window::clearDepth(); // Drawing background sky plane - skybox->draw(pctx, camera, assets, worldInfo.daytime, worldInfo.fog); + skybox->draw(pctx, &camera, assets, worldInfo.daytime, worldInfo.fog); // Actually world render with depth buffer on { @@ -367,6 +421,7 @@ void WorldRenderer::draw( // Debug lines if (hudVisible) { renderLines(camera, linesShader, ctx); + renderHands(camera, *assets); } } diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index 06e4bb63..8ccbd928 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -23,6 +23,7 @@ class Skybox; class PostProcessing; class DrawContext; class ModelBatch; +class Assets; struct EngineSettings; namespace model { @@ -41,16 +42,20 @@ class WorldRenderer { std::unique_ptr modelBatch; float timer = 0.0f; - bool drawChunk(size_t index, Camera* camera, Shader* shader, bool culling); - void drawChunks(Chunks* chunks, Camera* camera, Shader* shader); + bool drawChunk(size_t index, const Camera& camera, Shader* shader, bool culling); + void drawChunks(Chunks* chunks, const Camera& camera, Shader* shader); /// @brief Render block selection lines void renderBlockSelection(); + + void renderHands(const Camera& camera, const Assets& assets); /// @brief Render lines (selection and debug) /// @param camera active camera /// @param linesShader shader used - void renderLines(Camera* camera, Shader* linesShader, const DrawContext& pctx); + void renderLines( + const Camera& camera, Shader* linesShader, const DrawContext& pctx + ); /// @brief Render all debug lines (chunks borders, coord system guides) /// @param context graphics context @@ -58,13 +63,13 @@ class WorldRenderer { /// @param linesShader shader used void renderDebugLines( const DrawContext& context, - Camera* camera, + const Camera& camera, Shader* linesShader ); void setupWorldShader( Shader* shader, - Camera* camera, + const Camera& camera, const EngineSettings& settings, float fogFactor ); @@ -77,7 +82,7 @@ public: void draw( const DrawContext& context, - Camera* camera, + Camera& camera, bool hudVisible, bool pause, float delta, @@ -91,7 +96,7 @@ public: /// @param settings engine settings void renderLevel( const DrawContext& context, - Camera* camera, + const Camera& camera, const EngineSettings& settings, float delta, bool pause diff --git a/src/objects/Player.cpp b/src/objects/Player.cpp index d0e19c85..ec2516c2 100644 --- a/src/objects/Player.cpp +++ b/src/objects/Player.cpp @@ -252,7 +252,7 @@ entityid_t Player::getSelectedEntity() const { return selectedEid; } -std::shared_ptr Player::getInventory() const { +const std::shared_ptr& Player::getInventory() const { return inventory; } diff --git a/src/objects/Player.hpp b/src/objects/Player.hpp index c2a923e9..b676551c 100644 --- a/src/objects/Player.hpp +++ b/src/objects/Player.hpp @@ -91,7 +91,7 @@ public: entityid_t getSelectedEntity() const; - std::shared_ptr getInventory() const; + const std::shared_ptr& getInventory() const; glm::vec3 getPosition() const { return position; diff --git a/src/window/Camera.cpp b/src/window/Camera.cpp index 5e9dd36a..def9ff7c 100644 --- a/src/window/Camera.cpp +++ b/src/window/Camera.cpp @@ -29,21 +29,21 @@ void Camera::rotate(float x, float y, float z) { updateVectors(); } -glm::mat4 Camera::getProjection() { +glm::mat4 Camera::getProjection() const { constexpr float epsilon = 1e-6f; // 0.000001 float aspect_ratio = this->aspect; if (std::fabs(aspect_ratio) < epsilon) { aspect_ratio = (float)Window::width / (float)Window::height; } if (perspective) - return glm::perspective(fov * zoom, aspect_ratio, 0.05f, 1500.0f); + return glm::perspective(fov * zoom, aspect_ratio, near, far); else if (flipped) return glm::ortho(0.0f, fov * aspect_ratio, fov, 0.0f); else return glm::ortho(0.0f, fov * aspect_ratio, 0.0f, fov); } -glm::mat4 Camera::getView(bool pos) { +glm::mat4 Camera::getView(bool pos) const { glm::vec3 camera_pos = this->position; if (!pos) { camera_pos = glm::vec3(0.0f); @@ -55,7 +55,7 @@ glm::mat4 Camera::getView(bool pos) { } } -glm::mat4 Camera::getProjView(bool pos) { +glm::mat4 Camera::getProjView(bool pos) const { return getProjection() * getView(pos); } diff --git a/src/window/Camera.hpp b/src/window/Camera.hpp index 639a27df..1c2ecd60 100644 --- a/src/window/Camera.hpp +++ b/src/window/Camera.hpp @@ -18,6 +18,8 @@ public: bool perspective = true; bool flipped = false; float aspect = 0.0f; + float near = 0.05f; + float far = 1500.0f; Camera() { updateVectors(); @@ -27,9 +29,9 @@ public: void updateVectors(); void rotate(float x, float y, float z); - glm::mat4 getProjection(); - glm::mat4 getView(bool position = true); - glm::mat4 getProjView(bool position = true); + glm::mat4 getProjection() const; + glm::mat4 getView(bool position = true) const; + glm::mat4 getProjView(bool position = true) const; void setFov(float fov); float getFov() const;