]> git.localhorst.tv Git - blank.git/commitdiff
load models from assets
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 15 Oct 2015 12:02:36 +0000 (14:02 +0200)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 15 Oct 2015 13:22:22 +0000 (15:22 +0200)
17 files changed:
assets
src/ai/Spawner.cpp
src/ai/Spawner.hpp
src/app/Assets.hpp
src/app/app.cpp
src/client/InteractiveState.hpp
src/client/client.cpp
src/model/Instance.hpp
src/model/ModelRegistry.hpp [new file with mode: 0644]
src/model/Part.hpp
src/model/Skeletons.hpp [deleted file]
src/model/model.cpp
src/model/shape.cpp
src/server/ServerState.cpp
src/server/ServerState.hpp
src/standalone/MasterState.cpp
src/standalone/MasterState.hpp

diff --git a/assets b/assets
index 82ab37629683a73061240c2d7da64f0a612fde42..2e992fd6861d4c45c5938bd519600aeb8b8be386 160000 (submodule)
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 82ab37629683a73061240c2d7da64f0a612fde42
+Subproject commit 2e992fd6861d4c45c5938bd519600aeb8b8be386
index 064857cd6b51e9c53df88b1957d3a612bd9af9d3..a4b40309cca613c0a387d3ed605f9e0c3b3df826 100644 (file)
@@ -2,9 +2,8 @@
 
 #include "Chaser.hpp"
 #include "RandomWalk.hpp"
-#include "../app/TextureIndex.hpp"
 #include "../model/Model.hpp"
-#include "../model/Skeletons.hpp"
+#include "../model/ModelRegistry.hpp"
 #include "../rand/GaloisLFSR.hpp"
 #include "../world/BlockLookup.hpp"
 #include "../world/BlockType.hpp"
