This commit is contained in:
Bigjango13 2024-10-26 21:43:59 -07:00
commit 66e082695f
39 changed files with 492 additions and 271 deletions

@ -1 +1 @@
Subproject commit c13072404d3bb7ffe6b58fea72393c305c1f5eab Subproject commit 377f9ddbc4747ca3a640231d259c0e6fcc71b4b0

View File

@ -76,8 +76,11 @@
* `Force Survival Mode Inventory Behavior` (Disabled By Default) * `Force Survival Mode Inventory Behavior` (Disabled By Default)
* `Maximize Creative Mode Inventory Stack Size` (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 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 * Add Milk Buckets
* Included In The `Add Buckets` Feature Flag * Included In The `Add Buckets` Feature Flag
* Removed `Property Scale Animated Textures` Feature Flag
* Removed `Remove Invalid Item Background` Feature Flag
* Improve Death Messages * Improve Death Messages
* Massive Build System Improvements * Massive Build System Improvements
* Fix Item Dropping When Killing Players From The Server Console * Fix Item Dropping When Killing Players From The Server Console
@ -277,7 +280,7 @@
**2.2.11** **2.2.11**
* Add `Close Current Screen On Death` Feature Flag (Enabled By Default) To Prevent Bugs * 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** **2.2.10**
* Fix Bug With Picking Up Items In "Remove Creative Mode Restrictions" Mode * Fix Bug With Picking Up Items In "Remove Creative Mode Restrictions" Mode

View File

@ -4,6 +4,7 @@
#include <vector> #include <vector>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <trampoline/types.h>
#include "util.h" #include "util.h"
#include "bootstrap.h" #include "bootstrap.h"
@ -179,7 +180,7 @@ void bootstrap(const options_t &options) {
// Fix QEMU Bug // Fix QEMU Bug
#ifdef MCPI_RUNTIME_IS_QEMU #ifdef MCPI_RUNTIME_IS_QEMU
args.push_back("-B"); 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 #endif
// Specify MCPI Binary // Specify MCPI Binary

View File

@ -15,8 +15,7 @@ FALSE Maximize Creative Mode Inventory Stack Size
TRUE Animated Water TRUE Animated Water
TRUE Animated Lava TRUE Animated Lava
TRUE Animated Fire TRUE Animated Fire
TRUE Remove Invalid Item Background TRUE Regenerate "gui_blocks" Atlas
TRUE Disable "gui_blocks" Atlas
TRUE Fix Camera Rendering TRUE Fix Camera Rendering
TRUE Implement Chat TRUE Implement Chat
FALSE Hide Chat Messages FALSE Hide Chat Messages
@ -102,7 +101,6 @@ TRUE Log Chat Messages
TRUE Log Game Status TRUE Log Game Status
TRUE Screenshot Support TRUE Screenshot Support
TRUE Fix Camera Functionality TRUE Fix Camera Functionality
TRUE Property Scale Animated Textures
TRUE Allow High-Resolution Title TRUE Allow High-Resolution Title
TRUE Improved Classic Title Positioning TRUE Improved Classic Title Positioning
TRUE Use Updated Title TRUE Use Updated Title

View File

@ -7,6 +7,7 @@ set(CORE_SRC
src/cursor.cpp src/cursor.cpp
src/util.cpp src/util.cpp
src/events.cpp src/events.cpp
src/offscreen.cpp
src/audio/api.cpp src/audio/api.cpp
src/audio/engine.c src/audio/engine.c
src/audio/file.cpp src/audio/file.cpp

View File

@ -2,7 +2,6 @@
#include <SDL/SDL.h> #include <SDL/SDL.h>
#include <media-layer/core.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include "media.h" #include "media.h"
@ -37,7 +36,3 @@ int media_SDL_PushEvent(SDL_Event *event) {
queue.push_back(*event); queue.push_back(*event);
return 1; return 1;
} }
void media_ensure_loaded() {
// NOP
}

View 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++;
}

View File

@ -5,15 +5,21 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
// Load GL Function // Load GL Function
static char *gl_dlerror() { unsigned int media_context_id = 0;
return (char *) "Unknown Error"; #define GL_FUNC(name, return_type, args) \
} typedef return_type (*real_##name##_t)args; \
#define dlerror gl_dlerror __attribute__((__unused__)) static real_##name##_t real_##name() { \
static void *gl_dlsysm(__attribute__((unused)) void *handle, __attribute__((unused)) const char *name) { static real_##name##_t func = nullptr; \
return (void *) glfwGetProcAddress(name); static unsigned int old_context = 0; \
} if (!func || old_context != media_context_id) { \
#define dlsym gl_dlsysm old_context = media_context_id; \
#define GL_FUNC EXTERNAL_FUNC func = (real_##name##_t) glfwGetProcAddress(#name); \
if (!func) { \
ERR("Error Resolving OpenGL Function: " #name); \
} \
} \
return func; \
}
// Passthrough Functions // Passthrough Functions
GL_FUNC(glFogfv, void, (GLenum pname, const GLfloat *params)) 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) { void media_glDrawArrays(const GLenum mode, const GLint first, const GLsizei count) {
real_glDrawArrays()(mode, first, 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)) 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) { void media_glColor4f(const GLfloat red, const GLfloat green, const GLfloat blue, const GLfloat alpha) {
real_glColor4f()(red, green, blue, alpha); real_glColor4f()(red, green, blue, alpha);
@ -244,3 +246,9 @@ GL_FUNC(glLightModelfv, void, (GLenum pname, const GLfloat *params))
void media_glLightModelfv(const GLenum pname, const GLfloat *params) { void media_glLightModelfv(const GLenum pname, const GLfloat *params) {
real_glLightModelfv()(pname, 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);
}

View File

@ -99,6 +99,7 @@ extern "C" {
#define GL_FRONT_AND_BACK 0x408 #define GL_FRONT_AND_BACK 0x408
#define GL_AMBIENT_AND_DIFFUSE 0x1602 #define GL_AMBIENT_AND_DIFFUSE 0x1602
#define GL_LIGHT_MODEL_AMBIENT 0xb53 #define GL_LIGHT_MODEL_AMBIENT 0xb53
#define GL_STREAM_DRAW 0x88e0
typedef float GLfloat; typedef float GLfloat;
typedef float GLclampf; 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_glColorMaterial(GLenum face, GLenum mode);
void media_glLightModelfv(GLenum pname, const GLfloat *params); void media_glLightModelfv(GLenum pname, const GLfloat *params);
extern unsigned int media_context_id;
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -12,8 +12,6 @@ extern "C" {
#define USER_EVENT_CHARACTER 0 // data1 = 8-Bit Character #define USER_EVENT_CHARACTER 0 // data1 = 8-Bit Character
#define USER_EVENT_REAL_KEY 1 // data1 = SDL_RELEASED/PRESSED, data2 = GLFW Key Code #define USER_EVENT_REAL_KEY 1 // data1 = SDL_RELEASED/PRESSED, data2 = GLFW Key Code
void media_ensure_loaded();
void media_toggle_fullscreen(); void media_toggle_fullscreen();
void media_swap_buffers(); void media_swap_buffers();
void media_cleanup(); void media_cleanup();
@ -23,6 +21,8 @@ void media_disable_vsync();
void media_force_egl(); void media_force_egl();
void media_set_raw_mouse_motion_enabled(int enabled); void media_set_raw_mouse_motion_enabled(int enabled);
int media_has_extension(const char *name); int media_has_extension(const char *name);
void media_begin_offscreen_render(int width, int height);
void media_end_offscreen_render();
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -29,12 +29,13 @@ struct gl_array_details_t {
uint32_t pointer = 0; uint32_t pointer = 0;
}; };
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
struct { struct gl_array_details_obj_t {
gl_array_details_t media_glVertexPointer; gl_array_details_t media_glVertexPointer;
gl_array_details_t media_glColorPointer; gl_array_details_t media_glColorPointer;
gl_array_details_t media_glTexCoordPointer; gl_array_details_t media_glTexCoordPointer;
gl_array_details_t media_glNormalPointer; gl_array_details_t media_glNormalPointer;
} gl_array_details; };
static gl_array_details_obj_t gl_array_details;
#endif #endif
struct gl_state_t { struct gl_state_t {
GLuint bound_array_buffer = 0; GLuint bound_array_buffer = 0;
@ -86,6 +87,22 @@ struct gl_state_t {
static gl_state_t gl_state; static gl_state_t gl_state;
#endif #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 // 'pointer' Is Only Supported As An Integer, Not As An Actual Pointer
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
#define CALL_GL_POINTER(unique_id, name) \ #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)) CALL(18, media_glBufferData, void, (GLenum target, GLsizeiptr size, const void *data, GLenum usage))
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
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); trampoline(true, gl_state.bound_array_buffer, target, int32_t(size), copy_array(size, (unsigned char *) data), usage);
}
#else #else
media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>()); media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
GLenum target = args.next<GLenum>(); GLenum target = args.next<GLenum>();
int32_t size = args.next<int32_t>(); 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>(); const unsigned char *data = args.next_arr<unsigned char>();
#endif
GLenum usage = args.next<GLenum>(); GLenum usage = args.next<GLenum>();
func(target, size, data, usage); func(target, size, data, usage);
return 0; 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)) CALL(69, media_glBufferSubData, void, (GLenum target, GLintptr offset, GLsizeiptr size, const void *data))
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST #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 #else
media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>()); media_glBindBuffer(GL_ARRAY_BUFFER, args.next<GLuint>());
GLenum target = args.next<GLenum>(); GLenum target = args.next<GLenum>();
int32_t offset = args.next<int32_t>(); int32_t offset = args.next<int32_t>();
#ifdef MCPI_RUNTIME_IS_QEMU
int32_t size = args.next<int32_t>(); 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); func(target, offset, size, data);
return 0; return 0;
#endif #endif

View File

@ -67,10 +67,7 @@ static uint32_t trampoline_pipe(const uint32_t id, const bool allow_early_return
// Main Function // Main Function
uint32_t _raw_trampoline(const uint32_t id, const bool allow_early_return, const uint32_t length, const unsigned char *args) { uint32_t _raw_trampoline(const uint32_t id, const bool allow_early_return, const uint32_t length, const unsigned char *args) {
// Configure Method // Configure Method
static int use_syscall = -1; static bool use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
if (use_syscall == -1) {
use_syscall = getenv(TRAMPOLINE_ARGUMENTS_PIPE_ENV) == nullptr;
}
// Use Correct Method // Use Correct Method
if (use_syscall) { if (use_syscall) {
return trampoline_syscall(id, length, args); return trampoline_syscall(id, length, args);

View File

@ -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) \ #define CALL(unique_id, name, return_type, args) \
return_type name args { \ return_type name args { \
static unsigned char _id = unique_id; 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();

View File

@ -174,15 +174,6 @@ CALL(66, media_force_egl, void, ())
#endif #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)) CALL(71, media_has_extension, int, (const char *name))
#ifdef MEDIA_LAYER_TRAMPOLINE_GUEST #ifdef MEDIA_LAYER_TRAMPOLINE_GUEST
return trampoline(false, copy_array(name)); 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>()); return func(args.next_arr<char>());
#endif #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
}

View File

@ -0,0 +1,5 @@
#pragma once
extern "C" {
void atlas_update_tile(Textures *textures, int texture, const unsigned char *pixels);
}

View File

@ -15,6 +15,7 @@ typedef RakNet_RakString *(*RakNet_RakString_constructor_2_t)(RakNet_RakString *
extern RakNet_RakString_constructor_2_t RakNet_RakString_constructor_2; 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_update(const std::function<void(Minecraft *)> &func);
void misc_run_on_tick(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); void misc_run_on_recipes_setup(const std::function<void(Recipes *)> &func);

View File

@ -2,6 +2,9 @@
#include <GLES/gl.h> #include <GLES/gl.h>
struct Texture;
extern "C" { 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);
} }

View File

@ -1,2 +1,2 @@
# `atlas` Mod # `atlas` Mod
This mod allows disabling the `gui_blocks` atlas. This mod allows regenerating the `gui_blocks` atlas at runtime.

View File

@ -2,124 +2,229 @@
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include <media-layer/core.h>
#include <mods/feature/feature.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> #include <mods/init/init.h>
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled // Render Atlas
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) { #define ATLAS_SIZE 32
const int32_t leaves_id = Tile::leaves->id; #define ATLAS_ENTRY_SIZE 48
const int32_t grass_id = Tile::grass->id; static int get_atlas_key(Item *item, const int data) {
// Replace Rendered Item With Carried Variant const int id = item->id;
ItemInstance carried_item_instance; const int icon = item->getIcon(data);
bool use_carried = false; return (id << 16) | icon;
if (item_instance != nullptr) { }
if (item_instance->id == leaves_id) { static std::unordered_map<int, std::pair<int, int>> atlas_key_to_pos;
carried_item_instance.constructor_tile_extra(Tile::leaves_carried, item_instance->count, item_instance->auxiliary); static std::unordered_map<int, std::vector<std::pair<int, int>>> tile_texture_to_atlas_pos;
use_carried = true; static void render_atlas(Textures *textures) {
} else if (item_instance->id == grass_id) { int x = 0;
carried_item_instance.constructor_tile_extra(Tile::grass_carried, item_instance->count, item_instance->auxiliary); int y = 0;
use_carried = true; // 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 // Setup OpenGL
const GLboolean depth_test_was_enabled = media_glIsEnabled(GL_DEPTH_TEST); ((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); media_glDisable(GL_DEPTH_TEST);
// Call Original Method // Re-Upload Textures
original(font, textures, use_carried ? &carried_item_instance : item_instance, param_1, param_2); Textures *textures = Textures::allocate();
textures->constructor(&minecraft->options, minecraft->platform());
// Revert GL State Changes // Render
if (depth_test_was_enabled) { render_atlas(textures);
media_glEnable(GL_DEPTH_TEST);
// 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);
} }
} Texture texture;
texture.width = atlas_size;
// Fix Translucent Preview Items In Furnace UI Being Fully Opaque When The gui_blocks Atlas Is Disabled texture.height = atlas_size;
static int item_color_fix_mode = 0; texture.field3_0xc = 0;
#define POTENTIAL_FURNACE_ITEM_TRANSPARENCY 0x33 texture.field4_0x10 = true;
#define INVALID_FURNACE_ITEM_MULTIPLIER 0.25f texture.field5_0x11 = false;
static void Tesselator_color_injection(Tesselator_color_t original, Tesselator *tesselator, int32_t r, int32_t g, int32_t b, int32_t a) { texture.field6_0x14 = 0;
// Fix Furnace UI texture.field7_0x18 = -1;
if (item_color_fix_mode != 0) { texture.data = new unsigned char[atlas_size * line_size];
// Force Translucent media_glReadPixels(0, 0, atlas_size, atlas_size, GL_RGBA, GL_UNSIGNED_BYTE, texture.data);
if (item_color_fix_mode == 1) { for (int y = 0; y < (texture.height / 2); y++) {
a = POTENTIAL_FURNACE_ITEM_TRANSPARENCY; for (int x = 0; x < (texture.width * 4); x++) {
} else { unsigned char &a = texture.data[(y * line_size) + x];
static double multiplier = INVALID_FURNACE_ITEM_MULTIPLIER; unsigned char &b = texture.data[((texture.height - y - 1) * line_size) + x];
b *= multiplier; std::swap(a, b);
g *= multiplier;
r *= multiplier;
} }
} }
// Call Original Method // Restore Old Context
original(tesselator, r, g, b, a); textures->destructor();
} ::operator delete(textures);
static void Tesselator_begin_injection(Tesselator_begin_t original, Tesselator *tesselator, const int32_t mode) { media_end_offscreen_render();
// Call Original Method
original(tesselator, mode);
// Fix Furnace UI // Upload Texture
if (item_color_fix_mode != 0) { minecraft->textures->assignTexture("gui/gui_blocks.png", texture);
// Implicit Translucent DEBUG("Generated gui_blocks Atlas");
tesselator->color(0xff, 0xff, 0xff, 0xff); }
// 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;
} }
} // Get Position
static void InventoryPane_renderBatch_Tesselator_color_injection(Tesselator *tesselator, int32_t r, int32_t g, int32_t b) { Item *item = Item::items[item_instance.id];
// Call Original Method if (!item) {
tesselator->color(r, g, b, 0xff); return;
}
// Enable Item Color Fix const int key = get_atlas_key(item, item_instance.auxiliary);
item_color_fix_mode = 2; if (!atlas_key_to_pos.contains(key)) {
} WARN("Skipping Item Not In gui_blocks Atlas: %i:%i", item_instance.id, item_instance.auxiliary);
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) { return;
// Call Original Method }
original(font, textures, item_instance, param_1, param_2, param_3, param_4, param_5); const std::pair<int, int> &pos = atlas_key_to_pos[key];
// Convert To UV
// Disable Item Color Fix float u0 = float(pos.first) / ATLAS_SIZE;
item_color_fix_mode = 0; float u1 = float(pos.first + 1) / ATLAS_SIZE;
} float v0 = float(pos.second) / ATLAS_SIZE;
static void FurnaceScreen_render_ItemRenderer_renderGuiItem_one_injection(Font *font, Textures *textures, ItemInstance *item_instance, float param_1, float param_2, bool param_3) { float v1 = float(pos.second + 1) / ATLAS_SIZE;
// Enable Item Color Fix // Render
item_color_fix_mode = 1; textures->loadAndBindTexture("gui/gui_blocks.png");
Tesselator &t = Tesselator::instance;
// Call Original Method t.begin(GL_QUADS);
ItemRenderer::renderGuiItem_one(font, textures, item_instance, param_1, param_2, param_3); 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 // Fix Buggy Crop Textures
static float target_x; #define MAX_CROP_DATA 7
static float target_y; static int CropTile_getTexture2_injection(CropTile_getTexture2_t original, CropTile *self, const int face, int data) {
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) { if (data > MAX_CROP_DATA) {
target_x = x; data = MAX_CROP_DATA;
target_y = y; }
original(font, textures, item_instance, x, y, w, h, param_5); 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(); // Fix Open Inventory Button
media_glTranslatef(target_x, target_y, 0); 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) {
original(font, textures, item_instance, 0, 0); constexpr float size_scale = 2.0f / (ATLAS_SIZE * ATLAS_ENTRY_SIZE);
media_glPopMatrix();; 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 // Init
void init_atlas() { void init_atlas() {
// Disable The gui_blocks Atlas Which Contains Pre-Rendered Textures For Blocks In The Inventory // Generate Atlas
if (feature_has("Disable \"gui_blocks\" Atlas", server_disabled)) { if (feature_has("Regenerate \"gui_blocks\" Atlas", server_disabled)) {
unsigned char disable_gui_blocks_atlas_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop" misc_run_on_init(generate_atlas);
patch((void *) 0x63c2c, disable_gui_blocks_atlas_patch); overwrite_calls(CropTile_getTexture2, CropTile_getTexture2_injection);
// Fix Grass And Leaves Inventory Rendering When The gui_blocks Atlas Is Disabled overwrite_calls(ItemRenderer_renderGuiItem_two, ItemRenderer_renderGuiItem_two_injection);
overwrite_calls(ItemRenderer_renderGuiItemCorrect, ItemRenderer_renderGuiItemCorrect_injection_one); overwrite_call((void *) 0x26f50, (void *) Gui_renderToolBar_GuiComponent_blit_injection);
// 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);
} }
} }

View File

@ -5,6 +5,7 @@
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include <libreborn/libreborn.h> #include <libreborn/libreborn.h>
#include <GLES/gl.h>
#include <mods/misc/misc.h> #include <mods/misc/misc.h>
#include <mods/feature/feature.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 *entity = target.entity; Entity *entity = target.entity;
x = entity->x; x = entity->x;
y = entity->y; y = entity->y - entity->height_offset;
z = entity->z; z = entity->z;
type = "Entity"; type = "Entity";
type_info.push_back("Type ID: " + std::to_string(entity->getEntityTypeId())); // TODO: Specify name when RJ PR is merged 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 // Render Text With Background
static constexpr uint32_t debug_background_color = 0x90505050; static constexpr uint32_t debug_background_color = 0x90505050;
static constexpr int debug_text_color = 0xe0e0e0; 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 // Draw Background
const int width = gui->minecraft->font->width(line); const int width = gui->minecraft->font->width(line);
if (width == 0) { 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 y1 = y - 1;
int x2 = x + width; int x2 = x + width;
int y2 = y + line_height; int y2 = y + line_height;
if (pass == 0) {
gui->fill(x1, y1, x2, y2, debug_background_color); gui->fill(x1, y1, x2, y2, debug_background_color);
}
// Draw Text // Draw Text
if (pass == 1) {
gui->minecraft->font->draw(line, float(x), float(y), debug_text_color); gui->minecraft->font->draw(line, float(x), float(y), debug_text_color);
}
} }
// Draw Debug Information // Draw Debug Information
static bool debug_info_shown = false; static bool debug_info_shown = false;
static constexpr int debug_margin = 2; static constexpr int debug_margin = 2;
static constexpr int debug_line_padding = 1; 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; int y = debug_margin;
for (const std::string &line : info) { 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 += line_height;
y += debug_line_padding; y += debug_line_padding;
} }
} }
static void Gui_renderDebugInfo_injection(__attribute__((unused)) Gui_renderDebugInfo_t original, Gui *self) { static void Gui_renderDebugInfo_injection(__attribute__((unused)) Gui_renderDebugInfo_t original, Gui *self) {
if (debug_info_shown) { if (debug_info_shown) {
render_debug_info(self, get_debug_info_left(self->minecraft), false); for (int pass = 0; pass < 2; pass++) {
render_debug_info(self, get_debug_info_right(self->minecraft), true); 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);
}
}
} }
} }

