diff --git a/Minecraft.Client/Chunk.cpp b/Minecraft.Client/Chunk.cpp index bf292245..bd12adbf 100644 --- a/Minecraft.Client/Chunk.cpp +++ b/Minecraft.Client/Chunk.cpp @@ -214,7 +214,7 @@ void Chunk::rebuild() int r = 1; - int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; + int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * LevelRenderer::CHUNK_RENDER_LAYERS; lists += levelRenderer->chunkLists; PIXEndNamedEvent(); @@ -329,6 +329,7 @@ void Chunk::rebuild() levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); RenderManager.CBuffClear(lists + currentLayer); } + RenderManager.CBuffClear(lists + 2); delete region; delete tileRenderer; @@ -349,7 +350,7 @@ void Chunk::rebuild() bounds.boundingBox[4] = SIZE+g; bounds.boundingBox[5] = XZSIZE+g; } - for (int currentLayer = 0; currentLayer < 2; currentLayer++) + for (int currentLayer = 0; currentLayer < LevelRenderer::CHUNK_RENDER_LAYERS; currentLayer++) { bool renderNextLayer = false; bool rendered = false; @@ -413,7 +414,7 @@ void Chunk::rebuild() } int renderLayer = tile->getRenderLayer(); - if (renderLayer != currentLayer) + if (renderLayer > currentLayer) { renderNextLayer = true; } @@ -456,18 +457,30 @@ void Chunk::rebuild() if (rendered) { - levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + if (currentLayer < 2) + { + levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } } else { // 4J - added - clear any renderer data associated with this unused list - levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + if (currentLayer < 2) + { + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } RenderManager.CBuffClear(lists + currentLayer); } if((currentLayer==0)&&(!renderNextLayer)) { levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1); RenderManager.CBuffClear(lists + 1); + RenderManager.CBuffClear(lists + 2); + break; + } + if((currentLayer==1)&&(!renderNextLayer)) + { + RenderManager.CBuffClear(lists + 2); break; } } @@ -670,7 +683,7 @@ void Chunk::rebuild_SPU() Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r, r); TileRenderer tileRenderer(®ion); - int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; + int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * LevelRenderer::CHUNK_RENDER_LAYERS; lists += levelRenderer->chunkLists; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -695,7 +708,7 @@ void Chunk::rebuild_SPU() bounds.boundingBox[5] = SIZE+g; } - for (int currentLayer = 0; currentLayer < 2; currentLayer++) + for (int currentLayer = 0; currentLayer < LevelRenderer::CHUNK_RENDER_LAYERS; currentLayer++) { bool rendered = false; @@ -757,7 +770,7 @@ void Chunk::rebuild_SPU() if (!tile) continue; int renderLayer = tile->getRenderLayer(); - if (renderLayer != currentLayer) + if (renderLayer > currentLayer) { // renderNextLayer = true; } @@ -784,12 +797,18 @@ void Chunk::rebuild_SPU() } if (rendered) { - levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + if (currentLayer < 2) + { + levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } } else { // 4J - added - clear any renderer data associated with this unused list - levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + if (currentLayer < 2) + { + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } RenderManager.CBuffClear(lists + currentLayer); } @@ -961,11 +980,11 @@ void Chunk::reset() // printf("\t\t [dec] refcount %d at %d, %d, %d\n",refCount,x,y,z); if( refCount == 0 ) { - int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * 2; + int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * LevelRenderer::CHUNK_RENDER_LAYERS; if(lists >= 0) { lists += levelRenderer->chunkLists; - for (int i = 0; i < 2; i++) + for (int i = 0; i < LevelRenderer::CHUNK_RENDER_LAYERS; i++) { // 4J - added - clear any renderer data associated with this unused list RenderManager.CBuffClear(lists + i); @@ -987,12 +1006,13 @@ void Chunk::_delete() int Chunk::getList(int layer) { + if (layer < 0 || layer >= LevelRenderer::CHUNK_RENDER_LAYERS) return -1; if (!clipChunk->visible) return -1; - int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * 2; + int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * LevelRenderer::CHUNK_RENDER_LAYERS; lists += levelRenderer->chunkLists; - bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer); + bool empty = (layer < 2) && levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer); if (!empty) return lists + layer; return -1; } diff --git a/Minecraft.Client/GameRenderer.cpp b/Minecraft.Client/GameRenderer.cpp index a4269292..882eed85 100644 --- a/Minecraft.Client/GameRenderer.cpp +++ b/Minecraft.Client/GameRenderer.cpp @@ -1550,6 +1550,18 @@ void GameRenderer::renderLevel(float a, int64_t until) PIXEndNamedEvent(); } + glBlendFunc(GL_ZERO, GL_ONE); + PIXBeginNamedEvent(0,"Third pass level render"); + int visibleTopTransparentChunks = levelRenderer->render(cameraEntity, 2, a, updateChunks); + PIXEndNamedEvent(); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (visibleTopTransparentChunks > 0) + { + PIXBeginNamedEvent(0,"Third pass level direct render"); + levelRenderer->renderChunksDirect(2, a); + PIXEndNamedEvent(); + } + GL11::glShadeModel(GL11::GL_FLAT); } else @@ -1557,6 +1569,8 @@ void GameRenderer::renderLevel(float a, int64_t until) PIXBeginNamedEvent(0,"Second pass level render"); levelRenderer->render(cameraEntity, 1, a, updateChunks); PIXEndNamedEvent(); + levelRenderer->render(cameraEntity, 2, a, updateChunks); + PIXEndNamedEvent(); } // 4J - added - have split out translucent particle rendering so that it happens after the water is rendered, primarily for fireworks diff --git a/Minecraft.Client/LevelRenderer.cpp b/Minecraft.Client/LevelRenderer.cpp index f7d52d84..457a296e 100644 --- a/Minecraft.Client/LevelRenderer.cpp +++ b/Minecraft.Client/LevelRenderer.cpp @@ -160,13 +160,15 @@ LevelRenderer::LevelRenderer(Minecraft *mc, Textures *textures) visibleLists_layer0 = nullptr; visibleLists_layer1 = nullptr; + visibleLists_layer2 = nullptr; visibleCount_layer0 = 0; visibleCount_layer1 = 0; + visibleCount_layer2 = 0; this->mc = mc; this->textures = textures; - chunkLists = MemoryTracker::genLists(getGlobalChunkCount()*2); // *2 here is because there is one renderlist per chunk here for each of the opaque & transparent layers + chunkLists = MemoryTracker::genLists(getGlobalChunkCount() * CHUNK_RENDER_LAYERS); // One render list per chunk render layer. globalChunkFlags = new unsigned char[getGlobalChunkCount()]; memset(globalChunkFlags, 0, getGlobalChunkCount()); @@ -464,8 +466,10 @@ void LevelRenderer::allChanged(int playerIndex) // Free old visible chunk lists delete[] visibleLists_layer0; delete[] visibleLists_layer1; + delete[] visibleLists_layer2; visibleLists_layer0 = nullptr; visibleLists_layer1 = nullptr; + visibleLists_layer2 = nullptr; chunks[playerIndex] = ClipChunkArray(xChunks * yChunks * zChunks); // sortedChunks[playerIndex] = new vector(xChunks * yChunks * zChunks); // 4J - removed - not sorting our chunks anymore @@ -503,8 +507,10 @@ void LevelRenderer::allChanged(int playerIndex) int totalChunkCount = xChunks * yChunks * zChunks; visibleLists_layer0 = new int[totalChunkCount]; visibleLists_layer1 = new int[totalChunkCount]; + visibleLists_layer2 = new int[totalChunkCount]; visibleCount_layer0 = 0; visibleCount_layer1 = 0; + visibleCount_layer2 = 0; if (level != nullptr) { @@ -784,8 +790,18 @@ void LevelRenderer::renderChunksDirect(int layer, double alpha) glPushMatrix(); glTranslatef(static_cast(-xOff), static_cast(-yOff), static_cast(-zOff)); - int *lists = (layer == 0) ? visibleLists_layer0 : visibleLists_layer1; - int numVisible = (layer == 0) ? visibleCount_layer0 : visibleCount_layer1; + int *lists = visibleLists_layer2; + int numVisible = visibleCount_layer2; + if (layer == 0) + { + lists = visibleLists_layer0; + numVisible = visibleCount_layer0; + } + else if (layer == 1) + { + lists = visibleLists_layer1; + numVisible = visibleCount_layer1; + } bool first = true; if (lists != nullptr) { @@ -872,8 +888,18 @@ int LevelRenderer::renderChunks(int from, int to, int layer, double alpha) int count = 0; // Use compact visible lists built during cull() instead of iterating all chunks - int *lists = (layer == 0) ? visibleLists_layer0 : visibleLists_layer1; - int numVisible = (layer == 0) ? visibleCount_layer0 : visibleCount_layer1; + int *lists = visibleLists_layer2; + int numVisible = visibleCount_layer2; + if (layer == 0) + { + lists = visibleLists_layer0; + numVisible = visibleCount_layer0; + } + else if (layer == 1) + { + lists = visibleLists_layer1; + numVisible = visibleCount_layer1; + } if (lists != nullptr) { for (int i = 0; i < numVisible; i++) @@ -892,8 +918,8 @@ int LevelRenderer::renderChunks(int from, int to, int layer, double alpha) { if( !pClipChunk->visible ) continue; if( pClipChunk->globalIdx == -1 ) continue; - if( ( globalChunkFlags[pClipChunk->globalIdx] & emptyFlag ) == emptyFlag ) continue; - int list = pClipChunk->globalIdx * 2 + layer; + if (layer < 2 && ( globalChunkFlags[pClipChunk->globalIdx] & emptyFlag ) == emptyFlag) continue; + int list = pClipChunk->globalIdx * CHUNK_RENDER_LAYERS + layer; list += chunkLists; if(RenderManager.CBuffCall(list, first)) first = false; @@ -912,11 +938,11 @@ int LevelRenderer::renderChunks(int from, int to, int layer, double alpha) { if( !pClipChunk->visible ) continue; // This will be set if the chunk isn't visible, or isn't compiled, or has both empty flags set if( pClipChunk->globalIdx == -1 ) continue; // Not sure if we should ever encounter this... TODO check - if( ( globalChunkFlags[pClipChunk->globalIdx] & emptyFlag ) == emptyFlag ) continue; // Check that this particular layer isn't empty + if (layer < 2 && ( globalChunkFlags[pClipChunk->globalIdx] & emptyFlag ) == emptyFlag) continue; // Check that this particular layer isn't empty if( !(globalChunkFlags[pClipChunk->globalIdx] & LevelRenderer::CHUNK_FLAG_CUT_OUT) ) continue; // Does this chunk contain any cut out geometry // List can be calculated directly from the chunk's global idex - int list = pClipChunk->globalIdx * 2 + layer; + int list = pClipChunk->globalIdx * CHUNK_RENDER_LAYERS + layer; list += chunkLists; if(RenderManager.CBuffCallCutOut(list, first)) @@ -2639,6 +2665,7 @@ void LevelRenderer::cull(Culler *culler, float a) // Reset visible chunk lists for this frame visibleCount_layer0 = 0; visibleCount_layer1 = 0; + visibleCount_layer2 = 0; // Column-level frustum culling: test one AABB per XZ column before testing individual Y chunks. // At dist 64 this reduces ~278K clip() calls to ~17K column tests + per-chunk tests only for visible columns. @@ -2672,13 +2699,6 @@ void LevelRenderer::cull(Culler *culler, float a) ClipChunk *pClipChunk = &chunks[playerIndex][(z * yChunks + y) * xChunks + x]; unsigned char flags = pClipChunk->globalIdx == -1 ? 0 : globalChunkFlags[ pClipChunk->globalIdx ]; - // Skip frustum test for confirmed-empty compiled chunks - they have nothing to render - if ((flags & CHUNK_FLAG_COMPILED) && (flags & CHUNK_FLAG_EMPTYBOTH) == CHUNK_FLAG_EMPTYBOTH) - { - pClipChunk->visible = false; - continue; - } - bool clipres = clip(pClipChunk->aabb, fdraw); if ( (flags & CHUNK_FLAG_COMPILED ) && ( ( flags & CHUNK_FLAG_EMPTYBOTH ) != CHUNK_FLAG_EMPTYBOTH ) ) @@ -2699,11 +2719,12 @@ void LevelRenderer::cull(Culler *culler, float a) // Build compact visible chunk lists for renderChunks() if (pClipChunk->visible && pClipChunk->globalIdx != -1 && visibleLists_layer0 != nullptr) { - int list = pClipChunk->globalIdx * 2 + chunkLists; + int list = pClipChunk->globalIdx * CHUNK_RENDER_LAYERS + chunkLists; if (!((flags & CHUNK_FLAG_EMPTY0) == CHUNK_FLAG_EMPTY0)) visibleLists_layer0[visibleCount_layer0++] = list; if (!((flags & CHUNK_FLAG_EMPTY1) == CHUNK_FLAG_EMPTY1)) visibleLists_layer1[visibleCount_layer1++] = list + 1; + visibleLists_layer2[visibleCount_layer2++] = list + 2; } } } diff --git a/Minecraft.Client/LevelRenderer.h b/Minecraft.Client/LevelRenderer.h index 30db8c4c..3fa61445 100644 --- a/Minecraft.Client/LevelRenderer.h +++ b/Minecraft.Client/LevelRenderer.h @@ -46,6 +46,7 @@ private: public: static const int CHUNK_XZSIZE = 16; + static const int CHUNK_RENDER_LAYERS = 3; #ifdef _LARGE_WORLDS static const int CHUNK_SIZE = 16; #else @@ -274,8 +275,10 @@ public: // Visible chunk lists built by cull(), consumed by renderChunks() int *visibleLists_layer0; int *visibleLists_layer1; + int *visibleLists_layer2; int visibleCount_layer0; int visibleCount_layer1; + int visibleCount_layer2; bool dirtyChunkPresent; int64_t lastDirtyChunkFound; diff --git a/Minecraft.World/HalfTransparentTile.cpp b/Minecraft.World/HalfTransparentTile.cpp index 0b8c25c2..1a996062 100644 --- a/Minecraft.World/HalfTransparentTile.cpp +++ b/Minecraft.World/HalfTransparentTile.cpp @@ -16,21 +16,9 @@ bool HalfTransparentTile::isSolidRender(bool isServerLevel) bool HalfTransparentTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - int id = level->getTile(x, y, z); - if (this->id == 95) // Tile::stained_glass - { - bool isBlocking = level->isTopSolidBlocking(x, y, z); - if (face == 0 && level->isSolidBlockingTile(x, y + 1, z) != isBlocking) return true; // Facing::DOWN - else if (face == 1 && level->isTopSolidBlocking(x, y - 1, z) != isBlocking) return true; // Facing::UP - else if (face == 2 && level->isSolidBlockingTile(x, y, z + 1) != isBlocking) return true; // Facing::NORTH - else if (face == 3 && level->isSolidBlockingTile(x, y, z - 1) != isBlocking) return true; // Facing::SOUTH - else if (face == 4 && level->isSolidBlockingTile(x + 1, y, z) != isBlocking) return true; // Facing::WEST - else if (face == 5 && level->isSolidBlockingTile(x - 1, y, z) != isBlocking) return true; // Facing::EAST - else if (face == 6 && level->isSolidBlockingTile(x, y, z) != isBlocking) return true; // not really a direction? is this supposed to be here? - } - - if (!allowSame && id == this->id) return false; - return Tile::shouldRenderFace(level, x, y, z, face); + int id = level->getTile(x, y, z); + if (!allowSame && id == this->id) return false; + return Tile::shouldRenderFace(level, x, y, z, face); } bool HalfTransparentTile::blocksLight() @@ -41,4 +29,4 @@ bool HalfTransparentTile::blocksLight() void HalfTransparentTile::registerIcons(IconRegister *iconRegister) { icon = iconRegister->registerIcon(texture); -} \ No newline at end of file +} diff --git a/Minecraft.World/StainedGlassBlock.cpp b/Minecraft.World/StainedGlassBlock.cpp index 3fae3d46..dcf4e401 100644 --- a/Minecraft.World/StainedGlassBlock.cpp +++ b/Minecraft.World/StainedGlassBlock.cpp @@ -27,7 +27,7 @@ int StainedGlassBlock::getItemAuxValueForBlockData(int data) int StainedGlassBlock::getRenderLayer() { - return 1; + return 2; } void StainedGlassBlock::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/StainedGlassPaneBlock.cpp b/Minecraft.World/StainedGlassPaneBlock.cpp index 086d8ae5..a73be08b 100644 --- a/Minecraft.World/StainedGlassPaneBlock.cpp +++ b/Minecraft.World/StainedGlassPaneBlock.cpp @@ -38,7 +38,7 @@ int StainedGlassPaneBlock::getItemAuxValueForBlockData(int data) int StainedGlassPaneBlock::getRenderLayer() { - return 1; + return 2; } void StainedGlassPaneBlock::registerIcons(IconRegister *iconRegister) @@ -49,4 +49,4 @@ void StainedGlassPaneBlock::registerIcons(IconRegister *iconRegister) ICONS[i] = iconRegister->registerIcon(getIconName() + L"_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForBlockData(i)]); EDGE_ICONS[i] = iconRegister->registerIcon(getIconName() + L"_pane_top_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForBlockData(i)]); } -} \ No newline at end of file +}