2828int Chunk::updates = 0 ;
2929
3030#if defined(_LARGE_WORLDS)
31- thread_local uint8_t * Chunk::m_tlsTileIds = nullptr ;
31+ static thread_local unsigned char s_tlsTileIds[ 16 * 16 * Level::maxBuildHeight] ;
3232
33- void Chunk::CreateNewThreadStorage () {
34- m_tlsTileIds = new unsigned char [16 * 16 * Level::maxBuildHeight];
35- }
33+ void Chunk::CreateNewThreadStorage () {}
3634
37- void Chunk::ReleaseThreadStorage () { delete m_tlsTileIds; }
35+ void Chunk::ReleaseThreadStorage () {}
3836
39- uint8_t * Chunk::GetTileIdsStorage () { return m_tlsTileIds ; }
37+ uint8_t * Chunk::GetTileIdsStorage () { return s_tlsTileIds ; }
4038#else
4139// 4J Stu - Don't want this when multi-threaded
4240Tesselator* Chunk::t = Tesselator::getInstance();
@@ -272,19 +270,33 @@ void Chunk::rebuild() {
272270 static unsigned char tileIds[16 * 16 * Level::maxBuildHeight];
273271#endif
274272 std::vector<uint8_t > tileArray (16 * 16 * Level::maxBuildHeight);
275- level->getChunkAt (x, z)->getBlockData (tileArray);
273+ LevelChunk* sourceChunk = level->getChunkAt (x, z);
274+
275+ if (sourceChunk == nullptr ) {
276+ // Level chunk not loaded yet - treat as empty
277+ for (int currentLayer = 0 ; currentLayer < 2 ; currentLayer++) {
278+ levelRenderer->setGlobalChunkFlag (this ->x , this ->y , this ->z , level,
279+ LevelRenderer::CHUNK_FLAG_EMPTY0,
280+ currentLayer);
281+ PlatformRenderer.CBuffClear (lists + currentLayer);
282+ }
283+
284+ levelRenderer->setGlobalChunkFlag (this ->x , this ->y , this ->z , level,
285+ LevelRenderer::CHUNK_FLAG_NOTSKYLIT);
286+ levelRenderer->setGlobalChunkFlag (this ->x , this ->y , this ->z , level,
287+ LevelRenderer::CHUNK_FLAG_COMPILED);
288+
289+ return ;
290+ }
291+
292+ sourceChunk->getBlockData (tileArray);
276293 memcpy (
277294 tileIds, tileArray.data (),
278295 16 * 16 * Level::maxBuildHeight); // 4J - TODO - now our data has been
279296 // re-arranged, we could just extra
280297 // the vertical slice of this chunk
281298 // rather than the whole thing
282299
283- LevelSource* region =
284- new Region (level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r, r);
285- TileRenderer* tileRenderer =
286- new TileRenderer (region, this ->x , this ->y , this ->z , tileIds);
287-
288300 // AP - added a caching system for Chunk::rebuild to take advantage of
289301 // Basically we're storing of copy of the tileIDs array inside the region so
290302 // that calls to Region::getTile can grab data more quickly from this array
@@ -299,6 +311,16 @@ void Chunk::rebuild() {
299311 // tesselateInWorld in the unoptimised version of this function fall
300312 // into this category. By far the largest category of these are tiles in
301313 // solid regions of rock.
314+ static thread_local auto isOccluder = [] {
315+ std::array<bool , 256 > table{};
316+ for (int id = 1 ; id < 256 ; id++) {
317+ Tile* tile = Tile::tiles[id];
318+ if (tile != nullptr && tile->isSolidRender ()) table[id] = true ;
319+ }
320+ table[255 ] = true ; // already-marked-invisible
321+ return table;
322+ }();
323+
302324 bool empty = true ;
303325 {
304326 FRAME_PROFILE_SCOPE (ChunkPrepass);
@@ -319,50 +341,37 @@ void Chunk::rebuild() {
319341 (indexY + 0 ))];
320342 if (tileId > 0 ) empty = false ;
321343
322- // Don't bother trying to work out neighbours for this tile
323- // if we are at the edge of the chunk - apart from the very
324- // bottom of the world where we shouldn't ever be able to
325- // see
344+ // Don't bother trying to work out neighbours for this
345+ // tile if we are at the edge of the chunk - apart from
346+ // the very bottom of the world where we shouldn't ever
347+ // be able to see
326348 if (yy == (Level::maxBuildHeight - 1 )) continue ;
327349 if ((xx == 0 ) || (xx == 15 )) continue ;
328350 if ((zz == 0 ) || (zz == 15 )) continue ;
329351
330- // Establish whether this tile and its neighbours are all
331- // made of rock, dirt, unbreakable tiles, or have already
332- // been determined to meet this criteria themselves and have
333- // a tile of 255 set.
334- if (!((tileId == Tile::stone_Id) ||
335- (tileId == Tile::dirt_Id) ||
336- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
337- continue ;
338- tileId = tileIds[offset + (((xx - 1 ) << 11 ) |
339- ((zz + 0 ) << 7 ) | (indexY + 0 ))];
340- if (!((tileId == Tile::stone_Id) ||
341- (tileId == Tile::dirt_Id) ||
342- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
352+ // Establish whether this tile and its neighbours are
353+ // all occluders using lookup table
354+ if (!isOccluder[tileId]) continue ;
355+ if (!isOccluder[tileIds[offset + (((xx - 1 ) << 11 ) |
356+ ((zz + 0 ) << 7 ) |
357+ (indexY + 0 ))]])
343358 continue ;
344- tileId = tileIds[offset + (((xx + 1 ) << 11 ) |
345- ((zz + 0 ) << 7 ) | (indexY + 0 ))];
346- if (!((tileId == Tile::stone_Id) ||
347- (tileId == Tile::dirt_Id) ||
348- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
359+ if (!isOccluder[tileIds[offset + (((xx + 1 ) << 11 ) |
360+ ((zz + 0 ) << 7 ) |
361+ (indexY + 0 ))]])
349362 continue ;
350- tileId = tileIds[offset + (((xx + 0 ) << 11 ) |
351- ((zz - 1 ) << 7 ) | (indexY + 0 ))];
352- if (!((tileId == Tile::stone_Id) ||
353- (tileId == Tile::dirt_Id) ||
354- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
363+ if (!isOccluder[tileIds[offset + (((xx + 0 ) << 11 ) |
364+ ((zz - 1 ) << 7 ) |
365+ (indexY + 0 ))]])
355366 continue ;
356- tileId = tileIds[offset + (((xx + 0 ) << 11 ) |
357- ((zz + 1 ) << 7 ) | (indexY + 0 ))];
358- if (!((tileId == Tile::stone_Id) ||
359- (tileId == Tile::dirt_Id) ||
360- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
367+ if (!isOccluder[tileIds[offset + (((xx + 0 ) << 11 ) |
368+ ((zz + 1 ) << 7 ) |
369+ (indexY + 0 ))]])
361370 continue ;
362- // Treat the bottom of the world differently - we shouldn't
363- // ever be able to look up at this, so consider tiles as
364- // invisible if they are surrounded on sides other than the
365- // bottom
371+ // Treat the bottom of the world differently - we
372+ // shouldn't ever be able to look up at this, so
373+ // consider tiles as invisible if they are surrounded on
374+ // sides other than the bottom
366375 if (yy > 0 ) {
367376 int indexYMinusOne = yy - 1 ;
368377 int yMinusOneOffset = 0 ;
@@ -373,13 +382,10 @@ void Chunk::rebuild() {
373382 yMinusOneOffset =
374383 Level::COMPRESSED_CHUNK_SECTION_TILES;
375384 }
376- tileId = tileIds[yMinusOneOffset + (((xx + 0 ) << 11 ) |
377- ((zz + 0 ) << 7 ) |
378- indexYMinusOne)];
379- if (!((tileId == Tile::stone_Id) ||
380- (tileId == Tile::dirt_Id) ||
381- (tileId == Tile::unbreakable_Id) ||
382- (tileId == 255 )))
385+ if (!isOccluder[tileIds[yMinusOneOffset +
386+ (((xx + 0 ) << 11 ) |
387+ ((zz + 0 ) << 7 ) |
388+ indexYMinusOne)]])
383389 continue ;
384390 }
385391 int indexYPlusOne = yy + 1 ;
@@ -389,16 +395,13 @@ void Chunk::rebuild() {
389395 indexYPlusOne -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT;
390396 yPlusOneOffset = Level::COMPRESSED_CHUNK_SECTION_TILES;
391397 }
392- tileId = tileIds[yPlusOneOffset + (((xx + 0 ) << 11 ) |
393- ((zz + 0 ) << 7 ) |
394- indexYPlusOne)];
395- if (!((tileId == Tile::stone_Id) ||
396- (tileId == Tile::dirt_Id) ||
397- (tileId == Tile::unbreakable_Id) || (tileId == 255 )))
398+ if (!isOccluder[tileIds[yPlusOneOffset + (((xx + 0 ) << 11 ) |
399+ ((zz + 0 ) << 7 ) |
400+ indexYPlusOne)]])
398401 continue ;
399402
400- // This tile is surrounded. Flag it as not requiring to be
401- // rendered by setting its id to 255.
403+ // This tile is surrounded. Flag it as not requiring to
404+ // be rendered by setting its id to 255.
402405 tileIds[offset + (((xx + 0 ) << 11 ) | ((zz + 0 ) << 7 ) |
403406 (indexY + 0 ))] = 0xff ;
404407 }
@@ -424,13 +427,14 @@ void Chunk::rebuild() {
424427 LevelRenderer::CHUNK_FLAG_COMPILED);
425428#endif
426429
427- delete region;
428- delete tileRenderer;
429430 return ;
430431 }
431432 // 4J - optimisation ends
432433 // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
433434
435+ Region region (level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r, r);
436+ TileRenderer tileRenderer (®ion, this ->x , this ->y , this ->z , tileIds);
437+
434438 Tesselator::Bounds bounds; // 4J MGH - added
435439 {
436440 // this was the old default clip bounds for the chunk, set in
@@ -465,14 +469,15 @@ void Chunk::rebuild() {
465469
466470 // 4J - get tile from those copied into our local array in
467471 // earlier optimisation
468- unsigned char tileId =
472+ const unsigned char tileId =
469473 tileIds[offset +
470474 (((x - x0) << 11 ) | ((z - z0) << 7 ) | indexY)];
471475 // If flagged as not visible, drop out straight away
472- if (tileId == 0xff ) continue ;
476+ if (tileId == 0xff ) [[unlikely]]
477+ continue ;
473478 // int tileId =
474479 // region->getTile(x,y,z);
475- if (tileId > 0 ) {
480+ if (tileId > 0 ) [[unlikely]] {
476481 if (!started) {
477482 started = true ;
478483
@@ -487,7 +492,7 @@ void Chunk::rebuild() {
487492 Tile* tile = Tile::tiles[tileId];
488493 if (currentLayer == 0 && tile->isEntityTile ()) {
489494 std::shared_ptr<TileEntity> et =
490- region-> getTileEntity (x, y, z);
495+ region. getTileEntity (x, y, z);
491496 if (TileEntityRenderDispatcher::instance
492497 ->hasRenderer (et)) {
493498 renderableTileEntities.push_back (et);
@@ -499,7 +504,7 @@ void Chunk::rebuild() {
499504 renderNextLayer = true ;
500505 } else if (renderLayer == currentLayer) {
501506 rendered |=
502- tileRenderer-> tesselateInWorld (tile, x, y, z);
507+ tileRenderer. tesselateInWorld (tile, x, y, z);
503508 }
504509 }
505510 }
@@ -548,9 +553,6 @@ void Chunk::rebuild() {
548553 levelRenderer->setGlobalChunkConnectivity (globalIdx, conn);
549554#endif
550555
551- delete tileRenderer;
552- delete region;
553-
554556 // 4J - have rewritten the way that tile entities are stored globally to
555557 // make it work more easily with split screen. Chunks are now stored
556558 // globally in the levelrenderer, in a hashmap with a special key made up
0 commit comments