View File

@ -8,7 +8,9 @@
static int is_survival = -1; static int is_survival = -1;
// Patch Game Mode // 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) { if (is_survival != new_is_survival) {
DEBUG("Setting Game Mode: %s", new_is_survival ? "Survival" : "Creative"); 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); patch((void *) 0x16ee4, size_patch);
// Replace Default CreatorMode Constructor With CreatorMode Or SurvivalMode Constructor // 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; is_survival = new_is_survival;
} }
@ -50,6 +52,8 @@ static unsigned char *Minecraft_getCreator_injection(Minecraft_getCreator_t orig
void init_game_mode() { void init_game_mode() {
// Dynamic Game Mode Switching // Dynamic Game Mode Switching
if (feature_has("Implement Game-Mode Switching", server_enabled)) { 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); set_is_survival(true);
overwrite_calls(Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection); overwrite_calls(Minecraft_setIsCreativeMode, Minecraft_setIsCreativeMode_injection);

View File

@ -4,7 +4,6 @@
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
__attribute__((constructor)) static void init() { __attribute__((constructor)) static void init() {
media_ensure_loaded();
reborn_init_patch(); reborn_init_patch();
thunk_enabler = reborn_thunk_enabler; thunk_enabler = reborn_thunk_enabler;
run_tests(); run_tests();

View File

@ -47,6 +47,12 @@ HOOK(media_swap_buffers, void, ()) {
} }
// API // 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) { void misc_run_on_update(const std::function<void(Minecraft *)> &func) {
overwrite_calls(Minecraft_update, [func](Minecraft_update_t original, Minecraft *self) { overwrite_calls(Minecraft_update, [func](Minecraft_update_t original, Minecraft *self) {
original(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); media_glColor4f(1, 1, 1, 1);
minecraft->textures->loadAndBindTexture("gui/background.png"); minecraft->textures->loadAndBindTexture("gui/background.png");
Tesselator *t = &Tesselator::instance; Tesselator *t = &Tesselator::instance;
t->begin(7); t->begin(GL_QUADS);
t->color(color, color, color, 255); t->color(color, color, color, 255);
float x1 = x; float x1 = x;
float x2 = x + width; float x2 = x + width;

View File

@ -119,7 +119,7 @@ static void render_fire(EntityRenderer *self, Entity *entity, const float x, flo
media_glColor4f(1, 1, 1, 1); media_glColor4f(1, 1, 1, 1);
float zo = 0; float zo = 0;
int ss = 0; int ss = 0;
t.begin(7); t.begin(GL_QUADS);
while (h > 0) { while (h > 0) {
constexpr float xo = 0.0f; constexpr float xo = 0.0f;
float u0; float u0;
@ -220,7 +220,7 @@ static void render_shadow(const EntityRenderer *self, Entity *entity, const floa
const float yo = y - ey; const float yo = y - ey;
const float zo = z - ez; const float zo = z - ez;
Tesselator &tt = Tesselator::instance; Tesselator &tt = Tesselator::instance;
tt.begin(7); tt.begin(GL_QUADS);
for (int xt = x0; xt <= x1; xt++) { for (int xt = x0; xt <= x1; xt++) {
for (int yt = y0; yt <= y1; yt++) { for (int yt = y0; yt <= y1; yt++) {
for (int zt = z0; zt <= z1; zt++) { for (int zt = z0; zt <= z1; zt++) {

View File

@ -13,6 +13,13 @@ static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const
char *new_message = strdup(text.c_str()); char *new_message = strdup(text.c_str());
ALLOC_CHECK(new_message); ALLOC_CHECK(new_message);
sanitize_string(new_message, -1, 1); sanitize_string(new_message, -1, 1);
const std::string cpp_str = new_message;
// Process Message
static bool recursing = false;
if (!recursing) {
// Start Recursing
recursing = true;
// Print Log Message // Print Log Message
char *safe_message = from_cp437(new_message); char *safe_message = from_cp437(new_message);
@ -20,7 +27,14 @@ static void Gui_addMessage_injection(Gui_addMessage_t original, Gui *gui, const
free(safe_message); free(safe_message);
// Call Original Method // Call Original Method
original(gui, text); original(gui, cpp_str);
// End Recursing
recursing = false;
} else {
// Call Original Method
original(gui, cpp_str);
}
// Free // Free
free(new_message); free(new_message);

View File

@ -592,6 +592,13 @@ void init_misc() {
overwrite_call((void *) 0xb198c, (void *) Dimension_isValidSpawn_Level_getTopTile_injection); 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 Other Components
_init_misc_tinting(); _init_misc_tinting();
_init_misc_ui(); _init_misc_ui();

View File

@ -261,12 +261,6 @@ void _init_misc_ui() {
overwrite_calls(Screen_render, Screen_render_injection); 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 // Close Current Screen On Death To Prevent Bugs
if (feature_has("Close Current Screen On Death", server_disabled)) { if (feature_has("Close Current Screen On Death", server_disabled)) {
overwrite_calls(LocalPlayer_die, LocalPlayer_die_injection); overwrite_calls(LocalPlayer_die, LocalPlayer_die_injection);

View File

@ -0,0 +1,2 @@
# `multidraw` Mod
This mod optimizes rendering using `glMultiDrawArrays`.

View File

@ -84,7 +84,7 @@ void screenshot_take(Gui *gui) {
const int size = height * line_size; const int size = height * line_size;
// Read Pixels // Read Pixels
unsigned char *pixels = (unsigned char *) malloc(size); unsigned char *pixels = new unsigned char[size];
ALLOC_CHECK(pixels); ALLOC_CHECK(pixels);
media_glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); media_glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
@ -101,7 +101,7 @@ void screenshot_take(Gui *gui) {
} }
// Free // Free
free(pixels); delete[] pixels;
} }
// Init // Init

View File

@ -0,0 +1,2 @@
# `shading` Mod
This mod implements proper entity shading using OpenGL lighting.

View File

@ -97,7 +97,7 @@ static void Tesselator_draw_injection(Tesselator *self) {
if (vertices > 0) { if (vertices > 0) {
const GLuint buffer = get_next_buffer(); const GLuint buffer = get_next_buffer();
media_glBindBuffer(GL_ARRAY_BUFFER, 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) { if (self->has_texture) {
media_glTexCoordPointer(2, GL_FLOAT, sizeof(CustomVertex), (void *) offsetof(CustomVertex, uv)); media_glTexCoordPointer(2, GL_FLOAT, sizeof(CustomVertex), (void *) offsetof(CustomVertex, uv));
media_glEnableClientState(GL_TEXTURE_COORD_ARRAY); media_glEnableClientState(GL_TEXTURE_COORD_ARRAY);

View File

@ -27,7 +27,7 @@ static std::vector<pending_skin> &get_pending_skins() {
return pending_skins; return pending_skins;
} }
static pthread_mutex_t pending_skins_lock = PTHREAD_MUTEX_INITIALIZER; 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 // Lock
pthread_mutex_lock(&pending_skins_lock); pthread_mutex_lock(&pending_skins_lock);
@ -44,7 +44,8 @@ static void load_pending_skins(__attribute__((unused)) Minecraft *minecraft) {
GLint last_texture; GLint last_texture;
media_glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); media_glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture);
media_glBindTexture(GL_TEXTURE_2D, skin.texture_id); 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); media_glBindTexture(GL_TEXTURE_2D, last_texture);
// Free // Free
@ -114,7 +115,7 @@ static void *loader_thread(void *user_data) {
} }
// Intercept Texture Creation // 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 // Call Original Method
const int32_t id = original(textures, name, data); const int32_t id = original(textures, name, data);

View File

@ -10,6 +10,7 @@
#include <mods/misc/misc.h> #include <mods/misc/misc.h>
#include <mods/feature/feature.h> #include <mods/feature/feature.h>
#include <mods/textures/textures.h> #include <mods/textures/textures.h>
#include <mods/atlas/atlas.h>
#include <mods/init/init.h> #include <mods/init/init.h>
#include "textures-internal.h" #include "textures-internal.h"
@ -20,65 +21,20 @@ static void Minecraft_tick_injection(const Minecraft *minecraft) {
// Tick Dynamic Textures // Tick Dynamic Textures
Textures *textures = minecraft->textures; Textures *textures = minecraft->textures;
if (textures != nullptr) { if (textures != nullptr) {
textures->tick(true); for (DynamicTexture *texture : textures->dynamic_textures) {
} texture->tick();
} texture->bindTexture(textures);
for (int x = 0; x < texture->texture_size; x++) {
// Store Texture Sizes for (int y = 0; y < texture->texture_size; y++) {
struct texture_data { const Texture *data = textures->getTemporaryTextureData(textures->current_texture);
GLuint id; const int x_offset = 16 * ((texture->texture_index % 16) + x);
GLsizei width; const int y_offset = 16 * ((texture->texture_index / 16) + y);
GLsizei height; media_glTexSubImage2D_with_scaling(data, x_offset, y_offset, 16, 16, 256, 256, texture->pixels);
};
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;
} }
} }
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) // Scale Texture (Remember To Free)
@ -94,42 +50,33 @@ static int get_line_size(const int width) {
} }
return line_size; 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 old_line_size = get_line_size(old_width);
const int new_line_size = get_line_size(new_width); const int new_line_size = get_line_size(new_width);
// Allocate // Allocate
unsigned char *dst = (unsigned char *) malloc(new_height * new_line_size); unsigned char *dst = new unsigned char[new_height * new_line_size];
ALLOC_CHECK(dst);
// Scale // Scale
for (int new_x = 0; new_x < new_width; new_x++) { 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++) { 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); const int old_y = (int) (((float) new_y / (float) new_height) * (float) old_height);
// Find Position // Find Position
const int new_position = (new_y * new_line_size) + (new_x * PIXEL_SIZE); 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); const int old_position = (old_y * old_line_size) + (old_x * PIXEL_SIZE);
// Copy // Copy
static_assert(sizeof (int32_t) == PIXEL_SIZE, "Pixel Size Doesn't Match 32-Bit Integer Size"); 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]; *(int32_t *) &dst[new_position] = *(int32_t *) &src[old_position];
} }
} }
// Return // Return
return dst; return dst;
} }
// Scale Animated Textures // 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 // Get Current Texture Size
GLint current_texture; const GLsizei texture_width = target->width;
media_glGetIntegerv(GL_TEXTURE_BINDING_2D, &current_texture); const GLsizei texture_height = target->height;
GLsizei texture_width;
GLsizei texture_height;
get_texture_size(current_texture, &texture_width, &texture_height);
// Calculate Factor // Calculate Factor
const float width_factor = ((float) texture_width) / ((float) normal_texture_width); 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 // Only Scale If Needed
if (width_factor == 1.0f && height_factor == 1.0f) { if (width_factor == 1.0f && height_factor == 1.0f) {
// No Scaling // 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 { } else {
// Check
if (format != GL_RGBA || type != GL_UNSIGNED_BYTE) {
// Pixels Must Be 4 Bytes
ERR("Unsupported Texture Format For Scaling");
}
// Scale // Scale
const GLsizei new_width = width * width_factor; const GLsizei new_width = GLsizei(float(width) * width_factor);
const GLsizei new_height = height * height_factor; const GLsizei new_height = GLsizei(float(height) * height_factor);
void *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height); const unsigned char *new_pixels = scale_texture((const unsigned char *) pixels, width, height, new_width, new_height);
// Call Original Method // Call Original Method
const GLint new_xoffset = xoffset * width_factor; const GLint new_xoffset = GLint(float(xoffset) * width_factor);
const GLint new_yoffset = yoffset * height_factor; const GLint new_yoffset = GLint(float(yoffset) * height_factor);
media_glTexSubImage2D(target, level, new_xoffset, new_yoffset, new_width, new_height, format, type, new_pixels); media_glTexSubImage2D(GL_TEXTURE_2D, 0, new_xoffset, new_yoffset, new_width, new_height, GL_RGBA, GL_UNSIGNED_BYTE, new_pixels);
// Free // 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 // 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) { 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); _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 // Load Textures
overwrite_calls(AppPlatform_linux_loadTexture, AppPlatform_linux_loadTexture_injection); 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);
} }

View File

@ -109,9 +109,9 @@ static void StartMenuScreen_render_Screen_renderBackground_injection(StartMenuSc
const float y = float(get_title_y(self)); const float y = float(get_title_y(self));
constexpr int w = modern_title_width / 2; constexpr int w = modern_title_width / 2;
constexpr int h = modern_title_height; constexpr int h = modern_title_height;
Tesselator& t = Tesselator::instance; Tesselator &t = Tesselator::instance;
media_glColor4f(1, 1, 1, 1); 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, 0, 1);
t.vertexUV(x + w, y + h, self->z, 1, 1); t.vertexUV(x + w, y + h, self->z, 1, 1);
t.vertexUV(x + w, y, self->z, 1, 0); t.vertexUV(x + w, y, self->z, 1, 0);

View File

@ -162,6 +162,8 @@ set(SRC
src/tile/GrassTile.def src/tile/GrassTile.def
src/tile/HeavyTile.def src/tile/HeavyTile.def
src/tile/EntityTile.def src/tile/EntityTile.def
src/tile/Bush.def
src/tile/CropTile.def
src/misc/Strings.def src/misc/Strings.def
src/misc/I18n.def src/misc/I18n.def
src/misc/SimpleFoodData.def src/misc/SimpleFoodData.def

View File

@ -22,6 +22,7 @@ virtual-method void update() = 0x24;
virtual-method int handleBack(bool do_nothing) = 0x34; virtual-method int handleBack(bool do_nothing) = 0x34;
virtual-method void init() = 0x38; 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 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_width = 0x20;
property int screen_height = 0x24; property int screen_height = 0x24;

View File

@ -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 void tick(bool param_1) = 0x531c4;
method uint loadAndBindTexture(const std::string &name) = 0x539cc; method uint loadAndBindTexture(const std::string &name) = 0x539cc;
method uint loadTexture(const std::string &name, bool param_1) = 0x53800; 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 void addDynamicTexture(DynamicTexture *texture) = 0x534f8;
method Texture *getTemporaryTextureData(uint id) = 0x53168; 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;

View File

@ -0,0 +1,3 @@
extends Tile;
vtable 0x110fd0;

View File

@ -0,0 +1,3 @@
extends Bush;
vtable 0x1110f8;