]> git.localhorst.tv Git - blank.git/blob - src/model/model.cpp
store shapes in models rather than meshes
[blank.git] / src / model / model.cpp
1 #include "Model.hpp"
2 #include "Instance.hpp"
3 #include "Skeletons.hpp"
4
5 #include "Shape.hpp"
6 #include "ShapeRegistry.hpp"
7 #include "../app/TextureIndex.hpp"
8 #include "../graphics/DirectionalLighting.hpp"
9 #include "../graphics/EntityMesh.hpp"
10
11 #include <iostream>
12 #include <glm/gtx/quaternion.hpp>
13 #include <glm/gtx/io.hpp>
14
15
16 namespace blank {
17
18 Instance::Instance()
19 : model(nullptr)
20 , state()
21 , mesh()
22 , tex_map()
23 , hsl_mod(0.0f, 1.0f, 1.0f)
24 , rgb_mod(1.0f) {
25
26 }
27
28 Instance::~Instance() {
29
30 }
31
32 Instance::Instance(const Instance &other)
33 : model(other.model)
34 , state(other.state)
35 , mesh()
36 , tex_map(other.tex_map)
37 , hsl_mod(other.hsl_mod)
38 , rgb_mod(other.rgb_mod) {
39
40 }
41
42 Instance &Instance::operator =(const Instance &other) {
43         model = other.model;
44         state = other.state;
45         mesh.clear();
46         tex_map = other.tex_map;
47         hsl_mod = other.hsl_mod;
48         rgb_mod = other.rgb_mod;
49         return *this;
50 }
51
52 void Instance::Render(const glm::mat4 &M, DirectionalLighting &prog) {
53         if (mesh.empty()) {
54                 std::cout << "building meshes for instance" << std::endl;
55                 mesh.resize(state.size());
56                 model->RootPart().LoadMeshes(*this);
57         }
58         model->RootPart().Render(M, *this, prog);
59 }
60
61 void Instance::SetTextures(const std::vector<float> &t) {
62         tex_map = t;
63         mesh.clear();
64 }
65
66 void Instance::SetHSLModifier(const glm::vec3 &m) {
67         hsl_mod = m;
68         mesh.clear();
69 }
70
71 void Instance::SetRGBModifier(const glm::vec3 &m) {
72         rgb_mod = m;
73         mesh.clear();
74 }
75
76
77 Model::Model()
78 : id(0)
79 , root()
80 , part() {
81
82 }
83
84 void Model::Enumerate() {
85         part.clear();
86         part.resize(root.Enumerate(0), nullptr);
87         root.Index(part);
88 }
89
90 void Model::Instantiate(Instance &inst) const {
91         inst.model = this;
92         inst.state.clear();
93         inst.mesh.clear();
94         inst.state.resize(part.size());
95 }
96
97
98 Part::Part()
99 : id(0)
100 , bounds{ glm::vec3(0.0f), glm::vec3(0.0f) }
101 , initial()
102 , shape(nullptr)
103 , parent(nullptr)
104 , children() {
105
106 }
107
108 Part::~Part() {
109
110 }
111
112 Part &Part::AddChild() {
113         children.emplace_back();
114         children.back().parent = this;
115         return children.back();
116 }
117
118 std::uint16_t Part::Enumerate(std::uint16_t counter) noexcept {
119         id = counter++;
120         for (Part &part : children) {
121                 counter = part.Enumerate(counter);
122         }
123         return counter;
124 }
125
126 void Part::Index(std::vector<Part *> &index) noexcept {
127         index[id] = this;
128         for (Part &part : children) {
129                 part.Index(index);
130         }
131 }
132
133 glm::mat4 Part::LocalTransform(const Instance &inst) const noexcept {
134         glm::mat4 transform(toMat4(initial.orientation * inst.state[id].orientation));
135         transform[3] = glm::vec4(initial.position + inst.state[id].position, 1.0f);
136         return transform;
137 }
138
139 glm::mat4 Part::GlobalTransform(const Instance &inst) const noexcept {
140         if (parent) {
141                 return parent->GlobalTransform(inst) * LocalTransform(inst);
142         } else {
143                 return LocalTransform(inst);
144         }
145 }
146
147 namespace {
148
149 EntityMesh::Buffer buf;
150
151 }
152
153 void Part::LoadMeshes(Instance &inst) const {
154         if (shape && shape->IndexCount() > 0) {
155                 buf.Clear();
156                 buf.hsl_mods.resize(shape->VertexCount(), inst.hsl_mod);
157                 buf.rgb_mods.resize(shape->VertexCount(), inst.rgb_mod);
158                 shape->Fill(buf, inst.tex_map);
159                 inst.mesh[id].reset(new EntityMesh());
160                 inst.mesh[id]->Update(buf);
161         } else {
162                 inst.mesh[id].reset();
163         }
164         for (const Part &part : children) {
165                 part.LoadMeshes(inst);
166         }
167 }
168
169 void Part::Render(
170         const glm::mat4 &M,
171         const Instance &inst,
172         DirectionalLighting &prog
173 ) const {
174         glm::mat4 transform = M * LocalTransform(inst);
175         if (inst.mesh[id]) {
176                 prog.SetM(transform);
177                 inst.mesh[id]->Draw();
178         }
179         for (const Part &part : children) {
180                 part.Render(transform, inst, prog);
181         }
182 }
183
184
185 Skeletons::Skeletons()
186 : skeletons() {
187
188 }
189
190 Skeletons::~Skeletons() {
191
192 }
193
194 void Skeletons::Load(const ShapeRegistry &shapes) {
195         skeletons.clear();
196         skeletons.reserve(4);
197         AABB bounds{{ -0.5f, -0.5f, -0.5f }, { 0.5f, 0.5f, 0.5f }};
198         const Shape *shape = &shapes.Get("player_head_block");
199         {
200                 skeletons.emplace_back(new Model);
201                 skeletons[0]->ID(1);
202                 skeletons[0]->RootPart().bounds = bounds;
203                 skeletons[0]->RootPart().shape = shape;
204                 skeletons[0]->Enumerate();
205         }
206         {
207                 skeletons.emplace_back(new Model);
208                 skeletons[1]->ID(2);
209                 skeletons[1]->RootPart().bounds = bounds;
210                 skeletons[1]->RootPart().shape = shape;
211                 skeletons[1]->Enumerate();
212         }
213         {
214                 skeletons.emplace_back(new Model);
215                 skeletons[2]->ID(3);
216                 skeletons[2]->RootPart().bounds = bounds;
217                 skeletons[2]->RootPart().shape = shape;
218                 skeletons[2]->Enumerate();
219         }
220         {
221                 skeletons.emplace_back(new Model);
222                 skeletons[3]->ID(4);
223                 skeletons[3]->RootPart().bounds = bounds;
224                 skeletons[3]->RootPart().shape = shape;
225                 skeletons[3]->Enumerate();
226         }
227 }
228
229 Model *Skeletons::ByID(std::uint16_t id) noexcept {
230         if (id == 0 || id > skeletons.size()) {
231                 return nullptr;
232         } else {
233                 return skeletons[id - 1].get();
234         }
235 }
236
237 const Model *Skeletons::ByID(std::uint16_t id) const noexcept {
238         if (id == 0 || id > skeletons.size()) {
239                 return nullptr;
240         } else {
241                 return skeletons[id - 1].get();
242         }
243 }
244
245 }