X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fworld%2Fblock.cpp;h=a3db57d91242dfadece48003c0f656fc46ff1a64;hb=cdcfdb33e9b625976909a9fb604b756a1a057788;hp=727fcade04984bfcb8140dae48c4948a3580f2ce;hpb=b61d462707dd3d40a32a6104d88eb24f6a52df63;p=blank.git diff --git a/src/world/block.cpp b/src/world/block.cpp index 727fcad..a3db57d 100644 --- a/src/world/block.cpp +++ b/src/world/block.cpp @@ -1,19 +1,21 @@ #include "Block.hpp" +#include "BlockGravity.hpp" #include "BlockType.hpp" #include "BlockTypeRegistry.hpp" -#include "../model/geometry.hpp" +#include "../io/TokenStreamReader.hpp" +#include "../model/ShapeRegistry.hpp" +#include "../shared/ResourceIndex.hpp" -#include +#include +#include #include +#include #include namespace blank { -const NullBounds BlockType::DEFAULT_SHAPE; - - std::ostream &operator <<(std::ostream &out, const Block &block) { return out << "Block(" << block.type << ", " << block.GetFace() << ", " << block.GetTurn() << ')'; } @@ -70,12 +72,16 @@ std::ostream &operator <<(std::ostream &out, const Block::Turn &turn) { BlockType::BlockType() noexcept -: shape(&DEFAULT_SHAPE) -, texture(0) -, hsl_mod(0.0f, 1.0f, 1.0f) -, rgb_mod(1.0f, 1.0f, 1.0f) -, outline_color(-1, -1, -1) +: shape(nullptr) +, textures() +, hsl_mod(0, 255, 255) +, rgb_mod(255, 255, 255) +, outline_color(0, 0, 0, 255) +, gravity() +, name("anonymous") , label("some block") +, place_sound(-1) +, remove_sound(-1) , id(0) , luminosity(0) , visible(true) @@ -83,29 +89,139 @@ 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) -, commonness(1.0f) -, fill({ false, false, false, false, false, false }) { +, 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) { + +} + +void BlockType::Copy(const BlockType &other) noexcept { + shape = other.shape; + textures = other.textures; + hsl_mod = other.hsl_mod; + rgb_mod = other.rgb_mod; + outline_color = other.outline_color; + place_sound = other.place_sound; + remove_sound = other.remove_sound; + luminosity = other.luminosity; + visible = other.visible; + block_light = other.block_light; + collision = other.collision; + collide_block = collide_block; + generate = other.generate; + solidity = other.solidity; + humidity = other.humidity; + temperature = other.temperature; + richness = other.richness; + commonness = other.commonness; +} +void BlockType::Read( + TokenStreamReader &in, + ResourceIndex &snd_index, + ResourceIndex &tex_index, + const ShapeRegistry &shapes +) { + 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); + if (name == "visible") { + visible = in.GetBool(); + } else if (name == "texture") { + textures.clear(); + in.ReadString(name); + textures.push_back(tex_index.GetID(name)); + } else if (name == "textures") { + textures.clear(); + in.Skip(Token::BRACKET_OPEN); + while (in.Peek().type != Token::BRACKET_CLOSE) { + in.ReadString(name); + textures.push_back(tex_index.GetID(name)); + if (in.Peek().type == Token::COMMA) { + in.Skip(Token::COMMA); + } + } + in.Skip(Token::BRACKET_CLOSE); + } else if (name == "rgb_mod") { + in.ReadVec(color_conv); + rgb_mod = BlockMesh::ColorMod(color_conv * 255.0f); + } else if (name == "hsl_mod") { + in.ReadVec(color_conv); + hsl_mod = BlockMesh::ColorMod(color_conv * 255.0f); + } else if (name == "outline") { + in.ReadVec(color_conv); + outline_color = PrimitiveMesh::Color(color_conv * 255.0f, 255); + } else if (name == "gravity") { + gravity = BlockGravity::Read(in); + } else if (name == "label") { + in.ReadString(label); + } else if (name == "place_sound") { + in.ReadString(name); + place_sound = snd_index.GetID(name); + } else if (name == "remove_sound") { + in.ReadString(name); + remove_sound = snd_index.GetID(name); + } else if (name == "luminosity") { + luminosity = in.GetInt(); + } else if (name == "block_light") { + block_light = in.GetBool(); + } else if (name == "collision") { + collision = in.GetBool(); + } else if (name == "collide_block") { + collide_block = in.GetBool(); + } else if (name == "generate") { + generate = in.GetBool(); + } else if (name == "min_solidity") { + solidity.Min(in.GetFloat()); + } else if (name == "mid_solidity") { + solidity.Mid(in.GetFloat()); + } else if (name == "max_solidity") { + solidity.Max(in.GetFloat()); + } else if (name == "min_humidity") { + humidity.Min(in.GetFloat()); + } else if (name == "mid_humidity") { + humidity.Mid(in.GetFloat()); + } else if (name == "max_humidity") { + humidity.Max(in.GetFloat()); + } else if (name == "min_temperature") { + temperature.Min(in.GetFloat()); + } else if (name == "mid_temperature") { + temperature.Mid(in.GetFloat()); + } else if (name == "max_temperature") { + temperature.Max(in.GetFloat()); + } else if (name == "min_richness") { + richness.Min(in.GetFloat()); + } else if (name == "mid_richness") { + richness.Mid(in.GetFloat()); + } else if (name == "max_richness") { + richness.Max(in.GetFloat()); + } else if (name == "commonness") { + commonness = in.GetFloat(); + } else if (name == "shape") { + in.ReadIdentifier(name); + shape = &shapes.Get(name); + } else { + std::cerr << "warning: unknown block type property " << name << std::endl; + while (in.Peek().type != Token::SEMICOLON) { + in.Next(); + } + } + in.Skip(Token::SEMICOLON); + } + in.Skip(Token::ANGLE_BRACKET_CLOSE); } void BlockType::FillEntityMesh( EntityMesh::Buffer &buf, - const glm::mat4 &transform, - EntityMesh::Index idx_offset + const glm::mat4 &transform ) const noexcept { - shape->Vertices(buf, transform, texture, idx_offset); + if (!shape) return; + shape->Fill(buf, transform, textures); buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod); buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod); } @@ -115,12 +231,14 @@ void BlockType::FillBlockMesh( const glm::mat4 &transform, BlockMesh::Index idx_offset ) const noexcept { - shape->Vertices(buf, transform, texture, idx_offset); + if (!shape) return; + shape->Fill(buf, transform, textures, idx_offset); buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod); buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod); } -void BlockType::FillOutlineMesh(OutlineMesh::Buffer &buf) const noexcept { +void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept { + if (!shape) return; shape->Outline(buf); buf.colors.insert(buf.colors.end(), shape->OutlineCount(), outline_color); } @@ -128,20 +246,129 @@ void BlockType::FillOutlineMesh(OutlineMesh::Buffer &buf) const noexcept { BlockTypeRegistry::BlockTypeRegistry() { BlockType air; + air.name = "air"; + air.label = "Air"; air.visible = false; air.block_light = false; air.collision = false; air.collide_block = false; - Add(air); + Add(std::move(air)); } -Block::Type BlockTypeRegistry::Add(const BlockType &t) { +Block::Type BlockTypeRegistry::Add(BlockType &&t) { int id = types.size(); - types.push_back(t); + if (!names.emplace(t.name, id).second) { + throw std::runtime_error("duplicate block type name " + t.name); + } + types.push_back(std::move(t)); types.back().id = id; return id; } +BlockType &BlockTypeRegistry::Get(const std::string &name) { + auto entry = names.find(name); + if (entry != names.end()) { + return Get(entry->second); + } else { + throw std::runtime_error("unknown block type " + name); + } +} + +const BlockType &BlockTypeRegistry::Get(const std::string &name) const { + auto entry = names.find(name); + if (entry != names.end()) { + return Get(entry->second); + } else { + throw std::runtime_error("unknown block type " + name); + } +} + + +namespace { + +/// the "usual" type of gravity +/// direction is towards the block's center, strength is inverse +/// proportional to distance squared +/// note that the effect can get clipped at distances > 16 units +struct RadialGravity +: public BlockGravity { + + explicit RadialGravity(float strength) + : strength(strength) { } + + glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &) const noexcept override { + float dist2 = glm::length2(diff); + glm::vec3 dir = -glm::normalize(diff); + return dir * (strength / dist2); + } + + float strength; + +}; + +/// a "force field" variant of artificial gravity +/// strength and direction is constant throughout the cuboid +/// extent shouldn't exceed 16 units as gravity is only calculated for +/// chunks surrounding and entity (and sometimes not even those if they're +/// unavailable, but they will be for players) +struct CuboidFieldGravity +: public BlockGravity { + + explicit CuboidFieldGravity(const glm::vec3 &strength, const AABB &extent) + : strength(strength), extent(extent) { } + + glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &M) const noexcept override { + /// rotate AABB endpoints accordingly, ignore translation + glm::vec3 min(M * glm::vec4(extent.min, 0.0f)); + glm::vec3 max(M * glm::vec4(extent.max, 0.0f)); + if (diff.x < min.x || diff.y < min.y || diff.z < min.z || + diff.x > max.x || diff.y > max.y || diff.z > max.z) { + /// if point is outside, force is zero + return glm::vec3(0.0f); + } else { + /// otherwise it's out constant strength in block orientation + return glm::vec3(M * glm::vec4(strength, 0.0f)); + } + } + + glm::vec3 strength; + AABB extent; + +}; + + +} + +BlockGravity::~BlockGravity() { + +} + +std::unique_ptr BlockGravity::Read(TokenStreamReader &in) { + std::string type; + in.ReadIdentifier(type); + if (type == "Radial") { + float strength; + in.Skip(Token::PARENTHESIS_OPEN); + in.ReadNumber(strength); + in.Skip(Token::PARENTHESIS_CLOSE); + return std::unique_ptr(new RadialGravity(strength)); + } else if (type == "CuboidField") { + glm::vec3 strength; + AABB extent; + in.Skip(Token::PARENTHESIS_OPEN); + in.ReadVec(strength); + in.Skip(Token::COMMA); + in.ReadVec(extent.min); + in.Skip(Token::COMMA); + in.ReadVec(extent.max); + in.Skip(Token::PARENTHESIS_CLOSE); + extent.Adjust(); + return std::unique_ptr(new CuboidFieldGravity(strength, extent)); + } else { + throw std::runtime_error("unknown gravity type: " + type); + } +} + const glm::mat4 Block::orient2transform[ORIENT_COUNT] = { { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: up, turn: none