#include "Chunk.h" #include #include "Constants.h" #include "CustomDX11API.h" #include "FactoryCraftModel.h" #include "Globals.h" #include "Registries.h" Chunk::Chunk(Framework::Punkt location) : ReferenceCounter(), location(location), isLoading(0), lightChanged(0) { blocks = new Block*[CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT]; memset(blocks, 0, CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT * sizeof(Block*)); groundModel = new FactoryCraftModel(); Model3DData* chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->getModel( Text("chunk_ground_") + location.x + location.y); if (!chunkModel) { chunkModel = uiFactory.initParam.bildschirm->zGraphicsApi()->createModel( Text("chunk_ground_") + location.x + location.y); } chunkModel->setAmbientFactor(0.f); chunkModel->setDiffusFactor(1.f); chunkModel->setSpecularFactor(0.f); chunkModel->setVertecies(0, 0); groundModel->setModelDaten(chunkModel); groundModel->setPosition( (float)location.x, (float)location.y, (float)WORLD_HEIGHT / 2.f); groundModel->tick(0); } Chunk::Chunk(Framework::Punkt location, Framework::StreamReader* zReader) : Chunk(location) { load(zReader); buildGroundModel(); } Chunk::~Chunk() { char msg = 1; // remove observer if (World::INSTANCE) { World::INSTANCE->zClient()->chunkAPIRequest(location, &msg, 1); } for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } delete[] blocks; groundModel->release(); } void Chunk::appendAnimation( Block* zB, int boneId, double time, Vec3 pos, Vec3 rot) { if (!zB->zSkeleton() || !zB->zSkeleton()->zBone(boneId)) return; acs.lock(); for (BlockAnimation* animation : animations) { if (animation->zBlock() == zB) { animation->appendAnimation(boneId, time, pos, rot); acs.unlock(); return; } } SkeletonAnimation* sa = new SkeletonAnimation(); Bone* bone = zB->zSkeleton()->zBone(boneId); sa->addAnimation(boneId, bone->getPosition(), bone->getRotation()); sa->addKeyFrame(boneId, time, pos, rot); animations.add(new BlockAnimation(dynamic_cast(zB->getThis()), sa)); acs.unlock(); } void Chunk::load(Framework::StreamReader* zReader) { cs.lock(); for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { blocks[i]->release(); blocks[i] = 0; } } cs.unlock(); isLoading = 1; Framework::Vec3 pos = {0, 0, 0}; unsigned short id; zReader->lese((char*)&id, 2); int count = 0; while (id) { int index; zReader->lese((char*)&index, 4); pos = Vec3((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); if (blockTypes[id]->doesNeedInstance()) { cs.lock(); Block* b = blockTypes[id]->createBlock( {pos.x + location.x - CHUNK_SIZE / 2, pos.y + location.y - CHUNK_SIZE / 2, pos.z}); blocks[index] = b; cs.unlock(); vcs.lock(); if (b->isVisible()) { if (!blockTypes[id]->getModelInfo().getModelName().istGleich( "cube") && !blockTypes[id]->getModelInfo().getModelName().istGleich( "grass")) { b->tick(0); visibleBlocks.add(b); } } count++; vcs.unlock(); } zReader->lese((char*)&id, 2); } std::cout << "Loaded " << count << " blocks\n"; int index = 0; // light zReader->lese((char*)&index, 4); char lightData[6]; while (index >= -1) { if (index == -1) { int x = 0; int y = 0; int z = 0; zReader->lese((char*)&x, 4); zReader->lese((char*)&y, 4); zReader->lese((char*)&z, 4); zReader->lese(lightData, 6); if (x == -1) { int cacheIndex = y * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(WEST, (unsigned char*)lightData); } } else if (y == -1) { int cacheIndex = (x * CHUNK_SIZE) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(NORTH, (unsigned char*)lightData); } } else if (x == CHUNK_SIZE) { int cacheIndex = ((CHUNK_SIZE - 1) * CHUNK_SIZE + y) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(EAST, (unsigned char*)lightData); } } else if (y == CHUNK_SIZE) { int cacheIndex = (x * CHUNK_SIZE + (CHUNK_SIZE - 1)) * WORLD_HEIGHT + z; Block* zB = blocks[cacheIndex]; if (zB) { zB->setLightData(SOUTH, (unsigned char*)lightData); } } } else { zReader->lese(lightData, 6); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); for (int i = 0; i < 6; i++) { Framework::Vec3 pos = location + getDirection(getDirectionFromIndex(i)); if (pos.z >= 0 && pos.z < WORLD_HEIGHT) { if (pos.x >= 0 && pos.x < CHUNK_SIZE && pos.y >= 0 && pos.y < CHUNK_SIZE) { int cacheIndex = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; Block* zB = blocks[cacheIndex]; if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData); if (zB->isVisible() && !visible) { vcs.lock(); zB->tick(0); visibleBlocks.add(zB); vcs.unlock(); } } } else { pos.x += this->location.x - CHUNK_SIZE / 2; pos.y += this->location.y - CHUNK_SIZE / 2; Block* zB = World::INSTANCE->zBlockAt(pos); if (zB) { bool visible = zB->isVisible(); zB->setLightData( getOppositeDirection(getDirectionFromIndex(i)), (unsigned char*)lightData); if (zB->isVisible() && !visible) { Chunk* c = World::INSTANCE->zChunk( World::INSTANCE->getChunkCenter( pos.x, pos.y)); c->vcs.lock(); zB->tick(0); c->visibleBlocks.add(zB); c->vcs.unlock(); } } } } } } zReader->lese((char*)&index, 4); } isLoading = 0; } void Chunk::buildGroundModel() { vcs.lock(); visibleBlocks.leeren(); lightChanged = 0; Model3DData* chunkModel = groundModel->zModelData(); // remove old model while (chunkModel->getPolygonAnzahl() > 0) { chunkModel->removePolygon(0); } // calculate verticies Trie groundModelBuidler; Array groundPartArray; Vertex3D* groundVerticies = new Vertex3D[10000]; __int64* lightBuffer = new __int64[10000]; int groundVertexCount = 0; int groundVertexArraySize = 10000; for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { if (blocks[i] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("cube")) { blocks[i]->setPartOfGround(1); int index = 0; for (Text* textureName : *blocks[i]->zBlockType()->getModelInfo().getTexturNames()) { Framework::Vec3 location( (i / WORLD_HEIGHT) / CHUNK_SIZE, (i / WORLD_HEIGHT) % CHUNK_SIZE, i % WORLD_HEIGHT); if (isPartOfGroundModel(location, index)) { if (!groundModelBuidler.get( *textureName, textureName->getLength())) { GroundModelPart* part = new GroundModelPart(); part->indexList = new int[10000]; part->indexCount = 0; part->indexArraySize = 10000; part->name = *textureName; groundModelBuidler.set( *textureName, textureName->getLength(), part); groundPartArray.add(part); } GroundModelPart* part = groundModelBuidler.get( *textureName, textureName->getLength()); const Vertex3D* vBuffer = blocks[i]->zModelData()->zVertexBuffer(); Polygon3D* polygon = blocks[i]->zModelData()->getPolygon(index); if (part->indexCount + polygon->indexAnz > part->indexArraySize) { int* tmp = new int[part->indexArraySize + 10000]; memcpy(tmp, part->indexList, part->indexCount * 4); delete[] part->indexList; part->indexList = tmp; part->indexArraySize += 10000; } if (groundVertexCount + polygon->indexAnz > groundVertexArraySize) { Vertex3D* tmp = new Vertex3D[groundVertexArraySize + 10000]; memcpy(tmp, groundVerticies, groundVertexCount * sizeof(Vertex3D)); delete[] groundVerticies; groundVerticies = tmp; groundVertexArraySize += 10000; __int64* lTmp = new __int64[groundVertexArraySize]; memcpy(lTmp, lightBuffer, groundVertexCount * sizeof(__int64)); delete[] lightBuffer; lightBuffer = lTmp; } for (int vi = 0; vi < polygon->indexAnz; vi++) { lightBuffer[groundVertexCount] = calculateLight( vBuffer[polygon->indexList[vi]].pos, location, getDirectionFromIndex(index)); part->indexList[part->indexCount++] = groundVertexCount; groundVerticies[groundVertexCount++] = vBuffer[polygon->indexList[vi]]; groundVerticies[groundVertexCount - 1].pos += blocks[i]->getPos() - Vec3((float)this->location.x, (float)this->location.y, (float)WORLD_HEIGHT / 2.f); groundVerticies[groundVertexCount - 1].id = groundVertexCount - 1; } } index++; } } else if (blocks[i] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("grass")) { blocks[i]->setPartOfGround(1); __int64 light = blocks[i]->getMaxLight(); int index = 0; for (Text* textureName : *blocks[i]->zBlockType()->getModelInfo().getTexturNames()) { if (!groundModelBuidler.get( *textureName, textureName->getLength())) { GroundModelPart* part = new GroundModelPart(); part->indexList = new int[10000]; part->indexCount = 0; part->indexArraySize = 10000; part->name = *textureName; groundModelBuidler.set( *textureName, textureName->getLength(), part); groundPartArray.add(part); } GroundModelPart* part = groundModelBuidler.get( *textureName, textureName->getLength()); const Vertex3D* vBuffer = blocks[i]->zModelData()->zVertexBuffer(); Polygon3D* polygon = blocks[i]->zModelData()->getPolygon(index); if (part->indexCount + polygon->indexAnz > part->indexArraySize) { int* tmp = new int[part->indexArraySize + 10000]; memcpy(tmp, part->indexList, part->indexCount * 4); delete[] part->indexList; part->indexList = tmp; part->indexArraySize += 10000; } if (groundVertexCount + polygon->indexAnz > groundVertexArraySize) { Vertex3D* tmp = new Vertex3D[groundVertexArraySize + 10000]; memcpy(tmp, groundVerticies, groundVertexCount * sizeof(Vertex3D)); delete[] groundVerticies; groundVerticies = tmp; groundVertexArraySize += 10000; __int64* lTmp = new __int64[groundVertexArraySize]; memcpy(lTmp, lightBuffer, groundVertexCount * sizeof(__int64)); delete[] lightBuffer; lightBuffer = lTmp; } for (int vi = 0; vi < polygon->indexAnz; vi++) { lightBuffer[groundVertexCount] = light; part->indexList[part->indexCount++] = groundVertexCount; groundVerticies[groundVertexCount++] = vBuffer[polygon->indexList[vi]]; groundVerticies[groundVertexCount - 1].pos += blocks[i]->getPos() - Vec3((float)this->location.x, (float)this->location.y, (float)WORLD_HEIGHT / 2.f); groundVerticies[groundVertexCount - 1].id = groundVertexCount - 1; } index++; } } else { blocks[i]->setPartOfGround(0); visibleBlocks.add(blocks[i]); } } } Model3DTextur* textur = new Model3DTextur(); int pi = 0; for (GroundModelPart* part : groundPartArray) { Polygon3D* polygon = new Polygon3D(); polygon->indexAnz = part->indexCount; polygon->indexList = part->indexList; groundModel->zModelData()->addPolygon(polygon); textur->setPolygonTextur(pi, uiFactory.initParam.bildschirm->zGraphicsApi()->createOrGetTextur( part->name)); pi++; delete part; } groundModel->zModelData()->setVertecies(groundVerticies, groundVertexCount); groundModel->setModelTextur(textur); groundModel->setVertexLightBuffer(lightBuffer, groundVertexCount); vcs.unlock(); } void Chunk::updateGroundLight() { vcs.lock(); __int64* lightBuffer = groundModel->zLightBuffer(); int groundVertexCount = 0; for (int i = 0; i < CHUNK_SIZE * CHUNK_SIZE * WORLD_HEIGHT; i++) { if (blocks[i]) { if (blocks[i] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("cube")) { int index = 0; for (Text* textureName : *blocks[i]->zBlockType()->getModelInfo().getTexturNames()) { Framework::Vec3 location( (i / WORLD_HEIGHT) / CHUNK_SIZE, (i / WORLD_HEIGHT) % CHUNK_SIZE, i % WORLD_HEIGHT); if (isPartOfGroundModel(location, index)) { const Vertex3D* vBuffer = blocks[i]->zModelData()->zVertexBuffer(); Polygon3D* polygon = blocks[i]->zModelData()->getPolygon(index); for (int vi = 0; vi < polygon->indexAnz; vi++) { lightBuffer[groundVertexCount++] = calculateLight( vBuffer[polygon->indexList[vi]].pos, location, getDirectionFromIndex(index)); } } index++; } } else if (blocks[i] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("grass")) { __int64 light = blocks[i]->getMaxLight(); int index = 0; for (Text* textureName : *blocks[i]->zBlockType()->getModelInfo().getTexturNames()) { const Vertex3D* vBuffer = blocks[i]->zModelData()->zVertexBuffer(); Polygon3D* polygon = blocks[i]->zModelData()->getPolygon(index); for (int vi = 0; vi < polygon->indexAnz; vi++) { lightBuffer[groundVertexCount++] = light; } } } } } groundModel->copyLightToGPU(); vcs.unlock(); } __int64 Chunk::calculateLight( Vec3 vertexPos, Vec3 blockPos, Direction direction) { __int64 result = 0; int sumCount = 1; short lightSum[6]; Block* current = blocks[index(blockPos)]; const unsigned char* light = current->getLightData(direction); for (int i = 0; i < 6; i++) { lightSum[i] = (short)light[i]; } Vec3 vertexDirs(vertexPos.x < 0 ? -1 : 1, vertexPos.y < 0 ? -1 : 1, vertexPos.z < 0 ? -1 : 1); Directions dirs = getDirectionsFromVector(vertexDirs) & ~direction; Vec3 neighborDirs[3]; int neighborIndex = 0; for (int i = 0; i < 6; i++) { Direction dir = getDirectionFromIndex(i); if ((dirs | dir) == dirs) { neighborDirs[neighborIndex++] = getDirection(dir); if (neighborIndex == 2) break; } } neighborDirs[2] = neighborDirs[0] + neighborDirs[1]; for (int i = 0; i < 3; i++) { neighborDirs[i] += blockPos; if (neighborDirs[i].x >= 0 && neighborDirs[i].y >= 0 && neighborDirs[i].z >= 0 && neighborDirs[i].x < CHUNK_SIZE && neighborDirs[i].y < CHUNK_SIZE && neighborDirs[i].z < WORLD_HEIGHT) { int neighborIndex = index(neighborDirs[i]); Block* neighbor = blocks[neighborIndex]; if (neighbor) { const unsigned char* neighborLight = neighbor->getLightData(direction); if ((neighborLight[0] | neighborLight[1] | neighborLight[2] | neighborLight[3] | neighborLight[4] | neighborLight[5]) != 0) { sumCount++; for (int j = 0; j < 6; j++) { lightSum[j] += (short)neighborLight[j]; } } } } else { // TODO: get light from neighbor chunk } } for (int i = 0; i < 6; i++) { lightSum[i] = (lightSum[i] / sumCount) & 0xFF; } result = ((__int64)lightSum[0] << 24) | ((__int64)lightSum[1] << 16) | ((__int64)lightSum[2] << 8) | ((__int64)lightSum[3] << 56) | ((__int64)lightSum[4] << 48) | ((__int64)lightSum[5] << 40); return result; } bool Chunk::isPartOfGroundModel( Framework::Vec3 location, int directionIndex) { Framework::Vec3 neighborLocation = location + getDirection(getDirectionFromIndex(directionIndex)); bool needed = 0; if (neighborLocation.x < 0 || neighborLocation.y < 0 || neighborLocation.z < 0 || neighborLocation.x >= CHUNK_SIZE || neighborLocation.y >= CHUNK_SIZE || neighborLocation.z >= WORLD_HEIGHT) { needed = 1; } else { int naighborIndex = index(neighborLocation); if (!blocks[naighborIndex] || !blocks[naighborIndex] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("cube")) { needed = 1; } } return needed; } void Chunk::renderSolid(std::function f) { vcs.lock(); CustomDX11API* api = (CustomDX11API*)uiFactory.initParam.bildschirm->zGraphicsApi(); api->setCullBack(false); f(groundModel); api->setCullBack(true); float dist = 0.f; if (api->isInFrustrum(groundModel->getPos(), (CHUNK_SIZE / 2.f, CHUNK_SIZE / 2.f, WORLD_HEIGHT / 2.f), &dist)) { for (Block* b : visibleBlocks) { f(b); } } vcs.unlock(); } void Chunk::renderTransparent(std::function f) {} bool Chunk::tick(std::function f, double time) { acs.lock(); vcs.lock(); // TODO: enshure no dead lock occures if (modelChanged) { modelChanged = 0; buildGroundModel(); } if (lightChanged) { lightChanged = 0; updateGroundLight(); } bool res = groundModel->tick(time); auto iterator = animations.begin(); while (iterator) { if (iterator->tick(time)) { res |= iterator->zBlock()->tick(time); if (iterator->isFinished()) { iterator.remove(); continue; } } else { iterator.remove(); continue; } ++iterator; } vcs.unlock(); acs.unlock(); return 1; } void Chunk::destroy() { Model3DData* chunkModel = groundModel->zModelData(); // remove old model while (chunkModel->getPolygonAnzahl() > 0) { chunkModel->removePolygon(0); } chunkModel->setVertecies(0, 0); } void Chunk::api(char* message) { switch (message[0]) { case 0: // set block { int index = *(int*)(message + 1); int id = *(int*)(message + 5); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); location.x += this->location.x - CHUNK_SIZE / 2; location.y += this->location.y - CHUNK_SIZE / 2; if (blockTypes[id]->doesNeedInstance()) { Block* zB = blockTypes[id]->createBlock(location); setBlock(zB); } else { Block* zB = zBlockAt(location); if (zB) removeBlock(zB); } break; } case 1: // animate block { int index = *(int*)(message + 1); int boneId = *(int*)(message + 5); double time = *(double*)(message + 9); Framework::Vec3 pos; pos.x = *(float*)(message + 17); pos.y = *(float*)(message + 21); pos.z = *(float*)(message + 25); Framework::Vec3 rot; rot.x = *(float*)(message + 29); rot.y = *(float*)(message + 33); rot.z = *(float*)(message + 37); Framework::Vec3 location((index / WORLD_HEIGHT) / CHUNK_SIZE, (index / WORLD_HEIGHT) % CHUNK_SIZE, index % WORLD_HEIGHT); location.x += this->location.x - CHUNK_SIZE / 2; location.y += this->location.y - CHUNK_SIZE / 2; Block* zB = zBlockAt(location); if (zB) appendAnimation(zB, boneId, time, pos, rot); break; } } } Block* Chunk::zBlockAt(Framework::Vec3 location) { location.x = location.x % CHUNK_SIZE; location.y = location.y % CHUNK_SIZE; if (location.x < 0) location.x += CHUNK_SIZE; if (location.y < 0) location.y += CHUNK_SIZE; int index = (location.x * CHUNK_SIZE + location.y) * WORLD_HEIGHT + location.z; return blocks[index]; } void Chunk::setBlock(Block* block) { cs.lock(); Framework::Vec3 pos = block->getLocation(); pos.x = pos.x % CHUNK_SIZE; pos.y = pos.y % CHUNK_SIZE; if (pos.x < 0) pos.x += CHUNK_SIZE; if (pos.y < 0) pos.y += CHUNK_SIZE; int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; bool newAffectsGround = block && (block->zBlockType()->getModelInfo().getModelName().istGleich("cube") || block->zBlockType()->getModelInfo().getModelName().istGleich( "grass")); bool affectsGround = blocks[index] && (blocks[index]->zBlockType()->getModelInfo().getModelName().istGleich( "cube") || blocks[index] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("grass")); if (blocks[index]) { vcs.lock(); for (Framework::Iterator vi = visibleBlocks.begin(); vi; vi++) { if (blocks[index] == (Block*)vi) { vi.remove(); break; } } vcs.unlock(); blocks[index]->copyLightTo(block); blocks[index]->release(); blocks[index] = block; cs.unlock(); vcs.lock(); if (affectsGround || newAffectsGround) { modelChanged = 1; } if (block && block->isVisible() && !newAffectsGround) { block->tick(0); visibleBlocks.add(block); } vcs.unlock(); return; } blocks[index] = block; cs.unlock(); vcs.lock(); if (affectsGround || newAffectsGround) { modelChanged = 1; } if (block && block->isVisible() && !newAffectsGround) { block->tick(0); visibleBlocks.add(block); } vcs.unlock(); } void Chunk::removeBlock(Block* zBlock) { cs.lock(); vcs.lock(); for (Framework::Iterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zBlock == (Block*)iterator) { iterator.remove(); break; } } vcs.unlock(); Vec3 pos = zBlock->getLocation(); pos.x = pos.x % CHUNK_SIZE; pos.y = pos.y % CHUNK_SIZE; if (pos.x < 0) pos.x += CHUNK_SIZE; if (pos.y < 0) pos.y += CHUNK_SIZE; int index = (pos.x * CHUNK_SIZE + pos.y) * WORLD_HEIGHT + pos.z; if (blocks[index]) { bool affectsGround = blocks[index] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("cube") || blocks[index] ->zBlockType() ->getModelInfo() .getModelName() .istGleich("grass"); blocks[index]->release(); blocks[index] = 0; if (affectsGround) modelChanged = 1; } cs.unlock(); } void Chunk::blockVisibilityChanged(Block* zB) { vcs.lock(); if (zB->isVisible()) { zB->tick(0); visibleBlocks.add(zB); } else { for (Framework::Iterator iterator = visibleBlocks.begin(); iterator; iterator++) { if (zB == (Block*)iterator) { iterator.remove(); break; } } } vcs.unlock(); } Framework::Punkt Chunk::getCenter() const { return location; } Framework::Vec3 Chunk::getMin() const { return {location.x - CHUNK_SIZE / 2, location.y - CHUNK_SIZE / 2, 0}; } Framework::Vec3 Chunk::getMax() const { return { location.x + CHUNK_SIZE / 2, location.y + CHUNK_SIZE / 2, WORLD_HEIGHT}; } void Chunk::setGroundChanged() { modelChanged = 1; } void Chunk::setLightChanged() { lightChanged = 1; }