]> git.localhorst.tv Git - blank.git/blob - src/model/model.cpp
load models from assets
[blank.git] / src / model / model.cpp
1 #include "Model.hpp"
2 #include "ModelRegistry.hpp"
3 #include "Instance.hpp"
4 #include "Part.hpp"
5
6 #include "Shape.hpp"
7 #include "ShapeRegistry.hpp"
8 #include "../app/TextureIndex.hpp"
9 #include "../io/TokenStreamReader.hpp"
10 #include "../graphics/DirectionalLighting.hpp"
11 #include "../graphics/EntityMesh.hpp"
12
13 #include <iostream>
14 #include <glm/gtx/quaternion.hpp>
15 #include <glm/gtx/io.hpp>
16
17
18 namespace blank {
19
20 Instance::Instance()
21 : model(nullptr)
22 , state() {
23
24 }
25
26 Instance::~Instance() {
27
28 }
29
30 void Instance::Render(const glm::mat4 &M, DirectionalLighting &prog) {
31         model->RootPart().Render(M, *this, prog);
32 }
33
34
35 Model::Model()
36 : id(0)
37 , root()
38 , part() {
39
40 }
41
42 void Model::Enumerate() {
43         part.clear();
44         part.resize(root.Enumerate(0), nullptr);
45         root.Index(part);
46 }
47
48 void Model::Instantiate(Instance &inst) const {
49         inst.model = this;
50         inst.state.clear();
51         inst.state.resize(part.size());
52 }
53
54
55 ModelRegistry::ModelRegistry()
56 : models()
57 , name_index() {
58
59 }
60
61 Model &ModelRegistry::Add(const std::string &name) {
62         models.emplace_back(new Model());
63         models.back()->ID(models.size());
64         name_index[name] = &*models.back();
65         return *models.back();
66 }
67
68 Model &ModelRegistry::Get(const std::string &name) {
69         auto entry = name_index.find(name);
70         if (entry != name_index.end()) {
71                 return *entry->second;
72         } else {
73                 throw std::runtime_error("unknown model " + name);
74         }
75 }
76
77 const Model &ModelRegistry::Get(const std::string &name) const {
78         auto entry = name_index.find(name);
79         if (entry != name_index.end()) {
80                 return *entry->second;
81         } else {
82                 throw std::runtime_error("unknown model " + name);
83         }
84 }
85
86
87 Part::Part()
88 : parent(nullptr)
89 , shape(nullptr)
90 , children()
91 , tex_map()
92 , mesh()
93 , initial()
94 , hsl_mod(0.0f, 1.0f, 1.0f)
95 , rgb_mod(1.0f, 1.0f, 1.0f)
96 , id(0) {
97
98 }
99
100 Part::~Part() {
101
102 }
103
104 void Part::Read(TokenStreamReader &in, TextureIndex &tex_index, const ShapeRegistry &shapes) {
105         std::string name;
106         std::string shape_name;
107         std::string tex_name;
108         in.Skip(Token::ANGLE_BRACKET_OPEN);
109         while (in.HasMore() && in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
110                 in.ReadIdentifier(name);
111                 in.Skip(Token::EQUALS);
112                 if (name == "shape") {
113                         in.ReadIdentifier(shape_name);
114                         shape = &shapes.Get(shape_name);
115                 } else if (name == "position") {
116                         in.ReadVec(initial.position);
117                 } else if (name == "orientation") {
118                         in.ReadQuat(initial.orientation);
119                 } else if (name == "hsl_mod") {
120                         in.ReadVec(hsl_mod);
121                 } else if (name == "rgb_mod") {
122                         in.ReadVec(rgb_mod);
123                 } else if (name == "textures") {
124                         in.Skip(Token::BRACKET_OPEN);
125                         while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
126                                 in.ReadString(tex_name);
127                                 tex_map.push_back(tex_index.GetID(tex_name));
128                                 if (in.Peek().type == Token::COMMA) {
129                                         in.Skip(Token::COMMA);
130                                 }
131                         }
132                         in.Skip(Token::BRACKET_CLOSE);
133                 } else if (name == "children") {
134                         in.Skip(Token::BRACKET_OPEN);
135                         while (in.HasMore() && in.Peek().type != Token::BRACKET_CLOSE) {
136                                 Part &child = AddChild();
137                                 child.Read(in, tex_index, shapes);
138                                 if (in.Peek().type == Token::COMMA) {
139                                         in.Skip(Token::COMMA);
140                                 }
141                         }
142                         in.Skip(Token::BRACKET_CLOSE);
143                 } else {
144                         while (in.HasMore() && in.Peek().type != Token::SEMICOLON) {
145                                 in.Next();
146                         }
147                 }
148                 in.Skip(Token::SEMICOLON);
149         }
150         in.Skip(Token::ANGLE_BRACKET_CLOSE);
151 }
152
153 Part &Part::AddChild() {
154         children.emplace_back();
155         children.back().parent = this;
156         return children.back();
157 }
158
159 std::uint16_t Part::Enumerate(std::uint16_t counter) noexcept {
160         id = counter++;
161         for (Part &part : children) {
162                 counter = part.Enumerate(counter);
163         }
164         return counter;
165 }
166
167 void Part::Index(std::vector<Part *> &index) noexcept {
168         index[id] = this;
169         for (Part &part : children) {
170                 part.Index(index);
171         }
172 }
173
174 glm::mat4 Part::LocalTransform(const Instance &inst) const noexcept {
175         glm::mat4 transform(toMat4(initial.orientation * inst.state[id].orientation));
176         transform[3] = glm::vec4(initial.position + inst.state[id].position, 1.0f);
177         return transform;
178 }
179
180 glm::mat4 Part::GlobalTransform(const Instance &inst) const noexcept {
181         if (parent) {
182                 return parent->GlobalTransform(inst) * LocalTransform(inst);
183         } else {
184                 return LocalTransform(inst);
185         }
186 }
187
188 namespace {
189
190 EntityMesh::Buffer buf;
191
192 }
193
194 void Part::Render(
195         const glm::mat4 &M,
196         const Instance &inst,
197         DirectionalLighting &prog
198 ) const {
199         glm::mat4 transform = M * LocalTransform(inst);
200         if (shape && shape->IndexCount() > 0) {
201                 if (!mesh) {
202                         buf.Clear();
203                         buf.hsl_mods.resize(shape->VertexCount(), hsl_mod);
204                         buf.rgb_mods.resize(shape->VertexCount(), rgb_mod);
205                         shape->Fill(buf, tex_map);
206                         mesh.reset(new EntityMesh());
207                         mesh->Update(buf);
208                 }
209                 prog.SetM(transform);
210                 mesh->Draw();
211         }
212         for (const Part &part : children) {
213                 part.Render(transform, inst, prog);
214         }
215 }
216
217 }