diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index fc9f2293a5..fd09b004b4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -52,6 +52,7 @@ * `Increase Render Chunk Size` (Enabled By Default) * `Proper Entity Shading` (Enabled By Default) * `Fix Sugar Position In Hand` (Enabled By Default) + * `Chunk OpenGL Occlusion Checking` (Disabled By Default) * Existing Functionality (All Enabled By Default) * `Fix Screen Rendering When Hiding HUD` * `Sanitize Usernames` diff --git a/launcher/src/client/available-feature-flags b/launcher/src/client/available-feature-flags index 75212c0ee8..bfae111ebc 100644 --- a/launcher/src/client/available-feature-flags +++ b/launcher/src/client/available-feature-flags @@ -112,4 +112,5 @@ TRUE Render Entity Shadows TRUE Render Vignette TRUE Increase Render Chunk Size TRUE Proper Entity Shading -TRUE Fix Sugar Position In Hand \ No newline at end of file +TRUE Fix Sugar Position In Hand +FALSE Chunk OpenGL Occlusion Checking \ No newline at end of file diff --git a/mods/src/misc/graphics.cpp b/mods/src/misc/graphics.cpp index 240cd73434..d4627407a8 100644 --- a/mods/src/misc/graphics.cpp +++ b/mods/src/misc/graphics.cpp @@ -501,6 +501,63 @@ static int safe_log2(const int x) { return z; } +// Occlusion Checking +static int num_occlusion_ids; +static GLuint *occlusion_ids; +static LevelRenderer *LevelRenderer_injection(LevelRenderer_constructor_t original, LevelRenderer *self, Minecraft *minecraft) { + // Call Original Method + original(self, minecraft); + // Setup + self->occlusion_check = true; + num_occlusion_ids = self->num_buffers / 3; + occlusion_ids = new GLuint[num_occlusion_ids]; + media_glGenQueries(num_occlusion_ids, occlusion_ids); + return self; +} +static void LevelRenderer_allChanged_Chunk_setDirty_injection(Chunk *self) { + self->occlusion_id = int(occlusion_ids[self->id]); + // Call Original Method + self->setDirty(); +} +static void check_query_result(Chunk *chunk) { + if (chunk->occlusion_querying) { + GLuint val; + media_glGetQueryObjectuiv(chunk->occlusion_id, GL_QUERY_RESULT_AVAILABLE, &val); + if (val != 0) { + chunk->occlusion_querying = false; + media_glGetQueryObjectuiv(chunk->occlusion_id, GL_QUERY_RESULT, &val); + chunk->occlusion_visible = val != 0; + } + } +} +static int LevelRenderer_render_LevelRenderer_renderChunks_injection(LevelRenderer *self, const int start, const int end, const int a, const float b) { + for (int i = start; i < end; i++) { + Chunk *chunk = self->chunks[i]; + check_query_result(chunk); + chunk->occlusion_visible = true; + } + // Call Original Method + return self->renderChunks(start, end, a, b); +} +static bool LevelRenderer_render_Chunk_isEmpty_injection(Chunk *self) { + check_query_result(self); + // Call Original Method + return self->isEmpty(); +} +static void Chunk_renderBB_injection(__attribute__((unused)) Chunk_renderBB_t original, Chunk *self) { + media_glBeginQuery(GL_SAMPLES_PASSED, self->occlusion_id); + AABB aabb = { + .x1 = self->aabb.x1 - float(self->x), + .y1 = self->aabb.y1 - float(self->y), + .z1 = self->aabb.z1 - float(self->z), + .x2 = self->aabb.x2 - float(self->x), + .y2 = self->aabb.y2 - float(self->y), + .z2 = self->aabb.z2 - float(self->z) + }; + EntityRenderer::renderFlat(aabb); + media_glEndQuery(GL_SAMPLES_PASSED); +} + // Init void _init_misc_graphics() { // Disable V-Sync @@ -651,6 +708,15 @@ void _init_misc_graphics() { patch((void *) 0x4f20c, render_chunk_patch_seven); } + // Occlusion Checking + if(feature_has("Chunk OpenGL Occlusion Checking", server_disabled)) { + overwrite_calls(LevelRenderer_constructor, LevelRenderer_injection); + overwrite_call((void *) 0x4fce4, (void *) LevelRenderer_allChanged_Chunk_setDirty_injection); + overwrite_call((void *) 0x4f8d4, (void *) LevelRenderer_render_LevelRenderer_renderChunks_injection); + overwrite_call((void *) 0x4f960, (void *) LevelRenderer_render_Chunk_isEmpty_injection); + overwrite_calls(Chunk_renderBB, Chunk_renderBB_injection); + } + // Don't Render Game In Headless Mode if (reborn_is_headless()) { overwrite_calls(GameRenderer_render, nop); diff --git a/mods/src/multidraw/glue.cpp b/mods/src/multidraw/glue.cpp index 3d0255d2e6..46a0633850 100644 --- a/mods/src/multidraw/glue.cpp +++ b/mods/src/multidraw/glue.cpp @@ -94,13 +94,13 @@ static void multidraw_renderSameAsLast(const LevelRenderer *self, const float b) media_glDisableClientState(GL_TEXTURE_COORD_ARRAY); media_glPopMatrix(); } -static int LevelRenderer_renderChunks_injection(__attribute__((unused)) LevelRenderer_renderChunks_t original, LevelRenderer *self, const int start, const int end, const int a, const float b) { +static int LevelRenderer_renderChunks_injection(__attribute__((unused)) LevelRenderer_renderChunks_t original, const LevelRenderer *self, const int start, const int end, const int a, const float b) { // Batch multidraw_total = 0; for (int i = start; i < end; i++) { Chunk *chunk = self->chunks[i]; // Check If Chunk Is Visible - if (!chunk->field_1c[a] && chunk->visible) { + if (!chunk->field_1c[a] && chunk->visible && (!self->occlusion_check || chunk->occlusion_visible)) { const RenderChunk *render_chunk = chunk->getRenderChunk(a); // Get Data Block const int chunk_id = int(render_chunk->buffer - MULTIDRAW_BASE); diff --git a/symbols/src/entity/EntityRenderer.def b/symbols/src/entity/EntityRenderer.def index 4f6d6843b6..a91ad780ce 100644 --- a/symbols/src/entity/EntityRenderer.def +++ b/symbols/src/entity/EntityRenderer.def @@ -10,3 +10,4 @@ property float shadow_strength = 0x8; // Globals static-property EntityRenderDispatcher *entityRenderDispatcher = 0x137bc0; +static-method void renderFlat(const AABB &aabb) = 0x627c8; \ No newline at end of file diff --git a/symbols/src/level/renderer/Chunk.def b/symbols/src/level/renderer/Chunk.def index 9cc8d2460b..79dcaf59a3 100644 --- a/symbols/src/level/renderer/Chunk.def +++ b/symbols/src/level/renderer/Chunk.def @@ -3,7 +3,15 @@ property int y = 0x8; property int z = 0xc; property bool field_1c[3] = 0x1c; property bool visible = 0x4c; +property bool occlusion_visible = 0x4d; +property bool occlusion_querying = 0x4e; +property int occlusion_id = 0x50; +property AABB aabb = 0x30; +property int id = 0x48; method float distanceToSqr(const Entity *entity) = 0x47ba0; method int getList(int a) = 0x47e48; method RenderChunk *getRenderChunk(int a) = 0x47e74; +method void renderBB() = 0x47ed8; +method void setDirty() = 0x47ef0; +method bool isEmpty() = 0x47edc; \ No newline at end of file diff --git a/symbols/src/level/renderer/LevelRenderer.def b/symbols/src/level/renderer/LevelRenderer.def index b4a9be0add..3eed29fbc7 100644 --- a/symbols/src/level/renderer/LevelRenderer.def +++ b/symbols/src/level/renderer/LevelRenderer.def @@ -1,3 +1,7 @@ +vtable 0x107438; + +constructor (Minecraft *minecraft) = 0x4e5f8; + method void tick() = 0x4da1c; method int render(Mob *mob, int param_1, float delta) = 0x4f710; method void render_AABB(const AABB &box) = 0x4d740; @@ -10,4 +14,6 @@ method void renderEntities(Vec3 pos, void *unknown, float a) = 0x500ec; property Minecraft *minecraft = 0xb4; property RenderList render_list = 0x34; -property Chunk **chunks = 0x98; \ No newline at end of file +property Chunk **chunks = 0x98; +property bool occlusion_check = 0xb8; +property int num_buffers = 0xd0; \ No newline at end of file