|
@@ -423,79 +423,166 @@ void Chunk::api(Framework::StreamReader* zRequest,
|
|
|
|
|
|
void Chunk::initializeLightning()
|
|
|
{
|
|
|
- // TODO: initialize only daylight with a more efficient algorithm here and
|
|
|
- // add all light sources to the light update thread when the chunk is added
|
|
|
- // to the map
|
|
|
- unsigned char dayLight[6] = {255, 255, 255, 0, 0, 0};
|
|
|
- unsigned char noLight[6] = {0, 0, 0, 0, 0, 0};
|
|
|
- while (true)
|
|
|
+ unsigned char dayLight[3] = {255, 255, 255};
|
|
|
+ unsigned char noLight[3] = {0, 0, 0};
|
|
|
+ unsigned short visited[CHUNK_SIZE][WORLD_HEIGHT];
|
|
|
+ memset(visited, 0, sizeof(visited));
|
|
|
+ int minZ = 0;
|
|
|
+ int goUps = 0;
|
|
|
+ for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
|
|
|
{
|
|
|
- bool changes = false;
|
|
|
- for (int z = WORLD_HEIGHT - 1; z >= 0; z--)
|
|
|
+ minZ = z;
|
|
|
+ unsigned char max[3] = {0, 0, 0};
|
|
|
+ bool allVisited = 1;
|
|
|
+ for (int x = 0; x < CHUNK_SIZE; x++)
|
|
|
{
|
|
|
- for (int x = 0; x < CHUNK_SIZE; x++)
|
|
|
+ for (int y = 0; y < CHUNK_SIZE; y++)
|
|
|
{
|
|
|
- for (int y = 0; y < CHUNK_SIZE; y++)
|
|
|
+ if (visited[y][z] & (1 << x)) continue;
|
|
|
+ unsigned char* lightAbove
|
|
|
+ = z == WORLD_HEIGHT - 1
|
|
|
+ ? dayLight
|
|
|
+ : getLightData(Framework::Vec3<int>(x, y, z + 1));
|
|
|
+ if (lightAbove[0] | lightAbove[1] | lightAbove[2])
|
|
|
{
|
|
|
- int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
|
|
|
+ visited[y][z] |= 1 << x;
|
|
|
unsigned char* light
|
|
|
= getLightData(Framework::Vec3<int>(x, y, z));
|
|
|
- unsigned char newLight[6] = {0, 0, 0, 0, 0, 0};
|
|
|
- for (int i = 0; i < 6; i++)
|
|
|
- {
|
|
|
- unsigned char* neighborLeight;
|
|
|
- Framework::Vec3<int> neighborPos
|
|
|
- = Framework::Vec3<int>(x, y, z)
|
|
|
- + getDirection(getDirectionFromIndex(i));
|
|
|
- if (neighborPos.z < 0 || neighborPos.x < 0
|
|
|
- || neighborPos.y < 0 || neighborPos.x >= CHUNK_SIZE
|
|
|
- || neighborPos.y >= CHUNK_SIZE)
|
|
|
- {
|
|
|
- neighborLeight = noLight;
|
|
|
- }
|
|
|
- else if (neighborPos.z >= WORLD_HEIGHT)
|
|
|
- {
|
|
|
- neighborLeight = dayLight;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- neighborLeight = getLightData(neighborPos);
|
|
|
- }
|
|
|
- for (int j = 0; j < 3; j++)
|
|
|
- newLight[j] = (unsigned char)MAX(newLight[j],
|
|
|
- i == getDirectionIndex(TOP)
|
|
|
- ? neighborLeight[j]
|
|
|
- : (unsigned char)((float)neighborLeight[j]
|
|
|
- * 0.8f));
|
|
|
- for (int j = 3; j < 6; j++)
|
|
|
- newLight[j] = (unsigned char)MAX(newLight[j],
|
|
|
- (unsigned char)((float)neighborLeight[j]
|
|
|
- * 0.85f));
|
|
|
- }
|
|
|
+ int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
|
|
|
const Block* current
|
|
|
= blocks[index]
|
|
|
? blocks[index]
|
|
|
: Game::INSTANCE->zBlockType(blockIds[index])
|
|
|
->zDefault();
|
|
|
- // add own light emission
|
|
|
- for (int j = 3; j < 6; j++)
|
|
|
- newLight[j] = (unsigned char)MAX(newLight[j],
|
|
|
- current->getLightEmisionColor()[j - 3]);
|
|
|
- current->filterPassingLight(newLight);
|
|
|
- current->filterPassingLight(newLight + 3);
|
|
|
- for (int i = 0; i < 6; i++)
|
|
|
+ light[0] = lightAbove[0];
|
|
|
+ light[1] = lightAbove[1];
|
|
|
+ light[2] = lightAbove[2];
|
|
|
+ current->filterPassingLight(light);
|
|
|
+ max[0] = MAX(max[0], lightAbove[0]);
|
|
|
+ max[1] = MAX(max[1], lightAbove[1]);
|
|
|
+ max[2] = MAX(max[2], lightAbove[2]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ allVisited = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!(max[0] | max[1] | max[2])) break;
|
|
|
+ if (!allVisited)
|
|
|
+ {
|
|
|
+ bool goUp = 1;
|
|
|
+ while (goUp)
|
|
|
+ {
|
|
|
+ goUp = 0;
|
|
|
+ bool changes = 1;
|
|
|
+ while (changes)
|
|
|
+ {
|
|
|
+ changes = 0;
|
|
|
+ for (int x = 0; x < CHUNK_SIZE; x++)
|
|
|
{
|
|
|
- if (newLight[i] != light[i])
|
|
|
+ for (int y = 0; y < CHUNK_SIZE; y++)
|
|
|
{
|
|
|
- changes = 1;
|
|
|
- memcpy(light, newLight, 6);
|
|
|
- break;
|
|
|
+ int index = (x * CHUNK_SIZE + y) * WORLD_HEIGHT + z;
|
|
|
+ unsigned char* light
|
|
|
+ = getLightData(Framework::Vec3<int>(x, y, z));
|
|
|
+ const Block* current
|
|
|
+ = blocks[index]
|
|
|
+ ? blocks[index]
|
|
|
+ : Game::INSTANCE
|
|
|
+ ->zBlockType(blockIds[index])
|
|
|
+ ->zDefault();
|
|
|
+ unsigned char newLight[3] = {0, 0, 0};
|
|
|
+ for (int i = 0; i < 4; i++)
|
|
|
+ {
|
|
|
+ Framework::Vec3<int> neighborPos
|
|
|
+ = Framework::Vec3<int>(x, y, z)
|
|
|
+ + getDirection(getDirectionFromIndex(i));
|
|
|
+ if (neighborPos.x < 0 || neighborPos.y < 0
|
|
|
+ || neighborPos.x >= CHUNK_SIZE
|
|
|
+ || neighborPos.y >= CHUNK_SIZE)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ unsigned char* neighborLeight
|
|
|
+ = getLightData(neighborPos);
|
|
|
+ for (int j = 0; j < 3; j++)
|
|
|
+ {
|
|
|
+ newLight[j] = (unsigned char)MAX(
|
|
|
+ newLight[j],
|
|
|
+ (unsigned char)((float)neighborLeight[j]
|
|
|
+ * 0.8f));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ current->filterPassingLight(newLight);
|
|
|
+ if (newLight[0] > light[0] || newLight[1] > light[1]
|
|
|
+ || newLight[2] > light[2])
|
|
|
+ {
|
|
|
+ changes = 1;
|
|
|
+ light[0] = MAX(light[0], newLight[0]);
|
|
|
+ light[1] = MAX(light[1], newLight[1]);
|
|
|
+ light[2] = MAX(light[2], newLight[2]);
|
|
|
+ if (z < WORLD_HEIGHT - 1
|
|
|
+ && !(visited[y][z + 1] & (1 << x)))
|
|
|
+ {
|
|
|
+ unsigned char* lightAbove = getLightData(
|
|
|
+ Framework::Vec3<int>(x, y, z + 1));
|
|
|
+ newLight[0]
|
|
|
+ = (unsigned char)(light[0] * 0.8f);
|
|
|
+ newLight[1]
|
|
|
+ = (unsigned char)(light[1] * 0.8f);
|
|
|
+ newLight[2]
|
|
|
+ = (unsigned char)(light[2] * 0.8f);
|
|
|
+ const Block* above
|
|
|
+ = blocks[index - 1]
|
|
|
+ ? blocks[index - 1]
|
|
|
+ : Game::INSTANCE
|
|
|
+ ->zBlockType(
|
|
|
+ blockIds[index - 1])
|
|
|
+ ->zDefault();
|
|
|
+ above->filterPassingLight(newLight);
|
|
|
+ if (newLight[0] > lightAbove[0]
|
|
|
+ || newLight[1] > lightAbove[1]
|
|
|
+ || newLight[2] > lightAbove[2])
|
|
|
+ {
|
|
|
+ lightAbove[0]
|
|
|
+ = MAX(lightAbove[0], newLight[0]);
|
|
|
+ lightAbove[1]
|
|
|
+ = MAX(lightAbove[1], newLight[1]);
|
|
|
+ lightAbove[2]
|
|
|
+ = MAX(lightAbove[2], newLight[2]);
|
|
|
+ visited[y][z + 1] |= 1 << x;
|
|
|
+ goUp = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ if (goUp)
|
|
|
+ {
|
|
|
+ z++;
|
|
|
+ goUps++;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- if (!changes) break;
|
|
|
+ }
|
|
|
+ Framework::Logging::debug() << "goUps: " << goUps << " minZ: " << minZ;
|
|
|
+}
|
|
|
+
|
|
|
+void Chunk::updateLightSources()
|
|
|
+{
|
|
|
+ Dimension* zDim = Game::INSTANCE->zDimension(dimensionId);
|
|
|
+ for (int i : lightSources)
|
|
|
+ {
|
|
|
+ int x = (i / WORLD_HEIGHT) / CHUNK_SIZE;
|
|
|
+ int y = (i / WORLD_HEIGHT) % CHUNK_SIZE;
|
|
|
+ int z = i % WORLD_HEIGHT;
|
|
|
+ Framework::Vec3<int> pos = {x, y, z};
|
|
|
+ zDim->updateLightning(
|
|
|
+ Framework::Vec3<int>(x + this->location.x - CHUNK_SIZE / 2,
|
|
|
+ y + this->location.y - CHUNK_SIZE / 2,
|
|
|
+ z));
|
|
|
}
|
|
|
}
|
|
|
|