mirror of
https://github.com/4jcraft/4jcraft.git
synced 2026-04-23 14:33:36 +00:00
more-optimizations: first batch of optimizations at the levelrenderer
level
This commit is contained in:
parent
1f928fd28a
commit
8d4dd1a1d0
|
|
@ -13,11 +13,10 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "LevelRenderer.h"
|
||||
#include "app/linux/Stubs/winapi_stubs.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "TileRenderer.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "app/linux/Stubs/winapi_stubs.h"
|
||||
#include "minecraft/client/renderer/Tesselator.h"
|
||||
#include "minecraft/client/renderer/culling/Culler.h"
|
||||
#include "minecraft/client/renderer/tileentity/TileEntityRenderDispatcher.h"
|
||||
|
|
@ -29,6 +28,7 @@
|
|||
#include "minecraft/world/level/tile/Tile.h"
|
||||
#include "minecraft/world/level/tile/entity/TileEntity.h"
|
||||
#include "minecraft/world/phys/AABB.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
|
||||
int Chunk::updates = 0;
|
||||
|
||||
|
|
@ -174,6 +174,11 @@ void Chunk::setPos(int x, int y, int z) {
|
|||
levelRenderer->m_csDirtyChunks);
|
||||
unsigned char refCount =
|
||||
levelRenderer->incGlobalChunkRefCount(x, y, z, level);
|
||||
if ((clipChunk->globalIdx >= 0) &&
|
||||
((size_t)clipChunk->globalIdx <
|
||||
levelRenderer->m_globalClipChunks.size())) {
|
||||
levelRenderer->m_globalClipChunks[clipChunk->globalIdx] = clipChunk;
|
||||
}
|
||||
// printf("\t\t [inc] refcount %d at %d, %d, %d\n",refCount,x,y,z);
|
||||
|
||||
// int idx = levelRenderer->getGlobalIndexForChunk(x, y, z, level);
|
||||
|
|
@ -223,8 +228,15 @@ void Chunk::makeCopyForRebuild(Chunk* source) {
|
|||
this->globalRenderableTileEntities = source->globalRenderableTileEntities;
|
||||
this->globalRenderableTileEntities_cs =
|
||||
source->globalRenderableTileEntities_cs;
|
||||
this->buildContext = source->buildContext;
|
||||
}
|
||||
|
||||
void Chunk::setBuildContext(const ChunkBuildContext& ctx) {
|
||||
buildContext = ctx;
|
||||
}
|
||||
|
||||
const ChunkBuildContext& Chunk::getBuildContext() const { return buildContext; }
|
||||
|
||||
void Chunk::rebuild() {
|
||||
// if (!dirty) return;
|
||||
|
||||
|
|
@ -285,8 +297,8 @@ void Chunk::rebuild() {
|
|||
|
||||
LevelSource* region =
|
||||
new Region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r, r);
|
||||
TileRenderer* tileRenderer =
|
||||
new TileRenderer(region, this->x, this->y, this->z, tileIds);
|
||||
TileRenderer* tileRenderer = new TileRenderer(
|
||||
region, this->x, this->y, this->z, tileIds, &buildContext);
|
||||
|
||||
// AP - added a caching system for Chunk::rebuild to take advantage of
|
||||
// Basically we're storing of copy of the tileIDs array inside the region so
|
||||
|
|
@ -542,10 +554,14 @@ void Chunk::rebuild() {
|
|||
bb = {bounds.boundingBox[0], bounds.boundingBox[1], bounds.boundingBox[2],
|
||||
bounds.boundingBox[3], bounds.boundingBox[4], bounds.boundingBox[5]};
|
||||
|
||||
uint64_t conn = computeConnectivity(tileIds); // pass tileIds
|
||||
int globalIdx =
|
||||
levelRenderer->getGlobalIndexForChunk(this->x, this->y, this->z, level);
|
||||
#if defined(OCCLUSION_MODE_BFS)
|
||||
uint64_t conn = computeConnectivity(tileIds); // pass tileIds
|
||||
levelRenderer->setGlobalChunkConnectivity(globalIdx, conn);
|
||||
#else
|
||||
levelRenderer->setGlobalChunkConnectivity(globalIdx, ~0ULL);
|
||||
#endif
|
||||
|
||||
delete tileRenderer;
|
||||
delete region;
|
||||
|
|
@ -590,6 +606,7 @@ float Chunk::squishedDistanceToSqr(std::shared_ptr<Entity> player) {
|
|||
return xd * xd + yd * yd + zd * zd;
|
||||
}
|
||||
|
||||
#if defined(OCCLUSION_MODE_BFS)
|
||||
uint64_t Chunk::computeConnectivity(const uint8_t* tileIds) {
|
||||
const int W = 16;
|
||||
const int H = 16;
|
||||
|
|
@ -726,6 +743,7 @@ uint64_t Chunk::computeConnectivity(const uint8_t* tileIds) {
|
|||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
void Chunk::reset() {
|
||||
if (assigned) {
|
||||
int oldKey = -1;
|
||||
|
|
@ -742,6 +760,9 @@ void Chunk::reset() {
|
|||
//%d\n",refCount,x,y,z);
|
||||
if (refCount == 0 && oldKey != -1) {
|
||||
retireRenderableTileEntities = true;
|
||||
if ((size_t)oldKey < levelRenderer->m_globalClipChunks.size()) {
|
||||
levelRenderer->m_globalClipChunks[oldKey] = nullptr;
|
||||
}
|
||||
int lists = oldKey * 2;
|
||||
if (lists >= 0) {
|
||||
lists += levelRenderer->chunkLists;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,14 @@ class Entity;
|
|||
class Chunk;
|
||||
class Culler;
|
||||
|
||||
struct ChunkBuildContext {
|
||||
int64_t nowMs = 0;
|
||||
uint32_t batchId = 0;
|
||||
uint16_t veryNearCount = 0;
|
||||
bool onlyRebuild = false;
|
||||
bool deferredAtomic = false;
|
||||
};
|
||||
|
||||
class ClipChunk {
|
||||
public:
|
||||
Chunk* chunk;
|
||||
|
|
@ -57,7 +65,9 @@ public:
|
|||
int xm, ym, zm;
|
||||
AABB bb;
|
||||
ClipChunk* clipChunk;
|
||||
#if defined(OCCLUSION_MODE_BFS)
|
||||
uint64_t computeConnectivity(const uint8_t* tileIds);
|
||||
#endif
|
||||
int id;
|
||||
// public:
|
||||
// std::vector<std::shared_ptr<TileEntity> > renderableTileEntities;
|
||||
|
|
@ -67,6 +77,7 @@ private:
|
|||
LevelRenderer::rteMap* globalRenderableTileEntities;
|
||||
std::mutex* globalRenderableTileEntities_cs;
|
||||
bool assigned;
|
||||
ChunkBuildContext buildContext;
|
||||
|
||||
public:
|
||||
Chunk(Level* level, LevelRenderer::rteMap& globalRenderableTileEntities,
|
||||
|
|
@ -84,6 +95,8 @@ private:
|
|||
|
||||
public:
|
||||
void makeCopyForRebuild(Chunk* source);
|
||||
void setBuildContext(const ChunkBuildContext& ctx);
|
||||
const ChunkBuildContext& getBuildContext() const;
|
||||
void rebuild();
|
||||
float distanceToSqr(std::shared_ptr<Entity> player) const;
|
||||
float squishedDistanceToSqr(std::shared_ptr<Entity> player);
|
||||
|
|
|
|||
|
|
@ -6,24 +6,18 @@
|
|||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
#include "platform/PlatformTypes.h"
|
||||
#include "platform/sdl2/Input.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "BossMobGuiInfo.h"
|
||||
#include "Chunk.h"
|
||||
#include "ItemInHandRenderer.h"
|
||||
#include "LevelRenderer.h"
|
||||
#include "Tesselator.h"
|
||||
#include "app/common/App_enums.h"
|
||||
#include "platform/ShutdownManager.h"
|
||||
#include "app/common/src/Colours/ColourTable.h"
|
||||
#include "app/linux/LinuxGame.h"
|
||||
#include "app/linux/Stubs/winapi_stubs.h"
|
||||
#include "app/include/BufferedImage.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "app/include/stubs.h"
|
||||
#include "Tesselator.h"
|
||||
#include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h"
|
||||
|
||||
#include "app/linux/LinuxGame.h"
|
||||
#include "app/linux/Stubs/winapi_stubs.h"
|
||||
#include "java/Class.h"
|
||||
#include "java/FloatBuffer.h"
|
||||
#include "java/JavaMath.h"
|
||||
|
|
@ -78,10 +72,15 @@
|
|||
#include "minecraft/world/level/chunk/SparseLightStorage.h"
|
||||
#include "minecraft/world/level/dimension/Dimension.h"
|
||||
#include "minecraft/world/level/material/Material.h"
|
||||
#include "minecraft/world/level/storage/ConsoleSaveFileIO/compression.h"
|
||||
#include "minecraft/world/level/tile/Tile.h"
|
||||
#include "minecraft/world/phys/AABB.h"
|
||||
#include "minecraft/world/phys/HitResult.h"
|
||||
#include "minecraft/world/phys/Vec3.h"
|
||||
#include "platform/PlatformTypes.h"
|
||||
#include "platform/ShutdownManager.h"
|
||||
#include "platform/sdl2/Input.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
|
||||
bool GameRenderer::anaglyph3d = false;
|
||||
int GameRenderer::anaglyphPass = 0;
|
||||
|
|
@ -1115,6 +1114,7 @@ void GameRenderer::FinishedReassigning() { m_csDeleteStack.unlock(); }
|
|||
|
||||
int GameRenderer::runUpdate(void* lpParam) {
|
||||
Minecraft* minecraft = Minecraft::GetInstance();
|
||||
int64_t updatePassToken = 0;
|
||||
Tesselator::CreateNewThreadStorage(1024 * 1024);
|
||||
Compression::UseDefaultThreadStorage();
|
||||
RenderManager.InitialiseContext();
|
||||
|
|
@ -1150,8 +1150,10 @@ int GameRenderer::runUpdate(void* lpParam) {
|
|||
int count = 0;
|
||||
static const int MAX_DEFERRED_UPDATES = 10;
|
||||
bool shouldContinue = false;
|
||||
const int64_t tickNowMs = ++updatePassToken;
|
||||
do {
|
||||
shouldContinue = minecraft->levelRenderer->updateDirtyChunks();
|
||||
shouldContinue =
|
||||
minecraft->levelRenderer->updateDirtyChunks(tickNowMs);
|
||||
count++;
|
||||
} while (shouldContinue && count < MAX_DEFERRED_UPDATES);
|
||||
|
||||
|
|
@ -1421,7 +1423,8 @@ void GameRenderer::renderLevel(float a, int64_t until) {
|
|||
int visibleWaterChunks =
|
||||
levelRenderer->render(cameraEntity, 1, a, updateChunks);
|
||||
|
||||
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
RenderManager.StateSetBlendFunc(GL_SRC_ALPHA,
|
||||
GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
if (visibleWaterChunks > 0) {
|
||||
levelRenderer->render(
|
||||
|
|
|
|||
|
|
@ -11,27 +11,24 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <mutex>
|
||||
#include <numbers>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include "platform/PlatformTypes.h"
|
||||
#include "platform/sdl2/Input.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "Chunk.h"
|
||||
#include "GameRenderer.h"
|
||||
#include "Tesselator.h"
|
||||
#include "app/common/App_enums.h"
|
||||
#include "app/common/src/Audio/SoundEngine.h"
|
||||
#include "app/common/src/Colours/ColourTable.h"
|
||||
#include "app/common/src/Console_Debug_enum.h"
|
||||
#include "app/linux/LinuxGame.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "app/include/MobSkinMemTextureProcessor.h"
|
||||
#include "app/include/stubs.h"
|
||||
#include "Tesselator.h"
|
||||
#include "util/StringHelpers.h"
|
||||
#include "app/linux/LinuxGame.h"
|
||||
#include "java/Class.h"
|
||||
#include "java/JavaMath.h"
|
||||
#include "java/Random.h"
|
||||
|
|
@ -111,10 +108,19 @@
|
|||
#include "minecraft/world/phys/AABB.h"
|
||||
#include "minecraft/world/phys/HitResult.h"
|
||||
#include "minecraft/world/phys/Vec3.h"
|
||||
#include "platform/PlatformTypes.h"
|
||||
#include "platform/sdl2/Input.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "util/StringHelpers.h"
|
||||
|
||||
class Icon;
|
||||
class ItemInstance;
|
||||
|
||||
namespace {
|
||||
std::atomic<uint32_t> s_chunkBuildBatchCounter{0};
|
||||
std::atomic<int64_t> s_dirtyChunkPassToken{0};
|
||||
} // namespace
|
||||
|
||||
// #define DISABLE_SPU_CODE
|
||||
|
||||
ResourceLocation LevelRenderer::MOON_LOCATION =
|
||||
|
|
@ -216,6 +222,7 @@ LevelRenderer::LevelRenderer(Minecraft* mc, Textures* textures) {
|
|||
|
||||
dirtyChunkPresent = false;
|
||||
lastDirtyChunkFound = 0;
|
||||
m_dirtyChunksRequireFullScan = false;
|
||||
|
||||
this->mc = mc;
|
||||
this->textures = textures;
|
||||
|
|
@ -230,6 +237,8 @@ LevelRenderer::LevelRenderer(Minecraft* mc, Textures* textures) {
|
|||
globalChunkConnectivity = new uint64_t[getGlobalChunkCount()];
|
||||
memset(globalChunkConnectivity, 0xFF,
|
||||
getGlobalChunkCount() * sizeof(uint64_t)); // 0xFF >> Fully open
|
||||
m_globalClipChunks =
|
||||
std::vector<ClipChunk*>(getGlobalChunkCount(), nullptr);
|
||||
|
||||
starList = MemoryTracker::genLists(4);
|
||||
|
||||
|
|
@ -1699,7 +1708,14 @@ void LevelRenderer::renderAdvancedClouds(float alpha) {
|
|||
RenderManager.StateSetEnableViewportClipPlanes(false);
|
||||
}
|
||||
|
||||
bool LevelRenderer::updateDirtyChunks() {
|
||||
bool LevelRenderer::updateDirtyChunks(int64_t cachedNowMs) {
|
||||
const int64_t nowMs =
|
||||
(cachedNowMs >= 0)
|
||||
? cachedNowMs
|
||||
: (s_dirtyChunkPassToken.fetch_add(1, std::memory_order_relaxed) +
|
||||
1);
|
||||
const uint32_t chunkBuildBatchId =
|
||||
s_chunkBuildBatchCounter.fetch_add(1, std::memory_order_relaxed) + 1;
|
||||
#if defined(_LARGE_WORLDS)
|
||||
struct NearestClipChunkSet {
|
||||
std::array<std::pair<ClipChunk*, int>, MAX_CONCURRENT_CHUNK_REBUILDS>
|
||||
|
|
@ -1740,6 +1756,7 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
ClipChunk* nearChunk = nullptr; // Nearest chunk that is dirty
|
||||
int veryNearCount = 0;
|
||||
int minDistSq = 0x7fffffff; // Distances to this chunk
|
||||
bool onlyRebuild = false;
|
||||
std::unique_lock<std::recursive_mutex> dirtyChunksLock(m_csDirtyChunks);
|
||||
|
||||
// Set a flag if we should only rebuild existing chunks, not create anything
|
||||
|
|
@ -1756,11 +1773,165 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
}
|
||||
throttle++;
|
||||
*/
|
||||
bool onlyRebuild = (memAlloc >= MAX_COMMANDBUFFER_ALLOCATIONS);
|
||||
onlyRebuild = (memAlloc >= MAX_COMMANDBUFFER_ALLOCATIONS);
|
||||
|
||||
// Move any dirty chunks stored in the lock free stack into global flags
|
||||
int index = 0;
|
||||
|
||||
bool hasNonStackDirtySignal = false;
|
||||
std::vector<int> poppedDirtyIndices;
|
||||
|
||||
// We want to pop all the dirty chunk indices from the stack
|
||||
auto evaluateSparseDirtyClipChunk = [&](ClipChunk* pClipChunk) {
|
||||
if (pClipChunk == nullptr) return;
|
||||
if (pClipChunk->globalIdx < 0) return;
|
||||
|
||||
unsigned char flags = globalChunkFlags[pClipChunk->globalIdx];
|
||||
if (!(flags & CHUNK_FLAG_DIRTY)) return;
|
||||
|
||||
Chunk* candidateChunk = pClipChunk->chunk;
|
||||
if ((candidateChunk == nullptr) ||
|
||||
(candidateChunk->level == nullptr))
|
||||
return;
|
||||
|
||||
int bestDistSq = INT_MAX;
|
||||
int bestDistWeighted = INT_MAX;
|
||||
bool hasRelevantPlayer = false;
|
||||
|
||||
for (int p = 0; p < XUSER_MAX_COUNT; ++p) {
|
||||
std::shared_ptr<LocalPlayer> player = mc->localplayers[p];
|
||||
if (player == nullptr) continue;
|
||||
if (level[p] != candidateChunk->level) continue;
|
||||
|
||||
hasRelevantPlayer = true;
|
||||
int xd = candidateChunk->xm - (int)player->x;
|
||||
int yd = candidateChunk->ym - (int)player->y;
|
||||
int zd = candidateChunk->zm - (int)player->z;
|
||||
int distSq = xd * xd + yd * yd + zd * zd;
|
||||
int distSqWeighted = xd * xd + yd * yd * 4 + zd * zd;
|
||||
|
||||
if (distSq < bestDistSq) bestDistSq = distSq;
|
||||
if (distSqWeighted < bestDistWeighted)
|
||||
bestDistWeighted = distSqWeighted;
|
||||
}
|
||||
|
||||
if (!hasRelevantPlayer) return;
|
||||
|
||||
if ((!onlyRebuild) || (flags & CHUNK_FLAG_COMPILED) ||
|
||||
(bestDistSq < 20 * 20)) {
|
||||
#if defined(_LARGE_WORLDS)
|
||||
bool isNearer = nearestClipChunks.wouldAccept(bestDistWeighted);
|
||||
#else
|
||||
bool isNearer = bestDistWeighted < minDistSq;
|
||||
#endif
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
bool isCritical = (globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL) != 0;
|
||||
if ((!veryNearCount && isNearer) ||
|
||||
((bestDistSq < 20 * 20) && isCritical))
|
||||
#else
|
||||
if (isNearer)
|
||||
#endif
|
||||
{
|
||||
int chunkY = candidateChunk->y / CHUNK_SIZE;
|
||||
if ((chunkY >= 0) && (chunkY < CHUNK_Y_COUNT)) {
|
||||
LevelChunk* lc = candidateChunk->level->getChunkAt(
|
||||
candidateChunk->x, candidateChunk->z);
|
||||
if (!lc->isRenderChunkEmpty(chunkY * CHUNK_SIZE)) {
|
||||
nearChunk = pClipChunk;
|
||||
minDistSq = bestDistWeighted;
|
||||
#if defined(_LARGE_WORLDS)
|
||||
nearestClipChunks.insert(nearChunk, minDistSq);
|
||||
#endif
|
||||
} else {
|
||||
candidateChunk->clearDirty();
|
||||
globalChunkFlags[pClipChunk->globalIdx] |=
|
||||
CHUNK_FLAG_EMPTYBOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
if ((bestDistSq < 20 * 20) &&
|
||||
(globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL))
|
||||
#else
|
||||
if (bestDistSq < 20 * 20)
|
||||
#endif
|
||||
{
|
||||
veryNearCount++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto evaluateDirtyClipChunkForPlayer = [&](ClipChunk* pClipChunk,
|
||||
int px, int py, int pz) {
|
||||
if (pClipChunk == nullptr) return;
|
||||
if (pClipChunk->globalIdx < 0) return;
|
||||
|
||||
unsigned char flags = globalChunkFlags[pClipChunk->globalIdx];
|
||||
if (!(flags & CHUNK_FLAG_DIRTY)) return;
|
||||
|
||||
Chunk* candidateChunk = pClipChunk->chunk;
|
||||
if ((candidateChunk == nullptr) ||
|
||||
(candidateChunk->level == nullptr))
|
||||
return;
|
||||
|
||||
int xd = candidateChunk->xm - px;
|
||||
int yd = candidateChunk->ym - py;
|
||||
int zd = candidateChunk->zm - pz;
|
||||
int distSq = xd * xd + yd * yd + zd * zd;
|
||||
int distSqWeighted = xd * xd + yd * yd * 4 + zd * zd;
|
||||
|
||||
if ((!onlyRebuild) || (flags & CHUNK_FLAG_COMPILED) ||
|
||||
(distSq < 20 * 20)) {
|
||||
#if defined(_LARGE_WORLDS)
|
||||
bool isNearer = nearestClipChunks.wouldAccept(distSqWeighted);
|
||||
#else
|
||||
bool isNearer = distSqWeighted < minDistSq;
|
||||
#endif
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
if ((!veryNearCount && isNearer) ||
|
||||
(distSq < 20 * 20 &&
|
||||
(globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL)))
|
||||
#else
|
||||
if (isNearer)
|
||||
#endif
|
||||
{
|
||||
int chunkY = candidateChunk->y / CHUNK_SIZE;
|
||||
if ((chunkY >= 0) && (chunkY < CHUNK_Y_COUNT)) {
|
||||
LevelChunk* lc = candidateChunk->level->getChunkAt(
|
||||
candidateChunk->x, candidateChunk->z);
|
||||
if (!lc->isRenderChunkEmpty(chunkY * CHUNK_SIZE)) {
|
||||
nearChunk = pClipChunk;
|
||||
minDistSq = distSqWeighted;
|
||||
#if defined(_LARGE_WORLDS)
|
||||
nearestClipChunks.insert(nearChunk, minDistSq);
|
||||
#endif
|
||||
} else {
|
||||
candidateChunk->clearDirty();
|
||||
globalChunkFlags[pClipChunk->globalIdx] |=
|
||||
CHUNK_FLAG_EMPTYBOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
if (distSq < 20 * 20 &&
|
||||
((globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL)))
|
||||
#else
|
||||
if (distSq < 20 * 20)
|
||||
#endif
|
||||
{
|
||||
veryNearCount++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
do {
|
||||
// See comment on dirtyChunksLockFreeStack.Push() regarding details
|
||||
// of this casting/subtracting -2.
|
||||
|
|
@ -1775,7 +1946,10 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
true; // 1 is a special value passed to let this thread
|
||||
// know that a chunk which isn't on this stack has
|
||||
// been set to dirty
|
||||
else if (index > 1) {
|
||||
if (index == 1) {
|
||||
hasNonStackDirtySignal = true;
|
||||
m_dirtyChunksRequireFullScan = true;
|
||||
} else if (index > 1) {
|
||||
int i2 = index - 2;
|
||||
if (i2 >= DIMENSION_OFFSETS[2]) {
|
||||
i2 -= DIMENSION_OFFSETS[2];
|
||||
|
|
@ -1798,148 +1972,69 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
#endif
|
||||
|
||||
dirtyChunkPresent = true;
|
||||
poppedDirtyIndices.push_back(index - 2);
|
||||
}
|
||||
} while (index);
|
||||
|
||||
// Only bother searching round all the chunks if we have some dirty
|
||||
// chunk(s)
|
||||
if (dirtyChunkPresent) {
|
||||
lastDirtyChunkFound = System::currentTimeMillis();
|
||||
lastDirtyChunkFound = nowMs;
|
||||
|
||||
// Find nearest chunk that is dirty
|
||||
for (int p = 0; p < XUSER_MAX_COUNT; p++) {
|
||||
// It's possible that the localplayers member can be set to
|
||||
// nullptr on the main thread when a player chooses to exit the
|
||||
// game So take a reference to the player object now. As it is a
|
||||
// shared_ptr it should live as long as we need it
|
||||
std::shared_ptr<LocalPlayer> player = mc->localplayers[p];
|
||||
if (player == nullptr) continue;
|
||||
if (chunks[p].empty()) continue;
|
||||
if (level[p] == nullptr) continue;
|
||||
if (chunks[p].size() != xChunks * zChunks * CHUNK_Y_COUNT)
|
||||
continue;
|
||||
int px = (int)player->x;
|
||||
int py = (int)player->y;
|
||||
int pz = (int)player->z;
|
||||
bool useSparsePath = (!m_dirtyChunksRequireFullScan) &&
|
||||
(!hasNonStackDirtySignal) &&
|
||||
(!poppedDirtyIndices.empty());
|
||||
|
||||
// app.DebugPrintf("!! %d %d %d, %d %d %d
|
||||
//{%d,%d}
|
||||
//",px,py,pz,stackChunkDirty,nonStackChunkDirty,onlyRebuild,
|
||||
// xChunks, zChunks);
|
||||
if (useSparsePath) {
|
||||
std::sort(poppedDirtyIndices.begin(), poppedDirtyIndices.end());
|
||||
poppedDirtyIndices.erase(std::unique(poppedDirtyIndices.begin(),
|
||||
poppedDirtyIndices.end()),
|
||||
poppedDirtyIndices.end());
|
||||
|
||||
int considered = 0;
|
||||
int wouldBeNearButEmpty = 0;
|
||||
for (int x = 0; x < xChunks; x++) {
|
||||
for (int z = 0; z < zChunks; z++) {
|
||||
for (int y = 0; y < CHUNK_Y_COUNT; y++) {
|
||||
ClipChunk* pClipChunk =
|
||||
&chunks[p][(z * yChunks + y) * xChunks + x];
|
||||
// Get distance to this chunk - deliberately not
|
||||
// calling the chunk's method of doing this to avoid
|
||||
// overheads (passing entitie, type conversion etc.)
|
||||
// that this involves
|
||||
int xd = pClipChunk->xm - px;
|
||||
int yd = pClipChunk->ym - py;
|
||||
int zd = pClipChunk->zm - pz;
|
||||
int distSq = xd * xd + yd * yd + zd * zd;
|
||||
int distSqWeighted =
|
||||
xd * xd + yd * yd * 4 +
|
||||
zd * zd; // Weighting against y to prioritise
|
||||
// things in same x/z plane as player
|
||||
// first
|
||||
for (int dirtyIdx : poppedDirtyIndices) {
|
||||
if (dirtyIdx < 0) continue;
|
||||
if ((size_t)dirtyIdx >= m_globalClipChunks.size()) continue;
|
||||
evaluateSparseDirtyClipChunk(m_globalClipChunks[dirtyIdx]);
|
||||
}
|
||||
} else {
|
||||
bool sawAnyDirtyFlag = false;
|
||||
for (int p = 0; p < XUSER_MAX_COUNT; p++) {
|
||||
std::shared_ptr<LocalPlayer> player = mc->localplayers[p];
|
||||
if (player == nullptr) continue;
|
||||
if (chunks[p].empty()) continue;
|
||||
if (level[p] == nullptr) continue;
|
||||
if (chunks[p].size() != xChunks * zChunks * CHUNK_Y_COUNT)
|
||||
continue;
|
||||
|
||||
if (globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_DIRTY) {
|
||||
if ((!onlyRebuild) ||
|
||||
globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_COMPILED ||
|
||||
(distSq <
|
||||
20 * 20)) // Always rebuild really near
|
||||
// things or else building (say)
|
||||
// at tower up into empty blocks
|
||||
// when we are low on memory
|
||||
// will not create render data
|
||||
{
|
||||
considered++;
|
||||
// Is this chunk nearer than our nearest?
|
||||
#if defined(_LARGE_WORLDS)
|
||||
bool isNearer =
|
||||
nearestClipChunks.wouldAccept(
|
||||
distSqWeighted);
|
||||
#else
|
||||
bool isNearer = distSqWeighted < minDistSq;
|
||||
#endif
|
||||
const int px = (int)player->x;
|
||||
const int py = (int)player->y;
|
||||
const int pz = (int)player->z;
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
// AP - this will make sure that if a
|
||||
// deferred grouping has started, only
|
||||
// critical chunks go into that grouping,
|
||||
// even if a non-critical chunk is closer.
|
||||
if ((!veryNearCount && isNearer) ||
|
||||
(distSq < 20 * 20 &&
|
||||
(globalChunkFlags[pClipChunk
|
||||
->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL)))
|
||||
#else
|
||||
if (isNearer)
|
||||
#endif
|
||||
{
|
||||
// At this point we've got a chunk that
|
||||
// we would like to consider for
|
||||
// rendering, at least based on its
|
||||
// proximity to the player(s). Its
|
||||
// *quite* quick to generate empty
|
||||
// render data for render chunks, but if
|
||||
// we let the rebuilding do that then
|
||||
// the after rebuilding we will have to
|
||||
// start searching for the next nearest
|
||||
// chunk from scratch again. Instead,
|
||||
// its better to detect empty chunks at
|
||||
// this stage, flag them up as not dirty
|
||||
// (and empty), and carry on. The
|
||||
// levelchunk's isRenderChunkEmpty
|
||||
// method can be quite optimal as it can
|
||||
// make use of the chunk's data
|
||||
// compression to detect emptiness
|
||||
// without actually testing as many data
|
||||
// items as uncompressed data would.
|
||||
Chunk* chunk = pClipChunk->chunk;
|
||||
LevelChunk* lc = level[p]->getChunkAt(
|
||||
chunk->x, chunk->z);
|
||||
if (!lc->isRenderChunkEmpty(y * 16)) {
|
||||
nearChunk = pClipChunk;
|
||||
minDistSq = distSqWeighted;
|
||||
#if defined(_LARGE_WORLDS)
|
||||
nearestClipChunks.insert(nearChunk,
|
||||
minDistSq);
|
||||
#endif
|
||||
} else {
|
||||
chunk->clearDirty();
|
||||
globalChunkFlags[pClipChunk
|
||||
->globalIdx] |=
|
||||
CHUNK_FLAG_EMPTYBOTH;
|
||||
wouldBeNearButEmpty++;
|
||||
}
|
||||
}
|
||||
// app.DebugPrintf("!! %d %d %d, %d %d %d
|
||||
//{%d,%d}
|
||||
//",px,py,pz,stackChunkDirty,nonStackChunkDirty,onlyRebuild,
|
||||
// xChunks, zChunks);
|
||||
|
||||
#if defined(_CRITICAL_CHUNKS)
|
||||
// AP - is the chunk near and also critical
|
||||
if (distSq < 20 * 20 &&
|
||||
((globalChunkFlags[pClipChunk
|
||||
->globalIdx] &
|
||||
CHUNK_FLAG_CRITICAL)))
|
||||
#else
|
||||
if (distSq < 20 * 20)
|
||||
#endif
|
||||
{
|
||||
veryNearCount++;
|
||||
}
|
||||
for (int x = 0; x < xChunks; x++) {
|
||||
for (int z = 0; z < zChunks; z++) {
|
||||
for (int y = 0; y < CHUNK_Y_COUNT; y++) {
|
||||
ClipChunk* pClipChunk =
|
||||
&chunks[p][(z * yChunks + y) * xChunks + x];
|
||||
if (pClipChunk->globalIdx < 0) continue;
|
||||
if (globalChunkFlags[pClipChunk->globalIdx] &
|
||||
CHUNK_FLAG_DIRTY) {
|
||||
sawAnyDirtyFlag = true;
|
||||
}
|
||||
evaluateDirtyClipChunkForPlayer(pClipChunk, px,
|
||||
py, pz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// app.DebugPrintf("[%d,%d,%d]\n",nearestClipChunks.empty(),considered,wouldBeNearButEmpty);
|
||||
|
||||
if (!sawAnyDirtyFlag) {
|
||||
m_dirtyChunksRequireFullScan = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1973,7 +2068,15 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
// whilst we are doing this copy. The copy will then be
|
||||
// guaranteed to be consistent whilst rebuilding takes place
|
||||
// outside of that lock.
|
||||
const ChunkBuildContext buildContext = {
|
||||
nowMs,
|
||||
chunkBuildBatchId,
|
||||
static_cast<uint16_t>(std::min(veryNearCount, 0xffff)),
|
||||
onlyRebuild,
|
||||
veryNearCount > 0,
|
||||
};
|
||||
permaChunk[index].makeCopyForRebuild(chunk);
|
||||
permaChunk[index].setBuildContext(buildContext);
|
||||
++index;
|
||||
}
|
||||
dirtyChunksLock.unlock();
|
||||
|
|
@ -2064,7 +2167,15 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
// means that any chunks can't be repositioned whilst we are doing
|
||||
// this copy. The copy will then be guaranteed to be consistent
|
||||
// whilst rebuilding takes place outside of that lock.
|
||||
const ChunkBuildContext buildContext = {
|
||||
nowMs,
|
||||
chunkBuildBatchId,
|
||||
static_cast<uint16_t>(std::min(veryNearCount, 0xffff)),
|
||||
onlyRebuild,
|
||||
veryNearCount > 0,
|
||||
};
|
||||
permaChunk.makeCopyForRebuild(chunk);
|
||||
permaChunk.setBuildContext(buildContext);
|
||||
dirtyChunksLock.unlock();
|
||||
}
|
||||
// static int64_t totalTime = 0;
|
||||
|
|
@ -2086,8 +2197,8 @@ bool LevelRenderer::updateDirtyChunks() {
|
|||
// Nothing to do - clear flags that there are things to process, unless
|
||||
// it's been a while since we found any dirty chunks in which case force
|
||||
// a check next time through
|
||||
if ((System::currentTimeMillis() - lastDirtyChunkFound) >
|
||||
FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS) {
|
||||
if ((nowMs - lastDirtyChunkFound) >
|
||||
FORCE_DIRTY_CHUNK_CHECK_PERIOD_PASSES) {
|
||||
dirtyChunkPresent = true;
|
||||
} else {
|
||||
dirtyChunkPresent = false;
|
||||
|
|
@ -2323,6 +2434,12 @@ void LevelRenderer::setDirty(int x0, int y0, int z0, int x1, int y1, int z1,
|
|||
int _y1 = Mth::intFloorDiv(y1, CHUNK_SIZE);
|
||||
int _z1 = Mth::intFloorDiv(z1, CHUNK_XZSIZE);
|
||||
|
||||
#if !defined(_CRITICAL_CHUNKS)
|
||||
std::vector<intptr_t> pendingDirtyIndices;
|
||||
pendingDirtyIndices.reserve(
|
||||
((_x1 - _x0 + 1) * (_y1 - _y0 + 1) * (_z1 - _z0 + 1)));
|
||||
#endif
|
||||
|
||||
for (int x = _x0; x <= _x1; x++) {
|
||||
for (int y = _y0; y <= _y1; y++) {
|
||||
for (int z = _z0; z <= _z1; z++) {
|
||||
|
|
@ -2393,8 +2510,8 @@ void LevelRenderer::setDirty(int x0, int y0, int z0, int x1, int y1, int z1,
|
|||
|
||||
dirtyChunksLockFreeStack.Push((int*)(index));
|
||||
#else
|
||||
dirtyChunksLockFreeStack.Push(
|
||||
(int*)(intptr_t)(uintptr_t)(index + 2));
|
||||
pendingDirtyIndices.push_back(
|
||||
(intptr_t)(uintptr_t)(index + 2));
|
||||
#endif
|
||||
}
|
||||
// setGlobalChunkFlag(x * 16, y *
|
||||
|
|
@ -2402,6 +2519,19 @@ void LevelRenderer::setDirty(int x0, int y0, int z0, int x1, int y1, int z1,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_CRITICAL_CHUNKS)
|
||||
if (!pendingDirtyIndices.empty()) {
|
||||
std::sort(pendingDirtyIndices.begin(), pendingDirtyIndices.end());
|
||||
pendingDirtyIndices.erase(
|
||||
std::unique(pendingDirtyIndices.begin(), pendingDirtyIndices.end()),
|
||||
pendingDirtyIndices.end());
|
||||
|
||||
for (intptr_t encodedIndex : pendingDirtyIndices) {
|
||||
dirtyChunksLockFreeStack.Push((int*)encodedIndex);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LevelRenderer::tileChanged(int x, int y, int z) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#pragma once
|
||||
#include "OffsettedRenderList.h"
|
||||
#include "app/include/NetTypes.h"
|
||||
#include "app/include/SkinBox.h"
|
||||
#include "app/include/XboxStubs.h"
|
||||
#include "OffsettedRenderList.h"
|
||||
#include "platform/C4JThread.h"
|
||||
#include "util/Definitions.h"
|
||||
#include "java/JavaIntHash.h"
|
||||
#include "minecraft/core/particles/ParticleTypes.h"
|
||||
#include "minecraft/world/level/Level.h"
|
||||
#include "minecraft/world/level/LevelListener.h"
|
||||
#include "minecraft/world/phys/AABB.h"
|
||||
#include "platform/C4JThread.h"
|
||||
#include "util/Definitions.h"
|
||||
|
||||
class ClipChunk;
|
||||
class HitResult;
|
||||
|
|
@ -119,7 +119,7 @@ public:
|
|||
void renderClouds(float alpha);
|
||||
bool isInCloud(double x, double y, double z, float alpha);
|
||||
void renderAdvancedClouds(float alpha);
|
||||
bool updateDirtyChunks();
|
||||
bool updateDirtyChunks(int64_t cachedNowMs = -1);
|
||||
|
||||
public:
|
||||
void renderHit(std::shared_ptr<Player> player, HitResult* h, int mode,
|
||||
|
|
@ -225,6 +225,8 @@ private:
|
|||
uint64_t getGlobalChunkConnectivity(int index);
|
||||
std::vector<ClipChunk*> m_bfsGrid;
|
||||
std::vector<uint8_t> m_bfsVisitedFaces[4];
|
||||
std::vector<ClipChunk*> m_globalClipChunks;
|
||||
bool m_dirtyChunksRequireFullScan;
|
||||
std::unordered_map<int, BlockDestructionProgress*> destroyingBlocks;
|
||||
Icon** breakingTextures;
|
||||
|
||||
|
|
@ -355,7 +357,7 @@ public:
|
|||
|
||||
bool dirtyChunkPresent;
|
||||
int64_t lastDirtyChunkFound;
|
||||
static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 250;
|
||||
static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_PASSES = 64;
|
||||
|
||||
#if defined(_LARGE_WORLDS)
|
||||
static const int MAX_CONCURRENT_CHUNK_REBUILDS = 4;
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
#include "platform/sdl2/Render.h"
|
||||
#include "Chunk.h"
|
||||
#include "EntityTileRenderer.h"
|
||||
#include "GameRenderer.h"
|
||||
#include "Tesselator.h"
|
||||
#include "app/common/App_enums.h"
|
||||
#include "app/common/src/Colours/ColourTable.h"
|
||||
#include "app/include/FrameProfiler.h"
|
||||
#include "Tesselator.h"
|
||||
#include "minecraft/Direction.h"
|
||||
#include "minecraft/Facing.h"
|
||||
#include "minecraft/SharedConstants.h"
|
||||
|
|
@ -69,6 +69,7 @@
|
|||
#include "minecraft/world/level/tile/piston/PistonBaseTile.h"
|
||||
#include "minecraft/world/level/tile/piston/PistonExtensionTile.h"
|
||||
#include "minecraft/world/phys/Vec3.h"
|
||||
#include "platform/sdl2/Render.h"
|
||||
|
||||
bool TileRenderer::fancy = true;
|
||||
|
||||
|
|
@ -101,6 +102,7 @@ void TileRenderer::_init() {
|
|||
yMin = 0;
|
||||
zMin = 0;
|
||||
cache = nullptr;
|
||||
buildContext = nullptr;
|
||||
}
|
||||
|
||||
bool TileRenderer::isTranslucentAt(LevelSource* level, int x, int y, int z) {
|
||||
|
|
@ -204,7 +206,8 @@ int TileRenderer::getLightColor(Tile* tt, LevelSource* level, int x, int y,
|
|||
}
|
||||
|
||||
TileRenderer::TileRenderer(LevelSource* level, int xMin, int yMin, int zMin,
|
||||
unsigned char* tileIds) {
|
||||
unsigned char* tileIds,
|
||||
const ChunkBuildContext* buildContext) {
|
||||
this->level = level;
|
||||
_init();
|
||||
this->xMin = xMin;
|
||||
|
|
@ -214,6 +217,7 @@ TileRenderer::TileRenderer(LevelSource* level, int xMin, int yMin, int zMin,
|
|||
this->yMin2 = yMin - 2;
|
||||
this->zMin2 = zMin - 2;
|
||||
this->tileIds = tileIds;
|
||||
this->buildContext = buildContext;
|
||||
cache = new unsigned int[32 * 32 * 32];
|
||||
memset(cache, 0, 32 * 32 * 32 * sizeof(unsigned int));
|
||||
}
|
||||
|
|
@ -232,6 +236,10 @@ TileRenderer::TileRenderer() {
|
|||
_init();
|
||||
}
|
||||
|
||||
void TileRenderer::setBuildContext(const ChunkBuildContext* buildContext) {
|
||||
this->buildContext = buildContext;
|
||||
}
|
||||
|
||||
void TileRenderer::setFixedTexture(Icon* fixedTexture) {
|
||||
this->fixedTexture = fixedTexture;
|
||||
}
|
||||
|
|
@ -5254,10 +5262,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
ll0yZ = getShadeBrightness(tt, level, pX, pY, pZ + 1);
|
||||
llXy0 = getShadeBrightness(tt, level, pX + 1, pY, pZ);
|
||||
|
||||
bool llTransXy0 = Tile::transculent[level->getTile(pX + 1, pY - 1, pZ)];
|
||||
bool llTransxy0 = Tile::transculent[level->getTile(pX - 1, pY - 1, pZ)];
|
||||
bool llTrans0yZ = Tile::transculent[level->getTile(pX, pY - 1, pZ + 1)];
|
||||
bool llTrans0yz = Tile::transculent[level->getTile(pX, pY - 1, pZ - 1)];
|
||||
bool llTransXy0 = isTranslucentAt(level, pX + 1, pY - 1, pZ);
|
||||
bool llTransxy0 = isTranslucentAt(level, pX - 1, pY - 1, pZ);
|
||||
bool llTrans0yZ = isTranslucentAt(level, pX, pY - 1, pZ + 1);
|
||||
bool llTrans0yz = isTranslucentAt(level, pX, pY - 1, pZ - 1);
|
||||
|
||||
if (llTrans0yz || llTransxy0) {
|
||||
llxyz = getShadeBrightness(tt, level, pX - 1, pY, pZ - 1);
|
||||
|
|
@ -5346,10 +5354,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
ll0Yz = getShadeBrightness(tt, level, pX, pY, pZ - 1);
|
||||
ll0YZ = getShadeBrightness(tt, level, pX, pY, pZ + 1);
|
||||
|
||||
bool llTransXY0 = Tile::transculent[level->getTile(pX + 1, pY + 1, pZ)];
|
||||
bool llTransxY0 = Tile::transculent[level->getTile(pX - 1, pY + 1, pZ)];
|
||||
bool llTrans0YZ = Tile::transculent[level->getTile(pX, pY + 1, pZ + 1)];
|
||||
bool llTrans0Yz = Tile::transculent[level->getTile(pX, pY + 1, pZ - 1)];
|
||||
bool llTransXY0 = isTranslucentAt(level, pX + 1, pY + 1, pZ);
|
||||
bool llTransxY0 = isTranslucentAt(level, pX - 1, pY + 1, pZ);
|
||||
bool llTrans0YZ = isTranslucentAt(level, pX, pY + 1, pZ + 1);
|
||||
bool llTrans0Yz = isTranslucentAt(level, pX, pY + 1, pZ - 1);
|
||||
|
||||
if (llTrans0Yz || llTransxY0) {
|
||||
llxYz = getShadeBrightness(tt, level, pX - 1, pY, pZ - 1);
|
||||
|
|
@ -5429,10 +5437,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
cc0Yz = getLightColor(tt, level, pX, pY + 1, pZ);
|
||||
ccX0z = getLightColor(tt, level, pX + 1, pY, pZ);
|
||||
|
||||
bool llTransX0z = Tile::transculent[level->getTile(pX + 1, pY, pZ - 1)];
|
||||
bool llTransx0z = Tile::transculent[level->getTile(pX - 1, pY, pZ - 1)];
|
||||
bool llTrans0Yz = Tile::transculent[level->getTile(pX, pY + 1, pZ - 1)];
|
||||
bool llTrans0yz = Tile::transculent[level->getTile(pX, pY - 1, pZ - 1)];
|
||||
bool llTransX0z = isTranslucentAt(level, pX + 1, pY, pZ - 1);
|
||||
bool llTransx0z = isTranslucentAt(level, pX - 1, pY, pZ - 1);
|
||||
bool llTrans0Yz = isTranslucentAt(level, pX, pY + 1, pZ - 1);
|
||||
bool llTrans0yz = isTranslucentAt(level, pX, pY - 1, pZ - 1);
|
||||
|
||||
if (llTransx0z || llTrans0yz) {
|
||||
llxyz = getShadeBrightness(tt, level, pX - 1, pY - 1, pZ);
|
||||
|
|
@ -5597,10 +5605,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
cc0yZ = getLightColor(tt, level, pX, pY - 1, pZ);
|
||||
cc0YZ = getLightColor(tt, level, pX, pY + 1, pZ);
|
||||
|
||||
bool llTransX0Z = Tile::transculent[level->getTile(pX + 1, pY, pZ + 1)];
|
||||
bool llTransx0Z = Tile::transculent[level->getTile(pX - 1, pY, pZ + 1)];
|
||||
bool llTrans0YZ = Tile::transculent[level->getTile(pX, pY + 1, pZ + 1)];
|
||||
bool llTrans0yZ = Tile::transculent[level->getTile(pX, pY - 1, pZ + 1)];
|
||||
bool llTransX0Z = isTranslucentAt(level, pX + 1, pY, pZ + 1);
|
||||
bool llTransx0Z = isTranslucentAt(level, pX - 1, pY, pZ + 1);
|
||||
bool llTrans0YZ = isTranslucentAt(level, pX, pY + 1, pZ + 1);
|
||||
bool llTrans0yZ = isTranslucentAt(level, pX, pY - 1, pZ + 1);
|
||||
|
||||
if (llTransx0Z || llTrans0yZ) {
|
||||
llxyZ = getShadeBrightness(tt, level, pX - 1, pY - 1, pZ);
|
||||
|
|
@ -5765,10 +5773,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
ccx0Z = getLightColor(tt, level, pX, pY, pZ + 1);
|
||||
ccxY0 = getLightColor(tt, level, pX, pY + 1, pZ);
|
||||
|
||||
bool llTransxY0 = Tile::transculent[level->getTile(pX - 1, pY + 1, pZ)];
|
||||
bool llTransxy0 = Tile::transculent[level->getTile(pX - 1, pY - 1, pZ)];
|
||||
bool llTransx0z = Tile::transculent[level->getTile(pX - 1, pY, pZ - 1)];
|
||||
bool llTransx0Z = Tile::transculent[level->getTile(pX - 1, pY, pZ + 1)];
|
||||
bool llTransxY0 = isTranslucentAt(level, pX - 1, pY + 1, pZ);
|
||||
bool llTransxy0 = isTranslucentAt(level, pX - 1, pY - 1, pZ);
|
||||
bool llTransx0z = isTranslucentAt(level, pX - 1, pY, pZ - 1);
|
||||
bool llTransx0Z = isTranslucentAt(level, pX - 1, pY, pZ + 1);
|
||||
|
||||
if (llTransx0z || llTransxy0) {
|
||||
llxyz = getShadeBrightness(tt, level, pX, pY - 1, pZ - 1);
|
||||
|
|
@ -5929,10 +5937,10 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionTexLighting(
|
|||
ccX0Z = getLightColor(tt, level, pX, pY, pZ + 1);
|
||||
ccXY0 = getLightColor(tt, level, pX, pY + 1, pZ);
|
||||
|
||||
bool llTransXY0 = Tile::transculent[level->getTile(pX + 1, pY + 1, pZ)];
|
||||
bool llTransXy0 = Tile::transculent[level->getTile(pX + 1, pY - 1, pZ)];
|
||||
bool llTransX0Z = Tile::transculent[level->getTile(pX + 1, pY, pZ + 1)];
|
||||
bool llTransX0z = Tile::transculent[level->getTile(pX + 1, pY, pZ - 1)];
|
||||
bool llTransXY0 = isTranslucentAt(level, pX + 1, pY + 1, pZ);
|
||||
bool llTransXy0 = isTranslucentAt(level, pX + 1, pY - 1, pZ);
|
||||
bool llTransX0Z = isTranslucentAt(level, pX + 1, pY, pZ + 1);
|
||||
bool llTransX0z = isTranslucentAt(level, pX + 1, pY, pZ - 1);
|
||||
|
||||
if (llTransXy0 || llTransX0z) {
|
||||
llXyz = getShadeBrightness(tt, level, pX, pY - 1, pZ - 1);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ class BeaconTile;
|
|||
class HopperTile;
|
||||
class Icon;
|
||||
class Minecraft;
|
||||
struct ChunkBuildContext;
|
||||
|
||||
class TileRenderer {
|
||||
friend class FallingTileRenderer;
|
||||
|
|
@ -62,6 +63,7 @@ public:
|
|||
bool isTranslucentAt(LevelSource* level, int x, int y, int z);
|
||||
unsigned int* cache;
|
||||
unsigned char* tileIds;
|
||||
const ChunkBuildContext* buildContext;
|
||||
static const unsigned int cache_getLightColor_valid = 0x80000000;
|
||||
static const unsigned int cache_isTranslucentAt_valid = 0x40000000;
|
||||
static const unsigned int cache_isSolidBlockingTile_valid = 0x20000000;
|
||||
|
|
@ -74,10 +76,12 @@ public:
|
|||
|
||||
public:
|
||||
TileRenderer(LevelSource* level, int xMin, int yMin, int zMin,
|
||||
unsigned char* tileIds);
|
||||
unsigned char* tileIds,
|
||||
const ChunkBuildContext* buildContext = nullptr);
|
||||
TileRenderer(LevelSource* level);
|
||||
TileRenderer();
|
||||
~TileRenderer();
|
||||
void setBuildContext(const ChunkBuildContext* buildContext);
|
||||
void setFixedTexture(Icon* fixedTexture);
|
||||
void clearFixedTexture();
|
||||
bool hasFixedTexture();
|
||||
|
|
|
|||
Loading…
Reference in a new issue