123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- #include <cmath>
- #include "client/World.h"
- #include "client/rendering/Engine.h"
- #include "client/rendering/Mesh.h"
- #include "common/BlockStorage.h"
- #include "rendering/FileTexture.h"
- #include "utils/List.h"
- #include "utils/Logger.h"
- #include "utils/Random.h"
- static BlockStorage blocks{7, 7};
- static List<Entity*> entities;
- static Mesh mesh;
- static FileTexture texture;
- static bool dirty = true;
- bool World::init() {
- mesh.init();
- Error error = texture.load("resources/textures.png", 4);
- if(error.has()) {
- LOG_ERROR(error.message);
- }
- return error.has();
- }
- void World::addEntity(Entity* e) {
- entities.add(e);
- }
- void World::removeEntity(Entity* e) {
- for(int i = 0; i < entities.getLength(); i++) {
- if(entities[i] == e) {
- entities.removeBySwap(i);
- return;
- }
- }
- }
- static List<Box> getBoxes(const Box& box) {
- int minX = floorf(box.getMin()[0]);
- int minY = floorf(box.getMin()[1]);
- int minZ = floorf(box.getMin()[2]);
- int maxX = floorf(box.getMax()[0]);
- int maxY = floorf(box.getMax()[1]);
- int maxZ = floorf(box.getMax()[2]);
- List<Box> boxes;
- for(int x = minX; x <= maxX; x++) {
- for(int y = minY; y <= maxY; y++) {
- for(int z = minZ; z <= maxZ; z++) {
- Block::addBoxes(blocks.get(x, y, z), boxes,
- Vector3(static_cast<float>(x),
- static_cast<float>(y),
- static_cast<float>(z)));
- }
- }
- }
- return boxes;
- }
- static Vector3 limitMove(const Entity& e, Vector3 move) {
- Box box = e.getBox();
- List<Box> boxes = getBoxes(box.expand(move));
- if(boxes.getLength() == 0) {
- return move;
- }
- Vector3 realMove;
- constexpr float step = 0.05f;
- while(move[0] != 0.0f || move[1] != 0.0f || move[2] != 0.0f) {
- for(int i = 0; i < 3; i++) {
- Vector3 old = realMove;
- if(move[i] > step) {
- realMove[i] += step;
- move[i] -= step;
- } else if(move[i] < -step) {
- realMove[i] -= step;
- move[i] += step;
- } else if(move[i] != 0.0f) {
- realMove[i] += move[i];
- move[i] = 0.0f;
- }
- Box moved = box.offset(realMove);
- for(const Box& box : boxes) {
- if(box.collidesWith(moved)) {
- move[i] = 0.0f;
- realMove = old;
- break;
- }
- }
- }
- }
- return realMove;
- }
- void World::tick() {
- for(Entity* e : entities) {
- e->tick();
- if(!e->skip) {
- Vector3 move = limitMove(*e, e->getVelocity());
- e->move(move);
- }
- }
- }
- static bool isAir(int x, int y, int z) {
- return blocks.get(x, y, z) == 0;
- }
- static void addCube(TypedBuffer<Mesh::Triangle>& buffer, float x, float y,
- float z) {
- Vector3 v000(x, y, z);
- Vector3 v001(x, y, z + 1);
- Vector3 v010(x, y + 1, z);
- Vector3 v011(x, y + 1, z + 1);
- Vector3 v100(x + 1, y, z);
- Vector3 v101(x + 1, y, z + 1);
- Vector3 v110(x + 1, y + 1, z);
- Vector3 v111(x + 1, y + 1, z + 1);
- Vector2 t1(0.1875f, 0.0f);
- Vector2 t2(0.25f, 0.0f);
- Vector2 t3(0.25f, 0.0625f);
- Vector2 t4(0.1875f, 0.0625f);
- if(isAir(x, y - 1, z)) {
- Vector2 tb(0.125f, 0.0625f);
- buffer.add({{v000, {0.125f, 0.0f}}, {v100, t1}, {v001, tb}});
- buffer.add({{v100, t1}, {v101, t4}, {v001, tb}});
- }
- if(isAir(x, y + 1, z)) {
- Vector2 tt(0.3125f, 0.0f);
- buffer.add({{v010, t2}, {v011, t3}, {v110, tt}});
- buffer.add({{v110, tt}, {v011, t3}, {v111, {0.3125f, 0.0625f}}});
- }
- if(isAir(x - 1, y, z)) {
- buffer.add({{v000, t4}, {v001, t3}, {v010, t1}});
- buffer.add({{v001, t3}, {v011, t2}, {v010, t1}});
- }
- if(isAir(x + 1, y, z)) {
- buffer.add({{v100, t3}, {v110, t2}, {v101, t4}});
- buffer.add({{v101, t4}, {v110, t2}, {v111, t1}});
- }
- if(isAir(x, y, z + 1)) {
- buffer.add({{v001, t4}, {v101, t3}, {v011, t1}});
- buffer.add({{v111, t2}, {v011, t1}, {v101, t3}});
- }
- if(isAir(x, y, z - 1)) {
- buffer.add({{v000, t3}, {v010, t2}, {v100, t4}});
- buffer.add({{v110, t1}, {v100, t4}, {v010, t2}});
- }
- }
- static void rebuildRenderData() {
- TypedBuffer<Mesh::Triangle> buffer(100);
- for(int x = 0; x < blocks.getSize(); x++) {
- for(int y = 0; y < blocks.getHeight(); y++) {
- for(int z = 0; z < blocks.getSize(); z++) {
- if(!isAir(x, y, z)) {
- addCube(buffer, x, y, z);
- }
- }
- }
- }
- mesh.build(buffer);
- LOG_DEBUG("world render update");
- }
- void World::render() {
- if(dirty) {
- rebuildRenderData();
- dirty = false;
- }
- texture.bindTo(0);
- for(int x = -1; x <= 1; x++) {
- for(int z = -1; z <= 1; z++) {
- Engine::matrix
- .translateTo(blocks.getSize() * x, 0.0f, blocks.getSize() * z)
- .update();
- mesh.draw();
- }
- }
- }
- int World::getHeight() {
- return blocks.getHeight();
- }
- void World::setBlock(int x, int y, int z, Block::Id block) {
- dirty = true;
- blocks.set(x, y, z, block);
- }
|