@@ -19,9 +18,9 @@ using namespace std;
 
 namespace blank {
 
-Spawner::Spawner(World &world, Skeletons &skeletons, GaloisLFSR &rand)
+Spawner::Spawner(World &world, ModelRegistry &models, GaloisLFSR &rand)
 : world(world)
-, skeletons(skeletons)
+, models(models)
 , controllers()
 , random(rand)
 , timer(64)
@@ -29,9 +28,8 @@ Spawner::Spawner(World &world, Skeletons &skeletons, GaloisLFSR &rand)
 , spawn_distance(16 * 16)
 , max_entities(16)
 , chunk_range(4)
-, skeletons_offset(0)
-, skeletons_length(skeletons.size())
-, tex_map() {
+, model_offset(0)
+, model_length(models.size()) {
        timer.Start();
 }
 
@@ -42,21 +40,15 @@ Spawner::~Spawner() {
 }
 
 
-void Spawner::LimitSkeletons(size_t begin, size_t end) {
-       if (begin >= skeletons.size() || end > skeletons.size() || begin >= end) {
-               cout << "warning, skeleton limit out of bounds or invalid range given" << endl;
+void Spawner::LimitModels(size_t begin, size_t end) {
+       if (begin >= models.size() || end > models.size() || begin >= end) {
+               cout << "warning, models limit out of bounds or invalid range given" << endl;
        } else {
-               skeletons_offset = begin;
-               skeletons_length = end - begin;
+               model_offset = begin;
+               model_length = end - begin;
        }
 }
 
-void Spawner::LoadTextures(TextureIndex &tex_index) {
-       tex_map.clear();
-       tex_map.push_back(tex_index.GetID("rock-1"));
-       tex_map.push_back(tex_index.GetID("rock-face"));
-}
-
 void Spawner::Update(int dt) {
        CheckDespawn();
        timer.Update(dt);
@@ -99,7 +91,7 @@ void Spawner::CheckDespawn() noexcept {
 }
 
 void Spawner::TrySpawn() {
-       if (controllers.size() >= max_entities || skeletons_length == 0) return;
+       if (controllers.size() >= max_entities || model_length == 0) return;
 
        // select random player to punish
        auto &players = world.Players();
@@ -142,8 +134,7 @@ void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3
        e.Position(chunk, pos);
        e.Bounds({ { -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f } });
        e.WorldCollidable(true);
-       RandomSkeleton().Instantiate(e.GetModel());
-       e.GetModel().SetTextures(tex_map);
+       RandomModel().Instantiate(e.GetModel());
        e.AngularVelocity(rot);
        Controller *ctrl;
        if (random()) {
@@ -156,9 +147,9 @@ void Spawner::Spawn(Entity &reference, const glm::ivec3 &chunk, const glm::vec3
        controllers.emplace_back(ctrl);
 }
 
-Model &Spawner::RandomSkeleton() noexcept {
-       std::size_t offset = (random.Next<std::size_t>() % skeletons_length) + skeletons_offset;
-       return skeletons[offset];
+Model &Spawner::RandomModel() noexcept {
+       std::size_t offset = (random.Next<std::size_t>() % model_length) + model_offset;
+       return models[offset];
 }
 
 }
index 6591ef93d3a519648203526276608f437e0cd6ee..be2ff31b7307e99f484c5b183c788e329d260e82 100644 (file)
@@ -13,18 +13,16 @@ class Controller;
 class Entity;
 class GaloisLFSR;
 class Model;
-class Skeletons;
-class TextureIndex;
+class ModelRegistry;
 class World;
 
 class Spawner {
 
 public:
-       Spawner(World &, Skeletons &, GaloisLFSR &);
+       Spawner(World &, ModelRegistry &, GaloisLFSR &);
        ~Spawner();
 
-       void LimitSkeletons(std::size_t begin, std::size_t end);
-       void LoadTextures(TextureIndex &);
+       void LimitModels(std::size_t begin, std::size_t end);
 
        void Update(int dt);
 
@@ -33,11 +31,11 @@ private:
        void TrySpawn();
        void Spawn(Entity &reference, const glm::ivec3 &, const glm::vec3 &);
 
-       Model &RandomSkeleton() noexcept;
+       Model &RandomModel() noexcept;
 
 private:
        World &world;
-       Skeletons &skeletons;
+       ModelRegistry &models;
        std::vector<Controller *> controllers;
 
        GaloisLFSR &random;
@@ -48,10 +46,8 @@ private:
        unsigned int max_entities;
        int chunk_range;
 
-       std::size_t skeletons_offset;
-       std::size_t skeletons_length;
-
-       std::vector<float> tex_map;
+       std::size_t model_offset;
+       std::size_t model_length;
 
 };
 
index 941fa1ba51966f9b45617adf44dabe9437707a84..64bc72ce81f1239ab884b739989f701e9604ffe8 100644 (file)
@@ -11,6 +11,7 @@ namespace blank {
 class ArrayTexture;
 class BlockTypeRegistry;
 class CubeMap;
+class ModelRegistry;
 class ShapeRegistry;
 class Sound;
 class Texture;
@@ -28,6 +29,11 @@ public:
                const ShapeRegistry &) const;
        CubeMap LoadCubeMap(const std::string &name) const;
        Font LoadFont(const std::string &name, int size) const;
+       void LoadModels(
+               const std::string &set_name,
+               ModelRegistry &,
+               TextureIndex &,
+               const ShapeRegistry &) const;
        void LoadShapes(const std::string &set_name, ShapeRegistry &) const;
        Sound LoadSound(const std::string &name) const;
        Texture LoadTexture(const std::string &name) const;
index 367f3c21bc2e0bc175d2554d1d428616b7ac6fc1..7f5f02f0d5e1c557675c56dbdad3b7a1ac970189 100644 (file)
@@ -14,6 +14,8 @@
 #include "../graphics/Texture.hpp"
 #include "../io/TokenStreamReader.hpp"
 #include "../model/bounds.hpp"
+#include "../model/Model.hpp"
+#include "../model/ModelRegistry.hpp"
 #include "../model/Shape.hpp"
 #include "../model/ShapeRegistry.hpp"
 #include "../world/BlockType.hpp"
@@ -494,6 +496,43 @@ Font AssetLoader::LoadFont(const string &name, int size) const {
        return Font(full.c_str(), size);
 }
 
+void AssetLoader::LoadModels(
+       const string &set_name,
+       ModelRegistry &models,
+       TextureIndex &tex_index,
+       const ShapeRegistry &shapes
+) const {
+       string full = data + set_name + ".models";
+       std::ifstream file(full);
+       if (!file) {
+               throw std::runtime_error("failed to open model file " + full);
+       }
+       TokenStreamReader in(file);
+       string model_name;
+       string prop_name;
+       while (in.HasMore()) {
+               in.ReadIdentifier(model_name);
+               in.Skip(Token::EQUALS);
+               in.Skip(Token::ANGLE_BRACKET_OPEN);
+               Model &model = models.Add(model_name);
+               while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
+                       in.ReadIdentifier(prop_name);
+                       in.Skip(Token::EQUALS);
+                       if (prop_name == "root") {
+                               model.RootPart().Read(in, tex_index, shapes);
+                       } else {
+                               while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
+                                       in.Next();
+                               }
+                       }
+                       in.Skip(Token::SEMICOLON);
+               }
+               model.Enumerate();
+               in.Skip(Token::ANGLE_BRACKET_CLOSE);
+               in.Skip(Token::SEMICOLON);
+       }
+}
+
 void AssetLoader::LoadShapes(const string &set_name, ShapeRegistry &shapes) const {
        string full = data + set_name + ".shapes";
        std::ifstream file(full);
index 731ed0acd82d688e3e76181b129c679a080e03f4..2bc459a330a875e9fb748a9e0a10fda43f61c020 100644 (file)
@@ -9,8 +9,8 @@
 #include "../app/IntervalTimer.hpp"
 #include "../graphics/SkyBox.hpp"
 #include "../io/WorldSave.hpp"
+#include "../model/ModelRegistry.hpp"
 #include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
 #include "../net/Packet.hpp"
 #include "../ui/HUD.hpp"
 #include "../ui/InteractiveManipulator.hpp"
@@ -40,7 +40,7 @@ public:
        World &GetWorld() noexcept { return world; }
        Player &GetPlayer() noexcept { return player; }
        ChunkReceiver &GetChunkReceiver() noexcept { return chunk_receiver; }
-       Skeletons &GetSkeletons() noexcept { return skeletons; }
+       ModelRegistry &GetModels() noexcept { return models; }
 
        void OnEnter() override;
 
@@ -71,6 +71,7 @@ private:
        MasterState &master;
        ShapeRegistry shapes;
        BlockTypeRegistry block_types;
+       ModelRegistry models;
        WorldSave save;
        World world;
        Player &player;
@@ -80,13 +81,10 @@ private:
        Interface interface;
        ChunkReceiver chunk_receiver;
        ChunkRenderer chunk_renderer;
-       Skeletons skeletons;
        IntervalTimer loop_timer;
 
        SkyBox sky;
 
-       std::vector<float> tex_map;
-
        struct UpdateStatus {
                std::uint16_t last_packet;
                int last_update;
index 2618d98f3b0e0d1e1c0810c7b2f6db8bbb7964a1..cc3106f8e34a08be63d49f9ce789d83480da3f74 100644 (file)
@@ -50,6 +50,7 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id)
 : master(master)
 , shapes()
 , block_types()
+, models()
 , save(master.GetEnv().config.GetWorldPath(master.GetWorldConf().name, master.GetConfig().net.host))
 , world(block_types, master.GetWorldConf())
 , player(*world.AddPlayer(master.GetConfig().player.name))
@@ -59,10 +60,8 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id)
 , interface(master.GetConfig(), master.GetEnv().keymap, input, *this)
 , chunk_receiver(world.Chunks(), save)
 , chunk_renderer(player.GetChunks())
-, skeletons()
 , loop_timer(16)
 , sky(master.GetEnv().loader.LoadCubeMap("skybox"))
-, tex_map()
 , update_status() {
        if (!save.Exists()) {
                save.Write(master.GetWorldConf());
@@ -70,9 +69,7 @@ InteractiveState::InteractiveState(MasterState &master, uint32_t player_id)
        TextureIndex tex_index;
        master.GetEnv().loader.LoadShapes("default", shapes);
        master.GetEnv().loader.LoadBlockTypes("default", block_types, tex_index, shapes);
-       skeletons.Load(shapes);
-       tex_map.push_back(tex_index.GetID("rock-1"));
-       tex_map.push_back(tex_index.GetID("rock-face"));
+       master.GetEnv().loader.LoadModels("default", models, tex_index, shapes);
        interface.SetInventorySlots(block_types.size() - 1);
        chunk_renderer.LoadTextures(master.GetEnv().loader, tex_index);
        chunk_renderer.FogDensity(master.GetWorldConf().fog_density);
@@ -167,10 +164,9 @@ void InteractiveState::Handle(const Packet::SpawnEntity &pack) {
        pack.ReadEntity(entity);
        uint32_t skel_id;
        pack.ReadSkeletonID(skel_id);
-       Model *skel = skeletons.ByID(skel_id);
-       if (skel) {
-               skel->Instantiate(entity.GetModel());
-               entity.GetModel().SetTextures(tex_map);
+       if (skel_id > 0 && skel_id <= models.size()) {
+               Model &skel = models.Get(skel_id);
+               skel.Instantiate(entity.GetModel());
        }
        cout << "spawned entity #" << entity_id << "  (" << entity.Name()
                << ") at " << entity.AbsolutePosition() << endl;
index 60c0212793e132934cf2e2c808c05835ec6868a0..8b94bcd8c20ac0fc6a53de887201ecd5fa5b2748 100644 (file)
@@ -3,7 +3,6 @@
 
 #include "Part.hpp"
 
-#include <memory>
 #include <vector>
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
@@ -12,7 +11,6 @@
 namespace blank {
 
 class DirectionalLighting;
-class EntityMesh;
 class Model;
 class Part;
 
@@ -25,26 +23,14 @@ public:
        Instance();
        ~Instance();
 
-       Instance(const Instance &);
-       Instance &operator =(const Instance &);
-
        operator bool() const noexcept { return model; }
        const Model &GetModel() const noexcept { return *model; }
 
        void Render(const glm::mat4 &, DirectionalLighting &);
 
-       void SetTextures(const std::vector<float> &t);
-       void SetHSLModifier(const glm::vec3 &m);
-       void SetRGBModifier(const glm::vec3 &m);
-
 private:
        const Model *model;
        std::vector<Part::State> state;
-       std::vector<std::unique_ptr<EntityMesh>> mesh;
-
-       std::vector<float> tex_map;
-       glm::vec3 hsl_mod;
-       glm::vec3 rgb_mod;
 
 };
 
diff --git a/src/model/ModelRegistry.hpp b/src/model/ModelRegistry.hpp
new file mode 100644 (file)
index 0000000..b3ab1ee
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef BLANK_MODEL_MODELREGISTRY_HPP_
+#define BLANK_MODEL_MODELREGISTRY_HPP_
+
+#include "Model.hpp"
+
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+
+namespace blank {
+
+class ModelRegistry {
+
+public:
+       using size_type = std::size_t;
+       using reference = Model &;
+       using const_reference = const Model &;
+
+public:
+       ModelRegistry();
+
+       reference Add(const std::string &);
+
+       size_type size() const noexcept { return models.size(); }
+
+       // by offset
+       reference operator[](size_type i) noexcept { return *models[i]; }
+       const_reference operator[](size_type i) const noexcept { return *models[i]; }
+       // by ID
+       reference Get(std::uint16_t i) { return *models[i - 1]; }
+       const_reference Get(std::uint16_t i) const { return *models[i - 1]; }
+       // by name
+       reference Get(const std::string &);
+       const_reference Get(const std::string &) const;
+
+private:
+       std::vector<std::unique_ptr<Model>> models;
+       std::map<std::string, Model *> name_index;
+
+};
+
+}
+
+#endif
index f3d78e26f610e8c124d1047a89ddf26a4646b422..f71efc5425a1580a992ba1b857e38e8ef9797a44 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <cstdint>
 #include <list>
+#include <memory>
 #include <vector>
 #include <glm/glm.hpp>
 #include <glm/gtc/quaternion.hpp>
 namespace blank {
 
 class DirectionalLighting;
+class EntityMesh;
 class Instance;
 class Model;
 class Shape;
+class ShapeRegistry;
+class TextureIndex;
+class TokenStreamReader;
 
 struct Part {
 
-       std::uint16_t id;
-       AABB bounds;
+public:
        struct State {
                glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f);
                glm::quat orientation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
-       } initial;
-       const Shape *shape;
+       };
 
        Part();
        ~Part();
 
+       void Read(TokenStreamReader &, TextureIndex &, const ShapeRegistry &);
+
        Part &AddChild();
        const std::list<Part> &Children() const noexcept { return children; }
 
@@ -39,7 +44,6 @@ struct Part {
        glm::mat4 LocalTransform(const Instance &) const noexcept;
        glm::mat4 GlobalTransform(const Instance &) const noexcept;
 
-       void LoadMeshes(Instance &) const;
        void Render(
                const glm::mat4 &,
                const Instance &,
@@ -47,7 +51,14 @@ struct Part {
 
 private:
        const Part *parent;
+       const Shape *shape;
        std::list<Part> children;
+       std::vector<float> tex_map;
+       mutable std::unique_ptr<EntityMesh> mesh;
+       State initial;
+       glm::vec3 hsl_mod;
+       glm::vec3 rgb_mod;
+       std::uint16_t id;
 
 };
 
diff --git a/src/model/Skeletons.hpp b/src/model/Skeletons.hpp
deleted file mode 100644 (file)
index 3c7c886..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef BLANK_MODEL_SKELETONS_HPP_
-#define BLANK_MODEL_SKELETONS_HPP_
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-
-namespace blank {
-
-class Model;
-class ShapeRegistry;
-
-class Skeletons {
-
-public:
-       using size_type = std::size_t;
-       using reference = Model &;
-       using const_reference = const Model &;
-
-public:
-       Skeletons();
-       ~Skeletons();
-
-       void Load(const ShapeRegistry &);
-
-       size_type size() const noexcept { return skeletons.size(); }
-
-       reference operator[](size_type i) noexcept { return *skeletons[i]; }
-       const_reference operator[](size_type i) const noexcept { return *skeletons[i]; }
-
-       Model *ByID(std::uint16_t) noexcept;
-       const Model *ByID(std::uint16_t) const noexcept;
-
-private:
-       std::vector<std::unique_ptr<Model>> skeletons;
-
-};
-
-}
-
-#endif
index 730a34a330c4bd08c1336e2750039781f064c8ac..63187b863033569af1da8f1e446ac3ec54607d69 100644 (file)
@@ -1,10 +1,12 @@
 #include "Model.hpp"
+#include "ModelRegistry.hpp"
 #include "Instance.hpp"
-#include "Skeletons.hpp"
+#include "Part.hpp"
 
 #include "Shape.hpp"
 #include "ShapeRegistry.hpp"
 #include "../app/TextureIndex.hpp"
+#include "../io/TokenStreamReader.hpp"
 #include "../graphics/DirectionalLighting.hpp"
 #include "../graphics/EntityMesh.hpp"
 
@@ -17,11 +19,7 @@ namespace blank {
 
 Instance::Instance()
 : model(nullptr)
-, state()
-, mesh()
-, tex_map()
-, hsl_mod(0.0f, 1.0f, 1.0f)
-, rgb_mod(1.0f) {
+, state() {
 
 }
 
@@ -29,50 +27,10 @@ Instance::~Instance() {
 
 }
 
-Instance::Instance(const Instance &other)
-: model(other.model)
-, state(other.state)
-, mesh()
-, tex_map(other.tex_map)
-, hsl_mod(other.hsl_mod)
-, rgb_mod(other.rgb_mod) {
-
-}
-
-Instance &Instance::operator =(const Instance &other) {
-       model = other.model;
-       state = other.state;
-       mesh.clear();
-       tex_map = other.tex_map;
-       hsl_mod = other.hsl_mod;
-       rgb_mod = other.rgb_mod;
-       return *this;
-}
-
 void Instance::Render(const glm::mat4 &M, DirectionalLighting &prog) {
-       if (mesh.empty()) {
-               std::cout << "building meshes for instance" << std::endl;
-               mesh.resize(state.size());
-               model->RootPart().LoadMeshes(*this);
-       }
        model->RootPart().Render(M, *this, prog);
 }
 
-void Instance::SetTextures(const std::vector<float> &t) {
-       tex_map = t;
-       mesh.clear();
-}
-
-void Instance::SetHSLModifier(const glm::vec3 &m) {
-       hsl_mod = m;
-       mesh.clear();
-}
-
-void Instance::SetRGBModifier(const glm::vec3 &m) {
-       rgb_mod = m;
-       mesh.clear();
-}
-
 
 Model::Model()
 : id(0)
@@ -90,18 +48,52 @@ void Model::Enumerate() {
 void Model::Instantiate(Instance &inst) const {
        inst.model = this;
        inst.state.clear();
-       inst.mesh.clear();
        inst.state.resize(part.size());
 }
 
 
+ModelRegistry::ModelRegistry()
+: models()
+, name_index() {
+
+}
+
+Model &ModelRegistry::Add(const std::string &name) {
+       models.emplace_back(new Model());
+       models.back()->ID(models.size());
+       name_index[name] = &*models.back();
+       return *models.back();
+}
+
+Model &ModelRegistry::Get(const std::string &name) {
+       auto entry = name_index.find(name);
+       if (entry != name_index.end()) {
+               return *entry->second;
+       } else {
+               throw std::runtime_error("unknown model " + name);
+       }
+}
+
+const Model &ModelRegistry::Get(const std::string &name) const {
+       auto entry = name_index.find(name);
+       if (entry != name_index.end()) {
+               return *entry->second;
+       } else {
+               throw std::runtime_error("unknown model " + name);
+       }
+}
+
+
 Part::Part()
-: id(0)
-, bounds{ glm::vec3(0.0f), glm::vec3(0.0f) }
-, initial()
+: parent(nullptr)
 , shape(nullptr)
-, parent(nullptr)
-, children() {
+, children()
+, tex_map()
+, mesh()
+, initial()
+, hsl_mod(0.0f, 1.0f, 1.0f)
+, rgb_mod(1.0f, 1.0f, 1.0f)
+, id(0) {
 
 }
 
@@ -109,6 +101,55 @@ Part::~Part() {
 
 }
 
+void Part::Read(TokenStreamReader &in, TextureIndex &tex_index, const ShapeRegistry &shapes) {
+       std::string name;
+       std::string shape_name;
+       std::string tex_name;
+       in.Skip(Token::ANGLE_BRACKET_OPEN);
+       while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
+               in.ReadIdentifier(name);
+               in.Skip(Token::EQUALS);
+               if (name == "shape") {
+                       in.ReadIdentifier(shape_name);
+                       shape = &shapes.Get(shape_name);
+               } else if (name == "position") {
+                       in.ReadVec(initial.position);
+               } else if (name == "orientation") {
+                       in.ReadQuat(initial.orientation);
+               } else if (name == "hsl_mod") {
+                       in.ReadVec(hsl_mod);
+               } else if (name == "rgb_mod") {
+                       in.ReadVec(rgb_mod);
+               } else if (name == "textures") {
+                       in.Skip(Token::BRACKET_OPEN);
+                       while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
+                               in.ReadString(tex_name);
+                               tex_map.push_back(tex_index.GetID(tex_name));
+                               if (in.Peek().type == Token::COMMA) {
+                                       in.Skip(Token::COMMA);
+                               }
+                       }
+                       in.Skip(Token::BRACKET_CLOSE);
+               } else if (name == "children") {
+                       in.Skip(Token::BRACKET_OPEN);
+                       while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
+                               Part &child = AddChild();
+                               child.Read(in, tex_index, shapes);
+                               if (in.Peek().type == Token::COMMA) {
+                                       in.Skip(Token::COMMA);
+                               }
+                       }
+                       in.Skip(Token::BRACKET_CLOSE);
+               } else {
+                       while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
+                               in.Next();
+                       }
+               }
+               in.Skip(Token::SEMICOLON);
+       }
+       in.Skip(Token::ANGLE_BRACKET_CLOSE);
+}
+
 Part &Part::AddChild() {
        children.emplace_back();
        children.back().parent = this;
@@ -150,96 +191,27 @@ EntityMesh::Buffer buf;
 
 }
 
-void Part::LoadMeshes(Instance &inst) const {
-       if (shape && shape->IndexCount() > 0) {
-               buf.Clear();
-               buf.hsl_mods.resize(shape->VertexCount(), inst.hsl_mod);
-               buf.rgb_mods.resize(shape->VertexCount(), inst.rgb_mod);
-               shape->Fill(buf, inst.tex_map);
-               inst.mesh[id].reset(new EntityMesh());
-               inst.mesh[id]->Update(buf);
-       } else {
-               inst.mesh[id].reset();
-       }
-       for (const Part &part : children) {
-               part.LoadMeshes(inst);
-       }
-}
-
 void Part::Render(
        const glm::mat4 &M,
        const Instance &inst,
        DirectionalLighting &prog
 ) const {
        glm::mat4 transform = M * LocalTransform(inst);
-       if (inst.mesh[id]) {
+       if (shape && shape->IndexCount() > 0) {
+               if (!mesh) {
+                       buf.Clear();
+                       buf.hsl_mods.resize(shape->VertexCount(), hsl_mod);
+                       buf.rgb_mods.resize(shape->VertexCount(), rgb_mod);
+                       shape->Fill(buf, tex_map);
+                       mesh.reset(new EntityMesh());
+                       mesh->Update(buf);
+               }
                prog.SetM(transform);
-               inst.mesh[id]->Draw();
+               mesh->Draw();
        }
        for (const Part &part : children) {
                part.Render(transform, inst, prog);
        }
 }
 
-
-Skeletons::Skeletons()
-: skeletons() {
-
-}
-
-Skeletons::~Skeletons() {
-
-}
-
-void Skeletons::Load(const ShapeRegistry &shapes) {
-       skeletons.clear();
-       skeletons.reserve(4);
-       AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
-       const Shape *shape = &shapes.Get("player_head_block");
-       {
-               skeletons.emplace_back(new Model);
-               skeletons[0]->ID(1);
-               skeletons[0]->RootPart().bounds = bounds;
-               skeletons[0]->RootPart().shape = shape;
-               skeletons[0]->Enumerate();
-       }
-       {
-               skeletons.emplace_back(new Model);
-               skeletons[1]->ID(2);
-               skeletons[1]->RootPart().bounds = bounds;
-               skeletons[1]->RootPart().shape = shape;
-               skeletons[1]->Enumerate();
-       }
-       {
-               skeletons.emplace_back(new Model);
-               skeletons[2]->ID(3);
-               skeletons[2]->RootPart().bounds = bounds;
-               skeletons[2]->RootPart().shape = shape;
-               skeletons[2]->Enumerate();
-       }
-       {
-               skeletons.emplace_back(new Model);
-               skeletons[3]->ID(4);
-               skeletons[3]->RootPart().bounds = bounds;
-               skeletons[3]->RootPart().shape = shape;
-               skeletons[3]->Enumerate();
-       }
-}
-
-Model *Skeletons::ByID(std::uint16_t id) noexcept {
-       if (id == 0 || id > skeletons.size()) {
-               return nullptr;
-       } else {
-               return skeletons[id - 1].get();
-       }
-}
-
-const Model *Skeletons::ByID(std::uint16_t id) const noexcept {
-       if (id == 0 || id > skeletons.size()) {
-               return nullptr;
-       } else {
-               return skeletons[id - 1].get();
-       }
-}
-
 }
index 66eb25e99550d9a425701236eaa19cef264b1975..4943e6377c3525d0c21b0144f7a3384f74dd8f76 100644 (file)
@@ -108,7 +108,7 @@ void Shape::Read(TokenStreamReader &in) {
 
                } else {
                        // try to skip, might fail though
-                       while (in.Peek().type != Token::SEMICOLON) {
+                       while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
                                in.Next();
                        }
                }
index 98861bfacd17f5c723f7e0ee664218b96e4057f8..3e2869fc56b1da8afec9c2faccaf71c9eed97593 100644 (file)
@@ -21,21 +21,23 @@ ServerState::ServerState(
 : env(env)
 , shapes()
 , block_types()
+, models()
 , world(block_types, wc)
 , generator(gc)
 , chunk_loader(world.Chunks(), generator, ws)
-, skeletons()
-, spawner(world, skeletons, env.rng)
+, spawner(world, models, env.rng)
 , server(config.net, world, wc, ws)
 , loop_timer(16) {
        TextureIndex tex_index;
        env.loader.LoadShapes("default", shapes);
        env.loader.LoadBlockTypes("default", block_types, tex_index, shapes);
+       env.loader.LoadModels("default", models, tex_index, shapes);
+       if (models.size() < 2) {
+               throw std::runtime_error("need at least two models to run");
+       }
        generator.LoadTypes(block_types);
-       skeletons.Load(shapes);
-       spawner.LimitSkeletons(1, skeletons.size());
-       spawner.LoadTextures(tex_index);
-       server.SetPlayerModel(skeletons[0]);
+       spawner.LimitModels(1, models.size());
+       server.SetPlayerModel(models[0]);
 
        loop_timer.Start();
 
index bfefccf397f0ae0be42a5ac6213bbd01b2d33eb1..b62cf0904224f767730bf6cd33f5156c1d7e50f8 100644 (file)
@@ -5,8 +5,8 @@
 #include "../ai/Spawner.hpp"
 #include "../app/IntervalTimer.hpp"
 #include "../app/State.hpp"
+#include "../model/ModelRegistry.hpp"
 #include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
 #include "../world/BlockTypeRegistry.hpp"
 #include "../world/ChunkLoader.hpp"
 #include "../world/Generator.hpp"
@@ -42,10 +42,10 @@ private:
        HeadlessEnvironment &env;
        ShapeRegistry shapes;
        BlockTypeRegistry block_types;
+       ModelRegistry models;
        World world;
        Generator generator;
        ChunkLoader chunk_loader;
-       Skeletons skeletons;
        Spawner spawner;
        Server server;
        IntervalTimer loop_timer;
index 81994142cb8981c548550a8e9e588f2ba67668fa..9d95966953590d7b5ab146f36cb4439b64f68505 100644 (file)
@@ -23,6 +23,7 @@ MasterState::MasterState(
 , env(env)
 , shapes()
 , block_types()
+, models()
 , save(save)
 , world(block_types, wc)
 , spawn_index(world.Chunks().MakeIndex(wc.spawn, 3))
@@ -35,17 +36,18 @@ MasterState::MasterState(
 , generator(gc)
 , chunk_loader(world.Chunks(), generator, save)
 , chunk_renderer(player.GetChunks())
-, skeletons()
-, spawner(world, skeletons, env.rng)
+, spawner(world, models, env.rng)
 , sky(env.loader.LoadCubeMap("skybox"))
 , preload(env, chunk_loader, chunk_renderer)
 , unload(env, world.Chunks(), save) {
        TextureIndex tex_index;
        env.loader.LoadShapes("default", shapes);
        env.loader.LoadBlockTypes("default", block_types, tex_index, shapes);
-       skeletons.Load(shapes);
-       spawner.LimitSkeletons(0, skeletons.size());
-       spawner.LoadTextures(tex_index);
+       env.loader.LoadModels("default", models, tex_index, shapes);
+       if (models.size() < 2) {
+               throw std::runtime_error("need at least two models to run");
+       }
+       spawner.LimitModels(0, models.size());
        interface.SetInventorySlots(block_types.size() - 1);
        generator.LoadTypes(block_types);
        chunk_renderer.LoadTextures(env.loader, tex_index);
index 680bb5e620cbaa15a9a3f6414f02ecf0c767263c..f72c38ceed7b73f83059b3e1249c4da46f4c42f9 100644 (file)
@@ -8,8 +8,8 @@
 #include "UnloadState.hpp"
 #include "../ai/Spawner.hpp"
 #include "../graphics/SkyBox.hpp"
+#include "../model/ModelRegistry.hpp"
 #include "../model/ShapeRegistry.hpp"
-#include "../model/Skeletons.hpp"
 #include "../ui/DirectInput.hpp"
 #include "../ui/HUD.hpp"
 #include "../ui/InteractiveManipulator.hpp"
@@ -65,6 +65,7 @@ private:
        Environment &env;
        ShapeRegistry shapes;
        BlockTypeRegistry block_types;
+       ModelRegistry models;
        const WorldSave &save;
        World world;
        ChunkIndex &spawn_index;
@@ -77,7 +78,6 @@ private:
        Generator generator;
        ChunkLoader chunk_loader;
        ChunkRenderer chunk_renderer;
-       Skeletons skeletons;
        Spawner spawner;
 
        SkyBox sky;