diff --git a/CMakePresets.json b/CMakePresets.json index bc81fc91..47ba71e3 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -45,6 +45,16 @@ } ], "buildPresets": [ + { + "name": "Debug build", + "configurePreset": "default-vs-msvc-windows", + "configuration": "Debug" + }, + { + "name": "Release build", + "configurePreset": "default-vs-msvc-windows", + "configuration": "Release" + }, { "name": "default-vs-msvc-windows", "configurePreset": "default-vs-msvc-windows", diff --git a/res/shaders/entity.glslv b/res/shaders/entity.glslv index e318db38..3d916e9a 100644 --- a/res/shaders/entity.glslv +++ b/res/shaders/entity.glslv @@ -3,7 +3,7 @@ layout (location = 0) in vec3 v_position; layout (location = 1) in vec2 v_texCoord; layout (location = 2) in vec3 v_color; -layout (location = 3) in float v_light; +layout (location = 3) in vec4 v_light; out vec4 a_color; out vec2 a_texCoord; @@ -31,8 +31,7 @@ void main() { vec3 pos3d = modelpos.xyz - u_cameraPos; modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); - vec4 decomp_light = decompress_light(v_light); - vec3 light = decomp_light.rgb; + vec3 light = v_light.rgb; float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / u_torchlightDistance); light += torchlight * u_torchlightColor; @@ -41,7 +40,7 @@ void main() { a_dir = modelpos.xyz - u_cameraPos; vec3 skyLightColor = pick_sky_color(u_cubemap); - a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a) * v_color; + a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a) * v_color; a_color.a = u_opacity; float dist = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0)); diff --git a/res/shaders/lib/commons.glsl b/res/shaders/lib/commons.glsl index a3bdbbc7..3701fcc3 100644 --- a/res/shaders/lib/commons.glsl +++ b/res/shaders/lib/commons.glsl @@ -1,28 +1,17 @@ #ifndef COMMONS_GLSL_ #define COMMONS_GLSL_ - #include -vec4 decompress_light(float compressed_light) { - vec4 result; - int compressed = floatBitsToInt(compressed_light); - result.r = ((compressed >> 24) & 0xFF) / 255.f; - result.g = ((compressed >> 16) & 0xFF) / 255.f; - result.b = ((compressed >> 8) & 0xFF) / 255.f; - result.a = (compressed & 0xFF) / 255.f; - return result; -} - vec3 pick_sky_color(samplerCube cubemap) { vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb; skyLightColor *= SKY_LIGHT_TINT; - skyLightColor = min(vec3(1.0), skyLightColor*SKY_LIGHT_MUL); + skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL); skyLightColor = max(MIN_SKY_LIGHT, skyLightColor); return skyLightColor; } vec3 apply_planet_curvature(vec3 modelPos, vec3 pos3d) { - modelPos.y -= pow(length(pos3d.xz)*CURVATURE_FACTOR, 3.0); + modelPos.y -= pow(length(pos3d.xz) * CURVATURE_FACTOR, 3.0f); return modelPos; } diff --git a/res/shaders/main.glslf b/res/shaders/main.glslf index bccbd53a..d856acc2 100644 --- a/res/shaders/main.glslf +++ b/res/shaders/main.glslf @@ -7,10 +7,13 @@ out vec4 f_color; uniform sampler2D u_texture0; uniform samplerCube u_cubemap; uniform bool u_alphaClip; +uniform bool u_debugLights; void main() { vec3 fogColor = texture(u_cubemap, a_dir).rgb; vec4 tex_color = texture(u_texture0, a_texCoord); + if (u_debugLights) + tex_color.rgb = vec3(1.0); float alpha = a_color.a * tex_color.a; if (u_alphaClip) { if (alpha < 0.2f) diff --git a/res/shaders/main.glslv b/res/shaders/main.glslv index c8d05d5d..24ec6cae 100644 --- a/res/shaders/main.glslv +++ b/res/shaders/main.glslv @@ -2,7 +2,7 @@ layout (location = 0) in vec3 v_position; layout (location = 1) in vec2 v_texCoord; -layout (location = 2) in float v_light; +layout (location = 2) in vec4 v_light; out vec4 a_color; out vec2 a_texCoord; @@ -27,13 +27,12 @@ uniform vec3 u_torchlightColor; uniform float u_torchlightDistance; void main() { - vec4 modelpos = u_model * vec4(v_position, 1.0); + vec4 modelpos = u_model * vec4(v_position, 1.0f); vec3 pos3d = modelpos.xyz-u_cameraPos; modelpos.xyz = apply_planet_curvature(modelpos.xyz, pos3d); - vec4 decomp_light = decompress_light(v_light); - vec3 light = decomp_light.rgb; - float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / + vec3 light = v_light.rgb; + float torchlight = max(0.0, 1.0-distance(u_cameraPos, modelpos.xyz) / u_torchlightDistance); light += torchlight * u_torchlightColor; a_color = vec4(pow(light, vec3(u_gamma)),1.0f); @@ -41,7 +40,7 @@ void main() { a_dir = modelpos.xyz - u_cameraPos; vec3 skyLightColor = pick_sky_color(u_cubemap); - a_color.rgb = max(a_color.rgb, skyLightColor.rgb*decomp_light.a); + a_color.rgb = max(a_color.rgb, skyLightColor.rgb*v_light.a); a_distance = length(u_view * u_model * vec4(pos3d * FOG_POS_SCALE, 0.0)); float depth = (a_distance / 256.0); diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index cdbb28e2..80c1186d 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -257,12 +257,12 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { } } for (const auto& [_, def] : content->blocks.getDefs()) { - if (!def->modelName.empty() && - def->modelName.find(':') == std::string::npos) { + if (!def->model.name.empty() && + def->model.name.find(':') == std::string::npos) { loader.add( AssetType::MODEL, - MODELS_FOLDER + "/" + def->modelName, - def->modelName + MODELS_FOLDER + "/" + def->model.name, + def->model.name ); } } diff --git a/src/coders/png.cpp b/src/coders/png.cpp index ddf5fea8..4121b052 100644 --- a/src/coders/png.cpp +++ b/src/coders/png.cpp @@ -1,13 +1,12 @@ #include "png.hpp" #include -#include #include #include "debug/Logger.hpp" #include "io/io.hpp" -#include "graphics/core/GLTexture.hpp" +#include "graphics/core/Texture.hpp" #include "graphics/core/ImageData.hpp" static debug::Logger logger("png-coder"); @@ -206,7 +205,7 @@ std::unique_ptr png::load_image(const ubyte* bytes, size_t size) { std::unique_ptr png::load_texture(const ubyte* bytes, size_t size) { auto image = load_image(bytes, size); - auto texture = GLTexture::from(image.get()); + auto texture = Texture::from(image.get()); texture->setNearestFilter(); return texture; } diff --git a/src/content/ContentBuilder.cpp b/src/content/ContentBuilder.cpp index caab68976..c8b599ea 100644 --- a/src/content/ContentBuilder.cpp +++ b/src/content/ContentBuilder.cpp @@ -28,7 +28,7 @@ std::unique_ptr ContentBuilder::build() { // Generating runtime info def.rt.id = blockDefsIndices.size(); def.rt.emissive = *reinterpret_cast(def.emission); - def.rt.solid = def.model == BlockModel::block; + def.rt.solid = def.model.type == BlockModelType::BLOCK; def.rt.extended = def.size.x > 1 || def.size.y > 1 || def.size.z > 1; const float EPSILON = 0.01f; diff --git a/src/content/loading/BlockLoader.cpp b/src/content/loading/BlockLoader.cpp index d8ef7cdd..5e3b09be 100644 --- a/src/content/loading/BlockLoader.cpp +++ b/src/content/loading/BlockLoader.cpp @@ -86,20 +86,23 @@ template<> void ContentUnitLoader::loadUnit( } // block model - std::string modelTypeName = BlockModelMeta.getNameString(def.model); + auto& model = def.model; + std::string modelTypeName = BlockModelTypeMeta.getNameString(model.type); root.at("model").get(modelTypeName); - root.at("model-name").get(def.modelName); - if (BlockModelMeta.getItem(modelTypeName, def.model)) { - if (def.model == BlockModel::custom && def.customModelRaw == nullptr) { + root.at("model-name").get(def.model.name); + if (BlockModelTypeMeta.getItem(modelTypeName, model.type)) { + if (model.type == BlockModelType::CUSTOM && def.model.customRaw == nullptr) { if (root.has("model-primitives")) { - def.customModelRaw = root["model-primitives"]; - } else if (def.modelName.empty()) { - throw std::runtime_error(name + ": no 'model-primitives' or 'model-name' found"); + def.model.customRaw = root["model-primitives"]; + } else if (def.model.name.empty()) { + throw std::runtime_error( + name + ": no 'model-primitives' or 'model-name' found" + ); } } } else if (!modelTypeName.empty()) { logger.error() << "unknown model: " << modelTypeName; - def.model = BlockModel::none; + model.type = BlockModelType::NONE; } std::string cullingModeName = CullingModeMeta.getNameString(def.culling); @@ -171,9 +174,9 @@ template<> void ContentUnitLoader::loadUnit( "block " + util::quote(def.name) + ": invalid block size" ); } - if (def.model == BlockModel::block && + if (model.type == BlockModelType::BLOCK && (def.size.x != 1 || def.size.y != 1 || def.size.z != 1)) { - def.model = BlockModel::aabb; + model.type = BlockModelType::AABB; def.hitboxes = {AABB(def.size)}; } } diff --git a/src/core_defs.cpp b/src/core_defs.cpp index 07eebee5..fdc880da 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -19,7 +19,7 @@ void corecontent::setup(Input& input, ContentBuilder& builder) { block.skyLightPassing = true; block.obstacle = false; block.selectable = false; - block.model = BlockModel::none; + block.model.type = BlockModelType::NONE; block.pickingItem = CORE_EMPTY; } { diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 63db4490..6596733f 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -203,7 +203,8 @@ void Engine::updateHotkeys() { if (input->jpressed(Keycode::F2)) { saveScreenshot(); } - if (input->jpressed(Keycode::F8)) { + if (input->pressed(Keycode::LEFT_CONTROL) && input->pressed(Keycode::F3) && + input->jpressed(Keycode::U)) { gui->toggleDebug(); } if (input->jpressed(Keycode::F11)) { diff --git a/src/frontend/ContentGfxCache.cpp b/src/frontend/ContentGfxCache.cpp index 574c22a5..31199a90 100644 --- a/src/frontend/ContentGfxCache.cpp +++ b/src/frontend/ContentGfxCache.cpp @@ -35,10 +35,10 @@ void ContentGfxCache::refresh(const Block& def, const Atlas& atlas) { sideregions[def.rt.id * 6 + side] = atlas.get(TEXTURE_NOTFOUND); } } - if (def.model == BlockModel::custom) { - auto model = assets.require(def.modelName); + if (def.model.type == BlockModelType::CUSTOM) { + auto model = assets.require(def.model.name); // temporary dirty fix tbh - if (def.modelName.find(':') == std::string::npos) { + if (def.model.name.find(':') == std::string::npos) { for (auto& mesh : model.meshes) { size_t pos = mesh.texture.find(':'); if (pos == std::string::npos) { diff --git a/src/frontend/debug_panel.cpp b/src/frontend/debug_panel.cpp index 67b43f5a..06ab5fc8 100644 --- a/src/frontend/debug_panel.cpp +++ b/src/frontend/debug_panel.cpp @@ -93,11 +93,11 @@ std::shared_ptr create_debug_panel( panel->add(create_label(gui, []() { return L"fps: "+fpsString;})); panel->add(create_label(gui, []() { - return L"meshes: " + std::to_wstring(Mesh::meshesCount); + return L"meshes: " + std::to_wstring(MeshStats::meshesCount); })); panel->add(create_label(gui, []() { - int drawCalls = Mesh::drawCalls; - Mesh::drawCalls = 0; + int drawCalls = MeshStats::drawCalls; + MeshStats::drawCalls = 0; return L"draw-calls: " + std::to_wstring(drawCalls); })); panel->add(create_label(gui, []() { diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index 76f7e950..210ef802 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -184,16 +184,21 @@ void LevelScreen::saveWorldPreview() { void LevelScreen::updateHotkeys() { auto& settings = engine.getSettings(); - if (input.jpressed(Keycode::O)) { - settings.graphics.frustumCulling.toggle(); - } if (input.jpressed(Keycode::F1)) { hudVisible = !hudVisible; } - if (input.jpressed(Keycode::F3)) { - debug = !debug; - hud->setDebug(debug); - renderer->setDebug(debug); + if (!input.pressed(Keycode::LEFT_CONTROL)) { + if (input.jpressed(Keycode::F3)) { + debug = !debug; + hud->setDebug(debug); + renderer->setDebug(debug); + } + } else if (input.pressed(Keycode::F3)) { + if (input.jpressed(Keycode::L)) { + renderer->toggleLightsDebug(); + } else if (input.jpressed(Keycode::O)) { + settings.graphics.frustumCulling.toggle(); + } } } diff --git a/src/graphics/core/Batch2D.cpp b/src/graphics/core/Batch2D.cpp index 73ac9be2..38224a3f 100644 --- a/src/graphics/core/Batch2D.cpp +++ b/src/graphics/core/Batch2D.cpp @@ -4,19 +4,12 @@ #include "gl_util.hpp" #include "maths/UVRegion.hpp" -#include - #include -inline constexpr uint B2D_VERTEX_SIZE = 8; Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){ - const VertexAttribute attrs[] = { - {2}, {2}, {4}, {0} - }; - - buffer = std::make_unique(capacity * B2D_VERTEX_SIZE); - mesh = std::make_unique(buffer.get(), 0, attrs); + buffer = std::make_unique(capacity ); + mesh = std::make_unique>(buffer.get(), 0); index = 0; const ubyte pixels[] = { @@ -51,28 +44,20 @@ void Batch2D::vertex( float u, float v, float r, float g, float b, float a ) { - buffer[index++] = x; - buffer[index++] = y; - buffer[index++] = u * region.getWidth() + region.u1; - buffer[index++] = v * region.getHeight() + region.v1; - buffer[index++] = r; - buffer[index++] = g; - buffer[index++] = b; - buffer[index++] = a; + buffer[index].position = {x, y}; + buffer[index].uv = {u * region.getWidth() + region.u1, v * region.getHeight() + region.v1}; + buffer[index].color = {r, g, b, a}; + index++; } void Batch2D::vertex( glm::vec2 point, glm::vec2 uvpoint, float r, float g, float b, float a ) { - buffer[index++] = point.x; - buffer[index++] = point.y; - buffer[index++] = uvpoint.x * region.getWidth() + region.u1; - buffer[index++] = uvpoint.y * region.getHeight() + region.v1; - buffer[index++] = r; - buffer[index++] = g; - buffer[index++] = b; - buffer[index++] = a; + buffer[index].position = point; + buffer[index].uv = {uvpoint.x * region.getWidth() + region.u1, uvpoint.y * region.getHeight() + region.v1}; + buffer[index].color = {r, g, b, a}; + index++; } void Batch2D::texture(const Texture* new_texture){ @@ -99,14 +84,14 @@ void Batch2D::setRegion(UVRegion region) { } void Batch2D::point(float x, float y, float r, float g, float b, float a){ - if (index + 6*B2D_VERTEX_SIZE >= capacity) + if (index + 6 >= capacity) flush(); setPrimitive(DrawPrimitive::point); vertex(x, y, 0, 0, r,g,b,a); } void Batch2D::line(float x1, float y1, float x2, float y2, float r, float g, float b, float a){ - if (index + 6*B2D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } setPrimitive(DrawPrimitive::line); @@ -119,7 +104,7 @@ void Batch2D::rect(float x, float y, float w, float h){ const float g = color.g; const float b = color.b; const float a = color.a; - if (index + 6*B2D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } setPrimitive(DrawPrimitive::triangle); @@ -142,7 +127,7 @@ void Batch2D::rect( bool flippedY, glm::vec4 tint ) { - if (index + 6 * B2D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } setPrimitive(DrawPrimitive::triangle); @@ -230,14 +215,14 @@ void Batch2D::rect( } void Batch2D::lineRect(float x, float y, float w, float h) { - if (index + 8 * B2D_VERTEX_SIZE >= capacity) { + if (index + 8 >= capacity) { flush(); } setPrimitive(DrawPrimitive::line); vertex(x, y, 0.0f, 0.0f, color.r, color.g, color.b, color.a); vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); - + vertex(x, y+h, 0.0f, 1.0f, color.r, color.g, color.b, color.a); vertex(x+w, y+h, 1.0f, 1.0f, color.r, color.g, color.b, color.a); @@ -253,7 +238,7 @@ void Batch2D::rect( float u, float v, float tx, float ty, float r, float g, float b, float a ){ - if (index + 6*B2D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } setPrimitive(DrawPrimitive::triangle); @@ -271,7 +256,7 @@ void Batch2D::parallelogram( float u, float v, float tx, float ty, float r, float g, float b, float a ){ - if (index + 6*B2D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } setPrimitive(DrawPrimitive::triangle); @@ -292,7 +277,7 @@ void Batch2D::rect( float r3, float g3, float b3, float r4, float g4, float b4, int sh ){ - if (index + 30*B2D_VERTEX_SIZE >= capacity) { + if (index + 30 >= capacity) { flush(); } setPrimitive(DrawPrimitive::triangle); @@ -378,7 +363,7 @@ void Batch2D::sprite( void Batch2D::flush() { if (index == 0) return; - mesh->reload(buffer.get(), index / B2D_VERTEX_SIZE); + mesh->reload(buffer.get(), index); mesh->draw(gl::to_glenum(primitive)); index = 0; } diff --git a/src/graphics/core/Batch2D.hpp b/src/graphics/core/Batch2D.hpp index 8db99d99..6f29a1df 100644 --- a/src/graphics/core/Batch2D.hpp +++ b/src/graphics/core/Batch2D.hpp @@ -1,19 +1,32 @@ #pragma once #include -#include #include #include "commons.hpp" #include "maths/UVRegion.hpp" +#include "MeshData.hpp" +template class Mesh; class Texture; +struct Batch2DVertex { + glm::vec2 position; + glm::vec2 uv; + glm::vec4 color; + + static constexpr VertexAttribute ATTRIBUTES[] { + {VertexAttribute::Type::FLOAT, false, 2}, + {VertexAttribute::Type::FLOAT, false, 2}, + {VertexAttribute::Type::FLOAT, false, 4}, + {{}, 0}}; +}; + class Batch2D : public Flushable { - std::unique_ptr buffer; + std::unique_ptr buffer; size_t capacity; - std::unique_ptr mesh; + std::unique_ptr> mesh; std::unique_ptr blank; size_t index; glm::vec4 color; diff --git a/src/graphics/core/Batch3D.cpp b/src/graphics/core/Batch3D.cpp index a81f4ffb..43d161f6 100644 --- a/src/graphics/core/Batch3D.cpp +++ b/src/graphics/core/Batch3D.cpp @@ -3,21 +3,15 @@ #include "Mesh.hpp" #include "Texture.hpp" -#include #include "typedefs.hpp" #include "maths/UVRegion.hpp" -/// xyz, uv, rgba -inline constexpr uint B3D_VERTEX_SIZE = 9; - -Batch3D::Batch3D(size_t capacity) +Batch3D::Batch3D(size_t capacity) : capacity(capacity) { - const VertexAttribute attrs[] = { - {3}, {2}, {4}, {0} - }; - buffer = std::make_unique(capacity * B3D_VERTEX_SIZE); - mesh = std::make_unique(buffer.get(), 0, attrs); + + buffer = std::make_unique(capacity); + mesh = std::make_unique>(buffer.get(), 0); index = 0; const ubyte pixels[] = { @@ -40,69 +34,54 @@ void Batch3D::vertex( float x, float y, float z, float u, float v, float r, float g, float b, float a ) { - buffer[index++] = x; - buffer[index++] = y; - buffer[index++] = z; - buffer[index++] = u; - buffer[index++] = v; - buffer[index++] = r; - buffer[index++] = g; - buffer[index++] = b; - buffer[index++] = a; + buffer[index].position = {x, y, z}; + buffer[index].uv = {u, v}; + buffer[index].color = {r, g, b, a}; + index++; } void Batch3D::vertex( glm::vec3 coord, float u, float v, float r, float g, float b, float a ) { - buffer[index++] = coord.x; - buffer[index++] = coord.y; - buffer[index++] = coord.z; - buffer[index++] = u; - buffer[index++] = v; - buffer[index++] = r; - buffer[index++] = g; - buffer[index++] = b; - buffer[index++] = a; + buffer[index].position = coord; + buffer[index].uv = {u, v}; + buffer[index].color = {r, g, b, a}; + index++; } void Batch3D::vertex( glm::vec3 point, glm::vec2 uvpoint, float r, float g, float b, float a ) { - buffer[index++] = point.x; - buffer[index++] = point.y; - buffer[index++] = point.z; - buffer[index++] = uvpoint.x; - buffer[index++] = uvpoint.y; - buffer[index++] = r; - buffer[index++] = g; - buffer[index++] = b; - buffer[index++] = a; + buffer[index].position = point; + buffer[index].uv = uvpoint; + buffer[index].color = {r, g, b, a}; + index++; } void Batch3D::face( - const glm::vec3& coord, + const glm::vec3& coord, float w, float h, const glm::vec3& axisX, const glm::vec3& axisY, const UVRegion& region, const glm::vec4& tint ) { - if (index + B3D_VERTEX_SIZE * 6 > capacity) { + if (index + 6 >= capacity) { flush(); } - vertex(coord, region.u1, region.v1, + vertex(coord, region.u1, region.v1, tint.r, tint.g, tint.b, tint.a); - vertex(coord + axisX * w, region.u2, region.v1, + vertex(coord + axisX * w, region.u2, region.v1, tint.r, tint.g, tint.b, tint.a); - vertex(coord + axisX * w + axisY * h, region.u2, region.v2, + vertex(coord + axisX * w + axisY * h, region.u2, region.v2, tint.r, tint.g, tint.b, tint.a); - vertex(coord, region.u1, region.v1, + vertex(coord, region.u1, region.v1, tint.r, tint.g, tint.b, tint.a); vertex(coord + axisX * w + axisY * h, region.u2, region.v2, tint.r, tint.g, tint.b, tint.a); - vertex(coord + axisY * h, region.u1, region.v2, + vertex(coord + axisY * h, region.u1, region.v2, tint.r, tint.g, tint.b, tint.a); } @@ -134,18 +113,18 @@ void Batch3D::sprite( } void Batch3D::sprite( - const glm::vec3& pos, - const glm::vec3& up, - const glm::vec3& right, - float w, float h, - const UVRegion& uv, + const glm::vec3& pos, + const glm::vec3& up, + const glm::vec3& right, + float w, float h, + const UVRegion& uv, const glm::vec4& color ){ const float r = color.r; const float g = color.g; const float b = color.b; const float a = color.a; - if (index + 6*B3D_VERTEX_SIZE >= capacity) { + if (index + 6 >= capacity) { flush(); } @@ -194,17 +173,17 @@ void Batch3D::xSprite( float w, float h, const UVRegion& uv, const glm::vec4& tint, bool shading ) { face( - glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f), - w, h, - glm::vec3(1, 0, 0), - glm::vec3(0, 1, 0), + glm::vec3(-w * 0.25f, 0.0f, -w * 0.25f), + w, h, + glm::vec3(1, 0, 0), + glm::vec3(0, 1, 0), uv, (shading ? do_tint(1.0f)*tint : tint) ); face( - glm::vec3(w * 0.25f, 0.0f, w * 0.5f - w * 0.25f), + glm::vec3(w * 0.25f, 0.0f, w * 0.5f - w * 0.25f), w, h, - glm::vec3(0, 0, -1), - glm::vec3(0, 1, 0), + glm::vec3(0, 0, -1), + glm::vec3(0, 1, 0), uv, (shading ? do_tint(0.9f)*tint : tint) ); } @@ -221,41 +200,41 @@ void Batch3D::cube( const glm::vec3 Z(0.0f, 0.0f, 1.0f); face( - coord+glm::vec3(0.0f, 0.0f, 0.0f), - size.x, size.y, X, Y, texfaces[5], + coord+glm::vec3(0.0f, 0.0f, 0.0f), + size.x, size.y, X, Y, texfaces[5], (shading ? do_tint(0.8)*tint : tint) ); face( - coord+glm::vec3(size.x, 0.0f, -size.z), - size.x, size.y, -X, Y, texfaces[4], + coord+glm::vec3(size.x, 0.0f, -size.z), + size.x, size.y, -X, Y, texfaces[4], (shading ? do_tint(0.8f)*tint : tint) ); face( - coord+glm::vec3(0.0f, size.y, 0.0f), - size.x, size.z, X, -Z, texfaces[3], + coord+glm::vec3(0.0f, size.y, 0.0f), + size.x, size.z, X, -Z, texfaces[3], (shading ? do_tint(1.0f)*tint : tint) ); face( - coord+glm::vec3(0.0f, 0.0f, -size.z), - size.x, size.z, X, Z, texfaces[2], + coord+glm::vec3(0.0f, 0.0f, -size.z), + size.x, size.z, X, Z, texfaces[2], (shading ? do_tint(0.7f)*tint : tint) ); face( - coord+glm::vec3(0.0f, 0.0f, -size.z), - size.z, size.y, Z, Y, texfaces[0], + coord+glm::vec3(0.0f, 0.0f, -size.z), + size.z, size.y, Z, Y, texfaces[0], (shading ? do_tint(0.9f)*tint : tint) ); face( - coord+glm::vec3(size.x, 0.0f, 0.0f), - size.z, size.y, -Z, Y, texfaces[1], + coord+glm::vec3(size.x, 0.0f, 0.0f), + size.z, size.y, -Z, Y, texfaces[1], (shading ? do_tint(0.9f)*tint : tint) ); } void Batch3D::blockCube( - const glm::vec3& size, - const UVRegion(&texfaces)[6], - const glm::vec4& tint, + const glm::vec3& size, + const UVRegion(&texfaces)[6], + const glm::vec4& tint, bool shading ) { cube((1.0f - size) * -0.5f, size, texfaces, tint, shading); @@ -264,27 +243,27 @@ void Batch3D::blockCube( void Batch3D::vertex( const glm::vec3& coord, const glm::vec2& uv, const glm::vec4& tint ) { - if (index + B3D_VERTEX_SIZE >= capacity) { + if (index + 1 >= capacity) { flush(); } vertex(coord, uv, tint.r, tint.g, tint.b, tint.a); } void Batch3D::point(const glm::vec3& coord, const glm::vec4& tint) { - if (index + B3D_VERTEX_SIZE >= capacity) { + if (index + 1 >= capacity) { flushPoints(); } vertex(coord, {}, tint.r, tint.g, tint.b, tint.a); } void Batch3D::flush() { - mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE); + mesh->reload(buffer.get(), index); mesh->draw(); index = 0; } void Batch3D::flushPoints() { - mesh->reload(buffer.get(), index / B3D_VERTEX_SIZE); + mesh->reload(buffer.get(), index); mesh->draw(GL_POINTS); index = 0; } diff --git a/src/graphics/core/Batch3D.hpp b/src/graphics/core/Batch3D.hpp index 020f03bd..c3fb3775 100644 --- a/src/graphics/core/Batch3D.hpp +++ b/src/graphics/core/Batch3D.hpp @@ -2,19 +2,33 @@ #include "typedefs.hpp" #include "commons.hpp" +#include "MeshData.hpp" #include -#include +#include #include -class Mesh; +template class Mesh; + class Texture; struct UVRegion; +struct Batch3DVertex { + glm::vec3 position; + glm::vec2 uv; + glm::vec4 color; + + static constexpr VertexAttribute ATTRIBUTES[] { + {VertexAttribute::Type::FLOAT, false, 3}, + {VertexAttribute::Type::FLOAT, false, 2}, + {VertexAttribute::Type::FLOAT, false, 4}, + {{}, 0}}; +}; + class Batch3D : public Flushable { - std::unique_ptr buffer; + std::unique_ptr buffer; size_t capacity; - std::unique_ptr mesh; + std::unique_ptr> mesh; std::unique_ptr blank; size_t index; glm::vec4 tint {1.0f}; diff --git a/src/graphics/core/Cubemap.cpp b/src/graphics/core/Cubemap.cpp index 3267b25e..13bba31b 100644 --- a/src/graphics/core/Cubemap.cpp +++ b/src/graphics/core/Cubemap.cpp @@ -4,7 +4,7 @@ #include Cubemap::Cubemap(uint width, uint height, ImageFormat imageFormat) - : GLTexture(0, width, height) + : Texture(0, width, height) { glGenTextures(1, &id); glBindTexture(GL_TEXTURE_CUBE_MAP, id); diff --git a/src/graphics/core/Cubemap.hpp b/src/graphics/core/Cubemap.hpp index 3a80bda8..4ca1b988 100644 --- a/src/graphics/core/Cubemap.hpp +++ b/src/graphics/core/Cubemap.hpp @@ -1,9 +1,9 @@ #pragma once -#include "GLTexture.hpp" +#include "Texture.hpp" /// @brief Cubemap texture -class Cubemap : public GLTexture { +class Cubemap : public Texture { public: Cubemap(uint width, uint height, ImageFormat format); diff --git a/src/graphics/core/Framebuffer.cpp b/src/graphics/core/Framebuffer.cpp index 12f7637c..b0a452f4 100644 --- a/src/graphics/core/Framebuffer.cpp +++ b/src/graphics/core/Framebuffer.cpp @@ -1,7 +1,7 @@ #include "Framebuffer.hpp" #include -#include "GLTexture.hpp" +#include "Texture.hpp" Framebuffer::Framebuffer(uint fbo, uint depth, std::unique_ptr texture) : fbo(fbo), depth(depth), texture(std::move(texture)) @@ -25,7 +25,7 @@ static std::unique_ptr create_texture(int width, int height, int format glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0); - return std::make_unique(tex, width, height); + return std::make_unique(tex, width, height); } Framebuffer::Framebuffer(uint width, uint height, bool alpha) diff --git a/src/graphics/core/GLTexture.cpp b/src/graphics/core/GLTexture.cpp deleted file mode 100644 index f3d752d1..00000000 --- a/src/graphics/core/GLTexture.cpp +++ /dev/null @@ -1,101 +0,0 @@ -#include "GLTexture.hpp" -#include "gl_util.hpp" - -#include -#include -#include - -uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it - -GLTexture::GLTexture(uint id, uint width, uint height) - : Texture(width, height), id(id) { -} - -GLTexture::GLTexture(const ubyte* data, uint width, uint height, ImageFormat imageFormat) - : Texture(width, height) { - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_2D, id); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - GLenum format = gl::to_glenum(imageFormat); - glTexImage2D( - GL_TEXTURE_2D, 0, format, width, height, 0, - format, GL_UNSIGNED_BYTE, static_cast(data) - ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); - glBindTexture(GL_TEXTURE_2D, 0); -} - -GLTexture::~GLTexture() { - glDeleteTextures(1, &id); -} - -void GLTexture::bind() const { - glBindTexture(GL_TEXTURE_2D, id); -} - -void GLTexture::unbind() const { - glBindTexture(GL_TEXTURE_2D, 0); -} - -void GLTexture::reload(const ImageData& image) { - width = image.getWidth(); - height = image.getHeight(); - reload(image.getData()); -} - -void GLTexture::reload(const ubyte* data) { - glBindTexture(GL_TEXTURE_2D, id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, - GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); - glBindTexture(GL_TEXTURE_2D, 0); -} - -std::unique_ptr GLTexture::readData() { - auto data = std::make_unique(width * height * 4); - glBindTexture(GL_TEXTURE_2D, id); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); - glBindTexture(GL_TEXTURE_2D, 0); - return std::make_unique( - ImageFormat::rgba8888, width, height, std::move(data) - ); -} - -void GLTexture::setNearestFilter() { - bind(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); -} - -void GLTexture::setMipMapping(bool flag, bool pixelated) { - bind(); - if (flag) { - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - pixelated ? GL_NEAREST : GL_LINEAR_MIPMAP_NEAREST - ); - } else { - glTexParameteri( - GL_TEXTURE_2D, - GL_TEXTURE_MIN_FILTER, - pixelated ? GL_NEAREST : GL_LINEAR - ); - } - glBindTexture(GL_TEXTURE_2D, 0); -} - -std::unique_ptr GLTexture::from(const ImageData* image) { - uint width = image->getWidth(); - uint height = image->getHeight(); - void* data = image->getData(); - return std::make_unique(static_cast(data), width, height, image->getFormat()); -} - -uint GLTexture::getId() const { - return id; -} diff --git a/src/graphics/core/GLTexture.hpp b/src/graphics/core/GLTexture.hpp deleted file mode 100644 index 64fb5489..00000000 --- a/src/graphics/core/GLTexture.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "Texture.hpp" - -class GLTexture : public Texture { -protected: - uint id; -public: - GLTexture(uint id, uint width, uint height); - GLTexture(const ubyte* data, uint width, uint height, ImageFormat format); - virtual ~GLTexture(); - - virtual void bind() const override; - virtual void unbind() const override; - virtual void reload(const ubyte* data); - - void setNearestFilter(); - - virtual void reload(const ImageData& image) override; - - virtual void setMipMapping(bool flag, bool pixelated) override; - - virtual std::unique_ptr readData() override; - virtual uint getId() const override; - - virtual UVRegion getUVRegion() const override { - return UVRegion(0.0f, 0.0f, 1.0f, 1.0f); - } - - static std::unique_ptr from(const ImageData* image); -}; diff --git a/src/graphics/core/LineBatch.cpp b/src/graphics/core/LineBatch.cpp index aed8a249..9e33398a 100644 --- a/src/graphics/core/LineBatch.cpp +++ b/src/graphics/core/LineBatch.cpp @@ -3,12 +3,11 @@ #include -inline constexpr uint LB_VERTEX_SIZE = (3+4); LineBatch::LineBatch(size_t capacity) : capacity(capacity) { - const VertexAttribute attrs[] = { {3},{4}, {0} }; - buffer = std::make_unique(capacity * LB_VERTEX_SIZE * 2); - mesh = std::make_unique(buffer.get(), 0, attrs); + + buffer = std::make_unique(capacity * 2); + mesh = std::make_unique>(buffer.get(), 0); index = 0; } @@ -16,31 +15,21 @@ LineBatch::~LineBatch(){ } void LineBatch::line( - float x1, float y1, - float z1, float x2, + float x1, float y1, + float z1, float x2, float y2, float z2, float r, float g, float b, float a ) { - if (index + LB_VERTEX_SIZE * 2 >= capacity) { + if (index + 2 >= capacity) { flush(); } - buffer[index] = x1; - buffer[index+1] = y1; - buffer[index+2] = z1; - buffer[index+3] = r; - buffer[index+4] = g; - buffer[index+5] = b; - buffer[index+6] = a; - index += LB_VERTEX_SIZE; + buffer[index].position = {x1,y1,z1}; + buffer[index].color = {r,g,b,a}; + index++; - buffer[index] = x2; - buffer[index+1] = y2; - buffer[index+2] = z2; - buffer[index+3] = r; - buffer[index+4] = g; - buffer[index+5] = b; - buffer[index+6] = a; - index += LB_VERTEX_SIZE; + buffer[index].position = {x2,y2,z2}; + buffer[index].color = {r,g,b,a}; + index++; } void LineBatch::box(float x, float y, float z, float w, float h, float d, @@ -68,7 +57,7 @@ void LineBatch::box(float x, float y, float z, float w, float h, float d, void LineBatch::flush(){ if (index == 0) return; - mesh->reload(buffer.get(), index / LB_VERTEX_SIZE); + mesh->reload(buffer.get(), index); mesh->draw(GL_LINES); index = 0; } diff --git a/src/graphics/core/LineBatch.hpp b/src/graphics/core/LineBatch.hpp index fe77da60..eb32e1ee 100644 --- a/src/graphics/core/LineBatch.hpp +++ b/src/graphics/core/LineBatch.hpp @@ -5,12 +5,24 @@ #include #include "commons.hpp" +#include "MeshData.hpp" +template class Mesh; +struct LineVertex { + glm::vec3 position; + glm::vec4 color; + + static constexpr VertexAttribute ATTRIBUTES[] { + {VertexAttribute::Type::FLOAT, false, 3}, + {VertexAttribute::Type::FLOAT, false, 4}, + {{}, 0}}; +}; + class LineBatch : public Flushable { - std::unique_ptr mesh; - std::unique_ptr buffer; + std::unique_ptr> mesh; + std::unique_ptr buffer; size_t index; size_t capacity; public: diff --git a/src/graphics/core/Mesh.cpp b/src/graphics/core/Mesh.cpp index 808b88c4..f1f79f3e 100644 --- a/src/graphics/core/Mesh.cpp +++ b/src/graphics/core/Mesh.cpp @@ -1,93 +1,4 @@ -#include "Mesh.hpp" -#include -#include +#include "graphics/core/Mesh.hpp" -int Mesh::meshesCount = 0; -int Mesh::drawCalls = 0; - -inline size_t calc_vertex_size(const VertexAttribute* attrs) { - size_t vertexSize = 0; - for (int i = 0; attrs[i].size; i++) { - vertexSize += attrs[i].size; - } - assert(vertexSize != 0); - return vertexSize; -} - -Mesh::Mesh(const MeshData& data) - : Mesh(data.vertices.data(), - data.vertices.size() / calc_vertex_size(data.attrs.data()), - data.indices.data(), - data.indices.size(), - data.attrs.data()) {} - -Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs) : - ibo(0), - vertices(0), - indices(0) -{ - meshesCount++; - vertexSize = 0; - for (int i = 0; attrs[i].size; i++) { - vertexSize += attrs[i].size; - } - - glGenVertexArrays(1, &vao); - glGenBuffers(1, &vbo); - - reload(vertexBuffer, vertices, indexBuffer, indices); - - // attributes - int offset = 0; - for (int i = 0; attrs[i].size; i++) { - int size = attrs[i].size; - glVertexAttribPointer(i, size, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (GLvoid*)(offset * sizeof(float))); - glEnableVertexAttribArray(i); - offset += size; - } - - glBindVertexArray(0); -} - -Mesh::~Mesh(){ - meshesCount--; - glDeleteVertexArrays(1, &vao); - glDeleteBuffers(1, &vbo); - if (ibo != 0) glDeleteBuffers(1, &ibo); -} - -void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices){ - glBindVertexArray(vao); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - if (vertexBuffer != nullptr && vertices != 0) { - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STREAM_DRAW); - } else { - glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW); - } - if (indexBuffer != nullptr && indices != 0) { - if (ibo == 0) glGenBuffers(1, &ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices, indexBuffer, GL_STATIC_DRAW); - } - else if (ibo != 0) { - glDeleteBuffers(1, &ibo); - } - this->vertices = vertices; - this->indices = indices; -} - -void Mesh::draw(unsigned int primitive) const { - drawCalls++; - glBindVertexArray(vao); - if (ibo != 0) { - glDrawElements(primitive, indices, GL_UNSIGNED_INT, 0); - } - else { - glDrawArrays(primitive, 0, vertices); - } - glBindVertexArray(0); -} - -void Mesh::draw() const { - draw(GL_TRIANGLES); -} + int MeshStats::meshesCount = 0; + int MeshStats::drawCalls = 0; \ No newline at end of file diff --git a/src/graphics/core/Mesh.hpp b/src/graphics/core/Mesh.hpp index 482c82bf..3d428322 100644 --- a/src/graphics/core/Mesh.hpp +++ b/src/graphics/core/Mesh.hpp @@ -1,39 +1,54 @@ #pragma once -#include - -#include "typedefs.hpp" #include "MeshData.hpp" + +struct MeshStats { + static int meshesCount; + static int drawCalls; +}; + +template class Mesh { unsigned int vao; unsigned int vbo; unsigned int ibo; - size_t vertices; - size_t indices; - size_t vertexSize; + size_t vertexCount; + size_t indexCount; public: - Mesh(const MeshData& data); - Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs); - Mesh(const float* vertexBuffer, size_t vertices, const VertexAttribute* attrs) : - Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; + explicit Mesh(const MeshData& data); + + Mesh( + const VertexStructure* vertexBuffer, + size_t vertices, + const uint32_t* indexBuffer, + size_t indices + ); + + Mesh(const VertexStructure* vertexBuffer, size_t vertices) + : Mesh(vertexBuffer, vertices, nullptr, 0) {}; + ~Mesh(); - /// @brief Update GL vertex and index buffers data without changing VAO attributes + /// @brief Update GL vertex and index buffers data without changing VAO + /// attributes /// @param vertexBuffer vertex data buffer - /// @param vertices number of vertices in new buffer + /// @param vertexCount number of vertices in new buffer /// @param indexBuffer indices buffer - /// @param indices number of values in indices buffer - void reload(const float* vertexBuffer, size_t vertices, const int* indexBuffer = nullptr, size_t indices = 0); - + /// @param indexCount number of values in indices buffer + void reload( + const VertexStructure* vertexBuffer, + size_t vertexCount, + const uint32_t* indexBuffer = nullptr, + size_t indexCount = 0 + ); + /// @brief Draw mesh with specified primitives type /// @param primitive primitives type void draw(unsigned int primitive) const; /// @brief Draw mesh as triangles void draw() const; - - /// @brief Total numbers of alive mesh objects - static int meshesCount; - static int drawCalls; }; + +#include "graphics/core/Mesh.inl" diff --git a/src/graphics/core/Mesh.inl b/src/graphics/core/Mesh.inl new file mode 100644 index 00000000..390c2f9a --- /dev/null +++ b/src/graphics/core/Mesh.inl @@ -0,0 +1,124 @@ +#pragma once + +#include "MeshData.hpp" +#include "gl_util.hpp" + +inline constexpr size_t calc_size(const VertexAttribute attrs[]) { + size_t vertexSize = 0; + for (int i = 0; attrs[i].count; i++) { + vertexSize += attrs[i].size(); + } + return vertexSize; +} + +template +Mesh::Mesh(const MeshData& data) + : Mesh( + data.vertices.data(), + data.vertices.size(), + data.indices.data(), + data.indices.size() + ) { +} + +template +Mesh::Mesh( + const VertexStructure* vertexBuffer, + size_t vertices, + const uint32_t* indexBuffer, + size_t indices +) + : vao(0), vbo(0), ibo(0), vertexCount(0), indexCount(0) { + static_assert( + calc_size(VertexStructure::ATTRIBUTES) == sizeof(VertexStructure) + ); + + const auto& attrs = VertexStructure::ATTRIBUTES; + MeshStats::meshesCount++; + + glGenVertexArrays(1, &vao); + glGenBuffers(1, &vbo); + + reload(vertexBuffer, vertices, indexBuffer, indices); + + // attributes + int offset = 0; + for (int i = 0; attrs[i].count; i++) { + const VertexAttribute& attr = attrs[i]; + glVertexAttribPointer( + i, + attr.count, + gl::to_glenum(attr.type), + attr.normalized, + sizeof(VertexStructure), + (GLvoid*)(size_t)offset + ); + glEnableVertexAttribArray(i); + offset += attr.size(); + } + + glBindVertexArray(0); +} + +template +Mesh::~Mesh() { + MeshStats::meshesCount--; + glDeleteVertexArrays(1, &vao); + glDeleteBuffers(1, &vbo); + if (ibo != 0) { + glDeleteBuffers(1, &ibo); + } +} + +template +void Mesh::reload( + const VertexStructure* vertexBuffer, + size_t vertexCount, + const uint32_t* indexBuffer, + size_t indexCount +) { + this->vertexCount = vertexCount; + this->indexCount = indexCount; + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + if (vertexBuffer != nullptr && vertexCount != 0) { + glBufferData( + GL_ARRAY_BUFFER, + vertexCount * sizeof(VertexStructure), + vertexBuffer, + GL_STREAM_DRAW + ); + } else { + glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW); + } + + if (indexBuffer != nullptr && indexCount != 0) { + if (ibo == 0) glGenBuffers(1, &ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + sizeof(uint32_t) * indexCount, + indexBuffer, + GL_STATIC_DRAW + ); + } else if (ibo != 0) { + glDeleteBuffers(1, &ibo); + } +} + +template +void Mesh::draw(unsigned int primitive) const { + MeshStats::drawCalls++; + glBindVertexArray(vao); + if (ibo != 0) { + glDrawElements(primitive, indexCount, GL_UNSIGNED_INT, nullptr); + } else { + glDrawArrays(primitive, 0, vertexCount); + } + glBindVertexArray(0); +} + +template +void Mesh::draw() const { + draw(GL_TRIANGLES); +} diff --git a/src/graphics/core/MeshData.hpp b/src/graphics/core/MeshData.hpp index 39220119..82954b23 100644 --- a/src/graphics/core/MeshData.hpp +++ b/src/graphics/core/MeshData.hpp @@ -1,19 +1,46 @@ #pragma once -#include +#include #include "typedefs.hpp" #include "util/Buffer.hpp" /// @brief Vertex attribute info struct VertexAttribute { - ubyte size; + enum class Type { + FLOAT, + INT, UNSIGNED_INT, + SHORT, UNSIGNED_SHORT, + BYTE, UNSIGNED_BYTE + }; + + Type type = Type::FLOAT; + bool normalized = false; + ubyte count = 0; + + [[nodiscard]] constexpr uint32_t size() const { + switch (type) { + case Type::FLOAT: + return count * sizeof(float); + case Type::UNSIGNED_INT: + case Type::INT: + return count * sizeof(int32_t); + case Type::UNSIGNED_SHORT: + case Type::SHORT: + return count * sizeof(int16_t); + case Type::UNSIGNED_BYTE: + case Type::BYTE: + return count * sizeof(int8_t); + } + return 0; + } }; /// @brief Raw mesh data structure +template struct MeshData { - util::Buffer vertices; - util::Buffer indices; + util::Buffer vertices; + util::Buffer indices; util::Buffer attrs; MeshData() = default; @@ -22,8 +49,8 @@ struct MeshData { /// @param indices nullable indices buffer /// @param attrs vertex attribute sizes (must be null-terminated) MeshData( - util::Buffer vertices, - util::Buffer indices, + util::Buffer vertices, + util::Buffer indices, util::Buffer attrs ) : vertices(std::move(vertices)), indices(std::move(indices)), diff --git a/src/graphics/core/PostProcessing.cpp b/src/graphics/core/PostProcessing.cpp index c15aa8fb..2968cb4d 100644 --- a/src/graphics/core/PostProcessing.cpp +++ b/src/graphics/core/PostProcessing.cpp @@ -12,12 +12,16 @@ PostProcessing::PostProcessing(size_t effectSlotsCount) : effectSlots(effectSlotsCount) { // Fullscreen quad mesh bulding - float vertices[] { - -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f + PostProcessingVertex meshData[]{ + {{-1.0f, -1.0f}}, + {{-1.0f, 1.0f}}, + {{1.0f, 1.0f}}, + {{-1.0f, -1.0f}}, + {{1.0f, 1.0f}}, + {{1.0f, -1.0f}}, }; - VertexAttribute attrs[] {{2}, {0}}; - quadMesh = std::make_unique(vertices, 6, attrs); + + quadMesh = std::make_unique>(meshData, 6); } PostProcessing::~PostProcessing() = default; diff --git a/src/graphics/core/PostProcessing.hpp b/src/graphics/core/PostProcessing.hpp index 57a081c9..c6b3ae14 100644 --- a/src/graphics/core/PostProcessing.hpp +++ b/src/graphics/core/PostProcessing.hpp @@ -2,14 +2,24 @@ #include #include +#include +#include "MeshData.hpp" -class Mesh; +template class Mesh; class Assets; class Framebuffer; class DrawContext; class ImageData; class PostEffect; +struct PostProcessingVertex { + glm::vec2 position; + + static constexpr VertexAttribute ATTRIBUTES[] { + {VertexAttribute::Type::FLOAT, false, 2}, + {{}, 0}}; +}; + /// @brief Framebuffer with blitting with shaders. /// @attention Current implementation does not support multiple render passes /// for multiple effects. Will be implemented in v0.21 @@ -18,7 +28,7 @@ class PostProcessing { std::unique_ptr fbo; std::unique_ptr fboSecond; /// @brief Fullscreen quad mesh as the post-processing canvas - std::unique_ptr quadMesh; + std::unique_ptr> quadMesh; std::vector> effectSlots; public: PostProcessing(size_t effectSlotsCount); diff --git a/src/graphics/core/Texture.cpp b/src/graphics/core/Texture.cpp index 2484383e..1dc18a65 100644 --- a/src/graphics/core/Texture.cpp +++ b/src/graphics/core/Texture.cpp @@ -1,6 +1,103 @@ #include "Texture.hpp" -#include "GLTexture.hpp" +#include "gl_util.hpp" + +#include +#include +#include + +uint Texture::MAX_RESOLUTION = 1024; // Window.initialize overrides it + +Texture::Texture(uint id, uint width, uint height) + : id(id), width(width), height(height) { +} + +Texture::Texture(const ubyte* data, uint width, uint height, ImageFormat imageFormat) + : width(width), height(height) { + glGenTextures(1, &id); + glBindTexture(GL_TEXTURE_2D, id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + GLenum format = gl::to_glenum(imageFormat); + glTexImage2D( + GL_TEXTURE_2D, 0, format, width, height, 0, + format, GL_UNSIGNED_BYTE, static_cast(data) + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glGenerateMipmap(GL_TEXTURE_2D); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); + glBindTexture(GL_TEXTURE_2D, 0); +} + +Texture::~Texture() { + glDeleteTextures(1, &id); +} + +void Texture::bind() const { + glBindTexture(GL_TEXTURE_2D, id); +} + +void Texture::unbind() const { + glBindTexture(GL_TEXTURE_2D, 0); +} + +void Texture::reload(const ImageData& image) { + width = image.getWidth(); + height = image.getHeight(); + reload(image.getData()); +} + +void Texture::reload(const ubyte* data) { + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, static_cast(data)); + glBindTexture(GL_TEXTURE_2D, 0); +} + +std::unique_ptr Texture::readData() { + auto data = std::make_unique(width * height * 4); + glBindTexture(GL_TEXTURE_2D, id); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.get()); + glBindTexture(GL_TEXTURE_2D, 0); + return std::make_unique( + ImageFormat::rgba8888, width, height, std::move(data) + ); +} + +void Texture::setNearestFilter() { + bind(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glBindTexture(GL_TEXTURE_2D, 0); +} + +void Texture::setMipMapping(bool flag, bool pixelated) { + bind(); + if (flag) { + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + pixelated ? GL_NEAREST : GL_LINEAR_MIPMAP_NEAREST + ); + } else { + glTexParameteri( + GL_TEXTURE_2D, + GL_TEXTURE_MIN_FILTER, + pixelated ? GL_NEAREST : GL_LINEAR + ); + } + glBindTexture(GL_TEXTURE_2D, 0); +} std::unique_ptr Texture::from(const ImageData* image) { - return GLTexture::from(image); + uint width = image->getWidth(); + uint height = image->getHeight(); + void* data = image->getData(); + return std::make_unique( + static_cast(data), width, height, image->getFormat() + ); +} + +uint Texture::getId() const { + return id; } diff --git a/src/graphics/core/Texture.hpp b/src/graphics/core/Texture.hpp index 483c93da..59568619 100644 --- a/src/graphics/core/Texture.hpp +++ b/src/graphics/core/Texture.hpp @@ -8,33 +8,39 @@ class Texture { protected: + uint id; uint width; uint height; - - Texture(uint width, uint height) : width(width), height(height) {} public: - static uint MAX_RESOLUTION; + Texture(uint id, uint width, uint height); + Texture(const ubyte* data, uint width, uint height, ImageFormat format); + virtual ~Texture(); - virtual ~Texture() {} + virtual void bind() const; + virtual void unbind() const; + void reload(const ubyte* data); - virtual void bind() const = 0; - virtual void unbind() const = 0; + void setNearestFilter(); - virtual void reload(const ImageData& image) = 0; + void reload(const ImageData& image); - virtual std::unique_ptr readData() = 0; + void setMipMapping(bool flag, bool pixelated); - virtual uint getWidth() const { + std::unique_ptr readData(); + uint getId() const; + + UVRegion getUVRegion() const { + return UVRegion(0.0f, 0.0f, 1.0f, 1.0f); + } + + uint getWidth() const { return width; } - virtual uint getHeight() const { + + uint getHeight() const { return height; } - virtual UVRegion getUVRegion() const = 0; - - virtual uint getId() const = 0; - - virtual void setMipMapping(bool flag, bool pixelated) = 0; static std::unique_ptr from(const ImageData* image); + static uint MAX_RESOLUTION; }; diff --git a/src/graphics/core/TextureAnimation.cpp b/src/graphics/core/TextureAnimation.cpp index fd49e508..73af95a2 100644 --- a/src/graphics/core/TextureAnimation.cpp +++ b/src/graphics/core/TextureAnimation.cpp @@ -1,5 +1,5 @@ #include "TextureAnimation.hpp" -#include "GLTexture.hpp" +#include "Texture.hpp" #include "Framebuffer.hpp" #include diff --git a/src/graphics/core/gl_util.hpp b/src/graphics/core/gl_util.hpp index 3e34b923..da2abfb5 100644 --- a/src/graphics/core/gl_util.hpp +++ b/src/graphics/core/gl_util.hpp @@ -2,6 +2,7 @@ #include "commons.hpp" #include "ImageData.hpp" +#include "MeshData.hpp" #include @@ -23,4 +24,25 @@ namespace gl { }; return primitives[static_cast(primitive)]; } + + inline GLenum to_glenum(VertexAttribute::Type type) { + using Type = VertexAttribute::Type; + switch (type) { + case Type::FLOAT: + return GL_FLOAT; + case Type::UNSIGNED_INT: + return GL_UNSIGNED_INT; + case Type::INT: + return GL_INT; + case Type::UNSIGNED_SHORT: + return GL_UNSIGNED_SHORT; + case Type::SHORT: + return GL_SHORT; + case Type::UNSIGNED_BYTE: + return GL_UNSIGNED_BYTE; + case Type::BYTE: + return GL_BYTE; + } + return 0; + } } diff --git a/src/graphics/render/BlockWrapsRenderer.cpp b/src/graphics/render/BlockWrapsRenderer.cpp index ca10a2b9..3a5f118c 100644 --- a/src/graphics/render/BlockWrapsRenderer.cpp +++ b/src/graphics/render/BlockWrapsRenderer.cpp @@ -44,8 +44,8 @@ void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) { } if (vox->id != BLOCK_VOID) { const auto& def = level.content.getIndices()->blocks.require(vox->id); - switch (def.model) { - case BlockModel::block: + switch (def.model.type) { + case BlockModelType::BLOCK: batch->cube( glm::vec3(wrapper.position) + glm::vec3(0.5f), glm::vec3(1.01f), @@ -54,7 +54,7 @@ void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) { false ); break; - case BlockModel::aabb: { + case BlockModelType::AABB: { const auto& aabb = (def.rotatable ? def.rt.hitboxes[vox->state.rotation] : def.hitboxes) diff --git a/src/graphics/render/BlocksPreview.cpp b/src/graphics/render/BlocksPreview.cpp index 982d7f47..34c3e7df 100644 --- a/src/graphics/render/BlocksPreview.cpp +++ b/src/graphics/render/BlocksPreview.cpp @@ -32,17 +32,17 @@ std::unique_ptr BlocksPreview::draw( cache.getRegion(id, 4), cache.getRegion(id, 5)}; glm::vec3 offset(0.1f, 0.5f, 0.1f); - switch (def.model) { - case BlockModel::none: + switch (def.model.type) { + case BlockModelType::NONE: // something went wrong... break; - case BlockModel::block: + case BlockModelType::BLOCK: shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); batch.blockCube(glm::vec3(size * 0.63f), texfaces, glm::vec4(1.0f), !def.rt.emissive); batch.flush(); break; - case BlockModel::aabb: + case BlockModelType::AABB: { glm::vec3 hitbox {}; for (const auto& box : def.hitboxes) { @@ -60,7 +60,7 @@ std::unique_ptr BlocksPreview::draw( } batch.flush(); break; - case BlockModel::custom:{ + case BlockModelType::CUSTOM:{ glm::vec3 pmul = glm::vec3(size * 0.63f); glm::vec3 hitbox = glm::vec3(1.0f); glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f); @@ -78,7 +78,7 @@ std::unique_ptr BlocksPreview::draw( } break; } - case BlockModel::xsprite: { + case BlockModelType::XSPRITE: { shader.uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset)); glm::vec3 right = glm::normalize(glm::vec3(1.f, 0.f, -1.f)); batch.sprite( diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 22bab4d8..83086975 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -9,7 +9,8 @@ #include "lighting/Lightmap.hpp" #include "frontend/ContentGfxCache.hpp" -const glm::vec3 BlocksRenderer::SUN_VECTOR (0.2275f,0.9388f,-0.1005f); +const glm::vec3 BlocksRenderer::SUN_VECTOR(0.528265f, 0.833149f, -0.163704f); +const float DIRECTIONAL_LIGHT_FACTOR = 0.3f; BlocksRenderer::BlocksRenderer( size_t capacity, @@ -17,18 +18,18 @@ BlocksRenderer::BlocksRenderer( const ContentGfxCache& cache, const EngineSettings& settings ) : content(content), - vertexBuffer(std::make_unique(capacity * CHUNK_VERTEX_SIZE)), - indexBuffer(std::make_unique(capacity)), + vertexBuffer(std::make_unique(capacity)), + indexBuffer(std::make_unique(capacity)), + vertexCount(0), vertexOffset(0), - indexOffset(0), - indexSize(0), + indexCount(0), capacity(capacity), cache(cache), - settings(settings) + settings(settings) { voxelsBuffer = std::make_unique( - CHUNK_W + voxelBufferPadding*2, - CHUNK_H, + CHUNK_W + voxelBufferPadding*2, + CHUNK_H, CHUNK_D + voxelBufferPadding*2); blockDefsCache = content.getIndices()->blocks.getDefs(); } @@ -40,39 +41,31 @@ BlocksRenderer::~BlocksRenderer() { void BlocksRenderer::vertex( const glm::vec3& coord, float u, float v, const glm::vec4& light ) { - vertexBuffer[vertexOffset++] = coord.x; - vertexBuffer[vertexOffset++] = coord.y; - vertexBuffer[vertexOffset++] = coord.z; - vertexBuffer[vertexOffset++] = u; - vertexBuffer[vertexOffset++] = v; + vertexBuffer[vertexCount].position = coord; - union { - float floating; - uint32_t integer; - } compressed; + vertexBuffer[vertexCount].uv = {u,v}; - compressed.integer = (static_cast(light.r * 255) & 0xff) << 24; - compressed.integer |= (static_cast(light.g * 255) & 0xff) << 16; - compressed.integer |= (static_cast(light.b * 255) & 0xff) << 8; - compressed.integer |= (static_cast(light.a * 255) & 0xff); - - vertexBuffer[vertexOffset++] = compressed.floating; + vertexBuffer[vertexCount].color[0] = static_cast(light.r * 255); + vertexBuffer[vertexCount].color[1] = static_cast(light.g * 255); + vertexBuffer[vertexCount].color[2] = static_cast(light.b * 255); + vertexBuffer[vertexCount].color[3] = static_cast(light.a * 255); + vertexCount++; } -void BlocksRenderer::index(int a, int b, int c, int d, int e, int f) { - indexBuffer[indexSize++] = indexOffset + a; - indexBuffer[indexSize++] = indexOffset + b; - indexBuffer[indexSize++] = indexOffset + c; - indexBuffer[indexSize++] = indexOffset + d; - indexBuffer[indexSize++] = indexOffset + e; - indexBuffer[indexSize++] = indexOffset + f; - indexOffset += 4; +void BlocksRenderer::index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f) { + indexBuffer[indexCount++] = static_cast(vertexOffset + a); + indexBuffer[indexCount++] = static_cast(vertexOffset + b); + indexBuffer[indexCount++] = static_cast(vertexOffset + c); + indexBuffer[indexCount++] = static_cast(vertexOffset + d); + indexBuffer[indexCount++] = static_cast(vertexOffset + e); + indexBuffer[indexCount++] = static_cast(vertexOffset + f); + vertexOffset += 4; } /// @brief Add face with precalculated lights void BlocksRenderer::face( - const glm::vec3& coord, + const glm::vec3& coord, float w, float h, float d, const glm::vec3& axisX, const glm::vec3& axisY, @@ -81,7 +74,7 @@ void BlocksRenderer::face( const glm::vec4(&lights)[4], const glm::vec4& tint ) { - if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { + if (vertexCount + 4 >= capacity) { overflow = true; return; } @@ -97,7 +90,7 @@ void BlocksRenderer::face( } void BlocksRenderer::vertexAO( - const glm::vec3& coord, + const glm::vec3& coord, float u, float v, const glm::vec4& tint, const glm::vec3& axisX, @@ -121,7 +114,7 @@ void BlocksRenderer::faceAO( const UVRegion& region, bool lights ) { - if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { + if (vertexCount + 4 >= capacity) { overflow = true; return; } @@ -129,7 +122,7 @@ void BlocksRenderer::faceAO( float s = 0.5f; if (lights) { float d = glm::dot(glm::normalize(Z), SUN_VECTOR); - d = 0.7f + d * 0.3f; + d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR; auto axisX = glm::normalize(X); auto axisY = glm::normalize(Y); @@ -159,7 +152,7 @@ void BlocksRenderer::face( glm::vec4 tint, bool lights ) { - if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { + if (vertexCount + 4 >= capacity) { overflow = true; return; } @@ -167,7 +160,7 @@ void BlocksRenderer::face( float s = 0.5f; if (lights) { float d = glm::dot(glm::normalize(Z), SUN_VECTOR); - d = 0.7f + d * 0.3f; + d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR; tint *= d; } vertex(coord + (-X - Y + Z) * s, region.u1, region.v1, tint); @@ -178,10 +171,10 @@ void BlocksRenderer::face( } void BlocksRenderer::blockXSprite( - int x, int y, int z, - const glm::vec3& size, - const UVRegion& texface1, - const UVRegion& texface2, + int x, int y, int z, + const glm::vec3& size, + const UVRegion& texface1, + const UVRegion& texface2, float spread ) { glm::vec4 lights1[] { @@ -207,12 +200,12 @@ void BlocksRenderer::blockXSprite( face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, 1}, {0, 1, 0}, glm::vec3(), texface1, lights2, tint); - face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(), + face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, 1}, {0, 1, 0}, glm::vec3(), texface1, lights1, tint); - face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(), + face({x + xs, y, z + zs}, w, size.y, 0, {-1, 0, -1}, {0, 1, 0}, glm::vec3(), texface2, lights2, tint); - face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(), + face({x + xs, y, z + zs}, w, size.y, 0, {1, 0, -1}, {0, 1, 0}, glm::vec3(), texface2, lights1, tint); } @@ -221,8 +214,8 @@ void BlocksRenderer::blockXSprite( /// @brief AABB blocks render method void BlocksRenderer::blockAABB( const glm::ivec3& icoord, - const UVRegion(&texfaces)[6], - const Block* block, + const UVRegion(&texfaces)[6], + const Block* block, ubyte rotation, bool lights, bool ao @@ -249,7 +242,7 @@ void BlocksRenderer::blockAABB( orient.transform(hitbox); } coord -= glm::vec3(0.5f) - hitbox.center(); - + if (ao) { faceAO(coord, X*size.x, Y*size.y, Z*size.z, texfaces[5], lights); // north faceAO(coord, -X*size.x, Y*size.y, -Z*size.z, texfaces[4], lights); // south @@ -272,6 +265,19 @@ void BlocksRenderer::blockAABB( } } +static bool is_aligned(const glm::vec3& v, float e = 1e-6f) { + if (std::abs(v.y) < e && std::abs(v.z) < e && std::abs(v.x) > e) { + return true; + } + if (std::abs(v.x) < e && std::abs(v.z) < e && std::abs(v.y) > e) { + return true; + } + if (std::abs(v.x) < e && std::abs(v.y) < e && std::abs(v.z) > e) { + return true; + } + return false; +} + void BlocksRenderer::blockCustomModel( const glm::ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao ) { @@ -289,32 +295,44 @@ void BlocksRenderer::blockCustomModel( const auto& model = cache.getModel(block->rt.id); for (const auto& mesh : model.meshes) { - if (vertexOffset + CHUNK_VERTEX_SIZE * mesh.vertices.size() > capacity) { + if (vertexCount + mesh.vertices.size() >= capacity) { overflow = true; return; } for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) { auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord - mesh.vertices[triangle * 3 + 1].coord; + r = r.x * X + r.y * Y + r.z * Z; r = glm::normalize(r); + const auto& v0 = mesh.vertices[triangle * 3]; + auto n = v0.normal.x * X + v0.normal.y * Y + v0.normal.z * Z; + + if (!isOpen(glm::floor(coord + n * 1e-4f), *block) && is_aligned(n)) { + continue; + } + + float d = glm::dot(n, SUN_VECTOR); + d = (1.0f - DIRECTIONAL_LIGHT_FACTOR) + d * DIRECTIONAL_LIGHT_FACTOR; + glm::vec3 t = glm::cross(r, n); + for (int i = 0; i < 3; i++) { const auto& vertex = mesh.vertices[triangle * 3 + i]; - auto n = vertex.normal.x * X + vertex.normal.y * Y + - vertex.normal.z * Z; - float d = glm::dot(n, SUN_VECTOR); - d = 0.8f + d * 0.2f; const auto& vcoord = vertex.coord - 0.5f; - vertexAO( + + glm::vec4 aoColor {1.0f, 1.0f, 1.0f, 1.0f}; + if (ao) { + auto p = coord + vcoord.x * X + vcoord.y * Y + + vcoord.z * Z + r * 0.5f + t * 0.5f + n * 0.5f; + aoColor = pickSoftLight(p.x, p.y, p.z, glm::ivec3(r), glm::ivec3(t)); + } + this->vertex( coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, vertex.uv.x, vertex.uv.y, - glm::vec4(d, d, d, d), - glm::cross(r, n), - r, - n + glm::vec4(d, d, d, d) * aoColor ); - indexBuffer[indexSize++] = indexOffset++; + indexBuffer[indexCount++] = vertexOffset++; } } } @@ -322,9 +340,9 @@ void BlocksRenderer::blockCustomModel( /* Fastest solid shaded blocks render method */ void BlocksRenderer::blockCube( - const glm::ivec3& coord, - const UVRegion(&texfaces)[6], - const Block& block, + const glm::ivec3& coord, + const UVRegion(&texfaces)[6], + const Block& block, blockstate states, bool lights, bool ao @@ -340,7 +358,7 @@ void BlocksRenderer::blockCube( Y = orient.axes[1]; Z = orient.axes[2]; } - + if (ao) { if (isOpen(coord + Z, block)) { faceAO(coord, X, Y, Z, texfaces[5], lights); @@ -383,8 +401,8 @@ void BlocksRenderer::blockCube( } bool BlocksRenderer::isOpenForLight(int x, int y, int z) const { - blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, - y, + blockid_t id = voxelsBuffer->pickBlockId(chunk->x * CHUNK_W + x, + y, chunk->z * CHUNK_D + z); if (id == BLOCK_VOID) { return false; @@ -398,7 +416,7 @@ bool BlocksRenderer::isOpenForLight(int x, int y, int z) const { glm::vec4 BlocksRenderer::pickLight(int x, int y, int z) const { if (isOpenForLight(x, y, z)) { - light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y, + light_t light = voxelsBuffer->pickLight(chunk->x * CHUNK_W + x, y, chunk->z * CHUNK_D + z); return glm::vec4(Lightmap::extract(light, 0), Lightmap::extract(light, 1), @@ -426,8 +444,8 @@ glm::vec4 BlocksRenderer::pickSoftLight( float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up ) const { return pickSoftLight({ - static_cast(std::round(x)), - static_cast(std::round(y)), + static_cast(std::round(x)), + static_cast(std::round(y)), static_cast(std::round(z))}, right, up); } @@ -460,23 +478,23 @@ void BlocksRenderer::render( int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); int z = (i / CHUNK_D) % CHUNK_W; - switch (def.model) { - case BlockModel::block: + switch (def.model.type) { + case BlockModelType::BLOCK: blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, def.ambientOcclusion); break; - case BlockModel::xsprite: { - blockXSprite(x, y, z, glm::vec3(1.0f), + case BlockModelType::XSPRITE: { + blockXSprite(x, y, z, glm::vec3(1.0f), texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); break; } - case BlockModel::aabb: { - blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, + case BlockModelType::AABB: { + blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, !def.shadeless, def.ambientOcclusion); break; } - case BlockModel::custom: { - blockCustomModel({x, y, z}, &def, vox.state.rotation, + case BlockModelType::CUSTOM: { + blockCustomModel({x, y, z}, &def, vox.state.rotation, !def.shadeless, def.ambientOcclusion); break; } @@ -523,30 +541,30 @@ SortingMeshData BlocksRenderer::renderTranslucent( int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); int z = (i / CHUNK_D) % CHUNK_W; - switch (def.model) { - case BlockModel::block: + switch (def.model.type) { + case BlockModelType::BLOCK: blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, def.ambientOcclusion); break; - case BlockModel::xsprite: { - blockXSprite(x, y, z, glm::vec3(1.0f), + case BlockModelType::XSPRITE: { + blockXSprite(x, y, z, glm::vec3(1.0f), texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); break; } - case BlockModel::aabb: { - blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, + case BlockModelType::AABB: { + blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, !def.shadeless, def.ambientOcclusion); break; } - case BlockModel::custom: { - blockCustomModel({x, y, z}, &def, vox.state.rotation, + case BlockModelType::CUSTOM: { + blockCustomModel({x, y, z}, &def, vox.state.rotation, !def.shadeless, def.ambientOcclusion); break; } default: break; } - if (vertexOffset == 0) { + if (vertexCount == 0) { continue; } SortingMeshEntry entry { @@ -555,50 +573,50 @@ SortingMeshData BlocksRenderer::renderTranslucent( y + 0.5f, z + chunk->z * CHUNK_D + 0.5f ), - util::Buffer(indexSize * CHUNK_VERTEX_SIZE), 0}; + util::Buffer(indexCount), 0}; totalSize += entry.vertexData.size(); - for (int j = 0; j < indexSize; j++) { + for (int j = 0; j < indexCount; j++) { std::memcpy( - entry.vertexData.data() + j * CHUNK_VERTEX_SIZE, - vertexBuffer.get() + indexBuffer[j] * CHUNK_VERTEX_SIZE, - sizeof(float) * CHUNK_VERTEX_SIZE + entry.vertexData.data() + j, + vertexBuffer.get() + indexBuffer[j], + sizeof(ChunkVertex) ); - float& vx = entry.vertexData[j * CHUNK_VERTEX_SIZE + 0]; - float& vy = entry.vertexData[j * CHUNK_VERTEX_SIZE + 1]; - float& vz = entry.vertexData[j * CHUNK_VERTEX_SIZE + 2]; + ChunkVertex& vertex = entry.vertexData[j]; if (!aabbInit) { aabbInit = true; - aabb.a = aabb.b = {vx, vy, vz}; + aabb.a = aabb.b = vertex.position; } else { - aabb.addPoint(glm::vec3(vx, vy, vz)); + aabb.addPoint(vertex.position); } - vx += chunk->x * CHUNK_W + 0.5f; - vy += 0.5f; - vz += chunk->z * CHUNK_D + 0.5f; + + vertex.position.x += chunk->x * CHUNK_W + 0.5f; + vertex.position.y += 0.5f; + vertex.position.z += chunk->z * CHUNK_D + 0.5f; } sortingMesh.entries.push_back(std::move(entry)); - vertexOffset = 0; - indexOffset = indexSize = 0; + vertexCount = 0; + vertexOffset = indexCount = 0; } } // additional powerful optimization auto size = aabb.size(); - if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) && + if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) && sortingMesh.entries.size() > 1) { SortingMeshEntry newEntry { sortingMesh.entries[0].position, - util::Buffer(totalSize), + util::Buffer(totalSize), 0 }; size_t offset = 0; for (const auto& entry : sortingMesh.entries) { std::memcpy( newEntry.vertexData.data() + offset, - entry.vertexData.data(), entry.vertexData.size() * sizeof(float) + entry.vertexData.data(), + entry.vertexData.size() * sizeof(ChunkVertex) ); offset += entry.vertexData.size(); } @@ -630,7 +648,7 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { const voxel& vox = voxels[i]; blockid_t id = vox.id; const auto& def = *blockDefsCache[id]; - + if (beginEnds[def.drawGroup][0] == 0) { beginEnds[def.drawGroup][0] = i+1; } @@ -639,36 +657,37 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { cancelled = false; overflow = false; - vertexOffset = 0; - indexOffset = indexSize = 0; - + vertexCount = 0; + vertexOffset = indexCount = 0; + sortingMesh = renderTranslucent(voxels, beginEnds); - + overflow = false; + vertexCount = 0; vertexOffset = 0; - indexOffset = indexSize = 0; - + indexCount = 0; + render(voxels, beginEnds); } ChunkMeshData BlocksRenderer::createMesh() { - return ChunkMeshData { + return ChunkMeshData{ MeshData( - util::Buffer(vertexBuffer.get(), vertexOffset), - util::Buffer(indexBuffer.get(), indexSize), - util::Buffer( - CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(VertexAttribute) + util::Buffer(vertexBuffer.get(), vertexCount), + util::Buffer(indexBuffer.get(), indexCount), + util::Buffer( + ChunkVertex::ATTRIBUTES, sizeof(ChunkVertex::ATTRIBUTES) / sizeof(VertexAttribute) ) ), - std::move(sortingMesh)}; + std::move(sortingMesh) + }; } -ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { +ChunkMesh BlocksRenderer::render(const Chunk *chunk, const Chunks *chunks) { build(chunk, chunks); - size_t vcount = vertexOffset / CHUNK_VERTEX_SIZE; - return ChunkMesh{std::make_unique( - vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, CHUNK_VATTRS + return ChunkMesh{std::make_unique>( + vertexBuffer.get(), vertexCount, indexBuffer.get(), indexCount ), std::move(sortingMesh)}; } diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index c652b6a0..1edcbfcc 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -1,7 +1,5 @@ #pragma once -#include -#include #include #include #include "voxels/voxel.hpp" @@ -10,28 +8,27 @@ #include "voxels/Block.hpp" #include "voxels/Chunk.hpp" #include "voxels/VoxelsVolume.hpp" -#include "graphics/core/MeshData.hpp" #include "maths/util.hpp" #include "commons.hpp" #include "settings.hpp" +template class Mesh; class Content; -class Mesh; class Block; class Chunk; class Chunks; class VoxelsVolume; -class Chunks; class ContentGfxCache; struct UVRegion; class BlocksRenderer { static const glm::vec3 SUN_VECTOR; const Content& content; - std::unique_ptr vertexBuffer; - std::unique_ptr indexBuffer; + std::unique_ptr vertexBuffer; + std::unique_ptr indexBuffer; + size_t vertexCount; size_t vertexOffset; - size_t indexOffset, indexSize; + size_t indexCount; size_t capacity; int voxelBufferPadding = 2; bool overflow = false; @@ -48,7 +45,7 @@ class BlocksRenderer { SortingMeshData sortingMesh; void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); - void index(int a, int b, int c, int d, int e, int f); + void index(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint32_t e, uint32_t f); void vertexAO( const glm::vec3& coord, float u, float v, diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 535baa59..199d818b 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -74,7 +74,7 @@ ChunksRenderer::ChunksRenderer( if (!result.cancelled) { auto meshData = std::move(result.meshData); meshes[result.key] = ChunkMesh { - std::make_unique(meshData.mesh), + std::make_unique>(meshData.mesh), std::move(meshData.sortingMesh)}; } inwork.erase(result.key); @@ -92,7 +92,7 @@ ChunksRenderer::ChunksRenderer( ChunksRenderer::~ChunksRenderer() { } -const Mesh* ChunksRenderer::render( +const Mesh* ChunksRenderer::render( const std::shared_ptr& chunk, bool important ) { chunk->flags.modified = false; @@ -125,7 +125,7 @@ void ChunksRenderer::clear() { threadPool.clearQueue(); } -const Mesh* ChunksRenderer::getOrRender( +const Mesh* ChunksRenderer::getOrRender( const std::shared_ptr& chunk, bool important ) { auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); @@ -142,7 +142,7 @@ void ChunksRenderer::update() { threadPool.update(); } -const Mesh* ChunksRenderer::retrieveChunk( +const Mesh* ChunksRenderer::retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ) { auto chunk = chunks.getChunks()[index]; @@ -234,14 +234,14 @@ void ChunksRenderer::drawChunks( } static inline void write_sorting_mesh_entries( - float* buffer, const std::vector& chunkEntries + ChunkVertex* buffer, const std::vector& chunkEntries ) { for (const auto& entry : chunkEntries) { const auto& vertexData = entry.vertexData; std::memcpy( buffer, vertexData.data(), - vertexData.size() * sizeof(float) + vertexData.size() * sizeof(ChunkVertex) ); buffer += vertexData.size(); } @@ -288,10 +288,8 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (chunkEntries.size() == 1) { auto& entry = chunkEntries.at(0); if (found->second.sortedMesh == nullptr) { - found->second.sortedMesh = std::make_unique( - entry.vertexData.data(), - entry.vertexData.size() / CHUNK_VERTEX_SIZE, - CHUNK_VATTRS + found->second.sortedMesh = std::make_unique>( + entry.vertexData.data(), entry.vertexData.size() ); } found->second.sortedMesh->draw(); @@ -310,13 +308,13 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { size += entry.vertexData.size(); } - static util::Buffer buffer; + static util::Buffer buffer; if (buffer.size() < size) { - buffer = util::Buffer(size); + buffer = util::Buffer(size); } write_sorting_mesh_entries(buffer.data(), chunkEntries); - found->second.sortedMesh = std::make_unique( - buffer.data(), size / CHUNK_VERTEX_SIZE, CHUNK_VATTRS + found->second.sortedMesh = std::make_unique>( + buffer.data(), size ); } found->second.sortedMesh->draw(); diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 3e2ca9d9..aa9833af 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -9,12 +8,10 @@ #define GLM_ENABLE_EXPERIMENTAL #include -#include "voxels/Block.hpp" #include "util/ThreadPool.hpp" -#include "graphics/core/MeshData.hpp" #include "commons.hpp" -class Mesh; +template class Mesh; class Chunk; class Level; class Camera; @@ -52,7 +49,7 @@ class ChunksRenderer { std::unordered_map inwork; std::vector indices; util::ThreadPool, RendererResult> threadPool; - const Mesh* retrieveChunk( + const Mesh* retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ); public: @@ -66,13 +63,13 @@ public: ); virtual ~ChunksRenderer(); - const Mesh* render( + const Mesh* render( const std::shared_ptr& chunk, bool important ); void unload(const Chunk* chunk); void clear(); - const Mesh* getOrRender( + const Mesh* getOrRender( const std::shared_ptr& chunk, bool important ); void drawChunks(const Camera& camera, Shader& shader); diff --git a/src/graphics/render/MainBatch.cpp b/src/graphics/render/MainBatch.cpp index a440a43b..34976819 100644 --- a/src/graphics/render/MainBatch.cpp +++ b/src/graphics/render/MainBatch.cpp @@ -6,18 +6,15 @@ #include "voxels/Chunks.hpp" #include "voxels/Chunk.hpp" -static const VertexAttribute attrs[] = { - {3}, {2}, {3}, {1}, {0} -}; MainBatch::MainBatch(size_t capacity) - : buffer(std::make_unique(capacity * VERTEX_SIZE)), - capacity(capacity), - index(0), - mesh(std::make_unique(buffer.get(), 0, attrs)) { + : buffer(std::make_unique(capacity)), + capacity(capacity), + index(0), + mesh(std::make_unique>(buffer.get(), 0)) { const ubyte pixels[] = { - 255, 255, 255, 255, + 255, 255, 255, 255, }; ImageData image(ImageFormat::rgba8888, 1, 1, pixels); blank = Texture::from(&image); @@ -25,7 +22,7 @@ MainBatch::MainBatch(size_t capacity) MainBatch::~MainBatch() = default; -void MainBatch::setTexture(const Texture* texture) { +void MainBatch::setTexture(const Texture *texture) { if (texture == nullptr) { texture = blank.get(); } @@ -33,10 +30,10 @@ void MainBatch::setTexture(const Texture* texture) { flush(); } this->texture = texture; - region = UVRegion {0.0f, 0.0f, 1.0f, 1.0f}; + region = UVRegion{0.0f, 0.0f, 1.0f, 1.0f}; } -void MainBatch::setTexture(const Texture* texture, const UVRegion& region) { +void MainBatch::setTexture(const Texture *texture, const UVRegion ®ion) { setTexture(texture); this->region = region; } @@ -49,7 +46,7 @@ void MainBatch::flush() { texture = blank.get(); } texture->bind(); - mesh->reload(buffer.get(), index / VERTEX_SIZE); + mesh->reload(buffer.get(), index); mesh->draw(); index = 0; } @@ -60,76 +57,76 @@ void MainBatch::begin() { } void MainBatch::prepare(int vertices) { - if (index + VERTEX_SIZE * vertices > capacity * VERTEX_SIZE) { + if (index * vertices > capacity) { flush(); } } glm::vec4 MainBatch::sampleLight( - const glm::vec3& pos, const Chunks& chunks, bool backlight + const glm::vec3 &pos, const Chunks &chunks, bool backlight ) { light_t light = chunks.getLight( - std::floor(pos.x), - std::floor(std::min(CHUNK_H-1.0f, pos.y)), - std::floor(pos.z)); + std::floor(pos.x), + std::floor(std::min(CHUNK_H - 1.0f, pos.y)), + std::floor(pos.z)); light_t minIntensity = backlight ? 1 : 0; - return glm::vec4( - glm::max(Lightmap::extract(light, 0), minIntensity) / 15.0f, - glm::max(Lightmap::extract(light, 1), minIntensity) / 15.0f, - glm::max(Lightmap::extract(light, 2), minIntensity) / 15.0f, - glm::max(Lightmap::extract(light, 3), minIntensity) / 15.0f - ); + return { + (float) glm::max(Lightmap::extract(light, 0), minIntensity) / 15.0f, + (float) glm::max(Lightmap::extract(light, 1), minIntensity) / 15.0f, + (float) glm::max(Lightmap::extract(light, 2), minIntensity) / 15.0f, + (float) glm::max(Lightmap::extract(light, 3), minIntensity) / 15.0f + }; } inline glm::vec4 do_tint(float value) { - return glm::vec4(value, value, value, 1.0f); + return {value, value, value, 1.0f}; } void MainBatch::cube( - const glm::vec3& coord, - const glm::vec3& size, - const UVRegion(&texfaces)[6], - const glm::vec4& tint, - bool shading + const glm::vec3 &coord, + const glm::vec3 &size, + const UVRegion(&texfaces)[6], + const glm::vec4 &tint, + bool shading ) { const glm::vec3 X(1.0f, 0.0f, 0.0f); const glm::vec3 Y(0.0f, 1.0f, 0.0f); const glm::vec3 Z(0.0f, 0.0f, 1.0f); quad( - coord + Z * size.z * 0.5f, - X, Y, glm::vec2(size.x, size.y), - (shading ? do_tint(0.8) * tint : tint), - glm::vec3(1.0f), texfaces[5] + coord + Z * size.z * 0.5f, + X, Y, glm::vec2(size.x, size.y), + (shading ? do_tint(0.8) * tint : tint), + glm::vec3(1.0f), texfaces[5] ); quad( - coord - Z * size.z * 0.5f, - -X, Y, glm::vec2(size.x, size.y), - (shading ? do_tint(0.9f) * tint : tint), - glm::vec3(1.0f), texfaces[4] + coord - Z * size.z * 0.5f, + -X, Y, glm::vec2(size.x, size.y), + (shading ? do_tint(0.9f) * tint : tint), + glm::vec3(1.0f), texfaces[4] ); quad( - coord + Y * size.y * 0.5f, - -X, Z, glm::vec2(size.x, size.z), - (shading ? do_tint(1.0f) * tint : tint), - glm::vec3(1.0f), texfaces[3] + coord + Y * size.y * 0.5f, + -X, Z, glm::vec2(size.x, size.z), + (shading ? do_tint(1.0f) * tint : tint), + glm::vec3(1.0f), texfaces[3] ); quad( - coord - Y * size.y * 0.5f, - X, Z, glm::vec2(size.x, size.z), - (shading ? do_tint(0.7f) * tint : tint), - glm::vec3(1.0f), texfaces[2] + coord - Y * size.y * 0.5f, + X, Z, glm::vec2(size.x, size.z), + (shading ? do_tint(0.7f) * tint : tint), + glm::vec3(1.0f), texfaces[2] ); quad( - coord + X * size.x * 0.5f, - -Z, Y, glm::vec2(size.z, size.y), - (shading ? do_tint(0.8f) * tint : tint), - glm::vec3(1.0f), texfaces[1] + coord + X * size.x * 0.5f, + -Z, Y, glm::vec2(size.z, size.y), + (shading ? do_tint(0.8f) * tint : tint), + glm::vec3(1.0f), texfaces[1] ); quad( - coord - X * size.x * 0.5f, - Z, Y, glm::vec2(size.z, size.y), - (shading ? do_tint(0.9f) * tint : tint), - glm::vec3(1.0f), texfaces[1] + coord - X * size.x * 0.5f, + Z, Y, glm::vec2(size.z, size.y), + (shading ? do_tint(0.9f) * tint : tint), + glm::vec3(1.0f), texfaces[1] ); } diff --git a/src/graphics/render/MainBatch.hpp b/src/graphics/render/MainBatch.hpp index 36bf7a8e..2ca1d3d0 100644 --- a/src/graphics/render/MainBatch.hpp +++ b/src/graphics/render/MainBatch.hpp @@ -1,30 +1,46 @@ #pragma once +#include #include -#include +#include #include #include "typedefs.hpp" #include "maths/UVRegion.hpp" +#include "graphics/core/MeshData.hpp" +template class Mesh; class Texture; class Chunks; +struct MainBatchVertex { + glm::vec3 position; + glm::vec2 uv; + glm::vec3 tint; + std::array color; + + static constexpr VertexAttribute ATTRIBUTES[] = { + {VertexAttribute::Type::FLOAT, false, 3}, + {VertexAttribute::Type::FLOAT, false, 2}, + {VertexAttribute::Type::FLOAT, false, 3}, + {VertexAttribute::Type::UNSIGNED_BYTE, true, 4}, + {{}, 0}}; +}; + class MainBatch { - std::unique_ptr const buffer; + std::unique_ptr const buffer; size_t const capacity; size_t index; UVRegion region {0.0f, 0.0f, 1.0f, 1.0f}; - std::unique_ptr mesh; + std::unique_ptr> mesh; std::unique_ptr blank; const Texture* texture = nullptr; public: /// xyz, uv, color, compressed lights - static inline constexpr uint VERTEX_SIZE = 9; MainBatch(size_t capacity); @@ -47,27 +63,16 @@ public: const glm::vec4& light, const glm::vec3& tint ) { - float* buffer = this->buffer.get(); - buffer[index++] = pos.x; - buffer[index++] = pos.y; - buffer[index++] = pos.z; - buffer[index++] = uv.x * region.getWidth() + region.u1; - buffer[index++] = uv.y * region.getHeight() + region.v1; - buffer[index++] = tint.x; - buffer[index++] = tint.y; - buffer[index++] = tint.z; + MainBatchVertex* buffer = this->buffer.get(); + buffer[index].position = pos; + buffer[index].uv = {uv.x * region.getWidth() + region.u1,uv.y * region.getHeight() + region.v1}; + buffer[index].tint = tint; - union { - float floating; - uint32_t integer; - } compressed; - - compressed.integer = (static_cast(light.r * 255) & 0xff) << 24; - compressed.integer |= (static_cast(light.g * 255) & 0xff) << 16; - compressed.integer |= (static_cast(light.b * 255) & 0xff) << 8; - compressed.integer |= (static_cast(light.a * 255) & 0xff); - - buffer[index++] = compressed.floating; + buffer[index].color[0] = static_cast(light.r * 255); + buffer[index].color[1] = static_cast(light.g * 255); + buffer[index].color[2] = static_cast(light.b * 255); + buffer[index].color[3] = static_cast(light.a * 255); + index++; } inline void quad( diff --git a/src/graphics/render/ModelBatch.hpp b/src/graphics/render/ModelBatch.hpp index 4faf0ea8..e9323786 100644 --- a/src/graphics/render/ModelBatch.hpp +++ b/src/graphics/render/ModelBatch.hpp @@ -1,14 +1,12 @@ #pragma once -#include "maths/UVRegion.hpp" - #include #include #include #include #include -class Mesh; +template class Mesh; class Texture; class Chunks; class Assets; diff --git a/src/graphics/render/ModelsGenerator.cpp b/src/graphics/render/ModelsGenerator.cpp index 4d2858bf..acd6366f 100644 --- a/src/graphics/render/ModelsGenerator.cpp +++ b/src/graphics/render/ModelsGenerator.cpp @@ -50,16 +50,16 @@ static inline UVRegion get_region_for( void ModelsGenerator::prepare(Content& content, Assets& assets) { for (auto& [name, def] : content.blocks.getDefs()) { - if (def->model == BlockModel::custom && def->modelName.empty()) { + if (def->model.type == BlockModelType::CUSTOM && def->model.name.empty()) { assets.store( std::make_unique( loadCustomBlockModel( - def->customModelRaw, assets, !def->shadeless + def->model.customRaw, assets, !def->shadeless ) ), name + ".model" ); - def->modelName = def->name + ".model"; + def->model.name = def->name + ".model"; } } for (auto& [name, def] : content.items.getDefs()) { @@ -74,7 +74,7 @@ void ModelsGenerator::prepare(Content& content, Assets& assets) { model::Model ModelsGenerator::fromCustom( const Assets& assets, - const std::vector& modelBoxes, + const std::vector& modelBoxes, const std::vector& modelTextures, const std::vector& points, bool lighting @@ -95,32 +95,30 @@ model::Model ModelsGenerator::fromCustom( modelBoxes[i].center(), modelBoxes[i].size() * 0.5f, boxtexfaces ); } - glm::vec3 norm {0, 1, 0}; for (size_t i = 0; i < points.size() / 4; i++) { auto texture = modelTextures[modelBoxes.size() * 6 + i]; + const glm::vec3& v0 = points[i * 4]; + const glm::vec3& v1 = points[i * 4 + 1]; + const glm::vec3& v2 = points[i * 4 + 2]; + const glm::vec3& v3 = points[i * 4 + 3]; + + glm::vec3 edge1 = v1 - v0; + glm::vec3 edge2 = v2 - v0; + + glm::vec3 norm = glm::cross(edge1, edge2); + norm = glm::normalize(norm); + auto& mesh = model.addMesh(texture); mesh.lighting = lighting; auto reg = get_region_for(texture, assets); - mesh.vertices.push_back( - {points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm} - ); - mesh.vertices.push_back( - {points[i * 4 + 1], glm::vec2(reg.u2, reg.v1), norm} - ); - mesh.vertices.push_back( - {points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm} - ); - mesh.vertices.push_back( - {points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm} - ); - mesh.vertices.push_back( - {points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm} - ); - mesh.vertices.push_back( - {points[i * 4 + 3], glm::vec2(reg.u1, reg.v2), norm} - ); + mesh.vertices.push_back({v0, glm::vec2(reg.u1, reg.v1), norm}); + mesh.vertices.push_back({v1, glm::vec2(reg.u2, reg.v1), norm}); + mesh.vertices.push_back({v2, glm::vec2(reg.u2, reg.v2), norm}); + mesh.vertices.push_back({v0, glm::vec2(reg.u1, reg.v1), norm}); + mesh.vertices.push_back({v2, glm::vec2(reg.u2, reg.v2), norm}); + mesh.vertices.push_back({v3, glm::vec2(reg.u1, reg.v2), norm}); } return model; } @@ -131,12 +129,12 @@ model::Model ModelsGenerator::generate( if (def.iconType == ItemIconType::BLOCK) { auto model = assets.require("block"); const auto& blockDef = content.blocks.require(def.icon); - if (blockDef.model == BlockModel::xsprite) { + if (blockDef.model.type == BlockModelType::XSPRITE) { return create_flat_model( "blocks:" + blockDef.textureFaces.at(0), assets ); - } else if (blockDef.model == BlockModel::custom) { - model = assets.require(blockDef.modelName); + } else if (blockDef.model.type == BlockModelType::CUSTOM) { + model = assets.require(blockDef.model.name); for (auto& mesh : model.meshes) { mesh.scale(glm::vec3(0.2f)); } @@ -144,8 +142,8 @@ model::Model ModelsGenerator::generate( } for (auto& mesh : model.meshes) { mesh.lighting = !blockDef.shadeless; - switch (blockDef.model) { - case BlockModel::aabb: { + switch (blockDef.model.type) { + case BlockModelType::AABB: { glm::vec3 size = blockDef.hitboxes.at(0).size(); float m = glm::max(size.x, glm::max(size.y, size.z)); m = glm::min(1.0f, m); diff --git a/src/graphics/render/Skybox.cpp b/src/graphics/render/Skybox.cpp index 479bef85..d78b3917 100644 --- a/src/graphics/render/Skybox.cpp +++ b/src/graphics/render/Skybox.cpp @@ -24,10 +24,10 @@ const int STARS_COUNT = 3000; const int STARS_SEED = 632; -Skybox::Skybox(uint size, Shader& shader) - : size(size), - shader(shader), - batch3d(std::make_unique(4096)) +Skybox::Skybox(uint size, Shader& shader) + : size(size), + shader(shader), + batch3d(std::make_unique(4096)) { auto cubemap = std::make_unique(size, size, ImageFormat::rgb888); @@ -35,12 +35,16 @@ Skybox::Skybox(uint size, Shader& shader) glGenFramebuffers(1, &fboid); fbo = std::make_unique(fboid, 0, std::move(cubemap)); - float vertices[] { - -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f + SkyboxVertex vertices[]{ + {{-1.0f, -1.0f}}, + {{-1.0f, 1.0f}}, + {{1.0f, 1.0f}}, + {{-1.0f, -1.0f}}, + {{1.0f, 1.0f}}, + {{1.0f, -1.0f}} }; - VertexAttribute attrs[] {{2}, {0}}; - mesh = std::make_unique(vertices, 6, attrs); + + mesh = std::make_unique>(vertices, 6); sprites.push_back(skysprite { "misc/moon", @@ -95,11 +99,11 @@ void Skybox::drawStars(float angle, float opacity) { } void Skybox::draw( - const DrawContext& pctx, - const Camera& camera, - const Assets& assets, + const DrawContext& pctx, + const Camera& camera, + const Assets& assets, float daytime, - float fog) + float fog) { const glm::uvec2& viewport = pctx.getViewport(); @@ -116,7 +120,7 @@ void Skybox::draw( float angle = daytime * glm::pi() * 2.0f; float opacity = glm::pow(1.0f-fog, 7.0f); - + for (auto& sprite : sprites) { batch3d->texture(assets.get(sprite.texture)); @@ -129,7 +133,7 @@ void Skybox::draw( if (!sprite.emissive) { tint *= 0.6f+std::cos(angle)*0.4; } - batch3d->sprite(pos, glm::vec3(0, 0, 1), + batch3d->sprite(pos, glm::vec3(0, 0, 1), up, 1, 1, UVRegion(), tint); } @@ -153,7 +157,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) cubemap->bind(); shader.use(); t *= glm::pi()*2.0f; - + lightDir = glm::normalize(glm::vec3(sin(t), -cos(t), 0.0f)); shader.uniform1i("u_quality", quality); shader.uniform1f("u_mie", mie); @@ -171,7 +175,7 @@ void Skybox::refresh(const DrawContext& pctx, float t, float mie, uint quality) } prevMie = mie; prevT = t; - + cubemap->unbind(); glActiveTexture(GL_TEXTURE0); } @@ -190,7 +194,7 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) { {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, - + {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, @@ -200,7 +204,7 @@ void Skybox::refreshFace(uint face, Cubemap* cubemap) { {1.0f, 0.0f, 0.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}, - + {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, -1.0f}, {0.0f, 0.0f, 1.0f}, diff --git a/src/graphics/render/Skybox.hpp b/src/graphics/render/Skybox.hpp index a539ae07..f469b155 100644 --- a/src/graphics/render/Skybox.hpp +++ b/src/graphics/render/Skybox.hpp @@ -6,17 +6,25 @@ #include #include "typedefs.hpp" #include "maths/fastmaths.hpp" +#include "graphics/core/MeshData.hpp" -class Mesh; +template class Mesh; class Shader; class Assets; class Camera; class Batch3D; -class Shader; class Cubemap; class Framebuffer; class DrawContext; +struct SkyboxVertex { + glm::vec2 position; + + static constexpr VertexAttribute ATTRIBUTES[] { + {VertexAttribute::Type::FLOAT, false, 2}, + {{}, 0}}; +}; + struct skysprite { std::string texture; float phase; @@ -32,7 +40,7 @@ class Skybox { FastRandom random; glm::vec3 lightDir; - std::unique_ptr mesh; + std::unique_ptr> mesh; std::unique_ptr batch3d; std::vector sprites; int frameid = 0; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 04a0e427..20640a78 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -1,6 +1,5 @@ #include "WorldRenderer.hpp" -#include #include #include @@ -119,6 +118,7 @@ void WorldRenderer::setupWorldShader( shader.uniform1f("u_gamma", settings.graphics.gamma.get()); shader.uniform1f("u_fogFactor", fogFactor); shader.uniform1f("u_fogCurve", settings.graphics.fogCurve.get()); + shader.uniform1i("u_debugLights", lightsDebug); shader.uniform1f("u_weatherFogOpacity", weather.fogOpacity()); shader.uniform1f("u_weatherFogDencity", weather.fogDencity()); shader.uniform1f("u_weatherFogCurve", weather.fogCurve()); @@ -443,6 +443,10 @@ void WorldRenderer::setDebug(bool flag) { debug = flag; } +void WorldRenderer::toggleLightsDebug() { + lightsDebug = !lightsDebug; +} + Weather& WorldRenderer::getWeather() { return weather; } diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index fbcf5480..fbfd4998 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -48,6 +48,7 @@ class WorldRenderer { float timer = 0.0f; bool debug = false; + bool lightsDebug = false; /// @brief Render block selection lines void renderBlockSelection(); @@ -107,5 +108,7 @@ public: void setDebug(bool flag); + void toggleLightsDebug(); + Weather& getWeather(); }; diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 79b77393..cfc2f16c 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -1,25 +1,36 @@ #pragma once #include +#include #include +#include #include #include "graphics/core/MeshData.hpp" #include "util/Buffer.hpp" -/// @brief Chunk mesh vertex attributes -inline const VertexAttribute CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} }; -/// @brief Chunk mesh vertex size divided by sizeof(float) -inline constexpr int CHUNK_VERTEX_SIZE = 6; +/// @brief Chunk mesh vertex format +struct ChunkVertex { + glm::vec3 position; + glm::vec2 uv; + std::array color; + static constexpr VertexAttribute ATTRIBUTES[] = { + {VertexAttribute::Type::FLOAT, false, 3}, + {VertexAttribute::Type::FLOAT, false, 2}, + {VertexAttribute::Type::UNSIGNED_BYTE, true, 4}, + {{}, 0}}; +}; + +template class Mesh; struct SortingMeshEntry { glm::vec3 position; - util::Buffer vertexData; + util::Buffer vertexData; long long distance; - inline bool operator<(const SortingMeshEntry& o) const noexcept { + inline bool operator<(const SortingMeshEntry &o) const noexcept { return distance > o.distance; } }; @@ -29,12 +40,12 @@ struct SortingMeshData { }; struct ChunkMeshData { - MeshData mesh; + MeshData mesh; SortingMeshData sortingMesh; }; struct ChunkMesh { - std::unique_ptr mesh; + std::unique_ptr > mesh; SortingMeshData sortingMeshData; - std::unique_ptr sortedMesh = nullptr; + std::unique_ptr > sortedMesh = nullptr; }; diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index 8963926f..031611ee 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -312,7 +312,7 @@ static int l_get_textures(lua::State* L) { static int l_get_model(lua::State* L) { if (auto def = require_block(L)) { - return lua::pushlstring(L, BlockModelMeta.getName(def->model)); + return lua::pushlstring(L, BlockModelTypeMeta.getName(def->model.type)); } return 0; } diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index e7153665..b7b0d836 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -143,7 +143,6 @@ void Block::cloneTo(Block& dst) { if (particles) { dst.particles = std::make_unique(*particles); } - dst.customModelRaw = customModelRaw; } static std::set> RESERVED_BLOCK_FIELDS { diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 9e3a28df..378cbb5d 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -81,25 +81,35 @@ struct BlockRotProfile { static inline std::string PANE_NAME = "pane"; }; -enum class BlockModel { +enum class BlockModelType { /// @brief invisible - none, + NONE, /// @brief default cube shape - block, + BLOCK, /// @brief X-shape (grass) - xsprite, + XSPRITE, /// @brief box shape sized as block hitbox - aabb, + AABB, /// @brief custom model defined in json - custom + CUSTOM }; -VC_ENUM_METADATA(BlockModel) - {"none", BlockModel::none}, - {"block", BlockModel::block}, - {"X", BlockModel::xsprite}, - {"aabb", BlockModel::aabb}, - {"custom", BlockModel::custom}, +struct BlockModel { + BlockModelType type = BlockModelType::BLOCK; + + /// @brief Custom model raw data + dv::value customRaw = nullptr; + + /// @brief Custom model name (generated or an asset) + std::string name = ""; +}; + +VC_ENUM_METADATA(BlockModelType) + {"none", BlockModelType::NONE}, + {"block", BlockModelType::BLOCK}, + {"X", BlockModelType::XSPRITE}, + {"aabb", BlockModelType::AABB}, + {"custom", BlockModelType::CUSTOM}, VC_ENUM_END enum class CullingMode { @@ -114,8 +124,6 @@ VC_ENUM_METADATA(CullingMode) {"disabled", CullingMode::DISABLED}, VC_ENUM_END -using BoxModel = AABB; - /// @brief Common kit of block properties applied to groups of blocks struct BlockMaterial : Serializable { std::string name; @@ -154,13 +162,8 @@ public: /// @brief Influences visible block sides for transparent blocks uint8_t drawGroup = 0; - /// @brief Block model type - BlockModel model = BlockModel::block; - - /// @brief Custom model raw data - dv::value customModelRaw = nullptr; - - std::string modelName = ""; + /// @brief Block model + BlockModel model {}; /// @brief Culling mode CullingMode culling = CullingMode::DEFAULT; diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index ce533889..60422c60 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -10,7 +10,6 @@ #include "coders/byte_utils.hpp" #include "content/Content.hpp" #include "world/files/WorldFiles.hpp" -#include "graphics/core/Mesh.hpp" #include "lighting/Lightmap.hpp" #include "maths/aabb.hpp" #include "maths/rays.hpp"