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"
11 #include <glm/gtx/euler_angles.hpp>
12 #include <glm/gtx/norm.hpp>
13 #include <glm/gtx/transform.hpp>
18 std::ostream &operator <<(std::ostream &out, const Block &block) {
19 return out << "Block(" << block.type << ", " << block.GetFace() << ", " << block.GetTurn() << ')';
22 std::ostream &operator <<(std::ostream &out, const Block::Face &face) {
27 case Block::FACE_DOWN:
30 case Block::FACE_RIGHT:
33 case Block::FACE_LEFT:
36 case Block::FACE_FRONT:
39 case Block::FACE_BACK:
43 case Block::FACE_COUNT:
44 out << "invalid Block::Face";
50 std::ostream &operator <<(std::ostream &out, const Block::Turn &turn) {
52 case Block::TURN_NONE:
55 case Block::TURN_LEFT:
58 case Block::TURN_AROUND:
61 case Block::TURN_RIGHT:
65 case Block::TURN_COUNT:
66 out << "invalid Block::Turn";
73 BlockType::BlockType() noexcept
76 , hsl_mod(0.0f, 1.0f, 1.0f)
77 , rgb_mod(1.0f, 1.0f, 1.0f)
78 , outline_color(-1, -1, -1)
96 , min_temperature(-1.0f)
97 , mid_temperature(0.0f)
98 , max_temperature(1.0f)
106 void BlockType::Read(
107 TokenStreamReader &in,
108 ResourceIndex &snd_index,
109 ResourceIndex &tex_index,
110 const ShapeRegistry &shapes
113 in.Skip(Token::ANGLE_BRACKET_OPEN);
114 while (in.Peek().type != Token::ANGLE_BRACKET_CLOSE) {
115 in.ReadIdentifier(name);
116 in.Skip(Token::EQUALS);
117 if (name == "visible") {
118 visible = in.GetBool();
119 } else if (name == "texture") {
121 textures.push_back(tex_index.GetID(name));
122 } else if (name == "textures") {
123 in.Skip(Token::BRACKET_OPEN);
124 while (in.Peek().type != Token::BRACKET_CLOSE) {
126 textures.push_back(tex_index.GetID(name));
127 if (in.Peek().type == Token::COMMA) {
128 in.Skip(Token::COMMA);
131 in.Skip(Token::BRACKET_CLOSE);
132 } else if (name == "rgb_mod") {
134 } else if (name == "hsl_mod") {
136 } else if (name == "outline") {
137 in.ReadVec(outline_color);
138 } else if (name == "gravity") {
139 gravity = BlockGravity::Read(in);
140 } else if (name == "label") {
141 in.ReadString(label);
142 } else if (name == "place_sound") {
144 place_sound = snd_index.GetID(name);
145 } else if (name == "remove_sound") {
147 remove_sound = snd_index.GetID(name);
148 } else if (name == "luminosity") {
149 luminosity = in.GetInt();
150 } else if (name == "block_light") {
151 block_light = in.GetBool();
152 } else if (name == "collision") {
153 collision = in.GetBool();
154 } else if (name == "collide_block") {
155 collide_block = in.GetBool();
156 } else if (name == "generate") {
157 generate = in.GetBool();
158 } else if (name == "min_solidity") {
159 min_solidity = in.GetFloat();
160 } else if (name == "mid_solidity") {
161 mid_solidity = in.GetFloat();
162 } else if (name == "max_solidity") {
163 max_solidity = in.GetFloat();
164 } else if (name == "min_humidity") {
165 min_humidity = in.GetFloat();
166 } else if (name == "mid_humidity") {
167 mid_humidity = in.GetFloat();
168 } else if (name == "max_humidity") {
169 max_humidity = in.GetFloat();
170 } else if (name == "min_temperature") {
171 min_temperature = in.GetFloat();
172 } else if (name == "mid_temperature") {
173 mid_temperature = in.GetFloat();
174 } else if (name == "max_temperature") {
175 max_temperature = in.GetFloat();
176 } else if (name == "min_richness") {
177 min_richness = in.GetFloat();
178 } else if (name == "mid_richness") {
179 mid_richness = in.GetFloat();
180 } else if (name == "max_richness") {
181 max_richness = in.GetFloat();
182 } else if (name == "commonness") {
183 commonness = in.GetFloat();
184 } else if (name == "shape") {
185 in.ReadIdentifier(name);
186 shape = &shapes.Get(name);
188 std::cerr << "warning: unknown block type property " << name << std::endl;
189 while (in.Peek().type != Token::SEMICOLON) {
193 in.Skip(Token::SEMICOLON);
195 in.Skip(Token::ANGLE_BRACKET_CLOSE);
198 void BlockType::FillEntityMesh(
199 EntityMesh::Buffer &buf,
200 const glm::mat4 &transform
203 shape->Fill(buf, transform, textures);
204 buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod);
205 buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod);
208 void BlockType::FillBlockMesh(
209 BlockMesh::Buffer &buf,
210 const glm::mat4 &transform,
211 BlockMesh::Index idx_offset
214 shape->Fill(buf, transform, textures, idx_offset);
215 buf.hsl_mods.insert(buf.hsl_mods.end(), shape->VertexCount(), hsl_mod);
216 buf.rgb_mods.insert(buf.rgb_mods.end(), shape->VertexCount(), rgb_mod);
219 void BlockType::OutlinePrimitiveMesh(PrimitiveMesh::Buffer &buf) const noexcept {
222 buf.colors.insert(buf.colors.end(), shape->OutlineCount(), glm::vec4(outline_color, 1.0f));
226 BlockTypeRegistry::BlockTypeRegistry() {
229 air.block_light = false;
230 air.collision = false;
231 air.collide_block = false;
235 Block::Type BlockTypeRegistry::Add(BlockType &&t) {
236 int id = types.size();
237 types.push_back(std::move(t));
238 types.back().id = id;
245 /// the "usual" type of gravity
246 /// direction is towards the block's center, strength is inverse
247 /// proportional to distance squared
248 /// note that the effect can get clipped at distances > 16 units
250 : public BlockGravity {
252 explicit RadialGravity(float strength)
253 : strength(strength) { }
255 glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &) const noexcept override {
256 float dist2 = length2(diff);
257 glm::vec3 dir = -normalize(diff);
258 return dir * (strength / dist2);
265 /// a "force field" variant of artificial gravity
266 /// strength and direction is constant throughout the cuboid
267 /// extent shouldn't exceed 16 units as gravity is only calculated for
268 /// chunks surrounding and entity (and sometimes not even those if they're
269 /// unavailable, but they will be for players)
270 struct CuboidFieldGravity
271 : public BlockGravity {
273 explicit CuboidFieldGravity(const glm::vec3 &strength, const AABB &extent)
274 : strength(strength), extent(extent) { }
276 glm::vec3 GetGravity(const glm::vec3 &diff, const glm::mat4 &M) const noexcept override {
277 /// rotate AABB endpoints accordingly, ignore translation
278 glm::vec3 min(M * glm::vec4(extent.min, 0.0f));
279 glm::vec3 max(M * glm::vec4(extent.max, 0.0f));
280 if (diff.x < min.x || diff.y < min.y || diff.z < min.z ||
281 diff.x > max.x || diff.y > max.y || diff.z > max.z) {
282 /// if point is outside, force is zero
283 return glm::vec3(0.0f);
285 /// otherwise it's out constant strength in block orientation
286 return glm::vec3(M * glm::vec4(strength, 0.0f));
298 BlockGravity::~BlockGravity() {
302 std::unique_ptr<BlockGravity> BlockGravity::Read(TokenStreamReader &in) {
304 in.ReadIdentifier(type);
305 if (type == "Radial") {
307 in.Skip(Token::PARENTHESIS_OPEN);
308 in.ReadNumber(strength);
309 in.Skip(Token::PARENTHESIS_CLOSE);
310 return std::unique_ptr<BlockGravity>(new RadialGravity(strength));
311 } else if (type == "CuboidField") {
314 in.Skip(Token::PARENTHESIS_OPEN);
315 in.ReadVec(strength);
316 in.Skip(Token::COMMA);
317 in.ReadVec(extent.min);
318 in.Skip(Token::COMMA);
319 in.ReadVec(extent.max);
320 in.Skip(Token::PARENTHESIS_CLOSE);
322 return std::unique_ptr<BlockGravity>(new CuboidFieldGravity(strength, extent));
324 throw std::runtime_error("unknown gravity type: " + type);
329 const glm::mat4 Block::orient2transform[ORIENT_COUNT] = {
330 { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: up, turn: none
331 { 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: up, turn: left
332 { -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: up, turn: around
333 { 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: up, turn: right
334 { 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: down, turn: none
335 { 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: down, turn: left
336 { -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: down, turn: around
337 { 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: down, turn: right
338 { 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: right, turn: none
339 { 0, -1, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: right, turn: left
340 { 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: right, turn: around
341 { 0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: right, turn: right
342 { 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, }, // face: left, turn: none
343 { 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, }, // face: left, turn: left
344 { 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, }, // face: left, turn: around
345 { 0, 1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 1, }, // face: left, turn: right
346 { 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: none
347 { 0, 0, -1, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: left
348 { -1, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: around
349 { 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, }, // face: front, turn: right
350 { 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: none
351 { 0, 0, -1, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: left
352 { -1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: around
353 { 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, }, // face: back, turn: right
356 const glm::ivec3 Block::face2normal[FACE_COUNT] = {
365 const Block::Face Block::orient2face[ORIENT_COUNT][FACE_COUNT] = {
366 { FACE_UP, FACE_DOWN, FACE_RIGHT, FACE_LEFT, FACE_FRONT, FACE_BACK, }, // face: up, turn: none
367 { FACE_UP, FACE_DOWN, FACE_FRONT, FACE_BACK, FACE_LEFT, FACE_RIGHT, }, // face: up, turn: left
368 { FACE_UP, FACE_DOWN, FACE_LEFT, FACE_RIGHT, FACE_BACK, FACE_FRONT, }, // face: up, turn: around
369 { FACE_UP, FACE_DOWN, FACE_BACK, FACE_FRONT, FACE_RIGHT, FACE_LEFT, }, // face: up, turn: right
370 { FACE_DOWN, FACE_UP, FACE_RIGHT, FACE_LEFT, FACE_BACK, FACE_FRONT, }, // face: down, turn: none
371 { FACE_DOWN, FACE_UP, FACE_BACK, FACE_FRONT, FACE_LEFT, FACE_RIGHT, }, // face: down, turn: left
372 { FACE_DOWN, FACE_UP, FACE_LEFT, FACE_RIGHT, FACE_FRONT, FACE_BACK, }, // face: down, turn: around
373 { FACE_DOWN, FACE_UP, FACE_FRONT, FACE_BACK, FACE_RIGHT, FACE_LEFT, }, // face: down, turn: right
374 { FACE_LEFT, FACE_RIGHT, FACE_UP, FACE_DOWN, FACE_FRONT, FACE_BACK, }, // face: right, turn: none
375 { FACE_LEFT, FACE_RIGHT, FACE_FRONT, FACE_BACK, FACE_DOWN, FACE_UP, }, // face: right, turn: left
376 { FACE_LEFT, FACE_RIGHT, FACE_DOWN, FACE_UP, FACE_BACK, FACE_FRONT, }, // face: right, turn: around
377 { FACE_LEFT, FACE_RIGHT, FACE_BACK, FACE_FRONT, FACE_UP, FACE_DOWN, }, // face: right, turn: right
378 { FACE_RIGHT, FACE_LEFT, FACE_DOWN, FACE_UP, FACE_FRONT, FACE_BACK, }, // face: left, turn: none
379 { FACE_RIGHT, FACE_LEFT, FACE_FRONT, FACE_BACK, FACE_UP, FACE_DOWN, }, // face: left, turn: left
380 { FACE_RIGHT, FACE_LEFT, FACE_UP, FACE_DOWN, FACE_BACK, FACE_FRONT, }, // face: left, turn: around
381 { FACE_RIGHT, FACE_LEFT, FACE_BACK, FACE_FRONT, FACE_DOWN, FACE_UP, }, // face: left, turn: right
382 { FACE_BACK, FACE_FRONT, FACE_RIGHT, FACE_LEFT, FACE_UP, FACE_DOWN, }, // face: front, turn: none
383 { FACE_BACK, FACE_FRONT, FACE_UP, FACE_DOWN, FACE_LEFT, FACE_RIGHT, }, // face: front, turn: left
384 { FACE_BACK, FACE_FRONT, FACE_LEFT, FACE_RIGHT, FACE_DOWN, FACE_UP, }, // face: front, turn: around
385 { FACE_BACK, FACE_FRONT, FACE_DOWN, FACE_UP, FACE_RIGHT, FACE_LEFT, }, // face: front, turn: right
386 { FACE_FRONT, FACE_BACK, FACE_RIGHT, FACE_LEFT, FACE_DOWN, FACE_UP, }, // face: back, turn: none
387 { FACE_FRONT, FACE_BACK, FACE_DOWN, FACE_UP, FACE_LEFT, FACE_RIGHT, }, // face: back, turn: left
388 { FACE_FRONT, FACE_BACK, FACE_LEFT, FACE_RIGHT, FACE_UP, FACE_DOWN, }, // face: back, turn: around
389 { FACE_FRONT, FACE_BACK, FACE_UP, FACE_DOWN, FACE_RIGHT, FACE_LEFT, }, // face: back, turn: right