2 #include "BlockGravity.hpp"
3 #include "BlockType.hpp"
4 #include "BlockTypeRegistry.hpp"
6 #include "../io/TokenStreamReader.hpp"
7 #include "../model/ShapeRegistry.hpp"
8 #include "../shared/ResourceIndex.hpp"
12 #include <glm/gtx/euler_angles.hpp>
13 #include <glm/gtx/norm.hpp>
14 #include <glm/gtx/transform.hpp>
19 std::ostream &operator <<(std::ostream &out, const Block &block) {
20 return out << "Block(" << block.type << ", " << block.GetFace() << ", " << block.GetTurn() << ')';
23 std::ostream &operator <<(std::ostream &out, const Block::Face &face) {
28 case Block::FACE_DOWN:
31 case Block::FACE_RIGHT:
34 case Block::FACE_LEFT:
37 case Block::FACE_FRONT:
40 case Block::FACE_BACK:
44 case Block::FACE_COUNT:
45 out << "invalid Block::Face";
51 std::ostream &operator <<(std::ostream &out, const Block::Turn &turn) {
53 case Block::TURN_NONE:
56 case Block::TURN_LEFT:
59 case Block::TURN_AROUND:
62 case Block::TURN_RIGHT:
66 case Block::TURN_COUNT:
67 out << "invalid Block::Turn";
74 BlockType::BlockType() noexcept
77 , hsl_mod(0.0f, 1.0f, 1.0f)
78 , rgb_mod(1.0f, 1.0f, 1.0f)
79 , outline_color(-1, -1, -1)
98 , min_temperature(-1.0f)
99 , mid_temperature(0.0f)
100 , max_temperature(1.0f)
101 , min_richness(-1.0f)
108 void BlockType::Copy(const BlockType &other) noexcept {
110 textures = other.textures;
111 hsl_mod = other.hsl_mod;
112 rgb_mod = other.rgb_mod;
113 outline_color = other.outline_color;
114 place_sound = other.place_sound;
115 remove_sound = other.remove_sound;
116 luminosity = other.luminosity;
117 visible = other.visible;
118 block_light = other.block_light;
119 collision = other.collision;
120 collide_block = collide_block;
121 generate = other.generate;
122 min_solidity = other.min_solidity;
123 mid_solidity = other.mid_solidity;
124 max_solidity = other.max_solidity;
125 min_humidity = other.min_humidity;
126 mid_humidity = other.mid_humidity;
127 max_humidity = other.max_humidity;
128 min_temperature = other.min_temperature;
129 mid_temperature = other.mid_temperature;
130 max_temperature = other.max_temperature;
131 min_richness = other.min_richness;
132 mid_richness = other.mid_richness;
133 max_richness = other.max_richness;
134 commonness = other.commonness;
137 void BlockType::Read(
138 TokenStreamReader &in,
139 ResourceIndex &snd_index,
140 ResourceIndex &tex_index,
141 const ShapeRegistry &shapes
144 in.Skip(Token::ANGLE_BRACKET_OPEN);
145 while (in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
146 in.ReadIdentifier(name);
147 in.Skip(Token::EQUALS);
148 if (name == "visible") {
149 visible = in.GetBool();
150 } else if (name == "texture") {
153 textures.push_back(tex_index.GetID(name));
154 } else if (name == "textures") {
156 in.Skip(Token::BRACKET_OPEN);
157 while (in.Peek().type != Token::BRACKET_CLOSE) {
159 textures.push_back(tex_index.GetID(name));
160 if (in.Peek().type == Token::COMMA) {
161 in.Skip(Token::COMMA);
164 in.Skip(Token::BRACKET_CLOSE);
165 } else if (name == "rgb_mod") {
167 } else if (name == "hsl_mod") {
169 } else if (name == "outline") {
170 in.ReadVec(outline_color);
171 } else if (name == "gravity") {
172 gravity = BlockGravity::Read(in);
173 } else if (name == "label") {
174 in.ReadString(label);
175 } else if (name == "place_sound") {
177 place_sound = snd_index.GetID(name);
178 } else if (name == "remove_sound") {
180 remove_sound = snd_index.GetID(name);
181 } else if (name == "luminosity") {
182 luminosity = in.GetInt();
183 } else if (name == "block_light") {
184 block_light = in.GetBool();
185 } else if (name == "collision") {
186 collision = in.GetBool();
187 } else if (name == "collide_block") {
188 collide_block = in.GetBool();
189 } else if (name == "generate") {
190 generate = in.GetBool();
191 } else if (name == "min_solidity") {
192 min_solidity = in.GetFloat();
193 } else if (name == "mid_solidity") {
194 mid_solidity = in.GetFloat();
195 } else if (name == "max_solidity") {
196 max_solidity = in.GetFloat();
197 } else if (name == "min_humidity") {
198 min_humidity = in.GetFloat();
199 } else if (name == "mid_humidity") {
200 mid_humidity = in.GetFloat();
201 } else if (name == "max_humidity") {
202 max_humidity = in.GetFloat();
203 } else if (name == "min_temperature") {
204 min_temperature = in.GetFloat();
205 } else if (name == "mid_temperature") {
206 mid_temperature = in.GetFloat();
207 } else if (name == "max_temperature") {
208 max_temperature = in.GetFloat();
209 } else if (name == "min_richness") {
210 min_richness = in.GetFloat();
211 } else if (name == "mid_richness") {
212 mid_richness = in.GetFloat();
213 } else if (name == "max_richness") {
214 max_richness = in.GetFloat();
215 } else if (name == "commonness") {
216 commonness = in.GetFloat();
217 } else if (name == "shape") {
218 in.ReadIdentifier(name);
219 shape = &shapes.Get(name);
221 std::cerr << "warning: unknown block type property " << name << std::endl;
222 while (in.Peek().type != Token::SEMICOLON) {
226 in.Skip(Token::SEMICOLON);
228 in.Skip(Token::ANGLE_BRACKET_CLOSE);
231 void BlockType::FillEntityMesh(
232 EntityMesh::Buffer &buf,
233 const glm::mat4 &transform
236 shape->Fill(buf, transform, textures);
237 buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod);
238 buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod);
241 void BlockType::FillBlockMesh(
242 BlockMesh::Buffer &buf,
243 const glm::mat4 &transform,
244 BlockMesh::Index idx_offset
247 shape->Fill(buf, transform, textures, idx_offset);
248 buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod);
249 buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod);
252 void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept {
255 buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::vec4(outline_color, 1.0f));
259 BlockTypeRegistry::BlockTypeRegistry() {
264 air.block_light = false;
265 air.collision = false;
266 air.collide_block = false;
270 Block::Type BlockTypeRegistry::Add(BlockType &&t) {
271 int id = types.size();
272 if (!names.emplace(t.name, id).second) {
273 throw std::runtime_error("duplicate block type name " + t.name);
275 types.push_back(std::move(t));
276 types.back().id = id;
280 BlockType &BlockTypeRegistry::Get(const std::string &name) {
281 auto entry = names.find(name);
282 if (entry != names.end()) {
283 return Get(entry->second);
285 throw std::runtime_error("unknown block type " + name);
289 const BlockType &BlockTypeRegistry::Get(const std::string &name) const {
290 auto entry = names.find(name);
291 if (entry != names.end()) {
292 return Get(entry->second);
294 throw std::runtime_error("unknown block type " + name);
301 /// the "usual" type of gravity
302 /// direction is towards the block's center, strength is inverse
303 /// proportional to distance squared
304 /// note that the effect can get clipped at distances > 16 units
306 : public BlockGravity {
308 explicit RadialGravity(float strength)
309 : strength(strength) { }
311 glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &) const noexcept override {
312 float dist2 = length2(diff);
313 glm::vec3 dir = -normalize(diff);
314 return dir * (strength / dist2);
321 /// a "force field" variant of artificial gravity
322 /// strength and direction is constant throughout the cuboid
323 /// extent shouldn't exceed 16 units as gravity is only calculated for
324 /// chunks surrounding and entity (and sometimes not even those if they're
325 /// unavailable, but they will be for players)
326 struct CuboidFieldGravity
327 : public BlockGravity {
329 explicit CuboidFieldGravity(const glm::vec3 &strength, const AABB &extent)
330 : strength(strength), extent(extent) { }
332 glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &M) const noexcept override {
333 /// rotate AABB endpoints accordingly, ignore translation
334 glm::vec3 min(M * glm::vec4(extent.min, 0.0f));
335 glm::vec3 max(M * glm::vec4(extent.max, 0.0f));
336 if (diff.x < min.x || diff.y < min.y || diff.z < min.z ||
337 diff.x > max.x || diff.y > max.y || diff.z > max.z) {
338 /// if point is outside, force is zero
339 return glm::vec3(0.0f);
341 /// otherwise it's out constant strength in block orientation
342 return glm::vec3(M * glm::vec4(strength, 0.0f));
354 BlockGravity::~BlockGravity() {
358 std::unique_ptr<BlockGravity> BlockGravity::Read(TokenStreamReader &in) {
360 in.ReadIdentifier(type);
361 if (type == "Radial") {
363 in.Skip(Token::PARENTHESIS_OPEN);
364 in.ReadNumber(strength);
365 in.Skip(Token::PARENTHESIS_CLOSE);
366 return std::unique_ptr<BlockGravity>(new RadialGravity(strength));
367 } else if (type == "CuboidField") {
370 in.Skip(Token::PARENTHESIS_OPEN);
371 in.ReadVec(strength);
372 in.Skip(Token::COMMA);
373 in.ReadVec(extent.min);
374 in.Skip(Token::COMMA);
375 in.ReadVec(extent.max);
376 in.Skip(Token::PARENTHESIS_CLOSE);
378 return std::unique_ptr<BlockGravity>(new CuboidFieldGravity(strength, extent));
380 throw std::runtime_error("unknown gravity type: " + type);
385 const glm::mat4 Block::orient2transform[ORIENT_COUNT] = {
386 { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: up, turn: none
387 { 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: up, turn: left
388 { -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: up, turn: around
389 { 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: up, turn: right
390 { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: down, turn: none
391 { 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: down, turn: left
392 { -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: down, turn: around
393 { 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: down, turn: right
394 { 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: right, turn: none
395 { 0, -1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: right, turn: left
396 { 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: right, turn: around
397 { 0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: right, turn: right
398 { 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: left, turn: none
399 { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: left, turn: left
400 { 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: left, turn: around
401 { 0, 1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: left, turn: right
402 { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: none
403 { 0, 0, -1, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: left
404 { -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: around
405 { 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: right
406 { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: none
407 { 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: left
408 { -1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: around
409 { 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: right
412 const glm::ivec3 Block::face2normal[FACE_COUNT] = {
421 const Block::Face Block::orient2face[ORIENT_COUNT][FACE_COUNT] = {
422 { FACE_UP, FACE_DOWN, FACE_RIGHT, FACE_LEFT, FACE_FRONT, FACE_BACK, }, // face: up, turn: none
423 { FACE_UP, FACE_DOWN, FACE_FRONT, FACE_BACK, FACE_LEFT, FACE_RIGHT, }, // face: up, turn: left
424 { FACE_UP, FACE_DOWN, FACE_LEFT, FACE_RIGHT, FACE_BACK, FACE_FRONT, }, // face: up, turn: around
425 { FACE_UP, FACE_DOWN, FACE_BACK, FACE_FRONT, FACE_RIGHT, FACE_LEFT, }, // face: up, turn: right
426 { FACE_DOWN, FACE_UP, FACE_RIGHT, FACE_LEFT, FACE_BACK, FACE_FRONT, }, // face: down, turn: none
427 { FACE_DOWN, FACE_UP, FACE_BACK, FACE_FRONT, FACE_LEFT, FACE_RIGHT, }, // face: down, turn: left
428 { FACE_DOWN, FACE_UP, FACE_LEFT, FACE_RIGHT, FACE_FRONT, FACE_BACK, }, // face: down, turn: around
429 { FACE_DOWN, FACE_UP, FACE_FRONT, FACE_BACK, FACE_RIGHT, FACE_LEFT, }, // face: down, turn: right
430 { FACE_LEFT, FACE_RIGHT, FACE_UP, FACE_DOWN, FACE_FRONT, FACE_BACK, }, // face: right, turn: none
431 { FACE_LEFT, FACE_RIGHT, FACE_FRONT, FACE_BACK, FACE_DOWN, FACE_UP, }, // face: right, turn: left
432 { FACE_LEFT, FACE_RIGHT, FACE_DOWN, FACE_UP, FACE_BACK, FACE_FRONT, }, // face: right, turn: around
433 { FACE_LEFT, FACE_RIGHT, FACE_BACK, FACE_FRONT, FACE_UP, FACE_DOWN, }, // face: right, turn: right
434 { FACE_RIGHT, FACE_LEFT, FACE_DOWN, FACE_UP, FACE_FRONT, FACE_BACK, }, // face: left, turn: none
435 { FACE_RIGHT, FACE_LEFT, FACE_FRONT, FACE_BACK, FACE_UP, FACE_DOWN, }, // face: left, turn: left
436 { FACE_RIGHT, FACE_LEFT, FACE_UP, FACE_DOWN, FACE_BACK, FACE_FRONT, }, // face: left, turn: around
437 { FACE_RIGHT, FACE_LEFT, FACE_BACK, FACE_FRONT, FACE_DOWN, FACE_UP, }, // face: left, turn: right
438 { FACE_BACK, FACE_FRONT, FACE_RIGHT, FACE_LEFT, FACE_UP, FACE_DOWN, }, // face: front, turn: none
439 { FACE_BACK, FACE_FRONT, FACE_UP, FACE_DOWN, FACE_LEFT, FACE_RIGHT, }, // face: front, turn: left
440 { FACE_BACK, FACE_FRONT, FACE_LEFT, FACE_RIGHT, FACE_DOWN, FACE_UP, }, // face: front, turn: around
441 { FACE_BACK, FACE_FRONT, FACE_DOWN, FACE_UP, FACE_RIGHT, FACE_LEFT, }, // face: front, turn: right
442 { FACE_FRONT, FACE_BACK, FACE_RIGHT, FACE_LEFT, FACE_DOWN, FACE_UP, }, // face: back, turn: none
443 { FACE_FRONT, FACE_BACK, FACE_DOWN, FACE_UP, FACE_LEFT, FACE_RIGHT, }, // face: back, turn: left
444 { FACE_FRONT, FACE_BACK, FACE_LEFT, FACE_RIGHT, FACE_UP, FACE_DOWN, }, // face: back, turn: around
445 { FACE_FRONT, FACE_BACK, FACE_UP, FACE_DOWN, FACE_RIGHT, FACE_LEFT, }, // face: back, turn: right