From e3e598182da7d1639de83f473a55bf6a585b3c61 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 10 Dec 2015 13:22:58 +0100 Subject: [PATCH 01/16] update player after load from save this moves the chunk index to the correct base for preloading --- src/io/WorldSave.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/io/WorldSave.cpp b/src/io/WorldSave.cpp index d483c91..ce7c71d 100644 --- a/src/io/WorldSave.cpp +++ b/src/io/WorldSave.cpp @@ -144,6 +144,7 @@ void WorldSave::Read(Player &player) const { } } player.GetEntity().SetState(state); + player.Update(0); } void WorldSave::Write(const Player &player) const { -- 2.39.2 From 1e93bfb5089737f6b6d8fdd2f17260944fca44b2 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 17 Dec 2015 16:21:33 +0100 Subject: [PATCH 02/16] faster chunk culling test also seems to cull some more, need to check if it doesn't accidentally cull a little too much --- src/geometry/geometry.cpp | 39 +++++++++++++++++++++ src/geometry/primitive.hpp | 72 +++++++++++++++++++++++++++++++++++++- src/world/chunk.cpp | 30 +++++++++++++--- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/src/geometry/geometry.cpp b/src/geometry/geometry.cpp index 7798d33..1e84fbb 100644 --- a/src/geometry/geometry.cpp +++ b/src/geometry/geometry.cpp @@ -4,6 +4,8 @@ #include "rotation.hpp" #include +#include +#include #include #include #include @@ -39,6 +41,14 @@ glm::mat3 find_rotation(const glm::vec3 &a, const glm::vec3 &b) noexcept { return glm::mat3(1.0f) + vx + (pow2(vx) * f); } +std::ostream &operator <<(std::ostream &out, const AABB &box) { + return out << "AABB(" << box.min << ", " << box.max << ')'; +} + +std::ostream &operator <<(std::ostream &out, const Ray &ray) { + return out << "Ray(" << ray.orig << ", " << ray.dir << ')'; +} + bool Intersection( const Ray &ray, const AABB &aabb, @@ -187,6 +197,21 @@ bool Intersection( } +std::ostream &operator <<(std::ostream &out, const Plane &plane) { + return out << "Plane(" << plane.normal << ", " << plane.dist << ')'; +} + +std::ostream &operator <<(std::ostream &out, const Frustum &frustum) { + return out << "Frustum(" << std::endl + << "\tleft: " << frustum.plane[0] << std::endl + << "\tright: " << frustum.plane[1] << std::endl + << "\tbottom: " << frustum.plane[2] << std::endl + << "\ttop: " << frustum.plane[3] << std::endl + << "\tnear: " << frustum.plane[4] << std::endl + << "\tfar: " << frustum.plane[5] << std::endl + << ')'; +} + bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept { // transform corners into clip space glm::vec4 corners[8] = { @@ -223,4 +248,18 @@ bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept { return false; } +bool CullTest(const AABB &box, const Frustum &frustum) noexcept { + for (const Plane &plane : frustum.plane) { + const glm::vec3 np( + ((plane.normal.x > 0.0f) ? box.max.x : box.min.x), + ((plane.normal.y > 0.0f) ? box.max.y : box.min.y), + ((plane.normal.z > 0.0f) ? box.max.z : box.min.z) + ); + const float dp = dot(plane.normal, np); + // cull if nearest point is on the "outside" side of the plane + if (dp < -plane.dist) return true; + } + return false; +} + } diff --git a/src/geometry/primitive.hpp b/src/geometry/primitive.hpp index cdeae86..da4c37f 100644 --- a/src/geometry/primitive.hpp +++ b/src/geometry/primitive.hpp @@ -2,6 +2,7 @@ #define BLANK_GEOMETRY_PRIMITIVE_HPP_ #include +#include #include @@ -28,11 +29,15 @@ struct AABB { } }; +std::ostream &operator <<(std::ostream &, const AABB &); + struct Ray { glm::vec3 orig; glm::vec3 dir; }; +std::ostream &operator <<(std::ostream &, const Ray &); + bool Intersection( const Ray &, const AABB &, @@ -50,7 +55,72 @@ bool Intersection( float &depth, glm::vec3 &normal) noexcept; -bool CullTest(const AABB &box, const glm::mat4 &MVP) noexcept; + +struct Plane { + glm::vec3 normal; + float dist; + + float &A() noexcept { return normal.x; } + float &B() noexcept { return normal.y; } + float &C() noexcept { return normal.z; } + float &D() noexcept { return dist; } + float A() const noexcept { return normal.x; } + float B() const noexcept { return normal.y; } + float C() const noexcept { return normal.z; } + float D() const noexcept { return dist; } + + Plane(const glm::vec3 &n, float d) + : normal(n), dist(d) { } + Plane(const glm::vec4 &abcd) + : normal(abcd), dist(abcd.w) { } + + void Normalize() noexcept { + const float l = length(normal); + normal /= l; + dist /= l; + } +}; + +std::ostream &operator <<(std::ostream &, const Plane &); + +struct Frustum { + Plane plane[6]; + Plane &Left() noexcept { return plane[0]; } + Plane &Right() noexcept { return plane[1]; } + Plane &Bottom() noexcept { return plane[2]; } + Plane &Top() noexcept { return plane[3]; } + Plane &Near() noexcept { return plane[4]; } + Plane &Far() noexcept { return plane[5]; } + const Plane &Left() const noexcept { return plane[0]; } + const Plane &Right() const noexcept { return plane[1]; } + const Plane &Bottom() const noexcept { return plane[2]; } + const Plane &Top() const noexcept { return plane[3]; } + const Plane &Near() const noexcept { return plane[4]; } + const Plane &Far() const noexcept { return plane[5]; } + + /// create frustum from transposed MVP + Frustum(const glm::mat4 &mat) + : plane{ + { mat[3] + mat[0] }, + { mat[3] - mat[0] }, + { mat[3] + mat[1] }, + { mat[3] - mat[1] }, + { mat[3] + mat[2] }, + { mat[3] - mat[2] }, + } { } + + void Normalize() noexcept { + for (Plane &p : plane) { + p.Normalize(); + } + } +}; + +std::ostream &operator <<(std::ostream &, const Plane &); +std::ostream &operator <<(std::ostream &, const Frustum &); + +bool CullTest(const AABB &box, const glm::mat4 &) noexcept; +bool CullTest(const AABB &box, const Frustum &) noexcept; } diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index d124eb7..6eb027a 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + namespace blank { @@ -809,19 +812,36 @@ void ChunkRenderer::Render(Viewport &viewport) { chunk_prog.SetTexture(block_tex); chunk_prog.SetFogDensity(fog_density); + Frustum frustum(transpose(chunk_prog.GetVP())); + AABB box; + + //std::cout << "V = " << chunk_prog.View() << std::endl; + //std::cout << "P = " << chunk_prog.Projection() << std::endl; + //std::cout << "VP = " << chunk_prog.GetVP() << std::endl; + //std::cout << "frustum = " << frustum << std::endl; + for (int i = 0; i < index.TotalChunks(); ++i) { if (!index[i]) continue; - // TODO: optimize chunk culling, shoudn't be that hard - glm::mat4 m(index[i]->Transform(index.Base())); - glm::mat4 mvp(chunk_prog.GetVP() * m); - if (!CullTest(Chunk::Bounds(), mvp)) { + box.min = (index[i]->Position() - index.Base()) * ExactLocation::Extent(); + box.max = box.min + ExactLocation::FExtent(); + + if (!CullTest(box, frustum)) { + + //glm::mat4 m(index[i]->Transform(index.Base())); + //if (CullTest(Chunk::Bounds(), chunk_prog.GetVP() * m)) { + // std::cout << "M = " << m << std::endl; + // std::cout << "box = " << box.min << ", " << box.max << std::endl; + // std::cout << "should've been culled" << std::endl; + //} + if (index[i]->ShouldUpdateMesh()) { index[i]->Update(models[i]); } - chunk_prog.SetM(m); + chunk_prog.SetM(index[i]->Transform(index.Base())); models[i].Draw(); } } + //std::cout << std::endl; } -- 2.39.2 From f071bb512a09cece895e65ca48eba2a7155d6593 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 17 Dec 2015 17:22:42 +0100 Subject: [PATCH 03/16] save a little bandwidth --- src/graphics/BlockMesh.hpp | 2 +- src/graphics/EntityMesh.hpp | 2 +- src/graphics/PrimitiveMesh.hpp | 6 +++--- src/graphics/VertexArray.hpp | 4 ++-- src/graphics/VertexArray.inl | 8 ++++---- src/graphics/mesh.cpp | 14 +++++++------- src/model/Part.hpp | 4 ++-- src/model/model.cpp | 11 +++++++---- src/ui/ui.cpp | 2 +- src/world/BlockType.hpp | 6 +++--- src/world/block.cpp | 16 ++++++++++------ src/world/world.cpp | 2 +- 12 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/graphics/BlockMesh.hpp b/src/graphics/BlockMesh.hpp index e62b601..399ff32 100644 --- a/src/graphics/BlockMesh.hpp +++ b/src/graphics/BlockMesh.hpp @@ -15,7 +15,7 @@ class BlockMesh { public: using Position = glm::vec3; using TexCoord = glm::vec3; - using ColorMod = glm::vec3; + using ColorMod = glm::tvec3; using Light = float; using Index = unsigned int; diff --git a/src/graphics/EntityMesh.hpp b/src/graphics/EntityMesh.hpp index 6b894f9..804bb6e 100644 --- a/src/graphics/EntityMesh.hpp +++ b/src/graphics/EntityMesh.hpp @@ -15,7 +15,7 @@ class EntityMesh { public: using Position = glm::vec3; using TexCoord = glm::vec3; - using ColorMod = glm::vec3; + using ColorMod = glm::tvec3; using Normal = glm::vec3; using Index = unsigned int; diff --git a/src/graphics/PrimitiveMesh.hpp b/src/graphics/PrimitiveMesh.hpp index 013bf37..6a8b696 100644 --- a/src/graphics/PrimitiveMesh.hpp +++ b/src/graphics/PrimitiveMesh.hpp @@ -16,7 +16,7 @@ class PrimitiveMesh { public: using Position = glm::vec3; - using Color = glm::vec4; + using Color = glm::tvec4; using Index = unsigned short; using Positions = std::vector; @@ -50,13 +50,13 @@ public: void FillRect( float w, float h, - const glm::vec4 &color = glm::vec4(0.0f), + const Color &color = Color(0), const glm::vec2 &pivot = glm::vec2(0.0f) ); void OutlineBox( const AABB &, - const glm::vec4 &color = glm::vec4(0.0f) + const Color &color = Color(0) ); }; diff --git a/src/graphics/VertexArray.hpp b/src/graphics/VertexArray.hpp index c1c7495..5f70f42 100644 --- a/src/graphics/VertexArray.hpp +++ b/src/graphics/VertexArray.hpp @@ -27,7 +27,7 @@ public: void Bind() const noexcept; template - void PushAttribute(std::size_t which, const std::vector &data) noexcept; + void PushAttribute(std::size_t which, const std::vector &data, bool normalized = false) noexcept; template void PushIndices(std::size_t which, const std::vector &indices) noexcept; @@ -41,7 +41,7 @@ private: template void AttributeData(const std::vector &) noexcept; template - void AttributePointer(std::size_t which) noexcept; + void AttributePointer(std::size_t which, bool normalized = false) noexcept; void BindIndex(std::size_t which) const noexcept; template diff --git a/src/graphics/VertexArray.inl b/src/graphics/VertexArray.inl index 1b532b7..36c8fc2 100644 --- a/src/graphics/VertexArray.inl +++ b/src/graphics/VertexArray.inl @@ -48,11 +48,11 @@ void VertexArray::Bind() const noexcept { template template -void VertexArray::PushAttribute(std::size_t which, const std::vector &data) noexcept { +void VertexArray::PushAttribute(std::size_t which, const std::vector &data, bool normalized) noexcept { BindAttribute(which); AttributeData(data); EnableAttribute(which); - AttributePointer(which); + AttributePointer(which, normalized); } template @@ -75,12 +75,12 @@ void VertexArray::AttributeData(const std::vector &buf) noexcept { template template -void VertexArray::AttributePointer(std::size_t which) noexcept { +void VertexArray::AttributePointer(std::size_t which, bool normalized) noexcept { glVertexAttribPointer( which, // program location gl_traits::size, // element size gl_traits::type, // element type - GL_FALSE, // normalize to [-1,1] or [0,1] for unsigned types + normalized, // normalize to [-1,1] or [0,1] for unsigned types 0, // stride nullptr // offset ); diff --git a/src/graphics/mesh.cpp b/src/graphics/mesh.cpp index 5cd3883..9cb8c92 100644 --- a/src/graphics/mesh.cpp +++ b/src/graphics/mesh.cpp @@ -31,8 +31,8 @@ void EntityMesh::Update(const Buffer &buf) noexcept { vao.Bind(); vao.PushAttribute(ATTRIB_VERTEX, buf.vertices); vao.PushAttribute(ATTRIB_TEXCOORD, buf.tex_coords); - vao.PushAttribute(ATTRIB_HSL, buf.hsl_mods); - vao.PushAttribute(ATTRIB_RGB, buf.rgb_mods); + vao.PushAttribute(ATTRIB_HSL, buf.hsl_mods, true); + vao.PushAttribute(ATTRIB_RGB, buf.rgb_mods, true); vao.PushAttribute(ATTRIB_NORMAL, buf.normals); vao.PushIndices(ATTRIB_INDEX, buf.indices); } @@ -62,8 +62,8 @@ void BlockMesh::Update(const Buffer &buf) noexcept { vao.Bind(); vao.PushAttribute(ATTRIB_VERTEX, buf.vertices); vao.PushAttribute(ATTRIB_TEXCOORD, buf.tex_coords); - vao.PushAttribute(ATTRIB_HSL, buf.hsl_mods); - vao.PushAttribute(ATTRIB_RGB, buf.rgb_mods); + vao.PushAttribute(ATTRIB_HSL, buf.hsl_mods, true); + vao.PushAttribute(ATTRIB_RGB, buf.rgb_mods, true); vao.PushAttribute(ATTRIB_LIGHT, buf.lights); vao.PushIndices(ATTRIB_INDEX, buf.indices); } @@ -76,7 +76,7 @@ void BlockMesh::Draw() const noexcept { void PrimitiveMesh::Buffer::FillRect( float w, float h, - const glm::vec4 &color, + const Color &color, const glm::vec2 &pivot ) { Clear(); @@ -92,7 +92,7 @@ void PrimitiveMesh::Buffer::FillRect( indices.assign({ 0, 2, 1, 1, 2, 3 }); } -void PrimitiveMesh::Buffer::OutlineBox(const AABB &box, const glm::vec4 &color) { +void PrimitiveMesh::Buffer::OutlineBox(const AABB &box, const Color &color) { Clear(); Reserve(8, 24); @@ -124,7 +124,7 @@ void PrimitiveMesh::Update(const Buffer &buf) noexcept { vao.Bind(); vao.PushAttribute(ATTRIB_VERTEX, buf.vertices); - vao.PushAttribute(ATTRIB_COLOR, buf.colors); + vao.PushAttribute(ATTRIB_COLOR, buf.colors, true); vao.PushIndices(ATTRIB_INDEX, buf.indices); } diff --git a/src/model/Part.hpp b/src/model/Part.hpp index 9774346..3a17f20 100644 --- a/src/model/Part.hpp +++ b/src/model/Part.hpp @@ -56,8 +56,8 @@ private: std::vector tex_map; mutable std::unique_ptr mesh; State initial; - glm::vec3 hsl_mod; - glm::vec3 rgb_mod; + glm::tvec3 hsl_mod; + glm::tvec3 rgb_mod; std::uint16_t id; }; diff --git a/src/model/model.cpp b/src/model/model.cpp index db44cbf..ed44313 100644 --- a/src/model/model.cpp +++ b/src/model/model.cpp @@ -109,8 +109,8 @@ Part::Part() , tex_map() , mesh() , initial() -, hsl_mod(0.0f, 1.0f, 1.0f) -, rgb_mod(1.0f, 1.0f, 1.0f) +, hsl_mod(0, 255, 255) +, rgb_mod(255, 255, 255) , id(0) { } @@ -123,6 +123,7 @@ void Part::Read(TokenStreamReader &in, ResourceIndex &tex_index, const ShapeRegi std::string name; std::string shape_name; std::string tex_name; + glm::vec3 color_conv; in.Skip(Token::ANGLE_BRACKET_OPEN); while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) { in.ReadIdentifier(name); @@ -135,9 +136,11 @@ void Part::Read(TokenStreamReader &in, ResourceIndex &tex_index, const ShapeRegi } else if (name == "orientation") { in.ReadQuat(initial.orientation); } else if (name == "hsl_mod") { - in.ReadVec(hsl_mod); + in.ReadVec(color_conv); + hsl_mod = glm::tvec3(color_conv * 255.0f); } else if (name == "rgb_mod") { - in.ReadVec(rgb_mod); + in.ReadVec(color_conv); + rgb_mod = glm::tvec3(color_conv * 255.0f); } else if (name == "textures") { in.Skip(Token::BRACKET_OPEN); while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) { diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index be4ca9f..5f60d44 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -295,7 +295,7 @@ HUD::HUD(Environment &env, Config &config, const Player &player) buf.indices = std::vector({ 0, 1, 2, 3 }); - buf.colors.resize(4, { 10.0f, 10.0f, 10.0f, 1.0f }); + buf.colors.resize(4, { 255, 255, 255, 255 }); crosshair.Update(buf); } diff --git a/src/world/BlockType.hpp b/src/world/BlockType.hpp index ef328d4..3ca170a 100644 --- a/src/world/BlockType.hpp +++ b/src/world/BlockType.hpp @@ -24,9 +24,9 @@ struct BlockType { const Shape *shape; std::vector textures; - glm::vec3 hsl_mod; - glm::vec3 rgb_mod; - glm::vec3 outline_color; + glm::tvec3 hsl_mod; + glm::tvec3 rgb_mod; + glm::tvec3 outline_color; /// gravity configuration or null if not emitting gravity std::unique_ptr gravity; diff --git a/src/world/block.cpp b/src/world/block.cpp index e99c5be..c861893 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -74,8 +74,8 @@ std::ostream &operator <<(std::ostream &out, const Block::Turn &turn) { BlockType::BlockType() noexcept : shape(nullptr) , textures() -, hsl_mod(0.0f, 1.0f, 1.0f) -, rgb_mod(1.0f, 1.0f, 1.0f) +, hsl_mod(0, 255, 255) +, rgb_mod(255, 255, 255) , outline_color(-1, -1, -1) , gravity() , name("anonymous") @@ -142,6 +142,7 @@ void BlockType::Read( ) { std::string name; in.Skip(Token::ANGLE_BRACKET_OPEN); + glm::vec3 color_conv; while (in.Peek().type != Token::ANGLE_BRACKET_CLOSE) { in.ReadIdentifier(name); in.Skip(Token::EQUALS); @@ -163,11 +164,14 @@ void BlockType::Read( } in.Skip(Token::BRACKET_CLOSE); } else if (name == "rgb_mod") { - in.ReadVec(rgb_mod); + in.ReadVec(color_conv); + rgb_mod = glm::tvec3(color_conv * 255.0f); } else if (name == "hsl_mod") { - in.ReadVec(hsl_mod); + in.ReadVec(color_conv); + hsl_mod = glm::tvec3(color_conv * 255.0f); } else if (name == "outline") { - in.ReadVec(outline_color); + in.ReadVec(color_conv); + outline_color = glm::tvec3(color_conv * 255.0f); } else if (name == "gravity") { gravity = BlockGravity::Read(in); } else if (name == "label") { @@ -252,7 +256,7 @@ void BlockType::FillBlockMesh( void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept { if (!shape) return; shape->Outline(buf); - buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::vec4(outline_color, 1.0f)); + buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::tvec4(outline_color, 255)); } diff --git a/src/world/world.cpp b/src/world/world.cpp index 243fb8a..bf68a9e 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -1072,7 +1072,7 @@ void World::RenderDebug(Viewport &viewport) { PrimitiveMesh debug_mesh; PlainColor &prog = viewport.WorldColorProgram(); for (const Entity &entity : entities) { - debug_buf.OutlineBox(entity.Bounds(), glm::vec4(1.0f, 0.0f, 0.0f, 1.0f)); + debug_buf.OutlineBox(entity.Bounds(), glm::tvec4(255, 0, 0, 255)); debug_mesh.Update(debug_buf); prog.SetM(entity.Transform(players.front().GetEntity().ChunkCoords())); debug_mesh.DrawLines(); -- 2.39.2 From 2ad195d00eea2c4d48f3f1a3ccc60a8176e7da20 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Fri, 18 Dec 2015 10:08:30 +0100 Subject: [PATCH 04/16] ignore apitrace files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 334f308..ea7759b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.swp *.swo +*.trace blank blank.debug blank.profile -- 2.39.2 From ef2427f841a434f93805321f8bbac44be2dd4555 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Fri, 18 Dec 2015 14:28:42 +0100 Subject: [PATCH 05/16] avoid zero vertex draw calls --- src/graphics/BlockMesh.hpp | 8 +++++++- src/graphics/EntityMesh.hpp | 8 +++++++- src/graphics/PrimitiveMesh.hpp | 10 ++++++++-- src/graphics/SkyBoxMesh.hpp | 8 +++++++- src/graphics/SpriteMesh.hpp | 8 +++++++- src/graphics/VertexArray.hpp | 2 ++ src/graphics/mesh.cpp | 29 +++-------------------------- src/world/chunk.cpp | 20 ++++---------------- 8 files changed, 45 insertions(+), 48 deletions(-) diff --git a/src/graphics/BlockMesh.hpp b/src/graphics/BlockMesh.hpp index 399ff32..5342992 100644 --- a/src/graphics/BlockMesh.hpp +++ b/src/graphics/BlockMesh.hpp @@ -69,7 +69,13 @@ public: public: void Update(const Buffer &) noexcept; - void Draw() const noexcept; + bool Empty() const noexcept { + return vao.Empty(); + } + + void Draw() const noexcept { + vao.DrawTriangleElements(); + } private: VAO vao; diff --git a/src/graphics/EntityMesh.hpp b/src/graphics/EntityMesh.hpp index 804bb6e..58b29e5 100644 --- a/src/graphics/EntityMesh.hpp +++ b/src/graphics/EntityMesh.hpp @@ -69,7 +69,13 @@ public: public: void Update(const Buffer &) noexcept; - void Draw() const noexcept; + bool Empty() const noexcept { + return vao.Empty(); + } + + void Draw() const noexcept { + vao.DrawTriangleElements(); + } private: VAO vao; diff --git a/src/graphics/PrimitiveMesh.hpp b/src/graphics/PrimitiveMesh.hpp index 6a8b696..577321a 100644 --- a/src/graphics/PrimitiveMesh.hpp +++ b/src/graphics/PrimitiveMesh.hpp @@ -66,8 +66,14 @@ public: public: void Update(const Buffer &) noexcept; - void DrawLines() noexcept; - void DrawTriangles() noexcept; + bool Empty() const noexcept { + return vao.Empty(); + } + + void DrawLines() const noexcept; + void DrawTriangles() const noexcept { + vao.DrawTriangleElements(); + } private: VAO vao; diff --git a/src/graphics/SkyBoxMesh.hpp b/src/graphics/SkyBoxMesh.hpp index ab1da8d..2378327 100644 --- a/src/graphics/SkyBoxMesh.hpp +++ b/src/graphics/SkyBoxMesh.hpp @@ -47,7 +47,13 @@ public: void LoadUnitBox(); void Update(const Buffer &) noexcept; - void Draw() const noexcept; + bool Empty() const noexcept { + return vao.Empty(); + } + + void Draw() const noexcept { + vao.DrawTriangleElements(); + } private: VAO vao; diff --git a/src/graphics/SpriteMesh.hpp b/src/graphics/SpriteMesh.hpp index a7cfd64..0c6c9a1 100644 --- a/src/graphics/SpriteMesh.hpp +++ b/src/graphics/SpriteMesh.hpp @@ -60,7 +60,13 @@ public: public: void Update(const Buffer &) noexcept; - void Draw() noexcept; + bool Empty() const noexcept { + return vao.Empty(); + } + + void Draw() const noexcept { + vao.DrawTriangleElements(); + } private: VAO vao; diff --git a/src/graphics/VertexArray.hpp b/src/graphics/VertexArray.hpp index 5f70f42..ab02a56 100644 --- a/src/graphics/VertexArray.hpp +++ b/src/graphics/VertexArray.hpp @@ -24,6 +24,8 @@ public: VertexArray &operator =(VertexArray &&) noexcept; public: + bool Empty() const noexcept { return idx_count == 0; } + void Bind() const noexcept; template diff --git a/src/graphics/mesh.cpp b/src/graphics/mesh.cpp index 9cb8c92..906b20f 100644 --- a/src/graphics/mesh.cpp +++ b/src/graphics/mesh.cpp @@ -18,10 +18,10 @@ void EntityMesh::Update(const Buffer &buf) noexcept { std::cerr << "EntityMesh: not enough tex coords!" << std::endl; } if (buf.hsl_mods.size() < buf.vertices.size()) { - std::cerr << "BlockMesh: not enough HSL modifiers!" << std::endl; + std::cerr << "EntityMesh: not enough HSL modifiers!" << std::endl; } if (buf.rgb_mods.size() < buf.vertices.size()) { - std::cerr << "BlockMesh: not enough RGB modifiers!" << std::endl; + std::cerr << "EntityMesh: not enough RGB modifiers!" << std::endl; } if (buf.normals.size() < buf.vertices.size()) { std::cerr << "EntityMesh: not enough normals!" << std::endl; @@ -38,11 +38,6 @@ void EntityMesh::Update(const Buffer &buf) noexcept { } -void EntityMesh::Draw() const noexcept { - vao.DrawTriangleElements(); -} - - void BlockMesh::Update(const Buffer &buf) noexcept { #ifndef NDEBUG if (buf.tex_coords.size() < buf.vertices.size()) { @@ -69,11 +64,6 @@ void BlockMesh::Update(const Buffer &buf) noexcept { } -void BlockMesh::Draw() const noexcept { - vao.DrawTriangleElements(); -} - - void PrimitiveMesh::Buffer::FillRect( float w, float h, const Color &color, @@ -129,16 +119,12 @@ void PrimitiveMesh::Update(const Buffer &buf) noexcept { } -void PrimitiveMesh::DrawLines() noexcept { +void PrimitiveMesh::DrawLines() const noexcept { glEnable(GL_LINE_SMOOTH); glLineWidth(2.0f); vao.DrawLineElements(); } -void PrimitiveMesh::DrawTriangles() noexcept { - vao.DrawTriangleElements(); -} - void SkyBoxMesh::LoadUnitBox() { Buffer buffer; @@ -169,10 +155,6 @@ void SkyBoxMesh::Update(const Buffer &buf) noexcept { vao.PushIndices(ATTRIB_INDEX, buf.indices); } -void SkyBoxMesh::Draw() const noexcept { - vao.DrawTriangleElements(); -} - void SpriteMesh::Buffer::LoadRect( float w, float h, @@ -210,9 +192,4 @@ void SpriteMesh::Update(const Buffer &buf) noexcept { vao.PushIndices(ATTRIB_INDEX, buf.indices); } - -void SpriteMesh::Draw() noexcept { - vao.DrawTriangleElements(); -} - } diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index 6eb027a..596bcaf 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -815,33 +815,21 @@ void ChunkRenderer::Render(Viewport &viewport) { Frustum frustum(transpose(chunk_prog.GetVP())); AABB box; - //std::cout << "V = " << chunk_prog.View() << std::endl; - //std::cout << "P = " << chunk_prog.Projection() << std::endl; - //std::cout << "VP = " << chunk_prog.GetVP() << std::endl; - //std::cout << "frustum = " << frustum << std::endl; - for (int i = 0; i < index.TotalChunks(); ++i) { if (!index[i]) continue; box.min = (index[i]->Position() - index.Base()) * ExactLocation::Extent(); box.max = box.min + ExactLocation::FExtent(); if (!CullTest(box, frustum)) { - - //glm::mat4 m(index[i]->Transform(index.Base())); - //if (CullTest(Chunk::Bounds(), chunk_prog.GetVP() * m)) { - // std::cout << "M = " << m << std::endl; - // std::cout << "box = " << box.min << ", " << box.max << std::endl; - // std::cout << "should've been culled" << std::endl; - //} - if (index[i]->ShouldUpdateMesh()) { index[i]->Update(models[i]); } - chunk_prog.SetM(index[i]->Transform(index.Base())); - models[i].Draw(); + if (!models[i].Empty()) { + chunk_prog.SetM(index[i]->Transform(index.Base())); + models[i].Draw(); + } } } - //std::cout << std::endl; } -- 2.39.2 From 6513b55584093a86ce1e369e054263dd75c295c8 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 21 Dec 2015 13:17:47 +0100 Subject: [PATCH 06/16] fix default outline color actually, white doesn't look so bad for an outline, maybe that should be the default (but 255 then, not -1) --- src/world/block.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/block.cpp b/src/world/block.cpp index c861893..f518b64 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -76,7 +76,7 @@ BlockType::BlockType() noexcept , textures() , hsl_mod(0, 255, 255) , rgb_mod(255, 255, 255) -, outline_color(-1, -1, -1) +, outline_color(0, 0, 0) , gravity() , name("anonymous") , label("some block") -- 2.39.2 From ab0ba4313c473378b4516e3702d524dc1d1fc5d4 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 21 Dec 2015 13:14:44 +0100 Subject: [PATCH 07/16] faster ray/box test for AABBs --- src/geometry/geometry.cpp | 21 ++++++++-- src/geometry/primitive.hpp | 16 ++++++++ src/world/Chunk.hpp | 10 ++++- src/world/world.cpp | 11 +++-- tst/geometry/IntersectionTest.cpp | 67 +++++++++++++++++++++++++++++-- tst/geometry/IntersectionTest.hpp | 2 + 6 files changed, 116 insertions(+), 11 deletions(-) diff --git a/src/geometry/geometry.cpp b/src/geometry/geometry.cpp index 1e84fbb..668e729 100644 --- a/src/geometry/geometry.cpp +++ b/src/geometry/geometry.cpp @@ -49,6 +49,23 @@ std::ostream &operator <<(std::ostream &out, const Ray &ray) { return out << "Ray(" << ray.orig << ", " << ray.dir << ')'; } +bool Intersection( + const Ray &ray, + const AABB &box, + float &dist +) noexcept { + float t_min = 0.0f; + float t_max = std::numeric_limits::infinity(); + for (int i = 0; i < 3; ++i) { + float t1 = (box.min[i] - ray.orig[i]) * ray.inv_dir[i]; + float t2 = (box.max[i] - ray.orig[i]) * ray.inv_dir[i]; + t_min = std::max(t_min, std::min(t1, t2)); + t_max = std::min(t_max, std::max(t1, t2)); + } + dist = t_min; + return t_max >= t_min; +} + bool Intersection( const Ray &ray, const AABB &aabb, @@ -85,12 +102,11 @@ bool Intersection( } } - glm::vec3 min_all(min(t1, t2)); - if (dist) { *dist = t_min; } if (normal) { + glm::vec3 min_all(min(t1, t2)); if (min_all.x > min_all.y) { if (min_all.x > min_all.z) { normal->x = t2.x < t1.x ? 1 : -1; @@ -106,7 +122,6 @@ bool Intersection( return true; } - bool Intersection( const AABB &a_box, const glm::mat4 &a_m, diff --git a/src/geometry/primitive.hpp b/src/geometry/primitive.hpp index da4c37f..72da847 100644 --- a/src/geometry/primitive.hpp +++ b/src/geometry/primitive.hpp @@ -31,13 +31,29 @@ struct AABB { std::ostream &operator <<(std::ostream &, const AABB &); +// TODO: this should really use setters/getters for dir and inv_dir so +// manipulating code doesn't "forget" to call Update() struct Ray { glm::vec3 orig; glm::vec3 dir; + + glm::vec3 inv_dir; + + void Update() noexcept { + inv_dir = 1.0f / dir; + } }; std::ostream &operator <<(std::ostream &, const Ray &); +/// axis aligned boolean ray/box intersection test +/// if true, dist constains distance from ray's origin to intersection point +bool Intersection( + const Ray &, + const AABB &, + float &dist) noexcept; + +/// detailed oriented ray/box intersection test bool Intersection( const Ray &, const AABB &, diff --git a/src/world/Chunk.hpp b/src/world/Chunk.hpp index 7eceb98..045f58d 100644 --- a/src/world/Chunk.hpp +++ b/src/world/Chunk.hpp @@ -35,6 +35,14 @@ public: static glm::vec3 Center() noexcept { return glm::vec3(8.0f); } static float Radius() noexcept { return 27.71281292110203669632f; /* 16 * √3 */ } + /// get bounding box relative to given reference chunk + AABB RelativeBounds(const ExactLocation::Coarse &ref) const noexcept { + AABB bounds; + bounds.min = (position - ref) * ExactLocation::Extent(); + bounds.max = bounds.min + ExactLocation::FExtent(); + return bounds; + } + static constexpr bool InBounds(const ExactLocation::Fine &pos) noexcept { return pos.x >= 0.0f && pos.x < fside && @@ -141,7 +149,7 @@ public: const ExactLocation::Coarse &reference, float &dist ) const noexcept { - return blank::Intersection(ray, Bounds(), Transform(reference), &dist); + return blank::Intersection(ray, RelativeBounds(reference), dist); } /// check if given ray intersects any block of this chunk diff --git a/src/world/world.cpp b/src/world/world.cpp index bf68a9e..0daadfc 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -133,7 +133,9 @@ glm::mat4 Entity::ViewTransform(const glm::ivec3 &reference) const noexcept { Ray Entity::Aim(const ExactLocation::Coarse &chunk_offset) const noexcept { glm::mat4 transform = ViewTransform(chunk_offset); - return Ray{ glm::vec3(transform[3]), -glm::vec3(transform[2]) }; + Ray ray{ glm::vec3(transform[3]), -glm::vec3(transform[2]) }; + ray.Update(); + return ray; } void Entity::Update(World &world, float dt) { @@ -789,8 +791,11 @@ bool World::Intersection( candidates.clear(); - // TODO: convert to coords based iteration and trim based - // on ray direction + // TODO: change this so the test starts at the chunk of the ray's + // origin and "walks" forward until it hits (actually casting + // the ray, so to say). if this performs well (at least, better + // than now), this could also qualify for the chunk test itself + // see Bresenham's line algo or something similar for (Chunk *cur_chunk : *index) { float cur_dist; if (cur_chunk && cur_chunk->Intersection(ray, reference, cur_dist)) { diff --git a/tst/geometry/IntersectionTest.cpp b/tst/geometry/IntersectionTest.cpp index 41fb81a..521647e 100644 --- a/tst/geometry/IntersectionTest.cpp +++ b/tst/geometry/IntersectionTest.cpp @@ -20,6 +20,53 @@ void IntersectionTest::tearDown() { } +void IntersectionTest::testSimpleRayBoxIntersection() { + Ray ray{ { 0, 0, 0 }, { 1, 0, 0 } }; // at origin, pointing right + ray.Update(); + AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin + + const float delta = std::numeric_limits::epsilon(); + + float distance = 0; + + CPPUNIT_ASSERT_MESSAGE( + "ray at origin not intersecting box at origin", + Intersection(ray, box, distance) + ); + + // move ray outside the box, but have it still point at it + // should be 4 units to the left now + ray.orig.x = -5; + CPPUNIT_ASSERT_MESSAGE( + "ray pointing at box doesn't intersect", + Intersection(ray, box, distance) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "intersection distance way off", + 4.0f, distance, delta + ); + + // move ray to the other side, so it's pointing away now + ray.orig.x = 5; + CPPUNIT_ASSERT_MESSAGE( + "ray pointing away from box still intersects", + !Intersection(ray, box, distance) + ); + + // 45 deg down from 4 units away, so should be about 4 * sqrt(2) + ray.orig = { -5.0f, 4.5f, 0.0f }; + ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f }; + ray.Update(); + CPPUNIT_ASSERT_MESSAGE( + "ray pointing at box doesn't intersect", + Intersection(ray, box, distance) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "intersection distance way off", + 5.65685424949238019520f, distance, delta + ); +} + void IntersectionTest::testRayBoxIntersection() { Ray ray{ { 0, 0, 0 }, { 1, 0, 0 } }; // at origin, pointing right AABB box{ { -1, -1, -1 }, { 1, 1, 1 } }; // 2x2x2 cube centered around origin @@ -34,10 +81,6 @@ void IntersectionTest::testRayBoxIntersection() { "ray at origin not intersecting box at origin", Intersection(ray, box, M, &distance) ); - CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( - "intersection distance way off", - 0.0f, distance, delta - ); // normal undefined, so can't test // move ray outside the box, but have it still point at it @@ -62,6 +105,22 @@ void IntersectionTest::testRayBoxIntersection() { "ray pointing away from box still intersects", !Intersection(ray, box, M) ); + + // 45 deg down from 4 units away, so should be about 4 * sqrt(2) + ray.orig = { -5.0f, 4.5f, 0.0f }; + ray.dir = { 0.70710678118654752440f, -0.70710678118654752440f, 0.0f }; + CPPUNIT_ASSERT_MESSAGE( + "ray pointing at box doesn't intersect", + Intersection(ray, box, M, &distance, &normal) + ); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( + "intersection distance way off", + 5.65685424949238019520f, distance, delta + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong surface normal at intersection point", + glm::vec3(-1, 0, 0), normal + ); } void IntersectionTest::testBoxBoxIntersection() { diff --git a/tst/geometry/IntersectionTest.hpp b/tst/geometry/IntersectionTest.hpp index 7922290..6300e6e 100644 --- a/tst/geometry/IntersectionTest.hpp +++ b/tst/geometry/IntersectionTest.hpp @@ -12,6 +12,7 @@ class IntersectionTest CPPUNIT_TEST_SUITE(IntersectionTest); +CPPUNIT_TEST(testSimpleRayBoxIntersection); CPPUNIT_TEST(testRayBoxIntersection); CPPUNIT_TEST(testBoxBoxIntersection); @@ -21,6 +22,7 @@ public: void setUp(); void tearDown(); + void testSimpleRayBoxIntersection(); void testRayBoxIntersection(); void testBoxBoxIntersection(); -- 2.39.2 From 7c9675c5678f94bfbdf96e55f2865c53bd42fe7e Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Mon, 21 Dec 2015 15:06:59 +0100 Subject: [PATCH 08/16] typo in todo file and I bet it's not the last one --- doc/todo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/todo b/doc/todo index 4bbfb7d..3be3805 100644 --- a/doc/todo +++ b/doc/todo @@ -118,7 +118,7 @@ spawning need a way to find a suitable location to spawn new players in I imagine a "random block" function of ChunkIndex could be nice (also for use with the AI spawner) - also, finding a spawn position for a player must no fail. after a + also, finding a spawn position for a player must not fail. after a certain number of tries, the world must change to safely accomodate the player. chunk generation could be adjusted to make a little more room near the -- 2.39.2 From 1a8d4d31ef0a094ef6488127c5f873040151cb57 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 22 Dec 2015 10:46:15 +0100 Subject: [PATCH 09/16] initialize entity fields oops --- src/world/world.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/world/world.cpp b/src/world/world.cpp index 0daadfc..b9d9db7 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -46,6 +46,9 @@ Entity::Entity() noexcept , bounds() , radius(0.0f) , state() +, model_transform(1.0f) +, view_transform(1.0f) +, speed(0.0f) , heading(0.0f, 0.0f, -1.0f) , max_vel(5.0f) , max_force(25.0f) -- 2.39.2 From fda38181732e58537331c919dd699eaa830ead50 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 23 Dec 2015 13:31:47 +0100 Subject: [PATCH 10/16] smoother type selection during chunk generation --- Makefile | 1 + src/world/BlockType.hpp | 63 +++++++++++++++++++++++++++++++++-------- src/world/Generator.cpp | 20 ++++++------- src/world/block.cpp | 56 +++++++++++++----------------------- 4 files changed, 82 insertions(+), 58 deletions(-) diff --git a/Makefile b/Makefile index 42300ac..156d5cb 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ CPPFLAGS ?= CPPFLAGS += $(PKGFLAGS) CXXFLAGS ?= CXXFLAGS += -Wall +#CXXFLAGS += -march=native LDXXFLAGS ?= LDXXFLAGS += $(PKGLIBS) diff --git a/src/world/BlockType.hpp b/src/world/BlockType.hpp index 3ca170a..f1b887d 100644 --- a/src/world/BlockType.hpp +++ b/src/world/BlockType.hpp @@ -9,6 +9,7 @@ #include "../model/Shape.hpp" #include +#include #include @@ -58,20 +59,58 @@ struct BlockType { // generation properties /// whether to use this block in generation at all bool generate; + // min/mid/max points for the respective properties // should all be in the (-1,1) range - float min_solidity; - float mid_solidity; - float max_solidity; - float min_humidity; - float mid_humidity; - float max_humidity; - float min_temperature; - float mid_temperature; - float max_temperature; - float min_richness; - float mid_richness; - float max_richness; + class Distribution { + + public: + Distribution(float min, float mid, float max) + : xmin(min), xmid(mid), xmax(max) { Update(); } + + bool Valid(float x) const noexcept { + return x >= xmin && x <= xmax; + } + float Map(float x) const noexcept { + // previous algo as was used by Generator + //return 4.0f - ((x - xmid) * (x - xmid)); + + // linear mapping of [min,mid,max] to [-1,0,1] + x -= xmid; + x *= (x < 0) ? inv_neg : inv_pos; + + // smoothing: x^4 - 2x^2 + 1 + x *= x; + return x * x - 2.0f * x + 1.0f; + } + + void Min(float m) noexcept { xmin = m; Update(); } + float Min() const noexcept { return xmin; } + void Mid(float m) noexcept { xmid = m; Update(); } + float Mid() const noexcept { return xmid; } + void Max(float m) noexcept { xmax = m; Update(); } + float Max() const noexcept { return xmax; } + + private: + void Update() { + float abs_min = std::abs(xmin - xmid); + inv_neg = abs_min < std::numeric_limits::epsilon() ? 0.0f : 1.0f / abs_min; + float abs_max = std::abs(xmax - xmid); + inv_pos = abs_max < std::numeric_limits::epsilon() ? 0.0f : 1.0f / abs_max; + } + + float xmin; + float xmid; + float xmax; + float inv_neg; + float inv_pos; + + }; + + Distribution solidity; + Distribution humidity; + Distribution temperature; + Distribution richness; /// commonness factor, random chance is multiplied by this float commonness; diff --git a/src/world/Generator.cpp b/src/world/Generator.cpp index b6d53ae..fa6e01e 100644 --- a/src/world/Generator.cpp +++ b/src/world/Generator.cpp @@ -41,8 +41,8 @@ void Generator::LoadTypes(const BlockTypeRegistry ®) { for (const BlockType &type : reg) { if (type.generate) { types.push_back(&type); - if (type.min_solidity < min_solidity) { - min_solidity = type.min_solidity; + if (type.solidity.Min() < min_solidity) { + min_solidity = type.solidity.Min(); } } } @@ -160,14 +160,14 @@ Block Generator::Generate(const ValueField &field, const glm::ivec3 &pos) const candidates.clear(); float total = 0.0f; for (const BlockType *type : types) { - if (solidity < type->min_solidity || solidity > type->max_solidity) continue; - if (humidity < type->min_humidity || humidity > type->max_humidity) continue; - if (temperature < type->min_temperature || temperature > type->max_temperature) continue; - if (richness < type->min_richness || richness > type->max_richness) continue; - float solidity_match = 4.0f - ((solidity - type->mid_solidity) * (solidity - type->mid_solidity)); - float humidity_match = 4.0f - ((humidity - type->mid_humidity) * (humidity - type->mid_humidity)); - float temperature_match = 4.0f - ((temperature - type->mid_temperature) * (temperature - type->mid_temperature)); - float richness_match = 4.0f - ((richness - type->mid_richness) * (richness - type->mid_richness)); + if (!type->solidity.Valid(solidity)) continue; + if (!type->humidity.Valid(humidity)) continue; + if (!type->temperature.Valid(temperature)) continue; + if (!type->richness.Valid(richness)) continue; + float solidity_match = type->solidity.Map(solidity); + float humidity_match = type->humidity.Map(humidity); + float temperature_match = type->temperature.Map(temperature); + float richness_match = type->richness.Map(richness); float chance = (solidity_match + humidity_match + temperature_match + richness_match) * type->commonness; total += chance; candidates.emplace_back(type, total); diff --git a/src/world/block.cpp b/src/world/block.cpp index f518b64..b0fdf61 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -89,18 +89,10 @@ BlockType::BlockType() noexcept , collision(true) , collide_block(true) , generate(false) -, min_solidity(0.5f) -, mid_solidity(0.75f) -, max_solidity(1.0f) -, min_humidity(-1.0f) -, mid_humidity(0.0f) -, max_humidity(1.0f) -, min_temperature(-1.0f) -, mid_temperature(0.0f) -, max_temperature(1.0f) -, min_richness(-1.0f) -, mid_richness(0.0f) -, max_richness(1.0f) +, solidity(0.5f, 0.75f, 1.0f) +, humidity(-1.0f, 0.0f, 1.0f) +, temperature(-1.0f, 0.0f, 1.0f) +, richness(-1.0f, 0.0f, 1.0f) , commonness(1.0f) { } @@ -119,18 +111,10 @@ void BlockType::Copy(const BlockType &other) noexcept { collision = other.collision; collide_block = collide_block; generate = other.generate; - min_solidity = other.min_solidity; - mid_solidity = other.mid_solidity; - max_solidity = other.max_solidity; - min_humidity = other.min_humidity; - mid_humidity = other.mid_humidity; - max_humidity = other.max_humidity; - min_temperature = other.min_temperature; - mid_temperature = other.mid_temperature; - max_temperature = other.max_temperature; - min_richness = other.min_richness; - mid_richness = other.mid_richness; - max_richness = other.max_richness; + solidity = other.solidity; + humidity = other.humidity; + temperature = other.temperature; + richness = other.richness; commonness = other.commonness; } @@ -193,29 +177,29 @@ void BlockType::Read( } else if (name == "generate") { generate = in.GetBool(); } else if (name == "min_solidity") { - min_solidity = in.GetFloat(); + solidity.Min(in.GetFloat()); } else if (name == "mid_solidity") { - mid_solidity = in.GetFloat(); + solidity.Mid(in.GetFloat()); } else if (name == "max_solidity") { - max_solidity = in.GetFloat(); + solidity.Max(in.GetFloat()); } else if (name == "min_humidity") { - min_humidity = in.GetFloat(); + humidity.Min(in.GetFloat()); } else if (name == "mid_humidity") { - mid_humidity = in.GetFloat(); + humidity.Mid(in.GetFloat()); } else if (name == "max_humidity") { - max_humidity = in.GetFloat(); + humidity.Max(in.GetFloat()); } else if (name == "min_temperature") { - min_temperature = in.GetFloat(); + temperature.Min(in.GetFloat()); } else if (name == "mid_temperature") { - mid_temperature = in.GetFloat(); + temperature.Mid(in.GetFloat()); } else if (name == "max_temperature") { - max_temperature = in.GetFloat(); + temperature.Max(in.GetFloat()); } else if (name == "min_richness") { - min_richness = in.GetFloat(); + richness.Min(in.GetFloat()); } else if (name == "mid_richness") { - mid_richness = in.GetFloat(); + richness.Mid(in.GetFloat()); } else if (name == "max_richness") { - max_richness = in.GetFloat(); + richness.Max(in.GetFloat()); } else if (name == "commonness") { commonness = in.GetFloat(); } else if (name == "shape") { -- 2.39.2 From 242b87a5fb412f9006e4b7debc1408cf7ac83000 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Tue, 5 Jan 2016 12:44:57 +0100 Subject: [PATCH 11/16] improved ray/world collision a little --- src/geometry/primitive.hpp | 14 +++++++++++++ src/world/Chunk.hpp | 5 ++++- src/world/chunk.cpp | 10 ++++++++- src/world/world.cpp | 43 +++++++++++++++++++++++++++++--------- 4 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/geometry/primitive.hpp b/src/geometry/primitive.hpp index 72da847..b9f2187 100644 --- a/src/geometry/primitive.hpp +++ b/src/geometry/primitive.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace blank { @@ -42,6 +43,19 @@ struct Ray { void Update() noexcept { inv_dir = 1.0f / dir; } + + /// get shortest distance of this ray's line to given point + float Distance(const glm::vec3 &point) const noexcept { + // d = |(x2-x1)×(x1-x0)|/|x2-x1| + // where x0 is point, and x1 and x2 are points on the line + // for derivation, see http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html + // x1 = orig + // x2-x1 = dir, which means |x2-x1| is 1.0 + return length(cross(dir, orig - point)); + } + float DistanceSquared(const glm::vec3 &point) const noexcept { + return length2(cross(dir, orig - point)); + } }; std::ostream &operator <<(std::ostream &, const Ray &); diff --git a/src/world/Chunk.hpp b/src/world/Chunk.hpp index 045f58d..6779414 100644 --- a/src/world/Chunk.hpp +++ b/src/world/Chunk.hpp @@ -144,6 +144,8 @@ public: /// get gravity for one unit mass at given point glm::vec3 GravityAt(const ExactLocation &) const noexcept; + /// check if given ray passes this chunk at all + /// given reference indicates the chunk offset of the ray in world space bool Intersection( const Ray &ray, const ExactLocation::Coarse &reference, @@ -153,12 +155,13 @@ public: } /// check if given ray intersects any block of this chunk - /// given reference indicated the chunk offset of the ray in world space + /// given reference indicates the chunk offset of the ray in world space bool Intersection( const Ray &, const ExactLocation::Coarse &reference, WorldCollision &) noexcept; + /// get all blocks intersecting given box bool Intersection( const AABB &box, const glm::mat4 &Mbox, diff --git a/src/world/chunk.cpp b/src/world/chunk.cpp index 596bcaf..97ec3e3 100644 --- a/src/world/chunk.cpp +++ b/src/world/chunk.cpp @@ -415,9 +415,17 @@ bool Chunk::Intersection( if (!type.collision || !type.shape) { continue; } + RoughLocation::Fine pos(x, y, z); + + // center of the blok relative to the ray + glm::vec3 relative_center(glm::vec3((position - reference) * ExactLocation::Extent() + pos) + 0.5f); + if (ray.DistanceSquared(relative_center) > 3.0f) { + continue; + } + float cur_dist; glm::vec3 cur_norm; - if (type.shape->Intersects(ray, ToTransform(reference, RoughLocation::Fine(x, y, z), idx), cur_dist, cur_norm)) { + if (type.shape->Intersects(ray, ToTransform(reference, pos, idx), cur_dist, cur_norm)) { if (cur_dist < coll.depth) { coll.block = idx; coll.depth = cur_dist; diff --git a/src/world/world.cpp b/src/world/world.cpp index b9d9db7..a12d86e 100644 --- a/src/world/world.cpp +++ b/src/world/world.cpp @@ -784,7 +784,7 @@ bool World::Intersection( const ExactLocation::Coarse &reference, WorldCollision &coll ) { - // only consider chunks of the idex closest to reference + // only consider chunks of the index closest to reference // this makes the ray not be infinite anymore (which means it's // actually a line segment), but oh well ChunkIndex *index = chunks.ClosestIndex(reference); @@ -794,15 +794,38 @@ bool World::Intersection( candidates.clear(); - // TODO: change this so the test starts at the chunk of the ray's - // origin and "walks" forward until it hits (actually casting - // the ray, so to say). if this performs well (at least, better - // than now), this could also qualify for the chunk test itself - // see Bresenham's line algo or something similar - for (Chunk *cur_chunk : *index) { - float cur_dist; - if (cur_chunk && cur_chunk->Intersection(ray, reference, cur_dist)) { - candidates.push_back({ cur_chunk, cur_dist }); + // maybe worht to try: + // change this so the test starts at the chunk of the ray's + // origin and "walks" forward until it hits (actually casting + // the ray, so to say). if this performs well (at least, better + // than now), this could also qualify for the chunk test itself + // see Bresenham's line algo or something similar + + ExactLocation ray_loc(reference, ray.orig); + ray_loc.Correct(); + + ExactLocation::Coarse begin(index->CoordsBegin()); + ExactLocation::Coarse end(index->CoordsEnd()); + + // ignore chunks that are bind the ray's origin + for (int i = 0; i < 3; ++i) { + if (ray.dir[i] >= 0.0f) { + begin[i] = ray_loc.chunk[i]; + } + if (ray.dir[i] <= 0.0f) { + end[i] = ray_loc.chunk[i] + 1; + } + } + + for (ExactLocation::Coarse pos(begin); pos.z < end.z; ++pos.z) { + for (pos.y = begin.y; pos.y < end.y; ++pos.y) { + for (pos.x = begin.x; pos.x < end.x; ++pos.x) { + Chunk *cur_chunk = index->Get(pos); + float cur_dist; + if (cur_chunk && cur_chunk->Intersection(ray, reference, cur_dist)) { + candidates.push_back({ cur_chunk, cur_dist }); + } + } } } -- 2.39.2 From 110ef77a019384fccbbf33649955bcc064a6399e Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 6 Jan 2016 09:56:35 +0100 Subject: [PATCH 12/16] fix return type for Entity::Transform() --- src/world/Entity.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index 36f6868..e38e0b4 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -95,7 +95,7 @@ public: void SetHead(float pitch, float yaw) noexcept; /// get a transform for this entity's coordinate space - const glm::mat4 Transform() const noexcept { return model_transform; } + const glm::mat4 &Transform() const noexcept { return model_transform; } /// get a transform for this entity's coordinate space relative to reference chunk glm::mat4 Transform(const glm::ivec3 &reference) const noexcept; /// get a transform for this entity's view space relative to reference chunk -- 2.39.2 From 3e7901a804ef85eea01adfb60274218748c0337b Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Wed, 6 Jan 2016 15:05:29 +0100 Subject: [PATCH 13/16] first ideas for placing oriented blocks --- src/ui/ui.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++- src/world/Entity.hpp | 2 ++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 5f60d44..89c3410 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -182,14 +183,59 @@ void DirectInput::PickBlock() { } void DirectInput::PlaceBlock() { + // update block focus UpdatePlayer(); + // do nothing if not looking at any block if (!BlockFocus()) return; + // determine block adjacent to the face the player is looking at BlockLookup next_block(BlockFocus().chunk, BlockFocus().BlockPos(), Block::NormalFace(BlockFocus().normal)); + // abort if it's unavailable if (!next_block) { return; } - manip.SetBlock(next_block.GetChunk(), next_block.GetBlockIndex(), Block(InventorySlot() + 1)); + + // "can replace" check + // this prevents players from replacing solid blocks e.g. by looking through slabs + // simple for now, should be expanded to include things like + // entities in the way or replacable blocks like water and stuff + if (next_block.GetBlock().type != 0) { + return; + } + + Block new_block(InventorySlot() + 1); + + // block's up vector + // align with player's up + const glm::vec3 player_up(GetPlayer().GetEntity().Up()); + new_block.SetFace(Block::NormalFace(player_up)); + // to align with player's local up/down look (like stairs in minecraft), just invert + // it if pitch is positive + // or, align with focus normal (like logs in minecraft) + + // determine block's turn (local rotation about up axis) + // when aligned with player's up (first mode, and currently the only one implemented) + // project the player's view forward onto his entity's XZ plane and + // use the closest cardinal direction it's pointing in + const glm::vec3 view_forward(-GetPlayer().GetEntity().ViewTransform(GetPlayer().GetEntity().ChunkCoords())[3]); + // if view is straight up or down, this will be a null vector (NaN after normalization) + // in that case maybe the model forward should be used? + // the current implementation implicitly falls back to TURN_NONE which is -Z + const glm::vec3 local_forward(normalize(view_forward - proj(view_forward, player_up))); + // FIXME: I suspect this only works when player_up is positive Y + if (local_forward.x > 0.707f) { + new_block.SetTurn(Block::TURN_RIGHT); + } else if (local_forward.z > 0.707f) { + new_block.SetTurn(Block::TURN_AROUND); + } else if (local_forward.x < -0.707f) { + new_block.SetTurn(Block::TURN_LEFT); + } + // for mode two ("minecraft stairs") it should work the same, but I haven't properly + // thought that through (well, that's also true about the whole face/turn thing, but oh well) + // mode three I have absoloutely no clue. that placement would be appropriate for pipe-like + // blocks, where turn shouldn't make a difference, but what if it does? + + manip.SetBlock(next_block.GetChunk(), next_block.GetBlockIndex(), new_block); Invalidate(); } diff --git a/src/world/Entity.hpp b/src/world/Entity.hpp index e38e0b4..b140a08 100644 --- a/src/world/Entity.hpp +++ b/src/world/Entity.hpp @@ -96,6 +96,8 @@ public: /// get a transform for this entity's coordinate space const glm::mat4 &Transform() const noexcept { return model_transform; } + /// get the entity's local up vector + const glm::vec4 &Up() const noexcept { return model_transform[1]; } /// get a transform for this entity's coordinate space relative to reference chunk glm::mat4 Transform(const glm::ivec3 &reference) const noexcept; /// get a transform for this entity's view space relative to reference chunk -- 2.39.2 From ec85ac414e4e60295484ca1752876919ce5a8390 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 7 Jan 2016 10:52:30 +0100 Subject: [PATCH 14/16] added block orientation test --- tst/world/BlockTest.cpp | 32 ++++++++++++++++++++++++++++++++ tst/world/BlockTest.hpp | 3 +++ 2 files changed, 35 insertions(+) diff --git a/tst/world/BlockTest.cpp b/tst/world/BlockTest.cpp index 85b5a68..b1c2ad2 100644 --- a/tst/world/BlockTest.cpp +++ b/tst/world/BlockTest.cpp @@ -17,6 +17,38 @@ void BlockTest::tearDown() { } +void BlockTest::testOrientation() { + Block block(0, Block::FACE_DOWN, Block::TURN_LEFT); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong block face after initialization", + block.GetFace(), Block::FACE_DOWN + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "wrong block turn after initialization", + block.GetTurn(), Block::TURN_LEFT + ); + + block.SetFace(Block::FACE_BACK); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "changing block face has unexpected effect", + block.GetFace(), Block::FACE_BACK + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "changing block face affected turn", + block.GetTurn(), Block::TURN_LEFT + ); + + block.SetTurn(Block::TURN_AROUND); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "changing block turn has unexpected effect", + block.GetTurn(), Block::TURN_AROUND + ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "changing block turn affected face", + block.GetFace(), Block::FACE_BACK + ); +} + void BlockTest::testFaceOpposite() { CPPUNIT_ASSERT_EQUAL_MESSAGE( "DOWN not opposite of UP", diff --git a/tst/world/BlockTest.hpp b/tst/world/BlockTest.hpp index 467d260..1102ba0 100644 --- a/tst/world/BlockTest.hpp +++ b/tst/world/BlockTest.hpp @@ -12,6 +12,7 @@ class BlockTest CPPUNIT_TEST_SUITE(BlockTest); +CPPUNIT_TEST(testOrientation); CPPUNIT_TEST(testFaceOpposite); CPPUNIT_TEST(testFaceAxis); CPPUNIT_TEST(testFaceNormal); @@ -27,6 +28,8 @@ public: void setUp(); void tearDown(); + void testOrientation(); + void testFaceOpposite(); void testFaceAxis(); void testFaceNormal(); -- 2.39.2 From 54cead1fdf3d1df9187f0cd249322f1e4d85a639 Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 7 Jan 2016 10:53:06 +0100 Subject: [PATCH 15/16] fix forward axis in block placement orientation oh shoot, I'm such an idiot -.- --- src/ui/ui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index 89c3410..2d3b467 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -217,7 +217,7 @@ void DirectInput::PlaceBlock() { // when aligned with player's up (first mode, and currently the only one implemented) // project the player's view forward onto his entity's XZ plane and // use the closest cardinal direction it's pointing in - const glm::vec3 view_forward(-GetPlayer().GetEntity().ViewTransform(GetPlayer().GetEntity().ChunkCoords())[3]); + const glm::vec3 view_forward(-GetPlayer().GetEntity().ViewTransform(GetPlayer().GetEntity().ChunkCoords())[2]); // if view is straight up or down, this will be a null vector (NaN after normalization) // in that case maybe the model forward should be used? // the current implementation implicitly falls back to TURN_NONE which is -Z -- 2.39.2 From fcdce6d72f97d4749c0f120e22e8be00e88ebc6e Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Thu, 17 Mar 2016 16:17:17 +0100 Subject: [PATCH 16/16] fix direct rendering --- src/app/init.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/init.cpp b/src/app/init.cpp index a0ea7b5..fea5653 100644 --- a/src/app/init.cpp +++ b/src/app/init.cpp @@ -157,9 +157,9 @@ InitGL::InitGL(bool double_buffer, int sample_size) { throw SDLError("SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE)"); } - if (double_buffer) { - if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0) { - throw SDLError("SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1)"); + if (!double_buffer) { + if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0) != 0) { + throw SDLError("SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0)"); } } -- 2.39.2