diff --git a/dependencies/gles-compatibility-layer/src b/dependencies/gles-compatibility-layer/src index 68561e04..fedc5ac2 160000 --- a/dependencies/gles-compatibility-layer/src +++ b/dependencies/gles-compatibility-layer/src @@ -1 +1 @@ -Subproject commit 68561e0404a4ad09e523129bca67cf6be8cec2fc +Subproject commit fedc5ac21865fe44dcbc7adb0818af612205cd57 diff --git a/launcher/src/client/available-feature-flags b/launcher/src/client/available-feature-flags index 34b3dac1..51faee33 100644 --- a/launcher/src/client/available-feature-flags +++ b/launcher/src/client/available-feature-flags @@ -68,4 +68,5 @@ TRUE Fix Held Item Caching TRUE Add Reborn Info To Options FALSE Log FPS TRUE Add Welcome Screen -TRUE F3 Debug Information \ No newline at end of file +TRUE F3 Debug Information +TRUE Multidraw Rendering \ No newline at end of file diff --git a/media-layer/core/src/media.cpp b/media-layer/core/src/media.cpp index 9db8872a..9d2e3b3d 100644 --- a/media-layer/core/src/media.cpp +++ b/media-layer/core/src/media.cpp @@ -564,4 +564,13 @@ void media_get_framebuffer_size(int *width, int *height) { *width = DEFAULT_WIDTH; *height = DEFAULT_HEIGHT; } +} + +// Check OpenGL Extension +int media_has_extension(const char *name) { + if (glfw_window) { + return glfwExtensionSupported(name); + } else { + return 0; + } } \ No newline at end of file diff --git a/media-layer/include/media-layer/core.h b/media-layer/include/media-layer/core.h index 2ef93afa..a2d7b69c 100644 --- a/media-layer/include/media-layer/core.h +++ b/media-layer/include/media-layer/core.h @@ -22,6 +22,7 @@ void media_set_interactable(int is_interactable); void media_disable_vsync(); void media_force_egl(); void media_set_raw_mouse_motion_enabled(int enabled); +int media_has_extension(const char *name); #ifdef __cplusplus } diff --git a/media-layer/trampoline/src/GLESv1_CM.cpp b/media-layer/trampoline/src/GLESv1_CM.cpp index 1d08a3b3..a39b8fbe 100644 --- a/media-layer/trampoline/src/GLESv1_CM.cpp +++ b/media-layer/trampoline/src/GLESv1_CM.cpp @@ -138,6 +138,23 @@ CALL(15, glDrawArrays, void, (GLenum mode, GLint first, GLsizei count)) #endif } +#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER +CALL(70, glMultiDrawArrays, void, (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount)) +#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST + trampoline(true, gl_state, mode, copy_array(drawcount, first), copy_array(drawcount, count)); +#else + gl_state_t gl_state = args.next(); + gl_state.send_to_driver(); + GLenum mode = args.next(); + uint32_t drawcount; + const GLint *first = args.next_arr(&drawcount); + const GLsizei *count = args.next_arr(); + func(mode, first, count, GLsizei(drawcount)); + return 0; +#endif +} +#endif + CALL(16, glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST trampoline(true, red, green, blue, alpha); @@ -162,14 +179,14 @@ CALL(17, glClear, void, (GLbitfield mask)) CALL(18, glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage)) #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST - trampoline(true, gl_state.bound_array_buffer, target, copy_array(size, (unsigned char *) data), usage); + trampoline(true, gl_state.bound_array_buffer, target, int32_t(size), copy_array(size, (unsigned char *) data), usage); #else glBindBuffer(GL_ARRAY_BUFFER, args.next()); GLenum target = args.next(); - uint32_t size; - const unsigned char *data = args.next_arr(&size); + int32_t size = args.next(); + const unsigned char *data = args.next_arr(); GLenum usage = args.next(); - func(target, GLsizeiptr(size), data, usage); + func(target, size, data, usage); return 0; #endif } @@ -738,3 +755,17 @@ CALL(67, glGenBuffers, void, (GLsizei n, GLuint *buffers)) return 0; #endif } + +CALL(69, glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void *data)) +#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST + trampoline(true, gl_state.bound_array_buffer, target, int32_t(offset), int32_t(size), copy_array(size, (unsigned char *) data)); +#else + glBindBuffer(GL_ARRAY_BUFFER, args.next()); + GLenum target = args.next(); + int32_t offset = args.next(); + int32_t size = args.next(); + const unsigned char *data = args.next_arr(); + func(target, offset, size, data); + return 0; +#endif +} \ No newline at end of file diff --git a/media-layer/trampoline/src/host/host.h b/media-layer/trampoline/src/host/host.h index d71b726c..da4b91e7 100644 --- a/media-layer/trampoline/src/host/host.h +++ b/media-layer/trampoline/src/host/host.h @@ -38,6 +38,9 @@ struct TrampolineArguments { if (length != nullptr) { *length = size / sizeof(T); } + if (size == 0) { + return nullptr; + } const T *ret = (const T *) raw_args; raw_args += size; return ret; diff --git a/media-layer/trampoline/src/media-layer-core.cpp b/media-layer/trampoline/src/media-layer-core.cpp index f9c19aff..6836a0c5 100644 --- a/media-layer/trampoline/src/media-layer-core.cpp +++ b/media-layer/trampoline/src/media-layer-core.cpp @@ -182,3 +182,11 @@ CALL(68, media_ensure_loaded, void, ()) return 0; #endif } + +CALL(71, media_has_extension, int, (const char *name)) +#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST + return trampoline(false, copy_array(name)); +#else + return func(args.next_arr()); +#endif +} diff --git a/mods/CMakeLists.txt b/mods/CMakeLists.txt index 1004cfd5..1aa5ed1b 100644 --- a/mods/CMakeLists.txt +++ b/mods/CMakeLists.txt @@ -89,6 +89,10 @@ set(SRC src/init/init.cpp # f3 src/f3/f3.cpp + # multidraw + src/multidraw/glue.cpp + src/multidraw/buffer.cpp + src/multidraw/storage.cpp ) # Install Splashes install( diff --git a/mods/include/mods/init/init.h b/mods/include/mods/init/init.h index 776252a8..ca6ae430 100644 --- a/mods/include/mods/init/init.h +++ b/mods/include/mods/init/init.h @@ -29,4 +29,5 @@ void init_home(); void init_override(); void init_screenshot(); void init_f3(); +void init_multidraw(); } diff --git a/mods/src/init/init.cpp b/mods/src/init/init.cpp index c522104e..6cd82d14 100644 --- a/mods/src/init/init.cpp +++ b/mods/src/init/init.cpp @@ -43,5 +43,6 @@ __attribute__((constructor)) static void init() { if (!reborn_is_headless()) { init_screenshot(); init_f3(); + init_multidraw(); } } diff --git a/mods/src/misc/misc.cpp b/mods/src/misc/misc.cpp index 29a35a78..96c1fc07 100644 --- a/mods/src/misc/misc.cpp +++ b/mods/src/misc/misc.cpp @@ -724,7 +724,7 @@ static void sort_chunks(Chunk **chunks_begin, Chunk **chunks_end, DistanceChunkS // Display Date In Select World Screen static std::string AppPlatform_linux_getDateString_injection(__attribute__((unused)) AppPlatform_linux *app_platform, int time) { // From https://github.com/ReMinecraftPE/mcpe/blob/56e51027b1c2e67fe5a0e8a091cefe51d4d11926/platforms/sdl/base/AppPlatform_sdl_base.cpp#L68-L84 - time_t tt = time; + const time_t tt = time; tm t = {}; gmtime_r(&tt, &t); char buf[2048]; diff --git a/mods/src/multidraw/buffer.cpp b/mods/src/multidraw/buffer.cpp new file mode 100644 index 00000000..e483c170 --- /dev/null +++ b/mods/src/multidraw/buffer.cpp @@ -0,0 +1,29 @@ +#include + +#include "buffer.h" + +// Setup Buffer +Buffer::Buffer(const ssize_t size) { + // Client-Side Data + client_side_data = new unsigned char[size]; + // Server-Side Data + server_side_data = 0; + glGenBuffers(1, &server_side_data); + glBindBuffer(GL_ARRAY_BUFFER, server_side_data); + glBufferData(GL_ARRAY_BUFFER, size, nullptr, GL_DYNAMIC_DRAW); +} +Buffer::~Buffer() { + // Client-Side Data + delete[] client_side_data; + // Server-Side Data + glDeleteBuffers(1, &server_side_data); +} + +// Upload Data +void Buffer::upload(const intptr_t offset, const ssize_t size, const void *data) const { + // Client-Side Data + memcpy(client_side_data + offset, data, size); + // Server-Side Data + glBindBuffer(GL_ARRAY_BUFFER, server_side_data); + glBufferSubData(GL_ARRAY_BUFFER, offset, size, data); +} diff --git a/mods/src/multidraw/buffer.h b/mods/src/multidraw/buffer.h new file mode 100644 index 00000000..8a596cea --- /dev/null +++ b/mods/src/multidraw/buffer.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +// Keep An OpenGL Buffer And Client-Side Memory Synchronized +struct Buffer { + explicit Buffer(ssize_t size); + ~Buffer(); + + // Prevent Copying + Buffer(const Buffer &) = delete; + Buffer &operator=(const Buffer &) = delete; + + // Data + GLuint server_side_data; + unsigned char *client_side_data; + + // Upload Data + void upload(intptr_t offset, ssize_t size, const void *data) const; +}; \ No newline at end of file diff --git a/mods/src/multidraw/glue.cpp b/mods/src/multidraw/glue.cpp new file mode 100644 index 00000000..51502f1b --- /dev/null +++ b/mods/src/multidraw/glue.cpp @@ -0,0 +1,135 @@ +#include + +#include +#include +#include + +#include +#include + +#include "storage.h" + +// Fake Buffer IDs To Correspond To The Multidraw Storage +#define MULTIDRAW_BASE 1073741823 + +// Setup +static Storage *storage = nullptr; +static void setup_multidraw(int chunks, GLuint *buffers) { + delete storage; + storage = new Storage(chunks); + for (int i = 0; i < chunks; i++) { + buffers[i] = i + MULTIDRAW_BASE; + } +} +HOOK(glDeleteBuffers, void, (GLsizei n, const GLuint *buffers)) { + if (buffers[0] >= MULTIDRAW_BASE) { + delete storage; + } else { + ensure_glDeleteBuffers(); + real_glDeleteBuffers(n, buffers); + } +} + +// Usage +static int current_chunk = -1; +HOOK(glBindBuffer, void, (const GLenum target, GLuint buffer)) { + if (target == GL_ARRAY_BUFFER && buffer >= MULTIDRAW_BASE && storage != nullptr) { + current_chunk = int(buffer - MULTIDRAW_BASE); + buffer = storage->buffer->server_side_data; + } else { + current_chunk = -1; + } + ensure_glBindBuffer(); + real_glBindBuffer(target, buffer); +} +HOOK(glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage)) { + if (target == GL_ARRAY_BUFFER && current_chunk >= 0 && storage != nullptr) { + storage->upload(current_chunk, size, data); + } else { + ensure_glBufferData(); + real_glBufferData(target, size, data, usage); + } +} +#define VERTEX_SIZE 24 +#define MAX_RENDER_CHUNKS 4096 +static bool supports_multidraw() { + static int ret = -1; + if (ret == -1) { + ret = media_has_extension("GL_EXT_multi_draw_arrays"); + } + return ret; +} +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) { + // Prepare Offset + self->render_list.clear(); + const Mob *camera = self->minecraft->camera; + const float x = camera->old_x + ((camera->x - camera->old_x) * b); + const float y = camera->old_y + ((camera->y - camera->old_y) * b); + const float z = camera->old_z + ((camera->z - camera->old_z) * b); + glPushMatrix(); + glTranslatef(-x, -y, -z); + + // Setup OpenGL + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, storage->buffer->server_side_data); + glVertexPointer(3, GL_FLOAT, VERTEX_SIZE, (void *) 0); + glTexCoordPointer(2, GL_FLOAT, VERTEX_SIZE, (void *) 0xc); + glColorPointer(4, GL_UNSIGNED_BYTE, VERTEX_SIZE, (void *) 0x14); + + // Batch + static GLint firsts[MAX_RENDER_CHUNKS]; + static GLsizei counts[MAX_RENDER_CHUNKS]; + GLsizei 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) { + const RenderChunk *render_chunk = chunk->getRenderChunk(a); + // Get Data Block + const int chunk_id = int(render_chunk->buffer - MULTIDRAW_BASE); + const Block *block = storage->chunk_to_block[chunk_id]; + if (block == nullptr) { + continue; + } + // Queue + const int j = total++; + firsts[j] = block->offset / VERTEX_SIZE; + counts[j] = render_chunk->vertices; + } + } + + // Draw +#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER + if (supports_multidraw()) { + glMultiDrawArrays(GL_TRIANGLES, firsts, counts, total); + } else { +#endif + for (int i = 0; i < total; i++) { + glDrawArrays(GL_TRIANGLES, firsts[i], counts[i]); + } +#ifdef MCPI_USE_GLES1_COMPATIBILITY_LAYER + } +#endif + + // Cleanup + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glPopMatrix(); + + // Return + return total; +} + +// Init +void init_multidraw() { + // Setup + if (feature_has("Multidraw Rendering", server_disabled)) { + overwrite_call((void *) 0x4e51c, (void *) setup_multidraw); + overwrite_call((void *) 0x4e6f8, (void *) setup_multidraw); + overwrite_calls(LevelRenderer_renderChunks, LevelRenderer_renderChunks_injection); + unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" + patch((void *) 0x479fc, nop_patch); + } +} \ No newline at end of file diff --git a/mods/src/multidraw/storage.cpp b/mods/src/multidraw/storage.cpp new file mode 100644 index 00000000..99732884 --- /dev/null +++ b/mods/src/multidraw/storage.cpp @@ -0,0 +1,185 @@ +#include + +#include "storage.h" + +#include + +// Setup +#define DEFAULT_SIZE 16777216 // 16 MiB +Storage::Storage(const int chunks) { + // Allocate + total_size = DEFAULT_SIZE; + used_size = 0; + for (int i = 0; i < chunks; i++) { + chunk_to_block.push_back(nullptr); + } + buffer = new Buffer(total_size); + // First Free Block + Block *block = new Block; + block->offset = 0; + block->size = total_size; + free_blocks.push_back(block); +} +Storage::~Storage() { + delete buffer; + for (const std::vector &blocks : {free_blocks, used_blocks}) { + for (const Block *block : blocks) { + delete block; + } + } +} + +// Free Block +void Storage::free_block(Block *block) { + // Check + if (block == nullptr) { + return; + } + + // Find Block + std::vector::iterator it = std::find(used_blocks.begin(), used_blocks.end(), block); + if (it == used_blocks.end()) { + return; + } + used_blocks.erase(it); + + // Update Size + used_size -= block->size; + + // Merge With Next/Previous Blocks + for (it = free_blocks.begin(); it < free_blocks.end(); ++it) { + const Block *x = *it; + if (x->offset == (block->offset + block->size)) { + // Found Free Block After Target + block->size += x->size; + free_blocks.erase(it); + delete x; + break; + } + } + for (it = free_blocks.begin(); it < free_blocks.end(); ++it) { + const Block *x = *it; + if ((x->offset + x->size) == block->offset) { + // Found Free Block Before Target + block->size += x->size; + block->offset -= x->size; + free_blocks.erase(it); + delete x; + break; + } + } + + // Add To Free Block List + free_blocks.push_back(block); + + // Fragmentation + check_fragmentation(); +} + +// Check Fragmentation +ssize_t Storage::get_end() const { + ssize_t end = 0; + for (const Block *block : used_blocks) { + const ssize_t new_end = block->offset + block->size; + if (new_end > end) { + end = new_end; + } + } + return end; +} +void Storage::check_fragmentation() { + const ssize_t end = get_end(); + if (end == 0) { + return; + } + const float fragmentation = 1.0f - (float(used_size) / float(end)); + if (fragmentation >= 0.5f) { + // 50% Fragmentation + recreate(); + } +} + +// Upload Chunk +void Storage::upload(const int chunk, const ssize_t size, const void *data) { + // Free Old Block + free_block(chunk_to_block[chunk]); + + // Check Size + if (size == 0) { + chunk_to_block[chunk] = nullptr; + return; + } + + // Find Free Block + std::vector::iterator it; + while (true) { + for (it = free_blocks.begin(); it < free_blocks.end(); ++it) { + if ((*it)->size >= size) { + break; + } + } + if (it == free_blocks.end()) { + // Get Extra Space + recreate(size); + } else { + // Done! + break; + } + } + Block *old_free_block = *it; + + // Create New Used Block + Block *new_used_block = new Block; + new_used_block->offset = old_free_block->offset; + new_used_block->size = size; + used_blocks.push_back(new_used_block); + // Update Old Free Block + old_free_block->offset += size; + old_free_block->size -= size; + if (old_free_block->size == 0) { + free_blocks.erase(it); + delete old_free_block; + } + + // Upload + buffer->upload(new_used_block->offset, size, data); + + // Assign Block To Chunk + chunk_to_block[chunk] = new_used_block; + + // Update Size + used_size += size; + + // Check Fragmentation + check_fragmentation(); +} + +// Recreate/Defragment +void Storage::recreate(const ssize_t extra_size) { + // Create New Buffer + const ssize_t new_size = (used_size + extra_size) * 2; + Buffer *new_buffer = new Buffer(new_size); + + // Copy Used Blocks + intptr_t offset = 0; + for (Block *block : used_blocks) { + new_buffer->upload(offset, block->size, buffer->client_side_data + block->offset); + block->offset = offset; + offset += block->size; + } + + // Update Free Blocks + for (const Block *block : free_blocks) { + delete block; + } + free_blocks.clear(); + Block *block = new Block; + block->offset = offset; + block->size = new_size - offset; + free_blocks.push_back(block); + + // Use New Buffer + delete buffer; + buffer = new_buffer; + total_size = new_size; +} \ No newline at end of file diff --git a/mods/src/multidraw/storage.h b/mods/src/multidraw/storage.h new file mode 100644 index 00000000..ef4ae109 --- /dev/null +++ b/mods/src/multidraw/storage.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include "buffer.h" + +// Block Of Data +struct Block { + intptr_t offset; + ssize_t size; + // Prevent Copying + Block() { + offset = 0; + size = 0; + } + Block(const Block &) = delete; + Block &operator=(const Block &) = delete; +}; + +// Storage +struct Storage { + explicit Storage(int chunks); + ~Storage(); + + // Buffer + Buffer *buffer; + + // Chunks + std::vector chunk_to_block; + void upload(int chunk, ssize_t size, const void *data); + + // Management + ssize_t total_size; + ssize_t used_size; + std::vector free_blocks; + std::vector used_blocks; + void free_block(Block *block); + void recreate(ssize_t extra_size = 0); + void check_fragmentation(); + ssize_t get_end() const; +}; \ No newline at end of file diff --git a/mods/src/screenshot/screenshot.cpp b/mods/src/screenshot/screenshot.cpp index c8c4507e..fddb5975 100644 --- a/mods/src/screenshot/screenshot.cpp +++ b/mods/src/screenshot/screenshot.cpp @@ -91,11 +91,11 @@ void screenshot_take(Gui *gui) { if (save_png(file.c_str(), pixels, line_size, width, height)) { WARN("Screenshot Failed: %s", file.c_str()); } else { - std::string msg = "Screenshot Saved: "; - INFO("%s%s", msg.c_str(), file.c_str()); + INFO("Screenshot Saved: %s", file.c_str()); if (gui) { - msg += filename; - gui->addMessage(&msg); + std::string chat_msg = "Saved screenshot as "; + chat_msg += filename; + gui->addMessage(&chat_msg); } } diff --git a/symbols/CMakeLists.txt b/symbols/CMakeLists.txt index 79a2ae83..4f5b1f77 100644 --- a/symbols/CMakeLists.txt +++ b/symbols/CMakeLists.txt @@ -79,9 +79,9 @@ set(SRC src/level/ChunkStorage.def src/level/LightLayer.def src/level/Level.def - src/level/LevelRenderer.def + src/level/renderer/LevelRenderer.def src/level/LevelStorageSource.def - src/level/ParticleEngine.def + src/level/renderer/ParticleEngine.def src/level/RandomLevelSource.def src/level/LevelData.def src/level/LevelSettings.def @@ -90,7 +90,7 @@ set(SRC src/level/MultiPlayerLevel.def src/level/LevelSummary.def src/level/DistanceChunkSorter.def - src/level/Chunk.def + src/level/renderer/Chunk.def src/item/ItemRenderer.def src/item/ItemInHandRenderer.def src/item/AuxDataTileItem.def @@ -161,6 +161,8 @@ set(SRC src/misc/Vec3.def src/misc/HitResult.def src/misc/PerfRenderer.def + src/level/renderer/RenderList.def + src/level/renderer/RenderChunk.def src/textures/Texture.def src/textures/Textures.def src/textures/DynamicTexture.def diff --git a/symbols/src/level/Chunk.def b/symbols/src/level/Chunk.def deleted file mode 100644 index 9614e85d..00000000 --- a/symbols/src/level/Chunk.def +++ /dev/null @@ -1,5 +0,0 @@ -property int x = 0x4; -property int y = 0x8; -property int z = 0xc; - -method float distanceToSqr(Entity *entity) = 0x47ba0; diff --git a/symbols/src/level/renderer/Chunk.def b/symbols/src/level/renderer/Chunk.def new file mode 100644 index 00000000..ffe95f15 --- /dev/null +++ b/symbols/src/level/renderer/Chunk.def @@ -0,0 +1,9 @@ +property int x = 0x4; +property int y = 0x8; +property int z = 0xc; +property bool field_1c[3] = 0x1c; +property bool visible = 0x4c; + +method float distanceToSqr(Entity *entity) = 0x47ba0; +method int getList(int a) = 0x47e48; +method RenderChunk *getRenderChunk(int a) = 0x47e74; diff --git a/symbols/src/level/LevelRenderer.def b/symbols/src/level/renderer/LevelRenderer.def similarity index 69% rename from symbols/src/level/LevelRenderer.def rename to symbols/src/level/renderer/LevelRenderer.def index d15a4f48..93789b37 100644 --- a/symbols/src/level/LevelRenderer.def +++ b/symbols/src/level/renderer/LevelRenderer.def @@ -4,5 +4,8 @@ method void renderDebug(AABB *aabb, float delta) = 0x4d310; method void generateSky() = 0x4d0d4; method void renderHitSelect(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4e318; method void renderHitOutline(Player *player, HitResult *hit_result, int i, void *vp, float f) = 0x4dc14; +method int renderChunks(int start, int end, int a, float b) = 0x4f35c; -property Minecraft *minecraft = 0x4; +property Minecraft *minecraft = 0xb4; +property RenderList render_list = 0x34; +property Chunk **chunks = 0x98; \ No newline at end of file diff --git a/symbols/src/level/ParticleEngine.def b/symbols/src/level/renderer/ParticleEngine.def similarity index 100% rename from symbols/src/level/ParticleEngine.def rename to symbols/src/level/renderer/ParticleEngine.def diff --git a/symbols/src/level/renderer/RenderChunk.def b/symbols/src/level/renderer/RenderChunk.def new file mode 100644 index 00000000..f5e38bb7 --- /dev/null +++ b/symbols/src/level/renderer/RenderChunk.def @@ -0,0 +1,7 @@ +size 0x18; + +property uint buffer = 0x0; +property int vertices = 0x4; +property float x = 0xc; +property float y = 0x10; +property float z = 0x14; \ No newline at end of file diff --git a/symbols/src/level/renderer/RenderList.def b/symbols/src/level/renderer/RenderList.def new file mode 100644 index 00000000..568d41d3 --- /dev/null +++ b/symbols/src/level/renderer/RenderList.def @@ -0,0 +1,9 @@ +method void render() = 0x52800; +method void renderChunks() = 0x52708; +method void clear() = 0x5288c; +method void init(float x, float y, float z) = 0x526bc; +method void addR(RenderChunk *chunk) = 0x526dc; + +property int size = 0x1c; +property RenderChunk *chunks = 0x10; +property int field_14 = 0x14; \ No newline at end of file