800th Commit! Regenerating gui_blocks And Performance Fixes
This commit is contained in:
parent
ee44a0ce88
commit
69fcc6cdb3
2
dependencies/runtime/src
vendored
2
dependencies/runtime/src
vendored
@ -1 +1 @@
|
||||
Subproject commit c13072404d3bb7ffe6b58fea72393c305c1f5eab
|
||||
Subproject commit 377f9ddbc4747ca3a640231d259c0e6fcc71b4b0
|
@ -76,8 +76,11 @@
|
||||
* `Force Survival Mode Inventory Behavior` (Disabled By Default)
|
||||
* `Maximize Creative Mode Inventory Stack Size` (Disabled By Default)
|
||||
* Rename `Disable Buggy Held Item Caching` Feature Flag To `Fix Held Item Caching`
|
||||
* Rename `Disable 'gui_blocks' Atlas` Feature Flag To `Regenerate "gui_blocks" Atlas`
|
||||
* Add Milk Buckets
|
||||
* Included In The `Add Buckets` Feature Flag
|
||||
* Removed `Property Scale Animated Textures` Feature Flag
|
||||
* Removed `Remove Invalid Item Background` Feature Flag
|
||||
* Improve Death Messages
|
||||
* Massive Build System Improvements
|
||||
* Fix Item Dropping When Killing Players From The Server Console
|
||||
@ -277,7 +280,7 @@
|
||||
|
||||
**2.2.11**
|
||||
* Add `Close Current Screen On Death` Feature Flag (Enabled By Default) To Prevent Bugs
|
||||
* Fix More Furnace UI Bugs When Using "Disable 'gui_blocks' Atlas"
|
||||
* Fix More Furnace UI Bugs When Using `Disable 'gui_blocks' Atlas`
|
||||
|
||||
**2.2.10**
|
||||
* Fix Bug With Picking Up Items In "Remove Creative Mode Restrictions" Mode
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <trampoline/types.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "bootstrap.h"
|
||||
@ -179,7 +180,7 @@ void bootstrap(const options_t &options) {
|
||||
// Fix QEMU Bug
|
||||
#ifdef MCPI_RUNTIME_IS_QEMU
|
||||
args.push_back("-B");
|
||||
args.push_back("0x40000"); // Arbitrary Value (Aligns To 4k And 16k Page Sizes)
|
||||
args.push_back(std::to_string(QEMU_GUEST_BASE));
|
||||
#endif
|
||||
|
||||
// Specify MCPI Binary
|
||||
|
@ -15,8 +15,7 @@ FALSE Maximize Creative Mode Inventory Stack Size
|
||||
TRUE Animated Water
|
||||
TRUE Animated Lava
|
||||
TRUE Animated Fire
|
||||
TRUE Remove Invalid Item Background
|
||||
TRUE Disable "gui_blocks" Atlas
|
||||
TRUE Regenerate "gui_blocks" Atlas
|
||||
TRUE Fix Camera Rendering
|
||||
TRUE Implement Chat
|
||||
FALSE Hide Chat Messages
|
||||
@ -102,7 +101,6 @@ TRUE Log Chat Messages
|
||||
TRUE Log Game Status
|
||||
TRUE Screenshot Support
|
||||
TRUE Fix Camera Functionality
|
||||
TRUE Property Scale Animated Textures
|
||||
TRUE Allow High-Resolution Title
|
||||
TRUE Improved Classic Title Positioning
|
||||
TRUE Use Updated Title
|
||||
|
@ -7,6 +7,7 @@ set(CORE_SRC
|
||||
src/cursor.cpp
|
||||
src/util.cpp
|
||||
src/events.cpp
|
||||
src/offscreen.cpp
|
||||
src/audio/api.cpp
|
||||
src/audio/engine.c
|
||||
src/audio/file.cpp
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
#include <media-layer/core.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
#include "media.h"
|
||||
@ -37,7 +36,3 @@ int media_SDL_PushEvent(SDL_Event *event) {
|
||||
queue.push_back(*event);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void media_ensure_loaded() {
|
||||
// NOP
|
||||
}
|
||||
|
40
media-layer/core/src/offscreen.cpp
Normal file
40
media-layer/core/src/offscreen.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "media.h"
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
// Offscreen Rendering
|
||||
static GLFWwindow *offscreen_window = nullptr;
|
||||
void media_begin_offscreen_render(const int width, const int height) {
|
||||
if (!glfw_window) {
|
||||
IMPOSSIBLE();
|
||||
}
|
||||
// Setup GLFW
|
||||
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);
|
||||
glfwWindowHint(GLFW_ALPHA_BITS, 8);
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
|
||||
// Open Window
|
||||
offscreen_window = glfwCreateWindow(width, height, "Offscreen Rendering", nullptr, nullptr);
|
||||
if (!offscreen_window) {
|
||||
ERR("Unable To Create Offscreen Window");
|
||||
}
|
||||
// Switch Context
|
||||
glfwMakeContextCurrent(offscreen_window);
|
||||
media_context_id++;
|
||||
// Check Framebuffer Size
|
||||
int fb_width;
|
||||
int fb_height;
|
||||
glfwGetFramebufferSize(offscreen_window, &fb_width, &fb_height);
|
||||
if (fb_width != width || fb_height != height) {
|
||||
ERR("Offscreen Framebuffer Has Invalid Size");
|
||||
}
|
||||
}
|
||||
void media_end_offscreen_render() {
|
||||
// Destroy Window
|
||||
glfwDestroyWindow(offscreen_window);
|
||||
offscreen_window = nullptr;
|
||||
// Switch Context
|
||||
glfwMakeContextCurrent(glfw_window);
|
||||
media_context_id++;
|
||||
}
|
@ -5,15 +5,21 @@
|
||||
#include <libreborn/libreborn.h>
|
||||
|
||||
// Load GL Function
|
||||
static char *gl_dlerror() {
|
||||
return (char *) "Unknown Error";
|
||||
}
|
||||
#define dlerror gl_dlerror
|
||||
static void *gl_dlsysm(__attribute__((unused)) void *handle, __attribute__((unused)) const char *name) {
|
||||
return (void *) glfwGetProcAddress(name);
|
||||
}
|
||||
#define dlsym gl_dlsysm
|
||||
#define GL_FUNC EXTERNAL_FUNC
|
||||
unsigned int media_context_id = 0;
|
||||
#define GL_FUNC(name, return_type, args) \
|
||||
typedef return_type (*real_##name##_t)args; \
|
||||
__attribute__((__unused__)) static real_##name##_t real_##name() { \
|
||||
static real_##name##_t func = nullptr; \
|
||||
static unsigned int old_context = 0; \
|
||||
if (!func || old_context != media_context_id) { \
|
||||
old_context = media_context_id; \
|
||||
func = (real_##name##_t) glfwGetProcAddress(#name); \
|
||||
if (!func) { \
|
||||
ERR("Error Resolving OpenGL Function: " #name); \
|
||||
} \
|
||||
} \
|
||||
return func; \
|
||||
}
|
||||
|
||||
// Passthrough Functions
|
||||
GL_FUNC(glFogfv, void, (GLenum pname, const GLfloat *params))
|
||||
@ -36,10 +42,6 @@ GL_FUNC(glDrawArrays, void, (GLenum mode, GLint first, GLsizei count))
|
||||
void media_glDrawArrays(const GLenum mode, const GLint first, const GLsizei count) {
|
||||
real_glDrawArrays()(mode, first, count);
|
||||
}
|
||||
GL_FUNC(glMultiDrawArraysEXT, void, (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount))
|
||||
void media_glMultiDrawArrays(const GLenum mode, const GLint *first, const GLsizei *count, const GLsizei drawcount) {
|
||||
real_glMultiDrawArraysEXT()(mode, first, count, drawcount);
|
||||
}
|
||||
GL_FUNC(glColor4f, void, (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha))
|
||||
void media_glColor4f(const GLfloat red, const GLfloat green, const GLfloat blue, const GLfloat alpha) {
|
||||
real_glColor4f()(red, green, blue, alpha);
|
||||
@ -243,4 +245,10 @@ void media_glColorMaterial(const GLenum face, const GLenum mode) {
|
||||
GL_FUNC(glLightModelfv, void, (GLenum pname, const GLfloat *params))
|
||||
void media_glLightModelfv(const GLenum pname, const GLfloat *params) {
|
||||
real_glLightModelfv()(pname, params);
|
||||
}
|
||||
|
||||
// GL_EXT_multi_draw_arrays
|
||||
GL_FUNC(glMultiDrawArraysEXT, void, (GLenum mode, const GLint *first, const GLsizei *count, GLsizei drawcount))
|
||||
void media_glMultiDrawArrays(const GLenum mode, const GLint *first, const GLsizei *count, const GLsizei drawcount) {
|
||||
real_glMultiDrawArraysEXT()(mode, first, count, drawcount);
|
||||
}
|
@ -99,6 +99,7 @@ extern "C" {
|
||||
#define GL_FRONT_AND_BACK 0x408
|
||||
#define GL_AMBIENT_AND_DIFFUSE 0x1602
|
||||
#define GL_LIGHT_MODEL_AMBIENT 0xb53
|
||||
#define GL_STREAM_DRAW 0x88e0
|
||||
|
||||
typedef float GLfloat;
|
||||
typedef float GLclampf;
|
||||
@ -176,6 +177,8 @@ void media_glLightfv(GLenum light, GLenum pname, const GLfloat *params);
|
||||
void media_glColorMaterial(GLenum face, GLenum mode);
|
||||
void media_glLightModelfv(GLenum pname, const GLfloat *params);
|
||||
|
||||
extern unsigned int media_context_id;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -12,8 +12,6 @@ extern "C" {
|
||||
#define USER_EVENT_CHARACTER 0 // data1 = 8-Bit Character
|
||||
#define USER_EVENT_REAL_KEY 1 // data1 = SDL_RELEASED/PRESSED, data2 = GLFW Key Code
|
||||
|
||||
void media_ensure_loaded();
|
||||
|
||||
void media_toggle_fullscreen();
|
||||
void media_swap_buffers();
|
||||
void media_cleanup();
|
||||
@ -23,6 +21,8 @@ void media_disable_vsync();
|
||||
void media_force_egl();
|
||||
void media_set_raw_mouse_motion_enabled(int enabled);
|
||||
int media_has_extension(const char *name);
|
||||
void media_begin_offscreen_render(int width, int height);
|
||||
void media_end_offscreen_render();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -29,12 +29,13 @@ struct gl_array_details_t {
|
||||
uint32_t pointer = 0;
|
||||
};
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
struct {
|
||||
struct gl_array_details_obj_t {
|
||||
gl_array_details_t media_glVertexPointer;
|
||||
gl_array_details_t media_glColorPointer;
|
||||
gl_array_details_t media_glTexCoordPointer;
|
||||
gl_array_details_t media_glNormalPointer;
|
||||
} gl_array_details;
|
||||
};
|
||||
static gl_array_details_obj_t gl_array_details;
|
||||
#endif
|
||||
struct gl_state_t {
|
||||
GLuint bound_array_buffer = 0;
|
||||
@ -86,6 +87,22 @@ struct gl_state_t {
|
||||
static gl_state_t gl_state;
|
||||
#endif
|
||||
|
||||
// Backup/Restore State (For Offscreen Rendering)
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
static gl_state_t gl_state_backup;
|
||||
static gl_array_details_obj_t gl_array_details_backup;
|
||||
void _media_backup_gl_state() {
|
||||
gl_state_backup = gl_state;
|
||||
gl_array_details_backup = gl_array_details;
|
||||
gl_state = gl_state_t();
|
||||
gl_array_details = gl_array_details_obj_t();
|
||||
}
|
||||
void _media_restore_gl_state() {
|
||||
gl_state = gl_state_backup;
|
||||
gl_array_details = gl_array_details_backup;
|
||||
}
|
||||
#endif
|
||||
|
||||
// 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
#define CALL_GL_POINTER(unique_id, name) \
|
||||
@ -184,12 +201,25 @@ CALL(17, media_glClear, void, (GLbitfield mask))
|
||||
|
||||
CALL(18, media_glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(true, gl_state.bound_array_buffer, target, int32_t(size), copy_array(size, (unsigned char *) data), usage);
|
||||
static bool use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
|
||||
if (use_syscall) {
|
||||
trampoline(false, gl_state.bound_array_buffer, target, int32_t(size), uint32_t(data), usage);
|
||||
} else {
|
||||
trampoline(true, gl_state.bound_array_buffer, target, int32_t(size), copy_array(size, (unsigned char *) data), usage);
|
||||
}
|
||||
#else
|
||||
media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
|
||||
GLenum target = args.next<GLenum>();
|
||||
int32_t size = args.next<int32_t>();
|
||||
#ifdef MCPI_RUNTIME_IS_QEMU
|
||||
const unsigned char *data = nullptr;
|
||||
uint32_t data_addr = args.next<uint32_t>();
|
||||
if (data_addr != 0) {
|
||||
data = (const unsigned char *) (uintptr_t) (QEMU_GUEST_BASE + data_addr);
|
||||
}
|
||||
#else
|
||||
const unsigned char *data = args.next_arr<unsigned char>();
|
||||
#endif
|
||||
GLenum usage = args.next<GLenum>();
|
||||
func(target, size, data, usage);
|
||||
return 0;
|
||||
@ -768,13 +798,24 @@ CALL(67, media_glGenBuffers, void, (GLsizei n, GLuint *buffers))
|
||||
|
||||
CALL(69, media_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));
|
||||
static bool use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
|
||||
if (use_syscall) {
|
||||
trampoline(false, gl_state.bound_array_buffer, target, int32_t(offset), int32_t(size), uint32_t(data));
|
||||
} else {
|
||||
trampoline(true, gl_state.bound_array_buffer, target, int32_t(offset), copy_array(size, (unsigned char *) data));
|
||||
}
|
||||
#else
|
||||
media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
|
||||
GLenum target = args.next<GLenum>();
|
||||
int32_t offset = args.next<int32_t>();
|
||||
#ifdef MCPI_RUNTIME_IS_QEMU
|
||||
int32_t size = args.next<int32_t>();
|
||||
const unsigned char *data = args.next_arr<unsigned char>();
|
||||
uint32_t data_addr = args.next<uint32_t>();
|
||||
const unsigned char *data = (const unsigned char *) (uintptr_t) (QEMU_GUEST_BASE + data_addr);
|
||||
#else
|
||||
uint32_t size;
|
||||
const unsigned char *data = args.next_arr<unsigned char>(&size);
|
||||
#endif
|
||||
func(target, offset, size, data);
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -67,10 +67,7 @@ static uint32_t trampoline_pipe(const uint32_t id, const bool allow_early_return
|
||||
// Main Function
|
||||
uint32_t _raw_trampoline(const uint32_t id, const bool allow_early_return, const uint32_t length, const unsigned char *args) {
|
||||
// Configure Method
|
||||
static int use_syscall = -1;
|
||||
if (use_syscall == -1) {
|
||||
use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
|
||||
}
|
||||
static bool use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
|
||||
// Use Correct Method
|
||||
if (use_syscall) {
|
||||
return trampoline_syscall(id, length, args);
|
||||
|
@ -65,3 +65,7 @@ unsigned int _trampoline(const unsigned int id, const bool allow_early_return, A
|
||||
#define CALL(unique_id, name, return_type, args) \
|
||||
return_type name args { \
|
||||
static unsigned char _id = unique_id;
|
||||
|
||||
// Handle Cached GL State When Switching To Offscreen Context
|
||||
__attribute__((visibility("internal"))) void _media_backup_gl_state();
|
||||
__attribute__((visibility("internal"))) void _media_restore_gl_state();
|
||||
|
@ -174,15 +174,6 @@ CALL(66, media_force_egl, void, ())
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(68, media_ensure_loaded, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(true);
|
||||
#else
|
||||
func();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(71, media_has_extension, int, (const char *name))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
return trampoline(false, copy_array(name));
|
||||
@ -190,3 +181,25 @@ CALL(71, media_has_extension, int, (const char *name))
|
||||
return func(args.next_arr<char>());
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(76, media_begin_offscreen_render, void, (const int width, const int height))
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(true, width, height);
|
||||
_media_backup_gl_state();
|
||||
#else
|
||||
const int width = args.next<int32_t>();
|
||||
const int height = args.next<int32_t>();
|
||||
func(width, height);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
CALL(77, media_end_offscreen_render, void, ())
|
||||
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
|
||||
trampoline(true);
|
||||
_media_restore_gl_state();
|
||||
#else
|
||||
func();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
5
mods/include/mods/atlas/atlas.h
Normal file
5
mods/include/mods/atlas/atlas.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
void atlas_update_tile(Textures *textures, int texture, const unsigned char *pixels);
|
||||
}
|
@ -15,6 +15,7 @@ typedef RakNet_RakString *(*RakNet_RakString_constructor_2_t)(RakNet_RakString *
|
||||
extern RakNet_RakString_constructor_2_t RakNet_RakString_constructor_2;
|
||||
}
|
||||
|
||||
void misc_run_on_init(const std::function<void(Minecraft *)> &func);
|
||||
void misc_run_on_update(const std::function<void(Minecraft *)> &func);
|
||||
void misc_run_on_tick(const std::function<void(Minecraft *)> &func);
|
||||
void misc_run_on_recipes_setup(const std::function<void(Recipes *)> &func);
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <GLES/gl.h>
|
||||
|
||||
struct Texture;
|
||||
|
||||
extern "C" {
|
||||
void media_glTexSubImage2D_with_scaling(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei normal_texture_width, GLsizei normal_texture_height, GLenum format, GLenum type, const void *pixels);
|
||||
void media_glTexSubImage2D_with_scaling(const Texture *target, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLsizei normal_texture_width, GLsizei normal_texture_height, const void *pixels);
|
||||
void textures_add(int width, int height, const unsigned char *pixels);
|
||||
}
|
@ -1,2 +1,2 @@
|
||||
# `atlas` Mod
|
||||
This mod allows disabling the `gui_blocks` atlas.
|
||||
This mod allows regenerating the `gui_blocks` atlas at runtime.
|
||||
|
@ -2,124 +2,229 @@
|
||||
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <symbols/minecraft.h>
|
||||
#include <media-layer/core.h>
|
||||
|
||||
#include <mods/feature/feature.h>
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/textures/textures.h>
|
||||
#include <mods/atlas/atlas.h>
|
||||
#include <mods/init/init.h>
|
||||
|
||||
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
|
||||
static void ItemRenderer_renderGuiItemCorrect_injection_one(ItemRenderer_renderGuiItemCorrect_t original, Font *font, Textures *textures, const ItemInstance *item_instance, const int32_t param_1, const int32_t param_2) {
|
||||
const int32_t leaves_id = Tile::leaves->id;
|
||||
const int32_t grass_id = Tile::grass->id;
|
||||
// Replace Rendered Item With Carried Variant
|
||||
ItemInstance carried_item_instance;
|
||||
bool use_carried = false;
|
||||
if (item_instance != nullptr) {
|
||||
if (item_instance->id == leaves_id) {
|
||||
carried_item_instance.constructor_tile_extra(Tile::leaves_carried, item_instance->count, item_instance->auxiliary);
|
||||
use_carried = true;
|
||||
} else if (item_instance->id == grass_id) {
|
||||
carried_item_instance.constructor_tile_extra(Tile::grass_carried, item_instance->count, item_instance->auxiliary);
|
||||
use_carried = true;
|
||||
// Render Atlas
|
||||
#define ATLAS_SIZE 32
|
||||
#define ATLAS_ENTRY_SIZE 48
|
||||
static int get_atlas_key(Item *item, const int data) {
|
||||
const int id = item->id;
|
||||
const int icon = item->getIcon(data);
|
||||
return (id << 16) | icon;
|
||||
}
|
||||
static std::unordered_map<int, std::pair<int, int>> atlas_key_to_pos;
|
||||
static std::unordered_map<int, std::vector<std::pair<int, int>>> tile_texture_to_atlas_pos;
|
||||
static void render_atlas(Textures *textures) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
// Loop Over All Possible IDs
|
||||
for (int id = 0; id < 512; id++) {
|
||||
Item *item = Item::items[id];
|
||||
if (!item) {
|
||||
// Invalid ID
|
||||
continue;
|
||||
}
|
||||
// Count Unique Textures
|
||||
constexpr int amount_of_data_values_to_check = 512;
|
||||
std::unordered_map<int, int> key_to_data;
|
||||
for (int data = amount_of_data_values_to_check - 1; data >= 0; data--) {
|
||||
int key = get_atlas_key(item, data);
|
||||
key_to_data[key] = data;
|
||||
}
|
||||
// Loop Over All Data Values With Unique Textures
|
||||
for (const std::pair<int, int> info : key_to_data) {
|
||||
const int key = info.first;
|
||||
const int data = info.second;
|
||||
// Check Remaining Space (Leave Last Slot Empty)
|
||||
if (x == (ATLAS_SIZE - 1) && y == (ATLAS_SIZE - 1)) {
|
||||
WARN("Out Of gui_blocks Atlas Space!");
|
||||
return;
|
||||
}
|
||||
// Position
|
||||
media_glPushMatrix();
|
||||
media_glTranslatef(ATLAS_ENTRY_SIZE * x, ATLAS_ENTRY_SIZE * y, 0);
|
||||
constexpr float scale = ATLAS_ENTRY_SIZE / 16.0f;
|
||||
media_glScalef(scale, scale, 1);
|
||||
// Render
|
||||
ItemInstance obj = {
|
||||
.count = 1,
|
||||
.id = id,
|
||||
.auxiliary = data
|
||||
};
|
||||
ItemRenderer::renderGuiItemCorrect(nullptr, textures, &obj, 0, 0);
|
||||
media_glPopMatrix();
|
||||
// Store
|
||||
atlas_key_to_pos[key] = {x, y};
|
||||
if (id < 256) {
|
||||
Tile *tile = Tile::tiles[id];
|
||||
if (tile && !TileRenderer::canRender(tile->getRenderShape())) {
|
||||
int icon = item->getIcon(data);
|
||||
tile_texture_to_atlas_pos[icon].push_back(atlas_key_to_pos[key]);
|
||||
}
|
||||
}
|
||||
// Advance To Next Slot
|
||||
x++;
|
||||
if (x >= ATLAS_SIZE) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static void generate_atlas(Minecraft *minecraft) {
|
||||
// Setup Offscreen Rendering
|
||||
constexpr int atlas_size = ATLAS_SIZE * ATLAS_ENTRY_SIZE;
|
||||
media_begin_offscreen_render(atlas_size, atlas_size);
|
||||
|
||||
// Fix Toolbar Rendering
|
||||
const GLboolean depth_test_was_enabled = media_glIsEnabled(GL_DEPTH_TEST);
|
||||
// Setup OpenGL
|
||||
((NinecraftApp *) minecraft)->initGLStates();
|
||||
media_glViewport(0, 0, atlas_size, atlas_size);
|
||||
media_glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
media_glMatrixMode(GL_PROJECTION);
|
||||
media_glLoadIdentity();
|
||||
media_glOrthof(0, atlas_size, atlas_size, 0, 2000, 3000);
|
||||
media_glMatrixMode(GL_MODELVIEW);
|
||||
media_glLoadIdentity();
|
||||
media_glTranslatef(0, 0, -2000);
|
||||
media_glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Call Original Method
|
||||
original(font, textures, use_carried ? &carried_item_instance : item_instance, param_1, param_2);
|
||||
// Re-Upload Textures
|
||||
Textures *textures = Textures::allocate();
|
||||
textures->constructor(&minecraft->options, minecraft->platform());
|
||||
|
||||
// Revert GL State Changes
|
||||
if (depth_test_was_enabled) {
|
||||
media_glEnable(GL_DEPTH_TEST);
|
||||
// Render
|
||||
render_atlas(textures);
|
||||
|
||||
// Copy Open Inventory Button
|
||||
textures->loadAndBindTexture("gui/gui_blocks.png");
|
||||
constexpr int icon_width = 28;
|
||||
constexpr int icon_height = 8;
|
||||
minecraft->gui.blit(atlas_size - icon_width, atlas_size - icon_height, 242, 252, icon_width, icon_height, 14, 4);
|
||||
|
||||
// Read Texture
|
||||
int line_size = atlas_size * 4;
|
||||
{
|
||||
// Handle Alignment
|
||||
int alignment;
|
||||
media_glGetIntegerv(GL_PACK_ALIGNMENT, &alignment);
|
||||
// Round
|
||||
line_size = ALIGN_UP(line_size, alignment);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix Translucent Preview Items In Furnace UI Being Fully Opaque When The gui_blocks Atlas Is Disabled
|
||||
static int item_color_fix_mode = 0;
|
||||
#define POTENTIAL_FURNACE_ITEM_TRANSPARENCY 0x33
|
||||
#define INVALID_FURNACE_ITEM_MULTIPLIER 0.25f
|
||||
static void Tesselator_color_injection(Tesselator_color_t original, Tesselator *tesselator, int32_t r, int32_t g, int32_t b, int32_t a) {
|
||||
// Fix Furnace UI
|
||||
if (item_color_fix_mode != 0) {
|
||||
// Force Translucent
|
||||
if (item_color_fix_mode == 1) {
|
||||
a = POTENTIAL_FURNACE_ITEM_TRANSPARENCY;
|
||||
} else {
|
||||
static double multiplier = INVALID_FURNACE_ITEM_MULTIPLIER;
|
||||
b *= multiplier;
|
||||
g *= multiplier;
|
||||
r *= multiplier;
|
||||
Texture texture;
|
||||
texture.width = atlas_size;
|
||||
texture.height = atlas_size;
|
||||
texture.field3_0xc = 0;
|
||||
texture.field4_0x10 = true;
|
||||
texture.field5_0x11 = false;
|
||||
texture.field6_0x14 = 0;
|
||||
texture.field7_0x18 = -1;
|
||||
texture.data = new unsigned char[atlas_size * line_size];
|
||||
media_glReadPixels(0, 0, atlas_size, atlas_size, GL_RGBA, GL_UNSIGNED_BYTE, texture.data);
|
||||
for (int y = 0; y < (texture.height / 2); y++) {
|
||||
for (int x = 0; x < (texture.width * 4); x++) {
|
||||
unsigned char &a = texture.data[(y * line_size) + x];
|
||||
unsigned char &b = texture.data[((texture.height - y - 1) * line_size) + x];
|
||||
std::swap(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
original(tesselator, r, g, b, a);
|
||||
}
|
||||
static void Tesselator_begin_injection(Tesselator_begin_t original, Tesselator *tesselator, const int32_t mode) {
|
||||
// Call Original Method
|
||||
original(tesselator, mode);
|
||||
// Restore Old Context
|
||||
textures->destructor();
|
||||
::operator delete(textures);
|
||||
media_end_offscreen_render();
|
||||
|
||||
// Fix Furnace UI
|
||||
if (item_color_fix_mode != 0) {
|
||||
// Implicit Translucent
|
||||
tesselator->color(0xff, 0xff, 0xff, 0xff);
|
||||
// Upload Texture
|
||||
minecraft->textures->assignTexture("gui/gui_blocks.png", texture);
|
||||
DEBUG("Generated gui_blocks Atlas");
|
||||
}
|
||||
|
||||
// Use New Atlas
|
||||
static void ItemRenderer_renderGuiItem_two_injection(__attribute__((unused)) ItemRenderer_renderGuiItem_two_t original, __attribute__((unused)) Font *font, Textures *textures, const ItemInstance *item_instance_ptr, const float x, const float y, const float w, const float h, __attribute__((unused)) bool param_5) {
|
||||
// "Carried" Items
|
||||
ItemInstance item_instance = *item_instance_ptr;
|
||||
if (item_instance.id == Tile::leaves->id) {
|
||||
item_instance.id = Tile::leaves_carried->id;
|
||||
} else if (item_instance.id == Tile::grass->id) {
|
||||
item_instance.id = Tile::grass_carried->id;
|
||||
}
|
||||
}
|
||||
static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b) {
|
||||
// Call Original Method
|
||||
tesselator->color(r, g, b, 0xff);
|
||||
|
||||
// Enable Item Color Fix
|
||||
item_color_fix_mode = 2;
|
||||
}
|
||||
static void ItemRenderer_renderGuiItem_two_injection_one(ItemRenderer_renderGuiItem_two_t original, Font *font, Textures *textures, const ItemInstance *item_instance, const float param_1, const float param_2, const float param_3, const float param_4, const bool param_5) {
|
||||
// Call Original Method
|
||||
original(font, textures, item_instance, param_1, param_2, param_3, param_4, param_5);
|
||||
|
||||
// Disable Item Color Fix
|
||||
item_color_fix_mode = 0;
|
||||
}
|
||||
static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3) {
|
||||
// Enable Item Color Fix
|
||||
item_color_fix_mode = 1;
|
||||
|
||||
// Call Original Method
|
||||
ItemRenderer::renderGuiItem_one(font, textures, item_instance, param_1, param_2, param_3);
|
||||
// Get Position
|
||||
Item *item = Item::items[item_instance.id];
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
const int key = get_atlas_key(item, item_instance.auxiliary);
|
||||
if (!atlas_key_to_pos.contains(key)) {
|
||||
WARN("Skipping Item Not In gui_blocks Atlas: %i:%i", item_instance.id, item_instance.auxiliary);
|
||||
return;
|
||||
}
|
||||
const std::pair<int, int> &pos = atlas_key_to_pos[key];
|
||||
// Convert To UV
|
||||
float u0 = float(pos.first) / ATLAS_SIZE;
|
||||
float u1 = float(pos.first + 1) / ATLAS_SIZE;
|
||||
float v0 = float(pos.second) / ATLAS_SIZE;
|
||||
float v1 = float(pos.second + 1) / ATLAS_SIZE;
|
||||
// Render
|
||||
textures->loadAndBindTexture("gui/gui_blocks.png");
|
||||
Tesselator &t = Tesselator::instance;
|
||||
t.begin(GL_QUADS);
|
||||
t.colorABGR(item_instance.count > 0 ? 0xffffffff : 0x60ffffff);
|
||||
t.vertexUV(x, y + h, 0, u0, v1);
|
||||
t.vertexUV(x + w, y + h, 0, u1, v1);
|
||||
t.vertexUV(x + w, y, 0, u1, v0);
|
||||
t.vertexUV(x, y, 0, u0, v0);
|
||||
t.draw();
|
||||
}
|
||||
|
||||
// Smooth Scrolling
|
||||
static float target_x;
|
||||
static float target_y;
|
||||
static void ItemRenderer_renderGuiItem_two_injection_two(ItemRenderer_renderGuiItem_two_t original, Font *font, Textures *textures, const ItemInstance *item_instance, const float x, const float y, const float w, const float h, const bool param_5) {
|
||||
target_x = x;
|
||||
target_y = y;
|
||||
original(font, textures, item_instance, x, y, w, h, param_5);
|
||||
// Fix Buggy Crop Textures
|
||||
#define MAX_CROP_DATA 7
|
||||
static int CropTile_getTexture2_injection(CropTile_getTexture2_t original, CropTile *self, const int face, int data) {
|
||||
if (data > MAX_CROP_DATA) {
|
||||
data = MAX_CROP_DATA;
|
||||
}
|
||||
return original(self, face, data);
|
||||
}
|
||||
static void ItemRenderer_renderGuiItemCorrect_injection_two(ItemRenderer_renderGuiItemCorrect_t original, Font *font, Textures *textures, const ItemInstance *item_instance, __attribute__((unused)) int x, __attribute__((unused)) int y) {
|
||||
media_glPushMatrix();
|
||||
media_glTranslatef(target_x, target_y, 0);
|
||||
original(font, textures, item_instance, 0, 0);
|
||||
media_glPopMatrix();;
|
||||
|
||||
// Fix Open Inventory Button
|
||||
static void Gui_renderToolBar_GuiComponent_blit_injection(GuiComponent *self, int x_dest, int y_dest, __attribute__((unused)) const int x_src, __attribute__((unused)) const int y_src, const int width_dest, const int height_dest, const int width_src, const int height_src) {
|
||||
constexpr float size_scale = 2.0f / (ATLAS_SIZE * ATLAS_ENTRY_SIZE);
|
||||
constexpr float u1 = 1.0f;
|
||||
const float u0 = u1 - (float(width_src) * size_scale);
|
||||
constexpr float v1 = 1.0f;
|
||||
const float v0 = v1 - (float(height_src) * size_scale);
|
||||
Tesselator &t = Tesselator::instance;
|
||||
t.begin(GL_QUADS);
|
||||
t.vertexUV(x_dest, y_dest + height_dest, self->z, u0, v1);
|
||||
t.vertexUV(x_dest + width_dest, y_dest + height_dest, self->z, u1, v1);
|
||||
t.vertexUV(x_dest + width_dest, y_dest, self->z, u1, v0);
|
||||
t.vertexUV(x_dest, y_dest, self->z, u0, v0);
|
||||
t.draw();
|
||||
}
|
||||
|
||||
// Update Dynamic Textures In Atlas
|
||||
void atlas_update_tile(Textures *textures, const int texture, const unsigned char *pixels) {
|
||||
// Update Texture
|
||||
for (const std::pair<int, int> &pos : tile_texture_to_atlas_pos[texture]) {
|
||||
uint32_t atlas_id = textures->loadAndBindTexture("gui/gui_blocks.png");
|
||||
const Texture *atlas_data = textures->getTemporaryTextureData(atlas_id);
|
||||
constexpr int texture_size = 16;
|
||||
constexpr int fake_atlas_size = (ATLAS_SIZE * texture_size);
|
||||
media_glTexSubImage2D_with_scaling(atlas_data, pos.first * texture_size, pos.second * texture_size, texture_size, texture_size, fake_atlas_size, fake_atlas_size, pixels);
|
||||
}
|
||||
}
|
||||
|
||||
// Init
|
||||
void init_atlas() {
|
||||
// Disable The gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory
|
||||
if (feature_has("Disable \"gui_blocks\" Atlas", server_disabled)) {
|
||||
unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch);
|
||||
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled
|
||||
overwrite_calls(ItemRenderer_renderGuiItemCorrect, ItemRenderer_renderGuiItemCorrect_injection_one);
|
||||
// Fix Furnace UI
|
||||
overwrite_calls(Tesselator_begin, Tesselator_begin_injection);
|
||||
overwrite_calls(Tesselator_color, Tesselator_color_injection);
|
||||
overwrite_call((void *) 0x32324, (void *) FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection);
|
||||
overwrite_call((void *) 0x1e21c, (void *) InventoryPane_renderBatch_Tesselator_color_injection);
|
||||
overwrite_calls(ItemRenderer_renderGuiItem_two, ItemRenderer_renderGuiItem_two_injection_one);
|
||||
// Fix Inventory Scrolling
|
||||
overwrite_calls(ItemRenderer_renderGuiItem_two, ItemRenderer_renderGuiItem_two_injection_two);
|
||||
overwrite_calls(ItemRenderer_renderGuiItemCorrect, ItemRenderer_renderGuiItemCorrect_injection_two);
|
||||
// Generate Atlas
|
||||
if (feature_has("Regenerate \"gui_blocks\" Atlas", server_disabled)) {
|
||||
misc_run_on_init(generate_atlas);
|
||||
overwrite_calls(CropTile_getTexture2, CropTile_getTexture2_injection);
|
||||
overwrite_calls(ItemRenderer_renderGuiItem_two, ItemRenderer_renderGuiItem_two_injection);
|
||||
overwrite_call((void *) 0x26f50, (void *) Gui_renderToolBar_GuiComponent_blit_injection);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <symbols/minecraft.h>
|
||||
#include <libreborn/libreborn.h>
|
||||
#include <GLES/gl.h>
|
||||
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/feature/feature.h>
|
||||
@ -124,7 +125,7 @@ static std::vector<std::string> get_debug_info_right(const Minecraft *minecraft)
|
||||
// Entity
|
||||
Entity *entity = target.entity;
|
||||
x = entity->x;
|
||||
y = entity->y;
|
||||
y = entity->y - entity->height_offset;
|
||||
z = entity->z;
|
||||
type = "Entity";
|
||||
type_info.push_back("Type ID: " + std::to_string(entity->getEntityTypeId())); // TODO: Specify name when RJ PR is merged
|
||||
@ -151,7 +152,7 @@ static std::vector<std::string> get_debug_info_right(const Minecraft *minecraft)
|
||||
// Render Text With Background
|
||||
static constexpr uint32_t debug_background_color = 0x90505050;
|
||||
static constexpr int debug_text_color = 0xe0e0e0;
|
||||
static void render_debug_line(Gui *gui, const std::string &line, int x, const int y, const bool right_aligned) {
|
||||
static void render_debug_line(Gui *gui, const std::string &line, int x, const int y, const bool right_aligned, const int pass) {
|
||||
// Draw Background
|
||||
const int width = gui->minecraft->font->width(line);
|
||||
if (width == 0) {
|
||||
@ -165,26 +166,46 @@ static void render_debug_line(Gui *gui, const std::string &line, int x, const in
|
||||
int y1 = y - 1;
|
||||
int x2 = x + width;
|
||||
int y2 = y + line_height;
|
||||
gui->fill(x1, y1, x2, y2, debug_background_color);
|
||||
if (pass == 0) {
|
||||
gui->fill(x1, y1, x2, y2, debug_background_color);
|
||||
}
|
||||
// Draw Text
|
||||
gui->minecraft->font->draw(line, float(x), float(y), debug_text_color);
|
||||
if (pass == 1) {
|
||||
gui->minecraft->font->draw(line, float(x), float(y), debug_text_color);
|
||||
}
|
||||
}
|
||||
// Draw Debug Information
|
||||
static bool debug_info_shown = false;
|
||||
static constexpr int debug_margin = 2;
|
||||
static constexpr int debug_line_padding = 1;
|
||||
static void render_debug_info(Gui *self, const std::vector<std::string> &info, const bool right_aligned) {
|
||||
static void render_debug_info(Gui *self, const std::vector<std::string> &info, const bool right_aligned, const int pass) {
|
||||
int y = debug_margin;
|
||||
for (const std::string &line : info) {
|
||||
render_debug_line(self, line, debug_margin, y, right_aligned);
|
||||
render_debug_line(self, line, debug_margin, y, right_aligned, pass);
|
||||
y += line_height;
|
||||
y += debug_line_padding;
|
||||
}
|
||||
}
|
||||
static void Gui_renderDebugInfo_injection(__attribute__((unused)) Gui_renderDebugInfo_t original, Gui *self) {
|
||||
if (debug_info_shown) {
|
||||
render_debug_info(self, get_debug_info_left(self->minecraft), false);
|
||||
render_debug_info(self, get_debug_info_right(self->minecraft), true);
|
||||
for (int pass = 0; pass < 2; pass++) {
|
||||
Tesselator &t = Tesselator::instance;
|
||||
t.begin(GL_QUADS);
|
||||
t.voidBeginAndEndCalls(true);
|
||||
render_debug_info(self, get_debug_info_left(self->minecraft), false, pass);
|
||||
render_debug_info(self, get_debug_info_right(self->minecraft), true, pass);
|
||||
t.voidBeginAndEndCalls(false);
|
||||
if (pass == 0) {
|
||||
media_glEnable(GL_BLEND);
|
||||
media_glDisable(GL_TEXTURE_2D);
|
||||
media_glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
t.draw();
|
||||
if (pass == 0) {
|
||||
media_glEnable(GL_TEXTURE_2D);
|
||||
media_glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,9 @@
|
||||
static int is_survival = -1;
|
||||
|
||||
// Patch Game Mode
|
||||
static void set_is_survival(bool new_is_survival) {
|
||||
static void *survival_mode_constructor;
|
||||
static void *creative_mode_constructor;
|
||||
static void set_is_survival(const bool new_is_survival) {
|
||||
if (is_survival != new_is_survival) {
|
||||
DEBUG("Setting Game Mode: %s", new_is_survival ? "Survival" : "Creative");
|
||||
|
||||
@ -21,7 +23,7 @@ static void set_is_survival(bool new_is_survival) {
|
||||
patch((void *) 0x16ee4, size_patch);
|
||||
|
||||
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor
|
||||
overwrite_call((void *) 0x16ef4, new_is_survival ? (void *) SurvivalMode_constructor->get(true) : (void *) CreatorMode_constructor->get(true));
|
||||
overwrite_call((void *) 0x16ef4, new_is_survival ? survival_mode_constructor : creative_mode_constructor);
|
||||
|
||||
is_survival = new_is_survival;
|
||||
}
|
||||
@ -50,6 +52,8 @@ static unsigned char *Minecraft_getCreator_injection(Minecraft_getCreator_t orig
|
||||
void init_game_mode() {
|
||||
// Dynamic Game Mode Switching
|
||||
if (feature_has("Implement Game-Mode Switching", server_enabled)) {
|
||||
survival_mode_constructor = (void *) SurvivalMode_constructor->get(true);
|
||||
creative_mode_constructor = (void *) CreatorMode_constructor->get(true);
|
||||
set_is_survival(true);
|
||||
overwrite_calls(Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection);
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include <symbols/minecraft.h>
|
||||
|
||||
__attribute__((constructor)) static void init() {
|
||||
media_ensure_loaded();
|
||||
reborn_init_patch();
|
||||
thunk_enabler = reborn_thunk_enabler;
|
||||
run_tests();
|
||||
|
@ -47,6 +47,12 @@ HOOK(media_swap_buffers, void, ()) {
|
||||
}
|
||||
|
||||
// API
|
||||
void misc_run_on_init(const std::function<void(Minecraft *)> &func) {
|
||||
overwrite_calls(Minecraft_init, [func](Minecraft_init_t original, Minecraft *self) {
|
||||
original(self);
|
||||
func(self);
|
||||
});
|
||||
}
|
||||
void misc_run_on_update(const std::function<void(Minecraft *)> &func) {
|
||||
overwrite_calls(Minecraft_update, [func](Minecraft_update_t original, Minecraft *self) {
|
||||
original(self);
|
||||
@ -115,7 +121,7 @@ void misc_render_background(int color, const Minecraft *minecraft, const int x,
|
||||
media_glColor4f(1, 1, 1, 1);
|
||||
minecraft->textures->loadAndBindTexture("gui/background.png");
|
||||
Tesselator *t = &Tesselator::instance;
|
||||
t->begin(7);
|
||||
t->begin(GL_QUADS);
|
||||
t->color(color, color, color, 255);
|
||||
float x1 = x;
|
||||
float x2 = x + width;
|
||||
|
@ -119,7 +119,7 @@ static void render_fire(EntityRenderer *self, Entity *entity, const float x, flo
|
||||
media_glColor4f(1, 1, 1, 1);
|
||||
float zo = 0;
|
||||
int ss = 0;
|
||||
t.begin(7);
|
||||
t.begin(GL_QUADS);
|
||||
while (h > 0) {
|
||||
constexpr float xo = 0.0f;
|
||||
float u0;
|
||||
@ -220,7 +220,7 @@ static void render_shadow(const EntityRenderer *self, Entity *entity, const floa
|
||||
const float yo = y - ey;
|
||||
const float zo = z - ez;
|
||||
Tesselator &tt = Tesselator::instance;
|
||||
tt.begin(7);
|
||||
tt.begin(GL_QUADS);
|
||||
for (int xt = x0; xt <= x1; xt++) {
|
||||
for (int yt = y0; yt <= y1; yt++) {
|
||||
for (int zt = z0; zt <= z1; zt++) {
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <mods/feature/feature.h>
|
||||
|
||||
// Print Chat To Log
|
||||
static bool Gui_addMessage_recursing = false;
|
||||
static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const std::string &text) {
|
||||
// Sanitize Message
|
||||
char *new_message = strdup(text.c_str());
|
||||
@ -17,9 +16,10 @@ static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const
|
||||
const std::string cpp_str = new_message;
|
||||
|
||||
// Process Message
|
||||
if (!Gui_addMessage_recursing) {
|
||||
static bool recursing = false;
|
||||
if (!recursing) {
|
||||
// Start Recursing
|
||||
Gui_addMessage_recursing = true;
|
||||
recursing = true;
|
||||
|
||||
// Print Log Message
|
||||
char *safe_message = from_cp437(new_message);
|
||||
@ -30,7 +30,7 @@ static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const
|
||||
original(gui, cpp_str);
|
||||
|
||||
// End Recursing
|
||||
Gui_addMessage_recursing = false;
|
||||
recursing = false;
|
||||
} else {
|
||||
// Call Original Method
|
||||
original(gui, cpp_str);
|
||||
|
@ -592,6 +592,13 @@ void init_misc() {
|
||||
overwrite_call((void *) 0xb198c, (void *) Dimension_isValidSpawn_Level_getTopTile_injection);
|
||||
}
|
||||
|
||||
// Disable overwrite_calls() After Minecraft::init
|
||||
misc_run_on_init([](__attribute__((unused)) Minecraft *minecraft) {
|
||||
thunk_enabler = [](__attribute__((unused)) void *a, __attribute__((unused)) void *b) -> void * {
|
||||
IMPOSSIBLE();
|
||||
};
|
||||
});
|
||||
|
||||
// Init Other Components
|
||||
_init_misc_tinting();
|
||||
_init_misc_ui();
|
||||
|
@ -261,12 +261,6 @@ void _init_misc_ui() {
|
||||
overwrite_calls(Screen_render, Screen_render_injection);
|
||||
}
|
||||
|
||||
// Remove Invalid Item Background (A Red Background That Appears For Items That Are Not Included In The gui_blocks Atlas)
|
||||
if (feature_has("Remove Invalid Item Background", server_disabled)) {
|
||||
unsigned char invalid_item_background_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x63c98, invalid_item_background_patch);
|
||||
}
|
||||
|
||||
// Close Current Screen On Death To Prevent Bugs
|
||||
if (feature_has("Close Current Screen On Death", server_disabled)) {
|
||||
overwrite_calls(LocalPlayer_die, LocalPlayer_die_injection);
|
||||
|
2
mods/src/multidraw/README.md
Normal file
2
mods/src/multidraw/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# `multidraw` Mod
|
||||
This mod optimizes rendering using `glMultiDrawArrays`.
|
@ -84,7 +84,7 @@ void screenshot_take(Gui *gui) {
|
||||
const int size = height * line_size;
|
||||
|
||||
// Read Pixels
|
||||
unsigned char *pixels = (unsigned char *) malloc(size);
|
||||
unsigned char *pixels = new unsigned char[size];
|
||||
ALLOC_CHECK(pixels);
|
||||
media_glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
@ -101,7 +101,7 @@ void screenshot_take(Gui *gui) {
|
||||
}
|
||||
|
||||
// Free
|
||||
free(pixels);
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
// Init
|
||||
|
2
mods/src/shading/README.md
Normal file
2
mods/src/shading/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# `shading` Mod
|
||||
This mod implements proper entity shading using OpenGL lighting.
|
@ -97,7 +97,7 @@ static void Tesselator_draw_injection(Tesselator *self) {
|
||||
if (vertices > 0) {
|
||||
const GLuint buffer = get_next_buffer();
|
||||
media_glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||
media_glBufferData(GL_ARRAY_BUFFER, vertices * sizeof(CustomVertex), CustomTesselator::instance.vertices, GL_STATIC_DRAW);
|
||||
media_glBufferData(GL_ARRAY_BUFFER, vertices * sizeof(CustomVertex), CustomTesselator::instance.vertices, GL_STREAM_DRAW);
|
||||
if (self->has_texture) {
|
||||
media_glTexCoordPointer(2, GL_FLOAT, sizeof(CustomVertex), (void *) offsetof(CustomVertex, uv));
|
||||
media_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
@ -27,7 +27,7 @@ static std::vector<pending_skin> &get_pending_skins() {
|
||||
return pending_skins;
|
||||
}
|
||||
static pthread_mutex_t pending_skins_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static void load_pending_skins(__attribute__((unused)) Minecraft *minecraft) {
|
||||
static void load_pending_skins(Minecraft *minecraft) {
|
||||
// Lock
|
||||
pthread_mutex_lock(&pending_skins_lock);
|
||||
|
||||
@ -44,7 +44,8 @@ static void load_pending_skins(__attribute__((unused)) Minecraft *minecraft) {
|
||||
GLint last_texture;
|
||||
media_glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
|
||||
media_glBindTexture(GL_TEXTURE_2D, skin.texture_id);
|
||||
media_glTexSubImage2D_with_scaling(GL_TEXTURE_2D, 0, 0, 0, width, height, SKIN_WIDTH, SKIN_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, img);
|
||||
const Texture *texture = minecraft->textures->getTemporaryTextureData(skin.texture_id);
|
||||
media_glTexSubImage2D_with_scaling(texture, 0, 0, width, height, SKIN_WIDTH, SKIN_HEIGHT, img);
|
||||
media_glBindTexture(GL_TEXTURE_2D, last_texture);
|
||||
|
||||
// Free
|
||||
@ -114,7 +115,7 @@ static void *loader_thread(void *user_data) {
|
||||
}
|
||||
|
||||
// Intercept Texture Creation
|
||||
static int32_t Textures_assignTexture_injection(Textures_assignTexture_t original, Textures *textures, const std::string &name, unsigned char *data) {
|
||||
static int32_t Textures_assignTexture_injection(Textures_assignTexture_t original, Textures *textures, const std::string &name, const Texture &data) {
|
||||
// Call Original Method
|
||||
const int32_t id = original(textures, name, data);
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <mods/misc/misc.h>
|
||||
#include <mods/feature/feature.h>
|
||||
#include <mods/textures/textures.h>
|
||||
#include <mods/atlas/atlas.h>
|
||||
#include <mods/init/init.h>
|
||||
#include "textures-internal.h"
|
||||
|
||||
@ -20,65 +21,20 @@ static void Minecraft_tick_injection(const Minecraft *minecraft) {
|
||||
// Tick Dynamic Textures
|
||||
Textures *textures = minecraft->textures;
|
||||
if (textures != nullptr) {
|
||||
textures->tick(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Store Texture Sizes
|
||||
struct texture_data {
|
||||
GLuint id;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
};
|
||||
static std::vector<texture_data> &get_texture_data() {
|
||||
static std::vector<texture_data> data;
|
||||
return data;
|
||||
}
|
||||
HOOK(media_glTexImage2D, void, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels)) {
|
||||
// Store
|
||||
texture_data data = {};
|
||||
media_glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *) &data.id);
|
||||
data.width = width;
|
||||
data.height = height;
|
||||
get_texture_data().push_back(data);
|
||||
|
||||
// Call Original Method
|
||||
real_media_glTexImage2D()(target, level, internalformat, width, height, border, format, type, pixels);
|
||||
}
|
||||
HOOK(media_glDeleteTextures, void, (GLsizei n, const GLuint *textures)) {
|
||||
// Remove Old Data
|
||||
for (int i = 0; i < n; i++) {
|
||||
const GLuint id = textures[i];
|
||||
std::vector<texture_data>::iterator it = get_texture_data().begin();
|
||||
while (it != get_texture_data().end()) {
|
||||
const texture_data data = *it;
|
||||
if (data.id == id) {
|
||||
it = get_texture_data().erase(it);
|
||||
} else {
|
||||
++it;
|
||||
for (DynamicTexture *texture : textures->dynamic_textures) {
|
||||
texture->tick();
|
||||
texture->bindTexture(textures);
|
||||
for (int x = 0; x < texture->texture_size; x++) {
|
||||
for (int y = 0; y < texture->texture_size; y++) {
|
||||
const Texture *data = textures->getTemporaryTextureData(textures->current_texture);
|
||||
const int x_offset = 16 * ((texture->texture_index % 16) + x);
|
||||
const int y_offset = 16 * ((texture->texture_index / 16) + y);
|
||||
media_glTexSubImage2D_with_scaling(data, x_offset, y_offset, 16, 16, 256, 256, texture->pixels);
|
||||
}
|
||||
}
|
||||
atlas_update_tile(textures, texture->texture_index, texture->pixels);
|
||||
}
|
||||
}
|
||||
|
||||
// Call Original Method
|
||||
real_media_glDeleteTextures()(n, textures);
|
||||
}
|
||||
static void get_texture_size(const GLuint id, GLsizei *width, GLsizei *height) {
|
||||
// Iterate
|
||||
std::vector<texture_data>::iterator it = get_texture_data().begin();
|
||||
while (it != get_texture_data().end()) {
|
||||
const texture_data data = *it;
|
||||
if (data.id == id) {
|
||||
// Found
|
||||
*width = data.width;
|
||||
*height = data.height;
|
||||
return;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
// Not Found
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
}
|
||||
|
||||
// Scale Texture (Remember To Free)
|
||||
@ -94,42 +50,33 @@ static int get_line_size(const int width) {
|
||||
}
|
||||
return line_size;
|
||||
}
|
||||
static void *scale_texture(const unsigned char *src, const GLsizei old_width, const GLsizei old_height, const GLsizei new_width, const GLsizei new_height) {
|
||||
static unsigned char *scale_texture(const unsigned char *src, const GLsizei old_width, const GLsizei old_height, const GLsizei new_width, const GLsizei new_height) {
|
||||
const int old_line_size = get_line_size(old_width);
|
||||
const int new_line_size = get_line_size(new_width);
|
||||
|
||||
// Allocate
|
||||
unsigned char *dst = (unsigned char *) malloc(new_height * new_line_size);
|
||||
ALLOC_CHECK(dst);
|
||||
|
||||
unsigned char *dst = new unsigned char[new_height * new_line_size];
|
||||
// Scale
|
||||
for (int new_x = 0; new_x < new_width; new_x++) {
|
||||
const int old_x = (int) (((float) new_x / (float) new_width) * (float) old_width);
|
||||
for (int new_y = 0; new_y < new_height; new_y++) {
|
||||
const int old_x = (int) (((float) new_x / (float) new_width) * (float) old_width);
|
||||
const int old_y = (int) (((float) new_y / (float) new_height) * (float) old_height);
|
||||
|
||||
// Find Position
|
||||
const int new_position = (new_y * new_line_size) + (new_x * PIXEL_SIZE);
|
||||
const int old_position = (old_y * old_line_size) + (old_x * PIXEL_SIZE);
|
||||
|
||||
// Copy
|
||||
static_assert(sizeof (int32_t) == PIXEL_SIZE, "Pixel Size Doesn't Match 32-Bit Integer Size");
|
||||
*(int32_t *) &dst[new_position] = *(int32_t *) &src[old_position];
|
||||
}
|
||||
}
|
||||
|
||||
// Return
|
||||
return dst;
|
||||
}
|
||||
|
||||
// Scale Animated Textures
|
||||
void media_glTexSubImage2D_with_scaling(const GLenum target, const GLint level, const GLint xoffset, const GLint yoffset, const GLsizei width, const GLsizei height, const GLsizei normal_texture_width, const GLsizei normal_texture_height, const GLenum format, const GLenum type, const void *pixels) {
|
||||
void media_glTexSubImage2D_with_scaling(const Texture *target, const GLint xoffset, const GLint yoffset, const GLsizei width, const GLsizei height, const GLsizei normal_texture_width, const GLsizei normal_texture_height, const void *pixels) {
|
||||
// Get Current Texture Size
|
||||
GLint current_texture;
|
||||
media_glGetIntegerv(GL_TEXTURE_BINDING_2D, ¤t_texture);
|
||||
GLsizei texture_width;
|
||||
GLsizei texture_height;
|
||||
get_texture_size(current_texture, &texture_width, &texture_height);
|
||||
const GLsizei texture_width = target->width;
|
||||
const GLsizei texture_height = target->height;
|
||||
|
||||
// Calculate Factor
|
||||
const float width_factor = ((float) texture_width) / ((float) normal_texture_width);
|
||||
@ -138,31 +85,22 @@ void media_glTexSubImage2D_with_scaling(const GLenum target, const GLint level,
|
||||
// Only Scale If Needed
|
||||
if (width_factor == 1.0f && height_factor == 1.0f) {
|
||||
// No Scaling
|
||||
media_glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||
media_glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
} else {
|
||||
// Check
|
||||
if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) {
|
||||
// Pixels Must Be 4 Bytes
|
||||
ERR("Unsupported Texture Format For Scaling");
|
||||
}
|
||||
|
||||
// Scale
|
||||
const GLsizei new_width = width * width_factor;
|
||||
const GLsizei new_height = height * height_factor;
|
||||
void *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height);
|
||||
const GLsizei new_width = GLsizei(float(width) * width_factor);
|
||||
const GLsizei new_height = GLsizei(float(height) * height_factor);
|
||||
const unsigned char *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height);
|
||||
|
||||
// Call Original Method
|
||||
const GLint new_xoffset = xoffset * width_factor;
|
||||
const GLint new_yoffset = yoffset * height_factor;
|
||||
media_glTexSubImage2D(target, level, new_xoffset, new_yoffset, new_width, new_height, format, type, new_pixels);
|
||||
const GLint new_xoffset = GLint(float(xoffset) * width_factor);
|
||||
const GLint new_yoffset = GLint(float(yoffset) * height_factor);
|
||||
media_glTexSubImage2D(GL_TEXTURE_2D, 0, new_xoffset, new_yoffset, new_width, new_height, GL_RGBA, GL_UNSIGNED_BYTE, new_pixels);
|
||||
|
||||
// Free
|
||||
free(new_pixels);
|
||||
delete[] new_pixels;
|
||||
}
|
||||
}
|
||||
static void Textures_tick_glTexSubImage2D_injection(const GLenum target, const GLint level, const GLint xoffset, const GLint yoffset, const GLsizei width, const GLsizei height, const GLenum format, const GLenum type, const void *pixels) {
|
||||
media_glTexSubImage2D_with_scaling(target, level, xoffset, yoffset, width, height, 256, 256, format, type, pixels);
|
||||
}
|
||||
|
||||
// Load Textures
|
||||
static Texture AppPlatform_linux_loadTexture_injection(__attribute__((unused)) AppPlatform_linux_loadTexture_t original, __attribute__((unused)) AppPlatform_linux *app_platform, const std::string &path, const bool b) {
|
||||
@ -231,11 +169,10 @@ void init_textures() {
|
||||
_init_textures_lava(animated_water, animated_lava, animated_fire);
|
||||
}
|
||||
|
||||
// Scale Animated Textures
|
||||
if (feature_has("Property Scale Animated Textures", server_disabled)) {
|
||||
overwrite_call((void *) 0x53274, (void *) Textures_tick_glTexSubImage2D_injection);
|
||||
}
|
||||
|
||||
// Load Textures
|
||||
overwrite_calls(AppPlatform_linux_loadTexture, AppPlatform_linux_loadTexture_injection);
|
||||
|
||||
// Stop Reloading Textures On Resize
|
||||
unsigned char texture_reset_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
|
||||
patch((void *) 0x126b4, texture_reset_patch);
|
||||
}
|
||||
|
@ -109,9 +109,9 @@ static void StartMenuScreen_render_Screen_renderBackground_injection(StartMenuSc
|
||||
const float y = float(get_title_y(self));
|
||||
constexpr int w = modern_title_width / 2;
|
||||
constexpr int h = modern_title_height;
|
||||
Tesselator& t = Tesselator::instance;
|
||||
Tesselator &t = Tesselator::instance;
|
||||
media_glColor4f(1, 1, 1, 1);
|
||||
t.begin(7);
|
||||
t.begin(GL_QUADS);
|
||||
t.vertexUV(x - w, y + h, self->z, 0, 1);
|
||||
t.vertexUV(x + w, y + h, self->z, 1, 1);
|
||||
t.vertexUV(x + w, y, self->z, 1, 0);
|
||||
|
@ -161,6 +161,8 @@ set(SRC
|
||||
src/tile/GrassTile.def
|
||||
src/tile/HeavyTile.def
|
||||
src/tile/EntityTile.def
|
||||
src/tile/Bush.def
|
||||
src/tile/CropTile.def
|
||||
src/misc/Strings.def
|
||||
src/misc/I18n.def
|
||||
src/misc/SimpleFoodData.def
|
||||
|
@ -22,6 +22,7 @@ virtual-method void update() = 0x24;
|
||||
virtual-method int handleBack(bool do_nothing) = 0x34;
|
||||
virtual-method void init() = 0x38;
|
||||
virtual-method void selectLevel(const std::string &level_dir, const std::string &level_name, const LevelSettings &settings) = 0x40;
|
||||
virtual-method AppPlatform *platform() = 0x8;
|
||||
|
||||
property int screen_width = 0x20;
|
||||
property int screen_height = 0x24;
|
||||
|
@ -1,8 +1,15 @@
|
||||
size 0x4c;
|
||||
|
||||
constructor (Options *options, AppPlatform *app_platform) = 0x530e4;
|
||||
method void *destructor() = 0x53458;
|
||||
|
||||
method void tick(bool param_1) = 0x531c4;
|
||||
method uint loadAndBindTexture(const std::string &name) = 0x539cc;
|
||||
method uint loadTexture(const std::string &name, bool param_1) = 0x53800;
|
||||
method uint assignTexture(const std::string &name, uchar *data) = 0x5354c;
|
||||
method uint assignTexture(const std::string &name, const Texture &data) = 0x5354c;
|
||||
method void addDynamicTexture(DynamicTexture *texture) = 0x534f8;
|
||||
method Texture *getTemporaryTextureData(uint id) = 0x53168;
|
||||
|
||||
property bool blur = 0x39;
|
||||
property bool blur = 0x39;
|
||||
property std::vector<DynamicTexture *> dynamic_textures = 0x40;
|
||||
property uint current_texture = 0x3c;
|
3
symbols/src/tile/Bush.def
Normal file
3
symbols/src/tile/Bush.def
Normal file
@ -0,0 +1,3 @@
|
||||
extends Tile;
|
||||
|
||||
vtable 0x110fd0;
|
3
symbols/src/tile/CropTile.def
Normal file
3
symbols/src/tile/CropTile.def
Normal file
@ -0,0 +1,3 @@
|
||||
extends Bush;
|
||||
|
||||
vtable 0x1110f8;
|
Loading…
Reference in New Issue
Block a user